Warning: session_start(): open(/var/lib/php/sessions/sess_hr90o3t5esdkfa76kguk7ktrkl, 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
!include #1015743 // concept AIList
static ConceptFieldIndexCI nameIndex;
static volatile long totalChars = -1;
p {
dbSaveEvery(60);
dbIndexing(AIList, 'name);
nameIndex = indexConceptFieldCI(AIList, 'name);
thread { mech_guessLanguage(""); } // preload
calcOnConceptChanges(10000, f calcTotalSize, true);
updateListNamesList();
}
html {
temp countDispatch('html);
O response;
new Matches m;
bool authed = webAuthed(params);
if (eq(uri, "/list-count")) ret serveText(countConcepts(AIList));
if ((response = serveListText(uri, params, authed)) != null) ret response;
// Append API
if (swic(uri, "/bot-list-append/", m)) {
params.put(name := urldecode(m.rest());
uri = "/bot-list-append";
}
if (eq(uri, "/bot-list-append")) {
S mode = params.get('mode);
lock dbLock();
S name = params.get("name"), text = params.get("text");
if (!authed)
name = "Unauthorized Appends | " + name;
AIList l = getList(name);
//if (!authed) cset(l, status := "PUBLIC READ");
if (eq(mode, "uniqCI")) {
text = lines(listMinusSet(tlft(text), asCISet(tlft(l.text))));
if (empty(text)) ret "No change";
}
if (eq(mode, "uniq")) {
text = lines(listMinusSet(tlft(text), tlft(l.text)));
if (empty(text)) ret "No change";
}
listAppendWithLog(l, text);
ret "Changed";
}
if (!authed && eq(uri, "/list-names"))
ret serveText(jsonEncode(sortedIC(collect(publicReadLists(), 'name))));
if (!authed && eq(uri, "/list-md5s"))
ret serveText(jsonEncode(map(publicReadLists(), func(AIList l) -> LS { ll(l.name, md5OfList(l)) })));
if (eq(uri, "/authed")) ret yesno(authed);
if (!authed) ret redirectToWebAuth();
// AUTHED FROM HERE ON
try object html_serveDispatches(uri);
if (swic(uri, "/list-id/", m)) {
AIList l = getList_noCreate(urldecode(m.rest()));
ret l == null ? "List not found" : str(l.id);
}
if (eq(uri, "/fix-unauth")) {
for (AIList l) if (swic(l.name, "Unauthorized Appends |"))
cset(l, status := "");
ret "OK";
}
// API
if (eq(uri, "/download"))
ret subBot_serveFileWithName("mechlists-" + ymd_minus_hms() + ".gz", conceptsFile()); // TODO: concurrent writes?
if (eq(uri, "/list-names"))
ret serveText(jsonEncode(sortedIC(collect(list(AIList), 'name))));
if (eq(uri, "/list-md5s"))
ret serveText(jsonEncode(map(list(AIList), func(AIList l) -> LS { ll(l.name, md5OfList(l)) })));
if (eq(uri, "/bot-edited-lists"))
ret serveText(jsonEncode(sortedIC(collect(conceptsWhere(AIList, botFlag := true), 'name))));
// Create API
if (eq(uri, "/bot-list-create")) {
lock dbLock();
S name = params.get("name");
getList(name);
ret "OK";
}
// Edit API
if (eq(uri, "/bot-list-edit")) {
lock dbLock();
S name = params.get("name"), text = params.get("text");
AIList l = getList(name);
if (eq(l.text, text)) ret "No change";
listReplaceWithLog(l, text);
ret "Changed";
}
// Show list
if (startsWith(uri, "/list/", m)) {
S name = urldecode(m.get(0));
AIList l = eq("1", params.get("create")) ? getList(name) : getList_noCreate(name);
if (l == null) ret "List not found";
// Update text
S text = params.get("human");
S status = params.get("status");
if (text != null) {
lock dbLock();
//printStruct(ll(+text, +status));
if (neqAny(text, l.text, status, unnull(l.status))) {
logStructure("versions.log", litmap(id := l.id, +text, +status, date := now()));
if (eqic(status, "Delete me")) {
deleteConcept(l);
updateListNamesList();
ret "List deleted";
}
if (status != null) cset(l, +status);
cset(l, +text, textMD5 := md5(text), botFlag := false, modified := now());
//printStruct("l.text=" + sfu(text));
}
ret hrefresh(0, rawLink(uri) + "?random=" + randomID());
}
ret nav() + htitle_h2(htmlencode(l.name))
+ hpostform(
"Status: " + htextinput('status, value := l.status)
+ h3("Contents (" + (l.botFlag ? "bot" : "human") + "-edited)")
+ p(hsubmit("Save"))
+ htextarea(l.text, name := 'human, cols := 80, rows := 30));
}
// New list
S newList = trim(params.get('newList));
if (nempty(newList)) {
AIList l = getList(newList);
ret hrefresh(rawLink("/list/" + urlencode(l.name)));
}
// Search results
S q = params.get('q);
if (nempty(q))
ret hmobilefix()
+ htitle_h3("mech.tinybrain.de: Search results for " + htmlencode(singleQuote(q)))
+ listLists(scoredSearch_AIList(q, list(AIList)));
// Overview
bool alphabetical = eq(uri, "/alphabetical");
L list = alphabetical
? sortedByFieldIC('name, list(AIList))
: sortedByFieldDesc('modified, list(AIList));
ret hmobilefix()
+ htitle_h3("mech.tinybrain.de [" + n2(l(list), "list")
+ (totalChars >= 0 ? ", " + toK(totalChars) + "K chars" : "")
+ "]")
+ htableRaw_singleRow(ll(
hform("Search: " + htextinput('q, style := "width: 200px") + " " + hsubmit("Search")),
hpostform("| New list: " + htextinput('newList) + " " + hsubmit("Create list"))))
+ hBoolSelector(alphabetical, "/", "By date", "/alphabetical", "Alphabetical")
+ listLists(list);
}
sS nav() {
ret hmobilefix() + p(ahref(rawLink(), "<< back"));
}
static AIList getList_noCreate(S name) {
ret getList(name, false);
}
static AIList getList(S name) {
ret getList(name, true);
}
static AIList getList(S name, bool create) {
lock dbLock();
AIList l = findConcept(AIList, +name);
if (l == null) l = nameIndex.get(name);
if (l == null) if (!create) null; else {
l = cnew(AIList, +name);
logStructure("versions.log", litmap(id := l.id, +name, date := now(), mode := "List created"));
updateListNamesList();
}
if (l.modified == 0) cset(l, modified := now());
ret l;
}
sS listLists(L list) {
ret ul(map(list, func(AIList l) -> S {
int n = countLines(l.text);
new L status;
bool german = eq('german, mech_guessLanguage_quick(l.name));
if (l.mighty) status.add(german ? "GENUTZT" : "USED");
addIfNempty(status, htmlencode(l.status));
if (n != 0) status.add(n2(n, german ? "Zeile" : "line", german ? "Zeilen": "lines"));
ret ahref(rawLink("/list/" + urlencode(l.name)),
htmlencode(l.name)) + appendBracketed(joinWithComma(status));
}));
}
static L scoredSearch_AIList(S query, Iterable data) {
new Map scores;
L prepared = scoredSearch_prepare(query);
for (AIList l : data)
putUnlessZero(scores, l,
3*scoredSearch_score(l.name, prepared)
+ 2*scoredSearch_score(l.status, prepared)
+ scoredSearch_score(l.text, prepared));
ret keysSortedByValuesDesc(scores);
}
svoid calcTotalSize {
long total = 0;
for (AIList l)
total += l(l.text);
totalChars = total;
}
sS export_getListText(S listName) {
AIList l = getList_noCreate(listName);
ret l == null ? "" : l.text;
}
sS export_setListText(S listName, S text) {
AIList l = getList(listName);
if (eq(l.text, text)) ret "No change";
logStructure("versions.log", litmap(id := l.id, +text, date := now(), mode := "bot edit"));
cset(l, +text, textMD5 := md5(text), botFlag := true, modified := now());
ret "Changed";
}
sO serveListText(S uri, SS params, bool authed) {
new Matches m;
if (startsWith(uri, "/list-text/", m)) {
bool opt = eq("1", params.get("opt"));
bool create = authed && eq("1", params.get("create"));
S md5 = params.get("md5");
S name = urldecode(m.get(0));
lock dbLock();
AIList l = create ? getList(name) : getList_noCreate(name);
if (!authed && l != null && !l.isPublicRead()) ret subBot_serve404("Not logged in");
cset(l, mighty := true);
if (l == null)
if (opt)
ret serveText(jsonEncode(litmap("Text" := "")));
else
ret serveText(jsonEncode(litmap("Error", ll("List not found", name))));
else {
if (md5 != null) {
S actualMD5 = md5OfList(l);
print("md5: " + md5 + " / " + actualMD5);
if (eq(actualMD5, md5))
ret serveText(jsonEncode(litmap("Same" := true)));
}
ret serveText(jsonEncode(litmap("Name" := l.name, "Text" := l.text)));
}
}
null;
}
sS md5OfList(AIList l) {
lock dbLock();
if (l.textMD5 == null) l.textMD5 = md5(l.text);
ret l.textMD5;
}
static L publicReadLists() {
ret [AIList l : list(AIList) | l.isPublicRead()];
}
svoid updateListNamesList {
lock dbLock();
AIList l = getList("All public-read mech lists");
TreeSet actual = new TreeSet(collect(publicReadLists(), 'name));
Set listed = asHashSet(lines(l.text));
if (nempty(setMinusSet(listed, actual)))
listReplaceWithLog(l, lines(actual));
else
listAppendWithLog(l, lines(setMinusSet(actual, listed)));
}
svoid listAppendWithLog(AIList l, S text) {
if (emptyAfterTrim(text)) ret;
logStructure("versions.log", litmap(id := l.id, +text, date := now(), mode := "bot append"));
cset(l, text := appendNewLineIfNempty(rtrim(l.text)) + text, botFlag := true, modified := now(), textMD5 := null);
}
svoid listReplaceWithLog(AIList l, S text) {
if (eq(text, l.text)) ret;
logStructure("versions.log", litmap(id := l.id, +text, date := now(), mode := "bot edit"));
cset(l, +text, textMD5 := md5(text), botFlag := true, modified := now());
}