feat: add basic admin dashboard

This commit is contained in:
Sonny
2024-05-26 03:18:25 +02:00
committed by Sonny
parent f3f7f6272f
commit 202f70b010
24 changed files with 324 additions and 33 deletions

View File

@@ -0,0 +1,42 @@
import UsersController from '#controllers/users_controller';
import User from '#models/user';
import { inject } from '@adonisjs/core';
import type { HttpContext } from '@adonisjs/core/http';
import db from '@adonisjs/lucid/services/db';
class UserWithRelationCountDto {
constructor(private user: User) {}
public toJson() {
return {
id: this.user.id,
email: this.user.email,
fullname: this.user.name,
avatarUrl: this.user.avatarUrl,
isAdmin: this.user.isAdmin,
createdAt: this.user.createdAt,
updatedAt: this.user.updatedAt,
count: {
link: Number(this.user.$extras.totalLinks),
collection: Number(this.user.$extras.totalCollections),
},
};
}
}
@inject()
export default class AdminController {
constructor(protected usersController: UsersController) {}
async index({ inertia }: HttpContext) {
const users = await this.usersController.getAllUsersWithTotalRelations();
const links = await db.from('links').count('* as total');
const collections = await db.from('collections').count('* as total');
return inertia.render('admin/dashboard', {
users: users.map((user) => new UserWithRelationCountDto(user).toJson()),
totalLinks: Number(links[0].total),
totalCollections: Number(collections[0].total),
});
}
}

View File

@@ -1,6 +1,7 @@
import User from '#models/user';
import type { HttpContext } from '@adonisjs/core/http';
import logger from '@adonisjs/core/services/logger';
import db from '@adonisjs/lucid/services/db';
import { RouteName } from '@izzyjs/route/types';
export default class UsersController {
@@ -30,6 +31,7 @@ export default class UsersController {
return response.redirectToNamedRoute(this.redirectTo);
}
const userCount = await db.from('users').count('* as total');
const {
email,
id: providerId,
@@ -50,6 +52,7 @@ export default class UsersController {
avatarUrl,
token,
providerType: 'google',
isAdmin: userCount[0].total === '0',
}
);
@@ -66,4 +69,10 @@ export default class UsersController {
logger.info(`[${auth.user?.email}] disconnected successfully`);
response.redirectToNamedRoute(this.redirectTo);
}
async getAllUsersWithTotalRelations() {
return User.query()
.withCount('collections', (q) => q.as('totalCollections'))
.withCount('links', (q) => q.as('totalLinks'));
}
}

View File

@@ -0,0 +1,11 @@
import type { HttpContext } from '@adonisjs/core/http';
import type { NextFn } from '@adonisjs/core/types/http';
export default class AdminMiddleware {
async handle(ctx: HttpContext, next: NextFn) {
if (!ctx.auth.user?.isAdmin) {
return ctx.response.redirectToNamedRoute('dashboard');
}
return next();
}
}

View File

@@ -7,21 +7,19 @@ import { DateTime } from 'luxon';
export default class AppBaseModel extends BaseModel {
static namingStrategy = new CamelCaseNamingStrategy();
static selfAssignPrimaryKey = true;
serializeExtras = true;
@column({ isPrimary: true })
declare id: number;
@column.dateTime({
autoCreate: true,
serializeAs: 'created_at',
})
declare created_at: DateTime;
declare createdAt: DateTime;
@column.dateTime({
autoCreate: true,
autoUpdate: true,
serializeAs: 'updated_at',
})
declare updated_at: DateTime;
declare updatedAt: DateTime;
}

View File

@@ -21,7 +21,7 @@ export default class Collection extends AppBaseModel {
@column()
declare authorId: number;
@belongsTo(() => User, { foreignKey: 'authorId' })
@belongsTo(() => User, { foreignKey: 'author_id' })
declare author: BelongsTo<typeof User>;
@hasMany(() => Link)

View File

@@ -1,8 +1,8 @@
import Collection from '#models/collection';
import Link from '#models/link';
import type { GoogleToken } from '@adonisjs/ally/types';
import { column, computed, manyToMany } from '@adonisjs/lucid/orm';
import type { ManyToMany } from '@adonisjs/lucid/types/relations';
import { column, computed, hasMany } from '@adonisjs/lucid/orm';
import type { HasMany } from '@adonisjs/lucid/types/relations';
import AppBaseModel from './app_base_model.js';
export default class User extends AppBaseModel {
@@ -30,15 +30,15 @@ export default class User extends AppBaseModel {
@column({ serializeAs: null })
declare providerType: 'google';
@manyToMany(() => Collection, {
relatedKey: 'authorId',
@hasMany(() => Collection, {
foreignKey: 'authorId',
})
declare collections: ManyToMany<typeof Collection>;
declare collections: HasMany<typeof Collection>;
@manyToMany(() => Link, {
relatedKey: 'authorId',
@hasMany(() => Link, {
foreignKey: 'authorId',
})
declare links: ManyToMany<typeof Link>;
declare links: HasMany<typeof Link>;
@computed()
get fullname() {