diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrgApiService.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrgApiService.java index a62ca6d75..2901aeb0d 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrgApiService.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrgApiService.java @@ -6,6 +6,7 @@ import org.lowcoder.api.usermanagement.view.OrgView; import org.lowcoder.api.usermanagement.view.UpdateOrgRequest; import org.lowcoder.api.usermanagement.view.UpdateRoleRequest; +import org.lowcoder.domain.organization.model.OrgMember; import org.lowcoder.domain.organization.model.Organization; import org.lowcoder.domain.organization.model.Organization.OrganizationCommonSettings; import org.lowcoder.infra.annotation.NonEmptyMono; @@ -23,8 +24,12 @@ public interface OrgApiService { Mono updateRoleForMember(String orgId, UpdateRoleRequest updateRoleRequest); + Mono checkVisitorAdminRole(String orgId); + Mono switchCurrentOrganizationTo(String orgId); + Mono switchCurrentOrganizationTo(String userId, String orgId); + Mono deleteLogo(String orgId); Mono uploadLogo(String orgId, Mono fileMono); diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrgApiServiceImpl.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrgApiServiceImpl.java index e155f75da..85e7c89f1 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrgApiServiceImpl.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrgApiServiceImpl.java @@ -158,7 +158,8 @@ public Mono updateRoleForMember(String orgId, UpdateRoleRequest updateR MemberRole.fromValue(updateRoleRequest.getRole()))); } - private Mono checkVisitorAdminRole(String orgId) { + @Override + public Mono checkVisitorAdminRole(String orgId) { return sessionUserService.getVisitorId() .flatMap(visitor -> orgMemberService.getOrgMember(orgId, visitor)) .filter(it -> it.getRole() == MemberRole.ADMIN || it.getRole() == MemberRole.SUPER_ADMIN) @@ -177,15 +178,18 @@ private Mono checkDeveloperCount(String orgId, String role, String userId) @Override public Mono switchCurrentOrganizationTo(String nextCurrentOrgId) { return sessionUserService.getVisitorId() - .flatMap(it -> orgMemberService.getAllActiveOrgs(it).collectList()) + .flatMap(it -> switchCurrentOrganizationTo(it, nextCurrentOrgId)); + } + + @Override + public Mono switchCurrentOrganizationTo(String userId, String nextCurrentOrgId) { + return orgMemberService.getAllActiveOrgs(userId).collectList() .defaultIfEmpty(Collections.emptyList()) .flatMap(orgMembers -> { if (!collectSet(orgMembers, OrgMember::getOrgId).contains(nextCurrentOrgId)) { return Mono.error(new BizException(BizError.INVALID_ORG_ID, "INVALID_ORG_ID")); } - String userId = orgMembers.get(0).getUserId(); - Optional previousCurrentOrgMember = orgMembers.stream() .filter(OrgMember::isCurrentOrg) .findFirst(); diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/UserController.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/UserController.java index 8fe6ef8d9..6cd8d99fd 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/UserController.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/UserController.java @@ -3,17 +3,21 @@ import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.lowcoder.api.authentication.dto.OrganizationDomainCheckResult; +import org.lowcoder.api.authentication.service.AuthenticationApiService; import org.lowcoder.api.framework.view.ResponseView; import org.lowcoder.api.home.SessionUserService; import org.lowcoder.api.home.UserHomeApiService; import org.lowcoder.api.usermanagement.view.UpdateUserRequest; import org.lowcoder.api.usermanagement.view.UserProfileView; +import org.lowcoder.domain.organization.model.MemberRole; +import org.lowcoder.domain.organization.service.OrgMemberService; import org.lowcoder.domain.user.constant.UserStatusType; import org.lowcoder.domain.user.model.User; import org.lowcoder.domain.user.model.UserDetail; import org.lowcoder.domain.user.service.UserService; import org.lowcoder.domain.user.service.UserStatusService; import org.lowcoder.sdk.config.CommonConfig; +import org.lowcoder.sdk.constants.AuthSourceConstants; import org.lowcoder.sdk.exception.BizError; import org.springframework.http.HttpStatus; import org.springframework.http.codec.multipart.Part; @@ -35,6 +39,19 @@ public class UserController implements UserEndpoints private final UserStatusService userStatusService; private final UserApiService userApiService; private final CommonConfig commonConfig; + private final AuthenticationApiService authenticationApiService; + private final OrgMemberService orgMemberService; + + @Override + public Mono> createUserAndAddToOrg(@PathVariable String orgId, CreateUserRequest request) { + return orgApiService.checkVisitorAdminRole(orgId).flatMap(__ -> + authenticationApiService.authenticateByForm(request.email(), request.password(), + AuthSourceConstants.EMAIL, true, null, orgId)) + .flatMap(authUser -> userService.createNewUserByAuthUser(authUser, false)) + .delayUntil(user -> orgMemberService.tryAddOrgMember(orgId, user.getId(), MemberRole.MEMBER)) + .delayUntil(user -> orgApiService.switchCurrentOrganizationTo(user.getId(), orgId)) + .map(ResponseView::success); + } @Override public Mono> getUserProfile(ServerWebExchange exchange) { @@ -67,19 +84,27 @@ public Mono> markStatus(@RequestBody MarkUserStatusRequest @Override public Mono> update(@RequestBody UpdateUserRequest updateUserRequest, ServerWebExchange exchange) { return sessionUserService.getVisitorId() - .flatMap(uid -> { - User updateUser = new User(); - if (StringUtils.isNotBlank(updateUserRequest.getName())) { - updateUser.setName(updateUserRequest.getName()); - updateUser.setHasSetNickname(true); - } - if (StringUtils.isNotBlank(updateUserRequest.getUiLanguage())) { - updateUser.setUiLanguage(updateUserRequest.getUiLanguage()); - } - return userService.update(uid, updateUser); - }) - .flatMap(user -> userHomeApiService.buildUserProfileView(user, exchange)) - .map(ResponseView::success); + .flatMap(uid -> updateUser(uid, updateUserRequest, exchange)); + } + + @Override + public Mono> update(@PathVariable String orgId, @PathVariable String userId, @RequestBody UpdateUserRequest updateUserRequest, ServerWebExchange exchange) { + return orgApiService.checkVisitorAdminRole(orgId) + .flatMap(__ -> updateUser(userId, updateUserRequest, exchange)); + } + + public Mono> updateUser(String userId, @RequestBody UpdateUserRequest updateUserRequest, ServerWebExchange exchange) { + User updateUser = new User(); + if (StringUtils.isNotBlank(updateUserRequest.getName())) { + updateUser.setName(updateUserRequest.getName()); + updateUser.setHasSetNickname(true); + } + if (StringUtils.isNotBlank(updateUserRequest.getUiLanguage())) { + updateUser.setUiLanguage(updateUserRequest.getUiLanguage()); + } + return userService.update(userId, updateUser) + .flatMap(user -> userHomeApiService.buildUserProfileView(user, exchange)) + .map(ResponseView::success); } @Override @@ -89,6 +114,14 @@ public Mono> uploadProfilePhoto(@RequestPart("file") Mono< .map(ResponseView::success); } + @Override + public Mono> uploadProfilePhotoById(@PathVariable String orgId, @PathVariable String userId, @RequestPart("file") Mono fileMono) { + return orgApiService.checkVisitorAdminRole(orgId).flatMap(__ -> userService.findById(userId)) + .zipWith(fileMono) + .flatMap(tuple -> userService.saveProfilePhoto(tuple.getT2(), tuple.getT1())) + .map(ResponseView::success); + } + @Override public Mono> deleteProfilePhoto() { return sessionUserService.getVisitor() @@ -96,6 +129,13 @@ public Mono> deleteProfilePhoto() { .map(ResponseView::success)); } + @Override + public Mono> deleteProfilePhotoById(@PathVariable String orgId, @PathVariable String userId) { + return orgApiService.checkVisitorAdminRole(orgId).flatMap(__ -> userService.findById(userId)) + .flatMap(user -> userService.deleteProfilePhoto(user) + .map(ResponseView::success)); + } + @Override public Mono getProfilePhoto(ServerWebExchange exchange) { return sessionUserService.getVisitorId() diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/UserEndpoints.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/UserEndpoints.java index c58116272..2de3af919 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/UserEndpoints.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/UserEndpoints.java @@ -25,12 +25,20 @@ @RestController @RequestMapping(value = {Url.USER_URL, NewUrl.USER_URL}) -public interface UserEndpoints +public interface UserEndpoints { public static final String TAG_USER_MANAGEMENT = "User APIs"; public static final String TAG_USER_PASSWORD_MANAGEMENT = "User Password APIs"; public static final String TAG_USER_PROFILE_PHOTO_MANAGEMENT = "User Profile Photo APIs"; - + @Operation( + tags = TAG_USER_MANAGEMENT, + operationId = "createUserAndAddToOrg", + summary = "Create user and add to the org", + description = "Create a new user and add to specified organization." + ) + @PostMapping("/new/{orgId}") + public Mono> createUserAndAddToOrg(@PathVariable String orgId, @RequestBody CreateUserRequest request); + @Operation( tags = TAG_USER_MANAGEMENT, operationId = "getUserProfile", @@ -67,6 +75,15 @@ public interface UserEndpoints @PutMapping public Mono> update(@RequestBody UpdateUserRequest updateUserRequest, ServerWebExchange exchange); + @Operation( + tags = TAG_USER_MANAGEMENT, + operationId = "updateUser", + summary = "Update selected User", + description = "Update specified user profile information within Lowcoder, ensuring accuracy and relevance." + ) + @PutMapping("/{orgId}/{userId}") + public Mono> update(@PathVariable String orgId, @PathVariable String userId, @RequestBody UpdateUserRequest updateUserRequest, ServerWebExchange exchange); + @Operation( tags = TAG_USER_PROFILE_PHOTO_MANAGEMENT, operationId = "uploadUserProfilePhoto", @@ -78,12 +95,30 @@ public interface UserEndpoints @Operation( tags = TAG_USER_PROFILE_PHOTO_MANAGEMENT, - operationId = "deleteUserProfilePhoto", - summary = "Delete current users profile photo", - description = "Remove the profile Photo associated with the current User within Lowcoder." + operationId = "uploadUserProfilePhotoById", + summary = "Upload specific Users profile photo", + description = "Upload or change specific profile photo within Lowcoder for personalization." + ) + @PostMapping(value = "/photo/{orgId}/{userId}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public Mono> uploadProfilePhotoById(@PathVariable String orgId, @PathVariable String userId, @RequestPart("file") Mono fileMono); + + @Operation( + tags = TAG_USER_PROFILE_PHOTO_MANAGEMENT, + operationId = "deleteUserProfilePhotoById", + summary = "Delete specific users profile photo", + description = "Remove the profile Photo associated with the specific User within Lowcoder." ) - @DeleteMapping("/photo") - public Mono> deleteProfilePhoto(); + + @DeleteMapping("/photo/{orgId}/{userId}") + public Mono> deleteProfilePhotoById(@PathVariable String orgId, @PathVariable String userId); + @Operation( + tags = TAG_USER_PROFILE_PHOTO_MANAGEMENT, + operationId = "deleteUserProfilePhoto", + summary = "Delete current users profile photo", + description = "Remove the profile Photo associated with the current User within Lowcoder." + ) + @DeleteMapping("/photo") + public Mono> deleteProfilePhoto(); @Operation( tags = TAG_USER_PROFILE_PHOTO_MANAGEMENT, @@ -181,4 +216,7 @@ public record UpdatePasswordRequest(String oldPassword, String newPassword) { public record MarkUserStatusRequest(String type, Object value) { } + public record CreateUserRequest(String email, String password) { + } + }