Allow hyphen in username on server side + add icons for navigation
[vchess.git] / server / models / User.js
CommitLineData
c5c47010
BA
1const db = require("../utils/database");
2const genToken = require("../utils/tokenGenerator");
3const params = require("../config/parameters");
4const sendEmail = require('../utils/mailer');
8d7e2786
BA
5
6/*
7 * Structure:
8 * _id: integer
9 * name: varchar
10 * email: varchar
11 * loginToken: token on server only
12 * loginTime: datetime (validity)
13 * sessionToken: token in cookies for authentication
14 * notify: boolean (send email notifications for corr games)
83494c7f 15 * created: datetime
8d7e2786
BA
16 */
17
ab4f4bf2 18const UserModel =
8d7e2786 19{
dac39588
BA
20 checkNameEmail: function(o)
21 {
866842c3 22 return (
b9a5fe01 23 (!o.name || o.name.match(/^[\w-]+$/)) &&
866842c3
BA
24 (!o.email || o.email.match(/^[\w.+-]+@[\w.+-]+$/))
25 );
dac39588 26 },
98db2082 27
866842c3 28 create: function(name, email, notify, cb)
dac39588
BA
29 {
30 db.serialize(function() {
866842c3 31 const query =
dac39588
BA
32 "INSERT INTO Users " +
33 "(name, email, notify, created) VALUES " +
866842c3
BA
34 "('" + name + "','" + email + "'," + notify + "," + Date.now() + ")";
35 db.run(query, function(err) {
36 cb(err, {uid: this.lastID});
dac39588
BA
37 });
38 });
39 },
8d7e2786 40
866842c3 41 // Find one user by id, name, email, or token
dac39588
BA
42 getOne: function(by, value, cb)
43 {
44 const delimiter = (typeof value === "string" ? "'" : "");
45 db.serialize(function() {
46 const query =
47 "SELECT * " +
48 "FROM Users " +
49 "WHERE " + by + " = " + delimiter + value + delimiter;
50 db.get(query, cb);
51 });
52 },
8d7e2786 53
ed9c9c37
BA
54 getByIds: function(ids, cb) {
55 db.serialize(function() {
56 const query =
57 "SELECT id, name " +
1f49533d 58 "FROM Users " +
ed9c9c37
BA
59 "WHERE id IN (" + ids + ")";
60 db.all(query, cb);
61 });
1f49533d
BA
62 },
63
dac39588
BA
64 /////////
65 // MODIFY
8d7e2786 66
866842c3 67 setLoginToken: function(token, uid)
dac39588
BA
68 {
69 db.serialize(function() {
70 const query =
71 "UPDATE Users " +
866842c3 72 "SET loginToken = '" + token + "',loginTime = " + Date.now() + " " +
dac39588 73 "WHERE id = " + uid;
866842c3 74 db.run(query);
dac39588
BA
75 });
76 },
8d7e2786 77
dac39588
BA
78 // Set session token only if empty (first login)
79 // NOTE: weaker security (but avoid to re-login everywhere after each logout)
80 // TODO: option would be to reset all tokens periodically, e.g. every 3 months
58e7b94e 81 trySetSessionToken: function(uid, cb)
dac39588 82 {
dac39588 83 db.serialize(function() {
866842c3 84 let query =
dac39588
BA
85 "SELECT sessionToken " +
86 "FROM Users " +
87 "WHERE id = " + uid;
866842c3 88 db.get(query, (err,ret) => {
dac39588 89 const token = ret.sessionToken || genToken(params.token.length);
866842c3 90 query =
dac39588 91 "UPDATE Users " +
866842c3 92 // Also empty the login token to invalidate future attempts
dac39588
BA
93 "SET loginToken = NULL" +
94 (!ret.sessionToken ? (", sessionToken = '" + token + "'") : "") + " " +
95 "WHERE id = " + uid;
866842c3
BA
96 db.run(query);
97 cb(token);
dac39588
BA
98 });
99 });
100 },
ab4f4bf2 101
866842c3 102 updateSettings: function(user)
dac39588
BA
103 {
104 db.serialize(function() {
105 const query =
106 "UPDATE Users " +
107 "SET name = '" + user.name + "'" +
108 ", email = '" + user.email + "'" +
109 ", notify = " + user.notify + " " +
110 "WHERE id = " + user.id;
866842c3 111 db.run(query);
dac39588
BA
112 });
113 },
5d04793e
BA
114
115 /////////////////
116 // NOTIFICATIONS
117
fe4c7e67 118 notify: function(user, message)
5d04793e 119 {
fe4c7e67 120 const subject = "vchess.club - notification";
37ac10c2 121 const body = "Hello " + user.name + "!" + `
a749972c 122` + message;
fe4c7e67
BA
123 sendEmail(params.mail.noreply, user.email, subject, body);
124 },
125
126 tryNotify: function(id, message)
127 {
128 UserModel.getOne("id", id, (err,user) => {
866842c3
BA
129 if (!err && user.notify)
130 UserModel.notify(user, message);
2be5d614 131 });
83494c7f
BA
132 },
133
134 ////////////
135 // CLEANING
ab4f4bf2 136
83494c7f
BA
137 cleanUsersDb: function()
138 {
139 const tsNow = Date.now();
140 // 86400000 = 24 hours in milliseconds
141 const day = 86400000;
142 db.serialize(function() {
143 const query =
a97bdbda 144 "SELECT id, sessionToken, created, name, email " +
83494c7f
BA
145 "FROM Users";
146 db.all(query, (err, users) => {
147 users.forEach(u => {
a97bdbda 148 // Remove unlogged users for > 24h
83494c7f 149 if (!u.sessionToken && tsNow - u.created > day)
a97bdbda
BA
150 {
151 notify(
152 u,
153 "Your account has been deleted because " +
154 "you didn't log in for 24h after registration"
155 );
83494c7f 156 db.run("DELETE FROM Users WHERE id = " + u.id);
a97bdbda 157 }
83494c7f
BA
158 });
159 });
160 });
161 },
162}
d431028c 163
ab4f4bf2 164module.exports = UserModel;