diff --git a/sync-jira/src/main/kotlin/gropius/sync/jira/JiraDataService.kt b/sync-jira/src/main/kotlin/gropius/sync/jira/JiraDataService.kt index 4ec84a96..2895dffc 100644 --- a/sync-jira/src/main/kotlin/gropius/sync/jira/JiraDataService.kt +++ b/sync-jira/src/main/kotlin/gropius/sync/jira/JiraDataService.kt @@ -161,6 +161,27 @@ class JiraDataService( .firstOrNull { it.name == name } } + /** + * Generate a new IMSUser to be a placeholder in erroneous situations + * @param imsProject the project to map the user to + * @return the created IMSUser + */ + private suspend fun generateNullUser(imsProject: IMSProject, name: String, displayName: String): IMSUser { + val foundImsUser = imsProject.ims().value.users().firstOrNull { it.username == name } + if (foundImsUser != null) { + return foundImsUser + } + val imsUser = IMSUser( + displayName, null, null, name, mutableMapOf("jira_id" to "0") + ) + imsUser.ims().value = imsProject.ims().value + imsUser.template().value = imsUser.ims().value.template().value.imsUserTemplate().value + val newUser = neoOperations.save(imsUser).awaitSingle() + tokenManager.advertiseIMSUser(newUser) + imsProject.ims().value.users() += newUser + return newUser + } + /** * Get a IMSUser for a Jira user * @param imsProject the project to map the user to @@ -168,10 +189,21 @@ class JiraDataService( * @return the IMSUser for the Jira user */ suspend fun mapUser(imsProject: IMSProject, user: JsonElement): User { - val encodedAccountId = if (user.jsonObject["accountId"] != null) jsonNodeMapper.jsonNodeToDeterministicString( - objectMapper.valueToTree(user.jsonObject["accountId"]!!.jsonPrimitive.content) - ) - else jsonNodeMapper.jsonNodeToDeterministicString(objectMapper.valueToTree(user.jsonObject["key"]!!.jsonPrimitive.content)) + if ((user as? JsonObject) == null) { + logger.warn("User is not a JsonObject, falling back to dummy user") + return generateNullUser(imsProject, "null-user", "Null User") + } + val encodedAccountId = + if ((user.jsonObject["accountId"] as? JsonPrimitive) != null) jsonNodeMapper.jsonNodeToDeterministicString( + objectMapper.valueToTree(user.jsonObject["accountId"]!!.jsonPrimitive.content) + ) + else if ((user.jsonObject["key"] as? JsonPrimitive) != null) jsonNodeMapper.jsonNodeToDeterministicString( + objectMapper.valueToTree(user.jsonObject["key"]!!.jsonPrimitive.content) + ) + else { + logger.warn("User has no key, $user") + return generateNullUser(imsProject, "null-id-user", "Null ID User") + } val foundImsUser = imsProject.ims().value.users().firstOrNull { it.templatedFields["jira_id"] == encodedAccountId } if (foundImsUser != null) { @@ -259,7 +291,7 @@ class JiraDataService( } logger.info("Response Code for request with token token is ${res.status}(${res.status.isSuccess()}): $body is ${res.bodyAsText()}") return if (res.status.isSuccess()) { - logger.trace("Response for {} {}", res.request.url, res.bodyAsText()) + logger.debug("Response for {} {}", res.request.url, res.bodyAsText()) Optional.of(res) } else { Optional.empty() @@ -289,7 +321,7 @@ class JiraDataService( } logger.info("Response Code for request with token token is ${res.status}(${res.status.isSuccess()}): $body is ${res.bodyAsText()}") return if (res.status.isSuccess()) { - logger.trace("Response for {} {}", res.request.url, res.bodyAsText()) + logger.debug("Response for {} {}", res.request.url, res.bodyAsText()) Optional.of(res) } else { Optional.empty() diff --git a/sync-jira/src/main/kotlin/gropius/sync/jira/model/IssueData.kt b/sync-jira/src/main/kotlin/gropius/sync/jira/model/IssueData.kt index 35ecf263..a0b45723 100644 --- a/sync-jira/src/main/kotlin/gropius/sync/jira/model/IssueData.kt +++ b/sync-jira/src/main/kotlin/gropius/sync/jira/model/IssueData.kt @@ -145,8 +145,8 @@ class JiraTimelineItem(val id: String, val created: String, val author: JsonObje val convInfo = timelineItemConversionInformation ?: JiraTimelineItemConversionInformation(imsProject.rawId!!, id); val timelineId = timelineItemConversionInformation?.gropiusId - val sourceSet = data.fromString!!.split(' ').toSet() - val destinationSet = data.toString!!.split(' ').toSet() + val sourceSet = (data.fromString ?: "").split(' ').toSet() + val destinationSet = (data.toString ?: "").split(' ').toSet() logger.info("GOING FROM $sourceSet to $destinationSet, meaning added: ${(destinationSet subtract sourceSet)} and removed ${(sourceSet subtract destinationSet)}") for (addedLabel in (destinationSet subtract sourceSet)) { val addedLabelEvent = if (timelineId != null) service.neoOperations.findById( diff --git a/sync/src/main/kotlin/gropius/sync/AbstractSync.kt b/sync/src/main/kotlin/gropius/sync/AbstractSync.kt index c2e48c48..79779413 100644 --- a/sync/src/main/kotlin/gropius/sync/AbstractSync.kt +++ b/sync/src/main/kotlin/gropius/sync/AbstractSync.kt @@ -498,7 +498,7 @@ abstract class AbstractSync( nodesToSave: MutableList, savedNodeHandlers: MutableList Unit> ) { - logger.info("Syncing incoming for issue ${issue.rawId} $timelineItem ${timelineItem.identification()}") + logger.trace("Syncing incoming for issue ${issue.rawId} $timelineItem ${timelineItem.identification()}") val oldInfo = collectedSyncInfo.timelineItemConversionInformationService.findByImsProjectAndGithubId( imsProject.rawId!!, timelineItem.identification() ).firstOrNull() @@ -610,7 +610,7 @@ abstract class AbstractSync( imsProject.rawId!!, it.rawId ?: virtualIDs[it]!! )?.githubId != null } - logger.trace("LastNegativeEvent $lastNegativeEvent") + logger.debug("LastNegativeEvent $lastNegativeEvent") if (lastNegativeEvent == null) { return !restoresDefaultState } else { @@ -857,13 +857,13 @@ abstract class AbstractSync( val relevantTimeline = timeline.mapNotNull { it as? StateChangedEvent } if (relevantTimeline.isEmpty()) return val finalBlock = findFinalBlock(relevantTimeline) { it.newState().value } - logger.trace("finalBlock: $finalBlock in $relevantTimeline being ${relevantTimeline.map { it.newState().value.name }}") + logger.debug("finalBlock: $finalBlock in $relevantTimeline being ${relevantTimeline.map { it.newState().value.name }}") if (finalBlock.none { collectedSyncInfo.timelineItemConversionInformationService.findByImsProjectAndGropiusId( imsProject.rawId!!, it.rawId!! ) != null }) { - logger.trace("syncOutgoingStateChanges: $finalBlock") + logger.debug("syncOutgoingStateChanges: $finalBlock") val conversionInformation = syncStateChange(imsProject, issueInfo.githubId, finalBlock.first().newState().value, diff --git a/sync/src/main/kotlin/gropius/sync/TokenManager.kt b/sync/src/main/kotlin/gropius/sync/TokenManager.kt index 90418513..dc1a1939 100644 --- a/sync/src/main/kotlin/gropius/sync/TokenManager.kt +++ b/sync/src/main/kotlin/gropius/sync/TokenManager.kt @@ -202,16 +202,16 @@ abstract class TokenManager( if (isAllowed(imsProject, user, owner)) { val token = getUserToken(user) if (token?.token != null) { - logger.trace("Trying token of user ${user.rawId}") + logger.debug("Trying token of user ${user.rawId}") val ret = executor(token) if (ret.isPresent) { return user to ret.get() } } else { - logger.trace("User ${user.rawId} had no token") + logger.debug("User ${user.rawId} had no token") } } else { - logger.trace("User $user does not allow sync from $owner") + logger.debug("User $user does not allow sync from $owner") } } throw NoTokenValidException()