diff --git a/program/admin.py b/program/admin.py index 152fb677dd5b017ee5f48470bf00e9cea9c202ca..3035001a7c49e006bad96dc2908dadf16df49060 100644 --- a/program/admin.py +++ b/program/admin.py @@ -51,38 +51,44 @@ class ActiveHostsFilter(ActivityFilter): class TypeAdmin(admin.ModelAdmin): - list_display = ('type', 'admin_color', 'enabled') + list_display = ('type', 'admin_color', 'is_active') + list_filter = ('is_active',) prepopulated_fields = {'slug': ('type',)} class MusicFocusAdmin(admin.ModelAdmin): form = MusicFocusForm - list_display = ('focus', 'abbrev', 'admin_buttons') + list_display = ('focus', 'abbrev', 'admin_buttons', 'is_active') + list_filter = ('is_active',) prepopulated_fields = {'slug': ('focus',)} class CategoryAdmin(admin.ModelAdmin): - list_display = ('category', 'abbrev', 'admin_buttons') + list_display = ('category', 'abbrev', 'admin_buttons', 'is_active') + list_filter = ('is_active',) prepopulated_fields = {'slug': ('category',)} class LanguageAdmin(admin.ModelAdmin): - list_display = ('name',) + list_display = ('name', 'is_active') + list_filter = ('is_active',) class TopicAdmin(admin.ModelAdmin): - list_display = ('topic', 'abbrev', 'admin_buttons') + list_display = ('topic', 'abbrev', 'admin_buttons', 'is_active') + list_filter = ('is_active',) prepopulated_fields = {'slug': ('topic',)} class RTRCategoryAdmin(admin.ModelAdmin): - list_display = ('rtrcategory', 'abbrev', ) + list_display = ('rtrcategory', 'abbrev', 'is_active' ) + list_filter = ('is_active',) prepopulated_fields = {'slug': ('rtrcategory',)} class HostAdmin(admin.ModelAdmin): - list_display = ('name','email',) - list_filter = (ActiveHostsFilter, 'is_always_visible',) + list_display = ('name', 'email', 'is_active') + list_filter = (ActiveHostsFilter, 'is_active',) def get_queryset(self, request): if request.user.is_superuser: @@ -145,13 +151,13 @@ class NoteAdmin(admin.ModelAdmin): # Common users only see shows they own if not request.user.is_superuser: - kwargs['queryset'] = Show.objects.filter(pk__in=request.user.shows.all()) + kwargs['queryset'] = Show.objects.filter(pk__in=request.user.shows.all(), is_active=True) if db_field.name == 'host': # Common users only see hosts of shows they own if not request.user.is_superuser: - kwargs['queryset'] = Host.objects.filter(shows__in=request.user.shows.all()).distinct() + kwargs['queryset'] = Host.objects.filter(shows__in=request.user.shows.all(), is_active=True).distinct() return super(NoteAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs) @@ -257,12 +263,41 @@ class ShowAdmin(admin.ModelAdmin): except ValueError: show_id = None + print(db_field.name) + if db_field.name == 'predecessor' and show_id: kwargs['queryset'] = Show.objects.exclude(pk=show_id) + if db_field.name == 'type': + kwargs['queryset'] = Type.objects.filter(is_active=True) + + if db_field.name == 'rtrcategory': + kwargs['queryset'] = RTRCategory.objects.filter(is_active=True) + return super(ShowAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs) + def formfield_for_manytomany(self, db_field, request, **kwargs): + + if db_field.name == 'hosts': + kwargs["queryset"] = Host.objects.filter(is_active=True) + + if db_field.name == 'language': + kwargs["queryset"] = Language.objects.filter(is_active=True) + + if db_field.name == 'category': + kwargs["queryset"] = Category.objects.filter(is_active=True) + + if db_field.name == 'topic': + kwargs["queryset"] = Topic.objects.filter(is_active=True) + + if db_field.name == 'musicfocus': + kwargs["queryset"] = MusicFocus.objects.filter(is_active=True) + + + return super(ShowAdmin, self).formfield_for_manytomany(db_field, request, **kwargs) + + def save_formset(self, request, form, formset, change): """ Is called after the "save show"-form or collision-form were submitted diff --git a/program/migrations/0013_auto_20180124_1748.py b/program/migrations/0013_auto_20180124_1748.py new file mode 100644 index 0000000000000000000000000000000000000000..5a3ecdffdd22c0079f9b70e78241e8889d93fc49 --- /dev/null +++ b/program/migrations/0013_auto_20180124_1748.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.3 on 2018-01-24 17:48 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('program', '0012_auto_20180104_0005'), + ] + + operations = [ + migrations.RemoveField( + model_name='host', + name='is_always_visible', + ), + migrations.RemoveField( + model_name='type', + name='enabled', + ), + migrations.AddField( + model_name='category', + name='is_active', + field=models.BooleanField(default=True, verbose_name='Is active?'), + ), + migrations.AddField( + model_name='host', + name='is_active', + field=models.BooleanField(default=True, verbose_name='Is active?'), + ), + migrations.AddField( + model_name='language', + name='is_active', + field=models.BooleanField(default=True, verbose_name='Is active?'), + ), + migrations.AddField( + model_name='musicfocus', + name='is_active', + field=models.BooleanField(default=True, verbose_name='Is active?'), + ), + migrations.AddField( + model_name='rtrcategory', + name='is_active', + field=models.BooleanField(default=True, verbose_name='Is active?'), + ), + migrations.AddField( + model_name='topic', + name='is_active', + field=models.BooleanField(default=True, verbose_name='Is active?'), + ), + migrations.AddField( + model_name='type', + name='is_active', + field=models.BooleanField(default=True, verbose_name='Is active?'), + ), + migrations.AlterField( + model_name='timeslot', + name='is_repetition', + field=models.BooleanField(default=False, verbose_name='(REP)'), + ), + ] diff --git a/program/models.py b/program/models.py index 670eb5ae01274ec85539ee2d120c9b0cc4fff39a..397ae116ddfc105f9f6178d729f1b1dc9b3dde3e 100644 --- a/program/models.py +++ b/program/models.py @@ -23,9 +23,9 @@ from pv.settings import SECRET_KEY, AUTO_SET_UNTIL_DATE_TO_END_OF_YEAR, AUTO_SET class Type(models.Model): type = models.CharField(_("Type"), max_length=32) slug = models.SlugField(_("Slug"), max_length=32, unique=True) + is_active = models.BooleanField(_("Is active?"), default=True) color = models.CharField(_("Color"), max_length=7, default='#ffffff') text_color = models.CharField(_("Text color"), max_length=7, default='#000000') - enabled = models.BooleanField(_("Enabled"), default=True) class Meta: ordering = ('type',) @@ -47,6 +47,7 @@ class Category(models.Model): category = models.CharField(_("Category"), max_length=32) abbrev = models.CharField(_("Abbreviation"), max_length=4, unique=True) slug = models.SlugField(_("Slug"), max_length=32, unique=True) + is_active = models.BooleanField(_("Is active?"), default=True) color = models.TextField(_("Color"), max_length=7, blank=True) description = models.TextField(_("Description"), blank=True) button = models.ImageField(_("Button image"), blank=True, null=True, upload_to='buttons') @@ -106,6 +107,7 @@ class Topic(models.Model): topic = models.CharField(_("Topic"), max_length=32) abbrev = models.CharField(_("Abbreviation"), max_length=4, unique=True) slug = models.SlugField(_("Slug"), max_length=32, unique=True) + is_active = models.BooleanField(_("Is active?"), default=True) button = models.ImageField(_("Button image"), blank=True, null=True, upload_to='buttons') button_hover = models.ImageField(_("Button image (hover)"), blank=True, null=True, upload_to='buttons') big_button = models.ImageField(_("Big button image"), blank=True, null=True, upload_to='buttons') @@ -163,6 +165,7 @@ class MusicFocus(models.Model): focus = models.CharField(_("Focus"), max_length=32) abbrev = models.CharField(_("Abbreviation"), max_length=4, unique=True) slug = models.SlugField(_("Slug"), max_length=32, unique=True) + is_active = models.BooleanField(_("Is active?"), default=True) button = models.ImageField(_("Button image"), blank=True, null=True, upload_to='buttons') button_hover = models.ImageField(_("Button image (hover)"), blank=True, null=True, upload_to='buttons') big_button = models.ImageField(_("Big button image"), blank=True, null=True, upload_to='buttons') @@ -220,6 +223,7 @@ class RTRCategory(models.Model): rtrcategory = models.CharField(_("RTR Category"), max_length=32) abbrev = models.CharField(_("Abbreviation"), max_length=4, unique=True) slug = models.SlugField(_("Slug"), max_length=32, unique=True) + is_active = models.BooleanField(_("Is active?"), default=True) class Meta: ordering = ('rtrcategory',) @@ -232,6 +236,7 @@ class RTRCategory(models.Model): class Language(models.Model): name = models.CharField(_("Language"), max_length=32) + is_active = models.BooleanField(_("Is active?"), default=True) class Meta: ordering = ('language',) @@ -244,7 +249,7 @@ class Language(models.Model): class Host(models.Model): name = models.CharField(_("Name"), max_length=128) - is_always_visible = models.BooleanField(_("Is always visible"), default=False) # Deprecated? + is_active = models.BooleanField(_("Is active?"), default=True) email = models.EmailField(_("E-Mail"), blank=True) website = models.URLField(_("Website"), blank=True, help_text=_("URL to your personal website.")) biography = tinymce_models.HTMLField(_("Biography"), blank=True, null=True, help_text=_("Describe yourself and your fields of interest in a few sentences.")) @@ -295,8 +300,6 @@ class Host(models.Model): class Show(models.Model): - # TODO: add field 'is_always_visible'? - # -> categories predecessor = models.ForeignKey('self', blank=True, null=True, related_name='successors', verbose_name=_("Predecessor")) hosts = models.ManyToManyField(Host, blank=True, related_name='shows', verbose_name=_("Hosts")) owners = models.ManyToManyField(User, blank=True, related_name='shows', verbose_name=_("Owners")) @@ -1091,7 +1094,7 @@ class TimeSlot(models.Model): end = models.DateTimeField(_("End time")) show = models.ForeignKey(Show, editable=False, related_name='timeslots') memo = models.TextField(_("Memo"), blank=True) - is_repetition = models.BooleanField(_("REP"), default=False) + is_repetition = models.BooleanField(_("(REP)"), default=False) playlist_id = models.IntegerField(_("Playlist ID"), null=True) objects = TimeSlotManager() @@ -1104,7 +1107,7 @@ class TimeSlot(models.Model): def __str__(self): start = self.start.strftime('%a, %d.%m.%Y %H:%M') end = self.end.strftime('%H:%M') - is_repetition = ' (' + _('REP') + ')' if self.schedule.is_repetition is 1 else '' + is_repetition = ' ' + _('(REP)') if self.schedule.is_repetition is 1 else '' return '%s - %s %s (%s)' % (start, end, is_repetition, self.show.name) diff --git a/program/serializers.py b/program/serializers.py index a1b6936b18455fada66d5018a27eacb4d472fb65..53d87161bafae20780cb01cd4854692ee1c6970d 100644 --- a/program/serializers.py +++ b/program/serializers.py @@ -82,6 +82,7 @@ class CategorySerializer(serializers.ModelSerializer): instance.slug = validated_data.get('slug', instance.slug) instance.color = validated_data.get('color', instance.color) instance.description = validated_data.get('description', instance.description) + instance.is_active = validated_data.get('is_active', instance.is_active) instance.save() return instance @@ -99,7 +100,7 @@ class HostSerializer(serializers.ModelSerializer): """ instance.name = validated_data.get('name', instance.name) - instance.is_always_visible = validated_data.get('is_always_visible', instance.is_always_visible) + instance.is_active = validated_data.get('is_active', instance.is_active) instance.email = validated_data.get('email', instance.email) instance.website = validated_data.get('website', instance.website) instance.biography = validated_data.get('biography', instance.biography) @@ -127,6 +128,7 @@ class LanguageSerializer(serializers.ModelSerializer): Update and return an existing Language instance, given the validated data. """ instance.name = validated_data.get('name', instance.name) + instance.is_active = validated_data.get('is_active', instance.is_active) instance.save() return instance @@ -145,6 +147,7 @@ class TopicSerializer(serializers.ModelSerializer): instance.topic = validated_data.get('topic', instance.topic) instance.abbrev = validated_data.get('abbrev', instance.abbrev) instance.slug = validated_data.get('slug', instance.slug) + instance.is_active = validated_data.get('is_active', instance.is_active) instance.save() return instance @@ -163,6 +166,7 @@ class MusicFocusSerializer(serializers.ModelSerializer): instance.focus = validated_data.get('focus', instance.focus) instance.abbrev = validated_data.get('abbrev', instance.abbrev) instance.slug = validated_data.get('slug', instance.slug) + instance.is_active = validated_data.get('is_active', instance.is_active) instance.save() return instance @@ -182,7 +186,7 @@ class TypeSerializer(serializers.ModelSerializer): instance.slug = validated_data.get('slug', instance.slug) instance.color = validated_data.get('color', instance.color) instance.text_color = validated_data.get('text_color', instance.text_color) - instance.enabled = validated_data.get('enabled', instance.enabled) + instance.is_active = validated_data.get('is_active', instance.is_active) instance.save() return instance @@ -201,6 +205,7 @@ class RTRCategorySerializer(serializers.ModelSerializer): instance.rtrcategory = validated_data.get('rtrcategory', instance.rtrcategory) instance.abbrev = validated_data.get('abbrev', instance.abbrev) instance.slug = validated_data.get('slug', instance.slug) + instance.is_active = validated_data.get('is_active', instance.is_active) instance.save() return instance @@ -283,7 +288,6 @@ class ShowSerializer(serializers.HyperlinkedModelSerializer): return instance -# TODO: collision detection class ScheduleSerializer(serializers.ModelSerializer): rrule = serializers.PrimaryKeyRelatedField(queryset=RRule.objects.all()) show = serializers.PrimaryKeyRelatedField(queryset=Show.objects.all()) diff --git a/program/templatetags/content_boxes.py b/program/templatetags/content_boxes.py index f45ebaee390fa1941f6e26da0836f80bd66da007..ea068628d0b26c53ce0d8556d2fa0db8454a940c 100644 --- a/program/templatetags/content_boxes.py +++ b/program/templatetags/content_boxes.py @@ -7,7 +7,7 @@ register = template.Library() @register.inclusion_tag('boxes/type.html') def type(): - return {'type_list': Type.objects.filter(enabled=True)} + return {'type_list': Type.objects.filter(is_active=True)} @register.inclusion_tag('boxes/musicfocus.html') diff --git a/program/views.py b/program/views.py index b1e61b6d15ad1f6da134553f38fe0935f32289c8..f83da0083905a8c9b3ed8a43936eceae1d71d50d 100644 --- a/program/views.py +++ b/program/views.py @@ -29,7 +29,7 @@ class CalendarView(TemplateView): # Deprecated class HostListView(ListView): context_object_name = 'host_list' - queryset = Host.objects.filter(Q(is_always_visible=True) | Q(shows__schedules__until__gt=datetime.now())).distinct() + queryset = Host.objects.filter(Q(is_active=True) | Q(shows__schedules__until__gt=datetime.now())).distinct() template_name = 'host_list.html' @@ -207,7 +207,7 @@ class StylesView(TemplateView): def get_context_data(self, **kwargs): context = super(StylesView, self).get_context_data(**kwargs) - context['types'] = Type.objects.filter(enabled=True) + context['types'] = Type.objects.filter(is_active=True) context['musicfocus'] = MusicFocus.objects.all() context['category'] = Category.objects.all() context['topic'] = Topic.objects.all() @@ -977,8 +977,9 @@ class APINoteViewSet(viewsets.ModelViewSet): class APICategoryViewSet(viewsets.ModelViewSet): """ - /api/v1/categories/ Returns all categories (GET, POST) - /api/v1/categories/1 Returns a category by its ID (GET, PUT, DELETE) + /api/v1/categories/ Returns all categories (GET, POST) + /api/v1/categories/?active=true Returns all active categories (GET) + /api/v1/categories/1 Returns a category by its ID (GET, PUT, DELETE) """ queryset = Category.objects.all() @@ -986,12 +987,20 @@ class APICategoryViewSet(viewsets.ModelViewSet): permission_classes = [permissions.DjangoModelPermissionsOrAnonReadOnly] required_scopes = ['categories'] + def get_queryset(self): + '''Filters''' + + if self.request.GET.get('active') == 'true': + return Category.objects.filter(is_active=True) + + return Category.objects.all() class APITypeViewSet(viewsets.ModelViewSet): """ - /api/v1/types/ Returns all types (GET, POST) - /api/v1/types/1 Returns a type by its ID (GET, PUT, DELETE) + /api/v1/types/ Returns all types (GET, POST) + /api/v1/types/?active=true Returns all active types (GET) + /api/v1/types/1 Returns a type by its ID (GET, PUT, DELETE) """ queryset = Type.objects.all() @@ -999,12 +1008,20 @@ class APITypeViewSet(viewsets.ModelViewSet): permission_classes = [permissions.DjangoModelPermissionsOrAnonReadOnly] required_scopes = ['types'] + def get_queryset(self): + '''Filters''' + + if self.request.GET.get('active') == 'true': + return Type.objects.filter(is_active=True) + + return Type.objects.all() class APITopicViewSet(viewsets.ModelViewSet): """ - /api/v1/topics/ Returns all topics (GET, POST) - /api/v1/topics/1 Returns a topic by its ID (GET, PUT, DELETE) + /api/v1/topics/ Returns all topics (GET, POST) + /api/v1/topics/?active=true Returns all active topics (GET) + /api/v1/topics/1 Returns a topic by its ID (GET, PUT, DELETE) """ queryset = Topic.objects.all() @@ -1012,12 +1029,21 @@ class APITopicViewSet(viewsets.ModelViewSet): permission_classes = [permissions.DjangoModelPermissionsOrAnonReadOnly] required_scopes = ['topics'] + def get_queryset(self): + '''Filters''' + + if self.request.GET.get('active') == 'true': + return Topic.objects.filter(is_active=True) + + return Topic.objects.all() + class APIMusicFocusViewSet(viewsets.ModelViewSet): """ - /api/v1/musicfocus/ Returns all musicfocuses (GET, POST) - /api/v1/musicfocus/1 Returns a musicfocus by its ID (GET, PUT, DELETE) + /api/v1/musicfocus/ Returns all musicfocuses (GET, POST) + /api/v1/musicfocus/?active=true Returns all active musicfocuses (GET) + /api/v1/musicfocus/1 Returns a musicfocus by its ID (GET, PUT, DELETE) """ queryset = MusicFocus.objects.all() @@ -1025,12 +1051,21 @@ class APIMusicFocusViewSet(viewsets.ModelViewSet): permission_classes = [permissions.DjangoModelPermissionsOrAnonReadOnly] required_scopes = ['musicfocus'] + def get_queryset(self): + '''Filters''' + + if self.request.GET.get('active') == 'true': + return MusicFocus.objects.filter(is_active=True) + + return MusicFocus.objects.all() + class APIRTRCategoryViewSet(viewsets.ModelViewSet): """ - /api/v1/rtrcategories/ Returns all rtrcategories (GET, POST) - /api/v1/rtrcategories/1 Returns a rtrcategory by its ID (GET, PUT, DELETE) + /api/v1/rtrcategories/ Returns all rtrcategories (GET, POST) + /api/v1/rtrcategories/?active=true Returns all active rtrcategories (GET) + /api/v1/rtrcategories/1 Returns a rtrcategory by its ID (GET, PUT, DELETE) """ queryset = RTRCategory.objects.all() @@ -1038,11 +1073,21 @@ class APIRTRCategoryViewSet(viewsets.ModelViewSet): permission_classes = [permissions.DjangoModelPermissionsOrAnonReadOnly] required_scopes = ['rtrcategories'] + def get_queryset(self): + '''Filters''' + + if self.request.GET.get('active') == 'true': + return RTRCategory.objects.filter(is_active=True) + + return RTRCategory.objects.all() + + class APILanguageViewSet(viewsets.ModelViewSet): """ - /api/v1/languages/ Returns all languages (GET, POST) - /api/v1/languages/1 Returns a language by its ID (GET, PUT, DELETE) + /api/v1/languages/ Returns all languages (GET, POST) + /api/v1/languages/?active=true Returns all active languages (GET) + /api/v1/languages/1 Returns a language by its ID (GET, PUT, DELETE) """ queryset = Language.objects.all() @@ -1050,14 +1095,32 @@ class APILanguageViewSet(viewsets.ModelViewSet): permission_classes = [permissions.DjangoModelPermissionsOrAnonReadOnly] required_scopes = ['languages'] + def get_queryset(self): + '''Filters''' + + if self.request.GET.get('active') == 'true': + return Language.objects.filter(is_active=True) + + return Language.objects.all() + + class APIHostViewSet(viewsets.ModelViewSet): """ - /api/v1/hosts/ Returns all hosts (GET, POST) - /api/v1/hosts/1 Returns a host by its ID (GET, PUT, DELETE) + /api/v1/hosts/ Returns all hosts (GET, POST) + /api/v1/hosts/?active=true Returns all active hosts (GET) + /api/v1/hosts/1 Returns a host by its ID (GET, PUT, DELETE) """ queryset = Host.objects.all() serializer_class = HostSerializer permission_classes = [permissions.DjangoModelPermissionsOrAnonReadOnly] - required_scopes = ['hosts'] \ No newline at end of file + required_scopes = ['hosts'] + + def get_queryset(self): + '''Filters''' + + if self.request.GET.get('active') == 'true': + return Host.objects.filter(is_active=True) + + return Host.objects.all() \ No newline at end of file