Skip to content

Commit

Permalink
updated: not sending to client site visivility hidden product
Browse files Browse the repository at this point in the history
  • Loading branch information
anamulhaque22 committed Dec 3, 2024
1 parent 69d4362 commit 372bab7
Show file tree
Hide file tree
Showing 30 changed files with 534 additions and 10 deletions.
12 changes: 11 additions & 1 deletion server/src/analytics/analytics.controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { Controller, Get } from '@nestjs/common';
import { Controller, Get, UseGuards } from '@nestjs/common';
import { AuthGuard } from 'src/auth/guard/auth.guard';
import { Roles } from 'src/roles/roles.decorators';
import { RoleEnum } from 'src/roles/roles.enum';
import { RolesGuard } from 'src/roles/roles.guard';
import { NullableType } from 'src/utils/types/nullable.type';
import { AnalyticsService } from './analytics.service';
import { MonthlyRevenue } from './domain/analytics';
Expand All @@ -10,16 +14,22 @@ import { MonthlyRevenue } from './domain/analytics';
export class AnalyticsController {
constructor(private readonly analyticsService: AnalyticsService) {}

@UseGuards(AuthGuard, RolesGuard)
@Roles(RoleEnum.admin, RoleEnum.user)
@Get('best-selling-products')
async getBestSellingProducts() {
return this.analyticsService.getBestSellingProducts();
}

@UseGuards(AuthGuard, RolesGuard)
@Roles(RoleEnum.admin)
@Get('monthly-revenue')
async getMonthlyRevenue(): Promise<NullableType<MonthlyRevenue>> {
return this.analyticsService.getMonthlyRevenue();
}

@UseGuards(AuthGuard, RolesGuard)
@Roles(RoleEnum.admin)
@Get('dashboard-metrics')
async getDashboardMetrics() {
return this.analyticsService.getDashboardMetrics();
Expand Down
2 changes: 2 additions & 0 deletions server/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { SessionModule } from './session/session.module';
import stripeConfig from './stripe/config/stripe.config';
import { StripeModule } from './stripe/stripe.module';
import { UsersModule } from './users/users.module';
import { WishListModule } from './wish-list/wish-list.module';

@Module({
imports: [
Expand Down Expand Up @@ -56,6 +57,7 @@ import { UsersModule } from './users/users.module';
OrdersModule,
StripeModule,
AnalyticsModule,
WishListModule,
],
controllers: [AppController],
providers: [AppService],
Expand Down
42 changes: 41 additions & 1 deletion server/src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
import {
Body,
Controller,
Delete,
Get,
HttpCode,
HttpStatus,
Param,
Patch,
Post,
Request,
SerializeOptions,
UnprocessableEntityException,
UploadedFiles,
UseGuards,
UseInterceptors,
} from '@nestjs/common';
import { User } from 'src/users/domain/user';
import { FileFieldsInterceptor } from '@nestjs/platform-express';
import { Roles } from 'src/roles/roles.decorators';
import { RoleEnum } from 'src/roles/roles.enum';
import { RolesGuard } from 'src/roles/roles.guard';
import { User, UserImage } from 'src/users/domain/user';
import { imageFileFilter } from 'src/utils/image-file-filter';
import { NullableType } from 'src/utils/types/nullable.type';
import { AuthService } from './auth.service';
import { AuthConfirmEmailDto } from './dto/auth-confirm-email.dto';
Expand Down Expand Up @@ -116,4 +126,34 @@ export class AuthController {
sessionId: request.user.sessionId,
});
}

@Post('image')
@HttpCode(HttpStatus.OK)
@UseInterceptors(
FileFieldsInterceptor(
[
{
name: 'image',
},
],
{
fileFilter: imageFileFilter,
},
),
)
async uploadImage(@UploadedFiles() files: { image?: Express.Multer.File }) {
if (!files || !files.image) {
throw new UnprocessableEntityException('You need to upload an image.');
}
console.log(files.image);
return this.authService.uploadUserImage(files['image'][0]);
}

@Roles(RoleEnum.user)
@UseGuards(AuthGuard, RolesGuard)
@Delete('image/:id')
@HttpCode(HttpStatus.OK)
async removeImage(@Param('id') id: UserImage['id']) {
return this.authService.removeImage(id);
}
}
25 changes: 24 additions & 1 deletion server/src/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { RoleEnum } from 'src/roles/roles.enum';
import { Session } from 'src/session/domain/session';
import { SessionService } from 'src/session/session.service';
import { StatusEnum } from 'src/statuses/statuses.enum';
import { User } from 'src/users/domain/user';
import { User, UserImage } from 'src/users/domain/user';
import { UsersService } from 'src/users/users.service';
import { NullableType } from 'src/utils/types/nullable.type';
import { AuthProvidersEnum } from './auth-provider.enum';
Expand Down Expand Up @@ -465,6 +465,29 @@ export class AuthService {
return this.sessionService.deleteById(data.sessionId);
}

async uploadUserImage(files: Express.Multer.File): Promise<UserImage> {
return this.usersService.uploadUserImage(files);
// let imageUploadedRes: CloudinaryResponse;
// if (files) {
// imageUploadedRes = await this.cloudinaryService.uploadFile(
// files,
// 'users',
// );
// }

// return this.usersRepository.uploadUserImage({
// url: imageUploadedRes.secure_url,
// publicId: imageUploadedRes.public_id,
// });
}

async removeImage(id: UserImage['id']): Promise<void> {
// return this.usersService.removeImage(id);
// const result = await this.usersRepository.removeUserImage(id);
// await this.cloudinaryService.removeFile(result);
return;
}

private async getTokensData(data: {
id: User['id'];
role: User['role'];
Expand Down
3 changes: 3 additions & 0 deletions server/src/auth/dto/auth-update.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ export class AuthUpdateDto {
@Transform(lowerCaseTransformer)
email?: string;

@IsOptional()
phone?: string;

@IsOptional()
@IsNotEmpty()
@MinLength(6)
Expand Down
12 changes: 11 additions & 1 deletion server/src/auth/dto/auth.register-login.dto.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
import { Transform } from 'class-transformer';
import { IsEmail, IsNotEmpty, MinLength } from 'class-validator';
import {
IsEmail,
IsNotEmpty,
IsOptional,
IsString,
MinLength,
} from 'class-validator';
import { lowerCaseTransformer } from 'src/utils/transformers/lower-case.transformer';

export class AuthRegisterLoginDto {
@Transform(lowerCaseTransformer)
@IsEmail()
email: string;

@IsOptional()
@IsString()
phone: string | null;

@MinLength(6)
password: string;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { MigrationInterface, QueryRunner } from "typeorm";

export class AddedWishListEntity1732960349187 implements MigrationInterface {
name = 'AddedWishListEntity1732960349187'

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`CREATE TABLE "wish_list" ("id" SERIAL NOT NULL, "createdAt" TIMESTAMP NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP, "userId" integer, "productId" integer, CONSTRAINT "PK_f8e27bbb59891db7cd9f920c272" PRIMARY KEY ("id"))`);
await queryRunner.query(`ALTER TABLE "product" ALTER COLUMN "visibility" DROP DEFAULT`);
await queryRunner.query(`ALTER TABLE "wish_list" ADD CONSTRAINT "FK_96ce0d79f2168b7363c3fd9adbd" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "wish_list" ADD CONSTRAINT "FK_7645dfa8474d2ffe8755a44045b" FOREIGN KEY ("productId") REFERENCES "product"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "wish_list" DROP CONSTRAINT "FK_7645dfa8474d2ffe8755a44045b"`);
await queryRunner.query(`ALTER TABLE "wish_list" DROP CONSTRAINT "FK_96ce0d79f2168b7363c3fd9adbd"`);
await queryRunner.query(`ALTER TABLE "product" ALTER COLUMN "visibility" SET DEFAULT 'VISIBLE'`);
await queryRunner.query(`DROP TABLE "wish_list"`);
}

}
16 changes: 16 additions & 0 deletions server/src/database/migrations/1733122624591-AddedPhoneColumn.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { MigrationInterface, QueryRunner } from "typeorm";

export class AddedPhoneColumn1733122624591 implements MigrationInterface {
name = 'AddedPhoneColumn1733122624591'

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "user" ADD "phone" character varying`);
await queryRunner.query(`ALTER TABLE "wish_list" ADD CONSTRAINT "UQ_18512131a1ed8e3bc5fbe26ff31" UNIQUE ("userId", "productId")`);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "wish_list" DROP CONSTRAINT "UQ_18512131a1ed8e3bc5fbe26ff31"`);
await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "phone"`);
}

}
4 changes: 4 additions & 0 deletions server/src/products/infrastructure/entities/product.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { CategoryEntity } from "src/categories/infrastructure/entities/category.
import { ProductSizeEntity } from "src/product-sizes/infrastructure/entities/product-size.entity";
import { ProductVisibility } from "src/products/product-visibility.enum";
import { EntityHelper } from "src/utils/entity-helper";
import { WishListEntity } from "src/wish-list/infrastructure/entities/wish-list.entity";
import { ProductColorEntity } from "./product-color.entity";
import { ProductImageEntity } from "./product-image.entity";

Expand Down Expand Up @@ -69,6 +70,9 @@ export class ProductEntity extends EntityHelper {
// @Column({ type: 'boolean', default: false })
// recommended: boolean;

@OneToMany(() => WishListEntity, (wishlist) => wishlist.product)
wishlist: WishListEntity[];

@CreateDateColumn()
createdAt: Date;

Expand Down
3 changes: 3 additions & 0 deletions server/src/products/infrastructure/product.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { DeepPartial } from 'typeorm';
import { Product } from '../domain/product';
import { ProductImage } from '../domain/product-image';
import { QueryCategoryDto } from '../dto/query-product.dto';
import { ProductVisibility } from '../product-visibility.enum';

export abstract class ProductRepository {
abstract create(
Expand Down Expand Up @@ -33,6 +34,7 @@ export abstract class ProductRepository {
size,
minPrice,
maxPrice,
visibility,
}: {
// filterOptions: FilterUserDto | null;
// sortOptions: SortUserDto[] | null;
Expand All @@ -43,6 +45,7 @@ export abstract class ProductRepository {
// category: QueryCategoryDto | null;
subCategory: QueryCategoryDto[] | null;
paginationOptions: IPaginationOptions;
visibility: ProductVisibility | null;
}): Promise<Product[]>;

abstract update(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { ProductSizeDto } from 'src/product-sizes/dto/product-size.dto';
import { Product, ProductInfo } from 'src/products/domain/product';
import { ProductImage } from 'src/products/domain/product-image';
import { QueryCategoryDto } from 'src/products/dto/query-product.dto';
import { ProductVisibility } from 'src/products/product-visibility.enum';
import { NullableType } from 'src/utils/types/nullable.type';
import { IPaginationOptions } from 'src/utils/types/pagination-options';
import {
Expand Down Expand Up @@ -73,6 +74,7 @@ export class ProductRepositoryImpl implements ProductRepository {
size,
minPrice,
maxPrice,
visibility,
}: {
size: ProductSizeDto[];
minPrice: number | null;
Expand All @@ -81,6 +83,7 @@ export class ProductRepositoryImpl implements ProductRepository {
// category: QueryCategoryDto | null;
subCategory: QueryCategoryDto[] | null;
paginationOptions: IPaginationOptions;
visibility: ProductVisibility | null;
}): Promise<Product[]> {
let where: FindOptionsWhere<ProductEntity> = {};

Expand All @@ -106,6 +109,10 @@ export class ProductRepositoryImpl implements ProductRepository {
where.sellPrice = LessThanOrEqual(maxPrice);
}

if (visibility) {
where.visibility = visibility;
}

const entities = await this.productRepository.find({
skip: (paginationOptions.page - 1) * paginationOptions.limit,
take: paginationOptions.limit,
Expand All @@ -119,6 +126,7 @@ export class ProductRepositoryImpl implements ProductRepository {
const entity = await this.productRepository.findOne({
where: { id: Number(id) },
});

return entity ? ProductMapper.toDomain(entity) : null;
}

Expand Down
3 changes: 3 additions & 0 deletions server/src/products/products.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { CreateProductDto } from './dto/create-product.dto';
import { ImageRemoveDto } from './dto/image-remove.dto';
import { QueryProductDto } from './dto/query-product.dto';
import { UpdateProductDto } from './dto/update-product.dto';
import { ProductVisibility } from './product-visibility.enum';
import { ProductsService } from './products.service';

@Controller({
Expand Down Expand Up @@ -142,6 +143,7 @@ export class ProductsController {
page,
limit,
},
visibility: ProductVisibility.VISIBLE,
}),
{ page, limit },
);
Expand Down Expand Up @@ -176,6 +178,7 @@ export class ProductsController {
page,
limit,
},
visibility: null,
}),
{ page, limit },
);
Expand Down
6 changes: 4 additions & 2 deletions server/src/products/products.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { ImageRemoveDto } from './dto/image-remove.dto';
import { QueryCategoryDto } from './dto/query-product.dto';
import { UpdateProductDto } from './dto/update-product.dto';
import { ProductRepository } from './infrastructure/product.repository';
import { ProductVisibility } from './product-visibility.enum';

@Injectable()
export class ProductsService {
Expand Down Expand Up @@ -244,15 +245,14 @@ export class ProductsService {
}

async findManyWithPagination({
// filterOptions,
// sortOptions,
category,
subCategory,
search,
paginationOptions,
size,
minPrice,
maxPrice,
visibility,
}: {
// filterOptions: FilterUserDto | null;
// sortOptions: SortUserDto[] | null;
Expand All @@ -263,6 +263,7 @@ export class ProductsService {
category: QueryCategoryDto | null;
subCategory: QueryCategoryDto[] | null;
paginationOptions: IPaginationOptions;
visibility: ProductVisibility | null;
}) {
if (category && category.id && !subCategory && !subCategory?.length) {
const childCategories =
Expand All @@ -276,6 +277,7 @@ export class ProductsService {
size,
minPrice,
maxPrice,
visibility,
});
}

Expand Down
3 changes: 3 additions & 0 deletions server/src/users/domain/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ export class User {
@Expose({ groups: ['me', 'admin'] })
email: string;

@Expose({ groups: ['me', 'admin'] })
phone: string;

@Exclude({ toPlainOnly: true })
password?: string;

Expand Down
4 changes: 4 additions & 0 deletions server/src/users/dto/create-user.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ export class CreateUserDto {
@IsEmail()
email: string;

@IsOptional()
@IsString()
phone: string | null;

@MinLength(6)
password?: string;

Expand Down
Loading

0 comments on commit 372bab7

Please sign in to comment.