@20syldev/api 3.0.0 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/app.js +65 -6
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<a href="https://api.sylvain.pro"><img src="https://api.sylvain.pro/favicon.ico" alt="Logo" width="25%" height="auto"/></a>
|
|
3
3
|
|
|
4
4
|
# API Personnelle
|
|
5
|
-
[](https://github.com/20syldev/api/releases/latest)
|
|
6
6
|
</div>
|
|
7
7
|
|
|
8
8
|
---
|
|
@@ -44,7 +44,7 @@ Enfin, **exécutez** le script de build, qui installera les **dépendances** et
|
|
|
44
44
|
$ npm run build
|
|
45
45
|
```
|
|
46
46
|
```console
|
|
47
|
-
> @20syldev/api@3.
|
|
47
|
+
> @20syldev/api@3.2.0 build
|
|
48
48
|
> npm install && node app.js
|
|
49
49
|
|
|
50
50
|
[...]
|
package/app.js
CHANGED
|
@@ -2,6 +2,7 @@ import cors from 'cors';
|
|
|
2
2
|
import dotenv from 'dotenv';
|
|
3
3
|
import express from 'express';
|
|
4
4
|
import fetch from 'node-fetch';
|
|
5
|
+
import ical from 'ical.js';
|
|
5
6
|
import { createCanvas } from 'canvas';
|
|
6
7
|
import { randomBytes, getHashes, createHash } from 'crypto';
|
|
7
8
|
import { urlencoded, json } from 'express';
|
|
@@ -20,10 +21,11 @@ const versions = ['v1', 'v2', 'v3'];
|
|
|
20
21
|
const endpoints = {
|
|
21
22
|
v1: ['algorithms', 'captcha', 'color', 'convert', 'domain', 'infos', 'personal', 'qrcode', 'token', 'username', 'website'],
|
|
22
23
|
v2: ['algorithms', 'captcha', 'chat', 'color', 'convert', 'domain', 'hash', 'infos', 'personal', 'qrcode', 'tic-tac-toe', 'token', 'username', 'website'],
|
|
23
|
-
v3: ['algorithms', 'captcha', 'chat', 'color', 'convert', 'date', 'domain', 'hash', 'infos', 'levenshtein', 'personal', 'qrcode', 'tic-tac-toe', 'time', 'token', 'username', 'website']
|
|
24
|
+
v3: ['algorithms', 'captcha', 'chat', 'color', 'convert', 'date', 'domain', 'hash', 'hyperplanning', 'infos', 'levenshtein', 'personal', 'qrcode', 'tic-tac-toe', 'time', 'token', 'username', 'website']
|
|
24
25
|
};
|
|
25
26
|
|
|
26
|
-
// Arrowed functions (math & random)
|
|
27
|
+
// Arrowed functions (formatting, math & random)
|
|
28
|
+
const formatDate = d => new Date(d.getTime() - d.getTimezoneOffset() * 60000).toISOString().replace('Z', '');
|
|
27
29
|
const gcd = (a, b) => b === 0 ? a : gcd(b, a % b);
|
|
28
30
|
const genID = () => {
|
|
29
31
|
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
|
@@ -134,7 +136,7 @@ app.use((req, res, next) => {
|
|
|
134
136
|
// Internal Server Error
|
|
135
137
|
app.use((err, req, res, next) => {
|
|
136
138
|
console.error(err.stack);
|
|
137
|
-
res.status(500).
|
|
139
|
+
res.status(500).jsonResponse({
|
|
138
140
|
message: 'Internal Server Error',
|
|
139
141
|
error: err.message,
|
|
140
142
|
documentation: 'https://docs.sylvain.pro',
|
|
@@ -199,6 +201,7 @@ app.get('/', (req, res) => {
|
|
|
199
201
|
app.get('/v1', (req, res) => {
|
|
200
202
|
res.jsonResponse({
|
|
201
203
|
version: 'v1',
|
|
204
|
+
documentation: 'https://docs.sylvain.pro/v1',
|
|
202
205
|
endpoints: {
|
|
203
206
|
get: {
|
|
204
207
|
algorithm: '/v1/algorithms?method={algorithm}&value={value}(&value2={value2})',
|
|
@@ -222,6 +225,7 @@ app.get('/v1', (req, res) => {
|
|
|
222
225
|
app.get('/v2', (req, res) => {
|
|
223
226
|
res.jsonResponse({
|
|
224
227
|
version: 'v2',
|
|
228
|
+
documentation: 'https://docs.sylvain.pro/v2',
|
|
225
229
|
endpoints: {
|
|
226
230
|
get: {
|
|
227
231
|
algorithm: '/v2/algorithms?method={algorithm}&value={value}(&value2={value2})',
|
|
@@ -255,6 +259,7 @@ app.get('/v2', (req, res) => {
|
|
|
255
259
|
app.get('/v3', (req, res) => {
|
|
256
260
|
res.jsonResponse({
|
|
257
261
|
version: 'v3',
|
|
262
|
+
documentation: 'https://docs.sylvain.pro/v3',
|
|
258
263
|
endpoints: {
|
|
259
264
|
get: {
|
|
260
265
|
algorithm: '/v3/algorithms?method={algorithm}&value={value}(&value2={value2})',
|
|
@@ -276,6 +281,7 @@ app.get('/v3', (req, res) => {
|
|
|
276
281
|
private: '/v3/chat/private'
|
|
277
282
|
},
|
|
278
283
|
hash: '/v3/hash',
|
|
284
|
+
hyperplanning: '/v3/hyperplanning',
|
|
279
285
|
tic_tac_toe: {
|
|
280
286
|
tic_tac_toe: '/v3/tic-tac-toe',
|
|
281
287
|
fetch: '/v3/tic-tac-toe/fetch'
|
|
@@ -527,6 +533,11 @@ app.get('/:version/domain', (req, res) => {
|
|
|
527
533
|
});
|
|
528
534
|
});
|
|
529
535
|
|
|
536
|
+
// GET planning error
|
|
537
|
+
app.get('/:version/hyperplanning', (req, res) => {
|
|
538
|
+
res.jsonResponse({ error: 'This endpoint only supports POST requests.' });
|
|
539
|
+
});
|
|
540
|
+
|
|
530
541
|
// GET hash error
|
|
531
542
|
app.get('/:version/hash', (req, res) => {
|
|
532
543
|
res.jsonResponse({ error: 'This endpoint only supports POST requests.' });
|
|
@@ -547,8 +558,11 @@ app.get('/:version/infos', (req, res) => {
|
|
|
547
558
|
app.get('/:version/levenshtein', (req, res) => {
|
|
548
559
|
const { str1, str2 } = req.query;
|
|
549
560
|
|
|
550
|
-
if (!str1) return res.jsonResponse({ error: 'Please provide a first string (?str1={string})' });
|
|
551
|
-
if (!str2) return res.jsonResponse({ error: 'Please provide a second string (&str2={string})' });
|
|
561
|
+
if (!str1 || typeof str1 !== 'string') return res.jsonResponse({ error: 'Please provide a first string (?str1={string})' });
|
|
562
|
+
if (!str2 || typeof str2 !== 'string') return res.jsonResponse({ error: 'Please provide a second string (&str2={string})' });
|
|
563
|
+
|
|
564
|
+
if (str1.length > 1000) return res.jsonResponse({ error: 'First string exceeds 1000 characters.' });
|
|
565
|
+
if (str2.length > 1000) return res.jsonResponse({ error: 'Second string exceeds 1000 characters.' });
|
|
552
566
|
|
|
553
567
|
const lev = (a, b) => {
|
|
554
568
|
const m = Array.from({ length: a.length + 1 }, (_, i) => [i]);
|
|
@@ -834,6 +848,7 @@ app.get('/:version/website', async (req, res) => {
|
|
|
834
848
|
res.jsonResponse({
|
|
835
849
|
versions: {
|
|
836
850
|
api: process.env.API,
|
|
851
|
+
cdn: process.env.CDN,
|
|
837
852
|
coop_api: process.env.COOP_API,
|
|
838
853
|
coop_status: process.env.COOP_STATUS,
|
|
839
854
|
chat: process.env.CHAT,
|
|
@@ -846,6 +861,7 @@ app.get('/:version/website', async (req, res) => {
|
|
|
846
861
|
gemsync: process.env.GEMSYNC,
|
|
847
862
|
gitsite: process.env.GITSITE,
|
|
848
863
|
logs: process.env.LOGS,
|
|
864
|
+
minify: process.env.MINIFY,
|
|
849
865
|
morpion: process.env.MORPION,
|
|
850
866
|
nitrogen: process.env.NITROGEN,
|
|
851
867
|
old_database: process.env.OLD_DATABASE,
|
|
@@ -935,6 +951,49 @@ app.post('/:version/chat/private', (req, res) => {
|
|
|
935
951
|
return res.jsonResponse({ error: 'Invalid or expired token.' });
|
|
936
952
|
});
|
|
937
953
|
|
|
954
|
+
// Display a planning from an ICS file
|
|
955
|
+
app.post('/:version/hyperplanning', async (req, res) => {
|
|
956
|
+
const { url, detail } = req.body;
|
|
957
|
+
|
|
958
|
+
if (!url) res.jsonResponse({ error: 'Please provide a valid ICS file URL.' });
|
|
959
|
+
|
|
960
|
+
try {
|
|
961
|
+
const response = await fetch(url);
|
|
962
|
+
if (!response.ok || !(response.headers.get('content-type') || '').includes('text/calendar')) return res.jsonResponse({ error: 'Invalid ICS file format.' });
|
|
963
|
+
|
|
964
|
+
const events = new ical.Component(ical.parse(await response.text()))
|
|
965
|
+
.getAllSubcomponents('vevent')
|
|
966
|
+
.map(e => {
|
|
967
|
+
const evt = new ical.Event(e);
|
|
968
|
+
const summary = evt.summary.split(' ').filter(part => part !== '-');
|
|
969
|
+
const start = formatDate(evt.startDate.toJSDate());
|
|
970
|
+
const end = formatDate(evt.endDate.toJSDate());
|
|
971
|
+
|
|
972
|
+
if (detail === 'full') {
|
|
973
|
+
const desc = evt.description.split('\n').map(l => l.trim());
|
|
974
|
+
const extract = (p) => (desc.find(l => l.startsWith(p)) || '').replace(p, '').trim();
|
|
975
|
+
|
|
976
|
+
return {
|
|
977
|
+
summary,
|
|
978
|
+
subject: extract('Matière :'),
|
|
979
|
+
teacher: extract('Enseignant :'),
|
|
980
|
+
classes: extract('Promotions :').split(', ').map(c => c.trim()),
|
|
981
|
+
type: extract('Salle :') || undefined,
|
|
982
|
+
start,
|
|
983
|
+
end
|
|
984
|
+
};
|
|
985
|
+
}
|
|
986
|
+
if (detail === 'list') return { summary, start, end };
|
|
987
|
+
|
|
988
|
+
return { summary: evt.summary, start, end };
|
|
989
|
+
})
|
|
990
|
+
.sort((a, b) => new Date(a.start) - new Date(b.start))
|
|
991
|
+
.filter(e => new Date(e.start) >= new Date());
|
|
992
|
+
|
|
993
|
+
res.jsonResponse(events);
|
|
994
|
+
} catch { res.jsonResponse({ error: 'Failed to parse ICS file.' }); }
|
|
995
|
+
});
|
|
996
|
+
|
|
938
997
|
// Store tic tac toe games
|
|
939
998
|
app.post('/:version/tic-tac-toe', (req, res) => {
|
|
940
999
|
const { username, move, session, game } = req.body;
|
|
@@ -972,7 +1031,7 @@ app.post('/:version/tic-tac-toe', (req, res) => {
|
|
|
972
1031
|
if (result.winner || result.tie) {
|
|
973
1032
|
setTimeout(() => delete games[game], 600000);
|
|
974
1033
|
return res.jsonResponse({
|
|
975
|
-
message: `Move sent successfully. ${result.winner ? result.winner +
|
|
1034
|
+
message: `Move sent successfully. ${result.winner ? result.winner + ' wins. ' + result.loser + ' loses.' : 'It\'s a tie.'}`,
|
|
976
1035
|
...result
|
|
977
1036
|
});
|
|
978
1037
|
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "3.
|
|
2
|
+
"version": "3.2.0",
|
|
3
3
|
"name": "@20syldev/api",
|
|
4
4
|
"description": "Node.js API with multiple features. Check the documentation at https://docs.sylvain.pro",
|
|
5
5
|
"main": "app.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"start": "node app.js",
|
|
9
|
+
"dev": "nodemon app.js",
|
|
9
10
|
"build": "npm install && node app.js",
|
|
11
|
+
"lint": "prettier --write .",
|
|
10
12
|
"upgrade:minor": "npm upgrade",
|
|
11
13
|
"upgrade:major": "npx npm-check-updates -u && npm install",
|
|
12
14
|
"upgrade:build": "npm upgrade && npm install && node app.js"
|
|
@@ -16,6 +18,7 @@
|
|
|
16
18
|
"cors": "latest",
|
|
17
19
|
"dotenv": "latest",
|
|
18
20
|
"express": "latest",
|
|
21
|
+
"ical.js": "latest",
|
|
19
22
|
"mathjs": "latest",
|
|
20
23
|
"node-fetch": "latest",
|
|
21
24
|
"prettier": "latest",
|