mirror of
https://github.com/danbulant/ssps-bot
synced 2026-06-24 17:11:50 +00:00
Initial commit
This commit is contained in:
commit
db3f0dbca5
7 changed files with 250 additions and 0 deletions
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
node_modules
|
||||||
|
config.yml
|
||||||
|
package-lock.json
|
||||||
|
pnpm-lock.yaml
|
||||||
|
settings.sqlite
|
||||||
64
commands/ssps/rozvrh.js
Normal file
64
commands/ssps/rozvrh.js
Normal 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);
|
||||||
|
}
|
||||||
|
};
|
||||||
17
commands/ssps/suplovani.js
Normal file
17
commands/ssps/suplovani.js
Normal 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
38
index.js
Normal 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
11
package.json
Normal 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
BIN
settings.sqlite3
Normal file
Binary file not shown.
115
utils/api.js
Normal file
115
utils/api.js
Normal 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;
|
||||||
Loading…
Reference in a new issue