-
Notifications
You must be signed in to change notification settings - Fork 39
5577/property section backend #5693
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 40 commits
c414d34
b23c6ae
ac0ef38
b15fe2e
a9ea7ee
13f01c7
d34a4fc
fb66753
238aeb8
cf53b5d
2b452dd
f219218
15bc7b9
d6686e3
81d9d98
e2f40b4
81448a2
b1bcf09
b341279
ae3bdf4
2353efa
50fe405
a788f37
1161b05
474b273
b5f605d
2a0b913
fbee33a
b22454d
67122e6
cfe0243
46d1d94
a974137
d8e699e
1d47bb3
6e7af79
f3ef213
1fe0c52
9845437
cbe9162
3680303
448a970
7a70a4c
a325bf4
c59879a
535b4ee
678defa
dd6f5d0
1330c7d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| -- AlterTable | ||
| ALTER TABLE "listings" | ||
| ADD COLUMN "property_id" UUID; | ||
|
|
||
| -- CreateTable | ||
| CREATE TABLE "properties" ( | ||
| "id" UUID NOT NULL DEFAULT uuid_generate_v4(), | ||
| "created_at" TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
| "updated_at" TIMESTAMP(6) NOT NULL, | ||
| "name" TEXT NOT NULL, | ||
| "description" TEXT, | ||
| "url" TEXT, | ||
| "url_title" TEXT, | ||
| "jurisdiction_id" UUID, | ||
|
|
||
| CONSTRAINT "properties_pkey" PRIMARY KEY ("id") | ||
| ); | ||
|
|
||
| -- CreateIndex | ||
| CREATE INDEX "properties_id_name_idx" ON "properties"("id", "name"); | ||
|
|
||
| -- AddForeignKey | ||
| ALTER TABLE "listings" ADD CONSTRAINT "listings_property_id_fkey" FOREIGN KEY ("property_id") REFERENCES "properties"("id") ON DELETE SET NULL ON UPDATE CASCADE; | ||
|
|
||
| -- AddForeignKey | ||
| ALTER TABLE "properties" ADD CONSTRAINT "properties_jurisdiction_id_fkey" FOREIGN KEY ("jurisdiction_id") REFERENCES "jurisdictions"("id") ON DELETE NO ACTION ON UPDATE NO ACTION; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,139 @@ | ||
| import { | ||
| Body, | ||
| Controller, | ||
| Get, | ||
| Post, | ||
| Query, | ||
| Param, | ||
| ParseUUIDPipe, | ||
| Put, | ||
| UsePipes, | ||
| ValidationPipe, | ||
| Delete, | ||
| UseGuards, | ||
| Request, | ||
| } from '@nestjs/common'; | ||
| import { Request as ExpressRequest } from 'express'; | ||
| import { | ||
| ApiExtraModels, | ||
| ApiOkResponse, | ||
| ApiOperation, | ||
| ApiTags, | ||
| } from '@nestjs/swagger'; | ||
| import { PermissionTypeDecorator } from '../decorators/permission-type.decorator'; | ||
| import { PaginatedPropertyDto } from '../dtos/properties/paginated-property.dto'; | ||
| import { PropertyQueryParams } from '../dtos/properties/property-query-params.dto'; | ||
| import { PropertyService } from '../services/property.service'; | ||
| import PropertyCreate from '../dtos/properties/property-create.dto'; | ||
| import { PropertyUpdate } from '../dtos/properties/property-update.dto'; | ||
| import Property from '../dtos/properties/property.dto'; | ||
| import { IdDTO } from '../dtos/shared/id.dto'; | ||
| import { SuccessDTO } from '../dtos/shared/success.dto'; | ||
| import { defaultValidationPipeOptions } from '../utilities/default-validation-pipe-options'; | ||
| import { OptionalAuthGuard } from '../guards/optional.guard'; | ||
| import { mapTo } from '../utilities/mapTo'; | ||
| import { User } from '../dtos/users/user.dto'; | ||
| import { PaginationMeta } from '../dtos/shared/pagination.dto'; | ||
| import { PropertyFilterParams } from '../dtos/properties/property-filter-params.dto'; | ||
|
|
||
| @Controller('properties') | ||
| @ApiTags('properties') | ||
| @UseGuards(OptionalAuthGuard) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. question: the optionalAuthGuard allows for users that aren't logged in to hit these endpoints. Is that correct or should this require that a user is logged in to hit these endpoints?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @YazeedLoonat There were no specified requirements as to how exactly permissions should be handled. In my opinion, some of those endpoints should be protected against unwanted access; therefore, I was basing my work on how the |
||
| @ApiExtraModels( | ||
| PropertyCreate, | ||
| PropertyUpdate, | ||
| PropertyQueryParams, | ||
| PropertyFilterParams, | ||
| PaginationMeta, | ||
| IdDTO, | ||
| ) | ||
| @PermissionTypeDecorator('property') | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. question: this would get this to leverage the old property permissions from |
||
| export class PropertyController { | ||
| constructor(private readonly propertyService: PropertyService) {} | ||
|
|
||
| @Get() | ||
| @ApiOperation({ | ||
| summary: 'Get a paginated set of properties', | ||
| operationId: 'list', | ||
| }) | ||
| @UsePipes(new ValidationPipe(defaultValidationPipeOptions)) | ||
| @ApiOkResponse({ type: PaginatedPropertyDto }) | ||
| public async getPaginatedSet(@Query() queryParams: PropertyQueryParams) { | ||
| return await this.propertyService.list(queryParams); | ||
| } | ||
|
|
||
| @Get(':id') | ||
| @ApiOperation({ | ||
| summary: 'Get a property object by ID', | ||
| operationId: 'getById', | ||
| }) | ||
| public async getPropertyById( | ||
| @Param('id', new ParseUUIDPipe({ version: '4' })) propertyId: string, | ||
| ) { | ||
| return this.propertyService.findOne(propertyId); | ||
| } | ||
|
|
||
| @Post('list') | ||
| @ApiOperation({ | ||
| summary: 'Get a paginated filtered set of properties', | ||
| operationId: 'filterableList', | ||
| }) | ||
| @UsePipes(new ValidationPipe(defaultValidationPipeOptions)) | ||
| @ApiOkResponse({ type: PaginatedPropertyDto }) | ||
| public async getFiltrablePaginatedSet( | ||
| @Body() queryParams: PropertyQueryParams, | ||
| ) { | ||
| return await this.propertyService.list(queryParams); | ||
| } | ||
|
|
||
| @Post() | ||
| @ApiOperation({ | ||
| summary: 'Add a new property entry', | ||
| operationId: 'add', | ||
| }) | ||
| @UsePipes(new ValidationPipe(defaultValidationPipeOptions)) | ||
| @ApiOkResponse({ type: Property }) | ||
| public async addProperty( | ||
| @Request() req: ExpressRequest, | ||
| @Body() propertyDto: PropertyCreate, | ||
| ) { | ||
| return await this.propertyService.create( | ||
| propertyDto, | ||
| mapTo(User, req['user']), | ||
| ); | ||
| } | ||
|
|
||
| @Put() | ||
| @ApiOperation({ | ||
| summary: 'Update an exiting property entry by id', | ||
| operationId: 'update', | ||
| }) | ||
| @UsePipes(new ValidationPipe(defaultValidationPipeOptions)) | ||
| @ApiOkResponse({ type: Property }) | ||
| public async updateProperty( | ||
| @Request() req: ExpressRequest, | ||
| @Body() propertyDto: PropertyUpdate, | ||
| ) { | ||
| return await this.propertyService.update( | ||
| propertyDto, | ||
| mapTo(User, req['user']), | ||
| ); | ||
| } | ||
|
|
||
| @Delete() | ||
| @ApiOperation({ | ||
| summary: 'Delete an property entry by ID', | ||
| operationId: 'deleteById', | ||
| }) | ||
| @UsePipes(new ValidationPipe(defaultValidationPipeOptions)) | ||
| @ApiOkResponse({ type: SuccessDTO }) | ||
| public async deleteById( | ||
| @Request() req: ExpressRequest, | ||
| @Body() idDto: IdDTO, | ||
| ) { | ||
| return await this.propertyService.deleteOne( | ||
| idDto.id, | ||
| mapTo(User, req['user']), | ||
| ); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| import { PaginationFactory } from '../shared/pagination.dto'; | ||
| import Property from './property.dto'; | ||
|
|
||
| export class PaginatedPropertyDto extends PaginationFactory<Property>( | ||
| Property, | ||
| ) {} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| import { OmitType } from '@nestjs/swagger'; | ||
| import Property from './property.dto'; | ||
|
|
||
| export default class PropertyCreate extends OmitType(Property, [ | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. issue: to get this to match up to our pattern you should have this extend the update dto instead of the base dto |
||
| 'id', | ||
| 'createdAt', | ||
| 'updatedAt', | ||
| ]) {} | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| import { Expose } from 'class-transformer'; | ||
| import { BaseFilter } from '../shared/base-filter.dto'; | ||
| import { ApiPropertyOptional } from '@nestjs/swagger'; | ||
| import { IsString } from 'class-validator'; | ||
| import { ValidationsGroupsEnum } from '../../enums/shared/validation-groups-enum'; | ||
|
|
||
| export class PropertyFilterParams extends BaseFilter { | ||
| @Expose() | ||
| @ApiPropertyOptional({ | ||
| example: 'uuid', | ||
| }) | ||
| @IsString({ groups: [ValidationsGroupsEnum.default] }) | ||
| jurisdiction?: string; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| import { Expose, Type } from 'class-transformer'; | ||
| import { PaginationAllowsAllQueryParams } from '../shared/pagination.dto'; | ||
| import { ApiPropertyOptional } from '@nestjs/swagger'; | ||
| import { IsArray, MinLength, ValidateNested } from 'class-validator'; | ||
| import { ValidationsGroupsEnum } from '../../enums/shared/validation-groups-enum'; | ||
| import { PropertyFilterParams } from './property-filter-params.dto'; | ||
|
|
||
| export class PropertyQueryParams extends PaginationAllowsAllQueryParams { | ||
| @Expose() | ||
| @ApiPropertyOptional({ | ||
| example: 'search', | ||
| }) | ||
| @MinLength(3, { | ||
| message: 'Search must be at least 3 characters', | ||
| groups: [ValidationsGroupsEnum.default], | ||
| }) | ||
| search?: string; | ||
|
|
||
| @Expose() | ||
| @ApiPropertyOptional({ | ||
| type: [String], | ||
| }) | ||
| @IsArray({ groups: [ValidationsGroupsEnum.default] }) | ||
| @Type(() => PropertyFilterParams) | ||
| @ValidateNested({ groups: [ValidationsGroupsEnum.default], each: true }) | ||
| filter?: PropertyFilterParams[]; | ||
matzduniuk marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| import { ApiPropertyOptional, OmitType } from '@nestjs/swagger'; | ||
| import Property from './property.dto'; | ||
| import { Expose } from 'class-transformer'; | ||
| import { IsString } from 'class-validator'; | ||
| import { ValidationsGroupsEnum } from '../../enums/shared/validation-groups-enum'; | ||
|
|
||
| export class PropertyUpdate extends OmitType(Property, [ | ||
| 'createdAt', | ||
| 'updatedAt', | ||
| 'name', | ||
| ]) { | ||
| @Expose() | ||
| @IsString({ groups: [ValidationsGroupsEnum.default] }) | ||
| @ApiPropertyOptional() | ||
| name?: string; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. question: since name is required in the db why is it optional here? |
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| import { Expose, Type } from 'class-transformer'; | ||
| import { AbstractDTO } from '../shared/abstract.dto'; | ||
| import { IsDefined, IsString, IsUrl, ValidateNested } from 'class-validator'; | ||
| import { ValidationsGroupsEnum } from '../../enums/shared/validation-groups-enum'; | ||
| import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; | ||
| import { IdDTO } from '../shared/id.dto'; | ||
|
|
||
| export default class Property extends AbstractDTO { | ||
| @Expose() | ||
| @IsDefined({ groups: [ValidationsGroupsEnum.default] }) | ||
| @IsString({ groups: [ValidationsGroupsEnum.default] }) | ||
| @ApiProperty() | ||
| name: string; | ||
|
|
||
| @Expose() | ||
| @IsString({ groups: [ValidationsGroupsEnum.default] }) | ||
| @ApiPropertyOptional() | ||
| description?: string; | ||
|
|
||
| @Expose() | ||
| @IsString({ groups: [ValidationsGroupsEnum.default] }) | ||
| @IsUrl( | ||
| { require_protocol: true }, | ||
| { groups: [ValidationsGroupsEnum.default] }, | ||
| ) | ||
| @ApiPropertyOptional() | ||
| url?: string; | ||
|
|
||
| @Expose() | ||
| @IsString({ groups: [ValidationsGroupsEnum.default] }) | ||
| @ApiPropertyOptional() | ||
| urlTitle?: string; | ||
|
|
||
| @Expose() | ||
| @ValidateNested({ groups: [ValidationsGroupsEnum.default] }) | ||
| @Type(() => IdDTO) | ||
| @ApiPropertyOptional({ type: IdDTO }) | ||
| jurisdictions?: IdDTO; | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.