Commit | Line | Data |
---|---|---|
8d7e2786 | 1 | var db = require("../utils/database"); |
badeb466 | 2 | var genToken = require("../utils/tokenGenerator"); |
c018b304 | 3 | var params = require("../config/parameters"); |
2be5d614 | 4 | var 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 | { | |
22 | if (typeof o.name === "string") | |
23 | { | |
24 | if (o.name.length == 0) | |
25 | return "Empty name"; | |
26 | if (!o.name.match(/^[\w]+$/)) | |
27 | return "Bad characters in name"; | |
28 | } | |
29 | if (typeof o.email === "string") | |
30 | { | |
31 | if (o.email.length == 0) | |
32 | return "Empty email"; | |
33 | if (!o.email.match(/^[\w.+-]+@[\w.+-]+$/)) | |
34 | return "Bad characters in email"; | |
35 | } | |
58e7b94e | 36 | return ""; //NOTE: not required, but more consistent... (?!) |
dac39588 | 37 | }, |
98db2082 | 38 | |
dac39588 BA |
39 | // NOTE: parameters are already cleaned (in controller), thus no sanitization here |
40 | create: function(name, email, notify, callback) | |
41 | { | |
42 | db.serialize(function() { | |
43 | const insertQuery = | |
44 | "INSERT INTO Users " + | |
45 | "(name, email, notify, created) VALUES " + | |
46 | "('" + name + "', '" + email + "', " + notify + "," + Date.now() + ")"; | |
47 | db.run(insertQuery, err => { | |
48 | if (!!err) | |
49 | return callback(err); | |
50 | db.get("SELECT last_insert_rowid() AS rowid", callback); | |
51 | }); | |
52 | }); | |
53 | }, | |
8d7e2786 | 54 | |
dac39588 BA |
55 | // Find one user (by id, name, email, or token) |
56 | getOne: function(by, value, cb) | |
57 | { | |
58 | const delimiter = (typeof value === "string" ? "'" : ""); | |
59 | db.serialize(function() { | |
60 | const query = | |
61 | "SELECT * " + | |
62 | "FROM Users " + | |
63 | "WHERE " + by + " = " + delimiter + value + delimiter; | |
64 | db.get(query, cb); | |
65 | }); | |
66 | }, | |
8d7e2786 | 67 | |
ed9c9c37 BA |
68 | getByIds: function(ids, cb) { |
69 | db.serialize(function() { | |
70 | const query = | |
71 | "SELECT id, name " + | |
1f49533d | 72 | "FROM Users " + |
ed9c9c37 BA |
73 | "WHERE id IN (" + ids + ")"; |
74 | db.all(query, cb); | |
75 | }); | |
1f49533d BA |
76 | }, |
77 | ||
dac39588 BA |
78 | ///////// |
79 | // MODIFY | |
8d7e2786 | 80 | |
dac39588 BA |
81 | setLoginToken: function(token, uid, cb) |
82 | { | |
83 | db.serialize(function() { | |
84 | const query = | |
85 | "UPDATE Users " + | |
86 | "SET loginToken = '" + token + "', loginTime = " + Date.now() + " " + | |
87 | "WHERE id = " + uid; | |
88 | db.run(query, cb); | |
89 | }); | |
90 | }, | |
8d7e2786 | 91 | |
dac39588 BA |
92 | // Set session token only if empty (first login) |
93 | // NOTE: weaker security (but avoid to re-login everywhere after each logout) | |
94 | // TODO: option would be to reset all tokens periodically, e.g. every 3 months | |
58e7b94e | 95 | trySetSessionToken: function(uid, cb) |
dac39588 BA |
96 | { |
97 | // Also empty the login token to invalidate future attempts | |
98 | db.serialize(function() { | |
99 | const querySessionToken = | |
100 | "SELECT sessionToken " + | |
101 | "FROM Users " + | |
102 | "WHERE id = " + uid; | |
103 | db.get(querySessionToken, (err,ret) => { | |
104 | if (!!err) | |
105 | return cb(err); | |
106 | const token = ret.sessionToken || genToken(params.token.length); | |
107 | const queryUpdate = | |
108 | "UPDATE Users " + | |
109 | "SET loginToken = NULL" + | |
110 | (!ret.sessionToken ? (", sessionToken = '" + token + "'") : "") + " " + | |
111 | "WHERE id = " + uid; | |
112 | db.run(queryUpdate); | |
113 | cb(null, token); | |
114 | }); | |
115 | }); | |
116 | }, | |
ab4f4bf2 | 117 | |
dac39588 BA |
118 | updateSettings: function(user, cb) |
119 | { | |
120 | db.serialize(function() { | |
121 | const query = | |
122 | "UPDATE Users " + | |
123 | "SET name = '" + user.name + "'" + | |
124 | ", email = '" + user.email + "'" + | |
125 | ", notify = " + user.notify + " " + | |
126 | "WHERE id = " + user.id; | |
127 | db.run(query, cb); | |
128 | }); | |
129 | }, | |
5d04793e BA |
130 | |
131 | ///////////////// | |
132 | // NOTIFICATIONS | |
133 | ||
fe4c7e67 | 134 | notify: function(user, message) |
5d04793e | 135 | { |
fe4c7e67 BA |
136 | const subject = "vchess.club - notification"; |
137 | const body = "Hello " + user.name + "!\n" + message; | |
138 | sendEmail(params.mail.noreply, user.email, subject, body); | |
139 | }, | |
140 | ||
141 | tryNotify: function(id, message) | |
142 | { | |
143 | UserModel.getOne("id", id, (err,user) => { | |
144 | if (!err || !user.notify) | |
145 | return; //NOTE: error is ignored here | |
146 | UserModel.notify(user, message); | |
2be5d614 | 147 | }); |
83494c7f BA |
148 | }, |
149 | ||
150 | //////////// | |
151 | // CLEANING | |
ab4f4bf2 | 152 | |
83494c7f BA |
153 | cleanUsersDb: function() |
154 | { | |
155 | const tsNow = Date.now(); | |
156 | // 86400000 = 24 hours in milliseconds | |
157 | const day = 86400000; | |
158 | db.serialize(function() { | |
159 | const query = | |
160 | "SELECT id, sessionToken, created " + | |
161 | "FROM Users"; | |
162 | db.all(query, (err, users) => { | |
163 | users.forEach(u => { | |
164 | // Remove unlogged users for >1 day | |
165 | if (!u.sessionToken && tsNow - u.created > day) | |
166 | db.run("DELETE FROM Users WHERE id = " + u.id); | |
167 | }); | |
168 | }); | |
169 | }); | |
170 | }, | |
171 | } | |
d431028c | 172 | |
ab4f4bf2 | 173 | module.exports = UserModel; |