Skip to content

Commit 86fa678

Browse files
dragonpooludomikula
authored andcommitted
Added slug to organization and application
1 parent 4a06cc4 commit 86fa678

File tree

17 files changed

+154
-31
lines changed

17 files changed

+154
-31
lines changed

server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/model/Application.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,11 @@
33

44
import com.fasterxml.jackson.annotation.JsonIgnore;
55
import com.fasterxml.jackson.annotation.JsonProperty;
6-
import com.github.f4b6a3.uuid.UuidCreator;
76
import lombok.Getter;
87
import lombok.NoArgsConstructor;
98
import lombok.Setter;
109
import lombok.experimental.SuperBuilder;
1110
import lombok.extern.jackson.Jacksonized;
12-
import org.apache.commons.collections4.MapUtils;
1311
import org.apache.commons.lang3.BooleanUtils;
1412
import org.lowcoder.domain.application.ApplicationUtil;
1513
import org.lowcoder.domain.application.service.ApplicationRecordService;
@@ -20,11 +18,13 @@
2018
import org.lowcoder.sdk.util.JsonUtils;
2119
import org.springframework.data.annotation.Transient;
2220
import org.springframework.data.mongodb.core.mapping.Document;
23-
import org.springframework.util.StringUtils;
2421
import reactor.core.publisher.Mono;
2522

2623
import java.time.Instant;
27-
import java.util.*;
24+
import java.util.Collections;
25+
import java.util.HashMap;
26+
import java.util.Map;
27+
import java.util.Set;
2828
import java.util.function.Supplier;
2929

3030
import static com.google.common.base.Suppliers.memoize;
@@ -39,6 +39,9 @@
3939
public class Application extends HasIdAndAuditing {
4040
@Getter
4141
private String gid;
42+
@Setter
43+
@Getter
44+
private String slug;
4245
private String organizationId;
4346
private String name;
4447
private Integer applicationType;

server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/repository/ApplicationRepository.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,6 @@ public interface ApplicationRepository extends ReactiveMongoRepository<Applicati
6767
* Find all agency applications
6868
*/
6969
Flux<Application> findByPublicToAllIsTrueAndAgencyProfileIsTrue();
70+
Mono<Boolean> existsBySlug(String slug);
71+
7072
}

server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationService.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,6 @@ public interface ApplicationService {
7373

7474
Mono<Boolean> updateLastEditedAt(String applicationId, Instant time, String visitorId);
7575
Mono<Map<String, Object>> getLiveDSLByApplicationId(String applicationId);
76+
77+
Mono<Application> updateSlug(String applicationId, String newSlug);
7678
}

server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/service/ApplicationServiceImpl.java

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,16 @@
1414
import org.lowcoder.domain.application.model.ApplicationRequestType;
1515
import org.lowcoder.domain.application.model.ApplicationStatus;
1616
import org.lowcoder.domain.application.repository.ApplicationRepository;
17-
import org.lowcoder.domain.organization.repository.OrganizationRepository;
18-
import org.lowcoder.domain.organization.service.OrgMemberService;
1917
import org.lowcoder.domain.permission.model.ResourceRole;
2018
import org.lowcoder.domain.permission.model.ResourceType;
2119
import org.lowcoder.domain.permission.service.ResourcePermissionService;
22-
import org.lowcoder.domain.query.model.LibraryQuery;
23-
import org.lowcoder.domain.query.model.LibraryQueryRecord;
24-
import org.lowcoder.domain.query.service.LibraryQueryRecordService;
2520
import org.lowcoder.domain.user.repository.UserRepository;
26-
import org.lowcoder.domain.user.service.UserService;
2721
import org.lowcoder.infra.annotation.NonEmptyMono;
2822
import org.lowcoder.infra.mongo.MongoUpsertHelper;
2923
import org.lowcoder.sdk.constants.FieldName;
3024
import org.lowcoder.sdk.exception.BizError;
3125
import org.lowcoder.sdk.exception.BizException;
3226
import org.lowcoder.sdk.models.HasIdAndAuditing;
33-
import org.springframework.beans.factory.annotation.Autowired;
3427
import org.springframework.stereotype.Service;
3528

3629
import com.google.common.collect.Lists;
@@ -353,4 +346,18 @@ public Mono<Map<String, Object>> getLiveDSLByApplicationId(String applicationId)
353346
.switchIfEmpty(findById(applicationId)
354347
.map(Application::getEditingApplicationDSL));
355348
}
349+
350+
@Override
351+
public Mono<Application> updateSlug(String applicationId, String newSlug) {
352+
return repository.existsBySlug(newSlug).flatMap(exists -> {
353+
if (exists) {
354+
return Mono.error(new BizException(BizError.DUPLICATE_ENTRY, "Slug already exists"));
355+
}
356+
return repository.findById(applicationId)
357+
.flatMap(application -> {
358+
application.setSlug(newSlug);
359+
return repository.save(application);
360+
});
361+
});
362+
}
356363
}

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

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
package org.lowcoder.domain.organization.model;
22

3-
import static java.util.Optional.ofNullable;
4-
import static org.apache.commons.lang3.ObjectUtils.firstNonNull;
5-
import static org.lowcoder.infra.util.AssetUtils.toAssetPath;
6-
7-
import java.util.*;
8-
9-
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
10-
import com.fasterxml.jackson.annotation.JsonView;
11-
import com.github.f4b6a3.uuid.UuidCreator;
3+
import com.fasterxml.jackson.annotation.JsonIgnore;
4+
import com.fasterxml.jackson.annotation.JsonProperty;
5+
import lombok.Getter;
6+
import lombok.NoArgsConstructor;
7+
import lombok.Setter;
128
import lombok.experimental.SuperBuilder;
139
import lombok.extern.jackson.Jacksonized;
1410
import org.apache.commons.lang3.builder.ToStringBuilder;
@@ -17,16 +13,14 @@
1713
import org.lowcoder.domain.mongodb.BeforeMongodbWrite;
1814
import org.lowcoder.domain.mongodb.MongodbInterceptorContext;
1915
import org.lowcoder.sdk.auth.AbstractAuthConfig;
20-
import org.lowcoder.sdk.config.JsonViews;
2116
import org.lowcoder.sdk.models.HasIdAndAuditing;
2217
import org.springframework.data.mongodb.core.mapping.Document;
2318

24-
import com.fasterxml.jackson.annotation.JsonIgnore;
25-
import com.fasterxml.jackson.annotation.JsonProperty;
19+
import java.util.*;
2620

27-
import lombok.Getter;
28-
import lombok.NoArgsConstructor;
29-
import lombok.Setter;
21+
import static java.util.Optional.ofNullable;
22+
import static org.apache.commons.lang3.ObjectUtils.firstNonNull;
23+
import static org.lowcoder.infra.util.AssetUtils.toAssetPath;
3024

3125

3226
@Getter
@@ -41,6 +35,8 @@ public class Organization extends HasIdAndAuditing implements BeforeMongodbWrite
4135
@Getter
4236
private String gid;
4337

38+
private String slug;
39+
4440
private String name;
4541

4642
private Boolean isAutoGeneratedOrganization;

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,5 @@ public interface OrganizationRepository extends ReactiveMongoRepository<Organiza
2727
Mono<Organization> findByOrganizationDomain_DomainAndState(String domain, OrganizationState state);
2828

2929
Flux<Organization> findByOrganizationDomainIsNotNull();
30+
Mono<Boolean> existsBySlug(String slug);
3031
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,6 @@ public interface OrganizationService {
4848
Mono<Organization> getByDomain();
4949

5050
Mono<Boolean> updateCommonSettings(String orgId, String key, Object value);
51+
52+
Mono<Organization> updateSlug(String organizationId, String newSlug);
5153
}

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

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
import org.lowcoder.domain.organization.repository.OrganizationRepository;
1717
import org.lowcoder.domain.user.model.User;
1818
import org.lowcoder.domain.user.repository.UserRepository;
19-
import org.lowcoder.domain.user.service.UserService;
2019
import org.lowcoder.infra.annotation.PossibleEmptyMono;
2120
import org.lowcoder.infra.mongo.MongoUpsertHelper;
2221
import org.lowcoder.sdk.config.CommonConfig;
@@ -35,10 +34,8 @@
3534
import reactor.core.publisher.Mono;
3635

3736
import java.util.Collection;
38-
import java.util.List;
3937
import java.util.Locale;
4038

41-
import static org.lowcoder.domain.authentication.AuthenticationService.DEFAULT_AUTH_CONFIG;
4239
import static org.lowcoder.domain.organization.model.OrganizationState.ACTIVE;
4340
import static org.lowcoder.domain.organization.model.OrganizationState.DELETED;
4441
import static org.lowcoder.domain.util.QueryDslUtils.fieldName;
@@ -291,4 +288,18 @@ public Mono<Boolean> updateCommonSettings(String orgId, String key, Object value
291288
private String buildCommonSettingsUpdateTimeKey(String key) {
292289
return key + "_updateTime";
293290
}
291+
292+
@Override
293+
public Mono<Organization> updateSlug(String organizationId, String newSlug) {
294+
return repository.existsBySlug(newSlug).flatMap(exists -> {
295+
if (exists) {
296+
return Mono.error(new BizException(BizError.DUPLICATE_ENTRY, "Slug already exists"));
297+
}
298+
return repository.findById(organizationId)
299+
.flatMap(organization -> {
300+
organization.setSlug(newSlug);
301+
return repository.save(organization);
302+
});
303+
});
304+
}
294305
}

server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/exception/BizError.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,9 @@ public enum BizError {
152152
BUNDLE_NOT_EXIST(500, 6402),
153153
BUNDLE_NAME_CONFLICT(500, 6403),
154154
ILLEGAL_BUNDLE_PERMISSION_ID(500, 6404),
155-
;
155+
156+
//slug 6501 - 6501
157+
DUPLICATE_ENTRY(403, 6501);
156158

157159
static {
158160
checkDuplicates(values(), BizError::getBizErrorCode);

server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationApiService.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,6 @@ Mono<Boolean> grantPermission(String applicationId,
6262

6363
// Falk: why we have request.publicToMarketplace() - but here only agencyProfile? Not from request?
6464
Mono<Boolean> setApplicationAsAgencyProfile(String applicationId, boolean agencyProfile);
65+
66+
Mono<Application> updateSlug(String applicationId, String slug);
6567
}

server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationApiServiceImpl.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,11 @@ public Mono<Boolean> setApplicationAsAgencyProfile(String applicationId, boolean
600600
(applicationId, agencyProfile));
601601
}
602602

603+
@Override
604+
public Mono<Application> updateSlug(String applicationId, String slug) {
605+
return applicationService.updateSlug(applicationId, slug);
606+
}
607+
603608
private Map<String, Object> sanitizeDsl(Map<String, Object> applicationDsl) {
604609
if (applicationDsl.get("queries") instanceof List<?> queries) {
605610
List<Map<String, Object>> list = queries.stream().map(this::doSanitizeQuery).toList();

server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationController.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package org.lowcoder.api.application;
22

3-
import io.sentry.protocol.App;
43
import lombok.RequiredArgsConstructor;
54
import org.lowcoder.api.application.view.*;
65
import org.lowcoder.api.framework.view.PageResponseView;
@@ -165,6 +164,12 @@ public Mono<ResponseView<Boolean>> updateEditState(@PathVariable String applicat
165164
.map(ResponseView::success));
166165
}
167166

167+
@Override
168+
public Mono<ResponseView<Application>> updateSlug(@PathVariable String applicationId, @RequestBody String slug) {
169+
return applicationApiService.updateSlug(applicationId, slug)
170+
.map(ResponseView::success);
171+
}
172+
168173
@Override
169174
public Mono<ResponseView<UserHomepageView>> getUserHomePage(@RequestParam(required = false, defaultValue = "0") int applicationType) {
170175
ApplicationType type = ApplicationType.fromValue(applicationType);

server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationEndpoints.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,9 @@ public Mono<ResponseView<ApplicationView>> publish(@PathVariable String applicat
146146
public Mono<ResponseView<Boolean>> updateEditState(@PathVariable String applicationId,
147147
@RequestBody UpdateEditStateRequest updateEditStateRequest);
148148

149+
@PutMapping("/{applicationId}/slug")
150+
public Mono<ResponseView<Application>> updateSlug(@PathVariable String applicationId, @RequestBody String slug);
151+
149152
@Operation(
150153
tags = TAG_APPLICATION_MANAGEMENT,
151154
operationId = "getUserHomepageApplication",

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,4 +166,10 @@ public Mono<ResponseView<Long>> getOrgApiUsageCount(String orgId, Boolean lastMo
166166
.map(ResponseView::success));
167167
}
168168

169+
@Override
170+
public Mono<ResponseView<Organization>> updateSlug(@PathVariable String orgId, @RequestBody String slug) {
171+
return organizationService.updateSlug(orgId, slug)
172+
.map(ResponseView::success);
173+
}
174+
169175
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,9 @@ public Mono<ResponseView<Boolean>> removeUserFromOrg(@PathVariable String orgId,
181181
@GetMapping("/{orgId}/api-usage")
182182
public Mono<ResponseView<Long>> getOrgApiUsageCount(@PathVariable String orgId, @RequestParam(required = false) Boolean lastMonthOnly);
183183

184+
@PutMapping("/{orgId}/slug")
185+
Mono<ResponseView<Organization>> updateSlug(@PathVariable String orgId, @RequestBody String slug);
186+
184187
public record UpdateOrgCommonSettingsRequest(String key, Object value) {
185188

186189
}

server/api-service/lowcoder-server/src/test/java/org/lowcoder/api/application/ApplicationApiServiceTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.lowcoder.domain.application.model.ApplicationStatus;
2121
import org.lowcoder.domain.application.model.ApplicationType;
2222
import org.lowcoder.domain.application.service.ApplicationService;
23+
import org.lowcoder.domain.organization.model.Organization;
2324
import org.lowcoder.domain.permission.model.ResourceHolder;
2425
import org.lowcoder.domain.permission.model.ResourceRole;
2526
import org.lowcoder.sdk.constants.FieldName;
@@ -332,4 +333,24 @@ public void testAppCreateAndRetrievalByGID() {
332333
})
333334
.verifyComplete();
334335
}
336+
337+
@Test
338+
@WithMockUser
339+
public void testUpdateSlug() {
340+
// Create a dummy application
341+
Mono<String> applicationMono = createApplication("SlugTestApp", null)
342+
.map(applicationView -> applicationView.getApplicationInfoView().getApplicationId());
343+
344+
// Assume updateSlug is performed by passing applicationId and the new slug
345+
Mono<Application> updatedApplicationMono = applicationMono
346+
.flatMap(applicationId -> applicationApiService.updateSlug(applicationId, "new-slug-value"));
347+
348+
// Verify the application updates with the new slug
349+
StepVerifier.create(updatedApplicationMono)
350+
.assertNext(application -> {
351+
Assertions.assertNotNull(application.getSlug(), "Slug should not be null");
352+
Assertions.assertEquals("new-slug-value", application.getSlug(), "Slug should be updated to 'new-slug-value'");
353+
})
354+
.verifyComplete();
355+
}
335356
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package org.lowcoder.api.service;
2+
3+
import lombok.extern.slf4j.Slf4j;
4+
import org.junit.jupiter.api.Assertions;
5+
import org.junit.jupiter.api.Test;
6+
import org.junit.jupiter.api.TestInstance;
7+
import org.lowcoder.api.common.mockuser.WithMockUser;
8+
import org.lowcoder.domain.organization.model.Organization;
9+
import org.lowcoder.domain.organization.service.OrganizationService;
10+
import org.lowcoder.sdk.models.HasIdAndAuditing;
11+
import org.springframework.boot.test.context.SpringBootTest;
12+
import org.springframework.test.context.ActiveProfiles;
13+
import reactor.core.publisher.Mono;
14+
import reactor.test.StepVerifier;
15+
16+
@SpringBootTest
17+
//@RunWith(SpringRunner.class)
18+
@ActiveProfiles("OrganizationApiServiceTest")
19+
@Slf4j(topic = "OrganizationApiServiceTest")
20+
21+
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
22+
public class OrganizationServiceTest {
23+
24+
private OrganizationService organizationService;
25+
26+
private Mono<Organization> createOrganization(String name) {
27+
Organization organization = Organization.builder()
28+
.name(name)
29+
.build();
30+
return organizationService.create(organization, "", false);
31+
}
32+
33+
@Test
34+
@WithMockUser
35+
public void testUpdateSlug() {
36+
// Create a dummy organization
37+
Mono<String> organizationMono = createOrganization("SlugTestOrganization")
38+
.map(HasIdAndAuditing::getId);
39+
40+
// Assume updateSlug is performed by passing organizationId and the new slug
41+
Mono<Organization> updatedOrganizationMono = organizationMono
42+
.flatMap(organizationId -> organizationService.updateSlug(organizationId, "new-slug-value"));
43+
44+
// Verify the organization updates with the new slug
45+
StepVerifier.create(updatedOrganizationMono)
46+
.assertNext(organization -> {
47+
Assertions.assertNotNull(organization.getSlug(), "Slug should not be null");
48+
Assertions.assertEquals("new-slug-value", organization.getSlug(), "Slug should be updated to 'new-slug-value'");
49+
})
50+
.verifyComplete();
51+
}
52+
}

0 commit comments

Comments
 (0)