Skip to content

Commit

Permalink
New branch2 (#16)
Browse files Browse the repository at this point in the history
* fix: fixed deleting page and login after refresh Page

* fix: auth
  • Loading branch information
YuraGB authored Mar 24, 2024
1 parent 368582f commit 5125033
Show file tree
Hide file tree
Showing 9 changed files with 189 additions and 33 deletions.
22 changes: 22 additions & 0 deletions src/model/widget/removeWidget.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { db } from "../../db/db";
import { YoutubeWidget } from "../../db/schemas/widget";
import { eq } from "drizzle-orm";

interface TRemoveWidgetResponse {
id: number;
}
export const removeWidget = async (
id: number,
): Promise<TRemoveWidgetResponse[] | null> => {
try {
return await db
.delete(YoutubeWidget)
.where(eq(YoutubeWidget.pageId, id))
.returning({
id: YoutubeWidget.id,
});
} catch (e) {
console.log(e);
return null;
}
};
Original file line number Diff line number Diff line change
@@ -1,12 +1,35 @@
import type { FastifyReply, FastifyRequest } from "fastify";
import { type TRequestLogin } from "./types";
import tokenService from "../../../services/tokenService";
import { type User } from "../../../services/userService/types";

const refreshTokenController = async (
request: FastifyRequest<TRequestLogin>,
reply: FastifyReply,
) => {
return await tokenService.refreshToken(request, reply);
const decodedToken = await request.jwtVerify({
decode: {
complete: true,
},
verify: {
complete: true,
},
});

if (!decodedToken) {
return null;
}
console.log("decodedToken", decodedToken);
if (typeof decodedToken !== "string" && "payload" in decodedToken) {
const resp = await tokenService.refreshToken(
decodedToken as { payload: User },
reply,
);

reply.send(resp);
}

return null;
};

export default refreshTokenController;
4 changes: 2 additions & 2 deletions src/server.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import "dotenv/config";
import fastify, { type FastifyReply } from "fastify";
import fastify, { type FastifyInstance, type FastifyReply } from "fastify";
import cookie, { type FastifyCookieOptions } from "@fastify/cookie";
import fastifyJwt from "@fastify/jwt";
import cors from "@fastify/cors";
Expand All @@ -13,7 +13,7 @@ import corsConfig from "./plugins/corsPlugin/";

import decorators from "./decorators";

const build = (opts = {}) => {
const build = (opts = {}): FastifyInstance => {
const app = fastify(opts);

// Plugins
Expand Down
26 changes: 26 additions & 0 deletions src/services/authService/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,30 @@ import { passwordCompare } from "../util/passwordHashing";
import { type ICreateUser } from "../../routes/userController/createUser/types";

class AuthService implements AuthInterface {
/**
* User service
*/
userService: IUserService;
/**
* Token service
*/
tokenService: ITokenService;

/**
* Constructor
* @param userService
* @param tokenService
*/
constructor(userService: IUserService, tokenService: ITokenService) {
this.userService = userService;
this.tokenService = tokenService;
}

/**
* Login
* @param response
* @param user
*/
public async login(
response: FastifyReply,
user: TLoginRequest,
Expand Down Expand Up @@ -75,6 +91,11 @@ class AuthService implements AuthInterface {
});
}

/**
* Logout
* @param request
* @param response
*/
public async logout(request: FastifyRequest, response: FastifyReply) {
const { refreshToken } = request.cookies;
if (!refreshToken) {
Expand All @@ -92,6 +113,11 @@ class AuthService implements AuthInterface {
.send({ message: "Logged out" });
}

/**
* Sign up
* @param reply
* @param userData
*/
public async signUp(
reply: FastifyReply,
userData: ICreateUser,
Expand Down
25 changes: 24 additions & 1 deletion src/services/customPageService/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,17 @@ import {
type TRemovePageResponse,
} from "../../model/page/removePage";
import { formattedPagesResponse } from "./util/formatgetPagesResponse";
import { removeWidget } from "../../model/widget/removeWidget";

class CustomPageService {
/**
* User service
*/
userService: IUserService;

/**
* Widget service
*/
widgetService: IWidgetService;

/**
Expand Down Expand Up @@ -55,6 +63,10 @@ class CustomPageService {
return null;
}

/**
* Create custom page
* @param data
*/
public async createCustomPage(
data: TPageData["Body"],
): Promise<{ pageId: number | null } | null> {
Expand Down Expand Up @@ -119,14 +131,25 @@ class CustomPageService {
return formattedPagesResponse(pageData);
}

/**
* Remove page
* @param id page id
*/
public async removePage(id: number): Promise<TRemovePageResponse | null> {
if (!id) return null;

const getPage = await getPageById(id);

if (!getPage) return null;

// todo remove widgets
/**
* Remove all widgets from page
* @param {number} id Page id
*/
const removedWidgets = await removeWidget(id);

if (!removedWidgets) return null;

return await removePage(id);
}
}
Expand Down
61 changes: 40 additions & 21 deletions src/services/tokenService/index.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
import "dotenv/config";
import { type FastifyReply, type FastifyRequest } from "fastify";
import { type FastifyReply } from "fastify";
import { type User } from "../userService/types";
import { type ITokenService } from "./types";
import { saveRefreshToken } from "../../model/token/seveRefreshToken";
import { removeToken } from "../../model/token/removeToken";

class TokenService implements ITokenService {
/**
* Generate access token
* @param reply
* @param payload
*/
async generateAccessToken(
reply: FastifyReply,
payload: User,
): Promise<string> {
return await reply.jwtSign(
{
userEmail: payload.email,
userId: payload.id,
...payload,
name: "access-token",
},
{
Expand All @@ -22,6 +26,11 @@ class TokenService implements ITokenService {
);
}

/**
* Generate refresh token
* @param reply
* @param payload
*/
async generateRefreshToken(
reply: FastifyReply,
payload: User,
Expand All @@ -36,13 +45,21 @@ class TokenService implements ITokenService {
user: User,
): Promise<{ accessToken: string; refreshToken: string }> {
const [refreshToken, accessToken] = await Promise.all([
this.generateRefreshToken(reply, user),
this.generateAccessToken(reply, user),
await this.generateAccessToken(reply, user),
// refresh token should be in the end
// because during "jwtVerify" well take the last generated token
// by "reply.jwtSign"
await this.generateRefreshToken(reply, user),
]);
return { accessToken, refreshToken };
}

async saveRefreshToken(
/**
* Save refresh token
* @param userId
* @param refreshToken
*/
public async saveRefreshToken(
userId: number,
refreshToken: string,
): Promise<{
Expand All @@ -57,38 +74,40 @@ class TokenService implements ITokenService {
}
}

async deleteToken(refreshToken: string): Promise<boolean | null> {
/**
* Delete refresh token
* @param refreshToken
*/
public async deleteToken(refreshToken: string): Promise<boolean | null> {
if (refreshToken) {
return await removeToken(refreshToken);
}
return false;
}

async refreshToken(
request: FastifyRequest,
public async refreshToken(
token: { payload: User },
reply: FastifyReply,
): Promise<{ accessToken: string; refreshToken: string } | null> {
const token = request.cookies.refreshToken;
): Promise<{ accessToken: string; refreshToken: string; user: User } | null> {
if (!token) {
return null;
}
const decodedToken: { payload: Partial<User> } = await request.jwtDecode();

// take only users fields
const user = {
id: decodedToken.payload.id,
email: decodedToken.payload.email,
password: decodedToken.payload.password,
name: decodedToken.payload.name,
dateOfBirth: decodedToken.payload.dateOfBirth,
createdAt: decodedToken.payload.createdAt,
phoneNumber: decodedToken.payload.phoneNumber,
agreement: decodedToken.payload.agreement,
id: token.payload.id,
email: token.payload.email,
password: token.payload.password,
name: token.payload.name,
dateOfBirth: token.payload.dateOfBirth,
createdAt: token.payload.createdAt,
phoneNumber: token.payload.phoneNumber,
agreement: token.payload.agreement,
} as User;

const tokens = await this.generateTokens(reply, user);
await this.saveRefreshToken(user.id, tokens.refreshToken);
return tokens;
return { ...tokens, user };
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/services/tokenService/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type FastifyReply, type FastifyRequest } from "fastify";
import { type FastifyReply } from "fastify";
import { type User } from "../userService/types";
import { type TokenTable } from "../../db/schemas/token";
import { type InferSelectModel } from "drizzle-orm";
Expand All @@ -18,7 +18,7 @@ export interface ITokenService {
) => Promise<Token | null>;
deleteToken: (refreshToken: string) => Promise<boolean | null>;
refreshToken: (
request: FastifyRequest,
token: { payload: User },
reply: FastifyReply,
) => Promise<{ accessToken: string; refreshToken: string } | null>;
}
33 changes: 27 additions & 6 deletions src/services/userService/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ import { userUpdate } from "../../model/user/updateUser";
import { type TDeleteUser, userDelete } from "../../model/user/deleteUser";

class UserService implements IUserService {
async createUser(user: ICreateUser) {
/**
* Create user
* @param user
*/
public async createUser(user: ICreateUser) {
if (!user) return null;

const hashPassword = await passwordHashing(user.password);
Expand All @@ -29,7 +33,11 @@ class UserService implements IUserService {
return await createUser(newUser);
}

async getUserByEmail(email: string): Promise<User | null> {
/**
* Get user by email
* @param email
*/
public async getUserByEmail(email: string): Promise<User | null> {
if (!email) {
return null;
}
Expand All @@ -39,12 +47,20 @@ class UserService implements IUserService {
return await findUserByEmail(decodedEmail);
}

async getUserById(id: number): Promise<User | null> {
/**
* Get user by id
* @param id
*/
public async getUserById(id: number): Promise<User | null> {
if (!id) return null;
return await findUserById(id);
}

async updateUser(user: TRequestUpdateUser): Promise<User | null> {
/**
* Update user
* @param user
*/
public async updateUser(user: TRequestUpdateUser): Promise<User | null> {
if (!user) return null;

const existingUser = await this.getUserById(user.id);
Expand All @@ -54,13 +70,18 @@ class UserService implements IUserService {
return await updatedUser;
}

async deleteUser(id: number): TDeleteUser {
/**
* Delete user
* @param id
*/
public async deleteUser(id: number): TDeleteUser {
if (!id) return null;

return await userDelete(id);
}

async getUsers(): Promise<User[] | null> {
/** Get users */
public async getUsers(): Promise<User[] | null> {
return await findUsers();
}
}
Expand Down
Loading

0 comments on commit 5125033

Please sign in to comment.