99 lines
3.2 KiB
JavaScript
99 lines
3.2 KiB
JavaScript
const path = require('path');
|
|
const { authenticateToken, authenticateAdmin } = require(path.resolve(process.env.ROOT_PATH, './middleware/auth.js'));
|
|
|
|
class BaseController {
|
|
constructor() {
|
|
// Bind all methods to this to maintain context when used as route handlers
|
|
const methods = Object.getOwnPropertyNames(Object.getPrototypeOf(this))
|
|
.filter(method => method !== 'constructor' && typeof this[method] === 'function');
|
|
|
|
methods.forEach(method => {
|
|
this[method] = this[method].bind(this);
|
|
});
|
|
|
|
// Store original methods before potentially wrapping them with auth
|
|
this._originalMethods = {};
|
|
methods.forEach(method => {
|
|
this._originalMethods[method] = this[method];
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Protects the given methods with authentication
|
|
* @param {string|string[]} methodNames - The method names to protect
|
|
* @returns {BaseController} The current instance for method chaining
|
|
*/
|
|
protected(methodNames) {
|
|
if (!Array.isArray(methodNames)) {
|
|
methodNames = [methodNames];
|
|
}
|
|
|
|
methodNames.forEach(methodName => {
|
|
if (typeof this[methodName] !== 'function') {
|
|
throw new Error(`Method ${methodName} does not exist on ${this.constructor.name}`);
|
|
}
|
|
|
|
// Store original method if not already stored
|
|
if (!this._originalMethods[methodName]) {
|
|
this._originalMethods[methodName] = this[methodName];
|
|
}
|
|
|
|
// Replace the method with one that applies authentication first
|
|
this[methodName] = (req, res, next) => {
|
|
return authenticateToken(req, res, (err) => {
|
|
if (err) return next(err);
|
|
return this._originalMethods[methodName](req, res, next);
|
|
});
|
|
};
|
|
});
|
|
|
|
return this; // For method chaining
|
|
}
|
|
|
|
/**
|
|
* Protects the given methods with admin authentication
|
|
* @param {string|string[]} methodNames - The method names to protect. Use "*" to protect all methods.
|
|
* @returns {BaseController} The current instance for method chaining
|
|
*/
|
|
admin(methodNames) {
|
|
if (!Array.isArray(methodNames)) {
|
|
methodNames = [methodNames];
|
|
}
|
|
|
|
// If "*" is included, protect all methods
|
|
if (methodNames.includes("*")) {
|
|
const allMethods = Object.getOwnPropertyNames(Object.getPrototypeOf(this))
|
|
.filter(method =>
|
|
method !== 'constructor' &&
|
|
method !== 'protected' &&
|
|
method !== 'admin' &&
|
|
typeof this[method] === 'function'
|
|
);
|
|
|
|
return this.admin(allMethods);
|
|
}
|
|
|
|
methodNames.forEach(methodName => {
|
|
if (typeof this[methodName] !== 'function') {
|
|
throw new Error(`Method ${methodName} does not exist on ${this.constructor.name}`);
|
|
}
|
|
|
|
// Store original method if not already stored
|
|
if (!this._originalMethods[methodName]) {
|
|
this._originalMethods[methodName] = this[methodName];
|
|
}
|
|
|
|
// Replace the method with one that applies admin authentication first
|
|
this[methodName] = (req, res, next) => {
|
|
return authenticateAdmin(req, res, (err) => {
|
|
if (err) return next(err);
|
|
return this._originalMethods[methodName](req, res, next);
|
|
});
|
|
};
|
|
});
|
|
|
|
return this; // For method chaining
|
|
}
|
|
}
|
|
|
|
module.exports = BaseController;
|