Skip to content

Commit

Permalink
Feature: Excel Export
Browse files Browse the repository at this point in the history
  • Loading branch information
ialiaslani committed Dec 28, 2022
1 parent 8c8a4a3 commit 8286302
Show file tree
Hide file tree
Showing 9 changed files with 101 additions and 13 deletions.
7 changes: 6 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,9 @@ SWAGGER=true

REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_TTL=300
REDIS_TTL=300


TOKEN_SECRET=secretKey

LANGUAGE=fa
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
6. add filters *DONE
7. add csv export
8. add dwonload avatar
9. add user status
9. add user status *DONE
10. validate permission (no match, wrong structure) *DONE
11. update role's permission
12. name the routes
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
"cache-manager-ioredis": "^2.1.0",
"class-transformer": "^0.5.1",
"class-validator": "^0.13.2",
"date-fns-jalali": "^2.29.3-0",
"exceljs": "^4.3.0",
"nest-commander": "^3.3.0",
"passport-jwt": "^4.0.0",
"pg": "^8.8.0",
Expand Down Expand Up @@ -85,4 +87,4 @@
"coverageDirectory": "../coverage",
"testEnvironment": "node"
}
}
}
2 changes: 1 addition & 1 deletion src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import { ConfigModule } from '@nestjs/config';
CommonModule,
TypeOrmModule.forFeature([RequestLog]),
RequestLogModule,
CacheModule
CacheModule,
],
providers: [
{
Expand Down
19 changes: 13 additions & 6 deletions src/common/common.service.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
import { Injectable } from '@nestjs/common';
import { ExcelService } from 'src/excel/excel.service';
import { Repository } from 'typeorm';

@Injectable()
export abstract class CommonService {
export abstract class CommonService extends ExcelService {

protected constructor (
protected readonly repository: Repository<any>
) { }
protected readonly repository: Repository<any>,
) {
super()
}


async search(payload) {
async search(payload, columns?: { header: string, key: string, width: number }[]) {

const { size = 10, page = 1, all, ...params }: { size?: number, page?: number, all?: boolean } & { [key in string]: string } = payload
const { size = 10, page = 1, all, getExcel, ...params }: { size?: number, page?: number, all?: boolean, getExcel?: boolean } & { [key in string]: string } = payload

let query = this.repository.createQueryBuilder("repository")

if (!all) {
if (!all || !getExcel) {
query.skip((page - 1) * size)
query.take(size)
}
Expand All @@ -33,6 +36,10 @@ export abstract class CommonService {

const [data, total] = await query.getManyAndCount()

if (getExcel) {
const defaultColumns = Object.keys(data[0] || []).map(key => ({ header: key, key, width: 30 }))
return await this.exportExcel(params.sheetName || "deafult", data, columns || defaultColumns)
}

return {
data,
Expand Down
18 changes: 18 additions & 0 deletions src/excel/excel.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { ExcelService } from './excel.service';

describe('ExcelService', () => {
let service: ExcelService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [ExcelService],
}).compile();

service = module.get<ExcelService>(ExcelService);
});

it('should be defined', () => {
expect(service).toBeDefined();
});
});
42 changes: 42 additions & 0 deletions src/excel/excel.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { Injectable } from '@nestjs/common';
import { CommonEntity } from 'src/common/models/common.entity';
import * as excel from 'exceljs';
import { format } from 'date-fns-jalali';

@Injectable()
export class ExcelService {

async exportExcel(
sheetName: string,
records: CommonEntity[] = [],
columns: object[] = []
): Promise<excel.Buffer> {

//creating workbook
let workbook = new excel.Workbook();
let worksheet = workbook.addWorksheet(sheetName);

// change time
if (process.env.LANGUAGE === "fa") {

records.forEach((record: CommonEntity) => {

if (record.updated_at) {
record.updated_at = format(record.updated_at as any, "yyyy-MM-dd");
}


if (record.created_at) {
record.created_at = format(record.created_at as any, "yyyy-MM-dd");
}
});

}
worksheet.columns = columns;
worksheet.addRows(records);

const buffer = await workbook.xlsx.writeBuffer();

return buffer;
}
}
3 changes: 3 additions & 0 deletions src/user/Dtos/user.search.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ export class UserSearchDto {
@ApiProperty({ required: false })
all: boolean

@ApiProperty({ required: false })
getExcel: boolean

@ApiProperty({ required: false })
roles: string

Expand Down
17 changes: 14 additions & 3 deletions src/user/user.controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Body, ClassSerializerInterceptor, Controller, Get, Param, Post, Put, Query, UploadedFile, UseGuards, UseInterceptors } from '@nestjs/common';
import { Body, ClassSerializerInterceptor, Controller, Get, Param, Post, Put, Query, Response, UploadedFile, UseGuards, UseInterceptors } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { ApiBearerAuth, ApiBody, ApiConsumes, ApiProperty, ApiTags } from '@nestjs/swagger';
import { AuthGuard } from 'src/auth/auth.guard';
Expand All @@ -16,8 +16,19 @@ export class UserController {
constructor (private userService: UserService) { }

@Get("search")
async search(@Query() payload: UserSearchDto) {
return await this.userService.search({ ...payload, roles: ":relation" })
async search(@Query() payload: UserSearchDto, @Response() res) {
const data = await this.userService.search({ ...payload, roles: ":relation", sheetName: "users" })

if (payload.getExcel) {
res.header(
"Content-type",
"application/application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
)
.header("Content-Disposition", 'Content-Disposition: attachment; filename="users.xls"')
.send(data);
}

return data
}

@Put("update/:id")
Expand Down

0 comments on commit 8286302

Please sign in to comment.