Skip to content

Add slug to application and organization #1401

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 20, 2024
Merged
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 @@ -3,13 +3,11 @@

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.github.f4b6a3.uuid.UuidCreator;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.SuperBuilder;
import lombok.extern.jackson.Jacksonized;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.lowcoder.domain.application.ApplicationUtil;
import org.lowcoder.domain.application.service.ApplicationRecordService;
Expand All @@ -20,11 +18,13 @@
import org.lowcoder.sdk.util.JsonUtils;
import org.springframework.data.annotation.Transient;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.util.StringUtils;
import reactor.core.publisher.Mono;

import java.time.Instant;
import java.util.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;

import static com.google.common.base.Suppliers.memoize;
Expand All @@ -39,6 +39,9 @@
public class Application extends HasIdAndAuditing {
@Getter
private String gid;
@Setter
@Getter
private String slug;
private String organizationId;
private String name;
private Integer applicationType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,6 @@ public interface ApplicationRepository extends ReactiveMongoRepository<Applicati
* Find all agency applications
*/
Flux<Application> findByPublicToAllIsTrueAndAgencyProfileIsTrue();
Mono<Boolean> existsBySlug(String slug);

}
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,6 @@ public interface ApplicationService {

Mono<Boolean> updateLastEditedAt(String applicationId, Instant time, String visitorId);
Mono<Map<String, Object>> getLiveDSLByApplicationId(String applicationId);

Mono<Application> updateSlug(String applicationId, String newSlug);
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,16 @@
import org.lowcoder.domain.application.model.ApplicationRequestType;
import org.lowcoder.domain.application.model.ApplicationStatus;
import org.lowcoder.domain.application.repository.ApplicationRepository;
import org.lowcoder.domain.organization.repository.OrganizationRepository;
import org.lowcoder.domain.organization.service.OrgMemberService;
import org.lowcoder.domain.permission.model.ResourceRole;
import org.lowcoder.domain.permission.model.ResourceType;
import org.lowcoder.domain.permission.service.ResourcePermissionService;
import org.lowcoder.domain.query.model.LibraryQuery;
import org.lowcoder.domain.query.model.LibraryQueryRecord;
import org.lowcoder.domain.query.service.LibraryQueryRecordService;
import org.lowcoder.domain.user.repository.UserRepository;
import org.lowcoder.domain.user.service.UserService;
import org.lowcoder.infra.annotation.NonEmptyMono;
import org.lowcoder.infra.mongo.MongoUpsertHelper;
import org.lowcoder.sdk.constants.FieldName;
import org.lowcoder.sdk.exception.BizError;
import org.lowcoder.sdk.exception.BizException;
import org.lowcoder.sdk.models.HasIdAndAuditing;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.google.common.collect.Lists;
Expand Down Expand Up @@ -353,4 +346,18 @@ public Mono<Map<String, Object>> getLiveDSLByApplicationId(String applicationId)
.switchIfEmpty(findById(applicationId)
.map(Application::getEditingApplicationDSL));
}

@Override
public Mono<Application> updateSlug(String applicationId, String newSlug) {
return repository.existsBySlug(newSlug).flatMap(exists -> {
if (exists) {
return Mono.error(new BizException(BizError.DUPLICATE_ENTRY, "Slug already exists"));
}
return repository.findById(applicationId)
.flatMap(application -> {
application.setSlug(newSlug);
return repository.save(application);
});
});
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
package org.lowcoder.domain.organization.model;

import static java.util.Optional.ofNullable;
import static org.apache.commons.lang3.ObjectUtils.firstNonNull;
import static org.lowcoder.infra.util.AssetUtils.toAssetPath;

import java.util.*;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonView;
import com.github.f4b6a3.uuid.UuidCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.SuperBuilder;
import lombok.extern.jackson.Jacksonized;
import org.apache.commons.lang3.builder.ToStringBuilder;
Expand All @@ -17,16 +13,14 @@
import org.lowcoder.domain.mongodb.BeforeMongodbWrite;
import org.lowcoder.domain.mongodb.MongodbInterceptorContext;
import org.lowcoder.sdk.auth.AbstractAuthConfig;
import org.lowcoder.sdk.config.JsonViews;
import org.lowcoder.sdk.models.HasIdAndAuditing;
import org.springframework.data.mongodb.core.mapping.Document;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.*;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import static java.util.Optional.ofNullable;
import static org.apache.commons.lang3.ObjectUtils.firstNonNull;
import static org.lowcoder.infra.util.AssetUtils.toAssetPath;


@Getter
Expand All @@ -41,6 +35,8 @@ public class Organization extends HasIdAndAuditing implements BeforeMongodbWrite
@Getter
private String gid;

private String slug;

private String name;

private Boolean isAutoGeneratedOrganization;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,5 @@ public interface OrganizationRepository extends ReactiveMongoRepository<Organiza
Mono<Organization> findByOrganizationDomain_DomainAndState(String domain, OrganizationState state);

Flux<Organization> findByOrganizationDomainIsNotNull();
Mono<Boolean> existsBySlug(String slug);
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,6 @@ public interface OrganizationService {
Mono<Organization> getByDomain();

Mono<Boolean> updateCommonSettings(String orgId, String key, Object value);

Mono<Organization> updateSlug(String organizationId, String newSlug);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import org.lowcoder.domain.organization.repository.OrganizationRepository;
import org.lowcoder.domain.user.model.User;
import org.lowcoder.domain.user.repository.UserRepository;
import org.lowcoder.domain.user.service.UserService;
import org.lowcoder.infra.annotation.PossibleEmptyMono;
import org.lowcoder.infra.mongo.MongoUpsertHelper;
import org.lowcoder.sdk.config.CommonConfig;
Expand All @@ -35,10 +34,8 @@
import reactor.core.publisher.Mono;

import java.util.Collection;
import java.util.List;
import java.util.Locale;

import static org.lowcoder.domain.authentication.AuthenticationService.DEFAULT_AUTH_CONFIG;
import static org.lowcoder.domain.organization.model.OrganizationState.ACTIVE;
import static org.lowcoder.domain.organization.model.OrganizationState.DELETED;
import static org.lowcoder.domain.util.QueryDslUtils.fieldName;
Expand Down Expand Up @@ -291,4 +288,18 @@ public Mono<Boolean> updateCommonSettings(String orgId, String key, Object value
private String buildCommonSettingsUpdateTimeKey(String key) {
return key + "_updateTime";
}

@Override
public Mono<Organization> updateSlug(String organizationId, String newSlug) {
return repository.existsBySlug(newSlug).flatMap(exists -> {
if (exists) {
return Mono.error(new BizException(BizError.DUPLICATE_ENTRY, "Slug already exists"));
}
return repository.findById(organizationId)
.flatMap(organization -> {
organization.setSlug(newSlug);
return repository.save(organization);
});
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,9 @@ public enum BizError {
BUNDLE_NOT_EXIST(500, 6402),
BUNDLE_NAME_CONFLICT(500, 6403),
ILLEGAL_BUNDLE_PERMISSION_ID(500, 6404),
;

//slug 6501 - 6501
DUPLICATE_ENTRY(403, 6501);

static {
checkDuplicates(values(), BizError::getBizErrorCode);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,6 @@ Mono<Boolean> grantPermission(String applicationId,

// Falk: why we have request.publicToMarketplace() - but here only agencyProfile? Not from request?
Mono<Boolean> setApplicationAsAgencyProfile(String applicationId, boolean agencyProfile);

Mono<Application> updateSlug(String applicationId, String slug);
}
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,11 @@ public Mono<Boolean> setApplicationAsAgencyProfile(String applicationId, boolean
(applicationId, agencyProfile));
}

@Override
public Mono<Application> updateSlug(String applicationId, String slug) {
return applicationService.updateSlug(applicationId, slug);
}

private Map<String, Object> sanitizeDsl(Map<String, Object> applicationDsl) {
if (applicationDsl.get("queries") instanceof List<?> queries) {
List<Map<String, Object>> list = queries.stream().map(this::doSanitizeQuery).toList();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.lowcoder.api.application;

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

@Override
public Mono<ResponseView<Application>> updateSlug(@PathVariable String applicationId, @RequestBody String slug) {
return applicationApiService.updateSlug(applicationId, slug)
.map(ResponseView::success);
}

@Override
public Mono<ResponseView<UserHomepageView>> getUserHomePage(@RequestParam(required = false, defaultValue = "0") int applicationType) {
ApplicationType type = ApplicationType.fromValue(applicationType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@ public Mono<ResponseView<ApplicationView>> publish(@PathVariable String applicat
public Mono<ResponseView<Boolean>> updateEditState(@PathVariable String applicationId,
@RequestBody UpdateEditStateRequest updateEditStateRequest);

@PutMapping("/{applicationId}/slug")
public Mono<ResponseView<Application>> updateSlug(@PathVariable String applicationId, @RequestBody String slug);

@Operation(
tags = TAG_APPLICATION_MANAGEMENT,
operationId = "getUserHomepageApplication",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,4 +166,10 @@ public Mono<ResponseView<Long>> getOrgApiUsageCount(String orgId, Boolean lastMo
.map(ResponseView::success));
}

@Override
public Mono<ResponseView<Organization>> updateSlug(@PathVariable String orgId, @RequestBody String slug) {
return organizationService.updateSlug(orgId, slug)
.map(ResponseView::success);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,9 @@ public Mono<ResponseView<Boolean>> removeUserFromOrg(@PathVariable String orgId,
@GetMapping("/{orgId}/api-usage")
public Mono<ResponseView<Long>> getOrgApiUsageCount(@PathVariable String orgId, @RequestParam(required = false) Boolean lastMonthOnly);

@PutMapping("/{orgId}/slug")
Mono<ResponseView<Organization>> updateSlug(@PathVariable String orgId, @RequestBody String slug);

public record UpdateOrgCommonSettingsRequest(String key, Object value) {

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.lowcoder.domain.application.model.ApplicationStatus;
import org.lowcoder.domain.application.model.ApplicationType;
import org.lowcoder.domain.application.service.ApplicationService;
import org.lowcoder.domain.organization.model.Organization;
import org.lowcoder.domain.permission.model.ResourceHolder;
import org.lowcoder.domain.permission.model.ResourceRole;
import org.lowcoder.sdk.constants.FieldName;
Expand Down Expand Up @@ -324,4 +325,24 @@ public void testAppCreateAndRetrievalByGID() {
})
.verifyComplete();
}

@Test
@WithMockUser
public void testUpdateSlug() {
// Create a dummy application
Mono<String> applicationMono = createApplication("SlugTestApp", null)
.map(applicationView -> applicationView.getApplicationInfoView().getApplicationId());

// Assume updateSlug is performed by passing applicationId and the new slug
Mono<Application> updatedApplicationMono = applicationMono
.flatMap(applicationId -> applicationApiService.updateSlug(applicationId, "new-slug-value"));

// Verify the application updates with the new slug
StepVerifier.create(updatedApplicationMono)
.assertNext(application -> {
Assertions.assertNotNull(application.getSlug(), "Slug should not be null");
Assertions.assertEquals("new-slug-value", application.getSlug(), "Slug should be updated to 'new-slug-value'");
})
.verifyComplete();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package org.lowcoder.api.service;

import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.lowcoder.api.common.mockuser.WithMockUser;
import org.lowcoder.domain.organization.model.Organization;
import org.lowcoder.domain.organization.service.OrganizationService;
import org.lowcoder.sdk.models.HasIdAndAuditing;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;

@SpringBootTest
//@RunWith(SpringRunner.class)
@ActiveProfiles("OrganizationApiServiceTest")
@Slf4j(topic = "OrganizationApiServiceTest")

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class OrganizationServiceTest {

@Autowired
private OrganizationService organizationService;

private Mono<Organization> createOrganization(String name) {
Organization organization = Organization.builder()
.name(name)
.build();
return organizationService.create(organization, "user01", false);
}

@Test
@WithMockUser
public void testUpdateSlug() {
// Create a dummy organization
Mono<String> organizationMono = createOrganization("SlugTestOrganization")
.map(HasIdAndAuditing::getId);

// Assume updateSlug is performed by passing organizationId and the new slug
Mono<Organization> updatedOrganizationMono = organizationMono
.flatMap(organizationId -> organizationService.updateSlug(organizationId, "new-slug-value"));

// Verify the organization updates with the new slug
StepVerifier.create(updatedOrganizationMono)
.assertNext(organization -> {
Assertions.assertNotNull(organization.getSlug(), "Slug should not be null");
Assertions.assertEquals("new-slug-value", organization.getSlug(), "Slug should be updated to 'new-slug-value'");
})
.verifyComplete();
}
}
Loading