mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-16 12:50:38 +00:00
280 lines
7.3 KiB
TypeScript
280 lines
7.3 KiB
TypeScript
import { Service, Inject } from 'typedi';
|
|
import { Router, Request, Response } from 'express';
|
|
import { check, oneOf, ValidationChain } from 'express-validator';
|
|
import basicAuth from 'express-basic-auth';
|
|
import config from 'config';
|
|
import { License, Plan } from 'system/models';
|
|
import BaseController from 'api/controllers/BaseController';
|
|
import LicenseService from 'services/Payment/License';
|
|
import asyncMiddleware from 'api/middleware/asyncMiddleware';
|
|
import { ILicensesFilter } from 'interfaces';
|
|
|
|
@Service()
|
|
export default class LicensesController extends BaseController {
|
|
@Inject()
|
|
licenseService: LicenseService;
|
|
|
|
/**
|
|
* Router constructor.
|
|
*/
|
|
router() {
|
|
const router = Router();
|
|
|
|
router.use(
|
|
basicAuth({
|
|
users: {
|
|
[config.licensesAuth.user]: config.licensesAuth.password,
|
|
},
|
|
challenge: true,
|
|
})
|
|
);
|
|
router.post(
|
|
'/generate',
|
|
this.generateLicenseSchema,
|
|
this.validationResult,
|
|
asyncMiddleware(this.validatePlanExistance.bind(this)),
|
|
asyncMiddleware(this.generateLicense.bind(this))
|
|
);
|
|
router.post(
|
|
'/disable/:licenseId',
|
|
this.validationResult,
|
|
asyncMiddleware(this.validateLicenseExistance.bind(this)),
|
|
asyncMiddleware(this.validateNotDisabledLicense.bind(this)),
|
|
asyncMiddleware(this.disableLicense.bind(this))
|
|
);
|
|
router.post(
|
|
'/send',
|
|
this.sendLicenseSchemaValidation,
|
|
this.validationResult,
|
|
asyncMiddleware(this.sendLicense.bind(this))
|
|
);
|
|
router.delete(
|
|
'/:licenseId',
|
|
asyncMiddleware(this.validateLicenseExistance.bind(this)),
|
|
asyncMiddleware(this.deleteLicense.bind(this))
|
|
);
|
|
router.get('/', asyncMiddleware(this.listLicenses.bind(this)));
|
|
return router;
|
|
}
|
|
|
|
/**
|
|
* Generate license validation schema.
|
|
*/
|
|
get generateLicenseSchema(): ValidationChain[] {
|
|
return [
|
|
check('loop').exists().isNumeric().toInt(),
|
|
check('period').exists().isNumeric().toInt(),
|
|
check('period_interval')
|
|
.exists()
|
|
.isIn(['month', 'months', 'year', 'years', 'day', 'days']),
|
|
check('plan_id').exists().isNumeric().toInt(),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Specific license validation schema.
|
|
*/
|
|
get specificLicenseSchema(): ValidationChain[] {
|
|
return [
|
|
oneOf(
|
|
[check('license_id').exists().isNumeric().toInt()],
|
|
[check('license_code').exists().isNumeric().toInt()]
|
|
),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Send license validation schema.
|
|
*/
|
|
get sendLicenseSchemaValidation(): ValidationChain[] {
|
|
return [
|
|
check('period').exists().isNumeric(),
|
|
check('period_interval').exists().trim().escape(),
|
|
check('plan_id').exists().isNumeric().toInt(),
|
|
oneOf([
|
|
check('phone_number').exists().trim().escape(),
|
|
check('email').exists().trim().escape(),
|
|
]),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Validate the plan existance on the storage.
|
|
* @param {Request} req
|
|
* @param {Response} res
|
|
* @param {Function} next
|
|
*/
|
|
async validatePlanExistance(req: Request, res: Response, next: Function) {
|
|
const body = this.matchedBodyData(req);
|
|
const planId: number = body.planId || req.params.planId;
|
|
const foundPlan = await Plan.query().findById(planId);
|
|
|
|
if (!foundPlan) {
|
|
return res.status(400).send({
|
|
erorrs: [{ type: 'PLAN.NOT.FOUND', code: 100 }],
|
|
});
|
|
}
|
|
next();
|
|
}
|
|
|
|
/**
|
|
* Valdiate the license existance on the storage.
|
|
* @param {Request} req
|
|
* @param {Response} res
|
|
* @param {Function}
|
|
*/
|
|
async validateLicenseExistance(req: Request, res: Response, next: Function) {
|
|
const body = this.matchedBodyData(req);
|
|
|
|
const licenseId = body.licenseId || req.params.licenseId;
|
|
const foundLicense = await License.query().findById(licenseId);
|
|
|
|
if (!foundLicense) {
|
|
return res.status(400).send({
|
|
errors: [{ type: 'LICENSE.NOT.FOUND', code: 200 }],
|
|
});
|
|
}
|
|
next();
|
|
}
|
|
|
|
/**
|
|
* Validates whether the license id is disabled.
|
|
* @param {Request} req
|
|
* @param {Response} res
|
|
* @param {Function} next
|
|
*/
|
|
async validateNotDisabledLicense(
|
|
req: Request,
|
|
res: Response,
|
|
next: Function
|
|
) {
|
|
const licenseId = req.params.licenseId || req.query.licenseId;
|
|
const foundLicense = await License.query().findById(licenseId);
|
|
|
|
if (foundLicense.disabled) {
|
|
return res.status(400).send({
|
|
errors: [{ type: 'LICENSE.ALREADY.DISABLED', code: 200 }],
|
|
});
|
|
}
|
|
next();
|
|
}
|
|
|
|
/**
|
|
* Generate licenses codes with given period in bulk.
|
|
* @param {Request} req
|
|
* @param {Response} res
|
|
* @return {Response}
|
|
*/
|
|
async generateLicense(req: Request, res: Response, next: Function) {
|
|
const { loop = 10, period, periodInterval, planId } = this.matchedBodyData(
|
|
req
|
|
);
|
|
|
|
try {
|
|
await this.licenseService.generateLicenses(
|
|
loop,
|
|
period,
|
|
periodInterval,
|
|
planId
|
|
);
|
|
return res.status(200).send({
|
|
code: 100,
|
|
type: 'LICENSEES.GENERATED.SUCCESSFULLY',
|
|
message: 'The licenses have been generated successfully.',
|
|
});
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Disable the given license on the storage.
|
|
* @param {Request} req
|
|
* @param {Response} res
|
|
* @return {Response}
|
|
*/
|
|
async disableLicense(req: Request, res: Response) {
|
|
const { licenseId } = req.params;
|
|
|
|
await this.licenseService.disableLicense(licenseId);
|
|
|
|
return res.status(200).send({ license_id: licenseId });
|
|
}
|
|
|
|
/**
|
|
* Deletes the given license code on the storage.
|
|
* @param {Request} req
|
|
* @param {Response} res
|
|
* @return {Response}
|
|
*/
|
|
async deleteLicense(req: Request, res: Response) {
|
|
const { licenseId } = req.params;
|
|
|
|
await this.licenseService.deleteLicense(licenseId);
|
|
|
|
return res.status(200).send({ license_id: licenseId });
|
|
}
|
|
|
|
/**
|
|
* Send license code in the given period to the customer via email or phone number
|
|
* @param {Request} req
|
|
* @param {Response} res
|
|
* @return {Response}
|
|
*/
|
|
async sendLicense(req: Request, res: Response) {
|
|
const {
|
|
phoneNumber,
|
|
email,
|
|
period,
|
|
periodInterval,
|
|
planId,
|
|
} = this.matchedBodyData(req);
|
|
|
|
const license = await License.query()
|
|
.modify('filterActiveLicense')
|
|
.where('license_period', period)
|
|
.where('period_interval', periodInterval)
|
|
.where('plan_id', planId)
|
|
.first();
|
|
|
|
if (!license) {
|
|
return res.status(400).send({
|
|
status: 110,
|
|
message:
|
|
'There is no licenses availiable right now with the given period and plan.',
|
|
code: 'NO.AVALIABLE.LICENSE.CODE',
|
|
});
|
|
}
|
|
await this.licenseService.sendLicenseToCustomer(
|
|
license.licenseCode,
|
|
phoneNumber,
|
|
email
|
|
);
|
|
return res.status(200).send({
|
|
status: 100,
|
|
code: 'LICENSE.CODE.SENT',
|
|
message: 'The license has been sent to the given customer.',
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Listing licenses.
|
|
* @param {Request} req
|
|
* @param {Response} res
|
|
*/
|
|
async listLicenses(req: Request, res: Response) {
|
|
const filter: ILicensesFilter = {
|
|
disabled: false,
|
|
used: false,
|
|
sent: false,
|
|
active: false,
|
|
...req.query,
|
|
};
|
|
const licenses = await License.query().onBuild((builder) => {
|
|
builder.modify('filter', filter);
|
|
builder.orderBy('createdAt', 'ASC');
|
|
});
|
|
return res.status(200).send({ licenses });
|
|
}
|
|
}
|