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;