Skip to content
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 @@ -176,7 +176,7 @@ public Rsp<AppBuilderAppDto> queryLatestOrchestration(HttpClassicServerRequest h
* @return 查询结果列表。
*/
@GetMapping(value = "/{app_id}/recentPublished", description = "查询 app 的历史发布版本")
public Rsp<List<PublishedAppResDto>> recentPublished(HttpClassicServerRequest httpRequest,
public Rsp<RangedResultSet<AppBuilderAppDto>> recentPublished(HttpClassicServerRequest httpRequest,
@PathVariable("app_id") String appId, @PathVariable("tenant_id") String tenantId,
@RequestParam(value = "offset", defaultValue = "0") long offset,
@RequestParam(value = "limit", defaultValue = "10") int limit, @RequestBean AppQueryCondition cond) {
Expand Down Expand Up @@ -425,6 +425,23 @@ public Rsp<AppBuilderAppDto> importApp(HttpClassicServerRequest httpRequest,
}
}

/**
* 恢复应用到指定历史版本。
*
* @param httpRequest 表示 http 请求的 {@link HttpClassicServerRequest}。
* @param tenantId 表示租户唯一标识的 {@link String}。
* @param appId 表示应用唯一标识的 {@link String}。
* @param recoverAppId 表示指定历史版本唯一标识的 {@link String}。
* @return 表示恢复后应用信息的 {@link AppBuilderAppDto}。
*/
@CarverSpan(value = "operation.appBuilderApp.recoverApp")
@PostMapping(path = "/{app_id}/recover")
public Rsp<AppBuilderAppDto> recoverApp(HttpClassicServerRequest httpRequest,
@PathVariable("tenant_id") String tenantId, @PathVariable("app_id") String appId,
@RequestBody String recoverAppId) {
return Rsp.ok(this.appService.recoverApp(appId, recoverAppId, contextOf(httpRequest, tenantId)));
}

private AppQueryCondition buildAppQueryCondition(AppQueryCondition cond, String type) {
cond.setType(type);
if (cond.getExcludeNames() == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import modelengine.fit.jober.aipp.dto.template.TemplateAppCreateDto;
import modelengine.fit.jober.aipp.dto.template.TemplateInfoDto;
import modelengine.fit.jober.common.RangedResultSet;
import modelengine.fit.http.server.HttpClassicServerRequest;
import modelengine.fit.jane.common.entity.OperationContext;
import modelengine.fitframework.annotation.Genericable;

Expand Down Expand Up @@ -157,10 +156,10 @@ Rsp<RangedResultSet<AppBuilderAppMetadataDto>> list(AppQueryCondition cond, Oper
* @param limit 表示获取数据的最大个数的 {@code int}。
* @param appId 表示应用唯一标识的 {@link String}。
* @param context 表示操作上下文的 {@link OperationContext}。
* @return 获取到的历史版本信息集合的 {@link List}{@code <}{@link PublishedAppResDto}{@code >}。
* @return 获取到的历史版本信息集合的 {@link RangedResultSet}{@code <}{@link PublishedAppResDto}{@code >}。
*/
@Genericable(id = "modelengine.fit.jober.aipp.service.app.recent.published")
List<PublishedAppResDto> recentPublished(AppQueryCondition cond, long offset, int limit, String appId,
RangedResultSet<AppBuilderAppDto> recentPublished(AppQueryCondition cond, long offset, int limit, String appId,
OperationContext context);

/**
Expand Down Expand Up @@ -231,4 +230,15 @@ List<PublishedAppResDto> recentPublished(AppQueryCondition cond, long offset, in
*/
@Genericable(id = "modelengine.fit.jober.aipp.service.app.deleteTemplate")
void deleteTemplate(String templateId, OperationContext context);

/**
* 恢复应用到指定历史版本。
*
* @param appId 表示应用唯一标识的 {@link String}。
* @param resetId 表示指定历史版本唯一标识的 {@link String}。
* @param context 表示接口操作上下文的 {@link OperationContext}。
* @return 表示恢复应用完成后应用详情的 {@link AppBuilderAppDto}。
*/
@Genericable(id = "modelengine.fit.jober.aipp.service.app.recover")
AppBuilderAppDto recoverApp(String appId, String resetId, OperationContext context);
}
Original file line number Diff line number Diff line change
Expand Up @@ -600,15 +600,7 @@ private AppBuilderAppDto createAppWithTemplate(AppBuilderAppCreateDto dto, AppBu
AppBuilderFlowGraph flowGraph = templateApp.getFlowGraph();
flowGraph.setId(Entities.generateId());
Map<String, Object> appearance;
try {
appearance = JSONObject.parseObject(flowGraph.getAppearance(), new TypeReference<Map<String, Object>>() {});
} catch (JSONException e) {
log.error("Import config failed, cause: {}", e);
throw new AippException(AippErrCode.IMPORT_CONFIG_FIELD_ERROR, "flowGraph.appearance");
}
appearance.computeIfPresent("id", (key, value) -> flowGraph.getId());
// 这里在创建应用时需要保证graph中的title+version唯一,否则在发布flow时会报错
appearance.put("title", flowGraph.getId());
appearance = this.resetGraphId(flowGraph);
// 动态修改graph中的model为可选model的第一个
flowGraph.setAppearance(JSONObject.toJSONString(appearance));
String version = this.buildVersion(templateApp, isUpgrade);
Expand Down Expand Up @@ -1282,24 +1274,25 @@ public void deleteTemplate(String templateId, OperationContext context) {
}

@Override
public List<PublishedAppResDto> recentPublished(AppQueryCondition cond, long offset, int limit, String appId,
OperationContext context) {
public RangedResultSet<AppBuilderAppDto> recentPublished(AppQueryCondition cond, long offset, int limit,
String appId, OperationContext context) {
this.validateApp(appId);
try {
String aippId = MetaUtils.getAippIdByAppId(this.metaService, appId, context);
List<Meta> allPublishedMeta = MetaUtils.getAllPublishedMeta(this.metaService, aippId, context)
.stream()
.filter(meta -> !this.isAppBelong(appId, meta))
.collect(Collectors.toList());
RangedResultSet<Meta> metaRangedResultSet =
MetaUtils.getPublishedMetaByPage(this.metaService, aippId, offset, limit, context);
List<Meta> allPublishedMeta = metaRangedResultSet.getResults();
List<String> appIds = allPublishedMeta.stream()
.map(meta -> String.valueOf(meta.getAttributes().get(AippConst.ATTR_APP_ID_KEY)))
.collect(Collectors.toList());
cond.setIds(appIds);
cond.setTenantId(context.getTenantId());
List<AppBuilderApp> allPublishedApp = this.appRepository.selectWithCondition(cond);
Map<String, AppBuilderApp> appIdKeyAppValueMap =
allPublishedApp.stream().collect(Collectors.toMap(AppBuilderApp::getId, Function.identity()));
return this.buildPublishedAppResDtos(allPublishedMeta, appIdKeyAppValueMap);
Map<String, AppBuilderApp> appIdKeyAppValueMap = allPublishedApp.stream()
.map(app -> appFactory.create(app.getId()))
.collect(Collectors.toMap(AppBuilderApp::getId, Function.identity()));
return RangedResultSet.create(this.buildPublishedAppResDtos(allPublishedMeta, appIdKeyAppValueMap),
metaRangedResultSet.getRange());
} catch (AippTaskNotFoundException exception) {
throw new AippException(QUERY_PUBLICATION_HISTORY_FAILED);
}
Expand All @@ -1315,30 +1308,57 @@ public List<CheckResult> checkAvailable(List<AppCheckDto> appCheckDtos, Operatio
return results.stream().filter(result -> !result.isValid()).collect(Collectors.toList());
}

@Override
@Transactional
public AppBuilderAppDto recoverApp(String appId, String resetId, OperationContext context) {
AppBuilderApp resetApp = this.appFactory.create(resetId);
AppBuilderApp currentApp = this.appFactory.create(appId);
List<AppBuilderFormProperty> resetFormProperties = resetApp.getFormProperties();
List<AppBuilderFormProperty> currentFormProperties = currentApp.getFormProperties();
Map<String, AppBuilderFormProperty> currentPropMap = currentFormProperties.stream()
.collect(Collectors.toMap(AppBuilderFormProperty::getName, Function.identity()));
resetFormProperties.forEach(resetProp -> {
AppBuilderFormProperty currentProp = currentPropMap.get(resetProp.getName());
if (currentProp != null) {
currentProp.setDefaultValue(resetProp.getDefaultValue());
}
});
currentApp.getFormPropertyRepository().updateMany(currentFormProperties);

AppBuilderFlowGraph resetGraph = resetApp.getFlowGraph();
AppBuilderFlowGraph currentGraph = currentApp.getFlowGraph();
String currentGraphId = currentApp.getFlowGraphId();
resetGraph.setId(currentGraphId);

Map<String, Object> appearance;
appearance = this.resetGraphId(resetGraph);
currentGraph.setAppearance(JSONObject.toJSONString(appearance));
currentApp.getFlowGraphRepository().updateOne(currentGraph);

this.appFactory.update(currentApp);
return this.buildFullAppDto(currentApp);
}

private boolean isAppBelong(String appId, Meta meta) {
return Objects.equals(String.valueOf(meta.getAttributes().get(AippConst.ATTR_APP_ID_KEY)), appId);
}

private List<PublishedAppResDto> buildPublishedAppResDtos(List<Meta> metas,
private List<AppBuilderAppDto> buildPublishedAppResDtos(List<Meta> metas,
Map<String, AppBuilderApp> appIdKeyAppValueMap) {
return metas.stream()
.map(meta -> this.buildPublishedAppResDto(meta, appIdKeyAppValueMap))
.collect(Collectors.toList());
}

private PublishedAppResDto buildPublishedAppResDto(Meta meta, Map<String, AppBuilderApp> appIdKeyAppValueMap) {
private AppBuilderAppDto buildPublishedAppResDto(Meta meta, Map<String, AppBuilderApp> appIdKeyAppValueMap) {
String appId = String.valueOf(meta.getAttributes().get(AippConst.ATTR_APP_ID_KEY));
String publishedDescription = String.valueOf(meta.getAttributes().get(AippConst.ATTR_PUBLISH_DESCRIPTION));
String publishedUpdateLog = String.valueOf(meta.getAttributes().get(AippConst.ATTR_PUBLISH_UPDATE_LOG));
AppBuilderApp app = appIdKeyAppValueMap.get(appId);
return PublishedAppResDto.builder()
.appId(appId)
.appVersion(app.getVersion())
.publishedAt(meta.getCreationTime())
.publishedBy(meta.getCreator())
.publishedDescription(publishedDescription)
.publishedUpdateLog(publishedUpdateLog)
.build();
AppBuilderAppDto dto = this.buildFullAppDto(app);
dto.setPublishedDescription(publishedDescription);
dto.setPublishedUpdateLog(publishedUpdateLog);
return dto;
}

private static AppBuilderConfig resetConfig(List<AppBuilderFormProperty> formProperties, AppBuilderConfig config) {
Expand Down Expand Up @@ -2036,4 +2056,18 @@ private String getAttribute(Map<String, Object> attributes, String name) {
Object value = attributes.get(name);
return value == null ? StringUtils.EMPTY : String.valueOf(value);
}

private Map<String, Object> resetGraphId(AppBuilderFlowGraph flowGraph) {
Map<String, Object> appearance;
try {
appearance = JSONObject.parseObject(flowGraph.getAppearance(), new TypeReference<Map<String, Object>>() {});
} catch (JSONException e) {
log.error("Import config failed, cause: {}", e);
throw new AippException(AippErrCode.IMPORT_CONFIG_FIELD_ERROR, "flowGraph.appearance");
}
appearance.computeIfPresent("id", (key, value) -> flowGraph.getId());
// 这里在创建应用时需要保证graph中的title+version唯一,否则在发布flow时会报错
appearance.put("title", flowGraph.getId());
return appearance;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,24 @@ public static List<Meta> getAllPublishedMeta(MetaService metaService, String met
return getListMetaHandle(metaService, metaFilter, context);
}

/**
* 分页查询指定应用的已发布元数据列表,按更新时间倒序。
*
* @param metaService 表示提供元数据访问功能的 {@link MetaService}。
* @param metaId 表示指定应用唯一标识的 {@link String}。
* @param offset 表示偏移量的 {@code long}。
* @param limit 表示单页最大数量的 {@code int}。
* @param context 表示操作人上下文的 {@link OperationContext}。
* @return 表示查询到的结果集的 {@link RangedResultSet}{@code <}{@link Meta}{@code >}。
*/
public static RangedResultSet<Meta> getPublishedMetaByPage(MetaService metaService, String metaId, long offset,
int limit, OperationContext context) {
MetaFilter metaFilter = getNormalMetaFilter(metaId, NormalFilterEnum.PUBLISHED);
metaFilter.setOrderBys(Collections.singletonList(formatSorter(AippSortKeyEnum.UPDATE_AT.name(),
DirectionEnum.DESCEND.name())));
return metaService.list(metaFilter, false, offset, limit, context);
}

/**
* 查询指定aippId所有预览{@link Meta}, 按更新时间倒序
*
Expand Down
Loading