Browse Source

read permission proto by role and group

Ivan Asmer 6 years ago
parent
commit
bfa417429a
1 changed files with 158 additions and 9 deletions
  1. 158 9
      index.js

+ 158 - 9
index.js

@@ -1,5 +1,6 @@
 (async() => {
     const Sequelize = require("sequelize");
+	const Op = Sequelize.Op
     const sequelize = new Sequelize("test", "","",{
 		host: 'localhost',
 		dialect: 'mysql',
@@ -24,23 +25,53 @@
 			get(){
 				return this.getDataValue("slice").split(",")
 			},
-			set(newValue){
+			set(newValue){ //TODO: update users before with groups
 				newValue = "length" in newValue ? newValue.join(",") : newValue
 				return this.setDataValue("slice", newValue)
 			}
 		}
-	},{
+		},{
 		getterMethods: {
 			async all(){
-				const Op = Sequelize.Op
+				if (this._all) return this._all
+
 				this._subSlicesList = this.slice.filter(id => id[0] == "#" || id[0] == "-") //detect - or #
 												.map(   id => +id.substr(1)) //cut first char + toInt
-				let subSlices = await Slice.find({where: {id: {[Op.in]: this._subSlicesList}}})
-				for (let subSlice of subSlices){
-					this._subSlicesList = this._subSlicesList.filter(id => subSlice.id !== id)
-					this._subSlicesList = [...this._subSlicesList,... await subSlice.all()]
+				this._roles         = this.slice.filter(id => id[0] >= 'a' && id[0] <= 'z' )
+				this._userIds       = this.slice.filter(id => id[0] >= '0' && id[0] <= '9' )
+
+				if (this._subSlicesList.length) {
+					let subSlices = await Slice.findAll({where: {id: {[Op.in]: this._subSlicesList}}})
+					if (subSlices) for (let subSlice of subSlices){
+						this._subSlicesList = this._subSlicesList.filter(id => subSlice.id !== id)
+						let   subSliceAll   = await subSlice.all
+						this._subSlicesList = [...this._subSlicesList,... subSliceAll.slices]
+						this._roles         = [...this._roles,        ...subSliceAll.roles]
+						this._userIds       = [...this._userIds,      ...subSliceAll.userIds]
+					}
 				}
-				return this._subSlicesList
+
+				this._all = {slices: this._subSlicesList, roles: this._roles, userIds: this._userIds}
+
+				return this._all
+			},
+			async allRoles(){
+				return (await this.all).roles
+			},
+			async allSlices(){
+				return (await this.all).slices
+			},
+			async allUserIds(){
+				return (await this.all).userIds
+			},
+
+			roles(){
+				return this.slice.filter(id => id[0] >= 'a' && id[0] <= 'z' )
+			},
+
+			groups(){
+				return this.slice.filter(id => id[0] == "#" || id[0] == "-") //detect - or #
+												.map(   id => +id.substr(1)) //cut first char + toInt
 			}
 		},
 		indexes: [
@@ -61,11 +92,129 @@
 		data: Sequelize.TEXT
 	})
 
-	await sequelize.sync()
+	async function filldb(){
+		await sequelize.sync()
+
+		console.log('synced')
+
+		let [vasya, petya, kolya] = await Promise.all([
+			User.create({login: "Vasya", password: "qwe"}), 
+			User.create({login: "Petya", password: "qwe"}),
+			User.create({login: "Kolya", password: "qwe"}),
+		])
+
+		let groupSlice = await Slice.create({
+			permission: 'group',
+			model: 'group',
+			slice: [`${vasya.id}`, `${petya.id}`]
+		})
+
+		let [vasyaSlice, petyaSlice, kolyaSlice] = await Promise.all([
+			Slice.create({model: 'user', permission: 'user', modelId: vasya.id, slice: ["user", `#${groupSlice.id}`]}),
+			Slice.create({model: 'user', permission: 'user', modelId: petya.id, slice: ["user", `#${groupSlice.id}`]}),
+			Slice.create({model: 'user', permission: 'user', modelId: kolya.id, slice: ["user" ]})
+		])
+
+		let [hiddenContent, roleContent, groupContent] = await Promise.all([
+			Content.create({title: 'Hidden', data: 'HIDDEN'}),
+			Content.create({title: 'Role', data: 'ROLE'}),
+			Content.create({title: 'Group', data: 'GROUP'}),
+		])
+
+		let [hiddenSlice, roleSlice, groupContentSlice] = await Promise.all([
+			Slice.create({model: 'content', permission: 'read', modelId: hiddenContent.id, slice: []}),
+			Slice.create({model: 'content', permission: 'read', modelId: roleContent.id, slice: ["user"]}),
+			Slice.create({model: 'content', permission: 'read', modelId: groupContent.id, slice: [`#${groupSlice.id}`]}),
+		])
+	}
+
+	//filldb()
 
 	function sliced(model){
+		return async userId => {
+			let  user = await User.findByPk(userId)
+			if (!user) throw new ReferenceError(`user with userId ${userId} doesn't exists`)
+
+			let userSlice = await Slice.findOne({where: {
+				model: 'user', //TODO configure this
+				modelId: userId,
+				permission: 'user'
+			}})
+
+
+			let [userRoles, userGroups] = [userSlice.roles, userSlice.groups]
+
+			//console.log(userRoles, userGroups)
 
+			let mapMethodToPermission = {
+				read:  ["count",  "findAll", "findAndCountAll", "findByPk",  "findOne",  "max", "min", "sum"],
+				write: ["create", "destroy","findCreateFind","findOrCreate","update","upsert" ]
+			}
+
+			//sequelize.addHook('beforeCreate', (...params) => console.log(params))
+			let modelProxy =  new Proxy(model, {
+				get(model, method){
+					let found = false
+					for (var permission in mapMethodToPermission)  {
+						if (mapMethodToPermission[permission].includes(method)){
+							found = true
+							break;
+						}
+					}
+					if (!found){
+						console.log(`not found ${method}`)
+						return model[method]
+					}
+					let checker    = async slice => {
+						let intersect = (await slice.allRoles).filter(role => userRoles.includes(role))
+						return (intersect.length || (await slice.allUserIds).includes(userId + '')) 					
+					}
+					let wrappers   = {
+						async read(...params){
+							console.log('read wrapper')
+							let result =  await model[method](...params)
+							if (result instanceof Array){
+								let ids = result.map(instance => instance.id)
+								let slices = await Slice.findAll({where: {
+																		model: model.getTableName(), 
+																		modelId: {[Op.in]: ids},
+																		permission,
+																	}})
+								let filteredResult = []
+								for (let slice of slices){
+									let instance  = result.filter(instance => instance.id === slice.modelId)[0]
+									//role check
+									if (await checker(slice)) {
+										filteredResult.push(instance)
+										continue;
+									}
+								}
+								return filteredResult
+							}
+							if ('id' in result){ //one record
+								let slice = await Slice.findOne({where: {
+																		model: model.getTableName(), 
+																		modelId: result.id,
+																		permission,
+																	}})
+								return (await checker(slice)) ? result : null;
+							}
+						}
+					}
+					return wrappers[permission]
+				},
+			})
+
+			return modelProxy
+		}
 	}
 
+	let SlicedContent = await sliced(Content)(3)
+
+	let allContent    = await SlicedContent.findByPk(3)
+	console.log(allContent)
+
+
+
 	let delay = ms => new Promise(r => setTimeout(r, ms))
 })()