Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
3be9447
feat(user): export RoleService from user package
dipendraupreti Apr 10, 2024
98c16fe
feat: use new role service by createTenantOwnerRole
dipendraupreti Apr 10, 2024
78610e8
Merge branch 'feat/add-role-to-user' of github.com:dzangolab/fastify …
dipendraupreti Apr 10, 2024
6576b2e
feat(user): update roles type in user context
dipendraupreti Apr 10, 2024
55ae00e
chore: remove supertokens UserRoles from context and tenant resolver
dipendraupreti Apr 10, 2024
944f86b
refactor: replace supertokens role
dipendraupreti Apr 11, 2024
a4229cd
chore(user): fix add add to user sql
dipendraupreti Apr 11, 2024
a9299c2
chore: fix style
dipendraupreti Apr 11, 2024
80b55f6
Merge branch 'feat/add-role-to-user' of github.com:dzangolab/fastify …
dipendraupreti Apr 11, 2024
639317d
Merge branch 'feat/add-role-to-user' of github.com:dzangolab/fastify …
dipendraupreti Apr 15, 2024
383bda9
feat(user): update adminSignUp
dipendraupreti Apr 15, 2024
f789222
Merge branch 'feat/add-role-to-user' of github.com:dzangolab/fastify …
dipendraupreti Apr 15, 2024
1cd94ee
Merge branch 'feat/add-role-to-user' of github.com:dzangolab/fastify …
dipendraupreti Apr 15, 2024
28929d9
chore(user): fix style
dipendraupreti Apr 15, 2024
edf8d37
Merge branch 'feat/add-role-to-user' of github.com:dzangolab/fastify …
dipendraupreti Apr 22, 2024
6b03179
chore(user): update hasPermissionPlugin
dipendraupreti Apr 23, 2024
239dc8a
chore(user): improve query for isRoleExists and areRolesexist
dipendraupreti Apr 23, 2024
9b4321e
chore(user): update user resolver
dipendraupreti Apr 23, 2024
df2598f
Merge branch 'feat/add-role-to-user' of github.com:dzangolab/fastify …
dipendraupreti Apr 23, 2024
c504dea
chore(user): remove supertokens user roles recipe
dipendraupreti Apr 23, 2024
7cd8a0e
chore(user): improve createTenantOwnerRole
dipendraupreti Apr 23, 2024
a23ec1c
Merge branch 'feat/add-role-to-user' of github.com:dzangolab/fastify …
dipendraupreti Apr 23, 2024
a201374
chore(user): update getRolesbyName
dipendraupreti Apr 23, 2024
7eb5f9a
Merge branch 'feat/add-role-to-user' of github.com:dzangolab/fastify …
dipendraupreti Apr 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 28 additions & 3 deletions packages/multi-tenant/src/lib/createTenantOwnerRole.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,34 @@
import UserRoles from "supertokens-node/recipe/userroles";
import { RoleService } from "@dzangolab/fastify-user";

import { ROLE_TENANT_OWNER } from "../constants";

const createTenantOwnerRole = async () => {
await UserRoles.createNewRoleOrAddPermissions(ROLE_TENANT_OWNER, []);
import type { ApiConfig } from "@dzangolab/fastify-config";
import type { Database } from "@dzangolab/fastify-slonik";
import type {
Role,
RoleCreateInput,
RoleUpdateInput,
} from "@dzangolab/fastify-user";

const createTenantOwnerRole = async (config: ApiConfig, slonik: Database) => {
const service = new RoleService<Role, RoleCreateInput, RoleUpdateInput>(
config,
slonik
);

const filteredCount = await service.count({
key: "role",
operator: "eq",
value: ROLE_TENANT_OWNER,
});

if (!filteredCount) {
await service.create({
role: ROLE_TENANT_OWNER,
permissions: [],
default: false,
});
}
};

export default createTenantOwnerRole;
8 changes: 3 additions & 5 deletions packages/multi-tenant/src/lib/updateContext.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { wrapResponse } from "supertokens-node/framework/fastify";
import Session from "supertokens-node/recipe/session";
import UserRoles from "supertokens-node/recipe/userroles";

import getUserService from "../lib/getUserService";

import type { User } from "@dzangolab/fastify-user";
import type { FastifyRequest, FastifyReply } from "fastify";
import type { MercuriusContext } from "mercurius";

Expand All @@ -26,7 +26,7 @@ const updateContext = async (
const service = getUserService(config, slonik, tenant);

/* eslint-disable-next-line unicorn/no-null */
let user;
let user: User | null = null;

try {
user = await service.findById(userId);
Expand All @@ -39,10 +39,8 @@ const updateContext = async (
throw new Error("Unable to find user");
}

const { roles } = await UserRoles.getRolesForUser(userId);

context.user = user;
context.roles = roles;
context.roles = user.roles;
}
};

Expand Down
10 changes: 6 additions & 4 deletions packages/multi-tenant/src/model/tenants/handlers/all.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import UserRoles from "supertokens-node/recipe/userroles";

import { ROLE_TENANT_OWNER } from "../../../constants";
import getUserService from "../../../lib/getUserService";
import Service from "../service";

import type { User } from "@dzangolab/fastify-user";
import type { FastifyReply } from "fastify";
import type { SessionRequest } from "supertokens-node/framework/fastify";

Expand All @@ -24,11 +24,13 @@ const all = async (request: SessionRequest, reply: FastifyReply) => {

const service = new Service(request.config, request.slonik, request.dbSchema);

const { roles } = await UserRoles.getRolesForUser(userId);
const userService = getUserService(request.config, request.slonik);

const user = (await userService.findById(userId)) as User;

// [DU 2024-JAN-15] TODO: address the scenario in which a user possesses
// both roles: ADMIN and TENANT_OWNER
if (roles.includes(ROLE_TENANT_OWNER)) {
if (user.roles.some(({ role }) => role === ROLE_TENANT_OWNER)) {
service.ownerId = userId;
}

Expand Down
10 changes: 6 additions & 4 deletions packages/multi-tenant/src/model/tenants/handlers/tenant.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import UserRoles from "supertokens-node/recipe/userroles";

import { ROLE_TENANT_OWNER } from "../../../constants";
import getUserService from "../../../lib/getUserService";
import Service from "../service";

import type { User } from "@dzangolab/fastify-user";
import type { FastifyReply } from "fastify";
import type { SessionRequest } from "supertokens-node/framework/fastify";

Expand All @@ -24,11 +24,13 @@ const tenant = async (request: SessionRequest, reply: FastifyReply) => {

const service = new Service(request.config, request.slonik, request.dbSchema);

const { roles } = await UserRoles.getRolesForUser(userId);
const userService = getUserService(request.config, request.slonik);

const user = (await userService.findById(userId)) as User;

// [DU 2024-JAN-15] TODO: address the scenario in which a user possesses
// both roles: ADMIN and TENANT_OWNER
if (roles.includes(ROLE_TENANT_OWNER)) {
if (user.roles.some(({ role }) => role === ROLE_TENANT_OWNER)) {
service.ownerId = userId;
}

Expand Down
10 changes: 6 additions & 4 deletions packages/multi-tenant/src/model/tenants/handlers/tenants.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import UserRoles from "supertokens-node/recipe/userroles";

import { ROLE_TENANT_OWNER } from "../../../constants";
import getUserService from "../../../lib/getUserService";
import Service from "../service";

import type { User } from "@dzangolab/fastify-user";
import type { FastifyReply } from "fastify";
import type { SessionRequest } from "supertokens-node/framework/fastify";

Expand All @@ -24,11 +24,13 @@ const tenants = async (request: SessionRequest, reply: FastifyReply) => {

const service = new Service(request.config, request.slonik, request.dbSchema);

const { roles } = await UserRoles.getRolesForUser(userId);
const userService = getUserService(request.config, request.slonik);

const user = (await userService.findById(userId)) as User;

// [DU 2024-JAN-15] TODO: address the scenario in which a user possesses
// both roles: ADMIN and TENANT_OWNER
if (roles.includes(ROLE_TENANT_OWNER)) {
if (user.roles.some(({ role }) => role === ROLE_TENANT_OWNER)) {
service.ownerId = userId;
}

Expand Down
33 changes: 26 additions & 7 deletions packages/multi-tenant/src/model/tenants/resolver.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { User } from "@dzangolab/fastify-user";
import mercurius from "mercurius";
import UserRoles from "supertokens-node/recipe/userroles";

import Service from "./service";
import { ROLE_TENANT_OWNER } from "../../constants";
import getMultiTenantConfig from "../../lib/getMultiTenantConfig";
import getUserService from "../../lib/getUserService";

import type { TenantCreateInput } from "./../../types";
import type { FilterInput, SortInput } from "@dzangolab/fastify-slonik";
Expand Down Expand Up @@ -99,11 +100,17 @@ const Query = {
context.dbSchema
);

const { roles } = await UserRoles.getRolesForUser(userId);
const userService = getUserService(
context.config,
context.database,
context.tenant
);

const { roles } = (await userService.findById(userId)) as User;

// [DU 2024-JAN-15] TODO: address the scenario in which a user possesses
// both roles: ADMIN and TENANT_OWNER
if (roles.includes(ROLE_TENANT_OWNER)) {
if (roles.some(({ role }) => role === ROLE_TENANT_OWNER)) {
service.ownerId = userId;
}

Expand Down Expand Up @@ -138,11 +145,17 @@ const Query = {
context.dbSchema
);

const { roles } = await UserRoles.getRolesForUser(userId);
const userService = getUserService(
context.config,
context.database,
context.tenant
);

const { roles } = (await userService.findById(userId)) as User;

// [DU 2024-JAN-15] TODO: address the scenario in which a user possesses
// both roles: ADMIN and TENANT_OWNER
if (roles.includes(ROLE_TENANT_OWNER)) {
if (roles.some(({ role }) => role === ROLE_TENANT_OWNER)) {
service.ownerId = userId;
}

Expand Down Expand Up @@ -182,11 +195,17 @@ const Query = {
context.dbSchema
);

const { roles } = await UserRoles.getRolesForUser(userId);
const userService = getUserService(
context.config,
context.database,
context.tenant
);

const { roles } = (await userService.findById(userId)) as User;

// [DU 2024-JAN-15] TODO: address the scenario in which a user possesses
// both roles: ADMIN and TENANT_OWNER
if (roles.includes(ROLE_TENANT_OWNER)) {
if (roles.some(({ role }) => role === ROLE_TENANT_OWNER)) {
service.ownerId = userId;
}

Expand Down
4 changes: 2 additions & 2 deletions packages/multi-tenant/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ const plugin = async (
// Register domain discovery plugin
await fastify.register(tenantDiscoveryPlugin);

const { config } = fastify;
const { config, slonik } = fastify;

const supertokensConfig = { recipes };

// merge supertokens config
config.user.supertokens = merge(supertokensConfig, config.user.supertokens);

fastify.addHook("onReady", async () => {
await createTenantOwnerRole();
await createTenantOwnerRole(config, slonik);
});

done();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { areRolesExist, sendEmail, verifyEmail } from "@dzangolab/fastify-user";
import {
areRolesExist,
getRolesByNames,
sendEmail,
verifyEmail,
} from "@dzangolab/fastify-user";
import { deleteUser } from "supertokens-node";
import EmailVerification from "supertokens-node/recipe/emailverification";
import UserRoles from "supertokens-node/recipe/userroles";

import getUserService from "../../../lib/getUserService";
import Email from "../../utils/email";
Expand All @@ -19,7 +23,7 @@ const emailPasswordSignUp = (
return async (input) => {
const roles = (input.userContext.roles || []) as string[];

if (!(await areRolesExist(roles))) {
if (!(await areRolesExist(roles, config, slonik))) {
log.error(`At least one role from ${roles.join(", ")} does not exist.`);

throw {
Expand Down Expand Up @@ -73,22 +77,19 @@ const emailPasswordSignUp = (
};
}

const rolesResponse = await getRolesByNames(roles, config, slonik);

const rolesIds = rolesResponse.map(({ id }) => id);

await userService.addRolesToUser(originalResponse.user.id, rolesIds);

user = (await userService.findById(originalResponse.user.id)) as User;

originalResponse.user = {
...originalResponse.user,
...user,
};

for (const role of roles) {
const rolesResponse = await UserRoles.addRoleToUser(
originalResponse.user.id,
role
);

if (rolesResponse.status !== "OK") {
log.error(rolesResponse.status);
}
}

if (config.user.features?.signUp?.emailVerification) {
try {
if (input.userContext.autoVerifyEmail) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { areRolesExist } from "@dzangolab/fastify-user";
import { deleteUser } from "supertokens-node";
import { getUserByThirdPartyInfo } from "supertokens-node/recipe/thirdpartyemailpassword";
import UserRoles from "supertokens-node/recipe/userroles";

import getMultiTenantConfig from "../../../lib/getMultiTenantConfig";

Expand All @@ -13,7 +12,7 @@ const thirdPartySignInUp = (
originalImplementation: RecipeInterface,
fastify: FastifyInstance
): RecipeInterface["thirdPartySignInUp"] => {
const { config, log } = fastify;
const { config, log, slonik } = fastify;

return async (input) => {
const roles = (input.userContext.roles || []) as string[];
Expand Down Expand Up @@ -43,29 +42,20 @@ const thirdPartySignInUp = (
input
);

if (originalResponse.status === "OK" && originalResponse.createdNewUser) {
if (!(await areRolesExist(roles))) {
await deleteUser(originalResponse.user.id);
if (
originalResponse.status === "OK" &&
originalResponse.createdNewUser &&
!(await areRolesExist(roles, config, slonik))
) {
await deleteUser(originalResponse.user.id);

log.error(`At least one role from ${roles.join(", ")} does not exist.`);
log.error(`At least one role from ${roles.join(", ")} does not exist.`);

throw {
name: "SIGN_UP_FAILED",
message: "Something went wrong",
statusCode: 500,
} as FastifyError;
}

for (const role of roles) {
const rolesResponse = await UserRoles.addRoleToUser(
originalResponse.user.id,
role
);

if (rolesResponse.status !== "OK") {
log.error(rolesResponse.status);
}
}
throw {
name: "SIGN_UP_FAILED",
message: "Something went wrong",
statusCode: 500,
} as FastifyError;
}

return originalResponse;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { formatDate } from "@dzangolab/fastify-slonik";
import { ROLE_USER } from "@dzangolab/fastify-user";
import { ROLE_USER, getRolesByNames } from "@dzangolab/fastify-user";
import { deleteUser } from "supertokens-node";

import { ROLE_TENANT_OWNER } from "../../../constants";
Expand Down Expand Up @@ -80,7 +80,18 @@ const thirdPartySignInUpPOST = (
throw new Error("User not found");
}

user.roles = input.userContext.roles;
const rolesResponse = await getRolesByNames(
input.userContext.roles,
config,
slonik
);

const rolesIds = rolesResponse.map(({ id }) => id);

await userService.addRolesToUser(originalResponse.user.id, rolesIds);

user = (await userService.findById(originalResponse.user.id)) as User;

/*eslint-disable-next-line @typescript-eslint/no-explicit-any */
} catch (error: any) {
log.error("Error while creating user");
Expand Down Expand Up @@ -123,14 +134,11 @@ const thirdPartySignInUpPOST = (
});
}
return {
status: "OK",
createdNewUser: originalResponse.createdNewUser,
...originalResponse,
user: {
...originalResponse.user,
...user,
},
session: originalResponse.session,
authCodeResponse: originalResponse.authCodeResponse,
};
}

Expand Down
Loading