From 47513cff78169ad542fa48bd17fb9ee1f8ca07d2 Mon Sep 17 00:00:00 2001 From: greysonfang Date: Sat, 12 Oct 2024 15:27:49 +0800 Subject: [PATCH 1/9] =?UTF-8?q?feat=EF=BC=9A=E6=B5=81=E6=B0=B4=E7=BA=BF?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E5=B1=95=E7=A4=BA=E6=9D=83=E9=99=90=E6=8E=A7?= =?UTF-8?q?=E5=88=B6=20#10895?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../process/dao/label/PipelineViewGroupDao.kt | 4 +- .../process/engine/dao/PipelineInfoDao.kt | 4 +- .../RbacPipelinePermissionService.kt | 34 ++- .../config/PipelinePermConfiguration.kt | 6 +- .../service/PipelineListFacadeService.kt | 244 +++++++----------- .../service/view/PipelineViewGroupService.kt | 45 +++- .../view/PipelineViewGroupServiceTest.kt | 11 +- 7 files changed, 172 insertions(+), 176 deletions(-) diff --git a/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/dao/label/PipelineViewGroupDao.kt b/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/dao/label/PipelineViewGroupDao.kt index 4a98bf75e86..111f875e6d9 100644 --- a/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/dao/label/PipelineViewGroupDao.kt +++ b/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/dao/label/PipelineViewGroupDao.kt @@ -221,13 +221,15 @@ class PipelineViewGroupDao { fun countByViewId( dslContext: DSLContext, projectId: String, - viewIds: Collection + viewIds: Collection, + filterPipelineIds: List? = null ): Map { with(TPipelineViewGroup.T_PIPELINE_VIEW_GROUP) { return dslContext.select(VIEW_ID, count()) .from(this) .where(PROJECT_ID.eq(projectId)) .and(VIEW_ID.`in`(viewIds)) + .let { if (filterPipelineIds != null) it.and(PIPELINE_ID.`in`(filterPipelineIds)) else it } .groupBy(VIEW_ID) .fetch().map { it.value1() to it.value2() }.toMap() } diff --git a/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/engine/dao/PipelineInfoDao.kt b/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/engine/dao/PipelineInfoDao.kt index ec7e213bb72..c52dd85fe16 100644 --- a/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/engine/dao/PipelineInfoDao.kt +++ b/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/engine/dao/PipelineInfoDao.kt @@ -729,7 +729,8 @@ class PipelineInfoDao { projectId: String, excludePipelineIds: List, channelCode: ChannelCode? = null, - includeDelete: Boolean = false + includeDelete: Boolean = false, + filterPipelineIds: List? = null ): Int { with(T_PIPELINE_INFO) { return dslContext.selectCount() @@ -738,6 +739,7 @@ class PipelineInfoDao { .and(PIPELINE_ID.notIn(excludePipelineIds)) .let { if (channelCode == null) it else it.and(CHANNEL.eq(channelCode.name)) } .let { if (includeDelete) it else it.and(DELETE.eq(false)) } + .let { if (filterPipelineIds != null) it.and(PIPELINE_ID.`in`(filterPipelineIds)) else it } .fetchOne()?.value1() ?: 0 } } diff --git a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/RbacPipelinePermissionService.kt b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/RbacPipelinePermissionService.kt index 20f089fd897..402f462230f 100644 --- a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/RbacPipelinePermissionService.kt +++ b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/RbacPipelinePermissionService.kt @@ -37,19 +37,19 @@ import com.tencent.devops.common.auth.api.AuthResourceType import com.tencent.devops.common.auth.api.pojo.AuthResourceInstance import com.tencent.devops.common.auth.api.pojo.BkAuthGroup import com.tencent.devops.common.auth.code.PipelineAuthServiceCode +import com.tencent.devops.process.dao.label.PipelineViewGroupDao import com.tencent.devops.process.engine.dao.PipelineInfoDao -import com.tencent.devops.process.service.view.PipelineViewGroupService import org.jooq.DSLContext import org.slf4j.LoggerFactory @Suppress("LongParameterList") -class RbacPipelinePermissionService constructor( +class RbacPipelinePermissionService( val authPermissionApi: AuthPermissionApi, val authProjectApi: AuthProjectApi, val pipelineAuthServiceCode: PipelineAuthServiceCode, val dslContext: DSLContext, val pipelineInfoDao: PipelineInfoDao, - val pipelineViewGroupService: PipelineViewGroupService, + val pipelineViewGroupDao: PipelineViewGroupDao, val authResourceApi: AuthResourceApi ) : PipelinePermissionService { @@ -89,7 +89,7 @@ class RbacPipelinePermissionService constructor( } finally { logger.info( "It take(${System.currentTimeMillis() - startEpoch})ms to check pipeline permission|" + - "$userId|$projectId|$pipelineId|$permission|$authResourceType" + "$userId|$projectId|$pipelineId|$permission|$authResourceType" ) } } @@ -105,7 +105,12 @@ class RbacPipelinePermissionService constructor( resourceCode = projectId ) parents.add(projectInstance) - pipelineViewGroupService.listViewIdsByPipelineId(projectId, pipelineId).forEach { viewId -> + val pipelineIds = pipelineViewGroupDao.listByPipelineId( + dslContext = dslContext, + projectId = projectId, + pipelineId = pipelineId + ).map { it.viewId }.toSet() + pipelineIds.forEach { viewId -> parents.add( AuthResourceInstance( resourceType = AuthResourceType.PIPELINE_GROUP.value, @@ -125,10 +130,11 @@ class RbacPipelinePermissionService constructor( projectId: String, pipelineIds: List ): List { - val listViewIdsMap = pipelineViewGroupService.listViewIdsMap( + val listViewIdsMap = pipelineViewGroupDao.listByPipelineIds( + dslContext = dslContext, projectId = projectId, pipelineIds = pipelineIds - ) + ).groupBy({ it.pipelineId }, { it.viewId }) return pipelineIds.map { pipelineId -> val parents = mutableListOf() val projectInstance = AuthResourceInstance( @@ -198,10 +204,22 @@ class RbacPipelinePermissionService constructor( // 如果有项目下所有该资源权限,返回项目下流水线列表 instanceMap[AuthResourceType.PROJECT.value]?.contains(projectId) == true -> getAllAuthPipelineIds(projectId = projectId) + else -> { // 获取有权限流水线组下的流水线 val authViewPipelineIds = instanceMap[AuthResourceType.PIPELINE_GROUP.value]?.let { authViewIds -> - pipelineViewGroupService.listPipelineIdsByViewIds(projectId, authViewIds) + val viewIds = authViewIds.map { HashUtil.decodeIdToLong(it) } + val pipelineIds = mutableListOf() + val viewGroups = pipelineViewGroupDao.listByViewIds(dslContext, projectId, viewIds) + if (viewGroups.isEmpty()) { + pipelineIds.addAll(emptyList()) + } else { + pipelineIds.addAll(viewGroups.map { it.pipelineId }.toList()) + } + if (pipelineIds.isEmpty()) { + pipelineIds.add("##NONE##") // 特殊标志,避免有些判空逻辑导致过滤器没有执行 + } + pipelineIds } ?: emptyList() // 获取有权限的流水线列表 val authPipelineIds = instanceMap[AuthResourceType.PIPELINE_DEFAULT.value] ?: emptyList() diff --git a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/config/PipelinePermConfiguration.kt b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/config/PipelinePermConfiguration.kt index 1cb8988b4e2..82e87dc0e27 100644 --- a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/config/PipelinePermConfiguration.kt +++ b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/config/PipelinePermConfiguration.kt @@ -33,12 +33,12 @@ import com.tencent.devops.common.auth.api.AuthResourceApi import com.tencent.devops.common.auth.code.PipelineAuthServiceCode import com.tencent.devops.common.client.Client import com.tencent.devops.common.client.ClientTokenService +import com.tencent.devops.process.dao.label.PipelineViewGroupDao import com.tencent.devops.process.engine.dao.PipelineInfoDao import com.tencent.devops.process.permission.MockPipelinePermissionService import com.tencent.devops.process.permission.PipelinePermissionService import com.tencent.devops.process.permission.RbacPipelinePermissionService import com.tencent.devops.process.permission.StreamPipelinePermissionServiceImpl -import com.tencent.devops.process.service.view.PipelineViewGroupService import org.jooq.DSLContext import org.springframework.boot.autoconfigure.AutoConfigureOrder import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty @@ -107,7 +107,7 @@ class PipelinePermConfiguration { pipelineAuthServiceCode: PipelineAuthServiceCode, dslContext: DSLContext, pipelineInfoDao: PipelineInfoDao, - pipelineViewGroupService: PipelineViewGroupService, + pipelineViewGroupDao: PipelineViewGroupDao, authResourceApi: AuthResourceApi ): PipelinePermissionService = RbacPipelinePermissionService( authPermissionApi = authPermissionApi, @@ -115,7 +115,7 @@ class PipelinePermConfiguration { pipelineAuthServiceCode = pipelineAuthServiceCode, dslContext = dslContext, pipelineInfoDao = pipelineInfoDao, - pipelineViewGroupService = pipelineViewGroupService, + pipelineViewGroupDao = pipelineViewGroupDao, authResourceApi = authResourceApi ) } diff --git a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/PipelineListFacadeService.kt b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/PipelineListFacadeService.kt index e00bfae4d21..7c34907ae26 100644 --- a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/PipelineListFacadeService.kt +++ b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/PipelineListFacadeService.kt @@ -152,6 +152,14 @@ class PipelineListFacadeService @Autowired constructor( companion object { private val logger = LoggerFactory.getLogger(PipelineListFacadeService::class.java) + private val DEFAULT_VIEW_IDS = listOf( + PIPELINE_VIEW_FAVORITE_PIPELINES, + PIPELINE_VIEW_MY_PIPELINES, + PIPELINE_VIEW_ALL_PIPELINES, + PIPELINE_VIEW_MY_LIST_PIPELINES, + PIPELINE_VIEW_UNCLASSIFIED, + PIPELINE_VIEW_RECENT_USE + ) } fun sortPipelines(pipelines: MutableList, sortType: PipelineSortType) { @@ -505,13 +513,19 @@ class PipelineListFacadeService @Autowired constructor( val watcher = Watcher(id = "listViewPipelines|$projectId|$userId") watcher.start("perm_r_perm") val authPipelines = pipelinePermissionService.getResourceByPermission( - userId = userId, projectId = projectId, permission = AuthPermission.LIST + userId = userId, + projectId = projectId, + permission = AuthPermission.LIST ) watcher.stop() watcher.start("s_r_summary") try { - val favorPipelines = pipelineGroupService.getFavorPipelines(userId = userId, projectId = projectId) + val favorPipelines = pipelineGroupService.getFavorPipelines( + userId = userId, + projectId = projectId + ) + // 组装搜索条件 val pipelineFilterParamList = pipelineListQueryParamService.generatePipelineFilterParams( projectId = projectId, filterByPipelineName = filterByPipelineName, @@ -520,43 +534,18 @@ class PipelineListFacadeService @Autowired constructor( ) val pipelineIds = mutableSetOf() - val viewIdList = listOf( - PIPELINE_VIEW_FAVORITE_PIPELINES, - PIPELINE_VIEW_MY_PIPELINES, - PIPELINE_VIEW_ALL_PIPELINES, - PIPELINE_VIEW_MY_LIST_PIPELINES, - PIPELINE_VIEW_UNCLASSIFIED, - PIPELINE_VIEW_RECENT_USE + // 根据视图类型获取流水线 + val pipelineIdsByViewId = listPipelineIdsByViewId( + userId = userId, + projectId = projectId, + viewId = viewId, + filterByViewIds = filterByViewIds ) - val includeDelete = showDelete && (PIPELINE_VIEW_RECENT_USE == viewId || !viewIdList.contains(viewId)) - - if (!viewIdList.contains(viewId)) { // 已分组的视图 - pipelineIds.addAll(pipelineViewGroupService.listPipelineIdsByViewId(projectId, viewId)) - } else if (viewId == PIPELINE_VIEW_UNCLASSIFIED) { // 非分组的视图 - val allPipelineIds = pipelineInfoDao.listPipelineIdByProject(dslContext, projectId).toMutableSet() - pipelineIds.addAll( - allPipelineIds.subtract(pipelineViewGroupService.getClassifiedPipelineIds(projectId).toSet()) - ) - // 避免过滤器为空的情况 - if (pipelineIds.isEmpty()) { - pipelineIds.add("##NONE##") - } - } else if (viewId == PIPELINE_VIEW_RECENT_USE) { // 最近访问 - pipelineIds.addAll(pipelineRecentUseService.listPipelineIds(userId, projectId)) - } - // 剔除掉filterByViewIds - if (filterByViewIds != null) { - val pipelineIdsByFilterViewIds = - pipelineViewGroupService.listPipelineIdsByViewIds(projectId, filterByViewIds.split(",")).toSet() - if (pipelineIds.isEmpty()) { - pipelineIds.addAll(pipelineIdsByFilterViewIds) - } else { - pipelineIds.retainAll(pipelineIdsByFilterViewIds) - } + if (pipelineIdsByViewId.isNotEmpty()) { + pipelineIds.addAll(pipelineIdsByViewId) } - pipelineViewService.addUsingView(userId = userId, projectId = projectId, viewId = viewId) - + val includeDelete = showDelete && (PIPELINE_VIEW_RECENT_USE == viewId || !DEFAULT_VIEW_IDS.contains(viewId)) // 查询有权限查看的流水线总数 val totalAvailablePipelineSize = pipelineBuildSummaryDao.listPipelineInfoBuildSummaryCount( dslContext = dslContext, @@ -572,24 +561,27 @@ class PipelineListFacadeService @Autowired constructor( userId = userId ) - // 查询无权限查看的流水线总数 - val totalInvalidPipelineSize = - if (filterInvalid) 0 else pipelineBuildSummaryDao.listPipelineInfoBuildSummaryCount( - dslContext = dslContext, + val pipelineList = mutableListOf() + if (includeDelete) { + handlePipelineQueryList( + pipelineList = pipelineList, projectId = projectId, channelCode = channelCode, + sortType = sortType, pipelineIds = pipelineIds, - viewId = viewId, favorPipelines = favorPipelines, authPipelines = authPipelines, + viewId = viewId, pipelineFilterParamList = pipelineFilterParamList, - permissionFlag = false, - includeDelete = includeDelete, - userId = userId + permissionFlag = null, + page = page, + pageSize = pageSize, + includeDelete = true, + collation = collation, + userId = userId, + queryByWeb = queryByWeb ) - val pipelineList = mutableListOf() - val totalSize = totalAvailablePipelineSize + totalInvalidPipelineSize - if (includeDelete) { + } else if ((null != page && null != pageSize) && !(page == 1 && pageSize == -1)) { handlePipelineQueryList( pipelineList = pipelineList, projectId = projectId, @@ -600,103 +592,14 @@ class PipelineListFacadeService @Autowired constructor( authPipelines = authPipelines, viewId = viewId, pipelineFilterParamList = pipelineFilterParamList, - permissionFlag = null, + permissionFlag = true, page = page, pageSize = pageSize, - includeDelete = true, + includeDelete = includeDelete, collation = collation, userId = userId, queryByWeb = queryByWeb ) - } else if ((null != page && null != pageSize) && !(page == 1 && pageSize == -1)) { - // 判断可用的流水线是否已到最后一页 - val totalAvailablePipelinePage = PageUtil.calTotalPage(pageSize, totalAvailablePipelineSize) - if (page < totalAvailablePipelinePage) { - // 当前页未到可用流水线最后一页,不需要处理临界点(最后一页)的情况 - handlePipelineQueryList( - pipelineList = pipelineList, - projectId = projectId, - channelCode = channelCode, - sortType = sortType, - pipelineIds = pipelineIds, - favorPipelines = favorPipelines, - authPipelines = authPipelines, - viewId = viewId, - pipelineFilterParamList = pipelineFilterParamList, - permissionFlag = true, - page = page, - pageSize = pageSize, - includeDelete = includeDelete, - collation = collation, - userId = userId, - queryByWeb = queryByWeb - ) - } else if (page == totalAvailablePipelinePage && totalAvailablePipelineSize > 0) { - // 查询可用流水线最后一页不满页的数量 - val lastPageRemainNum = pageSize - totalAvailablePipelineSize % pageSize - handlePipelineQueryList( - pipelineList = pipelineList, - projectId = projectId, - channelCode = channelCode, - sortType = sortType, - pipelineIds = pipelineIds, - favorPipelines = favorPipelines, - authPipelines = authPipelines, - viewId = viewId, - pipelineFilterParamList = pipelineFilterParamList, - permissionFlag = true, - page = page, - pageSize = pageSize, - includeDelete = includeDelete, - collation = collation, - userId = userId, - queryByWeb = queryByWeb - ) - // 可用流水线最后一页不满页的数量需用不可用的流水线填充 - if (lastPageRemainNum > 0 && totalInvalidPipelineSize > 0) { - handlePipelineQueryList( - pipelineList = pipelineList, - projectId = projectId, - channelCode = channelCode, - sortType = sortType, - pipelineIds = pipelineIds, - favorPipelines = favorPipelines, - authPipelines = authPipelines, - viewId = viewId, - pipelineFilterParamList = pipelineFilterParamList, - permissionFlag = false, - page = 1, - pageSize = lastPageRemainNum.toInt(), - includeDelete = includeDelete, - collation = collation, - userId = userId, - queryByWeb = queryByWeb - ) - } - } else if (totalInvalidPipelineSize > 0) { - // 当前页大于可用流水线最后一页,需要排除掉可用流水线最后一页不满页的数量用不可用的流水线填充的情况 - val lastPageRemainNum = - if (totalAvailablePipelineSize > 0) pageSize - totalAvailablePipelineSize % pageSize else 0 - handlePipelineQueryList( - pipelineList = pipelineList, - projectId = projectId, - channelCode = channelCode, - sortType = sortType, - pipelineIds = pipelineIds, - favorPipelines = favorPipelines, - authPipelines = authPipelines, - viewId = viewId, - pipelineFilterParamList = pipelineFilterParamList, - permissionFlag = false, - page = page - totalAvailablePipelinePage, - pageSize = pageSize, - pageOffsetNum = lastPageRemainNum.toInt(), - includeDelete = includeDelete, - collation = collation, - userId = userId, - queryByWeb = queryByWeb - ) - } } else { // 不分页查询 handlePipelineQueryList( @@ -739,12 +642,17 @@ class PipelineListFacadeService @Autowired constructor( ) } } + // 记录用户最近使用过的视图 + pipelineViewService.addUsingView( + userId = userId, + projectId = projectId, + viewId = viewId + ) watcher.stop() - return PipelineViewPipelinePage( page = page ?: 1, - pageSize = pageSize ?: totalSize.toInt(), - count = totalSize, + pageSize = pageSize ?: totalAvailablePipelineSize.toInt(), + count = totalAvailablePipelineSize, records = fillPipelinePermissions( userId = userId, projectId = projectId, @@ -757,6 +665,48 @@ class PipelineListFacadeService @Autowired constructor( } } + private fun listPipelineIdsByViewId( + userId: String, + projectId: String, + viewId: String, + filterByViewIds: String? + ): Set { + val pipelineIds = mutableSetOf() + when { + // 非默认预置流水线组 + !DEFAULT_VIEW_IDS.contains(viewId) -> { + pipelineIds.addAll(pipelineViewGroupService.listPipelineIdsByViewId(projectId, viewId)) + } + // 流水线视图未分组 + viewId == PIPELINE_VIEW_UNCLASSIFIED -> { + val allPipelineIds = pipelineInfoDao.listPipelineIdByProject(dslContext, projectId).toMutableSet() + pipelineIds.addAll( + allPipelineIds.subtract(pipelineViewGroupService.getClassifiedPipelineIds(projectId).toSet()) + ) + // 避免过滤器为空的情况 + if (pipelineIds.isEmpty()) { + pipelineIds.add("##NONE##") + } + } + // 最近使用过的流水线组 + viewId == PIPELINE_VIEW_RECENT_USE -> { + pipelineIds.addAll(pipelineRecentUseService.listPipelineIds(userId, projectId)) + } + } + + // 剔除掉filterByViewIds + if (filterByViewIds != null) { + val pipelineIdsByFilterViewIds = + pipelineViewGroupService.listPipelineIdsByViewIds(projectId, filterByViewIds.split(",")).toSet() + if (pipelineIds.isEmpty()) { + pipelineIds.addAll(pipelineIdsByFilterViewIds) + } else { + pipelineIds.retainAll(pipelineIdsByFilterViewIds) + } + } + return pipelineIds + } + private fun pipelineFilterParams( projectId: String, filterByPipelineName: String?, @@ -868,7 +818,8 @@ class PipelineListFacadeService @Autowired constructor( favorPipelines = favorPipelines, viewId = PIPELINE_VIEW_ALL_PIPELINES, includeDelete = false, - userId = userId + userId = userId, + permissionFlag = true ).toInt() val myFavoriteCount = pipelineBuildSummaryDao.listPipelineInfoBuildSummaryCount( dslContext = dslContext, @@ -878,7 +829,8 @@ class PipelineListFacadeService @Autowired constructor( favorPipelines = favorPipelines, viewId = PIPELINE_VIEW_FAVORITE_PIPELINES, includeDelete = false, - userId = userId + userId = userId, + permissionFlag = true ).toInt() val myPipelineCount = pipelineBuildSummaryDao.listPipelineInfoBuildSummaryCount( dslContext = dslContext, @@ -888,7 +840,8 @@ class PipelineListFacadeService @Autowired constructor( favorPipelines = favorPipelines, viewId = PIPELINE_VIEW_MY_PIPELINES, includeDelete = false, - userId = userId + userId = userId, + permissionFlag = true ).toInt() val recentUseCount = pipelineBuildSummaryDao.listPipelineInfoBuildSummaryCount( dslContext = dslContext, @@ -899,7 +852,8 @@ class PipelineListFacadeService @Autowired constructor( viewId = PIPELINE_VIEW_RECENT_USE, includeDelete = false, userId = userId, - pipelineIds = recentUsePipelines + pipelineIds = recentUsePipelines, + permissionFlag = true ).toInt() val recycleCount = pipelineInfoDao.countPipeline( dslContext = dslContext, diff --git a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/view/PipelineViewGroupService.kt b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/view/PipelineViewGroupService.kt index 95954fe05e8..d7b2d5a0dcd 100644 --- a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/view/PipelineViewGroupService.kt +++ b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/view/PipelineViewGroupService.kt @@ -41,6 +41,7 @@ import com.tencent.devops.common.api.util.Watcher import com.tencent.devops.common.api.util.timestamp import com.tencent.devops.common.audit.ActionAuditContent import com.tencent.devops.common.auth.api.ActionId +import com.tencent.devops.common.auth.api.AuthPermission import com.tencent.devops.common.auth.api.ResourceTypeId import com.tencent.devops.common.client.Client import com.tencent.devops.common.client.ClientTokenService @@ -58,6 +59,7 @@ import com.tencent.devops.process.dao.label.PipelineViewTopDao import com.tencent.devops.process.engine.dao.PipelineInfoDao import com.tencent.devops.process.engine.dao.PipelineYamlViewDao import com.tencent.devops.process.enums.OperationLogType +import com.tencent.devops.process.permission.PipelinePermissionService import com.tencent.devops.process.pojo.classify.PipelineNewView import com.tencent.devops.process.pojo.classify.PipelineNewViewSummary import com.tencent.devops.process.pojo.classify.PipelineViewBulkAdd @@ -95,7 +97,8 @@ class PipelineViewGroupService @Autowired constructor( private val client: Client, private val clientTokenService: ClientTokenService, private val operationLogService: PipelineOperationLogService, - private val pipelineYamlViewDao: PipelineYamlViewDao + private val pipelineYamlViewDao: PipelineYamlViewDao, + private val pipelinePermissionService: PipelinePermissionService ) { private val allPipelineInfoCache = Caffeine.newBuilder() .maximumSize(10) @@ -837,7 +840,15 @@ class PipelineViewGroupService @Autowired constructor( fun listView(userId: String, projectId: String, projected: Boolean?, viewType: Int?): List { val views = pipelineViewDao.list(dslContext, userId, projectId, projected, viewType) - val countByViewId = pipelineViewGroupDao.countByViewId(dslContext, projectId, views.map { it.id }) + val authPipelines = pipelinePermissionService.getResourceByPermission( + userId = userId, projectId = projectId, permission = AuthPermission.LIST + ) + val countByViewId = pipelineViewGroupDao.countByViewId( + dslContext = dslContext, + projectId = projectId, + viewIds = views.map { it.id }, + filterPipelineIds = authPipelines + ) val yamlViews = pipelineYamlViewDao.listViewIds(dslContext, projectId) // 确保数据都初始化一下 views.filter { it.viewType == PipelineViewType.DYNAMIC } @@ -846,20 +857,26 @@ class PipelineViewGroupService @Autowired constructor( if (projected != false) { val classifiedPipelineIds = getClassifiedPipelineIds(projectId) val unclassifiedCount = - pipelineInfoDao.countExcludePipelineIds(dslContext, projectId, classifiedPipelineIds, ChannelCode.BS) - summaries.add( - 0, PipelineNewViewSummary( - id = PIPELINE_VIEW_UNCLASSIFIED, + pipelineInfoDao.countExcludePipelineIds( + dslContext = dslContext, projectId = projectId, - name = I18nUtil.getCodeLanMessage(PIPELINE_VIEW_UNCLASSIFIED), - projected = true, - createTime = LocalDateTime.now().timestamp(), - updateTime = LocalDateTime.now().timestamp(), - creator = "admin", - top = false, - viewType = PipelineViewType.UNCLASSIFIED, - pipelineCount = unclassifiedCount + excludePipelineIds = classifiedPipelineIds, + channelCode = ChannelCode.BS, + filterPipelineIds = authPipelines ) + summaries.add( + 0, PipelineNewViewSummary( + id = PIPELINE_VIEW_UNCLASSIFIED, + projectId = projectId, + name = I18nUtil.getCodeLanMessage(PIPELINE_VIEW_UNCLASSIFIED), + projected = true, + createTime = LocalDateTime.now().timestamp(), + updateTime = LocalDateTime.now().timestamp(), + creator = "admin", + top = false, + viewType = PipelineViewType.UNCLASSIFIED, + pipelineCount = unclassifiedCount + ) ) } return summaries diff --git a/src/backend/ci/core/process/biz-process/src/test/kotlin/com/tencent/devops/process/service/view/PipelineViewGroupServiceTest.kt b/src/backend/ci/core/process/biz-process/src/test/kotlin/com/tencent/devops/process/service/view/PipelineViewGroupServiceTest.kt index 39de1e17ee1..dae78d0f55e 100644 --- a/src/backend/ci/core/process/biz-process/src/test/kotlin/com/tencent/devops/process/service/view/PipelineViewGroupServiceTest.kt +++ b/src/backend/ci/core/process/biz-process/src/test/kotlin/com/tencent/devops/process/service/view/PipelineViewGroupServiceTest.kt @@ -70,7 +70,8 @@ class PipelineViewGroupServiceTest : BkCiAbstractTest() { client = client, clientTokenService = clientTokenService, operationLogService = operationLogService, - pipelineYamlViewDao = pipelineYamlViewDao + pipelineYamlViewDao = pipelineYamlViewDao, + pipelinePermissionService = pipelinePermissionService ), recordPrivateCalls = true ) @@ -904,8 +905,9 @@ class PipelineViewGroupServiceTest : BkCiAbstractTest() { @DisplayName("是项目流水线组") fun test_1() { every { pipelineViewDao.list(anyDslContext(), any(), any(), any(), any()) } returns emptyList() - every { pipelineViewGroupDao.countByViewId(anyDslContext(), any(), any()) } returns emptyMap() + every { pipelineViewGroupDao.countByViewId(anyDslContext(), any(), any(), any()) } returns emptyMap() every { pipelineYamlViewDao.listViewIds(anyDslContext(), any()) } returns emptyList() + every { pipelinePermissionService.getResourceByPermission(any(), any(), any()) } returns emptyList() every { self["sortViews2Summary"]( any() as String, @@ -924,8 +926,9 @@ class PipelineViewGroupServiceTest : BkCiAbstractTest() { @DisplayName("不是项目流水线组") fun test_2() { every { pipelineViewDao.list(anyDslContext(), any(), any(), any(), any()) } returns emptyList() - every { pipelineViewGroupDao.countByViewId(anyDslContext(), any(), any()) } returns emptyMap() + every { pipelineViewGroupDao.countByViewId(anyDslContext(), any(), any(), any()) } returns emptyMap() every { pipelineYamlViewDao.listViewIds(anyDslContext(), any()) } returns emptyList() + every { pipelinePermissionService.getResourceByPermission(any(), any(), any()) } returns emptyList() every { self["sortViews2Summary"]( any() as String, @@ -936,7 +939,7 @@ class PipelineViewGroupServiceTest : BkCiAbstractTest() { ) } returns mutableListOf() every { self["getClassifiedPipelineIds"](any() as String) } returns emptyList() - every { pipelineInfoDao.countExcludePipelineIds(anyDslContext(), any(), any(), any()) } returns 0 + every { pipelineInfoDao.countExcludePipelineIds(anyDslContext(), any(), any(), any(), any(), any()) } returns 0 self.listView("test", "test", true, PipelineViewType.DYNAMIC).let { Assertions.assertEquals(it.size, 1) Assertions.assertEquals(it[0].id, PIPELINE_VIEW_UNCLASSIFIED) From d0c464fe3429f998f95217a06b4dc21ea10dd658 Mon Sep 17 00:00:00 2001 From: greysonfang Date: Wed, 16 Oct 2024 11:25:37 +0800 Subject: [PATCH 2/9] =?UTF-8?q?feat=EF=BC=9A=E6=B5=81=E6=B0=B4=E7=BA=BF?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E5=B1=95=E7=A4=BA=E6=9D=83=E9=99=90=E6=8E=A7?= =?UTF-8?q?=E5=88=B6=20#10895?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RbacPipelinePermissionService.kt | 29 ++------ .../config/PipelinePermConfiguration.kt | 6 +- .../service/PipelineListFacadeService.kt | 66 +++--------------- .../view/PipelineViewGroupCommonService.kt | 67 +++++++++++++++++++ .../service/view/PipelineViewGroupService.kt | 26 ++----- 5 files changed, 90 insertions(+), 104 deletions(-) create mode 100644 src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/view/PipelineViewGroupCommonService.kt diff --git a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/RbacPipelinePermissionService.kt b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/RbacPipelinePermissionService.kt index 402f462230f..af215dc9c3d 100644 --- a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/RbacPipelinePermissionService.kt +++ b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/RbacPipelinePermissionService.kt @@ -37,8 +37,8 @@ import com.tencent.devops.common.auth.api.AuthResourceType import com.tencent.devops.common.auth.api.pojo.AuthResourceInstance import com.tencent.devops.common.auth.api.pojo.BkAuthGroup import com.tencent.devops.common.auth.code.PipelineAuthServiceCode -import com.tencent.devops.process.dao.label.PipelineViewGroupDao import com.tencent.devops.process.engine.dao.PipelineInfoDao +import com.tencent.devops.process.service.view.PipelineViewGroupCommonService import org.jooq.DSLContext import org.slf4j.LoggerFactory @@ -49,7 +49,7 @@ class RbacPipelinePermissionService( val pipelineAuthServiceCode: PipelineAuthServiceCode, val dslContext: DSLContext, val pipelineInfoDao: PipelineInfoDao, - val pipelineViewGroupDao: PipelineViewGroupDao, + val pipelineViewGroupCommonService: PipelineViewGroupCommonService, val authResourceApi: AuthResourceApi ) : PipelinePermissionService { @@ -105,12 +105,7 @@ class RbacPipelinePermissionService( resourceCode = projectId ) parents.add(projectInstance) - val pipelineIds = pipelineViewGroupDao.listByPipelineId( - dslContext = dslContext, - projectId = projectId, - pipelineId = pipelineId - ).map { it.viewId }.toSet() - pipelineIds.forEach { viewId -> + pipelineViewGroupCommonService.listViewIdsByPipelineId(projectId, pipelineId).forEach { viewId -> parents.add( AuthResourceInstance( resourceType = AuthResourceType.PIPELINE_GROUP.value, @@ -130,11 +125,10 @@ class RbacPipelinePermissionService( projectId: String, pipelineIds: List ): List { - val listViewIdsMap = pipelineViewGroupDao.listByPipelineIds( - dslContext = dslContext, + val listViewIdsMap = pipelineViewGroupCommonService.listViewIdsMap( projectId = projectId, pipelineIds = pipelineIds - ).groupBy({ it.pipelineId }, { it.viewId }) + ) return pipelineIds.map { pipelineId -> val parents = mutableListOf() val projectInstance = AuthResourceInstance( @@ -208,18 +202,7 @@ class RbacPipelinePermissionService( else -> { // 获取有权限流水线组下的流水线 val authViewPipelineIds = instanceMap[AuthResourceType.PIPELINE_GROUP.value]?.let { authViewIds -> - val viewIds = authViewIds.map { HashUtil.decodeIdToLong(it) } - val pipelineIds = mutableListOf() - val viewGroups = pipelineViewGroupDao.listByViewIds(dslContext, projectId, viewIds) - if (viewGroups.isEmpty()) { - pipelineIds.addAll(emptyList()) - } else { - pipelineIds.addAll(viewGroups.map { it.pipelineId }.toList()) - } - if (pipelineIds.isEmpty()) { - pipelineIds.add("##NONE##") // 特殊标志,避免有些判空逻辑导致过滤器没有执行 - } - pipelineIds + pipelineViewGroupCommonService.listPipelineIdsByViewIds(projectId, authViewIds) } ?: emptyList() // 获取有权限的流水线列表 val authPipelineIds = instanceMap[AuthResourceType.PIPELINE_DEFAULT.value] ?: emptyList() diff --git a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/config/PipelinePermConfiguration.kt b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/config/PipelinePermConfiguration.kt index 82e87dc0e27..14f6008c638 100644 --- a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/config/PipelinePermConfiguration.kt +++ b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/config/PipelinePermConfiguration.kt @@ -33,12 +33,12 @@ import com.tencent.devops.common.auth.api.AuthResourceApi import com.tencent.devops.common.auth.code.PipelineAuthServiceCode import com.tencent.devops.common.client.Client import com.tencent.devops.common.client.ClientTokenService -import com.tencent.devops.process.dao.label.PipelineViewGroupDao import com.tencent.devops.process.engine.dao.PipelineInfoDao import com.tencent.devops.process.permission.MockPipelinePermissionService import com.tencent.devops.process.permission.PipelinePermissionService import com.tencent.devops.process.permission.RbacPipelinePermissionService import com.tencent.devops.process.permission.StreamPipelinePermissionServiceImpl +import com.tencent.devops.process.service.view.PipelineViewGroupCommonService import org.jooq.DSLContext import org.springframework.boot.autoconfigure.AutoConfigureOrder import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty @@ -107,7 +107,7 @@ class PipelinePermConfiguration { pipelineAuthServiceCode: PipelineAuthServiceCode, dslContext: DSLContext, pipelineInfoDao: PipelineInfoDao, - pipelineViewGroupDao: PipelineViewGroupDao, + pipelineViewGroupCommonService: PipelineViewGroupCommonService, authResourceApi: AuthResourceApi ): PipelinePermissionService = RbacPipelinePermissionService( authPermissionApi = authPermissionApi, @@ -115,7 +115,7 @@ class PipelinePermConfiguration { pipelineAuthServiceCode = pipelineAuthServiceCode, dslContext = dslContext, pipelineInfoDao = pipelineInfoDao, - pipelineViewGroupDao = pipelineViewGroupDao, + pipelineViewGroupCommonService = pipelineViewGroupCommonService, authResourceApi = authResourceApi ) } diff --git a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/PipelineListFacadeService.kt b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/PipelineListFacadeService.kt index 7c34907ae26..eb255c354d7 100644 --- a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/PipelineListFacadeService.kt +++ b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/PipelineListFacadeService.kt @@ -521,6 +521,12 @@ class PipelineListFacadeService @Autowired constructor( watcher.start("s_r_summary") try { + // 记录用户最近使用过的视图 + pipelineViewService.addUsingView( + userId = userId, + projectId = projectId, + viewId = viewId + ) val favorPipelines = pipelineGroupService.getFavorPipelines( userId = userId, projectId = projectId @@ -532,26 +538,20 @@ class PipelineListFacadeService @Autowired constructor( filterByCreator = filterByCreator, filterByLabels = filterByLabels ) - - val pipelineIds = mutableSetOf() // 根据视图类型获取流水线 - val pipelineIdsByViewId = listPipelineIdsByViewId( + val pipelineIdsFilterByView = listPipelineIdsByViewId( userId = userId, projectId = projectId, viewId = viewId, filterByViewIds = filterByViewIds ) - if (pipelineIdsByViewId.isNotEmpty()) { - pipelineIds.addAll(pipelineIdsByViewId) - } - val includeDelete = showDelete && (PIPELINE_VIEW_RECENT_USE == viewId || !DEFAULT_VIEW_IDS.contains(viewId)) // 查询有权限查看的流水线总数 val totalAvailablePipelineSize = pipelineBuildSummaryDao.listPipelineInfoBuildSummaryCount( dslContext = dslContext, projectId = projectId, channelCode = channelCode, - pipelineIds = pipelineIds, + pipelineIds = pipelineIdsFilterByView, favorPipelines = favorPipelines, authPipelines = authPipelines, viewId = viewId, @@ -568,7 +568,7 @@ class PipelineListFacadeService @Autowired constructor( projectId = projectId, channelCode = channelCode, sortType = sortType, - pipelineIds = pipelineIds, + pipelineIds = pipelineIdsFilterByView, favorPipelines = favorPipelines, authPipelines = authPipelines, viewId = viewId, @@ -581,25 +581,6 @@ class PipelineListFacadeService @Autowired constructor( userId = userId, queryByWeb = queryByWeb ) - } else if ((null != page && null != pageSize) && !(page == 1 && pageSize == -1)) { - handlePipelineQueryList( - pipelineList = pipelineList, - projectId = projectId, - channelCode = channelCode, - sortType = sortType, - pipelineIds = pipelineIds, - favorPipelines = favorPipelines, - authPipelines = authPipelines, - viewId = viewId, - pipelineFilterParamList = pipelineFilterParamList, - permissionFlag = true, - page = page, - pageSize = pageSize, - includeDelete = includeDelete, - collation = collation, - userId = userId, - queryByWeb = queryByWeb - ) } else { // 不分页查询 handlePipelineQueryList( @@ -607,7 +588,7 @@ class PipelineListFacadeService @Autowired constructor( projectId = projectId, channelCode = channelCode, sortType = sortType, - pipelineIds = pipelineIds, + pipelineIds = pipelineIdsFilterByView, favorPipelines = favorPipelines, authPipelines = authPipelines, viewId = viewId, @@ -620,34 +601,7 @@ class PipelineListFacadeService @Autowired constructor( userId = userId, queryByWeb = queryByWeb ) - - if (filterInvalid) { - handlePipelineQueryList( - pipelineList = pipelineList, - projectId = projectId, - channelCode = channelCode, - sortType = sortType, - pipelineIds = pipelineIds, - favorPipelines = favorPipelines, - authPipelines = authPipelines, - viewId = viewId, - pipelineFilterParamList = pipelineFilterParamList, - permissionFlag = false, - page = page, - pageSize = pageSize, - includeDelete = includeDelete, - collation = collation, - userId = userId, - queryByWeb = queryByWeb - ) - } } - // 记录用户最近使用过的视图 - pipelineViewService.addUsingView( - userId = userId, - projectId = projectId, - viewId = viewId - ) watcher.stop() return PipelineViewPipelinePage( page = page ?: 1, diff --git a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/view/PipelineViewGroupCommonService.kt b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/view/PipelineViewGroupCommonService.kt new file mode 100644 index 00000000000..733fcf588f2 --- /dev/null +++ b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/view/PipelineViewGroupCommonService.kt @@ -0,0 +1,67 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license. + * + * A copy of the MIT License is included in this file. + * + * + * Terms of the MIT License: + * --------------------------------------------------- + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of + * the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package com.tencent.devops.process.service.view + +import com.tencent.devops.common.api.util.HashUtil +import com.tencent.devops.process.dao.label.PipelineViewGroupDao +import org.jooq.DSLContext +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Service + +@Service +class PipelineViewGroupCommonService @Autowired constructor( + private val pipelineViewGroupDao: PipelineViewGroupDao, + private val dslContext: DSLContext +) { + fun listPipelineIdsByViewIds(projectId: String, viewIdsEncode: List): List { + val viewIds = viewIdsEncode.map { HashUtil.decodeIdToLong(it) } + val pipelineIds = mutableListOf() + val viewGroups = pipelineViewGroupDao.listByViewIds(dslContext, projectId, viewIds) + if (viewGroups.isEmpty()) { + pipelineIds.addAll(emptyList()) + } else { + pipelineIds.addAll(viewGroups.map { it.pipelineId }.toList()) + } + if (pipelineIds.isEmpty()) { + pipelineIds.add("##NONE##") // 特殊标志,避免有些判空逻辑导致过滤器没有执行 + } + return pipelineIds + } + + fun listViewIdsByPipelineId(projectId: String, pipelineId: String): Set { + return pipelineViewGroupDao.listByPipelineId(dslContext, projectId, pipelineId).map { it.viewId }.toSet() + } + + fun listViewIdsMap(projectId: String, pipelineIds: List): Map> { + return pipelineViewGroupDao.listByPipelineIds( + dslContext = dslContext, + projectId = projectId, + pipelineIds = pipelineIds + ).groupBy({ it.pipelineId }, { it.viewId }) + } +} diff --git a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/view/PipelineViewGroupService.kt b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/view/PipelineViewGroupService.kt index d7b2d5a0dcd..96108165f9c 100644 --- a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/view/PipelineViewGroupService.kt +++ b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/view/PipelineViewGroupService.kt @@ -98,7 +98,8 @@ class PipelineViewGroupService @Autowired constructor( private val clientTokenService: ClientTokenService, private val operationLogService: PipelineOperationLogService, private val pipelineYamlViewDao: PipelineYamlViewDao, - private val pipelinePermissionService: PipelinePermissionService + private val pipelinePermissionService: PipelinePermissionService, + private val pipelineViewGroupCommonService: PipelineViewGroupCommonService ) { private val allPipelineInfoCache = Caffeine.newBuilder() .maximumSize(10) @@ -329,18 +330,7 @@ class PipelineViewGroupService @Autowired constructor( } fun listPipelineIdsByViewIds(projectId: String, viewIdsEncode: List): List { - val viewIds = viewIdsEncode.map { HashUtil.decodeIdToLong(it) } - val pipelineIds = mutableListOf() - val viewGroups = pipelineViewGroupDao.listByViewIds(dslContext, projectId, viewIds) - if (viewGroups.isEmpty()) { - pipelineIds.addAll(emptyList()) - } else { - pipelineIds.addAll(viewGroups.map { it.pipelineId }.toList()) - } - if (pipelineIds.isEmpty()) { - pipelineIds.add("##NONE##") // 特殊标志,避免有些判空逻辑导致过滤器没有执行 - } - return pipelineIds + return pipelineViewGroupCommonService.listPipelineIdsByViewIds(projectId, viewIdsEncode) } fun listPipelineIdsByViewId(projectId: String, viewIdEncode: String): List { @@ -989,15 +979,7 @@ class PipelineViewGroupService @Autowired constructor( } fun listViewIdsByPipelineId(projectId: String, pipelineId: String): Set { - return pipelineViewGroupDao.listByPipelineId(dslContext, projectId, pipelineId).map { it.viewId }.toSet() - } - - fun listViewIdsMap(projectId: String, pipelineIds: List): Map> { - return pipelineViewGroupDao.listByPipelineIds( - dslContext = dslContext, - projectId = projectId, - pipelineIds = pipelineIds - ).groupBy({ it.pipelineId }, { it.viewId }) + return pipelineViewGroupCommonService.listViewIdsByPipelineId(projectId, pipelineId) } fun listViewIdsByProjectId(projectId: String): Set { From eeb1fc9c87670eb58cd4911af93cdbe4e5b4d1b7 Mon Sep 17 00:00:00 2001 From: greysonfang Date: Wed, 16 Oct 2024 11:48:43 +0800 Subject: [PATCH 3/9] =?UTF-8?q?feat=EF=BC=9A=E6=B5=81=E6=B0=B4=E7=BA=BF?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E5=B1=95=E7=A4=BA=E6=9D=83=E9=99=90=E6=8E=A7?= =?UTF-8?q?=E5=88=B6=20#10895?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/view/PipelineViewGroupServiceTest.kt | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/backend/ci/core/process/biz-process/src/test/kotlin/com/tencent/devops/process/service/view/PipelineViewGroupServiceTest.kt b/src/backend/ci/core/process/biz-process/src/test/kotlin/com/tencent/devops/process/service/view/PipelineViewGroupServiceTest.kt index dae78d0f55e..d9713716dfe 100644 --- a/src/backend/ci/core/process/biz-process/src/test/kotlin/com/tencent/devops/process/service/view/PipelineViewGroupServiceTest.kt +++ b/src/backend/ci/core/process/biz-process/src/test/kotlin/com/tencent/devops/process/service/view/PipelineViewGroupServiceTest.kt @@ -56,6 +56,7 @@ class PipelineViewGroupServiceTest : BkCiAbstractTest() { private val clientTokenService: ClientTokenService = mockk() private val pipelineYamlViewDao: PipelineYamlViewDao = mockk() private val operationLogService: PipelineOperationLogService = mockk() + private val pipelineViewGroupCommonService: PipelineViewGroupCommonService = mockk() private val self: PipelineViewGroupService = spyk( PipelineViewGroupService( @@ -71,7 +72,16 @@ class PipelineViewGroupServiceTest : BkCiAbstractTest() { clientTokenService = clientTokenService, operationLogService = operationLogService, pipelineYamlViewDao = pipelineYamlViewDao, - pipelinePermissionService = pipelinePermissionService + pipelinePermissionService = pipelinePermissionService, + pipelineViewGroupCommonService = pipelineViewGroupCommonService + ), + recordPrivateCalls = true + ) + + private val self1: PipelineViewGroupCommonService = spyk( + PipelineViewGroupCommonService( + pipelineViewGroupDao = pipelineViewGroupDao, + dslContext = dslContext ), recordPrivateCalls = true ) @@ -394,7 +404,7 @@ class PipelineViewGroupServiceTest : BkCiAbstractTest() { @DisplayName("当ViewGroup为空列表时") fun test_1() { every { pipelineViewGroupDao.listByViewIds(anyDslContext(), any(), any()) } returns emptyList() - self.listPipelineIdsByViewIds("test", listOf("test")).let { + self1.listPipelineIdsByViewIds("test", listOf("test")).let { Assertions.assertTrue(it.size == 1) Assertions.assertEquals(it[0], "##NONE##") } @@ -404,7 +414,7 @@ class PipelineViewGroupServiceTest : BkCiAbstractTest() { @DisplayName("当ViewGroup不为空列表时") fun test_2() { every { pipelineViewGroupDao.listByViewIds(anyDslContext(), any(), any()) } returns listOf(pvg) - self.listPipelineIdsByViewIds("test", listOf("test")).let { + self1.listPipelineIdsByViewIds("test", listOf("test")).let { Assertions.assertTrue(it.size == 1) Assertions.assertEquals(it[0], pvg.pipelineId) } From 4af202f4a94f0f21cdaa9a1e9ccf5adf4040dac8 Mon Sep 17 00:00:00 2001 From: greysonfang Date: Mon, 28 Oct 2024 17:52:32 +0800 Subject: [PATCH 4/9] =?UTF-8?q?feat=EF=BC=9A=E6=B5=81=E6=B0=B4=E7=BA=BF?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E5=B1=95=E7=A4=BA=E6=9D=83=E9=99=90=E6=8E=A7?= =?UTF-8?q?=E5=88=B6=20#10895?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/api/migrate/OpAuthMigrateResource.kt | 8 + .../migrate/RbacPermissionMigrateService.kt | 11 + .../service/SamplePermissionMigrateService.kt | 2 + .../resources/OpAuthMigrateResourceImpl.kt | 4 + .../service/iam/PermissionMigrateService.kt | 5 + .../permission/PipelinePermissionService.kt | 6 + .../RbacPipelinePermissionService.kt | 12 +- .../StreamPipelinePermissionServiceImpl.kt | 2 + .../config/PipelinePermConfiguration.kt | 6 +- .../service/PipelineListFacadeService.kt | 198 +++++++++++++++++- .../service/view/PipelineViewGroupService.kt | 11 +- .../devops/project/pojo/ProjectProperties.kt | 4 +- 12 files changed, 260 insertions(+), 9 deletions(-) diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/migrate/OpAuthMigrateResource.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/migrate/OpAuthMigrateResource.kt index 868c8d533cc..98d9fb98965 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/migrate/OpAuthMigrateResource.kt +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/migrate/OpAuthMigrateResource.kt @@ -165,4 +165,12 @@ interface OpAuthMigrateResource { @Parameter(description = "迁移项目", required = true) projectCodes: List ): Result + + @POST + @Path("/enablePipelineListPermissionControl") + @Operation(summary = "开启流水线列表权限控制") + fun enablePipelineListPermissionControl( + @Parameter(description = "项目", required = true) + projectCodes: List + ): Result } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/migrate/RbacPermissionMigrateService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/migrate/RbacPermissionMigrateService.kt index 25241bdb92c..9e464c93f6f 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/migrate/RbacPermissionMigrateService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/migrate/RbacPermissionMigrateService.kt @@ -703,4 +703,15 @@ class RbacPermissionMigrateService constructor( } return true } + + override fun enablePipelineListPermissionControl(projectCodes: List): Boolean { + projectCodes.forEach { + val projectInfo = client.get(ServiceProjectResource::class).get(it).data!! + val properties = projectInfo.properties ?: ProjectProperties() + properties.pipelineListPermissionControl = true + logger.info("update project($it) properties|$properties") + client.get(ServiceProjectResource::class).updateProjectProperties(it, properties) + } + return true + } } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionMigrateService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionMigrateService.kt index aedbef85813..3c79190e0b0 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionMigrateService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionMigrateService.kt @@ -103,4 +103,6 @@ class SamplePermissionMigrateService( } override fun fixResourceGroups(projectCodes: List): Boolean = true + + override fun enablePipelineListPermissionControl(projectCodes: List) = true } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/OpAuthMigrateResourceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/OpAuthMigrateResourceImpl.kt index b2b53bb43bd..8592c98a9b3 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/OpAuthMigrateResourceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/OpAuthMigrateResourceImpl.kt @@ -113,4 +113,8 @@ class OpAuthMigrateResourceImpl @Autowired constructor( override fun fixResourceGroups(projectCodes: List): Result { return Result(permissionMigrateService.fixResourceGroups(projectCodes)) } + + override fun enablePipelineListPermissionControl(projectCodes: List): Result { + return Result(permissionMigrateService.enablePipelineListPermissionControl(projectCodes)) + } } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionMigrateService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionMigrateService.kt index 477cc8fe7c4..f9769b90ef3 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionMigrateService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionMigrateService.kt @@ -117,4 +117,9 @@ interface PermissionMigrateService { * 修复资源组数据,存在同步iam资源组数据,数据库 iam组id为NULL的情况,需要进行修复 */ fun fixResourceGroups(projectCodes: List): Boolean + + /** + * 开启流水线列表权限控制开关 + */ + fun enablePipelineListPermissionControl(projectCodes: List): Boolean } diff --git a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/PipelinePermissionService.kt b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/PipelinePermissionService.kt index 228b238c62b..51425474d52 100644 --- a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/PipelinePermissionService.kt +++ b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/PipelinePermissionService.kt @@ -154,4 +154,10 @@ interface PipelinePermissionService { userId: String, projectId: String ): Boolean + + /** + * 判断该项目是否进行列表权限控制 + * @param projectId projectId + */ + fun isControlPipelineListPermission(projectId: String): Boolean } diff --git a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/RbacPipelinePermissionService.kt b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/RbacPipelinePermissionService.kt index af215dc9c3d..2c6d78df27a 100644 --- a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/RbacPipelinePermissionService.kt +++ b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/RbacPipelinePermissionService.kt @@ -37,10 +37,13 @@ import com.tencent.devops.common.auth.api.AuthResourceType import com.tencent.devops.common.auth.api.pojo.AuthResourceInstance import com.tencent.devops.common.auth.api.pojo.BkAuthGroup import com.tencent.devops.common.auth.code.PipelineAuthServiceCode +import com.tencent.devops.common.client.Client import com.tencent.devops.process.engine.dao.PipelineInfoDao import com.tencent.devops.process.service.view.PipelineViewGroupCommonService +import com.tencent.devops.project.api.service.ServiceProjectResource import org.jooq.DSLContext import org.slf4j.LoggerFactory +import javax.ws.rs.NotFoundException @Suppress("LongParameterList") class RbacPipelinePermissionService( @@ -50,7 +53,8 @@ class RbacPipelinePermissionService( val dslContext: DSLContext, val pipelineInfoDao: PipelineInfoDao, val pipelineViewGroupCommonService: PipelineViewGroupCommonService, - val authResourceApi: AuthResourceApi + val authResourceApi: AuthResourceApi, + val client: Client ) : PipelinePermissionService { override fun checkPipelinePermission( @@ -296,6 +300,12 @@ class RbacPipelinePermissionService( return authProjectApi.checkProjectManager(userId, pipelineAuthServiceCode, projectId) } + override fun isControlPipelineListPermission(projectId: String): Boolean { + val projectInfo = client.get(ServiceProjectResource::class).get(englishName = projectId).data + ?: throw NotFoundException("Fail to find the project info of project($projectId)") + return projectInfo.properties?.pipelineListPermissionControl == true + } + companion object { private val resourceType = AuthResourceType.PIPELINE_DEFAULT private val logger = LoggerFactory.getLogger(RbacPipelinePermissionService::class.java) diff --git a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/StreamPipelinePermissionServiceImpl.kt b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/StreamPipelinePermissionServiceImpl.kt index 3c6123ba6b9..dc3dd010f9f 100644 --- a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/StreamPipelinePermissionServiceImpl.kt +++ b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/StreamPipelinePermissionServiceImpl.kt @@ -157,6 +157,8 @@ class StreamPipelinePermissionServiceImpl @Autowired constructor( ).data ?: false } + override fun isControlPipelineListPermission(projectId: String) = false + private fun getProjectAllInstance(projectId: String): List { return pipelineInfoDao.searchByProject(dslContext, projectId)?.map { it.pipelineId } ?: emptyList() } diff --git a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/config/PipelinePermConfiguration.kt b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/config/PipelinePermConfiguration.kt index 14f6008c638..92460f6d6c6 100644 --- a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/config/PipelinePermConfiguration.kt +++ b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/config/PipelinePermConfiguration.kt @@ -108,7 +108,8 @@ class PipelinePermConfiguration { dslContext: DSLContext, pipelineInfoDao: PipelineInfoDao, pipelineViewGroupCommonService: PipelineViewGroupCommonService, - authResourceApi: AuthResourceApi + authResourceApi: AuthResourceApi, + client: Client ): PipelinePermissionService = RbacPipelinePermissionService( authPermissionApi = authPermissionApi, authProjectApi = authProjectApi, @@ -116,6 +117,7 @@ class PipelinePermConfiguration { dslContext = dslContext, pipelineInfoDao = pipelineInfoDao, pipelineViewGroupCommonService = pipelineViewGroupCommonService, - authResourceApi = authResourceApi + authResourceApi = authResourceApi, + client = client ) } diff --git a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/PipelineListFacadeService.kt b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/PipelineListFacadeService.kt index eb255c354d7..79340c7f02c 100644 --- a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/PipelineListFacadeService.kt +++ b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/PipelineListFacadeService.kt @@ -560,8 +560,8 @@ class PipelineListFacadeService @Autowired constructor( includeDelete = includeDelete, userId = userId ) - val pipelineList = mutableListOf() + val isPipelineListPermissionControl = pipelinePermissionService.isControlPipelineListPermission(projectId) if (includeDelete) { handlePipelineQueryList( pipelineList = pipelineList, @@ -581,8 +581,29 @@ class PipelineListFacadeService @Autowired constructor( userId = userId, queryByWeb = queryByWeb ) + } else if (!isPipelineListPermissionControl) { + // 无列表权限控制下的流水线获取方法 + listPipelineWithoutPermission( + userId = userId, + projectId = projectId, + sortType = sortType, + channelCode = channelCode, + viewId = viewId, + filterInvalid = filterInvalid, + collation = collation, + queryByWeb = queryByWeb, + totalAvailablePipelineSize = totalAvailablePipelineSize, + pipelineList = pipelineList, + filterPipelineIds = pipelineIdsFilterByView, + favorPipelines = favorPipelines, + authPipelines = authPipelines, + pipelineFilterParamList = pipelineFilterParamList, + includeDelete = includeDelete, + page = page, + pageSize = pageSize + ) } else { - // 不分页查询 + // 列表权限控制下的流水线获取方法 handlePipelineQueryList( pipelineList = pipelineList, projectId = projectId, @@ -661,6 +682,179 @@ class PipelineListFacadeService @Autowired constructor( return pipelineIds } + /** + * 该方法之所以复杂,是为了达到将有权限列表的流水线展示在前面, + * 无列表权限的流水线挪在最后的目的。 + * 这种分页方法,需要对分页的各种情况的临界值进行处理。 + * */ + private fun listPipelineWithoutPermission( + userId: String, + projectId: String, + sortType: PipelineSortType, + channelCode: ChannelCode, + viewId: String, + filterInvalid: Boolean = false, + collation: PipelineCollation = PipelineCollation.DEFAULT, + queryByWeb: Boolean = false, + totalAvailablePipelineSize: Long, + pipelineList: MutableList, + filterPipelineIds: Collection? = null, + favorPipelines: List = emptyList(), + authPipelines: List = emptyList(), + pipelineFilterParamList: List? = null, + includeDelete: Boolean?, + page: Int?, + pageSize: Int? + ) { + // 查询无权限查看的流水线总数 + val totalInvalidPipelineSize = + if (filterInvalid) 0 else pipelineBuildSummaryDao.listPipelineInfoBuildSummaryCount( + dslContext = dslContext, + projectId = projectId, + channelCode = channelCode, + pipelineIds = filterPipelineIds, + viewId = viewId, + favorPipelines = favorPipelines, + authPipelines = authPipelines, + pipelineFilterParamList = pipelineFilterParamList, + permissionFlag = false, + includeDelete = includeDelete, + userId = userId + ) + + if ((null != page && null != pageSize) && !(page == 1 && pageSize == -1)) { + // 判断可用的流水线是否已到最后一页 + val totalAvailablePipelinePage = PageUtil.calTotalPage(pageSize, totalAvailablePipelineSize) + if (page < totalAvailablePipelinePage) { + // 当前页未到可用流水线最后一页,不需要处理临界点(最后一页)的情况 + handlePipelineQueryList( + pipelineList = pipelineList, + projectId = projectId, + channelCode = channelCode, + sortType = sortType, + pipelineIds = filterPipelineIds, + favorPipelines = favorPipelines, + authPipelines = authPipelines, + viewId = viewId, + pipelineFilterParamList = pipelineFilterParamList, + permissionFlag = true, + page = page, + pageSize = pageSize, + includeDelete = includeDelete, + collation = collation, + userId = userId, + queryByWeb = queryByWeb + ) + } else if (page == totalAvailablePipelinePage && totalAvailablePipelineSize > 0) { + // 查询可用流水线最后一页不满页的数量 + val lastPageRemainNum = pageSize - totalAvailablePipelineSize % pageSize + handlePipelineQueryList( + pipelineList = pipelineList, + projectId = projectId, + channelCode = channelCode, + sortType = sortType, + pipelineIds = filterPipelineIds, + favorPipelines = favorPipelines, + authPipelines = authPipelines, + viewId = viewId, + pipelineFilterParamList = pipelineFilterParamList, + permissionFlag = true, + page = page, + pageSize = pageSize, + includeDelete = includeDelete, + collation = collation, + userId = userId, + queryByWeb = queryByWeb + ) + // 可用流水线最后一页不满页的数量需用不可用的流水线填充 + if (lastPageRemainNum > 0 && totalInvalidPipelineSize > 0) { + handlePipelineQueryList( + pipelineList = pipelineList, + projectId = projectId, + channelCode = channelCode, + sortType = sortType, + pipelineIds = filterPipelineIds, + favorPipelines = favorPipelines, + authPipelines = authPipelines, + viewId = viewId, + pipelineFilterParamList = pipelineFilterParamList, + permissionFlag = false, + page = 1, + pageSize = lastPageRemainNum.toInt(), + includeDelete = includeDelete, + collation = collation, + userId = userId, + queryByWeb = queryByWeb + ) + } + } else if (totalInvalidPipelineSize > 0) { + // 当前页大于可用流水线最后一页,需要排除掉可用流水线最后一页不满页的数量用不可用的流水线填充的情况 + val lastPageRemainNum = + if (totalAvailablePipelineSize > 0) pageSize - totalAvailablePipelineSize % pageSize else 0 + handlePipelineQueryList( + pipelineList = pipelineList, + projectId = projectId, + channelCode = channelCode, + sortType = sortType, + pipelineIds = filterPipelineIds, + favorPipelines = favorPipelines, + authPipelines = authPipelines, + viewId = viewId, + pipelineFilterParamList = pipelineFilterParamList, + permissionFlag = false, + page = page - totalAvailablePipelinePage, + pageSize = pageSize, + pageOffsetNum = lastPageRemainNum.toInt(), + includeDelete = includeDelete, + collation = collation, + userId = userId, + queryByWeb = queryByWeb + ) + } + } else { + // 不分页查询 + handlePipelineQueryList( + pipelineList = pipelineList, + projectId = projectId, + channelCode = channelCode, + sortType = sortType, + pipelineIds = filterPipelineIds, + favorPipelines = favorPipelines, + authPipelines = authPipelines, + viewId = viewId, + pipelineFilterParamList = pipelineFilterParamList, + permissionFlag = true, + page = page, + pageSize = pageSize, + includeDelete = includeDelete, + collation = collation, + userId = userId, + queryByWeb = queryByWeb + ) + + if (filterInvalid) { + handlePipelineQueryList( + pipelineList = pipelineList, + projectId = projectId, + channelCode = channelCode, + sortType = sortType, + pipelineIds = filterPipelineIds, + favorPipelines = favorPipelines, + authPipelines = authPipelines, + viewId = viewId, + pipelineFilterParamList = pipelineFilterParamList, + permissionFlag = false, + page = page, + pageSize = pageSize, + includeDelete = includeDelete, + collation = collation, + userId = userId, + queryByWeb = queryByWeb + ) + } + } + } + private fun pipelineFilterParams( projectId: String, filterByPipelineName: String?, diff --git a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/view/PipelineViewGroupService.kt b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/view/PipelineViewGroupService.kt index 96108165f9c..f9292c49997 100644 --- a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/view/PipelineViewGroupService.kt +++ b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/view/PipelineViewGroupService.kt @@ -830,9 +830,14 @@ class PipelineViewGroupService @Autowired constructor( fun listView(userId: String, projectId: String, projected: Boolean?, viewType: Int?): List { val views = pipelineViewDao.list(dslContext, userId, projectId, projected, viewType) - val authPipelines = pipelinePermissionService.getResourceByPermission( - userId = userId, projectId = projectId, permission = AuthPermission.LIST - ) + val isControlPipelineListPermission = pipelinePermissionService.isControlPipelineListPermission(projectId) + val authPipelines = if (isControlPipelineListPermission) { + pipelinePermissionService.getResourceByPermission( + userId = userId, projectId = projectId, permission = AuthPermission.LIST + ) + } else { + null + } val countByViewId = pipelineViewGroupDao.countByViewId( dslContext = dslContext, projectId = projectId, diff --git a/src/backend/ci/core/project/api-project/src/main/kotlin/com/tencent/devops/project/pojo/ProjectProperties.kt b/src/backend/ci/core/project/api-project/src/main/kotlin/com/tencent/devops/project/pojo/ProjectProperties.kt index 2d33acb0ac4..18322222ca5 100644 --- a/src/backend/ci/core/project/api-project/src/main/kotlin/com/tencent/devops/project/pojo/ProjectProperties.kt +++ b/src/backend/ci/core/project/api-project/src/main/kotlin/com/tencent/devops/project/pojo/ProjectProperties.kt @@ -49,5 +49,7 @@ data class ProjectProperties( @get:Schema(title = "当项目不活跃时,是否禁用") var disableWhenInactive: Boolean? = null, @get:Schema(title = "该项目是否开启流水线可观测数据", required = false) - val buildMetrics: Boolean? = null + val buildMetrics: Boolean? = null, + @get:Schema(title = "是否控制流水线列表权限", required = false) + var pipelineListPermissionControl: Boolean? = null ) From 6b9f0758f7777db834f353746260038a961cbbfc Mon Sep 17 00:00:00 2001 From: greysonfang Date: Mon, 28 Oct 2024 19:59:39 +0800 Subject: [PATCH 5/9] =?UTF-8?q?feat=EF=BC=9A=E6=B5=81=E6=B0=B4=E7=BA=BF?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E5=B1=95=E7=A4=BA=E6=9D=83=E9=99=90=E6=8E=A7?= =?UTF-8?q?=E5=88=B6=20#10895?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../process/permission/AbstractPipelinePermissionService.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/AbstractPipelinePermissionService.kt b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/AbstractPipelinePermissionService.kt index 50b91946016..0ddfb5f80d6 100644 --- a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/AbstractPipelinePermissionService.kt +++ b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/permission/AbstractPipelinePermissionService.kt @@ -240,4 +240,8 @@ abstract class AbstractPipelinePermissionService constructor( serviceCode = pipelineAuthServiceCode ) } + + override fun isControlPipelineListPermission(projectId: String): Boolean { + return true + } } From 9b51322df4d1e052561c298c87a6c24dda478e36 Mon Sep 17 00:00:00 2001 From: greysonfang Date: Mon, 28 Oct 2024 21:07:45 +0800 Subject: [PATCH 6/9] =?UTF-8?q?feat=EF=BC=9A=E6=B5=81=E6=B0=B4=E7=BA=BF?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E5=B1=95=E7=A4=BA=E6=9D=83=E9=99=90=E6=8E=A7?= =?UTF-8?q?=E5=88=B6=20#10895?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../devops/process/service/PipelineListFacadeService.kt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/PipelineListFacadeService.kt b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/PipelineListFacadeService.kt index 79340c7f02c..aeaa6a9b481 100644 --- a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/PipelineListFacadeService.kt +++ b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/PipelineListFacadeService.kt @@ -573,7 +573,7 @@ class PipelineListFacadeService @Autowired constructor( authPipelines = authPipelines, viewId = viewId, pipelineFilterParamList = pipelineFilterParamList, - permissionFlag = null, + permissionFlag = true, page = page, pageSize = pageSize, includeDelete = true, @@ -956,6 +956,7 @@ class PipelineListFacadeService @Autowired constructor( val authPipelines = pipelinePermissionService.getResourceByPermission( userId = userId, projectId = projectId, permission = AuthPermission.LIST ) + val isControlPipelineListPermission = pipelinePermissionService.isControlPipelineListPermission(projectId) val favorPipelines = pipelineGroupService.getFavorPipelines(userId = userId, projectId = projectId) val recentUsePipelines = pipelineRecentUseService.listPipelineIds(userId, projectId) val totalCount = pipelineBuildSummaryDao.listPipelineInfoBuildSummaryCount( @@ -978,7 +979,7 @@ class PipelineListFacadeService @Autowired constructor( viewId = PIPELINE_VIEW_FAVORITE_PIPELINES, includeDelete = false, userId = userId, - permissionFlag = true + permissionFlag = isControlPipelineListPermission ).toInt() val myPipelineCount = pipelineBuildSummaryDao.listPipelineInfoBuildSummaryCount( dslContext = dslContext, @@ -989,7 +990,7 @@ class PipelineListFacadeService @Autowired constructor( viewId = PIPELINE_VIEW_MY_PIPELINES, includeDelete = false, userId = userId, - permissionFlag = true + permissionFlag = isControlPipelineListPermission ).toInt() val recentUseCount = pipelineBuildSummaryDao.listPipelineInfoBuildSummaryCount( dslContext = dslContext, @@ -1001,7 +1002,7 @@ class PipelineListFacadeService @Autowired constructor( includeDelete = false, userId = userId, pipelineIds = recentUsePipelines, - permissionFlag = true + permissionFlag = isControlPipelineListPermission ).toInt() val recycleCount = pipelineInfoDao.countPipeline( dslContext = dslContext, From 32e434932ff53f47b16b2d1b4e2353bf239a5a82 Mon Sep 17 00:00:00 2001 From: greysonfang Date: Tue, 29 Oct 2024 10:06:41 +0800 Subject: [PATCH 7/9] =?UTF-8?q?feat=EF=BC=9A=E6=B5=81=E6=B0=B4=E7=BA=BF?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E5=B1=95=E7=A4=BA=E6=9D=83=E9=99=90=E6=8E=A7?= =?UTF-8?q?=E5=88=B6=20#10895?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../devops/process/service/PipelineListFacadeService.kt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/PipelineListFacadeService.kt b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/PipelineListFacadeService.kt index aeaa6a9b481..0b0d59657da 100644 --- a/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/PipelineListFacadeService.kt +++ b/src/backend/ci/core/process/biz-process/src/main/kotlin/com/tencent/devops/process/service/PipelineListFacadeService.kt @@ -957,6 +957,7 @@ class PipelineListFacadeService @Autowired constructor( userId = userId, projectId = projectId, permission = AuthPermission.LIST ) val isControlPipelineListPermission = pipelinePermissionService.isControlPipelineListPermission(projectId) + val permissionFlag = if (isControlPipelineListPermission) true else null val favorPipelines = pipelineGroupService.getFavorPipelines(userId = userId, projectId = projectId) val recentUsePipelines = pipelineRecentUseService.listPipelineIds(userId, projectId) val totalCount = pipelineBuildSummaryDao.listPipelineInfoBuildSummaryCount( @@ -968,7 +969,7 @@ class PipelineListFacadeService @Autowired constructor( viewId = PIPELINE_VIEW_ALL_PIPELINES, includeDelete = false, userId = userId, - permissionFlag = true + permissionFlag = permissionFlag ).toInt() val myFavoriteCount = pipelineBuildSummaryDao.listPipelineInfoBuildSummaryCount( dslContext = dslContext, @@ -979,7 +980,7 @@ class PipelineListFacadeService @Autowired constructor( viewId = PIPELINE_VIEW_FAVORITE_PIPELINES, includeDelete = false, userId = userId, - permissionFlag = isControlPipelineListPermission + permissionFlag = permissionFlag ).toInt() val myPipelineCount = pipelineBuildSummaryDao.listPipelineInfoBuildSummaryCount( dslContext = dslContext, @@ -990,7 +991,7 @@ class PipelineListFacadeService @Autowired constructor( viewId = PIPELINE_VIEW_MY_PIPELINES, includeDelete = false, userId = userId, - permissionFlag = isControlPipelineListPermission + permissionFlag = permissionFlag ).toInt() val recentUseCount = pipelineBuildSummaryDao.listPipelineInfoBuildSummaryCount( dslContext = dslContext, @@ -1002,7 +1003,7 @@ class PipelineListFacadeService @Autowired constructor( includeDelete = false, userId = userId, pipelineIds = recentUsePipelines, - permissionFlag = isControlPipelineListPermission + permissionFlag = permissionFlag ).toInt() val recycleCount = pipelineInfoDao.countPipeline( dslContext = dslContext, From a55c654aa5f240ec9ef3dc4f2045c5089a68e3fb Mon Sep 17 00:00:00 2001 From: greysonfang Date: Tue, 29 Oct 2024 10:19:05 +0800 Subject: [PATCH 8/9] =?UTF-8?q?feat=EF=BC=9A=E6=B5=81=E6=B0=B4=E7=BA=BF?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E5=B1=95=E7=A4=BA=E6=9D=83=E9=99=90=E6=8E=A7?= =?UTF-8?q?=E5=88=B6=20#10895?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/tencent/devops/project/pojo/ProjectProperties.kt | 9 ++++++++- .../project/pojo/enums/PluginDetailsDisplayOrder.kt | 7 +++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 src/backend/ci/core/project/api-project/src/main/kotlin/com/tencent/devops/project/pojo/enums/PluginDetailsDisplayOrder.kt diff --git a/src/backend/ci/core/project/api-project/src/main/kotlin/com/tencent/devops/project/pojo/ProjectProperties.kt b/src/backend/ci/core/project/api-project/src/main/kotlin/com/tencent/devops/project/pojo/ProjectProperties.kt index 18322222ca5..eeadad23319 100644 --- a/src/backend/ci/core/project/api-project/src/main/kotlin/com/tencent/devops/project/pojo/ProjectProperties.kt +++ b/src/backend/ci/core/project/api-project/src/main/kotlin/com/tencent/devops/project/pojo/ProjectProperties.kt @@ -28,6 +28,7 @@ package com.tencent.devops.project.pojo import com.tencent.devops.common.api.pojo.PipelineAsCodeSettings +import com.tencent.devops.project.pojo.enums.PluginDetailsDisplayOrder import io.swagger.v3.oas.annotations.media.Schema @Schema(title = "项目其他配置") @@ -51,5 +52,11 @@ data class ProjectProperties( @get:Schema(title = "该项目是否开启流水线可观测数据", required = false) val buildMetrics: Boolean? = null, @get:Schema(title = "是否控制流水线列表权限", required = false) - var pipelineListPermissionControl: Boolean? = null + var pipelineListPermissionControl: Boolean? = null, + @get:Schema(title = "插件详情展示顺序", required = false) + var pluginDetailsDisplayOrder: List? = listOf( + PluginDetailsDisplayOrder.LOG, + PluginDetailsDisplayOrder.ARTIFACT, + PluginDetailsDisplayOrder.CONFIG + ) ) diff --git a/src/backend/ci/core/project/api-project/src/main/kotlin/com/tencent/devops/project/pojo/enums/PluginDetailsDisplayOrder.kt b/src/backend/ci/core/project/api-project/src/main/kotlin/com/tencent/devops/project/pojo/enums/PluginDetailsDisplayOrder.kt new file mode 100644 index 00000000000..91d9dcc4e48 --- /dev/null +++ b/src/backend/ci/core/project/api-project/src/main/kotlin/com/tencent/devops/project/pojo/enums/PluginDetailsDisplayOrder.kt @@ -0,0 +1,7 @@ +package com.tencent.devops.project.pojo.enums + +enum class PluginDetailsDisplayOrder { + LOG, + ARTIFACT, + CONFIG +} From af618bba906610307965418c5dc1e2bc5dfd6d04 Mon Sep 17 00:00:00 2001 From: greysonfang Date: Tue, 29 Oct 2024 15:58:44 +0800 Subject: [PATCH 9/9] =?UTF-8?q?feat=EF=BC=9A=E6=B5=81=E6=B0=B4=E7=BA=BF?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E5=B1=95=E7=A4=BA=E6=9D=83=E9=99=90=E6=8E=A7?= =?UTF-8?q?=E5=88=B6=20#10895?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../process/service/view/PipelineViewGroupServiceTest.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/backend/ci/core/process/biz-process/src/test/kotlin/com/tencent/devops/process/service/view/PipelineViewGroupServiceTest.kt b/src/backend/ci/core/process/biz-process/src/test/kotlin/com/tencent/devops/process/service/view/PipelineViewGroupServiceTest.kt index 6896cfbc29b..4b0f187669b 100644 --- a/src/backend/ci/core/process/biz-process/src/test/kotlin/com/tencent/devops/process/service/view/PipelineViewGroupServiceTest.kt +++ b/src/backend/ci/core/process/biz-process/src/test/kotlin/com/tencent/devops/process/service/view/PipelineViewGroupServiceTest.kt @@ -918,6 +918,8 @@ class PipelineViewGroupServiceTest : BkCiAbstractTest() { every { pipelineViewGroupDao.countByViewId(anyDslContext(), any(), any(), any()) } returns emptyMap() every { pipelineYamlViewDao.listViewIds(anyDslContext(), any()) } returns emptyList() every { pipelinePermissionService.getResourceByPermission(any(), any(), any()) } returns emptyList() + every { pipelinePermissionService.isControlPipelineListPermission(any()) } returns true + every { self["sortViews2Summary"]( any() as String, @@ -939,6 +941,7 @@ class PipelineViewGroupServiceTest : BkCiAbstractTest() { every { pipelineViewGroupDao.countByViewId(anyDslContext(), any(), any(), any()) } returns emptyMap() every { pipelineYamlViewDao.listViewIds(anyDslContext(), any()) } returns emptyList() every { pipelinePermissionService.getResourceByPermission(any(), any(), any()) } returns emptyList() + every { pipelinePermissionService.isControlPipelineListPermission(any()) } returns true every { self["sortViews2Summary"]( any() as String,