larvituser 0.19.0 → 0.20.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +74 -99
- package/dbmigration/2.js +18 -57
- package/dist/dataWriter.d.ts +27 -0
- package/dist/dataWriter.d.ts.map +1 -0
- package/dist/dataWriter.js +204 -0
- package/dist/dataWriter.js.map +1 -0
- package/dist/helpers.d.ts +19 -0
- package/dist/helpers.d.ts.map +1 -0
- package/dist/helpers.js +60 -0
- package/dist/helpers.js.map +1 -0
- package/dist/index.d.ts +156 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +418 -0
- package/dist/index.js.map +1 -0
- package/dist/userBase.d.ts +53 -0
- package/dist/userBase.d.ts.map +1 -0
- package/dist/userBase.js +120 -0
- package/dist/userBase.js.map +1 -0
- package/dist/users.d.ts +43 -0
- package/dist/users.d.ts.map +1 -0
- package/dist/users.js +186 -0
- package/dist/users.js.map +1 -0
- package/package.json +28 -12
- package/.eslintignore +0 -1
- package/.eslintrc +0 -35
- package/.travis.yml +0 -22
- package/config/db_travis.json +0 -9
- package/dataWriter.js +0 -716
- package/helpers.js +0 -110
- package/index.js +0 -953
- package/renovate.json +0 -9
- package/test/00test.js +0 -850
- package/test/98lint.js +0 -9
- package/users.js +0 -281
package/README.md
CHANGED
|
@@ -9,17 +9,15 @@ User module for node.js
|
|
|
9
9
|
First fire up the library connections like this:
|
|
10
10
|
|
|
11
11
|
```javascript
|
|
12
|
-
const
|
|
13
|
-
Intercom
|
|
14
|
-
winston
|
|
15
|
-
log
|
|
12
|
+
const UserLib = require('larvituser'),
|
|
13
|
+
Intercom = require('larvitamintercom'),
|
|
14
|
+
winston = require('winston'),
|
|
15
|
+
log = winston.createLogger({'transports': [new winston.transports.Console()]}),
|
|
16
16
|
userLib = new UserLib({
|
|
17
|
-
'db':
|
|
17
|
+
'db': require('larvitdb'),
|
|
18
18
|
|
|
19
19
|
// Optional parameters
|
|
20
|
-
'
|
|
21
|
-
'intercom': new Intercom({'conStr': 'loopback interface', 'log': log}),
|
|
22
|
-
'log': log
|
|
20
|
+
'log': log
|
|
23
21
|
});
|
|
24
22
|
|
|
25
23
|
db.setup(...); // See https://github.com/larvit/larvitdb for configuration details
|
|
@@ -29,94 +27,77 @@ Create a new user in the database, do like this:
|
|
|
29
27
|
|
|
30
28
|
```javascript
|
|
31
29
|
const userData = {
|
|
32
|
-
'firstname':
|
|
33
|
-
'lastname':
|
|
30
|
+
'firstname': 'Nisse',
|
|
31
|
+
'lastname': 'Nilsson',
|
|
34
32
|
'role': [
|
|
35
33
|
'user',
|
|
36
34
|
'subscriber'
|
|
37
35
|
]
|
|
38
36
|
}
|
|
39
37
|
|
|
40
|
-
userLib.create('myUsername', 'myPassword', userData
|
|
41
|
-
|
|
42
|
-
});
|
|
38
|
+
const user = await userLib.create('myUsername', 'myPassword', userData);
|
|
39
|
+
console.log('New user UUID: ' + user.uuid);
|
|
43
40
|
```
|
|
44
41
|
|
|
45
42
|
When creating a new user you can also give the user a uuid of your choice:
|
|
46
43
|
|
|
47
44
|
```javascript
|
|
48
45
|
|
|
49
|
-
const uuidLib
|
|
46
|
+
const uuidLib = require('uuid');
|
|
50
47
|
const uuid = uuidLib.v1();
|
|
51
48
|
const userData = {
|
|
52
|
-
'firstname':
|
|
53
|
-
'lastname':
|
|
49
|
+
'firstname': 'Nisse',
|
|
50
|
+
'lastname': 'Nilsson',
|
|
54
51
|
'role': [
|
|
55
52
|
'user',
|
|
56
53
|
'subscriber'
|
|
57
54
|
]
|
|
58
55
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
console.log('New user UUID: ' + user.uuid);
|
|
62
|
-
});
|
|
56
|
+
const user = await userLib.create('myUsername', 'myPassword', userData, uuid);
|
|
57
|
+
console.log('New user UUID: ' + user.uuid);
|
|
63
58
|
```
|
|
64
59
|
|
|
65
60
|
To fetch a user from database based on username and password, do like this:
|
|
66
61
|
|
|
67
62
|
```javascript
|
|
68
|
-
userLib.fromUserAndPass('myUsername', 'myPassword'
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
// No match found, or other more serious error
|
|
75
|
-
} else {
|
|
76
|
-
console.log('Fetched user ID: ' + user.id);
|
|
77
|
-
}
|
|
78
|
-
});
|
|
63
|
+
const user = await userLib.fromUserAndPass('myUsername', 'myPassword');
|
|
64
|
+
if ( ! user) {
|
|
65
|
+
// No match found, or other more serious error
|
|
66
|
+
} else {
|
|
67
|
+
console.log('Fetched user ID: ' + user.id);
|
|
68
|
+
}
|
|
79
69
|
```
|
|
80
70
|
|
|
81
71
|
List multiple users
|
|
82
72
|
|
|
83
73
|
```javascript
|
|
84
|
-
const
|
|
74
|
+
const users = new UserLib.Users({'db': db, 'log': log});
|
|
85
75
|
|
|
86
|
-
users.get(
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
console.log(userList); // An array of objects
|
|
90
|
-
});
|
|
76
|
+
const result = await users.get();
|
|
77
|
+
console.log(result.users); // An array of objects
|
|
91
78
|
```
|
|
92
79
|
|
|
93
80
|
Get distinct values for field from all users
|
|
94
81
|
|
|
95
82
|
```javascript
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
users.getFieldData('fieldName', function (err, result) {
|
|
99
|
-
if (err) throw err;
|
|
83
|
+
const users = new UserLib.Users({'db': db, 'log': log});
|
|
100
84
|
|
|
101
|
-
|
|
102
|
-
|
|
85
|
+
const result = await users.getFieldData('fieldName');
|
|
86
|
+
console.log(result); // An array of strings
|
|
103
87
|
```
|
|
104
88
|
|
|
105
89
|
List multiple users ordered by field
|
|
106
90
|
|
|
107
91
|
```javascript
|
|
108
|
-
const
|
|
92
|
+
const users = new UserLib.Users({'db': db, 'log': log});
|
|
109
93
|
|
|
110
94
|
users.order = {
|
|
111
95
|
by: 'username', // Sorting by something else than uuid or username the field needs to be included in "returnFields"
|
|
112
96
|
direction: 'desc' // "asc" is default
|
|
113
97
|
}
|
|
114
98
|
|
|
115
|
-
users.get(
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
console.log(userList); // An array of objects
|
|
119
|
-
});
|
|
99
|
+
const result = await users.get();
|
|
100
|
+
console.log(result.users); // An array of objects
|
|
120
101
|
```
|
|
121
102
|
|
|
122
103
|
### Advanced usage
|
|
@@ -124,33 +105,26 @@ users.get(function (err, userList) {
|
|
|
124
105
|
#### Add data to a user
|
|
125
106
|
|
|
126
107
|
```javascript
|
|
127
|
-
userLib.addUserDataField(userUuid, fieldName, fieldValue
|
|
128
|
-
// Field have been added
|
|
129
|
-
});
|
|
108
|
+
await userLib.addUserDataField(userUuid, fieldName, fieldValue);
|
|
130
109
|
```
|
|
131
110
|
|
|
132
111
|
#### Check a password for validity
|
|
133
112
|
|
|
134
113
|
```javascript
|
|
135
|
-
userLib.checkPassword('passwordToTest', 'theHashToTestAgainst'
|
|
136
|
-
// Result being either true or false
|
|
137
|
-
});
|
|
114
|
+
const isValid = await userLib.checkPassword('passwordToTest', 'theHashToTestAgainst');
|
|
138
115
|
```
|
|
139
116
|
|
|
140
117
|
#### Create a new user
|
|
141
118
|
|
|
142
119
|
```javascript
|
|
143
|
-
userLib.create('username', 'password', {'firstname': 'John', 'lastname': 'Smith'}
|
|
144
|
-
console.log(user.uuid); // 91f15599-c1fa-4051-9e0e-906cab9819fe (or rather, a random Uuid)
|
|
145
|
-
});
|
|
120
|
+
const user = await userLib.create('username', 'password', {'firstname': 'John', 'lastname': 'Smith'});console.log(user.uuid); // 91f15599-c1fa-4051-9e0e-906cab9819fe (or rather, a random Uuid)
|
|
146
121
|
```
|
|
147
122
|
|
|
148
123
|
Or set an Uuid manually like this:
|
|
149
124
|
|
|
150
125
|
```javascript
|
|
151
|
-
userLib.create('username', 'password', {'firstname': 'John', 'lastname': 'Smith'}, 'f9684592-b245-42fa-88c6-9f16b9236ac3'
|
|
152
|
-
|
|
153
|
-
});
|
|
126
|
+
const user = await userLib.create('username', 'password', {'firstname': 'John', 'lastname': 'Smith'}, 'f9684592-b245-42fa-88c6-9f16b9236ac3');
|
|
127
|
+
console.log(user.uuid); // f9684592-b245-42fa-88c6-9f16b9236ac3
|
|
154
128
|
```
|
|
155
129
|
|
|
156
130
|
#### Fetch a user based on a field
|
|
@@ -158,9 +132,8 @@ userLib.create('username', 'password', {'firstname': 'John', 'lastname': 'Smith'
|
|
|
158
132
|
Will fetch the first occurance in the database with this field name and field value.
|
|
159
133
|
|
|
160
134
|
```javascript
|
|
161
|
-
userLib.fromField('firstname', 'John'
|
|
162
|
-
|
|
163
|
-
});
|
|
135
|
+
const user = await userLib.fromField('firstname', 'John');
|
|
136
|
+
console.log(user.uuid); // f9684592-b245-42fa-88c6-9f16b9236ac3
|
|
164
137
|
```
|
|
165
138
|
|
|
166
139
|
#### Fetch a user based on several fields
|
|
@@ -168,33 +141,29 @@ userLib.fromField('firstname', 'John', function (err, user) {
|
|
|
168
141
|
Will fetch the first occurance in the database that matches all these field names and field values
|
|
169
142
|
|
|
170
143
|
```javascript
|
|
171
|
-
userLib.fromFields({'firstname': 'John', 'lastname': 'Smith'}
|
|
172
|
-
|
|
173
|
-
});
|
|
144
|
+
const user = await userLib.fromFields({'firstname': 'John', 'lastname': 'Smith'});
|
|
145
|
+
console.log(user.uuid); // f9684592-b245-42fa-88c6-9f16b9236ac3
|
|
174
146
|
```
|
|
175
147
|
|
|
176
148
|
#### Fetch a user based on just username
|
|
177
149
|
|
|
178
150
|
```javascript
|
|
179
|
-
userLib.fromUsername('username'
|
|
180
|
-
|
|
181
|
-
});
|
|
151
|
+
const user = await userLib.fromUsername('username');
|
|
152
|
+
console.log(user.uuid); // f9684592-b245-42fa-88c6-9f16b9236ac3 or user will be false if no user is found
|
|
182
153
|
```
|
|
183
154
|
|
|
184
155
|
#### Fetch a user from Uuid
|
|
185
156
|
|
|
186
157
|
```javascript
|
|
187
|
-
userLib.fromUuid('f9684592-b245-42fa-88c6-9f16b9236ac3'
|
|
188
|
-
|
|
189
|
-
});
|
|
158
|
+
const user = await userLib.fromUuid('f9684592-b245-42fa-88c6-9f16b9236ac3');
|
|
159
|
+
console.log(user.uuid); // f9684592-b245-42fa-88c6-9f16b9236ac3
|
|
190
160
|
```
|
|
191
161
|
|
|
192
162
|
#### Get field data from a user
|
|
193
163
|
|
|
194
164
|
```javascript
|
|
195
|
-
userLib.getFieldData('f9684592-b245-42fa-88c6-9f16b9236ac3', 'firstname'
|
|
196
|
-
|
|
197
|
-
});
|
|
165
|
+
const data = await userLib.getFieldData('f9684592-b245-42fa-88c6-9f16b9236ac3', 'firstname');
|
|
166
|
+
console.log(data); // ['John'] - Observe this will always be an array with values, since a field can hold several values
|
|
198
167
|
```
|
|
199
168
|
|
|
200
169
|
#### Replace user fields for a user
|
|
@@ -202,58 +171,64 @@ userLib.getFieldData('f9684592-b245-42fa-88c6-9f16b9236ac3', 'firstname', functi
|
|
|
202
171
|
IMPORTANT!!! Will clear all data not given in the fields parameter
|
|
203
172
|
|
|
204
173
|
```javascript
|
|
205
|
-
userLib.replaceUserFields('f9684592-b245-42fa-88c6-9f16b9236ac3', {'lastname': ['Smith', 'Johnsson']}
|
|
206
|
-
|
|
207
|
-
|
|
174
|
+
await userLib.replaceUserFields('f9684592-b245-42fa-88c6-9f16b9236ac3', {'lastname': ['Smith', 'Johnsson']});
|
|
175
|
+
// The field "lastname" will now be replaced with the two values "Smith" and "Johnsson"
|
|
176
|
+
// And all other fields will be removed
|
|
208
177
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
});
|
|
212
|
-
});
|
|
178
|
+
const data = await userLib.getFieldData('f9684592-b245-42fa-88c6-9f16b9236ac3', 'lastname');
|
|
179
|
+
console.log(data); // ['Smith', 'Johnsson']
|
|
213
180
|
```
|
|
214
181
|
|
|
215
182
|
#### Remove a field from a user
|
|
216
183
|
|
|
217
184
|
```javascript
|
|
218
|
-
userLib.rmUserField('f9684592-b245-42fa-88c6-9f16b9236ac3', 'lastname'
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
});
|
|
222
|
-
});
|
|
185
|
+
await userLib.rmUserField('f9684592-b245-42fa-88c6-9f16b9236ac3', 'lastname');
|
|
186
|
+
const user = await userLib.fromUuid('f9684592-b245-42fa-88c6-9f16b9236ac3');
|
|
187
|
+
console.log(user.fields); // {'firstname': ['John']}
|
|
223
188
|
```
|
|
224
189
|
|
|
225
190
|
#### Set password for a user
|
|
226
191
|
|
|
227
192
|
```javascript
|
|
228
|
-
userLib.setPassword('f9684592-b245-42fa-88c6-9f16b9236ac3', 'newSuperSecretPwd'
|
|
229
|
-
// Now the users password is updated to "newSuperSecretPwd"
|
|
230
|
-
});
|
|
193
|
+
await userLib.setPassword('f9684592-b245-42fa-88c6-9f16b9236ac3', 'newSuperSecretPwd');
|
|
231
194
|
```
|
|
232
195
|
|
|
233
196
|
To disable a login, use boolean false as the new password:
|
|
234
197
|
|
|
235
198
|
```javascript
|
|
236
|
-
userLib.setPassword('f9684592-b245-42fa-88c6-9f16b9236ac3', false
|
|
237
|
-
// This user can no longer login
|
|
238
|
-
});
|
|
199
|
+
await userLib.setPassword('f9684592-b245-42fa-88c6-9f16b9236ac3', false);
|
|
239
200
|
```
|
|
240
201
|
|
|
241
202
|
#### Set username for a user
|
|
242
203
|
|
|
243
204
|
```javascript
|
|
244
|
-
userLib.setUsername('f9684592-b245-42fa-88c6-9f16b9236ac3', 'theNewUsername'
|
|
245
|
-
|
|
246
|
-
|
|
205
|
+
await userLib.setUsername('f9684592-b245-42fa-88c6-9f16b9236ac3', 'theNewUsername');
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Errors
|
|
209
|
+
All functions in the API will throw an exception upon error.
|
|
210
|
+
|
|
211
|
+
For instance:
|
|
212
|
+
|
|
213
|
+
```javascript
|
|
214
|
+
const user1 = await userLib.create('nisse', false);
|
|
215
|
+
const user2 = await userLib.create('olle', false);
|
|
216
|
+
|
|
217
|
+
try {
|
|
218
|
+
await user2.setUsername('nisse'); // Will throw since username "nisse" is already taken
|
|
219
|
+
} catch (err) {
|
|
220
|
+
console.error(err);
|
|
221
|
+
}
|
|
247
222
|
```
|
|
248
223
|
|
|
249
224
|
## Tests
|
|
250
225
|
|
|
251
|
-
Run tests with
|
|
226
|
+
Run tests with ```npm test```, make sure to have an empty database configured for tests to pass correctly!
|
|
252
227
|
|
|
253
228
|
The default config file will be _application path_/config/db_test.json
|
|
254
229
|
|
|
255
230
|
Or a custom one can be used by running
|
|
256
231
|
|
|
257
232
|
```bash
|
|
258
|
-
|
|
233
|
+
DBCONFFILE=/path/to/config/db_another.json mocha test/test.js
|
|
259
234
|
```
|
package/dbmigration/2.js
CHANGED
|
@@ -1,63 +1,24 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
async = require('async'),
|
|
5
|
-
db = require('larvitdb');
|
|
3
|
+
const uuidLib = require('uuid');
|
|
6
4
|
|
|
7
|
-
exports = module.exports =
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
/* Create example data to test this migration against existing data * /
|
|
11
|
-
let userUuid = uuidLib.v1();
|
|
12
|
-
let username = 'fomme';
|
|
13
|
-
tasks.push(function (cb) {
|
|
14
|
-
db.query('INSERT INTO user_data_fields (name) VALUES(\'foo\'),(\'bar\');', cb);
|
|
15
|
-
});
|
|
16
|
-
tasks.push(function (cb) {
|
|
17
|
-
db.query('INSERT INTO user_users (uuid, username, password) VALUES(UNHEX(?),?,?);', [userUuid.replace(/-/g, ''), username, 'false'], cb);
|
|
18
|
-
});
|
|
19
|
-
tasks.push(function (cb) {
|
|
20
|
-
const sql = 'INSERT INTO user_users_data (userUuid, fieldId, data) SELECT UNHEX(\'' + userUuid.replace(/-/g, '') + '\'), id, \'mepp\' FROM user_data_fields WHERE name = \'foo\';';
|
|
21
|
-
|
|
22
|
-
db.query(sql, cb);
|
|
23
|
-
});
|
|
24
|
-
tasks.push(function (cb) {
|
|
25
|
-
const sql = 'INSERT INTO user_users_data (userUuid, fieldId, data) SELECT UNHEX(\'' + userUuid.replace(/-/g, '') + '\'), id, \'waff\' FROM user_data_fields WHERE name = \'bar\';';
|
|
26
|
-
|
|
27
|
-
db.query(sql, cb);
|
|
28
|
-
});/**/
|
|
5
|
+
exports = module.exports = async options => {
|
|
6
|
+
const {db} = options;
|
|
29
7
|
|
|
30
8
|
// Migrate stuff
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
async.parallel(tasks, cb);
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
tasks.push(function (cb) { db.query('ALTER TABLE `user_users_data` ADD `fieldUuid` binary(16) NOT NULL AFTER `userUuid`;', cb); });
|
|
54
|
-
tasks.push(function (cb) { db.query('UPDATE user_users_data uud SET fieldUuid = (SELECT uuid FROM user_data_fields WHERE id = uud.fieldId)', cb); });
|
|
55
|
-
tasks.push(function (cb) { db.query('ALTER TABLE `user_users_data` DROP FOREIGN KEY `user_users_data_ibfk_2`;', cb); });
|
|
56
|
-
tasks.push(function (cb) { db.query('ALTER TABLE `user_users_data` DROP `id`, DROP `fieldId`;', cb); });
|
|
57
|
-
tasks.push(function (cb) { db.query('ALTER TABLE `user_data_fields` DROP `id`;', cb); });
|
|
58
|
-
tasks.push(function (cb) { db.query('ALTER TABLE `user_data_fields` ADD PRIMARY KEY `uuid` (`uuid`);', cb); });
|
|
59
|
-
tasks.push(function (cb) { db.query('ALTER TABLE `user_users_data` ADD FOREIGN KEY (`fieldUuid`) REFERENCES `user_data_fields` (`uuid`) ON DELETE NO ACTION ON UPDATE NO ACTION;', cb); });
|
|
60
|
-
tasks.push(function (cb) { db.query('ALTER TABLE `user_users_data` DROP INDEX `userUuid_fieldId`;', cb); });
|
|
61
|
-
|
|
62
|
-
async.series(tasks, cb);
|
|
9
|
+
await db.query('ALTER TABLE `user_data_fields` ADD `uuid` binary(16) NOT NULL FIRST;');
|
|
10
|
+
|
|
11
|
+
const {rows} = await db.query('SELECT id, name FROM user_data_fields');
|
|
12
|
+
for (const row of rows) {
|
|
13
|
+
await db.query('UPDATE user_data_fields SET uuid = UNHEX(?) WHERE id = ?;', [uuidLib.v1().replace(/-/g, ''), row.id]);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
await db.query('ALTER TABLE `user_users_data` ADD `fieldUuid` binary(16) NOT NULL AFTER `userUuid`;');
|
|
17
|
+
await db.query('UPDATE user_users_data uud SET fieldUuid = (SELECT uuid FROM user_data_fields WHERE id = uud.fieldId)');
|
|
18
|
+
await db.query('ALTER TABLE `user_users_data` DROP FOREIGN KEY `user_users_data_ibfk_2`;');
|
|
19
|
+
await db.query('ALTER TABLE `user_users_data` DROP `id`, DROP `fieldId`;');
|
|
20
|
+
await db.query('ALTER TABLE `user_data_fields` DROP `id`;');
|
|
21
|
+
await db.query('ALTER TABLE `user_data_fields` ADD PRIMARY KEY `uuid` (`uuid`);');
|
|
22
|
+
await db.query('ALTER TABLE `user_users_data` ADD FOREIGN KEY (`fieldUuid`) REFERENCES `user_data_fields` (`uuid`) ON DELETE NO ACTION ON UPDATE NO ACTION;');
|
|
23
|
+
await db.query('ALTER TABLE `user_users_data` DROP INDEX `userUuid_fieldId`;');
|
|
63
24
|
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { LogInstance } from 'larvitutils';
|
|
2
|
+
export declare type DataWriterOptions = {
|
|
3
|
+
log?: LogInstance;
|
|
4
|
+
db: any;
|
|
5
|
+
};
|
|
6
|
+
export declare class DataWriter {
|
|
7
|
+
private lUtils;
|
|
8
|
+
private helpers;
|
|
9
|
+
private log;
|
|
10
|
+
private db;
|
|
11
|
+
constructor(options: DataWriterOptions);
|
|
12
|
+
runDbMigrations(scriptPath?: string): Promise<void>;
|
|
13
|
+
addUserDataFields(userUuid: string, fields: Record<string, string | string[]>): Promise<void>;
|
|
14
|
+
addUserField(name: string): Promise<void>;
|
|
15
|
+
create(user: {
|
|
16
|
+
uuid: string;
|
|
17
|
+
username: string;
|
|
18
|
+
password: string;
|
|
19
|
+
fields: Record<string, string | string[]>;
|
|
20
|
+
}): Promise<void>;
|
|
21
|
+
replaceFields(userUuid: string, fields: Record<string, string | string[]> | null): Promise<void>;
|
|
22
|
+
rmUser(userUuid: string): Promise<void>;
|
|
23
|
+
rmUserField(userUuid: string, fieldName: string): Promise<void>;
|
|
24
|
+
setPassword(userUuid: string, password: string): Promise<void>;
|
|
25
|
+
setUsername(userUuid: string, username: string): Promise<void>;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=dataWriter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dataWriter.d.ts","sourceRoot":"","sources":["../src/dataWriter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,WAAW,EAAS,MAAM,aAAa,CAAC;AAQtD,oBAAY,iBAAiB,GAAG;IAC/B,GAAG,CAAC,EAAE,WAAW,CAAC;IAClB,EAAE,EAAE,GAAG,CAAC;CACR,CAAC;AAEF,qBAAa,UAAU;IACtB,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,GAAG,CAAc;IACzB,OAAO,CAAC,EAAE,CAAM;gBAEJ,OAAO,EAAE,iBAAiB;IAahC,eAAe,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBnD,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,GAChF,OAAO,CAAC,IAAI,CAAC;IA6BV,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAczC,MAAM,CAAC,IAAI,EAAE;QAClB,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAA;KAC3F,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBX,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,GAAG,IAAI,GACnF,OAAO,CAAC,IAAI,CAAC;IAwEV,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAavC,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAY/D,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAc9D,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAUpE"}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
+
}) : (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
o[k2] = m[k];
|
|
8
|
+
}));
|
|
9
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
10
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
11
|
+
}) : function(o, v) {
|
|
12
|
+
o["default"] = v;
|
|
13
|
+
});
|
|
14
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
15
|
+
if (mod && mod.__esModule) return mod;
|
|
16
|
+
var result = {};
|
|
17
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
18
|
+
__setModuleDefault(result, mod);
|
|
19
|
+
return result;
|
|
20
|
+
};
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.DataWriter = void 0;
|
|
23
|
+
const larvitutils_1 = require("larvitutils");
|
|
24
|
+
const helpers_1 = require("./helpers");
|
|
25
|
+
const larvitdbmigration_1 = require("larvitdbmigration");
|
|
26
|
+
const uuidLib = __importStar(require("uuid"));
|
|
27
|
+
const topLogPrefix = 'larvituser: dataWriter.ts -';
|
|
28
|
+
class DataWriter {
|
|
29
|
+
constructor(options) {
|
|
30
|
+
if (!options.db)
|
|
31
|
+
throw new Error('Required option "db" not set');
|
|
32
|
+
this.db = options.db;
|
|
33
|
+
this.log = options.log ?? new larvitutils_1.Log();
|
|
34
|
+
this.lUtils = new larvitutils_1.Utils({ log: this.log });
|
|
35
|
+
this.helpers = new helpers_1.Helpers({
|
|
36
|
+
dataWriter: this,
|
|
37
|
+
log: this.log,
|
|
38
|
+
db: this.db,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
async runDbMigrations(scriptPath) {
|
|
42
|
+
// Change tablename from larvituser_db_version to users_db_version
|
|
43
|
+
// In case larvituser_db_version exists, that is.
|
|
44
|
+
// This is due to a breaking change in 0.17.0 and this was added as
|
|
45
|
+
// a patch in 0.17.1 to make applications not crash
|
|
46
|
+
const { rows } = await this.db.query('SHOW TABLES LIKE \'larvituser_db_version\'');
|
|
47
|
+
/* istanbul ignore if */ // Nasty to test
|
|
48
|
+
if (rows.length) {
|
|
49
|
+
await this.db.query('RENAME TABLE larvituser_db_version TO users_db_version');
|
|
50
|
+
}
|
|
51
|
+
const dbMigration = new larvitdbmigration_1.DbMigration({
|
|
52
|
+
dbType: 'mariadb',
|
|
53
|
+
dbDriver: this.db,
|
|
54
|
+
tableName: 'users_db_version',
|
|
55
|
+
migrationScriptPath: scriptPath ?? `${__dirname}/../dbmigration`,
|
|
56
|
+
log: this.log,
|
|
57
|
+
});
|
|
58
|
+
await dbMigration.run();
|
|
59
|
+
}
|
|
60
|
+
async addUserDataFields(userUuid, fields) {
|
|
61
|
+
const { helpers, lUtils } = this;
|
|
62
|
+
const logPrefix = `${topLogPrefix} addUserDataFields() -`;
|
|
63
|
+
let sql = 'INSERT INTO user_users_data (userUuid, fieldUuid, data) VALUES';
|
|
64
|
+
if (!Object.keys(fields).length) {
|
|
65
|
+
this.log.verbose(`${logPrefix} No fields specifed`);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const userUuidBuffer = helpers.valueOrThrow(lUtils.uuidToBuffer(userUuid), logPrefix, 'Invalid userUuid');
|
|
69
|
+
const dbValues = [];
|
|
70
|
+
for (const key in fields) {
|
|
71
|
+
const fieldUuid = helpers.valueOrThrow(await helpers.getFieldUuid(key), logPrefix, `Failed to get field uuid for: ${key}`);
|
|
72
|
+
const fieldUuidBuffer = helpers.valueOrThrow(lUtils.uuidToBuffer(fieldUuid), logPrefix, 'Invalid fieldUuid');
|
|
73
|
+
const values = (0, helpers_1.arrayify)(fields[key] ?? '');
|
|
74
|
+
for (const value of values) {
|
|
75
|
+
sql += '(?,?,?),';
|
|
76
|
+
dbValues.push(userUuidBuffer, fieldUuidBuffer, value);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
sql = sql.substring(0, sql.length - 1) + ';';
|
|
80
|
+
await this.db.query(sql, dbValues);
|
|
81
|
+
}
|
|
82
|
+
async addUserField(name) {
|
|
83
|
+
const { lUtils, helpers } = this;
|
|
84
|
+
const logPrefix = `${topLogPrefix} addUserField() -`;
|
|
85
|
+
const sql = 'INSERT IGNORE INTO user_data_fields (uuid, name) VALUES(?,?)';
|
|
86
|
+
// Check if this is already set in the database
|
|
87
|
+
const { rows } = await this.db.query('SELECT uuid FROM user_data_fields WHERE name = ?', [name]);
|
|
88
|
+
const uuid = rows.length ? lUtils.formatUuid(rows[0].uuid) : uuidLib.v1();
|
|
89
|
+
const uuidBuffer = helpers.valueOrThrow(lUtils.uuidToBuffer(uuid), logPrefix, 'Invalid field uuid');
|
|
90
|
+
await this.db.query(sql, [uuidBuffer, name]);
|
|
91
|
+
}
|
|
92
|
+
async create(user) {
|
|
93
|
+
const { helpers, lUtils } = this;
|
|
94
|
+
const logPrefix = `${topLogPrefix} create() -`;
|
|
95
|
+
const dbFields = [];
|
|
96
|
+
const sql = 'INSERT IGNORE INTO user_users (uuid, username, password) VALUES(?,?,?);';
|
|
97
|
+
const uuidBuffer = helpers.valueOrThrow(lUtils.uuidToBuffer(user.uuid), logPrefix, `Invalid user uuid supplied: "${user.uuid}`);
|
|
98
|
+
dbFields.push(uuidBuffer);
|
|
99
|
+
dbFields.push(user.username);
|
|
100
|
+
dbFields.push(user.password);
|
|
101
|
+
const results = await this.db.query(sql, dbFields);
|
|
102
|
+
if (results.rows.affectedRows === 0) {
|
|
103
|
+
const err = new Error('No user created, duplicate key on uuid: "' + user.uuid + '" or username: "' + user.username + '"');
|
|
104
|
+
this.log.warn(`${logPrefix} ${err.message}`);
|
|
105
|
+
throw err;
|
|
106
|
+
}
|
|
107
|
+
await this.addUserDataFields(user.uuid, user.fields);
|
|
108
|
+
}
|
|
109
|
+
async replaceFields(userUuid, fields) {
|
|
110
|
+
const { helpers, lUtils } = this;
|
|
111
|
+
const logPrefix = `${topLogPrefix} replaceFields() -`;
|
|
112
|
+
const userUuidBuf = helpers.valueOrThrow(lUtils.uuidToBuffer(userUuid), logPrefix, `Invalid user uuid supplied: "${userUuid}`);
|
|
113
|
+
const dbConn = await this.db.getConnection();
|
|
114
|
+
async function commitAndRelease(dbConn) {
|
|
115
|
+
await dbConn.commit();
|
|
116
|
+
await dbConn.release();
|
|
117
|
+
}
|
|
118
|
+
// Check so the user uuid is valid
|
|
119
|
+
const { rows } = await dbConn.query('SELECT * FROM user_users WHERE uuid = ?', userUuidBuf);
|
|
120
|
+
if (!rows.length) {
|
|
121
|
+
const err = new Error(`Invalid user uuid: "${userUuid}", no records found in database of this user`);
|
|
122
|
+
this.log.warn(`${logPrefix} ${err.message}`);
|
|
123
|
+
await dbConn.release();
|
|
124
|
+
throw err;
|
|
125
|
+
}
|
|
126
|
+
// Begin transaction
|
|
127
|
+
await dbConn.beginTransaction();
|
|
128
|
+
try {
|
|
129
|
+
// Clean out previous data
|
|
130
|
+
await dbConn.query('DELETE FROM user_users_data WHERE userUuid = ?', [userUuidBuf]);
|
|
131
|
+
// Get field uuids
|
|
132
|
+
if (!fields) {
|
|
133
|
+
await commitAndRelease(dbConn);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const fieldNamesToUuidBufs = {};
|
|
137
|
+
for (const fieldName of Object.keys(fields)) {
|
|
138
|
+
const fieldUuid = helpers.valueOrThrow(await helpers.getFieldUuid(fieldName, dbConn), logPrefix, `Invalid field uuid for field: ${fieldName}`);
|
|
139
|
+
const asBuffer = helpers.valueOrThrow(lUtils.uuidToBuffer(fieldUuid), logPrefix, `Failed to convert field uuid to buffer, uuid: ${fieldUuid}`);
|
|
140
|
+
fieldNamesToUuidBufs[fieldName] = asBuffer;
|
|
141
|
+
}
|
|
142
|
+
// Add new data
|
|
143
|
+
const dbFields = [];
|
|
144
|
+
let sql = 'INSERT INTO user_users_data (userUuid, fieldUuid, data) VALUES';
|
|
145
|
+
for (const fieldName of Object.keys(fields)) {
|
|
146
|
+
const fieldValues = (0, helpers_1.arrayify)(fields[fieldName]);
|
|
147
|
+
for (const fieldValue of fieldValues) {
|
|
148
|
+
sql += '(?,?,?),';
|
|
149
|
+
dbFields.push(userUuidBuf);
|
|
150
|
+
dbFields.push(fieldNamesToUuidBufs[fieldName]);
|
|
151
|
+
dbFields.push(fieldValue);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
sql = sql.substring(0, sql.length - 1) + ';';
|
|
155
|
+
if (dbFields.length) {
|
|
156
|
+
await dbConn.query(sql, dbFields);
|
|
157
|
+
}
|
|
158
|
+
await commitAndRelease(dbConn);
|
|
159
|
+
}
|
|
160
|
+
catch (_err) {
|
|
161
|
+
await dbConn.rollback();
|
|
162
|
+
await dbConn.release();
|
|
163
|
+
throw _err;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
async rmUser(userUuid) {
|
|
167
|
+
const { helpers, lUtils } = this;
|
|
168
|
+
const logPrefix = `${topLogPrefix} rmUser() -`;
|
|
169
|
+
const uuidBuffer = helpers.valueOrThrow(lUtils.uuidToBuffer(userUuid), logPrefix, 'Invalid user uuid');
|
|
170
|
+
let sql = 'DELETE FROM user_users_data WHERE userUuid = ?;';
|
|
171
|
+
await this.db.query(sql, [uuidBuffer]);
|
|
172
|
+
sql = 'DELETE FROM user_users WHERE uuid = ?;';
|
|
173
|
+
await this.db.query(sql, [uuidBuffer]);
|
|
174
|
+
}
|
|
175
|
+
async rmUserField(userUuid, fieldName) {
|
|
176
|
+
const { helpers, lUtils } = this;
|
|
177
|
+
const logPrefix = `${topLogPrefix} rmUserField() -`;
|
|
178
|
+
const userUuidBuffer = helpers.valueOrThrow(lUtils.uuidToBuffer(userUuid), logPrefix, 'Invalid user uuid');
|
|
179
|
+
const fieldUuid = helpers.valueOrThrow(await helpers.getFieldUuid(fieldName), logPrefix, `Could not get field uuid for field: ${fieldName}`);
|
|
180
|
+
const fieldUuidBuffer = helpers.valueOrThrow(lUtils.uuidToBuffer(fieldUuid), logPrefix, 'Invalid field uuid');
|
|
181
|
+
const sql = 'DELETE FROM user_users_data WHERE userUuid = ? AND fieldUuid = ?';
|
|
182
|
+
await this.db.query(sql, [userUuidBuffer, fieldUuidBuffer]);
|
|
183
|
+
}
|
|
184
|
+
async setPassword(userUuid, password) {
|
|
185
|
+
const { helpers, lUtils } = this;
|
|
186
|
+
const logPrefix = `${topLogPrefix} setPassword() -`;
|
|
187
|
+
const userUuidBuffer = helpers.valueOrThrow(lUtils.uuidToBuffer(userUuid), logPrefix, 'Invalid user uuid');
|
|
188
|
+
const dbFields = [];
|
|
189
|
+
dbFields.push(password);
|
|
190
|
+
dbFields.push(userUuidBuffer);
|
|
191
|
+
const sql = 'UPDATE user_users SET password = ? WHERE uuid = ?;';
|
|
192
|
+
await this.db.query(sql, dbFields);
|
|
193
|
+
}
|
|
194
|
+
async setUsername(userUuid, username) {
|
|
195
|
+
const { helpers, lUtils } = this;
|
|
196
|
+
const logPrefix = `${topLogPrefix} setUsername() -`;
|
|
197
|
+
const userUuidBuffer = helpers.valueOrThrow(lUtils.uuidToBuffer(userUuid), logPrefix, 'Invalid user uuid');
|
|
198
|
+
const sql = 'UPDATE user_users SET username = ? WHERE uuid = ?;';
|
|
199
|
+
const dbFields = [username, userUuidBuffer];
|
|
200
|
+
await this.db.query(sql, dbFields);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
exports.DataWriter = DataWriter;
|
|
204
|
+
//# sourceMappingURL=dataWriter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dataWriter.js","sourceRoot":"","sources":["../src/dataWriter.ts"],"names":[],"mappings":"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"}
|