Skip to content

Commit

Permalink
Merge branch 'develop' into feat/19
Browse files Browse the repository at this point in the history
  • Loading branch information
tkdwns414 authored Jan 9, 2024
2 parents f741a3d + d9c15be commit b325c5a
Show file tree
Hide file tree
Showing 18 changed files with 299 additions and 15 deletions.
10 changes: 0 additions & 10 deletions .github/ISSUE_TEMPLATE/이슈-생성-템플릿.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,6 @@ labels: ''
assignees: ''

---

---
name: ISSUE_TEMPLATE
about: "기본 이슈 템플릿입니다."
title: ''
labels: ''
assignees: ''

---

## Issue 📌

## Todo ✔️
Expand Down
2 changes: 1 addition & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
## Related Issue 📌
close #<issue_num>
- close #<issue_num>

## Description ✔️
-
Expand Down
20 changes: 20 additions & 0 deletions README.MD
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# 🌀Pingle

> 가볍게 네트워킹을 시작해보세요!
## 🌀 Developers

| 박상준 | 박재연 |
|:----------------------------------------------------------------------------------------:|:----------------------------------------------------------------------------------------:|
| <img width="300" alt="image" src="https://avatars.githubusercontent.com/u/74230343?v=4"> | <img width="300" alt="image" src="https://avatars.githubusercontent.com/u/98092394?v=4"> |
| [tkdwns414](https://github.com/tkdwns414) | [parkjyun](https://github.com/parkjyun) |


## 🌀 Project Architecture
[![stackticon](https://firebasestorage.googleapis.com/v0/b/stackticon-81399.appspot.com/o/images%2F1704700225293?alt=media&token=976f8fd7-14f6-47ef-b0fa-d36da1a332bc)](https://github.com/msdio/stackticon)

아키텍처 구조도 서버 2차 과제에 추가 예정
- Github Actions를 통한 CI/CD 구축
- blue-green deployment를 통한 무중단 배포
- nginx를 통한 reverse proxy 구축
- aws ec2를 통한 서버 배포
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.pingle.pingleserver.controller;

import lombok.RequiredArgsConstructor;
import org.pingle.pingleserver.annotation.UserId;
import org.pingle.pingleserver.dto.common.ApiResponse;
import org.pingle.pingleserver.dto.type.SuccessMessage;
import org.pingle.pingleserver.service.UserMeetingService;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/v1/meetings")
@RequiredArgsConstructor
public class MeetingController {

private static final String GROUP_ID = "Group-Id";

private final UserMeetingService userMeetingService;

@PostMapping("/{meetingId}/join")
public ApiResponse<?> participateMeeting (@UserId Long userId, @PathVariable("meetingId") Long meetingId) {
Long userMeetingId = userMeetingService.participateMeeting(userId, meetingId);
return ApiResponse.success(SuccessMessage.CREATED);
}

@DeleteMapping("/{meetingId}/cancel")
public ApiResponse<?> cancelMeeting (@UserId Long userId, @PathVariable("meetingId") Long meetingId) {
Long cancelledId = userMeetingService.cancelMeeting(userId, meetingId);
return ApiResponse.success(SuccessMessage.OK);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.pingle.pingleserver.controller;

import lombok.RequiredArgsConstructor;
import org.pingle.pingleserver.dto.common.ApiResponse;
import org.pingle.pingleserver.dto.reponse.LocationResponse;
import org.pingle.pingleserver.dto.type.SuccessMessage;
import org.pingle.pingleserver.utils.naversearchutil.NaverUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/v1")
@RequiredArgsConstructor
public class OpenApiController {

private final NaverUtil naverUtil;

@GetMapping("/location")
public ApiResponse<List<LocationResponse>> getLocationInfo(@RequestParam(name = "search") String location) {
return ApiResponse.success(SuccessMessage.OK, naverUtil.getLocationInfo(location));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,9 @@ public class UserMeeting extends BaseTimeEntity {
@Enumerated(EnumType.STRING)
private MRole meetingRole;


public UserMeeting(User user, Meeting meeting, MRole meetingRole) {
this.user = user;
this.meeting = meeting;
this.meetingRole = meetingRole;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.pingle.pingleserver.dto.reponse;

public record LocationResponse (double x, double y, String location, String address, String roadAddress) {

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.pingle.pingleserver.dto.reponse;

import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.List;

public record NaverLocationResponse(String lastBuildDate, int total, int start, int display, List<SearchLocationItem> items) {

@Getter
@NoArgsConstructor
public static class SearchLocationItem{
private String title;
private String link;
private String category;
private String description;
private String telephone;
private String address;
private String roadAddress;
private int mapx;
private int mapy;

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.pingle.pingleserver.dto.request;

import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

public record NaverLocationRequest(String query, int display, int start, String sort) {

private static final int DISPLAY = 5;

private static final int START = 1;

private static final String SORT = "random";

public static NaverLocationRequest of(String query) {
return new NaverLocationRequest(query, DISPLAY, START, SORT);
}

public MultiValueMap<String, String> toMap() {
var map = new LinkedMultiValueMap<String, String>();

map.add("query", query);
map.add("display", String.valueOf(DISPLAY));
map.add("start", String.valueOf(START));
map.add("sort", SORT);

return map;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public enum ErrorMessage {
JWT_TOKEN_IS_EMPTY(HttpStatus.UNAUTHORIZED, "JWT 토큰이 비어있습니다."),
// Invalid Argument Error 400
INVALID_HEADER_ERROR(HttpStatus.BAD_REQUEST, "유효하지 않은 헤더입니다."),
INVALID_PARAMETER_ERROR(HttpStatus.BAD_REQUEST, "유효하지 않은 파라미터입니다."),
INVALID_PROVIDER_ERROR(HttpStatus.BAD_REQUEST, "유효하지 않은 소셜 플랫폼입니다."),
BAD_REQUEST(HttpStatus.BAD_REQUEST, "잘못된 요청입니다."),
MISSING_REQUIRED_HEADER(HttpStatus.BAD_REQUEST, "필수 헤더가 누락되었습니다."),
Expand All @@ -29,8 +30,13 @@ public enum ErrorMessage {
// Not Found Error 404
USER_NOT_FOUND_ERROR(HttpStatus.NOT_FOUND, "사용자를 찾을 수 없습니다."),
NOT_FOUND_END_POINT(HttpStatus.NOT_FOUND, "존재하지 않는 API입니다."),
NOT_FOUND_RESOURCE(HttpStatus.NOT_FOUND, "해당 리소스가 존재하지 않습니다."),
// Method Not Allowed Error 405
METHOD_NOT_ALLOWED(HttpStatus.METHOD_NOT_ALLOWED, "지원하지 않는 HTTP 메소드입니다."),
// Conflict Error 409
RESOURCE_CONFLICT(HttpStatus.CONFLICT, "리소스 충돌이 일어났습니다."),
// OpenApi Server Error 500
NAVER_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "네이버 서버 오류입니다."),
// Internal Server Error 500
INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "서버 내부 오류입니다.");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public enum SuccessMessage {
OK(HttpStatus.OK, "OK"),
CREATED(HttpStatus.CREATED, "CREATED"),
LOGOUT_SUCCESS(HttpStatus.OK, "로그아웃 성공");

private final HttpStatus status;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package org.pingle.pingleserver.oauth.dto;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonNaming;

@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public record KakaoAccount (KakaoUserProfile kakaoUserProfile){
public record KakaoAccount (@JsonProperty("profile") KakaoUserProfile kakaoUserProfile, String email){
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
import com.fasterxml.jackson.databind.annotation.JsonNaming;

@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public record KakaoUserProfile (String nickname, String email){
public record KakaoUserProfile (String nickname){

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public SocialInfoDto getInfo(String providerToken) {
KakaoUserDto kakaoUserdto = kakaoFeignClient.getUserInformation("Bearer " + providerToken);
return SocialInfoDto.of(
kakaoUserdto.id().toString(),
kakaoUserdto.kakaoAccount().kakaoUserProfile().email(),
kakaoUserdto.kakaoAccount().email(),
kakaoUserdto.kakaoAccount().kakaoUserProfile().nickname());
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
package org.pingle.pingleserver.repository;

import org.pingle.pingleserver.domain.Meeting;
import org.pingle.pingleserver.domain.UserMeeting;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;
import java.util.Optional;

public interface UserMeetingRepository extends JpaRepository<UserMeeting, Long> {
List<UserMeeting> findAllByMeeting(Meeting meeting);
boolean existsByUserIdAndMeeting(Long userId, Meeting meeting);
Optional<UserMeeting> findByUserIdAndMeetingId(Long userId, Long MeetingId);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.pingle.pingleserver.service;

import lombok.RequiredArgsConstructor;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,54 @@
package org.pingle.pingleserver.service;

import lombok.RequiredArgsConstructor;
import org.pingle.pingleserver.domain.Meeting;
import org.pingle.pingleserver.domain.User;
import org.pingle.pingleserver.domain.UserMeeting;
import org.pingle.pingleserver.domain.enums.MRole;
import org.pingle.pingleserver.dto.type.ErrorMessage;
import org.pingle.pingleserver.exception.BusinessException;
import org.pingle.pingleserver.repository.MeetingRepository;
import org.pingle.pingleserver.repository.UserMeetingRepository;
import org.pingle.pingleserver.repository.UserRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class UserMeetingService {

private final UserMeetingRepository userMeetingRepository;
private final MeetingRepository meetingRepository;
private final UserRepository userRepository;

@Transactional
public Long participateMeeting(Long userId, Long meetingId) {
Meeting meeting = meetingRepository.findById(meetingId).orElseThrow(() -> new BusinessException(ErrorMessage.NOT_FOUND_RESOURCE));
if(isParticipating(userId, meeting))
throw new BusinessException(ErrorMessage.RESOURCE_CONFLICT);
if((getCurParticipants(meeting)) >= meeting.getMaxParticipants())
throw new BusinessException(ErrorMessage.RESOURCE_CONFLICT);
User user = userRepository.findById(userId).orElseThrow(() ->new BusinessException(ErrorMessage.NO_SUCH_USER));
return userMeetingRepository.save(new UserMeeting(user, meeting, MRole.PARTICIPANTS)).getId();

}

@Transactional
public Long cancelMeeting(Long userId, Long meetingId) {
UserMeeting userMeeting = userMeetingRepository.findByUserIdAndMeetingId(userId, meetingId)
.orElseThrow(() -> new BusinessException(ErrorMessage.NOT_FOUND_RESOURCE));
userMeetingRepository.delete(userMeeting);
return userMeeting.getId();
}

private int getCurParticipants(Meeting meeting) {
return userMeetingRepository.findAllByMeeting(meeting).size();
}

private boolean isParticipating(Long userId, Meeting meeting) {
return userMeetingRepository.existsByUserIdAndMeeting(userId, meeting);
}

}
Loading

0 comments on commit b325c5a

Please sign in to comment.