Initial commit
This commit is contained in:
commit
c8f1067c77
|
@ -0,0 +1 @@
|
|||
node_modules/
|
|
@ -0,0 +1,4 @@
|
|||
FROM node:18.0-slim
|
||||
COPY index.js package.json yarn.lock ./
|
||||
RUN yarn
|
||||
CMD [ "node", "index.js" ]
|
|
@ -0,0 +1,47 @@
|
|||
# WikiJs Metabot
|
||||
|
||||
Ein Skript was die Page-Listings auf [https://wiki.ctdo.de](https://wiki.ctdo.de)
|
||||
automatisch aktuell hält
|
||||
|
||||
## Verwendung
|
||||
|
||||
Um auf einer Wiki-Seite ein Page-Listing hinzuzufügen muss der Seite das `metapage`-Tag hinzugefügt
|
||||
werden und an der gewünschten Stelle ein Kommentar folgender Form eingefügt werden:
|
||||
|
||||
```markdown
|
||||
<!-- \pagelist QUERY -->
|
||||
```
|
||||
|
||||
Dabei muss `QUERY` eine Parameterlist für die `PageQuery::list`-Methode der WikiJs-GraphQL-API sein.
|
||||
Folgende Parameter werden unterstützt:
|
||||
|
||||
```text
|
||||
limit: Int
|
||||
orderBy: Enum CREATED | ID | PATH | TITLE | UPDATED
|
||||
orderByDirection: Enum ASC | DESC
|
||||
tags: [String]
|
||||
locale: String
|
||||
creatorId: Int
|
||||
authorId: Int
|
||||
```
|
||||
|
||||
### Beispiele
|
||||
|
||||
Liste aller Seiten die mit den Tags `top` und `new` versehen sind:
|
||||
|
||||
```markdown
|
||||
<!-- \pagelist tags: ["top", "new"] -->
|
||||
```
|
||||
|
||||
Liste der 10 zuletzt bearbeiteten Seiten:
|
||||
|
||||
```markdown
|
||||
<!-- \pagelist orderBy: UPDATED, orderByDirection: DESC, limit: 10 -->
|
||||
```
|
||||
|
||||
### Details
|
||||
|
||||
- Mehrere Parameter müssen mit einem 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 `Int` und vom Typ `Enum` müssen ohne Anführungszeichen angegeben werden
|
|
@ -0,0 +1,138 @@
|
|||
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,15 @@
|
|||
{
|
||||
"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"
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
# 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