feat: invite new user with email

This commit is contained in:
Elias Schneider
2023-02-21 08:51:04 +01:00
parent 759c55f625
commit f9840505b8
10 changed files with 111 additions and 29 deletions

View File

@@ -135,9 +135,27 @@ const configVariables: Prisma.ConfigCreateInput[] = [
"Hey!\nYou requested a password reset. Click this link to reset your password: {url}\nThe link expires in a hour.\nPingvin Share 🐧",
category: "email",
},
{
order: 13,
key: "INVITE_EMAIL_SUBJECT",
description:
"Subject of the email which gets sent when an admin invites an user.",
type: "string",
value: "Pingvin Share invite",
category: "email",
},
{
order: 14,
key: "INVITE_EMAIL_MESSAGE",
description:
"Message which gets sent when an admin invites an user. {url} will be replaced with the invite URL and {password} with the password.",
type: "text",
value:
"Hey!\nYou were invited to Pingvin Share. Click this link to accept the invite: {url}\nYour password is: {password}\nPingvin Share 🐧",
category: "email",
},
{
order: 15,
key: "SMTP_ENABLED",
description:
"Whether SMTP is enabled. Only set this to true if you entered the host, port, email, user and password of your SMTP server.",
@@ -147,7 +165,7 @@ const configVariables: Prisma.ConfigCreateInput[] = [
secret: false,
},
{
order: 14,
order: 16,
key: "SMTP_HOST",
description: "Host of the SMTP server",
type: "string",
@@ -155,7 +173,7 @@ const configVariables: Prisma.ConfigCreateInput[] = [
category: "smtp",
},
{
order: 15,
order: 17,
key: "SMTP_PORT",
description: "Port of the SMTP server",
type: "number",
@@ -163,7 +181,7 @@ const configVariables: Prisma.ConfigCreateInput[] = [
category: "smtp",
},
{
order: 16,
order: 18,
key: "SMTP_EMAIL",
description: "Email address which the emails get sent from",
type: "string",
@@ -171,7 +189,7 @@ const configVariables: Prisma.ConfigCreateInput[] = [
category: "smtp",
},
{
order: 17,
order: 19,
key: "SMTP_USERNAME",
description: "Username of the SMTP server",
type: "string",
@@ -179,7 +197,7 @@ const configVariables: Prisma.ConfigCreateInput[] = [
category: "smtp",
},
{
order: 18,
order: 20,
key: "SMTP_PASSWORD",
description: "Password of the SMTP server",
type: "string",

View File

@@ -73,6 +73,20 @@ export class EmailService {
});
}
async sendInviteEmail(recipientEmail: string, password: string) {
const loginUrl = `${this.config.get("APP_URL")}/auth/signIn`;
await this.getTransporter().sendMail({
from: `"Pingvin Share" <${this.config.get("SMTP_EMAIL")}>`,
to: recipientEmail,
subject: this.config.get("INVITE_EMAIL_SUBJECT"),
text: this.config
.get("INVITE_EMAIL_MESSAGE")
.replaceAll("{url}", loginUrl)
.replaceAll("{password}", password),
});
}
async sendTestMail(recipientEmail: string) {
try {
await this.getTransporter().sendMail({

View File

@@ -1,12 +1,15 @@
import { Expose, plainToClass } from "class-transformer";
import { Allow } from "class-validator";
import { plainToClass } from "class-transformer";
import { Allow, IsOptional, MinLength } from "class-validator";
import { UserDTO } from "./user.dto";
export class CreateUserDTO extends UserDTO {
@Expose()
@Allow()
isAdmin: boolean;
@MinLength(8)
@IsOptional()
password: string;
from(partial: Partial<CreateUserDTO>) {
return plainToClass(CreateUserDTO, partial, {
excludeExtraneousValues: true,

View File

@@ -1,8 +1,10 @@
import { Module } from "@nestjs/common";
import { EmailModule } from "src/email/email.module";
import { UserController } from "./user.controller";
import { UserSevice } from "./user.service";
@Module({
imports:[EmailModule],
providers: [UserSevice],
controllers: [UserController],
})

View File

@@ -1,13 +1,17 @@
import { BadRequestException, Injectable } from "@nestjs/common";
import { PrismaClientKnownRequestError } from "@prisma/client/runtime";
import * as argon from "argon2";
import { EmailService } from "src/email/email.service";
import { PrismaService } from "src/prisma/prisma.service";
import { CreateUserDTO } from "./dto/createUser.dto";
import { UpdateUserDto } from "./dto/updateUser.dto";
@Injectable()
export class UserSevice {
constructor(private prisma: PrismaService) {}
constructor(
private prisma: PrismaService,
private emailService: EmailService
) {}
async list() {
return await this.prisma.user.findMany();
@@ -18,7 +22,17 @@ export class UserSevice {
}
async create(dto: CreateUserDTO) {
const hash = await argon.hash(dto.password);
let hash: string;
// The password can be undefined if the user is invited by an admin
if (!dto.password) {
const randomPassword = crypto.randomUUID();
hash = await argon.hash(randomPassword);
this.emailService.sendInviteEmail(dto.email, randomPassword);
} else {
hash = await argon.hash(dto.password);
}
try {
return await this.prisma.user.create({
data: {