From 8e840c7d3c949af8e2a8a3f1126883bc3b54ed28 Mon Sep 17 00:00:00 2001
From: Andrey Sobolev <haiodo@users.noreply.github.com>
Date: Sun, 13 Oct 2024 23:59:38 +0700
Subject: [PATCH] UBERF-8455: Fix admin users (#6909)

Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
---
 models/tracker/src/viewlets.ts                |  8 +++++-
 .../projects/ProjectPresenter.svelte          | 13 ++++++++--
 .../src/components/navigator/NavLink.svelte   |  3 ++-
 .../src/components/Navigator.svelte           | 16 +++++++-----
 server/middleware/src/spaceSecurity.ts        | 25 ++++++-------------
 server/middleware/src/utils.ts                |  4 +--
 6 files changed, 40 insertions(+), 29 deletions(-)

diff --git a/models/tracker/src/viewlets.ts b/models/tracker/src/viewlets.ts
index ac55bde0ee..ee25b63197 100644
--- a/models/tracker/src/viewlets.ts
+++ b/models/tracker/src/viewlets.ts
@@ -528,7 +528,13 @@ export function defineViewlets (builder: Builder): void {
         hiddenKeys: ['identifier', 'name', 'description']
       },
       config: [
-        '',
+        {
+          key: '',
+          presenter: tracker.component.ProjectPresenter,
+          props: {
+            openIssues: true
+          }
+        },
         'members',
         {
           key: 'defaultAssignee',
diff --git a/plugins/tracker-resources/src/components/projects/ProjectPresenter.svelte b/plugins/tracker-resources/src/components/projects/ProjectPresenter.svelte
index a68ced6268..b694ea84ec 100644
--- a/plugins/tracker-resources/src/components/projects/ProjectPresenter.svelte
+++ b/plugins/tracker-resources/src/components/projects/ProjectPresenter.svelte
@@ -13,7 +13,7 @@
 // limitations under the License.
 -->
 <script lang="ts">
-  import presentation from '@hcengineering/presentation'
+  import presentation, { isAdminUser } from '@hcengineering/presentation'
   import { Project } from '@hcengineering/tracker'
   import {
     Icon,
@@ -24,12 +24,15 @@
     themeStore
   } from '@hcengineering/ui'
   import view from '@hcengineering/view'
+  import { NavLink } from '@hcengineering/view-resources'
   import tracker from '../../plugin'
+  import { getCurrentAccount } from '@hcengineering/core'
 
   export let value: Project | undefined
   export let inline: boolean = false
   export let accent: boolean = false
   export let colorInherit: boolean = false
+  export let openIssues: boolean
 </script>
 
 {#if value}
@@ -49,7 +52,13 @@
       />
     </div>
     <span class="label no-underline nowrap" class:fs-bold={accent}>
-      {value.name}
+      {#if openIssues && (isAdminUser() || value.members.includes(getCurrentAccount()._id))}
+        <NavLink space={value._id} special={'issues'} noUnderline={false}>
+          {value.name}
+        </NavLink>
+      {:else}
+        {value.name}
+      {/if}
       {#if value.archived}
         <Label label={presentation.string.Archived} />
       {/if}
diff --git a/plugins/view-resources/src/components/navigator/NavLink.svelte b/plugins/view-resources/src/components/navigator/NavLink.svelte
index 62f047a630..39fd9864a7 100644
--- a/plugins/view-resources/src/components/navigator/NavLink.svelte
+++ b/plugins/view-resources/src/components/navigator/NavLink.svelte
@@ -22,6 +22,7 @@
   export let disabled = false
   export let shrink: number | undefined = undefined
   export let restoreLastLocation = false
+  export let noUnderline = true
 
   $: loc = createLocation($location, app, space, special)
 
@@ -76,7 +77,7 @@
 {#if disabled}
   <slot />
 {:else}
-  <a class="noUnderline noBold" style:flex-shrink={shrink} {href} on:click={clickHandler}>
+  <a class:noUnderline class="noBold" style:flex-shrink={shrink} {href} on:click={clickHandler}>
     <slot />
   </a>
 {/if}
diff --git a/plugins/workbench-resources/src/components/Navigator.svelte b/plugins/workbench-resources/src/components/Navigator.svelte
index 8536d5aeb7..10b72261af 100644
--- a/plugins/workbench-resources/src/components/Navigator.svelte
+++ b/plugins/workbench-resources/src/components/Navigator.svelte
@@ -16,7 +16,7 @@
   import core, { Doc, Ref, SortingOrder, Space, getCurrentAccount, hasAccountRole } from '@hcengineering/core'
   import { getResource } from '@hcengineering/platform'
   import preference, { SpacePreference } from '@hcengineering/preference'
-  import { createQuery, getClient } from '@hcengineering/presentation'
+  import { createQuery, getClient, isAdminUser } from '@hcengineering/presentation'
   import { Scroller, NavItem } from '@hcengineering/ui'
   import { NavLink } from '@hcengineering/view-resources'
   import type { Application, NavigatorModel, SpecialNavModel } from '@hcengineering/workbench'
@@ -40,6 +40,8 @@
   let starred: Space[] = []
   let shownSpaces: Space[] = []
 
+  const adminUser = isAdminUser()
+
   $: if (model) {
     const classes = Array.from(new Set(getSpecialSpaceClass(model).flatMap((c) => hierarchy.getDescendants(c)))).filter(
       (it) => !hierarchy.isMixin(it)
@@ -47,10 +49,12 @@
     if (classes.length > 0) {
       query.query(
         classes.length === 1 ? classes[0] : core.class.Space,
-        {
-          ...(classes.length === 1 ? {} : { _class: { $in: classes } }),
-          members: getCurrentAccount()._id
-        },
+        !adminUser
+          ? {
+              ...(classes.length === 1 ? {} : { _class: { $in: classes } }),
+              members: getCurrentAccount()._id
+            }
+          : { ...(classes.length === 1 ? {} : { _class: { $in: classes } }) },
         (result) => {
           spaces = result
         },
@@ -187,7 +191,7 @@
       />
     {/if}
 
-    {#each model.spaces as m, i (m.label)}
+    {#each model.spaces as m (m.label)}
       <SpacesNav
         spaces={shownSpaces.filter((it) => hierarchy.isDerived(it._class, m.spaceClass))}
         {currentSpace}
diff --git a/server/middleware/src/spaceSecurity.ts b/server/middleware/src/spaceSecurity.ts
index 04e447e047..a7e76eeba1 100644
--- a/server/middleware/src/spaceSecurity.ts
+++ b/server/middleware/src/spaceSecurity.ts
@@ -503,17 +503,14 @@ export class SpaceSecurityMiddleware extends BaseMiddleware implements Middlewar
     const isSpace = this.context.hierarchy.isDerived(_class, core.class.Space)
     const field = this.getKey(domain)
 
-    if (
-      ctx.contextData.admin === true &&
-      this.context.hierarchy.isDerived(_class, core.class.Space) &&
-      (newQuery as DocumentQuery<Space>).members !== undefined
-    ) {
-      delete (newQuery as any).members
-    }
-
     let clientFilterSpaces: Set<Ref<Space>> | undefined
 
-    if (!this.skipFindCheck && !isSystem(account) && account.role !== AccountRole.DocGuest && domain !== DOMAIN_MODEL) {
+    if (
+      !this.skipFindCheck &&
+      !isSystem(account, ctx) &&
+      account.role !== AccountRole.DocGuest &&
+      domain !== DOMAIN_MODEL
+    ) {
       if (!isOwner(account, ctx) || !isSpace) {
         if (query[field] !== undefined) {
           const res = await this.mergeQuery(ctx, account, query[field], domain, isSpace)
@@ -566,12 +563,6 @@ export class SpaceSecurityMiddleware extends BaseMiddleware implements Middlewar
         }
       }
     }
-    if (ctx.contextData.admin === true && this.context.hierarchy.isDerived(_class, core.class.Space)) {
-      // We need to add amin to all spaces.
-      for (const d of findResult) {
-        ;(d as unknown as Space).members = [...((d as unknown as Space).members ?? []), ctx.contextData.account._id]
-      }
-    }
     return findResult
   }
 
@@ -583,7 +574,7 @@ export class SpaceSecurityMiddleware extends BaseMiddleware implements Middlewar
     await this.init(ctx)
     const newQuery = { ...query }
     const account = ctx.contextData.account
-    if (!isSystem(account)) {
+    if (!isSystem(account, ctx)) {
       const allSpaces = this.getAllAllowedSpaces(account, true)
       if (query.classes !== undefined) {
         const res = new Set<Ref<Space>>()
@@ -610,7 +601,7 @@ export class SpaceSecurityMiddleware extends BaseMiddleware implements Middlewar
 
   async isUnavailable (ctx: MeasureContext<SessionData>, space: Ref<Space>): Promise<boolean> {
     const account = ctx.contextData.account
-    if (isSystem(account)) return false
+    if (isSystem(account, ctx)) return false
     return !this.getAllAllowedSpaces(account, true).includes(space)
   }
 
diff --git a/server/middleware/src/utils.ts b/server/middleware/src/utils.ts
index 95e188f5de..1ab7e9a17f 100644
--- a/server/middleware/src/utils.ts
+++ b/server/middleware/src/utils.ts
@@ -19,6 +19,6 @@ export function isOwner (account: Account, ctx: MeasureContext<SessionData>): bo
   return account.role === AccountRole.Owner || account._id === core.account.System || ctx.contextData.admin === true
 }
 
-export function isSystem (account: Account): boolean {
-  return account._id === core.account.System || account._id.startsWith('system:')
+export function isSystem (account: Account, ctx: MeasureContext<SessionData>): boolean {
+  return account._id === core.account.System || ctx.contextData.admin === true
 }