feat(review): add backward compatibility for DRAFT status

Support both DRAFT (legacy) and UPLOADED (new flow) status in:
- SkillReviewSubmitService.submitForReview
- SkillReviewSubmitService.confirmPublish
- ReviewService.submitReview (both overloads)

This ensures existing data with DRAFT status continues to work
with the new visibility-based workflow introduced in OSS-02.
This commit is contained in:
xiose 2026-04-13 09:55:41 +08:00
parent f55c520ebe
commit f70d09aac7
3 changed files with 76 additions and 14 deletions

View file

@ -101,7 +101,9 @@ public class ReviewService {
throw new DomainForbiddenException("review.submit.no_permission");
}
if (skillVersion.getStatus() != SkillVersionStatus.DRAFT) {
// Support both DRAFT (legacy) and UPLOADED (new flow) status
if (skillVersion.getStatus() != SkillVersionStatus.DRAFT
&& skillVersion.getStatus() != SkillVersionStatus.UPLOADED) {
throw new DomainBadRequestException("review.submit.not_draft", skillVersionId);
}
@ -137,7 +139,9 @@ public class ReviewService {
.orElseThrow(() -> new DomainNotFoundException("namespace.not_found", skill.getNamespaceId()));
assertNamespaceActive(namespace);
if (skillVersion.getStatus() != SkillVersionStatus.DRAFT) {
// Support both DRAFT (legacy) and UPLOADED (new flow) status
if (skillVersion.getStatus() != SkillVersionStatus.DRAFT
&& skillVersion.getStatus() != SkillVersionStatus.UPLOADED) {
throw new DomainBadRequestException("review.submit.not_draft", skillVersionId);
}

View file

@ -55,8 +55,10 @@ public class SkillReviewSubmitService {
}
/**
* Submit an UPLOADED version for review.
* Transitions version status from UPLOADED to PENDING_REVIEW.
* Submit an UPLOADED or DRAFT version for review.
* Transitions version status from UPLOADED/DRAFT to PENDING_REVIEW.
*
* <p>Supports both UPLOADED (new flow) and DRAFT (legacy compatibility) status.
*
* @param skillId the skill ID
* @param versionId the version ID
@ -75,8 +77,9 @@ public class SkillReviewSubmitService {
// Validate ownership
assertCanManageLifecycle(skill, actorUserId, userNamespaceRoles);
// Validate version status
if (version.getStatus() != SkillVersionStatus.UPLOADED) {
// Validate version status - support both UPLOADED (new) and DRAFT (legacy)
if (version.getStatus() != SkillVersionStatus.UPLOADED
&& version.getStatus() != SkillVersionStatus.DRAFT) {
throw new DomainBadRequestException("error.skill.version.submit.notUploaded", version.getVersion());
}
@ -97,7 +100,9 @@ public class SkillReviewSubmitService {
/**
* Confirm publish for a PRIVATE skill version.
* Transitions version status from UPLOADED to PUBLISHED without review.
* Transitions version status from UPLOADED/DRAFT to PUBLISHED without review.
*
* <p>Supports both UPLOADED (new flow) and DRAFT (legacy compatibility) status.
*
* @param skillId the skill ID
* @param versionId the version ID
@ -120,8 +125,9 @@ public class SkillReviewSubmitService {
throw new DomainBadRequestException("error.skill.confirm.notPrivate");
}
// Validate version status
if (version.getStatus() != SkillVersionStatus.UPLOADED) {
// Validate version status - support both UPLOADED (new) and DRAFT (legacy)
if (version.getStatus() != SkillVersionStatus.UPLOADED
&& version.getStatus() != SkillVersionStatus.DRAFT) {
throw new DomainBadRequestException("error.skill.version.confirm.notUploaded", version.getVersion());
}

View file

@ -88,15 +88,42 @@ class SkillReviewSubmitServiceTest {
}
@Test
@DisplayName("should reject when version is not UPLOADED")
void shouldRejectWhenNotUploaded() {
@DisplayName("should accept DRAFT version (legacy compatibility)")
void shouldAcceptDraftForLegacyCompatibility() {
// Given
Long skillId = 1L;
Long versionId = 100L;
String userId = "user-1";
Long namespaceId = 10L;
Skill skill = createSkill(skillId, userId, namespaceId, SkillVisibility.PRIVATE);
SkillVersion version = createVersion(versionId, skillId, SkillVersionStatus.DRAFT);
when(skillRepository.findById(skillId)).thenReturn(Optional.of(skill));
when(skillVersionRepository.findById(versionId)).thenReturn(Optional.of(version));
when(reviewTaskRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
Map<Long, NamespaceRole> roles = Map.of();
// When
service.submitForReview(skillId, versionId, SkillVisibility.PUBLIC, userId, roles);
// Then
assertEquals(SkillVersionStatus.PENDING_REVIEW, version.getStatus());
assertEquals(SkillVisibility.PUBLIC, version.getRequestedVisibility());
verify(reviewTaskRepository).save(any(ReviewTask.class));
}
@Test
@DisplayName("should reject when version is neither UPLOADED nor DRAFT")
void shouldRejectWhenNotUploadedOrDraft() {
// Given
Long skillId = 1L;
Long versionId = 100L;
String userId = "user-1";
Skill skill = createSkill(skillId, userId, 10L, SkillVisibility.PRIVATE);
SkillVersion version = createVersion(versionId, skillId, SkillVersionStatus.DRAFT);
SkillVersion version = createVersion(versionId, skillId, SkillVersionStatus.PUBLISHED);
when(skillRepository.findById(skillId)).thenReturn(Optional.of(skill));
when(skillVersionRepository.findById(versionId)).thenReturn(Optional.of(version));
@ -156,6 +183,31 @@ class SkillReviewSubmitServiceTest {
verify(skillRepository).save(skill);
}
@Test
@DisplayName("should transition DRAFT version to PUBLISHED for PRIVATE skill (legacy compatibility)")
void shouldTransitionDraftToPublished() {
// Given
Long skillId = 1L;
Long versionId = 100L;
String userId = "user-1";
Long namespaceId = 10L;
Skill skill = createSkill(skillId, userId, namespaceId, SkillVisibility.PRIVATE);
SkillVersion version = createVersion(versionId, skillId, SkillVersionStatus.DRAFT);
when(skillRepository.findById(skillId)).thenReturn(Optional.of(skill));
when(skillVersionRepository.findById(versionId)).thenReturn(Optional.of(version));
// When
service.confirmPublish(skillId, versionId, userId, Map.of());
// Then
assertEquals(SkillVersionStatus.PUBLISHED, version.getStatus());
assertNotNull(version.getPublishedAt());
assertEquals(versionId, skill.getLatestVersionId());
verify(skillRepository).save(skill);
}
@Test
@DisplayName("should reject when skill is not PRIVATE")
void shouldRejectWhenNotPrivate() {
@ -176,8 +228,8 @@ class SkillReviewSubmitServiceTest {
}
@Test
@DisplayName("should reject when version is not UPLOADED")
void shouldRejectWhenNotUploaded() {
@DisplayName("should reject when version is neither UPLOADED nor DRAFT")
void shouldRejectWhenNotUploadedOrDraft() {
// Given
Long skillId = 1L;
Long versionId = 100L;