fix: goals archive exclude and permissions check for drilldown

This commit is contained in:
Nikolai Giman
2026-05-08 22:56:01 +02:00
parent f791822c79
commit 5afcc2d8ec
3 changed files with 37 additions and 23 deletions
@@ -29,14 +29,14 @@ export class AnalyticsManager {
}
async getAccessibleGoalIds(organizationId: number): Promise<number[]> {
const userData = this.user.getUserData()
if (!userData?.id || !userData?.email) return []
return this.fetchGoalIds(organizationId, [GoalPermissions.ANALYTICS_CAN_VIEW])
}
const ids = await this.user.organizationManager.isCurrentUserOrgOwner(organizationId)
? await this.repository.fetchAllGoalIdsInOrg(organizationId)
: await this.fetchMemberAccessibleGoalIds(userData.id, userData.email, organizationId)
return this.applyTokenFilter(ids)
async getDrillDownGoalIds(organizationId: number): Promise<number[]> {
return this.fetchGoalIds(organizationId, [
GoalPermissions.ANALYTICS_CAN_VIEW,
GoalPermissions.TASKS_CAN_WATCH_DETAILS,
])
}
async buildSections(params: AnalyticsArgBuildSections): Promise<AnalyticsSectionsResponse> {
@@ -96,7 +96,7 @@ export class AnalyticsManager {
return { sectionId, tasks: [], total: 0 }
}
const allAccessible = await this.getAccessibleGoalIds(organizationId)
const allAccessible = await this.getDrillDownGoalIds(organizationId)
const accessibleGoalIds = this.narrowToScope(allAccessible, scope)
const ctx: BuilderContext = {
@@ -116,13 +116,20 @@ export class AnalyticsManager {
return { sectionId, tasks, total: tasks.length }
}
private async fetchMemberAccessibleGoalIds(userId: number, email: string, organizationId: number): Promise<number[]> {
return this.repository.fetchGoalIdsWithPermission(
userId,
email,
organizationId,
GoalPermissions.ANALYTICS_CAN_VIEW,
)
private async fetchGoalIds(organizationId: number, permissions: string[]): Promise<number[]> {
const userData = this.user.getUserData()
if (!userData?.id || !userData?.email) return []
const ids = await this.user.organizationManager.isCurrentUserOrgOwner(organizationId)
? await this.repository.fetchAllGoalIdsInOrg(organizationId)
: await this.repository.fetchGoalIdsWithPermissions(
userData.id,
userData.email,
organizationId,
permissions,
)
return this.applyTokenFilter(ids)
}
private applyTokenFilter(ids: number[]): number[] {
@@ -1,4 +1,4 @@
import { eq, inArray, sql, type SQL } from 'drizzle-orm'
import { and, eq, inArray, sql, type SQL } from 'drizzle-orm'
import { GoalsSchema } from 'taskview-db-schemas'
import { Database } from '../../modules/db'
import { callWithCatch } from '../../utils/helpers'
@@ -74,24 +74,30 @@ export class AnalyticsRepository {
this.db.dbDrizzle
.select({ id: GoalsSchema.id })
.from(GoalsSchema)
.where(eq(GoalsSchema.organizationId, organizationId)),
.where(and(
eq(GoalsSchema.organizationId, organizationId),
eq(GoalsSchema.archive, 0),
)),
)
return (result ?? []).map(r => r.id).filter((id): id is number => id !== null)
}
async fetchGoalIdsWithPermission(
async fetchGoalIdsWithPermissions(
userId: number,
email: string,
organizationId: number,
permissionName: string,
permissionNames: string[],
): Promise<number[]> {
if (permissionNames.length === 0) return []
const result = await this.db.dbDrizzle.execute<{ id: number }>(sql`
select g.id from tasks.goals g
where g.organization_id = ${organizationId}
and g.archive = 0
and (
g.owner = ${userId}
or exists (
select 1
or (
select count(distinct p.name)
from collaboration.users cu
join collaboration.users_to_goals utg on utg.user_id = cu.id and utg.goal_id = g.id
join collaboration.users_to_roles utr on utr.user_id = cu.id
@@ -99,8 +105,8 @@ export class AnalyticsRepository {
join collaboration.permissions_to_role ptr on ptr.role_id = r.id
join tv_auth.permissions p on p.id = ptr.permission_id
where cu.email = ${email}
and p.name = ${permissionName}
)
and p.name = any(${sql`ARRAY[${sql.join(permissionNames.map(n => sql`${n}`), sql`, `)}]::text[]`})
) = ${permissionNames.length}
)
`)
return result.rows.map(r => Number(r.id)).filter(id => Number.isInteger(id))
@@ -88,6 +88,7 @@ export class WorkloadByAssigneeSection implements SectionBuilder {
no_priority: 'null',
}
const priorityFilter = priorityByDataset[arg.datasetId]
if (priorityFilter === undefined) return []
return ctx.repository.fetchOpenTasksAssignedWithPriority(
ctx.accessibleGoalIds,