Skip to content

Commit

Permalink
Merge pull request #35 from DDD-Community/develop
Browse files Browse the repository at this point in the history
7차 배포
  • Loading branch information
kikingki authored Oct 27, 2024
2 parents c3a1d6c + a66f277 commit d02379f
Show file tree
Hide file tree
Showing 23 changed files with 709 additions and 251 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public enum ErrorCode {

// 403
UNAUTHORIZED_REFRESH_TOKEN(HttpStatus.FORBIDDEN, "권한없는 Refresh Token입니다."),
NO_INFO_POST_UPDATE_PERMISSION(HttpStatus.FORBIDDEN, "게시글 수정 권한이 없습니다."),

// 404
NON_EXISTENT_USER_ID(HttpStatus.NOT_FOUND, "해당 id의 사용자가 존재하지 않습니다."),
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/com/dissonance/itit/common/util/DateUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@

public class DateUtil {
public static LocalDate stringToDate(String dateString) {
if (dateString == null) {
return null;
}

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy년 M월 d일");
try {
return LocalDate.parse(dateString, formatter);
Expand All @@ -22,6 +26,9 @@ public static String formatPeriod(LocalDate startDate, LocalDate endDate) {
}

public static String formatDate(LocalDate date) {
if (date == null)
return "";

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy년 MM월 dd일");
return date.format(formatter);
}
Expand Down
9 changes: 6 additions & 3 deletions src/main/java/com/dissonance/itit/config/SecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,13 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
)
.authorizeHttpRequests(authorizeRequests ->
authorizeRequests
.requestMatchers("/oauth/**", "/swagger-ui/**", "/v3/api-docs/**").permitAll()
.requestMatchers(HttpMethod.POST, "/info-posts").hasRole("ADMIN")
.requestMatchers("/oauth/**",
"/swagger-ui/**",
"/v3/api-docs/**",
"/info-posts/**",
"/featured-posts/**").permitAll()
.requestMatchers("/admin/info-posts/**").hasRole("ADMIN")
.requestMatchers(HttpMethod.PATCH, "/info-posts/{infoPostId}/reports").authenticated()
.requestMatchers("/info-posts/**", "/featured-posts/**").permitAll()
.anyRequest().authenticated()
)
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
Expand Down
63 changes: 32 additions & 31 deletions src/main/java/com/dissonance/itit/config/SwaggerConfig.java
Original file line number Diff line number Diff line change
@@ -1,43 +1,44 @@
package com.dissonance.itit.config;

import java.util.Collections;
import java.util.List;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.servers.Server;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Collections;
import java.util.List;

@Configuration
public class SwaggerConfig {
@Bean
public OpenAPI openAPI(){
Info info = new Info()
.title("ITIT API Document")
.version("v1.0")
.description("ITIT API 문서입니다.");

Server prodServer = new Server();
prodServer.description("Production Server")
.url("https://dissonance-server.duckdns.org/api/v1");

Server devServer = new Server();
devServer.description("Development Server")
.setUrl("http://localhost:8080/api/v1");

SecurityScheme securityScheme = new SecurityScheme()
.type(SecurityScheme.Type.HTTP).scheme("bearer").bearerFormat("JWT")
.in(SecurityScheme.In.HEADER).name("Authorization");
SecurityRequirement securityRequirement = new SecurityRequirement().addList("bearerAuth");

return new OpenAPI()
.info(info)
.servers(List.of(prodServer, devServer))
.components(new Components().addSecuritySchemes("bearerAuth", securityScheme))
.security(Collections.singletonList(securityRequirement));
}
@Bean
public OpenAPI openAPI() {
Info info = new Info()
.title("Mozip API Document")
.version("v1.0")
.description("Mozip API 문서입니다.");

Server prodServer = new Server();
prodServer.description("Production Server")
.url("https://dissonance-server.duckdns.org/api/v1");

Server devServer = new Server();
devServer.description("Development Server")
.setUrl("http://localhost:8080/api/v1");

SecurityScheme securityScheme = new SecurityScheme()
.type(SecurityScheme.Type.HTTP).scheme("bearer").bearerFormat("JWT")
.in(SecurityScheme.In.HEADER).name("Authorization");
SecurityRequirement securityRequirement = new SecurityRequirement().addList("bearerAuth");

return new OpenAPI()
.info(info)
.servers(List.of(prodServer, devServer))
.components(new Components().addSecuritySchemes("bearerAuth", securityScheme))
.security(Collections.singletonList(securityRequirement));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.dissonance.itit.controller;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.dissonance.itit.common.annotation.CurrentUser;
import com.dissonance.itit.common.util.ApiResponse;
import com.dissonance.itit.domain.entity.User;
import com.dissonance.itit.dto.request.InfoPostReq;
import com.dissonance.itit.dto.response.InfoPostCreateRes;
import com.dissonance.itit.dto.response.InfoPostDetailRes;
import com.dissonance.itit.dto.response.InfoPostUpdateRes;
import com.dissonance.itit.service.InfoPostService;

import io.swagger.v3.oas.annotations.Operation;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;

@RestController
@RequiredArgsConstructor
@RequestMapping("/admin/info-posts")
public class AdminInfoPostController {
private final InfoPostService infoPostService;

@PostMapping(consumes = {MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_JSON_VALUE})
@Operation(summary = "공고 게시글 등록", description = "공고 게시글을 등록합니다.")
public ApiResponse<InfoPostCreateRes> createInfoPost(@RequestPart MultipartFile imgFile,
@Valid @RequestPart InfoPostReq infoPostReq, @CurrentUser User loginUser) {
InfoPostCreateRes infoPostCreateRes = infoPostService.createInfoPost(imgFile, infoPostReq, loginUser);
return ApiResponse.success(infoPostCreateRes);
}

@DeleteMapping("/{infoPostId}")
@Operation(summary = "공고 게시글 삭제", description = "공고 게시글을 삭제합니다.")
public ApiResponse<String> deleteInfoPost(@PathVariable Long infoPostId) {
infoPostService.deleteInfoPostById(infoPostId);
return ApiResponse.success("게시글 삭제 성공");
}

@GetMapping("/{infoPostId}")
@Operation(summary = "공고 수정 - 게시글 조회", description = "공고 게시글 수정 페이지에 띄울 상세 정보를 조회합니다.")
public ApiResponse<InfoPostUpdateRes> getInfoPostDetailByIdForUpdate(@PathVariable Long infoPostId) {
InfoPostUpdateRes infoPostUpdateRes = infoPostService.getInfoPostDetailByIdForUpdate(infoPostId);
return ApiResponse.success(infoPostUpdateRes);
}

@PutMapping(value = "/{infoPostId}", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE,
MediaType.APPLICATION_JSON_VALUE})
@Operation(summary = "공고 게시글 수정", description = "공고 게시글을 수정합니다.")
public ApiResponse<InfoPostDetailRes> updateInfoPost(@PathVariable Long infoPostId,
@RequestPart(required = false) MultipartFile imgFile,
@Valid @RequestPart InfoPostReq infoPostReq, @CurrentUser User loginUser) {
InfoPostDetailRes infoPostDetailRes = infoPostService.updateInfoPost(infoPostId, imgFile, infoPostReq,
loginUser);
return ApiResponse.success(infoPostDetailRes);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,21 @@

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.dissonance.itit.common.annotation.CurrentUser;
import com.dissonance.itit.common.util.ApiResponse;
import com.dissonance.itit.domain.entity.User;
import com.dissonance.itit.dto.request.InfoPostReq;
import com.dissonance.itit.dto.response.InfoPostCreateRes;
import com.dissonance.itit.dto.response.InfoPostDetailRes;
import com.dissonance.itit.dto.response.InfoPostRes;
import com.dissonance.itit.service.InfoPostService;
import com.dissonance.itit.service.ReportService;

import io.swagger.v3.oas.annotations.Operation;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;

@RestController
Expand All @@ -33,14 +26,6 @@ public class InfoPostController {
private final InfoPostService infoPostService;
private final ReportService reportService;

@PostMapping(consumes = {MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_JSON_VALUE})
@Operation(summary = "공고 게시글 등록", description = "공고 게시글을 등록합니다.")
public ApiResponse<InfoPostCreateRes> createInfoPost(@RequestPart MultipartFile imgFile,
@Valid @RequestPart InfoPostReq infoPostReq, @CurrentUser User loginUser) {
InfoPostCreateRes infoPostCreateRes = infoPostService.createInfoPost(imgFile, infoPostReq, loginUser);
return ApiResponse.success(infoPostCreateRes);
}

@GetMapping("/{infoPostId}")
@Operation(summary = "공고 게시글 조회", description = "공고 게시글을 상세 조회합니다.")
public ApiResponse<InfoPostDetailRes> getInfoPostDetail(@PathVariable Long infoPostId) {
Expand Down
52 changes: 34 additions & 18 deletions src/main/java/com/dissonance/itit/domain/entity/Image.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
package com.dissonance.itit.domain.entity;

import com.dissonance.itit.domain.enums.Directory;
import jakarta.persistence.*;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.OneToOne;
import jakarta.persistence.Table;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.*;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Builder
Expand All @@ -13,23 +26,26 @@
@Entity
@Table(name = "image")
public class Image {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;

@Size(max = 500)
@NotNull
@Column(name = "image_url")
private String imageUrl;

@Size(max = 500)
@NotNull
@Column(name = "image_url")
private String imageUrl;
@Size(max = 255)
@NotNull
@Column(name = "convert_image_name")
private String convertImageName;

@Size(max = 255)
@NotNull
@Column(name = "convert_image_name")
private String convertImageName;
@Enumerated(EnumType.STRING)
@NotNull
@Column(name = "directory")
private Directory directory;

@Enumerated(EnumType.STRING)
@NotNull
@Column(name = "directory")
private Directory directory;
@OneToOne(mappedBy = "image")
private InfoPost infoPost;
}
34 changes: 25 additions & 9 deletions src/main/java/com/dissonance/itit/domain/entity/InfoPost.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import java.time.LocalDate;

import com.dissonance.itit.dto.request.InfoPostUpdateReq;

import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
Expand Down Expand Up @@ -38,27 +40,24 @@ public class InfoPost extends BaseTime {
@Column(name = "title")
private String title;

@Size(max = 2000)
@NotNull
@Size(max = 4000)
@Column(name = "content")
private String content;

@NotNull
@Column(name = "view_count")
private Integer viewCount;

@NotNull
@Column(name = "recruitment_start_date")
private LocalDate recruitmentStartDate;

@NotNull
@Column(name = "recruitment_end_date")
private LocalDate recruitmentEndDate;

@NotNull
@Column(name = "activity_start_date")
private LocalDate activityStartDate;

@NotNull
@Column(name = "activity_end_date")
private LocalDate activityEndDate;

Expand All @@ -67,7 +66,8 @@ public class InfoPost extends BaseTime {
@Column(name = "detail_url")
private String detailUrl;

@Size(max = 50)
@Size(max = 100)
@NotNull
@Column(name = "organization")
private String organization;

Expand All @@ -77,7 +77,7 @@ public class InfoPost extends BaseTime {
@Column(name = "recruitment_closed")
private Boolean recruitmentClosed;

@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
@OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "image_id")
private Image image;

Expand All @@ -89,7 +89,23 @@ public class InfoPost extends BaseTime {
@JoinColumn(name = "category_id")
private Category category;

public void updateReported() {
this.reported = true;
public void updateImage(Image newImage) {
this.image = newImage;
}

public void update(InfoPostUpdateReq updateReq) {
this.category = updateReq.category();
this.title = updateReq.title();
this.organization = updateReq.organization();
this.content = updateReq.content();
this.recruitmentStartDate = updateReq.recruitmentStartDate();
this.recruitmentEndDate = updateReq.recruitmentEndDate();
this.activityStartDate = updateReq.activityStartDate();
this.activityEndDate = updateReq.activityEndDate();
this.detailUrl = updateReq.detailUrl();
}

public boolean isAuthor(User loginUser) {
return this.getAuthor().getId().equals(loginUser.getId());
}
}
Loading

0 comments on commit d02379f

Please sign in to comment.