Skip to content

Commit

Permalink
feat(favorites): content-range, delete endpoint and admin page
Browse files Browse the repository at this point in the history
  • Loading branch information
Ealenn committed Jun 24, 2022
1 parent 942b897 commit a319da4
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 34 deletions.
8 changes: 7 additions & 1 deletion admin/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ import { BASE_URL } from "./configs/BaseUrl";

import { OpenGardenAdminLayout } from './themes/Layout';

import { TbSeeding, TbTree, TbPlant2 } from 'react-icons/tb';
import { TbSeeding, TbTree, TbPlant2, TbStar } from 'react-icons/tb';

import { PlantCreate, PlantEdit, PlantShow, PlantsList } from "./views/plants";
import { VarietyCreate, VarietyEdit, VarietyShow, VarietiesList } from "./views/varieties";
import { FloorCreate, FloorEdit, FloorShow, FloorsList } from "./views/floors";
import { FavoritesVarietiesList, FavoritesVarietyCreate, FavoritesVarietyShow } from "./views/favorites.varieties";

const App = () => (
<Admin
Expand All @@ -34,6 +35,11 @@ const App = () => (
list={VarietiesList}
show={VarietyShow}
icon={TbSeeding} />
<Resource name="favorites/varieties"
create={FavoritesVarietyCreate}
list={FavoritesVarietiesList}
show={FavoritesVarietyShow}
icon={TbStar} />
<Resource name="floors"
create={permissions.includes('ADMIN') ? FloorCreate : null}
edit={permissions.includes('ADMIN') ? FloorEdit : null}
Expand Down
6 changes: 4 additions & 2 deletions admin/src/configs/Provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { fetchUtils, DataProvider } from 'ra-core';

export default (apiUrl, httpClient = fetchUtils.fetchJson): DataProvider => ({
getList: (resource, params) => {
const resourceName = resource.split('/').slice(-1);
const { page, perPage } = params.pagination;
const query = {
...fetchUtils.flattenObject(params.filter),
Expand All @@ -19,7 +20,7 @@ export default (apiUrl, httpClient = fetchUtils.fetchJson): DataProvider => ({
);
}
return {
data: json[resource],
data: json[resourceName],
total: parseInt(
headers.get('content-range').split('/').pop(),
10
Expand All @@ -36,12 +37,13 @@ export default (apiUrl, httpClient = fetchUtils.fetchJson): DataProvider => ({
},

getMany: (resource, params) => {
const resourceName = resource.split('/').slice(-1);
console.log('getMany', resource, params);
const query = {
id: params.ids,
};
const url = `${apiUrl}/${resource}?${stringify(query)}`;
return httpClient(url).then(({ json }) => ({ data: json[resource] }))
return httpClient(url).then(({ json }) => ({ data: json[resourceName] }))
},

getManyReference: (resource, params) => {
Expand Down
71 changes: 71 additions & 0 deletions admin/src/views/favorites.varieties.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import * as React from "react";
import {
List,
Datagrid,
TextField,
DateField,
Show,
ReferenceOneField,
ShowButton,
Create,
SingleFieldList,
ChipField,
ArrayField,
TabbedShowLayout,
Tab,
ReferenceInput,
SelectInput,
SimpleForm,
ReferenceField
} from "react-admin";
import { StringToLabelObject } from '../helpers/StringToLabelObject';

export const FavoritesVarietyCreate = (props) => (
<Create {...props}>
<SimpleForm>
<ReferenceInput source="variety" reference="varieties">
<SelectInput optionText="name" />
</ReferenceInput>
</SimpleForm>
</Create>
);

export const FavoritesVarietiesList = (props) => {
return (
<List {...props} exporter={false}>
<Datagrid>
<ReferenceOneField reference="varieties" source="id" label="name">
<TextField source="name" />
</ReferenceOneField>
<DateField source="createdAt" />
<ShowButton />
</Datagrid>
</List>
);
};

export const FavoritesVarietyShow = (props) => (
<Show {...props}>
<TabbedShowLayout>
<Tab label="Summary">
<ReferenceField reference="varieties" source="id">
<TextField source="name" />
</ReferenceField>
</Tab>
<Tab label="Metadata">
<ReferenceOneField reference="profiles" source="createdBy">
<TextField source="username" />
<ArrayField source="roles">
<SingleFieldList>
<StringToLabelObject>
<ChipField source="label" />
</StringToLabelObject>
</SingleFieldList>
</ArrayField>
</ReferenceOneField>
<DateField source="createdAt" />
<DateField source="updatedAt" />
</Tab>
</TabbedShowLayout>
</Show>
);
15 changes: 10 additions & 5 deletions admin/src/views/floors.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,28 @@ import {
ArrayField,
Edit,
TabbedShowLayout,
Tab
Tab,
SimpleForm
} from "react-admin";
import { RichTextInput } from 'ra-input-rich-text';
import { StringToLabelObject } from '../helpers/StringToLabelObject';
import { GetPermissions } from "../helpers/GetPermissions";

export const FloorCreate = (props) => (
<Create {...props}>
<TextInput source="name" />
<RichTextInput source="description" multiline fullWidth />
<SimpleForm>
<TextInput source="name" />
<RichTextInput source="description" multiline fullWidth />
</SimpleForm>
</Create>
);

export const FloorEdit = (props) => (
<Edit {...props}>
<TextInput source="name" />
<RichTextInput source="description" multiline fullWidth />
<SimpleForm>
<TextInput source="name" />
<RichTextInput source="description" multiline fullWidth />
</SimpleForm>
</Edit>
);

Expand Down
45 changes: 22 additions & 23 deletions core/src/controllers/favorites/favorites.varieties.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
Delete,
Param,
NotFoundException,
Response,
} from '@nestjs/common';
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
import { Mapper } from '@automapper/core';
Expand All @@ -22,6 +23,7 @@ import {
} from './models/favorite.response.body';
import { FavoriteVariety } from '../../entities/favorites/models/favorite.variety.entity';
import { FavoriteVarietiesSearchRequestQuery } from './models/favorite.variety.request.query';
import { Response as Res } from 'express';

@ApiBearerAuth()
@ApiTags('Favorites')
Expand All @@ -33,22 +35,20 @@ export class FavoritesVarietiesController {

@Delete(':varietyId')
@ApiResponse({ status: 200 })
@ApiResponse({
status: 404,
description: 'Not Found',
type: ErrorsRequestBody,
})
async deleteFavorite(@Request() req, @Param('varietyId') varietyId: string) {
await this.favoritesService.deleteVariety(varietyId, req.user);
@ApiResponse({ status: 404, description: 'Not Found', type: ErrorsRequestBody })
async deleteFavorite(@Response() res: Res, @Request() req, @Param('varietyId') varietyId: string) {
const favorite = await this.favoritesService.deleteVariety(varietyId, req.user);
if (!favorite) {
throw new NotFoundException();
}

const body = this.mapper.map(favorite, FavoriteVariety, FavoriteVarietyResponseBody);
return res.set({ 'Content-Range': `elements 0-1/1` }).json(body);
}

@Post()
@ApiResponse({ status: 201, type: FavoriteVarietyResponseBody })
@ApiResponse({
status: 400,
description: 'Bad Request',
type: ErrorsRequestBody,
})
@ApiResponse({ status: 400, description: 'Bad Request', type: ErrorsRequestBody })
async createFavorite(@Request() req, @Body() createFavoriteRequestBody: CreateFavoriteVarietyRequestBody) {
const favorite = await this.favoritesService.addVariety(createFavoriteRequestBody.variety, req.user);
return this.mapper.map(favorite, FavoriteVariety, FavoriteVarietyResponseBody);
Expand All @@ -57,11 +57,12 @@ export class FavoritesVarietiesController {
@Get()
@ApiResponse({ status: 200, type: FavoriteVarietySearchResponseBody })
async getFavoritesVarieties(
@Response() res: Res,
@Query() favoritesSearchRequestQuery: FavoriteVarietiesSearchRequestQuery,
@Request() req,
) {
const { limit, offset, ...filters } = favoritesSearchRequestQuery;
const favorites = await this.favoritesService.getVarieties(
const [elements, count] = await this.favoritesService.getVarieties(
{
pagination: {
limit,
Expand All @@ -71,24 +72,22 @@ export class FavoritesVarietiesController {
},
req.user,
);
const result: FavoriteVarietySearchResponseBody = {
varieties: this.mapper.mapArray(favorites, FavoriteVariety, FavoriteVarietyResponseBody),
const body: FavoriteVarietySearchResponseBody = {
varieties: this.mapper.mapArray(elements, FavoriteVariety, FavoriteVarietyResponseBody),
};
return result;
return res.set({ 'Content-Range': `elements ${offset}-${offset + limit}/${count}` }).json(body);
}

@Get(':varietyId')
@ApiResponse({ status: 200, type: FavoriteVarietyResponseBody })
@ApiResponse({
status: 404,
description: 'Not Found',
type: ErrorsRequestBody,
})
async getFavoriteVariety(@Request() req, @Param('varietyId') varietyId: string) {
@ApiResponse({ status: 404, description: 'Not Found', type: ErrorsRequestBody })
async getFavoriteVariety(@Response() res: Res, @Request() req, @Param('varietyId') varietyId: string) {
const favorite = await this.favoritesService.getVariety(varietyId, req.user);
if (!favorite) {
throw new NotFoundException();
}
return this.mapper.map(favorite, FavoriteVariety, FavoriteVarietyResponseBody);

const body = this.mapper.map(favorite, FavoriteVariety, FavoriteVarietyResponseBody);
return res.set({ 'Content-Range': `elements 0-1/1` }).json(body);
}
}
11 changes: 8 additions & 3 deletions core/src/entities/favorites/favorites.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,21 @@ export class FavoritesService extends BaseEntityService {
filters = this._generateFilter(filters, 'createdBy', user._id);
filters = this._generateFilter(filters, 'variety', new Types.ObjectId(varietyId));
filters = this._generateFilter(filters, 'compositeKey', `${user._id.toString()}${varietyId}`);
return await this.favoriteVarietyModel.remove(filters).limit(1);
return await this.favoriteVarietyModel.findOneAndRemove(filters);
}

async getVarieties(params: FavoritesSearchParams, user: User): Promise<FavoriteVariety[]> {
async getVarieties(params: FavoritesSearchParams, user: User): Promise<[FavoriteVariety[], number]> {
const { pagination } = params;
const findParam = this._generateFilters({
createdBy: user._id,
});

return await this.favoriteVarietyModel.find(findParam).skip(pagination.offset).limit(pagination.limit);
const elements = await this.favoriteVarietyModel
.find(findParam)
.skip(pagination.offset)
.limit(pagination.limit);
const count = await this.favoriteVarietyModel.count(findParam);
return [elements, count];
}

async getVariety(varietyId: string, user: User): Promise<FavoriteVariety> {
Expand Down

0 comments on commit a319da4

Please sign in to comment.