diff --git a/cookbook/forms.py b/cookbook/forms.py
index dd62aa0b..4226af9c 100644
--- a/cookbook/forms.py
+++ b/cookbook/forms.py
@@ -450,7 +450,7 @@ class SpacePreferenceForm(forms.ModelForm):
class Meta:
model = Space
- fields = ('food_inherit', 'reset_food_inherit', 'use_plural')
+ fields = ('food_inherit', 'reset_food_inherit',)
help_texts = {
'food_inherit': _('Fields on food that should be inherited by default.'),
diff --git a/cookbook/helper/template_helper.py b/cookbook/helper/template_helper.py
index 016779a7..4db1f5bc 100644
--- a/cookbook/helper/template_helper.py
+++ b/cookbook/helper/template_helper.py
@@ -14,12 +14,14 @@ class IngredientObject(object):
unit = ""
food = ""
note = ""
+ numeric_amount = 0
def __init__(self, ingredient):
if ingredient.no_amount:
self.amount = ""
else:
self.amount = f""
+ self.numeric_amount = float(ingredient.amount)
if ingredient.unit:
if ingredient.unit.plural_name in (None, ""):
self.unit = bleach.clean(str(ingredient.unit))
@@ -83,9 +85,12 @@ def render_instructions(step): # TODO deduplicate markdown cleanup code
for i in step.ingredients.all():
ingredients.append(IngredientObject(i))
+ def scale(number):
+ return f""
+
try:
template = Template(instructions)
- instructions = template.render(ingredients=ingredients)
+ instructions = template.render(ingredients=ingredients, scale=scale)
except TemplateSyntaxError:
return _('Could not parse template code.') + ' Error: Template Syntax broken'
except UndefinedError:
diff --git a/cookbook/migrations/0209_remove_space_use_plural.py b/cookbook/migrations/0209_remove_space_use_plural.py
new file mode 100644
index 00000000..37a4b6fc
--- /dev/null
+++ b/cookbook/migrations/0209_remove_space_use_plural.py
@@ -0,0 +1,17 @@
+# Generated by Django 4.2.7 on 2024-01-28 07:42
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('cookbook', '0208_space_app_name_userpreference_max_owned_spaces'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='space',
+ name='use_plural',
+ ),
+ ]
diff --git a/cookbook/models.py b/cookbook/models.py
index df90415d..a0a2cbf3 100644
--- a/cookbook/models.py
+++ b/cookbook/models.py
@@ -303,7 +303,6 @@ class Space(ExportModelOperationsMixin('space'), models.Model):
max_recipes = models.IntegerField(default=0)
max_file_storage_mb = models.IntegerField(default=0, help_text=_('Maximum file storage for space in MB. 0 for unlimited, -1 to disable file upload.'))
max_users = models.IntegerField(default=0)
- use_plural = models.BooleanField(default=True)
allow_sharing = models.BooleanField(default=True)
no_sharing_limit = models.BooleanField(default=False)
demo = models.BooleanField(default=False)
diff --git a/cookbook/serializer.py b/cookbook/serializer.py
index d0ad0bfa..609ade4c 100644
--- a/cookbook/serializer.py
+++ b/cookbook/serializer.py
@@ -315,9 +315,8 @@ class SpaceSerializer(WritableNestedModelSerializer):
fields = (
'id', 'name', 'created_by', 'created_at', 'message', 'max_recipes', 'max_file_storage_mb', 'max_users',
'allow_sharing', 'demo', 'food_inherit', 'user_count', 'recipe_count', 'file_size_mb',
- 'image', 'nav_logo', 'space_theme', 'custom_space_theme', 'nav_bg_color', 'nav_text_color', 'use_plural',
- 'logo_color_32', 'logo_color_128', 'logo_color_144', 'logo_color_180', 'logo_color_192', 'logo_color_512',
- 'logo_color_svg',)
+ 'image', 'nav_logo', 'space_theme', 'custom_space_theme', 'nav_bg_color', 'nav_text_color',
+ 'logo_color_32', 'logo_color_128', 'logo_color_144', 'logo_color_180', 'logo_color_192', 'logo_color_512', 'logo_color_svg',)
read_only_fields = (
'id', 'created_by', 'created_at', 'max_recipes', 'max_file_storage_mb', 'max_users', 'allow_sharing',
'demo',)
diff --git a/cookbook/templatetags/theming_tags.py b/cookbook/templatetags/theming_tags.py
index d69ae7b0..f2984b97 100644
--- a/cookbook/templatetags/theming_tags.py
+++ b/cookbook/templatetags/theming_tags.py
@@ -3,7 +3,7 @@ from django.templatetags.static import static
from django_scopes import scopes_disabled
from cookbook.models import UserPreference, UserFile, Space
-from recipes.settings import STICKY_NAV_PREF_DEFAULT, UNAUTHENTICATED_THEME_FROM_SPACE
+from recipes.settings import STICKY_NAV_PREF_DEFAULT, UNAUTHENTICATED_THEME_FROM_SPACE, FORCE_THEME_FROM_SPACE
register = template.Library()
@@ -15,11 +15,14 @@ def theme_values(request):
def get_theming_values(request):
space = None
- if getattr(request,'space',None):
+ if getattr(request, 'space', None):
space = request.space
- if not request.user.is_authenticated and UNAUTHENTICATED_THEME_FROM_SPACE > 0:
+ if not request.user.is_authenticated and UNAUTHENTICATED_THEME_FROM_SPACE > 0 and FORCE_THEME_FROM_SPACE == 0:
with scopes_disabled():
space = Space.objects.filter(id=UNAUTHENTICATED_THEME_FROM_SPACE).first()
+ if FORCE_THEME_FROM_SPACE:
+ with scopes_disabled():
+ space = Space.objects.filter(id=FORCE_THEME_FROM_SPACE).first()
themes = {
UserPreference.BOOTSTRAP: 'themes/bootstrap.min.css',
diff --git a/docs/install/docker.md b/docs/install/docker.md
index 7d32ab4d..e02e28cc 100644
--- a/docs/install/docker.md
+++ b/docs/install/docker.md
@@ -204,6 +204,22 @@ server {
}
```
+Tandoor does not support directly serving of images, as explained in the [Nginx vs Gunicorn"](#nginx-vs-gunicorn) section. If you are already using nginx to serve as a reverse proxy, you can configure it to serve images as well.
+
+Add the following directly after the `location /` context:
+
+```
+ location /media/ {
+ root /media/;
+ index index.html index.htm;
+ }
+```
+
+Make sure you also update your `docker-compose.yml` file to mount the `mediafiles` directory. If you are using the [Plain](#plain) deployment, you do not need to make any changes. If you are using nginx to act as a reverse proxy for other apps, it may not be optimal to have `mediafiles` mounted to `/media`. In that case, adjust the directory declarations as needed, utilizing nginx's [`alias`](https://nginx.org/en/docs/http/ngx_http_core_module.html#alias) if needed.
+
+!!!note
+ Use `alias` if your mount point directory is not the same as the URL request path. Tandoor media files are requested from `$http_host/media/recipes/xxx.jpg`. This means if you are mounting to a directory that does **NOT** end in `./media`, you will need to use `alias`.
+
!!!note
Don't forget to [download and configure](#docker-compose) your ```.env``` file!
diff --git a/docs/system/configuration.md b/docs/system/configuration.md
index f6e64d24..8d93f985 100644
--- a/docs/system/configuration.md
+++ b/docs/system/configuration.md
@@ -560,6 +560,15 @@ With this setting you can specify the ID of a space of which the appearance sett
UNAUTHENTICATED_THEME_FROM_SPACE=
```
+#### Force Theme
+> default `0` - options `1-X` (space ID)
+
+Similar to the Default theme but forces the theme upon all users (authenticated/unauthenticated) and all spaces
+
+```
+FORCE_THEME_FROM_SPACE=
+```
+
### Rate Limiting / Performance
#### Shopping auto sync
diff --git a/recipes/settings.py b/recipes/settings.py
index 4f4328d0..36e68c4f 100644
--- a/recipes/settings.py
+++ b/recipes/settings.py
@@ -59,6 +59,7 @@ KJ_PREF_DEFAULT = bool(int(os.getenv('KJ_PREF_DEFAULT', False)))
STICKY_NAV_PREF_DEFAULT = bool(int(os.getenv('STICKY_NAV_PREF_DEFAULT', True)))
MAX_OWNED_SPACES_PREF_DEFAULT = int(os.getenv('MAX_OWNED_SPACES_PREF_DEFAULT', 100))
UNAUTHENTICATED_THEME_FROM_SPACE = int(os.getenv('UNAUTHENTICATED_THEME_FROM_SPACE', 0))
+FORCE_THEME_FROM_SPACE = int(os.getenv('FORCE_THEME_FROM_SPACE', 0))
# minimum interval that users can set for automatic sync of shopping lists
SHOPPING_MIN_AUTOSYNC_INTERVAL = int(
diff --git a/vue/src/components/CookbookSlider.vue b/vue/src/components/CookbookSlider.vue
index f2ccbb9a..71be6846 100644
--- a/vue/src/components/CookbookSlider.vue
+++ b/vue/src/components/CookbookSlider.vue
@@ -20,7 +20,7 @@
-
+
@@ -57,10 +57,7 @@ export default {
}
},
mounted(){
- let apiClient = new ApiApiFactory()
- apiClient.retrieveSpace(window.ACTIVE_SPACE_ID).then(r => {
- this.use_plural = r.data.use_plural
- })
+
},
data() {
return {
@@ -69,7 +66,6 @@ export default {
bounce_left: false,
bounce_right: false,
cookbook_editing: false,
- use_plural: false,
}
},
methods: {
diff --git a/vue/src/components/GenericHorizontalCard.vue b/vue/src/components/GenericHorizontalCard.vue
index ed43a1a2..f65b2edc 100644
--- a/vue/src/components/GenericHorizontalCard.vue
+++ b/vue/src/components/GenericHorizontalCard.vue
@@ -76,8 +76,7 @@
@@ -160,7 +159,6 @@ export default {
recipe_count: { type: String, default: "numrecipe" },
recipes: { type: String, default: "recipes" },
show_context_menu: { type: Boolean, default: true },
- use_plural: { type: Boolean, default: false},
},
data() {
return {
diff --git a/vue/src/components/IngredientsCard.vue b/vue/src/components/IngredientsCard.vue
index 6ab4c9ed..0b2cb69f 100644
--- a/vue/src/components/IngredientsCard.vue
+++ b/vue/src/components/IngredientsCard.vue
@@ -24,7 +24,6 @@
@@ -147,10 +146,6 @@ export default {
type: Boolean,
default: false,
},
- use_plural: {
- type: Boolean,
- default: false,
- },
},
computed: {
step_time: function() {