added ability to set space images

This commit is contained in:
vabene1111
2022-07-14 15:23:59 +02:00
parent ba473123ba
commit f4df84b609
5 changed files with 147 additions and 103 deletions

View File

@ -0,0 +1,19 @@
# Generated by Django 4.0.6 on 2022-07-14 11:14
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('cookbook', '0180_invitelink_reusable'),
]
operations = [
migrations.AddField(
model_name='space',
name='image',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='space_image', to='cookbook.userfile'),
),
]

View File

@ -4,6 +4,7 @@ import re
import uuid import uuid
from datetime import date, timedelta from datetime import date, timedelta
from PIL import Image
from annoying.fields import AutoOneToOneField from annoying.fields import AutoOneToOneField
from django.contrib import auth from django.contrib import auth
from django.contrib.auth.models import Group, User from django.contrib.auth.models import Group, User
@ -244,6 +245,7 @@ class FoodInheritField(models.Model, PermissionModelMixin):
class Space(ExportModelOperationsMixin('space'), models.Model): class Space(ExportModelOperationsMixin('space'), models.Model):
name = models.CharField(max_length=128, default='Default') name = models.CharField(max_length=128, default='Default')
image = models.ForeignKey("UserFile", on_delete=models.SET_NULL, null=True, related_name='space_image')
created_by = models.ForeignKey(User, on_delete=models.PROTECT, null=True) created_by = models.ForeignKey(User, on_delete=models.PROTECT, null=True)
created_at = models.DateTimeField(auto_now_add=True) created_at = models.DateTimeField(auto_now_add=True)
message = models.CharField(max_length=512, default='', blank=True) message = models.CharField(max_length=512, default='', blank=True)
@ -1177,6 +1179,13 @@ class UserFile(ExportModelOperationsMixin('user_files'), models.Model, Permissio
objects = ScopedManager(space='space') objects = ScopedManager(space='space')
space = models.ForeignKey(Space, on_delete=models.CASCADE) space = models.ForeignKey(Space, on_delete=models.CASCADE)
def is_image(self):
try:
img = Image.open(self.file.file.file)
return True
except Exception:
return False
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
if hasattr(self.file, 'file') and isinstance(self.file.file, UploadedFile) or isinstance(self.file.file, InMemoryUploadedFile): if hasattr(self.file, 'file') and isinstance(self.file.file, UploadedFile) or isinstance(self.file.file, InMemoryUploadedFile):
self.file.name = f'{uuid.uuid4()}' + pathlib.Path(self.file.name).suffix self.file.name = f'{uuid.uuid4()}' + pathlib.Path(self.file.name).suffix

View File

@ -173,104 +173,6 @@ class FoodInheritFieldSerializer(UniqueFieldsMixin, WritableNestedModelSerialize
read_only_fields = ['id'] read_only_fields = ['id']
class SpaceSerializer(WritableNestedModelSerializer):
user_count = serializers.SerializerMethodField('get_user_count')
recipe_count = serializers.SerializerMethodField('get_recipe_count')
file_size_mb = serializers.SerializerMethodField('get_file_size_mb')
food_inherit = FoodInheritFieldSerializer(many=True)
def get_user_count(self, obj):
return UserSpace.objects.filter(space=obj).count()
def get_recipe_count(self, obj):
return Recipe.objects.filter(space=obj).count()
def get_file_size_mb(self, obj):
try:
return UserFile.objects.filter(space=obj).aggregate(Sum('file_size_kb'))['file_size_kb__sum'] / 1000
except TypeError:
return 0
def create(self, validated_data):
raise ValidationError('Cannot create using this endpoint')
class Meta:
model = Space
fields = ('id', 'name', 'created_by', 'created_at', 'message', 'max_recipes', 'max_file_storage_mb', 'max_users',
'allow_sharing', 'demo', 'food_inherit', 'show_facet_count', 'user_count', 'recipe_count', 'file_size_mb',)
read_only_fields = ('id', 'created_by', 'created_at', 'max_recipes', 'max_file_storage_mb', 'max_users', 'allow_sharing', 'demo',)
class UserSpaceSerializer(WritableNestedModelSerializer):
user = UserNameSerializer(read_only=True)
groups = GroupSerializer(many=True)
def validate(self, data):
if self.instance.user == self.context['request'].space.created_by: # can't change space owner permission
raise serializers.ValidationError(_('Cannot modify Space owner permission.'))
return super().validate(data)
def create(self, validated_data):
raise ValidationError('Cannot create using this endpoint')
class Meta:
model = UserSpace
fields = ('id', 'user', 'space', 'groups', 'active', 'created_at', 'updated_at',)
read_only_fields = ('id', 'created_at', 'updated_at', 'space')
class SpacedModelSerializer(serializers.ModelSerializer):
def create(self, validated_data):
validated_data['space'] = self.context['request'].space
return super().create(validated_data)
class MealTypeSerializer(SpacedModelSerializer, WritableNestedModelSerializer):
def create(self, validated_data):
validated_data['created_by'] = self.context['request'].user
return super().create(validated_data)
class Meta:
list_serializer_class = SpaceFilterSerializer
model = MealType
fields = ('id', 'name', 'order', 'icon', 'color', 'default', 'created_by')
read_only_fields = ('created_by',)
class UserPreferenceSerializer(WritableNestedModelSerializer):
food_inherit_default = serializers.SerializerMethodField('get_food_inherit_defaults')
plan_share = UserNameSerializer(many=True, allow_null=True, required=False)
shopping_share = UserNameSerializer(many=True, allow_null=True, required=False)
food_children_exist = serializers.SerializerMethodField('get_food_children_exist')
def get_food_inherit_defaults(self, obj):
return FoodInheritFieldSerializer(obj.user.get_active_space().food_inherit.all(), many=True).data
def get_food_children_exist(self, obj):
space = getattr(self.context.get('request', None), 'space', None)
return Food.objects.filter(depth__gt=0, space=space).exists()
def update(self, instance, validated_data):
with scopes_disabled():
return super().update(instance, validated_data)
def create(self, validated_data):
raise ValidationError('Cannot create using this endpoint')
class Meta:
model = UserPreference
fields = (
'user', 'theme', 'nav_color', 'default_unit', 'default_page', 'use_fractions', 'use_kj',
'plan_share',
'ingredient_decimals', 'comments', 'shopping_auto_sync', 'mealplan_autoadd_shopping',
'food_inherit_default', 'default_delay',
'mealplan_autoinclude_related', 'mealplan_autoexclude_onhand', 'shopping_share', 'shopping_recent_days',
'csv_delim', 'csv_prefix',
'filter_to_supermarket', 'shopping_add_onhand', 'left_handed', 'food_children_exist'
)
class UserFileSerializer(serializers.ModelSerializer): class UserFileSerializer(serializers.ModelSerializer):
file = serializers.FileField(write_only=True) file = serializers.FileField(write_only=True)
file_download = serializers.SerializerMethodField('get_download_link') file_download = serializers.SerializerMethodField('get_download_link')
@ -347,6 +249,105 @@ class UserFileViewSerializer(serializers.ModelSerializer):
read_only_fields = ('id', 'file') read_only_fields = ('id', 'file')
class SpaceSerializer(WritableNestedModelSerializer):
user_count = serializers.SerializerMethodField('get_user_count')
recipe_count = serializers.SerializerMethodField('get_recipe_count')
file_size_mb = serializers.SerializerMethodField('get_file_size_mb')
food_inherit = FoodInheritFieldSerializer(many=True)
image = UserFileViewSerializer(required=False, many=False)
def get_user_count(self, obj):
return UserSpace.objects.filter(space=obj).count()
def get_recipe_count(self, obj):
return Recipe.objects.filter(space=obj).count()
def get_file_size_mb(self, obj):
try:
return UserFile.objects.filter(space=obj).aggregate(Sum('file_size_kb'))['file_size_kb__sum'] / 1000
except TypeError:
return 0
def create(self, validated_data):
raise ValidationError('Cannot create using this endpoint')
class Meta:
model = Space
fields = ('id', 'name', 'created_by', 'created_at', 'message', 'max_recipes', 'max_file_storage_mb', 'max_users',
'allow_sharing', 'demo', 'food_inherit', 'show_facet_count', 'user_count', 'recipe_count', 'file_size_mb', 'image',)
read_only_fields = ('id', 'created_by', 'created_at', 'max_recipes', 'max_file_storage_mb', 'max_users', 'allow_sharing', 'demo',)
class UserSpaceSerializer(WritableNestedModelSerializer):
user = UserNameSerializer(read_only=True)
groups = GroupSerializer(many=True)
def validate(self, data):
if self.instance.user == self.context['request'].space.created_by: # can't change space owner permission
raise serializers.ValidationError(_('Cannot modify Space owner permission.'))
return super().validate(data)
def create(self, validated_data):
raise ValidationError('Cannot create using this endpoint')
class Meta:
model = UserSpace
fields = ('id', 'user', 'space', 'groups', 'active', 'created_at', 'updated_at',)
read_only_fields = ('id', 'created_at', 'updated_at', 'space')
class SpacedModelSerializer(serializers.ModelSerializer):
def create(self, validated_data):
validated_data['space'] = self.context['request'].space
return super().create(validated_data)
class MealTypeSerializer(SpacedModelSerializer, WritableNestedModelSerializer):
def create(self, validated_data):
validated_data['created_by'] = self.context['request'].user
return super().create(validated_data)
class Meta:
list_serializer_class = SpaceFilterSerializer
model = MealType
fields = ('id', 'name', 'order', 'icon', 'color', 'default', 'created_by')
read_only_fields = ('created_by',)
class UserPreferenceSerializer(WritableNestedModelSerializer):
food_inherit_default = serializers.SerializerMethodField('get_food_inherit_defaults')
plan_share = UserNameSerializer(many=True, allow_null=True, required=False)
shopping_share = UserNameSerializer(many=True, allow_null=True, required=False)
food_children_exist = serializers.SerializerMethodField('get_food_children_exist')
def get_food_inherit_defaults(self, obj):
return FoodInheritFieldSerializer(obj.user.get_active_space().food_inherit.all(), many=True).data
def get_food_children_exist(self, obj):
space = getattr(self.context.get('request', None), 'space', None)
return Food.objects.filter(depth__gt=0, space=space).exists()
def update(self, instance, validated_data):
with scopes_disabled():
return super().update(instance, validated_data)
def create(self, validated_data):
raise ValidationError('Cannot create using this endpoint')
class Meta:
model = UserPreference
fields = (
'user', 'theme', 'nav_color', 'default_unit', 'default_page', 'use_fractions', 'use_kj',
'plan_share',
'ingredient_decimals', 'comments', 'shopping_auto_sync', 'mealplan_autoadd_shopping',
'food_inherit_default', 'default_delay',
'mealplan_autoinclude_related', 'mealplan_autoexclude_onhand', 'shopping_share', 'shopping_recent_days',
'csv_delim', 'csv_prefix',
'filter_to_supermarket', 'shopping_add_onhand', 'left_handed', 'food_children_exist'
)
class StorageSerializer(SpacedModelSerializer): class StorageSerializer(SpacedModelSerializer):
def create(self, validated_data): def create(self, validated_data):

View File

@ -32,15 +32,23 @@
{% for us in request.user.userspace_set.all %} {% for us in request.user.userspace_set.all %}
<div class="card"> <div class="card">
{% if us.space.image and us.space.image.is_image %}
<img style="height: 15vh; object-fit: cover" src="{{ us.space.image.file.url }}"
class="card-img-top" alt="Image">
{% else %}
<img style="height: 15vh; object-fit: cover" src="{% static 'assets/recipe_no_image.svg' %}"
class="card-img-top" alt="Image">
{% endif %}
<div class="card-body"> <div class="card-body">
<h5 class="card-title"><a <h5 class="card-title"><a
href="{% url 'view_switch_space' us.space.id %}">{{ us.space.name }}</a> href="{% url 'view_switch_space' us.space.id %}">{{ us.space.name }}</a>
</h5> </h5>
{# {% if us.active %}#} {# {% if us.active %}#}
{# <i class="far fa-dot-circle fa-fw"></i>#} {# <i class="far fa-dot-circle fa-fw"></i>#}
{# {% else %}#} {# {% else %}#}
{# <i class="far fa-circle fa-fw"></i>#} {# <i class="far fa-circle fa-fw"></i>#}
{# {% endif %}#} {# {% endif %}#}
<p class="card-text"><small <p class="card-text"><small
class="text-muted">{% trans 'Owner' %}: {{ us.space.created_by }}</small> class="text-muted">{% trans 'Owner' %}: {{ us.space.created_by }}</small>
{% if us.space.created_by != us.user %} {% if us.space.created_by != us.user %}

View File

@ -141,6 +141,13 @@
<label>{{ $t('Message') }}</label> <label>{{ $t('Message') }}</label>
<b-form-textarea v-model="space.message"></b-form-textarea> <b-form-textarea v-model="space.message"></b-form-textarea>
<label>{{ $t('Image') }}</label>
<generic-multiselect :initial_single_selection="space.image"
:model="Models.USERFILE"
:multiple="false"
@change="space.image = $event.val;"></generic-multiselect>
<br/>
<b-form-checkbox v-model="space.show_facet_count"> Facet Count</b-form-checkbox> <b-form-checkbox v-model="space.show_facet_count"> Facet Count</b-form-checkbox>
<span class="text-muted small">{{ $t('facet_count_info') }}</span><br/> <span class="text-muted small">{{ $t('facet_count_info') }}</span><br/>