diff --git a/app/controllers/admin/admin_controller.ts b/app/controllers/admin/admin_controller.ts new file mode 100644 index 0000000..e2109cb --- /dev/null +++ b/app/controllers/admin/admin_controller.ts @@ -0,0 +1,7 @@ +import { HttpContext } from '@adonisjs/core/http' + +export default class AdminController { + async render({ inertia }: HttpContext) { + return inertia.render('admin/index') + } +} diff --git a/app/controllers/admin/shares/admin_list_shares_controller.ts b/app/controllers/admin/shares/admin_list_shares_controller.ts new file mode 100644 index 0000000..fac9677 --- /dev/null +++ b/app/controllers/admin/shares/admin_list_shares_controller.ts @@ -0,0 +1,15 @@ +import { HttpContext } from '@adonisjs/core/http' +import Share from '#models/share' +import ShareListAdminDto from '../../../dtos/shares/share_admin_dto.js' + +export default class AdminListSharesController { + async render({ inertia }: HttpContext) { + const sharesModels = await Share.query().preload('folder') + + const shares = await Promise.all( + sharesModels.map((share) => ShareListAdminDto.fromModel(share)) + ) + + return inertia.render('admin/shares/index', { shares }) + } +} diff --git a/app/controllers/admin/users/admin_list_users_controller.ts b/app/controllers/admin/users/admin_list_users_controller.ts new file mode 100644 index 0000000..7e83862 --- /dev/null +++ b/app/controllers/admin/users/admin_list_users_controller.ts @@ -0,0 +1,14 @@ +// import type { HttpContext } from '@adonisjs/core/http' + +import User from '#models/user' +import { HttpContext } from '@adonisjs/core/http' +import UsersListingDto from '../../../dtos/users/users_listing_dto.js' + +export default class AdminListUserController { + async render({ inertia }: HttpContext) { + const users = await User.all() + const dtos = await Promise.all(users.map((user) => UsersListingDto.fromModel(user))) + + return inertia.render('admin/users/index', { users: dtos }) + } +} diff --git a/app/controllers/admin/users/admin_remove_users_controller.ts b/app/controllers/admin/users/admin_remove_users_controller.ts new file mode 100644 index 0000000..fe0e286 --- /dev/null +++ b/app/controllers/admin/users/admin_remove_users_controller.ts @@ -0,0 +1,18 @@ +import { HttpContext } from '@adonisjs/core/http' +import User from '#models/user' + +export default class AdminRemoveUsersController { + async remove({ request, response, session }: HttpContext) { + const user = await User.findOrFail(request.param('id')) + + if (user.email === 'admin@knowledge.fr') { + session.flash('error', 'You can not remove admin user') + return response.redirect().back() + } + + await user.delete() + + session.flash('success', 'User remove with successfully') + return response.redirect().back() + } +} diff --git a/app/controllers/admin/users/admin_store_users_controller.ts b/app/controllers/admin/users/admin_store_users_controller.ts new file mode 100644 index 0000000..e7d26bc --- /dev/null +++ b/app/controllers/admin/users/admin_store_users_controller.ts @@ -0,0 +1,39 @@ +import { HttpContext } from '@adonisjs/core/http' +import vine from '@vinejs/vine' +import User from '#models/user' +import Role from '../../../enums/role.js' + +export default class AdminStoreUsersController { + static validator = vine.compile( + vine.object({ + username: vine.string().minLength(3).maxLength(255), + email: vine.string().email(), + role: vine.enum(Role), + password: vine.string().minLength(3).maxLength(255), + passwordConfirmation: vine.string().confirmed({ confirmationField: 'password' }), + }) + ) + + async store({ request, response, session }: HttpContext) { + const { username, email, role, password } = await request.validateUsing( + AdminStoreUsersController.validator + ) + + const existingUser = await User.query().where('email', email).first() + + if (existingUser) { + session.flash('error', 'Email already in use !') + return response.redirect().back() + } + + await User.create({ + fullName: username, + role, + email, + password, + }) + + session.flash('success', 'User created successfully !') + return response.redirect().back() + } +} diff --git a/app/controllers/admin/users/admin_update_users_controller.ts b/app/controllers/admin/users/admin_update_users_controller.ts new file mode 100644 index 0000000..b807240 --- /dev/null +++ b/app/controllers/admin/users/admin_update_users_controller.ts @@ -0,0 +1,44 @@ +import vine from '@vinejs/vine' +import Role from '#enums/role' +import { HttpContext } from '@adonisjs/core/http' +import User from '#models/user' + +export default class AdminUpdateUsersController { + static validator = vine.compile( + vine.object({ + username: vine.string().minLength(3).maxLength(255), + email: vine.string().email(), + role: vine.enum(Role), + }) + ) + + async update({ request, response, session }: HttpContext) { + const { username, email, role } = await request.validateUsing( + AdminUpdateUsersController.validator + ) + + if (email === 'admin@knowledge.fr') { + session.flash('error', 'You can not update admin user') + return response.redirect().back() + } + + const existingUser = await User.query() + .where('email', email) + .whereNot('id', request.param('id')) + .first() + + if (existingUser) { + session.flash('error', 'Email already in use !') + return response.redirect().back() + } + + const user = await User.findOrFail(request.param('id')) + user.fullName = username + user.email = email + user.role = role + await user.save() + + session.flash('success', 'User created successfully !') + return response.redirect().back() + } +} diff --git a/app/controllers/profile/update_profile_controller.ts b/app/controllers/profile/update_profile_controller.ts index 1f587d2..6a702a2 100644 --- a/app/controllers/profile/update_profile_controller.ts +++ b/app/controllers/profile/update_profile_controller.ts @@ -1,5 +1,6 @@ import { HttpContext } from '@adonisjs/core/http' import vine from '@vinejs/vine' +import UserDto from '../../dtos/users/user_dto.js' export default class UpdateProfilesController { static validator = vine.compile( @@ -14,8 +15,9 @@ export default class UpdateProfilesController { if (!user) throw new Error('User not found') + const dto = await UserDto.fromModel(user) return inertia.render('profile/index', { - user, + user: dto, }) } diff --git a/app/dtos/shares/share_admin_dto.ts b/app/dtos/shares/share_admin_dto.ts new file mode 100644 index 0000000..3883d86 --- /dev/null +++ b/app/dtos/shares/share_admin_dto.ts @@ -0,0 +1,25 @@ +import env from '#start/env' +import Share from '#models/share' + +export default class ShareListAdminDto { + declare id: number + declare url: string + declare created_at: string + declare folder_path: string + + constructor(data: { id: number; url: string; folder_path: string; created_at: string }) { + this.id = data.id + this.url = data.url + this.folder_path = data.folder_path + this.created_at = data.created_at + } + + static async fromModel(share: Share): Promise { + return new ShareListAdminDto({ + id: share.id, + url: `${env.get('APP_URL')}/shares/${share.token}/${share.folder.path}`, + folder_path: share.folder.path, + created_at: share.createdAt.toFormat('dd/MM/yyyy'), + }) + } +} diff --git a/app/dtos/users/user_dto.ts b/app/dtos/users/user_dto.ts new file mode 100644 index 0000000..558fdbf --- /dev/null +++ b/app/dtos/users/user_dto.ts @@ -0,0 +1,25 @@ +import Role from '#enums/role' +import User from '#models/user' + +export default class UserDto { + declare id: number + declare email: string + declare username: string + declare role: Role + + constructor(data: { id: number; email: string; username: string; role: Role }) { + this.id = data.id + this.email = data.email + this.username = data.username + this.role = data.role + } + + static async fromModel(user: User): Promise { + return new UserDto({ + id: user.id, + email: user.email, + username: user.fullName, + role: user.role, + }) + } +} diff --git a/app/dtos/users/users_listing_dto.ts b/app/dtos/users/users_listing_dto.ts new file mode 100644 index 0000000..1a34a48 --- /dev/null +++ b/app/dtos/users/users_listing_dto.ts @@ -0,0 +1,33 @@ +import User from '#models/user' + +export default class UsersListingDto { + declare id: number + declare email: string + declare username: string + declare role: string + declare created_at: string + + constructor(data: { + id: number + email: string + username: string + role: string + created_at: string + }) { + this.id = data.id + this.email = data.email + this.username = data.username + this.role = data.role + this.created_at = data.created_at + } + + static async fromModel(user: User): Promise { + return new UsersListingDto({ + id: user.id, + email: user.email, + username: user.fullName, + role: user.roleLabel, + created_at: user.createdAt.toFormat('dd/MM/yyyy'), + }) + } +} diff --git a/app/enums/role.ts b/app/enums/role.ts new file mode 100644 index 0000000..d472395 --- /dev/null +++ b/app/enums/role.ts @@ -0,0 +1,6 @@ +enum Role { + ADMIN = 0, + MAINTAINER = 1, +} + +export default Role diff --git a/app/middleware/role_middleware.ts b/app/middleware/role_middleware.ts new file mode 100644 index 0000000..4030d25 --- /dev/null +++ b/app/middleware/role_middleware.ts @@ -0,0 +1,17 @@ +import type { HttpContext } from '@adonisjs/core/http' +import type { NextFn } from '@adonisjs/core/types/http' +import Role from '../enums/role.js' + +export default class RoleMiddleware { + async handle({ auth, response }: HttpContext, next: NextFn, options: { roles: Role[] }) { + const user = auth.user! + + if (!options.roles.includes(user.role)) { + return response.forbidden({ + message: 'You do not have permission to access this resource.', + }) + } + + return next() + } +} diff --git a/app/models/user.ts b/app/models/user.ts index dfe4857..e0185b3 100644 --- a/app/models/user.ts +++ b/app/models/user.ts @@ -3,6 +3,7 @@ import hash from '@adonisjs/core/services/hash' import { compose } from '@adonisjs/core/helpers' import { BaseModel, column } from '@adonisjs/lucid/orm' import { withAuthFinder } from '@adonisjs/auth/mixins/lucid' +import Role from '#enums/role' const AuthFinder = withAuthFinder(() => hash.use('scrypt'), { uids: ['email'], @@ -14,7 +15,7 @@ export default class User extends compose(BaseModel, AuthFinder) { declare id: number @column() - declare fullName: string | null + declare fullName: string @column() declare email: string @@ -22,9 +23,16 @@ export default class User extends compose(BaseModel, AuthFinder) { @column({ serializeAs: null }) declare password: string + @column() + declare role: Role + @column.dateTime({ autoCreate: true }) declare createdAt: DateTime @column.dateTime({ autoCreate: true, autoUpdate: true }) declare updatedAt: DateTime | null + + get roleLabel(): string { + return Role[this.role] + } } diff --git a/config/inertia.ts b/config/inertia.ts index ae8c0d2..4704df7 100644 --- a/config/inertia.ts +++ b/config/inertia.ts @@ -1,6 +1,7 @@ import { defineConfig } from '@adonisjs/inertia' import type { InferSharedProps } from '@adonisjs/inertia/types' import GetTreeByFolderAction from '../app/actions/get_tree_by_folder_action.js' +import UserDto from '../app/dtos/users/user_dto.js' const inertiaConfig = defineConfig({ /** @@ -12,7 +13,10 @@ const inertiaConfig = defineConfig({ * Data that should be shared with all rendered pages */ sharedData: { - user: (ctx) => ctx.inertia.always(() => ctx.auth.user), + user: (ctx) => + ctx.inertia.always(async () => + ctx.auth.user ? await UserDto.fromModel(ctx.auth.user) : null + ), flash: (ctx) => ({ success: ctx.session?.flashMessages.get('success'), error: ctx.session?.flashMessages.get('error'), diff --git a/database/migrations/1773935989197_create_add_role_users_table.ts b/database/migrations/1773935989197_create_add_role_users_table.ts new file mode 100644 index 0000000..7d22a76 --- /dev/null +++ b/database/migrations/1773935989197_create_add_role_users_table.ts @@ -0,0 +1,15 @@ +import { BaseSchema } from '@adonisjs/lucid/schema' + +export default class extends BaseSchema { + async up() { + this.schema.table('users', (table) => { + table.integer('role').defaultTo(1) + }) + } + + async down() { + this.schema.table('users', (table) => { + table.dropColumn('role') + }) + } +} diff --git a/database/seeders/user_seeder.ts b/database/seeders/user_seeder.ts index 1d63611..052a99c 100644 --- a/database/seeders/user_seeder.ts +++ b/database/seeders/user_seeder.ts @@ -1,5 +1,6 @@ import { BaseSeeder } from '@adonisjs/lucid/seeders' import User from '#models/user' +import Role from '#enums/role' export default class extends BaseSeeder { async run() { @@ -12,6 +13,7 @@ export default class extends BaseSeeder { fullName: 'admin', email: email, password: 'knowledge', + role: Role.ADMIN, }) console.log('Admin user created') diff --git a/inertia/components/layouts/sidebar/app-sidebar.tsx b/inertia/components/layouts/sidebar/app-sidebar.tsx index a53cf34..9a24aef 100644 --- a/inertia/components/layouts/sidebar/app-sidebar.tsx +++ b/inertia/components/layouts/sidebar/app-sidebar.tsx @@ -8,7 +8,7 @@ import { SidebarRail, useSidebar, } from '@/components/ui/sidebar' -import { BadgeCheck, ChevronsUpDown, LibraryBig, LogOut, Share2 } from 'lucide-react' +import { BadgeCheck, ChevronsUpDown, LibraryBig, LogOut, Settings, Share2 } from 'lucide-react' import { FragmentLoader } from '@/components/load_fragment' import { DropdownMenu, @@ -22,11 +22,13 @@ import { import { Avatar, AvatarFallback } from '@/components/ui/avatar' import { Link, router, usePage } from '@inertiajs/react' import { getInitials } from '@/lib/utils' +import Role from '#enums/role' interface CurrentUserPropsPage { user: { - fullName: string + username: string email: string + role: Role } [key: string]: unknown } @@ -56,11 +58,11 @@ export default function AppSidebar() { > - {getInitials(props.user.fullName)} + {getInitials(props.user.username)}
- {props.user.fullName} + {props.user.username} {props.user.email}
@@ -76,11 +78,11 @@ export default function AppSidebar() {
- {getInitials(props.user.fullName)} + {getInitials(props.user.username)}
- {props.user.fullName} + {props.user.username} {props.user.email}
@@ -100,6 +102,19 @@ export default function AppSidebar() { + {props.user.role === Role.ADMIN && ( + <> + + + + + + Administration + + + + + )} + ) + })} + + + ))} + + + +
{children}
+ + + ) +} diff --git a/inertia/features/admin/users/components/admin-create-user-modal.tsx b/inertia/features/admin/users/components/admin-create-user-modal.tsx new file mode 100644 index 0000000..7c4778b --- /dev/null +++ b/inertia/features/admin/users/components/admin-create-user-modal.tsx @@ -0,0 +1,138 @@ +import { router, useForm } from '@inertiajs/react' +import { + Dialog, + DialogClose, + DialogContent, + DialogFooter, + DialogHeader, + DialogTitle, +} from '@/components/ui/dialog' +import { Field, FieldError, FieldGroup } from '@/components/ui/field' +import { Label } from '@/components/ui/label' +import { Input } from '@/components/ui/input' +import { Button } from '@/components/ui/button' +import { Loader2 } from 'lucide-react' +import { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select' + +interface AdminCreateUserModalProps { + open: boolean + onOpenChange: (open: boolean) => void +} + +export default function AdminCreateUserModal({ open, onOpenChange }: AdminCreateUserModalProps) { + const { data, setData, processing, errors } = useForm({ + username: '', + email: '', + password: '', + passwordConfirmation: '', + role: 0, + }) + + const handleSubmit = (e: React.SyntheticEvent) => { + e.preventDefault() + + router.post('/admin/users/store', data, { + onSuccess: () => { + onOpenChange(false) + }, + }) + } + + return ( + + +
+ + Create user + + +
+ + + setData('username', e.target.value)} + /> + {errors.username && {errors.username}} + + + + setData('email', e.target.value)} + /> + {errors.email && {errors.email}} + +
+ + + + {errors.role && {errors.role}} + +
+ + + setData('password', e.target.value)} + /> + {errors.password && {errors.password}} + + + + setData('passwordConfirmation', e.target.value)} + /> + {errors.passwordConfirmation && ( + {errors.passwordConfirmation} + )} + +
+
+ + + + + + +
+
+
+ ) +} diff --git a/inertia/features/admin/users/components/admin-delete-user-dialog.tsx b/inertia/features/admin/users/components/admin-delete-user-dialog.tsx new file mode 100644 index 0000000..1142f2c --- /dev/null +++ b/inertia/features/admin/users/components/admin-delete-user-dialog.tsx @@ -0,0 +1,72 @@ +import { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from '@/components/ui/dialog' +import { Button } from '@/components/ui/button' +import { Loader2, Trash2 } from 'lucide-react' +import { useForm } from '@inertiajs/react' +import { useState } from 'react' + +interface AdminDeleteUserProps { + id: number +} + +export default function AdminDeleteUserDialog(props: AdminDeleteUserProps) { + const [open, setOpen] = useState(false) + const { delete: destroy, processing } = useForm() + + const handleSubmit = (e: React.SyntheticEvent) => { + e.preventDefault() + + destroy(`/admin/users/${props.id}/remove`, { + onSuccess: () => { + setOpen(false) + }, + }) + } + + return ( + + + + + + +
+ +
+ +
+ + Remove this user ? + + + Are you sure you want to remove this user ? This action cannot be undone. + +
+ + + + + + + + +
+
+
+ ) +} diff --git a/inertia/features/admin/users/components/admin-update-user-dialog.tsx b/inertia/features/admin/users/components/admin-update-user-dialog.tsx new file mode 100644 index 0000000..52a0a14 --- /dev/null +++ b/inertia/features/admin/users/components/admin-update-user-dialog.tsx @@ -0,0 +1,136 @@ +import { router, useForm } from '@inertiajs/react' +import { + Dialog, + DialogClose, + DialogContent, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from '@/components/ui/dialog' +import { Field, FieldError, FieldGroup } from '@/components/ui/field' +import { Label } from '@/components/ui/label' +import { Input } from '@/components/ui/input' +import { Button } from '@/components/ui/button' +import { Loader2, SquarePen } from 'lucide-react' +import { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select' +import { useState } from 'react' + +interface AdminUpdateUserModalProps { + user: { + id: number + username: string + email: string + role: string + } +} + +export default function AdminUpdateUserDialog({ user }: AdminUpdateUserModalProps) { + const [open, setOpen] = useState(false) + + const { data, setData, processing, errors } = useForm({ + username: user.username, + email: user.email, + role: user.role === 'ADMIN' ? '0' : '1', + }) + + console.log(user.role, typeof user.role) + + const handleSubmit = (e: React.SyntheticEvent) => { + e.preventDefault() + + router.post( + `/admin/users/${user.id}/update`, + { + ...data, + role: parseInt(data.role), + }, + { + onSuccess: () => { + setOpen(false) + }, + } + ) + } + + return ( + + + + + + +
+ + Update user + + +
+ + + setData('username', e.target.value)} + /> + {errors.username && {errors.username}} + + + + setData('email', e.target.value)} + /> + {errors.email && {errors.email}} + +
+ + + + {errors.role && {errors.role}} + +
+ + + + + + +
+
+
+ ) +} diff --git a/inertia/features/profile/components/update-profile.tsx b/inertia/features/profile/components/update-profile.tsx index e95d187..715ef55 100644 --- a/inertia/features/profile/components/update-profile.tsx +++ b/inertia/features/profile/components/update-profile.tsx @@ -6,14 +6,14 @@ import { Button } from '@/components/ui/button' interface UpdateProfileProps { user: { - fullName: string + username: string email: string } } export default function UpdateProfile({ user }: UpdateProfileProps) { const { data, setData, post, processing, errors } = useForm({ - fullName: user.fullName, + fullName: user.username, email: user.email, }) diff --git a/inertia/hooks/use_flash.ts b/inertia/hooks/use_flash.ts index eb23bbe..4a8c8d8 100644 --- a/inertia/hooks/use_flash.ts +++ b/inertia/hooks/use_flash.ts @@ -4,6 +4,7 @@ import { usePage } from '@inertiajs/react' type FlashMessages = { success?: string + error?: string } export function useFlash() { @@ -11,5 +12,6 @@ export function useFlash() { useEffect(() => { if (flash.success) toast.success(flash.success) + if (flash.error) toast.error(flash.error) }, [flash]) } diff --git a/inertia/pages/admin/index.tsx b/inertia/pages/admin/index.tsx new file mode 100644 index 0000000..a07d000 --- /dev/null +++ b/inertia/pages/admin/index.tsx @@ -0,0 +1,9 @@ +import AdminLayout from '@/features/admin/layouts/admin-layout' + +export default function Admin() { + return ( + +

Hello word

+
+ ) +} diff --git a/inertia/pages/admin/shares/index.tsx b/inertia/pages/admin/shares/index.tsx new file mode 100644 index 0000000..8db0fc1 --- /dev/null +++ b/inertia/pages/admin/shares/index.tsx @@ -0,0 +1,120 @@ +import { useState } from 'react' +import { toast } from 'sonner' +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip' +import { Check, Copy, Share2 } from 'lucide-react' +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from '@/components/ui/table' +import { Button } from '@/components/ui/button' +import DeleteShareDialog from '@/features/shares/delete-share-dialog' +import AdminLayout from '@/features/admin/layouts/admin-layout' + +interface ShareProfile { + id: number + url: string + folder_path: string + created_at: string +} +interface AdminSharesProps { + shares: ShareProfile[] +} + +export default function AdminShares({ shares }: AdminSharesProps) { + const [copiedId, setCopiedId] = useState(null) + + const handleCopy = (share: ShareProfile) => { + navigator.clipboard.writeText(share.url).then(() => () => {}) + + setCopiedId(share.id) + toast.success('Link is copied to clipboard!', { + description: share.url, + }) + + setTimeout(() => setCopiedId(null), 2000) + } + + return ( + + +
+
+
+ +

Shares

+
+
+
+ + {shares.length === 0 ? ( +
+ +

+
+ ) : ( +
+ + + + Path + Link + Created At + Actions + + + + {shares.map((share) => ( + + {share.folder_path} + + + + {share.url} + + + + + {share.created_at} + + + +
+ + + + + Copy link + + +
+
+
+ ))} +
+
+
+ )} +
+
+ ) +} diff --git a/inertia/pages/admin/users/index.tsx b/inertia/pages/admin/users/index.tsx new file mode 100644 index 0000000..97564ba --- /dev/null +++ b/inertia/pages/admin/users/index.tsx @@ -0,0 +1,77 @@ +import AdminLayout from '@/features/admin/layouts/admin-layout' +import { LucideUsers, Plus } from 'lucide-react' +import { Button } from '@/components/ui/button' +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from '@/components/ui/table' +import { useState } from 'react' +import AdminCreateUserModal from '@/features/admin/users/components/admin-create-user-modal' +import AdminDeleteUserDialog from '@/features/admin/users/components/admin-delete-user-dialog' +import AdminUpdateUserDialog from '@/features/admin/users/components/admin-update-user-dialog' + +export default function Users({ users }: { users: any[] }) { + const [openCreateUser, setOpenCreateUser] = useState(false) + + return ( + +
+
+ +

Users

+
+
+ +
+
+ + {users.length === 0 ? ( +
+ +

+
+ ) : ( +
+ + + + Username + Email + Role + Created At + Actions + + + + {users.map((user, index) => ( + + {user.username} + {user.email} + {user.role} + {user.created_at} + {user.email !== 'admin@knowledge.fr' && ( + +
+ + +
+
+ )} +
+ ))} +
+
+
+ )} + + +
+ ) +} diff --git a/package.json b/package.json index b3d20f4..5f1fb66 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "imports": { "#controllers/*": "./app/controllers/*.js", "#exceptions/*": "./app/exceptions/*.js", + "#enums/*": "./app/enums/*.js", "#models/*": "./app/models/*.js", "#mails/*": "./app/mails/*.js", "#services/*": "./app/services/*.js", diff --git a/start/kernel.ts b/start/kernel.ts index ddd0e49..6a460cd 100644 --- a/start/kernel.ts +++ b/start/kernel.ts @@ -48,4 +48,5 @@ router.use([ export const middleware = router.named({ guest: () => import('#middleware/guest_middleware'), auth: () => import('#middleware/auth_middleware'), + role: () => import('#middleware/role_middleware'), }) diff --git a/start/routes.ts b/start/routes.ts index b3fbcab..baabc4b 100644 --- a/start/routes.ts +++ b/start/routes.ts @@ -9,6 +9,22 @@ import router from '@adonisjs/core/services/router' import { middleware } from '#start/kernel' +import Role from '#enums/role' +const AdminListSharesController = () => + import('#controllers/admin/shares/admin_list_shares_controller') + +const AdminUpdateUsersController = () => + import('#controllers/admin/users/admin_update_users_controller') + +const AdminRemoveUsersController = () => + import('#controllers/admin/users/admin_remove_users_controller') + +const AdminController = () => import('#controllers/admin/admin_controller') + +const AdminListUserController = () => import('#controllers/admin/users/admin_list_users_controller') + +const AdminStoreUsersController = () => + import('#controllers/admin/users/admin_store_users_controller') const ShowImagesController = () => import('#controllers/images/show_images_controller') @@ -88,6 +104,23 @@ router //Upload router.post('/upload', [UploadImagesController, 'upload']).as('upload') + + // Admin + router + .group(() => { + router.get('/', [AdminController, 'render']).as('index') + router.get('/users', [AdminListUserController, 'render']).as('users.lists') + router.post('/users/store', [AdminStoreUsersController, 'store']).as('users.store') + router.post('/users/:id/update', [AdminUpdateUsersController, 'update']).as('users.update') + router + .delete('/users/:id/remove', [AdminRemoveUsersController, 'remove']) + .as('users.delete') + + router.get('/shares', [AdminListSharesController, 'render']).as('shares.lists') + }) + .middleware([middleware.role({ roles: [Role.ADMIN] })]) + .prefix('/admin') + .as('admin') }) .middleware([middleware.auth()])