Skip to content

Commit ef20864

Browse files
committed
App version initial classes
1 parent ebdc031 commit ef20864

File tree

12 files changed

+321
-0
lines changed

12 files changed

+321
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package org.lowcoder.domain.application.model;
2+
3+
import org.apache.commons.lang.StringUtils;
4+
5+
public record ApplicationCombineId(String applicationId, String applicationRecordId) {
6+
7+
public boolean isUsingLiveRecord() {
8+
return "latest".equals(applicationRecordId);
9+
}
10+
11+
public boolean isUsingEditingRecord() {
12+
return StringUtils.isBlank(applicationRecordId) || "editing".equals(applicationRecordId);
13+
}
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package org.lowcoder.domain.application.model;
2+
3+
import lombok.Getter;
4+
import lombok.NoArgsConstructor;
5+
import lombok.experimental.SuperBuilder;
6+
import lombok.extern.jackson.Jacksonized;
7+
import org.lowcoder.sdk.models.HasIdAndAuditing;
8+
import org.springframework.data.mongodb.core.mapping.Document;
9+
10+
import java.util.Map;
11+
12+
@Document
13+
@Getter
14+
@SuperBuilder
15+
@Jacksonized
16+
@NoArgsConstructor
17+
public class ApplicationRecord extends HasIdAndAuditing {
18+
19+
private String applicationId;
20+
private String tag;
21+
private String commitMessage;
22+
private Map<String, Object> applicationDSL;
23+
24+
public long getCreateTime() {
25+
return createdAt.toEpochMilli();
26+
}
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package org.lowcoder.domain.application.repository;
2+
3+
4+
import org.lowcoder.domain.application.model.ApplicationRecord;
5+
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
6+
import org.springframework.stereotype.Repository;
7+
import reactor.core.publisher.Flux;
8+
import reactor.core.publisher.Mono;
9+
10+
import java.util.List;
11+
12+
@Repository
13+
public interface ApplicationRecordRepository extends ReactiveMongoRepository<ApplicationRecord, String> {
14+
15+
Mono<Long> deleteByApplicationId(String applicationId);
16+
17+
Flux<ApplicationRecord> findByApplicationId(String applicationId);
18+
19+
Flux<ApplicationRecord> findByApplicationIdIn(List<String> ids);
20+
21+
Mono<ApplicationRecord> findTop1ByApplicationIdOrderByCreatedAtDesc(String applicationId);
22+
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package org.lowcoder.domain.application.service;
2+
3+
import org.lowcoder.domain.application.model.ApplicationRecord;
4+
import reactor.core.publisher.Mono;
5+
6+
import java.util.List;
7+
import java.util.Map;
8+
9+
public interface ApplicationRecordService {
10+
Mono<ApplicationRecord> insert(ApplicationRecord applicationRecord);
11+
12+
Mono<List<ApplicationRecord>> getByApplicationId(String applicationId);
13+
14+
Mono<Map<String, List<ApplicationRecord>>> getByApplicationIdIn(List<String> applicationIdList);
15+
16+
Mono<ApplicationRecord> getById(String id);
17+
18+
Mono<ApplicationRecord> getLatestRecordByApplicationId(String applicationId);
19+
20+
Mono<Long> deleteAllApplicationTagByApplicationId(String applicationId);
21+
22+
Mono<Void> deleteById(String id);
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package org.lowcoder.domain.application.service;
2+
3+
import lombok.RequiredArgsConstructor;
4+
import org.lowcoder.domain.application.model.ApplicationRecord;
5+
import org.lowcoder.domain.application.repository.ApplicationRecordRepository;
6+
import org.springframework.stereotype.Service;
7+
import reactor.core.publisher.Mono;
8+
9+
import java.util.Comparator;
10+
import java.util.List;
11+
import java.util.Map;
12+
import java.util.stream.Collectors;
13+
14+
import static org.lowcoder.sdk.exception.BizError.APPLICATION_NOT_FOUND;
15+
import static org.lowcoder.sdk.util.ExceptionUtils.deferredError;
16+
17+
@RequiredArgsConstructor
18+
@Service
19+
public class ApplicationRecordServiceImpl implements ApplicationRecordService {
20+
21+
private final ApplicationRecordRepository applicationRecordRepository;
22+
23+
@Override
24+
public Mono<ApplicationRecord> insert(ApplicationRecord applicationRecord) {
25+
return applicationRecordRepository.save(applicationRecord);
26+
}
27+
28+
/**
29+
* get all published versions
30+
*/
31+
@Override
32+
public Mono<List<ApplicationRecord>> getByApplicationId(String applicationId) {
33+
return applicationRecordRepository.findByApplicationId(applicationId)
34+
.sort(Comparator.comparing(ApplicationRecord::getCreatedAt).reversed())
35+
.collectList();
36+
}
37+
38+
@Override
39+
public Mono<Map<String, List<ApplicationRecord>>> getByApplicationIdIn(List<String> applicationIdList) {
40+
return applicationRecordRepository.findByApplicationIdIn(applicationIdList)
41+
.sort(Comparator.comparing(ApplicationRecord::getCreatedAt).reversed())
42+
.collectList()
43+
.map(applicationRecords -> applicationRecords.stream()
44+
.collect(Collectors.groupingBy(ApplicationRecord::getApplicationId)));
45+
}
46+
47+
@Override
48+
public Mono<ApplicationRecord> getById(String id) {
49+
return applicationRecordRepository.findById(id)
50+
.switchIfEmpty(deferredError(APPLICATION_NOT_FOUND, "APPLICATION_NOT_FOUND"));
51+
}
52+
53+
/**
54+
* get the latest published version
55+
*/
56+
@Override
57+
public Mono<ApplicationRecord> getLatestRecordByApplicationId(String applicationId) {
58+
return applicationRecordRepository.findTop1ByApplicationIdOrderByCreatedAtDesc(applicationId);
59+
}
60+
61+
@Override
62+
public Mono<Long> deleteAllApplicationTagByApplicationId(String applicationId) {
63+
return applicationRecordRepository.deleteByApplicationId(applicationId);
64+
}
65+
66+
@Override
67+
public Mono<Void> deleteById(String id) {
68+
return applicationRecordRepository.deleteById(id);
69+
}
70+
71+
72+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,5 @@ public interface ApplicationService {
7676
Flux<Application> findAll();
7777

7878
Mono<Boolean> updateLastEditedAt(String applicationId, Instant time, String visitorId);
79+
Mono<Map<String, Object>> getLiveDSLByApplicationId(String applicationId);
7980
}

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
import org.lowcoder.domain.permission.model.ResourceRole;
1919
import org.lowcoder.domain.permission.model.ResourceType;
2020
import org.lowcoder.domain.permission.service.ResourcePermissionService;
21+
import org.lowcoder.domain.query.model.LibraryQuery;
22+
import org.lowcoder.domain.query.model.LibraryQueryRecord;
23+
import org.lowcoder.domain.query.service.LibraryQueryRecordService;
2124
import org.lowcoder.domain.user.repository.UserRepository;
2225
import org.lowcoder.domain.user.service.UserService;
2326
import org.lowcoder.infra.annotation.NonEmptyMono;
@@ -45,6 +48,7 @@ public class ApplicationServiceImpl implements ApplicationService {
4548
private final ResourcePermissionService resourcePermissionService;
4649
private final ApplicationRepository repository;
4750
private final UserRepository userRepository;
51+
private final LibraryQueryRecordService applicationRecordService;
4852

4953
@Override
5054
public Mono<Application> findById(String id) {
@@ -355,4 +359,12 @@ public Mono<Boolean> updateLastEditedAt(String applicationId, Instant time, Stri
355359
.flatMap(repository::save)
356360
.hasElements();
357361
}
362+
363+
@Override
364+
public Mono<Map<String, Object>> getLiveDSLByApplicationId(String applicationId) {
365+
return applicationRecordService.getLatestRecordByLibraryQueryId(applicationId)
366+
.map(LibraryQueryRecord::getLibraryQueryDSL)
367+
.switchIfEmpty(findById(applicationId)
368+
.map(Application::getPublishedApplicationDSL));
369+
}
358370
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ public enum BizError {
6363
INVALID_HISTORY_SNAPSHOT(500, 5307),
6464

6565
NO_PERMISSION_TO_REQUEST_APP(403, 5308),
66+
APPLICATION_AND_ORG_NOT_MATCH(400, 5309),
6667

6768
// datasource related, code range 5500 - 5600
6869
DATASOURCE_NOT_FOUND(500, 5500),

server/api-service/lowcoder-sdk/src/main/resources/locale_en.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ TEMPLATE_NOT_CORRECT=Sorry, the template has some errors.
6060
EXCEED_QUERY_REQUEST_SIZE=Sorry, it exceeds query request limit size, please contact administrator.
6161
EXCEED_QUERY_RESPONSE_SIZE=Sorry, it exceeds query response limit size, please contact administrator.
6262
LIBRARY_QUERY_AND_ORG_NOT_MATCH=Query library does not match the workspace.
63+
APPLICATION_AND_ORG_NOT_MATCH=Application does not match the workspace.
6364
LIBRARY_QUERY_NOT_FOUND=Sorry, query library has no such query, please check again.
6465
INVALID_USER_STATUS=Sorry, the user status is illegal: {0}.
6566
FOLDER_OPERATE_NO_PERMISSION=Oops! It appears you don''t have operation permissions of the folder.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.lowcoder.api.application;
2+
3+
import org.lowcoder.api.application.view.ApplicationRecordMetaView;
4+
import org.lowcoder.domain.application.model.ApplicationCombineId;
5+
import reactor.core.publisher.Mono;
6+
7+
import java.util.List;
8+
import java.util.Map;
9+
10+
public interface ApplicationRecordApiService {
11+
Mono<Map<String, Object>> getRecordDSLFromApplicationCombineId(ApplicationCombineId applicationCombineId);
12+
13+
Mono<Void> delete(String id);
14+
15+
Mono<List<ApplicationRecordMetaView>> getByApplicationId(String applicationId);
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package org.lowcoder.api.application;
2+
3+
import lombok.RequiredArgsConstructor;
4+
import org.lowcoder.api.home.SessionUserService;
5+
import org.lowcoder.api.application.ApplicationApiServiceImpl;
6+
import org.lowcoder.api.application.view.ApplicationRecordMetaView;
7+
import org.lowcoder.api.usermanagement.OrgDevChecker;
8+
import org.lowcoder.domain.organization.model.OrgMember;
9+
import org.lowcoder.domain.application.model.Application;
10+
import org.lowcoder.domain.application.model.ApplicationCombineId;
11+
import org.lowcoder.domain.application.model.ApplicationRecord;
12+
import org.lowcoder.domain.application.service.ApplicationRecordService;
13+
import org.lowcoder.domain.application.service.ApplicationService;
14+
import org.lowcoder.domain.user.service.UserService;
15+
import org.springframework.stereotype.Service;
16+
import reactor.core.publisher.Mono;
17+
18+
import java.util.List;
19+
import java.util.Map;
20+
21+
import static org.lowcoder.api.util.ViewBuilder.multiBuild;
22+
import static org.lowcoder.sdk.exception.BizError.APPLICATION_AND_ORG_NOT_MATCH;
23+
import static org.lowcoder.sdk.util.ExceptionUtils.ofError;
24+
25+
@RequiredArgsConstructor
26+
@Service
27+
public class ApplicationRecordApiServiceImpl implements ApplicationRecordApiService {
28+
29+
private final ApplicationService applicationService;
30+
private final ApplicationRecordService applicationRecordService;
31+
private final ApplicationApiServiceImpl applicationApiService;
32+
private final SessionUserService sessionUserService;
33+
private final OrgDevChecker orgDevChecker;
34+
private final UserService userService;
35+
36+
@Override
37+
public Mono<Map<String, Object>> getRecordDSLFromApplicationCombineId(ApplicationCombineId applicationCombineId) {
38+
return checkApplicationRecordViewPermission(applicationCombineId)
39+
.then(Mono.defer(() -> {
40+
if (applicationCombineId.isUsingLiveRecord()) {
41+
return applicationService.getLiveDSLByApplicationId(applicationCombineId.applicationId());
42+
}
43+
return applicationRecordService.getById(applicationCombineId.applicationRecordId())
44+
.map(ApplicationRecord::getApplicationDSL);
45+
}));
46+
}
47+
48+
@Override
49+
public Mono<Void> delete(String id) {
50+
return checkApplicationRecordManagementPermission(id)
51+
.then(applicationRecordService.deleteById(id));
52+
}
53+
54+
@Override
55+
public Mono<List<ApplicationRecordMetaView>> getByApplicationId(String applicationId) {
56+
return applicationRecordService.getByApplicationId(applicationId)
57+
.flatMap(applicationRecords -> multiBuild(applicationRecords,
58+
ApplicationRecord::getCreatedBy,
59+
userService::getByIds,
60+
ApplicationRecordMetaView::from
61+
));
62+
}
63+
64+
65+
Mono<Void> checkApplicationRecordManagementPermission(String applicationRecordId) {
66+
return orgDevChecker.checkCurrentOrgDev()
67+
.then(sessionUserService.getVisitorOrgMemberCache())
68+
.zipWith(applicationRecordService.getById(applicationRecordId)
69+
.flatMap(applicationRecord -> applicationService.findById(applicationRecord.getApplicationId())))
70+
.flatMap(tuple2 -> {
71+
OrgMember orgMember = tuple2.getT1();
72+
Application application = tuple2.getT2();
73+
if (!orgMember.getOrgId().equals(application.getOrganizationId())) {
74+
return ofError(APPLICATION_AND_ORG_NOT_MATCH, "APPLICATION_AND_ORG_NOT_MATCH");
75+
}
76+
return Mono.empty();
77+
});
78+
}
79+
80+
Mono<Void> checkApplicationRecordViewPermission(ApplicationCombineId applicationCombineId) {
81+
return sessionUserService.getVisitorOrgMemberCache()
82+
.zipWith(Mono.defer(() -> {
83+
if (applicationCombineId.isUsingLiveRecord()) {
84+
return applicationService.findById(applicationCombineId.applicationId());
85+
}
86+
return applicationRecordService.getById(applicationCombineId.applicationRecordId())
87+
.flatMap(applicationRecord -> applicationService.findById(applicationRecord.getApplicationId()));
88+
89+
}))
90+
.flatMap(tuple2 -> {
91+
OrgMember orgMember = tuple2.getT1();
92+
Application application = tuple2.getT2();
93+
if (!orgMember.getOrgId().equals(application.getOrganizationId())) {
94+
return ofError(APPLICATION_AND_ORG_NOT_MATCH, "APPLICATION_AND_ORG_NOT_MATCH");
95+
}
96+
return Mono.empty();
97+
});
98+
}
99+
100+
101+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package org.lowcoder.api.application.view;
2+
3+
import org.lowcoder.domain.application.model.ApplicationRecord;
4+
import org.lowcoder.domain.user.model.User;
5+
6+
public record ApplicationRecordMetaView(String id,
7+
String applicationId,
8+
String tag,
9+
String commitMessage,
10+
long createTime,
11+
String creatorName) {
12+
13+
public static ApplicationRecordMetaView from(ApplicationRecord applicationRecord) {
14+
return new ApplicationRecordMetaView(applicationRecord.getId(),
15+
applicationRecord.getApplicationId(),
16+
applicationRecord.getTag(),
17+
applicationRecord.getCommitMessage(),
18+
applicationRecord.getCreatedAt().toEpochMilli(),
19+
null);
20+
}
21+
22+
public static ApplicationRecordMetaView from(ApplicationRecord applicationRecord, User applicationRecordCreator) {
23+
return new ApplicationRecordMetaView(applicationRecord.getId(),
24+
applicationRecord.getApplicationId(),
25+
applicationRecord.getTag(),
26+
applicationRecord.getCommitMessage(),
27+
applicationRecord.getCreatedAt().toEpochMilli(),
28+
applicationRecordCreator.getName());
29+
}
30+
}

0 commit comments

Comments
 (0)