Skip to content
Merged
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,4 @@ out/
**/application.properties

/lib/
/url/
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ dependencies {
implementation 'org.locationtech.jts:jts-core:1.19.0'

// Swagger-ui
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.5.0'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.3'

// EXIF metadata extraction
implementation 'com.drewnoakes:metadata-extractor:2.19.0'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
import jakarta.validation.Valid;
import kr.kro.photoliner.domain.album.dto.request.AlbumCreateRequest;
import kr.kro.photoliner.domain.album.dto.request.AlbumDeleteRequest;
import kr.kro.photoliner.domain.album.dto.request.AlbumItemCreateRequest;
import kr.kro.photoliner.domain.album.dto.request.AlbumItemDeleteRequest;
import kr.kro.photoliner.domain.album.dto.request.AlbumTitleUpdateRequest;
import kr.kro.photoliner.domain.album.dto.response.AlbumCreateResponse;
import kr.kro.photoliner.domain.album.dto.response.AlbumPhotoItemsResponse;
import kr.kro.photoliner.domain.album.dto.response.AlbumsResponse;
import kr.kro.photoliner.domain.album.service.AlbumService;
import lombok.RequiredArgsConstructor;
Expand All @@ -14,6 +18,8 @@
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
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.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
Expand Down Expand Up @@ -43,11 +49,46 @@ public ResponseEntity<AlbumsResponse> getAlbums(
return ResponseEntity.ok(albumService.getAlbums(userId, pageable));
}

@PatchMapping("/{albumId}/title")
public ResponseEntity<Void> updateAlbumTitle(
@PathVariable Long albumId,
@RequestBody @Valid AlbumTitleUpdateRequest request
) {
albumService.updateAlbumTitle(albumId, request);
return ResponseEntity.noContent().build();
}

@DeleteMapping
public ResponseEntity<Void> deletePhoto(
@Valid @RequestBody AlbumDeleteRequest request
) {
albumService.deleteAlbums(request);
return ResponseEntity.noContent().build();
}

@GetMapping("/{albumId}/photos")
public ResponseEntity<AlbumPhotoItemsResponse> getAlbumItems(
@PathVariable Long albumId,
@PageableDefault(sort = "capturedDt", direction = Sort.Direction.DESC) Pageable pageable
) {
return ResponseEntity.ok(albumService.getAlbumPhotoItems(albumId, pageable));
}

@PostMapping("/{albumId}/photos")
public ResponseEntity<Void> createAlbumItems(
@PathVariable Long albumId,
@RequestBody @Valid AlbumItemCreateRequest request
) {
albumService.createAlbumItems(albumId, request);
return ResponseEntity.noContent().build();
}

@DeleteMapping("/{albumId}/photos")
public ResponseEntity<Void> deleteAlbumItems(
@PathVariable Long albumId,
@RequestBody @Valid AlbumItemDeleteRequest request
) {
albumService.deleteAlbumItems(albumId, request);
return ResponseEntity.noContent().build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ public record AlbumCreateRequest(
@NotNull
Long userId,
@NotEmpty
String name
String title
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package kr.kro.photoliner.domain.album.dto.request;

import jakarta.validation.constraints.NotNull;
import java.util.List;

public record AlbumItemCreateRequest(
@NotNull
List<Long> ids
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package kr.kro.photoliner.domain.album.dto.request;

import jakarta.validation.constraints.NotNull;
import java.util.List;

public record AlbumItemDeleteRequest(
@NotNull
List<Long> ids
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package kr.kro.photoliner.domain.album.dto.request;

import jakarta.validation.constraints.NotNull;

public record AlbumTitleUpdateRequest(
@NotNull
String title
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public static AlbumCreateResponse from(Album album) {
return new AlbumCreateResponse(
new InnerAlbum(
album.getId(),
album.getName()
album.getTitle()
)
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package kr.kro.photoliner.domain.album.dto.response;

import java.time.LocalDateTime;
import java.util.List;
import kr.kro.photoliner.domain.album.model.view.AlbumPhotoView;
import org.springframework.data.domain.Page;

public record AlbumPhotoItemsResponse(
List<InnerAlbumPhotoItem> items
) {

public static AlbumPhotoItemsResponse from(Page<AlbumPhotoView> albumPhotoViews) {
return new AlbumPhotoItemsResponse(
albumPhotoViews.stream()
.map(InnerAlbumPhotoItem::from)
.toList()
);
}

public record InnerAlbumPhotoItem(
Long id,
Long photoId,
String fileName,
String filePath,
String thumbnailPath,
LocalDateTime capturedDt
) {

public static InnerAlbumPhotoItem from(AlbumPhotoView albumPhotoView) {
return new InnerAlbumPhotoItem(
albumPhotoView.getId(),
albumPhotoView.getPhotoId(),
albumPhotoView.getFileName(),
albumPhotoView.getFilePath(),
albumPhotoView.getThumbnailPath(),
albumPhotoView.getCapturedDt()
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public record InnerAlbum(
public static InnerAlbum from(Album album) {
return new InnerAlbum(
album.getId(),
album.getName()
album.getTitle()
);
}
}
Expand Down
38 changes: 36 additions & 2 deletions src/main/java/kr/kro/photoliner/domain/album/model/Album.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package kr.kro.photoliner.domain.album.model;

import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
Expand All @@ -8,8 +9,12 @@
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import jakarta.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import kr.kro.photoliner.common.model.BaseEntity;
import kr.kro.photoliner.domain.user.model.User;
import lombok.AccessLevel;
Expand All @@ -31,10 +36,39 @@ public class Album extends BaseEntity {
private Long id;

@NotNull
@Column(name = "name", nullable = false)
private String name;
@Column(name = "title", nullable = false)
private String title;

@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "user_id", referencedColumnName = "id")
private User user;

@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "album")
private List<PhotoItem> items = new ArrayList<>();

public void addPhotos(List<Long> photoIds) {
photoIds.forEach(this::addPhoto);
}

private void addPhoto(Long photoId) {
items.add(PhotoItem.of(this, photoId));
}

public void updateTitle(String title) {
this.title = title;
}

public void removePhotos(List<Long> photoIds) {
photoIds.forEach(this::removePhoto);
}

private void removePhoto(Long photoId) {
items.removeIf(item -> {
if (Objects.equals(item.getPhotoId(), photoId)) {
item.removeAlbum();
return true;
}
return false;
});
}
}
12 changes: 0 additions & 12 deletions src/main/java/kr/kro/photoliner/domain/album/model/Albums.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
package kr.kro.photoliner.domain.photo.model;
package kr.kro.photoliner.domain.album.model;

import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.util.Objects;
import kr.kro.photoliner.domain.album.model.Album;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

Expand All @@ -20,20 +18,29 @@
@AllArgsConstructor
@Table(name = "albums_photos")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class AlbumPhoto {
@Builder
public class PhotoItem {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne(fetch = FetchType.LAZY)
@ManyToOne
@JoinColumn(name = "album_id", nullable = false)
private Album album;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "photo_id", nullable = false)
private Photo photo;
private Long photoId;

public boolean isIncludedInAlbum(Long albumId) {
return Objects.equals(album.getId(), albumId);
public PhotoItem(Album album, Long photoId) {
this.album = album;
this.photoId = photoId;
}

public static PhotoItem of(Album album, Long photoId) {
return new PhotoItem(album, photoId);
}

public void removeAlbum() {
this.album = null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package kr.kro.photoliner.domain.album.model.view;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import java.time.LocalDateTime;
import java.util.Objects;
import lombok.Getter;
import org.hibernate.annotations.Immutable;
import org.locationtech.jts.geom.Point;

@Entity
@Immutable
@Getter
@Table(name = "vw_album_photos")
public class AlbumPhotoView {
Comment on lines +13 to +17
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

C

뷰테이블을 만들어서 맵핑하는 전략을 선택하셨군요. 이러면 DB가 바뀐다면 뷰테이블도 추가해줘야하는 불편함이 있을 것 같긴합니다.

@Id
@Column(name = "id")
private Long id;

@Column(name = "photo_id", nullable = false)
private Long photoId;

@Column(name = "file_name")
private String fileName;

@Column(name = "file_path")
private String filePath;

@Column(name = "thumbnail_path")
private String thumbnailPath;

@Column(name = "captured_dt")
private LocalDateTime capturedDt;

@Column(name = "location")
private Point location;

@Column(name = "album_id")
private Long albumId;

@Column(name = "user_id")
private Long userId;

public Double getLatitude() {
if (Objects.isNull(location)) {
return null;
}
return location.getX();
}

public Double getLongitude() {
if (Objects.isNull(location)) {
return null;
}
return location.getY();
}
Comment on lines +46 to +58
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A

좋네요

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package kr.kro.photoliner.domain.album.model.view;

import java.util.List;
import java.util.Objects;

public record AlbumPhotoViews(
List<AlbumPhotoView> albumPhotoViews
) {

public List<AlbumPhotoView> filterIncludedInAlbum(Long albumId) {
return albumPhotoViews.stream()
.filter(albumPhotoView -> Objects.equals(albumPhotoView.getAlbumId(), albumId))
.toList();
}

public List<AlbumPhotoView> filterExcludedFromAlbum(Long albumId) {
return albumPhotoViews.stream()
.filter(albumPhotoView -> !Objects.equals(albumPhotoView.getAlbumId(), albumId))
.toList();
}
}
Loading
Loading