@orthacms/content-server 0.4.2 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +38 -1
- package/dist/lib/content.module.d.ts.map +1 -1
- package/dist/lib/content.module.js +23 -1
- package/dist/lib/entries/http/controllers/create-entry.controller.d.ts.map +1 -1
- package/dist/lib/entries/http/controllers/create-entry.controller.js +1 -1
- package/dist/lib/entries/http/controllers/update-entry.controller.d.ts.map +1 -1
- package/dist/lib/entries/http/controllers/update-entry.controller.js +1 -1
- package/dist/lib/entries/http/dto/extension-bag.validator.d.ts +14 -0
- package/dist/lib/entries/http/dto/extension-bag.validator.d.ts.map +1 -0
- package/dist/lib/entries/http/dto/extension-bag.validator.js +42 -0
- package/dist/lib/entries/http/dto/save-entry.dto.d.ts +16 -0
- package/dist/lib/entries/http/dto/save-entry.dto.d.ts.map +1 -1
- package/dist/lib/entries/http/dto/save-entry.dto.js +30 -0
- package/dist/lib/entries/infrastructure/persistence/entry-writer.service.d.ts +28 -2
- package/dist/lib/entries/infrastructure/persistence/entry-writer.service.d.ts.map +1 -1
- package/dist/lib/entries/infrastructure/persistence/entry-writer.service.js +112 -15
- package/dist/lib/entries/infrastructure/persistence/relation-link.service.d.ts +38 -5
- package/dist/lib/entries/infrastructure/persistence/relation-link.service.d.ts.map +1 -1
- package/dist/lib/entries/infrastructure/persistence/relation-link.service.js +38 -6
- package/dist/lib/entries/infrastructure/queries/entries.service.d.ts +3 -1
- package/dist/lib/entries/infrastructure/queries/entries.service.d.ts.map +1 -1
- package/dist/lib/entries/infrastructure/queries/entries.service.js +17 -5
- package/dist/lib/entries/infrastructure/queries/entry-match.query.d.ts +82 -0
- package/dist/lib/entries/infrastructure/queries/entry-match.query.d.ts.map +1 -0
- package/dist/lib/entries/infrastructure/queries/entry-match.query.js +152 -0
- package/dist/lib/extension/entry-access-source.d.ts +112 -0
- package/dist/lib/extension/entry-access-source.d.ts.map +1 -0
- package/dist/lib/extension/entry-filter-provider.d.ts +79 -0
- package/dist/lib/extension/entry-filter-provider.d.ts.map +1 -0
- package/dist/lib/extension/entry-filter-provider.js +149 -0
- package/dist/lib/extension/entry-write-extension.d.ts +185 -0
- package/dist/lib/extension/entry-write-extension.d.ts.map +1 -0
- package/dist/lib/extension/entry-write-extension.js +182 -0
- package/dist/lib/extension/entry-write-hook.d.ts +98 -0
- package/dist/lib/extension/entry-write-hook.d.ts.map +1 -0
- package/dist/lib/extension/read-scope.d.ts +107 -0
- package/dist/lib/extension/read-scope.d.ts.map +1 -0
- package/dist/lib/extension/read-scope.js +131 -0
- package/dist/lib/public-api/infrastructure/public-entries.query.d.ts +14 -1
- package/dist/lib/public-api/infrastructure/public-entries.query.d.ts.map +1 -1
- package/dist/lib/public-api/infrastructure/public-entries.query.js +20 -3
- package/dist/lib/public-api/infrastructure/public-expansion.query.d.ts +16 -4
- package/dist/lib/public-api/infrastructure/public-expansion.query.d.ts.map +1 -1
- package/dist/lib/public-api/infrastructure/public-expansion.query.js +29 -9
- package/dist/lib/revisions/application/use-cases/restore-revision.use-case.d.ts.map +1 -1
- package/dist/lib/revisions/application/use-cases/restore-revision.use-case.js +12 -1
- package/dist/lib/revisions/infrastructure/persistence/revision-snapshot.d.ts +7 -1
- package/dist/lib/revisions/infrastructure/persistence/revision-snapshot.d.ts.map +1 -1
- package/dist/lib/revisions/infrastructure/persistence/revision-snapshot.js +9 -2
- package/dist/lib/revisions/types/revision-view.d.ts +11 -0
- package/dist/lib/revisions/types/revision-view.d.ts.map +1 -1
- package/dist/lib/utils/content-views-plugin.d.ts +28 -0
- package/dist/lib/utils/content-views-plugin.d.ts.map +1 -0
- package/dist/lib/utils/content-views-plugin.js +29 -0
- package/dist/lib/views/application/queries/saved-views.query.d.ts +16 -0
- package/dist/lib/views/application/queries/saved-views.query.d.ts.map +1 -0
- package/dist/lib/views/application/queries/saved-views.query.js +46 -0
- package/dist/lib/views/application/saved-view-access.service.d.ts +30 -0
- package/dist/lib/views/application/saved-view-access.service.d.ts.map +1 -0
- package/dist/lib/views/application/saved-view-access.service.js +55 -0
- package/dist/lib/views/application/use-cases/create-saved-view.use-case.d.ts +27 -0
- package/dist/lib/views/application/use-cases/create-saved-view.use-case.d.ts.map +1 -0
- package/dist/lib/views/application/use-cases/create-saved-view.use-case.js +57 -0
- package/dist/lib/views/application/use-cases/delete-saved-view.use-case.d.ts +15 -0
- package/dist/lib/views/application/use-cases/delete-saved-view.use-case.d.ts.map +1 -0
- package/dist/lib/views/application/use-cases/delete-saved-view.use-case.js +35 -0
- package/dist/lib/views/application/use-cases/set-default-view.use-case.d.ts +23 -0
- package/dist/lib/views/application/use-cases/set-default-view.use-case.d.ts.map +1 -0
- package/dist/lib/views/application/use-cases/set-default-view.use-case.js +51 -0
- package/dist/lib/views/application/use-cases/update-saved-view.use-case.d.ts +21 -0
- package/dist/lib/views/application/use-cases/update-saved-view.use-case.d.ts.map +1 -0
- package/dist/lib/views/application/use-cases/update-saved-view.use-case.js +61 -0
- package/dist/lib/views/application/view-scope.service.d.ts +25 -0
- package/dist/lib/views/application/view-scope.service.d.ts.map +1 -0
- package/dist/lib/views/application/view-scope.service.js +45 -0
- package/dist/lib/views/content-views.module.d.ts +22 -0
- package/dist/lib/views/content-views.module.d.ts.map +1 -0
- package/dist/lib/views/content-views.module.js +63 -0
- package/dist/lib/views/domain/errors/index.d.ts +6 -0
- package/dist/lib/views/domain/errors/index.d.ts.map +1 -0
- package/dist/lib/views/domain/errors/index.js +12 -0
- package/dist/lib/views/domain/errors/saved-view-forbidden.error.d.ts +10 -0
- package/dist/lib/views/domain/errors/saved-view-forbidden.error.d.ts.map +1 -0
- package/dist/lib/views/domain/errors/saved-view-forbidden.error.js +16 -0
- package/dist/lib/views/domain/errors/saved-view-limit-error.d.ts +9 -0
- package/dist/lib/views/domain/errors/saved-view-limit-error.d.ts.map +1 -0
- package/dist/lib/views/domain/errors/saved-view-limit-error.js +16 -0
- package/dist/lib/views/domain/errors/saved-view-name-taken.error.d.ts +5 -0
- package/dist/lib/views/domain/errors/saved-view-name-taken.error.d.ts.map +1 -0
- package/dist/lib/views/domain/errors/saved-view-name-taken.error.js +11 -0
- package/dist/lib/views/domain/errors/saved-view-not-found.error.d.ts +9 -0
- package/dist/lib/views/domain/errors/saved-view-not-found.error.d.ts.map +1 -0
- package/dist/lib/views/domain/errors/saved-view-not-found.error.js +15 -0
- package/dist/lib/views/domain/saved-view.d.ts +66 -0
- package/dist/lib/views/domain/saved-view.d.ts.map +1 -0
- package/dist/lib/views/domain/saved-view.js +18 -0
- package/dist/lib/views/domain/saved-view.repository.d.ts +77 -0
- package/dist/lib/views/domain/saved-view.repository.d.ts.map +1 -0
- package/dist/lib/views/domain/saved-view.repository.js +5 -0
- package/dist/lib/views/http/controllers/saved-views.controller.d.ts +45 -0
- package/dist/lib/views/http/controllers/saved-views.controller.d.ts.map +1 -0
- package/dist/lib/views/http/controllers/saved-views.controller.js +216 -0
- package/dist/lib/views/http/controllers/to-http-error.d.ts +10 -0
- package/dist/lib/views/http/controllers/to-http-error.d.ts.map +1 -0
- package/dist/lib/views/http/controllers/to-http-error.js +26 -0
- package/dist/lib/views/http/dto/save-view.dto.d.ts +54 -0
- package/dist/lib/views/http/dto/save-view.dto.d.ts.map +1 -0
- package/dist/lib/views/http/dto/save-view.dto.js +230 -0
- package/dist/lib/views/http/dto/view-payload.validator.d.ts +20 -0
- package/dist/lib/views/http/dto/view-payload.validator.d.ts.map +1 -0
- package/dist/lib/views/http/dto/view-payload.validator.js +52 -0
- package/dist/lib/views/infrastructure/persistence/drizzle-saved-view.repository.d.ts +17 -0
- package/dist/lib/views/infrastructure/persistence/drizzle-saved-view.repository.d.ts.map +1 -0
- package/dist/lib/views/infrastructure/persistence/drizzle-saved-view.repository.js +125 -0
- package/dist/lib/views/infrastructure/schema/external-refs.d.ts +68 -0
- package/dist/lib/views/infrastructure/schema/external-refs.d.ts.map +1 -0
- package/dist/lib/views/infrastructure/schema/external-refs.js +29 -0
- package/dist/lib/views/infrastructure/schema/index.d.ts +8 -0
- package/dist/lib/views/infrastructure/schema/index.d.ts.map +1 -0
- package/dist/lib/views/infrastructure/schema/index.js +13 -0
- package/dist/lib/views/infrastructure/schema/saved-views.d.ts +275 -0
- package/dist/lib/views/infrastructure/schema/saved-views.d.ts.map +1 -0
- package/dist/lib/views/infrastructure/schema/saved-views.js +87 -0
- package/dist/lib/views/views.constants.d.ts +26 -0
- package/dist/lib/views/views.constants.d.ts.map +1 -0
- package/dist/lib/views/views.constants.js +28 -0
- package/dist/lib/views/views.tokens.d.ts +17 -0
- package/dist/lib/views/views.tokens.d.ts.map +1 -0
- package/dist/lib/views/views.tokens.js +21 -0
- package/migrations/0000_saved_views.sql +29 -0
- package/migrations/meta/0000_snapshot.json +256 -0
- package/migrations/meta/_journal.json +13 -0
- package/package.json +13 -12
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"saved-view-access.service.d.ts","sourceRoot":"","sources":["../../../../src/lib/views/application/saved-view-access.service.ts"],"names":[],"mappings":"AACA,OAAO,EACH,YAAY,EAGZ,kBAAkB,EAClB,KAAK,UAAU,EAClB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC5E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAGvE;;;;;;;;;;;;;GAaG;AACH,qBACa,sBAAsB;IAE3B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,YAAY;gBADZ,WAAW,EAAE,kBAAkB,EAC/B,YAAY,EAAE,YAAY;IAG/C,wCAAwC;IACxC,WAAW,CAAC,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,UAAU,GAAG,IAAI;IAQ1D;;;OAGG;IACG,sBAAsB,CACxB,UAAU,EAAE,cAAc,EAC1B,IAAI,EAAE,UAAU,GACjB,OAAO,CAAC,IAAI,CAAC;CAanB"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SavedViewAccessService = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const common_1 = require("@nestjs/common");
|
|
6
|
+
const identity_server_1 = require("@orthacms/identity-server");
|
|
7
|
+
const saved_view_1 = require("../domain/saved-view");
|
|
8
|
+
const errors_1 = require("../domain/errors");
|
|
9
|
+
/**
|
|
10
|
+
* The two authorization rules saved views add on top of the route guards.
|
|
11
|
+
*
|
|
12
|
+
* The guards already establish that the caller is authenticated, a member of
|
|
13
|
+
* the open workspace, and may read content. What is left is per-row and
|
|
14
|
+
* per-visibility, so it cannot live in a decorator:
|
|
15
|
+
*
|
|
16
|
+
* - **Only the owner writes.** Editing or deleting someone else's view is a
|
|
17
|
+
* 403 even for an administrator — a shared view is its author's, and the
|
|
18
|
+
* remedy for disagreeing with one is "Save as new", not a silent rewrite.
|
|
19
|
+
* - **Sharing is a permission.** Making a view workspace-visible needs
|
|
20
|
+
* `views:share`; a member without it still saves as many private views as
|
|
21
|
+
* they like.
|
|
22
|
+
*/
|
|
23
|
+
let SavedViewAccessService = class SavedViewAccessService {
|
|
24
|
+
permissions;
|
|
25
|
+
accessPolicy;
|
|
26
|
+
constructor(permissions, accessPolicy) {
|
|
27
|
+
this.permissions = permissions;
|
|
28
|
+
this.accessPolicy = accessPolicy;
|
|
29
|
+
}
|
|
30
|
+
/** Throws unless `user` owns `view`. */
|
|
31
|
+
assertOwned(view, user) {
|
|
32
|
+
if (view.ownerId !== user.id) {
|
|
33
|
+
throw new errors_1.SavedViewForbiddenError('Only the person who saved a view can change it. Use “Save as new” instead.');
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Throws unless `user` may store a view at `visibility`. Private views need
|
|
38
|
+
* nothing beyond membership; workspace-visible ones need `views:share`.
|
|
39
|
+
*/
|
|
40
|
+
async assertCanUseVisibility(visibility, user) {
|
|
41
|
+
if (visibility !== saved_view_1.VIEW_VISIBILITY.Workspace)
|
|
42
|
+
return;
|
|
43
|
+
const granted = await this.permissions.forRole(user.roleId);
|
|
44
|
+
const allowed = this.accessPolicy.can({ userId: user.id, grantedPermissions: new Set(granted) }, identity_server_1.Permission.create(identity_server_1.PERMISSIONS.VIEWS_SHARE));
|
|
45
|
+
if (!allowed) {
|
|
46
|
+
throw new errors_1.SavedViewForbiddenError('Sharing a view with the workspace requires the “views:share” permission.');
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
exports.SavedViewAccessService = SavedViewAccessService;
|
|
51
|
+
exports.SavedViewAccessService = SavedViewAccessService = tslib_1.__decorate([
|
|
52
|
+
(0, common_1.Injectable)(),
|
|
53
|
+
tslib_1.__metadata("design:paramtypes", [identity_server_1.PermissionsService,
|
|
54
|
+
identity_server_1.AccessPolicy])
|
|
55
|
+
], SavedViewAccessService);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { PublicUser } from '@orthacms/identity-server';
|
|
2
|
+
import type { SavedView, SavedViewPayload, ViewVisibility } from '../../domain/saved-view';
|
|
3
|
+
import { type SavedViewRepository } from '../../domain/saved-view.repository';
|
|
4
|
+
import { SavedViewAccessService } from '../saved-view-access.service';
|
|
5
|
+
/** Input for {@link CreateSavedViewUseCase}. */
|
|
6
|
+
export interface CreateSavedViewInput {
|
|
7
|
+
/** The workspace the view belongs to. */
|
|
8
|
+
workspaceId: string;
|
|
9
|
+
/** The list it is over (`content:<typeName>`). */
|
|
10
|
+
scope: string;
|
|
11
|
+
/** Display name, already trimmed by the DTO. */
|
|
12
|
+
name: string;
|
|
13
|
+
/** Who may see it. */
|
|
14
|
+
visibility: ViewVisibility;
|
|
15
|
+
/** The slice it restores. */
|
|
16
|
+
payload: SavedViewPayload;
|
|
17
|
+
/** Whether to make it the caller's default for this scope. */
|
|
18
|
+
makeDefault?: boolean;
|
|
19
|
+
}
|
|
20
|
+
/** Saves a new view for the calling user. */
|
|
21
|
+
export declare class CreateSavedViewUseCase {
|
|
22
|
+
private readonly repository;
|
|
23
|
+
private readonly access;
|
|
24
|
+
constructor(repository: SavedViewRepository, access: SavedViewAccessService);
|
|
25
|
+
execute(input: CreateSavedViewInput, user: PublicUser): Promise<SavedView>;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=create-saved-view.use-case.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-saved-view.use-case.d.ts","sourceRoot":"","sources":["../../../../../src/lib/views/application/use-cases/create-saved-view.use-case.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAE5D,OAAO,KAAK,EACR,SAAS,EACT,gBAAgB,EAChB,cAAc,EACjB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAEH,KAAK,mBAAmB,EAC3B,MAAM,oCAAoC,CAAC;AAM5C,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAGtE,gDAAgD;AAChD,MAAM,WAAW,oBAAoB;IACjC,yCAAyC;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,sBAAsB;IACtB,UAAU,EAAE,cAAc,CAAC;IAC3B,6BAA6B;IAC7B,OAAO,EAAE,gBAAgB,CAAC;IAC1B,8DAA8D;IAC9D,WAAW,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,6CAA6C;AAC7C,qBACa,sBAAsB;IAG3B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,UAAU,EAAE,mBAAmB,EAC/B,MAAM,EAAE,sBAAsB;IAG7C,OAAO,CACT,KAAK,EAAE,oBAAoB,EAC3B,IAAI,EAAE,UAAU,GACjB,OAAO,CAAC,SAAS,CAAC;CAwCxB"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CreateSavedViewUseCase = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const common_1 = require("@nestjs/common");
|
|
6
|
+
const utils_server_1 = require("@orthacms/utils-server");
|
|
7
|
+
const saved_view_repository_1 = require("../../domain/saved-view.repository");
|
|
8
|
+
const errors_1 = require("../../domain/errors");
|
|
9
|
+
const views_constants_1 = require("../../views.constants");
|
|
10
|
+
const saved_view_access_service_1 = require("../saved-view-access.service");
|
|
11
|
+
const saved_views_query_1 = require("../queries/saved-views.query");
|
|
12
|
+
/** Saves a new view for the calling user. */
|
|
13
|
+
let CreateSavedViewUseCase = class CreateSavedViewUseCase {
|
|
14
|
+
repository;
|
|
15
|
+
access;
|
|
16
|
+
constructor(repository, access) {
|
|
17
|
+
this.repository = repository;
|
|
18
|
+
this.access = access;
|
|
19
|
+
}
|
|
20
|
+
async execute(input, user) {
|
|
21
|
+
await this.access.assertCanUseVisibility(input.visibility, user);
|
|
22
|
+
const held = await this.repository.countForOwner(input.workspaceId, input.scope, user.id);
|
|
23
|
+
if (held >= views_constants_1.VIEW_MAX_PER_SCOPE)
|
|
24
|
+
throw new errors_1.SavedViewLimitError();
|
|
25
|
+
// The unique index is the arbiter, not the count above: two concurrent
|
|
26
|
+
// saves of the same name both pass a read-then-write check and one of
|
|
27
|
+
// them has to lose at the constraint. Translate that loss into the same
|
|
28
|
+
// 409 a sequential duplicate gets.
|
|
29
|
+
let created;
|
|
30
|
+
try {
|
|
31
|
+
created = await this.repository.create({
|
|
32
|
+
workspaceId: input.workspaceId,
|
|
33
|
+
scope: input.scope,
|
|
34
|
+
ownerId: user.id,
|
|
35
|
+
visibility: input.visibility,
|
|
36
|
+
name: input.name,
|
|
37
|
+
payload: input.payload
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
if ((0, utils_server_1.isUniqueViolation)(error)) {
|
|
42
|
+
throw new errors_1.SavedViewNameTakenError(input.name);
|
|
43
|
+
}
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
if (input.makeDefault) {
|
|
47
|
+
await this.repository.setDefault(user.id, input.scope, created.id);
|
|
48
|
+
}
|
|
49
|
+
return (0, saved_views_query_1.toSavedView)(created, user.id, input.makeDefault ? created.id : null);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
exports.CreateSavedViewUseCase = CreateSavedViewUseCase;
|
|
53
|
+
exports.CreateSavedViewUseCase = CreateSavedViewUseCase = tslib_1.__decorate([
|
|
54
|
+
(0, common_1.Injectable)(),
|
|
55
|
+
tslib_1.__param(0, (0, common_1.Inject)(saved_view_repository_1.SAVED_VIEW_REPOSITORY)),
|
|
56
|
+
tslib_1.__metadata("design:paramtypes", [Object, saved_view_access_service_1.SavedViewAccessService])
|
|
57
|
+
], CreateSavedViewUseCase);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { PublicUser } from '@orthacms/identity-server';
|
|
2
|
+
import { type SavedViewRepository } from '../../domain/saved-view.repository';
|
|
3
|
+
import { SavedViewAccessService } from '../saved-view-access.service';
|
|
4
|
+
/**
|
|
5
|
+
* Deletes a view the caller owns. Anyone else's default pointing at it is
|
|
6
|
+
* cascaded away by the FK, so they fall back to the unfiltered list rather than
|
|
7
|
+
* to a dangling id.
|
|
8
|
+
*/
|
|
9
|
+
export declare class DeleteSavedViewUseCase {
|
|
10
|
+
private readonly repository;
|
|
11
|
+
private readonly access;
|
|
12
|
+
constructor(repository: SavedViewRepository, access: SavedViewAccessService);
|
|
13
|
+
execute(id: string, workspaceId: string, user: PublicUser): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=delete-saved-view.use-case.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delete-saved-view.use-case.d.ts","sourceRoot":"","sources":["../../../../../src/lib/views/application/use-cases/delete-saved-view.use-case.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAEH,KAAK,mBAAmB,EAC3B,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAEtE;;;;GAIG;AACH,qBACa,sBAAsB;IAG3B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,UAAU,EAAE,mBAAmB,EAC/B,MAAM,EAAE,sBAAsB;IAG7C,OAAO,CACT,EAAE,EAAE,MAAM,EACV,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,UAAU,GACjB,OAAO,CAAC,IAAI,CAAC;CAQnB"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DeleteSavedViewUseCase = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const common_1 = require("@nestjs/common");
|
|
6
|
+
const saved_view_repository_1 = require("../../domain/saved-view.repository");
|
|
7
|
+
const errors_1 = require("../../domain/errors");
|
|
8
|
+
const saved_view_access_service_1 = require("../saved-view-access.service");
|
|
9
|
+
/**
|
|
10
|
+
* Deletes a view the caller owns. Anyone else's default pointing at it is
|
|
11
|
+
* cascaded away by the FK, so they fall back to the unfiltered list rather than
|
|
12
|
+
* to a dangling id.
|
|
13
|
+
*/
|
|
14
|
+
let DeleteSavedViewUseCase = class DeleteSavedViewUseCase {
|
|
15
|
+
repository;
|
|
16
|
+
access;
|
|
17
|
+
constructor(repository, access) {
|
|
18
|
+
this.repository = repository;
|
|
19
|
+
this.access = access;
|
|
20
|
+
}
|
|
21
|
+
async execute(id, workspaceId, user) {
|
|
22
|
+
const existing = await this.repository.findById(id);
|
|
23
|
+
if (!existing || existing.workspaceId !== workspaceId) {
|
|
24
|
+
throw new errors_1.SavedViewNotFoundError(id);
|
|
25
|
+
}
|
|
26
|
+
this.access.assertOwned(existing, user);
|
|
27
|
+
await this.repository.delete(id);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
exports.DeleteSavedViewUseCase = DeleteSavedViewUseCase;
|
|
31
|
+
exports.DeleteSavedViewUseCase = DeleteSavedViewUseCase = tslib_1.__decorate([
|
|
32
|
+
(0, common_1.Injectable)(),
|
|
33
|
+
tslib_1.__param(0, (0, common_1.Inject)(saved_view_repository_1.SAVED_VIEW_REPOSITORY)),
|
|
34
|
+
tslib_1.__metadata("design:paramtypes", [Object, saved_view_access_service_1.SavedViewAccessService])
|
|
35
|
+
], DeleteSavedViewUseCase);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { PublicUser } from '@orthacms/identity-server';
|
|
2
|
+
import { type SavedViewRepository } from '../../domain/saved-view.repository';
|
|
3
|
+
/**
|
|
4
|
+
* Points a user's default for one list at a view, or clears it.
|
|
5
|
+
*
|
|
6
|
+
* Deliberately **not** owner-gated: a default is the reader's own landing
|
|
7
|
+
* choice, so anyone who can see a shared view may land on it. What is gated is
|
|
8
|
+
* visibility — the view has to be one this caller can actually read, which is
|
|
9
|
+
* what the ownership-or-shared check below establishes.
|
|
10
|
+
*/
|
|
11
|
+
export declare class SetDefaultViewUseCase {
|
|
12
|
+
private readonly repository;
|
|
13
|
+
constructor(repository: SavedViewRepository);
|
|
14
|
+
execute(id: string, workspaceId: string, user: PublicUser): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Clears the caller's default for the scope `id` belongs to. Addressed by
|
|
17
|
+
* view id rather than by scope so the route sits beside its `PUT`
|
|
18
|
+
* counterpart instead of colliding with `DELETE /views/:id`. Idempotent:
|
|
19
|
+
* clearing when the default points elsewhere, or nowhere, still succeeds.
|
|
20
|
+
*/
|
|
21
|
+
executeClear(id: string, workspaceId: string, user: PublicUser): Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=set-default-view.use-case.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"set-default-view.use-case.d.ts","sourceRoot":"","sources":["../../../../../src/lib/views/application/use-cases/set-default-view.use-case.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAE5D,OAAO,EAEH,KAAK,mBAAmB,EAC3B,MAAM,oCAAoC,CAAC;AAG5C;;;;;;;GAOG;AACH,qBACa,qBAAqB;IAG1B,OAAO,CAAC,QAAQ,CAAC,UAAU;gBAAV,UAAU,EAAE,mBAAmB;IAG9C,OAAO,CACT,EAAE,EAAE,MAAM,EACV,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,UAAU,GACjB,OAAO,CAAC,IAAI,CAAC;IAWhB;;;;;OAKG;IACG,YAAY,CACd,EAAE,EAAE,MAAM,EACV,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,UAAU,GACjB,OAAO,CAAC,IAAI,CAAC;CAOnB"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SetDefaultViewUseCase = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const common_1 = require("@nestjs/common");
|
|
6
|
+
const saved_view_1 = require("../../domain/saved-view");
|
|
7
|
+
const saved_view_repository_1 = require("../../domain/saved-view.repository");
|
|
8
|
+
const errors_1 = require("../../domain/errors");
|
|
9
|
+
/**
|
|
10
|
+
* Points a user's default for one list at a view, or clears it.
|
|
11
|
+
*
|
|
12
|
+
* Deliberately **not** owner-gated: a default is the reader's own landing
|
|
13
|
+
* choice, so anyone who can see a shared view may land on it. What is gated is
|
|
14
|
+
* visibility — the view has to be one this caller can actually read, which is
|
|
15
|
+
* what the ownership-or-shared check below establishes.
|
|
16
|
+
*/
|
|
17
|
+
let SetDefaultViewUseCase = class SetDefaultViewUseCase {
|
|
18
|
+
repository;
|
|
19
|
+
constructor(repository) {
|
|
20
|
+
this.repository = repository;
|
|
21
|
+
}
|
|
22
|
+
async execute(id, workspaceId, user) {
|
|
23
|
+
const existing = await this.repository.findById(id);
|
|
24
|
+
const readable = existing &&
|
|
25
|
+
existing.workspaceId === workspaceId &&
|
|
26
|
+
(existing.ownerId === user.id ||
|
|
27
|
+
existing.visibility === saved_view_1.VIEW_VISIBILITY.Workspace);
|
|
28
|
+
if (!existing || !readable)
|
|
29
|
+
throw new errors_1.SavedViewNotFoundError(id);
|
|
30
|
+
await this.repository.setDefault(user.id, existing.scope, id);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Clears the caller's default for the scope `id` belongs to. Addressed by
|
|
34
|
+
* view id rather than by scope so the route sits beside its `PUT`
|
|
35
|
+
* counterpart instead of colliding with `DELETE /views/:id`. Idempotent:
|
|
36
|
+
* clearing when the default points elsewhere, or nowhere, still succeeds.
|
|
37
|
+
*/
|
|
38
|
+
async executeClear(id, workspaceId, user) {
|
|
39
|
+
const existing = await this.repository.findById(id);
|
|
40
|
+
if (!existing || existing.workspaceId !== workspaceId) {
|
|
41
|
+
throw new errors_1.SavedViewNotFoundError(id);
|
|
42
|
+
}
|
|
43
|
+
await this.repository.clearDefault(user.id, existing.scope);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
exports.SetDefaultViewUseCase = SetDefaultViewUseCase;
|
|
47
|
+
exports.SetDefaultViewUseCase = SetDefaultViewUseCase = tslib_1.__decorate([
|
|
48
|
+
(0, common_1.Injectable)(),
|
|
49
|
+
tslib_1.__param(0, (0, common_1.Inject)(saved_view_repository_1.SAVED_VIEW_REPOSITORY)),
|
|
50
|
+
tslib_1.__metadata("design:paramtypes", [Object])
|
|
51
|
+
], SetDefaultViewUseCase);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { PublicUser } from '@orthacms/identity-server';
|
|
2
|
+
import type { SavedView, SavedViewPayload, ViewVisibility } from '../../domain/saved-view';
|
|
3
|
+
import { type SavedViewRepository } from '../../domain/saved-view.repository';
|
|
4
|
+
import { SavedViewAccessService } from '../saved-view-access.service';
|
|
5
|
+
/** The fields `PATCH /api/views/:id` may change. */
|
|
6
|
+
export interface UpdateSavedViewInput {
|
|
7
|
+
/** New display name. */
|
|
8
|
+
name?: string;
|
|
9
|
+
/** New visibility. */
|
|
10
|
+
visibility?: ViewVisibility;
|
|
11
|
+
/** New slice. */
|
|
12
|
+
payload?: SavedViewPayload;
|
|
13
|
+
}
|
|
14
|
+
/** Renames, re-shares, or re-captures an existing view. */
|
|
15
|
+
export declare class UpdateSavedViewUseCase {
|
|
16
|
+
private readonly repository;
|
|
17
|
+
private readonly access;
|
|
18
|
+
constructor(repository: SavedViewRepository, access: SavedViewAccessService);
|
|
19
|
+
execute(id: string, workspaceId: string, input: UpdateSavedViewInput, user: PublicUser): Promise<SavedView>;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=update-saved-view.use-case.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-saved-view.use-case.d.ts","sourceRoot":"","sources":["../../../../../src/lib/views/application/use-cases/update-saved-view.use-case.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAE5D,OAAO,KAAK,EACR,SAAS,EACT,gBAAgB,EAChB,cAAc,EACjB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAEH,KAAK,mBAAmB,EAC3B,MAAM,oCAAoC,CAAC;AAK5C,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAGtE,oDAAoD;AACpD,MAAM,WAAW,oBAAoB;IACjC,wBAAwB;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sBAAsB;IACtB,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,iBAAiB;IACjB,OAAO,CAAC,EAAE,gBAAgB,CAAC;CAC9B;AAED,2DAA2D;AAC3D,qBACa,sBAAsB;IAG3B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,UAAU,EAAE,mBAAmB,EAC/B,MAAM,EAAE,sBAAsB;IAG7C,OAAO,CACT,EAAE,EAAE,MAAM,EACV,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,oBAAoB,EAC3B,IAAI,EAAE,UAAU,GACjB,OAAO,CAAC,SAAS,CAAC;CA4CxB"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UpdateSavedViewUseCase = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const common_1 = require("@nestjs/common");
|
|
6
|
+
const utils_server_1 = require("@orthacms/utils-server");
|
|
7
|
+
const saved_view_repository_1 = require("../../domain/saved-view.repository");
|
|
8
|
+
const errors_1 = require("../../domain/errors");
|
|
9
|
+
const saved_view_access_service_1 = require("../saved-view-access.service");
|
|
10
|
+
const saved_views_query_1 = require("../queries/saved-views.query");
|
|
11
|
+
/** Renames, re-shares, or re-captures an existing view. */
|
|
12
|
+
let UpdateSavedViewUseCase = class UpdateSavedViewUseCase {
|
|
13
|
+
repository;
|
|
14
|
+
access;
|
|
15
|
+
constructor(repository, access) {
|
|
16
|
+
this.repository = repository;
|
|
17
|
+
this.access = access;
|
|
18
|
+
}
|
|
19
|
+
async execute(id, workspaceId, input, user) {
|
|
20
|
+
const existing = await this.repository.findById(id);
|
|
21
|
+
// The workspace check is part of the not-found decision, not a separate
|
|
22
|
+
// 403: an id from another workspace must read exactly like an unknown
|
|
23
|
+
// one, or the endpoint becomes a probe for views elsewhere.
|
|
24
|
+
if (!existing || existing.workspaceId !== workspaceId) {
|
|
25
|
+
throw new errors_1.SavedViewNotFoundError(id);
|
|
26
|
+
}
|
|
27
|
+
this.access.assertOwned(existing, user);
|
|
28
|
+
if (input.visibility !== undefined) {
|
|
29
|
+
await this.access.assertCanUseVisibility(input.visibility, user);
|
|
30
|
+
}
|
|
31
|
+
// Every field is optional, so `{}` is a valid body — and it would reach
|
|
32
|
+
// Drizzle as `.set({})`, which throws rather than updating nothing.
|
|
33
|
+
// Answer the row unchanged instead: a patch that asks for no change has
|
|
34
|
+
// already got what it asked for.
|
|
35
|
+
const changes = input.name !== undefined ||
|
|
36
|
+
input.visibility !== undefined ||
|
|
37
|
+
input.payload !== undefined;
|
|
38
|
+
if (!changes) {
|
|
39
|
+
const currentDefault = await this.repository.findDefaultId(user.id, existing.scope);
|
|
40
|
+
return (0, saved_views_query_1.toSavedView)(existing, user.id, currentDefault);
|
|
41
|
+
}
|
|
42
|
+
let updated;
|
|
43
|
+
try {
|
|
44
|
+
updated = await this.repository.update(id, input);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
if ((0, utils_server_1.isUniqueViolation)(error)) {
|
|
48
|
+
throw new errors_1.SavedViewNameTakenError(input.name ?? existing.name);
|
|
49
|
+
}
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
const defaultId = await this.repository.findDefaultId(user.id, updated.scope);
|
|
53
|
+
return (0, saved_views_query_1.toSavedView)(updated, user.id, defaultId);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
exports.UpdateSavedViewUseCase = UpdateSavedViewUseCase;
|
|
57
|
+
exports.UpdateSavedViewUseCase = UpdateSavedViewUseCase = tslib_1.__decorate([
|
|
58
|
+
(0, common_1.Injectable)(),
|
|
59
|
+
tslib_1.__param(0, (0, common_1.Inject)(saved_view_repository_1.SAVED_VIEW_REPOSITORY)),
|
|
60
|
+
tslib_1.__metadata("design:paramtypes", [Object, saved_view_access_service_1.SavedViewAccessService])
|
|
61
|
+
], UpdateSavedViewUseCase);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ContentTypeRegistry } from '../../registry/content-type-registry';
|
|
2
|
+
import { WorkspaceGrantsQuery } from '../../content-types/queries/workspace-grants.query';
|
|
3
|
+
/**
|
|
4
|
+
* Resolves a view's `scope` to a content type the open workspace may actually
|
|
5
|
+
* reach.
|
|
6
|
+
*
|
|
7
|
+
* Without this the views endpoint would be a way around
|
|
8
|
+
* {@link ContentGrantGuard}: `scope` names a content type, and an unchecked one
|
|
9
|
+
* lets a caller confirm that `content:salaries` exists in some workspace by
|
|
10
|
+
* saving a view over it. So the answer for an unknown type and for an ungranted
|
|
11
|
+
* one is the **same 404** the entries routes give — grants read before any
|
|
12
|
+
* registry decision, same status, same message.
|
|
13
|
+
*/
|
|
14
|
+
export declare class ViewScopeService {
|
|
15
|
+
private readonly registry;
|
|
16
|
+
private readonly grants;
|
|
17
|
+
constructor(registry: ContentTypeRegistry, grants: WorkspaceGrantsQuery);
|
|
18
|
+
/**
|
|
19
|
+
* Throws `NotFoundException` unless `scope` names a content type this
|
|
20
|
+
* workspace was granted. The DTO has already enforced the
|
|
21
|
+
* `content:<typeName>` shape.
|
|
22
|
+
*/
|
|
23
|
+
assertReachable(scope: string, workspaceId: string): Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=view-scope.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view-scope.service.d.ts","sourceRoot":"","sources":["../../../../src/lib/views/application/view-scope.service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAChF,OAAO,EAAE,oBAAoB,EAAE,MAAM,oDAAoD,CAAC;AAG1F;;;;;;;;;;GAUG;AACH,qBACa,gBAAgB;IAGrB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,QAAQ,EAAE,mBAAmB,EAC7B,MAAM,EAAE,oBAAoB;IAGjD;;;;OAIG;IACG,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAO3E"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ViewScopeService = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const common_1 = require("@nestjs/common");
|
|
6
|
+
const views_tokens_1 = require("../views.tokens");
|
|
7
|
+
const workspace_grants_query_1 = require("../../content-types/queries/workspace-grants.query");
|
|
8
|
+
const views_constants_1 = require("../views.constants");
|
|
9
|
+
/**
|
|
10
|
+
* Resolves a view's `scope` to a content type the open workspace may actually
|
|
11
|
+
* reach.
|
|
12
|
+
*
|
|
13
|
+
* Without this the views endpoint would be a way around
|
|
14
|
+
* {@link ContentGrantGuard}: `scope` names a content type, and an unchecked one
|
|
15
|
+
* lets a caller confirm that `content:salaries` exists in some workspace by
|
|
16
|
+
* saving a view over it. So the answer for an unknown type and for an ungranted
|
|
17
|
+
* one is the **same 404** the entries routes give — grants read before any
|
|
18
|
+
* registry decision, same status, same message.
|
|
19
|
+
*/
|
|
20
|
+
let ViewScopeService = class ViewScopeService {
|
|
21
|
+
registry;
|
|
22
|
+
grants;
|
|
23
|
+
constructor(registry, grants) {
|
|
24
|
+
this.registry = registry;
|
|
25
|
+
this.grants = grants;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Throws `NotFoundException` unless `scope` names a content type this
|
|
29
|
+
* workspace was granted. The DTO has already enforced the
|
|
30
|
+
* `content:<typeName>` shape.
|
|
31
|
+
*/
|
|
32
|
+
async assertReachable(scope, workspaceId) {
|
|
33
|
+
const typeName = scope.slice(views_constants_1.CONTENT_SCOPE_PREFIX.length);
|
|
34
|
+
const granted = await this.grants.grantedSlugs(workspaceId);
|
|
35
|
+
if (!granted.has(typeName) || !this.registry.get(typeName)) {
|
|
36
|
+
throw new common_1.NotFoundException(`Unknown content type "${typeName}".`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
exports.ViewScopeService = ViewScopeService;
|
|
41
|
+
exports.ViewScopeService = ViewScopeService = tslib_1.__decorate([
|
|
42
|
+
(0, common_1.Injectable)(),
|
|
43
|
+
tslib_1.__param(0, (0, views_tokens_1.InjectViewContentRegistry)()),
|
|
44
|
+
tslib_1.__metadata("design:paramtypes", [Function, workspace_grants_query_1.WorkspaceGrantsQuery])
|
|
45
|
+
], ViewScopeService);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type DynamicModule } from '@nestjs/common';
|
|
2
|
+
import type { ContentTypeRegistry } from '../registry/content-type-registry';
|
|
3
|
+
/**
|
|
4
|
+
* The saved-views module.
|
|
5
|
+
*
|
|
6
|
+
* A **second** module from this package rather than a branch of
|
|
7
|
+
* `ContentModule`, because it needs its own `ServerPlugin` entry — the contract
|
|
8
|
+
* carries exactly one `migrations` descriptor per plugin, and content's is
|
|
9
|
+
* already spent on the host-owned generated collection tables. Splitting the
|
|
10
|
+
* module keeps that seam honest: the views feature owns fixed tables it ships
|
|
11
|
+
* migrations for, and the content model's tables stay the host's.
|
|
12
|
+
*
|
|
13
|
+
* It provides the registry the plugin factory hands it under its **own** token
|
|
14
|
+
* (`VIEW_CONTENT_REGISTRY`), so `ViewScopeService` can resolve a scope without
|
|
15
|
+
* importing `ContentModule` — which would make the two plugins' load order
|
|
16
|
+
* load-bearing — and without two global modules both claiming
|
|
17
|
+
* `CONTENT_REGISTRY`.
|
|
18
|
+
*/
|
|
19
|
+
export declare class ContentViewsModule {
|
|
20
|
+
static forRoot(registry: ContentTypeRegistry): DynamicModule;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=content-views.module.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-views.module.d.ts","sourceRoot":"","sources":["../../../src/lib/views/content-views.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE5D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAa7E;;;;;;;;;;;;;;;GAeG;AACH,qBACa,kBAAkB;IAC3B,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,mBAAmB,GAAG,aAAa;CAuB/D"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var ContentViewsModule_1;
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.ContentViewsModule = void 0;
|
|
5
|
+
const tslib_1 = require("tslib");
|
|
6
|
+
const common_1 = require("@nestjs/common");
|
|
7
|
+
const workspace_grants_query_1 = require("../content-types/queries/workspace-grants.query");
|
|
8
|
+
const views_tokens_1 = require("./views.tokens");
|
|
9
|
+
const saved_view_repository_1 = require("./domain/saved-view.repository");
|
|
10
|
+
const drizzle_saved_view_repository_1 = require("./infrastructure/persistence/drizzle-saved-view.repository");
|
|
11
|
+
const saved_views_query_1 = require("./application/queries/saved-views.query");
|
|
12
|
+
const saved_view_access_service_1 = require("./application/saved-view-access.service");
|
|
13
|
+
const view_scope_service_1 = require("./application/view-scope.service");
|
|
14
|
+
const create_saved_view_use_case_1 = require("./application/use-cases/create-saved-view.use-case");
|
|
15
|
+
const update_saved_view_use_case_1 = require("./application/use-cases/update-saved-view.use-case");
|
|
16
|
+
const delete_saved_view_use_case_1 = require("./application/use-cases/delete-saved-view.use-case");
|
|
17
|
+
const set_default_view_use_case_1 = require("./application/use-cases/set-default-view.use-case");
|
|
18
|
+
const saved_views_controller_1 = require("./http/controllers/saved-views.controller");
|
|
19
|
+
/**
|
|
20
|
+
* The saved-views module.
|
|
21
|
+
*
|
|
22
|
+
* A **second** module from this package rather than a branch of
|
|
23
|
+
* `ContentModule`, because it needs its own `ServerPlugin` entry — the contract
|
|
24
|
+
* carries exactly one `migrations` descriptor per plugin, and content's is
|
|
25
|
+
* already spent on the host-owned generated collection tables. Splitting the
|
|
26
|
+
* module keeps that seam honest: the views feature owns fixed tables it ships
|
|
27
|
+
* migrations for, and the content model's tables stay the host's.
|
|
28
|
+
*
|
|
29
|
+
* It provides the registry the plugin factory hands it under its **own** token
|
|
30
|
+
* (`VIEW_CONTENT_REGISTRY`), so `ViewScopeService` can resolve a scope without
|
|
31
|
+
* importing `ContentModule` — which would make the two plugins' load order
|
|
32
|
+
* load-bearing — and without two global modules both claiming
|
|
33
|
+
* `CONTENT_REGISTRY`.
|
|
34
|
+
*/
|
|
35
|
+
let ContentViewsModule = ContentViewsModule_1 = class ContentViewsModule {
|
|
36
|
+
static forRoot(registry) {
|
|
37
|
+
return {
|
|
38
|
+
module: ContentViewsModule_1,
|
|
39
|
+
global: true,
|
|
40
|
+
controllers: [saved_views_controller_1.SavedViewsController],
|
|
41
|
+
providers: [
|
|
42
|
+
{ provide: views_tokens_1.VIEW_CONTENT_REGISTRY, useValue: registry },
|
|
43
|
+
{
|
|
44
|
+
provide: saved_view_repository_1.SAVED_VIEW_REPOSITORY,
|
|
45
|
+
useClass: drizzle_saved_view_repository_1.DrizzleSavedViewRepository
|
|
46
|
+
},
|
|
47
|
+
workspace_grants_query_1.WorkspaceGrantsQuery,
|
|
48
|
+
saved_views_query_1.SavedViewsQuery,
|
|
49
|
+
saved_view_access_service_1.SavedViewAccessService,
|
|
50
|
+
view_scope_service_1.ViewScopeService,
|
|
51
|
+
create_saved_view_use_case_1.CreateSavedViewUseCase,
|
|
52
|
+
update_saved_view_use_case_1.UpdateSavedViewUseCase,
|
|
53
|
+
delete_saved_view_use_case_1.DeleteSavedViewUseCase,
|
|
54
|
+
set_default_view_use_case_1.SetDefaultViewUseCase
|
|
55
|
+
],
|
|
56
|
+
exports: [saved_views_query_1.SavedViewsQuery]
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
exports.ContentViewsModule = ContentViewsModule;
|
|
61
|
+
exports.ContentViewsModule = ContentViewsModule = ContentViewsModule_1 = tslib_1.__decorate([
|
|
62
|
+
(0, common_1.Module)({})
|
|
63
|
+
], ContentViewsModule);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Transport-agnostic domain errors for saved views. */
|
|
2
|
+
export { SavedViewNotFoundError } from './saved-view-not-found.error';
|
|
3
|
+
export { SavedViewForbiddenError } from './saved-view-forbidden.error';
|
|
4
|
+
export { SavedViewNameTakenError } from './saved-view-name-taken.error';
|
|
5
|
+
export { SavedViewLimitError } from './saved-view-limit-error';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/lib/views/domain/errors/index.ts"],"names":[],"mappings":"AAAA,wDAAwD;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AACtE,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AACxE,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SavedViewLimitError = exports.SavedViewNameTakenError = exports.SavedViewForbiddenError = exports.SavedViewNotFoundError = void 0;
|
|
4
|
+
/** Transport-agnostic domain errors for saved views. */
|
|
5
|
+
var saved_view_not_found_error_1 = require("./saved-view-not-found.error");
|
|
6
|
+
Object.defineProperty(exports, "SavedViewNotFoundError", { enumerable: true, get: function () { return saved_view_not_found_error_1.SavedViewNotFoundError; } });
|
|
7
|
+
var saved_view_forbidden_error_1 = require("./saved-view-forbidden.error");
|
|
8
|
+
Object.defineProperty(exports, "SavedViewForbiddenError", { enumerable: true, get: function () { return saved_view_forbidden_error_1.SavedViewForbiddenError; } });
|
|
9
|
+
var saved_view_name_taken_error_1 = require("./saved-view-name-taken.error");
|
|
10
|
+
Object.defineProperty(exports, "SavedViewNameTakenError", { enumerable: true, get: function () { return saved_view_name_taken_error_1.SavedViewNameTakenError; } });
|
|
11
|
+
var saved_view_limit_error_1 = require("./saved-view-limit-error");
|
|
12
|
+
Object.defineProperty(exports, "SavedViewLimitError", { enumerable: true, get: function () { return saved_view_limit_error_1.SavedViewLimitError; } });
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The caller may read the view but not perform this write — editing or deleting
|
|
3
|
+
* someone else's view, or sharing one without `views:share`. Distinct from
|
|
4
|
+
* {@link SavedViewNotFoundError} because the view's existence is already known
|
|
5
|
+
* to the caller (it is listed for them), so a 403 discloses nothing new.
|
|
6
|
+
*/
|
|
7
|
+
export declare class SavedViewForbiddenError extends Error {
|
|
8
|
+
constructor(reason: string);
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=saved-view-forbidden.error.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"saved-view-forbidden.error.d.ts","sourceRoot":"","sources":["../../../../../src/lib/views/domain/errors/saved-view-forbidden.error.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;gBAClC,MAAM,EAAE,MAAM;CAI7B"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SavedViewForbiddenError = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* The caller may read the view but not perform this write — editing or deleting
|
|
6
|
+
* someone else's view, or sharing one without `views:share`. Distinct from
|
|
7
|
+
* {@link SavedViewNotFoundError} because the view's existence is already known
|
|
8
|
+
* to the caller (it is listed for them), so a 403 discloses nothing new.
|
|
9
|
+
*/
|
|
10
|
+
class SavedViewForbiddenError extends Error {
|
|
11
|
+
constructor(reason) {
|
|
12
|
+
super(reason);
|
|
13
|
+
this.name = 'SavedViewForbiddenError';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.SavedViewForbiddenError = SavedViewForbiddenError;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The caller has hit {@link VIEW_MAX_PER_SCOPE} views for one workspace + scope.
|
|
3
|
+
* A bound rather than a business rule: it keeps one account from filling the
|
|
4
|
+
* table, and the number is far above any realistic list of saved slices.
|
|
5
|
+
*/
|
|
6
|
+
export declare class SavedViewLimitError extends Error {
|
|
7
|
+
constructor();
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=saved-view-limit-error.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"saved-view-limit-error.d.ts","sourceRoot":"","sources":["../../../../../src/lib/views/domain/errors/saved-view-limit-error.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;;CAK7C"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SavedViewLimitError = void 0;
|
|
4
|
+
const views_constants_1 = require("../../views.constants");
|
|
5
|
+
/**
|
|
6
|
+
* The caller has hit {@link VIEW_MAX_PER_SCOPE} views for one workspace + scope.
|
|
7
|
+
* A bound rather than a business rule: it keeps one account from filling the
|
|
8
|
+
* table, and the number is far above any realistic list of saved slices.
|
|
9
|
+
*/
|
|
10
|
+
class SavedViewLimitError extends Error {
|
|
11
|
+
constructor() {
|
|
12
|
+
super(`You can save at most ${views_constants_1.VIEW_MAX_PER_SCOPE} views for one list.`);
|
|
13
|
+
this.name = 'SavedViewLimitError';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.SavedViewLimitError = SavedViewLimitError;
|