mirror of
https://github.com/danbulant/ssps-bot
synced 2026-06-14 11:51:17 +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 Person = require("../../utils/models/person");
|
||||
const api = require("../../utils/api");
|
||||
const Teacher = require("../../utils/models/teacher");
|
||||
const Student = require("../../utils/models/student");
|
||||
|
||||
module.exports = class profil extends commando.Command {
|
||||
constructor(client) {
|
||||
|
|
@ -32,11 +34,25 @@ module.exports = class profil extends commando.Command {
|
|||
return msg.say(embed);
|
||||
}
|
||||
embed.setTitle(person.name);
|
||||
if(person.avatar) embed.setThumbnail(person.avatar);
|
||||
embed.setDescription(person.about);
|
||||
embed.setThumbnail(person.avatar || user.displayAvatarURL());
|
||||
if(person.about) embed.setDescription(person.about);
|
||||
if(person.birthday) embed.addField("Narozeniny", DateTime.fromFormat(person.birthday, "yyyy-MM-dd").toFormat("dd. MM. yyyy"));
|
||||
embed.addField("Email", person.mail);
|
||||
embed.addField("Typ", api.isTeacherMail(person.mail) ? "Učitel" : api.isStudentMail(person.mail) ? "Student" : "Neprestižní");
|
||||
embed.addField("Email", person.mail, true);
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
"js-yaml": "^4.1.0",
|
||||
"luxon": "^2.0.2",
|
||||
"mariadb": "^2.5.5",
|
||||
"minimist": "^1.2.5",
|
||||
"node-fetch": "2",
|
||||
"sequelize": "^6.7.0",
|
||||
"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}`);
|
||||
id++;
|
||||
console.log("Trying", id);
|
||||
if(!res || Object.values(res).every(t => t === null)) {
|
||||
if(!res || Object.values(res).every(t => !t)) {
|
||||
errors++;
|
||||
console.log("Errored", errors, "times");
|
||||
continue;
|
||||
}
|
||||
errors = 0;
|
||||
|
|
@ -180,9 +181,6 @@ const letterMap = {
|
|||
"ú": "u",
|
||||
"ů": "u"
|
||||
};
|
||||
function removeCestina(str) {
|
||||
return str.split("").map(t => letterMap[t] || t).join("");
|
||||
}
|
||||
|
||||
class API {
|
||||
request = request;
|
||||
|
|
@ -223,11 +221,16 @@ class API {
|
|||
}
|
||||
|
||||
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) {
|
||||
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 = [
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ if(isMain) {
|
|||
global.config = config;
|
||||
}
|
||||
|
||||
const fetch = require("node-fetch");
|
||||
const sequelize = require("../sequelize");
|
||||
const api = require("../api");
|
||||
const server = require("../ssps-server");
|
||||
|
|
@ -70,7 +71,8 @@ sequelize.afterBulkSync(async () => {
|
|||
await Person.create({
|
||||
name: item.Teacher.Name,
|
||||
mail: api.buildTeacherMail(item.Teacher.Name),
|
||||
flags: 1
|
||||
flags: 1,
|
||||
type: "teacher"
|
||||
}).catch(contextErrors(item));
|
||||
const person = await Person.findOne({ where: { mail: api.buildTeacherMail(item.Teacher.Name) } });
|
||||
await Teacher.create({
|
||||
|
|
@ -108,16 +110,21 @@ sequelize.afterBulkSync(async () => {
|
|||
if(!user.email) 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");
|
||||
user.email = user.email.toLowerCase();
|
||||
console.log(user.email);
|
||||
var person = await Person.findOne({
|
||||
var [person] = await Person.findOrBuild({
|
||||
where: {
|
||||
[Op.or]: {
|
||||
mail: user.email,
|
||||
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.birthday) person.birthday = new Date(user.birthday);
|
||||
person.name = `${user.firstName} ${user.lastName}`;
|
||||
|
|
@ -144,7 +151,31 @@ sequelize.afterBulkSync(async () => {
|
|||
await student.save();
|
||||
}
|
||||
} 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");
|
||||
|
|
|
|||
|
|
@ -27,6 +27,10 @@ const Person = sequelize.define(
|
|||
discord: {
|
||||
type: DataTypes.BIGINT
|
||||
},
|
||||
type: {
|
||||
type: DataTypes.ENUM,
|
||||
values: ["student", "teacher"]
|
||||
},
|
||||
flags: {
|
||||
type: DataTypes.INTEGER
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,9 @@ const Teacher = sequelize.define(
|
|||
},
|
||||
name: {
|
||||
type: DataTypes.STRING
|
||||
},
|
||||
komise: {
|
||||
type: DataTypes.STRING
|
||||
}
|
||||
}, {
|
||||
indexes: [{
|
||||
|
|
|
|||
|
|
@ -51,4 +51,9 @@ Timetable.belongsTo(Room);
|
|||
Person.hasOne(Student);
|
||||
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