Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 43 additions & 3 deletions src/modules/common/services/goods.service.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { Component, BadRequestException } from "@nestjs/common";
import { Model as GoodsModels } from "@models/Good";
import { ObjectId } from "@models/common";
import { Model as GoodsModels, IGoods, IGoodsRaw } from "@models/Good";
import { ICategory } from "@models/Categroy";
import { Model as ValuesModel } from "@models/Value";
import { BaseService, IGetOptions } from "@services/base";
import { isArray } from "util";
import { isArray, isObject, isString } from "util";
import { config } from "@utils/config";
import fs = require("fs-extra");

@Component()
export class GoodsService extends BaseService {
Expand Down Expand Up @@ -134,7 +138,9 @@ export class GoodsService extends BaseService {
*/
public async editById(id: ObjectId, ctx: object) {
try {
await GoodsModels.findByIdAndUpdate(id, ctx).exec();
await GoodsModels
.update({ _id: id }, ctx, this.DEF_UPDATE_OPTIONS)
.exec();
} catch (error) {
throw new BadRequestException(error.toString());
}
Expand All @@ -144,4 +150,38 @@ export class GoodsService extends BaseService {
return GoodsModels.create(ctx);
}

public async remove(id: ObjectId) {
const doc = await this.getById(id);
if (!doc) {
throw new BadRequestException("Non Exist Good ID");
}
const good = doc.toObject();
try {
await GoodsModels.findByIdAndRemove(id).exec();
if (good.attributes.length > 0) {
const cond = (good.attributes as ObjectId[])
.reduce((obj, item) => {
obj.$or.push({ _id: item });
return obj;
}, { $or: [ ] });
await ValuesModel.remove(cond).exec();
}
} catch (error) {
throw new BadRequestException(error.toString());
}
await fs.remove(this.getFilepath(good));
}

public getFilepath(good: IGoods) {
const filename = good.filename;
const cid =
isObject(good.category) && (good.category as ICategory)._id ?
(good.category as ICategory)._id :
good.category;
if (!cid) {
throw new BadRequestException();
}
return `${config.paths.upload}/${cid}/${filename}`;
}

}
3 changes: 1 addition & 2 deletions src/modules/files/files.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,7 @@ export class FilesController {
}

const good = obj.toObject();
const filepath =
`${config.paths.upload}/${params.cid}/${good.filename}`;
const filepath = this.goodsSvr.getFilepath(good);

if (!good.active) {
throw new BadRequestException("Disallow download the File");
Expand Down
33 changes: 31 additions & 2 deletions src/modules/goods/goods.controller.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {
Controller, Req, Res, Body, Get, Post, Param, Session,
HttpStatus, BadRequestException, UseGuards, Delete, HttpCode, Query
HttpStatus, BadRequestException, UseGuards, Delete, HttpCode, Query, Put
} from "@nestjs/common";
import {
ApiBearerAuth, ApiUseTags, ApiResponse, ApiOperation, ApiImplicitParam,
Expand Down Expand Up @@ -32,7 +32,7 @@ import multer = require("multer");
import { isArray } from "util";

import { CreateValueDto, EditValueDto } from "../values/values.dto";
import { GoodAttributeParamDto, UploadQueryDto } from "./goods.dto";
import { GoodAttributeParamDto, UploadQueryDto, EditBodyDto } from "./goods.dto";

@UseGuards(RolesGuard)
@Controller("api/v1/goods")
Expand Down Expand Up @@ -347,4 +347,33 @@ export class GoodsAdminController {
return new DefResDto();
}

@Roles("admin")
@Put("/:gid")
@Delete("/:gid")
// region Swagger Docs
@HttpCode(HttpStatus.OK)
@ApiOperation({ title: "Modify Good" })
@ApiResponse({
status: HttpStatus.OK, description: "Modify Success"
})
// endregion Swagger Docs
public async edit(@Param() param: GidDto, @Body() body: EditBodyDto) {
await this.goodsSvr.editById(param.gid, body);
return new DefResDto();
}

@Roles("admin")
@Delete("/:gid")
// region Swagger Docs
@HttpCode(HttpStatus.OK)
@ApiOperation({ title: "Delete Good" })
@ApiResponse({
status: HttpStatus.OK, description: "Delete Success"
})
// endregion Swagger Docs
public async delete(@Param() param: GidDto) {
await this.goodsSvr.remove(param.gid);
return new DefResDto();
}

}
19 changes: 18 additions & 1 deletion src/modules/goods/goods.dto.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { IGidDto, IAidDto } from "@dtos/ids";
import { ApiModelProperty } from "@nestjs/swagger";
import { ApiModelProperty, ApiModelPropertyOptional } from "@nestjs/swagger";
import { IsMongoId, IsString, IsOptional } from "class-validator";
import { ObjectId } from "@models/common";
import { IGoods } from "@models/Good";
Expand Down Expand Up @@ -34,3 +34,20 @@ export class UploadQueryDto {
@IsOptional()
public readonly append?: string[];
}

export class EditBodyDto {
@ApiModelPropertyOptional({ type: String, description: "Good Name" })
@IsOptional()
public readonly name?: string;
@ApiModelPropertyOptional({ type: Boolean })
@IsOptional()
public readonly hidden?: boolean;
@ApiModelPropertyOptional({ type: String, description: "Category ID" })
@IsOptional()
public readonly category?: ObjectId;
@ApiModelPropertyOptional({
type: String, description: "Filename when download"
})
@IsOptional()
public readonly originname?: string;
}
125 changes: 125 additions & 0 deletions test/issues/gitlab/issue_1.e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import * as supertest from "supertest";
import categories = require("@db/categories");
import auth = require("@db/auth");
import * as db from "../../helpers/database";
import * as server from "../../helpers/server";
import { newName } from "../../helpers/utils";
import * as files from "../../helpers/files";
import goods = require("@db/goods");

/**
* Fix [Issue 1](http://git.pbr.link/BoxSystem/StoreBox/issues/1)
*/
describe("Fix Issues", () => {

let request: supertest.SuperTest<supertest.Test>;

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

const ids = {
users: [ ],
categories: [ ],
regexps: [ ],
goods: [ ]
};

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

before(async () => {
request = await server.init();
});

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

before("login", async () => {
ids.users.push((await auth.login(request))[0]);
});

let cids = [ ];
step("Add Category group", async () => {
cids = await categories.addCategories();
ids.categories.push(...cids);
});

describe("Gitlab 1 [Delete Good]", () => {

const filename = newName();
let cid;

step("Add One Category with Regexp", async () => {
const docs = await db.addCategoryAndRegexp(
new RegExp(filename)
);
cid = docs[0]._id;
ids.categories.push(cid);
ids.regexps.push(docs[1]._id);
});

let gid;

step("Upload File", async () => {
const filepath = await files.newFile(filename);
filepaths.push(filepath);
await files.uploadFile(request, filepath);
gid = await goods.getIdByOriginname(filename);
ids.goods.push(gid);
});

step("Delete Good", async () => {
const url = `/api/v1/goods/${gid}`;
const { status } = await request.delete(url).then();
status.should.be.eql(200);
});

step("404 for Good", async () => {
const url = `/files/categories/${cid}/goods/${gid}`;
const { status } = await request.get(url).then();
status.should.be.eql(404);
});

});

describe("Gitlab 1 [Move Good to Other Category]", () => {

const filename = newName();

step("Add One Category with Regexp", async () => {
const docs = await db.addCategoryAndRegexp(
new RegExp(filename)
);
ids.categories.push(docs[0]._id);
ids.regexps.push(docs[1]._id);
});

let gid;

step("Upload File", async () => {
const filepath = await files.newFile(filename);
filepaths.push(filepath);
await files.uploadFile(request, filepath);
gid = await goods.getIdByOriginname(filename);
ids.goods.push(gid);
});

step("Move Good ", async () => {
const url = `/api/v1/goods/${gid}`;
const cid = ids.categories[5].toString();
const { status } = await request.put(url)
.send({ category: cid })
.then();
status.should.be.eql(200);

const { body } = await request.get(url).then();
body.category._id.toString().should.be.eql(cid);
});

});

});