GIF89a php
Current File : /home/viralhoga/app_viralhoga/src/modules/auth/auth.controller.js
import AsyncHandler from '../../utils/AsyncHandler.js'
import ApiError from '../../utils/ApiErrorHandler.js'
import ApiResponse from '../../utils/ApiRespinseHandler.js'
import { fileDelete } from '../../utils/FileDelete.js'
import Auth from '../../models/auth.model.js'
import User from '../../models/user.model.js'
import bcrypt from 'bcrypt'
import crypto from 'crypto'
import config from '../../config/config.js'
import { setAuthCookies } from '../../utils/cookie.Handler.js'
import sessionModel from '../../models/session.model.js'
import jwt from 'jsonwebtoken'
import path from 'path'
import { generateOTP } from '../../services/otpService.js'
import OTPModel from '../../models/otp.model.js'

// export const signup = AsyncHandler(async (req, res) => {
//     const { fullName, email, password, location, role, mobile } = req.body;

//     if (!fullName || !email || !password || !mobile) {
//         fileDelete(req.file?.path)
//         throw new ApiError(400, 'All fields are mendatory')
//     };

//     const normalizedEmail = email.toLowerCase().trim();

//     const validatateDuplicateEmail = await Auth.findOne({ normalizedEmail });
//     if (validatateDuplicateEmail) {
//         fileDelete(req.file?.path)
//         throw new ApiError(400, 'Email already registered')
//     }

//     const hashedPassword = await bcrypt.hash(password, Number(config.BCRYPT_SALT_ROUNDS))

//     const auth = await Auth.create({
//         email: email,
//         password: hashedPassword,
//         mobile
//     })

//     if (!auth) {
//         fileDelete(req.file?.path)
//         throw new ApiError(400, 'Failed to create auth')
//     }

//     const image = req.file?.path
//     const result = image ? `uploads/${path.basename(image)}` : '';
//     console.log('image', result)

//     const roleInCaps = role?.toUpperCase()
//     const user = await User.create({
//         authId: auth._id,
//         fullName: fullName,
//         role: roleInCaps,
//         location,
//         avatar: result
//     })

//     if (!user) {
//         fileDelete(req.file?.path)
//         throw new ApiError(400, 'Failed to create user')
//     }

//     const refreshToken = auth.generateRefreshToken(user)
//     const refreshTokenHash = crypto.createHash('sha256').update(refreshToken).digest('hex');

//     //create session
//     const session = await sessionModel.create({
//         user: user._id,
//         refreshTokenHash,
//         ip: req.ip,
//         userAgent: req.headers["user-agent"]
//     })

//     const accessToken = auth.generateAccessToken(user)

//     setAuthCookies(res, refreshToken)

//     const responseData = {
//         email: auth.email,
//         fullName: user.fullName,
//         role: user.role,
//         location: user.location,
//         accessToken: accessToken
//     }

//     return res.status(201).json(
//         new ApiResponse(201, 'User registration has been completed', responseData)
//     )

// });


export const signup = AsyncHandler(async (req, res) => {
    const { firstName, lastName, email, password, location, role, mobile } = req.body;

    if (!firstName || !lastName || !email || !password || !mobile) {
        fileDelete(req.file?.path)
        throw new ApiError(400, 'All fields are mendatory')
    };

    const normalizedEmail = email.toLowerCase().trim();

    const validatateDuplicateEmail = await Auth.findOne({ normalizedEmail });
    if (validatateDuplicateEmail) {
        fileDelete(req.file?.path)
        throw new ApiError(400, 'Email already registered')
    }

    const hashedPassword = await bcrypt.hash(password, Number(config.BCRYPT_SALT_ROUNDS))

    const auth = await Auth.create({
        email: email,
        password: hashedPassword,
        mobile
    })

    if (!auth) {
        fileDelete(req.file?.path)
        throw new ApiError(400, 'Failed to create auth')
    }

    const image = req.file?.path
    const result = image ? `uploads/${path.basename(image)}` : '';
    console.log('image', result)

    const roleInCaps = role?.toUpperCase()
    const user = await User.create({
        authId: auth._id,
        firstName: firstName,
        lastName: lastName,
        role: roleInCaps,
        location,
        avatar: result
    })

    if (!user) {
        fileDelete(req.file?.path)
        throw new ApiError(400, 'Failed to create user')
    }

    const refreshToken = auth.generateRefreshToken(user)
    const refreshTokenHash = crypto.createHash('sha256').update(refreshToken).digest('hex');

    //create session
    const session = await sessionModel.create({
        user: user._id,
        refreshTokenHash,
        ip: req.ip,
        userAgent: req.headers["user-agent"]
    })

    const accessToken = auth.generateAccessToken(user)

    setAuthCookies(res, refreshToken)

    const responseData = {
        email: auth.email,
        firstName: user.firstName,
        lastName: user.lastName,
        role: user.role,
        location: user.location,
        accessToken: accessToken
    }

    return res.status(201).json(
        new ApiResponse(201, 'User registration has been completed', responseData)
    )

});

export const login = AsyncHandler(async (req, res) => {
    console.log('body', req.body)
    const { email, password } = req.body;
    if (!email || !password) throw new ApiError(400, 'Email and Password are required');

    const normalizedEmail = email.toLowerCase().trim();

    const auth = await Auth.findOne({ email: normalizedEmail })
    if (!auth) throw new ApiError(401, "Invalid credentials");

    const user = await User.findOne({
        authId: auth._id
    })
    if (!user) {
        throw new ApiError(404, "User profile not found");
    }

    const isPasswordCorrect = await bcrypt.compare(password, auth.password)
    if (!isPasswordCorrect) throw new ApiError(401, `Invalid credentials`);

    const refreshToken = auth.generateRefreshToken(user)
    const refreshTokenHash = crypto.createHash('sha256').update(refreshToken).digest('hex');

    //create session
    const session = await sessionModel.create({
        user: user._id,
        refreshTokenHash,
        ip: req.ip,
        userAgent: req.headers["user-agent"]
    })

    const accessToken = auth.generateAccessToken(user)

    setAuthCookies(res, refreshToken)

    return res.status(200).json(
        new ApiResponse(
            200,
            "User logged in successfully",
            {
                user: {
                    fullName: user.fullName,
                    email: auth.email,
                    avatar: user.avatar,
                    role: user.role,
                },
                accessToken: accessToken
            }
        )
    )

});

export const refreshAccessToken = AsyncHandler(async (req, res) => {
    const refreshToken = req.cookies.refreshToken;

    if (!refreshToken) {
        throw new ApiError(401, 'Refresh token not found')
    }

    const refreshTokenHash = crypto.createHash('sha256').update(refreshToken).digest('hex');
    const session = await sessionModel.findOne({
        refreshTokenHash,
        revoked: false
    })

    if (!session) {
        return res.status(401).json(
            new ApiResponse(401, 'Invalid refresh token', [])
        )
    }

    const decoded = jwt.verify(refreshToken, config.ACCESS_TOKEN_SECRET);
    const user = await User.findOne({
        authId: decoded._id
    })

    if (!user) {
        throw new ApiError(401, "User not found");
    }

    const accessToken = auth.generateAccessToken(user)

    const newRefreshToken = auth.generateRefreshToken(user)
    setAuthCookies(res, newRefreshToken)

    const newRefreshTokenHash = crypto.createHash('sha256').update(newRefreshToken).digest('hex')

    session.refreshTokenHash = newRefreshTokenHash;
    await session.save()

    res.status(200).json(
        new ApiResponse(200, 'Access token generate sucessfully', { accessToken })
    )


})

export const resetpassword = AsyncHandler(async (req, res) => {
    const userId = req.userId;
    console.log('userid', userId)
    console.log('useriddd', req.userId)
    const { oldPassword, newPassword } = req.body;

    if (!oldPassword || !newPassword) {
        throw new ApiError(400, 'All fields are required')
    }

    const user = await Auth.findOne({ _id: userId })
    if (!user) {
        throw new ApiError(400, 'Invalid request')
    }

    const isPasswordCorrect = await bcrypt.compare(oldPassword, user.password)
    if (!isPasswordCorrect) throw new ApiError(401, `Invalid credentials`);

    const hashedPassword = await bcrypt.hash(newPassword, Number(config.BCRYPT_SALT_ROUNDS))
    user.password = hashedPassword ?? user.password;
    user.save();

    res.status(200).json(
        new ApiResponse(200, 'Password updated successfully',)
    )

})

export const signupViaNumber = AsyncHandler(async (req, res) => {
    const { mobile } = req.body;

    if (!mobile) {
        throw new ApiError(400, 'Mobile number is required')
    }

    const isNumberExist = await Auth.findOne({ mobile })
    // if (isNumberExist) {
    //     throw new ApiError(409, 'This number already registered')
    // }

    const Otp = generateOTP()
    console.log('otp', Otp)

    const otp = await OTPModel.findOneAndUpdate(
        { mobile },
        { otp: Otp },
        { upsert: true, new: true }
    )

    if (!otp) {
        throw new ApiError(400, 'Error while create otp in DB, Please try again')
    }

    res.status(200).json(
        new ApiResponse(200, 'Otp sent successfully', Otp)
    )
})

export const verifyOtp = AsyncHandler(async (req, res) => {
    const { mobile, otp } = req.body;

    if (!mobile || !otp) {
        throw new ApiError(400, "Mobile & OTP both are required");
    }

    const otpDetails = await OTPModel.findOne({ mobile });

    if (!otpDetails) {
        throw new ApiError(400, "OTP not found");
    }

    if (otpDetails.otp.toString() !== otp.toString()) {
        throw new ApiError(400, "Invalid OTP");
    }

    // Check if auth already exists
    let auth = await Auth.findOne({ mobile });
    let user;

    // Registration Flow
    if (!auth) {
        auth = await Auth.create({
            mobile
        });

        user = await User.create({
            authId: auth._id
        });
    }
    // Login Flow
    else {
        user = await User.findOne({
            authId: auth._id
        });

        if (!user) {
            throw new ApiError(404, "User not found");
        }
    }

    const refreshToken = auth.generateRefreshToken(user);

    const refreshTokenHash = crypto
        .createHash("sha256")
        .update(refreshToken)
        .digest("hex");

    await sessionModel.create({
        user: user._id,
        refreshTokenHash,
        ip: req.ip,
        userAgent: req.headers["user-agent"]
    });

    const accessToken = auth.generateAccessToken(user);

    setAuthCookies(res, refreshToken);

    const responseData = {
        mobile: auth.mobile,
        role: user.role,
        accessToken
    };

    return res.status(200).json(
        new ApiResponse(
            200,
            auth.isNew ? "Registration successful" : "Login successful",
            responseData
        )
    );
});