mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-23 16:56:07 +00:00
UBERF-5812: Fix allow to delete based on all my accounts (#4823)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
parent
5cd8dca583
commit
ae6059c040
@ -326,7 +326,7 @@ function defineApplication (
|
|||||||
spaceClass: tracker.class.Project,
|
spaceClass: tracker.class.Project,
|
||||||
componentProps: {
|
componentProps: {
|
||||||
_class: tracker.class.Project,
|
_class: tracker.class.Project,
|
||||||
label: tracker.string.AllIssues,
|
label: tracker.string.AllProjects,
|
||||||
icon: tracker.icon.Issues
|
icon: tracker.icon.Issues
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,12 +187,22 @@ export async function setClient (_client: MeasureClient): Promise<void> {
|
|||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export async function refreshClient (): Promise<void> {
|
export async function refreshClient (): Promise<void> {
|
||||||
await liveQuery?.refreshConnect()
|
if (!(liveQuery?.isClosed() ?? true)) {
|
||||||
for (const q of globalQueries) {
|
await liveQuery?.refreshConnect()
|
||||||
q.refreshClient()
|
for (const q of globalQueries) {
|
||||||
|
q.refreshClient()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export async function purgeClient (): Promise<void> {
|
||||||
|
await liveQuery?.close()
|
||||||
|
await pipeline?.close()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
@ -529,13 +539,9 @@ export function isCollectionAttr (hierarchy: Hierarchy, key: KeyedAttribute): bo
|
|||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export function decodeTokenPayload (token: string): any {
|
export function decodeTokenPayload (token: string): any {
|
||||||
const parts = token.split('.')
|
return JSON.parse(atob(token.split('.')[1]))
|
||||||
|
}
|
||||||
const payload = parts[1]
|
|
||||||
|
export function isAdminUser (): boolean {
|
||||||
const decodedPayload = atob(payload)
|
return decodeTokenPayload(getMetadata(plugin.metadata.Token) ?? '').admin === 'true'
|
||||||
|
|
||||||
const parsedPayload = JSON.parse(decodedPayload)
|
|
||||||
|
|
||||||
return parsedPayload
|
|
||||||
}
|
}
|
||||||
|
@ -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 queries: Map<Ref<Class<Doc>>, Query[]> = new Map<Ref<Class<Doc>>, Query[]>()
|
||||||
private readonly queue: Query[] = []
|
private readonly queue: Query[] = []
|
||||||
private queryCounter: number = 0
|
private queryCounter: number = 0
|
||||||
|
private closed: boolean = false
|
||||||
|
|
||||||
// A map of _class to documents.
|
// A map of _class to documents.
|
||||||
private readonly documentRefs = new Map<string, Map<Ref<Doc>, DocumentRef>>()
|
private readonly documentRefs = new Map<string, Map<Ref<Doc>, DocumentRef>>()
|
||||||
@ -104,7 +105,12 @@ export class LiveQuery implements WithTx, Client {
|
|||||||
await this.refreshConnect()
|
await this.refreshConnect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public isClosed (): boolean {
|
||||||
|
return this.closed
|
||||||
|
}
|
||||||
|
|
||||||
async close (): Promise<void> {
|
async close (): Promise<void> {
|
||||||
|
this.closed = true
|
||||||
await this.client.close()
|
await this.client.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,16 +13,16 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Card } from '@hcengineering/presentation'
|
import { PersonAccount } from '@hcengineering/contact'
|
||||||
import { AccountRole, Doc, getCurrentAccount, Ref } from '@hcengineering/core'
|
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 view from '@hcengineering/view-resources/src/plugin'
|
||||||
import { createEventDispatcher } from 'svelte'
|
import { createEventDispatcher } from 'svelte'
|
||||||
import { PersonAccount } from '@hcengineering/contact'
|
|
||||||
import { personAccountByIdStore } from '../utils'
|
import { personAccountByIdStore } from '../utils'
|
||||||
import ui, { Button, Label } from '@hcengineering/ui'
|
|
||||||
import PersonAccountRefPresenter from './PersonAccountRefPresenter.svelte'
|
|
||||||
import PersonAccountPresenter from './PersonAccountPresenter.svelte'
|
import PersonAccountPresenter from './PersonAccountPresenter.svelte'
|
||||||
import { ObjectPresenter } from '@hcengineering/view-resources'
|
import PersonAccountRefPresenter from './PersonAccountRefPresenter.svelte'
|
||||||
|
|
||||||
export let object: Doc | Doc[]
|
export let object: Doc | Doc[]
|
||||||
export let deleteAction: () => void | Promise<void>
|
export let deleteAction: () => void | Promise<void>
|
||||||
@ -37,7 +37,8 @@
|
|||||||
$: canDelete =
|
$: canDelete =
|
||||||
(skipCheck ||
|
(skipCheck ||
|
||||||
(creators.length === 1 && creators.includes(getCurrentAccount()._id as Ref<PersonAccount>)) ||
|
(creators.length === 1 && creators.includes(getCurrentAccount()._id as Ref<PersonAccount>)) ||
|
||||||
getCurrentAccount().role === AccountRole.Owner) &&
|
getCurrentAccount().role === AccountRole.Owner ||
|
||||||
|
isAdminUser()) &&
|
||||||
canDeleteExtra
|
canDeleteExtra
|
||||||
$: label = canDelete ? view.string.DeleteObject : view.string.DeletePopupNoPermissionTitle
|
$: label = canDelete ? view.string.DeleteObject : view.string.DeletePopupNoPermissionTitle
|
||||||
</script>
|
</script>
|
||||||
|
@ -16,20 +16,21 @@
|
|||||||
import contact, { Employee } from '@hcengineering/contact'
|
import contact, { Employee } from '@hcengineering/contact'
|
||||||
import { AccountRole, getCurrentAccount, Ref } from '@hcengineering/core'
|
import { AccountRole, getCurrentAccount, Ref } from '@hcengineering/core'
|
||||||
import { tzDateCompare, type Department, type Request, type RequestType, type Staff } from '@hcengineering/hr'
|
import { tzDateCompare, type Department, type Request, type RequestType, type Staff } from '@hcengineering/hr'
|
||||||
|
import { isAdminUser } from '@hcengineering/presentation'
|
||||||
import {
|
import {
|
||||||
areDatesEqual,
|
areDatesEqual,
|
||||||
day as getDay,
|
|
||||||
daysInMonth,
|
daysInMonth,
|
||||||
|
deviceOptionsStore as deviceInfo,
|
||||||
eventToHTMLElement,
|
eventToHTMLElement,
|
||||||
|
day as getDay,
|
||||||
getWeekDayName,
|
getWeekDayName,
|
||||||
isWeekend,
|
isWeekend,
|
||||||
Label,
|
Label,
|
||||||
LabelAndProps,
|
LabelAndProps,
|
||||||
|
resizeObserver,
|
||||||
Scroller,
|
Scroller,
|
||||||
showPopup,
|
showPopup,
|
||||||
tooltip,
|
tooltip
|
||||||
deviceOptionsStore as deviceInfo,
|
|
||||||
resizeObserver
|
|
||||||
} from '@hcengineering/ui'
|
} from '@hcengineering/ui'
|
||||||
import hr from '../../plugin'
|
import hr from '../../plugin'
|
||||||
import { getHolidayDatesForEmployee, getRequests, isHoliday } from '../../utils'
|
import { getHolidayDatesForEmployee, getRequests, isHoliday } from '../../utils'
|
||||||
@ -183,7 +184,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function isEditable (employee: Staff): boolean {
|
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 {
|
function getTooltip (requests: Request[], day: Date, staff: Staff): LabelAndProps | undefined {
|
||||||
@ -306,7 +307,7 @@
|
|||||||
class="timeline-cell timeline-day-header flex-col-center justify-center"
|
class="timeline-cell timeline-day-header flex-col-center justify-center"
|
||||||
style={getCellStyle()}
|
style={getCellStyle()}
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
if (isFutureDate() || me.role === AccountRole.Owner) {
|
if (isFutureDate() || me.role === AccountRole.Owner || isAdminUser()) {
|
||||||
setPublicHoliday(day)
|
setPublicHoliday(day)
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { PersonAccount } from '@hcengineering/contact'
|
import { PersonAccount } from '@hcengineering/contact'
|
||||||
import { AccountRole, getCurrentAccount, roleOrder } from '@hcengineering/core'
|
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 setting, { SettingsCategory } from '@hcengineering/setting'
|
||||||
import {
|
import {
|
||||||
Component,
|
Component,
|
||||||
@ -27,7 +27,6 @@
|
|||||||
} from '@hcengineering/ui'
|
} from '@hcengineering/ui'
|
||||||
import { onDestroy } from 'svelte'
|
import { onDestroy } from 'svelte'
|
||||||
import { clearSettingsStore } from '../store'
|
import { clearSettingsStore } from '../store'
|
||||||
import { getMetadata } from '@hcengineering/platform'
|
|
||||||
|
|
||||||
export let kind: 'navigation' | 'content' | undefined
|
export let kind: 'navigation' | 'content' | undefined
|
||||||
export let categoryName: string
|
export let categoryName: string
|
||||||
@ -39,7 +38,7 @@
|
|||||||
let categories: SettingsCategory[] = []
|
let categories: SettingsCategory[] = []
|
||||||
const account = getCurrentAccount() as PersonAccount
|
const account = getCurrentAccount() as PersonAccount
|
||||||
|
|
||||||
const admin = decodeTokenPayload(getMetadata(presentation.metadata.Token) ?? '').admin === 'true'
|
const admin = isAdminUser()
|
||||||
|
|
||||||
const settingsQuery = createQuery()
|
const settingsQuery = createQuery()
|
||||||
settingsQuery.query(
|
settingsQuery.query(
|
||||||
@ -48,7 +47,7 @@
|
|||||||
(res) => {
|
(res) => {
|
||||||
categories = roleOrder[account.role] > roleOrder[AccountRole.User] ? res : res.filter((p) => !p.secured)
|
categories = roleOrder[account.role] > roleOrder[AccountRole.User] ? res : res.filter((p) => !p.secured)
|
||||||
if (!admin) {
|
if (!admin) {
|
||||||
categories = categories.filter((p) => !p.adminOnly)
|
categories = categories.filter((p) => !(p.adminOnly ?? false))
|
||||||
}
|
}
|
||||||
category = findCategory(categoryId)
|
category = findCategory(categoryId)
|
||||||
},
|
},
|
||||||
|
@ -14,9 +14,17 @@
|
|||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Project } from '@hcengineering/tracker'
|
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 tracker from '../../plugin'
|
||||||
import view from '@hcengineering/view'
|
import view from '@hcengineering/view'
|
||||||
|
import presentation from '@hcengineering/presentation'
|
||||||
|
|
||||||
export let value: Project | undefined
|
export let value: Project | undefined
|
||||||
export let inline: boolean = false
|
export let inline: boolean = false
|
||||||
@ -41,6 +49,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<span class="label no-underline nowrap" class:fs-bold={accent}>
|
<span class="label no-underline nowrap" class:fs-bold={accent}>
|
||||||
{value.name}
|
{value.name}
|
||||||
|
{#if value.archived}
|
||||||
|
<Label label={presentation.string.Archived} />
|
||||||
|
{/if}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -17,7 +17,12 @@
|
|||||||
import { Analytics } from '@hcengineering/analytics'
|
import { Analytics } from '@hcengineering/analytics'
|
||||||
import core, {
|
import core, {
|
||||||
AccountRole,
|
AccountRole,
|
||||||
type FindOptions,
|
ClassifierKind,
|
||||||
|
Hierarchy,
|
||||||
|
TxProcessor,
|
||||||
|
getCurrentAccount,
|
||||||
|
getObjectValue,
|
||||||
|
type Account,
|
||||||
type AggregateValue,
|
type AggregateValue,
|
||||||
type AttachedDoc,
|
type AttachedDoc,
|
||||||
type CategoryType,
|
type CategoryType,
|
||||||
@ -27,9 +32,7 @@ import core, {
|
|||||||
type Doc,
|
type Doc,
|
||||||
type DocumentQuery,
|
type DocumentQuery,
|
||||||
type DocumentUpdate,
|
type DocumentUpdate,
|
||||||
getCurrentAccount,
|
type FindOptions,
|
||||||
getObjectValue,
|
|
||||||
Hierarchy,
|
|
||||||
type Lookup,
|
type Lookup,
|
||||||
type Mixin,
|
type Mixin,
|
||||||
type Obj,
|
type Obj,
|
||||||
@ -38,38 +41,37 @@ import core, {
|
|||||||
type ReverseLookup,
|
type ReverseLookup,
|
||||||
type ReverseLookups,
|
type ReverseLookups,
|
||||||
type Space,
|
type Space,
|
||||||
type TxOperations,
|
|
||||||
type TxCUD,
|
type TxCUD,
|
||||||
type TxCollectionCUD,
|
type TxCollectionCUD,
|
||||||
TxProcessor,
|
|
||||||
type TxCreateDoc,
|
type TxCreateDoc,
|
||||||
type TxUpdateDoc,
|
|
||||||
type TxMixin,
|
type TxMixin,
|
||||||
ClassifierKind,
|
type TxOperations,
|
||||||
|
type TxUpdateDoc,
|
||||||
type TypeAny
|
type TypeAny
|
||||||
} from '@hcengineering/core'
|
} from '@hcengineering/core'
|
||||||
|
import { type Restrictions } from '@hcengineering/guest'
|
||||||
import type { Asset, IntlString } from '@hcengineering/platform'
|
import type { Asset, IntlString } from '@hcengineering/platform'
|
||||||
import { getResource, translate } from '@hcengineering/platform'
|
import { getResource, translate } from '@hcengineering/platform'
|
||||||
import {
|
import {
|
||||||
type AttributeCategory,
|
|
||||||
getAttributePresenterClass,
|
getAttributePresenterClass,
|
||||||
getClient,
|
getClient,
|
||||||
hasResource,
|
hasResource,
|
||||||
|
isAdminUser,
|
||||||
|
type AttributeCategory,
|
||||||
type KeyedAttribute
|
type KeyedAttribute
|
||||||
} from '@hcengineering/presentation'
|
} from '@hcengineering/presentation'
|
||||||
import { type Restrictions } from '@hcengineering/guest'
|
|
||||||
import {
|
import {
|
||||||
type AnyComponent,
|
|
||||||
type AnySvelteComponent,
|
|
||||||
ErrorPresenter,
|
ErrorPresenter,
|
||||||
getCurrentResolvedLocation,
|
getCurrentResolvedLocation,
|
||||||
getPanelURI,
|
getPanelURI,
|
||||||
getPlatformColorForText,
|
getPlatformColorForText,
|
||||||
type Location,
|
|
||||||
locationToUrl,
|
locationToUrl,
|
||||||
navigate,
|
navigate,
|
||||||
resolvedLocationStore,
|
resolvedLocationStore,
|
||||||
themeStore
|
themeStore,
|
||||||
|
type AnyComponent,
|
||||||
|
type AnySvelteComponent,
|
||||||
|
type Location
|
||||||
} from '@hcengineering/ui'
|
} from '@hcengineering/ui'
|
||||||
import view, {
|
import view, {
|
||||||
type AttributeModel,
|
type AttributeModel,
|
||||||
@ -80,10 +82,10 @@ import view, {
|
|||||||
type ViewletDescriptor
|
type ViewletDescriptor
|
||||||
} from '@hcengineering/view'
|
} from '@hcengineering/view'
|
||||||
|
|
||||||
|
import contact, { getName, type Contact, type PersonAccount } from '@hcengineering/contact'
|
||||||
import { get, writable } from 'svelte/store'
|
import { get, writable } from 'svelte/store'
|
||||||
import plugin from './plugin'
|
import plugin from './plugin'
|
||||||
import { noCategory } from './viewOptions'
|
import { noCategory } from './viewOptions'
|
||||||
import contact, { type Contact, getName } from '@hcengineering/contact'
|
|
||||||
|
|
||||||
export { getFiltredKeys, isCollectionAttr } from '@hcengineering/presentation'
|
export { getFiltredKeys, isCollectionAttr } from '@hcengineering/presentation'
|
||||||
|
|
||||||
@ -386,7 +388,8 @@ export async function buildModel (options: BuildModelOptions): Promise<Attribute
|
|||||||
|
|
||||||
export async function deleteObject (client: TxOperations, object: Doc): Promise<void> {
|
export async function deleteObject (client: TxOperations, object: Doc): Promise<void> {
|
||||||
const currentAcc = getCurrentAccount()
|
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)) {
|
if (client.getHierarchy().isDerived(object._class, core.class.AttachedDoc)) {
|
||||||
const adoc = object as AttachedDoc
|
const adoc = object as AttachedDoc
|
||||||
await client
|
await client
|
||||||
@ -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> {
|
export async function deleteObjects (client: TxOperations, objects: Doc[], skipCheck: boolean = false): Promise<void> {
|
||||||
|
let realObjects: Doc[] = []
|
||||||
if (!skipCheck) {
|
if (!skipCheck) {
|
||||||
const currentAcc = getCurrentAccount()
|
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')
|
const ops = client.apply('delete')
|
||||||
for (const object of objects) {
|
for (const object of realObjects) {
|
||||||
if (client.getHierarchy().isDerived(object._class, core.class.AttachedDoc)) {
|
if (client.getHierarchy().isDerived(object._class, core.class.AttachedDoc)) {
|
||||||
const adoc = object as AttachedDoc
|
const adoc = object as AttachedDoc
|
||||||
await ops
|
await ops
|
||||||
|
@ -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.
|
// For example, it could be global action and action for focus class, second one fill override first one.
|
||||||
override?: Ref<Action>[]
|
override?: Ref<Action>[]
|
||||||
|
|
||||||
// Avaible only for workspace owners
|
// Available only for workspace owners
|
||||||
secured?: boolean
|
secured?: boolean
|
||||||
allowedForEditableContent?: boolean
|
allowedForEditableContent?: boolean
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
import notification, { DocNotifyContext, InboxNotification, inboxId } from '@hcengineering/notification'
|
import notification, { DocNotifyContext, InboxNotification, inboxId } from '@hcengineering/notification'
|
||||||
import { BrowserNotificatator, InboxNotificationsClientImpl } from '@hcengineering/notification-resources'
|
import { BrowserNotificatator, InboxNotificationsClientImpl } from '@hcengineering/notification-resources'
|
||||||
import { IntlString, broadcastEvent, getMetadata, getResource } from '@hcengineering/platform'
|
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 setting from '@hcengineering/setting'
|
||||||
import support, { SupportStatus, supportLink } from '@hcengineering/support'
|
import support, { SupportStatus, supportLink } from '@hcengineering/support'
|
||||||
import {
|
import {
|
||||||
@ -633,7 +633,7 @@
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{:else if employee?.active || account.role === AccountRole.Owner}
|
{:else if employee?.active || account.role === AccountRole.Owner || isAdminUser()}
|
||||||
<ActionHandler />
|
<ActionHandler />
|
||||||
<svg class="svg-mask">
|
<svg class="svg-mask">
|
||||||
<clipPath id="notify-normal">
|
<clipPath id="notify-normal">
|
||||||
|
@ -11,7 +11,7 @@ import core, {
|
|||||||
} from '@hcengineering/core'
|
} from '@hcengineering/core'
|
||||||
import login, { loginId } from '@hcengineering/login'
|
import login, { loginId } from '@hcengineering/login'
|
||||||
import { addEventListener, broadcastEvent, getMetadata, getResource, setMetadata } from '@hcengineering/platform'
|
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 {
|
import {
|
||||||
fetchMetadataLocalStorage,
|
fetchMetadataLocalStorage,
|
||||||
getCurrentLocation,
|
getCurrentLocation,
|
||||||
@ -77,6 +77,8 @@ export async function connect (title: string): Promise<Client | undefined> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (_token !== token && _client !== undefined) {
|
if (_token !== token && _client !== undefined) {
|
||||||
|
// We need to flush all data from memory
|
||||||
|
await purgeClient()
|
||||||
await _client.close()
|
await _client.close()
|
||||||
_client = undefined
|
_client = undefined
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ import WorkbenchApp from './components/WorkbenchApp.svelte'
|
|||||||
import { doNavigate } from './utils'
|
import { doNavigate } from './utils'
|
||||||
import Workbench from './components/Workbench.svelte'
|
import Workbench from './components/Workbench.svelte'
|
||||||
import ServerManager from './components/ServerManager.svelte'
|
import ServerManager from './components/ServerManager.svelte'
|
||||||
|
import { isAdminUser } from '@hcengineering/presentation'
|
||||||
|
|
||||||
async function hasArchiveSpaces (spaces: Space[]): Promise<boolean> {
|
async function hasArchiveSpaces (spaces: Space[]): Promise<boolean> {
|
||||||
return spaces.find((sp) => sp.archived) !== undefined
|
return spaces.find((sp) => sp.archived) !== undefined
|
||||||
@ -51,7 +52,7 @@ export default async (): Promise<Resources> => ({
|
|||||||
},
|
},
|
||||||
function: {
|
function: {
|
||||||
HasArchiveSpaces: hasArchiveSpaces,
|
HasArchiveSpaces: hasArchiveSpaces,
|
||||||
IsOwner: async (docs: Space[]) => getCurrentAccount().role === AccountRole.Owner
|
IsOwner: async (docs: Space[]) => getCurrentAccount().role === AccountRole.Owner || isAdminUser()
|
||||||
},
|
},
|
||||||
actionImpl: {
|
actionImpl: {
|
||||||
Navigate: doNavigate
|
Navigate: doNavigate
|
||||||
|
@ -59,7 +59,7 @@ export class ConfigurationMiddleware extends BaseMiddleware implements Middlewar
|
|||||||
if (this.targetDomains.includes(domain)) {
|
if (this.targetDomains.includes(domain)) {
|
||||||
if (ctx.userEmail !== configurationAccountEmail) {
|
if (ctx.userEmail !== configurationAccountEmail) {
|
||||||
const account = await this.getUser(ctx)
|
const account = await this.getUser(ctx)
|
||||||
if (account.role !== AccountRole.Owner) {
|
if (account.role !== AccountRole.Owner && ctx.admin !== true) {
|
||||||
throw new PlatformError(new Status(Severity.ERROR, platform.status.Forbidden, {}))
|
throw new PlatformError(new Status(Severity.ERROR, platform.status.Forbidden, {}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -82,7 +82,7 @@ export class ConfigurationMiddleware extends BaseMiddleware implements Middlewar
|
|||||||
if (this.targetDomains.includes(domain)) {
|
if (this.targetDomains.includes(domain)) {
|
||||||
if (ctx.userEmail !== configurationAccountEmail) {
|
if (ctx.userEmail !== configurationAccountEmail) {
|
||||||
const account = await this.getUser(ctx)
|
const account = await this.getUser(ctx)
|
||||||
if (account.role !== AccountRole.Owner && account._id !== core.account.System) {
|
if (account.role !== AccountRole.Owner && account._id !== core.account.System && ctx.admin !== true) {
|
||||||
throw new PlatformError(new Status(Severity.ERROR, platform.status.Forbidden, {}))
|
throw new PlatformError(new Status(Severity.ERROR, platform.status.Forbidden, {}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -313,7 +313,7 @@ export class SpaceSecurityMiddleware extends BaseMiddleware implements Middlewar
|
|||||||
const space = this.privateSpaces[tx.objectSpace]
|
const space = this.privateSpaces[tx.objectSpace]
|
||||||
if (space !== undefined) {
|
if (space !== undefined) {
|
||||||
targets = await this.getTargets(space.members)
|
targets = await this.getTargets(space.members)
|
||||||
if (!isOwner(account)) {
|
if (!isOwner(account, ctx)) {
|
||||||
const cudTx = tx as TxCUD<Doc>
|
const cudTx = tx as TxCUD<Doc>
|
||||||
const isSpace = h.isDerived(cudTx.objectClass, core.class.Space)
|
const isSpace = h.isDerived(cudTx.objectClass, core.class.Space)
|
||||||
const allowed = this.allowedSpaces[account._id]
|
const allowed = this.allowedSpaces[account._id]
|
||||||
@ -482,7 +482,7 @@ export class SpaceSecurityMiddleware extends BaseMiddleware implements Middlewar
|
|||||||
const field = this.getKey(_class)
|
const field = this.getKey(_class)
|
||||||
|
|
||||||
if (!isSystem(account) && account.role !== AccountRole.Guest) {
|
if (!isSystem(account) && account.role !== AccountRole.Guest) {
|
||||||
if (!isOwner(account) || !this.storage.hierarchy.isDerived(_class, core.class.Space)) {
|
if (!isOwner(account, ctx) || !this.storage.hierarchy.isDerived(_class, core.class.Space)) {
|
||||||
if (query[field] !== undefined) {
|
if (query[field] !== undefined) {
|
||||||
;(newQuery as any)[field] = await this.mergeQuery(account, query[field], domain)
|
;(newQuery as any)[field] = await this.mergeQuery(account, query[field], domain)
|
||||||
} else {
|
} else {
|
||||||
@ -492,7 +492,7 @@ export class SpaceSecurityMiddleware extends BaseMiddleware implements Middlewar
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const findResult = await this.provideFindAll(ctx, _class, newQuery, options)
|
const findResult = await this.provideFindAll(ctx, _class, newQuery, options)
|
||||||
if (!isOwner(account) && account.role !== AccountRole.Guest) {
|
if (!isOwner(account, ctx) && account.role !== AccountRole.Guest) {
|
||||||
if (options?.lookup !== undefined) {
|
if (options?.lookup !== undefined) {
|
||||||
for (const object of findResult) {
|
for (const object of findResult) {
|
||||||
if (object.$lookup !== undefined) {
|
if (object.$lookup !== undefined) {
|
||||||
@ -521,7 +521,7 @@ export class SpaceSecurityMiddleware extends BaseMiddleware implements Middlewar
|
|||||||
async isUnavailable (ctx: SessionContext, space: Ref<Space>): Promise<boolean> {
|
async isUnavailable (ctx: SessionContext, space: Ref<Space>): Promise<boolean> {
|
||||||
if (this.privateSpaces[space] === undefined) return false
|
if (this.privateSpaces[space] === undefined) return false
|
||||||
const account = await getUser(this.storage, ctx)
|
const account = await getUser(this.storage, ctx)
|
||||||
if (isOwner(account)) return false
|
if (isOwner(account, ctx)) return false
|
||||||
return !this.allowedSpaces[account._id]?.includes(space)
|
return !this.allowedSpaces[account._id]?.includes(space)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,8 +51,8 @@ export async function getUser (storage: ServerStorage, ctx: SessionContext): Pro
|
|||||||
return account
|
return account
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isOwner (account: Account): boolean {
|
export function isOwner (account: Account, ctx: SessionContext): boolean {
|
||||||
return account.role === AccountRole.Owner || account._id === core.account.System
|
return account.role === AccountRole.Owner || account._id === core.account.System || ctx.admin === true
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isSystem (account: Account): boolean {
|
export function isSystem (account: Account): boolean {
|
||||||
|
Loading…
Reference in New Issue
Block a user