Skip to content

Commit

Permalink
Merge pull request #2547 from NationalSecurityAgency/t#2538/copy_proj…
Browse files Browse the repository at this point in the history
…_attachments1

#2544: fixed the usage of a share map to be thread local
  • Loading branch information
dwalizer authored Apr 2, 2024
2 parents 7195cd7 + 6aa2d37 commit 05e7404
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ class AttachmentService {
if (description) {
UUID_PATTERN.matcher(description).findAll().collect { it[1] }.each { uuid ->
Attachment attachment = attachmentRepo.findByUuid(uuid)
if (!attachment) {
throw new IllegalStateException("Failed to find attachment with uuid: [${uuid}]. method params are projectId: [${projectId}], quizId: [${quizId}], skillId: [${skillId}]")
}
boolean changed = false
if (attachment.projectId != projectId) {
attachment.setProjectId(projectId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,23 +130,28 @@ class ProjectCopyService {
void copyProject(String originalProjectId, ProjectRequest projectRequest) {
lockingService.lockProjects()

ProjDef fromProject = loadProject(originalProjectId)
validate(projectRequest)

ProjDef toProj = saveToProject(projectRequest)
saveProjectSettings(fromProject, toProj)

pinProjectForRootUser(toProj)

List<SkillInfo> allCollectedSkills = []
def newIcons = customIconFacade.copyIcons(originalProjectId, toProj.projectId)
saveSubjectsAndSkills(projectRequest, fromProject, toProj, allCollectedSkills, newIcons)
updateProjectAndSubjectLevels(fromProject, toProj)
saveBadgesAndTheirSkills(fromProject, toProj, newIcons)
flushEntityCache()
saveDependencies(fromProject, toProj)
saveReusedSkills(allCollectedSkills, fromProject, toProj)
handleQuizBasedUserPointsAndAchievements(toProj)
copiedAttachmentUuidsThreadLocal.set([:])
try {
ProjDef fromProject = loadProject(originalProjectId)
validate(projectRequest)

ProjDef toProj = saveToProject(projectRequest)
saveProjectSettings(fromProject, toProj)

pinProjectForRootUser(toProj)

List<SkillInfo> allCollectedSkills = []
def newIcons = customIconFacade.copyIcons(originalProjectId, toProj.projectId)
saveSubjectsAndSkills(projectRequest, fromProject, toProj, allCollectedSkills, newIcons)
updateProjectAndSubjectLevels(fromProject, toProj)
saveBadgesAndTheirSkills(fromProject, toProj, newIcons)
flushEntityCache()
saveDependencies(fromProject, toProj)
saveReusedSkills(allCollectedSkills, fromProject, toProj)
handleQuizBasedUserPointsAndAchievements(toProj)
} finally {
copiedAttachmentUuidsThreadLocal.set([:])
}
}

private void flushEntityCache() {
Expand Down Expand Up @@ -426,9 +431,10 @@ class ProjectCopyService {
}
}

private final Map<String,String> copiedAttachmentUuids = [:]
private final ThreadLocal<Map<String,String>> copiedAttachmentUuidsThreadLocal = new ThreadLocal<>();
@Profile
private String handleAttachmentsInDescription(String description, String newProjectId) {
Map<String,String> copiedAttachmentUuids = copiedAttachmentUuidsThreadLocal.get()
String res = description
if (description) {
attachmentService.findAttachmentUuids(res).each { String uuid ->
Expand All @@ -438,6 +444,7 @@ class ProjectCopyService {
Attachment copiedAttachment = attachmentService.copyAttachmentWithNewUuid(attachment, newProjectId)
copiedUuid = copiedAttachment.uuid
copiedAttachmentUuids[uuid] = copiedUuid
copiedAttachmentUuidsThreadLocal.set(copiedAttachmentUuids)
}
res = res.replaceAll(uuid, copiedUuid)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -974,6 +974,65 @@ class CopyProjectSpecs extends DefaultIntSpec {
copyProj.data.itemId.sort() == [projToCopy.projectId, p1subj1.subjectId, p1Skills[0].skillId].sort()
}

def "copy project with an attachment in description, then remove the copy then copy again"() {
def p1 = createProject(1)
skillsService.createProject(p1)

String contents = 'Test is a test'
String attachmentHref = attachFileAndReturnHref(p1.projectId, contents)

def p1subj1 = createSubject(1, 1)
p1subj1.description = "Here is a [Link](${attachmentHref})".toString()
skillsService.createSubject(p1subj1)

when:
def projToCopy = createProject(2)
skillsService.copyProject(p1.projectId, projToCopy)

def origSubj = skillsService.getSubject([projectId: p1.projectId, subjectId: p1subj1.subjectId])
def copySubj = skillsService.getSubject([projectId: projToCopy.projectId, subjectId: p1subj1.subjectId])

List<Attachment> attachments = attachmentRepo.findAll()
assert attachments.size() == 2
Attachment originalAttachment = attachments.find { attachmentHref.contains(it.uuid)}
Attachment newAttachment = attachments.find { !attachmentHref.contains(it.uuid)}

assert origSubj.description == "Here is a [Link](${attachmentHref})"
assert copySubj.description == "Here is a [Link](/api/download/${newAttachment.uuid})"

assert originalAttachment.projectId == p1.projectId
assert newAttachment.projectId == projToCopy.projectId

skillsService.deleteProject(projToCopy.projectId)

List<Attachment> attachmentsAfterDelete = attachmentRepo.findAll()
assert attachmentsAfterDelete.size() == 1
attachmentsAfterDelete.find { attachmentHref.contains(it.uuid)}

def secondCopy = createProject(3)
skillsService.copyProject(p1.projectId, secondCopy)

def origSubjAfterSecondCopy = skillsService.getSubject([projectId: p1.projectId, subjectId: p1subj1.subjectId])
def copySubjAfterSecondCopy = skillsService.getSubject([projectId: secondCopy.projectId, subjectId: p1subj1.subjectId])
List<Attachment> attachmentsAfterSecondCopy = attachmentRepo.findAll()
then:
origSubjAfterSecondCopy.description == "Here is a [Link](${attachmentHref})"

attachmentsAfterSecondCopy.size() == 2
Attachment originalAttachmentAfterSecondCopy = attachmentsAfterSecondCopy.find { attachmentHref.contains(it.uuid)}
Attachment newAttachmentAfterSecondCopy = attachmentsAfterSecondCopy.find { !attachmentHref.contains(it.uuid)}

originalAttachmentAfterSecondCopy.projectId == p1.projectId

newAttachmentAfterSecondCopy.projectId == secondCopy.projectId
copySubjAfterSecondCopy.description == "Here is a [Link](/api/download/${newAttachmentAfterSecondCopy.uuid})"

SkillsService.FileAndHeaders fileAndHeaders = skillsService.downloadAttachment("/api/download/${newAttachmentAfterSecondCopy.uuid}")
File file = fileAndHeaders.file
file
file.bytes == contents.getBytes()
}


static class Edge {
String from
Expand Down

0 comments on commit 05e7404

Please sign in to comment.