UI & Feature update - Alpha #9

Merged
Mathis merged 22 commits from dev into prod 2026-01-14 22:40:06 +01:00
5 changed files with 81 additions and 3 deletions
Showing only changes of commit 65f8860cc0 - Show all commits

View File

@@ -5,6 +5,7 @@ import { ScheduleModule } from "@nestjs/schedule";
import { ThrottlerModule } from "@nestjs/throttler";
import { redisStore } from "cache-manager-redis-yet";
import { ApiKeysModule } from "./api-keys/api-keys.module";
import { AdminModule } from "./admin/admin.module";
import { AppController } from "./app.controller";
import { AppService } from "./app.service";
import { AuthModule } from "./auth/auth.module";
@@ -42,6 +43,7 @@ import { UsersModule } from "./users/users.module";
SessionsModule,
ReportsModule,
ApiKeysModule,
AdminModule,
ScheduleModule.forRoot(),
ThrottlerModule.forRootAsync({
imports: [ConfigModule],

View File

@@ -5,6 +5,9 @@ import { SessionsModule } from "../sessions/sessions.module";
import { UsersModule } from "../users/users.module";
import { AuthController } from "./auth.controller";
import { AuthService } from "./auth.service";
import { AuthGuard } from "./guards/auth.guard";
import { OptionalAuthGuard } from "./guards/optional-auth.guard";
import { RolesGuard } from "./guards/roles.guard";
import { RbacService } from "./rbac.service";
import { RbacRepository } from "./repositories/rbac.repository";
@@ -16,7 +19,21 @@ import { RbacRepository } from "./repositories/rbac.repository";
DatabaseModule,
],
controllers: [AuthController],
providers: [AuthService, RbacService, RbacRepository],
exports: [AuthService, RbacService, RbacRepository],
providers: [
AuthService,
RbacService,
RbacRepository,
AuthGuard,
OptionalAuthGuard,
RolesGuard,
],
exports: [
AuthService,
RbacService,
RbacRepository,
AuthGuard,
OptionalAuthGuard,
RolesGuard,
],
})
export class AuthModule {}

View File

@@ -0,0 +1,43 @@
import {
CanActivate,
ExecutionContext,
Injectable,
} from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { getIronSession } from "iron-session";
import { JwtService } from "../../crypto/services/jwt.service";
import { getSessionOptions, SessionData } from "../session.config";
@Injectable()
export class OptionalAuthGuard implements CanActivate {
constructor(
private readonly jwtService: JwtService,
private readonly configService: ConfigService,
) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();
const response = context.switchToHttp().getResponse();
const session = await getIronSession<SessionData>(
request,
response,
getSessionOptions(this.configService.get("SESSION_PASSWORD") as string),
);
const token = session.accessToken;
if (!token) {
return true;
}
try {
const payload = await this.jwtService.verifyJwt(token);
request.user = payload;
} catch {
// Ignore invalid tokens for optional auth
}
return true;
}
}

View File

@@ -1,5 +1,5 @@
import { Injectable } from "@nestjs/common";
import { eq } from "drizzle-orm";
import { eq, sql } from "drizzle-orm";
import { DatabaseService } from "../../database/database.service";
import { categories } from "../../database/schemas";
import type { CreateCategoryDto } from "../dto/create-category.dto";
@@ -16,6 +16,13 @@ export class CategoriesRepository {
.orderBy(categories.name);
}
async countAll() {
const result = await this.databaseService.db
.select({ count: sql<number>`count(*)` })
.from(categories);
return Number(result[0].count);
}
async findOne(id: string) {
const result = await this.databaseService.db
.select()

View File

@@ -5,4 +5,13 @@ export class UpdateUserDto {
@IsString()
@MaxLength(32)
displayName?: string;
@IsOptional()
@IsString()
@MaxLength(255)
bio?: string;
@IsOptional()
@IsString()
avatarUrl?: string;
}