From 861bb98321beb19400282f0b6094d1a149be89b8 Mon Sep 17 00:00:00 2001 From: DylanBulmer Date: Fri, 26 Jul 2024 12:14:58 -0400 Subject: [PATCH] Document User, Profile, Role, and Permission; update naming convention from IEntity to EntityParamaters; update JWT token type --- deno.json | 5 ++- src/mod.ts | 1 + src/models/Annotation.ts | 8 ++-- src/models/Audit.ts | 5 ++- src/models/Authorization.ts | 43 ------------------- src/models/Base.ts | 18 ++++---- src/models/Dataset.ts | 8 ++-- src/models/Group.ts | 54 ++++++++++++++++++------ src/models/Message.ts | 11 +++-- src/models/Organization.ts | 42 +++++++++---------- src/models/Permission.ts | 78 ++++++++++++++++++++++++++++++++++ src/models/Profile.ts | 36 ++++++++-------- src/models/Project.ts | 8 ++-- src/models/Role.ts | 84 ++++++++++++++++++++++++------------- src/models/Sample.ts | 11 +++-- src/models/User.ts | 46 +++++++++++++------- src/models/UserGroup.ts | 8 ++-- src/models/mod.ts | 2 +- src/types/JWT.ts | 32 ++++++++++++-- 19 files changed, 317 insertions(+), 183 deletions(-) delete mode 100644 src/models/Authorization.ts create mode 100644 src/models/Permission.ts diff --git a/deno.json b/deno.json index e01a4bf..4bfae0e 100644 --- a/deno.json +++ b/deno.json @@ -1,13 +1,14 @@ { "name": "@codr/models", - "version": "0.1.5", + "version": "0.1.6", "exports": "./mod.ts", "fmt": { "lineWidth": 80, "indentWidth": 2, "useTabs": false, "semiColons": true, - "singleQuote": false + "singleQuote": false, + "proseWrap": "always" }, "publish": { "exclude": [".github/*", "tests/*.test.ts", ".gitignore", "coverage/*"] diff --git a/src/mod.ts b/src/mod.ts index 0ce6f2a..cccaa1e 100644 --- a/src/mod.ts +++ b/src/mod.ts @@ -1,2 +1,3 @@ // export * as Types from "./types/mod.ts"; export * from "./models/mod.ts"; +export type { JwtPayload } from "./types/mod.ts"; diff --git a/src/models/Annotation.ts b/src/models/Annotation.ts index 205b1c8..cbe09c6 100644 --- a/src/models/Annotation.ts +++ b/src/models/Annotation.ts @@ -1,8 +1,8 @@ import type { ObjectId } from "bson"; -import { Base, type IBase } from "./Base.ts"; +import { Base, type BaseParameters } from "./Base.ts"; import type { AtLeast } from "../types/mod.ts"; -export interface IAnnotation extends IBase<"Annotation"> { +export interface AnnotationParameters extends BaseParameters<"Annotation"> { projectId: ObjectId; datasetId: ObjectId; sampleId: ObjectId; @@ -30,7 +30,7 @@ export class Annotation extends Base<"Annotation"> { createdBy, updatedBy, }: AtLeast< - IAnnotation, + AnnotationParameters, | "createdBy" | "projectId" | "datasetId" @@ -46,7 +46,7 @@ export class Annotation extends Base<"Annotation"> { this.annotatedBy = annotatedBy; } - toJSON(): Omit { + toJSON(): Omit { const json = super.toJSON(); return { ...json, diff --git a/src/models/Audit.ts b/src/models/Audit.ts index 4c9cbbb..81a9cec 100644 --- a/src/models/Audit.ts +++ b/src/models/Audit.ts @@ -1,8 +1,9 @@ import type { ObjectId } from "bson"; -import type { IBase } from "./Base.ts"; +import type { BaseParameters } from "./Base.ts"; import type { ActionCode, ResourceCode } from "../types/mod.ts"; -export interface IAudit extends Omit, "createdBy"> { +export interface AuditParameters + extends Omit, "createdBy"> { type: ResourceCode; // Where: what system processed this event. action: ActionCode; // How: what action was taken. userId: ObjectId; // Who: which user made the change. diff --git a/src/models/Authorization.ts b/src/models/Authorization.ts deleted file mode 100644 index 90b4c45..0000000 --- a/src/models/Authorization.ts +++ /dev/null @@ -1,43 +0,0 @@ -import type { ObjectId } from "bson"; -import { Base, type IBase } from "./Base.ts"; -import type { ActionCode, AtLeast, ResourceCode } from "../types/mod.ts"; - -export interface IAuthorization extends IBase<"Authorization"> { - userId: ObjectId; - roleId: ObjectId[]; -} - -export interface IAuthorizationResponse { - userId: ObjectId; - roleCodes: string[]; - grants: Partial>>>; -} - -export class Authorization extends Base<"Authorization"> { - userId: ObjectId; - roleId: ObjectId[]; - - constructor({ - userId, - roleId = [], - _id, - _version, - createdAt, - updatedAt, - createdBy, - updatedBy, - }: AtLeast) { - super({ _id, _version, createdAt, updatedAt, createdBy, updatedBy }); - this.userId = userId; - this.roleId = roleId; - } - - toJSON(): Omit { - const json = super.toJSON(); - return { - userId: this.userId, - roleId: this.roleId, - ...json, - }; - } -} diff --git a/src/models/Base.ts b/src/models/Base.ts index f9cddb1..b3ab5f5 100644 --- a/src/models/Base.ts +++ b/src/models/Base.ts @@ -4,7 +4,7 @@ import type { AtLeast } from "../types/mod.ts"; /** * Base entity parameters for all database entities. */ -export interface IBase { +export interface BaseParameters { /** Typescript annotation for permissioning/authorization purposes. */ readonly kind: Kind; /** Entity version stored in the database. */ @@ -22,12 +22,12 @@ export interface IBase { } export class Base { - readonly _version: IBase["_version"]; - readonly _id: IBase["_id"]; - readonly createdAt: IBase["createdAt"]; - readonly updatedAt: IBase["updatedAt"]; - readonly createdBy: IBase["createdBy"]; - readonly updatedBy: IBase["updatedBy"]; + readonly _version: BaseParameters["_version"]; + readonly _id: BaseParameters["_id"]; + readonly createdAt: BaseParameters["createdAt"]; + readonly updatedAt: BaseParameters["updatedAt"]; + readonly createdBy: BaseParameters["createdBy"]; + readonly updatedBy: BaseParameters["updatedBy"]; constructor({ createdAt, @@ -36,7 +36,7 @@ export class Base { updatedBy, _id, _version = 0, - }: AtLeast, "createdBy">) { + }: AtLeast, "createdBy">) { this._version = _version; this._id = _id || new ObjectId(); @@ -52,7 +52,7 @@ export class Base { * Transforms the base class object into a json object. Useful for saving the entity to the database. * @returns a json representation of the base entity. */ - toJSON(): Omit, "kind"> { + toJSON(): Omit, "kind"> { return { _version: this._version, _id: this._id, diff --git a/src/models/Dataset.ts b/src/models/Dataset.ts index 0276e0c..788acbd 100644 --- a/src/models/Dataset.ts +++ b/src/models/Dataset.ts @@ -1,8 +1,8 @@ import type { ObjectId } from "bson"; import type { AtLeast, Flags } from "../types/mod.ts"; -import { Base, type IBase } from "./Base.ts"; +import { Base, type BaseParameters } from "./Base.ts"; -export interface IDataset extends IBase<"Dataset"> { +export interface DatasetParameters extends BaseParameters<"Dataset"> { projectId: ObjectId; flags: Flags; name: string; @@ -23,7 +23,7 @@ export class Dataset extends Base<"Dataset"> { name, createdBy, updatedBy, - }: AtLeast) { + }: AtLeast) { super({ _id, _version, @@ -37,7 +37,7 @@ export class Dataset extends Base<"Dataset"> { this.name = name; } - toJSON(): Omit { + toJSON(): Omit { const json = super.toJSON(); return { ...json, diff --git a/src/models/Group.ts b/src/models/Group.ts index 8ebd668..91b9506 100644 --- a/src/models/Group.ts +++ b/src/models/Group.ts @@ -1,31 +1,40 @@ import type { ObjectId } from "bson"; -import { Base, type IBase } from "./Base.ts"; +import { Base, type BaseParameters } from "./Base.ts"; import type { AtLeast, Flags } from "../types/mod.ts"; -export interface IGroup< +/** + * Parameters for creating a {@link Group} entity. + */ +export interface GroupParameters< Kind extends string = "Group", F extends object = Flags, -> extends IBase { - members: IGroupMember[]; +> extends BaseParameters { name: string; + members: GroupMemberParameters[]; flags: F; } -export interface IGroupMember { - type: GroupMemberEnum; +/** + * Parameters for adding Group members to the {@link GroupParameters}. + */ +export interface GroupMemberParameters { + type: GroupMemberType; _id: ObjectId; } -export enum GroupMemberEnum { - "USER" = "USER", - "TEAM" = "TEAM", +/** + * Type codes for the {@link GroupMemberParameters} object. + */ +export enum GroupMemberType { + "User" = "USER", + "Group" = "GROUP", } export class Group< K extends string = "Group", F extends object = Flags, > extends Base { - members: IGroupMember[]; + members: GroupMemberParameters[]; name: string; flags: F; @@ -39,14 +48,35 @@ export class Group< updatedAt, createdBy, updatedBy, - }: AtLeast, "createdBy" | "name" | "members" | "flags">) { + }: AtLeast< + GroupParameters, + "createdBy" | "name" | "members" | "flags" + >) { super({ _id, _version, createdAt, updatedAt, createdBy, updatedBy }); this.name = name; this.members = members; this.flags = flags; } - toJSON(): Omit, "kind"> { + addUser(id: ObjectId): GroupMemberParameters { + const member = { + type: GroupMemberType.User, + _id: id, + }; + this.members.push(member); + return member; + } + + addGroup(id: ObjectId): GroupMemberParameters { + const member = { + type: GroupMemberType.Group, + _id: id, + }; + this.members.push(member); + return member; + } + + toJSON(): Omit, "kind"> { const json = super.toJSON(); return { ...json, diff --git a/src/models/Message.ts b/src/models/Message.ts index 717f468..ada9563 100644 --- a/src/models/Message.ts +++ b/src/models/Message.ts @@ -1,8 +1,8 @@ import type { ObjectId } from "bson"; import type { AtLeast, MessageType } from "../types/mod.ts"; -import { Base, type IBase } from "./Base.ts"; +import { Base, type BaseParameters } from "./Base.ts"; -export interface IMessage extends IBase<"Message"> { +export interface MessageParameters extends BaseParameters<"Message"> { type: MessageType; subject: string; body: string; @@ -26,7 +26,10 @@ export class Message extends Base<"Message"> { updatedAt, createdBy, updatedBy, - }: AtLeast) { + }: AtLeast< + MessageParameters, + "createdBy" | "body" | "subject" | "to" | "type" + >) { super({ _id, _version, createdAt, updatedAt, createdBy, updatedBy }); this.body = body; this.subject = subject; @@ -34,7 +37,7 @@ export class Message extends Base<"Message"> { this.type = type; } - toJSON(): Omit { + toJSON(): Omit { const json = super.toJSON(); return { ...json, diff --git a/src/models/Organization.ts b/src/models/Organization.ts index 64a5224..1bf775c 100644 --- a/src/models/Organization.ts +++ b/src/models/Organization.ts @@ -1,26 +1,21 @@ import type { AtLeast } from "../types/mod.ts"; -import { Base, type IBase } from "./Base.ts"; - -/** - * Flags used in the {@link IOrganization} interface. - */ -interface OrganizationFlags { - /** Whether or not the organization is active */ - isActive: boolean; - /** Whether or not the organization is soft deleted */ - isDeleted: boolean; - /** Whether or not the organization is a demo organization */ - isDemo: boolean; -} +import { Base, type BaseParameters } from "./Base.ts"; /** * Parameters for building an {@link Organization} entity. */ -export interface IOrganization extends IBase<"Organization"> { +export interface OrganizationParameters extends BaseParameters<"Organization"> { /** A list of domains (and ports) linked to the Organziation */ domains: string[]; /** Flags options for the organization */ - flags: OrganizationFlags; + flags: { + /** Whether or not the organization is active */ + isActive: boolean; + /** Whether or not the organization is soft deleted */ + isDeleted: boolean; + /** Whether or not the organization is a demo organization */ + isDemo: boolean; + }; /** Name of the organization */ name: string; /** Slug for generating subdomains for the organization */ @@ -31,14 +26,14 @@ export interface IOrganization extends IBase<"Organization"> { * A class the represents an organization. */ export class Organization extends Base<"Organization"> { - readonly domains: string[]; - readonly flags: OrganizationFlags; - readonly name: string; - readonly slug: string; + readonly domains: OrganizationParameters["domains"]; + readonly flags: OrganizationParameters["flags"]; + readonly name: OrganizationParameters["name"]; + readonly slug: OrganizationParameters["slug"]; /** * Create an Organization entity. - * @param params An object of required and optional parameters referenced from the {@link IOrganization} interface. + * @param params An object of required and optional parameters referenced from the {@link OrganizationParameters} interface. */ constructor({ flags = { @@ -55,7 +50,10 @@ export class Organization extends Base<"Organization"> { name, slug, domains, - }: AtLeast) { + }: AtLeast< + OrganizationParameters, + "createdBy" | "domains" | "name" | "slug" + >) { super({ _id, _version, @@ -74,7 +72,7 @@ export class Organization extends Base<"Organization"> { * Transforms the organization class object to a json object. Useful for saving the entity to the database. * @returns a json representation of the organization. */ - toJSON(): Omit { + toJSON(): Omit { const json = super.toJSON(); return { ...json, diff --git a/src/models/Permission.ts b/src/models/Permission.ts new file mode 100644 index 0000000..319d968 --- /dev/null +++ b/src/models/Permission.ts @@ -0,0 +1,78 @@ +import { Base, type BaseParameters } from "./Base.ts"; +import type { User } from "./User.ts"; +import type { AtLeast } from "../types/mod.ts"; + +/** + * Parameters for creating a {@link Permission} entity. + */ +export interface PermissionParameters extends BaseParameters<"Permission"> { + title: string; + /** + * Permission code. + * @example `CREATE:USER` + */ + code: string; + /** Description/purpose of the role. */ + description: string; + /** Role flags */ + flags: { + /** + * Whether or not to enable the permission. + * @default true + */ + isActive: boolean; + /** + * Whether or not the permission is soft deleted. + * @default false + */ + isDeleted: boolean; + }; +} + +/** + * Permission entity class for representing a permission authoization. + */ +export class Permission extends Base<"Permission"> { + title: PermissionParameters["title"]; + code: PermissionParameters["code"]; + description: PermissionParameters["description"]; + flags: PermissionParameters["flags"]; + + constructor({ + title, + code, + description, + flags = { isActive: true, isDeleted: false }, + _id, + _version, + createdAt, + updatedAt, + createdBy, + updatedBy, + }: AtLeast< + PermissionParameters & { user: User }, + "createdBy" | "title" | "code" | "description" + >) { + super({ _id, _version, createdAt, updatedAt, createdBy, updatedBy }); + this.title = title; + this.code = code; + this.description = description; + this.flags = flags; + } + + /** + * Transforms the {@link Permission} class object into a {@link PermissionParameters}-like + * json object. Useful for saving the entity to the database. + * @returns a json representation of the permission authorization entity. + */ + toJSON(): Omit { + const json = super.toJSON(); + return { + title: this.title, + code: this.code, + description: this.description, + flags: this.flags, + ...json, + }; + } +} diff --git a/src/models/Profile.ts b/src/models/Profile.ts index d222e63..acc4604 100644 --- a/src/models/Profile.ts +++ b/src/models/Profile.ts @@ -1,30 +1,30 @@ import type { ObjectId } from "bson"; -import { Base, type IBase } from "./Base.ts"; +import { Base, type BaseParameters } from "./Base.ts"; import type { User } from "./User.ts"; import type { AtLeast } from "../types/mod.ts"; -export interface IProfile extends IBase<"Profile"> { +export interface ProfileParameters extends BaseParameters<"Profile"> { + /** Name of the user. */ name: { + /** First, or preferred name. */ first: string; + /** Last name. */ last: string; - preferred?: string; }; - phone?: string; + /** Optional avatar. */ avatarUrl?: string; + /** Username, unique within an organization. */ username: string; + /** Id of the user. */ userId: ObjectId; } export class Profile extends Base<"Profile"> { - name: { - first: string; - last: string; - preferred?: string; - }; - phone?: string; - avatarUrl?: string; - username: string; - userId: ObjectId; + name: ProfileParameters["name"]; + avatarUrl?: ProfileParameters["avatarUrl"]; + username: ProfileParameters["username"]; + userId: ProfileParameters["userId"]; + /** User entity linked to the profile. */ user?: User; constructor({ @@ -32,7 +32,6 @@ export class Profile extends Base<"Profile"> { avatarUrl, username, userId, - phone, _id, _version, user, @@ -41,25 +40,26 @@ export class Profile extends Base<"Profile"> { createdBy, updatedBy, }: AtLeast< - IProfile & { user: User }, + ProfileParameters & { user: User }, "createdBy" | "name" | "userId" | "username" >) { super({ _id, _version, createdAt, updatedAt, createdBy, updatedBy }); this.name = name; this.avatarUrl = avatarUrl; this.userId = userId; - this.phone = phone; this.username = username; this.user = user; } - toJSON(): Omit { + /** + * Profile entity class for representing a user profile. + */ + toJSON(): Omit { const json = super.toJSON(); return { name: this.name, avatarUrl: this.avatarUrl, userId: this.userId, - phone: this.phone, username: this.username, ...json, }; diff --git a/src/models/Project.ts b/src/models/Project.ts index 55d3352..135e81f 100644 --- a/src/models/Project.ts +++ b/src/models/Project.ts @@ -1,8 +1,8 @@ import type { ObjectId } from "bson"; import type { AtLeast, Flags, TaskType } from "../types/mod.ts"; -import { Base, type IBase } from "./Base.ts"; +import { Base, type BaseParameters } from "./Base.ts"; -export interface IProject extends IBase<"Project"> { +export interface ProjectParameters extends BaseParameters<"Project"> { name: string; type: TaskType; slug: string; @@ -40,7 +40,7 @@ export class Project extends Base<"Project"> { createdBy, updatedBy, }: AtLeast< - IProject, + ProjectParameters, "createdBy" | "bgColorClass" | "config" | "flags" | "slug" | "name" | "type" >) { super({ _id, _version, createdAt, updatedAt, createdBy, updatedBy }); @@ -54,7 +54,7 @@ export class Project extends Base<"Project"> { this.type = type; } - toJSON(): Omit { + toJSON(): Omit { const json = super.toJSON(); return { ...json, diff --git a/src/models/Role.ts b/src/models/Role.ts index 8a2923e..676b0b9 100644 --- a/src/models/Role.ts +++ b/src/models/Role.ts @@ -1,37 +1,55 @@ -import { Base, type IBase } from "./Base.ts"; +import { Base, type BaseParameters } from "./Base.ts"; import type { User } from "./User.ts"; -import type { AtLeast, JwtPayload } from "../types/mod.ts"; -import type { ActionCode, ResourceCode } from "../types/mod.ts"; +import type { AtLeast } from "../types/mod.ts"; +import type { ObjectId } from "bson"; -export interface IGrant { - resource: ResourceCode; - actions: ActionCode[]; - conditions: { - operator: "eq" | "within"; - subjectField: keyof JwtPayload; - resourceField: keyof R; - actions?: ActionCode[]; - }[]; -} - -export interface IRole extends IBase<"Role"> { - name: string; +/** + * Role parameters for creating a {@link Role} entity. + */ +export interface RoleParameters extends BaseParameters<"Role"> { + title: string; + /** + * Role code. + * @example `CODR:RESEARCHER` + */ code: string; + /** Description/purpose of the role. */ description: string; - grants: IGrant[]; + /** A list of ids that link to {@link Permission} entities. */ + permissions: ObjectId[]; + /** Role flags */ + flags: { + /** + * Whether or not to enable the role. Default is false to prevent accidental + * usage of an unready permission set. + * @default false + */ + isActive: boolean; + /** + * Whether or not the role is soft deleted. + * @default false + */ + isDeleted: boolean; + }; } +/** + * Role entity class for representing a role. A role is made of one or more + * {@link Permission}(s) for authorization. + */ export class Role extends Base<"Role"> { - name: string; - code: string; - description: string; - grants: IGrant[]; + title: RoleParameters["title"]; + code: RoleParameters["code"]; + description: RoleParameters["description"]; + permissions: RoleParameters["permissions"]; + flags: RoleParameters["flags"]; constructor({ - name, + title, code, description, - grants, + permissions, + flags = { isActive: false, isDeleted: false }, _id, _version, createdAt, @@ -39,23 +57,29 @@ export class Role extends Base<"Role"> { createdBy, updatedBy, }: AtLeast< - IRole & { user: User }, - "createdBy" | "name" | "code" | "description" | "grants" + RoleParameters & { user: User }, + "createdBy" | "title" | "code" | "description" | "permissions" >) { super({ _id, _version, createdAt, updatedAt, createdBy, updatedBy }); - this.name = name; + this.title = title; this.code = code; this.description = description; - this.grants = grants; + this.permissions = permissions; + this.flags = flags; } - toJSON(): Omit { + /** + * Transforms the {@link Role} class object into a {@link RoleParameters}-like json object. Useful for saving the entity to the database. + * @returns a json representation of the role authorization entity. + */ + toJSON(): Omit { const json = super.toJSON(); return { - name: this.name, + title: this.title, code: this.code, description: this.description, - grants: this.grants, + permissions: this.permissions, + flags: this.flags, ...json, }; } diff --git a/src/models/Sample.ts b/src/models/Sample.ts index 109f72d..6791e6e 100644 --- a/src/models/Sample.ts +++ b/src/models/Sample.ts @@ -1,8 +1,8 @@ import type { ObjectId } from "bson"; -import { Base, type IBase } from "./Base.ts"; +import { Base, type BaseParameters } from "./Base.ts"; import type { AtLeast } from "../types/mod.ts"; -export interface ISample extends IBase<"Sample"> { +export interface SampleParameters extends BaseParameters<"Sample"> { projectId: ObjectId; datasetId: ObjectId; payload: object; @@ -23,14 +23,17 @@ export class Sample extends Base<"Smaple"> { updatedAt, createdBy, updatedBy, - }: AtLeast) { + }: AtLeast< + SampleParameters, + "createdBy" | "datasetId" | "projectId" | "payload" + >) { super({ _id, _version, createdAt, updatedAt, createdBy, updatedBy }); this.projectId = projectId; this.datasetId = datasetId; this.payload = payload; } - toJSON(): Omit { + toJSON(): Omit { const json = super.toJSON(); return { ...json, diff --git a/src/models/User.ts b/src/models/User.ts index afa57df..27b5e57 100644 --- a/src/models/User.ts +++ b/src/models/User.ts @@ -1,27 +1,31 @@ -import { Base, type IBase } from "./Base.ts"; +import { Base, type BaseParameters } from "./Base.ts"; import type { AtLeast, UserTypeCode } from "../types/mod.ts"; import type { ObjectId } from "bson"; /** - * User entity parameters for creating a {@link User} entity. + * Parameters for creating a {@link User} entity. */ -export interface IUser extends IBase<"User"> { +export interface UserParameters extends BaseParameters<"User"> { /** Identifier from identitity provider. */ - identityId: string; + readonly identityId: string; /** The organization id the user belongs to. */ - organizationId: ObjectId; + readonly organizationId: ObjectId; /** Type of user from {@link UserTypeCode} */ type: UserTypeCode; - /** Email address used to signin, used for notification purposes only.*/ + /** Email address used for signin and notification purposes only. */ email: string; + /** Optional phone number. */ + phone?: string; + /** A list of {@link Role}s the user is assigned. */ + roles: ObjectId[]; /** User flags */ flags: { + /** Is the user account active or disabled */ + isActive: boolean; /** Is the user anonymous (primarily used for annotator accounts) */ isAnonymous: boolean; /** Is the user soft deleted */ isDeleted: boolean; - /** Is the user account active or disabled */ - isActive: boolean; }; } @@ -29,11 +33,12 @@ export interface IUser extends IBase<"User"> { * User entity class for representing a user account. */ export class User extends Base<"User"> { - identityId: IUser["identityId"]; - organizationId: IUser["organizationId"]; - type: IUser["type"]; - email: IUser["email"]; - flags: IUser["flags"]; + readonly identityId: UserParameters["identityId"]; + readonly organizationId: UserParameters["organizationId"]; + type: UserParameters["type"]; + email: UserParameters["email"]; + flags: UserParameters["flags"]; + roles: UserParameters["roles"]; constructor({ identityId, @@ -41,6 +46,7 @@ export class User extends Base<"User"> { type, email, flags = { isActive: false, isAnonymous: false, isDeleted: false }, + roles, _id, _version, createdAt, @@ -48,8 +54,14 @@ export class User extends Base<"User"> { createdBy, updatedBy, }: AtLeast< - IUser, - "createdBy" | "type" | "email" | "flags" | "organizationId" | "identityId" + UserParameters, + | "createdBy" + | "type" + | "email" + | "flags" + | "organizationId" + | "identityId" + | "roles" >) { super({ _id, _version, createdAt, updatedAt, createdBy, updatedBy }); this.type = type; @@ -57,18 +69,20 @@ export class User extends Base<"User"> { this.flags = flags; this.organizationId = organizationId; this.identityId = identityId; + this.roles = roles; } /** * Transforms the user class object into a json object. Useful for saving the entity to the database. * @returns a json representation of the user account. */ - toJSON(): Omit { + toJSON(): Omit { const json = super.toJSON(); return { identityId: this.identityId, organizationId: this.organizationId, type: this.type, + roles: this.roles, email: this.email, flags: this.flags, ...json, diff --git a/src/models/UserGroup.ts b/src/models/UserGroup.ts index 9068411..a539820 100644 --- a/src/models/UserGroup.ts +++ b/src/models/UserGroup.ts @@ -1,5 +1,5 @@ import type { Flags } from "../types/mod.ts"; -import { Group, type IGroup } from "./Group.ts"; +import { Group, type GroupParameters } from "./Group.ts"; interface UserGroupFlags extends Flags { // anonymize the data? @@ -7,7 +7,7 @@ interface UserGroupFlags extends Flags { // others can join? isJoinable: boolean; } -export type IUserGroup = IGroup<"UserGroup", UserGroupFlags>; +export type UserGroupParameters = GroupParameters<"UserGroup", UserGroupFlags>; export class UserGroup extends Group<"UserGroup", UserGroupFlags> { constructor({ @@ -25,7 +25,7 @@ export class UserGroup extends Group<"UserGroup", UserGroupFlags> { updatedBy, name, members, - }: IUserGroup) { + }: UserGroupParameters) { super({ _id, _version, @@ -39,7 +39,7 @@ export class UserGroup extends Group<"UserGroup", UserGroupFlags> { }); } - toJSON(): Omit { + toJSON(): Omit { const json = super.toJSON(); return { ...json, diff --git a/src/models/mod.ts b/src/models/mod.ts index fbe3d1f..8157433 100644 --- a/src/models/mod.ts +++ b/src/models/mod.ts @@ -1,11 +1,11 @@ export * from "./Annotation.ts"; export * from "./Audit.ts"; -export * from "./Authorization.ts"; export * from "./Base.ts"; export * from "./Dataset.ts"; export * from "./Group.ts"; export * from "./Message.ts"; export * from "./Organization.ts"; +export * from "./Permission.ts"; export * from "./Profile.ts"; export * from "./Project.ts"; export * from "./Role.ts"; diff --git a/src/types/JWT.ts b/src/types/JWT.ts index 797ed68..1de4562 100644 --- a/src/types/JWT.ts +++ b/src/types/JWT.ts @@ -1,10 +1,34 @@ import type { JwtPayload as JsonWebTokenPayload } from "jsonwebtoken"; -import type { IUser } from "../models/User.ts"; +import type { PermissionParameters, UserParameters } from "../mod.ts"; -interface DefinfedJwtPayload extends JsonWebTokenPayload { +export interface JwtParameters { + /** Type of user from {@link UserTypeCode}. */ + type: UserParameters["type"]; + /** A consolidated set of permission codes the user has accross all roles. */ + permissions: PermissionParameters["code"][]; +} + +export interface JwtPayload extends JsonWebTokenPayload, JwtParameters { + /** + * The issuer of the token. + * @default `https://api.codrcloud.com` + */ iss: string; + /** + * The user's stringified object id. + * @example ```User._id.toString();``` + */ sub: string; + /** + * JWT identifier, this should be a stringified ObjectId. + * @example ```new ObjectId().toString();``` + */ jti: string; + /** + * JWT Audience(s). This limits what domains the JWT can be used for. + * @example ``` + * [ "https://api.codrcloud.com/user", "https://api.codrcloud.com/project" ] + * ``` + */ + aud: string[]; } - -export type JwtPayload = DefinfedJwtPayload & IUser;