Skip to content

Commit

Permalink
feat(subscriptions): init mail subscriptions example ✨
Browse files Browse the repository at this point in the history
  • Loading branch information
PierreBrisorgueil committed Jul 9, 2020
1 parent 51e476e commit 34fdd9c
Show file tree
Hide file tree
Showing 11 changed files with 765 additions and 5 deletions.
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,17 @@ Our stack node is actually in Beta.

## :tada: Features Overview

#### Available
### Core

* **User** : classic register / auth or oAuth(microsoft, google) - profile management (update, avatar upload ...)
* **User data privacy** : delete all data - get all data - send all data by mail
* **User data privacy** : delete all - get all - send all by mail
* **Admin** : list users - get user - edit user - delete user
* **Tasks** : list tasks - get task - add tasks - edit tasks - delete tasks
* **Uploads** : get upload stream - add upload - delete upload - get image upload stream & sharp operations

### Examples

* **Tasks** : list - get - add - edit - delete
* **Files Uploads** : get stream - add - delete - get image stream & sharp operations
* **Mails Subscriptions** : list - get - add - edit - delete

## :pushpin: Prerequisites

Expand Down
97 changes: 97 additions & 0 deletions modules/subscriptions/controllers/subscriptions.controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/**
* Module dependencies
*/
const path = require('path');

const errors = require(path.resolve('./lib/helpers/errors'));
const responses = require(path.resolve('./lib/helpers/responses'));

const SubscriptionsService = require('../services/subscriptions.service');

/**
* @desc Endpoint to ask the service to get the list of subscriptions
* @param {Object} req - Express request object
* @param {Object} res - Express response object
*/
exports.list = async (req, res) => {
try {
const subscriptions = await SubscriptionsService.list();
responses.success(res, 'subscription list')(subscriptions);
} catch (err) {
responses.error(res, 422, 'Unprocessable Entity', errors.getMessage(err))(err);
}
};

/**
* @desc Endpoint to ask the service to create a subscription
* @param {Object} req - Express request object
* @param {Object} res - Express response object
*/
exports.create = async (req, res) => {
try {
const subscription = await SubscriptionsService.create(req.body);
responses.success(res, 'subscription created')(subscription);
} catch (err) {
responses.error(res, 422, 'Unprocessable Entity', errors.getMessage(err))(err);
}
};

/**
* @desc Endpoint to show the current subscription
* @param {Object} req - Express request object
* @param {Object} res - Express response object
*/
exports.get = (req, res) => {
const subscription = req.subscription ? req.subscription.toJSON() : {};
responses.success(res, 'subscription get')(subscription);
};

/**
* @desc Endpoint to ask the service to update a subscription
* @param {Object} req - Express request object
* @param {Object} res - Express response object
*/
exports.update = async (req, res) => {
try {
const subscription = await SubscriptionsService.update(req.subscription, req.body);
responses.success(res, 'subscription updated')(subscription);
} catch (err) {
responses.error(res, 422, 'Unprocessable Entity', errors.getMessage(err))(err);
}
};

/**
* @desc Endpoint to ask the service to delete a subscription
* @param {Object} req - Express request object
* @param {Object} res - Express response object
*/
exports.delete = async (req, res) => {
try {
const result = await SubscriptionsService.delete(req.subscription);
result.id = req.subscription.id;
responses.success(res, 'subscription deleted')(result);
} catch (err) {
responses.error(res, 422, 'Unprocessable Entity', errors.getMessage(err))(err);
}
};

/**
* @desc MiddleWare to ask the service the subscription for this id
* @param {Object} req - Express request object
* @param {Object} res - Express response object
* @param {Function} next - Express next middleware function
* @param {String} id - subscription id
*/
exports.subscriptionByID = async (req, res, next, id) => {
try {
const subscription = await SubscriptionsService.get(id);
if (!subscription) responses.error(res, 404, 'Not Found', 'No Subscription with that identifier has been found')();
else {
req.subscription = subscription;
// if (subscription.user) req.isOwner = subscription.user._id; // user id used if we proteck road by isOwner policy
next();
}
} catch (err) {
next(err);
}
};
39 changes: 39 additions & 0 deletions modules/subscriptions/models/subscriptions.model.mongoose.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* Module dependencies
*/
const mongoose = require('mongoose');

const Schema = mongoose.Schema;

/**
* Data Model Mongoose
*/
const SubscriptionMongoose = new Schema({
email: {
type: String,
unique: 'Email already exists',
},
news: Boolean,
}, {
timestamps: true,
});

/**
* @desc Function to add id (+ _id) to all objects
* @param {Object} subscription
* @return {Object} Subscription
*/
function addID() {
return this._id.toHexString();
}

/**
* Model configuration
*/
SubscriptionMongoose.virtual('id').get(addID);
// Ensure virtual fields are serialised.
SubscriptionMongoose.set('toJSON', {
virtuals: true,
});

mongoose.model('Subscription', SubscriptionMongoose);
16 changes: 16 additions & 0 deletions modules/subscriptions/models/subscriptions.schema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* Module dependencies
*/
const Joi = require('@hapi/joi');

/**
* Data Schema
*/
const SubscriptionSchema = Joi.object().keys({
email: Joi.string().email().required(),
news: Joi.boolean().default(true).required(),
});

module.exports = {
Subscription: SubscriptionSchema,
};
31 changes: 31 additions & 0 deletions modules/subscriptions/policies/subscriptions.policy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* Module dependencies
* */
const path = require('path');

const policy = require(path.resolve('./lib/middlewares/policy'));

/**
* Invoke Subscriptions Permissions
*/
exports.invokeRolesPolicies = () => {
policy.Acl.allow([{
roles: ['guest'],
allows: [{
resources: '/api/subscriptions',
permissions: ['post'],
}, {
resources: '/api/subscriptions/:subscriptionId',
permissions: ['get', 'put', 'delete'],
}],
}, {
roles: ['admin'],
allows: [{
resources: '/api/subscriptions',
permissions: '*',
}, {
resources: '/api/subscriptions/:subscriptionId',
permissions: '*',
}],
}]);
};
72 changes: 72 additions & 0 deletions modules/subscriptions/repositories/subscriptions.repository.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/**
* Module dependencies
*/
const mongoose = require('mongoose');

const Subscription = mongoose.model('Subscription');

/**
* @desc Function to get all subscription in db with filter or not
* @return {Array} subscriptions
*/
exports.list = (filter) => Subscription.find(filter).sort('-createdAt').exec();

/**
* @desc Function to create a subscription in db
* @param {Object} subscription
* @return {Object} subscription
*/
exports.create = (subscription) => new Subscription(subscription).save();

/**
* @desc Function to get a subscription from db
* @param {String} id
* @return {Object} subscription
*/
exports.get = (id) => {
if (!mongoose.Types.ObjectId.isValid(id)) return null;
return Subscription.findOne({ _id: id }).exec();
};

/**
* @desc Function to update a subscription in db
* @param {Object} subscription
* @return {Object} subscription
*/
exports.update = (subscription) => new Subscription(subscription).save();

/**
* @desc Function to delete a subscription in db
* @param {Object} subscription
* @return {Object} confirmation of delete
*/
exports.delete = (subscription) => Subscription.deleteOne({ _id: subscription.id }).exec();

/**
* @desc Function to delete subscriptions of one user in db
* @param {Object} filter
* @return {Object} confirmation of delete
*/
exports.deleteMany = (filter) => {
if (filter) return Subscription.deleteMany(filter).exec();
};

/**
* @desc Function to import list of subscriptions in db
* @param {[Object]} subscriptions
* @param {[String]} filters
* @return {Object} subscriptions
*/
exports.import = (subscriptions, filters) => Subscription.bulkWrite(subscriptions.map((subscription) => {
const filter = {};
filters.forEach((value) => {
filter[value] = subscription[value];
});
return {
updateOne: {
filter,
update: subscription,
upsert: true,
},
};
}));
29 changes: 29 additions & 0 deletions modules/subscriptions/routes/subscriptions.routes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* Module dependencies
*/
const passport = require('passport');
const path = require('path');

const model = require(path.resolve('./lib/middlewares/model'));
const policy = require(path.resolve('./lib/middlewares/policy'));
const subscriptions = require('../controllers/subscriptions.controller');
const subscriptionsSchema = require('../models/subscriptions.schema');

/**
* Routes
*/
module.exports = (app) => {
// list & post
app.route('/api/subscriptions')
.get(passport.authenticate('jwt'), policy.isAllowed, subscriptions.list) // list
.post(policy.isAllowed, model.isValid(subscriptionsSchema.Subscription), subscriptions.create); // create

// classic crud
app.route('/api/subscriptions/:subscriptionId').all(policy.isAllowed) // policy.isOwner available (require set in middleWare)
.get(subscriptions.get) // get
.put(model.isValid(subscriptionsSchema.Subscription), subscriptions.update) // update
.delete(model.isValid(subscriptionsSchema.Subscription), subscriptions.delete); // delete

// Finish by binding the subscription middleware
app.param('subscriptionId', subscriptions.subscriptionByID);
};
55 changes: 55 additions & 0 deletions modules/subscriptions/services/subscriptions.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
* Module dependencies
*/
const SubscriptionsRepository = require('../repositories/subscriptions.repository');

/**
* @desc Function to get all subscription in db
* @return {Promise} All subscriptions
*/
exports.list = async () => {
const result = await SubscriptionsRepository.list();
return Promise.resolve(result);
};

/**
* @desc Function to ask repository to create a subscription
* @param {Object} subscription
* @return {Promise} subscription
*/
exports.create = async (subscription) => {
const result = await SubscriptionsRepository.create(subscription);
return Promise.resolve(result);
};

/**
* @desc Function to ask repository to get a subscription
* @param {String} id
* @return {Promise} subscription
*/
exports.get = async (id) => {
const result = await SubscriptionsRepository.get(id);
return Promise.resolve(result);
};

/**
* @desc Functio to ask repository to update a subscription
* @param {Object} subscription - original subscription
* @param {Object} body - subscription edited
* @return {Promise} subscription
*/
exports.update = async (subscription, body) => {
subscription.email = body.email;
const result = await SubscriptionsRepository.update(subscription);
return Promise.resolve(result);
};

/**
* @desc Function to ask repository to delete a subscription
* @param {Object} subscription
* @return {Promise} confirmation of delete
*/
exports.delete = async (subscription) => {
const result = await SubscriptionsRepository.delete(subscription);
return Promise.resolve(result);
};
Loading

0 comments on commit 34fdd9c

Please sign in to comment.