Skip to content

Commit d06b92e

Browse files
authored
card RBAC (#10197)
Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
1 parent c6deabe commit d06b92e

File tree

159 files changed

+2962
-2227
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

159 files changed

+2962
-2227
lines changed

.vscode/launch.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@
9797
"MODEL_JSON": "${workspaceRoot}/models/all/bundle/model.json",
9898
// "SERVER_PROVIDER":"uweb"
9999
"SERVER_PROVIDER": "ws",
100-
"MODEL_VERSION": "0.7.278",
100+
"MODEL_VERSION": "0.7.301",
101101
// "version": "0.7.0",
102102
"COMMUNICATION_API_ENABLED": "true",
103103
"ELASTIC_INDEX_NAME": "local_storage_index",
@@ -315,10 +315,11 @@
315315
"SERVER_SECRET": "secret",
316316
"TRANSACTOR_URL": "ws://localhost:3332",
317317
"ACCOUNTS_URL": "http://localhost:3000",
318+
"ACCOUNTS_DB_URL": "postgresql://root@huly.local:26257/defaultdb?sslmode=disable",
318319
"FRONT_URL": "http://localhost:8080",
319320
"MAIL_URL": "",
320321
"STORAGE_CONFIG": "datalake|http://localhost:4030",
321-
"MODEL_VERSION": "0.7.153",
322+
"MODEL_VERSION": "0.7.301",
322323
"WS_OPERATION": "all+backup",
323324
"BACKUP_STORAGE": "minio|minio?accessKey=minioadmin&secretKey=minioadmin",
324325
"BACKUP_BUCKET": "dev-backups",

common/config/rush/pnpm-lock.yaml

Lines changed: 1892 additions & 1885 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

common/scripts/version.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
"0.7.292"
1+
"0.7.301"

dev/tool/src/communication.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ async function migrateChannel (
160160
autoJoin: doc.autoJoin,
161161
owners: doc.owners,
162162
types: [chat.masterTag.Thread],
163+
type: cardPlugin.spaceType.SpaceType,
163164
space: cardPlugin.space.Default,
164165
modifiedBy: doc.modifiedBy,
165166
modifiedOn: doc.modifiedOn,

models/card/src/index.ts

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,18 @@ import {
2626
type FavoriteType,
2727
type MasterTag,
2828
type ParentInfo,
29+
type PermissionObjectClass,
2930
type Role,
3031
type Tag
3132
} from '@hcengineering/card'
3233
import chunter from '@hcengineering/chunter'
3334
import core, {
3435
AccountRole,
3536
type Blobs,
37+
type Class,
3638
ClassifierKind,
3739
type CollectionSize,
40+
type Doc,
3841
DOMAIN_MODEL,
3942
DOMAIN_SPACE,
4043
IndexKind,
@@ -45,22 +48,23 @@ import core, {
4548
SortingOrder
4649
} from '@hcengineering/core'
4750
import {
51+
ArrOf,
4852
type Builder,
4953
Collection,
5054
Hidden,
5155
Index,
5256
Mixin,
5357
Model,
5458
Prop,
59+
ReadOnly,
5560
TypeCollaborativeDoc,
5661
TypeNumber,
5762
TypeRef,
5863
TypeString,
59-
UX,
60-
ReadOnly
64+
UX
6165
} from '@hcengineering/model'
6266
import attachment from '@hcengineering/model-attachment'
63-
import { TAttachedDoc, TClass, TDoc, TMixin, TSpace } from '@hcengineering/model-core'
67+
import { TRole as TBaseRole, TClass, TDoc, TMixin, TTypedSpace } from '@hcengineering/model-core'
6468
import { createPublicLinkAction } from '@hcengineering/model-guest'
6569
import preference, { TPreference } from '@hcengineering/model-preference'
6670
import presentation from '@hcengineering/model-presentation'
@@ -72,8 +76,9 @@ import time, { type ToDo } from '@hcengineering/time'
7276
import { PaletteColorIndexes } from '@hcengineering/ui/src/colors'
7377
import { type AnyComponent } from '@hcengineering/ui/src/types'
7478
import { type BuildModelKey } from '@hcengineering/view'
75-
import card from './plugin'
7679
import { createActions } from './actions'
80+
import card from './plugin'
81+
import { definePermissions } from './permissions'
7782

7883
export { cardId } from '@hcengineering/card'
7984

@@ -141,10 +146,11 @@ export class TCard extends TDoc implements Card {
141146
peerId?: string
142147
}
143148

144-
@Model(card.class.CardSpace, core.class.Space, DOMAIN_SPACE)
149+
@Model(card.class.CardSpace, core.class.TypedSpace, DOMAIN_SPACE)
145150
@UX(core.string.Space)
146-
export class TCardSpace extends TSpace implements CardSpace {
147-
types!: Ref<MasterTag>[]
151+
export class TCardSpace extends TTypedSpace implements CardSpace {
152+
@Prop(ArrOf(TypeRef(card.class.MasterTag)), card.string.MasterTags)
153+
types!: Ref<MasterTag>[]
148154
}
149155

150156
@Model(card.class.MasterTagEditorSection, core.class.Doc, DOMAIN_MODEL)
@@ -169,11 +175,9 @@ export class TCardViewDefaults extends TMasterTag implements CardViewDefaults {
169175
defaultNavigation?: string
170176
}
171177

172-
@Model(card.class.Role, core.class.AttachedDoc, DOMAIN_MODEL)
173-
export class TRole extends TAttachedDoc implements Role {
174-
name!: string
175-
declare attachedTo: Ref<MasterTag | Tag>
176-
declare collection: 'roles'
178+
@Model(card.class.Role, core.class.Role, DOMAIN_MODEL)
179+
export class TRole extends TBaseRole implements Role {
180+
type!: Ref<MasterTag | Tag>
177181
}
178182

179183
@Model(card.class.FavoriteCard, preference.class.Preference)
@@ -187,6 +191,11 @@ export class TFavoriteType extends TPreference implements FavoriteType {
187191
declare attachedTo: Ref<MasterTag>
188192
}
189193

194+
@Model(card.class.PermissionObjectClass, core.class.Doc, DOMAIN_MODEL)
195+
export class TPermissionObjectClass extends TDoc implements PermissionObjectClass {
196+
objectClass!: Ref<Class<Doc>>
197+
}
198+
190199
@Mixin(card.mixin.CreateCardExtension, card.class.MasterTag)
191200
export class TCreateCardExtension extends TMasterTag implements CreateCardExtension {
192201
component?: AnyComponent
@@ -355,6 +364,7 @@ export function createSystemType (
355364

356365
export function createModel (builder: Builder): void {
357366
builder.createModel(
367+
TPermissionObjectClass,
358368
TMasterTag,
359369
TTag,
360370
TCard,
@@ -368,7 +378,20 @@ export function createModel (builder: Builder): void {
368378
TCreateCardExtension
369379
)
370380

381+
builder.createDoc(
382+
core.class.SpaceType,
383+
core.space.Model,
384+
{
385+
name: '',
386+
descriptor: core.descriptor.SpacesType,
387+
roles: 0,
388+
targetClass: core.mixin.SpacesTypeData
389+
},
390+
card.spaceType.SpaceType
391+
)
392+
371393
defineTabs(builder)
394+
definePermissions(builder)
372395

373396
builder.mixin(card.class.Card, core.class.Class, view.mixin.ObjectIcon, {
374397
component: card.component.CardIcon

models/card/src/migration.ts

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,16 @@
1313
// limitations under the License.
1414
//
1515

16-
import { type Card, cardId, DOMAIN_CARD } from '@hcengineering/card'
17-
import core, { DOMAIN_MODEL, type Ref, TxOperations, type Client, type Data, type Doc } from '@hcengineering/core'
16+
import cardPlugin, { type Card, cardId, DOMAIN_CARD, type Role } from '@hcengineering/card'
17+
import core, {
18+
DOMAIN_MODEL,
19+
type Ref,
20+
TxOperations,
21+
type Client,
22+
type Data,
23+
type Doc,
24+
type DocumentUpdate
25+
} from '@hcengineering/core'
1826
import {
1927
tryMigrate,
2028
tryUpgrade,
@@ -82,11 +90,42 @@ export const cardOperation: MigrateOperation = {
8290
state: 'make-config-sortable',
8391
mode: 'upgrade',
8492
func: makeConfigSortable
93+
},
94+
{
95+
state: 'migrate-roles-v2',
96+
mode: 'upgrade',
97+
func: migrateRolesToBaseRole
98+
},
99+
{
100+
state: 'add-space-type',
101+
mode: 'upgrade',
102+
func: addSpaceType
85103
}
86104
])
87105
}
88106
}
89107

108+
async function addSpaceType (client: MigrationUpgradeClient): Promise<void> {
109+
const txOp = new TxOperations(client, core.account.System)
110+
const spaces = await client.findAll(card.class.CardSpace, { type: { $exists: false } })
111+
for (const space of spaces) {
112+
await txOp.diffUpdate(space, { type: cardPlugin.spaceType.SpaceType })
113+
}
114+
}
115+
116+
async function migrateRolesToBaseRole (client: MigrationUpgradeClient): Promise<void> {
117+
const txOp = new TxOperations(client, core.account.System)
118+
const roles = await client.findAll(card.class.Role, { attachedTo: { $ne: cardPlugin.spaceType.SpaceType } })
119+
for (const role of roles) {
120+
const baseRoleData: DocumentUpdate<Role> = {
121+
type: role.attachedTo as any,
122+
attachedTo: cardPlugin.spaceType.SpaceType,
123+
attachedToClass: core.class.SpaceType
124+
}
125+
await txOp.update(role, baseRoleData)
126+
}
127+
}
128+
90129
async function fillParentInfo (client: Client): Promise<void> {
91130
const txOp = new TxOperations(client, core.account.System)
92131
const cards = await client.findAll(card.class.Card, { parentInfo: { $exists: false }, parent: { $ne: null } })
@@ -249,6 +288,7 @@ async function createDefaultProject (tx: TxOperations): Promise<void> {
249288
members: [],
250289
archived: false,
251290
autoJoin: true,
291+
type: card.spaceType.SpaceType,
252292
types: topLevelTypes.map((it) => it._id)
253293
},
254294
card.space.Default

models/card/src/permissions.ts

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// Copyright © 2025 Hardcore Engineering Inc.
2+
//
3+
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License. You may
5+
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
6+
//
7+
// Unless required by applicable law or agreed to in writing, software
8+
// distributed under the License is distributed on an "AS IS" BASIS,
9+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
//
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
import core from '@hcengineering/core'
15+
import { type Builder } from '@hcengineering/model'
16+
import card from '.'
17+
18+
export function definePermissions (builder: Builder): void {
19+
builder.createDoc(
20+
core.class.Permission,
21+
core.space.Model,
22+
{
23+
label: card.string.AddTagPermission,
24+
txClass: core.class.TxMixin,
25+
objectClass: card.class.Card,
26+
scope: 'space'
27+
},
28+
card.permission.AddTag
29+
)
30+
31+
builder.createDoc(
32+
core.class.Permission,
33+
core.space.Model,
34+
{
35+
label: card.string.RemoveTag,
36+
txClass: core.class.TxUpdateDoc,
37+
txMatch: {
38+
'operations.$unset': {
39+
$exists: true
40+
}
41+
},
42+
objectClass: card.class.Card,
43+
scope: 'space'
44+
},
45+
card.permission.RemoveTag
46+
)
47+
48+
builder.createDoc(
49+
core.class.Permission,
50+
core.space.Model,
51+
{
52+
label: card.string.CreateCardPermission,
53+
txClass: core.class.TxCreateDoc,
54+
objectClass: card.class.Card,
55+
scope: 'space'
56+
},
57+
card.permission.CreateCard
58+
)
59+
60+
builder.createDoc(
61+
core.class.Permission,
62+
core.space.Model,
63+
{
64+
label: card.string.UpdateCard,
65+
txClass: core.class.TxUpdateDoc,
66+
objectClass: card.class.Card,
67+
scope: 'space'
68+
},
69+
card.permission.UpdateCard
70+
)
71+
72+
builder.createDoc(
73+
core.class.Permission,
74+
core.space.Model,
75+
{
76+
label: card.string.RemoveCard,
77+
txClass: core.class.TxRemoveDoc,
78+
objectClass: card.class.Card,
79+
scope: 'space'
80+
},
81+
card.permission.RemoveCard
82+
)
83+
84+
builder.createDoc(
85+
core.class.Permission,
86+
core.space.Model,
87+
{
88+
label: card.string.ForbidAddTagPermission,
89+
txClass: core.class.TxMixin,
90+
objectClass: card.class.Card,
91+
scope: 'space',
92+
forbid: true
93+
},
94+
card.permission.ForbidAddTag
95+
)
96+
97+
builder.createDoc(
98+
core.class.Permission,
99+
core.space.Model,
100+
{
101+
label: card.string.ForbidRemoveTag,
102+
txClass: core.class.TxUpdateDoc,
103+
txMatch: {
104+
'operations.$unset': {
105+
$exists: true
106+
}
107+
},
108+
objectClass: card.class.Card,
109+
scope: 'space',
110+
forbid: true
111+
},
112+
card.permission.ForbidRemoveTag
113+
)
114+
115+
builder.createDoc(
116+
core.class.Permission,
117+
core.space.Model,
118+
{
119+
label: card.string.ForbidCreateCardPermission,
120+
txClass: core.class.TxCreateDoc,
121+
objectClass: card.class.Card,
122+
scope: 'space',
123+
forbid: true
124+
},
125+
card.permission.ForbidCreateCard
126+
)
127+
128+
builder.createDoc(
129+
core.class.Permission,
130+
core.space.Model,
131+
{
132+
label: card.string.ForbidUpdateCard,
133+
txClass: core.class.TxUpdateDoc,
134+
objectClass: card.class.Card,
135+
scope: 'space',
136+
forbid: true
137+
},
138+
card.permission.ForbidUpdateCard
139+
)
140+
141+
builder.createDoc(
142+
core.class.Permission,
143+
core.space.Model,
144+
{
145+
label: card.string.ForbidRemoveCard,
146+
txClass: core.class.TxRemoveDoc,
147+
objectClass: card.class.Card,
148+
scope: 'space',
149+
forbid: true
150+
},
151+
card.permission.ForbidRemoveCard
152+
)
153+
}

0 commit comments

Comments
 (0)