diff --git a/data/dao/user/UserDAO.ts b/data/dao/user/UserDAO.ts index 671b4dff..ec3714df 100644 --- a/data/dao/user/UserDAO.ts +++ b/data/dao/user/UserDAO.ts @@ -6,8 +6,6 @@ export interface UserDAO { insertUser(userData: RegisterUserData): Promise; - fetchUser(userId: number): Promise; - fetchUserByEmail(email: string): Promise; getOtp(email: string, timestamp: number): Promise; diff --git a/data/dao/user/UserDAOImpl.ts b/data/dao/user/UserDAOImpl.ts index ffd6480e..9316136a 100644 --- a/data/dao/user/UserDAOImpl.ts +++ b/data/dao/user/UserDAOImpl.ts @@ -1,9 +1,10 @@ import { Otp } from "../../db_models/Otp"; import { RegisterUserData } from "../../../domain/models/RegisterUserData"; import { User } from "../../db_models/User"; -import { FetchUserByEmail, FetchUserUserDAO, InsertOTPUserDAO, InsertUserUSerDAO, IsEmailExistUserDAO, OTPNotFoundInDB, UnknownDatabaseError, UserNotFoundInDB } from "../../../routes/auth/errorhandling/ErrorCodes"; -import { AuthError, DatabaseError } from "../../../routes/auth/errorhandling/ErrorUtils"; +import { FetchUserByEmail, GetOTPUserDAO, InsertOTPUserDAO, InsertUserUSerDAO, OTPNotFoundInDB, UnknownDatabaseError, UpdatePasswordUserDao, UserNotFoundInDB } from "../../../routes/auth/errorhandling/ErrorCodes"; +import { AuthError } from "../../../routes/auth/errorhandling/ErrorUtils"; import { UserDAO } from "./UserDAO"; +import { DatabaseError } from "../../../utils/errors/ErrorUtils"; @@ -15,7 +16,12 @@ export class UserDAOImpl implements UserDAO { const [updatedCount] = await User.update({ password_hash: password }, { where: { email: email } }); return updatedCount == 1 } catch (error) { - throw new DatabaseError("e is not a instance of Error: UserDAOImpl --- updatePassword", UnknownDatabaseError); + if (error instanceof Error) { + throw new DatabaseError(error.message, UpdatePasswordUserDao); + } else { + throw new DatabaseError("e is not a instance of Error: UserDAOImpl --- updatePassword", UnknownDatabaseError); + } + } } @@ -25,9 +31,7 @@ export class UserDAOImpl implements UserDAO { const otpData = await Otp.create({ email: email, otp_hash: otp, generated_at: now.getTime() }) return otpData } catch (error) { - if (error instanceof AuthError) { - throw error - } else if (error instanceof Error) { + if (error instanceof Error) { throw new DatabaseError(error.message, InsertOTPUserDAO); } else { throw new DatabaseError("e is not a instance of Error: UserDAOImpl --- insertOtp", UnknownDatabaseError); @@ -55,7 +59,7 @@ export class UserDAOImpl implements UserDAO { if (error instanceof AuthError) { throw error } else if (error instanceof Error) { - throw new DatabaseError("error.message", IsEmailExistUserDAO); + throw new DatabaseError("error.message", GetOTPUserDAO); } else { throw new DatabaseError("e is not a instance of Error: UserDAOImpl --- getOtp", UnknownDatabaseError); } @@ -63,8 +67,6 @@ export class UserDAOImpl implements UserDAO { } - - async insertUser(userData: RegisterUserData): Promise { try { @@ -81,28 +83,6 @@ export class UserDAOImpl implements UserDAO { } - } - - async fetchUser(userId: number): Promise { - - try { - const user = await User.findByPk(userId); - - if (user == null) { - throw new AuthError("user with id: " + userId + "is not found in the database", UserNotFoundInDB) - } - return user; - } catch (error) { - if (error instanceof AuthError) { - throw error - } else if (error instanceof Error) { - throw new DatabaseError(error.message, FetchUserUserDAO); - } else { - throw new DatabaseError("e is not a instance of Error: UserDAOImpl --- fetchUser", UnknownDatabaseError); - } - } - - } async fetchUserByEmail(email: string): Promise { diff --git a/data/dao/waterft_calculator/WaterFtCalcDAO.ts b/data/dao/waterft_calculator/WaterFtCalcDAO.ts new file mode 100644 index 00000000..283e299a --- /dev/null +++ b/data/dao/waterft_calculator/WaterFtCalcDAO.ts @@ -0,0 +1,52 @@ +import { IngredientRow } from "../../db_models/IngredientRowData"; +import { IngredientRowItem } from "../../db_models/IngredientRowItem"; + +export interface WaterFtCalcDAO { + + insertIngredientRow( + rowOrder: number + ): Promise + + insertIngredientRowItem( + itemId: number, + rowId: number, + name: string, + amt: number, + unit: string, + waterFootprint: number, + unselectedBgImageUrl: string, + selectedBgImageUrl: string, + sampleImageUrl: string, + sampleImageSize: number, + scaleFactor: number, + iconScalefactor: number, + cornerType: string, + doneXOffSet: number, + doneYOffSet: number, + pluseXOffSet: number, + pluseYOffSet: number, + minusXOffSet: number, + minusYOffSet: number, + xOffset: number, + yOffset: number + ): Promise + + + getIngredientRow( + rowId: number, + ): Promise + + getIngredientRows( + + ): Promise + + getIngredientRowItem( + rowId: number, + ): Promise + + getIngredientRowItems( + rowId: number, + ): Promise + + getWaterConsumptionOfIngredient(ingredientId: number): Promise +} \ No newline at end of file diff --git a/data/dao/waterft_calculator/WaterFtCalcDAOImpl.ts b/data/dao/waterft_calculator/WaterFtCalcDAOImpl.ts new file mode 100644 index 00000000..560f73f7 --- /dev/null +++ b/data/dao/waterft_calculator/WaterFtCalcDAOImpl.ts @@ -0,0 +1,177 @@ + +import { GetIngredientRowDAOError, GetIngredientRowItemDAOError, GetIngredientRowItemsDAOError, GetIngredientRowsDAOError, GetWaterConsumptionOfIngredientDAOError, IngredientNotFoundError, InsertIngredientRowDAOError, InsertIngredientRowItemDAOError, UnknownDatabaseError } from '../../../routes/water_ft_catculator/errorhandling/ErrorCodes'; +import { WaterFtCalcError } from '../../../routes/water_ft_catculator/errorhandling/ErrorUtils'; +import { WaterFtCalcDAO } from './WaterFtCalcDAO'; +import { IngredientRow } from '../../db_models/IngredientRowData'; +import { IngredientRowItem } from '../../db_models/IngredientRowItem'; +import { ForeignKeyConstraintError, UniqueConstraintError } from 'sequelize'; +import { DatabaseError } from "../../../utils/errors/ErrorUtils"; + + +const FileName = "WaterFtCalcDAOImpl" + +export class WaterFtCalcDAOImpl implements WaterFtCalcDAO { + + async getIngredientRow(rowId: number): Promise { + try { + const row = await IngredientRow.findOne({ where: { id: rowId } }) + if (row == null) { + throw new WaterFtCalcError("Row not found", GetIngredientRowDAOError) + } + return row + } catch (error) { + if (error instanceof Error) { + + throw new DatabaseError(error.message, InsertIngredientRowDAOError); + } else { + throw new DatabaseError(`e is not a instance of Error: ${FileName} --- getIngredientRow`, UnknownDatabaseError); + } + } + } + async getIngredientRows(): Promise { + try { + const rows = await IngredientRow.findAll() + if (rows == null) { + throw new WaterFtCalcError("Rows not found", GetIngredientRowsDAOError) + } + return rows + } catch (error) { + if (error instanceof Error) { + throw new DatabaseError(error.message, GetIngredientRowsDAOError); + } else { + throw new DatabaseError(`e is not a instance of Error: ${FileName} --- getIngredientRows`, UnknownDatabaseError); + } + } + } + async getIngredientRowItem(rowId: number): Promise { + try { + + const row = await IngredientRowItem.findOne({ where: { id: rowId } }) + if (row == null) { + throw new WaterFtCalcError("Row item not found", GetIngredientRowItemDAOError) + } + return row + } catch (error) { + if (error instanceof Error) { + + throw new DatabaseError(error.message, InsertIngredientRowDAOError); + } else { + throw new DatabaseError(`e is not a instance of Error: ${FileName} --- getIngredientRowItem`, UnknownDatabaseError); + } + } + } + async getIngredientRowItems(rowId: number): Promise { + try { + + const rows = await IngredientRowItem.findAll({ where: { rowId: rowId } }) + if (rows == null) { + throw new WaterFtCalcError("Row items not found", GetIngredientRowItemsDAOError) + } + return rows + } catch (error) { + if (error instanceof Error) { + + throw new DatabaseError(error.message, GetIngredientRowItemsDAOError); + } else { + throw new DatabaseError(`e is not a instance of Error: ${FileName} --- getIngredientRowItems`, UnknownDatabaseError); + } + } + } + async insertIngredientRow(rowOrder: number): Promise { + try { + const row = await IngredientRow.create({ rowOrder: rowOrder }) + return row + } catch (error) { + if (error instanceof Error) { + + throw new DatabaseError(error.message, InsertIngredientRowDAOError); + } else { + throw new DatabaseError(`e is not a instance of Error: ${FileName} --- insertIngredientRow`, UnknownDatabaseError); + } + } + } + async insertIngredientRowItem( + itemId: number, + rowId: number, + name: string, + amt: number, + unit: string, + waterFootprint: number, + unselectedBgImageUrl: string, + selectedBgImageUrl: string, + sampleImageUrl: string, + sampleImageSize: number, + scaleFactor: number, + iconScalefactor: number, + cornerType: string, + doneXOffSet: number, + doneYOffSet: number, + pluseXOffSet: number, + pluseYOffSet: number, + minusXOffSet: number, + minusYOffSet: number, + xOffset: number, + yOffset: number + ): Promise { + try { + const rowItem = await IngredientRowItem.create( + { + itemId: itemId, + rowId: rowId, + name: name, + amt: amt, + unit: unit, + water_footprint: waterFootprint, + unselectedBgImageUrl: unselectedBgImageUrl, + selectedBgImageUrl: selectedBgImageUrl, + sampleImageUrl: sampleImageUrl, + sampleImageSize: sampleImageSize, + scaleFactor: scaleFactor, + iconScalefactor: iconScalefactor, + cornerType: cornerType, + doneXOffSet: doneXOffSet, + doneYOffSet: doneYOffSet, + pluseXOffSet: pluseXOffSet, + pluseYOffSet: pluseYOffSet, + minusXOffSet: minusXOffSet, + minusYOffSet: minusYOffSet, + xOffset: xOffset, + yOffset: yOffset + } + ) + return rowItem + } catch (error) { + + + if (error instanceof Error) { + throw new DatabaseError(error.message, InsertIngredientRowItemDAOError); + } else { + throw new DatabaseError(`e is not a instance of Error: ${FileName} --- insertIngredientRowItem`, UnknownDatabaseError); + } + } + } + async getWaterConsumptionOfIngredient(ingredientId: number): Promise { + try { + + const ingredient = await IngredientRowItem.findByPk(ingredientId); + + if (ingredient == null) { + throw new WaterFtCalcError("ingredient is not available", IngredientNotFoundError) + } + + return ingredient.water_footprint + + } catch (error) { + if (error instanceof WaterFtCalcError) { + throw error + } else if (error instanceof Error) { + + throw new DatabaseError(error.message, GetWaterConsumptionOfIngredientDAOError); + } else { + throw new DatabaseError(`e is not a instance of Error: ${FileName} --- getWaterConsumptionOfIngredient`, UnknownDatabaseError); + } + } + } + + +} \ No newline at end of file diff --git a/data/db_models/IngredientRowData.ts b/data/db_models/IngredientRowData.ts new file mode 100644 index 00000000..49f87f4f --- /dev/null +++ b/data/db_models/IngredientRowData.ts @@ -0,0 +1,45 @@ +import { Optional, Model, DataTypes, Sequelize } from "sequelize"; +import { IngredientRowItem } from "./IngredientRowItem"; + + +interface IngredientRowAttributes { + id: number; + rowOrder: number; +} + +interface IngredientRowCreationAttributes extends Optional {} + +export class IngredientRow extends Model { + static hasMany(IngredientRowItem: IngredientRowItem, arg1: { foreignKey: string; }) { + throw new Error('Method not implemented.'); + } + declare id: number; + declare rowOrder: number; + + public readonly createdAt!: Date; + public readonly updatedAt!: Date; + +} + +export function initIngredientRow(sequelize: Sequelize) { + + IngredientRow.init( + { + id: { + type: DataTypes.INTEGER, + autoIncrement: true, + primaryKey: true, + }, + rowOrder: { + type: DataTypes.INTEGER, + allowNull: false, + unique: true, + } + }, + { + sequelize: sequelize, + tableName: 'ingredient_rows', + timestamps: true + } + ).sync({ alter: true }) + } diff --git a/data/db_models/IngredientRowItem.ts b/data/db_models/IngredientRowItem.ts new file mode 100644 index 00000000..6ab6ebd9 --- /dev/null +++ b/data/db_models/IngredientRowItem.ts @@ -0,0 +1,175 @@ +import { DataTypes, Model, Optional, Sequelize } from "sequelize"; +import { IngredientRow } from "./IngredientRowData"; + + +interface IngredientRowItemAttributes { + id: number; + rowId: number; + itemId: number; + name: string; + amt: number; + unit: string; + water_footprint: number; + unselectedBgImageUrl: string; + selectedBgImageUrl: string; + sampleImageUrl: string; + sampleImageSize: number; + scaleFactor: number; + iconScalefactor: number; + cornerType: string; + doneXOffSet: number; + doneYOffSet: number; + pluseXOffSet: number; + pluseYOffSet: number; + minusXOffSet: number; + minusYOffSet: number; + xOffset: number; + yOffset: number; +} + +interface IngredientRowItemCreationAttributes extends Optional {} + +export class IngredientRowItem extends Model { + static belongsTo(IngredientRow: typeof IngredientRow, arg1: { foreignKey: string; }) { + throw new Error('Method not implemented.'); + } + declare id: number; + declare itemId: number; + declare rowId: number; + declare name: string; + declare amt: number; + declare unit: string; + declare water_footprint: number; + declare unselectedBgImageUrl: string; + declare selectedBgImageUrl: string; + declare sampleImageUrl: string; + declare sampleImageSize: number; + declare scaleFactor: number; + declare iconScalefactor: number; + declare cornerType: string; + declare doneXOffSet: number; + declare doneYOffSet: number; + declare pluseXOffSet: number; + declare pluseYOffSet: number; + declare minusXOffSet: number; + declare minusYOffSet: number; + declare xOffset: number; + declare yOffset: number; + + public readonly createdAt!: Date; + public readonly updatedAt!: Date; + + } + + export function initIngredientRowItem(sequelize: Sequelize) { + + IngredientRowItem.init( + { + id: { + type: DataTypes.INTEGER, + autoIncrement: true, + unique: true, + primaryKey: true, + }, + itemId: { + type: DataTypes.INTEGER, + allowNull: false, + + }, + rowId: { + type: DataTypes.INTEGER, + allowNull: false, + references: { + model: IngredientRow, + key: 'id', + }, + }, + name: { + type: DataTypes.STRING(255), + allowNull: false, + unique: true + }, + amt: { + type: DataTypes.DECIMAL, + allowNull: false + }, + unit: { + type: DataTypes.STRING, + allowNull: false + }, + water_footprint: { + type: DataTypes.DECIMAL, + allowNull: false + }, + unselectedBgImageUrl: { + type: DataTypes.STRING, + allowNull: false + }, + selectedBgImageUrl: { + type: DataTypes.STRING, + allowNull: false + }, + sampleImageUrl: { + type: DataTypes.STRING, + allowNull: false + }, + sampleImageSize: { + type: DataTypes.DECIMAL, + allowNull: false + }, + scaleFactor: { + type: DataTypes.DECIMAL, + allowNull: false + }, + iconScalefactor: { + type: DataTypes.DECIMAL, + allowNull: false + }, + cornerType: { + type: DataTypes.STRING, + allowNull: false + }, + doneXOffSet: { + type: DataTypes.DECIMAL, + allowNull: false + }, + doneYOffSet: { + type: DataTypes.DECIMAL, + allowNull: false + }, + pluseXOffSet: { + type: DataTypes.DECIMAL, + allowNull: false + }, + pluseYOffSet: { + type: DataTypes.DECIMAL, + allowNull: false + }, + minusXOffSet: { + type: DataTypes.DECIMAL, + allowNull: false + }, + minusYOffSet: { + type: DataTypes.DECIMAL, + allowNull: false + }, + xOffset: { + type: DataTypes.DECIMAL, + allowNull: false, + }, + yOffset: { + type: DataTypes.DECIMAL, + allowNull: false, + + } + }, + { + sequelize: sequelize, + tableName: 'ingredient_row_item', + timestamps: true + } + ).sync({ alter: true }) + + +} + \ No newline at end of file diff --git a/data/db_models/Otp.ts b/data/db_models/Otp.ts index 91c62628..6fba328d 100644 --- a/data/db_models/Otp.ts +++ b/data/db_models/Otp.ts @@ -1,14 +1,14 @@ import { Model, Optional, DataTypes, Sequelize } from 'sequelize'; interface OtpAttributes { - id: number; - email: string; - otp_hash: string; - generated_at: number; - }; + id: number; + email: string; + otp_hash: string; + generated_at: number; +}; -interface OtpCreationAttributes extends Optional {} +interface OtpCreationAttributes extends Optional { } export class Otp extends Model { declare id: number; @@ -19,36 +19,35 @@ export class Otp extends Model { } export function initOtp(sequelize: Sequelize) { - - Otp.init( - { - id: { - type: DataTypes.INTEGER, - autoIncrement: true, - primaryKey: true, - }, - email: { - type: DataTypes.STRING, - allowNull: false, - //unique: true, - }, - otp_hash: { - type: DataTypes.STRING, - allowNull: false, - unique: true, - }, - generated_at: { - type: DataTypes.BIGINT, - allowNull: false, // Optional timestamp - }, - - }, - { - sequelize, - tableName: 'otps' - } - ).sync({ alter: true }); - + + Otp.init( + { + id: { + type: DataTypes.INTEGER, + autoIncrement: true, + primaryKey: true, + }, + email: { + type: DataTypes.STRING, + allowNull: false, + //unique: true, + }, + otp_hash: { + type: DataTypes.STRING, + allowNull: false, + unique: true, + }, + generated_at: { + type: DataTypes.BIGINT, + allowNull: false, // Optional timestamp + }, + + }, + { + sequelize, + tableName: 'otps' } - - \ No newline at end of file + ).sync({ alter: true }); + +} + diff --git a/data/db_models/User.ts b/data/db_models/User.ts index 8b4ff298..851354d4 100644 --- a/data/db_models/User.ts +++ b/data/db_models/User.ts @@ -8,7 +8,7 @@ interface UserAttributes { // other attributes... }; -interface UserCreationAttributes extends Optional {} +interface UserCreationAttributes extends Optional { } export class User extends Model { declare id: number; @@ -18,12 +18,12 @@ export class User extends Model { public readonly createdAt!: Date; public readonly updatedAt!: Date; - // other attributes... + } export function initUser(sequelize: Sequelize) { - + User.init( { id: { @@ -45,17 +45,17 @@ export function initUser(sequelize: Sequelize) { allowNull: false, unique: true, }, - - }, + + }, { sequelize: sequelize, tableName: 'users2', timestamps: true } - ).sync({ - alter: true + ).sync({ + alter: true }); - + } diff --git a/data/requests/auth/GenerateOTPReq.ts b/data/requests/auth/GenerateOTPReq.ts new file mode 100644 index 00000000..e85ed47c --- /dev/null +++ b/data/requests/auth/GenerateOTPReq.ts @@ -0,0 +1,5 @@ + + +export interface GenerateOTPReq { + email: string +} \ No newline at end of file diff --git a/data/requests/auth/LoginUserReq.ts b/data/requests/auth/LoginUserReq.ts new file mode 100644 index 00000000..5c92e709 --- /dev/null +++ b/data/requests/auth/LoginUserReq.ts @@ -0,0 +1,5 @@ + +export interface LoginUserReq { + email: string; + password: string; +} \ No newline at end of file diff --git a/data/requests/auth/RegisterUserReq.ts b/data/requests/auth/RegisterUserReq.ts new file mode 100644 index 00000000..5208f8d8 --- /dev/null +++ b/data/requests/auth/RegisterUserReq.ts @@ -0,0 +1,6 @@ + +export interface RegisterUserReq { + name: string, + email: string; + password: string; +} \ No newline at end of file diff --git a/data/requests/auth/ResetPasswordReq.ts b/data/requests/auth/ResetPasswordReq.ts new file mode 100644 index 00000000..82ffafe9 --- /dev/null +++ b/data/requests/auth/ResetPasswordReq.ts @@ -0,0 +1,5 @@ + +export interface ResetPasswordReq { + email: string, + new_password: string +} \ No newline at end of file diff --git a/data/requests/auth/VerifyOTPReq.ts b/data/requests/auth/VerifyOTPReq.ts new file mode 100644 index 00000000..8dfb9426 --- /dev/null +++ b/data/requests/auth/VerifyOTPReq.ts @@ -0,0 +1,6 @@ + +export interface VerifyOTPReq { + email: string, + otp: string, + created_on: number +} \ No newline at end of file diff --git a/data/requests/waterft_calc/CalcWaterFootprint.ts b/data/requests/waterft_calc/CalcWaterFootprint.ts new file mode 100644 index 00000000..d78e38e7 --- /dev/null +++ b/data/requests/waterft_calc/CalcWaterFootprint.ts @@ -0,0 +1,12 @@ + +export interface CalcWaterFootPrintReq { + + user_id: string, + data: IngredientReq[] + +} + +interface IngredientReq { + ingredient_id: number, + amt: number +} \ No newline at end of file diff --git a/data/requests/waterft_calc/FetchIngredientRowsRes.ts b/data/requests/waterft_calc/FetchIngredientRowsRes.ts new file mode 100644 index 00000000..7811745e --- /dev/null +++ b/data/requests/waterft_calc/FetchIngredientRowsRes.ts @@ -0,0 +1,8 @@ +import { IngredientRowItem } from "../../db_models/IngredientRowItem"; + + +export interface IngredientRowRes { + rowId: number, + rowOrder: number, + rowItems: IngredientRowItem[] +} \ No newline at end of file diff --git a/data/requests/waterft_calc/InsertIngredientRow.ts b/data/requests/waterft_calc/InsertIngredientRow.ts new file mode 100644 index 00000000..e8dcbcee --- /dev/null +++ b/data/requests/waterft_calc/InsertIngredientRow.ts @@ -0,0 +1,5 @@ + + +export interface InsertIngredientRow { + rowOrder: number +} \ No newline at end of file diff --git a/data/requests/waterft_calc/InsertIngredientRowItem.ts b/data/requests/waterft_calc/InsertIngredientRowItem.ts new file mode 100644 index 00000000..04370252 --- /dev/null +++ b/data/requests/waterft_calc/InsertIngredientRowItem.ts @@ -0,0 +1,25 @@ + + +export interface InsertIngredientRowItem { + itemId: number; + rowId: number; + name: string; + amt: number; + unit: string; + waterFootprint: number; + unselectedBgImageUrl: string; + selectedBgImageUrl: string; + sampleImageUrl: string; + sampleImageSize: number; + scaleFactor: number; + iconScalefactor: number; + cornerType: string; + doneXOffSet: number; + doneYOffSet: number; + pluseXOffSet: number; + pluseYOffSet: number; + minusXOffSet: number; + minusYOffSet: number; + xOffset: number; + yOffset: number; +} \ No newline at end of file diff --git a/data/responses/auth/LoginUserResData.ts b/data/responses/auth/LoginUserResData.ts new file mode 100644 index 00000000..d976de1a --- /dev/null +++ b/data/responses/auth/LoginUserResData.ts @@ -0,0 +1,9 @@ + + +export interface LoginUserResData { + + access_token: string, + user_id: number, + name: string, + email: string +} \ No newline at end of file diff --git a/data/responses/auth/VerifyOtpResData.ts b/data/responses/auth/VerifyOtpResData.ts new file mode 100644 index 00000000..247d7b8b --- /dev/null +++ b/data/responses/auth/VerifyOtpResData.ts @@ -0,0 +1,6 @@ + + +export interface VerifyOtpResData { + email: string, + access_token: string +} \ No newline at end of file diff --git a/di/container.ts b/di/container.ts index 329556ba..50e14e24 100644 --- a/di/container.ts +++ b/di/container.ts @@ -2,6 +2,8 @@ import { UserDAOImpl } from '../data/dao/user/UserDAOImpl'; import { Container } from 'brandi'; import { TOKENS } from './tokens'; import { AuthService } from '../services/AuthService'; +import { WaterFtCalcDAOImpl } from '../data/dao/waterft_calculator/WaterFtCalcDAOImpl'; +import { WaterftCalcService } from '../services/WaterFtCalcService'; @@ -12,9 +14,19 @@ container .toInstance(UserDAOImpl) .inTransientScope(); + container + .bind(TOKENS.waterFtCalculatorDao) + .toInstance(WaterFtCalcDAOImpl) + .inTransientScope(); + container .bind(TOKENS.authService) .toInstance(AuthService) .inTransientScope(); - \ No newline at end of file + container + .bind(TOKENS.waterFtCalcService) + .toInstance(WaterftCalcService) + .inTransientScope(); + + diff --git a/di/tokens.ts b/di/tokens.ts index 3d386e66..1033c529 100644 --- a/di/tokens.ts +++ b/di/tokens.ts @@ -1,9 +1,12 @@ import { token } from 'brandi'; import { UserDAO } from '../data/dao/user/UserDAO'; import { AuthService } from '../services/AuthService'; +import { WaterFtCalcDAO } from '../data/dao/waterft_calculator/WaterFtCalcDAO'; +import { WaterftCalcService } from '../services/WaterFtCalcService'; export const TOKENS = { userDao: token('user_dao'), authService: token('auth_service'), - + waterFtCalculatorDao: token('water_ft_calc_dao'), + waterFtCalcService: token('water_ft_calc_service') }; \ No newline at end of file diff --git a/index.ts b/index.ts index 4fe2171f..a1f0139e 100644 --- a/index.ts +++ b/index.ts @@ -1,52 +1,60 @@ import express from 'express'; import winston from 'winston'; import authRouter from './routes/auth/AuthRoutes'; +import waterFtCalcRouter from './routes/water_ft_catculator/WaterfootprintCalcRoutes'; import { initUser } from './data/db_models/User'; import sequelize from './db'; import { initOtp } from './data/db_models/Otp'; -import dotenv from 'dotenv'; +import * as dotenv from 'dotenv'; +import path from 'path'; +import { IngredientRow, initIngredientRow } from './data/db_models/IngredientRowData'; +import { IngredientRowItem, initIngredientRowItem } from './data/db_models/IngredientRowItem'; +dotenv.config() -dotenv.config(); +initUser(sequelize) +initOtp(sequelize) +initIngredientRow(sequelize) +initIngredientRowItem(sequelize) -initUser(sequelize); -initOtp(sequelize); - +IngredientRow.hasMany(IngredientRowItem, { foreignKey: 'rowId' }); +IngredientRowItem.belongsTo(IngredientRow, { foreignKey: 'rowId' }); export const logger = winston.createLogger({ - level: 'info', + level: 'info', // Set the minimum log level format: winston.format.combine( winston.format.timestamp(), winston.format.json() ), transports: [ - new winston.transports.File({ - filename: 'server_logs' - }) + new winston.transports.Console() // Log to console ] -}); - -const app = express(); -const port = 3000; +}) +const app = express() +const port = 3000 -app.use(express.json()); +// Body parser middleware (already included in Express.js) +app.use(express.json()) -app.use('/api/auth', authRouter); +app.use('/images', express.static(path.join(__dirname, 'resources','public'))) +app.use('/api/auth', authRouter) +app.use('/api/user/', waterFtCalcRouter) -app.get('/', (_req, res) => { - res.send('Welcome to Puddle server!'); -}); +app.get('/', (req, res) => { + logger.info('Received a GET request to the root path') + res.send('Welcome to my server!') +}) app.listen(port, () => { - logger.info(`Server is running on port ${port}`); -}); \ No newline at end of file + logger.info(`Server is running on port ${port}`) +}) \ No newline at end of file diff --git a/routes/auth/errorhandling/ErrorCodes.ts b/routes/auth/errorhandling/ErrorCodes.ts index 123a9ad3..f83749dd 100644 --- a/routes/auth/errorhandling/ErrorCodes.ts +++ b/routes/auth/errorhandling/ErrorCodes.ts @@ -1,29 +1,14 @@ - - -//CRUD Operation Errors -export const InsertionError = 1 -export const UpdationError = 2 -export const DeletionError = 3 -export const ReadError = 4 - -//Connection Errors -export const DatabaseDisconnected = 5 - - - -export const UnknownDatabaseError = 6 - //Function Specific Errors -- UserDAO -export const IsEmailExistUserDAO = 7 -export const InsertUserUSerDAO = 8 -export const FetchUserUserDAO = 9 -export const FetchUserByEmail = 10 -export const InsertOTPUserDAO = 11 +export const InsertUserUSerDAO = 7 +export const FetchUserByEmail = 8 +export const InsertOTPUserDAO = 9 +export const GetOTPUserDAO = 10 +export const UpdatePasswordUserDao = 11 -//error +//AuthError export const UserNotFoundInDB = 12 export const OTPNotFoundInDB = 13 export const InvalidUserCredentials = 14 diff --git a/routes/auth/errorhandling/ErrorResponseUtils.ts b/routes/auth/errorhandling/ErrorResponseUtils.ts index 3b5b4d53..463f86cc 100644 --- a/routes/auth/errorhandling/ErrorResponseUtils.ts +++ b/routes/auth/errorhandling/ErrorResponseUtils.ts @@ -1,14 +1,14 @@ import { Response } from "express"; -import { DeletionError, ForgotPasswordEmailNotSent, InsertionError, InvalidOTPCredentials, InvalidResetPasswordToken, InvalidUserCredentials, OTPNotFoundInDB, OTPValidityExpired, ResetPasswordTokenExpired, UpdationError, UserNotFoundInDB } from "./ErrorCodes"; -import { AuthError, DatabaseError } from "./ErrorUtils"; +import { FetchUserByEmail, GetOTPUserDAO, InsertOTPUserDAO, InsertUserUSerDAO, InvalidOTPCredentials, InvalidResetPasswordToken, InvalidUserCredentials, OTPNotFoundInDB, OTPValidityExpired, ResetPasswordTokenExpired, UpdatePasswordUserDao, UserNotFoundInDB } from "./ErrorCodes"; +import { AuthError } from "./ErrorUtils"; +import { DatabaseError } from "../../../utils/errors/ErrorUtils"; + export function handleLoginRouteError(err: Error, res: Response) { if (err instanceof DatabaseError) { switch (err.code) { - case InsertionError: - case UpdationError: - case DeletionError: + case FetchUserByEmail: res.status(500).json({ status_code: 500, access_token: null, @@ -44,8 +44,6 @@ export function handleLoginRouteError(err: Error, res: Response) { }); } } else { - // Handle other unexpected errors here (optional) - console.error('Unexpected error:', err); res.status(500).json({ status_code: 500, access_token: null, @@ -59,9 +57,7 @@ export function handleRegisterRouteError(err: Error, res: Response) { if (err instanceof DatabaseError) { switch (err.code) { - case InsertionError: - case UpdationError: - case DeletionError: + case InsertUserUSerDAO: res.status(500).json({ status_code: 500, user_info: null, @@ -77,13 +73,6 @@ export function handleRegisterRouteError(err: Error, res: Response) { } } else if (err instanceof AuthError) { switch (err.code) { - case 12: - res.status(404).json({ - status_code: 404, - user_info: null, - message: err.message - }); - break; default: res.status(500).json({ status_code: 500, @@ -92,8 +81,6 @@ export function handleRegisterRouteError(err: Error, res: Response) { }); } } else { - // Handle other unexpected errors here (optional) - console.error('Unexpected error:', err); res.status(500).json({ status_code: 500, user_info: null, @@ -106,9 +93,7 @@ export function handleRegisterRouteError(err: Error, res: Response) { export function handleGentOTPRouteError(err: Error, res: Response) { if (err instanceof DatabaseError) { switch (err.code) { - case InsertionError: - case UpdationError: - case DeletionError: + case InsertOTPUserDAO: res.status(500).json({ status_code: 500, created_on: null, @@ -124,13 +109,6 @@ export function handleGentOTPRouteError(err: Error, res: Response) { } } else if (err instanceof AuthError) { switch (err.code) { - case ForgotPasswordEmailNotSent: - res.status(404).json({ - status_code: 404, - created_on: null, - message: err.message - }); - break; default: res.status(500).json({ status_code: 500, @@ -139,8 +117,6 @@ export function handleGentOTPRouteError(err: Error, res: Response) { }); } } else { - // Handle other unexpected errors here (optional) - console.error('Unexpected error:', err); res.status(500).json({ status_code: 500, message: 'An unexpected error occurred.' @@ -151,9 +127,7 @@ export function handleGentOTPRouteError(err: Error, res: Response) { export function handleVerifyOTPRouteError(err: Error, res: Response) { if (err instanceof DatabaseError) { switch (err.code) { - case InsertionError: - case UpdationError: - case DeletionError: + case GetOTPUserDAO: res.status(500).json({ status_code: 500, access_token: null, @@ -186,8 +160,6 @@ export function handleVerifyOTPRouteError(err: Error, res: Response) { }); } } else { - // Handle other unexpected errors here (optional) - console.error('Unexpected error:', err); res.status(500).json({ status_code: 500, access_token: null, @@ -199,9 +171,7 @@ export function handleVerifyOTPRouteError(err: Error, res: Response) { export function handleresetPasswordRouteError(err: Error, res: Response) { if (err instanceof DatabaseError) { switch (err.code) { - case InsertionError: - case UpdationError: - case DeletionError: + case UpdatePasswordUserDao: res.status(500).json({ status_code: 500, message: err.message @@ -229,8 +199,6 @@ export function handleresetPasswordRouteError(err: Error, res: Response) { }); } } else { - // Handle other unexpected errors here (optional) - console.error('Unexpected error:', err); res.status(500).json({ status_code: 500, message: 'An unexpected error occurred.' diff --git a/routes/auth/errorhandling/ErrorUtils.ts b/routes/auth/errorhandling/ErrorUtils.ts index 3188a51d..fbde4f11 100644 --- a/routes/auth/errorhandling/ErrorUtils.ts +++ b/routes/auth/errorhandling/ErrorUtils.ts @@ -1,12 +1,4 @@ -export class DatabaseError extends Error { - constructor(message: string, public code: number) { - super(message); - this.name = 'DatabaseError'; - } - } - - export class AuthError extends Error { constructor(message: string, public code: number) { super(message); diff --git a/routes/water_ft_catculator/WaterfootprintCalcRoutes.ts b/routes/water_ft_catculator/WaterfootprintCalcRoutes.ts new file mode 100644 index 00000000..863ec27c --- /dev/null +++ b/routes/water_ft_catculator/WaterfootprintCalcRoutes.ts @@ -0,0 +1,115 @@ +import express from "express"; +import { container } from "../../di/container"; +import { TOKENS } from "../../di/tokens"; +import { handleAddIngredientRowItemRouteError, handleAddIngredientRowRouteError, handleCalculateWaterFootprintRouteError, handleGetIngredientsRowsRouteError } from "./errorhandling/ErrorResponses"; +import { CalcWaterFootPrintReq } from "../../data/requests/waterft_calc/CalcWaterFootprint"; +import { InsertIngredientRow } from "../../data/requests/waterft_calc/InsertIngredientRow"; +import { InsertIngredientRowItem } from '../../data/requests/waterft_calc/InsertIngredientRowItem'; + + + +const router = express.Router(); + + +const waterFtCalcService = container.get(TOKENS.waterFtCalcService); + + + + +router.post('/add-ingredient-row', async (req, res) => { + + try { + const request: InsertIngredientRow = req.body + + const result = await waterFtCalcService.addIngredientRow(request.rowOrder) + + res.status(200).json( + { + status_code: 200, + ingredient_row: result, + message: "ingredient Row added successfully" + } + ); + + + } catch (err) { + + if (err instanceof Error) { + handleAddIngredientRowRouteError(err, res) + } + + } +}); + +router.post('/add-ingredient-row-item', async (req, res) => { + + try { + const request: InsertIngredientRowItem = req.body + + const result = await waterFtCalcService.addIngredientRowItem(request) + + res.status(200).json( + { + status_code: 200, + ingredient_row_item: result, + message: "ingredient Row Item added successfully" + } + ); + + + } catch (err) { + + if (err instanceof Error) { + handleAddIngredientRowItemRouteError(err, res) + } + + } +}); + +router.get('/fetch-ingredients', async (req, res) => { + + try { + const result = await waterFtCalcService.getIngredientsRows() + + res.status(200).json( + { + status_code: 200, + data: result, + message: "ingredients data fetched successfully" + } + ) + + + } catch (err) { + + if (err instanceof Error) { + handleGetIngredientsRowsRouteError(err, res) + } + + } +}); + +router.post('/calc-water-footprint', async (req, res) => { + try { + + const request: CalcWaterFootPrintReq = req.body + const result = await waterFtCalcService.calculateWaterFootprint(request) + + res.status(200).json( + { + status_code: 200, + water_footprint: result, + message: "water footprint calculated successfully" + } + ); + } catch (err) { + + if (err instanceof Error) { + handleCalculateWaterFootprintRouteError(err, res) + } + + } +}); + + +export default router; \ No newline at end of file diff --git a/routes/water_ft_catculator/errorhandling/ErrorCodes.ts b/routes/water_ft_catculator/errorhandling/ErrorCodes.ts new file mode 100644 index 00000000..996286a6 --- /dev/null +++ b/routes/water_ft_catculator/errorhandling/ErrorCodes.ts @@ -0,0 +1,16 @@ + + + +//Function Specific Errors -- WaterFtCalcDAO +export const GetWaterConsumptionOfIngredientDAOError = 25 +export const InsertIngredientRowDAOError = 26 +export const InsertIngredientRowItemDAOError = 27 + +//WaterFtCalcError +export const GetIngredientRowDAOError = 28 +export const GetIngredientRowsDAOError = 29 +export const GetIngredientRowItemDAOError = 30 +export const GetIngredientRowItemsDAOError = 31 +export const IngredientNotFoundError = 32 + + diff --git a/routes/water_ft_catculator/errorhandling/ErrorResponses.ts b/routes/water_ft_catculator/errorhandling/ErrorResponses.ts new file mode 100644 index 00000000..441beb26 --- /dev/null +++ b/routes/water_ft_catculator/errorhandling/ErrorResponses.ts @@ -0,0 +1,163 @@ +import { Response } from "express"; +import { GetIngredientRowItemsDAOError, GetIngredientRowsDAOError, GetWaterConsumptionOfIngredientDAOError, InsertIngredientRowDAOError, InsertIngredientRowItemDAOError } from "./ErrorCodes"; +import { WaterFtCalcError } from "./ErrorUtils"; +import { DatabaseError } from "../../../utils/errors/ErrorUtils"; + +export function handleAddIngredientRowRouteError(err: Error, res: Response) { + if (err instanceof DatabaseError) { + switch (err.code) { + + case InsertIngredientRowDAOError: + + res.status(500).json({ + status_code: 500, + ingredient_row: null, + message: err.message + }); + break; + default: + res.status(500).json({ + status_code: 500, + ingredient_row: null, + message: err.message + }); + } + } else if (err instanceof WaterFtCalcError) { + switch (err.code) { + default: + res.status(500).json({ + status_code: 500, + ingredient_row: null, + message: 'Unknown water_footprint_calculator error' + }); + } + } else { + res.status(500).json({ + status_code: 500, + ingredient_row: null, + message: 'An unexpected error occurred.' + }); + } +} + +export function handleAddIngredientRowItemRouteError(err: Error, res: Response) { + if (err instanceof DatabaseError) { + switch (err.code) { + + case InsertIngredientRowItemDAOError: + + res.status(500).json({ + status_code: 500, + ingredient_row_item: null, + message: err.message + }); + break; + default: + res.status(500).json({ + status_code: 500, + ingredient_row_item: null, + message: err.message + }); + } + } else if (err instanceof WaterFtCalcError) { + switch (err.code) { + default: + res.status(500).json({ + status_code: 500, + ingredient_row_item: null, + message: 'Unknown water_footprint_calculator error' + }); + } + } else { + res.status(500).json({ + status_code: 500, + ingredient_row_item: null, + message: 'An unexpected error occurred.' + }); + } +} + +export function handleGetIngredientsRowsRouteError(err: Error, res: Response) { + if (err instanceof DatabaseError) { + switch (err.code) { + + case GetIngredientRowsDAOError: + case GetIngredientRowItemsDAOError: + + res.status(500).json({ + status_code: 500, + data: null, + message: err.message + }); + break; + default: + res.status(500).json({ + status_code: 500, + data: null, + message: err.message + }); + } + } else if (err instanceof WaterFtCalcError) { + switch (err.code) { + case GetIngredientRowsDAOError: + case GetIngredientRowItemsDAOError: + res.status(500).json({ + status_code: 500, + data: null, + message: err.message + }); + break; + + default: + res.status(500).json({ + status_code: 500, + data: null, + message: 'Unknown water_footprint_calculator error' + }); + } + } else { + res.status(500).json({ + status_code: 500, + data: null, + message: 'An unexpected error occurred.' + }); + } +} + +export function handleCalculateWaterFootprintRouteError(err: Error, res: Response) { + if (err instanceof DatabaseError) { + switch (err.code) { + + case GetWaterConsumptionOfIngredientDAOError: + + res.status(500).json({ + status_code: 500, + water_footprint: null, + message: err.message + }); + break; + default: + res.status(500).json({ + status_code: 500, + water_footprint: null, + message: err.message + }); + } + } else if (err instanceof WaterFtCalcError) { + switch (err.code) { + default: + res.status(500).json({ + status_code: 500, + water_footprint: false, + message: 'Unknown water_footprint_calculator error' + }); + } + } else { + res.status(500).json({ + status_code: 500, + water_footprint: null, + message: 'An unexpected error occurred.' + }); + } +} + diff --git a/routes/water_ft_catculator/errorhandling/ErrorUtils.ts b/routes/water_ft_catculator/errorhandling/ErrorUtils.ts new file mode 100644 index 00000000..bfd2c696 --- /dev/null +++ b/routes/water_ft_catculator/errorhandling/ErrorUtils.ts @@ -0,0 +1,7 @@ + +export class WaterFtCalcError extends Error { + constructor(message: string, public code: number) { + super(message); + this.name = 'WaterFtCalcError'; + } +} \ No newline at end of file diff --git a/services/AuthService.ts b/services/AuthService.ts index 37437f7b..a3c0ca36 100644 --- a/services/AuthService.ts +++ b/services/AuthService.ts @@ -99,13 +99,10 @@ export class AuthService { transporter.sendMail(mailOptions, (error, info) => { if (error) { - console.error(error); + throw new AuthError("we're facing an issue to send an email: " + error.message, ForgotPasswordEmailNotSent); - } else { - console.log('Email sent: %s', info); - } }); diff --git a/services/WaterFtCalcService.ts b/services/WaterFtCalcService.ts new file mode 100644 index 00000000..5ee941f4 --- /dev/null +++ b/services/WaterFtCalcService.ts @@ -0,0 +1,85 @@ +import { injected } from 'brandi'; +import { WaterFtCalcDAO } from '../data/dao/waterft_calculator/WaterFtCalcDAO'; +import { TOKENS } from '../di/tokens'; +import { CalcWaterFootPrintReq } from '../data/requests/waterft_calc/CalcWaterFootprint'; +import { IngredientRow } from '../data/db_models/IngredientRowData'; +import { IngredientRowItem } from '../data/db_models/IngredientRowItem'; +import { InsertIngredientRowItem } from '../data/requests/waterft_calc/InsertIngredientRowItem'; +import { IngredientRowRes } from '../data/requests/waterft_calc/FetchIngredientRowsRes'; + + + +export class WaterftCalcService { + + constructor(private readonly dao: WaterFtCalcDAO) { } + + + async addIngredientRow(rowOrder: number): Promise { + + const row = this.dao.insertIngredientRow(rowOrder) + + return row + } + + async addIngredientRowItem( + req: InsertIngredientRowItem + ): Promise { + const rowItem = this.dao.insertIngredientRowItem( + req.itemId, + req.rowId, + req.name, + req.amt, + req.unit, + req.waterFootprint, + req.unselectedBgImageUrl, + req.selectedBgImageUrl, + req.sampleImageUrl, + req.sampleImageSize, + req.scaleFactor, + req.iconScalefactor, + req.cornerType, + req.doneXOffSet, + req.doneYOffSet, + req.pluseXOffSet, + req.pluseYOffSet, + req.minusXOffSet, + req.minusYOffSet, + req.xOffset, + req.yOffset + ) + return rowItem + } + + + async getIngredientsRows(): Promise { + + const rows = await this.dao.getIngredientRows() + + return await Promise.all(rows.map(async (element) => { + const rowItems = await this.dao.getIngredientRowItems(element.id); + + return { + rowId: element.id, + rowOrder: element.rowOrder, + rowItems: rowItems + } as IngredientRowRes + })) + + + } + + async calculateWaterFootprint(req: CalcWaterFootPrintReq): Promise { + + let totalWaterConsumption = 0 + for (const ing_req of req.data) { + const water_consumption = await this.dao.getWaterConsumptionOfIngredient(ing_req.ingredient_id) + totalWaterConsumption = totalWaterConsumption + ing_req.amt * water_consumption + + } + + return totalWaterConsumption + } + +} + +injected(WaterftCalcService, TOKENS.waterFtCalculatorDao); \ No newline at end of file diff --git a/utils/errors/ErrorCodes.ts b/utils/errors/ErrorCodes.ts new file mode 100644 index 00000000..c208cd15 --- /dev/null +++ b/utils/errors/ErrorCodes.ts @@ -0,0 +1,3 @@ +//Connection Errors +export const DatabaseDisconnected = 5 +export const UnknownDatabaseError = 6 \ No newline at end of file diff --git a/utils/errors/ErrorUtils.ts b/utils/errors/ErrorUtils.ts new file mode 100644 index 00000000..976de3e0 --- /dev/null +++ b/utils/errors/ErrorUtils.ts @@ -0,0 +1,6 @@ +export class DatabaseError extends Error { + constructor(message: string, public code: number) { + super(message); + this.name = 'DatabaseError'; + } + }