diff --git a/admin/src/App.js b/admin/src/App.js
index 7214dfc..9f606aa 100644
--- a/admin/src/App.js
+++ b/admin/src/App.js
@@ -7,8 +7,9 @@ import { BASE_URL } from "./configs/BaseUrl";
import { OpenGardenAdminLayout } from './themes/Layout';
-import { IoFlower } from "react-icons/io5";
+import { IoFlower, IoFlowerOutline } from "react-icons/io5";
import { PlantCreate, PlantEdit, PlantShow, PlantsList } from "./views/plants";
+import { VarietyCreate, VarietyEdit, VarietyShow, VarietiesList } from "./views/varieties";
const App = () => (
(
list={PlantsList}
show={PlantShow}
icon={IoFlower} />
+
>
)}
diff --git a/admin/src/configs/Provider.js b/admin/src/configs/Provider.js
index 6d99ba3..8618a5f 100644
--- a/admin/src/configs/Provider.js
+++ b/admin/src/configs/Provider.js
@@ -41,7 +41,7 @@ export default (apiUrl, httpClient = fetchUtils.fetchJson): DataProvider => ({
id: params.ids,
};
const url = `${apiUrl}/${resource}?${stringify(query)}`;
- return httpClient(url).then(({ json }) => ({ data: json }));
+ return httpClient(url).then(({ json }) => ({ data: json[resource] }))
},
getManyReference: (resource, params) => {
diff --git a/admin/src/views/plants.js b/admin/src/views/plants.js
index d949fdd..8055cd2 100644
--- a/admin/src/views/plants.js
+++ b/admin/src/views/plants.js
@@ -31,7 +31,7 @@ export const PlantCreate = (props) => (
-
+
@@ -55,7 +55,7 @@ export const PlantEdit = (props) => (
-
+
@@ -86,6 +86,7 @@ export const PlantsList = (props) => {
+
{permissions.includes('ADMIN') && }
@@ -117,8 +118,16 @@ export const PlantShow = (props) => (
+
+
+
+
+
+
+
+
diff --git a/admin/src/views/varieties.js b/admin/src/views/varieties.js
new file mode 100644
index 0000000..403595d
--- /dev/null
+++ b/admin/src/views/varieties.js
@@ -0,0 +1,258 @@
+import * as React from "react";
+import {
+ List,
+ Datagrid,
+ TextField,
+ DateField,
+ Show,
+ RichTextField,
+ ReferenceOneField,
+ ShowButton,
+ EditButton,
+ Create,
+ TextInput,
+ SingleFieldList,
+ ChipField,
+ ArrayField,
+ Edit,
+ TabbedForm,
+ FormTab,
+ TabbedShowLayout,
+ Tab,
+ ReferenceArrayInput,
+ SelectArrayInput,
+ ReferenceInput,
+ SelectInput,
+ NumberInput,
+ ReferenceField,
+ ReferenceArrayField
+} from "react-admin";
+import { RichTextInput } from 'ra-input-rich-text';
+import { StringToLabelObject } from '../helpers/StringToLabelObject';
+import { GetPermissions } from "../helpers/GetPermissions";
+
+const monthsSelectItems = [
+ { id: 1, name: 'January' },
+ { id: 2, name: 'February' },
+ { id: 3, name: 'March' },
+ { id: 4, name: 'April' },
+ { id: 5, name: 'May' },
+ { id: 6, name: 'June' },
+ { id: 7, name: 'July' },
+ { id: 8, name: 'August' },
+ { id: 9, name: 'September' },
+ { id: 10, name: 'October' },
+ { id: 11, name: 'November' },
+ { id: 12, name: 'December' },
+];
+
+const origins = ["AF", "AL", "DZ", "AS", "AD", "AO", "AI", "AQ", "AG", "AR", "AM", "AW", "AU", "AT", "AZ", "BS", "BH", "BD", "BB", "BY", "BE", "BZ", "BJ", "BM", "BT", "BO", "BA", "BW", "BV", "BR", "IO", "BN", "BG", "BF", "BI", "KH", "CM", "CA", "CV", "KY", "CF", "TD", "CL", "CN", "CX", "CC", "CO", "KM", "CG", "CD", "CK", "CR", "CI", "HR", "CU", "CY", "CZ", "DK", "DJ", "DM", "DO", "EC", "EG", "SV", "GQ", "ER", "EE", "ET", "FK", "FO", "FJ", "FI", "FR", "GF", "PF", "TF", "GA", "GM", "GE", "DE", "GH", "GI", "GR", "GL", "GD", "GP", "GU", "GT", "GN", "GW", "GY", "HT", "HM", "VA", "HN", "HK", "HU", "IS", "IN", "ID", "IR", "IQ", "IE", "IL", "IT", "JM", "JP", "JO", "KZ", "KE", "KI", "KP", "KR", "KW", "KG", "LA", "LV", "LB", "LS", "LR", "LY", "LI", "LT", "LU", "MO", "MG", "MW", "MY", "MV", "ML", "MT", "MH", "MQ", "MR", "MU", "YT", "MX", "FM", "MD", "MC", "MN", "MS", "MA", "MZ", "MM", "NA", "NR", "NP", "NL", "NC", "NZ", "NI", "NE", "NG", "NU", "NF", "MK", "MP", "NO", "OM", "PK", "PW", "PS", "PA", "PG", "PY", "PE", "PH", "PN", "PL", "PT", "PR", "QA", "RE", "RO", "RU", "RW", "SH", "KN", "LC", "PM", "VC", "WS", "SM", "ST", "SA", "SN", "SC", "SL", "SG", "SK", "SI", "SB", "SO", "ZA", "GS", "ES", "LK", "SD", "SR", "SJ", "SZ", "SE", "CH", "SY", "TW", "TJ", "TZ", "TH", "TL", "TG", "TK", "TO", "TT", "TN", "TR", "TM", "TC", "TV", "UG", "UA", "AE", "GB", "US", "UM", "UY", "UZ", "VU", "VE", "VN", "VG", "VI", "WF", "EH", "YE", "ZM", "ZW", "AX", "BQ", "CW", "GG", "IM", "JE", "ME", "BL", "MF", "RS", "SX", "SS", "XK "];
+const originSelectItem = origins.map((origin) => ({ id: origin, name: origin }));
+
+export const VarietyCreate = (props) => (
+
+
+
+
+
+
+
+
+
+
+
+
+ Water
+
+
+ Sun
+
+
+ Floors
+
+
+
+
+
+ Types
+
+
+
+
+
+
+
+
+
+
+
+
+);
+
+export const VarietyEdit = (props) => (
+
+
+
+
+
+
+
+
+
+
+
+
+ Water
+
+
+ Sun
+
+
+ Floors
+
+
+
+
+
+ Types
+
+
+
+
+
+
+
+
+
+
+
+
+);
+
+export const VarietiesList = (props) => {
+ const permissions = GetPermissions();
+ return (
+
+ permissions.includes('ADMIN')}>
+
+
+
+
+
+
+
+ {permissions.includes('ADMIN') && }
+
+
+
+ );
+};
+
+export const VarietyShow = (props) => (
+
+
+
+
+
+
+
+
+
+
+
+
+ Water
+
+
+ Sun
+
+
+ Floors
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+);
diff --git a/core/src/controllers/plants/plants.controller.ts b/core/src/controllers/plants/plants.controller.ts
index 5771533..a5c4925 100644
--- a/core/src/controllers/plants/plants.controller.ts
+++ b/core/src/controllers/plants/plants.controller.ts
@@ -68,12 +68,14 @@ export class PlantsController {
@Get(':plantId')
@ApiResponse({ status: 200, type: PlantResponseBody })
@ApiResponse({ status: 404, description: 'Not Found', type: ErrorsRequestBody })
- async getPlantById(@Param('plantId') plantId: string) {
+ async getPlantById(@Response() res: Res, @Param('plantId') plantId: string) {
const plant = await this.plantsService.findOneById(plantId);
if (!plant) {
throw new NotFoundException();
}
- return this.mapper.map(plant, Plant, PlantResponseBody);
+
+ const body = this.mapper.map(plant, Plant, PlantResponseBody);
+ return res.set({ 'Content-Range': `elements 0-1/1` }).json(body);
}
@Get()
@@ -91,10 +93,6 @@ export class PlantsController {
const body: PlantSearchResponseBody = {
plants: this.mapper.mapArray(elements, Plant, PlantResponseBody),
};
- return res
- .set({
- 'Content-Range': `elements ${offset}-${offset + limit}/${count}`,
- })
- .json(body);
+ return res.set({ 'Content-Range': `elements ${offset}-${offset + limit}/${count}` }).json(body);
}
}
diff --git a/core/src/controllers/varieties/models/mapper.profiles.ts b/core/src/controllers/varieties/models/mapper.profiles.ts
index 80d4e08..52c9b76 100644
--- a/core/src/controllers/varieties/models/mapper.profiles.ts
+++ b/core/src/controllers/varieties/models/mapper.profiles.ts
@@ -119,7 +119,7 @@ export class VarietyMapperProfiles extends AutomapperProfile {
mapFrom((s) => s.plant.toString()),
),
forMember(
- (d) => d.variety,
+ (d) => d.name,
mapFrom((s) => escapeHtml(s.name)),
),
forMember(
diff --git a/core/src/controllers/varieties/models/variety.response.body.ts b/core/src/controllers/varieties/models/variety.response.body.ts
index e9d7028..d6b4a1e 100644
--- a/core/src/controllers/varieties/models/variety.response.body.ts
+++ b/core/src/controllers/varieties/models/variety.response.body.ts
@@ -63,7 +63,7 @@ export class VarietyResponseBody {
plant: string;
@ApiProperty()
- variety: string;
+ name: string;
@ApiProperty({ enum: Country })
origin: Country;
diff --git a/core/src/controllers/varieties/varieties.controller.ts b/core/src/controllers/varieties/varieties.controller.ts
index 7072713..03a9221 100644
--- a/core/src/controllers/varieties/varieties.controller.ts
+++ b/core/src/controllers/varieties/varieties.controller.ts
@@ -1,4 +1,15 @@
-import { Body, Request, Controller, Get, NotFoundException, Param, Post, Query } from '@nestjs/common';
+import {
+ Body,
+ Request,
+ Controller,
+ Get,
+ NotFoundException,
+ Param,
+ Post,
+ Query,
+ Response,
+ Delete,
+} from '@nestjs/common';
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
import { Mapper } from '@automapper/core';
import { InjectMapper } from '@automapper/nestjs';
@@ -13,6 +24,7 @@ import { ErrorsRequestBody } from '../models/errors.response.body';
import { Roles } from '../../auth/roles/roles.decorator';
import { Role } from '../../auth/roles/role.enum';
import { PublishedState } from '../../entities/base.published.entity';
+import { Response as Res } from 'express';
@ApiBearerAuth()
@ApiTags('Varieties')
@@ -20,7 +32,7 @@ import { PublishedState } from '../../entities/base.published.entity';
@ApiResponse({ status: 429, description: 'Too Many Requests' })
@Controller('varieties')
export class VarietiesController {
- constructor(private plantsService: VarietiesService, @InjectMapper() private mapper: Mapper) {}
+ constructor(private varietiesService: VarietiesService, @InjectMapper() private mapper: Mapper) {}
@Post()
@Roles(Role.ADMIN)
@@ -47,34 +59,50 @@ export class VarietiesController {
updatedAt: new Date(),
createdBy: req.user._id,
};
- const plant = await this.plantsService.create(createVariety);
+ const plant = await this.varietiesService.create(createVariety);
return this.mapper.map(plant, Variety, VarietyResponseBody);
}
+ @Delete(':varietyId')
+ @Roles(Role.ADMIN)
+ @ApiResponse({ status: 403, description: 'Forbidden', type: ErrorsRequestBody })
+ @ApiResponse({ status: 404, description: 'Not Found', type: ErrorsRequestBody })
+ @ApiResponse({ status: 200, type: VarietyResponseBody })
+ async deletePlant(@Request() req, @Param('varietyId') varietyId: string) {
+ const variety = await this.varietiesService.delete(varietyId);
+ if (!variety) {
+ throw new NotFoundException();
+ }
+
+ return this.mapper.map(variety, Variety, VarietyResponseBody);
+ }
+
@Get(':varietyId')
@ApiResponse({ status: 200, type: VarietyResponseBody })
- async getVarietyById(@Param('varietyId') varietyId: string) {
- const plant = await this.plantsService.findOneById(varietyId);
+ async getVarietyById(@Response() res: Res, @Param('varietyId') varietyId: string) {
+ const plant = await this.varietiesService.findOneById(varietyId);
if (!plant) {
throw new NotFoundException();
}
- return this.mapper.map(plant, Variety, VarietyResponseBody);
+
+ const body = this.mapper.map(plant, Variety, VarietyResponseBody);
+ return res.set({ 'Content-Range': `elements 0-1/1` }).json(body);
}
@Get()
@ApiResponse({ status: 200, type: VarietySearchResponseBody })
- async getVarieties(@Query() plantsSearchRequestQuery: VarietiesSearchRequestQuery) {
+ async getVarieties(@Response() res: Res, @Query() plantsSearchRequestQuery: VarietiesSearchRequestQuery) {
const { limit, offset, ...filters } = plantsSearchRequestQuery;
- const plants = await this.plantsService.search({
+ const [elements, count] = await this.varietiesService.search({
pagination: {
limit,
offset,
},
...filters,
});
- const result: VarietySearchResponseBody = {
- varieties: this.mapper.mapArray(plants, Variety, VarietyResponseBody),
+ const body: VarietySearchResponseBody = {
+ varieties: this.mapper.mapArray(elements, Variety, VarietyResponseBody),
};
- return result;
+ return res.set({ 'Content-Range': `elements ${offset}-${offset + limit}/${count}` }).json(body);
}
}
diff --git a/core/src/entities/varieties/varieties.service.ts b/core/src/entities/varieties/varieties.service.ts
index 81e31fe..5061c08 100644
--- a/core/src/entities/varieties/varieties.service.ts
+++ b/core/src/entities/varieties/varieties.service.ts
@@ -25,14 +25,14 @@ export class VarietySearchParams extends BaseSearchParams {
@Injectable()
export class VarietiesService extends BaseEntityService {
- constructor(@InjectModel(Variety.name) private plantModel: Model) {
+ constructor(@InjectModel(Variety.name) private varietyModel: Model) {
super();
}
async create(plant: Variety): Promise {
try {
plant._id = new mongoose.Types.ObjectId();
- return await this.plantModel.create(plant);
+ return await this.varietyModel.create(plant);
} catch (exception) {
if (exception.code === 11000) {
throw new ConflictException();
@@ -41,11 +41,19 @@ export class VarietiesService extends BaseEntityService {
}
}
+ async delete(varietyId: string): Promise {
+ try {
+ return await this.varietyModel.findByIdAndDelete(varietyId);
+ } catch {
+ return null;
+ }
+ }
+
async findOneById(id: string): Promise {
- return await this.plantModel.findById(id);
+ return await this.varietyModel.findById(id);
}
- async search(params: VarietySearchParams): Promise {
+ async search(params: VarietySearchParams): Promise<[Variety[], number]> {
const {
pagination,
sunNeed,
@@ -90,6 +98,9 @@ export class VarietiesService extends BaseEntityService {
findParam = this._generateFilter(findParam, 'culture.sowingPeriod', sowingPeriod);
findParam = this._generateFilter(findParam, 'culture.growingOnPeriod', growingOnPeriod);
findParam = this._generateFilter(findParam, 'culture.harvestPeriod', harvestPeriod);
- return await this.plantModel.find(findParam).skip(pagination.offset).limit(pagination.limit);
+
+ const elements = await this.varietyModel.find(findParam).skip(pagination.offset).limit(pagination.limit);
+ const count = await this.varietyModel.count(findParam);
+ return [elements, count];
}
}