- Initial commit... A DB, some routes, and basic authentication routines...
This commit is contained in:
36
models/bid.js
Normal file
36
models/bid.js
Normal file
@@ -0,0 +1,36 @@
|
||||
const mongoose = require('mongoose');
|
||||
const timestamps = require('mongoose-timestamp');
|
||||
|
||||
const BidSchema = new mongoose.Schema(
|
||||
{
|
||||
itemId: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
bidderId: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
bidAmount: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
maxAmount: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
time: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
{ minimize: false },
|
||||
);
|
||||
|
||||
BidSchema.plugin(timestamps);
|
||||
|
||||
const Bid = mongoose.model('Bid', BidSchema);
|
||||
module.exports = Bid;
|
||||
44
models/common/address.js
Normal file
44
models/common/address.js
Normal file
@@ -0,0 +1,44 @@
|
||||
const mongoose = require('mongoose');
|
||||
const mongooseStringQuery = require('mongoose-string-query');
|
||||
const mongooseTimestamps = require('mongoose-timestamp');
|
||||
|
||||
const AddressSchema = new mongoose.Schema(
|
||||
{
|
||||
address1: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
address2: {
|
||||
type: String,
|
||||
trim: true,
|
||||
},
|
||||
locality: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
state: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
postalCode: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
required: true,
|
||||
enum: [ 'billing', 'shipping' ],
|
||||
},
|
||||
},
|
||||
|
||||
{ minimize: false },
|
||||
);
|
||||
|
||||
AddressSchema.plugin(mongooseStringQuery);
|
||||
AddressSchema.plugin(mongooseTimestamps);
|
||||
|
||||
module.exports = AddressSchema;
|
||||
30
models/common/email.js
Normal file
30
models/common/email.js
Normal file
@@ -0,0 +1,30 @@
|
||||
const mongoose = require('mongoose');
|
||||
const mongooseStringQuery = require('mongoose-string-query');
|
||||
const mongooseTimestamps = require('mongoose-timestamp');
|
||||
|
||||
const EmailSchema = new mongoose.Schema(
|
||||
{
|
||||
user: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
domain: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
|
||||
{ minimize: false },
|
||||
);
|
||||
|
||||
EmailSchema.virtual('address').get(function() {
|
||||
return this.user + '@' + this.domain;
|
||||
});
|
||||
|
||||
EmailSchema.plugin(mongooseStringQuery);
|
||||
EmailSchema.plugin(mongooseTimestamps);
|
||||
|
||||
module.exports = EmailSchema;
|
||||
29
models/common/phone.js
Normal file
29
models/common/phone.js
Normal file
@@ -0,0 +1,29 @@
|
||||
const mongoose = require('mongoose');
|
||||
const mongooseStringQuery = require('mongoose-string-query');
|
||||
const mongooseTimestamps = require('mongoose-timestamp');
|
||||
|
||||
const PhoneSchema = new mongoose.Schema(
|
||||
{
|
||||
countryCode: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: '1',
|
||||
},
|
||||
number: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
required: true,
|
||||
enum: [ 'home', 'mobile' ],
|
||||
},
|
||||
},
|
||||
|
||||
{ minimize: false },
|
||||
);
|
||||
|
||||
PhoneSchema.plugin(mongooseStringQuery);
|
||||
PhoneSchema.plugin(mongooseTimestamps);
|
||||
|
||||
module.exports = PhoneSchema;
|
||||
16
models/constants.js
Normal file
16
models/constants.js
Normal file
@@ -0,0 +1,16 @@
|
||||
module.exports = {
|
||||
ITEM_TYPES: {
|
||||
type: String,
|
||||
required: true,
|
||||
enum: [
|
||||
'auction',
|
||||
'donation',
|
||||
'event',
|
||||
'raffle',
|
||||
'membership',
|
||||
'popup',
|
||||
'ticket',
|
||||
],
|
||||
default: 'auction',
|
||||
},
|
||||
};
|
||||
147
models/event.js
Normal file
147
models/event.js
Normal file
@@ -0,0 +1,147 @@
|
||||
const config = require('../config.js');
|
||||
const mongoose = require('mongoose');
|
||||
const timestamps = require('mongoose-timestamp');
|
||||
|
||||
const PostSchema = new mongoose.Schema(
|
||||
{
|
||||
author: String,
|
||||
|
||||
title: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
content: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
|
||||
isPublic: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
|
||||
scheduledPost: String,
|
||||
|
||||
sendNotification: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
notificationContent: String,
|
||||
notificationLinksTo: String,
|
||||
}
|
||||
);
|
||||
|
||||
const TicketSchema = new mongoose.Schema(
|
||||
{
|
||||
name: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
price: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
|
||||
capacity: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
available: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
|
||||
itemId: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
|
||||
startSale: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
endSale: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
},
|
||||
|
||||
{ minimize: false },
|
||||
);
|
||||
|
||||
const EventSchema = new mongoose.Schema(
|
||||
{
|
||||
eventDate: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
startTime: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
endTime: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
|
||||
title: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
tagline: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
|
||||
isTicketed: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
ticketClasses: [ TicketSchema ],
|
||||
|
||||
showFrom: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
showUntil: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
|
||||
requireLoginToSeeAuction: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
|
||||
images: [{
|
||||
url: String,
|
||||
}],
|
||||
url: String,
|
||||
|
||||
posts: [ PostSchema ],
|
||||
},
|
||||
|
||||
{ minimize: false },
|
||||
);
|
||||
|
||||
EventSchema.plugin(timestamps);
|
||||
|
||||
EventSchema.path('images').get(v => `${config.assetStoreUrl}${v.url}`)
|
||||
|
||||
const Event = mongoose.model('Event', EventSchema);
|
||||
module.exports = Event;
|
||||
49
models/install.js
Normal file
49
models/install.js
Normal file
@@ -0,0 +1,49 @@
|
||||
const mongoose = require('mongoose');
|
||||
const timestamps = require('mongoose-timestamp');
|
||||
|
||||
const InstallSchema = new mongoose.Schema(
|
||||
{
|
||||
timeZone: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
deviceType: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
enum: [ 'android', 'ios', 'web' ],
|
||||
},
|
||||
badge: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
installationId: {
|
||||
type: String,
|
||||
required: true,
|
||||
unique: true,
|
||||
},
|
||||
email: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
appIdentifier: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
localeIdentifier: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
},
|
||||
|
||||
{ minimize: false },
|
||||
);
|
||||
|
||||
InstallSchema.plugin(timestamps);
|
||||
|
||||
const Install = mongoose.model('Install', InstallSchema);
|
||||
module.exports = Install;
|
||||
136
models/item.js
Normal file
136
models/item.js
Normal file
@@ -0,0 +1,136 @@
|
||||
const { ITEM_TYPES } = require('./constants.js');
|
||||
|
||||
const config = require('../config.js');
|
||||
const mongoose = require('mongoose');
|
||||
const mongooseStringQuery = require('mongoose-string-query');
|
||||
const timestamps = require('mongoose-timestamp');
|
||||
|
||||
const ItemSchema = new mongoose.Schema(
|
||||
{
|
||||
eventId: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
|
||||
title: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
subtitle: {
|
||||
type: String,
|
||||
trim: true,
|
||||
},
|
||||
donor: {
|
||||
type: String,
|
||||
trim: true,
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
images: [{
|
||||
url: String
|
||||
}],
|
||||
|
||||
type: ITEM_TYPES,
|
||||
|
||||
quantityAvailable: {
|
||||
type: Number,
|
||||
required: true,
|
||||
default: 1,
|
||||
},
|
||||
soldCount: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
|
||||
currentPrice: {
|
||||
required: true,
|
||||
type: Number,
|
||||
},
|
||||
startingPrice: {
|
||||
type: Number,
|
||||
},
|
||||
reservePrice: {
|
||||
type: Number,
|
||||
},
|
||||
estimatedValue: {
|
||||
type: Number,
|
||||
},
|
||||
|
||||
currentWinner: {
|
||||
type: String,
|
||||
trim: true,
|
||||
},
|
||||
bidders: [{
|
||||
name: String,
|
||||
}],
|
||||
bidCount: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
bidIncrement: {
|
||||
type: Number,
|
||||
default: 10,
|
||||
},
|
||||
|
||||
catalogNumber: {
|
||||
type: Number,
|
||||
},
|
||||
|
||||
start: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
end: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
hideBeforeStart: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
default: false,
|
||||
},
|
||||
hideAfterEnd: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
default: false,
|
||||
},
|
||||
notifyOnAvailable: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
default: false,
|
||||
},
|
||||
|
||||
isShippable: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
shippingCost: Number,
|
||||
|
||||
organizationTake: {
|
||||
type: Number,
|
||||
required: true,
|
||||
default: 1,
|
||||
},
|
||||
},
|
||||
|
||||
{ minimize: false },
|
||||
);
|
||||
|
||||
ItemSchema.plugin(timestamps);
|
||||
|
||||
ItemSchema.path('images').get(v => `${config.assetStoreUrl}${v.url}`);
|
||||
|
||||
/**
|
||||
* STATICS
|
||||
*/
|
||||
ItemSchema.statics.addBatch = function(data = [], callback = () => {}) {
|
||||
|
||||
};
|
||||
|
||||
const Item = mongoose.model('Item', ItemSchema);
|
||||
module.exports = Item;
|
||||
63
models/organization.js
Normal file
63
models/organization.js
Normal file
@@ -0,0 +1,63 @@
|
||||
const mongoose = require('mongoose');
|
||||
const timestamps = require('mongoose-timestamp');
|
||||
|
||||
const PeopleSchema = new mongoose.Schema(
|
||||
{
|
||||
name: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
|
||||
bio: {
|
||||
type: String,
|
||||
trim: true,
|
||||
},
|
||||
|
||||
address: AddressSchema,
|
||||
email: EmailSchema,
|
||||
phone: PhoneSchema,
|
||||
},
|
||||
|
||||
{ minimize: false },
|
||||
);
|
||||
|
||||
const OrganizationSchema = new mongoose.Schema(
|
||||
{
|
||||
name: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
|
||||
url: String,
|
||||
address: [ AddressSchema ],
|
||||
telephone: [ TelephoneSchema ],
|
||||
|
||||
about: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
|
||||
team: [ PeopleSchema ],
|
||||
board: [ PeopleSchema ],
|
||||
|
||||
privacyUrl: String,
|
||||
tosUrl: String,
|
||||
|
||||
copyright: String,
|
||||
},
|
||||
|
||||
{ minimize: false },
|
||||
);
|
||||
|
||||
OrganizationSchema.plugin(timestamps);
|
||||
|
||||
const Organization = mongoose.model('Organization', OrganizationSchema);
|
||||
module.exports = Organization;
|
||||
44
models/sale.js
Normal file
44
models/sale.js
Normal file
@@ -0,0 +1,44 @@
|
||||
const { ITEM_TYPES } = require('./constants.js');
|
||||
|
||||
const mongoose = require('mongoose');
|
||||
const timestamps = require('mongoose-timestamp');
|
||||
|
||||
const SaleSchema = new mongoose.Schema(
|
||||
{
|
||||
itemId: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
userId: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
amount: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
|
||||
itemType: ITEM_TYPES,
|
||||
paymentToken: String,
|
||||
|
||||
isPaid: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
default: false,
|
||||
},
|
||||
isPickedUp: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
|
||||
{ minimize: false },
|
||||
);
|
||||
|
||||
SaleSchema.plugin(timestamps);
|
||||
|
||||
const Sale = mongoose.model('Sale', SaleSchema);
|
||||
module.exports = Sale;
|
||||
284
models/user.js
Normal file
284
models/user.js
Normal file
@@ -0,0 +1,284 @@
|
||||
const crypto = require('crypto');
|
||||
const jwt = require('jsonwebtoken');
|
||||
const mongoose = require('mongoose');
|
||||
const timestamps = require('mongoose-timestamp');
|
||||
|
||||
const config = require('../config.js');
|
||||
|
||||
const AddressSchema = require('./common/address.js');
|
||||
const PhoneSchema = require('./common/phone.js');
|
||||
|
||||
const LoginSchema = new mongoose.Schema(
|
||||
{
|
||||
method: {
|
||||
type: String,
|
||||
required: true,
|
||||
enum: [ 'apple', 'facebook', 'google', 'local' ],
|
||||
},
|
||||
userId: {
|
||||
type: String,
|
||||
trim: true,
|
||||
},
|
||||
accessToken: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
secret: {
|
||||
type: String,
|
||||
trim: true,
|
||||
},
|
||||
profile: {},
|
||||
},
|
||||
|
||||
{ minimize: false },
|
||||
);
|
||||
|
||||
const UserSchema = new mongoose.Schema(
|
||||
{
|
||||
nomDeBid: {
|
||||
type: String,
|
||||
trim: true,
|
||||
unique: true,
|
||||
},
|
||||
firstName: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
lastName: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
},
|
||||
email: {
|
||||
type: String,
|
||||
required: true,
|
||||
unique: true,
|
||||
},
|
||||
|
||||
avatar: {
|
||||
type: String,
|
||||
trim: true,
|
||||
},
|
||||
|
||||
address: [ AddressSchema ],
|
||||
phone: [ PhoneSchema ],
|
||||
|
||||
credentials: [ LoginSchema ],
|
||||
|
||||
organizationIdentifier: {
|
||||
type: String,
|
||||
trim: true,
|
||||
},
|
||||
paymentToken: {
|
||||
type: String,
|
||||
trim: true,
|
||||
},
|
||||
|
||||
isVerified: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isAllowedToBid: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isOrganizationEmployee: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
|
||||
{ minimize: false },
|
||||
);
|
||||
|
||||
/**
|
||||
* PLUGINS
|
||||
*/
|
||||
UserSchema.plugin(timestamps);
|
||||
|
||||
|
||||
/**
|
||||
* METHODS
|
||||
*/
|
||||
UserSchema.methods.authenticate = function (username, password) {
|
||||
const user = this.model('User').findOne({ email: username });
|
||||
const strategy = user ? user.getAuthStrategy('local') : null;
|
||||
|
||||
if (strategy) {
|
||||
let hash = crypto.pbkdf2Sync(password, strategy.get('secret'), 10000, 512, 'sha512').toString('hex')
|
||||
return strategy.get('accessToken') === hash;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
UserSchema.methods.generateJWT = function (props = {}) {
|
||||
const { exp, iss } = props;
|
||||
const today = new Date();
|
||||
|
||||
let expirationDate = exp;
|
||||
if (!expirationDate) {
|
||||
expirationDate = new Date(today);
|
||||
expirationDate.setDate(today.getDate() + config.security.jwt.daysValid);
|
||||
}
|
||||
|
||||
return jwt.sign({
|
||||
sub: this._id,
|
||||
iss: iss || config.security.jwt.issuer,
|
||||
aud: config.security.jwt.audience,
|
||||
iat: parseInt(today.getTime()),
|
||||
exp: parseInt(expirationDate.getTime() / 1000, 10),
|
||||
}, config.security.jwt.secret);
|
||||
}
|
||||
|
||||
UserSchema.methods.getAuthStrategy = function (method = 'local') {
|
||||
return this.credentials.filter((strategy) => {
|
||||
return strategy.method === method;
|
||||
}).pop() || false;
|
||||
};
|
||||
|
||||
UserSchema.methods.getNomDeBid = function () {
|
||||
return this.nomDeBid || `${this.firstName} ${this.lastName.charAt(0)}`;
|
||||
};
|
||||
|
||||
UserSchema.methods.isEventManager = function () {
|
||||
return this.isOrganizationEmployee || false;
|
||||
};
|
||||
|
||||
UserSchema.methods.isRegistrationVerified = function () {
|
||||
return this.isVerified || false;
|
||||
};
|
||||
|
||||
UserSchema.methods.setPassword = function (password, callback = () => {}) {
|
||||
const hasLocalStrategy = !!this.credentials.length &&
|
||||
!!this.credentials.filter(strategy => strategy.method === 'local').length;
|
||||
|
||||
const salt = crypto.randomBytes(16).toString('hex');
|
||||
const accessToken = crypto.pbkdf2Sync(password, salt, 10000, 512, 'sha512').toString('hex');
|
||||
|
||||
const strategy = {
|
||||
accessToken,
|
||||
method: 'local',
|
||||
secret: salt,
|
||||
};
|
||||
|
||||
if (hasLocalStrategy) {
|
||||
this.model('User').findOneAndUpdate(
|
||||
{ _id: this._id, 'credentials.method': 'local' },
|
||||
{ $set: { 'credentials.$': strategy } },
|
||||
{ upsert: true },
|
||||
callback,
|
||||
);
|
||||
}
|
||||
|
||||
if (!hasLocalStrategy) {
|
||||
this.credentials.push(strategy);
|
||||
this.save(callback);
|
||||
}
|
||||
};
|
||||
|
||||
UserSchema.methods.toAuthJSON = function () {
|
||||
const hasNomDeBid = !!this.nomDeBid;
|
||||
const nomDeBid = this.getNomDeBid();
|
||||
|
||||
return {
|
||||
email: this.email,
|
||||
token: this.generateJWT(),
|
||||
user: {
|
||||
nomDeBid: nomDeBid,
|
||||
email: this.email,
|
||||
firstName: this.firstName,
|
||||
lastName: this.lastName,
|
||||
avatar: this.avatar,
|
||||
isAllowedToBid: this.isAllowedToBid,
|
||||
isOrganizationEmployee: this.isOrganizationEmployee,
|
||||
generatedNomDeBid: !hasNomDeBid,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
UserSchema.methods.validatePassword = function (password) {
|
||||
const strategy = this.getAuthStrategy('local');
|
||||
|
||||
if (strategy) {
|
||||
let hash = crypto.pbkdf2Sync(password, strategy.secret, 10000, 512, 'sha512').toString('hex');
|
||||
return strategy.accessToken === hash;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* STATICS
|
||||
*/
|
||||
UserSchema.statics.findOrCreate = function (filter = {}, profile = {}, callback = () => {}) {
|
||||
const self = this;
|
||||
|
||||
this.findOne(filter, function(err,result) {
|
||||
if (err) {
|
||||
callback(err, null);
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
self.create(profile, (err, result) => callback(err, result));
|
||||
}else{
|
||||
callback(err, result);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
UserSchema.statics.findOneAndUpdateOrCreate = function (
|
||||
filter = {},
|
||||
strategy = {},
|
||||
profile = {},
|
||||
callback = () => {},
|
||||
) {
|
||||
const self = this;
|
||||
|
||||
this.findOne(filter, function(err, result) {
|
||||
if (err) {
|
||||
callback(err, null);
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
self.create(
|
||||
{
|
||||
strategy: [ strategy ],
|
||||
...profile
|
||||
},
|
||||
(err, result) => callback(err, result),
|
||||
);
|
||||
} else {
|
||||
const hasStrategy = !!result.credentials.length &&
|
||||
!!result.credentials.filter(auth => auth.method === strategy.method).length;
|
||||
|
||||
if (hasStrategy) {
|
||||
self.model('User').findOneAndUpdate(
|
||||
{ _id: result._id, 'credentials.method': strategy.method },
|
||||
{ $set: { 'credentials.$': strategy } },
|
||||
{ upsert: true },
|
||||
callback,
|
||||
);
|
||||
} else {
|
||||
result.credentials.push(strategy);
|
||||
result.save(callback);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* PATH OPERATIONS
|
||||
*/
|
||||
UserSchema.path('avatar').get(v => `${config.assetStoreUrl}${v}`);
|
||||
|
||||
/**
|
||||
* Export
|
||||
*/
|
||||
const User = mongoose.model('User', UserSchema);
|
||||
|
||||
module.exports = User;
|
||||
Reference in New Issue
Block a user