Warning: session_start(): open(/var/lib/php/sessions/sess_2leinf24ustsloqlu5qfvurd2d, 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 early #1030953 // specialized Compact Module Include
import loadableUtils.utils.User;
import loadableUtils.utils.UserPost;
import static loadableUtils.utils.botMod;
!include once #1030833 // BEACalculations
set flag NoNanoHTTPD.
module GazelleBEA > DynGazelleRocks {
switchable bool mirrorBEAObjects; // don't do it for now
switchable bool enableAutoRuns = true;
switchable bool enableNewBEAObjectNotis = true;
transient ReliableSingleThread_Multi rstAutoRuns = new(1000, lambda1 performAutoRuns);
transient Q notificationQ;
transient ReliableSingleThread_Multi rstDistributeNewObject = new(1000, lambda1 distributeNewObject_impl);
transient Set newObjectsDistributed = weakSet();
transient BEACalculations calculations = new(this);
transient int newFieldsToShow = 3;
transient bool allowAnonymousInputUpload = true; // TODO
switchable int maxInputLength = 50000;
// add more fields here
//!include #1030883 // DB quickImport mix-in
void init {
super.init();
botName = heading = adminName = "Gazelle BEA";
set enableVars;
set showTalkToBotLink;
unset phoneNumberSpecialInputField;
}
void startDB { db(); }
void start {
assertEquals(BEAObject, callF(defaultDefaultClassFinder(), "main$BEAObject"));
assertEquals(ConceptWithGlobalID, callF(defaultDefaultClassFinder(), "main$ConceptWithGlobalID"));
seedDBFrom(#1030602);
set storeBaseClassesInStructure;
super.start();
print("main concepts: " + db_mainConcepts() + ", count: " + db_mainConcepts().countConcepts());
print(renderConceptClassesWithCount(db_mainConcepts()));
print("Inputs: " + n2(beaCount("Input")));
set showCRUDToEveryone;
//set showOnlySelectedObject;
if (!enabled) ret;
// mirror all objects to be sure
rstUpdateBEAMirrors.addAll(list(BEAObject));
newObjectsDistributed.addAll(list(BEAObject));
/*onIndividualConceptChange_notOnAllChanged(BEAObject,
p -> { calculations.makeSyntacticPattern(p); });*/
onIndividualConceptChange_notOnAllChanged(BEAObject,
o -> {
if (enableAutoRuns) rstAutoRuns.add(o);
if (enableNewBEAObjectNotis && newObjectsDistributed.add(o))
rstDistributeNewObject.add(o);
});
notificationQ = dm_startQ();
// Until the ref leak bug is fixed, fix things every 30...
dm_doEvery(30.0, r {
print(ConceptsRefChecker(db_mainConcepts()).runAndFixAll());
});
}
void makeIndices :: after {
indexConceptFieldDesc(BEAObject, "_modified");
indexConceptFieldIC(BEAObject, "type");
// TODO: don't index nulls, also maybe just use backRefs
indexConceptField(BEAObject, "input"); // e.g. for counting how many matches we have for a given input
}
L crudClasses(Req req) {
ret listPlus(super.crudClasses(req), BEAObject);
}
S authFormHeading() {
ret h3("Gazelle BEA");
}
void makeFramer(Req req) {
super.makeFramer(req);
req.framer.renderTitle = () -> h1(ahref(baseLink + "/", "Gazelle BEA")
+ " " + htmlEncode2(req.framer.title));
req.framer.addInHead(hjs_autoExpandingTextAreas());
}
HCRUD_Concepts crudData(Class c, Req req) {
HCRUD_Concepts cc = super.crudData(c, req);
if (c == BEAObject) {
cc.humanizeFieldNames = false;
cc.convertConceptValuesToRefs = true;
cc.itemName = () -> "BEA Object";
cc.onCreate.add(o ->
cset(o, createdBy := currentUser()));
cc.getObjectForDuplication = id -> {
MapSO item = cc.getObjectForDuplication_base(id);
item.put(creator := req.auth.user!); // set default creator to current user
item.put(createdFrom := getConcept(toLong(id)));
ret item;
};
cc.emptyObject = () -> {
MapSO item = cc.emptyObject_base();
item.put(type := "");
ret item;
};
Set deletableRefs = litciset("Match");
cc.objectCanBeDeleted = id ->
all(findBackRefs(BEAObject, cc.conceptForID(id)),
o -> contains(deletableRefs, o.type()));
cc.actuallyDeleteConcept = o -> {
deleteConcepts(filter(findBackRefs(BEAObject, o),
o2 -> contains(deletableRefs, o2.type())));
cdelete(o);
};
}
ret cc;
}
HCRUD makeCRUD(Class c, Req req, HTMLFramer1 framer) {
HCRUD crud = super.makeCRUD(c, req, framer);
HCRUD_Concepts data = cast crud.data;
crud.showOnlySelected = true;
crud.showSearchField = true;
if (data.customFilter == null)
crud.descending = true; // show latest objects first by default except when searching
crud.cleanItemIDs = true;
if (c == BEAObject) {
crud.cellColumnToolTips = true;
crud.unshownFields = litset("mirrorPost", "globalID");
crud.showTextFieldsAsAutoExpandingTextAreas = true;
HCRUD_Concepts cc = cast crud.data;
S typeFilter = req.get("type");
if (nempty(typeFilter))
cc.addCIFilter(type := typeFilter);
crud.renderCmds = map -> {
BEAObject o = getConcept BEAObject(crud.itemIDAsLong(map));
new LS cmds;
// special commands for BEA types or objects with certain fields
if (nempty(o.text()))
cmds.add(
targetBlank(addParamsToURL(baseLink + "/query",
q := o.text(), algorithm := "process input"),
"Use text as query"));
if (o.typeIs("Input")) {
cmds.add(ahref(addParamsToURL(crudLink(BEAObject),
cmd := "new",
title := "Add Pattern For Input",
f_type := "Pattern",
f_text := getStringOpt text(o),
f_shouldMatch := o.id, metaInfo_shouldMatch := "concept",
), "Add pattern"));
cmds.add(ahref(appendParamsToURL(baseLink + "/query", q := o.text(), algorithm := "Apply all text functions"),
"Apply all text functions"));
}
if (o.typeIs("Pattern"))
cmds.add(ahref(appendParamsToURL(baseLink + "/query", q := o.id, algorithm := "Run pattern"),
"Run pattern against all inputs"));
if (o.typeIs("Match"))
cmds.add(ahref(appendParamsToURL(baseLink + "/query", q := o.id, algorithm := "Find rewrites for match"),
"Find rewrites"));
cmds.add(
ahref(addParamsToURL(baseLink + "/markUseful",
redirect := beaShortURL(o),
objectID := o.id),
"Mark useful"));
cmds.add(ahref(addParamsToURL(crudLink(BEAObject),
cmd := "new",
title := "Add Comment",
f_type := "Comment",
f_on := o.id,
f_text := "",
metaInfo_on := "concept"), "Add comment"));
if (o.typeIsOneOf("Script", "Step in script") || eqic(beforeVerticalBar(o.type()), "Instruction"))
cmds.add(
ahref(addParamsToURL(baseLink + "/runInstruction",
instruction := o.id),
"Run"));
if (o.typeIs("Function Result") && eqic(cget resultType(o), "string"))
cmds.add(
ahref(addParamsToURL(baseLink + "/convertResultToInput",
result := o.id),
"Convert to input"));
framer.addInHead(hjs_copyToClipboard());
cmds.add(ahref_onClick(formatFunctionCall copyToClipboard(jsQuote(o.globalIDStr())), "Copy global ID [" + o.globalIDStr() + "]"));
ret joinNemptiesWithVBar(
crud.renderCmds_base(map),
!o.typeIsOneOf("Input", "Pattern", "Syntactic Pattern")
? null : addRewriteHTML(o),
hPopDownButton(cmds));
};
cc.massageItemMapForList = (item, map) -> {
BEAObject o = cast item;
if (o.typeIs("Input")) {
Cl matches = objectsWhereCI(findBackRefs(o, BEAObject), type := "match");
map/Map.put("Best Matches", HTML(hparagraphs(
lmap matchDescHTML(takeFirst(3, matches)))));
}
S idField = crud.idField();
O id = map/Map.get(idField);
if (id instanceof S)
map/Map.put(idField, HTML(ahref(beaShortURL(o), id)));
if (o.typeIs("Function Result")) {
O value = o~.result;
map/Map.put("result", HTML(javaValueToHTML(value)));
}
};
crud.massageFormMatrix = (map, matrix) -> {
for (int i = 1; i <= newFieldsToShow; i++) {
S nf = "newField" + i;
S refSelector =
crud.renderInput("\*nf*/_conceptValue",
cc.makeConceptsComboBox("\*nf*/_conceptValue", BEAObject), null)
+ hjs([[$("[name=]] + nf + [[_conceptValue]").hide()]]);
LS types = ll("String", "BEAObject", "Bool");
S typeSelector = hselect_list(types, name := "\*nf*/_type",
onchange := [[
var value = this.value;
$("[name=]] + nf + [[_value]").toggle(value != "BEAObject");
$("#]] + nf + [[_refBox").toggle(value == "BEAObject");
]]);
matrix.add(ll("Add field:
" + htextfield("\*nf*/_name", title := "New field name"),
htmlTable2_noHtmlEncode(ll(ll(
// string input
htextfield("\*nf*/_value"),
span(refSelector, id := "\*nf*/_refBox", style := "display: none"),
"Type", typeSelector
)),
noHeader := true,
tableParams := litobjectarray(style := "width: 100%"))));
}
};
crud.preprocessUpdateParams = params -> {
params = cloneMap(params);
// drop empty strings
//removeFromMapWhereValue(params, v -> eq(v, ""));
params = mapValues(params, v -> eq(v, "") ? null : v);
for (int i = 1; i <= max(newFieldsToShow, 10); i++) {
S nf = "newField" + i;
S name = params.get("\*nf*/_name"),
type = params.get("\*nf*/_type"),
refValue = params.get("\*nf*/_conceptValue"),
value = params.get("\*nf*/_value");
if (eqic(type, "BEAObject")) {
value = refValue;
params.put("metaInfo_" + name, "concept");
} else if (eqic(type, "Bool"))
params.put("metaInfo_" + name, "bool");
if (eq(value, "")) value = null;
if (nempty(name) /*&& neqOneOf(value, null, "")*/)
params.put(crud.fieldPrefix + name, value);
}
ret params;
};
}
ret crud;
}
O serveBotFunction(Req req, S function, Map data, User user) {
if (eq(function, "beaList")) {
long changedAfter = toLong(data.get("changedAfter"));
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 objects;
while true {
objects = changedAfter == 0 ? list(BEAObject)
: conceptsWithFieldGreaterThan_sorted(BEAObject, _modified := changedAfter);
// return when there are results, no polling or poll expired
if (nempty(objects) || pollFor == 0 || elapsedSeconds_sysNow(startTime) >= pollFor)
ret serveJSON_breakAtLevels(2, result := map(objects, obj ->
litorderedmap(gid := str(obj.globalID()), struct := obj.structureString())
));
// sleep and try again
sleep(bot_pollInterval);
}
}
ret super.serveBotFunction(req, function, data, user);
}
transient ReliableSingleThread_Multi rstUpdateBEAMirrors = new(100, c -> c.updateMirrorPost());
O serveOtherPage2(Req req) null {
printVars_str serveOtherPage2(uri := req.uri);
try object super.serveOtherPage2(req);
S uri = dropTrailingSlashIfNemptyAfterwards(req.uri);
new Matches m;
if (swic_notSame(uri, "/beaCRUD/", m))
ret renderBEAObjectTable(req, urldecode(m.rest()));
if (eq(uri, "/inputs"))
ret renderBEAObjectTable(req, "input");
if (eq(uri, "/syntacticPatternsWithoutRewrites")) {
HCRUD crud = makeBEAObjectCRUD(req, "Syntactic Pattern");
HCRUD_Concepts data = cast crud.data;
IF1 prev = data.customFilter;
data.customFilter = list -> {
list = filter(list, c -> empty(beaBackRefs(c, "Rewrite")));
ret postProcess(prev, list);
};
crud.customTitle = "Syntactic patterns without rewrites";
ret serveCRUD(req, BEAObject, crud);
}
if (eq(uri, "/inputsWithoutRewrites")) {
HCRUD crud = makeBEAObjectCRUD(req, "input");
HCRUD_Concepts data = cast crud.data;
IF1 prev = data.customFilter;
data.customFilter = list -> {
list = filter(list, c -> empty(beaBackRefs(c, "Rewrite")));
ret postProcess(prev, list);
};
crud.customTitle = "Inputs without rewrites";
ret serveCRUD(req, BEAObject, crud);
}
if (eq(uri, "/inputsWithoutMatches")) {
HCRUD crud = makeBEAObjectCRUD(req, "input");
HCRUD_Concepts data = cast crud.data;
IF1 prev = data.customFilter;
data.customFilter = list -> {
list = filter(list, c -> empty(beaBackRefs(c, "Match")));
ret postProcess(prev, list);
};
crud.customTitle = "Inputs without matches";
ret serveCRUD(req, BEAObject, crud);
}
if (eq(uri, "/patterns"))
ret renderBEAObjectTable(req, "pattern");
if (eq(uri, "/syntacticPatterns"))
ret renderBEAObjectTable(req, "Syntactic Pattern");
if (eq(uri, "/matches"))
ret renderBEAObjectTable(req, "match");
if (eq(uri, "/rewrites"))
ret renderBEAObjectTable(req, "rewrite");
if (eq(uri, "/aiTasks"))
ret renderBEAObjectTable(req, "AI Task");
if (eq(uri, "/query"))
ret calculations.serveQueryPage(req);
if (eq(uri, "/saveInput")) {
S text = trim(req.get("text"));
S info = trim(req.get("info"));
if (empty(text)) ret subBot_serve500("Input empty");
if (l(text) > maxInputLength) ret subBot_serve500("Input too long");
BEAObject input = uniqCI BEAObject(type := "Input", +text, createdBy := user(req));
if (nempty(info))
uniqCI BEAObject(type := "Input Source", +input, source := info);
ret hrefresh(or2(req.get("redirect"), baseLink + "/"));
}
if (eq(uri, "/markUseful")) {
BEAObject o = beaGet(req.get("objectID"));
if (o == null) ret subBot_serve500("Object not found");
uniqCI BEAObject(type := "Useful", object := o, createdBy := user(req));
ret hrefresh(or2(req.get("redirect"), baseLink + "/"));
}
if (eq(uri, "/saveAnswer")) {
S text = trim(req.get("text"));
S rewriteType = or2(trim(req.get("rewriteType")), "Suggested Answer";
long inputID = toLong(req.get("inputID"));
BEAObject input = beaGet(inputID);
if (input == null) ret subBot_serve500("Input not found");
if (empty(text)) ret subBot_serve500("Text empty");
if (l(text) > maxInputLength) ret subBot_serve500("Text too long");
uniqCI BEAObject(type := "Rewrite", +text, isRewriteOf := input, +rewriteType, createdBy := user(req));
ret hrefresh(or2(req.get("redirect"), baseLink + "/"));
}
// add more public URLs here
if (!inMasterMode(req)) null;
if (eq(uri, "/uploadInputs"))
ret serveUploadTexts(req, "Input");
if (eq(uri, "/uploadPatterns"))
ret serveUploadTexts(req, "Pattern");
if (eq(uri, "/analyzeInput"))
ret calculations.serveAnalyzeInput(req);
if (eq(uri, "/allBEATypes")) {
MultiSet ms = asCIMultiSet(collect type(list(BEAObject)));
ret h2_title("All BEA object types")
//+ hpre(renderMultiSetAsLines_byPopularity(ms));
+ ul(mapPairs(multiSetToPairsByPopularity(ms),
(type, count) -> {
S _type = or2(type, "(no type)");
ret count + " " + ahref(baseLink + "/beaCRUD/" + urlencode(_type), htmlEncode2(_type));
}));
}
if (eq(uri, "/storeMatch")) {
BEAObject pattern = beaGet(req.get("pattern"));
BEAObject input = beaGet(req.get("input"));
S label = req.get("label");
BEAObject match = calculations.reactInputWithPattern(input, pattern);
if (match == null) ret "Couldn't match";
cset(match, +label);
ret hrefresh(or2(req.get("redirect"), beaObjectURL(match)));
}
if (eq(uri, "/saveSyntacticPattern")) {
S text = req.get("text");
BEAObject fromInput = beaGet(req.get("fromInput"));
BEAObject pat = uniqCI BEAObject(type := "Syntactic Pattern", +text, createdBy := user(req));
csetIfUnset(pat, +fromInput);
if (fromInput != null)
calculations.reactInputWithPattern(fromInput, pat);
ret hrefresh(or2(req.get("redirect"), baseLink + "/"));
}
if (eq(uri, "/runInstruction")) {
BEAObject o = beaGet(req.get("instruction"));
runInstruction(o);
ret hrefresh(beaObjectURL(o));
}
if (eq(uri, "/convertResultToInput")) {
BEAObject result = beaGet(req.get("result"));
if (result == null) ret subBot_serve500("Object not found");
S text = unquote(getString result(result));
if (l(text) > maxInputLength) ret subBot_serve500("Input too long");
BEAObject input = uniqCI BEAObject(type := "Input", +text);
uniqCI BEAObject(type := "Input Source", +input, source := result);
ret hrefresh(beaShortURL(input));
}
// add more master-mode URLs here
}
HCRUD makeBEAObjectCRUD(Req req, S type) {
HCRUD crud = makeCRUD(BEAObject, req);
crud.baseLink = req.uri();
HCRUD_Concepts data = cast crud.data;
data.itemName = () -> firstToUpper(type);
data.addCIFilter(type := eqic(type, "(no type)") ? null : type);
if (eqicOneOf(type, "Input", "Pattern", "AI Task")) {
IF0 prev = data.emptyObject;
data.emptyObject = () -> {
MapSO item = data.emptyObject_fallback(prev);
item.put(text := ""); // show text field when creating new objects
ret item;
};
}
ret crud;
}
O renderBEAObjectTable(Req req, S type) {
HCRUD crud = makeBEAObjectCRUD(req, type);
ret serveCRUD(req, BEAObject, crud);
}
O serveUploadTexts(Req req, S type) {
S inputs = req.get("text");
new LS output;
if (nempty(inputs)) {
for (S text : tlft(inputs)) {
Pair p = uniqCI2_sync BEAObject(+type, +text);
if (cget uploadedBy(p.a) == null)
cset(p.a, uploadedBy := req.auth.user);
output.add(type + " " + (p.b ? "added" : "exists")
+ " (ID " + p.a.id + "): " + text);
}
}
ret h2("Upload " + plural(type))
+ hpostform(
p(plural(type) + " (one per line):")
+ p(htextarea(inputs, name := "text"))
+ pIfNempty(htmlEncode_nlToBR(lines(output)))
+ hsubmit("Upload " + plural(type)));
}
Cl beaObjectsOfType(S type) {
ret conceptsWhereCI BEAObject(+type);
}
void reactAllInputsWithSomePatterns {
calculations.reactAllInputsWithSomePatterns();
}
S navDiv() {
HCRUD crud = makeCRUD(BEAObject, currentReq!);
int inputsWithoutRewrites = countPred(beaList("Input"), c -> empty(beaBackRefs(c, "Rewrite")));
int inputsWithoutMatches = countPred(beaList("Input"), c -> empty(beaBackRefs(c, "Match")));
int syntacticPatternsWithoutRewrites = countPred(beaList("Syntactic Pattern"), c -> empty(beaBackRefs(c, "Rewrite")));
ret joinNemptiesWithVBar(
beaNavLink("Input", crud),
beaNavLink("Pattern", crud),
beaNavLink("Syntactic Pattern", crud),
ahref(baseLink + "/syntacticPatternsWithoutRewrites", n2(syntacticPatternsWithoutRewrites) + " Syntactic patterns w/o rewrites"),
beaNavLink("Match", crud),
beaNavLink("Rewrite", crud),
beaNavLink("AI Task", crud),
ahref(baseLink + "/query", "Query"),
ahref(baseLink + "/inputsWithoutMatches", n2(inputsWithoutMatches) + " Inputs w/o matches"),
ahref(baseLink + "/inputsWithoutRewrites", n2(inputsWithoutRewrites) + " Inputs w/o rewrites"),
hPopDownButtonWithText("Bot Forum", navLinks(flat := true, withStats := false)),
hPopDownButton(
ahref(baseLink + "/allBEATypes", "All object types"),
ahref(baseLink + "/stats", "Stats"),
!inMasterMode(currentReq!) ? null : ahref(baseLink + "/refchecker", "Reference checker"),
));
}
// crud is just the cached BEAObject crud to check for creation rights
S beaNavLink(S type, HCRUD crud, int count default beaCount(type)) {
S plural = firstToLower(plural(type));
S link = baseLink + "/" + camelCase(plural);
ret ahref(link, count + " " + firstToUpper(plural)) + (!crud.actuallyAllowCreate() ? "" : " " + ahref(addParamToURL(link, cmd := "new"), "+"));
}
S beaObjectURL(BEAObject o) {
ret conceptLink(o, currentReq!);
/*ret o == null ?:
addParamsToURL(baseLink + "/crud/BEAObject",
selectObj := o.id) + "#" + o.id;*/
}
S matchDescHTML(BEAObject m) {
pcall {
BEAObject pat = cget pattern(m);
SS mapping = cast cget mapping(m);
ret ahref_undecorated(crudLink(m), htmlEncode2(quote(getString text(pat)))
+ "
with " + renderEqualsCommaProperties(mapping));
}
ret htmlEncode2(str(m));
}
int beaCount(S type) {
ret countConceptsWhereCI BEAObject(+type);
}
Cl beaList(S type) {
ret conceptsWhereCI BEAObject(+type);
}
Cl beaListAny(S... types) {
ret concatLists(lmap beaList(litciset(types)));
}
BEAObject beaGet(long id) {
ret getConceptOpt BEAObject(id);
}
BEAObject beaGet(S id) {
ret beaGet(parseFirstLong(id));
}
BEAObject mapMethodLike cgetBEA(S field, BEAObject o) {
ret (BEAObject) cget(field, o);
}
S beaLinkHTML(BEAObject o) {
ret o == null ?: ahref(conceptLink(o), htmlEncode2_nlToBr(str(o));
}
S beaToHTML(BEAObject o) { ret beaLinkHTML(o); }
S beaHTML(BEAObject o) { ret beaLinkHTML(o); }
S beaShortURL(BEAObject o) {
ret o == null ?: baseLink + "/" + o.id;
}
Cl beaBackRefs(BEAObject o, S type) {
ret objectsWhereCI(findBackRefs BEAObject(o), +type);
}
O serveDefaultPage(Req req) {
HTMLFramer1 framer = req.framer;
framer.add(hcenter3(hsnippetimg_scaleToWidth(200, #1102967, 200, 110, title := "Gazelle"), style := "margin-top: 100px"));
ret completeFrame(req);
}
S html_loggedIn() {
User user = user(currentReq!);
ret user == null
? /*"Not logged in"*/ ahref(baseLink + "/", "Log in")
: "Logged in as " + htmlEncode2(user.name);
}
void distributeNewObject_impl(BEAObject o) {
if (o.typeIs("Match")) ret;
distributeNotification("New object: " + o);
}
void performAutoRuns(BEAObject o) {
print("performAutoRuns", o);
for (BEAObject autoRun : beaList("Auto Run")) {
if (!isTrue(getOpt enabled(autoRun)))
continue with print("Not enabled: " + autoRun);
S type = getString onChangedObjectOfType(autoRun);
if (!o.typeIs(type)) continue with print("Wrong type: " + type;
print("Running " + autoRun);
BEAObject procedure = cast cget procedure(autoRun);
S internalCode = getString internalCode(procedure);
print(+internalCode);
if (eqic(internalCode, "convertInputToPattern")) {
S text = o.text();
if (!containsAngleBracketVars(text)) continue with print("No angle bracket vars");
BEAObject p = uniqCI_returnIfNew BEAObject(type := "Pattern", +text);
cset(p, fromInput := o, byProcedure := procedure, byAutoRun := autoRun);
print(+p);
} else if (eqic(internalCode, "makeSyntacticPattern")) {
print(sp := calculations.makeSyntacticPattern(o));
} else
print("Unknown internal code");
}
}
BEAObject findInput(S text) {
ret conceptWhereIC(BEAObject, type := "Input", +text);
}
S addRewriteHTML(BEAObject o) {
ret ahref(addParamsToURL(crudLink(BEAObject),
cmd := "new",
title := "Add Rewrite",
f_type := "Rewrite",
f_text := getStringOpt text(o),
f_isRewriteOf := o.id, metaInfo_isRewriteOf := "concept",
), "Add Rewrite");
}
O serveIntegerLink(Req req, long id) {
BEAObject o = getConceptOpt BEAObject(id);
if (o != null)
ret htitle(str(o)) + hrefresh(conceptLink(o));
ret super.serveIntegerLink(req, id);
}
void distributeTestNotification() {
distributeNotification("It is " + localTimeWithSeconds());
}
void distributeNotification(S text) {
notificationQ.add(r {
/*for (User user)
if (nemptyAfterTrim(user.notificationSetting))
sendNotification(text);*/
for (Pair p : syncMapToPairs(webSockets)) {
// TODO: check user
S jsCode =
"window.createNotification({ theme: 'success', showDuration: 3000 })("
+ jsonEncodeMap(message := text) + ");";
call(p.a, "send", jsonEncodeMap(eval := jsCode));
}
});
}
void runInstruction(BEAObject o) {
if (o == null) ret;
try {
BEAObject instruction = o;
if (o.typeIs("Step in script"))
instruction = (BEAObject) cget(o, "instruction");
if (instruction.typeIs("Instruction | List objects by type")) {
saveInstructionResult(o, beaList(getString typeToList(instruction)));
ret;
}
if (instruction.typeIs("Instruction | List object types"))
ret with saveInstructionResult(o, distinctCIFieldValuesOfConcepts(BEAObject, "type"));
if (instruction.typeIs("Instruction | Filter list by text starting with")) {
// find list made before
BEAObject scriptRun = cgetBEA scriptRun(o);
if (scriptRun == null) fail("Need to be run as part of script");
L steps = scriptRunSteps(scriptRun);
int idx = indexOf(steps, o);
if (idx < 0) fail("Step not found in script run");
L list = firstNotNull(map(reversed(takeFirst(steps, idx)),
step -> optCast L(cget data(cgetBEA result(step)))));
S prefix = getString prefix(instruction);
L filtered = filter(list, obj -> swic(obj.text(), prefix);
saveInstructionResult(o, filtered);
ret;
}
if (instruction.typeIs("Script")) {
BEAObject script = instruction;
BEAObject scriptRun = cnew BEAObject(type := "Script Run", +script);
// Make an instance of all the instructions
int i = 0;
new L steps;
while not null (instruction = (BEAObject) cget(instruction, "step" + (++i))) {
BEAObject step = cnew(BEAObject, type := "Step in script", step := i, +scriptRun, +instruction);
steps.add(step);
}
cset(scriptRun, +steps);
// TODO: run steps?
ret;
}
cnew BEAObject(type := "Instruction Error", instruction := o, error := "Unknown instruction type");
} catch e {
cnew BEAObject(type := "Instruction Error", instruction := o, error := getStackTrace(e));
}
}
BEAObject saveInstructionResult(BEAObject instruction, O data) {
BEAObject result = cnew BEAObject(type := "Instruction Result",
+instruction, +data);
cset(instruction, +result);
ret result;
}
L scriptRunSteps(BEAObject scriptRun) {
ret (L) cget steps(scriptRun);
}
} // end of module
extend User {
S notificationSetting;
}
concept BEAObject > ConceptWithGlobalID {
new Ref mirrorPost;
void change :: after {
((GazelleBEA) botMod()).rstUpdateBEAMirrors.add(this);
}
void delete :: before {
cdelete(mirrorPost!);
}
void updateMirrorPost {
GazelleBEA mod = cast botMod();
if (isDeleted() || !mod.mirrorBEAObjects) ret;
if (!mirrorPost.has())
cset(this, mirrorPost := cnew UserPost(
type := "BEA Object",
creator := mod.internalUser(),
botInfo := "BEA Mirror Bot"));
S text = structureString();
cset(mirrorPost!,
title := str(this),
+text);
}
S structureString() {
S text = "Error";
pcall {
structure_Data data = new {
structure_ClassInfo newClass(Class c) {
structure_ClassInfo info = super.newClass(c);
if (c == Concept.Ref.class) {
info.special = true;
info.serializeObject = o -> {
Concept cc = cast deref((Concept.Ref) o);
//append("cu CRef " + (cc != null ? str(cc.id) : "null"), 3);
if (cc cast BEAObject)
append("CRef(gid=" + quote(cc.globalID()) + ")", 6);
else if (cc != null)
append("CRef(id=" + cc.id + ")", 6);
else
append("CRef", 1);
};
}
ret info;
}
void setFields(structure_ClassInfo info, L fields) {
if (isSubclassOf(info.c, BEAObject)) {
// Don't serialize "refs" and "backRefs" fields
removeAll(fields,
getField(BEAObject, "refs"),
getField(BEAObject, "backRefs"));
}
super.setFields(info, fields);
}
};
S struct = structure(this, data);
struct = dropLoadableUtilsPackageFromStruct(struct);
text = indentStructureString_firstLevels(1, struct);
}
ret text;
}
toString {
S type = strOrNull(cget type(this));
S s = super.toString();
if (nempty(type)) {
s = type + " " + id;
if (eqic(type, "Match"))
s += appendBracketed(strOrNull(this~.label))
+ " " + this.~mapping
+ appendBracketed(this.~input + " + " + this~.pattern);
}
bool enabled = eq(true, getOpt enabled(this));
if (enabled) s += " [enabled]";
S text = or2(text(), getStringOpt name(this));
if (text != null)
s += " " + quote(text);
O fc = this~.functionCalled;
if (fc != null) s += " " + fc;
ret s;
}
S type() { ret getStringOpt type(this); }
bool typeIs(S type) { ret eqic(type(), type); }
bool typeIsOneOf(S... types) { ret eqicOneOf(type(), types); }
S text() { ret getStringOpt text(this); }
} // end of BEAObject