Skip to content

Commit

Permalink
Chore/backend cleanup (#605)
Browse files Browse the repository at this point in the history
* move dtos to dto folder

* split auth controller by functionnality
  • Loading branch information
hissalht authored Jan 11, 2024
1 parent 02580ac commit b0101e7
Show file tree
Hide file tree
Showing 20 changed files with 281 additions and 215 deletions.
10 changes: 5 additions & 5 deletions confiture-rest-api/src/audits/audit.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ import { omit, pick, setWith } from "lodash";

import { PrismaService } from "../prisma.service";
import * as RGAA from "../rgaa.json";
import { AuditReportDto } from "./audit-report.dto";
import { CreateAuditDto } from "./create-audit.dto";
import { AuditReportDto } from "./dto/audit-report.dto";
import { CreateAuditDto } from "./dto/create-audit.dto";
import { CRITERIA_BY_AUDIT_TYPE } from "./criteria";
import { FileStorageService } from "./file-storage.service";
import { UpdateAuditDto } from "./update-audit.dto";
import { UpdateResultsDto } from "./update-results.dto";
import { PatchAuditDto } from "./patch-audit.dto";
import { UpdateAuditDto } from "./dto/update-audit.dto";
import { UpdateResultsDto } from "./dto/update-results.dto";
import { PatchAuditDto } from "./dto/patch-audit.dto";

const AUDIT_EDIT_INCLUDE: Prisma.AuditInclude = {
recipients: true,
Expand Down
12 changes: 6 additions & 6 deletions confiture-rest-api/src/audits/audits.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ import { CriterionResult } from "src/generated/nestjs-dto/criterionResult.entity
import { MailService } from "../mail/mail.service";
import { AuditExportService } from "./audit-export.service";
import { AuditService } from "./audit.service";
import { CreateAuditDto } from "./create-audit.dto";
import { DuplicateAuditDto } from "./duplicate-audit.dto";
import { UpdateAuditDto } from "./update-audit.dto";
import { PatchAuditDto } from "./patch-audit.dto";
import { UpdateResultsDto } from "./update-results.dto";
import { UploadImageDto } from "./upload-image.dto";
import { CreateAuditDto } from "./dto/create-audit.dto";
import { DuplicateAuditDto } from "./dto/duplicate-audit.dto";
import { UpdateAuditDto } from "./dto/update-audit.dto";
import { PatchAuditDto } from "./dto/patch-audit.dto";
import { UpdateResultsDto } from "./dto/update-results.dto";
import { UploadImageDto } from "./dto/upload-image.dto";
import { AuthRequired } from "src/auth/auth-required.decorator";
import { User } from "src/auth/user.decorator";
import { AuthenticationJwtPayload } from "src/auth/jwt-payloads";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
ValidationOptions
} from "class-validator";

import { CRITERIA } from "./criteria";
import { CRITERIA } from "../criteria";

/** Validates the criterium property to make sure the criterium exists in the RGAA. */
export function IsRgaaCriterium(validationOptions?: ValidationOptions) {
Expand Down
2 changes: 1 addition & 1 deletion confiture-rest-api/src/audits/reports.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
ApiTags
} from "@nestjs/swagger";

import { AuditReportDto } from "./audit-report.dto";
import { AuditReportDto } from "./dto/audit-report.dto";
import { AuditService } from "./audit.service";
import { AuditExportService } from "./audit-export.service";

Expand Down
199 changes: 1 addition & 198 deletions confiture-rest-api/src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
import {
BadRequestException,
Body,
ConflictException,
Controller,
Delete,
Get,
HttpCode,
Post,
Put,
Query,
UnauthorizedException
} from "@nestjs/common";
import {
ApiBadRequestResponse,
ApiConflictResponse,
ApiCreatedResponse,
ApiOkResponse,
ApiTags,
Expand All @@ -24,24 +19,13 @@ import { AuditService } from "../audits/audit.service";
import { FeedbackService } from "../feedback/feedback.service";
import { MailService } from "../mail/mail.service";
import { AuthRequired } from "./auth-required.decorator";
import {
AuthService,
InvalidVerificationTokenError,
SigninError,
TokenRegenerationError,
UsernameAlreadyExistsError
} from "./auth.service";
import { CreateAccountDto } from "./dto/create-account.dto";
import { AuthService, SigninError } from "./auth.service";
import { DeleteAccountResponseDto } from "./dto/delete-account-response.dto";
import { DeleteAccountDto } from "./dto/delete-account.dto";
import { ResendVerificationEmailDto } from "./dto/resend-verification-email.dto";
import { SigninDto } from "./dto/signin.dto";
import { UpdatePasswordDto } from "./dto/update-password.dto";
import { VerifyAccountDto } from "./dto/verify-account.dto";
import { AuthenticationJwtPayload } from "./jwt-payloads";
import { User } from "./user.decorator";
import { UpdateEmailDto } from "./update-email.dto";
import { VerifyEmailUpdateDto } from "./verify-email-update.dto";

@Controller("auth")
@ApiTags("Authentication")
Expand All @@ -53,98 +37,6 @@ export class AuthController {
private readonly audit: AuditService
) {}

/**
* Create a new user account.
*
* The account is not useable right away, it first needs to be verified.
* To do this, an email containing a verification link is sent to the user
* mail adress (their username).
*
* This link contains a *verification token* that will be sent to the
* `/api/auth/verify` endpoint to activate the account.
*/
@Post("signup")
@ApiConflictResponse({
description: "A verified account with this username already exists."
})
@ApiCreatedResponse({
description: "Account successfully created (pending verification)."
})
async createAccount(@Body() body: CreateAccountDto) {
try {
const verificationToken = await this.auth.createUnverifiedUser(
body.username,
body.password
);
await this.email.sendAccountVerificationEmail(
body.username,
verificationToken
);
} catch (e) {
if (e instanceof UsernameAlreadyExistsError) {
throw new ConflictException();
}
throw e;
}
}

@Post("resend-verification-email")
@HttpCode(200)
@ApiOkResponse({ description: "Verification email has been resent." })
@ApiBadRequestResponse({
description:
"Either no such user exist or the account has already been verified."
})
async resetVarificationEmail(@Body() body: ResendVerificationEmailDto) {
try {
const verificationToken = await this.auth.regenerateVerificationToken(
body.username
);
console.log("verificationToken:", verificationToken);
await this.email.sendAccountVerificationEmail(
body.username,
verificationToken
);
} catch (e) {
if (e instanceof TokenRegenerationError) {
console.log("Token regeneration failed:", e.message);
throw new BadRequestException();
}
throw e;
}
}

/**
* Verify an account by validating the given token.
*/
@Post("verify")
@HttpCode(200)
@ApiOkResponse({ description: "Account successfully verified." })
@ApiUnauthorizedResponse({ description: "Invalid verification token." })
async verifyAccount(@Body() body: VerifyAccountDto) {
try {
const email = await this.auth.getEmailFromVerificationToken(body.token);

await this.auth.verifyAccount(body.token);
this.email.sendAccountConfirmationEmail(email).catch((err) => {
console.error(`Failed to send email for account creation ${email}`);
console.error(err);
});
} catch (e) {
if (e instanceof InvalidVerificationTokenError) {
console.log("Account verification failed:", e.message);
throw new UnauthorizedException("Invalid token");
}
throw e;
}
}

/** Check if account is verified. */
@Get("verified")
async isAccountVerified(@Query("username") username: string) {
return await this.auth.isAccountVerified(username);
}

/**
* Login using *username and password*. An authentication token is returned.
*
Expand Down Expand Up @@ -247,93 +139,4 @@ export class AuthController {

return;
}
/** Update the user's email adress. The change is not effective immediately.
* The new email adress must first be verified using the
* `account/verify-email-update` route. */
@Put("account/email")
@ApiOkResponse({
description:
"Email update successfully requested. The new email must be confirmed by using the `account/verify-email-update` route."
})
@AuthRequired()
async updateEmail(
@Body() body: UpdateEmailDto,
@User() user: AuthenticationJwtPayload
) {
if (!(await this.auth.checkCredentialsWithUid(user.sub, body.password))) {
throw new UnauthorizedException();
}
try {
const verificationToken = await this.auth.addNewEmail(
user.sub,
body.newEmail
);

await this.email.sendNewEmailVerificationEmail(
body.newEmail,
verificationToken
);
} catch (e) {
if (e instanceof UsernameAlreadyExistsError) {
throw new ConflictException();
}
throw e;
}
}

/** Trigger a new verification email for the email update. */
@Post("account/resend-email-update-verification-email")
@HttpCode(200)
@AuthRequired()
async resendNewEmailVerificationEmail(
@User() user: AuthenticationJwtPayload
) {
try {
const { token, email } =
await this.auth.regenerateEmailUpdateVerificationToken(user.sub);
await this.email.sendNewEmailVerificationEmail(email, token);
} catch (e) {
if (e instanceof TokenRegenerationError) {
console.log("Token regeneration failed:", e.message);
throw new BadRequestException();
}
throw e;
}
}

/** Verify an email adress by receiving the verification token sent the wanted email adress. */
@Post("account/verify-email-update")
async verifyEmailUpdate(@Body() body: VerifyEmailUpdateDto) {
try {
const email = await this.auth.getEmailFromVerificationToken(body.token);

await this.auth.verifyEmailUpdate(body.token);
this.email.sendEmailUpdateConfirmationEmail(email);
} catch (e) {
if (e instanceof InvalidVerificationTokenError) {
console.log("Email update verification failed:", e.message);
throw new UnauthorizedException("Invalid token");
}
throw e;
}
}

@Post("account/cancel-email-update")
@AuthRequired()
async cancelEmailUpdate(@User() user: AuthenticationJwtPayload) {
await this.auth.cancelEmailUpdate(user.email);
}

/** Checks if given email is verified for the authenticated user. */
@Get("account/verified-email-update")
@ApiOkResponse({
type: Boolean
})
@AuthRequired()
async isNewEmailVerified(
@User() user: AuthenticationJwtPayload,
@Query("email") email: string
) {
return await this.auth.userHasEmail(user.sub, email);
}
}
9 changes: 8 additions & 1 deletion confiture-rest-api/src/auth/auth.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,17 @@ import { AuthController } from "./auth.controller";
import { AuthService } from "./auth.service";
import { AuditsModule } from "src/audits/audits.module";
import { PasswordResetController } from "./password-reset.controller";
import { UpdateEmailController } from "./update-email.controller";
import { CreateAccountController } from "./create-account.controller";

@Module({
providers: [AuthService, PrismaService],
controllers: [AuthController, PasswordResetController],
controllers: [
AuthController,
CreateAccountController,
PasswordResetController,
UpdateEmailController
],
imports: [
MailModule,
JwtModule.registerAsync({
Expand Down
Loading

0 comments on commit b0101e7

Please sign in to comment.