Skip to content

Commit

Permalink
Add GroupId, remove Axios, validate host, fix error font size
Browse files Browse the repository at this point in the history
- Add `groupId` to fetch meal plans for a specific group
- Remove dependency on axios, use native fetch
- Add valid url check for host
- Fix translation string
- Reduce the font size of error messages
- Disable console output of meal plans
  • Loading branch information
zanix committed Mar 8, 2024
1 parent ea9a334 commit c201c2c
Show file tree
Hide file tree
Showing 7 changed files with 213 additions and 260 deletions.
21 changes: 18 additions & 3 deletions MMM-MealieMenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Module.register("MMM-MealieMenu", {
apiKey: "", // An API key generated from a user profile in Mealie.
username: "", // The username/email for your Mealie account.
password: "", // The password for your for Mealie account.
groupId: "", // Group ID of the meal plan.

// Look and Feel
weekStartsOnMonday: false, // Show Monday as the first day of the week.
Expand Down Expand Up @@ -52,7 +53,7 @@ Module.register("MMM-MealieMenu", {
this.sanitzeConfig();

// Validate host.
if (!this.config.host) {
if (!this.config.host || !this.isValidURL(this.config.host)) {
Log.error(this.translate("ERROR_INVALID", {value: "host"}));
this.error = this.translate("ERROR_NO_HOST");

Expand Down Expand Up @@ -92,7 +93,7 @@ Module.register("MMM-MealieMenu", {
return;
}

this.sendSocketNotification("MEALIE_CREATE_FETCHER", {
this.sendSocketNotification("MEALIE_INIT", {
identifier: this.identifier,
host: this.config.host,
apiKey: this.config.apiKey,
Expand Down Expand Up @@ -170,7 +171,7 @@ Module.register("MMM-MealieMenu", {

this.formattedMenuData = {meals: this.formatMeals(payload.meals)};

Log.info(this.formattedMenuData);
// Log.info(this.formattedMenuData);
this.error = null;
this.updateDom(this.config.animationSpeed);

Expand Down Expand Up @@ -244,6 +245,7 @@ Module.register("MMM-MealieMenu", {
apiKey: this.config.apiKey,
username: this.config.username,
password: this.config.password,
groupId: this.config.groupId,
weekStartsOnMonday: this.config.weekStartsOnMonday
});
},
Expand Down Expand Up @@ -362,5 +364,18 @@ Module.register("MMM-MealieMenu", {
this.config.updateInterval = 1;
Log.warn("updateInterval should be 1 or greater. Setting to 1.");
}
},

/**
* Assert valid URL.
*/
isValidURL (url) {
try {
// eslint-disable-next-line no-new
new URL(url);
return true;
} catch (err) {
return false;
}
}
});
2 changes: 1 addition & 1 deletion MMM-MealieMenu.njk
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

{% if error %}
<div class="light small">{{ error | safe }}</div>
<div class="light xsmall">{{ error | safe }}</div>
{% elif loading %}
<div class="dimmed light small">{{ phrases.loading | safe }}</div>
{% endif %}
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ These are the possible options:
| `apiKey` | <p>An API key generated from a user profile in Mealie.</p><p>**REQUIRED** When not using username and password<br>**Type:** `string`<br>**Example:** `"eyhJbcG..."`<br>**Default value:** none</p><p>**Note:** You can generate a key by going to your user profile in Mealie then to API Tokens link (or using this path `/user/profile/api-tokens`).</p>|
| `username` | <p>The username/email for your Mealie account.</p><p>**REQUIRED** When not using `apiKey`<br>**Type:** `string`<br>**Example:** `"yourmeailieemail@email.com"`<br>**Default value:** none</p>|
| `password` | <p>The password for your for Mealie account.</p><p>**REQUIRED** When not using `apiKey`<br>**Type:** `string`<br>**Example:** `"Secret!"`<br>**Default value:** none</p>|
| `groupId` | <p>The Group ID (as a UUID) to use when fetching the meal plan.</p><p>**Type:** `string`<br>**Example:** `"c0aa0c1c-bdbb-4948-823b-2a725fb05ce1"`<br>**Default value:** none ("Home" group)</p><p>**Note 1:** You can get the UUID of a group from Settings > Groups.</p><p>**Note 2:** The default "Home" group is used when this is blank.</p>|
| `weekStartsOnMonday` | <p>Show Monday as the first day of the week. Set to `true` to show Monday as the first day of the week.</p><p>**Type:** `boolean`<br>**Default value:** `false`<br>**Possible values:** `true` and `false`|
| `priorDayLimit` | <p>How many previous days of the current week will be displayed. </p><p>**Type:** `integer`<br>**Example:** `5`<br>**Default value:** `7`<br>**Unit:** `days`</p><p>**Note:** If `0`, only today until the end of the week will be shown.</p>|
| `priorEntryLimit` | <p>How many entries from previous days should be shown in total. </p><p>**Type:** `integer`<br>**Example:** `25`<br>**Default value:** `50`<br>**Unit:** `days`</p><p>**Note:** `priorDayLimit` takes precedence. For example, with `3` entries per day, `priorEntryLimit` set to `5` and `priorDayLimit` set to `1`, you will only see `3` prior entries.</p>|
Expand Down Expand Up @@ -118,7 +119,6 @@ It is possible to use multiple instances of this module just by adding another e

This package depends on the following:

- [axios](https://www.npmjs.com/package/axios)
- [moment](https://www.npmjs.com/package/moment)

## Contributing
Expand Down
81 changes: 48 additions & 33 deletions node_helper.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
const NodeHelper = require("node_helper");
const Log = require("logger");
const axios = require("axios").default;
const moment = require("moment");

// Example result from mealplans API see example_data.json.

module.exports = NodeHelper.create({
start () {
Log.log(`Starting node_helper for module [${this.name}]`);
this.mealieApi = null;
this.token = null;
this.outstandingRequest = false;
},

socketNotificationReceived (notification, payload) {
switch (notification) {
case "MEALIE_CREATE_FETCHER":
case "MEALIE_INIT":
// Use API Key or fetch a token.
if (payload.apiKey) {
this.token = payload.apiKey;
this.createFetcher(payload);
this.initComplete(payload);
} else {
this.getToken(payload);
}
Expand All @@ -31,20 +29,35 @@ module.exports = NodeHelper.create({
}
},

initComplete (config) {
this.sendSocketNotification("MEALIE_INITIALIZED", {
identifier: config.identifier
});
},

getToken (config) {
const params = new URLSearchParams();
params.append("username", config.username);
params.append("password", config.password);

axios.post(`${config.host}/api/auth/token`, params, {
fetch(`${config.host}/api/auth/token`, {
method: "POST",
headers: {
accept: "application/json",
Accept: "application/json",
"Content-Type": "application/x-www-form-urlencoded"
}
},
body: params
})
.then((response) => {
this.token = response.data.access_token;
this.createFetcher(config);
if (response.ok) {
return response;
}
throw response.statusText;
})
.then((response) => response.json())
.then((data) => {
this.token = data.access_token;
this.initComplete(config);
})
.catch((error) => {
this.sendSocketNotification("MEALIE_ERROR", {
Expand All @@ -55,22 +68,6 @@ module.exports = NodeHelper.create({
});
},

createFetcher (config) {
// Create single API handler
if (this.mealieApi === null) {
this.mealieApi = axios.create({
baseURL: config.host,
headers: {
accept: "application/json",
Authorization: `Bearer ${this.token}`
}
});
}
this.sendSocketNotification("MEALIE_INITIALIZED", {
identifier: config.identifier
});
},

getMeals (config) {
if (this.outstandingRequest === true) {
Log.info(`[${this.name}] Outstanding request, not trying again.`);
Expand All @@ -85,17 +82,35 @@ module.exports = NodeHelper.create({

Log.info(`[${this.name}] Week starts: ${startOfWeek.format("YYYY-MM-DD")}, next week starts: ${nextWeek.format("YYYY-MM-DD")}`);

const url = new URL(`${config.host}/api/groups/mealplans`);

const params = new URLSearchParams();
params.append("start_date", startOfWeek.format("YYYY-MM-DD"));
params.append("end_date", lastDayOfWeek.format("YYYY-MM-DD"));
params.append("orderBy", "date");
params.append("orderDirection", "asc");
if (config.groupId) {
params.append("group_id", config.groupId);
}
url.search = params.toString();

// Get the full list of meals from Mealie.
this.mealieApi.get("/api/groups/mealplans", {
params: {
start_date: startOfWeek.format("YYYY-MM-DD"), // eslint-disable-line camelcase
end_date: lastDayOfWeek.format("YYYY-MM-DD"), // eslint-disable-line camelcase
orderBy: "date",
orderDirection: "asc"
fetch(url, {
method: "GET",
headers: {
Accept: "application/json",
Authorization: `Bearer ${this.token}`
}
})
.then((response) => {
const meals = response.data.items;
if (response.ok) {
return response;
}
throw response.statusText;
})
.then((response) => response.json())
.then((data) => {
const meals = data.items;

this.sendSocketNotification("MEALIE_MENU_DATA", {
identifier: config.identifier,
Expand All @@ -109,7 +124,7 @@ module.exports = NodeHelper.create({
identifier: config.identifier
});
})
.then(() => {
.finally(() => {
this.outstandingRequest = false;
});
},
Expand Down
Loading

0 comments on commit c201c2c

Please sign in to comment.