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() {