Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

863
LINES

< > BotCompany Repo | #1030928 // Gazelle BEA [backup with old "add field" layout]

JavaX source code (Dynamic Module) [tags: use-pretranspiled] - run with: Stefan's OS

Uses 1059K of libraries. Click here for Pure Java version (41281L/266K).

!7

!include once #1030833 // BEACalculations

set flag NoNanoHTTPD.

cmodule2 GazelleBEA > DynGazelleRocks {
  switchable bool mirrorBEAObjects; // don't do it for now
  switchable bool enableAutoRuns = true;
  switchable bool enableNewBEAObjectNotis = true;
  
  transient ReliableSingleThread_Multi<BEAObject> rstAutoRuns = new(1000, lambda1 performAutoRuns);
  transient Q notificationQ;
  transient ReliableSingleThread_Multi<BEAObject> rstDistributeNewObject = new(1000, lambda1 distributeNewObject_impl);
  transient Set<BEAObject> 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;
  }

  start {
    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<Class> 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());
  }

  <A extends Concept> HCRUD_Concepts<A> crudData(Class<A> c, Req req) {
    HCRUD_Concepts<A> 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<S> 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;
  }

  <A extends Concept> HCRUD makeCRUD(Class<A> c, Req req, HTMLFramer1 framer) {
    HCRUD crud = super.makeCRUD(c, req, framer);
    HCRUD_Concepts data = cast crud.data;
    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
        
        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<BEAObject> 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", htmlTable2_noHtmlEncode(ll(
            ll("Name", htextfield("\*nf*/_name"),
            "Value",
              // string input
              htextfield("\*nf*/_value"),
  
              span(refSelector, id := "\*nf*/_refBox", style := "display: none"),
            "Type", typeSelector
            )),
            noHeader := true)));
          }
        };
      
      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<BEAObject> 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<BEAObject> 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, "/inputsWithoutRewrites")) {
      HCRUD crud = makeBEAObjectCRUD(req, "input");
      HCRUD_Concepts<BEAObject> data = cast crud.data;
      
      /*IF1 prev = crud.renderCmds;
      crud.renderCmds = o -> {
        S cmds = crud.renderCmds_fallback(prev, o);
        ret joinNemptiesWithVBar(addRewriteHTML(data.getConcept(o)), cmds);
      };*/
      
      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, "/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<S> 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(beaObjectURL(match));
    }
    
    if (eq(uri, "/saveSyntacticPattern")) {
      S text = req.get("text");
      uniqCI BEAObject(type := "Syntactic Pattern", +text, createdBy := user(req));
      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<MapSO> 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<BEAObject, Bool> 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<BEAObject> 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")));
    
    ret joinNemptiesWithVBar(
      beaNavLink("Input", crud),
      beaNavLink("Pattern", crud),
      beaNavLink("Syntactic Pattern", crud),
      beaNavLink("Match", crud),
      beaNavLink("Rewrite", crud),
      beaNavLink("AI Task", crud),
      ahref(baseLink + "/query", "Query"),
      ahref(baseLink + "/inputsWithoutRewrites", n2(inputsWithoutRewrites) + " Inputs without 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)))
        + "<br>&nbsp; with " + renderEqualsCommaProperties(mapping));
    }
    ret htmlEncode2(str(m));
  }
  
  int beaCount(S type) {
    ret countConceptsWhereCI BEAObject(+type);
  }
  
  Cl<BEAObject> beaList(S type) {
    ret conceptsWhereCI BEAObject(+type);
  }
  
  Cl<BEAObject> 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<BEAObject> 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<virtual WebSocket, WebSocketInfo> 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<BEAObject> steps = scriptRunSteps(scriptRun);
        int idx = indexOf(steps, o);
        if (idx < 0) fail("Step not found in script run");
        
        L<BEAObject> list = firstNotNull(map(reversed(takeFirst(steps, idx)),
          step -> optCast L(cget data(cgetBEA result(step)))));
         
        S prefix = getString prefix(instruction);
        L<BEAObject> 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<BEAObject> 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<BEAObject> scriptRunSteps(BEAObject scriptRun) {
    ret (L) cget steps(scriptRun);
  }
} // end of module

extend User {
  S notificationSetting;
}

concept BEAObject > ConceptWithGlobalID {
  new Ref<UserPost> 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<Field> 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

Author comment

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: 187 / 221
Referenced in: [show references]