Skip to content
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

Add snapshot search params to list endpoint #1236

Merged
merged 4 commits into from
Oct 17, 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
@@ -0,0 +1,23 @@
package org.lowcoder.domain.application.model;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import org.lowcoder.sdk.models.HasIdAndAuditing;
import org.springframework.data.mongodb.core.mapping.Document;

import java.util.Map;

@ToString(callSuper = true)
@Document
@Getter
@Setter
@NoArgsConstructor
public class ApplicationHistorySnapshotTS extends HasIdAndAuditing {

private String applicationId;
private Map<String, Object> dsl;
private Map<String, Object> context;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.lowcoder.domain.application.repository;

import org.lowcoder.domain.application.model.ApplicationHistorySnapshot;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.repository.Query;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.time.Instant;

@Repository
public interface ApplicationHistoryArchivedSnapshotRepository extends ReactiveMongoRepository<ApplicationHistorySnapshot, String> {

@Query(value = "{ 'applicationId': ?0, $and: [" +
"{$or: [ { 'context.operations': { $elemMatch: { 'compName': ?1 } } }, { $expr: { $eq: [?1, null] } } ]}, " +
"{$or: [ { 'dsl.settings.themeId': ?2 }, { $expr: { $eq: [?2, null] } } ] }, " +
"{$or: [ { 'createdAt': { $gte: ?3} }, { $expr: { $eq: [?3, null] } } ] }, " +
"{$or: [ { 'createdAt': { $lte: ?4} }, { $expr: { $eq: [?4, null] } } ] } " +
"]}",
fields = "{applicationId : 1, context: 1, createdBy : 1, createdAt : 1}")
Flux<ApplicationHistorySnapshot> findAllByApplicationId(String applicationId, String compName, String theme, Instant createdAtFrom, Instant createdAtTo, Pageable pageable);

Mono<Long> countByApplicationId(String applicationId);
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
package org.lowcoder.domain.application.repository;

import org.lowcoder.domain.application.model.ApplicationHistorySnapshot;
import org.lowcoder.domain.application.model.ApplicationHistorySnapshotTS;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.repository.Query;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
import org.springframework.stereotype.Repository;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.time.Instant;

@Repository
public interface ApplicationHistorySnapshotRepository extends ReactiveMongoRepository<ApplicationHistorySnapshot, String> {
public interface ApplicationHistorySnapshotRepository extends ReactiveMongoRepository<ApplicationHistorySnapshotTS, String> {

@Query(fields = "{applicationId : 1, context: 1, createdBy : 1, createdAt : 1}")
Flux<ApplicationHistorySnapshot> findAllByApplicationId(String applicationId, Pageable pageable);
@Query(value = "{ 'applicationId': ?0, $and: [" +
"{$or: [ { 'context.operations': { $elemMatch: { 'compName': ?1 } } }, { $expr: { $eq: [?1, null] } } ]}, " +
"{$or: [ { 'dsl.settings.themeId': ?2 }, { $expr: { $eq: [?2, null] } } ] }, " +
"{$or: [ { 'createdAt': { $gte: ?3} }, { $expr: { $eq: [?3, null] } } ] }, " +
"{$or: [ { 'createdAt': { $lte: ?4} }, { $expr: { $eq: [?4, null] } } ] } " +
"]}",
fields = "{applicationId : 1, context: 1, createdBy : 1, createdAt : 1}")
Flux<ApplicationHistorySnapshotTS> findAllByApplicationId(String applicationId, String compName, String theme, Instant createdAtFrom, Instant createdAtTo, Pageable pageable);

Mono<Long> countByApplicationId(String applicationId);
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
package org.lowcoder.domain.application.service;

import java.util.List;
import java.util.Map;

import org.lowcoder.domain.application.model.ApplicationHistorySnapshot;
import org.lowcoder.domain.application.model.ApplicationHistorySnapshotTS;
import org.springframework.data.domain.PageRequest;

import reactor.core.publisher.Mono;

import java.time.Instant;
import java.util.List;
import java.util.Map;

public interface ApplicationHistorySnapshotService {

Mono<Boolean> createHistorySnapshot(String applicationId, Map<String, Object> dsl, Map<String, Object> context, String userId);

Mono<List<ApplicationHistorySnapshot>> listAllHistorySnapshotBriefInfo(String applicationId, PageRequest pageRequest);
Mono<List<ApplicationHistorySnapshotTS>> listAllHistorySnapshotBriefInfo(String applicationId, String compName, String theme, Instant from, Instant to, PageRequest pageRequest);
Mono<List<ApplicationHistorySnapshot>> listAllHistorySnapshotBriefInfoArchived(String applicationId, String compName, String theme, Instant from, Instant to, PageRequest pageRequest);

Mono<Long> countByApplicationId(String applicationId);

Mono<ApplicationHistorySnapshot> getHistorySnapshotDetail(String historySnapshotId);
Mono<ApplicationHistorySnapshotTS> getHistorySnapshotDetail(String historySnapshotId);

Mono<ApplicationHistorySnapshot> getLastSnapshotByApp(String applicationId);
Mono<ApplicationHistorySnapshot> getHistorySnapshotDetailArchived(String historySnapshotId);
}
Original file line number Diff line number Diff line change
@@ -1,46 +1,53 @@
package org.lowcoder.domain.application.service.impl;

import static org.lowcoder.sdk.exception.BizError.INVALID_HISTORY_SNAPSHOT;
import static org.lowcoder.sdk.util.ExceptionUtils.deferredError;
import static org.lowcoder.sdk.util.ExceptionUtils.ofException;

import java.time.Instant;
import java.util.List;
import java.util.Map;

import lombok.RequiredArgsConstructor;
import org.lowcoder.domain.application.model.ApplicationHistorySnapshot;
import org.lowcoder.domain.application.model.ApplicationHistorySnapshotTS;
import org.lowcoder.domain.application.repository.ApplicationHistoryArchivedSnapshotRepository;
import org.lowcoder.domain.application.repository.ApplicationHistorySnapshotRepository;
import org.lowcoder.domain.application.service.ApplicationHistorySnapshotService;
import org.lowcoder.sdk.exception.BizError;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.stereotype.Service;

import reactor.core.publisher.Mono;

import java.time.Instant;
import java.util.List;
import java.util.Map;

import static org.lowcoder.sdk.exception.BizError.INVALID_HISTORY_SNAPSHOT;
import static org.lowcoder.sdk.util.ExceptionUtils.deferredError;
import static org.lowcoder.sdk.util.ExceptionUtils.ofException;

@RequiredArgsConstructor
@Service
public class ApplicationHistorySnapshotServiceImpl implements ApplicationHistorySnapshotService {

private final ApplicationHistorySnapshotRepository repository;
private final ApplicationHistoryArchivedSnapshotRepository repositoryArchived;

@Override
public Mono<Boolean> createHistorySnapshot(String applicationId, Map<String, Object> dsl, Map<String, Object> context, String userId) {
ApplicationHistorySnapshot applicationHistorySnapshot = new ApplicationHistorySnapshot();
applicationHistorySnapshot.setApplicationId(applicationId);
applicationHistorySnapshot.setDsl(dsl);
applicationHistorySnapshot.setContext(context);
return repository.save(applicationHistorySnapshot)
ApplicationHistorySnapshotTS applicationHistorySnapshotTS = new ApplicationHistorySnapshotTS();
applicationHistorySnapshotTS.setApplicationId(applicationId);
applicationHistorySnapshotTS.setDsl(dsl);
applicationHistorySnapshotTS.setContext(context);
return repository.save(applicationHistorySnapshotTS)
.thenReturn(true)
.onErrorReturn(false);
}

@Override
public Mono<List<ApplicationHistorySnapshot>> listAllHistorySnapshotBriefInfo(String applicationId, PageRequest pageRequest) {
return repository.findAllByApplicationId(applicationId, pageRequest.withSort(Direction.DESC, "id"))
public Mono<List<ApplicationHistorySnapshotTS>> listAllHistorySnapshotBriefInfo(String applicationId, String compName, String theme, Instant from, Instant to, PageRequest pageRequest) {
return repository.findAllByApplicationId(applicationId, compName, theme, from, to, pageRequest.withSort(Direction.DESC, "id"))
.collectList()
.onErrorMap(Exception.class, e -> ofException(BizError.FETCH_HISTORY_SNAPSHOT_FAILURE, "FETCH_HISTORY_SNAPSHOT_FAILURE"));
}

@Override
public Mono<List<ApplicationHistorySnapshot>> listAllHistorySnapshotBriefInfoArchived(String applicationId, String compName, String theme, Instant from, Instant to, PageRequest pageRequest) {
return repositoryArchived.findAllByApplicationId(applicationId, compName, theme, from, to, pageRequest.withSort(Direction.DESC, "id"))
.collectList()
.onErrorMap(Exception.class, e -> ofException(BizError.FETCH_HISTORY_SNAPSHOT_FAILURE, "FETCH_HISTORY_SNAPSHOT_FAILURE"));
}
Expand All @@ -54,17 +61,15 @@ public Mono<Long> countByApplicationId(String applicationId) {


@Override
public Mono<ApplicationHistorySnapshot> getHistorySnapshotDetail(String historySnapshotId) {
public Mono<ApplicationHistorySnapshotTS> getHistorySnapshotDetail(String historySnapshotId) {
return repository.findById(historySnapshotId)
.switchIfEmpty(deferredError(INVALID_HISTORY_SNAPSHOT, "INVALID_HISTORY_SNAPSHOT", historySnapshotId));
}


@Override
public Mono<ApplicationHistorySnapshot> getLastSnapshotByApp(String applicationId) {
ApplicationHistorySnapshot _default = new ApplicationHistorySnapshot();
_default.setCreatedAt(Instant.ofEpochMilli(0));
_default.setCreatedBy("");
return repository.findAllByApplicationId(applicationId, PageRequest.of(0, 1).withSort(Direction.DESC, "createdAt"))
.switchIfEmpty(Mono.just(_default)).next();
public Mono<ApplicationHistorySnapshot> getHistorySnapshotDetailArchived(String historySnapshotId) {
return repositoryArchived.findById(historySnapshotId)
.switchIfEmpty(deferredError(INVALID_HISTORY_SNAPSHOT, "INVALID_HISTORY_SNAPSHOT", historySnapshotId));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ public static class Marketplace {
@Setter
public static class Query {
private long readStructureTimeout = 15000;
private long appSnapshotKeepDuration = 30;
}

@Data
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
package org.lowcoder.api.application;

import static org.lowcoder.api.util.ViewBuilder.multiBuild;

import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.google.common.collect.ImmutableMap;
import lombok.RequiredArgsConstructor;
import org.lowcoder.api.application.view.HistorySnapshotDslView;
import org.lowcoder.api.framework.view.ResponseView;
import org.lowcoder.api.home.SessionUserService;
import org.lowcoder.api.util.Pagination;
import org.lowcoder.domain.application.model.Application;
import org.lowcoder.domain.application.model.ApplicationHistorySnapshot;
import org.lowcoder.domain.application.model.ApplicationHistorySnapshotTS;
import org.lowcoder.domain.application.service.ApplicationHistorySnapshotService;
import org.lowcoder.domain.application.service.ApplicationService;
import org.lowcoder.domain.permission.model.ResourceAction;
Expand All @@ -22,11 +18,14 @@
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;

import com.google.common.collect.ImmutableMap;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import lombok.RequiredArgsConstructor;
import reactor.core.publisher.Mono;
import static org.lowcoder.api.util.ViewBuilder.multiBuild;

@RequiredArgsConstructor
@RestController
Expand Down Expand Up @@ -55,15 +54,56 @@ public Mono<ResponseView<Boolean>> create(@RequestBody ApplicationHistorySnapsho

@Override
public Mono<ResponseView<Map<String, Object>>> listAllHistorySnapshotBriefInfo(@PathVariable String applicationId,
@RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "10") int size) {
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size,
@RequestParam String compName,
@RequestParam String theme,
@RequestParam Instant from,
@RequestParam Instant to) {

Pagination pagination = Pagination.of(page, size).check();

return sessionUserService.getVisitorId()
.delayUntil(visitor -> resourcePermissionService.checkResourcePermissionWithError(visitor, applicationId,
ResourceAction.EDIT_APPLICATIONS))
.flatMap(__ -> applicationHistorySnapshotService.listAllHistorySnapshotBriefInfo(applicationId, compName, theme, from, to, pagination.toPageRequest()))
.flatMap(snapshotList -> {
Mono<List<ApplicationHistorySnapshotBriefInfo>> snapshotBriefInfoList = multiBuild(snapshotList,
ApplicationHistorySnapshotTS::getCreatedBy,
userService::getByIds,
(applicationHistorySnapshotTS, user) -> new ApplicationHistorySnapshotBriefInfo(
applicationHistorySnapshotTS.getId(),
applicationHistorySnapshotTS.getContext(),
applicationHistorySnapshotTS.getCreatedBy(),
user.getName(),
user.getAvatarUrl(),
applicationHistorySnapshotTS.getCreatedAt().toEpochMilli()
)
);

Mono<Long> applicationHistorySnapshotCount = applicationHistorySnapshotService.countByApplicationId(applicationId);

return Mono.zip(snapshotBriefInfoList, applicationHistorySnapshotCount)
.map(tuple -> ImmutableMap.of("list", tuple.getT1(), "count", tuple.getT2()));
})
.map(ResponseView::success);
}

@Override
public Mono<ResponseView<Map<String, Object>>> listAllHistorySnapshotBriefInfoArchived(@PathVariable String applicationId,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size,
@RequestParam String compName,
@RequestParam String theme,
@RequestParam Instant from,
@RequestParam Instant to) {

Pagination pagination = Pagination.of(page, size).check();

return sessionUserService.getVisitorId()
.delayUntil(visitor -> resourcePermissionService.checkResourcePermissionWithError(visitor, applicationId,
ResourceAction.EDIT_APPLICATIONS))
.flatMap(__ -> applicationHistorySnapshotService.listAllHistorySnapshotBriefInfo(applicationId,
pagination.toPageRequest()))
.flatMap(__ -> applicationHistorySnapshotService.listAllHistorySnapshotBriefInfoArchived(applicationId, compName, theme, from, to, pagination.toPageRequest()))
.flatMap(snapshotList -> {
Mono<List<ApplicationHistorySnapshotBriefInfo>> snapshotBriefInfoList = multiBuild(snapshotList,
ApplicationHistorySnapshot::getCreatedBy,
Expand Down Expand Up @@ -93,8 +133,30 @@ public Mono<ResponseView<HistorySnapshotDslView>> getHistorySnapshotDsl(@PathVar
.delayUntil(visitor -> resourcePermissionService.checkResourcePermissionWithError(visitor, applicationId,
ResourceAction.EDIT_APPLICATIONS))
.flatMap(__ -> applicationHistorySnapshotService.getHistorySnapshotDetail(snapshotId))
.map(ApplicationHistorySnapshotTS::getDsl)
.zipWhen(applicationService::getAllDependentModulesFromDsl)
.map(tuple -> {
Map<String, Object> applicationDsl = tuple.getT1();
List<Application> dependentModules = tuple.getT2();
Map<String, Map<String, Object>> dependentModuleDsl = dependentModules.stream()
.collect(Collectors.toMap(Application::getId, Application::getLiveApplicationDsl, (a, b) -> b));
return HistorySnapshotDslView.builder()
.applicationsDsl(applicationDsl)
.moduleDSL(dependentModuleDsl)
.build();
})
.map(ResponseView::success);
}

@Override
public Mono<ResponseView<HistorySnapshotDslView>> getHistorySnapshotDslArchived(@PathVariable String applicationId,
@PathVariable String snapshotId) {
return sessionUserService.getVisitorId()
.delayUntil(visitor -> resourcePermissionService.checkResourcePermissionWithError(visitor, applicationId,
ResourceAction.EDIT_APPLICATIONS))
.flatMap(__ -> applicationHistorySnapshotService.getHistorySnapshotDetailArchived(snapshotId))
.map(ApplicationHistorySnapshot::getDsl)
.zipWhen(dsl -> applicationService.getAllDependentModulesFromDsl(dsl))
.zipWhen(applicationService::getAllDependentModulesFromDsl)
.map(tuple -> {
Map<String, Object> applicationDsl = tuple.getT1();
List<Application> dependentModules = tuple.getT2();
Expand Down
Loading
Loading