Skip to content

Commit

Permalink
add product favorite module & fix product video removal job
Browse files Browse the repository at this point in the history
  • Loading branch information
bahram1249 committed Jul 27, 2024
1 parent 6b9ce6b commit 75b0dfc
Show file tree
Hide file tree
Showing 9 changed files with 364 additions and 2 deletions.
6 changes: 5 additions & 1 deletion apps/e-commerce/src/e-commerce.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ import { HomePageModule } from './home/home.module';
import { ProcessHomeRunnerService } from './home/process-home-runner.service';
import { ProductVideoModule } from './product-video/product-video.module';
import { ProductVideoRemovalService } from './product-video-removal/product-video-removal.service';
import { ProductFavoriteModule } from './user/product-favorite/product-favorite.module';
import { ProductVideoRemovalModule } from './product-video-removal/product-video-removal.module';

@Module({
imports: [
Expand Down Expand Up @@ -116,6 +118,7 @@ import { ProductVideoRemovalService } from './product-video-removal/product-vide
AddressModule,
ProductPhotoModule,
ProductImageRemovalModule,
ProductVideoRemovalModule,
VendorModule,
UserVendorModule,
VendorAddressModule,
Expand Down Expand Up @@ -176,6 +179,7 @@ import { ProductVideoRemovalService } from './product-video-removal/product-vide
HomePhotoModule,
HomePageModule,
ProductVideoModule,
ProductFavoriteModule,
],
providers: [
{
Expand Down Expand Up @@ -207,7 +211,7 @@ export class ECommerceModule implements NestModule {
app.get(ProductImageRemovalService).run();

// add product video removal job
//app.get(ProductVideoRemovalService).run();
app.get(ProductVideoRemovalService).run();

// add discount cacher
app.get(ProductDiscountJobRunnerService).run();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { IntersectionType } from '@nestjs/swagger';
import { ListFilter } from '@rahino/query-filter';

export class GetProductFavoriteDto extends IntersectionType(ListFilter) {}
2 changes: 2 additions & 0 deletions apps/e-commerce/src/user/product-favorite/dto/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './get-product-favorite.dto';
export * from './product-favorite.dto';
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { I18nTranslations } from 'apps/main/src/generated/i18n.generated';
import { AutoMap } from 'automapper-classes';
import { IsNumber } from 'class-validator';
import { i18nValidationMessage } from 'nestjs-i18n';

export class ProductFavoriteDto {
@AutoMap()
@IsNumber(
{},
{
message: i18nValidationMessage<I18nTranslations>('validation.NUMBER'),
},
)
productId: bigint;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import {
Body,
Controller,
Delete,
Get,
HttpCode,
HttpStatus,
Param,
Post,
Put,
Query,
UseGuards,
UseInterceptors,
} from '@nestjs/common';
import { JsonResponseTransformInterceptor } from '@rahino/response/interceptor';
import {
ApiBearerAuth,
ApiOperation,
ApiQuery,
ApiTags,
} from '@nestjs/swagger';
import { JwtGuard } from '@rahino/auth/guard';
import { ProductFavoriteService } from './product-favorite.service';
import { ProductFavoriteDto, GetProductFavoriteDto } from './dto';
import { GetUser } from '@rahino/auth/decorator';
import { User } from '@rahino/database/models/core/user.entity';
import { OptionalSessionGuard } from '../session/guard';

@ApiTags('ProductFavorite')
@UseGuards(JwtGuard, OptionalSessionGuard)
@ApiBearerAuth()
@UseInterceptors(JsonResponseTransformInterceptor)
@Controller({
path: '/api/ecommerce/user/productFavorites',
version: ['1'],
})
export class ProductFavoriteController {
constructor(private service: ProductFavoriteService) {}

// public url
@ApiOperation({ description: 'show all my favorites' })
@Get('/')
@ApiQuery({
name: 'filter',
type: GetProductFavoriteDto,
style: 'deepObject',
explode: true,
})
@HttpCode(HttpStatus.OK)
async findAll(@GetUser() user: User, @Query() filter: GetProductFavoriteDto) {
return await this.service.findAll(user, filter);
}

@ApiOperation({ description: 'show favorite by given id' })
@Get('/status/:productId')
@HttpCode(HttpStatus.OK)
async findById(@GetUser() user: User, @Param('productId') entityId: bigint) {
return await this.service.statusByProductId(user, entityId);
}

@ApiOperation({ description: 'create favorite by user' })
@Post('/')
@HttpCode(HttpStatus.CREATED)
async create(@GetUser() user: User, @Body() dto: ProductFavoriteDto) {
return await this.service.create(user, dto);
}

@ApiOperation({ description: 'remove favorite by user' })
@Delete('/product/:productId')
@HttpCode(HttpStatus.OK)
async deleteById(
@GetUser() user: User,
@Param('productId') entityId: bigint,
) {
return await this.service.deleteByProductId(user, entityId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Module } from '@nestjs/common';
import { ProductFavoriteController } from './product-favorite.controller';
import { ProductFavoriteService } from './product-favorite.service';
import { SequelizeModule } from '@nestjs/sequelize';
import { SessionModule } from '../session/session.module';
import { ProductModule } from '@rahino/ecommerce/product/product.module';
import { ECProductFavorite } from '@rahino/database/models/ecommerce-eav/ec-product-favorite';

@Module({
imports: [
SessionModule,
ProductModule,
SequelizeModule.forFeature([ECProductFavorite]),
],
controllers: [ProductFavoriteController],
providers: [ProductFavoriteService],
exports: [ProductFavoriteService],
})
export class ProductFavoriteModule {}
101 changes: 101 additions & 0 deletions apps/e-commerce/src/user/product-favorite/product-favorite.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import {
BadRequestException,
Injectable,
NotFoundException,
} from '@nestjs/common';
import { ProductFavoriteDto, GetProductFavoriteDto } from './dto';
import { InjectModel } from '@nestjs/sequelize';
import { QueryOptionsBuilder } from '@rahino/query-filter/sequelize-query-builder';
import { Op, Sequelize } from 'sequelize';
import * as _ from 'lodash';
import { ECAddress } from '@rahino/database/models/ecommerce-eav/ec-address.entity';
import { User } from '@rahino/database/models/core/user.entity';
import { ECProvince } from '@rahino/database/models/ecommerce-eav/ec-province.entity';
import { ECCity } from '@rahino/database/models/ecommerce-eav/ec-city.entity';
import { ECNeighborhood } from '@rahino/database/models/ecommerce-eav/ec-neighborhood.entity';
import { I18nTranslations } from 'apps/main/src/generated/i18n.generated';
import { I18nContext, I18nService } from 'nestjs-i18n';
import { ECProductFavorite } from '@rahino/database/models/ecommerce-eav/ec-product-favorite';
import { ProductRepositoryService } from '@rahino/ecommerce/product/service/product-repository.service';

@Injectable()
export class ProductFavoriteService {
constructor(
@InjectModel(ECProductFavorite)
private repository: typeof ECProductFavorite,
private productRepositoryService: ProductRepositoryService,
private readonly i18n: I18nService<I18nTranslations>,
) {}

async findAll(user: User, filter: GetProductFavoriteDto) {
const queryBuilder = new QueryOptionsBuilder().filter({
userId: user.id,
});
const count = await this.repository.count(queryBuilder.build());

let products = await this.repository.findAll(queryBuilder.build());
for (let index = 0; index < products.length; index++) {
const product = products[index];
product.set(
'product',
await this.productRepositoryService.findById({}, product.id),
);
products[index] = product;
}

return {
result: products,
total: count,
};
}

async statusByProductId(user: User, entityId: bigint) {
const item = await this.repository.findOne(
new QueryOptionsBuilder()
.filter({
userId: user.id,
})
.filter({ productId: entityId })
.build(),
);
const result = item ? true : false;

return {
result: result,
};
}

async create(user: User, dto: ProductFavoriteDto) {
const item = await this.repository.findOne(
new QueryOptionsBuilder()
.filter({
userId: user.id,
})
.filter({ productId: dto.productId })
.build(),
);
if (!item) {
await this.repository.create({
userId: user.id,
productId: dto.productId,
});
}

return {
result: 'ok',
};
}

async deleteByProductId(user: User, entityId: bigint) {
await this.repository.destroy({
where: {
userId: user.id,
productId: entityId,
},
});

return {
result: 'ok',
};
}
}
109 changes: 108 additions & 1 deletion apps/main/src/sql/core-v1.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2471,7 +2471,7 @@ END
GO


-- eav products
-- eav product photos
IF NOT EXISTS (SELECT 1 FROM Migrations WHERE version = 'eav-product-photos-v1'
)
AND EXISTS (
Expand All @@ -2496,6 +2496,32 @@ END

GO


-- eav products videos
IF NOT EXISTS (SELECT 1 FROM Migrations WHERE version = 'eav-product-videos-v1'
)
AND EXISTS (
SELECT 1 FROM Settings
WHERE ([key] = 'SITE_NAME' AND [value] IN ('ecommerce'))
)
BEGIN

CREATE TABLE EAVEntityVideos (
entityId bigint NOT NULL,
attachmentId bigint NOT NULL,
[createdAt] datetimeoffset NOT NULL,
[updatedAt] datetimeoffset NOT NULL,
PRIMARY KEY CLUSTERED(entityId, attachmentId),
);



INSERT INTO Migrations(version, createdAt, updatedAt)
SELECT 'eav-product-videos-v1', GETDATE(), GETDATE()
END

GO

-- eav user session
IF NOT EXISTS (SELECT 1 FROM Migrations WHERE version = 'ec-user-session-v1'
)
Expand Down Expand Up @@ -7720,6 +7746,25 @@ GO



-- ecommerce product-video
IF NOT EXISTS ((SELECT 1 FROM Migrations WHERE version = 'CORE-AttachmentTypes-Data-v13'
))
BEGIN

INSERT INTO AttachmentTypes(id, typeName, createdAt, updatedAt)
SELECT 14, N'productTempVideo', getdate(), getdate()

INSERT INTO AttachmentTypes(id, typeName, createdAt, updatedAt)
SELECT 15, N'product-video', getdate(), getdate()

INSERT INTO Migrations(version, createdAt, updatedAt)
SELECT 'CORE-AttachmentTypes-Data-v13', GETDATE(), GETDATE()
END

GO



-- courier settings
IF NOT EXISTS ( SELECT 1 FROM Migrations WHERE version = 'ec-couriersettings-Data-v1'
)
Expand Down Expand Up @@ -15341,6 +15386,68 @@ END

GO


-- ecommerce/productvideos
IF NOT EXISTS ((SELECT 1 FROM Migrations WHERE version = 'CORE-Permissions-Data-v65'
))
AND EXISTS (
SELECT 1 FROM Settings WHERE 1=1
AND ([key] = 'SITE_NAME' AND [value] IN ('ecommerce'))
)
BEGIN

DECLARE @roleId int = (SELECT TOP 1 id FROM Roles WHERE static_id = 1)
DECLARE @userId bigint = (SELECT TOP 1 id FROM Users WHERE static_id = 1)

DECLARE @GroupTemp TABLE (
gorupId int
);

DECLARE @groupId int = null;

DECLARE @entityName nvarchar(256) = N'ProductVideos'
DECLARE @groupName nvarchar(256) = N'ecommerce.productvideos'


DECLARE @permissionSymbolUploadImage nvarchar(512) = @groupName + '.uploadVideo';



-- permission groups
INSERT INTO PermissionGroups(permissionGroupName, [visibility], createdAt, updatedAt)
OUTPUT inserted.id INTO @GroupTemp(gorupId)
SELECT @groupName, 1, GETDATE(), GETDATE();

SELECT @groupId = gorupId FROM @GroupTemp


-- permissions


DECLARE @PermissionTemp TABLE (
permissionId int
);



INSERT INTO Permissions(permissionName ,permissionSymbol,permissionGroupId, createdAt, updatedAt)
OUTPUT inserted.id INTO @PermissionTemp(permissionId)
SELECT 'UPLOADVIDEO_' + @entityName, @permissionSymbolUploadImage, @groupId, GETDATE(), GETDATE()

-- CRUD THIS Enity FOR super-admin
INSERT INTO RolePermissions(roleId, permissionId, createdAt, updatedAt)
SELECT @roleId, permissionId, GETDATE(), GETDATE()
FROM @PermissionTemp

DELETE FROM @PermissionTemp


INSERT INTO Migrations(version, createdAt, updatedAt)
SELECT 'CORE-Permissions-Data-v65', GETDATE(), GETDATE()
END

GO

-- period types
IF NOT EXISTS (SELECT 1 FROM Migrations WHERE version = 'PCMPeriodTypes-Data-v1'
)
Expand Down
Loading

0 comments on commit 75b0dfc

Please sign in to comment.