HEX
Server: nginx/1.24.0
System: Linux nowruzgan 6.8.0-57-generic #59-Ubuntu SMP PREEMPT_DYNAMIC Sat Mar 15 17:40:59 UTC 2025 x86_64
User: babak (1000)
PHP: 8.3.6
Disabled: NONE
Upload Files
File: /var/dev/farhangmoaser/web/models/userAccess.js
"use strict";
var md5 = require('md5');
var path = require('path');
var db = require(path.join(BASEDIR, 'connectors/mysql'));
var redis = require(path.join(BASEDIR, 'connectors/redis.js'));
var redclient;
redis.connect(function(client) {
	redclient = client;
});

var actions = [];

class UserAccessModel {

	/**
	 * Constructor
	 * @param  {object} conn db connection from db pool.
	 * @param  {Object} data values for table fields.
	 *                       At least on of `title` or `id` must be set.
	 */
	constructor(data) {
		this.data = data;
	}

	field(key, value) {
		if(arguments.length==0) return;
		if(arguments.length==1)
			return this.data[key];
		
		if(value===undefined)
			delete this.data[key];
		else
			this.data[key] = value;
	}

	fields(){

		return this.data;
	}

	static fail(conn, reject, err){
		if(conn) conn.release();
		reject(err);
	};

	save() {
		var self = this;
		return new Promise(function(resolve, reject){
			if(!self.data.hasOwnProperty('action'))
				return reject('action is required.');
			if(!self.data.hasOwnProperty('role'))
				return reject('role is required.');

			db.getConnection(function(err, conn){
				conn.release();
				if(err) return reject(err.message);
				conn.query(`INSERT INTO user_role_access SET ?`, {role: self.data.role, action: self.data.action}, function(err, result){
					if(err) return reject(err.message);
					self.data.id = result.insertId;
					redclient.set('permit|'+self.data.role+'|'+self.data.action, true, function(){
						resolve(self);
					});
				});
			});
		});
	}

	remove() {
		var self = this;
		return new Promise(function(resolve, reject){
			if(!self.data.hasOwnProperty('action'))
				return reject('action is required.');
			if(!self.data.hasOwnProperty('role'))
				return reject('role is required.');

			db.getConnection(function(err, conn){
				conn.release();
				if(err) return reject(err.message);
				conn.query(`DELETE FROM user_role_access WHERE !!`, {role: self.data.role, action: self.data.action}, function(err, result){
					if(err) return reject(err.message);
					self.data.id = result.insertId;
					redclient.del('permit|'+self.data.role+'|'+self.data.action, function(){
						resolve(self);
					});
				});
			});
		});
	}

	static list(action, role) {
		return new Promise(function(resolve, reject){
			db.getConnection(function(err, conn){
				if(err) return UserAccessModel.fail(conn, reject, err.message);

				var query = {};
				if(action) query.action = action;
				if(role) query.role = role;

				var where = '';
				if(action || role) where = 'WHERE !!';
				
				conn.query(`SELECT action,role FROM user_role_access ${where} GROUP BY action,role`, query, function(err, rows, fields){
					if (err) return UserAccessModel.fail(conn, reject, err.message);
					resolve(rows);
				});
			});
		});
	}

	static register(action, desc) {
		let newaction = true;
		actions.map(function(elem, index){
			if (elem.id == action)
				newaction = false;
		});
		if(newaction)
			actions.push({id: action, desc: desc});
	}

	static listActions() {
		return actions;
	}

	static check(action, role){
		return new Promise(function(resolve, reject){
			redclient.get('permit|'+role+'|'+action, function(err, value){
				if(err) UserAccessModel.fail(conn, reject, err.message);
				resolve(value=='true');
			});
		});
	}

	static rebuild(){
		return new Promise(function(resolve, reject){
			db.getConnection(function(err, conn){
				if(err) return UserAccessModel.fail(conn, reject, err.message);

				var listRoles = function(callback){
					conn.query(`SELECT id FROM user_role`, function(err, rows, fields){
						if(err) return UserAccessModel.fail(conn, reject, err.message);
						callback(rows);
					});
				};

				var listAccessRules = function(callback) {
					conn.query(`SELECT action,role FROM user_role_access GROUP BY action,role`, function(err, rows, fields){
						if(err) return UserAccessModel.fail(conn, reject, err.message);
						callback(rows);
					});
				};

				var setKeys = function(keyList, callback){
					var setNext = function() {
						if(keyList.length) {
							let key = keyList.pop();
							redclient.set(key, true, setNext);
						}
						else callback();
					};
					setNext();
				};

				var deleteKeys = function(keyList, callback){
					var deleteNext = function() {
						if(keyList.length) {
							let key = keyList.pop();
							redclient.del(key, deleteNext);
						}
						else callback();
					};
					deleteNext();
				};

				listRoles(function(roles){
					var keyList = [];

					for(let ax in actions)
						for(let rx in roles)
							keyList.push('permit|'+roles[rx].id+'|'+actions[ax].id);
					
					deleteKeys(keyList, function(){

						listAccessRules(function(rules){
							keyList = [];
							for(let i in rules)
								keyList.push('permit|'+rules[i].role+'|'+rules[i].action);
							
							setKeys(keyList, function(){
								resolve();
							});
						});
					});
				});
			});
		});
	}
}

module.exports = UserAccessModel;