@@ -12,18 +12,25 @@ import {
1212 HttpCode ,
1313 HttpStatus ,
1414} from '@nestjs/common' ;
15- import { ApiTags , ApiOperation , ApiResponse , ApiParam , ApiQuery , ApiBearerAuth } from '@nestjs/swagger' ;
15+ import { ApiTags , ApiQuery , ApiResponse , ApiBearerAuth } from '@nestjs/swagger' ;
16+ import { Api } from '../common/decorators/api.decorator' ;
1617import { JobService } from './job.service' ;
1718import { CreateJobDto } from './dto/create-job.dto' ;
1819import { UpdateJobDto } from './dto/update-job.dto' ;
1920import { JobOrderByDto } from './dto/job-order-by.dto' ;
21+ import { CompanyPathParamsDto , TagPathParamsDto , JobIdPathParamsDto } from './dto/job-path-params.dto' ;
22+ import { JobFilterQueryDto } from './dto/job-filter-query.dto' ;
2023import { RedisAuthGuard } from '../auth/redis-auth.guard' ;
2124import { UserEntity as User } from '../common/decorators/user.decorator' ;
2225import { ApiPaginationQuery } from './../common/decorators/api-nested-query.decorator' ;
2326import { PaginationArgs } from '../common/pagination/pagination.args' ;
2427import { Web3CareerService } from './web3career.service' ;
2528import { RedditService } from './reddit.service' ;
2629import { NotificationsService } from './notifications.service' ;
30+ import { PaginatedResponse } from '../common/models/paginated-response' ;
31+ import { CreateJobDto as JobDto } from './dto/create-job.dto' ;
32+
33+ class PaginatedJobResponse extends PaginatedResponse ( JobDto ) { }
2734
2835/**
2936 * Job Controller
@@ -49,11 +56,11 @@ export class JobController {
4956 * Fetch new jobs from Reddit and Web3Career, store them, and send notifications
5057 */
5158 @Get ( 'fetch' )
52- @ApiOperation ( {
59+ @Api ( {
5360 summary : 'Fetch new jobs from Reddit and Web3Career' ,
5461 description : 'Fetches new jobs from both sources, stores them, and sends notifications.' ,
62+ responses : [ { status : 200 , description : 'Jobs fetched and notifications sent.' } ] ,
5563 } )
56- @ApiResponse ( { status : 200 , description : 'Jobs fetched and notifications sent.' } )
5764 async fetchJobs ( ) : Promise < { redditJobs : any [ ] ; web3CareerJobs : any [ ] } > {
5865 // Fetch Reddit jobs
5966 const redditSubreddits = [
@@ -83,15 +90,13 @@ export class JobController {
8390 * Retrieves all job listings for a specific company
8491 */
8592 @Get ( 'company/:companyId' )
86- @ApiOperation ( {
93+ @Api ( {
8794 summary : 'Get jobs by company' ,
8895 description : 'Retrieves all job listings for a specific company' ,
89- } )
90- @ApiParam ( { name : 'companyId' , description : 'Company ID' , type : Number } )
91- @ApiPaginationQuery ( )
92- @ApiResponse ( {
93- status : 200 ,
94- description : 'Company jobs retrieved successfully' ,
96+ pathParamsFrom : CompanyPathParamsDto ,
97+ paginatedResponseType : JobDto ,
98+ envelope : true ,
99+ queriesFrom : [ PaginationArgs ] ,
95100 } )
96101 async findByCompany (
97102 @Param ( 'companyId' , ParseIntPipe ) companyId : number ,
@@ -116,15 +121,13 @@ export class JobController {
116121 * Retrieves all job listings that have a specific tag
117122 */
118123 @Get ( 'tag/:tagName' )
119- @ApiOperation ( {
124+ @Api ( {
120125 summary : 'Get jobs by tag' ,
121126 description : 'Retrieves all job listings that have a specific tag' ,
122- } )
123- @ApiParam ( { name : 'tagName' , description : 'Tag name' , type : String } )
124- @ApiPaginationQuery ( )
125- @ApiResponse ( {
126- status : 200 ,
127- description : 'Tagged jobs retrieved successfully' ,
127+ pathParamsFrom : TagPathParamsDto ,
128+ paginatedResponseType : JobDto ,
129+ envelope : true ,
130+ queriesFrom : [ PaginationArgs ] ,
128131 } )
129132 async findByTag (
130133 @Param ( 'tagName' ) tagName : string ,
@@ -149,23 +152,16 @@ export class JobController {
149152 * Creates a new job entry in the database with the provided information
150153 */
151154 @Post ( )
152- @UseGuards ( RedisAuthGuard )
153- @ApiBearerAuth ( )
154- @ApiOperation ( {
155+ @Api ( {
155156 summary : 'Create a new job listing' ,
156157 description : 'Creates a new job listing with title, description, company info, and other details' ,
157- } )
158- @ApiResponse ( {
159- status : 201 ,
160- description : 'Job successfully created' ,
161- } )
162- @ApiResponse ( {
163- status : 400 ,
164- description : 'Invalid job data provided' ,
165- } )
166- @ApiResponse ( {
167- status : 401 ,
168- description : 'Unauthorized - authentication required' ,
158+ bodyType : CreateJobDto ,
159+ authenticationRequired : true ,
160+ responses : [
161+ { status : 201 , description : 'Job successfully created' } ,
162+ { status : 400 , description : 'Invalid job data provided' } ,
163+ { status : 401 , description : 'Unauthorized - authentication required' } ,
164+ ] ,
169165 } )
170166 @HttpCode ( HttpStatus . CREATED )
171167 async create ( @Body ( ) createJobDto : CreateJobDto , @User ( ) user : any ) {
@@ -177,19 +173,12 @@ export class JobController {
177173 * Supports filtering by company, location, remote status, and tags
178174 */
179175 @Get ( )
180- @ApiOperation ( {
176+ @Api ( {
181177 summary : 'Get all job listings' ,
182178 description : 'Retrieves a paginated list of job listings with optional filtering' ,
183- } )
184- @ApiPaginationQuery ( )
185- @ApiQuery ( { name : 'search' , required : false , description : 'Search in job title and description' } )
186- @ApiQuery ( { name : 'companyId' , required : false , description : 'Filter by company ID' } )
187- @ApiQuery ( { name : 'location' , required : false , description : 'Filter by location' } )
188- @ApiQuery ( { name : 'isRemote' , required : false , description : 'Filter by remote status' , type : Boolean } )
189- @ApiQuery ( { name : 'tags' , required : false , description : 'Filter by tag names (comma-separated)' } )
190- @ApiResponse ( {
191- status : 200 ,
192- description : 'List of job listings retrieved successfully' ,
179+ paginatedResponseType : JobDto ,
180+ envelope : true ,
181+ queriesFrom : [ PaginationArgs , JobFilterQueryDto ] ,
193182 } )
194183 async findAll (
195184 @Query ( ) paginationArgs : PaginationArgs ,
@@ -228,18 +217,14 @@ export class JobController {
228217 * Returns detailed information about a single job including company, tags, and metadata
229218 */
230219 @Get ( ':id' )
231- @ApiOperation ( {
220+ @Api ( {
232221 summary : 'Get job by ID' ,
233222 description : 'Retrieves a specific job listing with all related data' ,
234- } )
235- @ApiParam ( { name : 'id' , description : 'Job ID' , type : Number } )
236- @ApiResponse ( {
237- status : 200 ,
238- description : 'Job details retrieved successfully' ,
239- } )
240- @ApiResponse ( {
241- status : 404 ,
242- description : 'Job not found' ,
223+ pathParamsFrom : JobIdPathParamsDto ,
224+ responses : [
225+ { status : 200 , description : 'Job details retrieved successfully' } ,
226+ { status : 404 , description : 'Job not found' } ,
227+ ] ,
243228 } )
244229 async findOne ( @Param ( 'id' , ParseIntPipe ) id : number ) {
245230 return this . jobService . findOne ( id ) ;
@@ -250,24 +235,17 @@ export class JobController {
250235 * Updates job information - requires authentication
251236 */
252237 @Put ( ':id' )
253- @UseGuards ( RedisAuthGuard )
254- @ApiBearerAuth ( )
255- @ApiOperation ( {
238+ @Api ( {
256239 summary : 'Update job listing' ,
257240 description : 'Updates an existing job listing with new information' ,
258- } )
259- @ApiParam ( { name : 'id' , description : 'Job ID' , type : Number } )
260- @ApiResponse ( {
261- status : 200 ,
262- description : 'Job updated successfully' ,
263- } )
264- @ApiResponse ( {
265- status : 404 ,
266- description : 'Job not found' ,
267- } )
268- @ApiResponse ( {
269- status : 401 ,
270- description : 'Unauthorized - authentication required' ,
241+ authenticationRequired : true ,
242+ bodyType : UpdateJobDto ,
243+ pathParamsFrom : JobIdPathParamsDto ,
244+ responses : [
245+ { status : 200 , description : 'Job updated successfully' } ,
246+ { status : 404 , description : 'Job not found' } ,
247+ { status : 401 , description : 'Unauthorized - authentication required' } ,
248+ ] ,
271249 } )
272250 async update ( @Param ( 'id' , ParseIntPipe ) id : number , @Body ( ) updateJobDto : UpdateJobDto , @User ( ) user : any ) {
273251 return this . jobService . update ( id , updateJobDto , user . id ) ;
@@ -278,24 +256,16 @@ export class JobController {
278256 * Removes a job listing from the database - requires authentication
279257 */
280258 @Delete ( ':id' )
281- @UseGuards ( RedisAuthGuard )
282- @ApiBearerAuth ( )
283- @ApiOperation ( {
259+ @Api ( {
284260 summary : 'Delete job listing' ,
285261 description : 'Removes a job listing from the database' ,
286- } )
287- @ApiParam ( { name : 'id' , description : 'Job ID' , type : Number } )
288- @ApiResponse ( {
289- status : 200 ,
290- description : 'Job deleted successfully' ,
291- } )
292- @ApiResponse ( {
293- status : 404 ,
294- description : 'Job not found' ,
295- } )
296- @ApiResponse ( {
297- status : 401 ,
298- description : 'Unauthorized - authentication required' ,
262+ authenticationRequired : true ,
263+ pathParamsFrom : JobIdPathParamsDto ,
264+ responses : [
265+ { status : 200 , description : 'Job deleted successfully' } ,
266+ { status : 404 , description : 'Job not found' } ,
267+ { status : 401 , description : 'Unauthorized - authentication required' } ,
268+ ] ,
299269 } )
300270 @HttpCode ( HttpStatus . OK )
301271 async remove ( @Param ( 'id' , ParseIntPipe ) id : number , @User ( ) user : any ) {
0 commit comments