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