!752 // must be run together with sub-bot #1002185 (queries the // slack slurper's database) static class SlackMsg { S user, botName; // one of these is going to be set S userName; // looked up if user != null S type, text, ts; O reactions; S channelID; } static class McMsg { S miniChat, user, text; long when; } static PersistentMap> tagsByTS; static S editPW; static class Tag { S name; //O addedBy; // not used yet *(S *name/*, O *addedBy*/) {} *() {} } p { tagsByTS = new PersistentMap("tagsByTS.log"); editPW = loadSecretTextFileMandatory("edit-pw").trim(); makeBot("Slack Tagger Bot!!"); } synchronized answer { if match "get tags for msg *" { S msgID = m.unq(0); L tags = tagsByTS.get(msgID); if (empty(tags)) ret "No tags for that msg"; else ret structure(tags); } } static S html(S uri, Map params) { try answer serveTextFile(uri, "tagsByTS.log"); L keepFields = litlist("channel", "n", "q"); S channelName = formatChannelName(or(params.get("channel"), "talkingbots")); O slurper = getBot("#1002185"); if (slurper == null) ret "Slurper not found"; L log = cast call(slurper, "getLog", channelName); log = filterLog(log, params.get("q")); // perform search boolean canEdit = master() || (!empty(editPW) && eq(editPW, params.get("edit-pw"))); print("editPW has " + l(editPW) + " chars. canEdit: " + canEdit); if (canEdit) for (S key : keys(params)) if (key.startsWith("tag_")) { S ts = dropPrefix("tag_", key); S val = params.get(key); new L tags; for (S t : splitByJavaToken(val, ",")) tags.add(new Tag(t.trim())); tagsByTS.put(ts, tags); } O mcBot = getBot("#1002433"); new L data; int n; if (!empty(params.get("n"))) n = parseInt(params.get("n")); else n = max(0, l(log)-1)/100*100; for (int i = n; i < min(n+100, l(log)); i++) { O o = log.get(i); S ts = getString(o, "ts"); L tags = unnull(tagsByTS.get(ts)); L names = asList(getSortedSet(tags, "name")); S tagNames = join(", ", names); // Pure text fields Map map = htmlencode(litmap( "Timestamp", ts, "User", get(o, "userName"), "Text", get(o, "text"), "#", i+1 )); // Fields with actual HTML map.put("Tags", htag("input", "", "type", "text", "name", "tag_" + ts, "value", tagNames)); if (mcBot != null) pcall { L mc = cast call(mcBot, "listMiniChat", "dc" + ts); new L miniChat; for (O _m : mc) { McMsg m = cast restructure(_m); miniChat.add(htmlencode(m.user + ": " + m.text)); } map.put("Mini-Chat", join("
", miniChat)); } data.add(map); } new StringBuilder buf; S title = "Tagging " + channelName; buf.append(htag("title", title)); buf.append(htag("h3", title)); // navigation new L l; for (int i = 0; i < l(log); i += 100) l.add(htag("a", str(i/100+1), "href", selfLink(params, keepFields, "n", str(i)))); buf.append(htag("p", "Pages: " + join("\n", l))); S formContents = htmlTable(data, false); if (canEdit) formContents += htag("p","You are clear to edit."); formContents += htag("p", "Search term: " + htag("input", "", "type", "text", "name", "q", "value", params.get("q"))); //formContents += htag("p", "Edit password: " + htag("input", "", "type", "password", "name", "edit-pw", "value", params.get("edit-pw"))); formContents += htag("input", "", "type", "submit", "value", "Submit!"); formContents += hiddenFields(params, minus(keepFields, "q")); buf.append(htag("form", formContents, "method", "POST")); ret str(buf); } static L filterLog(L log, S query) { query = trim(query); if (empty(query)) ret log; new L l; for (O o : log) { S text = getString(o, "text"); if (indexOfIgnoreCase(text, query) >= 0) l.add(o); } ret l; }