controller.ts 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. import { IMongoService, IDBDocument } from '../mongo';
  2. import { ChainPController } from '../promise-all-middleware';
  3. import PlanDB, { CompletePlanDB, Weekday, Plan, WeeklyPlanner } from './model';
  4. import moment, { Moment } from 'moment';
  5. import { ObjectId } from 'bson';
  6. type Controller<U, T> = (db: IMongoService) => ChainPController<U, T>;
  7. export const getWeekDay = (day: Moment): Weekday => day.format('dddd').toLowerCase() as Weekday;
  8. const validPlan = (mbPlan: any): Promise<Plan> => {
  9. if (mbPlan.date && mbPlan.week && mbPlan.recipe && mbPlan.meal) {
  10. return Promise.resolve({
  11. ...mbPlan,
  12. date: new Date(mbPlan.date),
  13. recipe: new ObjectId(mbPlan.recipe)
  14. } as Plan)
  15. } else {
  16. return Promise.reject('Required fields: day, week, recipe and meal');
  17. }
  18. }
  19. const validateRange: Controller<void, {from: Date, to: Date}> = () => req => () => {
  20. const from = moment(req.params.from),
  21. to = moment(req.params.to);
  22. return from.isValid() && to.isValid() && to.diff(from, 'days') === 6 ?
  23. Promise.resolve({ from: from.toDate(), to: to.toDate()}) :
  24. Promise.reject('Invalid date range');
  25. }
  26. const getPlannerByRange: Controller<{from: Date, to: Date}, WeeklyPlanner> = db => () => ({ from, to }) => {
  27. return db.aggregate<CompletePlanDB>([
  28. {
  29. '$match': {
  30. 'date': {'$gte': from, '$lte': to}
  31. }
  32. }, {
  33. '$lookup': {
  34. 'from': 'recipes',
  35. 'localField': 'recipe',
  36. 'foreignField': '_id',
  37. 'as': 'recipe'
  38. }
  39. }, {
  40. '$unwind': {
  41. 'path': '$recipe'
  42. }
  43. }, {
  44. '$project': {
  45. 'recipe': {
  46. 'author': 0,
  47. 'details': 0,
  48. 'instructions': 0
  49. }
  50. }
  51. }
  52. ]).then(plans => plans.reduce((planner, plan) => {
  53. const date = moment(plan.date);
  54. return {
  55. ...planner,
  56. [getWeekDay(date)]: {
  57. ...planner[getWeekDay(date)],
  58. date: date,
  59. [plan.meal]: plan.recipe
  60. }
  61. };
  62. }, { week: moment(from).isoWeek() } as WeeklyPlanner))
  63. }
  64. const savePlan: Controller<void, PlanDB> = db => req => prevResult => {
  65. const plan = req.body;
  66. return validPlan(plan).then(db.insertOne)
  67. }
  68. type PlannerRequest = {
  69. planner: Plan[],
  70. from: Date,
  71. to: Date
  72. };
  73. const toPlan = (plan: any): Plan => ({
  74. ...plan,
  75. date: new Date(plan.date),
  76. recipe: new ObjectId(plan.recipe),
  77. })
  78. const validatePlanner: Controller<any, PlannerRequest> = () => ({ body }) => async () => {
  79. if (body.planner && Array.isArray(body.planner) && new Date(body.from) && new Date(body.to)) {
  80. const planner: Plan[] = body.planner.map(toPlan);
  81. return Promise.resolve({
  82. planner,
  83. from: new Date(body.from),
  84. to: new Date(body.to)
  85. })
  86. } else {
  87. return Promise.reject('Invalid request: Body must have planner, from and to properties')
  88. }
  89. }
  90. const saveWeekPlanner: Controller<PlannerRequest, IDBDocument<Plan[]>> = db => req => async ({ planner, from , to }) => {
  91. try {
  92. return db.deleteMany({
  93. 'date': {'$gte': new Date(from), '$lte': new Date(to)}
  94. }).then(result => {
  95. return planner.length ? db.insertMany<Plan>(planner) : []
  96. })
  97. } catch(error) {
  98. console.error(error)
  99. return error;
  100. }
  101. }
  102. export {
  103. savePlan,
  104. saveWeekPlanner,
  105. validatePlanner,
  106. validateRange,
  107. getPlannerByRange
  108. }