refactoring, better README (breaking commit...)
[qomet.git] / models / user.js
1 const params = require("../config/parameters");
2 const db = require("../utils/database");
3
4 const UserModel =
5 {
6 /*
7 * Structure:
8 * _id: BSON id
9 * ** Strings, identification informations:
10 * email
11 * name
12 * initials : computed, Benjamin Auder --> ba ...etc
13 * loginToken: {
14 * value: string
15 * timestamp: datetime (validity)
16 * ip: address of requesting machine
17 * }
18 * sessionTokens (array): cookie identification
19 */
20
21 // BASIC FUNCTIONS
22 //////////////////
23
24 getInitialsByPrefix: function(prefix, cb)
25 {
26 db.users.find(
27 { initials: new RegExp("^" + prefix) },
28 { initials: 1, _id: 0 },
29 cb
30 );
31 },
32
33 insert: function(newUser, cb)
34 {
35 db.users.insert(Object.assign({},
36 newUser,
37 {
38 loginToken: { },
39 sessionTokens: [ ],
40 }),
41 cb
42 );
43 },
44
45 getByLoginToken: function(token, cb)
46 {
47 db.users.findOne(
48 { "loginToken.value": token },
49 cb
50 );
51 },
52
53 getBySessionToken: function(token, cb)
54 {
55 db.users.findOne(
56 { sessionTokens: token},
57 cb
58 );
59 },
60
61 getById: function(uid, cb)
62 {
63 db.users.findOne(
64 { _id: uid },
65 cb
66 );
67 },
68
69 getByEmail: function(email, cb)
70 {
71 db.users.findOne(
72 { email: email },
73 cb
74 );
75 },
76
77 getByInitials: function(initials, cb)
78 {
79 db.users.findOne(
80 { initials: initials },
81 cb
82 );
83 },
84
85 getUnlogged: function(cb)
86 {
87 var tsNow = new Date().getTime();
88 // 86400000 = 24 hours in milliseconds
89 var day = 86400000;
90 db.users.find({}, (err,userArray) => {
91 let unlogged = userArray.filter( u => {
92 return u.sessionTokens.length==0 && u._id.getTimestamp().getTime() + day < tsNow;
93 });
94 cb(err, unlogged);
95 });
96 },
97
98 getAll: function(cb)
99 {
100 db.users.find({}, cb);
101 },
102
103 setLoginToken: function(token, uid, ip, cb)
104 {
105 db.users.update(
106 { _id: uid },
107 { $set: { loginToken: {
108 value: token,
109 timestamp: new Date().getTime(),
110 ip: ip,
111 }}
112 },
113 cb
114 );
115 },
116
117 setSessionToken: function(token, uid, cb)
118 {
119 // Also empty the login token to invalidate future attempts
120 db.users.update(
121 { _id: uid },
122 {
123 $set: { loginToken: {} },
124 $push: { sessionTokens: {
125 $each: [token],
126 $slice: -7 //only allow 7 simultaneous connections per user (TODO?)
127 }}
128 },
129 cb
130 );
131 },
132
133 removeToken: function(uid, token, cb)
134 {
135 db.users.update(
136 { _id: uid },
137 { $pull: {sessionTokens: token} },
138 cb
139 );
140 },
141
142 // TODO: later, allow account removal
143 remove: function(uids)
144 {
145 db.users.remove({_id: uids});
146 },
147
148 /////////////////////
149 // ADVANCED FUNCTIONS
150
151 create: function(newUser, callback)
152 {
153 // Determine initials from name parts
154 let nameParts = newUser.name.split(/[ -]+/);
155 let initials = nameParts.map( n => { return n.charAt(0).toLowerCase(); }).join("");
156 // First retrieve all users with similar prefix initials
157 UserModel.getInitialsByPrefix(initials, (err,userArray) => {
158 if (!!userArray && userArray.length == 1)
159 initials = initials + "2"; //thus number == users count for this hash
160 else if (!!userArray && userArray.length > 1)
161 {
162 // Pick the highest number after initials (if any), and increment
163 let numbers = userArray.map( u => {
164 let digitMatch = u.initials.match(/[0-9]/);
165 if (!digitMatch)
166 return 1; //irrelevant
167 let firstDigit = digitMatch.index;
168 return parseInt(u.initials.slice(digitMatch.index));
169 });
170 initials = initials + (Math.max(...numbers)+1);
171 }
172 Object.assign(newUser, {initials: initials});
173 UserModel.insert(newUser, callback);
174 });
175 },
176
177 whitelistCheck: function(email)
178 {
179 if (params.whitelist.length == 0)
180 return true; //no whitelist, everyone allowed
181 for (let w of params.whitelist)
182 {
183 if ((w.indexOf('@') >= 0 && w==email) || !!email.match(new RegExp(w+"$")))
184 return true;
185 }
186 return false;
187 },
188
189 cleanUsersDb: function()
190 {
191 UserModel.getUnlogged( (err,unlogged) => {
192 UserModel.remove(unlogged);
193 });
194 },
195 }
196
197 module.exports = UserModel;