Passed
Push — development ( cae74d...4e024d )
by Peter
09:26 queued 14s
created

BicyclesController.updateBatchPositions   A

Complexity

Conditions 1

Size

Total Lines 21
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1.512

Importance

Changes 0
Metric Value
cc 1
eloc 19
dl 0
loc 21
ccs 1
cts 5
cp 0.2
crap 1.512
rs 9.45
c 0
b 0
f 0
1 6
import {
2
  Controller,
3
  Get,
4
  Post,
5
  Param,
6
  Patch,
7
  Body,
8
  Query,
9
  BadRequestException,
10
} from '@nestjs/common';
11 6
import {
12
  ApiBearerAuth,
13
  ApiOperation,
14
  ApiResponse,
15
  ApiParam,
16
  ApiBody,
17
  ApiTags,
18
  ApiQuery,
19
} from '@nestjs/swagger';
20
// we have removed all JwtAuthGuards from this route.
21
//  import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
22 6
import { BicyclesService } from './bicycles.service';
23 6
import { UpdateBicycleDto } from './dto/update-bicycle.dto';
24 6
import { Bicycle } from './entities/bicycle.entity';
25
import { BicycleResponse } from './types/bicycle-response.interface';
26 6
import { CreateBicycleDto } from './dto/create-bicycle.dto';
27 6
import { CityName } from 'src/cities/types/city.enum';
28 6
import { BatchUpdateBicyclePositionsDto, BicycleBatchResponseDto, BicyclePositionDto } from './dto/batch-update.dto';
0 ignored issues
show
introduced by
Replace ·BatchUpdateBicyclePosi...,·BicyclePositionDto· with ⏎··BatchUpdateBicycl...
Loading history...
introduced by
'BicyclePositionDto' is defined but never used.
Loading history...
29
import { BicycleBatchResponse } from './types/BicycleBatchResponse';
0 ignored issues
show
introduced by
'BicycleBatchResponse' is defined but never used.
Loading history...
30
31 6
const BIKE_ID = 'b1e77dd3-9fb9-4e6c-a5c6-b6fc58f59464';
32 6
const BIKE_STATUS_AVAILABLE = 'Available';
0 ignored issues
show
introduced by
'BIKE_STATUS_AVAILABLE' is assigned a value but never used.
Loading history...
33 6
const CREATED_AT = '2024-12-01T05:01:01.000Z';
0 ignored issues
show
introduced by
'CREATED_AT' is assigned a value but never used.
Loading history...
34 6
const UPDATED_AT = '2024-12-07T18:30:30.000Z';
0 ignored issues
show
introduced by
'UPDATED_AT' is assigned a value but never used.
Loading history...
35 6
const UNAUTHORIZED_ERROR_MESSAGE = 'Unauthorized. Authentication required';
36 6
const CITY_ID_GOTHENBURG = '123e4567-e89b-12d3-a456-426614174000';
0 ignored issues
show
introduced by
'CITY_ID_GOTHENBURG' is assigned a value but never used.
Loading history...
37
38
@ApiTags('Bicycles')
39
@Controller({ path: 'bike', version: '1' })
40 6
export class BicyclesController {
41 8
  constructor(private readonly bicyclesService: BicyclesService) {}
42
43
  @Get()
44
  @ApiBearerAuth()
45
  @ApiOperation({ summary: 'Get all bicycles' })
46
  @ApiQuery({
47
    name: 'city',
48
    required: false,
49
    enum: CityName,
50
  })
51
  @ApiQuery({ name: 'lat', required: false, minimum: -90, maximum: 90 })
52
  @ApiQuery({ name: 'lon', required: false, minimum: -180, maximum: 180 })
53
  @ApiQuery({ name: 'radius', required: false, minimum: 0, maximum: 100000 })
54
  @ApiResponse({
55
    status: 200,
56
    description: 'List of bicycles',
57
    type: [Bicycle],
58
  })
59
  @ApiResponse({
60
    status: 401,
61
    description: 'Unauthorized. Authentication required',
62
  })
63 6
  async getAllBicycles(
64
    @Query('lat') lat?: string,
65
    @Query('lon') lon?: string,
66
    @Query('radius') radius?: string,
67
    @Query('city') city?: CityName,
68
  ): Promise<BicycleResponse[]> {
69 4
    const latitude = lat ? parseFloat(lat) : undefined;
70 4
    const longitude = lon ? parseFloat(lon) : undefined;
71 4
    const radi = radius ? parseFloat(radius) : 3000;
72
73 5
    if ((latitude && !longitude) || (longitude && !latitude)) {
74 1
      throw new BadRequestException('Both lat and lon must be provided for location search');
75
    }
76
77 3
    if (city) {
78 1
      if (latitude) {
79
        return this.bicyclesService.toBicycleResponses(
80
          await this.bicyclesService.findByCityAndLocation(city, latitude, longitude, radi),
81
        );
82
      }
83 1
      return this.bicyclesService.toBicycleResponses(await this.bicyclesService.findByCity(city));
84
    }
85
86 2
    if (latitude) {
87 1
      return this.bicyclesService.toBicycleResponses(
88
        await this.bicyclesService.findByLocation(latitude, longitude, radi),
89
      );
90
    }
91
92 1
    return this.bicyclesService.toBicycleResponses(await this.bicyclesService.findAll());
93
  }
94
95
  @Post('create')
96
  @ApiBearerAuth()
97
  @ApiOperation({ summary: 'Create a new bicycle' })
98
  @ApiBody({
99
    type: CreateBicycleDto,
100
    description: 'Bicycle creation data',
101
    required: false,
102
  })
103
  @ApiResponse({
104
    status: 201,
105
    description: 'Bicycle created successfully',
106
    type: Bicycle,
107
  })
108 6
  async createABike(@Body() createBicycleDto: CreateBicycleDto): Promise<Bicycle> {
109 1
    console.log('skapa cykel');
110 1
    return await this.bicyclesService.createBike(createBicycleDto);
111
  }
112
113
  @Post('create-many')
114
  @ApiBearerAuth()
115
  @ApiOperation({
116
    summary: 'Create multiple bicycles',
117
    description: 'Creates multiple bicycles in a single request. At least one bicycle must be provided.',
0 ignored issues
show
introduced by
Insert ⏎·····
Loading history...
118
  })
119
  @ApiBody({
120
    type: [CreateBicycleDto],
121
    description: 'Array of bicycle creation data',
122
    required: true,
123
  })
124
  @ApiResponse({
125
    status: 201,
126
    description: 'Bicycles created successfully',
127
    type: [Bicycle],
128
  })
129
  @ApiResponse({
130
    status: 400,
131
    description: 'Bad Request - Empty array or invalid bicycle data provided',
132
  })
133 6
  async createManyBikes(@Body() createBicycleDto: CreateBicycleDto[]): Promise<Bicycle[]> {
134 1
    if (!createBicycleDto?.length) {
135
      throw new BadRequestException('At least one bike is required');
136
    }
137
    return await this.bicyclesService.createManyBikes(createBicycleDto);
138
  }
139
140
  @Get(':bikeId')
141
  @ApiBearerAuth()
142
  @ApiOperation({ summary: 'Get a bicycle by ID' })
143
  @ApiParam({
144
    name: 'bikeId',
145
    description: 'Unique identifier of the bicycle',
146
    type: 'string',
147
    example: BIKE_ID,
148
  })
149
  @ApiResponse({
150
    status: 200,
151
    description: 'Bicycle details retrieved successfully',
152
    type: Bicycle,
153
  })
154
  @ApiResponse({
155
    status: 401,
156
    description: UNAUTHORIZED_ERROR_MESSAGE,
157
  })
158
  @ApiResponse({
159
    status: 404,
160
    description: 'Bicycle not found',
161
  })
162 6
  async getBikeById(@Param('bikeId') id: string): Promise<Bicycle> {
163 1
    return await this.bicyclesService.findById(id);
164
  }
165
166
  @Patch(':bikeId')
167
  @ApiBearerAuth()
168
  @ApiOperation({ summary: 'Update bicycle by ID' })
169
  @ApiParam({
170
    name: 'bikeId',
171
    description: 'Unique identifier of the bicycle',
172
    type: 'string',
173
    example: BIKE_ID,
174
  })
175
  @ApiBody({
176
    description: 'Bicycle update details',
177
    type: UpdateBicycleDto,
178
  })
179
  @ApiResponse({
180
    status: 200,
181
    description: 'Bicycle updated successfully',
182
    type: Bicycle
0 ignored issues
show
introduced by
Insert ,
Loading history...
183
  })
184
  @ApiResponse({
185
    status: 400,
186
    description: 'Invalid input',
187
  })
188
  @ApiResponse({
189
    status: 404,
190
    description: 'Bicycle not found',
191
  })
192
  @ApiResponse({
193
    status: 401,
194
    description: UNAUTHORIZED_ERROR_MESSAGE,
195
  })
196 6
  async updateBicycle(@Param('bikeId') bikeId: string, @Body() updateBicycleDto: UpdateBicycleDto) {
197 1
    return this.bicyclesService.update(bikeId, updateBicycleDto);
198
  }
199
200
  @Patch('/batch/positions')
201
  @ApiOperation({ summary: 'Update multiple bicycle positions' })
202
  @ApiResponse({
203
    status: 200,
204
    description: 'Bicycle positions updated successfully',
205
    type: BicycleBatchResponseDto,
206
  })
207
  @ApiResponse({
208
    status: 400,
209
    description: 'Error: Bad Request (Invalid request payload)',
210
  })
211 6
  async updateBatchPositions(
212
    @Body() dto: BatchUpdateBicyclePositionsDto
0 ignored issues
show
introduced by
Insert ,
Loading history...
213
  ): Promise<BicycleBatchResponseDto> {
214
    const results = await this.bicyclesService.updatePositionsParallel(dto.updates);
215
    return {
216
      results,
217
      totalCount: results.length,
218
      successCount: results.filter(r => r.success).length,
0 ignored issues
show
introduced by
Replace r with (r)
Loading history...
219
      failureCount: results.filter(r => !r.success).length,
0 ignored issues
show
introduced by
Replace r with (r)
Loading history...
220
    };
221
  }
222
223
  @Get('city/:cityName')
224
  @ApiBearerAuth()
225
  @ApiOperation({ summary: 'Get all bicycles in a specific city' })
226
  @ApiResponse({
227
    status: 200,
228
    description: 'List of bicycles in the specified city',
229
    type: [Bicycle],
230
  })
231
  @ApiResponse({
232
    status: 401,
233
    description: UNAUTHORIZED_ERROR_MESSAGE,
234
  })
235
  @ApiParam({
236
    name: 'cityName',
237
    description: 'Name of the city',
238
    type: 'string',
239
    enum: CityName,
240
  })
241 6
  async getBicyclesByCity(@Param('cityName') cityName: CityName): Promise<Bicycle[]> {
242
    return await this.bicyclesService.findByCity(cityName);
243
  }
244
}
245