Commit | Line | Data |
---|---|---|
c5c47010 BA |
1 | const db = require("../utils/database"); |
2 | const genToken = require("../utils/tokenGenerator"); | |
3 | const params = require("../config/parameters"); | |
4 | const 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 | 18 | const UserModel = |
8d7e2786 | 19 | { |
dac39588 BA |
20 | checkNameEmail: function(o) |
21 | { | |
866842c3 | 22 | return ( |
188b4a8f BA |
23 | (!o.name || !!(o.name.match(/^[\w-]+$/))) && |
24 | (!o.email || !!(o.email.match(/^[\w.+-]+@[\w.+-]+$/))) | |
866842c3 | 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 | 164 | module.exports = UserModel; |