Skip to content

Commit

Permalink
v1.8.2 (#339)
Browse files Browse the repository at this point in the history
  • Loading branch information
kdomo authored Feb 15, 2024
2 parents f3b166d + f5bc8da commit 60fe6e9
Show file tree
Hide file tree
Showing 9 changed files with 176 additions and 11 deletions.
80 changes: 80 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# 10MM - 하루 10분으로 시작하는 습관 만들기

![image](https://github.com/depromeet/10mm-server/assets/64088250/95881667-069b-49f4-acb2-e299121c2ad2)
</br></br>
</br></br>

### ⏰ 하루 10분을 투자해서 나를 변화시킬 수 있다면?!

많은 사람들은 역량적, 신체적, 정서적인 다양한 방면에서 자기발전을 위해 노력하고 있습니다.
하지만 다양한 목표를 세우고 하루하루 지키면서 기록을 관리하기란 쉽지 않죠 😒
10MM은 그런 우리들의 자기 발전을 위해서 다양한 서비스를 제공합니다!

목표설정 🎯 > 트래킹과 아카이빙 📊 > 인증과 공유 📸 과정을 통해 자연스러운 습관 형성 환경을 만들어 갈 수 있어요.

**하루 10분**을 투자하여 나만의 습관 형성과 시간 관리 환경을 만들어 볼까요? 🚩
</br></br>
</br></br>

## ✨ 주요 기능
### 💙 10분 단위로 내가 집중한 시간을 알 수 있는 ‘스톱워치’
![](https://media.disquiet.io/images/product/gallery/adf69cc050e7c2fe3d90f3a49accdd03d8b29c4e44af962903a30a969bf81c98)
</br></br>
</br></br>

### 💙 친구와 미션 현황을 공유하며 긍정적인 영향력을 주고 받는 ‘홈’, ‘피드’
![](https://media.disquiet.io/images/product/gallery/d27ac52c9166eb8776c0b9a6a1dc37d721079ec5feb155b57cb468c300cf68f1)

![](https://media.disquiet.io/images/product/gallery/02f057262ac14c37afef536414c60b92412c92c4287e52d9ff1055b4e3c5d5b3)
</br></br>
</br></br>

### 💙 성취를 한눈에 볼 수 있는 ‘결과 페이지’
![](https://media.disquiet.io/images/product/gallery/558fa239926a7e55b7d1578e5ebf2770550acd733558a3d8f9f19f8274241ee8)
</br></br>

## 💌 궁금한 점이 있으신가요?
- 문의사항 | [[email protected]](mailto:[email protected])
- 인스타그램 | [@10mm.today](https://www.instagram.com/10mm.today)
- [서비스 피드백하기](https://forms.gle/RPHLaUgeHjuBqu4k8)
</br></br>

## 📝 직접 사용해보기
- [iOS](https://apps.apple.com/kr/app/10%EB%B6%84%EB%A7%8C-10mm-10%EB%B6%84%EC%9C%BC%EB%A1%9C-%EC%8B%9C%EC%9E%91%ED%95%98%EB%8A%94-%EC%8A%B5%EA%B4%80-%ED%98%95%EC%84%B1/id6475635740)
- [AOS](https://play.google.com/store/apps/details?id=com.tenminuteapp)
- [WEB](https://10mm.today/)
</br></br>

# 🖥️ Tech
## 🏛️ Architecture
<p align="center">
<img src="https://github.com/depromeet/10mm-server/assets/64088250/d878e879-3758-44a6-8dd1-141430627fc7" width="600"/>
</p>
</br></br>

## 🛠️ Tech Stack
<div align="left">
<div>
<img src="https://img.shields.io/badge/Spring Boot-6DB33F?style=flat-square&logo=Spring Boot&logoColor=white">
<img src="https://img.shields.io/badge/Gradle-02303A?style=flat-square&logo=Gradle&logoColor=white">
</div>
<div>
<img src="https://img.shields.io/badge/MySQL-4479A1.svg?style=flat-square&logo=MySQL&logoColor=white">
<img src="https://img.shields.io/badge/Redis-DC382D?style=flat-square&logo=Redis&logoColor=white">
</div>

<div>
<img src="https://img.shields.io/badge/Docker-2496ED?style=flat-square&logo=Docker&logoColor=white">
<img src="https://img.shields.io/badge/JSON Web Tokens-000000?style=flat-square&logo=JSON Web Tokens&logoColor=white">
</div>

<div>
<img src="https://img.shields.io/badge/SonarCloud-F3702A?style=flat-square&logo=SonarCloud&logoColor=white">
<img src="https://img.shields.io/badge/Slack-4A154B?style=flat-square&logo=slack&logoColor=white">
</div>
</br></br>

## 🧑🏻‍💻 Developers
| ![](https://avatars.githubusercontent.com/u/64088250?v=4) | ![](https://avatars.githubusercontent.com/u/91878695?v=4) |![](https://avatars.githubusercontent.com/u/68099546?v=4) |
| :--: | :--: | :--: |
| [김동호](https://github.com/kdomo) | [안재현](https://github.com/uwoobeat) | [차윤범](https://github.com/uiurihappy) |
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
import com.depromeet.domain.feed.application.FeedService;
import com.depromeet.domain.feed.dto.response.FeedOneByProfileResponse;
import com.depromeet.domain.feed.dto.response.FeedOneResponse;
import com.depromeet.domain.mission.domain.MissionVisibility;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
Expand All @@ -20,6 +22,13 @@ public class FeedController {

private final FeedService feedService;

@Operation(summary = "피드 탭", description = "피드 탭을 조회합니다.")
@GetMapping
public List<FeedOneResponse> feedFindAll(
@RequestParam(value = "visibility", required = false) MissionVisibility visibility) {
return feedService.findAllFeedByVisibility(visibility);
}

@Operation(summary = "피드 탭", description = "피드 탭을 조회합니다.")
@GetMapping("/me")
public List<FeedOneResponse> feedFindAll() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.depromeet.domain.feed.dto.response.FeedOneResponse;
import com.depromeet.domain.follow.dao.MemberRelationRepository;
import com.depromeet.domain.follow.domain.MemberRelation;
import com.depromeet.domain.member.dao.MemberRepository;
import com.depromeet.domain.member.domain.Member;
import com.depromeet.domain.mission.domain.MissionVisibility;
import com.depromeet.domain.missionRecord.dao.MissionRecordRepository;
Expand All @@ -26,16 +27,28 @@ public class FeedService {
private final MissionRecordRepository missionRecordRepository;
private final MemberRelationRepository memberRelationRepository;
private final SecurityUtil securityUtil;
private final MemberRepository memberRepository;

@Transactional(readOnly = true)
public List<FeedOneResponse> findAllFeedByVisibility(MissionVisibility visibilities) {
if (visibilities == MissionVisibility.ALL) {
final List<Member> members = memberRepository.findAll();
return missionRecordRepository.findFeedByVisibility(members, List.of(visibilities));
}

final Member currentMember = memberUtil.getCurrentMember();
List<Member> sourceMembers = getSourceMembers(currentMember.getId());

sourceMembers.add(currentMember);
return missionRecordRepository.findFeedAll(sourceMembers);
}

@Transactional(readOnly = true)
public List<FeedOneResponse> findAllFeed() {
final Member currentMember = memberUtil.getCurrentMember();
List<Member> members =
memberRelationRepository.findAllBySourceId(currentMember.getId()).stream()
.map(MemberRelation::getTarget)
.collect(Collectors.toList());
members.add(currentMember);
List<Member> members = getSourceMembers(currentMember.getId());

members.add(currentMember);
return missionRecordRepository.findFeedAll(members);
}

Expand All @@ -49,6 +62,12 @@ public List<FeedOneByProfileResponse> findAllFeedByTargetId(Long targetId) {
return findFeedByCurrentMember(sourceId);
}

private List<Member> getSourceMembers(Long currentMemberId) {
return memberRelationRepository.findAllBySourceId(currentMemberId).stream()
.map(MemberRelation::getTarget)
.collect(Collectors.toList());
}

private boolean isMyFeedRequired(Long targetId, Long sourceId) {
return !targetId.equals(sourceId);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,4 +134,13 @@ record ->
.findFirst()
.isPresent();
}

public boolean isFinished() {
if (this.getDurationStatus() == DurationStatus.FINISHED
|| this.archiveStatus == ArchiveStatus.ARCHIVED
|| this.getFinishedAt().isBefore(LocalDateTime.now())) {
return true;
}
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ public interface MissionRecordRepositoryCustom {

List<FeedOneResponse> findFeedAll(List<Member> members);

List<FeedOneResponse> findFeedByVisibility(
List<Member> members, List<MissionVisibility> visibility);

List<MissionRecord> findFeedAllByMemberId(Long memberId, List<MissionVisibility> visibilities);

boolean isCompletedMissionExistsToday(Long missionId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,14 @@ public boolean isCompletedMissionExistsToday(Long missionId) {

@Override
public List<FeedOneResponse> findFeedAll(List<Member> members) {
return findFeedByVisibility(
members, List.of(MissionVisibility.FOLLOWER, MissionVisibility.ALL));
}

@Override
public List<FeedOneResponse> findFeedByVisibility(
List<Member> members, List<MissionVisibility> visibilities) {

return jpaQueryFactory
.select(
Projections.constructor(
Expand All @@ -86,9 +94,8 @@ public List<FeedOneResponse> findFeedAll(List<Member> members) {
.on(mission.member.id.eq(missionRecord.mission.member.id))
.where(
missionRecord.mission.member.in(members),
missionRecord.mission.visibility.in(
MissionVisibility.FOLLOWER, MissionVisibility.ALL),
missionRecord.uploadStatus.eq(ImageUploadStatus.COMPLETE))
missionRecord.mission.visibility.in(visibilities),
uploadStatusCompleteEq())
.orderBy(missionRecord.finishedAt.desc())
.limit(FEED_TAB_LIMIT)
.fetch();
Expand All @@ -104,7 +111,7 @@ public List<MissionRecord> findFeedAllByMemberId(
.where(
mission.visibility.in(visibilities),
mission.member.id.eq(memberId),
missionRecord.uploadStatus.eq(ImageUploadStatus.COMPLETE))
uploadStatusCompleteEq())
.orderBy(missionRecord.startedAt.desc())
.fetch();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public void sendUrgingPush(PushUrgingSendRequest request) {
final Member targetMember = mission.getMember();

validateSelfSending(currentMember.getId(), targetMember.getId());
validateFinishedMission(mission);
validateMissionNotCompletedToday(mission);

fcmService.sendMessageSync(
Expand All @@ -50,6 +51,12 @@ public void sendUrgingPush(PushUrgingSendRequest request) {
notificationRepository.save(notification);
}

private void validateFinishedMission(Mission mission) {
if (mission.isFinished()) {
throw new CustomException(ErrorCode.FINISHED_MISSION_URGING_NOT_ALLOWED);
}
}

private void validateMissionNotCompletedToday(Mission mission) {
if (mission.isCompletedMissionToday()) {
throw new CustomException(ErrorCode.TODAY_COMPLETED_MISSION_SENDING_NOT_ALLOWED);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public enum ErrorCode {
SELF_SENDING_NOT_ALLOWED(HttpStatus.BAD_REQUEST, "본인에게 메세지를 전송할 수 없습니다."),
TODAY_COMPLETED_MISSION_SENDING_NOT_ALLOWED(
HttpStatus.BAD_REQUEST, "오늘 미션을 완료한 미션에는 메세지를 전송할 수 없습니다."),
FINISHED_MISSION_URGING_NOT_ALLOWED(HttpStatus.BAD_REQUEST, "종료된 미션에는 재촉하기를 할 수 없습니다."),

// Reaction
REACTION_NOT_FOUND(HttpStatus.NOT_FOUND, "해당 리액션을 찾을 수 없습니다."),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,6 @@ class 친구에게_미션을_재촉할_때 {
void 본인에게_재촉할_경우_예외를_발생시킨다() {
// given
PushUrgingSendRequest request = new PushUrgingSendRequest(1L);

// when, then
Member currentMember =
memberRepository.save(
Member.createNormalMember(
Expand All @@ -124,6 +122,38 @@ class 친구에게_미션을_재촉할_때 {
.hasMessage(ErrorCode.SELF_SENDING_NOT_ALLOWED.getMessage());
}

@Test
void 종료된_미션을_재촉할_경우_예외를_발생시킨다() {
// given
PushUrgingSendRequest request = new PushUrgingSendRequest(1L);
Member currentMember =
memberRepository.save(
Member.createNormalMember(
Profile.createProfile("testNickname1", "testImageUrl1")));
Member targetMember =
memberRepository.save(
Member.createNormalMember(
Profile.createProfile("testNickname2", "testImageUrl2")));
LocalDateTime today = LocalDateTime.now();
LocalDateTime missionStartedAt = today.minusWeeks(3);
LocalDateTime missionFinishedAt = missionStartedAt.plusWeeks(2);
missionRepository.save(
Mission.createMission(
"testMissionName",
"testMissionContent",
1,
MissionCategory.ETC,
MissionVisibility.ALL,
missionStartedAt,
missionFinishedAt,
targetMember));

// when, then
assertThatThrownBy(() -> pushService.sendUrgingPush(request))
.isInstanceOf(CustomException.class)
.hasMessage(ErrorCode.FINISHED_MISSION_URGING_NOT_ALLOWED.getMessage());
}

@Test
void 미션이_당일_완료된_경우_예외를_발생시킨다() {
// given
Expand Down

0 comments on commit 60fe6e9

Please sign in to comment.