import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'; import Config from '@ioc:Adonis/Core/Config'; import Database from '@ioc:Adonis/Lucid/Database'; import User from 'App/Models/User'; import { Exception } from '@adonisjs/core/build/standalone'; const permissionTable = Config.get('rolePermission.permission_table', 'permissions'); const rolePermissionTable = Config.get('rolePermission.role_permission_table', 'role_has_permissions'); const roleTable = Config.get('rolePermission.role_table', 'roles'); const userRoleTable = Config.get('rolePermission.user_role_table', 'link_accounts_roles'); /** * Permission authentication to check if user has any of the specified permissions * * Should be called after auth middleware */ export default class Can { /** * Handle request */ public async handle( { auth, response }: HttpContextContract, next: () => Promise, permissionNames: string[] ) { /** * Check if user is logged-in */ let user = await auth.user; if (!user) { return response.unauthorized({ error: 'Must be logged in' }); } let hasPermission = await this.checkHasPermissions(user, permissionNames); if (!hasPermission) { // return response.unauthorized({ // error: `Doesn't have required role(s): ${permissionNames.join(',')}`, // }); throw new Exception(`Doesn't have required permission(s): ${permissionNames.join(',')}`, 401); } await next(); } private async checkHasPermissions(user: User, permissionNames: Array): Promise { let rolePlaceHolder = '('; let placeholders = new Array(permissionNames.length).fill('?'); rolePlaceHolder += placeholders.join(','); rolePlaceHolder += ')'; // let test = user // .related('roles') // .query() // .count('permissions.name') // .innerJoin('gba.role_has_permissions', function () { // this.on('gba.role_has_permissions.role_id', 'roles.id'); // }) // .innerJoin('gba.permissions', function () { // this.on('role_has_permissions.permission_id', 'permissions.id'); // }) // .andWhereIn('permissions.name', permissionNames); // select "permissions"."name" // from "gba"."roles" // inner join "gba"."link_accounts_roles" on "roles"."id" = "link_accounts_roles"."role_id" // inner join "gba"."role_has_permissions" on "gba"."role_has_permissions"."role_id" = "roles"."id" // inner join "gba"."permissions" on "role_has_permissions"."permission_id" = "permissions"."id" // where ("permissions"."name" in ('dataset-list', 'dataset-publish')) // and ("link_accounts_roles"."account_id" = 1) let { rows: { 0: { permissioncount }, }, } = await Database.rawQuery( 'SELECT count("p"."name") as permissionCount FROM ' + roleTable + ' r INNER JOIN ' + userRoleTable + ' ur ON ur.role_id=r.id AND "ur"."account_id"=? ' + ' INNER JOIN ' + rolePermissionTable + ' rp ON rp.role_id=r.id ' + ' INNER JOIN ' + permissionTable + ' p ON rp.permission_id=p.id AND "p"."name" in ' + rolePlaceHolder + ' LIMIT 1', [user.id, ...permissionNames] ); return permissioncount > 0; } }