start mailing service, and public form output

This commit is contained in:
wodka 2019-08-29 19:07:09 +02:00
parent 93f63f7421
commit 70859f6871
28 changed files with 266 additions and 28 deletions

View File

@ -33,6 +33,7 @@
"bcrypt": "^3.0.6",
"class-transformer": "^0.2.3",
"class-validator": "^0.9.1",
"handlebars": "^4.1.2",
"mongoose": "^5.6.7",
"nestjs-typegoose": "^5.2.1",
"passport": "^0.4.0",

View File

@ -8,6 +8,7 @@ import { AppService } from './app.service';
import { UserModule } from "./user/user.module"
import { FormModule } from "./form/form.module"
import { AuthModule } from './auth/auth.module';
import { MailModule } from "./mail/mail.module"
@Module({
imports: [
@ -19,6 +20,7 @@ import { AuthModule } from './auth/auth.module';
UserModule,
FormModule,
AuthModule,
MailModule,
],
controllers: [AppController],
providers: [AppService],

View File

@ -5,11 +5,13 @@ import { jwtConstants } from "./constants"
import { JwtModule } from "@nestjs/jwt"
import controllers from './auth.controllers'
import providers from './auth.providers'
import { MailModule } from "../mail/mail.module"
@Module({
imports: [
UserModule,
PassportModule,
MailModule,
JwtModule.register({
secret: jwtConstants.secret,
signOptions: { expiresIn: '12h' },

View File

@ -3,6 +3,7 @@ import { PasswordService } from "./services/password.service"
import { PasswordStrategy } from "./strategies/password.strategy"
import { JwtStrategy } from "./strategies/jwt.strategy"
import { JwtRefreshStrategy } from "./strategies/jwt.refresh.strategy"
import { RegisterService } from "./services/register.service"
export default [
AuthService,
@ -10,4 +11,5 @@ export default [
PasswordStrategy,
JwtStrategy,
JwtRefreshStrategy,
RegisterService,
]

View File

@ -1,21 +1,18 @@
import { Controller, Request, Post, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { Controller, Post, Body } from '@nestjs/common';
import { AuthService } from "../services/auth.service"
import { AuthJwtDto } from "../dto/auth.jwt.dto"
import {ApiBearerAuth, ApiImplicitBody, ApiImplicitQuery, ApiResponse, ApiUseTags} from "@nestjs/swagger"
import { ApiBadRequestResponse, ApiCreatedResponse, ApiUseTags } from "@nestjs/swagger"
import { RegisterDto } from "../dto/register.dto"
import {RegisterService} from "../services/register.service"
@ApiUseTags('authentication')
@Controller('auth')
export class RegisterController {
constructor(private readonly authService: AuthService) {}
constructor(private readonly registerService: RegisterService) {}
@ApiResponse({ status: 201, description: 'Successful registration.', type: AuthJwtDto})
@ApiImplicitQuery({name: 'email', type: String})
@ApiImplicitQuery({name: 'username', type: String})
@ApiImplicitQuery({name: 'password', type: String})
@ApiCreatedResponse({ description: 'Successful registration.'})
@ApiBadRequestResponse({})
@Post('register')
async register(@Request() req): Promise<AuthJwtDto> {
// TODO
return null
async register(@Body() params: RegisterDto): Promise<void> {
await this.registerService.register(params.username, params.email, params.password)
}
}

View File

@ -0,0 +1,12 @@
import { ApiModelProperty } from "@nestjs/swagger"
export class RegisterDto {
@ApiModelProperty()
readonly username: string;
@ApiModelProperty()
readonly password: string;
@ApiModelProperty()
readonly email: string;
}

View File

@ -0,0 +1,21 @@
import { Injectable } from "@nestjs/common"
import { MailService } from "../../mail/services/mail.service"
@Injectable()
export class RegisterService {
constructor(private readonly mailService: MailService) {}
async register (username: string, email: string, password: string): Promise<void> {
// TODO actually create user
await this.mailService.sendEmail(
{
template: 'auth/register.hbs',
to: email
},
{
confirm: 'some url'
}
)
}
}

View File

@ -3,7 +3,7 @@ import { PassportStrategy } from '@nestjs/passport';
import { Injectable } from '@nestjs/common';
import { jwtConstants } from '../constants';
import { AuthService } from "../services/auth.service"
import {AuthUser} from "../interfaces/auth.user.interface"
import { AuthUser } from "../interfaces/auth.user.interface"
@Injectable()
export class JwtRefreshStrategy extends PassportStrategy(Strategy, 'jwt.refresh') {

View File

@ -1,10 +1,11 @@
import {Controller, Request, Get, Post, Put, Delete, UseGuards, Param} from '@nestjs/common';
import {Controller, Request, Get, Post, Put, Delete, UseGuards, Param, NotImplementedException} from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { ApiUseTags } from "@nestjs/swagger"
import { ApiBearerAuth, ApiImplicitQuery, ApiResponse, ApiUseTags } from "@nestjs/swagger"
import { FormService } from "../services/form.service"
import {Form} from "../models/form.model"
import { FormDto } from "../dto/form.dto"
@ApiUseTags('forms')
@ApiBearerAuth()
@Controller('forms')
export class FormController {
constructor(private readonly formService: FormService) {}
@ -12,28 +13,31 @@ export class FormController {
@Get()
@UseGuards(AuthGuard('jwt'))
async list(@Request() req): Promise<any> {
return true;
throw new NotImplementedException()
}
@Post()
@UseGuards(AuthGuard('jwt'))
async create(@Request() req): Promise<Form> {
return null;
async create(@Request() req): Promise<FormDto> {
throw new NotImplementedException()
}
@ApiResponse({ status: 200, description: 'Form Object', type: FormDto})
@ApiImplicitQuery({name: 'id', type: String})
@Get(':id')
@UseGuards(AuthGuard('jwt'))
async read(@Param('id') id): Promise<Form> {
return this.formService.findById(id);
async read(@Param('id') id): Promise<FormDto> {
return new FormDto(await this.formService.findById(id));
}
@Put(':id')
@UseGuards(AuthGuard('jwt'))
async update(@Param('id') id, @Request() req): Promise<Form> {
return this.formService.findById(id);
async update(@Param('id') id, @Request() req): Promise<FormDto> {
throw new NotImplementedException()
}
@Delete(':id')
@UseGuards(AuthGuard('jwt'))
async delete(@Param('id') id): Promise<void> {
throw new NotImplementedException()
}
}

View File

@ -0,0 +1,24 @@
import { Controller, Get, Param, NotFoundException } from '@nestjs/common';
import { ApiImplicitQuery, ApiResponse, ApiUseTags } from "@nestjs/swagger"
import { FormService } from "../services/form.service"
import { Form } from "../models/form.model"
import { PublicFormDto } from "../dto/public.form.dto"
@ApiUseTags('forms')
@Controller('public')
export class PublicController {
constructor(private readonly formService: FormService) {}
@ApiResponse({ status: 200, description: 'Form Object', type: PublicFormDto})
@ApiImplicitQuery({name: 'id', type: String})
@Get(':id')
async read(@Param('id') id): Promise<PublicFormDto> {
const form:Form = await this.formService.findById(id)
if (!form.isLive) {
throw new NotFoundException();
}
return new PublicFormDto(form);
}
}

View File

@ -0,0 +1,17 @@
import { ApiModelProperty } from '@nestjs/swagger';
import { Form } from "../models/form.model"
export class FormDto {
@ApiModelProperty()
id: string;
@ApiModelProperty()
title: string;
fields: [];
constructor(partial: Partial<Form>) {
this.id = partial._id.toString();
this.title = partial.title
}
}

View File

@ -0,0 +1,17 @@
import { ApiModelProperty } from '@nestjs/swagger';
import { Form } from "../models/form.model"
export class PublicFormDto {
@ApiModelProperty()
id: string;
@ApiModelProperty()
title: string;
fields: [];
constructor(partial: Partial<Form>) {
this.id = partial._id.toString();
this.title = partial.title
}
}

View File

@ -1,5 +1,7 @@
import { FormController } from "./controllers/form.controller"
import { PublicController } from "./controllers/public.controller"
export default [
FormController,
PublicController,
]

View File

@ -1,4 +1,4 @@
import {prop, Ref, Typegoose} from "typegoose"
import {arrayProp, prop, Ref, Typegoose} from "typegoose"
import {Analytics} from "./embedded/analytics"
import {Field} from "./embedded/field"
import {StartPage} from "./embedded/start.page"
@ -8,12 +8,18 @@ import {RespondentNotifications} from "./embedded/respondent.notifications"
import {Design} from "./embedded/design"
import {User} from "../../user/models/user.model"
export class Form extends Typegoose{
export class Form extends Typegoose {
readonly _id: any;
@prop({
trim: true,
required: 'Form Title cannot be blank'
})
readonly firstName: string;
readonly title: string;
readonly created: any;
readonly lastModified: any;
@prop({
enum: ['en', 'fr', 'es', 'it', 'de'],
@ -25,7 +31,8 @@ export class Form extends Typegoose{
@prop()
readonly analytics: Analytics;
@prop({
@arrayProp({
items: Field,
default: []
})
readonly form_fields: Field[];

View File

@ -0,0 +1,12 @@
export class OptionsDto {
template: string;
language?: string;
to: string;
cc?: string[];
bcc?: string[];
}

View File

@ -0,0 +1,5 @@
import { MailService } from "./services/mail.service"
export default [
MailService
]

View File

@ -0,0 +1,10 @@
import { Module } from '@nestjs/common';
import providers from './mail.providers'
import exportList from './mail.exports'
@Module({
imports: [],
providers,
exports: exportList,
})
export class MailModule {}

View File

@ -0,0 +1,5 @@
import { MailService } from "./services/mail.service"
export default [
MailService
]

View File

@ -0,0 +1,10 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import { OptionsDto } from "../dto/options.dto"
@Injectable()
export class MailService {
// TODO
async sendEmail(options:OptionsDto, placeholders:any): Promise<boolean> {
return false
}
}

View File

@ -0,0 +1,6 @@
Hi,
if you have not requested a new password you can ignore this email. To set a new password for your account
just follow this link: {{ recover }}
See you soon

View File

@ -0,0 +1,5 @@
Welcome to OhMyForm!
please confirm your account by following the following link: {{ confirm }}
enjoy!

View File

@ -15,7 +15,7 @@ async function bootstrap() {
transform: true,
}));
// app.useGlobalInterceptors(new ClassSerializerInterceptor(app.get(Reflector)))
app.useGlobalInterceptors(new ClassSerializerInterceptor(app.get(Reflector)))
const options = new DocumentBuilder()
.setTitle('OhMyForm')

View File

@ -0,0 +1,50 @@
import {Controller, Request, Get, Post, Put, Delete, UseGuards, Param, NotImplementedException} from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { ApiBearerAuth, ApiImplicitQuery, ApiResponse, ApiUseTags } from "@nestjs/swagger"
import { UserService } from "../services/user.service"
import { UserDto } from "../dto/user.dto"
@ApiUseTags('users')
@ApiBearerAuth()
@Controller('users')
export class UserController {
constructor(private readonly userService: UserService) {}
@Get()
@UseGuards(AuthGuard('jwt'))
async list(@Request() req): Promise<any> {
throw new NotImplementedException()
}
@ApiResponse({ status: 200, description: 'User Object', type: UserDto})
@Post()
@UseGuards(AuthGuard('jwt'))
async create(@Request() req): Promise<UserDto> {
throw new NotImplementedException()
}
@ApiResponse({ status: 200, description: 'User Object', type: UserDto})
@ApiImplicitQuery({name: 'id', type: String})
@Get(':id')
@UseGuards(AuthGuard('jwt'))
async read(@Param('id') id): Promise<UserDto> {
return new UserDto(await this.userService.findById(id));
}
@ApiResponse({ status: 200, description: 'User Object', type: UserDto})
@ApiImplicitQuery({name: 'id', type: String})
@Put(':id')
@UseGuards(AuthGuard('jwt'))
async update(@Param('id') id, @Request() req): Promise<UserDto> {
throw new NotImplementedException()
}
@ApiResponse({ status: 200, description: 'User Object', type: UserDto})
@ApiImplicitQuery({name: 'id', type: String})
@Delete(':id')
@UseGuards(AuthGuard('jwt'))
async delete(@Param('id') id): Promise<void> {
throw new NotImplementedException()
}
}

View File

@ -0,0 +1,15 @@
import { ApiModelProperty } from '@nestjs/swagger';
import {User} from "../models/user.model"
export class UserDto {
@ApiModelProperty()
id: string;
@ApiModelProperty()
username: string;
constructor(partial: Partial<User>) {
this.id = partial._id.toString();
this.username = partial.username
}
}

View File

@ -2,6 +2,7 @@ import {Injectable, NotFoundException} from '@nestjs/common';
import { InjectModel } from 'nestjs-typegoose';
import { ModelType } from 'typegoose';
import { User } from "../models/user.model"
import {Form} from "../../form/models/form.model"
@Injectable()
export class UserService {
@ -23,4 +24,8 @@ export class UserService {
return results[0]
}
async findById(id: string): Promise<User> {
return await this.userModel.findById(id).exec()
}
}

View File

@ -0,0 +1,5 @@
import { UserController } from "./controllers/user.controller"
export default [
UserController,
]

View File

@ -3,11 +3,13 @@ import { TypegooseModule } from 'nestjs-typegoose';
import providers from './user.providers'
import exportList from './user.exports'
import { User } from "./models/user.model"
import controllers from './user.controllers'
@Module({
imports: [
TypegooseModule.forFeature([User]),
],
controllers,
providers,
exports: exportList,
})