Skip to content

Commit

Permalink
implement user domain; fine-tune user entity
Browse files Browse the repository at this point in the history
  • Loading branch information
DylanBulmer committed Jun 18, 2023
1 parent 8141b49 commit 9540983
Show file tree
Hide file tree
Showing 20 changed files with 153 additions and 93 deletions.
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@codrjs/mongo",
"version": "1.0.3",
"version": "1.0.4",
"description": "A utility module to manage all mongodb connections.",
"main": "./cjs/index.js",
"module": "./esm/index.js",
Expand Down Expand Up @@ -48,11 +48,12 @@
"@casl/ability": "^6.5.0",
"@casl/mongoose": "^7.1.3",
"@codrjs/config": "^1.0.7",
"@codrjs/models": "^1.0.11",
"@codrjs/models": "^1.0.13",
"mongoose": "^7.3.0",
"tsc-alias": "^1.8.6"
},
"peerDependencies": {
"@codrjs/models": "^1.0.11",
"mongoose": "^7.3.0"
}
}
10 changes: 4 additions & 6 deletions src/abilities/Profile.ability.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import { IProfile, Types } from "@codrjs/models";
import { IProfile, Profile, Types } from "@codrjs/models";

const permissions: Types.Permissions<IProfile> = {
const permissions: Types.Permissions<IProfile, typeof Profile> = {
"codr:system": (_user, { can, cannot }) => {
can("manage", "Profile");
cannot("update", "Profile", { username: { $eq: "System" } });
cannot("delete", "Profile", { username: { $eq: "System" } });
cannot("manipulate", "Profile", { username: { $eq: "System" } });
},
"codr:admin": (_user, { can, cannot }) => {
can("manage", "Profile");
cannot("update", "Profile", { username: { $eq: "System" } });
cannot("delete", "Profile", { username: { $eq: "System" } });
cannot("manipulate", "Profile", { username: { $eq: "System" } });
},
"codr:researcher": (user, { can }) => {
// can read all profiles and update it's own
Expand Down
4 changes: 2 additions & 2 deletions src/abilities/Session.ability.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Types, ISession } from "@codrjs/models";
import { Types, ISession, Session } from "@codrjs/models";

const permissions: Types.Permissions<ISession> = {
const permissions: Types.Permissions<ISession, typeof Session> = {
"codr:system": (_user, { can }) => {
can("manage", "Session");
},
Expand Down
17 changes: 9 additions & 8 deletions src/abilities/User.ability.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
import { IUser, Types } from "@codrjs/models";
import { IUser, Types, User } from "@codrjs/models";
import { Types as MongoTypes } from "mongoose";

const permissions: Types.Permissions<IUser> = {
const permissions: Types.Permissions<IUser, typeof User> = {
/**
* @TODO find a way to disallow system from creating system users.
*/
"codr:system": (_user, { can, cannot }) => {
can("manage", "User");
cannot("update", "User", { role: { $eq: Types.UserRoleEnum.SYSTEM } });
cannot("delete", "User", { role: { $eq: Types.UserRoleEnum.SYSTEM } });
cannot("manipulate", "User", { type: { $eq: Types.UserEnum.SYSTEM } });
cannot("manipulate", "User", { role: { $eq: Types.UserRoleEnum.SYSTEM } });
},
/**
* @TODO find a way to disallow admin from creating system users.
*/
"codr:admin": (_user, { can, cannot }) => {
can("manage", "User");
cannot("update", "User", { role: { $eq: Types.UserRoleEnum.SYSTEM } });
cannot("delete", "User", { role: { $eq: Types.UserRoleEnum.SYSTEM } });
cannot("manipulate", "User", { type: { $eq: Types.UserEnum.SYSTEM } });
cannot("manipulate", "User", { role: { $eq: Types.UserRoleEnum.SYSTEM } });
},
"codr:researcher": (user, { can }) => {
// can only read it's own user
can("read", "User", { _id: user._id });
can("read", "User", { _id: new MongoTypes.ObjectId(user.sub) });
},
"codr:annotator": (user, { can }) => {
// can only read it's own user
can("read", "User", { _id: user._id });
can("read", "User", { _id: new MongoTypes.ObjectId(user.sub) });
},
};

Expand Down
7 changes: 4 additions & 3 deletions src/abilities/UserGroup.ability.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Types, IUserGroup } from "@codrjs/models";
import { Types, IUserGroup, UserGroup } from "@codrjs/models";

const permissions: Types.Permissions<IUserGroup> = {
const permissions: Types.Permissions<IUserGroup, typeof UserGroup> = {
"codr:system": (_user, { can }) => {
can("manage", "UserGroup");
},
Expand All @@ -20,5 +20,6 @@ const permissions: Types.Permissions<IUserGroup> = {
},
};

const UserGroupAbility = (user: Types.JwtPayload) => Types.DefineAbility(user, permissions);
const UserGroupAbility = (user: Types.JwtPayload) =>
Types.DefineAbility(user, permissions);
export default UserGroupAbility;
7 changes: 5 additions & 2 deletions src/schemas/Profile.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { IProfile, IUser } from "@codrjs/models";
import { IProfile } from "@codrjs/models";
import { Schema, SchemaTypes } from "mongoose";
import {
AccessibleFieldsModel,
AccessibleModel,
accessibleFieldsPlugin,
accessibleRecordsPlugin,
} from "@casl/mongoose";
import { UserDocument } from "./User";

export type ProfileDocument = IProfile & AccessibleFieldsModel<IProfile>;

export function createProfileModel(userModel: AccessibleModel<IUser>) {
export function createProfileModel(userModel: AccessibleModel<UserDocument>) {
const ProfileSchema = new Schema<IProfile>(
{
avatarUrl: String,
Expand All @@ -34,6 +35,8 @@ export function createProfileModel(userModel: AccessibleModel<IUser>) {
},
required: true,
},
createdAt: { type: Date },
updatedAt: { type: Date },
},
{
timestamps: true,
Expand Down
9 changes: 5 additions & 4 deletions src/schemas/Session.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { ISession, IUser } from "@codrjs/models";
import { ISession } from "@codrjs/models";
import { Schema, SchemaTypes } from "mongoose";
import {
AccessibleFieldsModel,
AccessibleModel,
accessibleFieldsPlugin,
accessibleRecordsPlugin,
} from "@casl/mongoose";
import { UserDocument } from "./User";

export type SessionDocument = ISession & AccessibleFieldsModel<ISession>;

export function createSessionModel(userModel: AccessibleModel<IUser>) {
export function createSessionModel(userModel: AccessibleModel<UserDocument>) {
const SessionSchema = new Schema<ISession>(
{
status: {
Expand All @@ -28,8 +29,8 @@ export function createSessionModel(userModel: AccessibleModel<IUser>) {
os: { type: String },
browser: { type: String },
ipAddress: { type: String },
createdAt: String,
updatedAt: String,
createdAt: { type: Date },
updatedAt: { type: Date },
},
{
timestamps: true,
Expand Down
16 changes: 14 additions & 2 deletions src/schemas/User.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { EmailRegex, IUser, Types } from "@codrjs/models";
import { Schema } from "mongoose";
import { Schema, SchemaTypes } from "mongoose";
import {
AccessibleFieldsModel,
accessibleFieldsPlugin,
accessibleRecordsPlugin,
} from "@casl/mongoose";

export type UserDocument = IUser & AccessibleFieldsModel<IUser>;
const UserSchema = new Schema<UserDocument>(
const UserSchema = new Schema<IUser>(
{
type: {
type: String,
Expand Down Expand Up @@ -41,6 +41,18 @@ const UserSchema = new Schema<UserDocument>(
isDeleted: false,
},
},
createdAt: { type: Date },
updatedAt: { type: Date },
createdBy: {
type: SchemaTypes.ObjectId,
required: true,
ref: "User",
},
updatedBy: {
type: SchemaTypes.ObjectId,
required: true,
ref: "User",
},
},
{
timestamps: true,
Expand Down
9 changes: 5 additions & 4 deletions src/schemas/UserGroup.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { IUser, IUserGroup } from "@codrjs/models";
import { IUserGroup } from "@codrjs/models";
import { Schema, SchemaTypes } from "mongoose";
import {
AccessibleFieldsModel,
AccessibleModel,
accessibleFieldsPlugin,
accessibleRecordsPlugin,
} from "@casl/mongoose";
import { UserDocument } from "./User";

export type UserGroupDocument = IUserGroup & AccessibleFieldsModel<IUserGroup>;

export function createUserGroupModel(userModel: AccessibleModel<IUser>) {
export function createUserGroupModel(userModel: AccessibleModel<UserDocument>) {
const UserGroupSchema = new Schema<UserGroupDocument>(
{
createdBy: {
Expand Down Expand Up @@ -51,8 +52,8 @@ export function createUserGroupModel(userModel: AccessibleModel<IUser>) {
isPrivate: false,
},
},
createdAt: { type: String },
updatedAt: { type: String },
createdAt: { type: Date },
updatedAt: { type: Date },
},
{
timestamps: true,
Expand Down
2 changes: 1 addition & 1 deletion src/types/CoreDatabase.ts → src/types/Database/Core.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DatabaseEnum } from "./Database";
import { DatabaseEnum } from ".";

export enum CoreModelEnum {
CONFIG = "Config",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DatabaseEnum } from "./Database";
import { DatabaseEnum } from ".";

export enum NotificationModelEnum {
MESSAGE = "Message",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DatabaseEnum } from "./Database";
import { DatabaseEnum } from ".";

export enum ProjectModelEnum {
ANNOTATION = "Annotation",
Expand Down
27 changes: 27 additions & 0 deletions src/types/Database/User.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { AccessibleModel } from "@casl/mongoose";
import { DatabaseEnum } from ".";
import { ProfileDocument } from "@/schemas/Profile";
import { SessionDocument } from "@/schemas/Session";
import { UserGroupDocument } from "@/schemas/UserGroup";
import { UserDocument } from "@/schemas/User";

export enum UserModelEnum {
PROFILE = "Profile",
SESSION = "Session",
USERGROUP = "UserGroup",
USER = "User",
}
export type UserModelType = keyof typeof UserModelEnum;
export type UserModels = `${UserModelEnum}`;

export interface DatabaseUserConfig {
name: DatabaseEnum.USER;
models: UserModels[];
}

export interface ILoadedUserModels<T extends UserModels> {
Profile: T extends "Profile" ? AccessibleModel<ProfileDocument> : never;
Session: T extends "Session" ? AccessibleModel<SessionDocument> : never;
UserGroup: T extends "UserGroup" ? AccessibleModel<UserGroupDocument> : never;
User: AccessibleModel<UserDocument>;
}
File renamed without changes.
5 changes: 5 additions & 0 deletions src/types/MongooseEvent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export type MongooseConnectionEvent =
| "open"
| "close"
| "reconnected"
| "disconnected";
24 changes: 0 additions & 24 deletions src/types/UserDatabase.ts

This file was deleted.

9 changes: 5 additions & 4 deletions src/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from "./CoreDatabase";
export * from "./Database";
export * from "./NotificationDatabase";
export * from "./ProjectDatabase";
export * from "./UserDatabase";
export * from "./Database/Core";
export * from "./Database/Notification";
export * from "./Database/Project";
export * from "./Database/User";
export * from "./MongooseEvent";
39 changes: 19 additions & 20 deletions src/utils/MongoManager/UserDatabaseSetup.ts
Original file line number Diff line number Diff line change
@@ -1,43 +1,42 @@
import { createProfileModel } from "@/schemas/Profile";
import { createSessionModel } from "@/schemas/Session";
import UserSchema from "@/schemas/User";
import { createUserGroupModel } from "@/schemas/UserGroup";
import { UserModelEnum, UserModels } from "@/types";
import { ProfileDocument, createProfileModel } from "@/schemas/Profile";
import { SessionDocument, createSessionModel } from "@/schemas/Session";
import UserSchema, { UserDocument } from "@/schemas/User";
import { UserGroupDocument, createUserGroupModel } from "@/schemas/UserGroup";
import { ILoadedUserModels, UserModelEnum, UserModels } from "@/types";
import { AccessibleModel } from "@casl/mongoose";
import { IProfile, ISession, IUser, IUserGroup } from "@codrjs/models";
import mongoose from "mongoose";
import type { Connection } from "mongoose";

export default function userDatabaseSetup(
database: mongoose.Connection,
database: Connection,
use: Record<UserModels, boolean>,
loaded: Record<UserModels, AccessibleModel<any>>,
loaded: ILoadedUserModels<UserModels>,
) {
// add model only if needed.
if (use.User) {
loaded.User = database.model<IUser, AccessibleModel<IUser>>(
loaded.User = database.model<UserDocument, AccessibleModel<UserDocument>>(
UserModelEnum.USER,
UserSchema,
);
}

if (use.Profile) {
loaded.Profile = database.model<IProfile, AccessibleModel<IProfile>>(
UserModelEnum.PROFILE,
createProfileModel(loaded.User),
);
loaded.Profile = database.model<
ProfileDocument,
AccessibleModel<ProfileDocument>
>(UserModelEnum.PROFILE, createProfileModel(loaded.User));
}

if (use.Session) {
loaded.Session = database.model<ISession, AccessibleModel<ISession>>(
UserModelEnum.SESSION,
createSessionModel(loaded.User),
);
loaded.Session = database.model<
SessionDocument,
AccessibleModel<SessionDocument>
>(UserModelEnum.SESSION, createSessionModel(loaded.User));
}

if (use.UserGroup) {
loaded.UserGroup = database.model<
IUserGroup,
AccessibleModel<IUserGroup>
UserGroupDocument,
AccessibleModel<UserGroupDocument>
>(UserModelEnum.USERGROUP, createUserGroupModel(loaded.User));
}
}
Loading

0 comments on commit 9540983

Please sign in to comment.