Skip to content

Commit 1b820ca

Browse files
aq-ikhwa-techludomikula
authored andcommitted
Add support for SUPER_ADMIN role
1 parent f3358b5 commit 1b820ca

File tree

20 files changed

+170
-29
lines changed

20 files changed

+170
-29
lines changed

server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/group/model/GroupMember.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ public boolean isAdmin() {
3636
return role == MemberRole.ADMIN;
3737
}
3838

39+
public boolean isSuperAdmin() {
40+
return role == MemberRole.SUPER_ADMIN;
41+
}
42+
43+
3944
@JsonIgnore
4045
public boolean isInvalid() {
4146
return this == NOT_EXIST || StringUtils.isBlank(groupId);

server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/organization/model/MemberRole.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
public enum MemberRole {
88

99
MEMBER("member"),
10-
ADMIN("admin");
10+
ADMIN("admin"),
11+
SUPER_ADMIN("super_admin");
1112

1213
private static final Map<String, MemberRole> VALUE_MAP;
1314

server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/organization/model/OrgMember.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ public MemberRole getRole() {
5252
return role;
5353
}
5454

55+
public boolean isSuperAdmin() {
56+
return role == MemberRole.SUPER_ADMIN;
57+
}
58+
5559
public boolean isAdmin() {
5660
return role == MemberRole.ADMIN;
5761
}

server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/organization/service/OrganizationService.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ public interface OrganizationService {
1717
@PossibleEmptyMono
1818
Mono<Organization> getOrganizationInEnterpriseMode();
1919

20-
Mono<Organization> create(Organization organization, String creatorUserId);
20+
Mono<Organization> create(Organization organization, String creatorUserId, boolean isSuperAdmin);
2121

22-
Mono<Organization> createDefault(User user);
22+
Mono<Organization> createDefault(User user, boolean isSuperAdmin);
2323

2424
Mono<Organization> getById(String id);
2525

server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/organization/service/OrganizationServiceImpl.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ public OrganizationServiceImpl(ConfigCenter configCenter) {
8686
}
8787

8888
@Override
89-
public Mono<Organization> createDefault(User user) {
89+
public Mono<Organization> createDefault(User user, boolean isSuperAdmin) {
9090
return Mono.deferContextual(contextView -> {
9191
Locale locale = getLocale(contextView);
9292
String userOrgSuffix = getMessage(locale, "USER_ORG_SUFFIX");
@@ -96,7 +96,7 @@ public Mono<Organization> createDefault(User user) {
9696
organization.setIsAutoGeneratedOrganization(true);
9797
// saas mode
9898
if (commonConfig.getWorkspace().getMode() == WorkspaceMode.SAAS) {
99-
return create(organization, user.getId());
99+
return create(organization, user.getId(), isSuperAdmin);
100100
}
101101
// enterprise mode
102102
return joinOrganizationInEnterpriseMode(user.getId())
@@ -107,7 +107,7 @@ public Mono<Organization> createDefault(User user) {
107107
OrganizationDomain organizationDomain = new OrganizationDomain();
108108
organizationDomain.setConfigs(List.of(DEFAULT_AUTH_CONFIG));
109109
organization.setOrganizationDomain(organizationDomain);
110-
return create(organization, user.getId());
110+
return create(organization, user.getId(), isSuperAdmin);
111111
});
112112
});
113113
}
@@ -145,7 +145,7 @@ private Mono<Organization> getByEnterpriseOrgId() {
145145
}
146146

147147
@Override
148-
public Mono<Organization> create(Organization organization, String creatorId) {
148+
public Mono<Organization> create(Organization organization, String creatorId, boolean isSuperAdmin) {
149149

150150
return Mono.defer(() -> {
151151
if (organization == null || StringUtils.isNotBlank(organization.getId())) {
@@ -155,19 +155,19 @@ public Mono<Organization> create(Organization organization, String creatorId) {
155155
return Mono.just(organization);
156156
})
157157
.flatMap(repository::save)
158-
.flatMap(newOrg -> onOrgCreated(creatorId, newOrg))
158+
.flatMap(newOrg -> onOrgCreated(creatorId, newOrg, isSuperAdmin))
159159
.log();
160160
}
161161

162-
private Mono<Organization> onOrgCreated(String userId, Organization newOrg) {
162+
private Mono<Organization> onOrgCreated(String userId, Organization newOrg, boolean isSuperAdmin) {
163163
return groupService.createAllUserGroup(newOrg.getId())
164164
.then(groupService.createDevGroup(newOrg.getId()))
165-
.then(setOrgAdmin(userId, newOrg))
165+
.then(setOrgAdmin(userId, newOrg, isSuperAdmin))
166166
.thenReturn(newOrg);
167167
}
168168

169-
private Mono<Boolean> setOrgAdmin(String userId, Organization newOrg) {
170-
return orgMemberService.addMember(newOrg.getId(), userId, MemberRole.ADMIN);
169+
private Mono<Boolean> setOrgAdmin(String userId, Organization newOrg, boolean isSuperAdmin) {
170+
return orgMemberService.addMember(newOrg.getId(), userId, isSuperAdmin ? MemberRole.SUPER_ADMIN : MemberRole.ADMIN);
171171
}
172172

173173
@Override

server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/permission/service/ResourcePermissionHandler.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public Mono<Map<String, List<ResourcePermission>>> getAllMatchingPermissions(Str
6161
return getOrgId(resourceIds.iterator().next())
6262
.flatMap(orgId -> orgMemberService.getOrgMember(orgId, userId))
6363
.flatMap(orgMember -> {
64-
if (orgMember.isAdmin()) {
64+
if (orgMember.isAdmin() || orgMember.isSuperAdmin()) {
6565
return Mono.just(buildAdminPermissions(resourceType, resourceIds, userId));
6666
}
6767
return getAllMatchingPermissions0(userId, orgMember.getOrgId(), resourceType, resourceIds, resourceAction);
@@ -97,7 +97,7 @@ public Mono<UserPermissionOnResourceStatus> checkUserPermissionStatusOnResource(
9797
Mono<UserPermissionOnResourceStatus> orgUserPermissionMono = getOrgId(resourceId)
9898
.flatMap(orgId -> orgMemberService.getOrgMember(orgId, userId))
9999
.flatMap(orgMember -> {
100-
if (orgMember.isAdmin()) {
100+
if (orgMember.isAdmin() || orgMember.isSuperAdmin()) {
101101
return Mono.just(UserPermissionOnResourceStatus.success(buildAdminPermission(resourceType, resourceId, userId)));
102102
}
103103
return getAllMatchingPermissions0(userId, orgMember.getOrgId(), resourceType, Collections.singleton(resourceId), resourceAction)

server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/service/UserServiceImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ protected Mono<List<Map<String, String>>> buildUserDetailGroups(String userId, O
316316
Locale locale) {
317317
String orgId = orgMember.getOrgId();
318318
Flux<Group> groups;
319-
if (orgMember.isAdmin()) {
319+
if (orgMember.isAdmin() || orgMember.isSuperAdmin()) {
320320
groups = groupService.getByOrgId(orgId).sort();
321321
} else {
322322
if (withoutDynamicGroups) {

server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/config/CommonConfig.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ public class CommonConfig {
4545
private JsExecutor jsExecutor = new JsExecutor();
4646
private Set<String> disallowedHosts = new HashSet<>();
4747
private List<String> pluginDirs = new ArrayList<>();
48+
private SuperAdmin superAdmin = new SuperAdmin();
4849

4950
public boolean isSelfHost() {
5051
return !isCloud();
@@ -152,4 +153,10 @@ public static class JsExecutor {
152153
public static class Query {
153154
private long readStructureTimeout = 15000;
154155
}
156+
157+
@Data
158+
public static class SuperAdmin {
159+
private String userName;
160+
private String password;
161+
}
155162
}

server/api-service/lowcoder-server/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,12 @@
173173
<version>4.4.0</version>
174174
</dependency>
175175

176+
<dependency>
177+
<groupId>org.passay</groupId>
178+
<artifactId>passay</artifactId>
179+
<version>1.6.3</version>
180+
</dependency>
181+
176182
<dependency>
177183
<groupId>it.ozimov</groupId>
178184
<artifactId>embedded-redis</artifactId>

server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/AuthenticationApiServiceImpl.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ public Mono<Void> loginOrRegister(AuthUser authUser, ServerWebExchange exchange,
143143
// after register
144144
.delayUntil(user -> {
145145
if (user.getIsNewUser()) {
146-
return onUserRegister(user);
146+
return onUserRegister(user, false);
147147
}
148148
return Mono.empty();
149149
})
@@ -160,7 +160,7 @@ public Mono<Void> loginOrRegister(AuthUser authUser, ServerWebExchange exchange,
160160
.then(businessEventPublisher.publishUserLoginEvent(authUser.getSource()));
161161
}
162162

163-
private Mono<User> updateOrCreateUser(AuthUser authUser) {
163+
public Mono<User> updateOrCreateUser(AuthUser authUser) {
164164
return findByAuthUser(authUser)
165165
.flatMap(findByAuthUser -> {
166166
if (findByAuthUser.userExist()) {
@@ -224,8 +224,8 @@ protected Connection getAuthConnection(AuthUser authUser, User user) {
224224
.get();
225225
}
226226

227-
protected Mono<Void> onUserRegister(User user) {
228-
return organizationService.createDefault(user).then();
227+
public Mono<Void> onUserRegister(User user, boolean isSuperAdmin) {
228+
return organizationService.createDefault(user, isSuperAdmin).then();
229229
}
230230

231231
protected Mono<Void> onUserLogin(String orgId, User user, String source) {
@@ -330,7 +330,7 @@ private Mono<Void> removeTokensByAuthId(String authId) {
330330
private Mono<Void> checkIfAdmin() {
331331
return sessionUserService.getVisitorOrgMemberCache()
332332
.flatMap(orgMember -> {
333-
if (orgMember.isAdmin()) {
333+
if (orgMember.isAdmin() || orgMember.isSuperAdmin()) {
334334
return Mono.empty();
335335
}
336336
return deferredError(BizError.NOT_AUTHORIZED, "NOT_AUTHORIZED");

server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/home/FolderApiService.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ public Flux<?> getElements(@Nullable String folderId, @Nullable ApplicationType
241241
if (folderInfoView == null) {
242242
return;
243243
}
244-
folderInfoView.setManageable(orgMember.isAdmin() || orgMember.getUserId().equals(folderInfoView.getCreateBy()));
244+
folderInfoView.setManageable(orgMember.isAdmin() || orgMember.isSuperAdmin() || orgMember.getUserId().equals(folderInfoView.getCreateBy()));
245245

246246
List<FolderInfoView> folderInfoViews = folderNode.getFolderChildren().stream().filter(FolderInfoView::isVisible).toList();
247247
folderInfoView.setSubFolders(folderInfoViews);
@@ -335,7 +335,7 @@ private Mono<Tree<ApplicationInfoView, FolderInfoView>> buildApplicationInfoView
335335
private Mono<OrgMember> checkManagePermission(String folderId) {
336336
return sessionUserService.getVisitorOrgMemberCache()
337337
.flatMap(orgMember -> {
338-
if (orgMember.isAdmin()) {
338+
if (orgMember.isAdmin() || orgMember.isSuperAdmin()) {
339339
return Mono.just(orgMember);
340340
}
341341
return isCreator(folderId)

server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/GroupApiService.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ public Mono<GroupMemberAggregateView> getGroupMembers(String groupId, int page,
5858
Mono<MemberRole> visitorRoleMono = groupAndOrgMemberInfo.flatMap(tuple -> {
5959
GroupMember groupMember = tuple.getT1();
6060
OrgMember orgMember = tuple.getT2();
61+
if (groupMember.isSuperAdmin() || orgMember.isSuperAdmin()) {
62+
return Mono.just(MemberRole.SUPER_ADMIN);
63+
}
6164
if (groupMember.isAdmin() || orgMember.isAdmin()) {
6265
return Mono.just(MemberRole.ADMIN);
6366
}
@@ -109,7 +112,7 @@ private boolean hasReadPermission(Tuple2<GroupMember, OrgMember> tuple) {
109112
private boolean hasManagePermission(Tuple2<GroupMember, OrgMember> tuple) {
110113
GroupMember groupMember = tuple.getT1();
111114
OrgMember orgMember = tuple.getT2();
112-
return groupMember.isAdmin() || orgMember.isAdmin();
115+
return groupMember.isAdmin() || orgMember.isAdmin() || groupMember.isSuperAdmin() || orgMember.isSuperAdmin();
113116
}
114117

115118
private Mono<Tuple2<GroupMember, OrgMember>> getGroupAndOrgMemberInfo(String groupId) {
@@ -175,10 +178,16 @@ public Mono<List<GroupView>> getGroups() {
175178
return sessionUserService.getVisitorOrgMemberCache()
176179
.flatMap(orgMember -> {
177180
String orgId = orgMember.getOrgId();
178-
if (orgMember.isAdmin()) {
181+
if (orgMember.isAdmin() || orgMember.isSuperAdmin()) {
182+
MemberRole memberRole;
183+
if(orgMember.isAdmin()) {
184+
memberRole = MemberRole.ADMIN;
185+
} else {
186+
memberRole = MemberRole.SUPER_ADMIN;
187+
}
179188
return groupService.getByOrgId(orgId)
180189
.sort()
181-
.flatMapSequential(group -> GroupView.from(group, MemberRole.ADMIN.getValue()))
190+
.flatMapSequential(group -> GroupView.from(group, memberRole.getValue()))
182191
.collectList();
183192
}
184193
return groupMemberService.getUserGroupMembersInOrg(orgId, orgMember.getUserId())
@@ -211,7 +220,7 @@ public Mono<Boolean> deleteGroup(String groupId) {
211220

212221
public Mono<Group> create(CreateGroupRequest createGroupRequest) {
213222
return sessionUserService.getVisitorOrgMemberCache()
214-
.filter(OrgMember::isAdmin)
223+
.filter(orgMember -> orgMember.isAdmin() || orgMember.isSuperAdmin())
215224
.switchIfEmpty(deferredError(BizError.NOT_AUTHORIZED, NOT_AUTHORIZED))
216225
.delayUntil(orgMember -> bizThresholdChecker.checkMaxGroupCount(orgMember))
217226
.flatMap(orgMember -> {

server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrgApiServiceImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ public Mono<OrgView> create(Organization organization) {
266266
return sessionUserService.getVisitorId()
267267
.delayUntil(userId -> bizThresholdChecker.checkMaxOrgCount(userId))
268268
.delayUntil(__ -> checkIfSaasMode())
269-
.flatMap(userId -> organizationService.create(organization, userId))
269+
.flatMap(userId -> organizationService.create(organization, userId, false))
270270
.map(OrgView::new);
271271
}
272272

server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrgDevChecker.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public Mono<Void> checkCurrentOrgDev() {
4444
public Mono<Boolean> isCurrentOrgDev() {
4545
return sessionUserService.getVisitorOrgMemberCache()
4646
.flatMap(orgMember -> {
47-
if (orgMember.isAdmin()) {
47+
if (orgMember.isAdmin() || orgMember.isSuperAdmin()) {
4848
return Mono.just(true);
4949
}
5050
return inDevGroup(orgMember.getOrgId(), orgMember.getUserId());

server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/UserApiService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public Mono<UserDetail> getUserDetailById(String userId) {
4646
private Mono<Void> checkAdminPermissionAndUserBelongsToCurrentOrg(String userId) {
4747
return sessionUserService.getVisitorOrgMemberCache()
4848
.flatMap(orgMember -> {
49-
if (!orgMember.isAdmin()) {
49+
if (!orgMember.isAdmin() && !orgMember.isSuperAdmin()) {
5050
return ofError(UNSUPPORTED_OPERATION, "BAD_REQUEST");
5151
}
5252
return orgMemberService.getOrgMember(orgMember.getOrgId(), userId)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package org.lowcoder.api.util;
2+
3+
import org.passay.CharacterData;
4+
import org.passay.CharacterRule;
5+
import org.passay.EnglishCharacterData;
6+
import org.passay.PasswordGenerator;
7+
8+
public class RandomPasswordGeneratorConfig {
9+
10+
public String generatePassayPassword() {
11+
PasswordGenerator gen = new PasswordGenerator();
12+
CharacterData lowerCaseChars = EnglishCharacterData.LowerCase;
13+
CharacterRule lowerCaseRule = new CharacterRule(lowerCaseChars);
14+
lowerCaseRule.setNumberOfCharacters(3);
15+
16+
CharacterData upperCaseChars = EnglishCharacterData.UpperCase;
17+
CharacterRule upperCaseRule = new CharacterRule(upperCaseChars);
18+
upperCaseRule.setNumberOfCharacters(3);
19+
20+
CharacterData digitChars = EnglishCharacterData.Digit;
21+
CharacterRule digitRule = new CharacterRule(digitChars);
22+
digitRule.setNumberOfCharacters(3);
23+
24+
25+
String password = gen.generatePassword(10, lowerCaseRule, upperCaseRule, digitRule);
26+
return password;
27+
}
28+
}

server/api-service/lowcoder-server/src/main/java/org/lowcoder/runner/migrations/DatabaseChangelog.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.lowcoder.infra.config.model.ServerConfig;
1919
import org.lowcoder.infra.eventlog.EventLog;
2020
import org.lowcoder.infra.serverlog.ServerLog;
21+
import org.lowcoder.runner.migrations.job.AddSuperAdminUser;
2122
import org.lowcoder.runner.migrations.job.CompleteAuthType;
2223
import org.lowcoder.runner.migrations.job.MigrateAuthConfigJob;
2324
import org.springframework.data.domain.Sort;
@@ -175,6 +176,11 @@ public void completeAuthType(CompleteAuthType completeAuthType) {
175176
completeAuthType.complete();
176177
}
177178

179+
@ChangeSet(order = "019", id = "add-super-admin-user", author = "")
180+
public void addSuperAdminUser(AddSuperAdminUser addSuperAdminUser) {
181+
addSuperAdminUser.addSuperAdmin();
182+
}
183+
178184
public static Index makeIndex(String... fields) {
179185
if (fields.length == 1) {
180186
return new Index(fields[0], Sort.Direction.ASC).named(fields[0]);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package org.lowcoder.runner.migrations.job;
2+
3+
public interface AddSuperAdminUser {
4+
5+
void addSuperAdmin();
6+
}

0 commit comments

Comments
 (0)