Skip to content
10 changes: 7 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ install:
script:
- "npm run tsc && npm test"

after_success:
- npm install coveralls@~3.0.0 --global
- npm run report-coverage
jobs:
include:
- stage: Coverage Report
node_js: node
after_success:
- npm install coveralls@~3.0.0 --global
- npm run report-coverage
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "storebox-api",
"version": "1.3.2",
"version": "1.3.3",
"description": "",
"main": "index.js",
"scripts": {
Expand Down
14 changes: 13 additions & 1 deletion src/models/Categroy.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { model, SchemaDefinition, Model as M, SchemaTypes } from "mongoose";
import { Base, IDoc, IDocRaw, ObjectId, MODIFY_MOTHODS } from "@models/common";
import { Base, IDoc, IDocRaw, ObjectId, MODIFY_MOTHODS, existsValidator } from "@models/common";
import { IValues, Flag as ValueFlag } from "@models/Value";
import { DEF_PER_COUNT } from "@dtos/page";
import { isArray } from "util";
Expand Down Expand Up @@ -40,6 +40,18 @@ export interface ICategoryRaw extends ICategory {

const CategorySchema = new Base(Definition).createSchema();

// region Validators
CategorySchema.path("name").validate({
isAsync: true,
validator: async function nameExistValidator(value, respond) {
return respond(await existsValidator.bind(this)(
Model, "name", value
));
},
message: "The name is exist"
});
// endregion Validators

const getIdGroups = (obj): string[] => {
const selfIdArr = [ obj._id.toString() ];
if (obj.pid) {
Expand Down
29 changes: 20 additions & 9 deletions src/modules/admin/goods/goods.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { Roles } from "@decorators/roles";
import { User } from "@decorators/route";
import { GidDto } from "@dtos/ids";
import { IReqUser } from "@dtos/req";
import { PerPageDto, ListResponse } from "@dtos/page";
import { ListResponse } from "@dtos/page";
import { DefResDto } from "@dtos/res";
import { CreateValueDto, EditValueDto } from "@dtos/values";
import { ParseIntPipe } from "@pipes/parse-int";
Expand All @@ -33,7 +33,7 @@ import multer = require("multer");
import { isArray } from "util";

import {
GoodAttributeParamDto, UploadQueryDto, EditBodyDto
GoodAttributeParamDto, UploadQueryDto, EditBodyDto, GetGoodsDto
} from "./goods.dto";
import { RegexpCountCheckInterceptor } from "@interceptors/regexp-count-check";
import { LogsService } from "@services/logs";
Expand Down Expand Up @@ -72,13 +72,24 @@ export class GoodsAdminController {
type: ListResponse
})
// endregion Swagger Docs
public async getGoods(@Query(new ParseIntPipe()) query: PerPageDto) {
const arr = await this.goodsSvr.getByUids(
[ ], query
);
return UtilService.toListRespone(arr, Object.assign({
total: await this.goodsSvr.countByUids([ ])
}, query));
public async getGoods(
@Query(new ParseIntPipe()) query: GetGoodsDto
) {
let arr: any[], total: number;
if (query.cid) {
arr = await this.goodsSvr.listByCategoryId(query.cid, query);
total = await this.goodsSvr.countByCids(query.cid);
} else {
arr = await this.goodsSvr.getByUids([ ], query);
total = await this.goodsSvr.countByUids([ ]);
}
for (let i = 0; i < arr.length; i++) {
const good = arr[i];
good.downloaded =
await this.logsSvr.goodDownloadCount(good._id);
arr[i] = good;
}
return UtilService.toListRespone(arr, Object.assign({ total }, query));
}

private async getCategoriesIds(names: string[]) {
Expand Down
11 changes: 6 additions & 5 deletions src/modules/admin/goods/goods.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ApiModelProperty, ApiModelPropertyOptional } from "@nestjs/swagger";
import { IsMongoId, IsString, IsOptional } from "class-validator";
import { ObjectId } from "@models/common";
import { IGoods } from "@models/Good";
import { PerPageDto } from "@dtos/page";

export class GoodAttributeParamDto implements IGidDto, IAidDto {
@ApiModelProperty({ type: String, description: "Good ID" })
Expand All @@ -13,11 +14,11 @@ export class GoodAttributeParamDto implements IGidDto, IAidDto {
public readonly aid: ObjectId;
}

export class GoodsDto {
@ApiModelProperty({ type: String, description: "Collection Name" })
public readonly name: string;
@ApiModelProperty({ type: Object, description: "Goods", isArray: true })
public readonly goods: IGoods[];
export class GetGoodsDto extends PerPageDto {
@ApiModelPropertyOptional({type: String, description: "Category ID"})
@IsMongoId()
@IsOptional()
public readonly cid: ObjectId;
}

export class UploadQueryDto {
Expand Down
4 changes: 1 addition & 3 deletions src/modules/admin/regexps/regexps.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ import {
ApiBearerAuth, ApiUseTags, ApiResponse, ApiOperation, ApiImplicitParam
} from "@nestjs/swagger";
import { RegexpDoc } from "@models/Regexp";
import {
NewRegexp, EditRegexpDot, EditRegexpRawDot
} from "./regexps.dto";
import { NewRegexp, EditRegexpDot } from "./regexps.dto";
import { Roles } from "@decorators/roles";
import { RolesGuard } from "@guards/roles";
import { PerPageDto, ListResponse } from "@dtos/page";
Expand Down
12 changes: 5 additions & 7 deletions src/modules/admin/regexps/regexps.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,14 @@ interface IRegexp {
name?: string;
value?: string;
link?: ObjectId;
hidden?: boolean;
}

export interface INewRegexp extends IRegexp {
name: string;
value: string;
}

export class EditRegexpRawDot implements IRegexp {
public name?: string;
public value?: string;
public link?: ObjectId;
public hidden?: boolean;
}

export class NewRegexp implements INewRegexp {
@ApiModelProperty({ type: String })
@IsString()
Expand All @@ -31,6 +25,10 @@ export class NewRegexp implements INewRegexp {
@IsOptional()
@IsMongoId()
public readonly link: ObjectId;
@ApiModelPropertyOptional({ type: Boolean, default: false })
@IsOptional()
@IsBoolean()
public readonly hidden: boolean;
}

export class EditRegexpDot implements IRegexp {
Expand Down
36 changes: 21 additions & 15 deletions src/modules/public/goods/goods.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,21 +51,27 @@ export class GoodsController {
}, { });

const cids = Object.keys(categoryMap);
const goods =
(await this.goodsSvr.getByCids(cids, query))
.map((doc) => {
const good = doc.toObject() as IGoodsRaw;
const category = categoryMap[good.category.toString()];
// delete good.category;
good.uploader = good.uploader.nickname as any;
good.tags =
Array.from(new Set(good.tags.concat(category.tags)));
good.attributes = Array.from(new Set(
good.attributes.concat(category.attributes)
)) as any;
good.downloaded = this.logsSvr.goodDownloadCount(good._id);
return good;
});
const goodDocs = await this.goodsSvr.getByCids(cids, query);
const goods = [ ];
for (const doc of goodDocs) {
const good = doc.toObject() as IGoodsRaw;
const category = categoryMap[good.category.toString()];
// delete good.category;
good.uploader = good.uploader.nickname as any;
// good.tags =
// Array.from(new Set(good.tags.concat(category.tags)));
good.attributes = Array.from(new Set(
good.attributes.concat(category.attributes)
)) as any;
good.downloaded =
await this.logsSvr.goodDownloadCount(good._id);

for (const key of ["active", "hidden", "tags"]) {
delete good[key];
}

goods.push(good);
}
return UtilService.toListRespone(goods, Object.assign({
total: await this.goodsSvr.countByCids(cids)
}, query));
Expand Down
2 changes: 1 addition & 1 deletion src/services/goods.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export class GoodsService extends BaseService<IGoods> {
cids = [ cids ];
}
if (cids.length === 0) {
return [ ];
return Promise.resolve(0);
}
const conditions = this.getConditionsByCids(cids);
return this.total(conditions);
Expand Down
50 changes: 50 additions & 0 deletions test/api/goods/get_by_category.e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { connect, drop } from "../../helpers/database";
import { init } from "../../helpers/server";
import { newIds } from "../../helpers/utils";
import { GuestRequest, AdminRequest } from "../../helpers/request";
import * as files from "../../helpers/files";

describe("Get Good List By Category ID", () => {

let request: AdminRequest;

before(() => {
return connect();
});

const ids = newIds();

after(() => {
return drop(ids);
});

const filepaths = [ ];

after(() => {
return files.remove(filepaths);
});

before("login", async () => {
const req = await new GuestRequest(await init(), ids, filepaths);
request = await req.login();
});

step(("Init Env"), async () => {
await request.newFile();
await request.addCategoryWithRegexp();
await request.uploadFile();
await request.newFile();
await request.addCategoryWithRegexp();
await request.uploadFile();
});

step("Checker Number", async () => {
const url = "/api/v1/goods";
const { body: result0 } = await request.get(url).then();
result0.should.have.property("total", 2);
const cid = ids.categories[ids.categories.length - 1];
const { body: result1 } = await request.get(`${url}?cid=${cid}`).then();
result1.should.have.property("total", 1);
});

});
61 changes: 61 additions & 0 deletions test/api/goods/goods_method.e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import faker = require("faker");

import {
connect, drop, addCategoryAndRegexp
} from "../../helpers/database";
import { init } from "../../helpers/server";
import { newIds, newName } from "../../helpers/utils";
import { GuestRequest, AdminRequest } from "../../helpers/request";
import * as files from "../../helpers/files";

describe("Check `/goods` methods", () => {

let request: AdminRequest;

before(() => {
return connect();
});

const ids = newIds();

after(() => {
return drop(ids);
});

const filepaths = [ ];

after(() => {
return files.remove(filepaths);
});

before("login", async () => {
request = await new GuestRequest(await init(), ids, filepaths).login();
});

const tags = [ newName(), newName() ];

step("Init Env", async () => {
await request.newFile();
await request.addCategoryWithRegexp();
await request.uploadFile();
const id = ids.categories[ids.categories.length - 1];
await request.put(`/api/v1/categories/${id}`).send({
tags
}).then();
});

step("Check Goods Method", async () => {
const query = tags.reduce((arr, item) => {
arr.push("tags=" + encodeURI(item));
return arr;
}, [ ]).join("&");
const { status, body } = await request.get(`/goods?${query}`).then();
status.should.be.eql(200);
const data: any[] = body.data;
data.should.matchEach((val) => {
val.should.have.property("downloaded").which.is.a.Number();
val.should.have.not.properties(["active", "hidden", "tags"]);
});
});

});
2 changes: 1 addition & 1 deletion test/issues/github/issue_57.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ describe("Fix Issues", () => {
});

before("login", async () => {
request = new GuestRequest(await init(), ids);
request = await new GuestRequest(await init(), ids);
});

describe("Github 57 [Get `/goods` Fail]", () => {
Expand Down
47 changes: 47 additions & 0 deletions test/issues/github/issue_60.e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import faker = require("faker");

import {
connect, drop, addCategoryAndRegexp
} from "../../helpers/database";
import { init } from "../../helpers/server";
import { newIds, newName } from "../../helpers/utils";
import { GuestRequest, AdminRequest } from "../../helpers/request";
import * as files from "../../helpers/files";

/**
* Fix [Issue 60](https://github.com/BoxSystem/StoreBox-Api/issues/60)
*/
describe("Fix Issues", () => {

let request: AdminRequest;

before(() => {
return connect();
});

const ids = newIds();

after(() => {
return drop(ids);
});

before("login", async () => {
request = await new GuestRequest(await init(), ids).login();
});

describe("Github 60 [Can Add Category with exist name]", () => {

it("Cant", async () => {
const name = newName();
const req1 =
await request.post("/api/v1/categories").send({ name }).then();
req1.status.should.be.eql(201);
ids.categories.push(req1.body._id);
const req2 =
await request.post("/api/v1/categories").send({ name }).then();
req2.status.should.be.eql(400);
});

});

});