Create basic crud for activities, units and user profiles
This commit is contained in:
parent
31c5b22011
commit
def02622a6
5
.idea/.gitignore
vendored
Normal file
5
.idea/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
12
.idea/backend.iml
Normal file
12
.idea/backend.iml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="WEB_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
67
.idea/codeStyles/Project.xml
Normal file
67
.idea/codeStyles/Project.xml
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<code_scheme name="Project" version="173">
|
||||||
|
<option name="OTHER_INDENT_OPTIONS">
|
||||||
|
<value>
|
||||||
|
<option name="INDENT_SIZE" value="1" />
|
||||||
|
<option name="TAB_SIZE" value="1" />
|
||||||
|
<option name="USE_TAB_CHARACTER" value="true" />
|
||||||
|
<option name="SMART_TABS" value="true" />
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
|
<HTMLCodeStyleSettings>
|
||||||
|
<option name="HTML_SPACE_INSIDE_EMPTY_TAG" value="true" />
|
||||||
|
</HTMLCodeStyleSettings>
|
||||||
|
<JSCodeStyleSettings version="0">
|
||||||
|
<option name="FORCE_SEMICOLON_STYLE" value="true" />
|
||||||
|
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
|
||||||
|
<option name="USE_DOUBLE_QUOTES" value="false" />
|
||||||
|
<option name="FORCE_QUOTE_STYlE" value="true" />
|
||||||
|
<option name="ENFORCE_TRAILING_COMMA" value="Remove" />
|
||||||
|
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
|
||||||
|
<option name="SPACES_WITHIN_IMPORTS" value="true" />
|
||||||
|
</JSCodeStyleSettings>
|
||||||
|
<TypeScriptCodeStyleSettings version="0">
|
||||||
|
<option name="FORCE_SEMICOLON_STYLE" value="true" />
|
||||||
|
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
|
||||||
|
<option name="USE_DOUBLE_QUOTES" value="false" />
|
||||||
|
<option name="FORCE_QUOTE_STYlE" value="true" />
|
||||||
|
<option name="ENFORCE_TRAILING_COMMA" value="Remove" />
|
||||||
|
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
|
||||||
|
<option name="SPACES_WITHIN_IMPORTS" value="true" />
|
||||||
|
</TypeScriptCodeStyleSettings>
|
||||||
|
<VueCodeStyleSettings>
|
||||||
|
<option name="INTERPOLATION_NEW_LINE_AFTER_START_DELIMITER" value="false" />
|
||||||
|
<option name="INTERPOLATION_NEW_LINE_BEFORE_END_DELIMITER" value="false" />
|
||||||
|
</VueCodeStyleSettings>
|
||||||
|
<codeStyleSettings language="HTML">
|
||||||
|
<option name="SOFT_MARGINS" value="125" />
|
||||||
|
<indentOptions>
|
||||||
|
<option name="INDENT_SIZE" value="2" />
|
||||||
|
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||||
|
<option name="TAB_SIZE" value="2" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="JavaScript">
|
||||||
|
<option name="SOFT_MARGINS" value="125" />
|
||||||
|
<indentOptions>
|
||||||
|
<option name="INDENT_SIZE" value="2" />
|
||||||
|
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||||
|
<option name="TAB_SIZE" value="2" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="TypeScript">
|
||||||
|
<option name="SOFT_MARGINS" value="125" />
|
||||||
|
<indentOptions>
|
||||||
|
<option name="INDENT_SIZE" value="2" />
|
||||||
|
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||||
|
<option name="TAB_SIZE" value="2" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="Vue">
|
||||||
|
<option name="SOFT_MARGINS" value="125" />
|
||||||
|
<indentOptions>
|
||||||
|
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
</code_scheme>
|
||||||
|
</component>
|
5
.idea/codeStyles/codeStyleConfig.xml
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<state>
|
||||||
|
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||||
|
</state>
|
||||||
|
</component>
|
6
.idea/inspectionProfiles/Project_Default.xml
Normal file
6
.idea/inspectionProfiles/Project_Default.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
</profile>
|
||||||
|
</component>
|
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/backend.iml" filepath="$PROJECT_DIR$/.idea/backend.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
@ -1,8 +1,15 @@
|
|||||||
const roles = ['user', 'admin'];
|
const roles = ['user', 'admin'];
|
||||||
|
|
||||||
|
const allRights = [
|
||||||
|
'getUsers', 'manageUsers',
|
||||||
|
'getActivities', 'manageActivities',
|
||||||
|
'getProfiles', 'manageProfiles',
|
||||||
|
'getUnits', 'manageUnits',
|
||||||
|
];
|
||||||
|
|
||||||
const roleRights = new Map();
|
const roleRights = new Map();
|
||||||
roleRights.set(roles[0], []);
|
roleRights.set(roles[0], allRights);
|
||||||
roleRights.set(roles[1], ['getUsers', 'manageUsers']);
|
roleRights.set(roles[1], allRights);
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
roles,
|
roles,
|
||||||
|
43
src/controllers/activity.controller.js
Normal file
43
src/controllers/activity.controller.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
const httpStatus = require('http-status');
|
||||||
|
const pick = require('../utils/pick');
|
||||||
|
const ApiError = require('../utils/ApiError');
|
||||||
|
const catchAsync = require('../utils/catchAsync');
|
||||||
|
const { activityService } = require('../services');
|
||||||
|
|
||||||
|
const createActivity = catchAsync(async (req, res) => {
|
||||||
|
const activity = await activityService.createActivity(req.body);
|
||||||
|
res.status(httpStatus.CREATED).send(activity);
|
||||||
|
});
|
||||||
|
|
||||||
|
const getActivities = catchAsync(async (req, res) => {
|
||||||
|
const filter = pick(req.query, ['name', 'factor']);
|
||||||
|
const options = pick(req.query, ['sortBy', 'limit', 'page']);
|
||||||
|
const result = await activityService.queryActivities(filter, options);
|
||||||
|
res.send(result);
|
||||||
|
});
|
||||||
|
|
||||||
|
const getActivity = catchAsync(async (req, res) => {
|
||||||
|
const activity = await activityService.getActivityById(req.params.activityId);
|
||||||
|
if (!activity) {
|
||||||
|
throw new ApiError(httpStatus.NOT_FOUND, 'Activity not found');
|
||||||
|
}
|
||||||
|
res.send(activity);
|
||||||
|
});
|
||||||
|
|
||||||
|
const updateActivity = catchAsync(async (req, res) => {
|
||||||
|
const activity = await activityService.updateActivityById(req.params.activityId, req.body);
|
||||||
|
res.send(activity);
|
||||||
|
});
|
||||||
|
|
||||||
|
const deleteActivity = catchAsync(async (req, res) => {
|
||||||
|
await activityService.deleteActivityById(req.params.activityId);
|
||||||
|
res.status(httpStatus.NO_CONTENT).send();
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
createActivity,
|
||||||
|
getActivities,
|
||||||
|
getActivity,
|
||||||
|
updateActivity,
|
||||||
|
deleteActivity,
|
||||||
|
};
|
@ -1,2 +1,5 @@
|
|||||||
module.exports.authController = require('./auth.controller');
|
module.exports.authController = require('./auth.controller');
|
||||||
module.exports.userController = require('./user.controller');
|
module.exports.userController = require('./user.controller');
|
||||||
|
module.exports.profileController = require('./profile.controller');
|
||||||
|
module.exports.activityController = require('./activity.controller');
|
||||||
|
module.exports.unitController = require('./unit.controller');
|
||||||
|
44
src/controllers/profile.controller.js
Normal file
44
src/controllers/profile.controller.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
const httpStatus = require('http-status');
|
||||||
|
const pick = require('../utils/pick');
|
||||||
|
const ApiError = require('../utils/ApiError');
|
||||||
|
const catchAsync = require('../utils/catchAsync');
|
||||||
|
const { profileService } = require('../services');
|
||||||
|
|
||||||
|
const createProfile = catchAsync(async (req, res) => {
|
||||||
|
req.body.userId = req.user._id;
|
||||||
|
const profile = await profileService.createProfile(req.body);
|
||||||
|
res.status(httpStatus.CREATED).send(profile);
|
||||||
|
});
|
||||||
|
|
||||||
|
const getProfiles = catchAsync(async (req, res) => {
|
||||||
|
const filter = pick(req.query, ['name', 'role']);
|
||||||
|
const options = pick(req.query, ['sortBy', 'limit', 'page']);
|
||||||
|
const result = await profileService.queryProfiles(filter, options);
|
||||||
|
res.send(result);
|
||||||
|
});
|
||||||
|
|
||||||
|
const getProfile = catchAsync(async (req, res) => {
|
||||||
|
const profile = await profileService.getProfileById(req.params.profileId);
|
||||||
|
if (!profile) {
|
||||||
|
throw new ApiError(httpStatus.NOT_FOUND, 'Profile not found');
|
||||||
|
}
|
||||||
|
res.send(profile);
|
||||||
|
});
|
||||||
|
|
||||||
|
const updateProfile = catchAsync(async (req, res) => {
|
||||||
|
const profile = await profileService.getProfileById(req.params.profileId, req.body);
|
||||||
|
res.send(profile);
|
||||||
|
});
|
||||||
|
|
||||||
|
const deleteProfile = catchAsync(async (req, res) => {
|
||||||
|
await profileService.deleteProfileById(req.params.profileId);
|
||||||
|
res.status(httpStatus.NO_CONTENT).send();
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
createProfile,
|
||||||
|
getProfiles,
|
||||||
|
getProfile,
|
||||||
|
updateProfile,
|
||||||
|
deleteProfile,
|
||||||
|
};
|
43
src/controllers/unit.controller.js
Normal file
43
src/controllers/unit.controller.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
const httpStatus = require('http-status');
|
||||||
|
const pick = require('../utils/pick');
|
||||||
|
const ApiError = require('../utils/ApiError');
|
||||||
|
const catchAsync = require('../utils/catchAsync');
|
||||||
|
const { unitService } = require('../services');
|
||||||
|
|
||||||
|
const createUnit = catchAsync(async (req, res) => {
|
||||||
|
const unit = await unitService.createUnit(req.body);
|
||||||
|
res.status(httpStatus.CREATED).send(unit);
|
||||||
|
});
|
||||||
|
|
||||||
|
const getUnits = catchAsync(async (req, res) => {
|
||||||
|
const filter = pick(req.query, ['name']);
|
||||||
|
const options = pick(req.query, ['sortBy', 'limit', 'page']);
|
||||||
|
const result = await unitService.queryUnits(filter, options);
|
||||||
|
res.send(result);
|
||||||
|
});
|
||||||
|
|
||||||
|
const getUnit = catchAsync(async (req, res) => {
|
||||||
|
const unit = await unitService.getUnitById(req.params.unitId);
|
||||||
|
if (!unit) {
|
||||||
|
throw new ApiError(httpStatus.NOT_FOUND, 'Unit not found');
|
||||||
|
}
|
||||||
|
res.send(unit);
|
||||||
|
});
|
||||||
|
|
||||||
|
const updateUnit = catchAsync(async (req, res) => {
|
||||||
|
const unit = await unitService.updateUnitById(req.params.unitId, req.body);
|
||||||
|
res.send(unit);
|
||||||
|
});
|
||||||
|
|
||||||
|
const deleteUnit = catchAsync(async (req, res) => {
|
||||||
|
await unitService.deleteUnitById(req.params.unitId);
|
||||||
|
res.status(httpStatus.NO_CONTENT).send();
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
createUnit,
|
||||||
|
getUnits,
|
||||||
|
getUnit,
|
||||||
|
updateUnit,
|
||||||
|
deleteUnit,
|
||||||
|
};
|
@ -1,11 +1,13 @@
|
|||||||
const mongoose = require('mongoose');
|
const mongoose = require('mongoose');
|
||||||
const { toJSON } = require('./plugins');
|
const { toJSON, paginate } = require('./plugins');
|
||||||
|
|
||||||
const activitySchema = mongoose.Schema(
|
const activitySchema = mongoose.Schema(
|
||||||
{
|
{
|
||||||
type: {
|
name: {
|
||||||
type: String,
|
type: String,
|
||||||
|
unique: true,
|
||||||
required: true,
|
required: true,
|
||||||
|
trim: true,
|
||||||
},
|
},
|
||||||
factor: {
|
factor: {
|
||||||
type: Number,
|
type: Number,
|
||||||
@ -19,6 +21,18 @@ const activitySchema = mongoose.Schema(
|
|||||||
|
|
||||||
// add plugin that converts mongoose to json
|
// add plugin that converts mongoose to json
|
||||||
activitySchema.plugin(toJSON);
|
activitySchema.plugin(toJSON);
|
||||||
|
activitySchema.plugin(paginate);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if name is taken
|
||||||
|
* @param {string} name - The activity's name
|
||||||
|
* @param {ObjectId} [excludeActivityId] - The id of the activity to be excluded
|
||||||
|
* @returns {Promise<boolean>}
|
||||||
|
*/
|
||||||
|
activitySchema.statics.isNameTaken = async function (name, excludeActivityId) {
|
||||||
|
const activity = await this.findOne({ name, _id: { $ne: excludeActivityId } });
|
||||||
|
return !!activity;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef Activity
|
* @typedef Activity
|
||||||
|
@ -1,2 +1,5 @@
|
|||||||
module.exports.Token = require('./token.model');
|
module.exports.Token = require('./token.model');
|
||||||
module.exports.User = require('./user.model');
|
module.exports.User = require('./user.model');
|
||||||
|
module.exports.Profile = require('./profile.model');
|
||||||
|
module.exports.Activity = require('./activity.model');
|
||||||
|
module.exports.Unit = require('./unit.model');
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
const mongoose = require('mongoose');
|
const mongoose = require('mongoose');
|
||||||
const { toJSON } = require('./plugins');
|
const { toJSON, paginate } = require('./plugins');
|
||||||
|
|
||||||
const profileSchema = mongoose.Schema(
|
const profileSchema = mongoose.Schema(
|
||||||
{
|
{
|
||||||
@ -26,12 +26,12 @@ const profileSchema = mongoose.Schema(
|
|||||||
rateOfChange: {
|
rateOfChange: {
|
||||||
type: Number,
|
type: Number,
|
||||||
},
|
},
|
||||||
activity: {
|
activityId: {
|
||||||
type: mongoose.SchemaTypes.ObjectId,
|
type: mongoose.SchemaTypes.ObjectId,
|
||||||
ref: 'Activity',
|
ref: 'Activity',
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
user: {
|
userId: {
|
||||||
type: mongoose.SchemaTypes.ObjectId,
|
type: mongoose.SchemaTypes.ObjectId,
|
||||||
ref: 'User',
|
ref: 'User',
|
||||||
required: true,
|
required: true,
|
||||||
@ -44,6 +44,19 @@ const profileSchema = mongoose.Schema(
|
|||||||
|
|
||||||
// add plugin that converts mongoose to json
|
// add plugin that converts mongoose to json
|
||||||
profileSchema.plugin(toJSON);
|
profileSchema.plugin(toJSON);
|
||||||
|
profileSchema.plugin(paginate);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if user has profile
|
||||||
|
* @param {ObjectId} userId - The user's id
|
||||||
|
* @param {ObjectId} [excludeProfileId] - The id of the profile to be excluded
|
||||||
|
* @returns {Promise<boolean>}
|
||||||
|
*/
|
||||||
|
profileSchema.statics.hasUser = async function (userId, excludeProfileId) {
|
||||||
|
const user = await this.findOne({ userId, _id: { $ne: excludeProfileId } });
|
||||||
|
return !!user;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef Profile
|
* @typedef Profile
|
||||||
|
38
src/models/unit.model.js
Normal file
38
src/models/unit.model.js
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
const mongoose = require('mongoose');
|
||||||
|
const { toJSON, paginate } = require('./plugins');
|
||||||
|
|
||||||
|
const unitSchema = mongoose.Schema(
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
unique: true,
|
||||||
|
required: true,
|
||||||
|
trim: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timestamps: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// add plugin that converts mongoose to json
|
||||||
|
unitSchema.plugin(toJSON);
|
||||||
|
unitSchema.plugin(paginate);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if name is taken
|
||||||
|
* @param {string} name - The unit's name
|
||||||
|
* @param {ObjectId} [excludeUnitId] - The id of the unit to be excluded
|
||||||
|
* @returns {Promise<boolean>}
|
||||||
|
*/
|
||||||
|
unitSchema.statics.isNameTaken = async function (name, excludeUnitId) {
|
||||||
|
const activity = await this.findOne({ name, _id: { $ne: excludeUnitId } });
|
||||||
|
return !!activity;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef Unit
|
||||||
|
*/
|
||||||
|
const Unit = mongoose.model('Unit', unitSchema);
|
||||||
|
|
||||||
|
module.exports = Unit;
|
@ -1,26 +0,0 @@
|
|||||||
const mongoose = require('mongoose');
|
|
||||||
const { toJSON } = require('./plugins');
|
|
||||||
|
|
||||||
const unitSchema = mongoose.Schema(
|
|
||||||
{
|
|
||||||
type: {
|
|
||||||
type: String,
|
|
||||||
unique: true,
|
|
||||||
required: true,
|
|
||||||
trim: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
timestamps: true,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// add plugin that converts mongoose to json
|
|
||||||
unitSchema.plugin(toJSON);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef Unit
|
|
||||||
*/
|
|
||||||
const Unit = mongoose.model('Unit', unitSchema);
|
|
||||||
|
|
||||||
module.exports = Unit;
|
|
@ -38,7 +38,7 @@ const userSchema = mongoose.Schema(
|
|||||||
role: {
|
role: {
|
||||||
type: String,
|
type: String,
|
||||||
enum: roles,
|
enum: roles,
|
||||||
default: 'user',
|
default: 'admin',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
231
src/routes/v1/activity.route.js
Normal file
231
src/routes/v1/activity.route.js
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const auth = require('../../middlewares/auth');
|
||||||
|
const validate = require('../../middlewares/validate');
|
||||||
|
const activityValidation = require('../../validations/activity.validation');
|
||||||
|
const activityController = require('../../controllers/activity.controller');
|
||||||
|
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
router
|
||||||
|
.route('/')
|
||||||
|
.post(auth('manageActivities'), validate(activityValidation.createActivity), activityController.createActivity)
|
||||||
|
.get(auth('getActivities'), validate(activityValidation.getActivities), activityController.getActivities);
|
||||||
|
|
||||||
|
router
|
||||||
|
.route('/:activityId')
|
||||||
|
.get(auth('getActivities'), validate(activityValidation.getActivity), activityController.getActivity)
|
||||||
|
.patch(auth('manageActivities'), validate(activityValidation.updateActivity), activityController.updateActivity)
|
||||||
|
.delete(auth('manageActivities'), validate(activityValidation.deleteActivity), activityController.deleteActivity);
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* tags:
|
||||||
|
* name: Activities
|
||||||
|
* description: Activity management
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* path:
|
||||||
|
* /activities:
|
||||||
|
* post:
|
||||||
|
* summary: Create a activity
|
||||||
|
* description: Only admins can create activities.
|
||||||
|
* tags: [Activities]
|
||||||
|
* security:
|
||||||
|
* - bearerAuth: []
|
||||||
|
* requestBody:
|
||||||
|
* required: true
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* required:
|
||||||
|
* - name
|
||||||
|
* - factor
|
||||||
|
* properties:
|
||||||
|
* name:
|
||||||
|
* type: string
|
||||||
|
* description: must be unique
|
||||||
|
* factor:
|
||||||
|
* type: number
|
||||||
|
* example:
|
||||||
|
* name: g
|
||||||
|
* factor: 1
|
||||||
|
* responses:
|
||||||
|
* "201":
|
||||||
|
* description: Created
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/Activity'
|
||||||
|
* "401":
|
||||||
|
* $ref: '#/components/responses/Unauthorized'
|
||||||
|
* "403":
|
||||||
|
* $ref: '#/components/responses/Forbidden'
|
||||||
|
*
|
||||||
|
* get:
|
||||||
|
* summary: Get all activities
|
||||||
|
* description: Only admins can retrieve all activities.
|
||||||
|
* tags: [Activities]
|
||||||
|
* security:
|
||||||
|
* - bearerAuth: []
|
||||||
|
* parameters:
|
||||||
|
* - in: query
|
||||||
|
* name: name
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* description: Activity name
|
||||||
|
* - in: query
|
||||||
|
* name: factor
|
||||||
|
* schema:
|
||||||
|
* type: number
|
||||||
|
* description: Activity factor
|
||||||
|
* - in: query
|
||||||
|
* name: sortBy
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* description: sort by query in the form of field:desc/asc (ex. name:asc)
|
||||||
|
* - in: query
|
||||||
|
* name: limit
|
||||||
|
* schema:
|
||||||
|
* type: integer
|
||||||
|
* minimum: 1
|
||||||
|
* default: 10
|
||||||
|
* description: Maximum number of activities
|
||||||
|
* - in: query
|
||||||
|
* name: page
|
||||||
|
* schema:
|
||||||
|
* type: integer
|
||||||
|
* minimum: 1
|
||||||
|
* default: 1
|
||||||
|
* description: Page number
|
||||||
|
* responses:
|
||||||
|
* "200":
|
||||||
|
* description: OK
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* results:
|
||||||
|
* type: array
|
||||||
|
* items:
|
||||||
|
* $ref: '#/components/schemas/Activity'
|
||||||
|
* page:
|
||||||
|
* type: integer
|
||||||
|
* example: 1
|
||||||
|
* limit:
|
||||||
|
* type: integer
|
||||||
|
* example: 10
|
||||||
|
* totalPages:
|
||||||
|
* type: integer
|
||||||
|
* example: 1
|
||||||
|
* totalResults:
|
||||||
|
* type: integer
|
||||||
|
* example: 1
|
||||||
|
* "401":
|
||||||
|
* $ref: '#/components/responses/Unauthorized'
|
||||||
|
* "403":
|
||||||
|
* $ref: '#/components/responses/Forbidden'
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* path:
|
||||||
|
* /activities/{id}:
|
||||||
|
* get:
|
||||||
|
* summary: Get a activity
|
||||||
|
* description: Only admins can fetch activities.
|
||||||
|
* tags: [Users]
|
||||||
|
* security:
|
||||||
|
* - bearerAuth: []
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: id
|
||||||
|
* required: true
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* description: Activity id
|
||||||
|
* responses:
|
||||||
|
* "200":
|
||||||
|
* description: OK
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/Activity'
|
||||||
|
* "401":
|
||||||
|
* $ref: '#/components/responses/Unauthorized'
|
||||||
|
* "403":
|
||||||
|
* $ref: '#/components/responses/Forbidden'
|
||||||
|
* "404":
|
||||||
|
* $ref: '#/components/responses/NotFound'
|
||||||
|
*
|
||||||
|
* patch:
|
||||||
|
* summary: Update a activity
|
||||||
|
* description: Only admins can update activities.
|
||||||
|
* tags: [Activities]
|
||||||
|
* security:
|
||||||
|
* - bearerAuth: []
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: id
|
||||||
|
* required: true
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* description: Activity id
|
||||||
|
* requestBody:
|
||||||
|
* required: true
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* name:
|
||||||
|
* type: string
|
||||||
|
* description: must be unique
|
||||||
|
* factor:
|
||||||
|
* type: number
|
||||||
|
* example:
|
||||||
|
* name: normal
|
||||||
|
* factor: 1
|
||||||
|
* responses:
|
||||||
|
* "200":
|
||||||
|
* description: OK
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/Activity'
|
||||||
|
* "400":
|
||||||
|
* "401":
|
||||||
|
* $ref: '#/components/responses/Unauthorized'
|
||||||
|
* "403":
|
||||||
|
* $ref: '#/components/responses/Forbidden'
|
||||||
|
* "404":
|
||||||
|
* $ref: '#/components/responses/NotFound'
|
||||||
|
*
|
||||||
|
* delete:
|
||||||
|
* summary: Delete a activity
|
||||||
|
* description: Only admins can delete activities.
|
||||||
|
* tags: [Activities]
|
||||||
|
* security:
|
||||||
|
* - bearerAuth: []
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: id
|
||||||
|
* required: true
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* description: Activity id
|
||||||
|
* responses:
|
||||||
|
* "200":
|
||||||
|
* description: No content
|
||||||
|
* "401":
|
||||||
|
* $ref: '#/components/responses/Unauthorized'
|
||||||
|
* "403":
|
||||||
|
* $ref: '#/components/responses/Forbidden'
|
||||||
|
* "404":
|
||||||
|
* $ref: '#/components/responses/NotFound'
|
||||||
|
*/
|
@ -1,12 +1,18 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const authRoute = require('./auth.route');
|
const authRoute = require('./auth.route');
|
||||||
const userRoute = require('./user.route');
|
const userRoute = require('./user.route');
|
||||||
|
const profileRoute = require('./profile.route');
|
||||||
|
const activityRoute = require('./activity.route');
|
||||||
|
const unitRoute = require('./unit.route');
|
||||||
const docsRoute = require('./docs.route');
|
const docsRoute = require('./docs.route');
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
router.use('/auth', authRoute);
|
router.use('/auth', authRoute);
|
||||||
router.use('/users', userRoute);
|
router.use('/users', userRoute);
|
||||||
|
router.use('/profiles', profileRoute);
|
||||||
|
router.use('/activities', activityRoute);
|
||||||
|
router.use('/units', unitRoute);
|
||||||
router.use('/docs', docsRoute);
|
router.use('/docs', docsRoute);
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
254
src/routes/v1/profile.route.js
Normal file
254
src/routes/v1/profile.route.js
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const auth = require('../../middlewares/auth');
|
||||||
|
const validate = require('../../middlewares/validate');
|
||||||
|
const profileValidation = require('../../validations/profile.validation');
|
||||||
|
const profileController = require('../../controllers/profile.controller');
|
||||||
|
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
router
|
||||||
|
.route('/')
|
||||||
|
.post(auth(), validate(profileValidation.createProfile), profileController.createProfile)
|
||||||
|
.get(auth('getProfiles'), validate(profileValidation.getProfiles), profileController.getProfiles);
|
||||||
|
|
||||||
|
router
|
||||||
|
.route('/:profileId')
|
||||||
|
.get(auth('getProfiles'), validate(profileValidation.getProfile), profileController.getProfile)
|
||||||
|
.patch(auth('manageProfiles'), validate(profileValidation.updateProfile), profileController.updateProfile)
|
||||||
|
.delete(auth('manageProfiles'), validate(profileValidation.deleteProfile), profileController.deleteProfile);
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* tags:
|
||||||
|
* name: Profiles
|
||||||
|
* description: Profile management and retrieval
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* path:
|
||||||
|
* /profiles:
|
||||||
|
* post:
|
||||||
|
* summary: Create a user
|
||||||
|
* description: Only admins can create other users.
|
||||||
|
* tags: [Users]
|
||||||
|
* security:
|
||||||
|
* - bearerAuth: []
|
||||||
|
* requestBody:
|
||||||
|
* required: true
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* required:
|
||||||
|
* - name
|
||||||
|
* - email
|
||||||
|
* - password
|
||||||
|
* - role
|
||||||
|
* properties:
|
||||||
|
* name:
|
||||||
|
* type: string
|
||||||
|
* email:
|
||||||
|
* type: string
|
||||||
|
* format: email
|
||||||
|
* description: must be unique
|
||||||
|
* password:
|
||||||
|
* type: string
|
||||||
|
* format: password
|
||||||
|
* minLength: 8
|
||||||
|
* description: At least one number and one letter
|
||||||
|
* role:
|
||||||
|
* type: string
|
||||||
|
* enum: [user, admin]
|
||||||
|
* example:
|
||||||
|
* name: fake name
|
||||||
|
* email: fake@example.com
|
||||||
|
* password: password1
|
||||||
|
* role: user
|
||||||
|
* responses:
|
||||||
|
* "201":
|
||||||
|
* description: Created
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/User'
|
||||||
|
* "400":
|
||||||
|
* $ref: '#/components/responses/DuplicateEmail'
|
||||||
|
* "401":
|
||||||
|
* $ref: '#/components/responses/Unauthorized'
|
||||||
|
* "403":
|
||||||
|
* $ref: '#/components/responses/Forbidden'
|
||||||
|
*
|
||||||
|
* get:
|
||||||
|
* summary: Get all profiles
|
||||||
|
* description: Only admins can retrieve all profiles.
|
||||||
|
* tags: [Profiles]
|
||||||
|
* security:
|
||||||
|
* - bearerAuth: []
|
||||||
|
* parameters:
|
||||||
|
* - in: query
|
||||||
|
* name: name
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* description: User name
|
||||||
|
* - in: query
|
||||||
|
* name: role
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* description: User role
|
||||||
|
* - in: query
|
||||||
|
* name: sortBy
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* description: sort by query in the form of field:desc/asc (ex. name:asc)
|
||||||
|
* - in: query
|
||||||
|
* name: limit
|
||||||
|
* schema:
|
||||||
|
* type: integer
|
||||||
|
* minimum: 1
|
||||||
|
* default: 10
|
||||||
|
* description: Maximum number of users
|
||||||
|
* - in: query
|
||||||
|
* name: page
|
||||||
|
* schema:
|
||||||
|
* type: integer
|
||||||
|
* minimum: 1
|
||||||
|
* default: 1
|
||||||
|
* description: Page number
|
||||||
|
* responses:
|
||||||
|
* "200":
|
||||||
|
* description: OK
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* results:
|
||||||
|
* type: array
|
||||||
|
* items:
|
||||||
|
* $ref: '#/components/schemas/User'
|
||||||
|
* page:
|
||||||
|
* type: integer
|
||||||
|
* example: 1
|
||||||
|
* limit:
|
||||||
|
* type: integer
|
||||||
|
* example: 10
|
||||||
|
* totalPages:
|
||||||
|
* type: integer
|
||||||
|
* example: 1
|
||||||
|
* totalResults:
|
||||||
|
* type: integer
|
||||||
|
* example: 1
|
||||||
|
* "401":
|
||||||
|
* $ref: '#/components/responses/Unauthorized'
|
||||||
|
* "403":
|
||||||
|
* $ref: '#/components/responses/Forbidden'
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* path:
|
||||||
|
* /profiles/{id}:
|
||||||
|
* get:
|
||||||
|
* summary: Get a profile
|
||||||
|
* description: Logged in users can fetch only their own profile information. Only admins can fetch other profiles.
|
||||||
|
* tags: [Profiles]
|
||||||
|
* security:
|
||||||
|
* - bearerAuth: []
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: id
|
||||||
|
* required: true
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* description: User id
|
||||||
|
* responses:
|
||||||
|
* "200":
|
||||||
|
* description: OK
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/User'
|
||||||
|
* "401":
|
||||||
|
* $ref: '#/components/responses/Unauthorized'
|
||||||
|
* "403":
|
||||||
|
* $ref: '#/components/responses/Forbidden'
|
||||||
|
* "404":
|
||||||
|
* $ref: '#/components/responses/NotFound'
|
||||||
|
*
|
||||||
|
* patch:
|
||||||
|
* summary: Update a profile
|
||||||
|
* description: Logged in users can only update their own information. Only admins can update other profiles.
|
||||||
|
* tags: [Profiles]
|
||||||
|
* security:
|
||||||
|
* - bearerAuth: []
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: id
|
||||||
|
* required: true
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* description: User id
|
||||||
|
* requestBody:
|
||||||
|
* required: true
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* name:
|
||||||
|
* type: string
|
||||||
|
* email:
|
||||||
|
* type: string
|
||||||
|
* format: email
|
||||||
|
* description: must be unique
|
||||||
|
* password:
|
||||||
|
* type: string
|
||||||
|
* format: password
|
||||||
|
* minLength: 8
|
||||||
|
* description: At least one number and one letter
|
||||||
|
* example:
|
||||||
|
* name: fake name
|
||||||
|
* email: fake@example.com
|
||||||
|
* password: password1
|
||||||
|
* responses:
|
||||||
|
* "200":
|
||||||
|
* description: OK
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/User'
|
||||||
|
* "400":
|
||||||
|
* $ref: '#/components/responses/DuplicateEmail'
|
||||||
|
* "401":
|
||||||
|
* $ref: '#/components/responses/Unauthorized'
|
||||||
|
* "403":
|
||||||
|
* $ref: '#/components/responses/Forbidden'
|
||||||
|
* "404":
|
||||||
|
* $ref: '#/components/responses/NotFound'
|
||||||
|
*
|
||||||
|
* delete:
|
||||||
|
* summary: Delete a profile
|
||||||
|
* description: Logged in users can delete only themselves. Only admins can delete other users.
|
||||||
|
* tags: [Users]
|
||||||
|
* security:
|
||||||
|
* - bearerAuth: []
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: id
|
||||||
|
* required: true
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* description: User id
|
||||||
|
* responses:
|
||||||
|
* "200":
|
||||||
|
* description: No content
|
||||||
|
* "401":
|
||||||
|
* $ref: '#/components/responses/Unauthorized'
|
||||||
|
* "403":
|
||||||
|
* $ref: '#/components/responses/Forbidden'
|
||||||
|
* "404":
|
||||||
|
* $ref: '#/components/responses/NotFound'
|
||||||
|
*/
|
224
src/routes/v1/unit.route.js
Normal file
224
src/routes/v1/unit.route.js
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const auth = require('../../middlewares/auth');
|
||||||
|
const validate = require('../../middlewares/validate');
|
||||||
|
const unitValidation = require('../../validations/unit.validation');
|
||||||
|
const unitController = require('../../controllers/unit.controller');
|
||||||
|
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
router
|
||||||
|
.route('/')
|
||||||
|
.post(auth('manageUnits'), validate(unitValidation.createUnit), unitController.createUnit)
|
||||||
|
.get(auth('getUnits'), validate(unitValidation.getUnits), unitController.getUnits);
|
||||||
|
|
||||||
|
router
|
||||||
|
.route('/:activityId')
|
||||||
|
.get(auth('getUnits'), validate(unitValidation.getUnit), unitController.getUnit)
|
||||||
|
.patch(auth('manageUnits'), validate(unitValidation.updateUnit), unitController.updateUnit)
|
||||||
|
.delete(auth('manageUnits'), validate(unitValidation.deleteUnit), unitController.deleteUnit);
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* tags:
|
||||||
|
* name: Units
|
||||||
|
* description: Unit management
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* path:
|
||||||
|
* /units:
|
||||||
|
* post:
|
||||||
|
* summary: Create a unit
|
||||||
|
* description: Only admins can create units.
|
||||||
|
* tags: [Units]
|
||||||
|
* security:
|
||||||
|
* - bearerAuth: []
|
||||||
|
* requestBody:
|
||||||
|
* required: true
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* required:
|
||||||
|
* - name
|
||||||
|
* properties:
|
||||||
|
* name:
|
||||||
|
* type: string
|
||||||
|
* description: must be unique
|
||||||
|
* example:
|
||||||
|
* name: g
|
||||||
|
* responses:
|
||||||
|
* "201":
|
||||||
|
* description: Created
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/Unit'
|
||||||
|
* "400":
|
||||||
|
* "401":
|
||||||
|
* $ref: '#/components/responses/Unauthorized'
|
||||||
|
* "403":
|
||||||
|
* $ref: '#/components/responses/Forbidden'
|
||||||
|
*
|
||||||
|
* get:
|
||||||
|
* summary: Get all units
|
||||||
|
* description: Only admins can retrieve all units.
|
||||||
|
* tags: [Units]
|
||||||
|
* security:
|
||||||
|
* - bearerAuth: []
|
||||||
|
* parameters:
|
||||||
|
* - in: query
|
||||||
|
* name: name
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* description: unit name
|
||||||
|
* - in: query
|
||||||
|
* name: name
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* description: Unit name
|
||||||
|
* - in: query
|
||||||
|
* name: sortBy
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* description: sort by query in the form of field:desc/asc (ex. name:asc)
|
||||||
|
* - in: query
|
||||||
|
* name: limit
|
||||||
|
* schema:
|
||||||
|
* type: integer
|
||||||
|
* minimum: 1
|
||||||
|
* default: 10
|
||||||
|
* description: Maximum number of units
|
||||||
|
* - in: query
|
||||||
|
* name: page
|
||||||
|
* schema:
|
||||||
|
* type: integer
|
||||||
|
* minimum: 1
|
||||||
|
* default: 1
|
||||||
|
* description: Page number
|
||||||
|
* responses:
|
||||||
|
* "200":
|
||||||
|
* description: OK
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* results:
|
||||||
|
* type: array
|
||||||
|
* items:
|
||||||
|
* $ref: '#/components/schemas/Unit'
|
||||||
|
* page:
|
||||||
|
* type: integer
|
||||||
|
* example: 1
|
||||||
|
* limit:
|
||||||
|
* type: integer
|
||||||
|
* example: 10
|
||||||
|
* totalPages:
|
||||||
|
* type: integer
|
||||||
|
* example: 1
|
||||||
|
* totalResults:
|
||||||
|
* type: integer
|
||||||
|
* example: 1
|
||||||
|
* "401":
|
||||||
|
* $ref: '#/components/responses/Unauthorized'
|
||||||
|
* "403":
|
||||||
|
* $ref: '#/components/responses/Forbidden'
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* path:
|
||||||
|
* /units/{id}:
|
||||||
|
* get:
|
||||||
|
* summary: Get a unit
|
||||||
|
* description: Logged in users and admins can fetch units.
|
||||||
|
* tags: [Units]
|
||||||
|
* security:
|
||||||
|
* - bearerAuth: []
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: id
|
||||||
|
* required: true
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* description: Unit id
|
||||||
|
* responses:
|
||||||
|
* "200":
|
||||||
|
* description: OK
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/Unit'
|
||||||
|
* "401":
|
||||||
|
* $ref: '#/components/responses/Unauthorized'
|
||||||
|
* "403":
|
||||||
|
* $ref: '#/components/responses/Forbidden'
|
||||||
|
* "404":
|
||||||
|
* $ref: '#/components/responses/NotFound'
|
||||||
|
*
|
||||||
|
* patch:
|
||||||
|
* summary: Update a unit
|
||||||
|
* description: Only admins can update units.
|
||||||
|
* tags: [Users]
|
||||||
|
* security:
|
||||||
|
* - bearerAuth: []
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: id
|
||||||
|
* required: true
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* description: Unit id
|
||||||
|
* requestBody:
|
||||||
|
* required: true
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* name:
|
||||||
|
* type: string
|
||||||
|
* description: must be unique
|
||||||
|
* example:
|
||||||
|
* name: g
|
||||||
|
* responses:
|
||||||
|
* "200":
|
||||||
|
* description: OK
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/Unit'
|
||||||
|
* "401":
|
||||||
|
* $ref: '#/components/responses/Unauthorized'
|
||||||
|
* "403":
|
||||||
|
* $ref: '#/components/responses/Forbidden'
|
||||||
|
* "404":
|
||||||
|
* $ref: '#/components/responses/NotFound'
|
||||||
|
*
|
||||||
|
* delete:
|
||||||
|
* summary: Delete a unit
|
||||||
|
* description: Only admins can delete units.
|
||||||
|
* tags: [Users]
|
||||||
|
* security:
|
||||||
|
* - bearerAuth: []
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: id
|
||||||
|
* required: true
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* description: Unit id
|
||||||
|
* responses:
|
||||||
|
* "200":
|
||||||
|
* description: No content
|
||||||
|
* "401":
|
||||||
|
* $ref: '#/components/responses/Unauthorized'
|
||||||
|
* "403":
|
||||||
|
* $ref: '#/components/responses/Forbidden'
|
||||||
|
* "404":
|
||||||
|
* $ref: '#/components/responses/NotFound'
|
||||||
|
*/
|
77
src/services/activity.service.js
Normal file
77
src/services/activity.service.js
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
const httpStatus = require('http-status');
|
||||||
|
const { Activity } = require('../models');
|
||||||
|
const ApiError = require('../utils/ApiError');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a activity
|
||||||
|
* @param {Object} activityBody
|
||||||
|
* @returns {Promise<Activity>}
|
||||||
|
*/
|
||||||
|
const createActivity = async (activityBody) => {
|
||||||
|
if (await Activity.isNameTaken(activityBody.name)) {
|
||||||
|
throw new ApiError(httpStatus.BAD_REQUEST, 'Name already taken');
|
||||||
|
}
|
||||||
|
const activity = await Activity.create(activityBody);
|
||||||
|
return activity;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query for activity
|
||||||
|
* @param {Object} filter - Mongo filter
|
||||||
|
* @param {Object} options - Query options
|
||||||
|
* @param {string} [options.sortBy] - Sort option in the format: sortField:(desc|asc)
|
||||||
|
* @param {number} [options.limit] - Maximum number of results per page (default = 10)
|
||||||
|
* @param {number} [options.page] - Current page (default = 1)
|
||||||
|
* @returns {Promise<QueryResult>}
|
||||||
|
*/
|
||||||
|
const queryActivities = async (filter, options) => {
|
||||||
|
const activities = await Activity.paginate(filter, options);
|
||||||
|
return activities;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get profile by id
|
||||||
|
* @param {ObjectId} id
|
||||||
|
* @returns {Promise<Profile>}
|
||||||
|
*/
|
||||||
|
const getActivityById = async (id) => {
|
||||||
|
return Activity.findById(id);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update activity by id
|
||||||
|
* @param {ObjectId} activityId
|
||||||
|
* @param {Object} updateBody
|
||||||
|
* @returns {Promise<Profile>}
|
||||||
|
*/
|
||||||
|
const updateActivityById = async (activityId, updateBody) => {
|
||||||
|
const activity = await getActivityById(activityId);
|
||||||
|
if (!activity) {
|
||||||
|
throw new ApiError(httpStatus.NOT_FOUND, 'Activity not found');
|
||||||
|
}
|
||||||
|
Object.assign(activity, updateBody);
|
||||||
|
await activity.save();
|
||||||
|
return activity;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete activity by id
|
||||||
|
* @param {ObjectId} activityId
|
||||||
|
* @returns {Promise<Activity>}
|
||||||
|
*/
|
||||||
|
const deleteActivityById = async (activityId) => {
|
||||||
|
const activity = await getActivityById(activityId);
|
||||||
|
if (!activity) {
|
||||||
|
throw new ApiError(httpStatus.NOT_FOUND, 'Activity not found');
|
||||||
|
}
|
||||||
|
await activity.remove();
|
||||||
|
return activity;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
createActivity,
|
||||||
|
queryActivities,
|
||||||
|
getActivityById,
|
||||||
|
updateActivityById,
|
||||||
|
deleteActivityById,
|
||||||
|
};
|
@ -2,3 +2,6 @@ module.exports.authService = require('./auth.service');
|
|||||||
module.exports.emailService = require('./email.service');
|
module.exports.emailService = require('./email.service');
|
||||||
module.exports.tokenService = require('./token.service');
|
module.exports.tokenService = require('./token.service');
|
||||||
module.exports.userService = require('./user.service');
|
module.exports.userService = require('./user.service');
|
||||||
|
module.exports.profileService = require('./profile.service');
|
||||||
|
module.exports.activityService = require('./activity.service');
|
||||||
|
module.exports.unitService = require('./unit.service');
|
||||||
|
87
src/services/profile.service.js
Normal file
87
src/services/profile.service.js
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
const httpStatus = require('http-status');
|
||||||
|
const { Profile } = require('../models');
|
||||||
|
const ApiError = require('../utils/ApiError');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a profile
|
||||||
|
* @param {Object} profileBody
|
||||||
|
* @returns {Promise<Profile>}
|
||||||
|
*/
|
||||||
|
const createProfile = async (profileBody) => {
|
||||||
|
if (await Profile.hasUser(profileBody.userId)) {
|
||||||
|
throw new ApiError(httpStatus.BAD_REQUEST, 'User already has a profile');
|
||||||
|
}
|
||||||
|
const profile = await Profile.create(profileBody);
|
||||||
|
return profile;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query for profiles
|
||||||
|
* @param {Object} filter - Mongo filter
|
||||||
|
* @param {Object} options - Query options
|
||||||
|
* @param {string} [options.sortBy] - Sort option in the format: sortField:(desc|asc)
|
||||||
|
* @param {number} [options.limit] - Maximum number of results per page (default = 10)
|
||||||
|
* @param {number} [options.page] - Current page (default = 1)
|
||||||
|
* @returns {Promise<QueryResult>}
|
||||||
|
*/
|
||||||
|
const queryProfiles = async (filter, options) => {
|
||||||
|
const profiles = await Profile.paginate(filter, options);
|
||||||
|
return profiles;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get profile by id
|
||||||
|
* @param {ObjectId} id
|
||||||
|
* @returns {Promise<Profile>}
|
||||||
|
*/
|
||||||
|
const getProfileById = async (id) => {
|
||||||
|
return Profile.findById(id);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get profile by user id
|
||||||
|
* @param {ObjectId} id
|
||||||
|
* @returns {Promise<User>}
|
||||||
|
*/
|
||||||
|
const getProfileByUserId = async (id) => {
|
||||||
|
return Profile.findOne({ user: id });
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update profile by id
|
||||||
|
* @param {ObjectId} profileId
|
||||||
|
* @param {Object} updateBody
|
||||||
|
* @returns {Promise<Profile>}
|
||||||
|
*/
|
||||||
|
const updateProfileById = async (profileId, updateBody) => {
|
||||||
|
const profile = await getProfileById(profileId);
|
||||||
|
if (!profile) {
|
||||||
|
throw new ApiError(httpStatus.NOT_FOUND, 'Profile not found');
|
||||||
|
}
|
||||||
|
Object.assign(profile, updateBody);
|
||||||
|
await profile.save();
|
||||||
|
return profile;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete profile by id
|
||||||
|
* @param {ObjectId} profileId
|
||||||
|
* @returns {Promise<User>}
|
||||||
|
*/
|
||||||
|
const deleteProfileById = async (profileId) => {
|
||||||
|
const profile = await getProfileById(profileId);
|
||||||
|
if (!profile) {
|
||||||
|
throw new ApiError(httpStatus.NOT_FOUND, 'Profile not found');
|
||||||
|
}
|
||||||
|
await profile.remove();
|
||||||
|
return profile;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
createProfile,
|
||||||
|
queryProfiles,
|
||||||
|
getProfileById,
|
||||||
|
getProfileByUserId,
|
||||||
|
updateProfileById,
|
||||||
|
deleteProfileById,
|
||||||
|
};
|
77
src/services/unit.service.js
Normal file
77
src/services/unit.service.js
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
const httpStatus = require('http-status');
|
||||||
|
const { Unit } = require('../models');
|
||||||
|
const ApiError = require('../utils/ApiError');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a unit
|
||||||
|
* @param {Object} unitBody
|
||||||
|
* @returns {Promise<Unit>}
|
||||||
|
*/
|
||||||
|
const createUnit = async (unitBody) => {
|
||||||
|
if (await Unit.isNameTaken(unitBody.name)) {
|
||||||
|
throw new ApiError(httpStatus.BAD_REQUEST, 'Name already taken');
|
||||||
|
}
|
||||||
|
const unit = await Unit.create(unitBody);
|
||||||
|
return unit;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query for unit
|
||||||
|
* @param {Object} filter - Mongo filter
|
||||||
|
* @param {Object} options - Query options
|
||||||
|
* @param {string} [options.sortBy] - Sort option in the format: sortField:(desc|asc)
|
||||||
|
* @param {number} [options.limit] - Maximum number of results per page (default = 10)
|
||||||
|
* @param {number} [options.page] - Current page (default = 1)
|
||||||
|
* @returns {Promise<QueryResult>}
|
||||||
|
*/
|
||||||
|
const queryUnits = async (filter, options) => {
|
||||||
|
const units = await Unit.paginate(filter, options);
|
||||||
|
return units;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get unit by id
|
||||||
|
* @param {ObjectId} id
|
||||||
|
* @returns {Promise<Unit>}
|
||||||
|
*/
|
||||||
|
const getUnitById = async (id) => {
|
||||||
|
return Unit.findById(id);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update unit by id
|
||||||
|
* @param {ObjectId} unitId
|
||||||
|
* @param {Object} updateBody
|
||||||
|
* @returns {Promise<Unit>}
|
||||||
|
*/
|
||||||
|
const updateUnitById = async (unitId, updateBody) => {
|
||||||
|
const unit = await getUnitById(unitId);
|
||||||
|
if (!unit) {
|
||||||
|
throw new ApiError(httpStatus.NOT_FOUND, 'Unit not found');
|
||||||
|
}
|
||||||
|
Object.assign(unit, updateBody);
|
||||||
|
await Unit.save();
|
||||||
|
return unit;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete unit by id
|
||||||
|
* @param {ObjectId} unitId
|
||||||
|
* @returns {Promise<Activity>}
|
||||||
|
*/
|
||||||
|
const deleteUnitById = async (unitId) => {
|
||||||
|
const unit = await getUnitById(unitId);
|
||||||
|
if (!unit) {
|
||||||
|
throw new ApiError(httpStatus.NOT_FOUND, 'Unit not found');
|
||||||
|
}
|
||||||
|
await Unit.remove();
|
||||||
|
return unit;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
createUnit,
|
||||||
|
queryUnits,
|
||||||
|
getUnitById,
|
||||||
|
updateUnitById,
|
||||||
|
deleteUnitById,
|
||||||
|
};
|
50
src/validations/activity.validation.js
Normal file
50
src/validations/activity.validation.js
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
const Joi = require('joi');
|
||||||
|
const { objectId } = require('./custom.validation');
|
||||||
|
|
||||||
|
const createActivity = {
|
||||||
|
body: Joi.object().keys({
|
||||||
|
name: Joi.string().required(),
|
||||||
|
factor: Joi.number().required(),
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
const getActivities = {
|
||||||
|
query: Joi.object().keys({
|
||||||
|
name: Joi.string(),
|
||||||
|
factor: Joi.number(),
|
||||||
|
limit: Joi.number().integer(),
|
||||||
|
page: Joi.number().integer(),
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
const getActivity = {
|
||||||
|
params: Joi.object().keys({
|
||||||
|
activityId: Joi.string().custom(objectId),
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateActivity = {
|
||||||
|
params: Joi.object().keys({
|
||||||
|
activityId: Joi.string().custom(objectId),
|
||||||
|
}),
|
||||||
|
body: Joi.object()
|
||||||
|
.keys({
|
||||||
|
name: Joi.string().required(),
|
||||||
|
factor: Joi.number().required(),
|
||||||
|
})
|
||||||
|
.min(1),
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteActivity = {
|
||||||
|
params: Joi.object().keys({
|
||||||
|
profileId: Joi.string().custom(objectId),
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
createActivity,
|
||||||
|
getActivities,
|
||||||
|
getActivity,
|
||||||
|
updateActivity,
|
||||||
|
deleteActivity,
|
||||||
|
};
|
@ -1,2 +1,5 @@
|
|||||||
module.exports.authValidation = require('./auth.validation');
|
module.exports.authValidation = require('./auth.validation');
|
||||||
module.exports.userValidation = require('./user.validation');
|
module.exports.userValidation = require('./user.validation');
|
||||||
|
module.exports.profileValidation = require('./profile.validation');
|
||||||
|
module.exports.activityValidation = require('./activity.validation');
|
||||||
|
module.exports.unitValidation = require('./unit.validation');
|
||||||
|
60
src/validations/profile.validation.js
Normal file
60
src/validations/profile.validation.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
const Joi = require('joi');
|
||||||
|
const { objectId } = require('./custom.validation');
|
||||||
|
|
||||||
|
const createProfile = {
|
||||||
|
body: Joi.object().keys({
|
||||||
|
sex: Joi.string().required().valid('male', 'female'),
|
||||||
|
birthday: Joi.date().required(),
|
||||||
|
height: Joi.number().required(),
|
||||||
|
currentWeight: Joi.number().required(),
|
||||||
|
targetWeight: Joi.number(),
|
||||||
|
rateOfChange: Joi.number(),
|
||||||
|
activityId: Joi.string().custom(objectId).required(),
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
const getProfiles = {
|
||||||
|
query: Joi.object().keys({
|
||||||
|
sex: Joi.string(),
|
||||||
|
sortBy: Joi.string(),
|
||||||
|
limit: Joi.number().integer(),
|
||||||
|
page: Joi.number().integer(),
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
const getProfile = {
|
||||||
|
params: Joi.object().keys({
|
||||||
|
profileId: Joi.string().custom(objectId),
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateProfile = {
|
||||||
|
params: Joi.object().keys({
|
||||||
|
profileId: Joi.required().custom(objectId),
|
||||||
|
}),
|
||||||
|
body: Joi.object()
|
||||||
|
.keys({
|
||||||
|
sex: Joi.string().required().valid('male', 'female'),
|
||||||
|
birthday: Joi.date().required(),
|
||||||
|
height: Joi.number().required(),
|
||||||
|
currentWeight: Joi.number().required(),
|
||||||
|
targetWeight: Joi.number(),
|
||||||
|
rateOfChange: Joi.number(),
|
||||||
|
activityId: Joi.string().custom(objectId).required(),
|
||||||
|
})
|
||||||
|
.min(1),
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteProfile = {
|
||||||
|
params: Joi.object().keys({
|
||||||
|
profileId: Joi.string().custom(objectId).required(),
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
createProfile,
|
||||||
|
getProfiles,
|
||||||
|
getProfile,
|
||||||
|
updateProfile,
|
||||||
|
deleteProfile,
|
||||||
|
};
|
47
src/validations/unit.validation.js
Normal file
47
src/validations/unit.validation.js
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
const Joi = require('joi');
|
||||||
|
const { objectId } = require('./custom.validation');
|
||||||
|
|
||||||
|
const createUnit = {
|
||||||
|
body: Joi.object().keys({
|
||||||
|
name: Joi.string().required(),
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
const getUnits = {
|
||||||
|
query: Joi.object().keys({
|
||||||
|
name: Joi.string(),
|
||||||
|
limit: Joi.number().integer(),
|
||||||
|
page: Joi.number().integer(),
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
const getUnit = {
|
||||||
|
params: Joi.object().keys({
|
||||||
|
unitId: Joi.string().custom(objectId),
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateUnit = {
|
||||||
|
params: Joi.object().keys({
|
||||||
|
unitId: Joi.string().custom(objectId),
|
||||||
|
}),
|
||||||
|
body: Joi.object()
|
||||||
|
.keys({
|
||||||
|
name: Joi.string().required(),
|
||||||
|
})
|
||||||
|
.min(1),
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteUnit = {
|
||||||
|
params: Joi.object().keys({
|
||||||
|
unitId: Joi.string().custom(objectId),
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
createUnit,
|
||||||
|
getUnits,
|
||||||
|
getUnit,
|
||||||
|
updateUnit,
|
||||||
|
deleteUnit,
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user