Warning: session_start(): open(/var/lib/php/sessions/sess_esa28ojpcspm625auevqv40qa7, 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
switchable double bot_maxPollSeconds = 600;
switchable int bot_pollInterval = 500;
Class extends Concept> defaultCRUDClass() {
ret Sequence;
}
O serveOtherPage2(Req req) null {
new Matches m;
S uri = dropTrailingSlashIfNemptyAfterwards(req.uri);
if (eq(uri, "/admin"))
ret hrefresh(baseLink + "/crud/" + shortClassName(defaultCRUDClass()));
if (eq(uri, "/latestPost")) {
UserPost post = highestConceptByField UserPost("created");
if (post == null) ret serve404("No posts in database");
ret servePost(post, req);
}
if (eq(uri, "/latestModifiedPost")) {
UserPost post = highestConceptByField UserPost("_modified");
if (post == null) ret serve404("No posts in database");
ret servePost(post, req);
}
if (eq(uri, "/rootPosts")) {
Cl posts = sortedByConceptIDDesc(filter(list(UserPost), post -> empty(post.postRefs)));
framer().navBeforeTitle = true;
framer().title = "Root Posts";
framer().add(ul(lmap postToHTMLWithDate(posts)));
ret framer().render();
}
if (eq(uri, "/allPosts")) {
Cl posts = sortedByConceptIDDesc(list(UserPost));
framer().navBeforeTitle = true;
framer().title = "All Posts";
framer().add(ul(lmap postToHTMLWithDate(posts)));
ret framer().render();
}
if (eq(uri, "/latestPosts")) {
Cl posts = takeFirst(50, sortedByConceptIDDesc(list(UserPost)));
framer().navBeforeTitle = true;
framer().title = "Latest Posts & Replies";
framer().add(ul(lmap postToHTMLWithDate(posts)));
ret framer().render();
}
if (eq(uri, "/latestModifiedPosts")) {
Cl posts = takeFirst(50, sortedByFieldDesc _modified(list(UserPost)));
framer().navBeforeTitle = true;
framer().title = "Latest Modified Posts & Replies";
framer().add(ul(lmap postToHTMLWithDate(posts)));
ret framer().render();
}
if (eq(uri, "/mainPosts")) {
Cl posts = takeFirst(50, sortedByConceptID(conceptsWhereCI UserPost(type := "Main")));
framer().navBeforeTitle = true;
framer().title = "Main Posts";
framer().add(ul(lmap postToHTMLWithDate(posts)));
ret framer().render();
}
if (swic(uri, "/html/", m) && isInteger(m.rest())) {
long id = parseLong(m.rest());
ret serveHTMLPost(id);
}
if (swic(uri, "/htmlEmbedded/", m) && isInteger(m.rest())) {
long id = parseLong(m.rest());
UserPost post = getConcept UserPost(id);
if (post == null) ret serve404("Post not found");
HTMLFramer1 framer = framer();
framer.title = "[" + post.id + "] " + or2(post.title, shorten(post.text));
framer.add(hcomment("Post begins here") + "\n" + post.text + "\n" + hcomment("Post ends here"));
ret framer.render();
}
if (swic(uri, "/css/", m) && isInteger(m.rest())) {
long id = parseLong(m.rest());
UserPost post = getConcept UserPost(id);
if (post == null) ret serve404("Post not found");
ret serveWithContentType(post.text, "text/css");
}
if (eq(uri, "/search")) {
framer().navBeforeTitle = true;
S q = trim(req.params.get("q"));
framer().title = joinNemptiesWithColon("Search", q);
framer().add(hcomment("cookie: " + req.webRequest.cookie()));
framer().add(hform(hinputfield(+q, autofocus := true) + " " + hsubmit("Search")));
framer().add(p(small("Search help: If you search for multiple words, they can appear in any order in the text. An underscore matches any character. Plus means space. Post titles, texts and types are searched.")));
if (nempty(q)) {
ScoredSearcher searcher = new(q);
long id = parseLongOpt_pcall(q);
for (UserPost post)
searcher.add(post, (post.id == id ? 4 : 0)
+ searcher.score(post.title)*3
+ searcher.score(post.text)*2
+ searcher.score(post.type)
+ searcher.score(joinWithSpace(post.postRefTags))*0.5);
L posts = searcher!;
framer().add(p(b(addPlusToCount(searcher.maxResults, l(posts), nPosts(posts))
+ " found for " + htmlEncode2(q))));
framer().add(ul(lmap postToHTMLWithDate(posts)));
}
ret framer().render();
}
// serve replies for JSTree AJAX call
if (eq(uri, "/jstree/replies")) {
UserPost post = getConcept UserPost(parseLong(req.params.get("post")));
if (post == null) ret serveJSON(ll());
Cl refs = referencingPosts(post);
/*[
{ "id" : "demo_root_1", "text" : "Root 1", "children" : true, "type" : "root" },
{ "id" : "demo_root_2", "text" : "Root 2", "type" : "root" }
]*/
ret serveJSON(map(refs, p -> litorderedmap(
id := p.id,
text := postToHTMLWithDate(post),
children := nempty(referencingPosts(p)) ? true : null,
type := "root" // ?
)));
}
if (startsWith(uri, "/touchPost/", m)) {
long id = parseLong(m.rest());
UserPost post = getConcept UserPost(id);
if (post == null) ret serve404("Post not found");
if (!canEditPost(post)) ret "You are not authorized to do this";
touchConcept(post);
ret hscript([[setTimeout('history.go(-1)', 1000);]]) + "Post " + post.id + " touched";
}
if (startsWith(uri, "/hidePost/", m)) {
long id = parseLong(m.rest());
UserPost post = getConcept UserPost(id);
if (post == null) ret serve404("Post not found");
if (!canEditPost(post)) ret "You are not authorized to do this";
cset(post, hidden := true);
ret hrefresh(postLink(post));
}
if (startsWith(uri, "/unhidePost/", m)) {
long id = parseLong(m.rest());
UserPost post = getConcept UserPost(id);
if (post == null) ret serve404("Post not found");
if (!canEditPost(post)) ret "You are not authorized to do this";
cset(post, hidden := false);
ret hrefresh(postLink(post));
}
if (startsWith(uri, "/markSafe/", m)) {
long id = parseLong(m.rest());
UserPost post = getConcept UserPost(id);
if (post == null) ret serve404("Post not found");
UserPost codePost = optCast UserPost(first(post.postRefs));
if (codePost == null) ret "Code post not found";
if (!canEditPost(codePost)) ret "You are not authorized to do this";
// create "Mark safe" post
uniqCI UserPost(creator := currentUser(), text := "Mark safe", postRefs := ll(post));
sleepSeconds(6); // allow bot to react
// touch code post
touchConcept(codePost);
ret hrefresh(postLink(codePost));
}
if (eq(uri, "/mirrorAllConversations")) {
if (!req.masterAuthed) ret serveAuthForm(rawLink(uri));
for (Conversation c)
rstUpdateMirrorPosts.add(c);
ret "OK";
}
if (startsWith(uri, "/mirrorConversation/", m)) {
if (!req.masterAuthed) ret serveAuthForm(rawLink(uri));
long id = parseLong(m.rest());
Conversation conv = getConcept Conversation(id);
if (conv == null) ret "Conversation not found";
conv.updateMirrorPost();
ret "Mirror post updated (" + htmlEncode2(str(conv.mirrorPost!)) + ")";
}
if (eqic(uri, "/favicon.ico"))
ret serveFavIcon();
// start of /bot commands
if (startsWith(uri, "/bot/", m)) {
req.subURI = m.rest();
S json = req.params.get("json");
new Map data;
if (nempty(json)) data = jsonDecodeMap(json);
data.putAll(withoutKey("json", req.params));
User user;
S userName = cast data.get("_user");
if (nempty(userName)) {
S botToken = cast data.get("_botToken");
if (botToken == null) ret serveJSON(error := "Need _botToken");
user = conceptWhereIC User(name := userName);
if (user == null) ret serveJSON(error := "User not found");
if (!eq(botToken, getVar(user.botToken))) ret serveJSON(error := "Wrong bot token");
} else
user = user(req);
S function = beforeSlashOrAll(req.subURI);
req.subURI = substring(req.subURI, l(function)+1);
req.webRequest.noSpam(); // might want to change this
try object servePossiblyUserlessBotFunction(req, function, data, user);
if (user == null) ret serveJSON(error := "Need _user");
if (eq(function, "getCookie"))
ret serveJSON(cookie := req.cookie());
if (eq(function, "authTest"))
ret serveJSON(status := "You are authorized as " + user.name + " " + roundBracket(user.isMaster ? "master user" : "non-master user"));
if (eq(function, "postCount"))
ret serveJSON(result := countConcepts(UserPost));
if (eq(function, "listPosts")) {
LS fields = unnull(stringToStringListOpt tok_identifiersInOrder(data.get("fields")));
if (!fields.contains("id")) fields.add(0, "id");
long changedAfter = toLong(data.get("changedAfter"));
long repliesTo = toLong(data.get("repliesTo"));
double pollFor = min(bot_maxPollSeconds, toLong(data.get("pollFor"))); // how long to poll (seconds)
long startTime = sysNow();
// We're super-anal about catching all changes. This will probably never trigger
if (changedAfter > 0 && changedAfter == now()) sleep(1);
Cl posts;
while true {
if (repliesTo != 0) {
posts = referencingPosts(getConcept UserPost(repliesTo));
if (changedAfter != 0) posts = objectsWhereFieldGreaterThan(posts, _modified := changedAfter);
} else {
posts = changedAfter == 0 ? list(UserPost)
: conceptsWithFieldGreaterThan_sorted(UserPost, _modified := changedAfter);
}
// return when there are results, no polling or poll expired
if (nempty(posts) || pollFor == 0 || elapsedSeconds_sysNow(startTime) >= pollFor)
ret serveJSON_breakAtLevels(2, result := map(posts, post ->
mapToValues(fields, field -> getPostFieldForBot(post, field))
));
// sleep and try again
sleep(bot_pollInterval);
}
}
if (eq(function, "createPost")) {
Either e = createPostArgs(user, data);
if (e.isB())
ret serveJSON(error := e.b());
Pair post = uniq2 UserPost(e.a());
if (!post.b) post.a.bump(); // bump if exact same post exists
ret serveJSON(status := post.b ? "Post created" : "Post existed already, bumped", postID := post.a.id);
}
if (eq(function, "editPost")) {
long postID = toLong(data.get("postID"));
UserPost post = getConcept UserPost(postID);
if (post == null)
ret serveJSON(error := "Post " + postID + " not found");
Either e = createPostArgs(user, data);
if (e.isB())
ret serveJSON(error := e.b());
int changes = cset(post, e.a());
// TODO: bump if no changes?
ret serveJSON(changes > 0 ? "Post updated" : "Post updated, no changes", +postID);
}
if (eq(function, "deletePosts")) {
L ids = allToLong(tok_integersInOrder((S) data.get("ids")));
new LS results;
new LS errors;
fOr (long id : ids) {
UserPost post = getConceptOpt UserPost(id);
if (post == null) errors.add("Post " + id + " not found");
else {
if (!user.isMaster && neq(post.creator!, user))
errors.add("Can't delete post " + id + " from other user");
else {
deletePost(post);
results.add("Post " + id + " deleted");
}
}
}
ret serveJSON(litorderedmap(+results, +errors));
}
ret serveBotFunction(req, function, data, user);
}
if (teamPostID != 0 && eq(uri, "/team"))
ret serveHTMLPost(teamPostID);
if (startsWith(uri, "/history/", m)) {
long id = parseLong(m.rest());
UserPost post = getConcept UserPost(id);
if (post == null) ret serve404("Post not found");
ret servePostHistory(post);
}
if (startsWith(uri, "/htmlBot/", m)) {
long id = parseLong(beforeSlashOrAll(m.rest()));
UserPost post = getConcept UserPost(id);
if (post == null) ret serve404("Post not found");
ret doPost(htmlBotURLOnBotServer(id), req.params());
}
if (eq(uri, "/deletedPosts")) {
temp CloseableItIt lines = linesFromFile(deletedPostsFile());
new L