add first operation in user role
This commit is contained in:
@ -8,7 +8,11 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/client": "^6.7.0",
|
"@prisma/client": "^6.7.0",
|
||||||
"elysia": "latest"
|
"@types/jsonwebtoken": "^9.0.9",
|
||||||
|
"cookie": "^1.0.2",
|
||||||
|
"elysia": "latest",
|
||||||
|
"joi": "^17.13.3",
|
||||||
|
"jsonwebtoken": "^9.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"bun-types": "latest",
|
"bun-types": "latest",
|
||||||
|
|||||||
46
src/helpers/jwt/decodeToken/index.ts
Normal file
46
src/helpers/jwt/decodeToken/index.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import jwt from "jsonwebtoken";
|
||||||
|
import { Context } from "elysia";
|
||||||
|
import { JWTAuthToken } from "./types";
|
||||||
|
import { returnErrorResponse } from "../../callback/httpResponse";
|
||||||
|
import { parse } from "cookie";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies the authentication cookie from the request header.
|
||||||
|
*
|
||||||
|
* This helper function is used in an ElysiaJS context to check the validity of
|
||||||
|
* a user's authentication token stored in cookies. If the cookie is not found,
|
||||||
|
* it returns a `400 Bad Request`. If the token is invalid or expired, it returns
|
||||||
|
* a `401 Unauthorized`. If the token is valid, it returns the decoded user data.
|
||||||
|
*
|
||||||
|
* @param ctx - The request context from Elysia, used to read headers and set the response.
|
||||||
|
*
|
||||||
|
* @returns The decoded JWT payload if the token is valid,
|
||||||
|
* or a standardized error response if the cookie is missing or invalid.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const decodedToken = decodeAuthToken(ctx);
|
||||||
|
* ctx => Elysia context
|
||||||
|
*/
|
||||||
|
export const JWTDecodeToken = (ctx: Context): JWTAuthToken => {
|
||||||
|
const cookiePayload = ctx.request.headers.get("Cookie");
|
||||||
|
if (!cookiePayload)
|
||||||
|
throw returnErrorResponse(ctx.set, 400, "Bad Request", "No cookies found");
|
||||||
|
|
||||||
|
const cookies = parse(cookiePayload);
|
||||||
|
const cookiesToken = cookies.auth_token!;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const decodedToken = jwt.verify(
|
||||||
|
cookiesToken,
|
||||||
|
process.env.JWT_SECRET!
|
||||||
|
) as JWTAuthToken;
|
||||||
|
return decodedToken;
|
||||||
|
} catch (error) {
|
||||||
|
throw returnErrorResponse(
|
||||||
|
ctx.set,
|
||||||
|
401,
|
||||||
|
"Unauthorized",
|
||||||
|
"Invalid or expired token"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
62
src/helpers/jwt/decodeToken/types.ts
Normal file
62
src/helpers/jwt/decodeToken/types.ts
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
export interface JWTAuthToken {
|
||||||
|
id: string;
|
||||||
|
isAuthenticated: boolean;
|
||||||
|
userId: string;
|
||||||
|
deviceType: string;
|
||||||
|
deviceOs: string;
|
||||||
|
deviceIp: string;
|
||||||
|
isOnline: boolean;
|
||||||
|
lastOnline: Date;
|
||||||
|
validUntil: Date;
|
||||||
|
deletedAt: null;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
user: User;
|
||||||
|
iat: number;
|
||||||
|
exp: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface User {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
username: string;
|
||||||
|
email: string;
|
||||||
|
birthDate: null;
|
||||||
|
gender: null;
|
||||||
|
phoneCC: null;
|
||||||
|
phoneNumber: null;
|
||||||
|
bioProfile: null;
|
||||||
|
profilePicture: null;
|
||||||
|
commentPicture: null;
|
||||||
|
preferenceId: null;
|
||||||
|
verifiedAt: null;
|
||||||
|
disabledAt: null;
|
||||||
|
deletedAt: null;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
roles: Role[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Role {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
primaryColor: string;
|
||||||
|
secondaryColor: string;
|
||||||
|
pictureImage: string;
|
||||||
|
badgeImage: null;
|
||||||
|
isSuperadmin: boolean;
|
||||||
|
canEditMedia: boolean;
|
||||||
|
canManageMedia: boolean;
|
||||||
|
canEditEpisodes: boolean;
|
||||||
|
canManageEpisodes: boolean;
|
||||||
|
canEditComment: boolean;
|
||||||
|
canManageComment: boolean;
|
||||||
|
canEditUser: boolean;
|
||||||
|
canManageUser: boolean;
|
||||||
|
canEditSystem: boolean;
|
||||||
|
canManageSystem: boolean;
|
||||||
|
createdBy: string;
|
||||||
|
deletedAt: null;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
}
|
||||||
@ -1,5 +1,80 @@
|
|||||||
|
import { Prisma } from "@prisma/client";
|
||||||
import { Context } from "elysia";
|
import { Context } from "elysia";
|
||||||
|
import {
|
||||||
|
returnErrorResponse,
|
||||||
|
returnWriteResponse,
|
||||||
|
} from "../../../helpers/callback/httpResponse";
|
||||||
|
import { handlePrismaError } from "../../../utils/databases/prisma/error/handler";
|
||||||
|
import { createUserRoleSchema } from "../userRole.schema";
|
||||||
|
import { JWTDecodeToken } from "../../../helpers/jwt/decodeToken";
|
||||||
|
import { prisma } from "../../../utils/databases/prisma/connection";
|
||||||
|
import { createUserRoleService } from "../services/createUserRole.service";
|
||||||
|
|
||||||
export const createUserRole = (ctx: Context) => {
|
/**
|
||||||
return "Hello User Role Module";
|
* @function createUserRole
|
||||||
|
* @description Creates a new user role in the database.
|
||||||
|
*
|
||||||
|
* @param {Context & { body: UserRole }} ctx - The context object containing the request body.
|
||||||
|
* @param {UserRole} ctx.body - The user role data to be created.
|
||||||
|
*
|
||||||
|
* @returns {Promise<Object>} A response object indicating success or failure.
|
||||||
|
* @throws {Object} An error response object if validation fails or an error occurs during role creation.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* Request route: POST /roles
|
||||||
|
* Request body:
|
||||||
|
* {
|
||||||
|
* "userID": "e31668e6-c261-4a7e-9469-ffad734cf2dd",
|
||||||
|
* "name": "Admin",
|
||||||
|
* "primaryColor": "#D9D9D9",
|
||||||
|
* "secondaryColor": "#FFFFFF",
|
||||||
|
* "pictureImage": "https://example.com/picture.jpg",
|
||||||
|
* "badgeImage": "https://example.com/badge.jpg",
|
||||||
|
* "isSuperadmin": false,
|
||||||
|
* "canEditMedia": false,
|
||||||
|
* "canManageMedia": false,
|
||||||
|
* "canEditEpisodes": false,
|
||||||
|
* "canManageEpisodes": false,
|
||||||
|
* "canEditComment": false,
|
||||||
|
* "canManageComment": false,
|
||||||
|
* "canEditUser": false,
|
||||||
|
* "canManageUser": false,
|
||||||
|
* "canEditSystem": false,
|
||||||
|
* "canManageSystem": false
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
export const createUserRole = async (
|
||||||
|
ctx: Context & { body: Prisma.UserRoleUncheckedCreateInput }
|
||||||
|
) => {
|
||||||
|
const { error } = createUserRoleSchema.validate(ctx.body);
|
||||||
|
if (error)
|
||||||
|
return returnErrorResponse(ctx.set, 400, "Invalid user input", error);
|
||||||
|
|
||||||
|
const formData: Prisma.UserRoleUncheckedCreateInput = { ...ctx.body };
|
||||||
|
const userCreator = JWTDecodeToken(ctx);
|
||||||
|
|
||||||
|
const dataPayload = {
|
||||||
|
...formData,
|
||||||
|
isSuperadmin: Boolean(formData.isSuperadmin),
|
||||||
|
canEditMedia: Boolean(formData.canEditMedia),
|
||||||
|
canManageMedia: Boolean(formData.canManageMedia),
|
||||||
|
canEditEpisodes: Boolean(formData.canEditEpisodes),
|
||||||
|
canManageEpisodes: Boolean(formData.canManageEpisodes),
|
||||||
|
canEditComment: Boolean(formData.canEditComment),
|
||||||
|
canManageComment: Boolean(formData.canManageComment),
|
||||||
|
canEditUser: Boolean(formData.canEditUser),
|
||||||
|
canManageUser: Boolean(formData.canManageUser),
|
||||||
|
canEditSystem: Boolean(formData.canEditSystem),
|
||||||
|
canManageSystem: Boolean(formData.canManageSystem),
|
||||||
|
createdBy: userCreator.user.id,
|
||||||
|
deletedAt: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
createUserRoleService(dataPayload)
|
||||||
|
.then((result) =>
|
||||||
|
returnWriteResponse(ctx.set, 201, "User role created", result)
|
||||||
|
)
|
||||||
|
.catch((error) =>
|
||||||
|
returnErrorResponse(ctx.set, 500, "Internal Server Error", error)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,20 @@
|
|||||||
|
import { Prisma } from "@prisma/client";
|
||||||
|
import { userRoleModel } from "../userRole.model";
|
||||||
|
import { handlePrismaError } from "../../../utils/databases/prisma/error/handler";
|
||||||
|
import { returnErrorResponse } from "../../../helpers/callback/httpResponse";
|
||||||
|
import { Context } from "elysia";
|
||||||
|
|
||||||
|
export const createUserRoleService = async (
|
||||||
|
ctx: Context,
|
||||||
|
userRoleData: Prisma.UserRoleUncheckedCreateInput
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
const newUserRole = await userRoleModel.create({
|
||||||
|
data: userRoleData,
|
||||||
|
});
|
||||||
|
return newUserRole;
|
||||||
|
} catch (error) {
|
||||||
|
const { status, message, details } = handlePrismaError(error);
|
||||||
|
throw returnErrorResponse(ctx.set, status, message, details);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@ -0,0 +1,3 @@
|
|||||||
|
import { prisma } from "../../utils/databases/prisma/connection";
|
||||||
|
|
||||||
|
export const userRoleModel = prisma.userRole;
|
||||||
|
|||||||
@ -0,0 +1,28 @@
|
|||||||
|
import Joi from "joi";
|
||||||
|
|
||||||
|
export const createUserRoleSchema = Joi.object({
|
||||||
|
name: Joi.string().min(4).max(255).required(),
|
||||||
|
primaryColor: Joi.string()
|
||||||
|
.pattern(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/)
|
||||||
|
.optional(),
|
||||||
|
secondaryColor: Joi.string()
|
||||||
|
.pattern(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/)
|
||||||
|
.optional(),
|
||||||
|
pictureImage: Joi.string()
|
||||||
|
.uri({ scheme: ["http", "https"] })
|
||||||
|
.optional(),
|
||||||
|
badgeImage: Joi.string()
|
||||||
|
.uri({ scheme: ["http", "https"] })
|
||||||
|
.optional(),
|
||||||
|
isSuperadmin: Joi.boolean().required(),
|
||||||
|
canEditMedia: Joi.boolean().required(),
|
||||||
|
canManageMedia: Joi.boolean().required(),
|
||||||
|
canEditEpisodes: Joi.boolean().required(),
|
||||||
|
canManageEpisodes: Joi.boolean().required(),
|
||||||
|
canEditComment: Joi.boolean().required(),
|
||||||
|
canManageComment: Joi.boolean().required(),
|
||||||
|
canEditUser: Joi.boolean().required(),
|
||||||
|
canManageUser: Joi.boolean().required(),
|
||||||
|
canEditSystem: Joi.boolean().required(),
|
||||||
|
canManageSystem: Joi.boolean().required(),
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user