Add initial project files
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
export default [
|
||||
{
|
||||
slug: 'admins.view',
|
||||
name: 'Admin view',
|
||||
},
|
||||
{
|
||||
slug: 'admins.create',
|
||||
name: 'Admin create',
|
||||
},
|
||||
{
|
||||
slug: 'admins.update',
|
||||
name: 'Admin update',
|
||||
},
|
||||
{
|
||||
slug: 'admins.delete',
|
||||
name: 'Admin delete',
|
||||
},
|
||||
]
|
||||
@@ -0,0 +1,96 @@
|
||||
import { HttpContext } from '@adonisjs/core/http'
|
||||
import { createAdminValidator } from '#base_modules/Admin/validators/admin_create_validator'
|
||||
import { updateAdminValidator } from '#base_modules/Admin/validators/admin_update_validator'
|
||||
import { addSearchFilter, searchableColumns } from '#services/database_inspector'
|
||||
import Admins from '#base_modules/Admin/model/admin'
|
||||
import AdminsPolicy from '#base_modules/Admin/policy/admin_policy'
|
||||
import { updateProfileAdminValidator } from '#base_modules/Admin/validators/admin_update_profile_validator'
|
||||
import db from '@adonisjs/lucid/services/db'
|
||||
|
||||
export default class AdminsController {
|
||||
public async index({ request, response, bouncer }: HttpContext) {
|
||||
await bouncer.with(AdminsPolicy).authorize('viewList')
|
||||
const {
|
||||
page = 1,
|
||||
perPage = 10,
|
||||
search = null,
|
||||
sortBy = 'id',
|
||||
sortOrder = 'desc',
|
||||
status = null,
|
||||
} = request.all()
|
||||
const query = Admins.query()
|
||||
if (status) {
|
||||
const statuses = Array.isArray(status) ? status : [status]
|
||||
query.whereIn('status', statuses)
|
||||
}
|
||||
if (search) {
|
||||
const columns = Admins.searchable || (await searchableColumns('admins'))
|
||||
addSearchFilter(query, columns, search)
|
||||
}
|
||||
const result = await query.orderBy(sortBy, sortOrder).paginate(page, perPage)
|
||||
return response.ok(result)
|
||||
}
|
||||
|
||||
public async store({ request, response, bouncer }: HttpContext) {
|
||||
await bouncer.with(AdminsPolicy).authorize('create')
|
||||
const data = await createAdminValidator.validate(request.all())
|
||||
const record = await Admins.create(data)
|
||||
if (record) {
|
||||
await record.related('roles').sync(data.roles)
|
||||
return response.created({ message: 'Successfully created.' })
|
||||
}
|
||||
return response.badRequest({ message: 'Cannot create.' })
|
||||
}
|
||||
|
||||
public async show({ request, response, bouncer }: HttpContext) {
|
||||
await bouncer.with(AdminsPolicy).authorize('view')
|
||||
const { id } = request.params()
|
||||
if (!id) return response.notFound({ message: 'Not found.' })
|
||||
const record = await Admins.find(id)
|
||||
if (!record) return response.notFound({ message: 'Not found.' })
|
||||
await record.load('roles')
|
||||
return response.ok(record)
|
||||
}
|
||||
|
||||
public async update({ request, response, bouncer }: HttpContext) {
|
||||
await bouncer.with(AdminsPolicy).authorize('update')
|
||||
const { id } = request.params()
|
||||
if (!id) return response.notFound({ message: 'Not found.' })
|
||||
const data = await updateAdminValidator.validate(request.all())
|
||||
const record = await Admins.find(id)
|
||||
if (!record) return response.notFound({ message: 'Not found.' })
|
||||
record.merge(data)
|
||||
await record.save()
|
||||
await record.related('roles').sync(data.roles)
|
||||
return response.ok({ message: 'Updated.' })
|
||||
}
|
||||
|
||||
public async destroy({ request, response, bouncer }: HttpContext) {
|
||||
await bouncer.with(AdminsPolicy).authorize('delete')
|
||||
const { id } = request.params()
|
||||
if (!id) return response.notFound({ message: 'Not found.' })
|
||||
const admins = await Admins.all()
|
||||
if (admins.length === 1) {
|
||||
return response.badRequest({ message: "Last Admin can't be deleted!" })
|
||||
}
|
||||
const record = await Admins.find(id)
|
||||
if (!record) return response.notFound({ message: 'Not found.' })
|
||||
await Admins.query().where('id', id).delete()
|
||||
return response.ok({ message: 'Deleted.' })
|
||||
}
|
||||
|
||||
public async updateProfile({ request, response, auth }: HttpContext) {
|
||||
const user = auth.use('api').user
|
||||
if (!user) return response.unauthorized()
|
||||
const data = await updateProfileAdminValidator.validate(request.all())
|
||||
user.merge(data)
|
||||
user.save()
|
||||
await user.load('roles')
|
||||
const roles = user.roles.map((role) => role.id)
|
||||
const permissions = await db
|
||||
.from('role_permissions')
|
||||
.whereIn('role_id', roles)
|
||||
.select('permission_slug')
|
||||
return response.ok({ user, permissions: permissions.map((perm) => perm.permission_slug) })
|
||||
}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
import hash from '@adonisjs/core/services/hash'
|
||||
import { compose } from '@adonisjs/core/helpers'
|
||||
import { withAuthFinder } from '@adonisjs/auth/mixins/lucid'
|
||||
import { DbAccessTokensProvider } from '@adonisjs/auth/access_tokens'
|
||||
import { BaseModel, column, manyToMany } from '@adonisjs/lucid/orm'
|
||||
import type { ManyToMany } from '@adonisjs/lucid/types/relations'
|
||||
import { DateTime } from 'luxon'
|
||||
import Role from '#base_modules/Role/model/role'
|
||||
import Permission from '#base_modules/Permission/model/permission'
|
||||
|
||||
const AuthFinder = withAuthFinder(() => hash.use('scrypt'), {
|
||||
uids: ['email'],
|
||||
passwordColumnName: 'password',
|
||||
})
|
||||
|
||||
const ComposedModel = compose(BaseModel, AuthFinder) as typeof BaseModel
|
||||
|
||||
export default class Admins extends ComposedModel {
|
||||
static searchable = {
|
||||
string: ['email', 'first_name', 'last_name'],
|
||||
number: ['id'],
|
||||
}
|
||||
|
||||
@column({ isPrimary: true, columnName: 'id' })
|
||||
declare id: number
|
||||
|
||||
@column({ columnName: 'first_name' })
|
||||
declare firstName: string | null
|
||||
|
||||
@column({ columnName: 'last_name' })
|
||||
declare lastName: string | null
|
||||
|
||||
@column({ columnName: 'email' })
|
||||
declare email: string
|
||||
|
||||
@column({ columnName: 'status' })
|
||||
declare status: 'active' | 'inactive'
|
||||
|
||||
@column({ serializeAs: null, columnName: 'password' })
|
||||
declare password: string
|
||||
|
||||
@column.dateTime({ autoCreate: true, columnName: 'created_at' })
|
||||
declare createdAt: DateTime
|
||||
|
||||
@column.dateTime({ autoCreate: true, autoUpdate: true, columnName: 'updated_at' })
|
||||
declare updatedAt: DateTime | null
|
||||
|
||||
@manyToMany(() => Role, {
|
||||
pivotTable: 'admin_roles',
|
||||
pivotForeignKey: 'admin_id',
|
||||
pivotRelatedForeignKey: 'role_id',
|
||||
})
|
||||
declare roles: ManyToMany<typeof Role>
|
||||
|
||||
declare permissions: Permission[]
|
||||
|
||||
static accessTokens = DbAccessTokensProvider.forModel(Admins)
|
||||
|
||||
async loadPermissions() {
|
||||
this.permissions = await Permission.query()
|
||||
.join('role_permissions', 'permissions.id', 'role_permissions.permission_id')
|
||||
.join('admin_roles', 'role_permissions.role_id', 'admin_roles.role_id')
|
||||
.where('admin_roles.admin_id', this.id)
|
||||
.exec()
|
||||
return this
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import { BasePolicy } from '@adonisjs/bouncer'
|
||||
import type { AuthorizerResponse } from '@adonisjs/bouncer/types'
|
||||
import Admins from '#base_modules/Admin/model/admin'
|
||||
import { getAdminPermissionSlugs } from '#services/permission_service'
|
||||
|
||||
export default class AdminsPolicy extends BasePolicy {
|
||||
// Example permission slugs: admins.view, admins.create, admins.update, admins.delete
|
||||
async viewList(user: Admins): Promise<AuthorizerResponse> {
|
||||
if (!user) return false
|
||||
const perms = await getAdminPermissionSlugs(user)
|
||||
return perms.has('admins.view')
|
||||
}
|
||||
|
||||
async view(user: Admins): Promise<AuthorizerResponse> {
|
||||
if (!user) return false
|
||||
const perms = await getAdminPermissionSlugs(user)
|
||||
return perms.has('admins.view')
|
||||
}
|
||||
|
||||
async create(user: Admins): Promise<AuthorizerResponse> {
|
||||
if (!user) return false
|
||||
const perms = await getAdminPermissionSlugs(user)
|
||||
return perms.has('admins.create')
|
||||
}
|
||||
|
||||
async update(user: Admins): Promise<AuthorizerResponse> {
|
||||
if (!user) return false
|
||||
const perms = await getAdminPermissionSlugs(user)
|
||||
return perms.has('admins.update')
|
||||
}
|
||||
|
||||
async delete(user: Admins): Promise<AuthorizerResponse> {
|
||||
if (!user) return false
|
||||
const perms = await getAdminPermissionSlugs(user)
|
||||
return perms.has('admins.delete')
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import router from '@adonisjs/core/services/router'
|
||||
import { middleware } from '#start/kernel'
|
||||
|
||||
const adminController = () => import('#base_modules/Admin/controller/admin_controller')
|
||||
|
||||
router.put('/admin/update-profile', [adminController, 'updateProfile']).use([middleware.auth()])
|
||||
router.resource('/admin', adminController).apiOnly().use('*', [middleware.auth()]) //.use(['store', 'update', 'destroy'], [middleware.auth()])
|
||||
@@ -0,0 +1,20 @@
|
||||
import vine from '@vinejs/vine'
|
||||
|
||||
export const createAdminValidator = vine.compile(
|
||||
vine.object({
|
||||
id: vine.number().optional(),
|
||||
email: vine
|
||||
.string()
|
||||
.trim()
|
||||
.email()
|
||||
.unique(async (db, value) => {
|
||||
const exists = await db.from('admins').where('email', value).first()
|
||||
return !exists
|
||||
}),
|
||||
password: vine.string().trim().minLength(8),
|
||||
firstName: vine.string().trim().optional(),
|
||||
lastName: vine.string().trim().optional(),
|
||||
status: vine.enum(['active', 'inactive']),
|
||||
roles: vine.array(vine.number()),
|
||||
})
|
||||
)
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
import vine from '@vinejs/vine'
|
||||
|
||||
export const updateProfileAdminValidator = vine.compile(
|
||||
vine.object({
|
||||
id: vine.number(),
|
||||
email: vine
|
||||
.string()
|
||||
.trim()
|
||||
.email()
|
||||
.unique(async (db, value, field) => {
|
||||
const id = field.data.id
|
||||
const exists = await db.from('admins').where('email', value).whereNot('id', id).first()
|
||||
return !exists
|
||||
}),
|
||||
password: vine.string().trim().minLength(8).optional(),
|
||||
firstName: vine.string().trim().minLength(1),
|
||||
lastName: vine.string().trim().minLength(1),
|
||||
status: vine.enum(['active', 'inactive']).optional(),
|
||||
})
|
||||
)
|
||||
@@ -0,0 +1,22 @@
|
||||
import vine from '@vinejs/vine'
|
||||
|
||||
export const updateAdminValidator = vine.compile(
|
||||
vine.object({
|
||||
id: vine.number().optional(),
|
||||
email: vine
|
||||
.string()
|
||||
.trim()
|
||||
.email()
|
||||
.unique(async (db, value, field) => {
|
||||
const id = field.data.id
|
||||
const exists = await db.from('admins').where('email', value).whereNot('id', id).first()
|
||||
return !exists
|
||||
})
|
||||
.optional(),
|
||||
password: vine.string().trim().minLength(8).optional(),
|
||||
firstName: vine.string().trim().optional(),
|
||||
lastName: vine.string().trim().optional(),
|
||||
status: vine.enum(['active', 'inactive']).optional(),
|
||||
roles: vine.array(vine.number()),
|
||||
})
|
||||
)
|
||||
Reference in New Issue
Block a user