Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import in.koreatech.koin.admin.abtest.useragent.UserAgentInfo;
import in.koreatech.koin.admin.history.aop.AdminActivityLogging;
import in.koreatech.koin.admin.history.enums.DomainType;
import in.koreatech.koin.admin.manager.dto.request.AdminAuthenticationStatusUpdateRequest;
import in.koreatech.koin.admin.manager.dto.request.AdminLoginRequest;
import in.koreatech.koin.admin.manager.dto.request.AdminPasswordChangeRequest;
import in.koreatech.koin.admin.manager.dto.request.AdminPermissionUpdateRequest;
Expand Down Expand Up @@ -49,7 +50,13 @@ public interface AdminApi {
@ApiResponse(responseCode = "409", content = @Content(schema = @Schema(hidden = true))),
}
)
@Operation(summary = "어드민 회원가입")
@Operation(summary = "어드민 회원가입", description = """
### track_name
- ANDROID, BACKEND, FRONTEND, GAME, PM, PL, DESIGN, IOS, DA, SECURITY
### team_name
- KOIN, BUSINESS, CAMPUS, USER
""")
@PostMapping("/admin")
ResponseEntity<Void> createAdmin(
@RequestBody @Valid CreateAdminRequest request,
Expand Down Expand Up @@ -178,6 +185,7 @@ ResponseEntity<AdminsResponse> getAdmins(
@PutMapping("/admin/{id}/authed")
@AdminActivityLogging(domain = DomainType.ADMIN, domainIdParam = "id")
ResponseEntity<Void> adminAuthenticate(
@RequestBody @Valid AdminAuthenticationStatusUpdateRequest request,
@PathVariable Integer id,
@Auth(permit = {ADMIN}) Integer adminId
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import in.koreatech.koin.admin.abtest.useragent.UserAgentInfo;
import in.koreatech.koin.admin.history.aop.AdminActivityLogging;
import in.koreatech.koin.admin.history.enums.DomainType;
import in.koreatech.koin.admin.manager.dto.request.AdminAuthenticationStatusUpdateRequest;
import in.koreatech.koin.admin.manager.dto.request.AdminLoginRequest;
import in.koreatech.koin.admin.manager.dto.request.AdminPasswordChangeRequest;
import in.koreatech.koin.admin.manager.dto.request.AdminPermissionUpdateRequest;
Expand Down Expand Up @@ -122,10 +123,11 @@ public ResponseEntity<AdminsResponse> getAdmins(
@PutMapping("/admin/{id}/authed")
@AdminActivityLogging(domain = DomainType.ADMIN, domainIdParam = "id")
public ResponseEntity<Void> adminAuthenticate(
@RequestBody @Valid AdminAuthenticationStatusUpdateRequest request,
@PathVariable Integer id,
@Auth(permit = {ADMIN}) Integer adminId
) {
adminService.adminAuthenticate(id, adminId);
adminService.adminAuthenticate(request, id, adminId);
return ResponseEntity.ok().build();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package in.koreatech.koin.admin.manager.dto.request;

import static com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;

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

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;

@JsonNaming(value = SnakeCaseStrategy.class)
public record AdminAuthenticationStatusUpdateRequest(
@Schema(description = "인증 상태", example = "true", requiredMode = REQUIRED)
@NotNull(message = "인증 상태는 필수 입력 사항입니다.")
Boolean isAuthed
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@

@JsonNaming(value = SnakeCaseStrategy.class)
public record AdminPermissionUpdateRequest(
@Schema(description = "어드민 생성 권한", example = "false", requiredMode = REQUIRED)
@NotNull(message = "어드민 생성 권한은 필수 입력 사항입니다")
Boolean canCreateAdmin,

@Schema(description = "슈퍼 어드민 권한", example = "false", requiredMode = REQUIRED)
@NotNull(message = "슈퍼 어드민 권한은 필수 입력 사항입니다")
Boolean superAdmin
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
import static com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;

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

import in.koreatech.koin.admin.manager.enums.TeamType;
import in.koreatech.koin.admin.manager.enums.TrackType;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
Expand All @@ -19,10 +19,7 @@ public record AdminUpdateRequest(

@Schema(description = "트랙 타입", example = "BACKEND", requiredMode = REQUIRED)
@NotNull(message = "트랙 타입은 필수 입력 사항입니다.")
TrackType trackType,

@Schema(description = "팀 타입", example = "USER", requiredMode = REQUIRED)
@NotNull(message = "팀 타입은 필수 입력 사항입니다.")
TeamType teamType
@JsonProperty(value = "track_name")
TrackType trackType
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,6 @@ public record AdminResponse(
@Schema(description = "트랙 이름", example = "Backend", requiredMode = REQUIRED)
String trackName,

@Schema(description = "팀 이름", example = "User", requiredMode = REQUIRED)
String teamName,

@Schema(description = "어드민 생성 권한", example = "false", requiredMode = REQUIRED)
Boolean canCreateAdmin,

@Schema(description = "슈퍼 어드민 권한", example = "false", requiredMode = REQUIRED)
Boolean superAdmin
) {
Expand All @@ -40,8 +34,6 @@ public static AdminResponse from(Admin admin) {
admin.getEmail(),
user.getName(),
admin.getTrackType().getValue(),
admin.getTeamType().getValue(),
admin.isCanCreateAdmin(),
admin.isSuperAdmin()
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,6 @@ public record InnerAdminsResponse(
@Schema(description = "트랙 이름", example = "Backend", requiredMode = REQUIRED)
String trackName,

@Schema(description = "팀 이름", example = "User", requiredMode = REQUIRED)
String teamName,

@Schema(description = "어드민 생성 권한", example = "false", requiredMode = REQUIRED)
Boolean canCreateAdmin,

@Schema(description = "슈퍼 어드민 권한", example = "false", requiredMode = REQUIRED)
Boolean superAdmin
) {
Expand All @@ -62,8 +56,6 @@ public static InnerAdminsResponse from(Admin admin) {
admin.getEmail(),
user.getName(),
admin.getTrackType().getValue(),
admin.getTeamType().getValue(),
admin.isCanCreateAdmin(),
admin.isSuperAdmin()
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package in.koreatech.koin.admin.manager.dto.response;

import static com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy;
import static in.koreatech.koin.admin.manager.enums.TeamType.KOIN;
import static in.koreatech.koin.domain.user.model.UserType.ADMIN;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;

import org.springframework.security.crypto.password.PasswordEncoder;

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

import in.koreatech.koin.admin.manager.enums.TeamType;
import in.koreatech.koin.admin.manager.enums.TrackType;
import in.koreatech.koin.admin.manager.model.Admin;
import in.koreatech.koin.domain.user.model.User;
Expand All @@ -34,11 +35,8 @@ public record CreateAdminRequest(

@Schema(description = "트랙 타입", example = "BACKEND", requiredMode = REQUIRED)
@NotNull(message = "트랙 타입을 입력해주세요.")
TrackType trackType,

@Schema(description = "팀 타입", example = "USER", requiredMode = REQUIRED)
@NotNull(message = "팀 타입을 입력해주세요.")
TeamType teamType
@JsonProperty(value = "track_name")
TrackType trackType
) {

public Admin toAdmin(PasswordEncoder passwordEncoder) {
Expand All @@ -47,15 +45,15 @@ public Admin toAdmin(PasswordEncoder passwordEncoder) {
.loginPw(passwordEncoder.encode(password))
.name(name)
.userType(ADMIN)
.isAuthed(false)
.isAuthed(true)
.isDeleted(false)
.build();

return Admin.builder()
.email(email)
.loginId(loginId)
.trackType(trackType)
.teamType(teamType)
.teamType(KOIN)
.user(user)
.build();
}
Expand Down
24 changes: 12 additions & 12 deletions src/main/java/in/koreatech/koin/admin/manager/model/Admin.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,11 @@ public class Admin {
@Column(name = "login_id", nullable = false, unique = true, length = 30)
private String loginId;

@NotNull
@Enumerated(EnumType.STRING)
@Column(name = "team_type", nullable = false)
private TeamType teamType;

@NotNull
@Enumerated(EnumType.STRING)
@Column(name = "track_type", nullable = false)
private TrackType trackType;

@Column(name = "can_create_admin", columnDefinition = "TINYINT")
private boolean canCreateAdmin = false;

@Column(name = "super_admin", columnDefinition = "TINYINT")
private boolean superAdmin = false;

Expand All @@ -61,6 +53,16 @@ public class Admin {
@JoinColumn(name = "user_id", referencedColumnName = "id")
private User user;

// 레거시 필드

@NotNull
@Enumerated(EnumType.STRING)
@Column(name = "team_type", nullable = false)
private TeamType teamType;

@Column(name = "can_create_admin", columnDefinition = "TINYINT")
private boolean canCreateAdmin = false;

@Builder
private Admin(
Integer id,
Expand All @@ -82,14 +84,12 @@ private Admin(
this.user = user;
}

public void updateTeamTrack(TeamType teamName, TrackType trackName) {
this.teamType = teamName;
public void updateTrack(TrackType trackName) {
this.trackType = trackName;
}

/* 어드민 권한이 추가 되면, 해당 메소드에도 추가해야 합니다. */
public void updatePermission(boolean canCreateAdmin, boolean superAdmin) {
this.canCreateAdmin = canCreateAdmin;
public void updatePermission(boolean superAdmin) {
this.superAdmin = superAdmin;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

import java.time.LocalDateTime;

import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import in.koreatech.koin.admin.abtest.useragent.UserAgentInfo;
import in.koreatech.koin.admin.manager.dto.request.AdminAuthenticationStatusUpdateRequest;
import in.koreatech.koin.admin.manager.dto.request.AdminLoginRequest;
import in.koreatech.koin.admin.manager.dto.request.AdminPasswordChangeRequest;
import in.koreatech.koin.admin.manager.dto.request.AdminPermissionUpdateRequest;
Expand All @@ -23,6 +25,8 @@
import in.koreatech.koin.admin.manager.model.Admin;
import in.koreatech.koin.admin.manager.repository.AdminRepository;
import in.koreatech.koin.admin.user.repository.AdminUserRepository;
import in.koreatech.koin.common.event.AdminAuthenticationStatusChangeEvent;
import in.koreatech.koin.common.event.AdminRegisterEvent;
import in.koreatech.koin.common.model.Criteria;
import in.koreatech.koin.domain.user.model.User;
import in.koreatech.koin.domain.user.service.RefreshTokenService;
Expand All @@ -41,17 +45,24 @@ public class AdminService {
private final AdminValidation adminValidation;
private final RefreshTokenService refreshTokenService;
private final AdminUserRepository adminUserRepository;
private final ApplicationEventPublisher applicationEventPublisher;

@Transactional
public AdminResponse createAdmin(CreateAdminRequest request, Integer adminId) {
Admin admin = adminRepository.getById(adminId);
if (!admin.isCanCreateAdmin() || !admin.isSuperAdmin()) {
if (!admin.isSuperAdmin()) {
throw new AuthorizationException("어드민 계정 생성 권한이 없습니다.");
}

adminValidation.validateEmailForAdminCreated(request.email());
Admin savedAdmin = adminRepository.save(request.toAdmin(passwordEncoder));

applicationEventPublisher.publishEvent(new AdminRegisterEvent(
admin.getLoginId(),
admin.getUser().getName(),
savedAdmin.getLoginId(),
savedAdmin.getUser().getName()
));
return AdminResponse.from(savedAdmin);
}

Expand Down Expand Up @@ -106,14 +117,23 @@ public AdminsResponse getAdmins(AdminsCondition adminsCondition) {
}

@Transactional
public void adminAuthenticate(Integer id, Integer adminId) {
public void adminAuthenticate(AdminAuthenticationStatusUpdateRequest request, Integer id, Integer adminId) {
Admin admin = adminRepository.getById(adminId);
if (!admin.isSuperAdmin()) {
throw new AuthorizationException("어드민 승인 권한이 없습니다.");
}

User user = adminRepository.getById(id).getUser();
user.permitAuth();
Admin targetAdmin = adminRepository.getById(id);
User user = targetAdmin.getUser();
user.updateAuthenticationStatus(request.isAuthed());

applicationEventPublisher.publishEvent(new AdminAuthenticationStatusChangeEvent(
admin.getLoginId(),
admin.getUser().getName(),
targetAdmin.getLoginId(),
targetAdmin.getUser().getName(),
request.isAuthed()
));
}

@Transactional
Expand All @@ -122,7 +142,7 @@ public void updateAdmin(AdminUpdateRequest request, Integer id) {
User user = admin.getUser();

user.updateName(request.name());
admin.updateTeamTrack(request.teamType(), request.trackType());
admin.updateTrack(request.trackType());
}

@Transactional
Expand All @@ -132,6 +152,6 @@ public void updateAdminPermission(AdminPermissionUpdateRequest request, Integer
throw new AuthorizationException("슈퍼 어드민 권한이 없습니다.");
}

adminRepository.getById(id).updatePermission(request.canCreateAdmin(), request.superAdmin());
adminRepository.getById(id).updatePermission(request.superAdmin());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package in.koreatech.koin.common.event;

public record AdminAuthenticationStatusChangeEvent(
String changedByAdminId,
String changedByAdminName,
String targetAdminId,
String targetAdminName,
Boolean isAuthed
) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package in.koreatech.koin.common.event;

public record AdminRegisterEvent(
String creatorId,
String creatorName,
String newAdminId,
String newAdminName
) {

}
4 changes: 4 additions & 0 deletions src/main/java/in/koreatech/koin/domain/user/model/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,10 @@ public void permitAuth() {
this.isAuthed = true;
}

public void updateAuthenticationStatus(boolean isAuthed) {
this.isAuthed = isAuthed;
}

public void permitNotification(String deviceToken) {
this.deviceToken = deviceToken;
}
Expand Down
Loading
Loading