Skip to content

Commit

Permalink
implement new policy, rule, authorization, and organization models
Browse files Browse the repository at this point in the history
  • Loading branch information
DylanBulmer committed Apr 7, 2024
1 parent 8109cc6 commit e1b9491
Show file tree
Hide file tree
Showing 23 changed files with 276 additions and 162 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@codrjs/models",
"version": "1.0.14",
"version": "1.0.15",
"description": "",
"main": "./cjs/index.js",
"module": "./esm/index.js",
Expand Down Expand Up @@ -57,6 +57,6 @@
"uuid": "^9.0.0"
},
"peerDependencies": {
"@codrjs/config": "^1.0.6"
"@codrjs/config": "^1.0.7"
}
}
6 changes: 3 additions & 3 deletions src/entities/Audit.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { Types } from "mongoose";
import type { IBase } from "./Base";
import type { ActionType, EntityType } from "../types";
import type { ActionEnum, ResourceEnum } from "../types";

export interface IAudit extends Omit<IBase<"Audit">, "createdBy"> {
entityType: EntityType; // (where) what entity got modified
action: ActionType; // action taken
entityType: ResourceEnum; // (where) what entity got modified
action: ActionEnum; // action taken
userId: Types.ObjectId; // who
payload: object; // what data got modified
}
43 changes: 43 additions & 0 deletions src/entities/Authorization.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import type { Types } from "mongoose";
import { Base, IBase } from "./Base";
import type { ActionType, AtLeast, ResourceType } from "@/types";

export interface IAuthorization extends IBase<"Authorization"> {
userId: Types.ObjectId;
roleId: Types.ObjectId[];
}

export interface IAuthorizationResponse {
userId: Types.ObjectId;
roleCodes: string[];
grants: Partial<Record<ResourceType, Partial<Record<ActionType, boolean>>>>;
}

export class Authorization extends Base {
userId: Types.ObjectId;
roleId: Types.ObjectId[];

constructor({
userId,
roleId = [],
_id,
__v,
createdAt,
updatedAt,
createdBy,
updatedBy,
}: AtLeast<IAuthorization, "createdBy" | "userId">) {
super({ _id, __v, createdAt, updatedAt, createdBy, updatedBy });
this.userId = userId;
this.roleId = roleId;
}

toJSON() {
const json = super.toJSON();
return {
userId: this.userId,
roles: this.roleId,
...json,
};
}
}
4 changes: 2 additions & 2 deletions src/entities/Base.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Types } from "mongoose";
import { AtLeast, IModelKind } from "../types";
import { AtLeast } from "../types";

export interface IBase<K extends string = string> extends IModelKind<K> {
export interface IBase<K extends string = string> {
readonly kind: K;
__v?: number;
_id: Types.ObjectId;
Expand Down
8 changes: 3 additions & 5 deletions src/entities/Dataset.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { Types } from "mongoose";
import { Group, IGroup } from "./Group";
import { AtLeast } from "@/types";
import { AtLeast, Flags } from "@/types";

// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface IDataset extends IGroup<"Dataset"> {
export interface IDataset extends IGroup<"Dataset", Flags> {
projectId: Types.ObjectId;
}

Expand All @@ -19,12 +19,11 @@ export class Dataset extends Group {
updatedAt,
name,
members,
teams,
createdBy,
updatedBy,
}: AtLeast<
IDataset,
"createdBy" | "name" | "members" | "teams" | "flags" | "projectId"
"createdBy" | "name" | "members" | "flags" | "projectId"
>) {
super({
_id,
Expand All @@ -35,7 +34,6 @@ export class Dataset extends Group {
updatedBy,
name,
members,
teams,
flags,
});
this.projectId = projectId;
Expand Down
33 changes: 19 additions & 14 deletions src/entities/Group.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,45 @@
import type { Types } from "mongoose";
import { Base, IBase } from "./Base";
import { Flags } from "../types/Flags";
import { AtLeast } from "@/types";

export interface IGroup<Kind extends string = "Group", F = object>
extends IBase<Kind> {
createdBy: Types.ObjectId;
members: Types.ObjectId[];
export interface IGroup<
Kind extends string = "Group",
F extends object = object,
> extends IBase<Kind> {
members: IGroupMember[];
name: string;
teams: Types.ObjectId[];
flags: Flags & F;
flags: F;
}

export interface IGroupMember {
type: GroupMemberEnum;
_id: Types.ObjectId;
}

export enum GroupMemberEnum {
"USER" = "USER",
"TEAM" = "TEAM",
}

export class Group extends Base {
members: Types.ObjectId[];
members: IGroupMember[];
name: string;
teams: Types.ObjectId[];
flags: Flags & object;
flags: object;

constructor({
name,
members,
teams,
flags,
_id,
__v,
createdAt,
updatedAt,
createdBy,
updatedBy,
}: AtLeast<IGroup, "createdBy" | "name" | "members" | "teams" | "flags">) {
}: AtLeast<IGroup, "createdBy" | "name" | "members" | "flags">) {
super({ _id, __v, createdAt, updatedAt, createdBy, updatedBy });
this.name = name;
this.members = members;
this.teams = teams;
this.flags = flags;
}

Expand All @@ -43,7 +49,6 @@ export class Group extends Base {
...json,
members: this.members,
name: this.name,
teams: this.teams,
flags: this.flags,
};
}
Expand Down
54 changes: 54 additions & 0 deletions src/entities/Organization.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { Group, IGroup } from "./Group";

interface Flags {
isActive: boolean;
isDeleted: boolean;
}
export interface IOrganization extends IGroup<"Organization", Flags> {
slug: string;
domain: string; // to restrict signin to a specified domain
}

export class Organization extends Group {
readonly slug: string;
readonly domain: string;

constructor({
flags = {
isActive: true,
isDeleted: false,
},
_id,
__v,
createdAt,
updatedAt,
createdBy,
updatedBy,
name,
members,
slug,
domain,
}: IOrganization) {
super({
_id,
__v,
createdAt,
updatedAt,
createdBy,
updatedBy,
name,
members,
flags,
});
this.slug = slug;
this.domain = domain;
}

toJSON() {
const json = super.toJSON();
return {
...json,
slug: this.slug,
};
}
}
62 changes: 62 additions & 0 deletions src/entities/Role.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { Base, IBase } from "./Base";
import { User } from "./User";
import { AtLeast, JwtPayload } from "@/types";
import { ActionEnum, ResourceEnum } from "@/types/Permissions";

export interface IGrant<R = object> {
resource: ResourceEnum;
actions: ActionEnum[];
conditions: {
operator: "eq" | "within";
subjectField: keyof JwtPayload;
resourceField: keyof R;
actions?: ActionEnum[];
}[];
}

export interface IRole extends IBase<"Role"> {
name: string;
code: string;
description: string;
grants: IGrant[];
}

export class Role extends Base {
name: string;
code: string;
description?: string;
grants: IGrant[];

constructor({
name,
code,
description,
grants,
_id,
__v,
createdAt,
updatedAt,
createdBy,
updatedBy,
}: AtLeast<
IRole & { user: User },
"createdBy" | "name" | "code" | "description" | "grants"
>) {
super({ _id, __v, createdAt, updatedAt, createdBy, updatedBy });
this.name = name;
this.code = code;
this.description = description;
this.grants = grants;
}

toJSON() {
const json = super.toJSON();
return {
name: this.name,
code: this.code,
description: this.description,
grants: this.grants,
...json,
};
}
}
11 changes: 4 additions & 7 deletions src/entities/User.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Base, IBase } from "./Base";
import { AtLeast, UserEnum, UserRoleEnum } from "../types";
import { AtLeast, UserEnum } from "../types";
import { Types } from "mongoose";

export interface IUser extends IBase<"User"> {
organizationId: Types.ObjectId;
type: UserEnum;
email: string;
role: UserRoleEnum;
flags: {
isAnonymous: boolean;
isDeleted: boolean;
Expand All @@ -15,7 +16,6 @@ export interface IUser extends IBase<"User"> {
export class User extends Base {
type: UserEnum;
email: string;
role: UserRoleEnum;
flags: {
isAnonymous: boolean;
isDeleted: boolean;
Expand All @@ -25,28 +25,25 @@ export class User extends Base {
constructor({
type,
email,
role,
flags = { isDisabled: false, isAnonymous: false, isDeleted: false },
_id,
__v,
createdAt,
updatedAt,
createdBy,
updatedBy,
}: AtLeast<IUser, "createdBy" | "type" | "role" | "email" | "flags">) {
}: AtLeast<IUser, "createdBy" | "type" | "email" | "flags">) {
super({ _id, __v, createdAt, updatedAt, createdBy, updatedBy });
this.type = type;
this.email = email;
this.flags = flags;
this.role = role;
}

toJSON() {
const json = super.toJSON();
return {
type: this.type,
email: this.email,
role: this.role,
flags: this.flags,
...json,
};
Expand Down
5 changes: 2 additions & 3 deletions src/entities/UserGroup.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Flags } from "@/types";
import { Group, IGroup } from "./Group";

interface IAdditionalFlags {
interface IAdditionalFlags extends Flags {
// anonymize the data?
isAnonymous: boolean;
// others can join?
Expand All @@ -24,7 +25,6 @@ export class UserGroup extends Group {
updatedBy,
name,
members,
teams,
}: IUserGroup) {
super({
_id,
Expand All @@ -35,7 +35,6 @@ export class UserGroup extends Group {
updatedBy,
name,
members,
teams,
flags,
});
}
Expand Down
3 changes: 3 additions & 0 deletions src/entities/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
export * from "./Annotation";
export * from "./Audit";
export * from "./Authorization";
export * from "./Base";
export * as Config from "./Config";
export * from "./Dataset";
export * from "./Group";
export * from "./Message";
export * from "./Organization";
export * from "./Profile";
export * from "./Project";
export * from "./Role";
export * from "./Sample";
export * from "./Session";
export * from "./Template";
Expand Down
Loading

0 comments on commit e1b9491

Please sign in to comment.