Do not allow to assign guest as space owner (#10803)

* Exclude guests from space owners

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Show guest if he is in owners

Signed-off-by: Artem Savchenko <armisav@gmail.com>

---------

Signed-off-by: Artem Savchenko <armisav@gmail.com>
This commit is contained in:
Artyom Savchenko
2026-04-25 18:29:08 +07:00
committed by GitHub
parent 738a2d0040
commit 338b16d665
9 changed files with 46 additions and 8 deletions
@@ -13,7 +13,7 @@
// limitations under the License. // limitations under the License.
--> -->
<script lang="ts"> <script lang="ts">
import { AccountArrayEditor, employeeRefByAccountUuidStore } from '@hcengineering/contact-resources' import { AccountArrayEditor, employeeRefByAccountUuidStore, getAnonymousRefs } from '@hcengineering/contact-resources'
import core, { import core, {
AccountRole, AccountRole,
AccountUuid, AccountUuid,
@@ -51,6 +51,8 @@
let roles = client.getModel().findAllSync(card.class.Role, { types: { $in: types } }) let roles = client.getModel().findAllSync(card.class.Role, { types: { $in: types } })
$: roles = client.getModel().findAllSync(card.class.Role, { types: { $in: types } }) $: roles = client.getModel().findAllSync(card.class.Role, { types: { $in: types } })
$: readOnlyGuestOwnerExcludeItems = getAnonymousRefs($employeeRefByAccountUuidStore, owners)
let name: string = space?.name ?? '' let name: string = space?.name ?? ''
let isPrivate: boolean = space?.private ?? false let isPrivate: boolean = space?.private ?? false
@@ -247,6 +249,7 @@
</div> </div>
<AccountArrayEditor <AccountArrayEditor
value={owners} value={owners}
excludeItems={readOnlyGuestOwnerExcludeItems}
label={core.string.Owners} label={core.string.Owners}
onChange={handleOwnersChanged} onChange={handleOwnersChanged}
kind={'regular'} kind={'regular'}
+16
View File
@@ -67,6 +67,7 @@ import core, {
type Permission, type Permission,
type PersonId, type PersonId,
pickPrimarySocialId, pickPrimarySocialId,
readOnlyGuestAccountUuid,
type Ref, type Ref,
type SocialId, type SocialId,
SocialIdType, SocialIdType,
@@ -373,6 +374,21 @@ export const primarySocialIdByEmployeeRefStore = writable<Map<Ref<Employee>, Per
*/ */
export const employeeRefByAccountUuidStore = writable<Map<AccountUuid, Ref<Employee>>>(new Map()) export const employeeRefByAccountUuidStore = writable<Map<AccountUuid, Ref<Employee>>>(new Map())
/**
* {@link Ref}<{@link Person}>[] for `excludeItems` so the read-only anonymous guest does not appear in the picker
* when not already selected. If they are in `selectedAccountUuids`, returns [] so they stay visible among chips.
*/
export function getAnonymousRefs (
byAccount: Map<AccountUuid, Ref<Employee>>,
selectedAccountUuids: readonly AccountUuid[] = []
): Array<Ref<Person>> {
if (selectedAccountUuids.includes(readOnlyGuestAccountUuid)) {
return []
}
const ref = byAccount.get(readOnlyGuestAccountUuid)
return ref !== undefined ? [ref as unknown as Ref<Person>] : []
}
/** /**
* [PersonId (social ID) => Employee] mapping * [PersonId (social ID) => Employee] mapping
*/ */
@@ -15,7 +15,7 @@
<script lang="ts"> <script lang="ts">
import { deepEqual } from 'fast-equals' import { deepEqual } from 'fast-equals'
import { createEventDispatcher } from 'svelte' import { createEventDispatcher } from 'svelte'
import { AccountArrayEditor, employeeRefByAccountUuidStore } from '@hcengineering/contact-resources' import { AccountArrayEditor, employeeRefByAccountUuidStore, getAnonymousRefs } from '@hcengineering/contact-resources'
import core, { import core, {
Data, Data,
DocumentUpdate, DocumentUpdate,
@@ -58,6 +58,7 @@
$: isNew = docSpace === undefined $: isNew = docSpace === undefined
$: membersPersons = members.map((m) => $employeeRefByAccountUuidStore.get(m)).filter(notEmpty) $: membersPersons = members.map((m) => $employeeRefByAccountUuidStore.get(m)).filter(notEmpty)
$: readOnlyGuestOwnerExcludeItems = getAnonymousRefs($employeeRefByAccountUuidStore, owners)
let typeId: Ref<DocumentSpaceType> | undefined = docSpace?.type ?? documents.spaceType.DocumentSpaceType let typeId: Ref<DocumentSpaceType> | undefined = docSpace?.type ?? documents.spaceType.DocumentSpaceType
let spaceType: WithLookup<DocumentSpaceType> | undefined let spaceType: WithLookup<DocumentSpaceType> | undefined
@@ -283,6 +284,7 @@
</div> </div>
<AccountArrayEditor <AccountArrayEditor
value={owners} value={owners}
excludeItems={readOnlyGuestOwnerExcludeItems}
label={core.string.Owners} label={core.string.Owners}
onChange={handleOwnersChanged} onChange={handleOwnersChanged}
kind={'regular'} kind={'regular'}
@@ -14,7 +14,7 @@
--> -->
<script lang="ts"> <script lang="ts">
import { deepEqual } from 'fast-equals' import { deepEqual } from 'fast-equals'
import { AccountArrayEditor, employeeRefByAccountUuidStore } from '@hcengineering/contact-resources' import { AccountArrayEditor, employeeRefByAccountUuidStore, getAnonymousRefs } from '@hcengineering/contact-resources'
import core, { import core, {
Data, Data,
DocumentUpdate, DocumentUpdate,
@@ -71,6 +71,7 @@
$: isNew = teamspace === undefined $: isNew = teamspace === undefined
$: membersPersons = members.map((m) => $employeeRefByAccountUuidStore.get(m)).filter(notEmpty) $: membersPersons = members.map((m) => $employeeRefByAccountUuidStore.get(m)).filter(notEmpty)
$: readOnlyGuestOwnerExcludeItems = getAnonymousRefs($employeeRefByAccountUuidStore, owners)
let typeId: Ref<SpaceType> | undefined = teamspace?.type ?? document.spaceType.DefaultTeamspaceType let typeId: Ref<SpaceType> | undefined = teamspace?.type ?? document.spaceType.DefaultTeamspaceType
let spaceType: WithLookup<SpaceType> | undefined let spaceType: WithLookup<SpaceType> | undefined
@@ -377,6 +378,7 @@
</div> </div>
<AccountArrayEditor <AccountArrayEditor
value={owners} value={owners}
excludeItems={readOnlyGuestOwnerExcludeItems}
label={core.string.Owners} label={core.string.Owners}
onChange={handleOwnersChanged} onChange={handleOwnersChanged}
kind={'regular'} kind={'regular'}
@@ -15,7 +15,7 @@
<script lang="ts"> <script lang="ts">
import { deepEqual } from 'fast-equals' import { deepEqual } from 'fast-equals'
import { createEventDispatcher } from 'svelte' import { createEventDispatcher } from 'svelte'
import { AccountArrayEditor, employeeRefByAccountUuidStore } from '@hcengineering/contact-resources' import { AccountArrayEditor, employeeRefByAccountUuidStore, getAnonymousRefs } from '@hcengineering/contact-resources'
import core, { import core, {
Data, Data,
RolesAssignment, RolesAssignment,
@@ -58,6 +58,7 @@
let spaceType: WithLookup<SpaceType> | undefined let spaceType: WithLookup<SpaceType> | undefined
$: membersPersons = members.map((m) => $employeeRefByAccountUuidStore.get(m)).filter(notEmpty) $: membersPersons = members.map((m) => $employeeRefByAccountUuidStore.get(m)).filter(notEmpty)
$: readOnlyGuestOwnerExcludeItems = getAnonymousRefs($employeeRefByAccountUuidStore, owners)
$: void loadSpaceType(typeId) $: void loadSpaceType(typeId)
const loadSpaceType = reduceCalls(async (id: typeof typeId): Promise<void> => { const loadSpaceType = reduceCalls(async (id: typeof typeId): Promise<void> => {
spaceType = spaceType =
@@ -248,6 +249,7 @@
</div> </div>
<AccountArrayEditor <AccountArrayEditor
value={owners} value={owners}
excludeItems={readOnlyGuestOwnerExcludeItems}
label={core.string.Owners} label={core.string.Owners}
onChange={handleOwnersChanged} onChange={handleOwnersChanged}
kind={'regular'} kind={'regular'}
@@ -14,7 +14,7 @@
// limitations under the License. // limitations under the License.
--> -->
<script lang="ts"> <script lang="ts">
import { AccountArrayEditor, employeeRefByAccountUuidStore } from '@hcengineering/contact-resources' import { AccountArrayEditor, employeeRefByAccountUuidStore, getAnonymousRefs } from '@hcengineering/contact-resources'
import core, { import core, {
getCurrentAccount, getCurrentAccount,
Ref, Ref,
@@ -56,6 +56,7 @@
let owners: AccountUuid[] = funnel?.owners !== undefined ? hierarchy.clone(funnel.owners) : [getCurrentAccount().uuid] let owners: AccountUuid[] = funnel?.owners !== undefined ? hierarchy.clone(funnel.owners) : [getCurrentAccount().uuid]
$: membersPersons = members.map((m) => $employeeRefByAccountUuidStore.get(m)).filter(notEmpty) $: membersPersons = members.map((m) => $employeeRefByAccountUuidStore.get(m)).filter(notEmpty)
$: readOnlyGuestOwnerExcludeItems = getAnonymousRefs($employeeRefByAccountUuidStore, owners)
$: void loadSpaceType(typeId) $: void loadSpaceType(typeId)
async function loadSpaceType (id: typeof typeId): Promise<void> { async function loadSpaceType (id: typeof typeId): Promise<void> {
spaceType = spaceType =
@@ -230,6 +231,7 @@
</div> </div>
<AccountArrayEditor <AccountArrayEditor
value={owners} value={owners}
excludeItems={readOnlyGuestOwnerExcludeItems}
label={core.string.Owners} label={core.string.Owners}
onChange={handleOwnersChanged} onChange={handleOwnersChanged}
kind={'regular'} kind={'regular'}
@@ -23,7 +23,7 @@
import { type Product, ProductVersionState } from '@hcengineering/products' import { type Product, ProductVersionState } from '@hcengineering/products'
import { type Attachment } from '@hcengineering/attachment' import { type Attachment } from '@hcengineering/attachment'
import { AttachmentPresenter, AttachmentStyledBox } from '@hcengineering/attachment-resources' import { AttachmentPresenter, AttachmentStyledBox } from '@hcengineering/attachment-resources'
import { AccountArrayEditor, employeeRefByAccountUuidStore } from '@hcengineering/contact-resources' import { AccountArrayEditor, employeeRefByAccountUuidStore, getAnonymousRefs } from '@hcengineering/contact-resources'
import core, { import core, {
AccountUuid, AccountUuid,
Data, Data,
@@ -72,6 +72,7 @@
let spaceType: WithLookup<SpaceType> | undefined let spaceType: WithLookup<SpaceType> | undefined
$: membersPersons = object.members.map((m) => $employeeRefByAccountUuidStore.get(m)).filter(notEmpty) $: membersPersons = object.members.map((m) => $employeeRefByAccountUuidStore.get(m)).filter(notEmpty)
$: readOnlyGuestOwnerExcludeItems = getAnonymousRefs($employeeRefByAccountUuidStore, object.owners ?? [])
let roles: Role[] = [] let roles: Role[] = []
const rolesQuery = createQuery() const rolesQuery = createQuery()
@@ -327,6 +328,7 @@
<AccountArrayEditor <AccountArrayEditor
value={object.owners ?? []} value={object.owners ?? []}
excludeItems={readOnlyGuestOwnerExcludeItems}
label={core.string.Owners} label={core.string.Owners}
emptyLabel={core.string.Owners} emptyLabel={core.string.Owners}
onChange={handleOwnersChanged} onChange={handleOwnersChanged}
@@ -15,7 +15,7 @@
<script lang="ts"> <script lang="ts">
import { deepEqual } from 'fast-equals' import { deepEqual } from 'fast-equals'
import { createEventDispatcher } from 'svelte' import { createEventDispatcher } from 'svelte'
import { AccountArrayEditor, employeeRefByAccountUuidStore } from '@hcengineering/contact-resources' import { AccountArrayEditor, employeeRefByAccountUuidStore, getAnonymousRefs } from '@hcengineering/contact-resources'
import { Asset } from '@hcengineering/platform' import { Asset } from '@hcengineering/platform'
import core, { import core, {
Data, Data,
@@ -64,6 +64,7 @@
let members: AccountUuid[] = let members: AccountUuid[] =
project?.members !== undefined ? hierarchy.clone(project.members) : [getCurrentAccount().uuid] project?.members !== undefined ? hierarchy.clone(project.members) : [getCurrentAccount().uuid]
$: membersPersons = members.map((m) => $employeeRefByAccountUuidStore.get(m)).filter(notEmpty) $: membersPersons = members.map((m) => $employeeRefByAccountUuidStore.get(m)).filter(notEmpty)
$: readOnlyGuestOwnerExcludeItems = getAnonymousRefs($employeeRefByAccountUuidStore, owners)
let owners: AccountUuid[] = let owners: AccountUuid[] =
project?.owners !== undefined ? hierarchy.clone(project.owners) : [getCurrentAccount().uuid] project?.owners !== undefined ? hierarchy.clone(project.owners) : [getCurrentAccount().uuid]
let rolesAssignment: RolesAssignment = {} let rolesAssignment: RolesAssignment = {}
@@ -343,6 +344,7 @@
</div> </div>
<AccountArrayEditor <AccountArrayEditor
value={owners} value={owners}
excludeItems={readOnlyGuestOwnerExcludeItems}
label={core.string.Owners} label={core.string.Owners}
onChange={handleOwnersChanged} onChange={handleOwnersChanged}
kind={'regular'} kind={'regular'}
@@ -15,7 +15,12 @@
<script lang="ts"> <script lang="ts">
import { Analytics } from '@hcengineering/analytics' import { Analytics } from '@hcengineering/analytics'
import { Employee } from '@hcengineering/contact' import { Employee } from '@hcengineering/contact'
import { AccountArrayEditor, AssigneeBox, employeeRefByAccountUuidStore } from '@hcengineering/contact-resources' import {
AccountArrayEditor,
AssigneeBox,
employeeRefByAccountUuidStore,
getAnonymousRefs
} from '@hcengineering/contact-resources'
import core, { import core, {
AccountRole, AccountRole,
AccountUuid, AccountUuid,
@@ -83,6 +88,7 @@
let typeId: Ref<ProjectType> | undefined = project?.type let typeId: Ref<ProjectType> | undefined = project?.type
$: typeType = typeId !== undefined ? $typeStore.get(typeId) : undefined $: typeType = typeId !== undefined ? $typeStore.get(typeId) : undefined
$: membersPersons = members.map((m) => $employeeRefByAccountUuidStore.get(m)).filter(notEmpty) $: membersPersons = members.map((m) => $employeeRefByAccountUuidStore.get(m)).filter(notEmpty)
$: readOnlyGuestOwnerExcludeItems = getAnonymousRefs($employeeRefByAccountUuidStore, owners)
let autoJoin = project?.autoJoin ?? typeType?.autoJoin ?? false let autoJoin = project?.autoJoin ?? typeType?.autoJoin ?? false
let autoJoinForRoles: AccountRole[] = let autoJoinForRoles: AccountRole[] =
project?.autoJoinForRoles != null ? hierarchy.clone(project.autoJoinForRoles) : [] project?.autoJoinForRoles != null ? hierarchy.clone(project.autoJoinForRoles) : []
@@ -512,6 +518,7 @@
</div> </div>
<AccountArrayEditor <AccountArrayEditor
value={owners} value={owners}
excludeItems={readOnlyGuestOwnerExcludeItems}
label={core.string.Owners} label={core.string.Owners}
allowGuests allowGuests
onChange={handleOwnersChanged} onChange={handleOwnersChanged}