mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-05-24 01:12:54 -04:00
Frontend Fixes + Adjust Caddyfile (#518)
* token error handling * Add additional settings to recipes * fixes #515 * remove index.html Co-authored-by: hay-kot <hay-kot@pm.me>
This commit is contained in:
parent
17a7d0b31e
commit
d7c883feca
@ -29,7 +29,7 @@
|
||||
handle {
|
||||
header @static Cache-Control max-age=31536000
|
||||
root * /app/dist
|
||||
try_files {path}.html {path} /index.html
|
||||
try_files {path}.html {path} /
|
||||
file_server
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
import { recipeIngredient } from "./recipeIngredient";
|
||||
import { recipeNumber } from "./recipeNumber";
|
||||
|
||||
export const ingredientScaler = {
|
||||
process(ingredientArray, scale) {
|
||||
console.log(scale);
|
||||
let workingArray = ingredientArray.map(x =>
|
||||
ingredientScaler.markIngredient(x)
|
||||
);
|
||||
return workingArray.map(x => ingredientScaler.adjustIngredients(x, scale));
|
||||
},
|
||||
|
||||
adjustIngredients(ingredient, scale) {
|
||||
var scaledQuantity = new recipeNumber(ingredient.quantity).multiply(scale);
|
||||
const newText = ingredient.text.replace(
|
||||
ingredient.quantity,
|
||||
scaledQuantity
|
||||
);
|
||||
return { ...ingredient, quantity: scaledQuantity, text: newText };
|
||||
},
|
||||
|
||||
markIngredient(ingredient) {
|
||||
console.log(ingredient);
|
||||
const returnVar = ingredient.replace(
|
||||
/^([\d/?[^\s&]*)(?: |\s)(\w*)/g,
|
||||
(match, quantity, unit) => {
|
||||
return `${unit}${quantity},${match}`;
|
||||
}
|
||||
);
|
||||
const split = returnVar.split(",");
|
||||
const [unit, quantity, match] = split;
|
||||
console.log("Split", unit, quantity, match);
|
||||
const n = new recipeNumber(quantity);
|
||||
const i = new recipeIngredient(n, unit);
|
||||
const serializedQuantity = n.isFraction() ? n.toImproperFraction() : n;
|
||||
return {
|
||||
unit: i,
|
||||
quantity: serializedQuantity.toString(),
|
||||
text: match,
|
||||
};
|
||||
},
|
||||
};
|
@ -1,75 +0,0 @@
|
||||
export const recipeIngredient = function(quantity, unit) {
|
||||
this.quantity = quantity;
|
||||
this.unit = unit;
|
||||
};
|
||||
|
||||
recipeIngredient.prototype.isSingular = function() {
|
||||
return this.quantity > 0 && this.quantity <= 1;
|
||||
};
|
||||
|
||||
recipeIngredient.prototype.pluralize = function() {
|
||||
if (this.isSingular()) {
|
||||
return this.unit;
|
||||
} else {
|
||||
return `${this.unit}s`;
|
||||
}
|
||||
};
|
||||
|
||||
recipeIngredient.prototype.getSingularUnit = function() {
|
||||
if (this.isSingular()) {
|
||||
return this.unit;
|
||||
} else {
|
||||
return this.unit.replace(/s$/, "");
|
||||
}
|
||||
};
|
||||
|
||||
recipeIngredient.prototype.toString = function() {
|
||||
return `${this.quantity.toString()} ${this.pluralize()}`;
|
||||
};
|
||||
|
||||
recipeIngredient.prototype.convertUnits = function() {
|
||||
const conversion = recipeIngredient.CONVERSIONS[this.unit] || {};
|
||||
if (conversion.min && this.quantity < conversion.min.value) {
|
||||
this.unit = conversion.min.next;
|
||||
this.quantity.multiply(conversion.to[this.unit]);
|
||||
} else if (conversion.max && this.quantity >= conversion.max.value) {
|
||||
this.unit = conversion.max.next;
|
||||
this.quantity.multiply(conversion.to[this.unit]);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
recipeIngredient.CONVERSIONS = {
|
||||
cup: {
|
||||
to: {
|
||||
tablespoon: 16,
|
||||
},
|
||||
min: {
|
||||
value: 1 / 4,
|
||||
next: "tablespoon",
|
||||
},
|
||||
},
|
||||
tablespoon: {
|
||||
to: {
|
||||
teaspoon: 3,
|
||||
cup: 1 / 16,
|
||||
},
|
||||
min: {
|
||||
value: 1,
|
||||
next: "teaspoon",
|
||||
},
|
||||
max: {
|
||||
value: 4,
|
||||
next: "cup",
|
||||
},
|
||||
},
|
||||
teaspoon: {
|
||||
to: {
|
||||
tablespoon: 1 / 3,
|
||||
},
|
||||
max: {
|
||||
value: 3,
|
||||
next: "tablespoon",
|
||||
},
|
||||
},
|
||||
};
|
@ -1,166 +0,0 @@
|
||||
export const recipeNumber = function(number) {
|
||||
const match = number.match(
|
||||
/^(?:(\d+)|(?:(\d+)(?: | ))?(?:(\d+)\/(\d+))?)$/
|
||||
);
|
||||
if (!match || !match[0] || match[4] == "0") {
|
||||
throw `Invalid number: "${number}".`;
|
||||
}
|
||||
this.wholeNumber = +(match[1] || match[2]);
|
||||
this.numerator = +match[3];
|
||||
this.denominator = +match[4];
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines if the number is a fraction.
|
||||
* @this {recipeNumber}
|
||||
* @return {boolean} If the number is a fraction.
|
||||
*/
|
||||
recipeNumber.prototype.isFraction = function() {
|
||||
return !!(this.numerator && this.denominator);
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines if the fraction is proper, which is defined as
|
||||
* the numerator being strictly less than the denominator.
|
||||
* @this {recipeNumber}
|
||||
* @return {boolean} If the fraction is proper.
|
||||
*/
|
||||
recipeNumber.prototype.isProperFraction = function() {
|
||||
return this.numerator < this.denominator;
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines if the fraction is improper, which is defined as
|
||||
* the numerator being greater than or equal to the denominator.
|
||||
* @this {recipeNumber}
|
||||
* @return {boolean} If the fraction is improper.
|
||||
*/
|
||||
recipeNumber.prototype.isImproperFraction = function() {
|
||||
return this.numerator >= this.denominator;
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines if the fraction is mixed, which is defined as
|
||||
* a whole number with a proper fraction.
|
||||
* @this {recipeNumber}
|
||||
* @return {boolean} If the fraction is mixed.
|
||||
*/
|
||||
recipeNumber.prototype.isMixedFraction = function() {
|
||||
return this.isProperFraction() && !isNaN(this.wholeNumber);
|
||||
};
|
||||
|
||||
/**
|
||||
* Simplifies fractions. Examples:
|
||||
* 3/2 = 1 1/2
|
||||
* 4/2 = 2
|
||||
* 1 3/2 = 2 1/2
|
||||
* 0/1 = 0
|
||||
* 1 0/1 = 1
|
||||
* @this {recipeNumber}
|
||||
* @return {recipeNumber} The instance.
|
||||
*/
|
||||
recipeNumber.prototype.simplifyFraction = function() {
|
||||
if (this.isImproperFraction()) {
|
||||
this.wholeNumber |= 0;
|
||||
this.wholeNumber += Math.floor(this.numerator / this.denominator);
|
||||
const modulus = this.numerator % this.denominator;
|
||||
if (modulus) {
|
||||
this.numerator = modulus;
|
||||
} else {
|
||||
this.numerator = this.denominator = NaN;
|
||||
}
|
||||
} else if (this.numerator == 0) {
|
||||
this.wholeNumber |= 0;
|
||||
this.numerator = this.denominator = NaN;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Reduces a fraction. Examples:
|
||||
* 2/6 = 1/3
|
||||
* 6/2 = 3/1
|
||||
* @this {recipeNumber}
|
||||
* @return {recipeNumber} The instance.
|
||||
*/
|
||||
recipeNumber.prototype.reduceFraction = function() {
|
||||
if (this.isFraction()) {
|
||||
const gcd = recipeNumber.gcd(this.numerator, this.denominator);
|
||||
this.numerator /= gcd;
|
||||
this.denominator /= gcd;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts proper fractions to improper fractions. Examples:
|
||||
* 1 1/2 = 3/2
|
||||
* 3/2 = 3/2
|
||||
* 1/2 = 1/2
|
||||
* 2 = 2
|
||||
*
|
||||
* @this {recipeNumber}
|
||||
* @return {recipeNumber} The instance.
|
||||
*/
|
||||
recipeNumber.prototype.toImproperFraction = function() {
|
||||
if (!isNaN(this.wholeNumber)) {
|
||||
this.numerator |= 0;
|
||||
this.denominator = this.denominator || 1;
|
||||
this.numerator += this.wholeNumber * this.denominator;
|
||||
this.wholeNumber = NaN;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Multiplies the number by some decimal value.
|
||||
* @param {number} multiplier The multiplier.
|
||||
* @this {recipeNumber}
|
||||
* @return {recipeNumber} The instance.
|
||||
*/
|
||||
recipeNumber.prototype.multiply = function(multiplier) {
|
||||
this.toImproperFraction();
|
||||
this.numerator *= multiplier;
|
||||
return this.reduceFraction().simplifyFraction();
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets a string representation of the number.
|
||||
* @this {recipeNumber}
|
||||
* @return {string} The string representation of the number.
|
||||
*/
|
||||
recipeNumber.prototype.toString = function() {
|
||||
let number = "";
|
||||
let fraction = "";
|
||||
if (!isNaN(this.wholeNumber)) {
|
||||
number += this.wholeNumber;
|
||||
}
|
||||
if (this.isFraction()) {
|
||||
fraction = `${this.numerator}/${this.denominator}`;
|
||||
}
|
||||
if (number && fraction) {
|
||||
number += ` ${fraction}`;
|
||||
}
|
||||
return number || fraction;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets a numeric representation of the number.
|
||||
* @this {recipeNumber}
|
||||
* @return {number} The numeric representation of the number.
|
||||
*/
|
||||
recipeNumber.prototype.valueOf = function() {
|
||||
let value = this.wholeNumber || 0;
|
||||
value += this.numerator / this.denominator || 0;
|
||||
return value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Euclid's algorithm to find the greatest common divisor of two numbers.
|
||||
* @param {number} a One number.
|
||||
* @param {number} b Another number.
|
||||
* @return {number} The GCD of the numbers.
|
||||
*/
|
||||
recipeNumber.gcd = function gcd(a, b) {
|
||||
return b ? recipeNumber.gcd(b, a % b) : a;
|
||||
};
|
@ -36,7 +36,6 @@ export const recipeAPI = {
|
||||
|
||||
async requestDetails(recipeSlug) {
|
||||
const response = await apiReq.getSafe(API_ROUTES.recipesRecipeSlug(recipeSlug));
|
||||
console.log(response);
|
||||
return response;
|
||||
},
|
||||
|
||||
|
@ -1,20 +1,16 @@
|
||||
import { API_ROUTES } from "./apiRoutes";
|
||||
import { apiReq } from "./api-utils";
|
||||
import axios from "axios";
|
||||
import i18n from "@/i18n.js";
|
||||
|
||||
export const userAPI = {
|
||||
async login(formData) {
|
||||
let response = await apiReq.post(API_ROUTES.authToken, formData, null, function() {
|
||||
let response = await apiReq.post(API_ROUTES.authToken, formData, null, () => {
|
||||
return i18n.t("user.user-successfully-logged-in");
|
||||
});
|
||||
return response;
|
||||
},
|
||||
async refresh() {
|
||||
let response = await axios.get(API_ROUTES.authRefresh).catch(function(event) {
|
||||
console.log("Fetch failed", event);
|
||||
});
|
||||
return response.data ? response.data : false;
|
||||
return apiReq.getSafe(API_ROUTES.authRefresh);
|
||||
},
|
||||
async allUsers() {
|
||||
let response = await apiReq.get(API_ROUTES.users);
|
||||
@ -29,8 +25,7 @@ export const userAPI = {
|
||||
);
|
||||
},
|
||||
async self() {
|
||||
let response = await apiReq.get(API_ROUTES.usersSelf);
|
||||
return response.data;
|
||||
return apiReq.getSafe(API_ROUTES.usersSelf);
|
||||
},
|
||||
async byID(id) {
|
||||
let response = await apiReq.get(API_ROUTES.usersId(id));
|
||||
|
@ -106,9 +106,6 @@ export default {
|
||||
},
|
||||
|
||||
watch: {
|
||||
startDate(val) {
|
||||
console.log(val);
|
||||
},
|
||||
dateDif() {
|
||||
this.planDays = [];
|
||||
for (let i = 0; i < this.dateDif; i++) {
|
||||
|
@ -10,12 +10,10 @@
|
||||
<slot> </slot>
|
||||
</v-img>
|
||||
<div class="icon-slot" v-else @click="$emit('click')">
|
||||
<div>
|
||||
<slot> </slot>
|
||||
</div>
|
||||
<v-icon color="primary" class="icon-position" :size="iconSize">
|
||||
{{ $globals.icons.primary }}
|
||||
</v-icon>
|
||||
<slot> </slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -82,9 +82,6 @@ export default {
|
||||
this.$set(this.editKeys, comment.id, false);
|
||||
}
|
||||
},
|
||||
editKeys() {
|
||||
console.log(this.editKeys);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
resetImage() {
|
||||
@ -103,7 +100,6 @@ export default {
|
||||
this.$emit(UPDATE_COMMENT_EVENT);
|
||||
},
|
||||
async createNewComment() {
|
||||
console.log(this.slug);
|
||||
await api.recipes.createComment(this.slug, { text: this.newComment });
|
||||
this.$emit(NEW_COMMENT_EVENT);
|
||||
|
||||
|
@ -47,6 +47,8 @@ export default {
|
||||
showNutrition: this.$t("recipe.show-nutrition-values"),
|
||||
showAssets: this.$t("recipe.show-assets"),
|
||||
landscapeView: this.$t("recipe.landscape-view-coming-soon"),
|
||||
disableComments: this.$t("recipe.disable-comments"),
|
||||
disableAmount: this.$t("recipe.disable-amount"),
|
||||
};
|
||||
},
|
||||
},
|
||||
|
@ -27,7 +27,7 @@
|
||||
<Rating :value="rating" :name="name" :slug="slug" :small="true" />
|
||||
<v-spacer></v-spacer>
|
||||
<RecipeChips :truncate="true" :items="tags" :title="false" :limit="2" :small="true" :isCategory="false" />
|
||||
<ContextMenu :slug="slug" :name="name"/>
|
||||
<ContextMenu :slug="slug" :name="name" />
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-hover>
|
||||
|
@ -210,6 +210,8 @@
|
||||
"calories-suffix": "calories",
|
||||
"carbohydrate-content": "Carbohydrate",
|
||||
"categories": "Categories",
|
||||
"disable-comments": "Disable Comments",
|
||||
"disable-amount": "Disable Ingredient Amounts",
|
||||
"delete-confirmation": "Are you sure you want to delete this recipe?",
|
||||
"delete-recipe": "Delete Recipe",
|
||||
"description": "Description",
|
||||
|
@ -150,7 +150,13 @@ export default {
|
||||
|
||||
methods: {
|
||||
async refreshProfile() {
|
||||
this.user = await api.users.self();
|
||||
const [response, err] = await api.users.self();
|
||||
|
||||
if (err) {
|
||||
return; // TODO: Log or Notifty User of Error
|
||||
}
|
||||
|
||||
this.user = response.data;
|
||||
},
|
||||
openAvatarPicker() {
|
||||
this.showAvatarPicker = true;
|
||||
|
@ -55,6 +55,7 @@
|
||||
/>
|
||||
</v-card>
|
||||
<CommentsSection
|
||||
v-if="recipeDetails.settings && !recipeDetails.settings.disableComments"
|
||||
class="mt-2 d-print-none"
|
||||
:slug="recipeDetails.slug"
|
||||
:comments="recipeDetails.comments"
|
||||
|
@ -199,7 +199,6 @@ export default {
|
||||
},
|
||||
async importIngredients(selected) {
|
||||
const [response, error] = await api.recipes.requestDetails(selected.slug);
|
||||
console.log(response);
|
||||
|
||||
if (error) {
|
||||
console.log(error);
|
||||
|
@ -56,8 +56,13 @@ const mutations = {
|
||||
const actions = {
|
||||
async requestUserData({ getters, commit }) {
|
||||
if (getters.getIsLoggedIn) {
|
||||
const userData = await api.users.self();
|
||||
commit("setUserData", userData);
|
||||
const [response, err] = await api.users.self();
|
||||
|
||||
if (err) {
|
||||
return; // TODO: Log or Notifty User of Error
|
||||
}
|
||||
|
||||
commit("setUserData", response.data);
|
||||
}
|
||||
},
|
||||
|
||||
@ -76,13 +81,15 @@ const actions = {
|
||||
console.log("Not Logged In");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
let authResponse = await api.users.refresh();
|
||||
commit("setToken", authResponse.access_token);
|
||||
} catch {
|
||||
|
||||
const [response, err] = await api.users.refresh();
|
||||
|
||||
if (err) {
|
||||
console.log("Failed Token Refresh, Logging Out...");
|
||||
commit("setIsLoggedIn", false);
|
||||
}
|
||||
|
||||
commit("setToken", response.data.access_token);
|
||||
},
|
||||
|
||||
async initTheme({ dispatch, getters }) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
from mealie.db.models.model_base import BaseMixins, SqlAlchemyBase
|
||||
from requests import Session
|
||||
from sqlalchemy import Boolean, Column, ForeignKey, Integer, String, Table, orm
|
||||
from sqlalchemy import Column, ForeignKey, Integer, String, Table, orm
|
||||
|
||||
ingredients_to_units = Table(
|
||||
"ingredients_to_units",
|
||||
@ -82,14 +82,10 @@ class RecipeIngredient(SqlAlchemyBase):
|
||||
quantity = Column(Integer)
|
||||
|
||||
# Extras
|
||||
disable_amount = Column(Boolean, default=False)
|
||||
|
||||
def __init__(
|
||||
self, title: str, note: str, unit: dict, food: dict, quantity: int, disable_amount: bool, session: Session, **_
|
||||
) -> None:
|
||||
def __init__(self, title: str, note: str, unit: dict, food: dict, quantity: int, session: Session, **_) -> None:
|
||||
self.title = title
|
||||
self.note = note
|
||||
self.unit = IngredientUnit.get_ref_or_create(session, unit)
|
||||
self.food = IngredientFood.get_ref_or_create(session, food)
|
||||
self.quantity = quantity
|
||||
self.disable_amount = disable_amount
|
||||
|
@ -10,9 +10,21 @@ class RecipeSettings(SqlAlchemyBase):
|
||||
show_nutrition = sa.Column(sa.Boolean)
|
||||
show_assets = sa.Column(sa.Boolean)
|
||||
landscape_view = sa.Column(sa.Boolean)
|
||||
disable_amount = sa.Column(sa.Boolean, default=False)
|
||||
disable_comments = sa.Column(sa.Boolean, default=False)
|
||||
|
||||
def __init__(self, public=True, show_nutrition=True, show_assets=True, landscape_view=True) -> None:
|
||||
def __init__(
|
||||
self,
|
||||
public=True,
|
||||
show_nutrition=True,
|
||||
show_assets=True,
|
||||
landscape_view=True,
|
||||
disable_amount=True,
|
||||
disable_comments=False,
|
||||
) -> None:
|
||||
self.public = public
|
||||
self.show_nutrition = show_nutrition
|
||||
self.show_assets = show_assets
|
||||
self.landscape_view = landscape_view
|
||||
self.disable_amount = disable_amount
|
||||
self.disable_comments = disable_comments
|
||||
|
@ -16,6 +16,8 @@ class RecipeSettings(CamelModel):
|
||||
show_nutrition: bool = True
|
||||
show_assets: bool = True
|
||||
landscape_view: bool = True
|
||||
disable_comments: bool = False
|
||||
disable_amount: bool = False
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
|
Loading…
x
Reference in New Issue
Block a user