replace with embeddable script
This commit is contained in:
parent
5acb247fb0
commit
a97f9f4980
|
@ -1 +0,0 @@
|
||||||
node_modules/
|
|
|
@ -1,4 +0,0 @@
|
||||||
FROM node:18.0-slim
|
|
||||||
COPY index.js package.json yarn.lock ./
|
|
||||||
RUN yarn
|
|
||||||
CMD [ "node", "index.js" ]
|
|
59
README.md
59
README.md
|
@ -1,19 +1,20 @@
|
||||||
# WikiJs Metabot
|
# WikiJs Metabot
|
||||||
|
|
||||||
Ein Skript was die Page-Listings auf [https://wiki.ctdo.de](https://wiki.ctdo.de)
|
Ein Skript was die Page-Listings auf [https://wiki.ctdo.de](https://wiki.ctdo.de)
|
||||||
automatisch aktuell hält
|
automatisch befüllt
|
||||||
|
|
||||||
## Verwendung
|
## Verwendung
|
||||||
|
|
||||||
Um auf einer Wiki-Seite ein Page-Listing hinzuzufügen muss der Seite das `metapage`-Tag hinzugefügt
|
Um auf einer Wiki-Seite ein Page-Listing hinzuzufügen muss in den Metadaten der Seite der Inhalt von
|
||||||
werden und an der gewünschten Stelle ein Kommentar folgender Form eingefügt werden:
|
`metapage.js.html` als Skript gesetzt werden.
|
||||||
|
Dann kann an der gewünschten Stelle ein HTML-Element folgender Form eingefügt werden:
|
||||||
|
|
||||||
```text
|
```html
|
||||||
<!-- \pagelist QUERY -->
|
<ul class="pagelist" data-query="QUERY"></ul>
|
||||||
```
|
```
|
||||||
|
|
||||||
Dabei muss `QUERY` eine Parameterlist für die `PageQuery::list`-Methode der WikiJs-GraphQL-API sein.
|
Dabei muss `QUERY` eine Parameterliste für die `PageQuery::list`-Methode der WikiJs-GraphQL-API
|
||||||
Folgende Parameter werden unterstützt:
|
sein. Folgende Parameter werden unterstützt:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
limit: Int
|
limit: Int
|
||||||
|
@ -29,57 +30,33 @@ authorId: Int
|
||||||
|
|
||||||
Liste aller Seiten die mit den Tags `top` und `new` versehen sind:
|
Liste aller Seiten die mit den Tags `top` und `new` versehen sind:
|
||||||
|
|
||||||
```text
|
```html
|
||||||
<!-- \pagelist tags: ["top", "new"] -->
|
<ul class="pagelist" data-query="tags: ['top', 'new']"></ul>
|
||||||
```
|
```
|
||||||
|
|
||||||
Liste der 10 zuletzt bearbeiteten Seiten:
|
Liste der 10 zuletzt bearbeiteten Seiten:
|
||||||
|
|
||||||
```text
|
```html
|
||||||
<!-- \pagelist orderBy: UPDATED, orderByDirection: DESC, limit: 10 -->
|
<ul
|
||||||
|
class="pagelist"
|
||||||
|
data-query="orderBy: UPDATED, orderByDirection: DESC, limit: 10"
|
||||||
|
></ul>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Details
|
### Details
|
||||||
|
|
||||||
- Mehrere Parameter müssen mit einem Komma getrennt werden
|
- Mehrere Parameter müssen mit einem Komma getrennt werden
|
||||||
- Mehrere Tags im `tags`-Parameter müssen ebenfalls mit Komma getrennt werden
|
- Mehrere Tags im `tags`-Parameter müssen ebenfalls mit Komma getrennt werden
|
||||||
- Parameter vom Typ `String` müssen in doppelte Anführungszeichen `"` eingeschlossen werden
|
- Parameter vom Typ `String` müssen in einfache Anführungszeichen `'` eingeschlossen werden
|
||||||
- Parameter vom Typ `Int` und vom Typ `Enum` müssen ohne Anführungszeichen angegeben werden
|
- Parameter vom Typ `Int` und vom Typ `Enum` müssen ohne Anführungszeichen angegeben werden
|
||||||
|
|
||||||
## Features und Einschränkungen
|
## Features und Einschränkungen
|
||||||
|
|
||||||
Zur Rekursionsvermeidung können leider die mit `metapage` getaggten Seiten nicht selbst in den
|
|
||||||
Page-Listings auftauchen.
|
|
||||||
Eine Seite welche die zuletzt aktualisierten Seiten enthält, kann also nur Seiten enthalten welche
|
|
||||||
nicht mit `metapage` getaggt sind.
|
|
||||||
|
|
||||||
Seiten deren Pfad mit einem Unterstrich `_` beginnt werden als versteckt interpretiert und nicht in
|
Seiten deren Pfad mit einem Unterstrich `_` beginnt werden als versteckt interpretiert und nicht in
|
||||||
Page-Listings angezeigt.
|
Page-Listings angezeigt.
|
||||||
Das wird beispielsweise auf der Topictreff-Seite verwendet damit das Topic-Template nicht unter den
|
Das wird beispielsweise auf der Topictreff-Seite verwendet damit das Topic-Template nicht unter den
|
||||||
neuen Topics aufgelistet wird.
|
neuen Topics aufgelistet wird.
|
||||||
|
|
||||||
Bei gesetzten Limits kommt es vor, dass weniger Seiten als angegeben aufgelistet werden.
|
Bei gesetzten Limits kommt es vor, dass weniger Seiten als angegeben aufgelistet werden.
|
||||||
Das liegt daran, dass das Filtern zur Rekursionsvermeidung und zum verstecken von Seiten erst nach
|
Das scheint ein Bug im WikiJs zu sein wodurch manche Seiten nicht in dem Ergebnis zurückgegeben aber
|
||||||
dem Ausführen der GraphQL-Query passiert.
|
trotzdem gezählt werden.
|
||||||
Außerdem scheint auch das WikiJs einen ähnlichen Bug zu haben wodurch manche Seiten nicht in dem
|
|
||||||
Ergebnis zurückgegeben aber trotzdem gezählt werden.
|
|
||||||
|
|
||||||
## Ausführen des Bots
|
|
||||||
|
|
||||||
Damit der Bot Seiten bearbeiten darf muss die Umgebungsvariable `CTDO_WIKIJS_API_KEY` auf einen
|
|
||||||
gültigen Api-Key gesetzt sein.
|
|
||||||
Api-Keys für das WikiJs können hier generiert werden: [https://wiki.ctdo.de/a/api](https://wiki.ctdo.de/a/api).
|
|
||||||
|
|
||||||
### Docker commands
|
|
||||||
|
|
||||||
Docker Container für den Bot bauen:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
docker build -t wikijs-metabot .
|
|
||||||
```
|
|
||||||
|
|
||||||
Docker container ausführen:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
docker run -it -e CTDO_WIKIJS_API_KEY wikijs-metabot
|
|
||||||
```
|
|
||||||
|
|
138
index.js
138
index.js
|
@ -1,138 +0,0 @@
|
||||||
import WebSocket from 'ws';
|
|
||||||
|
|
||||||
process.on('SIGINT', () => process.exit(0));
|
|
||||||
|
|
||||||
const apiKey = process.env['CTDO_WIKIJS_API_KEY'];
|
|
||||||
|
|
||||||
async function graphql(query) {
|
|
||||||
const res = await fetch('https://wiki.ctdo.de/graphql', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
Authorization: `Bearer ${apiKey}`,
|
|
||||||
},
|
|
||||||
body: JSON.stringify({ query }),
|
|
||||||
});
|
|
||||||
return await res.json();
|
|
||||||
}
|
|
||||||
|
|
||||||
function graphqlSubscribe(query, callback) {
|
|
||||||
const ws = new WebSocket(
|
|
||||||
'wss://wiki.ctdo.de/graphql-subscriptions',
|
|
||||||
'graphql-ws'
|
|
||||||
);
|
|
||||||
ws.onmessage = (event) => callback(JSON.parse(event.data));
|
|
||||||
ws.onopen = () => {
|
|
||||||
ws.send(JSON.stringify({ type: 'connection_init' }));
|
|
||||||
ws.send(
|
|
||||||
JSON.stringify({
|
|
||||||
id: '1',
|
|
||||||
type: 'start',
|
|
||||||
payload: { query: `subscription ${query}` },
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async function update() {
|
|
||||||
const pageIds = (
|
|
||||||
await graphql('query { pages { list(tags: ["metapage"]) { id } } }')
|
|
||||||
).data.pages.list.map((page) => page.id);
|
|
||||||
console.log('checking metapages', { pageIds });
|
|
||||||
pageIds.forEach((pageId) => updatePage(pageId));
|
|
||||||
}
|
|
||||||
|
|
||||||
async function updatePage(pageId) {
|
|
||||||
console.log('checking page', { pageId });
|
|
||||||
|
|
||||||
const page = (
|
|
||||||
await graphql(`query { pages { single(id: ${pageId}) {
|
|
||||||
id
|
|
||||||
content
|
|
||||||
description
|
|
||||||
editor
|
|
||||||
isPrivate
|
|
||||||
isPublished
|
|
||||||
locale
|
|
||||||
path
|
|
||||||
publishEndDate
|
|
||||||
publishStartDate
|
|
||||||
scriptCss
|
|
||||||
scriptJs
|
|
||||||
tags { tag }
|
|
||||||
title
|
|
||||||
} } }`)
|
|
||||||
).data.pages.single;
|
|
||||||
page.tags = page.tags.map((tag) => tag.tag);
|
|
||||||
|
|
||||||
let contentLines = page.content.split('\n');
|
|
||||||
const pagelistConfigs = contentLines.filter((line) =>
|
|
||||||
line.match(/^\s*<!--\s*\\pagelist[^>]*-->\s*$/)
|
|
||||||
);
|
|
||||||
|
|
||||||
for (const pagelistConfig of pagelistConfigs) {
|
|
||||||
await updatePagelist(pagelistConfig, contentLines);
|
|
||||||
}
|
|
||||||
|
|
||||||
const updatedContent = contentLines.join('\n');
|
|
||||||
|
|
||||||
if (page.content !== updatedContent) {
|
|
||||||
page.content = updatedContent;
|
|
||||||
console.log('updating page');
|
|
||||||
console.log({ page });
|
|
||||||
const mutation = Object.entries(page)
|
|
||||||
.map(([key, value]) => `${key}: ${JSON.stringify(value)}`)
|
|
||||||
.join(', ');
|
|
||||||
const result = await graphql(
|
|
||||||
`mutation { pages { update(${mutation}) { responseResult { succeeded, message, errorCode } } } }`
|
|
||||||
);
|
|
||||||
console.log({ result: JSON.stringify(result) });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function updatePagelist(pagelistConfig, contentLines) {
|
|
||||||
const query = pagelistConfig
|
|
||||||
.replace(/^\s*<!--\s*\\pagelist\s*/, '')
|
|
||||||
.replace(/\s*-->\s*$/, '');
|
|
||||||
|
|
||||||
const result = (
|
|
||||||
await graphql(`query { pages { list(${query}) { path, title, tags } }}`)
|
|
||||||
).data.pages.list
|
|
||||||
.filter((page) => !page.path.includes('/_'))
|
|
||||||
.filter((page) => !page.tags.includes('metapage'))
|
|
||||||
.map((page) => `- [${page.title}](/${page.path})`);
|
|
||||||
|
|
||||||
console.log({ pagelistConfig, query, result });
|
|
||||||
|
|
||||||
const startIndex = contentLines.findIndex((line) => line == pagelistConfig);
|
|
||||||
let endIndex = startIndex + 1;
|
|
||||||
while (
|
|
||||||
endIndex < contentLines.length &&
|
|
||||||
contentLines[endIndex].startsWith('- ')
|
|
||||||
) {
|
|
||||||
endIndex++;
|
|
||||||
}
|
|
||||||
contentLines.splice(
|
|
||||||
startIndex,
|
|
||||||
endIndex - startIndex,
|
|
||||||
`<!-- \\pagelist ${query} -->`,
|
|
||||||
...result
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function main() {
|
|
||||||
await update();
|
|
||||||
|
|
||||||
graphqlSubscribe('{ loggingLiveTrail { output } }', async (message) => {
|
|
||||||
if (
|
|
||||||
message.type === 'data' &&
|
|
||||||
message.payload.data.loggingLiveTrail.output.includes(
|
|
||||||
'Committing updated file'
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
await update();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
main();
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
<script>
|
||||||
|
// https://git.ctdo.de/ctdo/wikijs-metabot/
|
||||||
|
|
||||||
|
async function graphql(query) {
|
||||||
|
const res = await fetch('https://wiki.ctdo.de/graphql', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ query }),
|
||||||
|
});
|
||||||
|
return await res.json();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadPagelists() {
|
||||||
|
console.log('populating pagelists');
|
||||||
|
|
||||||
|
const pagelists = [...document.getElementsByClassName('pagelist')];
|
||||||
|
pagelists.forEach(async (element) => {
|
||||||
|
console.log('processing', element);
|
||||||
|
const parameters = element
|
||||||
|
.getAttribute('data-query')
|
||||||
|
.replaceAll("'", '"');
|
||||||
|
const query = `query { pages { list(${parameters}) { path, title } }}`;
|
||||||
|
const result = await graphql(query);
|
||||||
|
console.log({ query, result });
|
||||||
|
const pages = result.data.pages.list.filter(
|
||||||
|
(page) => !page.path.includes('/_')
|
||||||
|
);
|
||||||
|
const pagelist = pages.map((page) => {
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = `/${page.path}`;
|
||||||
|
link.classList.add('is-internal-link');
|
||||||
|
link.classList.add('is-valid-page');
|
||||||
|
link.textContent = page.title;
|
||||||
|
|
||||||
|
const listItem = document.createElement('li');
|
||||||
|
listItem.appendChild(link);
|
||||||
|
return listItem;
|
||||||
|
});
|
||||||
|
|
||||||
|
pagelist.forEach((page) => element.appendChild(page));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function isElementLoaded(selector) {
|
||||||
|
while (document.querySelector(selector) === null) {
|
||||||
|
await new Promise((resolve) => requestAnimationFrame(resolve));
|
||||||
|
}
|
||||||
|
return document.querySelector(selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
isElementLoaded('.contents').then(() => loadPagelists());
|
||||||
|
</script>
|
15
package.json
15
package.json
|
@ -1,15 +0,0 @@
|
||||||
{
|
|
||||||
"name": "wikijs-metabot",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "",
|
|
||||||
"main": "index.js",
|
|
||||||
"scripts": {
|
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
|
||||||
},
|
|
||||||
"author": "",
|
|
||||||
"license": "AGPL-3.0-or-later",
|
|
||||||
"dependencies": {
|
|
||||||
"ws": "^8.9.0"
|
|
||||||
},
|
|
||||||
"type": "module"
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
||||||
# yarn lockfile v1
|
|
||||||
|
|
||||||
|
|
||||||
ws@^8.9.0:
|
|
||||||
version "8.9.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/ws/-/ws-8.9.0.tgz#2a994bb67144be1b53fe2d23c53c028adeb7f45e"
|
|
||||||
integrity sha512-Ja7nszREasGaYUYCI2k4lCKIRTt+y7XuqVoHR44YpI49TtryyqbqvDMn5eqfW7e6HzTukDRIsXqzVHScqRcafg==
|
|
Loading…
Reference in New Issue