Initial commit

This commit is contained in:
Daniel Bulant 2021-10-06 08:12:14 +02:00
commit db3f0dbca5
7 changed files with 250 additions and 0 deletions

5
.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
node_modules
config.yml
package-lock.json
pnpm-lock.yaml
settings.sqlite

64
commands/ssps/rozvrh.js Normal file
View file

@ -0,0 +1,64 @@
const commando = require("@iceprod/discord.js-commando");
const { MessageEmbed } = require("discord.js");
const api = require("../../utils/api");
/**
* @typedef {T extends PromiseLike<infer U> ? U : T} Depromise
* @template T
*/
/** @type {Record<string, Depromise<ReturnType<api["getSchedule"]>>>} */
var cache = {};
var map = {
"1K": "1Y"
}
module.exports = class rozvrh extends commando.Command {
constructor(client) {
super(client, {
name: "rozvrh",
memberName: "rozvrh",
group: "ssps",
description: "Zobrazí rozvrh hodin pro danou třídu",
args: [{
key: "className",
type: "string",
prompt: "Jakou třídu chcete zvolit?",
validate(val) {
return /^[1-4]\.?[ABCKGL]$/i.test(val);
}
}]
});
}
async run(msg, { className }) {
className = className.replace(".", "").toUpperCase();
className = map[className];
if(!className) return msg.reply("Třída není podporovaná.");
if(!cache[className]) {
cache[className] = await api.getSchedule(className);
}
const date = new Date;
const dayOfWeek = (date.getDay() > 1 && date.getDay() < 6 ? date.getDay() : 1) - 1;
const schedule = cache[className].schedule[dayOfWeek];
const embed = new MessageEmbed();
embed.setTitle("Rozvrh");
for(const cellI in schedule) {
const cell = schedule[cellI];
if(!cell) {
console.log("Wut?", cellI, cell);
continue;
}
try {
embed.addField(cell.Subject.Abbrev, `${cell.Room.Abbrev} - ${cell.Teacher.Name}`);
} catch(e) {
console.warn(e, cellI, cell);
}
}
return msg.reply(embed);
}
};

View file

@ -0,0 +1,17 @@
const commando = require("@iceprod/discord.js-commando");
module.exports = class suplovani extends commando.Command {
constructor(client) {
super(client, {
name: "suplovani",
memberName: "suplovani",
group: "ssps",
description: "Zobrazí stav suplování",
args: []
});
}
run(msg) {
return msg.reply("TBD");
}
};

38
index.js Normal file
View file

@ -0,0 +1,38 @@
const Commando = require('@iceprod/discord.js-commando');
const sqlite = require('sqlite');
const sqlite3 = require("sqlite3");
const yaml = require("js-yaml");
const fs = require("fs-extra");
const path = require("path");
const config = yaml.load(fs.readFileSync("./config.yml", { encoding: "utf-8" }));
const client = new Commando.Client({
owner: '820696421912412191',
commandPrefix: "ssps!"
});
client.on("commandError", (c, e) => {
console.error(e);
});
client.on("ready", () => {
console.log("Ready");
});
client.registry
.registerGroups([
["ssps", "Příkazy pro SSPŠ"],
["nastaveni", "Nastavení bota"]
])
.registerDefaults()
.registerCommandsIn(path.join(__dirname, 'commands'));
client.setProvider(
sqlite.open({
driver: sqlite3.Database,
filename: path.join(__dirname, 'settings.sqlite3')
}).then(db => new Commando.SQLiteProvider(db))
).catch(console.error);
client.login(config.token);

11
package.json Normal file
View file

@ -0,0 +1,11 @@
{
"dependencies": {
"@iceprod/discord.js-commando": "^0.14.4",
"discord.js": "12",
"fs-extra": "^10.0.0",
"js-yaml": "^4.1.0",
"node-fetch": "2",
"sqlite": "^4.0.23",
"sqlite3": "^5.0.2"
}
}

BIN
settings.sqlite3 Normal file

Binary file not shown.

115
utils/api.js Normal file
View file

@ -0,0 +1,115 @@
const fetch = require("node-fetch");
async function request(endpoint, body) {
const res = await fetch("https://www.ssps.cz/" + endpoint, {
method: body ? "POST" : "GET",
body,
headers: {
accept: "application/json",
"user-agent": "Discord Bot (https://danbulant.eu Daniel Bulant bulant.da.2021@ssps.cz)",
"x-notes": "Zobrazeni informaci o skole v ramci Discordu"
}
});
return await res.json();
}
/**
* @typedef AbsentClass
* @property {ClassEntity} Entity
* @property {(null | "ODP")[]} Reasons
*/
/**
* @typedef ClassEntity
* @property {string} Id
* @property {string} Abbrev
*/
/**
* @typedef ChangedClass
* @property {ClassEntity} Class
* @property {ChangedLesson[]} ChangedLessons
* @property {ChangedLesson[]} CancelledLessons
* @property {string[]} ChangedGroups
*/
/**
* @typedef ChangedLesson
* @property {"supluje" | "přesun >>" | "přesun <<" | "spojí"} ChgType1
* @property {string} ChgType2
* @property {string} Hour Číslo ale ve stringu
* @property {string} Subject 3 letter code in uppercase
* @property {string} Group Empty if all
* @property {string} [Room] Room number
* @property {string} [Teacher] Teacher code (Abbrev)
*/
class Supplementations {
constructor(data) {
this.data = data;
}
getByClassName(name) {
/** @type {AbsentClass[]} */
const absent = this.data.AbsentClasses.filter(t => t.Entity.Abbrev === name);
/** @type {ChangedClass[]} */
const changed = this.data.ChangesForClasses.filter(t => t.Class.Abbrev === name);
return { absent, changed };
}
getByTeacher(abbrev) {
return this.data.ChangesForTeachers.filter(t => t.Teacher.Abbrev === abbrev || t.Teacher.Name === abbrev);
}
}
/**
* @typedef Atom
* @property {string} Id
* @property {string} Abbrev
* @property {string} Name
*/
/**
* @typedef CellAtom
* @property {Atom} Class
* @property {Atom} Group
* @property {Atom} Subject
* @property {Atom} Teacher
* @property {Atom} Room
* @property {Atom[]} Cycles
* @property {Atom[]} Stamps
*/
class Schedule {
/** @type {CellAtom[][]} */
schedule = [];
constructor(data) {
this.data = data;
for(var cell of data.Cells) {
if(!this.schedule[cell.DayIndex]) this.schedule[cell.DayIndex] = [];
this.schedule[cell.DayIndex][cell.HourIndex] = cell.Atoms;
}
}
get type() {
return this.data.Type;
}
get id() {
return this.data.TargetId;
}
}
class API {
request = request;
async getSupplementations(date = new Date) {
const res = await request(`wp-content/themes/ssps-wordpress-theme/supplementation.php/?date=${date.getFullYear()}${date.getMonth().toString().padStart(2, "0")}${date.getDate().toString().padStart(2, "0")}`);
return new Supplementations(res);
}
async getSchedule(className) {
const res = await request(`wp-content/themes/ssps-wordpress-theme/schedule.php/?class=${className}`);
return new Schedule(res);
}
}
module.exports = new API;