2weekmail/api/controllers/BaseController.js
2025-03-19 19:56:57 -05:00

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;