332 lines
7.5 KiB
JavaScript
332 lines
7.5 KiB
JavaScript
import SimpleSchema from 'simpl-schema';
|
|
import { ValidatedMethod } from 'meteor/mdg:validated-method';
|
|
import { RateLimiterMixin } from 'ddp-rate-limiter-mixin';
|
|
import '/imports/api/users/methods/deleteMyAccount.js';
|
|
import '/imports/api/users/methods/addEmail.js';
|
|
import '/imports/api/users/methods/removeEmail.js';
|
|
import '/imports/api/users/methods/updateFileStorageUsed.js';
|
|
|
|
import { some } from 'lodash';
|
|
const defaultLibraries = process.env.DEFAULT_LIBRARIES && process.env.DEFAULT_LIBRARIES.split(',') || [];
|
|
const defaultLibraryCollections = process.env.DEFAULT_LIBRARY_COLLECTIONS && process.env.DEFAULT_LIBRARY_COLLECTIONS.split(',') || [];
|
|
|
|
const userSchema = new SimpleSchema({
|
|
username: {
|
|
type: String,
|
|
optional: true,
|
|
max: 30,
|
|
min: 4,
|
|
},
|
|
emails: {
|
|
type: Array,
|
|
optional: true,
|
|
},
|
|
'emails.$': {
|
|
type: Object,
|
|
},
|
|
'emails.$.address': {
|
|
type: String,
|
|
regEx: SimpleSchema.RegEx.Email,
|
|
},
|
|
'emails.$.verified': {
|
|
type: Boolean,
|
|
},
|
|
registered_emails: {
|
|
type: Array,
|
|
optional: true,
|
|
},
|
|
'registered_emails.$': {
|
|
type: Object,
|
|
blackbox: true,
|
|
},
|
|
createdAt: {
|
|
type: Date
|
|
},
|
|
services: {
|
|
type: Object,
|
|
optional: true,
|
|
blackbox: true,
|
|
},
|
|
roles: {
|
|
type: Array,
|
|
optional: true,
|
|
},
|
|
'roles.$': {
|
|
type: String
|
|
},
|
|
// In order to avoid an 'Exception in setInterval callback' from Meteor
|
|
heartbeat: {
|
|
type: Date,
|
|
optional: true,
|
|
},
|
|
apiKey: {
|
|
type: String,
|
|
index: 1,
|
|
optional: true,
|
|
},
|
|
darkMode: {
|
|
type: Boolean,
|
|
optional: true,
|
|
},
|
|
subscribedLibraries: {
|
|
type: Array,
|
|
defaultValue: defaultLibraries,
|
|
maxCount: 100,
|
|
},
|
|
'subscribedLibraries.$': {
|
|
type: String,
|
|
regEx: SimpleSchema.RegEx.Id,
|
|
},
|
|
subscribedLibraryCollections: {
|
|
type: Array,
|
|
defaultValue: defaultLibraryCollections,
|
|
maxCount: 100,
|
|
},
|
|
'subscribedLibraryCollections.$': {
|
|
type: String,
|
|
regEx: SimpleSchema.RegEx.Id,
|
|
},
|
|
subscribedCharacters: {
|
|
type: Array,
|
|
defaultValue: [],
|
|
max: 100,
|
|
},
|
|
'subscribedCharacters.$': {
|
|
type: String,
|
|
regEx: SimpleSchema.RegEx.Id,
|
|
},
|
|
fileStorageUsed: {
|
|
type: Number,
|
|
optional: true,
|
|
},
|
|
profile: {
|
|
type: Object,
|
|
blackbox: true,
|
|
optional: true,
|
|
},
|
|
preferences: {
|
|
type: Object,
|
|
optional: true,
|
|
defaultValue: {},
|
|
},
|
|
'preferences.swapAbilityScoresAndModifiers': {
|
|
type: Boolean,
|
|
optional: true,
|
|
},
|
|
'preferences.hidePropertySelectDialogHelp': {
|
|
type: Boolean,
|
|
optional: true,
|
|
},
|
|
});
|
|
|
|
Meteor.users.attachSchema(userSchema);
|
|
|
|
Meteor.users.generateApiKey = new ValidatedMethod({
|
|
name: 'users.generateApiKey',
|
|
validate: null,
|
|
mixins: [RateLimiterMixin],
|
|
rateLimit: {
|
|
numRequests: 5,
|
|
timeInterval: 5000,
|
|
},
|
|
run(){
|
|
if(Meteor.isClient) return;
|
|
var user = Meteor.users.findOne(this.userId);
|
|
if (!user) return;
|
|
if (user && user.apiKey) return;
|
|
var apiKey = Random.id(30);
|
|
Meteor.users.update(this.userId, {$set: {apiKey}});
|
|
},
|
|
});
|
|
|
|
Meteor.users.setDarkMode = new ValidatedMethod({
|
|
name: 'users.setDarkMode',
|
|
validate: new SimpleSchema({
|
|
darkMode: { type: Boolean },
|
|
}).validator(),
|
|
mixins: [RateLimiterMixin],
|
|
rateLimit: {
|
|
numRequests: 5,
|
|
timeInterval: 5000,
|
|
},
|
|
run({darkMode}){
|
|
if (!this.userId) return;
|
|
Meteor.users.update(this.userId, {$set: {darkMode}});
|
|
},
|
|
});
|
|
|
|
Meteor.users.sendVerificationEmail = new ValidatedMethod({
|
|
name: 'users.sendVerificationEmail',
|
|
validate: new SimpleSchema({
|
|
userId:{
|
|
type: String,
|
|
optional: true,
|
|
},
|
|
address: {
|
|
type: String,
|
|
},
|
|
}).validator(),
|
|
mixins: [RateLimiterMixin],
|
|
rateLimit: {
|
|
numRequests: 5,
|
|
timeInterval: 5000,
|
|
},
|
|
run({userId, address}){
|
|
userId = this.userId || userId;
|
|
let user = Meteor.users.findOne(userId);
|
|
if (!user) {
|
|
throw new Meteor.Error('User not found',
|
|
'Can\'t send a validation email to a user that does not exist');
|
|
}
|
|
if (!some(user.emails, email => email.address === address)) {
|
|
throw new Meteor.Error('Email address not found',
|
|
'The specified email address wasn\'t found on this user account');
|
|
}
|
|
Accounts.sendVerificationEmail(userId, address);
|
|
}
|
|
});
|
|
|
|
Meteor.users.canPickUsername = new ValidatedMethod({
|
|
name: 'users.canPickUsername',
|
|
validate: userSchema.pick('username').validator(),
|
|
mixins: [RateLimiterMixin],
|
|
rateLimit: {
|
|
numRequests: 5,
|
|
timeInterval: 5000,
|
|
},
|
|
run({username}){
|
|
if (Meteor.isClient) return;
|
|
let user = Accounts.findUserByUsername(username);
|
|
// You can pick your own username
|
|
if (user && user._id === this.userId){
|
|
return false;
|
|
}
|
|
return !!user;
|
|
}
|
|
});
|
|
|
|
Meteor.users.setUsername = new ValidatedMethod({
|
|
name: 'users.setUsername',
|
|
validate: userSchema.pick('username').validator(),
|
|
mixins: [RateLimiterMixin],
|
|
rateLimit: {
|
|
numRequests: 5,
|
|
timeInterval: 5000,
|
|
},
|
|
run({username}){
|
|
if (!this.userId) throw 'Can only set your username if logged in';
|
|
if (Meteor.isClient) return;
|
|
return Accounts.setUsername(this.userId, username)
|
|
}
|
|
});
|
|
|
|
Meteor.users.setPreference = new ValidatedMethod({
|
|
name: 'users.setPreference',
|
|
validate: new SimpleSchema({
|
|
preference:{
|
|
type: String,
|
|
},
|
|
value: {
|
|
type: SimpleSchema.oneOf(Boolean),
|
|
},
|
|
}).validator(),
|
|
mixins: [RateLimiterMixin],
|
|
rateLimit: {
|
|
numRequests: 5,
|
|
timeInterval: 5000,
|
|
},
|
|
run({preference, value}){
|
|
if (!this.userId) throw 'You can only set preferences once logged in';
|
|
let prefPath = `preferences.${preference}`
|
|
if (value == true){
|
|
return Meteor.users.update(this.userId, {
|
|
$set: {[prefPath]: true},
|
|
});
|
|
} else {
|
|
return Meteor.users.update(this.userId, {
|
|
$unset: {[prefPath]: 1},
|
|
});
|
|
}
|
|
},
|
|
});
|
|
|
|
Meteor.users.subscribeToLibrary = new ValidatedMethod({
|
|
name: 'users.subscribeToLibrary',
|
|
validate: new SimpleSchema({
|
|
libraryId:{
|
|
type: String,
|
|
regEx: SimpleSchema.RegEx.Id,
|
|
},
|
|
subscribe: {
|
|
type: Boolean,
|
|
},
|
|
}).validator(),
|
|
mixins: [RateLimiterMixin],
|
|
rateLimit: {
|
|
numRequests: 5,
|
|
timeInterval: 5000,
|
|
},
|
|
run({libraryId, subscribe}){
|
|
if (!this.userId) throw 'Can only subscribe if logged in';
|
|
if (subscribe){
|
|
return Meteor.users.update(this.userId, {
|
|
$addToSet: {subscribedLibraries: libraryId},
|
|
});
|
|
} else {
|
|
return Meteor.users.update(this.userId, {
|
|
$pullAll: {subscribedLibraries: libraryId},
|
|
});
|
|
}
|
|
}
|
|
});
|
|
|
|
Meteor.users.subscribeToLibraryCollection = new ValidatedMethod({
|
|
name: 'users.subscribeToLibraryCollection',
|
|
validate: new SimpleSchema({
|
|
libraryCollectionId:{
|
|
type: String,
|
|
regEx: SimpleSchema.RegEx.Id,
|
|
},
|
|
subscribe: {
|
|
type: Boolean,
|
|
},
|
|
}).validator(),
|
|
mixins: [RateLimiterMixin],
|
|
rateLimit: {
|
|
numRequests: 5,
|
|
timeInterval: 5000,
|
|
},
|
|
run({libraryCollectionId, subscribe}){
|
|
if (!this.userId) throw 'Can only subscribe if logged in';
|
|
if (subscribe){
|
|
return Meteor.users.update(this.userId, {
|
|
$addToSet: {subscribedLibraryCollections: libraryCollectionId},
|
|
});
|
|
} else {
|
|
return Meteor.users.update(this.userId, {
|
|
$pullAll: {subscribedLibraryCollections: libraryCollectionId},
|
|
});
|
|
}
|
|
}
|
|
});
|
|
|
|
Meteor.users.findUserByUsernameOrEmail = new ValidatedMethod({
|
|
name: 'users.findUserByUsernameOrEmail',
|
|
validate: new SimpleSchema({
|
|
usernameOrEmail:{
|
|
type: String,
|
|
},
|
|
}).validator(),
|
|
mixins: [RateLimiterMixin],
|
|
rateLimit: {
|
|
numRequests: 5,
|
|
timeInterval: 5000,
|
|
},
|
|
run({usernameOrEmail}){
|
|
if (Meteor.isClient) return;
|
|
let user = Accounts.findUserByUsername(usernameOrEmail) ||
|
|
Accounts.findUserByEmail(usernameOrEmail);
|
|
return user && user._id;
|
|
}
|
|
});
|