aboutsummaryrefslogtreecommitdiffstats
path: root/src/internal-server/app/Controllers/Http/RecipeController.js
blob: 1a7595a9d35d5e7e15b9c51c4fc7c61a71ca2bea (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
const Recipe = use('App/Models/Recipe');
const Drive = use('Drive');
const {
  validateAll,
} = use('Validator');
const Env = use('Env');

const fetch = require('node-fetch');
const debug = require('debug')('Ferdi:internalServer:RecipeController');
const { LIVE_FERDI_API } = require('../../../../config');
const { API_VERSION } = require('../../../../environment');

const RECIPES_URL = `${LIVE_FERDI_API}/${API_VERSION}/recipes`;

class RecipeController {
  // List official and custom recipes
  async list({
    response,
  }) {
    const officialRecipes = JSON.parse(await (await fetch(RECIPES_URL)).text());
    const customRecipesArray = (await Recipe.all()).rows;
    const customRecipes = customRecipesArray.map(recipe => ({
      id: recipe.recipeId,
      name: recipe.name,
      ...JSON.parse(recipe.data),
    }));

    const recipes = [
      ...officialRecipes,
      ...customRecipes,
    ];

    return response.send(recipes);
  }

  // Search official and custom recipes
  async search({
    request,
    response,
  }) {
    // Validate user input
    const validation = await validateAll(request.all(), {
      needle: 'required',
    });
    if (validation.fails()) {
      return response.status(401).send({
        message: 'Please provide a needle',
        messages: validation.messages(),
        status: 401,
      });
    }

    const needle = request.input('needle');

    // Get results
    let results;

    if (needle === 'ferdi:custom') {
      const dbResults = (await Recipe.all()).toJSON();
      results = dbResults.map(recipe => ({
        id: recipe.recipeId,
        name: recipe.name,
        ...JSON.parse(recipe.data),
      }));
    } else {
      let remoteResults = [];
      if (Env.get('CONNECT_WITH_FRANZ') == 'true') { // eslint-disable-line eqeqeq
        remoteResults = JSON.parse(await (await fetch(`${RECIPES_URL}/search?needle=${encodeURIComponent(needle)}`)).text());
      }

      debug('remoteResults:', remoteResults);

      const localResultsArray = (await Recipe.query().where('name', 'LIKE', `%${needle}%`).fetch()).toJSON();
      const localResults = localResultsArray.map(recipe => ({
        id: recipe.recipeId,
        name: recipe.name,
        ...JSON.parse(recipe.data),
      }));

      debug('localResults:', localResults);

      results = [
        ...localResults,
        ...remoteResults || [],
      ];
    }

    return response.send(results);
  }

  // Download a recipe
  async download({
    response,
    params,
  }) {
    // Validate user input
    const validation = await validateAll(params, {
      recipe: 'required|accepted',
    });
    if (validation.fails()) {
      return response.status(401).send({
        message: 'Please provide a recipe ID',
        messages: validation.messages(),
        status: 401,
      });
    }

    const service = params.recipe;

    // Check for invalid characters
    if (/\.{1,}/.test(service) || /\/{1,}/.test(service)) {
      return response.send('Invalid recipe name');
    }

    // Check if recipe exists in recipes folder
    if (await Drive.exists(`${service}.tar.gz`)) {
      return response.send(await Drive.get(`${service}.tar.gz`));
    } if (Env.get('CONNECT_WITH_FRANZ') == 'true') { // eslint-disable-line eqeqeq
      return response.redirect(`${RECIPES_URL}/download/${service}`);
    }
    return response.status(400).send({
      message: 'Recipe not found',
      code: 'recipe-not-found',
    });
  }
}

module.exports = RecipeController;