All files / src/services users_service.ts

81.41% Statements 92/113
80% Branches 16/20
80% Functions 12/15
81.41% Lines 92/113

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 1131x 1x 1x 1x 1x 1x 1x 1x 1x 1x 9x 9x 1x 1x 1x 7x 7x 7x 7x 1x 1x       1x 1x 6x 6x 1x 1x 2x 2x 2x 1x 1x 1x 1x 2x 2x 2x 1x 1x 1x 1x 1x 1x 1x 7x 7x 7x 1x 1x 9x 9x 1x 1x 1x 6x 6x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 1x 1x 2x 2x 2x 2x 2x 2x 2x 2x 2x       2x                 2x 1x 1x 3x 3x 1x 1x           1x 1x     1x 1x 4x 4x 4x
import { UserModel } from '../models/user_model';
import {IUser, UserData} from 'types/user_types';
import bcrypt from 'bcrypt';
import jwt from 'jsonwebtoken';
import { RefreshTokenModel } from '../models/refresh_token_model';
import * as config from '../config/config'
import {Document} from "mongoose";
import { BlacklistedTokenModel } from '../models/Blacklisted_token_model';
 
const userToUserData = (user: Document<unknown, {}, IUser> & IUser): UserData => {
    return { ...user.toJSON(), id: user.id.toString() };
};
 
 
export const addUser = async (username: string, password: string, email: string): Promise<UserData> => {
    const newUser = new UserModel({username, password, email});
    await newUser.save()
    return userToUserData(newUser);
};
 
export const getUsers = async (): Promise<UserData[]> => {
    const users = await UserModel.find().exec();
    return users.map(userToUserData);
}
 
export const getUserByEmail = async (email: string): Promise<IUser | null> => {
    return await  UserModel.findOne({ email }).exec();
};
 
export const getUserById = async (id: string): Promise<UserData | null> => {
    const user = await UserModel.findById(id).exec();
    return user ? userToUserData(user) : null;
};
 
 
 
export const updateUserById = async (id: string, updateData: Partial<UserData>): Promise<UserData | null> => {
    const user = await UserModel.findByIdAndUpdate(id, updateData, { new: true }).exec();
    return user ? userToUserData(user) : null;
};
 
export const deleteUserById = async (id: string): Promise<UserData | null> => {
    const user = await UserModel.findByIdAndDelete(id).exec();
    return user ? userToUserData(user) : null;
};
 
export const registerUser = async (username: string, password: string, email: string): Promise<UserData> => {
    const hashedPassword = await bcrypt.hash(password, config.default.auth.salt);
    return await addUser(username, hashedPassword, email);
};
 
export const getUserByUsernameOrEmail = async (username: string, email: string) => {
    return await UserModel.findOne({ $or: [{ username }, { email }] }).exec();
};
 
 
export const loginUser = async (email: string, password: string): Promise<{ accessToken: string, refreshToken: string, userId: string } | null> => {
    const user = await getUserByEmail(email);
    if (!user || !(await bcrypt.compare(password, user.password))) {
        return null;
    }
 
    const accessToken = jwt.sign({ userId: user.id }, config.default.auth.access_token, { expiresIn: '15m' });
    const refreshToken = jwt.sign({ userId: user.id }, config.default.auth.refresh_token, { expiresIn: '7d' });
 
    await new RefreshTokenModel({ userId: user.id, token: refreshToken, accessToken: accessToken }).save();
 
    return { accessToken, refreshToken, userId: user.id };
};
 
export const logoutUser = async (refreshToken: string | undefined, userId: string): Promise<boolean> => {
    if (refreshToken) {
        // Find the refresh token document
        const tokenDoc = await findRefreshToken(refreshToken);
        if (tokenDoc && tokenDoc.userId === userId) {
            // Delete the specific refresh token
            await RefreshTokenModel.findOneAndDelete({ token: refreshToken }).exec();
            await BlacklistedTokenModel.create({ token: tokenDoc.accessToken });
            return true;
        } else {
            // Invalid refresh token
            return false;
        }
    } else {
        // No refresh token provided, delete all refresh tokens for the user
        const refreshTokens = await RefreshTokenModel.find({ userId }).exec();
        for (const tokenDoc of refreshTokens) {
            await BlacklistedTokenModel.create({ token: tokenDoc.accessToken });
        }
        await RefreshTokenModel.deleteMany({ userId }).exec();
        return true;
    }
};
 
export const findRefreshToken = async (token: string) => {
    return await RefreshTokenModel.findOne({ token }).exec();
};
 
export const updateRefreshTokenAccessToken = async (refreshToken: string, newAccessToken: string): Promise<void> => {
    await RefreshTokenModel.findOneAndUpdate(
        { token: refreshToken },
        { accessToken: newAccessToken }
    ).exec();
};
 
export const blacklistToken = async (token: string): Promise<void> => {
    await new BlacklistedTokenModel({ token }).save();
};
 
export const isAccessTokenBlacklisted = async (token: string): Promise<boolean> => {
    const blacklistedToken = await BlacklistedTokenModel.findOne({ token }).exec();
    return !!blacklistedToken;
};