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
concept AIList {
S name;
S text;
bool botFlag, mighty;
long modified;
S status;
}
static ConceptFieldIndexCI nameIndex;
static volatile long totalChars = -1;
p {
dbIndexing(AIList, 'name);
nameIndex = indexConceptFieldCI(AIList, 'name);
thread { mech_guessLanguage(""); } // preload
calcOnConceptChanges(10000, f calcTotalSize, true);
}
html {
temp countDispatch('html);
if (!webAuthed(params)) ret redirectToWebAuth();
try object html_serveDispatches(uri);
new Matches m;
// API
if (eq(uri, "/list-count")) ret serveText(countConcepts(AIList));
if (startsWith(uri, "/list-text/", m)) {
bool opt = eq("1", params.get("opt"));
S name = urldecode(m.get(0));
AIList l = getList_noCreate(name);
cset(l, mighty := true);
if (l == null)
if (opt)
ret serveText(jsonEncode(litmap("Error", ll("List not found", name))));
else
ret serveText(jsonEncode(litmap("Text" := "")));
else
ret serveText(jsonEncode(litmap("Name" := l.name, "Text" := l.text)));
}
if (eq(uri, "/list-names"))
ret serveText(jsonEncode(sortedIC(collect(list(AIList), 'name))));
if (eq(uri, "/bot-edited-lists"))
ret serveText(jsonEncode(sortedIC(collect(conceptsWhere(AIList, botFlag := true), 'name))));
// 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";
logStructure("versions.log", litmap(id := l.id, +text, date := now(), mode := "bot edit"));
cset(l, +text, botFlag := true, modified := now());
ret "Changed";
}
// Append API
if (eq(uri, "/bot-list-append")) {
S mode = params.get('mode);
lock dbLock();
S name = params.get("name"), text = params.get("text");
AIList l = getList(name);
if (eq(mode, "uniqCI")) {
text = lines(listMinusSet(tlft(text), asCISet(tlft(l.text))));
if (empty(text)) ret "No change";
}
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());
ret "Changed";
}
// Show list
if (startsWith(uri, "/list/", m)) {
AIList l = getList_noCreate(urldecode(m.get(0)));
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);
ret "List deleted";
}
if (status != null) cset(l, +status);
cset(l, +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 = uniq_sync(AIList, +name);
AIList l = findConcept(AIList, +name);
if (l == null) l = nameIndex.get(name);
if (l == null) if (!create) null; else l = cnew(AIList, +name);
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(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;
}