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

339
LINES

< > BotCompany Repo | #1023708 // agi.blue source [backup before switching from url to q]

JavaX module (desktop)

Download Jar.

1  
!7
2  
3  
// See #1023660 for the older 99 lines version
4  
5  
concept PhysicalSlice { new Ref<Page> slicePage; }
6  
7  
concept Page {
8  
  new Ref<PhysicalSlice> slice;
9  
  S globalID = aGlobalID();
10  
  S url;
11  
}
12  
13  
concept Entry {
14  
  S globalID = aGlobalID();
15  
  new Ref<Page> page;
16  
  int count;
17  
  S key, value;
18  
  S ip;
19  
  new Ref<Signer> signer;
20  
}
21  
22  
concept Signer {
23  
  S globalID = aGlobalID();
24  
  S publicKey;
25  
  bool trusted;
26  
  S approvedBy;
27  
}
28  
29  
concept Session {
30  
  S cookie;
31  
  Page slicePage;
32  
}
33  
34  
static int displayLength = 140;
35  
36  
static int lines;
37  
sbool allowMultipleCasesInValues = true;
38  
static ConceptFieldIndexDesc idx_latestEntries, idx_latestCreatedPages, idx_latestChangedPages;
39  
40  
p {
41  
  dbIndexingCI(Page, 'url, Entry, 'key, Entry, 'value);
42  
  dbIndexing(Signer, 'publicKey);
43  
  dbIndexing(Session, 'cookie);
44  
  idx_latestCreatedPages = new ConceptFieldIndexDesc(Page, 'created);
45  
  idx_latestChangedPages = new ConceptFieldIndexDesc(Page, '_modified);
46  
  idx_latestEntries = new ConceptFieldIndexDesc(Entry, 'created);
47  
  
48  
  // Approve this machine's key
49  
  PKIKeyPair machineKey = agiBot_trustedKeyForMachine();
50  
  if (machineKey != null) {
51  
    print("Approving this machine's key: " + machineKey.publicKey);
52  
    cset(uniq_sync(Signer, publicKey := machineKey.publicKey), trusted := true, approvedBy := "local");
53  
  }
54  
  
55  
  lines = countLines(mySource());
56  
}
57  
58  
// DB functions
59  
60  
sbool hasPage(S url) { ret hasConceptWhereIC(Page, +url); }
61  
sS getValue(Page page, S key) {
62  
  ret getString value(highestByField count(objectsWhereIC(findBackRefs(page, Entry), +key)));
63  
}
64  
sS pageDisplayName(Page page) {
65  
  S name = getValue(page, "read as");
66  
  bool unnaturalName = nempty(name) && !eq(makeAGIDomain(name), page.url);
67  
  ret unnaturalName ? name + " " + squareBracketed(page.url) : or2(name, unpackAGIDomainOpt(page.url));
68  
}
69  
70  
// Serve page
71  
72  
set flag NoNanoHTTPD. html {
73  
  ret new Request().serve(uri, params);
74  
}
75  
76  
sclass Request {
77  
  S cookie;
78  
  Session session;
79  
  
80  
  O serve(S uri, SS params) {
81  
    new Matches m;
82  
    
83  
    cookie = cookieFromUser();
84  
    if (cookie != null)
85  
      session = uniq_sync(Session, +cookie);
86  
    else
87  
      session = unlistedWithValues(Session);
88  
89  
    if (swic(uri, "/bot/", m)) ret serveBot("/" + m.rest(), params);
90  
    
91  
    S q = params.get('q);
92  
    S domain = or2(params.get('domain), domain());
93  
    if (nempty(q)) {
94  
      domain = makeAGIDomain(q);
95  
      if (l(domain) > maximumDomainPartLength()) // escape with "domain="
96  
        ret hrefresh("http://agi.blue/" + hquery(+domain, key := "read as", value := q));
97  
      ret hrefresh("http://" + domain + (eq(q, domain) ? "" : "/" +  hquery(key := "read as", value := q)));
98  
      //uri = "/"; replaceMapWithParams(params, key := "read as", value := q);
99  
    }
100  
    S url = domain + dropTrailingSlash(uri);
101  
    Page page, bool newPage = unpair uniqCI2_sync(Page, +url);
102  
    if (newPage) dbLog("New page", +url);
103  
  
104  
    S top = hcomment("cookie: " + takeFirst(4, session.cookie)) + p(ahref("http://agi.blue", hsnippetimg(#1101682, width := 565/5, height := 800/5, title := "Robot by Peerro @ DeviantArt")))
105  
        + p(small(b(ahref("http://agi.blue", "agi.blue"))
106  
        + " | " + targetBlank(progLink(), "source code") + " of this web site (" + nLines(lines) + ") | " + targetBlank("https://gitter.im/agi-blue/community", "sponsor https?") + " | by " + targetBlank("https://BotCompany.de", "BC") + " | " + targetBlank("http://fiverr.tinybrain.de/", "Fiverr") + " | " + targetBlank("https://discordapp.com/invite/SEAjPqk", "Discord") + " | " + targetBlank("https://www.youtube.com/watch?v=b6jtRdV3Ev8", "Video")));
107  
    
108  
    if (eqicOneOf(url, "agi.blue", "www.agi.blue"))
109  
      ret hhtml(hhead_title("agi.blue Overview") // HOME PAGE
110  
        + hbody_fullcenter(top
111  
          + hform(b("GIVE ME INPUT:") + "<br><br>" + htextinput('q) + " " + hsubmit("Ask"))
112  
          + h1("agi.blue has " + nPages(countConcepts(Page)))
113  
          + p(nlToBr(nemptyLines(map(pageToHTMLLink(), sortedByFieldDesc _modified(list(Page))))))
114  
        ));
115  
        
116  
    S key = trim(params.get('key)), value = trim(params.get('value));
117  
    L<Entry> entries = GetEntriesAndPost().go(page, params).entries;
118  
    
119  
    S get = params.get('get);
120  
    if (nempty(get))
121  
      ret serveText(jsonEncode(collect value(llNotNulls(firstWhereIC(entries, key := get)))));
122  
    
123  
    S key2 = key, value2 = value; if (nempty(key) && nempty(value)) key2 = value2 = ""; // input reset
124  
  
125  
    bool withHidden = eq(params.get('withHidden), "1");
126  
    new Set<Int> hide;
127  
    if (!withHidden) for (Entry e : entries) if (eqic(e.key, 'hide) && isSquareBracketedInt(e.value)) addAll(hide, e.count, parseInt(unSquareBracket(e.value)));
128  
    new MultiMap<Int, S> mmMeta;
129  
    for (Entry e : entries) if (isSquareBracketedInt(e.key)) mmMeta.put(parseInt(unSquareBracket(e.key)), e.value);
130  
    new MultiMap<S> mm;
131  
    for (Entry e : entries) mm.put(e.key, e.value);
132  
    
133  
    S name = or2(/* ouch */ last(mm.get("read as")), /* end ouch */ unpackAGIDomain(page.url), page.url);
134  
    
135  
    L<Entry> valueRefs = conceptsWhereIC Entry(value := name);
136  
    Set<Page> valueRefPages = asSet(ccollect page(valueRefs));
137  
    valueRefPages.remove(page);
138  
    
139  
    S mainContents =
140  
        top + h1(ahref_unstyled("http://" + url, htmlEncode2(name)) + (newPage ? " [huh????]" : ""))
141  
      + p(nlToBr(nemptyLines(map(entries, func(Entry e) -> S {
142  
        !withHidden && (hide.contains(e.count) || eqic(e.key, "read as") && eqic(e.value, name)) ? "" : "[" + e.count + "] " +
143  
        htmlencode2(e.key) + ": " + b(
144  
          isURL(e.value)
145  
          || cic(mmMeta.get(e.count), "is a URL")
146  
          || isAGIDomain(e.value)
147  
            ? ahref(fixAGILink(absoluteURL(e.value)), htmlencode2(shorten(displayLength, e.value)))
148  
            : ahref(agiBlue_linkForPhrase(e.value), htmlencode2(shorten(displayLength, e.value)))
149  
        ) }))))
150  
      + hpostform(h3("Add an entry")
151  
        + "Key: " + hinputfield(key := key2) + " Value: " + hinputfield(value := value2) + "<br><br>" + hsubmit("Add")
152  
        );
153  
        
154  
    S sideContents =
155  
      hform(b("GIVE ME INPUT:") + " " + htextinput('q) + " " + hsubmit("Ask"))
156  
      
157  
      + h3("References (" + l(valueRefPages) + ")")
158  
      
159  
      + p(nlToBr(nemptyLines(map(pageToHTMLLink(), takeFirst(10, valueRefPages)))));
160  
161  
    // serve a page
162  
    ret hhtml(hhead_title(pageDisplayName(page)) + hbody(
163  
      tag('table, tr(
164  
        td(mainContents, align := 'center, valign := 'top) +
165  
        td(sideContents, align := 'right, valign := 'top)),
166  
        width := "100%", height := "100%")));
167  
  }
168  
}
169  
170  
svoid dbLog(O... params) {
171  
  logStructure(programFile("db.log"), ll(params));
172  
}
173  
174  
// uri = without the "/bot" in front
175  
sO serveBot(S uri, SS params) {
176  
  S q = params.get('q), url = params.get('url);
177  
  if (nempty(q)) url = makeAGIDomain(q);
178  
  if (eqic(uri, "/hello")) ret serveJSON("hello");
179  
  if (eqic(uri, "/hasPage")) ret serveJSON(hasPage(url));
180  
  if (eqic(uri, "/randomPageContaining")) {
181  
    assertNempty(q);
182  
    ret servePageToBot(random(filter(list(Page), p -> cic(p.url, q))), params);
183  
  }
184  
  if (eqic(uri, "/allPagesEndingWith")) {
185  
    assertNempty(q);
186  
    ret servePagesToBot(filter(list(Page), p -> ewic(p.url, q)), params);
187  
  }
188  
  
189  
  if (eqicOneOf(uri, "/postSigned", "/makePhysicalSlice", "/approveTrustRequest")) {
190  
    S text = rtrim(params.get('text));
191  
    S key = getSignerKey(text);
192  
    if (empty(key)) ret subBot_serve500("Please include your public key");
193  
    if (!isSignedWithKey(text, key)) ret subBot_serve500("Signature didn't verify");
194  
    text = dropLastTwoLines(text); // drop signer + sig line
195  
    
196  
    Signer signer = uniq_sync Signer(publicKey := key);
197  
    
198  
    if (eqic(uri, "/makePhysicalSlice")) {
199  
      if (!signer.trusted) ret subBot_serve500("Untrusted signer");
200  
      Page page = findPageFromParams(jsonDecodeMap(text));
201  
      if (page == null) ret subBot_serve500("Page not found");
202  
      ret jsonEncode(uniq2_sync(PhysicalSlice, slicePage := page).b ? "Slice made" : "Slice exists");
203  
    }
204  
  
205  
    if (eqic(uri, "/postSigned")) {
206  
      new L out;
207  
      for (S line : tlft(text)) {
208  
        SS map = jsonDecodeMap(line);
209  
        new GetEntriesAndPost x;
210  
        x.signer = signer;
211  
        Page page = findOrMakePageFromParams(map);
212  
        if (page == null) continue with out.add("Page not found: " + quote(url));
213  
        x.go(page, map);
214  
        out.add(x.newEntry ? "Saved" : x.entry != null ? "Entry exists" : "Need key and value");
215  
      }
216  
      ret serveJSON(out);
217  
    }
218  
    
219  
    if (eqic(uri, "/approveTrustRequest")) {
220  
      if (!signer.trusted) ret subBot_serve500("Untrusted signer");
221  
      Signer toApprove = conceptWhere Signer(publicKey := trim(text));
222  
      if (toApprove == null) ret subBot_serve500("Signer to approve not found");
223  
      cset(toApprove, trusted := true, approvedBy := signer.globalID);
224  
      ret serveJSON("Approved: " + trim(text));
225  
    }
226  
    
227  
    ret subBot_serve500("CONFUSION");
228  
  }
229  
  
230  
  if (eqic(uri, "/post")) {
231  
    new GetEntriesAndPost x;
232  
    x.go(conceptWhereCI Page(+url), params);
233  
    ret serveJSON(x.newEntry ? "Saved" : x.entry != null ? "Entry exists" : "Need key and value");
234  
  }
235  
  if (eqic(uri, "/latestEntries"))
236  
    ret serveJSON_shallowLineBreaks(map(takeFirst(10, idx_latestEntries.objectIterator()), entryToMap(true)));
237  
  if (eqic(uri, "/latestPages"))
238  
    ret serveJSON_shallowLineBreaks(map(takeFirst(10, idx_latestCreatedPages.objectIterator()), pageToMap()));
239  
  if (eqic(uri, "/latestChangedPages"))
240  
    ret serveJSON_shallowLineBreaks(map(takeFirst(10, idx_latestChangedPages.objectIterator()), pageToMap()));
241  
    
242  
  if (eqic(uri, "/totalPageCount"))
243  
    ret serveJSON(countConcepts(Page));
244  
  if (eqic(uri, "/physicalSliceCount"))
245  
    ret serveJSON(countConcepts(PhysicalSlice));
246  
  if (eqic(uri, "/trustedSignersCount"))
247  
    ret serveJSON(countConcepts(Signer, trusted := true));
248  
    
249  
  if (eqic(uri, "/valueSearch")) {
250  
    S value = params.get('value);
251  
    L<Entry> entries = conceptsWhereIC Entry(+value);
252  
    ret serveJSON_shallowLineBreaks(map(takeFirst(100, entries), entryToMap(true));
253  
  }
254  
    
255  
  // end of bot functions
256  
257  
  ret subBot_serve404();
258  
}
259  
260  
static IF1<Page, Map> pageToMap(O... _) {
261  
  bool withEntries = boolPar withEntries(_);
262  
  ret (IF1<Page, Map>) p -> {
263  
    L<Entry> entries = findBackRefs(p, Entry);
264  
    ret litorderedmap(
265  
      url := p.url,
266  
      nEntries := l(entries),
267  
      created := p.created,
268  
      modified := p._modified,
269  
      entries := !withEntries ? null : map(entries, entryToMap(false)));
270  
  };
271  
}
272  
273  
static IF1<Entry, Map> entryToMap(bool withPage) {
274  
  ret (IF1<Entry, Map>) e -> litorderedmap(
275  
    created := e.created,
276  
    i := e.count,
277  
    key := e.key,
278  
    value := e.value,
279  
    url := withPage ? e.page->url : null,
280  
    signer := getString globalID(e.signer!));
281  
}
282  
283  
sO servePageToBot(Page page, SS params) {
284  
  if (page == null) ret serveJSON(null);
285  
  params = asCIMap(params);
286  
  Map map = pageToMap(withEntries := valueIs1 withEntries(params)).get(page);
287  
  ret serveJSON(map);
288  
}
289  
290  
sO servePagesToBot(Iterable<Page> pages, SS params) {
291  
  ret serveJSON(map(pageToMap(), pages));
292  
}
293  
294  
sclass GetEntriesAndPost {
295  
  L<Entry> entries;
296  
  Entry entry;
297  
  bool newEntry;
298  
  Signer signer;
299  
  
300  
  GetEntriesAndPost go(Page page, SS params) {
301  
    S key = trim(params.get('key)), value = trim(params.get('value));
302  
    withDBLock {
303  
      entries = findBackRefs(page, Entry);
304  
      if (nempty(key) && nempty(value)) {
305  
        S ip = subBot_clientIP();
306  
        entry = firstThat(e -> eqic(e.key, key) && eq_icIf(!allowMultipleCasesInValues, e.value, value) && eq(e.ip, ip), entries);
307  
        if (entry == null) {
308  
          print("SAVING");
309  
          Entry e = cnew Entry(+page, +key, +value, +ip, count := l(entries) + 1, +signer);
310  
          page.change(); // bump modification date
311  
          entry = e;
312  
          newEntry = true;
313  
          entries.add(entry);
314  
          dbLog("New entry", page := page.url, globalID := e.globalID, count := e.count, +key, +value);
315  
        }
316  
      }
317  
    }
318  
319  
    sortByFieldInPlace created(entries);
320  
    numberEntriesInConceptField count(entries);
321  
    this;
322  
  }
323  
}
324  
325  
static Page findPageFromParams(Map map) {
326  
  S url = nempty(getString q(map)) ? makeAGIDomain(getString q(map)) : getString url(map);
327  
  ret empty(url) ? null : conceptWhereCI Page(+url);
328  
}
329  
330  
static Page findOrMakePageFromParams(Map map) {
331  
  S url = nempty(getString q(map)) ? makeAGIDomain(getString q(map)) : getString url(map);
332  
  ret empty(url) ? null : uniqCI_sync Page(+url);
333  
}
334  
335  
static F1<Page, S> pageToHTMLLink() {
336  
  ret func(Page p) -> S {
337  
    ahref(fixAGILink("http://" + p.url), htmlEncode2(pageDisplayName(p)))
338  
  };
339  
}

Author comment

Began life as a copy of #1023558

download  show line numbers  debug dex  old transpilations   

Travelled to 6 computer(s): bhatertpkbcr, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tvejysmllsmz, vouqrxazstgt

No comments. add comment

Snippet ID: #1023708
Snippet name: agi.blue source [backup before switching from url to q]
Eternal ID of this version: #1023708/1
Text MD5: 34195892a56a499c7c979d24a90ad67e
Author: stefan
Category: javax / html
Type: JavaX module (desktop)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2019-07-03 22:29:11
Source code size: 12857 bytes / 339 lines
Pitched / IR pitched: No / No
Views / Downloads: 178 / 288
Referenced in: [show references]