Skip to content
This repository was archived by the owner on Jun 27, 2019. It is now read-only.

Commit 30dabc7

Browse files
added user invite service and uuid package
1 parent 1ca5e0a commit 30dabc7

File tree

12 files changed

+166
-8
lines changed

12 files changed

+166
-8
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
"shortid": "~2.2.8",
101101
"slug": "~0.9.1",
102102
"trunc-html": "^1.1.2",
103+
"uuid": "^3.3.2",
103104
"valid-url": "^1.0.9",
104105
"winston": "~3.0.0-rc5"
105106
},

server/channels.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ module.exports = function (app) {
4747
// });
4848

4949
app.service('contributions').publish('patched', () => app.channel('authenticated'));
50+
app.service('settings').publish('patched', () => app.channel('anonymous', 'authenticated'));
5051

5152
app.service('categories').publish(() => app.channel('anonymous', 'authenticated'));
5253
app.service('comments').publish(() => app.channel('authenticated'));

server/hooks/save-remote-images.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ const { isEmpty } = require('lodash');
88
const fs = require('fs');
99
const path = require('path');
1010
const request = require('request');
11-
const faker = require('faker');
1211
const mime = require('mime/lite');
1312
const validUrl = require('valid-url');
13+
const uuid = require('uuid/v1');
1414

1515
function createUploadDirIfNeeded () {
1616
const uploadDir = path.resolve('public/uploads');
@@ -60,8 +60,7 @@ module.exports = function (options = []) { // eslint-disable-line no-unused-vars
6060
loading++;
6161
imgCount++;
6262
// TODO: fix that to use the data _id or somethink similar
63-
let uuid = faker.fake('{{random.uuid}}');
64-
const imgName = `${field}_${uuid}`;
63+
const imgName = `${field}_${uuid()}`;
6564
let imgPath = path.resolve('public', 'uploads/' + imgName);
6665

6766
if (typeof hook.data[field] === 'object') {

server/models/invites.model.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// invites-model.js - A mongoose model
2-
//
2+
//
33
// See http://mongoosejs.com/docs/models.html
44
// for more of what you can do here.
55
module.exports = function (app) {
@@ -12,6 +12,7 @@ module.exports = function (app) {
1212
enum: ['admin', 'moderator', 'manager', 'editor', 'user'],
1313
default: 'user'
1414
},
15+
invitedByUserId: { type: String },
1516
language: { type: String },
1617
badgeIds: [],
1718
wasUsed: { type: Boolean },

server/services/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const usersettings = require('./usersettings/usersettings.service.js');
2222
const pages = require('./pages/pages.service.js');
2323
const systemNotifications = require('./system-notifications/system-notifications.service.js');
2424
const settings = require('./settings/settings.service.js');
25+
const userInvites = require('./user-invites/user-invites.service.js');
2526

2627
module.exports = function () {
2728
const app = this; // eslint-disable-line no-unused-vars
@@ -49,4 +50,5 @@ module.exports = function () {
4950
app.configure(pages);
5051
app.configure(systemNotifications);
5152
app.configure(settings);
53+
app.configure(userInvites);
5254
};

server/services/settings/settings.hooks.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
const { authenticate } = require('@feathersjs/authentication').hooks;
21
const isAdmin = require('../../hooks/is-admin');
32
const mapCreateToUpsert = require('../../hooks/map-create-to-upsert');
43

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/* eslint-disable no-unused-vars */
2+
const errors = require('@feathersjs/errors');
3+
const uuid = require('uuid/v1');
4+
const { genInviteCode } = require('../../helper/seed-helpers');
5+
6+
class Service {
7+
constructor (options) {
8+
this.options = options || {};
9+
if (!options.app) {
10+
throw new Error('user-invites services missing option.app');
11+
}
12+
this.app = options.app;
13+
}
14+
15+
async find (params) {
16+
if (!params.user._id) {
17+
throw new errors.Forbidden('no user id found');
18+
}
19+
const res = await this.app.service('invites').find(Object.assign(params.query || {}, {
20+
query: {
21+
$limit: 10,
22+
invitedByUserId: params.user._id
23+
}
24+
}));
25+
return res;
26+
}
27+
28+
async get (id, params) {
29+
throw new errors.NotImplemented();
30+
}
31+
32+
async create (data, params) {
33+
// 1. check user
34+
if (!params.user._id) {
35+
throw new errors.Forbidden('no used id found');
36+
}
37+
// 2. get system settings for max invite count
38+
let settings = await this.app.service('settings').find({query: {key: 'system'}});
39+
settings = settings.pop();
40+
// do cancel of the settings prohibit it
41+
if (!settings || !settings.invites || !settings.invites.userCanInvite || !settings.invites.maxInvitesByUser) {
42+
throw new errors.Forbidden('system settings not valid');
43+
}
44+
// 3. get user invite count
45+
const maxInvitesByUser = settings.invites.maxInvitesByUser;
46+
// 4. check if the user has still free invites
47+
const myInvites = await this.find(Object.assign(params, {query: { $limit: -1 }}));
48+
let remainingInvites = maxInvitesByUser - myInvites.total;
49+
if (remainingInvites <= 0) {
50+
throw new errors.Forbidden('no invites left');
51+
}
52+
// 5. generate one remaining free invites
53+
let output = [];
54+
while (remainingInvites--) {
55+
const res = await this.app.service('invites').create({
56+
email: uuid(),
57+
code: genInviteCode(),
58+
invitedByUserId: params.user._id,
59+
role: 'user'
60+
});
61+
output.push(res);
62+
}
63+
64+
return output;
65+
}
66+
67+
async update (id, data, params) {
68+
throw new errors.NotImplemented();
69+
}
70+
71+
async patch (id, data, params) {
72+
throw new errors.NotImplemented();
73+
}
74+
75+
async remove (id, params) {
76+
throw new errors.NotImplemented();
77+
}
78+
}
79+
80+
module.exports = function (options) {
81+
return new Service(options);
82+
};
83+
84+
module.exports.Service = Service;
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
const { authenticate } = require('@feathersjs/authentication').hooks;
2+
3+
module.exports = {
4+
before: {
5+
all: [ authenticate('jwt') ],
6+
find: [],
7+
get: [],
8+
create: [],
9+
update: [],
10+
patch: [],
11+
remove: []
12+
},
13+
14+
after: {
15+
all: [
16+
17+
],
18+
find: [],
19+
get: [],
20+
create: [],
21+
update: [],
22+
patch: [],
23+
remove: []
24+
},
25+
26+
error: {
27+
all: [],
28+
find: [],
29+
get: [],
30+
create: [],
31+
update: [],
32+
patch: [],
33+
remove: []
34+
}
35+
};
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Initializes the `user-invites` service on path `/user-invites`
2+
const createService = require('./user-invites.class.js');
3+
const hooks = require('./user-invites.hooks');
4+
5+
module.exports = function (app) {
6+
7+
const paginate = app.get('paginate');
8+
9+
const options = {
10+
paginate,
11+
app
12+
};
13+
14+
// Initialize our service with any options it requires
15+
app.use('/user-invites', createService(options));
16+
17+
// Get our initialized service so that we can register hooks
18+
const service = app.service('user-invites');
19+
20+
service.hooks(hooks);
21+
};

server/services/users/hooks/invite-code.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,23 @@ module.exports = function (options = {}) { // eslint-disable-line no-unused-vars
55
return {
66
before: async function (hook) {
77
// check the invite code for the given email / code combination
8-
const query = {
8+
let query = {
99
query: {
1010
email: hook.data.email,
1111
code: hook.data.inviteCode
1212
}
1313
};
14+
if (hook.data.invitedByUserId) {
15+
// invite was created
16+
delete query.query.email;
17+
query.query.invitedByUserId = hook.data.invitedByUserId;
18+
}
1419
const inviteRes = await hook.app.service('invites').find(query);
1520
// throw an error if the invite code does not match the one from the invite
1621
if (!inviteRes.data.length) {
1722
throw new errors.Forbidden('invite code is invalid');
1823
}
19-
24+
2025
// set some user data from the invite like batches and roles
2126
hook.data.wasInvited = true;
2227
hook.data.inviteId = inviteRes.data[0]._id;

0 commit comments

Comments
 (0)