Initial commit

This commit is contained in:
Andrew 2023-03-26 14:40:47 +07:00
commit 24f0a28a3c
25 changed files with 3190 additions and 0 deletions

245
db/index.js Normal file
View file

@ -0,0 +1,245 @@
import pgPkg from 'pg';
const { Pool } = pgPkg;
const pool = new Pool();
const parseVoter = (voter) => ({
id: parseInt(voter.id),
login: voter.login,
password: voter.password,
full_name: voter.full_name,
vgroup_id: parseInt(voter.vgroup_id),
is_admin: JSON.parse(voter.is_admin),
registration_date: voter.registration_date,
});
const parseVgroup = (vgroup) => ({
id: parseInt(vgroup.id),
name: vgroup.name,
description: vgroup.description,
});
const parseVote = (vote) => ({
id: parseInt(vote.id),
health: parseInt(vote.health),
love: parseInt(vote.love),
sex: parseInt(vote.sex),
rest: parseInt(vote.rest),
finances: parseInt(vote.finances),
meaning_of_life: parseInt(vote.meaning_of_life),
serenity: parseInt(vote.serenity),
relations: parseInt(vote.relations),
pers_growth: parseInt(vote.pers_growth),
work: parseInt(vote.work),
vote_date: vote.vote_date,
voter_id: parseInt(vote.voter_id),
});
// TODO: implement
const parseVoteResult = (voteResult) => ({
});
export class DBAccess {
static async tableExists(table) {
const res = await pool.query("SELECT 1 FROM pg_database WHERE datname = $1", [table]);
return res.rows.length > 0;
}
static async scaffold() {
await pool.query(`CREATE TABLE IF NOT EXISTS vgroup (
id SERIAL PRIMARY KEY,
name VARCHAR(50) NOT NULL,
description VARCHAR(255) NOT NULL DEFAULT ''
)`);
await pool.query(`CREATE TABLE IF NOT EXISTS voter (
id SERIAL PRIMARY KEY,
login VARCHAR(255) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
vgroup_id INT,
full_name VARCHAR(255) NOT NULL DEFAULT '',
is_admin BOOLEAN NOT NULL DEFAULT false,
registration_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT fk_vgroup FOREIGN KEY(vgroup_id) REFERENCES vgroup(id)
)`);
await pool.query(`CREATE TABLE IF NOT EXISTS vote (
id SERIAL PRIMARY KEY,
health INT NOT NULL,
love INT NOT NULL,
sex INT NOT NULL,
rest INT NOT NULL,
finances INT NOT NULL,
meaning_of_life INT NOT NULL,
serenity INT NOT NULL,
relations INT NOT NULL,
pers_growth INT NOT NULL,
work INT NOT NULL,
vote_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
voter_id INT NOT NULL,
CONSTRAINT voter FOREIGN KEY(voter_id) REFERENCES voter(id)
)`);
}
static async dropAll() {
await pool.query("DROP TABLE IF EXISTS vote");
await pool.query("DROP TABLE IF EXISTS voter");
await pool.query("DROP TABLE IF EXISTS vgroup");
}
static query(text, params, callback) {
return pool.query(text, params, callback);
}
static async queryAsync(text, params) {
return pool.query(text, params);
}
static async countVoters() {
const res = await pool.query("SELECT COUNT(*) FROM voter");
return parseInt(res.rows[0].count);
}
static async findVoterByLogin(login) {
const res = await pool.query("SELECT * FROM voter WHERE login = $1", [login]);
if (res.rows.length != 0) {
return parseVoter(res.rows[0]);
}
return null;
}
static async validateVoter(login, password) {
const res = await pool.query("SELECT * FROM voter WHERE login = $1 AND password = $2", [login, password]);
if (res.rows.length != 0) {
return parseVoter(res.rows[0]);
}
return null;
}
static async createVoter(login, password, full_name, is_admin) {
let res = await pool.query(
"INSERT INTO voter(login, password, full_name, is_admin) VALUES ($1, $2, $3, $4) RETURNING *",
[login, password, full_name, is_admin]
);
if (res.rows.length != 0) {
if (is_admin) {
let adminGroup = await pool.query("SELECT * FROM vgroup WHERE name = $1", ["admin"]);
if (adminGroup.rows.length === 0) {
adminGroup = await pool.query("INSERT INTO vgroup(name, description) VALUES ($1, $2) RETURNING *", ["admin", "Администраторы"]);
}
res = await pool.query("UPDATE voter SET vgroup_id = $1 WHERE login = $2 RETURNING *", [adminGroup.rows[0].id, login]);
}
if (res.rows.length != 0) {
return parseVoter(res.rows[0]);
}
}
return null;
}
static async getVoters() {
const res = await pool.query("SELECT * FROM voter ORDER BY registration_date");
return res.rows.map(parseVoter);
}
static async getVoterById(id) {
const res = await pool.query("SELECT * FROM voter WHERE id = $1", [id]);
if (res.rows.length != 0) {
return parseVoter(res.rows[0]);
}
return null;
}
static async deleteVoterVotes(id) {
await pool.query("DELETE FROM vote WHERE voter_id = $1", [id]);
}
static async deleteVoter(id) {
await this.deleteVoterVotes(id);
await pool.query("DELETE FROM voter WHERE id = $1", [id]);
}
static async promoteVoter(id, vgroup_id, setAdmin) {
const user = await this.getVoterById(id);
const admCount = (await this.getVoters()).reduce((acc, item) => acc + (item.is_admin ? 1 : 0), 0);
if (user) {
if (user.is_admin && admCount === 1) {
throw new Error("Нельзя удалить последнего администратора");
}
if (setAdmin) {
await pool.query("UPDATE voter SET vgroup_id = $1, is_admin = true WHERE id = $2", [vgroup_id, id]);
} else {
await pool.query("UPDATE voter SET vgroup_id = $1, is_admin = false WHERE id = $2", [vgroup_id, id]);
}
} else {
throw new Error("Такого пользователя нет");
}
}
static async getVgroups() {
const res = await pool.query("SELECT * FROM vgroup");
return res.rows.map(parseVgroup);
}
static async createVgroup(name, description) {
const res = await pool.query("INSERT INTO vgroup(name, description) VALUES ($1, $2) RETURNING *", [name, description]);
if (res.rows.length != 0) {
return parseVgroup(res.rows[0]);
}
return null;
}
static async deleteVgroup(id) {
await pool.query("DELETE FROM vgroup WHERE id = $1", [id]);
}
static async createVote(vote) {
const res = await pool.query(`INSERT INTO vote(
health, love, sex, rest, relations, pers_growth, work,
finances, meaning_of_life, serenity, voter_id
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) RETURNING *`, [
vote.health, vote.love, vote.sex, vote.rest, vote.relations, vote.pers_growth, vote.work,
vote.finances, vote.meaning_of_life, vote.serenity, vote.voter_id
]);
if (res.rows.length != 0) {
return parseVote(res.rows[0]);
}
return null;
}
static async getVotes() {
const res = await pool.query("SELECT * FROM vote ORDER BY vote.vote_date desc");
return res.rows.map(parseVote);
}
static async getVotesByVoterId(voter_id) {
const res = await pool.query("SELECT * FROM vote WHERE voter_id = $1", [voter_id]);
return res.rows.map(parseVote);
}
static async deleteVote(id) {
await pool.query("DELETE FROM vote WHERE id = $1", [id]);
}
static async getGrouppedVotes() {
const res = await pool.query(`
select
array_agg(v.health) as health, array_agg(v.love) as love, array_agg(v.sex) as sex, array_agg(v.rest) as rest, array_agg(v.finances) as finances,
array_agg(v.meaning_of_life) as meaning_of_life, array_agg(v.serenity) as serenity, array_agg(v.relations) as relations,
array_agg(v.pers_growth) as pers_growth, array_agg(v.work) as work,
v1.vgroup_id, to_char(v.vote_date, 'mm.yyyy') as vote_date
from vote as v
inner join voter v1 on v1.id = v.voter_id
group by v1.vgroup_id, to_char(v.vote_date, 'mm.yyyy')
order by to_char(v.vote_date, 'mm.yyyy') asc`.trim());
return res.rows;//.map(parseVote);
}
static async didUserBotedThisMonth(voter_id) {
const res = await pool.query("SELECT * FROM vote WHERE voter_id = $1 AND vote_date >= date_trunc('month', now())", [voter_id]);
return res.rows.length != 0;
}
static async shutdown() {
return await pool.end();
}
}