Skip to content

Commit

Permalink
UBERF-5812: Fix allow to delete based on all my accounts
Browse files Browse the repository at this point in the history
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
  • Loading branch information
haiodo committed Mar 1, 2024
1 parent 94f1b86 commit 81a71e1
Show file tree
Hide file tree
Showing 15 changed files with 116 additions and 61 deletions.
2 changes: 1 addition & 1 deletion models/tracker/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ function defineApplication (
spaceClass: tracker.class.Project,
componentProps: {
_class: tracker.class.Project,
label: tracker.string.AllIssues,
label: tracker.string.AllProjects,
icon: tracker.icon.Issues
}
}
Expand Down
28 changes: 17 additions & 11 deletions packages/presentation/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,12 +187,22 @@ export async function setClient (_client: MeasureClient): Promise<void> {
* @public
*/
export async function refreshClient (): Promise<void> {
await liveQuery?.refreshConnect()
for (const q of globalQueries) {
q.refreshClient()
if (!(liveQuery?.isClosed() ?? true)) {
await liveQuery?.refreshConnect()
for (const q of globalQueries) {
q.refreshClient()
}
}
}

/**
* @public
*/
export async function purgeClient (): Promise<void> {
await liveQuery?.close()
await pipeline?.close()
}

/**
* @public
*/
Expand Down Expand Up @@ -529,13 +539,9 @@ export function isCollectionAttr (hierarchy: Hierarchy, key: KeyedAttribute): bo
* @public
*/
export function decodeTokenPayload (token: string): any {
const parts = token.split('.')

const payload = parts[1]

const decodedPayload = atob(payload)

const parsedPayload = JSON.parse(decodedPayload)
return JSON.parse(atob(token.split('.')[1]))
}

return parsedPayload
export function isAdminUser (): boolean {
return decodeTokenPayload(getMetadata(plugin.metadata.Token) ?? '').admin === 'true'
}
6 changes: 6 additions & 0 deletions packages/query/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export class LiveQuery implements WithTx, Client {
private readonly queries: Map<Ref<Class<Doc>>, Query[]> = new Map<Ref<Class<Doc>>, Query[]>()
private readonly queue: Query[] = []
private queryCounter: number = 0
private closed: boolean = false

// A map of _class to documents.
private readonly documentRefs = new Map<string, Map<Ref<Doc>, DocumentRef>>()
Expand All @@ -104,7 +105,12 @@ export class LiveQuery implements WithTx, Client {
await this.refreshConnect()
}

public isClosed (): boolean {
return this.closed
}

async close (): Promise<void> {
this.closed = true
await this.client.close()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,16 @@
// limitations under the License.
-->
<script lang="ts">
import { Card } from '@hcengineering/presentation'
import { AccountRole, Doc, getCurrentAccount, Ref } from '@hcengineering/core'
import { PersonAccount } from '@hcengineering/contact'
import { AccountRole, Doc, Ref, getCurrentAccount } from '@hcengineering/core'
import { Card, isAdminUser } from '@hcengineering/presentation'
import ui, { Button, Label } from '@hcengineering/ui'
import { ObjectPresenter } from '@hcengineering/view-resources'
import view from '@hcengineering/view-resources/src/plugin'
import { createEventDispatcher } from 'svelte'
import { PersonAccount } from '@hcengineering/contact'
import { personAccountByIdStore } from '../utils'
import ui, { Button, Label } from '@hcengineering/ui'
import PersonAccountRefPresenter from './PersonAccountRefPresenter.svelte'
import PersonAccountPresenter from './PersonAccountPresenter.svelte'
import { ObjectPresenter } from '@hcengineering/view-resources'
import PersonAccountRefPresenter from './PersonAccountRefPresenter.svelte'
export let object: Doc | Doc[]
export let deleteAction: () => void | Promise<void>
Expand All @@ -37,7 +37,8 @@
$: canDelete =
(skipCheck ||
(creators.length === 1 && creators.includes(getCurrentAccount()._id as Ref<PersonAccount>)) ||
getCurrentAccount().role === AccountRole.Owner) &&
(getCurrentAccount().role === AccountRole.Owner ||
isAdminUser())) &&
canDeleteExtra
$: label = canDelete ? view.string.DeleteObject : view.string.DeletePopupNoPermissionTitle
</script>
Expand Down
13 changes: 7 additions & 6 deletions plugins/hr-resources/src/components/schedule/MonthView.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,21 @@
import contact, { Employee } from '@hcengineering/contact'
import { AccountRole, getCurrentAccount, Ref } from '@hcengineering/core'
import { tzDateCompare, type Department, type Request, type RequestType, type Staff } from '@hcengineering/hr'
import { isAdminUser } from '@hcengineering/presentation'
import {
areDatesEqual,
day as getDay,
daysInMonth,
deviceOptionsStore as deviceInfo,
eventToHTMLElement,
day as getDay,
getWeekDayName,
isWeekend,
Label,
LabelAndProps,
resizeObserver,
Scroller,
showPopup,
tooltip,
deviceOptionsStore as deviceInfo,
resizeObserver
tooltip
} from '@hcengineering/ui'
import hr from '../../plugin'
import { getHolidayDatesForEmployee, getRequests, isHoliday } from '../../utils'
Expand Down Expand Up @@ -183,7 +184,7 @@
}
function isEditable (employee: Staff): boolean {
return editableList.includes(employee._id) && (isFutureDate() || me.role === AccountRole.Owner)
return editableList.includes(employee._id) && (isFutureDate() || me.role === AccountRole.Owner || isAdminUser())
}
function getTooltip (requests: Request[], day: Date, staff: Staff): LabelAndProps | undefined {
Expand Down Expand Up @@ -306,7 +307,7 @@
class="timeline-cell timeline-day-header flex-col-center justify-center"
style={getCellStyle()}
on:click={() => {
if (isFutureDate() || me.role === AccountRole.Owner) {
if (isFutureDate() || me.role === AccountRole.Owner || isAdminUser()) {
setPublicHoliday(day)
}
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<script lang="ts">
import { PersonAccount } from '@hcengineering/contact'
import { AccountRole, getCurrentAccount, roleOrder } from '@hcengineering/core'
import presentation, { createQuery, decodeTokenPayload } from '@hcengineering/presentation'
import { createQuery, isAdminUser } from '@hcengineering/presentation'
import setting, { SettingsCategory } from '@hcengineering/setting'
import {
Component,
Expand All @@ -27,7 +27,6 @@
} from '@hcengineering/ui'
import { onDestroy } from 'svelte'
import { clearSettingsStore } from '../store'
import { getMetadata } from '@hcengineering/platform'
export let kind: 'navigation' | 'content' | undefined
export let categoryName: string
Expand All @@ -39,7 +38,7 @@
let categories: SettingsCategory[] = []
const account = getCurrentAccount() as PersonAccount
const admin = decodeTokenPayload(getMetadata(presentation.metadata.Token) ?? '').admin === 'true'
const admin = isAdminUser()
const settingsQuery = createQuery()
settingsQuery.query(
Expand All @@ -48,7 +47,7 @@
(res) => {
categories = roleOrder[account.role] > roleOrder[AccountRole.User] ? res : res.filter((p) => !p.secured)
if (!admin) {
categories = categories.filter((p) => !p.adminOnly)
categories = categories.filter((p) => !(p.adminOnly ?? false))
}
category = findCategory(categoryId)
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@
-->
<script lang="ts">
import { Project } from '@hcengineering/tracker'
import { Icon, IconWithEmoji, getPlatformColorDef, getPlatformColorForTextDef, themeStore } from '@hcengineering/ui'
import { Icon, IconWithEmoji, getPlatformColorDef, getPlatformColorForTextDef, themeStore, Label } from '@hcengineering/ui'
import tracker from '../../plugin'
import view from '@hcengineering/view'
import presentation from '@hcengineering/presentation'
export let value: Project | undefined
export let inline: boolean = false
Expand All @@ -41,6 +42,9 @@
</div>
<span class="label no-underline nowrap" class:fs-bold={accent}>
{value.name}
{#if value.archived}
<Label label={presentation.string.Archived}/>
{/if}
</span>
</div>
{/if}
71 changes: 53 additions & 18 deletions plugins/view-resources/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@
import { Analytics } from '@hcengineering/analytics'
import core, {
AccountRole,
type FindOptions,
ClassifierKind,
Hierarchy,
TxProcessor,
getCurrentAccount,
getObjectValue,
type Account,
type AggregateValue,
type AttachedDoc,
type CategoryType,
Expand All @@ -27,9 +32,7 @@ import core, {
type Doc,
type DocumentQuery,
type DocumentUpdate,
getCurrentAccount,
getObjectValue,
Hierarchy,
type FindOptions,
type Lookup,
type Mixin,
type Obj,
Expand All @@ -38,38 +41,37 @@ import core, {
type ReverseLookup,
type ReverseLookups,
type Space,
type TxOperations,
type TxCUD,
type TxCollectionCUD,
TxProcessor,
type TxCreateDoc,
type TxUpdateDoc,
type TxMixin,
ClassifierKind,
type TxOperations,
type TxUpdateDoc,
type TypeAny
} from '@hcengineering/core'
import { type Restrictions } from '@hcengineering/guest'
import type { Asset, IntlString } from '@hcengineering/platform'
import { getResource, translate } from '@hcengineering/platform'
import {
type AttributeCategory,
getAttributePresenterClass,
getClient,
hasResource,
isAdminUser,
type AttributeCategory,
type KeyedAttribute
} from '@hcengineering/presentation'
import { type Restrictions } from '@hcengineering/guest'
import {
type AnyComponent,
type AnySvelteComponent,
ErrorPresenter,
getCurrentResolvedLocation,
getPanelURI,
getPlatformColorForText,
type Location,
locationToUrl,
navigate,
resolvedLocationStore,
themeStore
themeStore,
type AnyComponent,
type AnySvelteComponent,
type Location
} from '@hcengineering/ui'
import view, {
type AttributeModel,
Expand All @@ -80,10 +82,10 @@ import view, {
type ViewletDescriptor
} from '@hcengineering/view'

import contact, { getName, type Contact, type PersonAccount } from '@hcengineering/contact'
import { get, writable } from 'svelte/store'
import plugin from './plugin'
import { noCategory } from './viewOptions'
import contact, { type Contact, getName } from '@hcengineering/contact'

export { getFiltredKeys, isCollectionAttr } from '@hcengineering/presentation'

Expand Down Expand Up @@ -386,7 +388,8 @@ export async function buildModel (options: BuildModelOptions): Promise<Attribute

export async function deleteObject (client: TxOperations, object: Doc): Promise<void> {
const currentAcc = getCurrentAccount()
if (currentAcc.role !== AccountRole.Owner && object.createdBy !== currentAcc._id) return
const accounts = await getCurrentPersonAccounts()
if (currentAcc.role !== AccountRole.Owner && !accounts.has(object.createdBy)) return
if (client.getHierarchy().isDerived(object._class, core.class.AttachedDoc)) {
const adoc = object as AttachedDoc
await client
Expand All @@ -401,13 +404,45 @@ export async function deleteObject (client: TxOperations, object: Doc): Promise<
}
}

export async function getCurrentPersonAccounts (): Promise<Set<Ref<Account> | undefined>> {
return new Set(
(
await getClient().findAll(contact.class.PersonAccount, { person: (getCurrentAccount() as PersonAccount).person })
).map((it) => it._id)
)
}

export async function deleteObjects (client: TxOperations, objects: Doc[], skipCheck: boolean = false): Promise<void> {
let realObjects: Doc[] = []
if (!skipCheck) {
const currentAcc = getCurrentAccount()
if (currentAcc.role !== AccountRole.Owner && objects.some((p) => p.createdBy !== currentAcc._id)) return

// We need to find all person current accounts
const allPersonAccounts = await getCurrentPersonAccounts()

const byClass = new Map<Ref<Class<Doc>>, Doc[]>()
for (const d of objects) {
byClass.set(d._class, [...(byClass.get(d._class) ?? []), d])
}
const adminUser = isAdminUser()
for (const [cl, docs] of byClass.entries()) {
const realDocs = await client.findAll(cl, { _id: { $in: docs.map((it: Doc) => it._id) } })
const notAllowed = realDocs.filter((p) => !allPersonAccounts.has(p.createdBy))

if (notAllowed.length > 0) {
console.error('You are not allowed to delete this object', notAllowed)
}
if (currentAcc.role === AccountRole.Owner || adminUser) {
realObjects.push(...realDocs)
} else {
realObjects.push(...realDocs.filter((p) => allPersonAccounts.has(p.createdBy)))
}
}
} else {
realObjects = objects
}
const ops = client.apply('delete')
for (const object of objects) {
for (const object of realObjects) {
if (client.getHierarchy().isDerived(object._class, core.class.AttachedDoc)) {
const adoc = object as AttachedDoc
await ops
Expand Down
2 changes: 1 addition & 1 deletion plugins/view/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,7 @@ export interface Action<T extends Doc = Doc, P = Record<string, any>> extends Do
// For example, it could be global action and action for focus class, second one fill override first one.
override?: Ref<Action>[]

// Avaible only for workspace owners
// Available only for workspace owners
secured?: boolean
allowedForEditableContent?: boolean
}
Expand Down
4 changes: 2 additions & 2 deletions plugins/workbench-resources/src/components/Workbench.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import notification, { DocNotifyContext, InboxNotification, inboxId } from '@hcengineering/notification'
import { BrowserNotificatator, InboxNotificationsClientImpl } from '@hcengineering/notification-resources'
import { IntlString, broadcastEvent, getMetadata, getResource } from '@hcengineering/platform'
import { ActionContext, createQuery, getClient } from '@hcengineering/presentation'
import { ActionContext, createQuery, getClient, isAdminUser } from '@hcengineering/presentation'
import setting from '@hcengineering/setting'
import support, { SupportStatus, supportLink } from '@hcengineering/support'
import {
Expand Down Expand Up @@ -633,7 +633,7 @@
}}
/>
</div>
{:else if employee?.active || account.role === AccountRole.Owner}
{:else if employee?.active || account.role === AccountRole.Owner || isAdminUser()}
<ActionHandler />
<svg class="svg-mask">
<clipPath id="notify-normal">
Expand Down
4 changes: 3 additions & 1 deletion plugins/workbench-resources/src/connect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import core, {
} from '@hcengineering/core'
import login, { loginId } from '@hcengineering/login'
import { addEventListener, broadcastEvent, getMetadata, getResource, setMetadata } from '@hcengineering/platform'
import presentation, { closeClient, refreshClient, setClient } from '@hcengineering/presentation'
import presentation, { closeClient, purgeClient, refreshClient, setClient } from '@hcengineering/presentation'
import {
fetchMetadataLocalStorage,
getCurrentLocation,
Expand Down Expand Up @@ -77,6 +77,8 @@ export async function connect (title: string): Promise<Client | undefined> {
}

if (_token !== token && _client !== undefined) {
// We need to flush all data from memory
await purgeClient()
await _client.close()
_client = undefined
}
Expand Down
Loading

0 comments on commit 81a71e1

Please sign in to comment.