Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UBERF-5812: Fix allow to delete based on all my accounts #4823

Merged
merged 1 commit into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,17 @@
-->
<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 +49,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
Loading