Skip to content

Commit

Permalink
Merge pull request #136 from 05AM/feature/admin-login
Browse files Browse the repository at this point in the history
#135 [FEAT] Admin Login API 구현
  • Loading branch information
05AM authored Oct 28, 2023
2 parents 0dbfcbf + c340455 commit 643f59f
Show file tree
Hide file tree
Showing 28 changed files with 797 additions and 511 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.tattour.server.domain.admin.controller.dto.request;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;

@Schema(description = "로그인 request")
@Getter
public class AdminLoginReq {

private String userName;
private String password;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.tattour.server.domain.admin.controller.dto.response;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;

@Schema(description = "관리자 로그인 Response")
@Getter
@Builder
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class AdminLoginRes {

@Schema(description = "JWT access token")
private String accessToken;

public static AdminLoginRes of(String accessToken) {
return AdminLoginRes.builder()
.accessToken(accessToken)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package org.tattour.server.domain.admin.domain;

import java.sql.Timestamp;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.DynamicInsert;

@Entity(name = "admin")
@DynamicInsert
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class Admin {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;

private String adminName;

private String password;

@Column(columnDefinition = "TINYINT")
private Integer loginFailCnt;

private Timestamp createdAt;

public void addLoginFailCnt() {
this.loginFailCnt += 1;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package org.tattour.server.domain.admin.domain;

import java.sql.Timestamp;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.DynamicInsert;

@Entity(name = "admin_access_log")
@DynamicInsert
@Getter
@Builder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class AdminAccessLog {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "admin_id")
private Admin admin;

private String accessIp;

private Timestamp accessTime;

public static AdminAccessLog of(Admin admin, String accessIp) {
return AdminAccessLog.builder()
.admin(admin)
.accessIp(accessIp)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.tattour.server.domain.admin.facade;

import org.tattour.server.domain.admin.controller.dto.request.AdminLoginReq;
import org.tattour.server.domain.admin.controller.dto.response.AdminLoginRes;

public interface AdminFacade {

AdminLoginRes login(AdminLoginReq req, String accessIp);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.tattour.server.domain.admin.facade.impl;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.tattour.server.domain.admin.controller.dto.request.AdminLoginReq;
import org.tattour.server.domain.admin.controller.dto.response.AdminLoginRes;
import org.tattour.server.domain.admin.domain.Admin;
import org.tattour.server.domain.admin.facade.AdminFacade;
import org.tattour.server.domain.admin.service.AdminService;
import org.tattour.server.domain.user.domain.UserRole;
import org.tattour.server.global.config.jwt.JwtService;
import org.tattour.server.global.exception.BusinessException;
import org.tattour.server.global.exception.ErrorType;

@Service
@RequiredArgsConstructor
public class AdminFacadeImpl implements AdminFacade {

private final JwtService jwtService;
private final AdminService adminService;

@Override
@Transactional
public AdminLoginRes login(AdminLoginReq req, String accessIp) {
Admin admin = adminService.readAdminByAdminName(req.getUserName());

if (adminService.isAccountLocked(admin)) {
throw new BusinessException(ErrorType.ACCOUNT_LOCKED_EXCEPTION);
}

if (!adminService.validateCredentials(admin, req.getUserName(), req.getPassword())) {
adminService.addLoginFailCnt(admin);
throw new BusinessException(ErrorType.AUTHENTICATION_FAILED_EXCEPTION);
}

adminService.saveAdminAccessLog(admin, accessIp);
return AdminLoginRes.of(
jwtService.issuedToken(admin.getId(), UserRole.ADMIN.toString()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.tattour.server.domain.admin.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import org.tattour.server.domain.admin.domain.AdminAccessLog;

@Repository
public interface AdminAccessLogRepository extends JpaRepository<AdminAccessLog, Integer> {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.tattour.server.domain.admin.repository;

import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import org.tattour.server.domain.admin.domain.Admin;

@Repository
public interface AdminRepositoryImpl extends JpaRepository<Admin, Integer> {

Optional<Admin> findByAdminName(String adminName);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.tattour.server.domain.admin.service;

import org.tattour.server.domain.admin.domain.Admin;

public interface AdminService {

void saveAdmin(Admin admin);

Admin readAdminByAdminName(String adminName);

boolean validateCredentials(Admin admin, String adminName, String password);

boolean isAccountLocked(Admin admin);

void addLoginFailCnt(Admin admin);

void saveAdminAccessLog(Admin admin, String accessIp);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package org.tattour.server.domain.admin.service.impl;

import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.tattour.server.domain.admin.domain.Admin;
import org.tattour.server.domain.admin.domain.AdminAccessLog;
import org.tattour.server.domain.admin.repository.AdminAccessLogRepository;
import org.tattour.server.domain.admin.repository.AdminRepositoryImpl;
import org.tattour.server.domain.admin.service.AdminService;
import org.tattour.server.global.exception.BusinessException;
import org.tattour.server.global.exception.ErrorType;

@Service
@RequiredArgsConstructor
public class AdminServiceImpl implements AdminService {

private final PasswordEncoder passwordEncoder;
private final AdminRepositoryImpl adminRepository;
private final AdminAccessLogRepository adminAccessLogRepository;

@Override
public void saveAdmin(Admin admin) {
adminRepository.save(admin);
}

@Override
public Admin readAdminByAdminName(String adminName) {
return adminRepository.findByAdminName(adminName)
.orElseThrow(
() -> new BusinessException(ErrorType.AUTHENTICATION_FAILED_EXCEPTION));
}

@Override
public boolean validateCredentials(Admin admin, String adminName, String password) {
return admin.getAdminName().equals(adminName)
&& passwordEncoder.matches(password, admin.getPassword());
}

@Override
public boolean isAccountLocked(Admin admin) {
return admin.getLoginFailCnt() == 5;
}

@Override
public void addLoginFailCnt(Admin admin) {
admin.addLoginFailCnt();
saveAdmin(admin);
}

@Override
public void saveAdminAccessLog(Admin admin, String accessIp) {
adminAccessLogRepository.save(AdminAccessLog.of(admin, accessIp));
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
package org.tattour.server.domain.point.domain;

import java.util.Arrays;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public enum PointLogCategory {
PURCHASE("상품구매"),
APPLY_CUSTOM("커스텀신청"),
CANCEL_PURCHASE("결제취소"),
REQUEST_CHARGE("포인트충전요청"),
CANCEL_CHARGE("충전취소"),
PURCHASE("상품 구매"),
APPLY_CUSTOM("커스텀 신청"),
CANCEL_PURCHASE("결제 취소"),
REQUEST_CHARGE("포인트 충전 요청"),
CANCEL_CHARGE("충전 취소"),
;

private final String value;

public static PointLogCategory fromValue(String value) {
return Arrays.stream(PointLogCategory.values())
.filter(category -> category.value.equals(value))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException(
"입력한 value와 일치하는 Enum 타입이 없습니다: " + value));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ public class UserPointLog {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
// private String title;
@Column(name = "title")
@Enumerated(EnumType.STRING)
private PointLogCategory pointLogCategory;
Expand All @@ -38,8 +37,8 @@ public class UserPointLog {
@JoinColumn(name = "user_id")
private User user;

private UserPointLog(PointLogCategory pointLogCategory, String content, Integer amount, Integer resultPointAmount,
User user) {
private UserPointLog(PointLogCategory pointLogCategory, String content, Integer amount,
Integer resultPointAmount, User user) {
this.pointLogCategory = pointLogCategory;
this.content = content;
this.amount = amount;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,10 @@

public interface PointService {

// 포인트 충전 요청 저장하기
void savePointChargeRequest(PointChargeRequest pointChargeRequest);

// 포인트 로그 저장하기
void savePointLog(UserPointLog userPointLog);

// 포인트 충전 요청 수정하기
// TODO : 삭제하기
void updatePointChargeRequest(PointChargeRequest pointChargeRequest, int transferredAmount,
boolean isDeposited, boolean isAmountMatched, boolean isApproved, boolean isCompleted);
Expand Down
Loading

0 comments on commit 643f59f

Please sign in to comment.