From e77284871c9694221b76c9ee08af207ce40fea6e Mon Sep 17 00:00:00 2001 From: Davide Crestini Date: Tue, 9 Jul 2019 16:26:10 +0100 Subject: [PATCH 1/9] updated recipe graphql type --- src/apollo/types/recipe.gql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/apollo/types/recipe.gql b/src/apollo/types/recipe.gql index 0b01ad4..dac7e2a 100644 --- a/src/apollo/types/recipe.gql +++ b/src/apollo/types/recipe.gql @@ -28,7 +28,7 @@ type RecipeRating { } type Recipe { - id: ID + _id: ID slug: String title: String description: String @@ -52,7 +52,7 @@ type Recipe { # INPUT input RecipeLevelInput { - id: String + _id: String name: String } From 4534b1143f3537b9758a9a6ca0eabfc88d283004 Mon Sep 17 00:00:00 2001 From: Davide Crestini Date: Tue, 9 Jul 2019 16:42:34 +0100 Subject: [PATCH 2/9] created backbone structure for event deletion and edit --- src/apollo/resolvers/mealPlan.ts | 17 ++++++++++ src/apollo/types/mealPlan.gql | 21 +++++++++++- src/context/mealplan/index.ts | 13 ++++++- src/context/mealplan/services/index.ts | 47 ++++++++++++++++++++++++++ src/types/mealPlan.d.ts | 18 ++++++++++ 5 files changed, 114 insertions(+), 2 deletions(-) diff --git a/src/apollo/resolvers/mealPlan.ts b/src/apollo/resolvers/mealPlan.ts index ebb2a98..17806a3 100644 --- a/src/apollo/resolvers/mealPlan.ts +++ b/src/apollo/resolvers/mealPlan.ts @@ -5,9 +5,11 @@ import { IContext, IObjectId } from 'types/global'; import { IMealEvent, IMealEventAddInput, + IMealEventEditInput, IMealPlanRangeInput, IWorkoutEvent, IWorkoutEventAddInput, + IWorkoutEventEditInput, } from 'types/mealPlan'; import { IRecipe } from 'types/recipe'; @@ -45,6 +47,21 @@ export default { data: IWorkoutEventAddInput, ctx: IContext ): Promise => MealPlan.addWorkoutEvent(data, ctx), + deleteEvent: async ( + _: object, + id: IObjectId, + ctx: IContext + ): Promise => MealPlan.deleteEvent(id, ctx), + editMealEvent: async ( + _: object, + data: IMealEventEditInput, + ctx: IContext + ): Promise => MealPlan.editMealEvent(data, ctx), + editWorkoutEvent: async ( + _: object, + data: IWorkoutEventEditInput, + ctx: IContext + ): Promise => MealPlan.editWorkoutEvent(data, ctx), }, Query: { mealPlanEvents: async ( diff --git a/src/apollo/types/mealPlan.gql b/src/apollo/types/mealPlan.gql index 6e45afc..b09f079 100644 --- a/src/apollo/types/mealPlan.gql +++ b/src/apollo/types/mealPlan.gql @@ -30,11 +30,25 @@ input MealEventAddInput { mealType: String! } +input MealEventEditInput { + _id: ID! + startTime: Date! + endTime: Date! + recipes: [ID]! + mealType: String! +} + input WorkoutEventAddInput { startTime: Date! endTime: Date! } +input WorkoutEventEditInput { + _id: ID! + startTime: Date! + endTime: Date! +} + input MealPlanRangeInput { startDay: Date! endDay: Date! @@ -49,5 +63,10 @@ type Mutation { @auth(role: USER) addWorkoutEvent(input: WorkoutEventAddInput!): WorkoutEvent @auth(role: USER) - # deleteRecipe(id: ID!): Boolean @auth(role: USER) + deleteEvent(id: ID!): Boolean + @auth(role: USER) + editMealEvent(input: MealEventEditInput!): MealEvent + @auth(role: USER) + editWorkoutEvent(input: WorkoutEventEditInput!): WorkoutEvent + @auth(role: USER) } \ No newline at end of file diff --git a/src/context/mealplan/index.ts b/src/context/mealplan/index.ts index 04eb372..bcdb293 100644 --- a/src/context/mealplan/index.ts +++ b/src/context/mealplan/index.ts @@ -2,10 +2,12 @@ import { IContext, ILimitSkipInput, IObjectId } from 'types/global'; import { IMealEvent, IMealEventAddInput, + IMealEventEditInput, IMealPlanEvent, IMealPlanRangeInput, IWorkoutEvent, IWorkoutEventAddInput, + IWorkoutEventEditInput, } from 'types/mealPlan'; import MealPlanService from './services'; @@ -20,10 +22,19 @@ export default { data: IWorkoutEventAddInput, ctx: IContext ): Promise => mealPlanService.addWorkoutEvent(data, ctx), + deleteEvent: (id: IObjectId, ctx: IContext): Promise => + mealPlanService.deleteEvent(id, ctx), + editMealEvent: ( + data: IMealEventEditInput, + ctx: IContext + ): Promise => mealPlanService.editMealEvent(data, ctx), + editWorkoutEvent: ( + data: IWorkoutEventEditInput, + ctx: IContext + ): Promise => mealPlanService.editWorkoutEvent(data, ctx), findWithinRange: ( data: IMealPlanRangeInput, ctx: IContext ): Promise> => mealPlanService.findWithinRange(data, ctx), - // list: (): Promise => mealPlanService.list(), }; diff --git a/src/context/mealplan/services/index.ts b/src/context/mealplan/services/index.ts index 809b0b7..130dd9c 100644 --- a/src/context/mealplan/services/index.ts +++ b/src/context/mealplan/services/index.ts @@ -5,10 +5,12 @@ import { IContext, IObjectId } from 'types/global'; import { IMealEvent, IMealEventAddInput, + IMealEventEditInput, IMealPlanEvent, IMealPlanRangeInput, IWorkoutEvent, IWorkoutEventAddInput, + IWorkoutEventEditInput, } from 'types/mealPlan'; import MealPlanRepo from '../repo'; @@ -71,6 +73,22 @@ export default class MealPlanService { return this.mealPlanEventRepo.createMealEvent(data, creator); } + public async editMealEvent( + data: IMealEventEditInput, + ctx: IContext + ): Promise { + const event = await this.mealPlanEventRepo.findBy({ + _id: data.input._id, + owner: ctx.user._id, + }); + + if (!event) { + throw new Error('Provided evenet does not exist '); + } + + return event; + } + public async addWorkoutEvent( data: IWorkoutEventAddInput, ctx: IContext @@ -88,4 +106,33 @@ export default class MealPlanService { return created; } + + public async editWorkoutEvent( + data: IWorkoutEventEditInput, + ctx: IContext + ): Promise { + const event = await this.mealPlanEventRepo.findBy({ + _id: data.input._id, + owner: ctx.user._id, + }); + + if (!event) { + throw new Error('Provided event does not exist'); + } + + return event; + } + + public async deleteEvent(id: IObjectId, ctx: IContext): Promise { + const event = await this.mealPlanEventRepo.findBy({ + _id: id, + owner: ctx.user._id, + }); + + if (!event) { + throw new Error('Provided event does not exist '); + } + + return event; + } } diff --git a/src/types/mealPlan.d.ts b/src/types/mealPlan.d.ts index 913ed61..7526ced 100644 --- a/src/types/mealPlan.d.ts +++ b/src/types/mealPlan.d.ts @@ -36,6 +36,15 @@ export interface IMealEventAddInput { mealType: string; }; } +export interface IMealEventEditInput { + input: { + _id: IObjectId; + startTime: Date; + endTime: Date; + recipes: [IObjectId]; + mealType: string; + }; +} export interface IWorkoutEventAddInput { input: { @@ -43,3 +52,12 @@ export interface IWorkoutEventAddInput { endTime: Date; }; } + + +export interface IWorkoutEventEditInput { + input: { + _id: IObjectId; + startTime: Date; + endTime: Date; + }; +} \ No newline at end of file From 534b68f60c6931d722053d5cf4f332651db0b38b Mon Sep 17 00:00:00 2001 From: Davide Crestini Date: Tue, 9 Jul 2019 17:15:59 +0100 Subject: [PATCH 3/9] added handler and tests for event deletion --- package.json | 1 + .../mealplan/__test__/mealplan.spec.ts | 53 +++++++++++++++++-- src/context/mealplan/index.ts | 2 + src/context/mealplan/services/index.ts | 22 +++++--- yarn.lock | 7 +++ 5 files changed, 72 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index 0bd71e0..87bb229 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "apollo-tracing": "^0.4.0", "bcrypt-nodejs": "^0.0.3", "body-parser": "^1.15.0", + "chai-as-promised": "^7.1.1", "chai-datetime": "^1.5.0", "compression": "^1.7.3", "cors": "^2.8.1", diff --git a/src/context/mealplan/__test__/mealplan.spec.ts b/src/context/mealplan/__test__/mealplan.spec.ts index fa45e6b..8a52f23 100644 --- a/src/context/mealplan/__test__/mealplan.spec.ts +++ b/src/context/mealplan/__test__/mealplan.spec.ts @@ -1,8 +1,7 @@ import chai, { expect } from 'chai'; import chaiDatetime from 'chai-datetime'; import 'mocha'; -import moment from 'moment'; -import mongoose from 'mongoose'; + import { IContext } from 'types/global'; import { IMealEventAddInput, @@ -21,9 +20,8 @@ import MealPlanContext from '../index'; chai.use(chaiDatetime); describe('Meal Plan Context', () => { - const user1 = fakeAccount({ - // _id: new mongoose.mongo.ObjectID('5d1c935b0a13de0022030159'), - }); + const user1 = fakeAccount({}); + const user2 = fakeAccount({}); const recipe1 = fakeRecipe({ createdBy: user1._id }); const recipe2 = fakeRecipe({ createdBy: user1._id }); @@ -49,6 +47,12 @@ describe('Meal Plan Context', () => { startTime: new Date('2019-08-28T13:30:00'), }); + const mealEvent5 = fakeMealEvent({ + endTime: new Date('2019-09-28T15:30:00'), + owner: user2._id, + startTime: new Date('2019-08-28T13:30:00'), + }); + const workoutEvent1 = fakeWorkoutEvent({ endTime: new Date('2019-08-28T15:30:00'), owner: user1._id, @@ -64,12 +68,14 @@ describe('Meal Plan Context', () => { before(async () => { try { await user1.save(); + await user2.save(); await recipe1.save(); await recipe2.save(); await mealEvent1.save(); await mealEvent2.save(); await mealEvent3.save(); await mealEvent4.save(); + await mealEvent5.save(); await workoutEvent1.save(); await workoutEvent2.save(); } catch (e) { @@ -175,4 +181,41 @@ describe('Meal Plan Context', () => { .to.equalDate(new Date('2019-08-28T13:30:00')); expect(result).to.have.property('type', 'WorkoutEvent'); }); + + it('should delete an event', async () => { + const ctx: IContext = { + user: { + _id: user1._id, + email: user1.email, + firstName: user1.firstName, + lastName: user1.lastName, + }, + }; + + await MealPlanContext.deleteEvent(mealEvent1._id, ctx); + + const expected = await MealPlanContext.findBy( + mealEvent1._id.toString(), + '_id' + ); + + expect(expected).to.be.a('null'); + }); + + it.only('should throw an error when deleting, if the user is not the owner', async () => { + const ctx: IContext = { + user: { + _id: user1._id, + email: user1.email, + firstName: user1.firstName, + lastName: user1.lastName, + }, + }; + + try { + await MealPlanContext.deleteEvent(mealEvent5._id, ctx); + } catch (error) { + expect(error).to.be.an('error'); + } + }); }); diff --git a/src/context/mealplan/index.ts b/src/context/mealplan/index.ts index bcdb293..6691645 100644 --- a/src/context/mealplan/index.ts +++ b/src/context/mealplan/index.ts @@ -32,6 +32,8 @@ export default { data: IWorkoutEventEditInput, ctx: IContext ): Promise => mealPlanService.editWorkoutEvent(data, ctx), + findBy: (field: string, fieldName: string) => + mealPlanService.findBy(field, fieldName), findWithinRange: ( data: IMealPlanRangeInput, ctx: IContext diff --git a/src/context/mealplan/services/index.ts b/src/context/mealplan/services/index.ts index 130dd9c..f329a17 100644 --- a/src/context/mealplan/services/index.ts +++ b/src/context/mealplan/services/index.ts @@ -67,7 +67,7 @@ export default class MealPlanService { const creator = await this.accountContext.findBy(ctx.user._id, '_id'); if (!creator) { - throw new AuthenticationError('Provided user does not exist '); + throw new AuthenticationError('Provided user does not exist'); } return this.mealPlanEventRepo.createMealEvent(data, creator); @@ -77,13 +77,13 @@ export default class MealPlanService { data: IMealEventEditInput, ctx: IContext ): Promise { - const event = await this.mealPlanEventRepo.findBy({ + const event = await this.mealPlanEventRepo.findOneBy({ _id: data.input._id, owner: ctx.user._id, }); if (!event) { - throw new Error('Provided evenet does not exist '); + throw new Error('Provided evenet does not exist'); } return event; @@ -96,7 +96,7 @@ export default class MealPlanService { const creator = await this.accountContext.findBy(ctx.user._id, '_id'); if (!creator) { - throw new AuthenticationError('Provided user does not exist '); + throw new AuthenticationError('Provided user does not exist'); } const created = await this.mealPlanEventRepo.createWorkoutEvent( @@ -111,7 +111,7 @@ export default class MealPlanService { data: IWorkoutEventEditInput, ctx: IContext ): Promise { - const event = await this.mealPlanEventRepo.findBy({ + const event = await this.mealPlanEventRepo.findOneBy({ _id: data.input._id, owner: ctx.user._id, }); @@ -124,15 +124,21 @@ export default class MealPlanService { } public async deleteEvent(id: IObjectId, ctx: IContext): Promise { - const event = await this.mealPlanEventRepo.findBy({ + const event = await this.mealPlanEventRepo.findOneBy({ _id: id, owner: ctx.user._id, }); if (!event) { - throw new Error('Provided event does not exist '); + throw new Error('Provided event does not exist'); } - return event; + await this.mealPlanEventRepo.hardDelete({ _id: id }); + + return true; + } + + public async findBy(field: string, fieldName: string) { + return this.mealPlanEventRepo.findOneBy({ [fieldName]: field }); } } diff --git a/yarn.lock b/yarn.lock index 2d7227c..fad16cf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -984,6 +984,13 @@ caseless@~0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" +chai-as-promised@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-7.1.1.tgz#08645d825deb8696ee61725dbf590c012eb00ca0" + integrity sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA== + dependencies: + check-error "^1.0.2" + chai-datetime@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/chai-datetime/-/chai-datetime-1.5.0.tgz#3742f18b024c75b76a2b7eee291662324467596c" From ae3f6266c72e7f8f17b1379fe23efd52f995d638 Mon Sep 17 00:00:00 2001 From: Davide Crestini Date: Wed, 10 Jul 2019 09:22:20 +0100 Subject: [PATCH 4/9] added edit workout handler --- .../mealplan/__test__/mealplan.spec.ts | 60 ++++++++++++++++++- src/context/mealplan/repo/index.ts | 16 ++++- src/context/mealplan/schema/index.ts | 1 - src/context/mealplan/services/index.ts | 2 +- 4 files changed, 75 insertions(+), 4 deletions(-) diff --git a/src/context/mealplan/__test__/mealplan.spec.ts b/src/context/mealplan/__test__/mealplan.spec.ts index 8a52f23..5b99f67 100644 --- a/src/context/mealplan/__test__/mealplan.spec.ts +++ b/src/context/mealplan/__test__/mealplan.spec.ts @@ -5,8 +5,10 @@ import 'mocha'; import { IContext } from 'types/global'; import { IMealEventAddInput, + IMealEventEditInput, IMealPlanRangeInput, IWorkoutEventAddInput, + IWorkoutEventEditInput, } from 'types/mealPlan'; import '../../../../tests'; import { fakeAccount } from '../../../../tests/stub/account'; @@ -182,6 +184,62 @@ describe('Meal Plan Context', () => { expect(result).to.have.property('type', 'WorkoutEvent'); }); + it.only('should edit a workout WorkoutEvent', async () => { + const data: IWorkoutEventEditInput = { + input: { + _id: workoutEvent1._id, + endTime: new Date('2019-11-28T15:30:00'), + startTime: new Date('2019-11-28T14:30:00'), + }, + }; + + const ctx: IContext = { + user: { + _id: user1._id, + email: user1.email, + firstName: user1.firstName, + lastName: user1.lastName, + }, + }; + + const result = await MealPlanContext.editWorkoutEvent(data, ctx); + + expect(result).to.have.property('_id'); + expect(result).to.have.property('owner'); + expect(result) + .to.have.property('startTime') + .to.equalDate(new Date('2019-11-28T14:30:00')); + expect(result) + .to.have.property('endTime') + .to.equalDate(new Date('2019-11-28T15:30:00')); + expect(result).to.have.property('type', 'WorkoutEvent'); + }); + + it('should reject editing a WorkoutEvent if the owner is not correct', async () => { + const data: IWorkoutEventEditInput = { + input: { + _id: workoutEvent2._id, + endTime: new Date('2019-08-28T13:30:00'), + startTime: new Date('2019-08-28T12:30:00'), + }, + }; + + const ctx: IContext = { + user: { + _id: user2._id, + email: user2.email, + firstName: user2.firstName, + lastName: user2.lastName, + }, + }; + + try { + await MealPlanContext.editWorkoutEvent(data, ctx); + } catch (error) { + expect(error).to.be.an('error'); + } + }); + it('should delete an event', async () => { const ctx: IContext = { user: { @@ -202,7 +260,7 @@ describe('Meal Plan Context', () => { expect(expected).to.be.a('null'); }); - it.only('should throw an error when deleting, if the user is not the owner', async () => { + it('should throw an error when deleting, if the user is not the owner', async () => { const ctx: IContext = { user: { _id: user1._id, diff --git a/src/context/mealplan/repo/index.ts b/src/context/mealplan/repo/index.ts index 805596f..44798c9 100644 --- a/src/context/mealplan/repo/index.ts +++ b/src/context/mealplan/repo/index.ts @@ -1,7 +1,6 @@ import Repository from '@lib/Repository'; import moment from 'moment'; import { IAccount } from 'types/account'; -import { ITimezonedDate } from 'types/global'; import { IMealEvent, @@ -9,6 +8,7 @@ import { IMealPlanEvent, IWorkoutEvent, IWorkoutEventAddInput, + IWorkoutEventEditInput, } from 'types/mealPlan'; import { MealPlanEvent } from '../schema'; import { MealEvent } from '../schema/MealEvent'; @@ -50,4 +50,18 @@ export default class IMealPlanEventRepo extends Repository { const recipe = new WorkoutEvent(workoutEventData); return recipe.save(); } + + public async editWorkoutEvent( + data: IWorkoutEventEditInput + ): Promise { + const query = { _id: data.input._id }; + const set = { + endTime: data.input.endTime, + startTime: data.input.startTime, + timezoneOffset: data.input.startTime.getTimezoneOffset(), + }; + + const upda = await this.findOneAndUpdate(query, set); + return upda; + } } diff --git a/src/context/mealplan/schema/index.ts b/src/context/mealplan/schema/index.ts index ac893cc..d8be557 100644 --- a/src/context/mealplan/schema/index.ts +++ b/src/context/mealplan/schema/index.ts @@ -1,5 +1,4 @@ import _ from 'lodash'; -import moment from 'moment'; import mongoose, { Model } from 'mongoose'; import { IMealPlanEvent } from 'types/mealPlan'; diff --git a/src/context/mealplan/services/index.ts b/src/context/mealplan/services/index.ts index f329a17..1050943 100644 --- a/src/context/mealplan/services/index.ts +++ b/src/context/mealplan/services/index.ts @@ -120,7 +120,7 @@ export default class MealPlanService { throw new Error('Provided event does not exist'); } - return event; + return this.mealPlanEventRepo.editWorkoutEvent(data); } public async deleteEvent(id: IObjectId, ctx: IContext): Promise { From 29523d527190d45ddfc8a0785f7cfd1fca46be86 Mon Sep 17 00:00:00 2001 From: Davide Crestini Date: Wed, 10 Jul 2019 09:51:29 +0100 Subject: [PATCH 5/9] added meal event edit --- .../mealplan/__test__/mealplan.spec.ts | 315 +++++++++++------- src/context/mealplan/repo/MealEventRepo.ts | 45 +++ src/context/mealplan/repo/WorkoutEventRepo.ts | 42 +++ src/context/mealplan/repo/index.ts | 49 +-- src/context/mealplan/schema/MealEvent.ts | 2 +- src/context/mealplan/services/index.ts | 24 +- 6 files changed, 298 insertions(+), 179 deletions(-) create mode 100644 src/context/mealplan/repo/MealEventRepo.ts create mode 100644 src/context/mealplan/repo/WorkoutEventRepo.ts diff --git a/src/context/mealplan/__test__/mealplan.spec.ts b/src/context/mealplan/__test__/mealplan.spec.ts index 5b99f67..f6e67a9 100644 --- a/src/context/mealplan/__test__/mealplan.spec.ts +++ b/src/context/mealplan/__test__/mealplan.spec.ts @@ -2,7 +2,7 @@ import chai, { expect } from 'chai'; import chaiDatetime from 'chai-datetime'; import 'mocha'; -import { IContext } from 'types/global'; +import { IContext, IObjectId } from 'types/global'; import { IMealEventAddInput, IMealEventEditInput, @@ -118,126 +118,203 @@ describe('Meal Plan Context', () => { expect(eventIds).to.not.include(workoutEvent2._id.toString()); }); - it('should create a new MealEvent', async () => { - const data: IMealEventAddInput = { - input: { - endTime: new Date('2019-08-28T13:30:00'), - mealType: 'mt-1', - recipes: [recipe1._id], - startTime: new Date('2019-08-28T12:30:00'), - }, - }; - - const ctx: IContext = { - user: { - _id: user1._id, - email: user1.email, - firstName: user1.firstName, - lastName: user1.lastName, - }, - }; - - const result = await MealPlanContext.addMealEvent(data, ctx); - - expect(result).to.have.property('_id'); - expect(result).to.have.property('owner'); - expect(result) - .to.have.property('startTime') - .to.equalDate(new Date('2019-08-28T12:30:00')); - expect(result) - .to.have.property('endTime') - .to.equalDate(new Date('2019-08-28T13:30:00')); - expect(result).to.have.property('mealType', 'mt-1'); - expect(result).to.have.property('type', 'MealEvent'); - expect(result.recipes) - .to.be.an('array') - .that.include(recipe1._id); - }); - - it('should create a new WorkoutEvent', async () => { - const data: IWorkoutEventAddInput = { - input: { - endTime: new Date('2019-08-28T13:30:00'), - startTime: new Date('2019-08-28T12:30:00'), - }, - }; - - const ctx: IContext = { - user: { - _id: user1._id, - email: user1.email, - firstName: user1.firstName, - lastName: user1.lastName, - }, - }; - - const result = await MealPlanContext.addWorkoutEvent(data, ctx); - - expect(result).to.have.property('_id'); - expect(result).to.have.property('owner'); - expect(result) - .to.have.property('startTime') - .to.equalDate(new Date('2019-08-28T12:30:00')); - expect(result) - .to.have.property('endTime') - .to.equalDate(new Date('2019-08-28T13:30:00')); - expect(result).to.have.property('type', 'WorkoutEvent'); + describe('Meal Event', () => { + it('should create a new MealEvent', async () => { + const data: IMealEventAddInput = { + input: { + endTime: new Date('2019-08-28T13:30:00'), + mealType: 'mt-1', + recipes: [recipe1._id], + startTime: new Date('2019-08-28T12:30:00'), + }, + }; + + const ctx: IContext = { + user: { + _id: user1._id, + email: user1.email, + firstName: user1.firstName, + lastName: user1.lastName, + }, + }; + + const result = await MealPlanContext.addMealEvent(data, ctx); + + expect(result).to.have.property('_id'); + expect(result).to.have.property('owner'); + expect(result) + .to.have.property('startTime') + .to.equalDate(new Date('2019-08-28T12:30:00')); + expect(result) + .to.have.property('endTime') + .to.equalDate(new Date('2019-08-28T13:30:00')); + expect(result).to.have.property('mealType', 'mt-1'); + expect(result).to.have.property('type', 'MealEvent'); + expect(result.recipes) + .to.be.an('array') + .that.include(recipe1._id); + }); + + it('should edit a MealEvent', async () => { + const data: IMealEventEditInput = { + input: { + _id: mealEvent4._id, + endTime: new Date('2019-11-28T15:30:00'), + mealType: 'mt-2', + recipes: [recipe2._id], + startTime: new Date('2019-11-28T14:30:00'), + }, + }; + + const ctx: IContext = { + user: { + _id: user1._id, + email: user1.email, + firstName: user1.firstName, + lastName: user1.lastName, + }, + }; + + const result = await MealPlanContext.editMealEvent(data, ctx); + + expect(result).to.have.property('_id'); + expect(result).to.have.property('owner'); + expect(result) + .to.have.property('startTime') + .to.equalDate(new Date('2019-11-28T14:30:00')); + expect(result) + .to.have.property('endTime') + .to.equalDate(new Date('2019-11-28T15:30:00')); + expect(result).to.have.property('mealType', 'mt-2'); + expect(result).to.have.property('type', 'MealEvent'); + + expect(result.recipes).to.be.an('array'); + + const recipes = result.recipes.map((id: IObjectId) => id.toString()); + expect(recipes) + .to.be.an('array') + .that.include(recipe2._id.toString()); + + // Ensure recipe 1 is removed + expect(recipes) + .to.be.an('array') + .that.not.include(recipe1._id.toString()); + }); + + it('should reject editing a MealEvent if the owner is not correct', async () => { + const data: IMealEventEditInput = { + input: { + _id: mealEvent2._id, + endTime: new Date('2019-11-28T15:30:00'), + mealType: 'mt-2', + recipes: [recipe2._id], + startTime: new Date('2019-11-28T14:30:00'), + }, + }; + + const ctx: IContext = { + user: { + _id: user2._id, + email: user2.email, + firstName: user2.firstName, + lastName: user2.lastName, + }, + }; + + try { + await MealPlanContext.editMealEvent(data, ctx); + } catch (error) { + expect(error).to.be.an('error'); + } + }); }); - it.only('should edit a workout WorkoutEvent', async () => { - const data: IWorkoutEventEditInput = { - input: { - _id: workoutEvent1._id, - endTime: new Date('2019-11-28T15:30:00'), - startTime: new Date('2019-11-28T14:30:00'), - }, - }; - - const ctx: IContext = { - user: { - _id: user1._id, - email: user1.email, - firstName: user1.firstName, - lastName: user1.lastName, - }, - }; - - const result = await MealPlanContext.editWorkoutEvent(data, ctx); - - expect(result).to.have.property('_id'); - expect(result).to.have.property('owner'); - expect(result) - .to.have.property('startTime') - .to.equalDate(new Date('2019-11-28T14:30:00')); - expect(result) - .to.have.property('endTime') - .to.equalDate(new Date('2019-11-28T15:30:00')); - expect(result).to.have.property('type', 'WorkoutEvent'); - }); - - it('should reject editing a WorkoutEvent if the owner is not correct', async () => { - const data: IWorkoutEventEditInput = { - input: { - _id: workoutEvent2._id, - endTime: new Date('2019-08-28T13:30:00'), - startTime: new Date('2019-08-28T12:30:00'), - }, - }; - - const ctx: IContext = { - user: { - _id: user2._id, - email: user2.email, - firstName: user2.firstName, - lastName: user2.lastName, - }, - }; - - try { - await MealPlanContext.editWorkoutEvent(data, ctx); - } catch (error) { - expect(error).to.be.an('error'); - } + describe('Workout Event', () => { + it('should create a new WorkoutEvent', async () => { + const data: IWorkoutEventAddInput = { + input: { + endTime: new Date('2019-08-28T13:30:00'), + startTime: new Date('2019-08-28T12:30:00'), + }, + }; + + const ctx: IContext = { + user: { + _id: user1._id, + email: user1.email, + firstName: user1.firstName, + lastName: user1.lastName, + }, + }; + + const result = await MealPlanContext.addWorkoutEvent(data, ctx); + + expect(result).to.have.property('_id'); + expect(result).to.have.property('owner'); + expect(result) + .to.have.property('startTime') + .to.equalDate(new Date('2019-08-28T12:30:00')); + expect(result) + .to.have.property('endTime') + .to.equalDate(new Date('2019-08-28T13:30:00')); + expect(result).to.have.property('type', 'WorkoutEvent'); + }); + + it('should edit a WorkoutEvent', async () => { + const data: IWorkoutEventEditInput = { + input: { + _id: workoutEvent1._id, + endTime: new Date('2019-11-28T15:30:00'), + startTime: new Date('2019-11-28T14:30:00'), + }, + }; + + const ctx: IContext = { + user: { + _id: user1._id, + email: user1.email, + firstName: user1.firstName, + lastName: user1.lastName, + }, + }; + + const result = await MealPlanContext.editWorkoutEvent(data, ctx); + + expect(result).to.have.property('_id'); + expect(result).to.have.property('owner'); + expect(result) + .to.have.property('startTime') + .to.equalDate(new Date('2019-11-28T14:30:00')); + expect(result) + .to.have.property('endTime') + .to.equalDate(new Date('2019-11-28T15:30:00')); + expect(result).to.have.property('type', 'WorkoutEvent'); + }); + + it('should reject editing a WorkoutEvent if the owner is not correct', async () => { + const data: IWorkoutEventEditInput = { + input: { + _id: workoutEvent2._id, + endTime: new Date('2019-08-28T13:30:00'), + startTime: new Date('2019-08-28T12:30:00'), + }, + }; + + const ctx: IContext = { + user: { + _id: user2._id, + email: user2.email, + firstName: user2.firstName, + lastName: user2.lastName, + }, + }; + + try { + await MealPlanContext.editWorkoutEvent(data, ctx); + } catch (error) { + expect(error).to.be.an('error'); + } + }); }); it('should delete an event', async () => { diff --git a/src/context/mealplan/repo/MealEventRepo.ts b/src/context/mealplan/repo/MealEventRepo.ts new file mode 100644 index 0000000..0ac44b3 --- /dev/null +++ b/src/context/mealplan/repo/MealEventRepo.ts @@ -0,0 +1,45 @@ +import Repository from '@lib/Repository'; +import { IAccount } from 'types/account'; + +import { + IMealEvent, + IMealEventAddInput, + IMealEventEditInput, +} from 'types/mealPlan'; +import { MealEvent } from '../schema/MealEvent'; + +export default class IMealEventRepo extends Repository { + constructor() { + super(MealEvent); + } + + public async create( + data: IMealEventAddInput, + user: IAccount + ): Promise { + const mealEventData = { + endTime: data.input.endTime, + mealType: data.input.mealType, + owner: user._id, + recipes: data.input.recipes, + startTime: data.input.startTime, + timezoneOffset: data.input.startTime.getTimezoneOffset(), + }; + + const mealEvent = new MealEvent(mealEventData); + return mealEvent.save(); + } + + public async edit(data: IMealEventEditInput): Promise { + const query = { _id: data.input._id }; + const set = { + endTime: data.input.endTime, + mealType: data.input.mealType, + recipes: data.input.recipes, + startTime: data.input.startTime, + timezoneOffset: data.input.startTime.getTimezoneOffset(), + }; + + return this.findOneAndUpdate(query, set); + } +} diff --git a/src/context/mealplan/repo/WorkoutEventRepo.ts b/src/context/mealplan/repo/WorkoutEventRepo.ts new file mode 100644 index 0000000..fea0579 --- /dev/null +++ b/src/context/mealplan/repo/WorkoutEventRepo.ts @@ -0,0 +1,42 @@ +import Repository from '@lib/Repository'; +import { IAccount } from 'types/account'; + +import { + IWorkoutEvent, + IWorkoutEventAddInput, + IWorkoutEventEditInput, +} from 'types/mealPlan'; +import { MealPlanEvent } from '../schema'; +import { WorkoutEvent } from '../schema/WorkoutEvent'; + +export default class IWorkoutPlanEventRepo extends Repository { + constructor() { + super(MealPlanEvent); + } + + public async create( + data: IWorkoutEventAddInput, + user: IAccount + ): Promise { + const workoutEventData = { + endTime: data.input.endTime, + owner: user._id, + startTime: data.input.startTime, + timezoneOffset: data.input.startTime.getTimezoneOffset(), + }; + + const workoutEvent = new WorkoutEvent(workoutEventData); + return workoutEvent.save(); + } + + public async edit(data: IWorkoutEventEditInput): Promise { + const query = { _id: data.input._id }; + const set = { + endTime: data.input.endTime, + startTime: data.input.startTime, + timezoneOffset: data.input.startTime.getTimezoneOffset(), + }; + + return this.findOneAndUpdate(query, set); + } +} diff --git a/src/context/mealplan/repo/index.ts b/src/context/mealplan/repo/index.ts index 44798c9..7d6f72d 100644 --- a/src/context/mealplan/repo/index.ts +++ b/src/context/mealplan/repo/index.ts @@ -1,11 +1,10 @@ import Repository from '@lib/Repository'; -import moment from 'moment'; import { IAccount } from 'types/account'; import { IMealEvent, IMealEventAddInput, - IMealPlanEvent, + IMealEventEditInput, IWorkoutEvent, IWorkoutEventAddInput, IWorkoutEventEditInput, @@ -18,50 +17,4 @@ export default class IMealPlanEventRepo extends Repository { constructor() { super(MealPlanEvent); } - - public async createMealEvent( - data: IMealEventAddInput, - user: IAccount - ): Promise { - const mealEventData = { - endTime: data.input.endTime, - mealType: data.input.mealType, - owner: user._id, - recipes: data.input.recipes, - startTime: data.input.startTime, - timezoneOffset: data.input.startTime.getTimezoneOffset(), - }; - - const recipe = new MealEvent(mealEventData); - return recipe.save(); - } - - public async createWorkoutEvent( - data: IWorkoutEventAddInput, - user: IAccount - ): Promise { - const workoutEventData = { - endTime: data.input.endTime, - owner: user._id, - startTime: data.input.startTime, - timezoneOffset: data.input.startTime.getTimezoneOffset(), - }; - - const recipe = new WorkoutEvent(workoutEventData); - return recipe.save(); - } - - public async editWorkoutEvent( - data: IWorkoutEventEditInput - ): Promise { - const query = { _id: data.input._id }; - const set = { - endTime: data.input.endTime, - startTime: data.input.startTime, - timezoneOffset: data.input.startTime.getTimezoneOffset(), - }; - - const upda = await this.findOneAndUpdate(query, set); - return upda; - } } diff --git a/src/context/mealplan/schema/MealEvent.ts b/src/context/mealplan/schema/MealEvent.ts index b627183..475813b 100644 --- a/src/context/mealplan/schema/MealEvent.ts +++ b/src/context/mealplan/schema/MealEvent.ts @@ -5,7 +5,7 @@ import { MealPlanEvent } from './index'; const MealEventSchema = new mongoose.Schema({ mealType: String, // ('Breakfast', 'Snack', 'Dinner'...) --- Use codes so it cna potentially be translated - recipes: [], // @TODO This needs to contain, name, id, picture and slug of recipe + recipes: [], }); export const MealEvent: Model = MealPlanEvent.discriminator( diff --git a/src/context/mealplan/services/index.ts b/src/context/mealplan/services/index.ts index 1050943..e3b4d78 100644 --- a/src/context/mealplan/services/index.ts +++ b/src/context/mealplan/services/index.ts @@ -1,6 +1,5 @@ import AccountContext, { IAccountContext } from '@context/account'; import { AuthenticationError } from 'apollo-server'; -import moment from 'moment'; import { IContext, IObjectId } from 'types/global'; import { IMealEvent, @@ -13,13 +12,19 @@ import { IWorkoutEventEditInput, } from 'types/mealPlan'; import MealPlanRepo from '../repo'; +import MealEventRepo from '../repo/MealEventRepo'; +import WorkoutEventRepo from '../repo/WorkoutEventRepo'; export default class MealPlanService { public mealPlanEventRepo: MealPlanRepo; + public mealEventRepo: MealEventRepo; + public workoutEventRepo: WorkoutEventRepo; public accountContext: IAccountContext; constructor() { this.mealPlanEventRepo = new MealPlanRepo(); + this.mealEventRepo = new MealEventRepo(); + this.workoutEventRepo = new WorkoutEventRepo(); this.accountContext = AccountContext; } @@ -70,23 +75,23 @@ export default class MealPlanService { throw new AuthenticationError('Provided user does not exist'); } - return this.mealPlanEventRepo.createMealEvent(data, creator); + return this.mealEventRepo.create(data, creator); } public async editMealEvent( data: IMealEventEditInput, ctx: IContext ): Promise { - const event = await this.mealPlanEventRepo.findOneBy({ + const event = await this.mealEventRepo.findOneBy({ _id: data.input._id, owner: ctx.user._id, }); if (!event) { - throw new Error('Provided evenet does not exist'); + throw new Error('Provided event does not exist'); } - return event; + return this.mealEventRepo.edit(data); } public async addWorkoutEvent( @@ -99,10 +104,7 @@ export default class MealPlanService { throw new AuthenticationError('Provided user does not exist'); } - const created = await this.mealPlanEventRepo.createWorkoutEvent( - data, - creator - ); + const created = await this.workoutEventRepo.create(data, creator); return created; } @@ -111,7 +113,7 @@ export default class MealPlanService { data: IWorkoutEventEditInput, ctx: IContext ): Promise { - const event = await this.mealPlanEventRepo.findOneBy({ + const event = await this.workoutEventRepo.findOneBy({ _id: data.input._id, owner: ctx.user._id, }); @@ -120,7 +122,7 @@ export default class MealPlanService { throw new Error('Provided event does not exist'); } - return this.mealPlanEventRepo.editWorkoutEvent(data); + return this.workoutEventRepo.edit(data); } public async deleteEvent(id: IObjectId, ctx: IContext): Promise { From 90a109f95c83d34b61337077894dd301ce85bc5f Mon Sep 17 00:00:00 2001 From: Davide Crestini Date: Thu, 11 Jul 2019 16:38:09 +0100 Subject: [PATCH 6/9] fixed issue with event deleting in graphql definition --- src/apollo/resolvers/mealPlan.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/apollo/resolvers/mealPlan.ts b/src/apollo/resolvers/mealPlan.ts index 17806a3..6ae878b 100644 --- a/src/apollo/resolvers/mealPlan.ts +++ b/src/apollo/resolvers/mealPlan.ts @@ -49,7 +49,7 @@ export default { ): Promise => MealPlan.addWorkoutEvent(data, ctx), deleteEvent: async ( _: object, - id: IObjectId, + { id }: { id: IObjectId }, ctx: IContext ): Promise => MealPlan.deleteEvent(id, ctx), editMealEvent: async ( From 993316cfe67dca71cc2fa8c7c44f0da9c26abe9a Mon Sep 17 00:00:00 2001 From: Davide Date: Sun, 14 Jul 2019 11:46:16 +0100 Subject: [PATCH 7/9] small fixes --- src/context/mealplan/services/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/context/mealplan/services/index.ts b/src/context/mealplan/services/index.ts index e3b4d78..806b42a 100644 --- a/src/context/mealplan/services/index.ts +++ b/src/context/mealplan/services/index.ts @@ -33,7 +33,7 @@ export default class MealPlanService { ctx: IContext ): Promise<[IMealEvent | IWorkoutEvent]> { const { startDay, endDay } = range.input; - + console.log(startDay); const startRange = new Date( startDay.getFullYear(), startDay.getMonth(), From 4b65c234cd578b3d14958d6ed9e2de9209e34772 Mon Sep 17 00:00:00 2001 From: Davide Date: Wed, 17 Jul 2019 10:53:45 +0100 Subject: [PATCH 8/9] fixes --- src/context/auth/index.ts | 1 - src/context/mealplan/services/index.ts | 2 +- src/lib/mailer/index.ts | 5 +++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/context/auth/index.ts b/src/context/auth/index.ts index 60c25b4..1a20494 100644 --- a/src/context/auth/index.ts +++ b/src/context/auth/index.ts @@ -22,7 +22,6 @@ export default class Auth { } public async signup(data: ISignupInput): Promise { - console.log('Here', data); const doesAccountExist = await AccountContext.emailExists(data.input.email); if (doesAccountExist) { diff --git a/src/context/mealplan/services/index.ts b/src/context/mealplan/services/index.ts index 806b42a..e3b4d78 100644 --- a/src/context/mealplan/services/index.ts +++ b/src/context/mealplan/services/index.ts @@ -33,7 +33,7 @@ export default class MealPlanService { ctx: IContext ): Promise<[IMealEvent | IWorkoutEvent]> { const { startDay, endDay } = range.input; - console.log(startDay); + const startRange = new Date( startDay.getFullYear(), startDay.getMonth(), diff --git a/src/lib/mailer/index.ts b/src/lib/mailer/index.ts index 6cfbe02..fa15b4e 100644 --- a/src/lib/mailer/index.ts +++ b/src/lib/mailer/index.ts @@ -18,6 +18,7 @@ interface IOptions { export default class Mailer { public options: IOptions; public sender: string; + public name: string; constructor() { this.options = { @@ -28,6 +29,7 @@ export default class Mailer { method: 'POST', url: 'https://api.sendinblue.com/v3/smtp/email', }; + this.name = 'Healfit Team'; this.sender = config('sendInBlue.sender'); } @@ -54,7 +56,7 @@ export default class Mailer { NAME: params.name, RESET_PASSWORD_LINK: params.resetPasswordLink, }, - templateId: 5, + templateId: 6, }; default: throw new Error('Email type does not exists!'); @@ -81,7 +83,6 @@ export default class Mailer { if (error) { throw new Error(error); } - console.log('EMAIL'); }); } } From badee3a5b7ad6c20df5a838deebdec972b0e930c Mon Sep 17 00:00:00 2001 From: Davide Crestini Date: Fri, 2 Aug 2019 12:01:15 +0100 Subject: [PATCH 9/9] added migration for createdby attribute on recipe --- src/apollo/resolvers/mealPlan.ts | 3 +++ src/apollo/types/mealPlan.gql | 10 +++++++++- src/apollo/types/recipe.gql | 2 +- src/context/mealplan/index.ts | 3 +++ src/context/mealplan/services/index.ts | 21 +++++++++++++++++++++ src/context/recipe/index.ts | 14 ++++++++++++++ src/migrations/versions/20190606142523.ts | 4 ++-- src/migrations/versions/20190802103600.ts | 21 +++++++++++++++++++++ src/types/mealPlan.d.ts | 9 ++++++++- 9 files changed, 82 insertions(+), 5 deletions(-) create mode 100644 src/migrations/versions/20190802103600.ts diff --git a/src/apollo/resolvers/mealPlan.ts b/src/apollo/resolvers/mealPlan.ts index 6ae878b..df12c95 100644 --- a/src/apollo/resolvers/mealPlan.ts +++ b/src/apollo/resolvers/mealPlan.ts @@ -6,6 +6,7 @@ import { IMealEvent, IMealEventAddInput, IMealEventEditInput, + IMealMacro, IMealPlanRangeInput, IWorkoutEvent, IWorkoutEventAddInput, @@ -18,6 +19,8 @@ import { IAccount } from 'types/account'; export default { MealEvent: { + macros: async (mealEvent: { _id: IObjectId }): Promise => + MealPlan.getMealMacros(mealEvent._id), recipes: async (mealEvent: { recipes: IObjectId[] }): Promise => Recipe.findByIds(mealEvent.recipes), }, diff --git a/src/apollo/types/mealPlan.gql b/src/apollo/types/mealPlan.gql index b09f079..e185351 100644 --- a/src/apollo/types/mealPlan.gql +++ b/src/apollo/types/mealPlan.gql @@ -5,6 +5,13 @@ interface MealPlanEvent { owner: Account } +type MealMacros { + carbs: Float + protein: Float + fat: Float + calories: Float +} + type MealEvent implements MealPlanEvent { _id: ID startTime: Date @@ -12,6 +19,7 @@ type MealEvent implements MealPlanEvent { owner: Account mealType: String recipes: [Recipe] + macros: MealMacros } type WorkoutEvent implements MealPlanEvent { @@ -69,4 +77,4 @@ type Mutation { @auth(role: USER) editWorkoutEvent(input: WorkoutEventEditInput!): WorkoutEvent @auth(role: USER) -} \ No newline at end of file +} diff --git a/src/apollo/types/recipe.gql b/src/apollo/types/recipe.gql index dac7e2a..6aa76fc 100644 --- a/src/apollo/types/recipe.gql +++ b/src/apollo/types/recipe.gql @@ -52,7 +52,7 @@ type Recipe { # INPUT input RecipeLevelInput { - _id: String + id: String name: String } diff --git a/src/context/mealplan/index.ts b/src/context/mealplan/index.ts index 6691645..f9de011 100644 --- a/src/context/mealplan/index.ts +++ b/src/context/mealplan/index.ts @@ -3,6 +3,7 @@ import { IMealEvent, IMealEventAddInput, IMealEventEditInput, + IMealMacro, IMealPlanEvent, IMealPlanRangeInput, IWorkoutEvent, @@ -39,4 +40,6 @@ export default { ctx: IContext ): Promise> => mealPlanService.findWithinRange(data, ctx), + getMealMacros: (mealId: IObjectId): Promise => + mealPlanService.getMealMacros(mealId), }; diff --git a/src/context/mealplan/services/index.ts b/src/context/mealplan/services/index.ts index e3b4d78..fe00ee4 100644 --- a/src/context/mealplan/services/index.ts +++ b/src/context/mealplan/services/index.ts @@ -1,10 +1,12 @@ import AccountContext, { IAccountContext } from '@context/account'; +import RecipeContext, { IRecipeContext } from '@context/recipe'; import { AuthenticationError } from 'apollo-server'; import { IContext, IObjectId } from 'types/global'; import { IMealEvent, IMealEventAddInput, IMealEventEditInput, + IMealMacro, IMealPlanEvent, IMealPlanRangeInput, IWorkoutEvent, @@ -20,12 +22,14 @@ export default class MealPlanService { public mealEventRepo: MealEventRepo; public workoutEventRepo: WorkoutEventRepo; public accountContext: IAccountContext; + public recipeContext: IRecipeContext; constructor() { this.mealPlanEventRepo = new MealPlanRepo(); this.mealEventRepo = new MealEventRepo(); this.workoutEventRepo = new WorkoutEventRepo(); this.accountContext = AccountContext; + this.recipeContext = RecipeContext; } public async findWithinRange( @@ -143,4 +147,21 @@ export default class MealPlanService { public async findBy(field: string, fieldName: string) { return this.mealPlanEventRepo.findOneBy({ [fieldName]: field }); } + + public async getMealMacros(mealId: IObjectId): Promise { + const event = await this.mealPlanEventRepo.findById(mealId); + const recipes = await this.recipeContext.findByIds(event.recipes); + + const macros: IMealMacro = recipes.reduce( + (acc, recipe) => ({ + calories: acc.calories + recipe.calories, + carbs: acc.carbs + recipe.carbohydrates, + fat: acc.fat + recipe.fat, + protein: acc.protein + recipe.protein, + }), + { calories: 0, carbs: 0, fat: 0, protein: 0 } + ); + + return macros; + } } diff --git a/src/context/recipe/index.ts b/src/context/recipe/index.ts index 516f1ed..8cf2a56 100644 --- a/src/context/recipe/index.ts +++ b/src/context/recipe/index.ts @@ -32,3 +32,17 @@ export default { recipeService.searchByTitle(name), show: (slug: string): Promise => recipeService.show(slug), }; + +export interface IRecipeContext { + create: (data: IRecipeCreateInput, ctx: IContext) => Promise; + delete: (id: IObjectId) => Promise; + edit: (data: IRecipeEditInput, ctx: IContext) => Promise; + findByIds: (ids: IObjectId[]) => Promise; + likeOrDislike: (data: IRecipeLikeInput, ctx: IContext) => Promise; + list: (data: ILimitSkipInput) => Promise; + rate: (data: IRecipeRateInput, ctx: IContext) => Promise; + rating: (recipeId: IObjectId) => Promise; + ratings: (recipeId: IObjectId) => Promise; + searchByTitle: (name: string) => Promise; + show: (slug: string) => Promise; +} diff --git a/src/migrations/versions/20190606142523.ts b/src/migrations/versions/20190606142523.ts index 1769c58..e8893d2 100644 --- a/src/migrations/versions/20190606142523.ts +++ b/src/migrations/versions/20190606142523.ts @@ -1,11 +1,11 @@ -import { Recipe as RecipeModel } from '../../context/recipe/schema'; +import { RecipeSchema } from '../../context/recipe/schema'; export default function Version20190606142523() { return { execute: async () => { // migration - await RecipeModel.collection.dropIndexes(); + await RecipeSchema.collection.dropIndexes(); return true; }, }; diff --git a/src/migrations/versions/20190802103600.ts b/src/migrations/versions/20190802103600.ts new file mode 100644 index 0000000..8b52e13 --- /dev/null +++ b/src/migrations/versions/20190802103600.ts @@ -0,0 +1,21 @@ +import { RecipeSchema } from '../../context/recipe/schema'; + +export default function Version20190802103600() { + return { + execute: async () => { + const recipes = await RecipeSchema.collection.find(); + recipes.forEach(recipe => { + const { createdBy } = recipe; + if (createdBy.hasOwnProperty('name')) { + RecipeSchema.collection.update( + { _id: recipe._id }, + { + $set: { createdBy: createdBy.id }, + } + ); + } + }); + return true; + }, + }; +} diff --git a/src/types/mealPlan.d.ts b/src/types/mealPlan.d.ts index 7526ced..1103e78 100644 --- a/src/types/mealPlan.d.ts +++ b/src/types/mealPlan.d.ts @@ -3,7 +3,7 @@ import { IObjectId } from './global'; export interface IMealPlanEvent extends Document { _id: IObjectId; - type: number; + type: string; start: Date; end: Date; // owner: { _id: false; type: 'ObjectId'; ref: 'account' }; @@ -15,6 +15,13 @@ export interface IWorkoutEvent extends IMealPlanEvent { workoutType: number; } +export interface IMealMacro { + carbs: number; + protein: number; + fat: number; + calories: number; +} + export interface IMealEvent extends IMealPlanEvent { _id: IObjectId; recipes: [];