[gitlab] handle project members returned as empty objects

IDEA-320382 Fixed

GitOrigin-RevId: 76952d02fed8a9f4a16c175c27024076624f24a7
This commit is contained in:
Ivan Semenov
2023-05-17 14:41:25 +00:00
committed by intellij-monorepo-bot
parent 7fe273ab5d
commit 372c6441fc
3 changed files with 41 additions and 23 deletions
@@ -1,30 +1,49 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.plugins.gitlab.api.dto
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import com.fasterxml.jackson.databind.deser.std.StdDeserializer
import com.intellij.collaboration.api.dto.GraphQLFragment
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.diagnostic.logger
import org.jetbrains.plugins.gitlab.api.data.GitLabAccessLevel
@JsonDeserialize(using = GitLabMemberDTODeserializer::class)
@GraphQLFragment("graphql/fragment/member.graphql")
class GitLabMemberDTO(
val id: String,
val user: GitLabUserDTO,
accessLevel: AccessLevel
) {
val accessLevel: GitLabAccessLevel = parseAccessLevel(accessLevel.stringValue)
val accessLevel: GitLabAccessLevel
)
class AccessLevel(val stringValue: String)
class GitLabMemberDTODeserializer : StdDeserializer<GitLabMemberDTO?>(GitLabMemberDTO::class.java) {
override fun deserialize(jsonParser: JsonParser, context: DeserializationContext): GitLabMemberDTO? {
val codec = jsonParser.codec
val node: JsonNode = codec.readTree(jsonParser)
companion object {
private val logger: Logger = logger<GitLabMemberDTO>()
private fun parseAccessLevel(accessLevel: String) = try {
GitLabAccessLevel.valueOf(accessLevel)
}
catch (_: IllegalArgumentException) {
logger.error("Unable to parse access level")
GitLabAccessLevel.NO_ACCESS
return if (node.isEmpty) null
else {
//codec.treeToValue(node, GitLabMemberDTO::class.java) leads to SOE
val id: String = node["id"].asText()
val user: GitLabUserDTO = codec.treeToValue(node["user"], GitLabUserDTO::class.java)
val accessLevel = node["accessLevel"]["stringValue"].asText().let(::parseAccessLevel)
GitLabMemberDTO(id, user, accessLevel)
}
}
private fun parseAccessLevel(accessLevel: String) = try {
GitLabAccessLevel.valueOf(accessLevel)
}
catch (_: IllegalArgumentException) {
LOG.error("Unable to parse access level")
GitLabAccessLevel.NO_ACCESS
}
companion object {
private val LOG: Logger = logger<GitLabMemberDTO>()
}
}
@@ -29,10 +29,10 @@ suspend fun GitLabApi.getAllProjectMembers(project: GitLabProjectCoordinates): L
)
val request = gqlQuery(project.serverPath.gqlApiUri, GitLabGQLQueries.getProjectMembers, parameters)
loadGQLResponse(request, ProjectMembersConnection::class.java, "project", "projectMembers").body()
}.map { it.nodes }.foldToList()
}.map { it.nodes }.foldToList().filterNotNull()
private class LabelConnection(pageInfo: GraphQLCursorPageInfoDTO, nodes: List<GitLabLabelDTO>)
: GraphQLConnectionDTO<GitLabLabelDTO>(pageInfo, nodes)
private class ProjectMembersConnection(pageInfo: GraphQLCursorPageInfoDTO, nodes: List<GitLabMemberDTO>)
: GraphQLConnectionDTO<GitLabMemberDTO>(pageInfo, nodes)
private class ProjectMembersConnection(pageInfo: GraphQLCursorPageInfoDTO, nodes: List<GitLabMemberDTO?>)
: GraphQLConnectionDTO<GitLabMemberDTO?>(pageInfo, nodes)
@@ -7,7 +7,6 @@ import kotlinx.coroutines.cancel
import kotlinx.coroutines.test.runTest
import org.jetbrains.plugins.gitlab.api.data.GitLabAccessLevel
import org.jetbrains.plugins.gitlab.api.dto.GitLabMemberDTO
import org.jetbrains.plugins.gitlab.api.dto.GitLabMemberDTO.AccessLevel
import org.jetbrains.plugins.gitlab.api.dto.GitLabUserDTO
import org.jetbrains.plugins.gitlab.mergerequest.data.loaders.GitLabMergeRequestsListLoader
import org.jetbrains.plugins.gitlab.mergerequest.ui.filters.GitLabMergeRequestsFiltersValue
@@ -115,7 +114,7 @@ internal class GitLabMergeRequestsFiltersViewModelImplTest {
loaderSupplier = loaderSupplierMock)
val user = GitLabUserDTO(id = "", username = "", name = "", avatarUrl = "", webUrl = "")
val member = GitLabMemberDTO(id = "", user = user, accessLevel = AccessLevel(GitLabAccessLevel.GUEST.name))
val member = GitLabMemberDTO(id = "", user = user, accessLevel = GitLabAccessLevel.GUEST)
verifyFilterParticipantSelect(filterVm, loaderSupplierMock, GitLabMergeRequestsFiltersValue(
state = MergeRequestStateFilterValue.OPENED,
author = MergeRequestsAuthorFilterValue(member.user.username, member.user.name)
@@ -184,11 +183,11 @@ internal class GitLabMergeRequestsFiltersViewModelImplTest {
fun `available participants for merge request filters`() = runTest {
val cs = childScope()
val guest = GitLabMemberDTO(id = "guest", mock(), accessLevel = AccessLevel(GitLabAccessLevel.GUEST.name))
val reporter = GitLabMemberDTO(id = "reporter", mock(), accessLevel = AccessLevel(GitLabAccessLevel.REPORTER.name))
val developer = GitLabMemberDTO(id = "developer", mock(), accessLevel = AccessLevel(GitLabAccessLevel.DEVELOPER.name))
val maintainer = GitLabMemberDTO(id = "maintainer", mock(), accessLevel = AccessLevel(GitLabAccessLevel.MAINTAINER.name))
val owner = GitLabMemberDTO(id = "owner", mock(), accessLevel = AccessLevel(GitLabAccessLevel.OWNER.name))
val guest = GitLabMemberDTO(id = "guest", mock(), accessLevel = GitLabAccessLevel.GUEST)
val reporter = GitLabMemberDTO(id = "reporter", mock(), accessLevel = GitLabAccessLevel.REPORTER)
val developer = GitLabMemberDTO(id = "developer", mock(), accessLevel = GitLabAccessLevel.DEVELOPER)
val maintainer = GitLabMemberDTO(id = "maintainer", mock(), accessLevel = GitLabAccessLevel.MAINTAINER)
val owner = GitLabMemberDTO(id = "owner", mock(), accessLevel = GitLabAccessLevel.OWNER)
val members = listOf(guest, reporter, developer, maintainer, owner)
val filterVm = GitLabMergeRequestsFiltersViewModelImpl(scope = cs, historyModel = mock(), currentUser = mockedUser,