Warning: session_start(): open(/var/lib/php/sessions/sess_51mlh017drls3b2ebmlrhs953e, O_RDWR) failed: No space left on device (28) in /var/www/tb-usercake/models/config.php on line 51
Warning: session_start(): Failed to read session data: files (path: /var/lib/php/sessions) in /var/www/tb-usercake/models/config.php on line 51
!7
sS passwordSalt() {
ret loadTextFileOrCreateWithRandomID(javaxSecretDir("password-salt"));
}
concept PostReferenceable {}
concept User > PostReferenceable {
S name;
SecretValue passwordMD5;
S contact; // e.g. mail address
bool isMaster;
SecretValue botToken = aSecretGlobalID/*UnlessLoading*/();
toString { ret nempty(name) ? "User " + name : super.toString(); }
}
extend AuthedDialogID {
new Ref user; // who is logged in
bool userMode; // show things as if user was not master
}
concept UserCreatedObject > PostReferenceable {
new Ref creator;
S botInfo; // info on how this was made. set to anything non-empty if made by bot
//S nameInRepo; // unique by user, for URL
}
concept UserPost > UserCreatedObject {
S type, title, text;
bool isPublic = true;
S text() { ret text; }
new RefL postRefs;
new LS postRefTags;
sS _fieldOrder = "isPublic text type title postRefs";
toString {
S content = nempty(title) ? shorten(title) : shorten(text);
if (isBotPost())
ret "Bot post by " + userName(creator!) + " [" + botInfo + "]: " + content;
else
ret "Post by " + userName(creator!) + ": " + content;
}
bool isBotPost() { ret nempty(botInfo); }
}
/*concept BotHandle > UserCreatedObject {
S globalID = aGlobalIDUnlessLoading();
S comment;
SecretValue token;
}*/
!include once #1029928 // new Compact Module include
set flag NoNanoHTTPD.
/*c*/module GazelleExamples > DynNewBot2 {
void start {
botName = heading = adminName = "gazelle.rocks";
set enableUsers;
set useWebSockets;
set showRegisterLink;
unset showTalkToBotLink;
set alwaysRedirectToHttps;
set redirectOnLogout;
passwordSalt(); // make early
super.start();
db_mainConcepts().modifyOnCreate = true;
indexConceptFieldCI(User, "name");
}
// web socket stuff
class WebSocketInfo {}
transient Map webSockets = syncWeakHashMap();
void cleanMeUp_webSockets {
closeAllKeysAndClear((Map) webSockets);
}
void handleWebSocket(virtual WebSocket ws) {
set(ws, onClose := r { webSockets.remove(ws) });
set(ws, onOpen := rEnter {
S uri = cast rcall getUri(ws);
print("WebSocket opened! uri: " + uri);
});
}
S serveRegisterForm(SS params) {
S user = trim(params.get("user"));
S pw = trim(params.get("f_pw"));
S pw2 = trim(params.get("pw2"));
S redirect = params.get("redirect");
S contact = trim(params.get("contact"));
redirect = dropParamFromURL(redirect, "logout"); // don't log us out right again
if (empty(redirect)) redirect = baseLink + "/";
new LS msgs;
if (nempty(user) || nempty(pw)) {
lock dbLock();
if (empty(user)) msgs.add("Please enter a user name");
else if (l(user) < 4) msgs.add("Minimum user name length: 4 characters");
else if (l(user) > 30) msgs.add("Maximum user name length: 30 characters");
else if (hasConceptIC User(name := user))
msgs.add("This user exists, please choose a different name");
if (regexpContainsIC("[^a-z0-9\\-\\.]", user))
msgs.add("Bad characters in user name (please use only a-z, 0-9, - and .)");
if (empty(pw)) msgs.add("Please enter a password");
else if (l(pw) < 6) msgs.add("Minimum password length: 6 characters");
if (neq(pw, pw2)) msgs.add("Passwords don't match");
if (empty(msgs)) {
cnew User(name := user, passwordMD5 := SecretValue(hashPW(pw)), +contact);
ret hrefresh(5.0, redirect) + "User " + user + " created! Redirecting...";
}
}
ret hhtml(hhead(htitle("Register new user")
+ hsansserif() + hmobilefix() + hresponstable()) + hbody(hfullcenter(
h3_htmlEncode(adminName + " | Register new user")
+ hpostform(
hhidden(+redirect)
+ tag table(
(empty(msgs) ? "" : tr(td() + td() + td(htmlEncode2_nlToBr(lines_rtrim(msgs)))))
+ tr(td_valignTop("Choose a user name:")
+ td_valignTop(hinputfield(+user) + "
" + "(Minimum length 4. Characters allowed: a-z, 0-9, - and .)"))
+ tr(td_valignTop("Choose a password:")
+ td_valignTop(hpassword(f_pw := pw) + "
" + "(Minimum length 6 characters)"))
+ tr(td_valignTop("Repeat the password please:") + td(hpassword(+pw2)))
+ tr(td_valignTop("Way to contact you (e.g. e-mail) - optional:") + td(hpassword(+contact)))
+ tr(td() + td(hsubmit("Register"))), class := "responstable"),
action := baseLink + "/register")
)));
}
bool calcMasterAuthed(Req req) {
ret super.calcMasterAuthed(req)
|| req.auth != null && req.auth.user.has() && req.auth.user->isMaster;
}
O serveOtherPage(Req req) {
S uri = req.uri;
new Matches m;
if (eq(uri, "/register"))
ret serveRegisterForm(req.params);
if (eq(uri, "/becomeMaster") && req.auth != null && req.auth.user != null) {
S pw = trim(req.params.get("masterPW"));
if (eq(pw, realPW())) {
cset(req.auth.user, isMaster := true);
ret "You are master, " + req.auth.user + "!";
}
if (nempty(pw))
ret "Bad master PW";
ret hhtml(hhead(htitle("Become master")
+ hsansserif() + hmobilefix() + hresponstable()) + hbody(hfullcenter(
h3_htmlEncode(adminName + " | Become master")
+ hpostform(
tag table(
tr(td_valignTop("You are:")
+ td_valignTop(htmlEncode2(req.auth.user->name)))
+ tr(td_valignTop("Enter the master password:")
+ td_valignTop(hpassword(masterPW := pw)))
+ tr(td() + td(hsubmit("Become master user"))), class := "responstable"),
action := baseLink + "/becomeMaster")
)));
}
if (swic(uri, "/text/", m)) {
long id = parseLong(m.rest());
UserPost post = getConceptOpt UserPost(id);
if (post == null) ret serve404("Post with ID " + id + " not found");
if (!post.isPublic) ret serve404("Post is not public");
ret serveText(post.text());
}
// Serve a post
S uri2 = dropSlashPrefix(uri);
if (isInteger(uri2)) {
long id = parseLong(uri2);
UserPost post = getConceptOpt UserPost(id);
if (post == null) ret serve404("Post with ID " + id + " not found");
ret servePost(post);
}
try object serveOtherPage2(req);
ret super.serveOtherPage(req);
}
!include #1029962 // serveOtherPage2
O servePost(UserPost post) {
if (!post.isPublic) ret serve404("Post is not public");
HTMLFramer1 framer = framer();
framer.title = or2(post.title, shorten(post.text));
framer.add(p("By " + (post.creator.has() ? htmlEncode2(post.creator->name) : "?") + ". " + renderConceptDate(post)));
if (nempty(post.type))
framer.add(p("Post type: "+ htmlEncode2(post.type)));
framer.add(div(hsourcecode(post.text), style := hstyle_sourceCodeLikeInRepo()));
// show render link
if (eqic(post.type, "HTML"))
framer.add(p(ahref("/html/" + post.id, "Show as HTML page")));
// show edit link
if (canEditPost(post))
framer.add(p(ahref(conceptEditLink(post), "Edit post")));
// show reply link
framer.add(p(ahref(replyLink(post), "Reply to this post")));
// show post refs
L postRefs = cloneList(post.postRefs);
if (nempty(postRefs)) {
framer.add(p("In reference to:"));
framer.add(ul(cloneMap(postRefs, ref ->
ahref(objectLink(ref), htmlEncode_nlToBr_withIndents(str(ref))))));
}
// show referencing posts
Cl refs = referencingPosts(post);
if (nempty(refs)) {
framer.add(p("Referenced by posts:"));
framer.add(ul(lmap objectToHTML(refs)));
}
ret framer.render();
}
L referencingPosts(UserPost post) {
ret sortedByConceptID(instancesOf UserPost(allBackRefs(post)));
}
S serveAuthForm(S redirect) {
ret hAddToHead(super.serveAuthForm(redirect), hInitWebSocket());
}
S authFormMoreContent() {
ret p_vbar(navLinks());
}
// handle user log-in (create/update AuthedDialogID concept)
O handleAuth(Req req, S cookie) null {
S name = trim(req.params.get('user)), pw = trim(req.params.get('pw));
if (nempty(name) && nempty(pw) && nempty(cookie)) {
Domain authDomain;
User user = conceptWhereCI User(+name);
if (user == null)
ret errorMsg("User " + htmlEncode2(name) + " not found");
if (!eq(getVar(user.passwordMD5), hashPW(pw)))
ret errorMsg("Bad password, please try again");
// auth
cset(uniq AuthedDialogID(+cookie), restrictedToDomain := null, master := user.isMaster, +user);
S redirect = req.params.get('redirect);
if (nempty(redirect))
ret hrefresh(redirect);
}
}
O serve2(Req req) {
/*S userMode = req.params.get("userMode");
if (nempty(userMode) && req.auth != null)
req.auth.userMode = eq(userMode, "1");*/
if (req.auth != null) cset(req.auth, userMode := false);
ret super.serve2(req);
}
S hashPW(S pw) { ret md5(pw + passwordSalt()); }
bool inMasterMode(Req req) {
ret req.masterAuthed && !req.auth.userMode;
}
MapSO filtersForClass(Class c, Req req) {
if (c == UserPost) {
if (req.auth != null && !inMasterMode(req))
ret litmap(creator := req.auth.user!);
}
ret super.filtersForClass(c, req);
}
S loggedInUserDesc(Req req) {
ret req.auth == null ? "not logged in" : req.auth.user! == null ? (req.masterAuthed ? "master user" : "weird user") : "user " + req.auth.user->name;
}
HCRUD_Concepts crudData(Class c, Req req) {
HCRUD_Concepts cc = super.crudData(c, req);
if (c == UserPost) {
cc.addRenderer("text", new HCRUD_Data.TextArea(80, 10));
cc.fieldHelp(
type := "Type of post (any format, optional)",
title := "Title for this post (any format, optional)",
text := "Text contents of this post (any format)",
nameInRepo := "Name in repository (not really used yet)",
botInfo := "Info on which bot made this post (if any)");
cc.massageItemMapForList = (item, map) -> {
applyFunctionToValue shorten(map, "text", "title", "type", "nameInRepo");
map.put("postRefs", HTML(joinWithBR(lmap objectToHTML(item/UserPost.postRefs))));
};
cc.emptyObject = () -> {
MapSO item = cc.emptyObject_base();
item.put(creator := req.auth.user!); // set default creator to current user if in master mode
ret item;
};
}
ret cc;
}
HCRUD makeCRUD(Class c, Req req) {
HCRUD crud = super.makeCRUD(c, req);
if (c == UserPost) {
crud.renderCmds = map -> {
UserPost post = getConcept UserPost(toLong(crud.itemID(map)));
ret joinNemptiesWithVBar(crud.renderCmds_base(map),
targetBlank(postLink(post), "Show post"),
targetBlank(touchLink(post), "Touch", title := "Mark post as modified so it is looked at by bots again"));
};
crud.uneditableFields = litset("postRefTags");
}
if (c == User) {
crud.allowCreate = false;
crud.uneditableFields = litset("passwordMD5");
}
ret crud;
}
S authFormHeading() {
ret h3_htmlEncode("Welcome to the Gazelle AI System")
+ p(hsnippetimg_scaleToWidth(200, #1101482, 425, 257, title := "Gazelle"));
}
void makeFramer(Req req) {
super.makeFramer(req);
/*if (req.masterAuthed)
req.framer.add(p_vbar(
ahrefIf(req.auth.userMode, appendQueryToURL(baseLink + req.uri, userMode := 0), "Master mode", title := "View pages as master"),
ahrefIf(!req.auth.userMode, appendQueryToURL(baseLink + req.uri, userMode := 1), "User mode", title := "View pages as user")));*/
req.framer.add(p_vbar(navLinks()));
}
HTMLFramer1 framer() {
Req req = currentReq!;
if (req.framer == null) makeFramer(req);
ret req.framer;
}
// link to show post
S postLink(UserPost post) {
ret objectLink(post);
}
S touchLink(UserPost post) { ret baseLink + "/touchPost" + post.id; }
S objectLink(Concept c) {
ret baseLink + "/" + c.id;
}
S objectToHTML(Concept c) {
ret ahref(objectLink(c), htmlEncode2(str(c)));
}
S postToHTMLWithDate(UserPost post) {
ret post == null ? "" : objectToHTML(post)
+ " " + span(htmlEncode2(
renderHowLongAgoPlusModified(post.created, post._modified)), style := "color: #888");
}
bool canEditPost(UserPost post) {
Req req = currentReq!;
ret req != null && req.auth != null && req.auth.user! != null
&& (req.auth.user->isMaster || req.auth.user! == post.creator!);
}
S replyLink(UserPost post) {
ret appendQueryToURL(crudLink(UserPost), cmd := "new", fList_postRefs_0 := post.id);
}
User currentUser() {
if (currentReq! == null) null;
AuthedDialogID auth = currentReq->auth;
if (auth == null) null;
ret auth.user!;
}
LS navLinks() {
ret llNonNulls(
currentUser() != null ? ahref(crudLink(UserPost), "Admin") : null,
ahref("/search", "Search"),
ahref("/rootPosts", "Root Posts"),
ahref("/allPosts", "All Posts"),
ahref("/latestPosts", "Latest Posts"),
ahref("/html/803", "Home Page Design Test"));
}
L botCmdClasses() {
ret ll();
}
L crudClasses(Req req) {
L l = super.crudClasses(req);
l = listMinusSet(l, litset(Conversation, Lead, ConversationFeedback, Domain, UserKeyword, UploadedSound, Settings));
l.add(UserPost);
l.add(UploadedImage);
if (req.masterAuthed)
l.add(User);
ret l;
}
O getPostField(UserPost post, S field) {
if (eq(field, "creatorID")) ret post.creator->id;
if (eq(field, "creatorName")) ret post.creator->name;
ret cget(post, field);
}
} // end of module
sS userName(User user) {
ret user != null ? user.name : "?";
}