mirror of
https://github.com/danbulant/ssps-bot
synced 2026-06-24 17:11:50 +00:00
propojení profilů, větší podpora pro učitele
This commit is contained in:
parent
b1b82bfa5e
commit
78554b24d6
8 changed files with 224 additions and 15 deletions
146
commands/ssps/cmd.js
Normal file
146
commands/ssps/cmd.js
Normal file
|
|
@ -0,0 +1,146 @@
|
||||||
|
const commando = require("@iceprod/discord.js-commando");
|
||||||
|
const minimist = require("minimist");
|
||||||
|
const api = require("../../utils/api");
|
||||||
|
const ssps = require("../../utils/ssps-server");
|
||||||
|
const Student = require("../../utils/models/student");
|
||||||
|
const Person = require("../../utils/models/person");
|
||||||
|
const Teacher = require("../../utils/models/teacher");
|
||||||
|
|
||||||
|
module.exports = class cmd extends commando.Command {
|
||||||
|
constructor(client) {
|
||||||
|
super(client, {
|
||||||
|
name: "cmd",
|
||||||
|
memberName: "cmd",
|
||||||
|
aliases: ["run"],
|
||||||
|
group: "ssps",
|
||||||
|
description: "Runs a management command",
|
||||||
|
argsType: "multiple"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async run(msg, args) {
|
||||||
|
const argv = minimist(args, {
|
||||||
|
alias: {
|
||||||
|
help: "h"
|
||||||
|
},
|
||||||
|
string: "_"
|
||||||
|
});
|
||||||
|
|
||||||
|
/** @param {string} str */
|
||||||
|
function send(str) {
|
||||||
|
var lines = str.split("\n").map(t => t.trimRight());
|
||||||
|
while(lines[0].length === 0) lines.shift();
|
||||||
|
while(lines[lines.length - 1].length === 0) lines.pop();
|
||||||
|
var shortestTrim = lines
|
||||||
|
.map(a => a.match(/\S/) && a.match(/^\s*/)[0].length)
|
||||||
|
.filter(a => a !== null)
|
||||||
|
.reduce((a, b) => Math.min(a, b));
|
||||||
|
lines = lines.map(t => t.substr(shortestTrim));
|
||||||
|
while(lines[0].length === 0) lines.shift();
|
||||||
|
while(lines[lines.length - 1].length === 0) lines.pop();
|
||||||
|
var sentLines = [""];
|
||||||
|
for(const line of lines) {
|
||||||
|
if(sentLines[sentLines.length - 1] && sentLines[sentLines.length - 1].length + line.lenght > 2048)
|
||||||
|
sentLines[sentLines.length] = line;
|
||||||
|
else
|
||||||
|
sentLines[sentLines.length - 1] = (sentLines[sentLines.length - 1] || "") + "\n" + line;
|
||||||
|
}
|
||||||
|
return sentLines.map(t => msg.say("```\n" + t.substr(1) + "\n```"));
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(argv._[0]) {
|
||||||
|
case "help":
|
||||||
|
return send(`
|
||||||
|
Runs a simple management command without fancy argument parsing.
|
||||||
|
For help of a given command, run it with -h or --help flag.
|
||||||
|
|
||||||
|
Available commands:
|
||||||
|
help - Shows this page
|
||||||
|
connect <email> [--discord <id>] - Connects discord and user profile
|
||||||
|
teacher-connect <discord id> <email>- Connects discord and teacher profile
|
||||||
|
set-teacher-room <room> [email] - Sets teacher's homeroom
|
||||||
|
`);
|
||||||
|
case "connect":
|
||||||
|
return this.connectCmd(argv, send, msg);
|
||||||
|
case "teacher-connect":
|
||||||
|
return this.teacherConnectCmd(argv, send, msg);
|
||||||
|
case "set-teacher-room":
|
||||||
|
return send("Not yet implemented");
|
||||||
|
default:
|
||||||
|
return send(`Command ${argv._[0]} not found`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async teacherConnectCmd(argv, send, msg) {
|
||||||
|
if(argv.help) return send(`
|
||||||
|
Connects discord and teacher profile.
|
||||||
|
Owner only
|
||||||
|
|
||||||
|
Format: teacher-connect <discord id> <email>
|
||||||
|
`);
|
||||||
|
if(!this.client.isOwner(msg.author)) return send("You are not in the sudoers file, this incident will be reported.");
|
||||||
|
var discord = argv._[1];
|
||||||
|
var mail = argv._[2];
|
||||||
|
|
||||||
|
if(!/^[0-9]+$/.test(discord)) return send("Špatný discord účet");
|
||||||
|
var user = await this.client.users.fetch(discord).catch((e) => console.warn(e));
|
||||||
|
if(!user) return send("Uživatel musí být v SSPŠ discordu.");
|
||||||
|
|
||||||
|
if(!api.isTeacherMail(mail)) return send("Email má špatný formát.");
|
||||||
|
|
||||||
|
const person = await Person.findOne({
|
||||||
|
where: {
|
||||||
|
mail
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(!person) return send("Učitel nenalezen");
|
||||||
|
const teacher = await Teacher.findOne({
|
||||||
|
where: {
|
||||||
|
personId: person.id
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(!teacher) return send("Nastala neznámá chyba při hledání učitele");
|
||||||
|
person.discord = discord;
|
||||||
|
await person.save();
|
||||||
|
return send("Učitel propojen");
|
||||||
|
}
|
||||||
|
|
||||||
|
async connectCmd(argv, send, msg) {
|
||||||
|
if(argv.help) return send(`
|
||||||
|
Connects discord and user profile.
|
||||||
|
Defaults to connecting this account, use --discord <id> to connect another account.
|
||||||
|
Only bot owner can connect other discord accounts.
|
||||||
|
If there's already a connected account, it's disconnected first.
|
||||||
|
|
||||||
|
Format: connect <email> [--discord <id>]
|
||||||
|
`);
|
||||||
|
var discord = argv.discord || msg.author.id;
|
||||||
|
if(!/^[0-9]+$/.test(discord)) return send("Špatný discord účet");
|
||||||
|
var user = await this.client.users.fetch(discord).catch(() => null);
|
||||||
|
if(!user) return send("Uživatel musí být v SSPŠ discordu.");
|
||||||
|
if(argv.discord && !this.client.isOwner(msg.author)) return send("Pouze vlastník může použít --discord <id>.");
|
||||||
|
const email = argv._[1];
|
||||||
|
if(!email) return send("Chybí email");
|
||||||
|
if(!api.isStudentMail(email)) return send("Špatný email. Použijte školní email bez skola.");
|
||||||
|
|
||||||
|
const student = await Student.findOne({
|
||||||
|
where: {
|
||||||
|
id: email.split("@")[0]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(!student) return send("Student nenalezen. Momentálně je vyžadováno aby byl student registrovaný na profesní síti.");
|
||||||
|
const userClass = ssps.getClass(msg.author);
|
||||||
|
const classID = api.map[userClass];
|
||||||
|
if(student.classId !== classID) return send(`Třída neodpovídá roli na SSPŠ serveru`);
|
||||||
|
if(!student.personId) return send("Není vytvoření uživatelský profil - BUG");
|
||||||
|
const person = await Person.findOne({
|
||||||
|
where: {
|
||||||
|
id: student.personId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(person.mail !== email) return send("Student nenalezen.");
|
||||||
|
person.discord = discord;
|
||||||
|
await person.save();
|
||||||
|
return send("Propojeno");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -3,6 +3,8 @@ const { MessageEmbed, APIMessage } = require("discord.js");
|
||||||
const { DateTime } = require("luxon");
|
const { DateTime } = require("luxon");
|
||||||
const Person = require("../../utils/models/person");
|
const Person = require("../../utils/models/person");
|
||||||
const api = require("../../utils/api");
|
const api = require("../../utils/api");
|
||||||
|
const Teacher = require("../../utils/models/teacher");
|
||||||
|
const Student = require("../../utils/models/student");
|
||||||
|
|
||||||
module.exports = class profil extends commando.Command {
|
module.exports = class profil extends commando.Command {
|
||||||
constructor(client) {
|
constructor(client) {
|
||||||
|
|
@ -32,11 +34,25 @@ module.exports = class profil extends commando.Command {
|
||||||
return msg.say(embed);
|
return msg.say(embed);
|
||||||
}
|
}
|
||||||
embed.setTitle(person.name);
|
embed.setTitle(person.name);
|
||||||
if(person.avatar) embed.setThumbnail(person.avatar);
|
embed.setThumbnail(person.avatar || user.displayAvatarURL());
|
||||||
embed.setDescription(person.about);
|
if(person.about) embed.setDescription(person.about);
|
||||||
if(person.birthday) embed.addField("Narozeniny", DateTime.fromFormat(person.birthday, "yyyy-MM-dd").toFormat("dd. MM. yyyy"));
|
if(person.birthday) embed.addField("Narozeniny", DateTime.fromFormat(person.birthday, "yyyy-MM-dd").toFormat("dd. MM. yyyy"));
|
||||||
embed.addField("Email", person.mail);
|
embed.addField("Email", person.mail, true);
|
||||||
embed.addField("Typ", api.isTeacherMail(person.mail) ? "Učitel" : api.isStudentMail(person.mail) ? "Student" : "Neprestižní");
|
embed.addField("Typ", person.type === "teacher" ? "Učitel" : person.type === "student" ? "Student" : "Neprestižní", true);
|
||||||
|
if(person.discord) embed.addField("Discord", "<@" + person.discord + ">", true)
|
||||||
|
if(person.type === "teacher") {
|
||||||
|
const teacher = await Teacher.findOne({
|
||||||
|
where: { personId: person.id }
|
||||||
|
});
|
||||||
|
embed.addField("Zkratka", teacher.abbrev, true);
|
||||||
|
if(teacher.roomId) embed.addField("Místnost", teacher.roomId, true);
|
||||||
|
if(teacher.komise) embed.addField("Komise", teacher.komise, true);
|
||||||
|
} else if(person.type === "student") {
|
||||||
|
const student = await Student.findOne({
|
||||||
|
where: { personId: person.id }
|
||||||
|
});
|
||||||
|
embed.addField("Třída", api.demap[student.class]);
|
||||||
|
}
|
||||||
|
|
||||||
return msg.say(embed);
|
return msg.say(embed);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
"luxon": "^2.0.2",
|
"luxon": "^2.0.2",
|
||||||
"mariadb": "^2.5.5",
|
"mariadb": "^2.5.5",
|
||||||
|
"minimist": "^1.2.5",
|
||||||
"node-fetch": "2",
|
"node-fetch": "2",
|
||||||
"sequelize": "^6.7.0",
|
"sequelize": "^6.7.0",
|
||||||
"sqlite": "^4.0.23",
|
"sqlite": "^4.0.23",
|
||||||
|
|
|
||||||
15
utils/api.js
15
utils/api.js
|
|
@ -156,8 +156,9 @@ class ProfesniSitAPI {
|
||||||
const res = await request(`https://profesnisit.ssps.cz/user/get-user?id=${id}`);
|
const res = await request(`https://profesnisit.ssps.cz/user/get-user?id=${id}`);
|
||||||
id++;
|
id++;
|
||||||
console.log("Trying", id);
|
console.log("Trying", id);
|
||||||
if(!res || Object.values(res).every(t => t === null)) {
|
if(!res || Object.values(res).every(t => !t)) {
|
||||||
errors++;
|
errors++;
|
||||||
|
console.log("Errored", errors, "times");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
errors = 0;
|
errors = 0;
|
||||||
|
|
@ -180,9 +181,6 @@ const letterMap = {
|
||||||
"ú": "u",
|
"ú": "u",
|
||||||
"ů": "u"
|
"ů": "u"
|
||||||
};
|
};
|
||||||
function removeCestina(str) {
|
|
||||||
return str.split("").map(t => letterMap[t] || t).join("");
|
|
||||||
}
|
|
||||||
|
|
||||||
class API {
|
class API {
|
||||||
request = request;
|
request = request;
|
||||||
|
|
@ -223,11 +221,16 @@ class API {
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTeacherMail(name) {
|
buildTeacherMail(name) {
|
||||||
return `${removeCestina(name).replace(/ /g, ".")}@ssps.cz`.toLowerCase();
|
if(!Array.isArray(name)) name = name.split(" ");
|
||||||
|
return `${this.removeCestina(name[1] + " " + name[0]).replace(/ /g, ".")}@ssps.cz`.toLowerCase();
|
||||||
}
|
}
|
||||||
buildStudentMail(name, year) {
|
buildStudentMail(name, year) {
|
||||||
if(!Array.isArray(name)) name = name.split(" ");
|
if(!Array.isArray(name)) name = name.split(" ");
|
||||||
return `${removeCestina(name[1])}.${removeCestina(name[0]).substr(0,2)}.${year}@ssps.cz`.toLowerCase();
|
return `${this.removeCestina(name[1])}.${this.removeCestina(name[0]).substr(0,2)}.${year}@ssps.cz`.toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
removeCestina(str) {
|
||||||
|
return str.split("").map(t => letterMap[t] || t).join("");
|
||||||
}
|
}
|
||||||
|
|
||||||
groups = [
|
groups = [
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ if(isMain) {
|
||||||
global.config = config;
|
global.config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fetch = require("node-fetch");
|
||||||
const sequelize = require("../sequelize");
|
const sequelize = require("../sequelize");
|
||||||
const api = require("../api");
|
const api = require("../api");
|
||||||
const server = require("../ssps-server");
|
const server = require("../ssps-server");
|
||||||
|
|
@ -70,7 +71,8 @@ sequelize.afterBulkSync(async () => {
|
||||||
await Person.create({
|
await Person.create({
|
||||||
name: item.Teacher.Name,
|
name: item.Teacher.Name,
|
||||||
mail: api.buildTeacherMail(item.Teacher.Name),
|
mail: api.buildTeacherMail(item.Teacher.Name),
|
||||||
flags: 1
|
flags: 1,
|
||||||
|
type: "teacher"
|
||||||
}).catch(contextErrors(item));
|
}).catch(contextErrors(item));
|
||||||
const person = await Person.findOne({ where: { mail: api.buildTeacherMail(item.Teacher.Name) } });
|
const person = await Person.findOne({ where: { mail: api.buildTeacherMail(item.Teacher.Name) } });
|
||||||
await Teacher.create({
|
await Teacher.create({
|
||||||
|
|
@ -108,16 +110,21 @@ sequelize.afterBulkSync(async () => {
|
||||||
if(!user.email) continue;
|
if(!user.email) continue;
|
||||||
if(!user.email.endsWith("ssps.cz")) continue;
|
if(!user.email.endsWith("ssps.cz")) continue;
|
||||||
if(user.email.endsWith("@skola.ssps.cz")) user.email = user.email.replace("@skola.ssps.cz", "@ssps.cz");
|
if(user.email.endsWith("@skola.ssps.cz")) user.email = user.email.replace("@skola.ssps.cz", "@ssps.cz");
|
||||||
|
user.email = user.email.toLowerCase();
|
||||||
console.log(user.email);
|
console.log(user.email);
|
||||||
var person = await Person.findOne({
|
var [person] = await Person.findOrBuild({
|
||||||
where: {
|
where: {
|
||||||
[Op.or]: {
|
[Op.or]: {
|
||||||
mail: user.email,
|
mail: user.email,
|
||||||
name: `${user.firstName} ${user.lastName}`
|
name: `${user.firstName} ${user.lastName}`
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
defaults: {
|
||||||
|
mail: user.email,
|
||||||
|
flags: 1,
|
||||||
|
type: api.isStudentMail(user.email) ? "student" : api.isTeacherMail(user.email) ? "teacher" : null
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if(!person) person = Person.build({ mail: user.email, flags: 1 });
|
|
||||||
if(user.about) person.about = user.about;
|
if(user.about) person.about = user.about;
|
||||||
if(user.birthday) person.birthday = new Date(user.birthday);
|
if(user.birthday) person.birthday = new Date(user.birthday);
|
||||||
person.name = `${user.firstName} ${user.lastName}`;
|
person.name = `${user.firstName} ${user.lastName}`;
|
||||||
|
|
@ -144,7 +151,31 @@ sequelize.afterBulkSync(async () => {
|
||||||
await student.save();
|
await student.save();
|
||||||
}
|
}
|
||||||
} else if(api.isTeacherMail(user.email)) {
|
} else if(api.isTeacherMail(user.email)) {
|
||||||
// synced by timetables
|
const res = await fetch(`https://www.ssps.cz/ucitel/${api.removeCestina(person.name.replace(/ /g, "-").toLowerCase())}`);
|
||||||
|
console.log(`Fetching https://www.ssps.cz/ucitel/${api.removeCestina(person.name.replace(/ /g, "-").toLowerCase())}`);
|
||||||
|
if(res.status !== 200) continue;
|
||||||
|
const text = await res.text();
|
||||||
|
const teacher = await Teacher.findOne({
|
||||||
|
where: {
|
||||||
|
personId: person.id
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(!teacher) {
|
||||||
|
console.log("No teacher for", user.email);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let room = text.match(/kabinetu(?:.|\n)*?"value">((?:.|\n)*?)</)?.[1];
|
||||||
|
let komise = text.match(/Komise(?:.|\n)*?"value">((?:.|\n)*?)</)?.[1];
|
||||||
|
if(!room && !komise) continue;
|
||||||
|
room = room.trim();
|
||||||
|
komise = komise.trim();
|
||||||
|
console.log(room, komise);
|
||||||
|
await Room.create({
|
||||||
|
id: room
|
||||||
|
}, { ignoreDuplicates: true });
|
||||||
|
teacher.roomId = room;
|
||||||
|
teacher.komise = komise;
|
||||||
|
await teacher.save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log("Profesni sit synced");
|
console.log("Profesni sit synced");
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,10 @@ const Person = sequelize.define(
|
||||||
discord: {
|
discord: {
|
||||||
type: DataTypes.BIGINT
|
type: DataTypes.BIGINT
|
||||||
},
|
},
|
||||||
|
type: {
|
||||||
|
type: DataTypes.ENUM,
|
||||||
|
values: ["student", "teacher"]
|
||||||
|
},
|
||||||
flags: {
|
flags: {
|
||||||
type: DataTypes.INTEGER
|
type: DataTypes.INTEGER
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,9 @@ const Teacher = sequelize.define(
|
||||||
},
|
},
|
||||||
name: {
|
name: {
|
||||||
type: DataTypes.STRING
|
type: DataTypes.STRING
|
||||||
|
},
|
||||||
|
komise: {
|
||||||
|
type: DataTypes.STRING
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
indexes: [{
|
indexes: [{
|
||||||
|
|
|
||||||
|
|
@ -51,4 +51,9 @@ Timetable.belongsTo(Room);
|
||||||
Person.hasOne(Student);
|
Person.hasOne(Student);
|
||||||
Person.hasOne(Teacher);
|
Person.hasOne(Teacher);
|
||||||
|
|
||||||
sequelize.sync({ force: global.config.mysql.forceUpdate });
|
Teacher.belongsTo(Room);
|
||||||
|
|
||||||
|
sequelize.sync({
|
||||||
|
force: global.config.mysql.forceUpdate,
|
||||||
|
alter: global.config.mysql.update
|
||||||
|
});
|
||||||
Loading…
Reference in a new issue