Uses 1059K of libraries. Click here for Pure Java version (41281L/266K).
1 | !7 |
2 | |
3 | !include once #1030833 // BEACalculations |
4 | |
5 | set flag NoNanoHTTPD. |
6 | |
7 | cmodule2 GazelleBEA > DynGazelleRocks { |
8 | switchable bool mirrorBEAObjects; // don't do it for now |
9 | switchable bool enableAutoRuns = true; |
10 | switchable bool enableNewBEAObjectNotis = true; |
11 | |
12 | transient ReliableSingleThread_Multi<BEAObject> rstAutoRuns = new(1000, lambda1 performAutoRuns); |
13 | transient Q notificationQ; |
14 | transient ReliableSingleThread_Multi<BEAObject> rstDistributeNewObject = new(1000, lambda1 distributeNewObject_impl); |
15 | transient Set<BEAObject> newObjectsDistributed = weakSet(); |
16 | |
17 | transient BEACalculations calculations = new(this); |
18 | transient int newFieldsToShow = 3; |
19 | transient bool allowAnonymousInputUpload = true; // TODO |
20 | switchable int maxInputLength = 50000; |
21 | |
22 | // add more fields here |
23 | |
24 | //!include #1030883 // DB quickImport mix-in |
25 | |
26 | void init { |
27 | super.init(); |
28 | botName = heading = adminName = "Gazelle BEA"; |
29 | set enableVars; |
30 | set showTalkToBotLink; |
31 | unset phoneNumberSpecialInputField; |
32 | } |
33 | |
34 | start { |
35 | set showCRUDToEveryone; |
36 | set showOnlySelectedObject; |
37 | |
38 | if (!enabled) ret; |
39 | |
40 | // mirror all objects to be sure |
41 | rstUpdateBEAMirrors.addAll(list(BEAObject)); |
42 | |
43 | newObjectsDistributed.addAll(list(BEAObject)); |
44 | |
45 | /*onIndividualConceptChange_notOnAllChanged(BEAObject, |
46 | p -> { calculations.makeSyntacticPattern(p); });*/ |
47 | |
48 | onIndividualConceptChange_notOnAllChanged(BEAObject, |
49 | o -> { |
50 | if (enableAutoRuns) rstAutoRuns.add(o); |
51 | if (enableNewBEAObjectNotis && newObjectsDistributed.add(o)) |
52 | rstDistributeNewObject.add(o); |
53 | }); |
54 | |
55 | notificationQ = dm_startQ(); |
56 | |
57 | // Until the ref leak bug is fixed, fix things every 30... |
58 | |
59 | dm_doEvery(30.0, r { |
60 | print(ConceptsRefChecker(db_mainConcepts()).runAndFixAll()); |
61 | }); |
62 | } |
63 | |
64 | void makeIndices :: after { |
65 | indexConceptFieldDesc(BEAObject, "_modified"); |
66 | indexConceptFieldIC(BEAObject, "type"); |
67 | |
68 | // TODO: don't index nulls, also maybe just use backRefs |
69 | indexConceptField(BEAObject, "input"); // e.g. for counting how many matches we have for a given input |
70 | } |
71 | |
72 | L<Class> crudClasses(Req req) { |
73 | ret listPlus(super.crudClasses(req), BEAObject); |
74 | } |
75 | |
76 | S authFormHeading() { |
77 | ret h3("Gazelle BEA"); |
78 | } |
79 | |
80 | void makeFramer(Req req) { |
81 | super.makeFramer(req); |
82 | |
83 | req.framer.renderTitle = () -> h1(ahref(baseLink + "/", "Gazelle BEA") |
84 | + " " + htmlEncode2(req.framer.title)); |
85 | |
86 | req.framer.addInHead(hjs_autoExpandingTextAreas()); |
87 | } |
88 | |
89 | <A extends Concept> HCRUD_Concepts<A> crudData(Class<A> c, Req req) { |
90 | HCRUD_Concepts<A> cc = super.crudData(c, req); |
91 | |
92 | if (c == BEAObject) { |
93 | cc.humanizeFieldNames = false; |
94 | cc.convertConceptValuesToRefs = true; |
95 | cc.itemName = () -> "BEA Object"; |
96 | |
97 | cc.onCreate.add(o -> |
98 | cset(o, createdBy := currentUser())); |
99 | |
100 | cc.getObjectForDuplication = id -> { |
101 | MapSO item = cc.getObjectForDuplication_base(id); |
102 | item.put(creator := req.auth.user!); // set default creator to current user |
103 | item.put(createdFrom := getConcept(toLong(id))); |
104 | ret item; |
105 | }; |
106 | |
107 | cc.emptyObject = () -> { |
108 | MapSO item = cc.emptyObject_base(); |
109 | item.put(type := ""); |
110 | ret item; |
111 | }; |
112 | |
113 | Set<S> deletableRefs = litciset("Match"); |
114 | |
115 | cc.objectCanBeDeleted = id -> |
116 | all(findBackRefs(BEAObject, cc.conceptForID(id)), |
117 | o -> contains(deletableRefs, o.type())); |
118 | |
119 | cc.actuallyDeleteConcept = o -> { |
120 | deleteConcepts(filter(findBackRefs(BEAObject, o), |
121 | o2 -> contains(deletableRefs, o2.type()))); |
122 | cdelete(o); |
123 | }; |
124 | } |
125 | |
126 | ret cc; |
127 | } |
128 | |
129 | <A extends Concept> HCRUD makeCRUD(Class<A> c, Req req, HTMLFramer1 framer) { |
130 | HCRUD crud = super.makeCRUD(c, req, framer); |
131 | HCRUD_Concepts data = cast crud.data; |
132 | crud.showSearchField = true; |
133 | if (data.customFilter == null) |
134 | crud.descending = true; // show latest objects first by default except when searching |
135 | crud.cleanItemIDs = true; |
136 | |
137 | if (c == BEAObject) { |
138 | crud.cellColumnToolTips = true; |
139 | crud.unshownFields = litset("mirrorPost", "globalID"); |
140 | crud.showTextFieldsAsAutoExpandingTextAreas = true; |
141 | HCRUD_Concepts cc = cast crud.data; |
142 | |
143 | S typeFilter = req.get("type"); |
144 | if (nempty(typeFilter)) |
145 | cc.addCIFilter(type := typeFilter); |
146 | |
147 | crud.renderCmds = map -> { |
148 | BEAObject o = getConcept BEAObject(crud.itemIDAsLong(map)); |
149 | |
150 | new LS cmds; |
151 | |
152 | // special commands for BEA types |
153 | |
154 | if (o.typeIs("Input")) { |
155 | cmds.add(ahref(addParamsToURL(crudLink(BEAObject), |
156 | cmd := "new", |
157 | title := "Add Pattern For Input", |
158 | f_type := "Pattern", |
159 | f_text := getStringOpt text(o), |
160 | f_shouldMatch := o.id, metaInfo_shouldMatch := "concept", |
161 | ), "Add pattern")); |
162 | |
163 | cmds.add(ahref(appendParamsToURL(baseLink + "/query", q := o.text(), algorithm := "Apply all text functions"), |
164 | "Apply all text functions")); |
165 | } |
166 | |
167 | if (o.typeIs("Pattern")) |
168 | cmds.add(ahref(appendParamsToURL(baseLink + "/query", q := o.id, algorithm := "Run pattern"), |
169 | "Run pattern against all inputs")); |
170 | |
171 | if (o.typeIs("Match")) |
172 | cmds.add(ahref(appendParamsToURL(baseLink + "/query", q := o.id, algorithm := "Find rewrites for match"), |
173 | "Find rewrites")); |
174 | |
175 | cmds.add( |
176 | ahref(addParamsToURL(baseLink + "/markUseful", |
177 | redirect := beaShortURL(o), |
178 | objectID := o.id), |
179 | "Mark useful")); |
180 | |
181 | cmds.add(ahref(addParamsToURL(crudLink(BEAObject), |
182 | cmd := "new", |
183 | title := "Add Comment", |
184 | f_type := "Comment", |
185 | f_on := o.id, |
186 | f_text := "", |
187 | metaInfo_on := "concept"), "Add comment")); |
188 | |
189 | if (o.typeIsOneOf("Script", "Step in script") || eqic(beforeVerticalBar(o.type()), "Instruction")) |
190 | cmds.add( |
191 | ahref(addParamsToURL(baseLink + "/runInstruction", |
192 | instruction := o.id), |
193 | "Run")); |
194 | |
195 | if (o.typeIs("Function Result") && eqic(cget resultType(o), "string")) |
196 | cmds.add( |
197 | ahref(addParamsToURL(baseLink + "/convertResultToInput", |
198 | result := o.id), |
199 | "Convert to input")); |
200 | |
201 | framer.addInHead(hjs_copyToClipboard()); |
202 | |
203 | cmds.add(ahref_onClick(formatFunctionCall copyToClipboard(jsQuote(o.globalIDStr())), "Copy global ID [" + o.globalIDStr() + "]")); |
204 | |
205 | ret joinNemptiesWithVBar( |
206 | crud.renderCmds_base(map), |
207 | !o.typeIsOneOf("Input", "Pattern", "Syntactic Pattern") |
208 | ? null : addRewriteHTML(o), |
209 | hPopDownButton(cmds)); |
210 | }; |
211 | |
212 | cc.massageItemMapForList = (item, map) -> { |
213 | BEAObject o = cast item; |
214 | if (o.typeIs("Input")) { |
215 | Cl<BEAObject> matches = objectsWhereCI(findBackRefs(o, BEAObject), type := "match"); |
216 | map/Map.put("Best Matches", HTML(hparagraphs( |
217 | lmap matchDescHTML(takeFirst(3, matches))))); |
218 | } |
219 | S idField = crud.idField(); |
220 | O id = map/Map.get(idField); |
221 | if (id instanceof S) |
222 | map/Map.put(idField, HTML(ahref(beaShortURL(o), id))); |
223 | if (o.typeIs("Function Result")) { |
224 | O value = o~.result; |
225 | map/Map.put("result", HTML(javaValueToHTML(value))); |
226 | } |
227 | }; |
228 | |
229 | crud.massageFormMatrix = (map, matrix) -> { |
230 | for (int i = 1; i <= newFieldsToShow; i++) { |
231 | S nf = "newField" + i; |
232 | |
233 | S refSelector = |
234 | crud.renderInput("\*nf*/_conceptValue", |
235 | cc.makeConceptsComboBox("\*nf*/_conceptValue", BEAObject), null) |
236 | + hjs([[$("[name=]] + nf + [[_conceptValue]").hide()]]); |
237 | |
238 | LS types = ll("String", "BEAObject", "Bool"); |
239 | |
240 | S typeSelector = hselect_list(types, name := "\*nf*/_type", |
241 | onchange := [[ |
242 | var value = this.value; |
243 | $("[name=]] + nf + [[_value]").toggle(value != "BEAObject"); |
244 | $("#]] + nf + [[_refBox").toggle(value == "BEAObject"); |
245 | ]]); |
246 | |
247 | matrix.add(ll("Add field", htmlTable2_noHtmlEncode(ll( |
248 | ll("Name", htextfield("\*nf*/_name"), |
249 | "Value", |
250 | // string input |
251 | htextfield("\*nf*/_value"), |
252 | |
253 | span(refSelector, id := "\*nf*/_refBox", style := "display: none"), |
254 | "Type", typeSelector |
255 | )), |
256 | noHeader := true))); |
257 | } |
258 | }; |
259 | |
260 | crud.preprocessUpdateParams = params -> { |
261 | params = cloneMap(params); |
262 | |
263 | // drop empty strings |
264 | //removeFromMapWhereValue(params, v -> eq(v, "")); |
265 | params = mapValues(params, v -> eq(v, "") ? null : v); |
266 | |
267 | for (int i = 1; i <= max(newFieldsToShow, 10); i++) { |
268 | S nf = "newField" + i; |
269 | S name = params.get("\*nf*/_name"), |
270 | type = params.get("\*nf*/_type"), |
271 | refValue = params.get("\*nf*/_conceptValue"), |
272 | value = params.get("\*nf*/_value"); |
273 | |
274 | if (eqic(type, "BEAObject")) { |
275 | value = refValue; |
276 | params.put("metaInfo_" + name, "concept"); |
277 | } else if (eqic(type, "Bool")) |
278 | params.put("metaInfo_" + name, "bool"); |
279 | |
280 | if (eq(value, "")) value = null; |
281 | |
282 | if (nempty(name) /*&& neqOneOf(value, null, "")*/) |
283 | params.put(crud.fieldPrefix + name, value); |
284 | } |
285 | |
286 | ret params; |
287 | }; |
288 | } |
289 | |
290 | ret crud; |
291 | } |
292 | |
293 | O serveBotFunction(Req req, S function, Map data, User user) { |
294 | if (eq(function, "beaList")) { |
295 | long changedAfter = toLong(data.get("changedAfter")); |
296 | double pollFor = min(bot_maxPollSeconds, toLong(data.get("pollFor"))); // how long to poll (seconds) |
297 | long startTime = sysNow(); |
298 | |
299 | // We're super-anal about catching all changes. This will probably never trigger |
300 | if (changedAfter > 0 && changedAfter == now()) sleep(1); |
301 | |
302 | Cl<BEAObject> objects; |
303 | while true { |
304 | objects = changedAfter == 0 ? list(BEAObject) |
305 | : conceptsWithFieldGreaterThan_sorted(BEAObject, _modified := changedAfter); |
306 | |
307 | // return when there are results, no polling or poll expired |
308 | if (nempty(objects) || pollFor == 0 || elapsedSeconds_sysNow(startTime) >= pollFor) |
309 | ret serveJSON_breakAtLevels(2, result := map(objects, obj -> |
310 | litorderedmap(gid := str(obj.globalID()), struct := obj.structureString()) |
311 | )); |
312 | |
313 | // sleep and try again |
314 | sleep(bot_pollInterval); |
315 | } |
316 | } |
317 | |
318 | ret super.serveBotFunction(req, function, data, user); |
319 | } |
320 | |
321 | transient ReliableSingleThread_Multi<BEAObject> rstUpdateBEAMirrors = new(100, c -> c.updateMirrorPost()); |
322 | |
323 | O serveOtherPage2(Req req) null { |
324 | printVars_str serveOtherPage2(uri := req.uri); |
325 | try object super.serveOtherPage2(req); |
326 | |
327 | S uri = dropTrailingSlashIfNemptyAfterwards(req.uri); |
328 | new Matches m; |
329 | |
330 | if (swic_notSame(uri, "/beaCRUD/", m)) |
331 | ret renderBEAObjectTable(req, urldecode(m.rest())); |
332 | |
333 | if (eq(uri, "/inputs")) |
334 | ret renderBEAObjectTable(req, "input"); |
335 | |
336 | if (eq(uri, "/inputsWithoutRewrites")) { |
337 | HCRUD crud = makeBEAObjectCRUD(req, "input"); |
338 | HCRUD_Concepts<BEAObject> data = cast crud.data; |
339 | |
340 | /*IF1 prev = crud.renderCmds; |
341 | crud.renderCmds = o -> { |
342 | S cmds = crud.renderCmds_fallback(prev, o); |
343 | ret joinNemptiesWithVBar(addRewriteHTML(data.getConcept(o)), cmds); |
344 | };*/ |
345 | |
346 | IF1 prev = data.customFilter; |
347 | data.customFilter = list -> { |
348 | list = filter(list, c -> empty(beaBackRefs(c, "Rewrite"))); |
349 | ret postProcess(prev, list); |
350 | }; |
351 | crud.customTitle = "Inputs without rewrites"; |
352 | ret serveCRUD(req, BEAObject, crud); |
353 | } |
354 | |
355 | if (eq(uri, "/patterns")) |
356 | ret renderBEAObjectTable(req, "pattern"); |
357 | |
358 | if (eq(uri, "/syntacticPatterns")) |
359 | ret renderBEAObjectTable(req, "Syntactic Pattern"); |
360 | |
361 | if (eq(uri, "/matches")) |
362 | ret renderBEAObjectTable(req, "match"); |
363 | |
364 | if (eq(uri, "/rewrites")) |
365 | ret renderBEAObjectTable(req, "rewrite"); |
366 | |
367 | if (eq(uri, "/aiTasks")) |
368 | ret renderBEAObjectTable(req, "AI Task"); |
369 | |
370 | if (eq(uri, "/query")) |
371 | ret calculations.serveQueryPage(req); |
372 | |
373 | if (eq(uri, "/saveInput")) { |
374 | S text = trim(req.get("text")); |
375 | S info = trim(req.get("info")); |
376 | if (empty(text)) ret subBot_serve500("Input empty"); |
377 | if (l(text) > maxInputLength) ret subBot_serve500("Input too long"); |
378 | BEAObject input = uniqCI BEAObject(type := "Input", +text, createdBy := user(req)); |
379 | if (nempty(info)) |
380 | uniqCI BEAObject(type := "Input Source", +input, source := info); |
381 | ret hrefresh(or2(req.get("redirect"), baseLink + "/")); |
382 | } |
383 | |
384 | if (eq(uri, "/markUseful")) { |
385 | BEAObject o = beaGet(req.get("objectID")); |
386 | if (o == null) ret subBot_serve500("Object not found"); |
387 | uniqCI BEAObject(type := "Useful", object := o, createdBy := user(req)); |
388 | ret hrefresh(or2(req.get("redirect"), baseLink + "/")); |
389 | } |
390 | |
391 | if (eq(uri, "/saveAnswer")) { |
392 | S text = trim(req.get("text")); |
393 | S rewriteType = or2(trim(req.get("rewriteType")), "Suggested Answer"; |
394 | long inputID = toLong(req.get("inputID")); |
395 | BEAObject input = beaGet(inputID); |
396 | if (input == null) ret subBot_serve500("Input not found"); |
397 | if (empty(text)) ret subBot_serve500("Text empty"); |
398 | if (l(text) > maxInputLength) ret subBot_serve500("Text too long"); |
399 | uniqCI BEAObject(type := "Rewrite", +text, isRewriteOf := input, +rewriteType, createdBy := user(req)); |
400 | ret hrefresh(or2(req.get("redirect"), baseLink + "/")); |
401 | } |
402 | |
403 | // add more public URLs here |
404 | |
405 | if (!inMasterMode(req)) null; |
406 | |
407 | if (eq(uri, "/uploadInputs")) |
408 | ret serveUploadTexts(req, "Input"); |
409 | |
410 | if (eq(uri, "/uploadPatterns")) |
411 | ret serveUploadTexts(req, "Pattern"); |
412 | |
413 | if (eq(uri, "/analyzeInput")) |
414 | ret calculations.serveAnalyzeInput(req); |
415 | |
416 | if (eq(uri, "/allBEATypes")) { |
417 | MultiSet<S> ms = asCIMultiSet(collect type(list(BEAObject))); |
418 | ret h2_title("All BEA object types") |
419 | //+ hpre(renderMultiSetAsLines_byPopularity(ms)); |
420 | + ul(mapPairs(multiSetToPairsByPopularity(ms), |
421 | (type, count) -> { |
422 | S _type = or2(type, "(no type)"); |
423 | ret count + " " + ahref(baseLink + "/beaCRUD/" + urlencode(_type), htmlEncode2(_type)); |
424 | })); |
425 | } |
426 | |
427 | if (eq(uri, "/storeMatch")) { |
428 | BEAObject pattern = beaGet(req.get("pattern")); |
429 | BEAObject input = beaGet(req.get("input")); |
430 | S label = req.get("label"); |
431 | BEAObject match = calculations.reactInputWithPattern(input, pattern); |
432 | if (match == null) ret "Couldn't match"; |
433 | cset(match, +label); |
434 | ret hrefresh(beaObjectURL(match)); |
435 | } |
436 | |
437 | if (eq(uri, "/saveSyntacticPattern")) { |
438 | S text = req.get("text"); |
439 | uniqCI BEAObject(type := "Syntactic Pattern", +text, createdBy := user(req)); |
440 | ret hrefresh(or2(req.get("redirect"), baseLink + "/")); |
441 | } |
442 | |
443 | if (eq(uri, "/runInstruction")) { |
444 | BEAObject o = beaGet(req.get("instruction")); |
445 | runInstruction(o); |
446 | ret hrefresh(beaObjectURL(o)); |
447 | } |
448 | |
449 | if (eq(uri, "/convertResultToInput")) { |
450 | BEAObject result = beaGet(req.get("result")); |
451 | if (result == null) ret subBot_serve500("Object not found"); |
452 | S text = unquote(getString result(result)); |
453 | if (l(text) > maxInputLength) ret subBot_serve500("Input too long"); |
454 | BEAObject input = uniqCI BEAObject(type := "Input", +text); |
455 | uniqCI BEAObject(type := "Input Source", +input, source := result); |
456 | ret hrefresh(beaShortURL(input)); |
457 | } |
458 | |
459 | // add more master-mode URLs here |
460 | } |
461 | |
462 | HCRUD makeBEAObjectCRUD(Req req, S type) { |
463 | HCRUD crud = makeCRUD(BEAObject, req); |
464 | crud.baseLink = req.uri(); |
465 | HCRUD_Concepts data = cast crud.data; |
466 | data.itemName = () -> firstToUpper(type); |
467 | data.addCIFilter(type := eqic(type, "(no type)") ? null : type); |
468 | |
469 | if (eqicOneOf(type, "Input", "Pattern", "AI Task")) { |
470 | IF0<MapSO> prev = data.emptyObject; |
471 | data.emptyObject = () -> { |
472 | MapSO item = data.emptyObject_fallback(prev); |
473 | item.put(text := ""); // show text field when creating new objects |
474 | ret item; |
475 | }; |
476 | } |
477 | ret crud; |
478 | } |
479 | |
480 | O renderBEAObjectTable(Req req, S type) { |
481 | HCRUD crud = makeBEAObjectCRUD(req, type); |
482 | ret serveCRUD(req, BEAObject, crud); |
483 | } |
484 | |
485 | O serveUploadTexts(Req req, S type) { |
486 | S inputs = req.get("text"); |
487 | |
488 | new LS output; |
489 | |
490 | if (nempty(inputs)) { |
491 | for (S text : tlft(inputs)) { |
492 | Pair<BEAObject, Bool> p = uniqCI2_sync BEAObject(+type, +text); |
493 | if (cget uploadedBy(p.a) == null) |
494 | cset(p.a, uploadedBy := req.auth.user); |
495 | output.add(type + " " + (p.b ? "added" : "exists") |
496 | + " (ID " + p.a.id + "): " + text); |
497 | } |
498 | } |
499 | |
500 | ret h2("Upload " + plural(type)) |
501 | + hpostform( |
502 | p(plural(type) + " (one per line):") |
503 | + p(htextarea(inputs, name := "text")) |
504 | + pIfNempty(htmlEncode_nlToBR(lines(output))) |
505 | + hsubmit("Upload " + plural(type))); |
506 | } |
507 | |
508 | Cl<BEAObject> beaObjectsOfType(S type) { |
509 | ret conceptsWhereCI BEAObject(+type); |
510 | } |
511 | |
512 | void reactAllInputsWithSomePatterns { |
513 | calculations.reactAllInputsWithSomePatterns(); |
514 | } |
515 | |
516 | S navDiv() { |
517 | HCRUD crud = makeCRUD(BEAObject, currentReq!); |
518 | |
519 | int inputsWithoutRewrites = countPred(beaList("Input"), c -> empty(beaBackRefs(c, "Rewrite"))); |
520 | |
521 | ret joinNemptiesWithVBar( |
522 | beaNavLink("Input", crud), |
523 | beaNavLink("Pattern", crud), |
524 | beaNavLink("Syntactic Pattern", crud), |
525 | beaNavLink("Match", crud), |
526 | beaNavLink("Rewrite", crud), |
527 | beaNavLink("AI Task", crud), |
528 | ahref(baseLink + "/query", "Query"), |
529 | ahref(baseLink + "/inputsWithoutRewrites", n2(inputsWithoutRewrites) + " Inputs without rewrites"), |
530 | hPopDownButtonWithText("Bot Forum", navLinks(flat := true, withStats := false)), |
531 | hPopDownButton( |
532 | ahref(baseLink + "/allBEATypes", "All object types"), |
533 | ahref(baseLink + "/stats", "Stats"), |
534 | !inMasterMode(currentReq!) ? null : ahref(baseLink + "/refchecker", "Reference checker"), |
535 | )); |
536 | } |
537 | |
538 | // crud is just the cached BEAObject crud to check for creation rights |
539 | S beaNavLink(S type, HCRUD crud, int count default beaCount(type)) { |
540 | S plural = firstToLower(plural(type)); |
541 | S link = baseLink + "/" + camelCase(plural); |
542 | |
543 | ret ahref(link, count + " " + firstToUpper(plural)) + (!crud.actuallyAllowCreate() ? "" : " " + ahref(addParamToURL(link, cmd := "new"), "+")); |
544 | } |
545 | |
546 | S beaObjectURL(BEAObject o) { |
547 | ret conceptLink(o, currentReq!); |
548 | /*ret o == null ?: |
549 | addParamsToURL(baseLink + "/crud/BEAObject", |
550 | selectObj := o.id) + "#" + o.id;*/ |
551 | } |
552 | |
553 | S matchDescHTML(BEAObject m) { |
554 | pcall { |
555 | BEAObject pat = cget pattern(m); |
556 | SS mapping = cast cget mapping(m); |
557 | ret ahref_undecorated(crudLink(m), htmlEncode2(quote(getString text(pat))) |
558 | + "<br> with " + renderEqualsCommaProperties(mapping)); |
559 | } |
560 | ret htmlEncode2(str(m)); |
561 | } |
562 | |
563 | int beaCount(S type) { |
564 | ret countConceptsWhereCI BEAObject(+type); |
565 | } |
566 | |
567 | Cl<BEAObject> beaList(S type) { |
568 | ret conceptsWhereCI BEAObject(+type); |
569 | } |
570 | |
571 | Cl<BEAObject> beaListAny(S... types) { |
572 | ret concatLists(lmap beaList(litciset(types))); |
573 | } |
574 | |
575 | BEAObject beaGet(long id) { |
576 | ret getConceptOpt BEAObject(id); |
577 | } |
578 | |
579 | BEAObject beaGet(S id) { |
580 | ret beaGet(parseFirstLong(id)); |
581 | } |
582 | |
583 | BEAObject mapMethodLike cgetBEA(S field, BEAObject o) { |
584 | ret (BEAObject) cget(field, o); |
585 | } |
586 | |
587 | S beaLinkHTML(BEAObject o) { |
588 | ret o == null ?: ahref(conceptLink(o), htmlEncode2_nlToBr(str(o)); |
589 | } |
590 | |
591 | S beaToHTML(BEAObject o) { ret beaLinkHTML(o); } |
592 | S beaHTML(BEAObject o) { ret beaLinkHTML(o); } |
593 | |
594 | S beaShortURL(BEAObject o) { |
595 | ret o == null ?: baseLink + "/" + o.id; |
596 | } |
597 | |
598 | Cl<BEAObject> beaBackRefs(BEAObject o, S type) { |
599 | ret objectsWhereCI(findBackRefs BEAObject(o), +type); |
600 | } |
601 | |
602 | O serveDefaultPage(Req req) { |
603 | HTMLFramer1 framer = req.framer; |
604 | framer.add(hcenter3(hsnippetimg_scaleToWidth(200, #1102967, 200, 110, title := "Gazelle"), style := "margin-top: 100px")); |
605 | ret completeFrame(req); |
606 | } |
607 | |
608 | S html_loggedIn() { |
609 | User user = user(currentReq!); |
610 | ret user == null |
611 | ? /*"Not logged in"*/ ahref(baseLink + "/", "Log in") |
612 | : "Logged in as " + htmlEncode2(user.name); |
613 | } |
614 | |
615 | void distributeNewObject_impl(BEAObject o) { |
616 | if (o.typeIs("Match")) ret; |
617 | distributeNotification("New object: " + o); |
618 | } |
619 | |
620 | void performAutoRuns(BEAObject o) { |
621 | print("performAutoRuns", o); |
622 | |
623 | for (BEAObject autoRun : beaList("Auto Run")) { |
624 | if (!isTrue(getOpt enabled(autoRun))) |
625 | continue with print("Not enabled: " + autoRun); |
626 | |
627 | S type = getString onChangedObjectOfType(autoRun); |
628 | if (!o.typeIs(type)) continue with print("Wrong type: " + type; |
629 | |
630 | print("Running " + autoRun); |
631 | BEAObject procedure = cast cget procedure(autoRun); |
632 | |
633 | S internalCode = getString internalCode(procedure); |
634 | print(+internalCode); |
635 | |
636 | if (eqic(internalCode, "convertInputToPattern")) { |
637 | S text = o.text(); |
638 | if (!containsAngleBracketVars(text)) continue with print("No angle bracket vars"); |
639 | BEAObject p = uniqCI_returnIfNew BEAObject(type := "Pattern", +text); |
640 | cset(p, fromInput := o, byProcedure := procedure, byAutoRun := autoRun); |
641 | print(+p); |
642 | } else if (eqic(internalCode, "makeSyntacticPattern")) { |
643 | print(sp := calculations.makeSyntacticPattern(o)); |
644 | } else |
645 | print("Unknown internal code"); |
646 | } |
647 | } |
648 | |
649 | BEAObject findInput(S text) { |
650 | ret conceptWhereIC(BEAObject, type := "Input", +text); |
651 | } |
652 | |
653 | S addRewriteHTML(BEAObject o) { |
654 | ret ahref(addParamsToURL(crudLink(BEAObject), |
655 | cmd := "new", |
656 | title := "Add Rewrite", |
657 | f_type := "Rewrite", |
658 | f_text := getStringOpt text(o), |
659 | f_isRewriteOf := o.id, metaInfo_isRewriteOf := "concept", |
660 | ), "Add Rewrite"); |
661 | } |
662 | |
663 | O serveIntegerLink(Req req, long id) { |
664 | BEAObject o = getConceptOpt BEAObject(id); |
665 | if (o != null) |
666 | ret htitle(str(o)) + hrefresh(conceptLink(o)); |
667 | ret super.serveIntegerLink(req, id); |
668 | } |
669 | |
670 | void distributeTestNotification() { |
671 | distributeNotification("It is " + localTimeWithSeconds()); |
672 | } |
673 | |
674 | void distributeNotification(S text) { |
675 | notificationQ.add(r { |
676 | /*for (User user) |
677 | if (nemptyAfterTrim(user.notificationSetting)) |
678 | sendNotification(text);*/ |
679 | |
680 | for (Pair<virtual WebSocket, WebSocketInfo> p : syncMapToPairs(webSockets)) { |
681 | // TODO: check user |
682 | S jsCode = |
683 | "window.createNotification({ theme: 'success', showDuration: 3000 })(" |
684 | + jsonEncodeMap(message := text) + ");"; |
685 | call(p.a, "send", jsonEncodeMap(eval := jsCode)); |
686 | } |
687 | }); |
688 | } |
689 | |
690 | void runInstruction(BEAObject o) { |
691 | if (o == null) ret; |
692 | try { |
693 | BEAObject instruction = o; |
694 | if (o.typeIs("Step in script")) |
695 | instruction = (BEAObject) cget(o, "instruction"); |
696 | |
697 | if (instruction.typeIs("Instruction | List objects by type")) { |
698 | saveInstructionResult(o, beaList(getString typeToList(instruction))); |
699 | ret; |
700 | } |
701 | |
702 | if (instruction.typeIs("Instruction | List object types")) |
703 | ret with saveInstructionResult(o, distinctCIFieldValuesOfConcepts(BEAObject, "type")); |
704 | |
705 | if (instruction.typeIs("Instruction | Filter list by text starting with")) { |
706 | // find list made before |
707 | BEAObject scriptRun = cgetBEA scriptRun(o); |
708 | if (scriptRun == null) fail("Need to be run as part of script"); |
709 | L<BEAObject> steps = scriptRunSteps(scriptRun); |
710 | int idx = indexOf(steps, o); |
711 | if (idx < 0) fail("Step not found in script run"); |
712 | |
713 | L<BEAObject> list = firstNotNull(map(reversed(takeFirst(steps, idx)), |
714 | step -> optCast L(cget data(cgetBEA result(step))))); |
715 | |
716 | S prefix = getString prefix(instruction); |
717 | L<BEAObject> filtered = filter(list, obj -> swic(obj.text(), prefix); |
718 | saveInstructionResult(o, filtered); |
719 | ret; |
720 | } |
721 | |
722 | if (instruction.typeIs("Script")) { |
723 | BEAObject script = instruction; |
724 | BEAObject scriptRun = cnew BEAObject(type := "Script Run", +script); |
725 | |
726 | // Make an instance of all the instructions |
727 | |
728 | int i = 0; |
729 | new L<BEAObject> steps; |
730 | while not null (instruction = (BEAObject) cget(instruction, "step" + (++i))) { |
731 | BEAObject step = cnew(BEAObject, type := "Step in script", step := i, +scriptRun, +instruction); |
732 | steps.add(step); |
733 | } |
734 | |
735 | cset(scriptRun, +steps); |
736 | |
737 | // TODO: run steps? |
738 | |
739 | ret; |
740 | } |
741 | |
742 | cnew BEAObject(type := "Instruction Error", instruction := o, error := "Unknown instruction type"); |
743 | } catch e { |
744 | cnew BEAObject(type := "Instruction Error", instruction := o, error := getStackTrace(e)); |
745 | } |
746 | } |
747 | |
748 | BEAObject saveInstructionResult(BEAObject instruction, O data) { |
749 | BEAObject result = cnew BEAObject(type := "Instruction Result", |
750 | +instruction, +data); |
751 | cset(instruction, +result); |
752 | ret result; |
753 | } |
754 | |
755 | L<BEAObject> scriptRunSteps(BEAObject scriptRun) { |
756 | ret (L) cget steps(scriptRun); |
757 | } |
758 | } // end of module |
759 | |
760 | extend User { |
761 | S notificationSetting; |
762 | } |
763 | |
764 | concept BEAObject > ConceptWithGlobalID { |
765 | new Ref<UserPost> mirrorPost; |
766 | |
767 | void change :: after { |
768 | ((GazelleBEA) botMod()).rstUpdateBEAMirrors.add(this); |
769 | } |
770 | |
771 | void delete :: before { |
772 | cdelete(mirrorPost!); |
773 | } |
774 | |
775 | void updateMirrorPost { |
776 | GazelleBEA mod = cast botMod(); |
777 | if (isDeleted() || !mod.mirrorBEAObjects) ret; |
778 | |
779 | if (!mirrorPost.has()) |
780 | cset(this, mirrorPost := cnew UserPost( |
781 | type := "BEA Object", |
782 | creator := mod.internalUser(), |
783 | botInfo := "BEA Mirror Bot")); |
784 | |
785 | S text = structureString(); |
786 | |
787 | cset(mirrorPost!, |
788 | title := str(this), |
789 | +text); |
790 | } |
791 | |
792 | S structureString() { |
793 | S text = "Error"; |
794 | pcall { |
795 | structure_Data data = new { |
796 | structure_ClassInfo newClass(Class c) { |
797 | structure_ClassInfo info = super.newClass(c); |
798 | if (c == Concept.Ref.class) { |
799 | info.special = true; |
800 | info.serializeObject = o -> { |
801 | Concept cc = cast deref((Concept.Ref) o); |
802 | //append("cu CRef " + (cc != null ? str(cc.id) : "null"), 3); |
803 | if (cc cast BEAObject) |
804 | append("CRef(gid=" + quote(cc.globalID()) + ")", 6); |
805 | else if (cc != null) |
806 | append("CRef(id=" + cc.id + ")", 6); |
807 | else |
808 | append("CRef", 1); |
809 | }; |
810 | } |
811 | ret info; |
812 | } |
813 | |
814 | void setFields(structure_ClassInfo info, L<Field> fields) { |
815 | if (isSubclassOf(info.c, BEAObject)) { |
816 | // Don't serialize "refs" and "backRefs" fields |
817 | removeAll(fields, |
818 | getField(BEAObject, "refs"), |
819 | getField(BEAObject, "backRefs")); |
820 | } |
821 | super.setFields(info, fields); |
822 | } |
823 | }; |
824 | |
825 | S struct = structure(this, data); |
826 | struct = dropLoadableUtilsPackageFromStruct(struct); |
827 | text = indentStructureString_firstLevels(1, struct); |
828 | } |
829 | |
830 | ret text; |
831 | } |
832 | |
833 | toString { |
834 | S type = strOrNull(cget type(this)); |
835 | S s = super.toString(); |
836 | |
837 | if (nempty(type)) { |
838 | s = type + " " + id; |
839 | if (eqic(type, "Match")) |
840 | s += appendBracketed(strOrNull(this~.label)) |
841 | + " " + this.~mapping |
842 | + appendBracketed(this.~input + " + " + this~.pattern); |
843 | } |
844 | |
845 | bool enabled = eq(true, getOpt enabled(this)); |
846 | if (enabled) s += " [enabled]"; |
847 | |
848 | S text = or2(text(), getStringOpt name(this)); |
849 | if (text != null) |
850 | s += " " + quote(text); |
851 | |
852 | O fc = this~.functionCalled; |
853 | if (fc != null) s += " " + fc; |
854 | |
855 | ret s; |
856 | } |
857 | |
858 | S type() { ret getStringOpt type(this); } |
859 | bool typeIs(S type) { ret eqic(type(), type); } |
860 | bool typeIsOneOf(S... types) { ret eqicOneOf(type(), types); } |
861 | |
862 | S text() { ret getStringOpt text(this); } |
863 | } // end of BEAObject |
Began life as a copy of #1030602
download show line numbers debug dex old transpilations
Travelled to 4 computer(s): bhatertpkbcr, mqqgnosmbjvj, pyentgdyhuwx, vouqrxazstgt
No comments. add comment
Snippet ID: | #1030928 |
Snippet name: | Gazelle BEA [backup with old "add field" layout] |
Eternal ID of this version: | #1030928/1 |
Text MD5: | 608ecd2fc55f3b046ff27bcecb3635c9 |
Transpilation MD5: | cb96a81ac0c2d9a580082bcc66e1224b |
Author: | stefan |
Category: | javax |
Type: | JavaX source code (Dynamic Module) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2021-04-12 15:56:25 |
Source code size: | 29531 bytes / 863 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 188 / 222 |
Referenced in: | [show references] |