Skip to content

Commit

Permalink
Merge pull request #3 from iverly/feature/add-notes-module
Browse files Browse the repository at this point in the history
feat: add notes module
  • Loading branch information
iverly authored Nov 27, 2023
2 parents 8370b32 + 0560f15 commit 088b8bb
Show file tree
Hide file tree
Showing 36 changed files with 769 additions and 5 deletions.
2 changes: 2 additions & 0 deletions apps/api/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { AuthModule } from '@nx-next-nest-prisma-ory-template/auth';
import { DatabaseModule } from '@nx-next-nest-prisma-ory-template/database';
import { NotesModule } from '@nx-next-nest-prisma-ory-template/notes';
import { OpenTelemetryModule } from '@nx-next-nest-prisma-ory-template/opentelemetry';

@Module({
Expand All @@ -10,6 +11,7 @@ import { OpenTelemetryModule } from '@nx-next-nest-prisma-ory-template/opentelem
ConfigModule.forRoot(),
AuthModule,
DatabaseModule,
NotesModule,
],
controllers: [],
providers: [],
Expand Down
Empty file removed config/keto/namespaces/.gitkeep
Empty file.
4 changes: 4 additions & 0 deletions config/keto/namespaces/notes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"id": 1,
"name": "notes"
}
1 change: 1 addition & 0 deletions config/oathkeeper/oathkeeper.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ access_rules:
- file:///etc/config/oathkeeper/rules/auth.yaml
- file:///etc/config/oathkeeper/rules/kratos.yaml
- file:///etc/config/oathkeeper/rules/dev.yaml
- file:///etc/config/oathkeeper/rules/api-notes.yaml

authenticators:
anonymous:
Expand Down
63 changes: 63 additions & 0 deletions config/oathkeeper/rules/api-notes.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#######################################
# Notes Access Rules #
#######################################
- id: "api:create-note:protected"
upstream:
preserve_host: true
url: "http://api:3100"
match:
url: http://api.nx-next-nest-prisma-ory-template.<127\.0\.0\.1\.sslip\.io|com>/notes
methods:
- POST
authenticators:
- handler: cookie_session
authorizer:
handler: allow
mutators:
- handler: id_token
errors:
- handler: redirect

- id: "api:note:protected"
upstream:
preserve_host: true
url: "http://api:3100"
match:
url: http://api.nx-next-nest-prisma-ory-template.<127\.0\.0\.1\.sslip\.io|com>/notes/<([0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})>
methods:
- GET
- PATCH
- DELETE
authenticators:
- handler: cookie_session
authorizer:
handler: remote_json
config:
payload: |
{
"namespace": "notes",
"object": "{{ printIndex .MatchContext.RegexpCaptureGroups 1 }}",
"relation": "owner",
"subject_id": "{{ print .Subject }}"
}
mutators:
- handler: id_token
errors:
- handler: redirect

- id: "api:list-note:protected"
upstream:
preserve_host: true
url: "http://api:3100"
match:
url: http://api.nx-next-nest-prisma-ory-template.<127\.0\.0\.1\.sslip\.io|com>/notes
methods:
- GET
authenticators:
- handler: cookie_session
authorizer:
handler: allow
mutators:
- handler: id_token
errors:
- handler: redirect
1 change: 1 addition & 0 deletions docker-compose.base.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ services:
- ./config/oathkeeper/id_token.jwks.json:/etc/config/oathkeeper/id_token.jwks.json
- ./config/oathkeeper/rules/auth.yaml:/etc/config/oathkeeper/rules/auth.yaml
- ./config/oathkeeper/rules/kratos.yaml:/etc/config/oathkeeper/rules/kratos.yaml
- ./config/oathkeeper/rules/api-notes.yaml:/etc/config/oathkeeper/rules/api-notes.yaml
depends_on:
- kratos

Expand Down
18 changes: 18 additions & 0 deletions packages/notes/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"extends": ["../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
}
]
}
11 changes: 11 additions & 0 deletions packages/notes/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/* eslint-disable */
export default {
displayName: 'notes',
preset: '../../jest.preset.js',
testEnvironment: 'node',
transform: {
'^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
},
moduleFileExtensions: ['ts', 'js', 'html'],
coverageDirectory: '../../coverage/packages/notes',
};
23 changes: 23 additions & 0 deletions packages/notes/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "notes",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "packages/notes/src",
"projectType": "library",
"targets": {
"lint": {
"executor": "@nx/eslint:lint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["packages/notes/**/*.ts"]
}
},
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
"options": {
"jestConfig": "packages/notes/jest.config.ts"
}
}
},
"tags": []
}
1 change: 1 addition & 0 deletions packages/notes/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './lib/notes.module';
159 changes: 159 additions & 0 deletions packages/notes/src/lib/notes.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import {
Body,
Controller,
NotFoundException,
Param,
Req,
RequestMethod,
} from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { ApiRouteAuthenticated } from '@nx-next-nest-prisma-ory-template/utils';
import { NotesService } from './notes.service';
import { FastifyRequest } from 'fastify';
import {
CreateNoteDto,
Note,
NoteDto,
UpdateNoteDto,
} from '@nx-next-nest-prisma-ory-template/types';

@ApiTags('Notes')
@Controller('notes')
export class NotesController {
constructor(private notesService: NotesService) {}

@ApiRouteAuthenticated({
method: RequestMethod.POST,
operation: {
summary: 'Create a note',
description: 'Create a new note with the given name and type',
},
response: {
status: 201,
type: NoteDto,
},
})
create(
@Body() body: CreateNoteDto,
@Req() request: FastifyRequest
): Promise<NoteDto> {
return this.notesService.create(body, request.user.sub);
}

@ApiRouteAuthenticated({
method: RequestMethod.GET,
operation: {
summary: 'List all notes',
description: 'Returns the list of all notes (limited to 1000)',
},
response: {
status: 200,
schema: {
type: 'array',
items: {
type: 'object',
properties: {
id: {
type: 'string',
description: 'The note id',
example: 'b1774d2f-05f7-4ea4-b427-0d808bdca583',
},
title: {
type: 'string',
description: 'The note title',
example: 'My note',
},
body: {
type: 'string',
description: 'The note body',
example: 'This is the body of my note',
},
createdAt: {
type: 'string',
description: 'The note creation date',
example: '2021-03-11T20:43:06.000Z',
},
},
},
},
},
})
async list(@Req() request: FastifyRequest): Promise<Note[]> {
const notes = await this.notesService.list(request.user.sub);

if (!notes) {
throw new NotFoundException();
}

return notes;
}

@ApiRouteAuthenticated({
method: RequestMethod.GET,
path: ':noteId',
operation: {
summary: 'Get a specific note',
description: 'Returns the note with the given id',
},
response: {
status: 200,
type: NoteDto,
},
})
async get(@Param('noteId') noteId: string): Promise<NoteDto> {
const note = await this.notesService.get(noteId);

if (!note) {
throw new NotFoundException();
}

return note;
}

@ApiRouteAuthenticated({
method: RequestMethod.PATCH,
path: ':noteId',
operation: {
summary: 'Update a specific note',
description: 'Updates the note with the given id',
},
response: {
status: 200,
type: NoteDto,
},
})
async patch(
@Body() body: UpdateNoteDto,
@Param('noteId') noteId: string
): Promise<NoteDto> {
const note = await this.notesService.patch(noteId, body);

if (!note) {
throw new NotFoundException();
}

return note;
}

@ApiRouteAuthenticated({
method: RequestMethod.DELETE,
path: ':noteId',
operation: {
summary: 'Delete a specific note',
description: 'Deletes the note with the given id',
},
response: {
status: 200,
type: NoteDto,
},
})
async delete(@Param('noteId') noteId: string): Promise<NoteDto> {
const note = await this.notesService.delete(noteId);

if (!note) {
throw new NotFoundException();
}

return note;
}
}
13 changes: 13 additions & 0 deletions packages/notes/src/lib/notes.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Module } from '@nestjs/common';
import { AuthModule } from '@nx-next-nest-prisma-ory-template/auth';
import { DatabaseModule } from '@nx-next-nest-prisma-ory-template/database';
import { NotesController } from './notes.controller';
import { NotesService } from './notes.service';

@Module({
imports: [AuthModule, DatabaseModule],
controllers: [NotesController],
providers: [NotesService],
exports: [],
})
export class NotesModule {}
Loading

0 comments on commit 088b8bb

Please sign in to comment.