diff --git a/backend/src/controllers/channelController.js b/backend/src/controllers/channelController.js index da3157fc..5c6e6216 100644 --- a/backend/src/controllers/channelController.js +++ b/backend/src/controllers/channelController.js @@ -2,6 +2,7 @@ import { addGuestService, createChannelService, getChannelByIdService, + getChannelGuestInfoService, } from '../services/channelService.js'; export const createChannelController = async (req, res) => { @@ -69,3 +70,21 @@ export const getChannelInfoController = async (req, res) => { return res.status(500).json({ success: false, message: 'Server error' }); } }; + +export const getChannelGuestInfoController = async (req, res) => { + const { channelId, guestId } = req.params; + try { + const result = await getChannelGuestInfoService(channelId, guestId); + if (result) { + res.status(200).json({ + success: true, + message: 'Get guest data successfully', + data: result, + }); + } else { + res.status(404).json({ message: 'Channel or guest not found' }); + } + } catch (error) { + res.status(500).json({ message: 'Server error', error }); + } +}; diff --git a/backend/src/repositories/channelRepository.js b/backend/src/repositories/channelRepository.js index 8877125b..9f888ee1 100644 --- a/backend/src/repositories/channelRepository.js +++ b/backend/src/repositories/channelRepository.js @@ -61,6 +61,8 @@ export const getChannelWithGuestsByIdFromDB = async id => { lat: guest.end_location.lat, lng: guest.end_location.lng, }, + path: guest.path, + marker_style: guest.marker_style, })), }; } catch (error) { @@ -68,3 +70,54 @@ export const getChannelWithGuestsByIdFromDB = async id => { throw error; } }; + +export const getGuestByChannelAndGuestIdFromDB = async (channelId, guestId) => { + try { + const channelQuery = ` + SELECT * + FROM "main"."channel" + WHERE id = $1; + `; + const channelResult = await pool.query(channelQuery, [channelId]); + if (channelResult.rows.length === 0) { + return null; + } + + const guestQuery = ` + SELECT * + FROM "main"."guest" + WHERE channel_id = $1 + AND id = $2; + `; + const guestResult = await pool.query(guestQuery, [channelId, guestId]); + if (guestResult.rows.length === 0) { + return null; + } + + const channel = channelResult.rows[0]; + const guest = guestResult.rows[0]; + + return { + id: channel.id, + name: channel.name, + host_id: channel.host_id, + guest: { + id: guest.id, + name: guest.name, + start_location: { + lat: guest.start_location.lat, + lng: guest.start_location.lng, + }, + end_location: { + lat: guest.end_location.lat, + lng: guest.end_location.lng, + }, + path: guest.path, + marker_style: guest.marker_style, + }, + }; + } catch (error) { + console.error('Database error:', error); + throw error; + } +}; diff --git a/backend/src/routes/authRouter.js b/backend/src/routes/authRouter.js index 65d8dfcf..582c0254 100644 --- a/backend/src/routes/authRouter.js +++ b/backend/src/routes/authRouter.js @@ -7,27 +7,30 @@ export const authRouter = express.Router(); /** * @swagger - * /api/auth/login: + * /auth/login: * post: - * summary: User login - * description: Logs in a user with their ID and password. + * summary: 사용자 로그인 API + * description: 사용자가 로그인할 수 있도록 ID와 비밀번호를 통해 인증 후 토큰을 반환합니다. * requestBody: * required: true + * description: 로그인을 위한 ID와 비밀번호를 포함한 요청 body * content: * application/json: * schema: * $ref: '#/components/schemas/LoginRequest' * responses: * 200: - * description: Successfully logged in + * description: 로그인 성공, 토큰 및 사용자 정보 반환 * content: * application/json: * schema: * $ref: '#/components/schemas/LoginResponse' * 400: - * description: Invalid input (e.g. invalid ID or password) + * description: 잘못된 요청, 필수 정보 누락 또는 형식 오류 + * 401: + * description: 잘못된 ID나 비밀번호 * 500: - * description: Internal server error + * description: 서버 에러 */ authRouter.post( '/login', diff --git a/backend/src/routes/channelRouter.js b/backend/src/routes/channelRouter.js index 9f9ca076..b0696321 100644 --- a/backend/src/routes/channelRouter.js +++ b/backend/src/routes/channelRouter.js @@ -3,37 +3,34 @@ import { body, param } from 'express-validator'; import { addGuestController, createChannelController, + getChannelGuestInfoController, getChannelInfoController, } from '../controllers/channelController.js'; import { validationMiddleware } from '../middleware/validationMiddleware.js'; export const channelRouter = express.Router(); +// 채널 생성 API 경로 /** * @swagger - * /channels: - * post: - * summary: 'Create a new channel' - * description: 'Create a new channel with guests and their respective locations and paths.' - * operationId: 'createChannel' - * requestBody: - * description: 'Channel data to be created' - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/CreateChannelRequest' - * required: true - * responses: - * 201: - * description: 'Channel created successfully' + * paths: + * /channel: + * post: + * summary: '새로운 채널 생성 API' + * description: '채널 이름, 주인, 게스트 정보를 포함하여 채널을 생성합니다.' + * requestBody: + * required: true * content: * application/json: * schema: - * $ref: '#/components/schemas/CreateChannelResponse' - * 400: - * description: 'Invalid input data' - * 500: - * description: 'Server error' + * $ref: '#/components/schemas/CreateChannelRequest' + * responses: + * 201: + * description: '채널 생성 성공' + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/CreateChannelResponse' */ channelRouter.post( '/', @@ -45,91 +42,34 @@ channelRouter.post( createChannelController, ); +// 게스트 추가 API 경로 /** * @swagger - * /channels/{channelId}/guests: - * post: - * summary: 'Add guests to an existing channel' - * description: 'Add new guests to an existing channel by providing guest information.' - * operationId: 'addGuest' - * parameters: - * - in: path - * name: channelId - * required: true - * description: 'ID of the channel to which guests are being added' - * schema: - * type: string - * example: '123e4567-e89b-12d3-a456-426614174000' - * requestBody: - * description: 'Guest data to be added to the channel' - * content: - * application/json: + * paths: + * /channel/{channelId}/guests: + * post: + * summary: '게스트 추가 API' + * description: '특정 채널에 게스트를 추가합니다.' + * parameters: + * - name: 'channelId' + * in: 'path' + * required: true * schema: - * type: object - * properties: - * guests: - * type: array - * items: - * type: object - * properties: - * name: - * type: string - * description: 'Guest\'s name' - * start_location: - * type: object - * properties: - * lat: - * type: number - * description: 'Latitude of the start location' - * lng: - * type: number - * description: 'Longitude of the start location' - * end_location: - * type: object - * properties: - * lat: - * type: number - * description: 'Latitude of the end location' - * lng: - * type: number - * description: 'Longitude of the end location' - * path: - * type: array - * items: - * type: object - * properties: - * lat: - * type: number - * description: 'Latitude of a waypoint' - * lng: - * type: number - * description: 'Longitude of a waypoint' - * marker_style: - * type: object - * properties: - * color: - * type: string - * description: 'Color for the guest marker' - * responses: - * 200: - * description: 'Guests added successfully' + * type: 'string' + * description: '채널의 고유 ID' + * requestBody: + * required: true * content: * application/json: * schema: - * type: object - * properties: - * success: - * type: boolean - * example: true - * message: - * type: string - * example: 'Guests added successfully' - * 400: - * description: 'Invalid input data' - * 404: - * description: 'Channel not found' - * 500: - * description: 'Server error' + * $ref: '#/components/schemas/AddGuestRequest' + * responses: + * 200: + * description: '게스트 추가 성공' + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/AddGuestResponse' */ channelRouter.post( '/:channelId/guests', @@ -138,32 +78,28 @@ channelRouter.post( addGuestController, ); +// 채널 정보 조회 API 경로 /** * @swagger - * /channels/{id}: - * get: - * summary: 'Get channel information' - * description: 'Retrieve information about a specific channel by ID.' - * operationId: 'getChannelInfo' - * parameters: - * - in: path - * name: id - * required: true - * description: 'ID of the channel to retrieve' - * schema: - * type: string - * example: '123e4567-e89b-12d3-a456-426614174000' - * responses: - * 200: - * description: 'Channel information retrieved successfully' - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ChannelInfo' - * 404: - * description: 'Channel not found' - * 500: - * description: 'Server error' + * paths: + * /channel/{id}: + * get: + * summary: '채널 정보 조회 API' + * description: '특정 채널의 정보를 조회합니다.' + * parameters: + * - name: 'id' + * in: 'path' + * required: true + * schema: + * type: 'string' + * description: '채널의 고유 ID' + * responses: + * 200: + * description: '채널 정보 조회 성공' + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/ChannelResponse' */ channelRouter.get( '/:id', @@ -171,3 +107,42 @@ channelRouter.get( validationMiddleware, getChannelInfoController, ); + +// 게스트 정보 조회 API 경로 +/** + * @swagger + * paths: + * /channel/{channelId}/guest/{guestId}: + * get: + * summary: '게스트 정보 조회 API' + * description: '특정 채널 내의 게스트 정보를 조회합니다.' + * parameters: + * - name: 'channelId' + * in: 'path' + * required: true + * schema: + * type: 'string' + * description: '채널의 고유 ID' + * - name: 'guestId' + * in: 'path' + * required: true + * schema: + * type: 'string' + * description: '게스트의 고유 ID' + * responses: + * 200: + * description: '게스트 정보 조회 성공' + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/GuestResponse' + */ +channelRouter.get( + '/:channelId/guest/:guestId', + [ + param('channelId').notEmpty().withMessage('Channel ID is required'), + param('guestId').notEmpty().withMessage('Guest ID is required'), + ], + validationMiddleware, + getChannelGuestInfoController, +); diff --git a/backend/src/services/channelService.js b/backend/src/services/channelService.js index 69e06501..12850fc9 100644 --- a/backend/src/services/channelService.js +++ b/backend/src/services/channelService.js @@ -2,6 +2,7 @@ import { createChannelInDB, getChannelInfoByIdInDB, getChannelWithGuestsByIdFromDB, + getGuestByChannelAndGuestIdFromDB, } from '../repositories/channelRepository.js'; import { addGuestToChannel } from '../repositories/guestRepository.js'; @@ -56,3 +57,12 @@ export const getChannelByIdService = async id => { throw error; } }; + +export const getChannelGuestInfoService = async (channelId, guestId) => { + try { + return await getGuestByChannelAndGuestIdFromDB(channelId, guestId); + } catch (error) { + console.error('Error fetching channel:', error); + throw error; + } +}; diff --git a/backend/swaggerConfig.js b/backend/swaggerConfig.js index c8a32a8c..f43d6624 100644 --- a/backend/swaggerConfig.js +++ b/backend/swaggerConfig.js @@ -249,6 +249,8 @@ const swaggerDefinition = { }, }, }, + + // 채널 정보 가져오기 응답 스키마 ChannelResponse: { type: 'object', properties: { @@ -303,167 +305,109 @@ const swaggerDefinition = { }, }, }, + path: { + type: 'array', + items: { + type: 'object', + properties: { + lat: { + type: 'number', + description: '경로 n번째 지점의 위도', + }, + lng: { + type: 'number', + description: '경로 n번째 지점의 경도', + }, + }, + }, + description: '게스트의 경로를 나타내는 배열', + }, + marker_style: { + type: 'object', + properties: { + color: { + type: 'string', + description: '게스트를 구분하는 색상 스타일', + }, + }, + description: '게스트 마커의 스타일 정보', + }, }, }, description: '해당 채널의 게스트 목록', }, }, }, - }, - }, - paths: { - '/auth/login': { - post: { - summary: '사용자 로그인 API', - description: '사용자가 로그인할 수 있도록 ID와 비밀번호를 통해 인증 후 토큰을 반환합니다.', - operationId: 'login', - requestBody: { - description: '로그인을 위한 ID와 비밀번호를 포함한 요청 body', - content: { - 'application/json': { - schema: { - $ref: '#/components/schemas/LoginRequest', - }, - }, - }, - required: true, - }, - responses: { - 200: { - description: '로그인 성공, 토큰 및 사용자 정보 반환', - content: { - 'application/json': { - schema: { - $ref: '#/components/schemas/LoginResponse', - }, - }, - }, - }, - 400: { - description: '잘못된 요청, 필수 정보 누락 또는 형식 오류', - }, - 401: { - description: '잘못된 ID나 비밀번호', + + // 특정 게스트의 정보 가져오기 응답 스키마 + GuestResponse: { + type: 'object', + properties: { + id: { + type: 'string', + description: '게스트의 ID (UUID 형식)', }, - 500: { - description: '서버 에러', + name: { + type: 'string', + description: '게스트 이름', }, - }, - }, - }, - '/channel': { - post: { - summary: '새로운 채널 생성 API', - description: '채널 이름, 주인, 게스트 정보를 포함하여 채널을 생성합니다.', - operationId: 'createChannel', - requestBody: { - description: '채널 생성에 필요한 데이터', - content: { - 'application/json': { - schema: { - $ref: '#/components/schemas/CreateChannelRequest', + start_location: { + type: 'object', + properties: { + lat: { + type: 'number', + description: '출발지 마커의 위도', }, - }, - }, - required: true, - }, - responses: { - 201: { - description: '채널 생성 성공', - content: { - 'application/json': { - schema: { - $ref: '#/components/schemas/CreateChannelResponse', - }, + lng: { + type: 'number', + description: '출발지 마커의 경도', }, }, + description: '출발 위치 정보', }, - 400: { - description: '입력 데이터 유효성 검증 실패', - }, - 500: { - description: '서버 에러', - }, - }, - }, - }, - '/channel/guests': { - post: { - summary: '채널에 게스트 추가 API', - description: '주어진 채널에 새로운 게스트를 추가합니다.', - operationId: 'addGuest', - requestBody: { - description: '채널에 게스트를 추가하기 위한 데이터', - content: { - 'application/json': { - schema: { - $ref: '#/components/schemas/AddGuestRequest', + end_location: { + type: 'object', + properties: { + lat: { + type: 'number', + description: '도착지 마커의 위도', + }, + lng: { + type: 'number', + description: '도착지 마커의 경도', }, }, + description: '도착 위치 정보', }, - required: true, - }, - responses: { - 200: { - description: '게스트 추가 성공', - content: { - 'application/json': { - schema: { - $ref: '#/components/schemas/AddGuestResponse', + path: { + type: 'array', + items: { + type: 'object', + properties: { + lat: { + type: 'number', + description: '경로 지점의 위도', + }, + lng: { + type: 'number', + description: '경로 지점의 경도', }, }, }, + description: '게스트의 경로 (위도, 경도)를 담은 배열', }, - 400: { - description: '잘못된 요청, 채널 ID나 게스트 정보가 잘못됨', - }, - 404: { - description: '채널을 찾을 수 없음', - }, - 500: { - description: '서버 에러', - }, - }, - }, - }, - '/channel/{id}': { - get: { - summary: '채널 정보 조회 API', - description: - '채널의 ID를 통해 해당 채널에 속한 게스트들의 정보를 포함한 채널 정보를 조회합니다.', - operationId: 'getChannelInfo', - parameters: [ - { - name: 'id', - in: 'path', - description: '채널의 고유 ID (UUID 형식)', - required: true, - schema: { - type: 'string', - }, - }, - ], - responses: { - 200: { - description: '채널 정보 조회 성공', - content: { - 'application/json': { - schema: { - $ref: '#/components/schemas/ChannelResponse', - }, + marker_style: { + type: 'object', + properties: { + color: { + type: 'string', + description: '게스트를 구분하는 색상 스타일', }, }, - }, - 400: { - description: '잘못된 요청, 잘못된 채널 ID 형식', - }, - 404: { - description: '채널을 찾을 수 없음', - }, - 500: { - description: '서버 에러', + description: '마커 스타일 정보', }, }, + description: '특정 게스트의 정보', }, }, }, @@ -471,7 +415,7 @@ const swaggerDefinition = { const options = { swaggerDefinition, - apis: ['./routes/*.js'], + apis: ['./src/routes/**/*.js'], }; export const specs = swaggerJSDoc(options);