From adonis-lucid-permission
This guide migrates an app from adonis-lucid-permission to @eienjs/adonisjs-permission.
What changed
| Before | Now |
|---|---|
withAuthorizable({ rolesPivotTable, permissionsPivotTable }) | HasAuthorizable mixin, no arguments |
adonis-lucid-permission/services/role and /services/permission | Your own Role and Permission models using Roleable / Permissible |
One pivot table per model type (user_has_roles, ...) | Shared polymorphic model_has_roles and model_has_permissions |
node ace permissions:pivot-table | Removed |
Config only had tableNames | Models, morph map, guards, teams, wildcard, catalog... |
adonis-lucid-permission/role_middleware | @eienjs/adonisjs-permission/middleware/role_middleware |
1. Replace the package
npm uninstall adonis-lucid-permission
node ace add @eienjs/adonisjs-permission
When prompted, scaffold the models and middlewares, but say no to migrations (you will adapt your existing tables in step 3).
Then remove the old entries in adonisrc.ts (adonis-lucid-permission/commands and adonis-lucid-permission/permissions_provider) if they are still there.
2. Update the models
import { withAuthorizable } from 'adonis-lucid-permission'
const HasAuthorizable = withAuthorizable({
rolesPivotTable: 'user_has_roles',
permissionsPivotTable: 'user_has_permissions',
})
export default class User extends compose(BaseModel, HasAuthorizable) {}
import { HasAuthorizable } from '@eienjs/adonisjs-permission'
export default class User extends compose(BaseModel, HasAuthorizable) {}
Replace the old service imports with your own models:
// Before
import { Role } from 'adonis-lucid-permission/services/role'
import { Permission } from 'adonis-lucid-permission/services/permission'
// After
import Role from '#models/role'
import Permission from '#models/permission'
Register a morphMap alias for every model that has roles or permissions in config/permissions.ts:
export default defineConfig({
models: {
role: () => import('#models/role'),
permission: () => import('#models/permission'),
},
morphMap: {
user: () => import('#models/user'),
},
})
3. Migrate the database
The new package stores assignments for all models in two polymorphic tables. Create a migration that adapts your schema and copies the data. Adjust names to your project:
import { BaseSchema } from '@adonisjs/lucid/schema'
export default class extends BaseSchema {
async up() {
// roles / permissions: add guard column
this.schema.alterTable('roles', (table) => {
table.string('guard_name').notNullable().defaultTo('web')
})
this.schema.alterTable('permissions', (table) => {
table.string('guard_name').notNullable().defaultTo('web')
})
// polymorphic pivots
this.schema.createTable('model_has_roles', (table) => {
table.integer('role_id').unsigned().references('id').inTable('roles').onDelete('CASCADE')
table.string('model_type').notNullable()
table.string('model_id').notNullable()
table.index(['model_id', 'model_type'])
table.index(['role_id', 'model_id', 'model_type'])
})
this.schema.createTable('model_has_permissions', (table) => {
table.integer('permission_id').unsigned().references('id').inTable('permissions').onDelete('CASCADE')
table.string('model_type').notNullable()
table.string('model_id').notNullable()
table.index(['model_id', 'model_type'])
table.index(['permission_id', 'model_id', 'model_type'])
})
// copy data from the old pivots ("user" must match your morphMap alias)
this.defer(async (db) => {
const roles = await db.from('user_has_roles').select('*')
for (const row of roles) {
await db.table('model_has_roles').insert({
role_id: row.role_id,
model_type: 'user',
model_id: String(row.user_id),
})
}
const permissions = await db.from('user_has_permissions').select('*')
for (const row of permissions) {
await db.table('model_has_permissions').insert({
permission_id: row.permission_id,
model_type: 'user',
model_id: String(row.user_id),
})
}
})
this.schema.dropTable('user_has_roles')
this.schema.dropTable('user_has_permissions')
}
async down() {
// restore the old tables if you need a rollback path
}
}
role_id, user_id, ...) may differ in your app. Check your existing tables first. Column types must match your primary keys: use uuid / bigInteger instead of integer where needed. If you used custom table names, set them in tableNames instead of renaming tables.Your role_has_permissions table is kept as it is (the default name is the same), as long as the columns are role_id and permission_id. Otherwise map them with columnNames.
node ace migration:run
4. Rename the methods
| Before | Now |
|---|---|
role.hasAnyRoles(...) | hasAnyRole(...) |
user.withPermissionTo(p) | user.hasPermissionTo(p) (user.can(p) is an alias) |
user.canAnyPermission(...) | user.hasAnyPermission(...) |
revokeRole, syncRoles, assignRole | unchanged |
givePermissionTo, revokePermissionTo, syncPermissions | unchanged |
hasRole, hasAllRoles, getRoleNames | unchanged |
hasDirectPermission, hasPermissionViaRole, getDirectPermissions, getPermissionsViaRoles, getAllPermissions, getPermissionNames | unchanged |
checkPermissionTo, hasAllPermissions | unchanged |
Search your project for the old names:
grep -rnE "hasAnyRoles|withPermissionTo|canAnyPermission|adonis-lucid-permission" app start config
5. Update the middlewares
In start/kernel.ts, change the import paths:
export const middleware = router.named({
role: () => import('@eienjs/adonisjs-permission/middleware/role_middleware'),
permission: () => import('@eienjs/adonisjs-permission/middleware/permission_middleware'),
roleOrPermission: () => import('@eienjs/adonisjs-permission/middleware/role_or_permission_middleware'),
})
Route usage (middleware.role({ roles }), middleware.permission({ permissions }), middleware.roleOrPermission({ roleOrPermission })) is the same.
6. Verify
node ace permissions:show
node ace permissions:cache-reset
Run your test suite and confirm that roles and permissions of an existing user are still resolved:
await user.getRoleNames()
await user.getAllPermissions()
