diff --git a/profile/migrations/0003_auto_20171213_1737.py b/profile/migrations/0003_auto_20171213_1737.py new file mode 100644 index 0000000000000000000000000000000000000000..1d4de59c5312a4407eff36f2a9459bd550e2d008 --- /dev/null +++ b/profile/migrations/0003_auto_20171213_1737.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.3 on 2017-12-13 17:37 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('profile', '0002_auto_20171129_1828'), + ] + + operations = [ + migrations.RemoveField( + model_name='profile', + name='biography', + ), + migrations.RemoveField( + model_name='profile', + name='cba_url', + ), + migrations.RemoveField( + model_name='profile', + name='dorftv_url', + ), + migrations.RemoveField( + model_name='profile', + name='facebook_url', + ), + migrations.RemoveField( + model_name='profile', + name='googleplus_url', + ), + migrations.RemoveField( + model_name='profile', + name='height', + ), + migrations.RemoveField( + model_name='profile', + name='image', + ), + migrations.RemoveField( + model_name='profile', + name='linkedin_url', + ), + migrations.RemoveField( + model_name='profile', + name='ppoi', + ), + migrations.RemoveField( + model_name='profile', + name='twitter_url', + ), + migrations.RemoveField( + model_name='profile', + name='website', + ), + migrations.RemoveField( + model_name='profile', + name='width', + ), + migrations.RemoveField( + model_name='profile', + name='youtube_url', + ), + ] diff --git a/profile/models.py b/profile/models.py index bcb5ebd4b4c84f52fe8b1706c8d808d7c7b749be..0a2d867c596bd1e2d02d25a810879b6413e416bb 100644 --- a/profile/models.py +++ b/profile/models.py @@ -12,21 +12,8 @@ from tinymce import models as tinymce_models class Profile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile', editable=False) - biography = tinymce_models.HTMLField(_("Biography"), blank=True, null=True, help_text=_("Describe yourself and your fields of interest in a few sentences.")) - website = models.URLField(_("Website"), blank=True, help_text=_("URL to your personal website.")) - googleplus_url = models.URLField(_("Google+ URL"), blank=True, help_text=_("URL to your Google+ profile.")) - facebook_url = models.URLField(_("Facebook URL"), blank=True, help_text=_("URL to your Facebook profile.")) - twitter_url = models.URLField(_("Twitter URL"), blank=True, help_text=_("URL to your Twitter profile.")) - linkedin_url = models.URLField(_("LinkedIn URL"), blank=True, help_text=_("URL to your LinkedIn profile.")) - youtube_url = models.URLField(_("Youtube URL"), blank=True, help_text=_("URL to your Youtube channel.")) - dorftv_url = models.URLField(_("DorfTV URL"), blank=True, help_text=_("URL to your dorfTV channel.")) - cba_url = models.URLField(_("CBA URL"), blank=True, help_text=_("URL to your CBA profile.")) cba_username = models.CharField(_("CBA Username"), blank=True, max_length=60, help_text=_("Your username in CBA. This is necessary for uploading files to your account.")) cba_user_token = models.CharField(_("CBA Token"), blank=True, max_length=255, help_text=_("The CBA upload token for your account. This is NOT your password which you use to log into CBA!")) - ppoi = PPOIField('Image PPOI') - height = models.PositiveIntegerField('Image Height', blank=True, null=True, editable=False) - width = models.PositiveIntegerField('Image Width', blank=True, null=True,editable=False) - image = VersatileImageField(_("Profile picture"), blank=True, null=True, upload_to='user_images', width_field='width', height_field='height', ppoi_field='ppoi', help_text=_("Upload a picture of yourself. Images are automatically cropped around the 'Primary Point of Interest'. Click in the image to change it and press Save.")) def __str__(self): return self.user.username @@ -35,9 +22,4 @@ class Profile(models.Model): db_table = 'profile' def save(self, *args, **kwargs): - super(Profile, self).save(*args, **kwargs) - - # Generate thumbnails - if self.image.name and settings.THUMBNAIL_SIZES: - for size in settings.THUMBNAIL_SIZES: - thumbnail = self.image.crop[size].name \ No newline at end of file + super(Profile, self).save(*args, **kwargs) \ No newline at end of file diff --git a/profile/serializers.py b/profile/serializers.py new file mode 100644 index 0000000000000000000000000000000000000000..6cee555320d7d1aae076b0a7d4f989f6623a37d9 --- /dev/null +++ b/profile/serializers.py @@ -0,0 +1,8 @@ +from django.contrib.auth.models import User +from rest_framework import serializers +from profile.models import Profile + +class ProfileSerializer(serializers.ModelSerializer): + class Meta: + model = Profile + fields = '__all__' \ No newline at end of file diff --git a/profile/urls.py b/profile/urls.py index 7ac3efa351fc14074722a1b54094f59a3b786351..ef961e396751416108478255257a693492979967 100644 --- a/profile/urls.py +++ b/profile/urls.py @@ -1,5 +1,9 @@ from django.contrib import admin +from rest_framework import routers admin.autodiscover() -urlpatterns = [] \ No newline at end of file +urlpatterns = [] + +router = routers.DefaultRouter() +router.register(r'users', APIUserViewSet) \ No newline at end of file diff --git a/program/admin.py b/program/admin.py index c3760334ea5f58169f150f7acdd2578cd62165a7..9d4bff8fa9be27543053b0d8f8e00980f1b9f980 100644 --- a/program/admin.py +++ b/program/admin.py @@ -81,7 +81,7 @@ class RTRCategoryAdmin(admin.ModelAdmin): class HostAdmin(admin.ModelAdmin): - list_display = ('name',) + list_display = ('name','email',) list_filter = (ActiveHostsFilter, 'is_always_visible',) diff --git a/program/migrations/0016_auto_20171213_1737.py b/program/migrations/0016_auto_20171213_1737.py new file mode 100644 index 0000000000000000000000000000000000000000..c87b746ced70f2a609271de34e125fd891ebd6d5 --- /dev/null +++ b/program/migrations/0016_auto_20171213_1737.py @@ -0,0 +1,87 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.3 on 2017-12-13 17:37 +from __future__ import unicode_literals + +from django.db import migrations, models +import tinymce.models +import versatileimagefield.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('program', '0015_note_audio_url'), + ] + + operations = [ + migrations.AddField( + model_name='host', + name='biography', + field=tinymce.models.HTMLField(blank=True, help_text='Describe yourself and your fields of interest in a few sentences.', null=True, verbose_name='Biography'), + ), + migrations.AddField( + model_name='host', + name='cba_url', + field=models.URLField(blank=True, help_text='URL to your CBA profile.', verbose_name='CBA URL'), + ), + migrations.AddField( + model_name='host', + name='dorftv_url', + field=models.URLField(blank=True, help_text='URL to your dorfTV channel.', verbose_name='DorfTV URL'), + ), + migrations.AddField( + model_name='host', + name='facebook_url', + field=models.URLField(blank=True, help_text='URL to your Facebook profile.', verbose_name='Facebook URL'), + ), + migrations.AddField( + model_name='host', + name='googleplus_url', + field=models.URLField(blank=True, help_text='URL to your Google+ profile.', verbose_name='Google+ URL'), + ), + migrations.AddField( + model_name='host', + name='height', + field=models.PositiveIntegerField(blank=True, editable=False, null=True, verbose_name='Image Height'), + ), + migrations.AddField( + model_name='host', + name='image', + field=versatileimagefield.fields.VersatileImageField(blank=True, height_field='height', help_text="Upload a picture of yourself. Images are automatically cropped around the 'Primary Point of Interest'. Click in the image to change it and press Save.", null=True, upload_to='user_images', verbose_name='Profile picture', width_field='width'), + ), + migrations.AddField( + model_name='host', + name='linkedin_url', + field=models.URLField(blank=True, help_text='URL to your LinkedIn profile.', verbose_name='LinkedIn URL'), + ), + migrations.AddField( + model_name='host', + name='ppoi', + field=versatileimagefield.fields.PPOIField(default='0.5x0.5', editable=False, max_length=20, verbose_name='Image PPOI'), + ), + migrations.AddField( + model_name='host', + name='twitter_url', + field=models.URLField(blank=True, help_text='URL to your Twitter profile.', verbose_name='Twitter URL'), + ), + migrations.AddField( + model_name='host', + name='width', + field=models.PositiveIntegerField(blank=True, editable=False, null=True, verbose_name='Image Width'), + ), + migrations.AddField( + model_name='host', + name='youtube_url', + field=models.URLField(blank=True, help_text='URL to your Youtube channel.', verbose_name='Youtube URL'), + ), + migrations.AlterField( + model_name='host', + name='website', + field=models.URLField(blank=True, help_text='URL to your personal website.', verbose_name='Website'), + ), + 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 bcf6d4b2e3fde7c38c57344be2d022bad5cccd00..570169a57b86308e5e5dded59c44643fdc2a584c 100644 --- a/program/models.py +++ b/program/models.py @@ -243,7 +243,19 @@ class Host(models.Model): name = models.CharField(_("Name"), max_length=128) is_always_visible = models.BooleanField(_("Is always visible"), default=False) email = models.EmailField(_("E-Mail"), blank=True) - website = models.URLField(_("Website"), 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.")) + googleplus_url = models.URLField(_("Google+ URL"), blank=True, help_text=_("URL to your Google+ profile.")) + facebook_url = models.URLField(_("Facebook URL"), blank=True, help_text=_("URL to your Facebook profile.")) + twitter_url = models.URLField(_("Twitter URL"), blank=True, help_text=_("URL to your Twitter profile.")) + linkedin_url = models.URLField(_("LinkedIn URL"), blank=True, help_text=_("URL to your LinkedIn profile.")) + youtube_url = models.URLField(_("Youtube URL"), blank=True, help_text=_("URL to your Youtube channel.")) + dorftv_url = models.URLField(_("DorfTV URL"), blank=True, help_text=_("URL to your dorfTV channel.")) + cba_url = models.URLField(_("CBA URL"), blank=True, help_text=_("URL to your CBA profile.")) + ppoi = PPOIField('Image PPOI') + height = models.PositiveIntegerField('Image Height', blank=True, null=True, editable=False) + width = models.PositiveIntegerField('Image Width', blank=True, null=True,editable=False) + image = VersatileImageField(_("Profile picture"), blank=True, null=True, upload_to='user_images', width_field='width', height_field='height', ppoi_field='ppoi', help_text=_("Upload a picture of yourself. Images are automatically cropped around the 'Primary Point of Interest'. Click in the image to change it and press Save.")) class Meta: ordering = ('name',) @@ -259,6 +271,14 @@ class Host(models.Model): def active_shows(self): return self.shows.filter(schedules__until__gt=datetime.today()) + def save(self, *args, **kwargs): + super(Host, self).save(*args, **kwargs) + + # Generate thumbnails + if self.image.name and settings.THUMBNAIL_SIZES: + for size in settings.THUMBNAIL_SIZES: + thumbnail = self.image.crop[size].name + class Show(models.Model): predecessor = models.ForeignKey('self', blank=True, null=True, related_name='successors', verbose_name=_("Predecessor")) @@ -567,7 +587,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(_("WH"), default=False) + is_repetition = models.BooleanField(_("REP"), default=False) playlist_id = models.IntegerField(_("Playlist ID"), null=True) objects = TimeSlotManager() @@ -580,7 +600,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 = ' ' + _('WH') 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 2850bb3961d782df84b0cc6eca31e0a6449a4e79..47594149f97eea514fc6da87c9c1e592663ac6d8 100644 --- a/program/serializers.py +++ b/program/serializers.py @@ -4,12 +4,7 @@ from rest_framework import serializers, status from rest_framework.response import Response from program.models import Show, Schedule, TimeSlot, Category, RTRCategory, Host, Language, Topic, MusicFocus, Note, Type, Language from profile.models import Profile - - -class ProfileSerializer(serializers.ModelSerializer): - class Meta: - model = Profile - fields = '__all__' +from profile.serializers import ProfileSerializer class UserSerializer(serializers.ModelSerializer): @@ -31,16 +26,8 @@ class UserSerializer(serializers.ModelSerializer): instance.last_name = validated_data.get('last_name', instance.last_name) instance.email = validated_data.get('email', instance.email) + # TODO: How to hook into this from ProfileSerializer without having to call it here? profile = Profile.objects.get(user=instance.id) - profile.biography = validated_data['profile'].get('biography') - profile.website = validated_data['profile'].get('website') - profile.googleplus_url = validated_data['profile'].get('googleplus_url') - profile.facebook_url = validated_data['profile'].get('facebook_url') - profile.twitter_url = validated_data['profile'].get('twitter_url') - profile.linkedin_url = validated_data['profile'].get('linkedin_url') - profile.youtube_url = validated_data['profile'].get('youtube_url') - profile.dorftv_url = validated_data['profile'].get('dorftv_url') - profile.cba_url = validated_data['profile'].get('cba_url') profile.cba_username = validated_data['profile'].get('cba_username') profile.cba_user_token = validated_data['profile'].get('cba_user_token') profile.save() @@ -60,6 +47,27 @@ class HostSerializer(serializers.ModelSerializer): model = Host fields = '__all__' + def update(self, instance, validated_data): + """ + Update and return an existing Host instance, given the validated data. + """ + instance.name = validated_data.get('name', instance.name) + instance.is_always_visible = validated_data.get('is_always_visible', instance.is_always_visible) + instance.email = validated_data.get('email', instance.email) + instance.website = validated_data.get('website', instance.website) + instance.biography = validated_data.get('biography', instance.biography) + instance.googleplus_url = validated_data.get('googleplus_url', instance.googleplus_url) + instance.facebook_url = validated_data.get('facebook_url', instance.facebook_url) + instance.twitter_url = validated_data.get('twitter_url', instance.twitter_url) + instance.linkedin_url = validated_data.get('linkedin_url', instance.linkedin_url) + instance.youtube_url = validated_data.get('youtube_url', instance.youtube_url) + instance.dorftv_url = validated_data.get('dorftv_url', instance.dorftv_url) + instance.cba_url = validated_data.get('cba_url', instance.cba_url) + instance.image = validated_data.get('image', instance.image) + + instance.save() + return instance + class LanguageSerializer(serializers.ModelSerializer): class Meta: diff --git a/program/views.py b/program/views.py index bdd3534b30a577ce4c790c35f4ad843e60fa5c69..85f468dc0581cccf9f4401cff4221a862ca264e5 100644 --- a/program/views.py +++ b/program/views.py @@ -18,7 +18,6 @@ from rest_framework.response import Response from oauth2_provider.contrib.rest_framework import TokenHasReadWriteScope, TokenHasScope from program.models import Type, MusicFocus, Language, Note, Show, Category, RTRCategory, Topic, TimeSlot, Host, Schedule -from profile.models import Profile from program.serializers import TypeSerializer, LanguageSerializer, MusicFocusSerializer, NoteSerializer, ShowSerializer, CategorySerializer, RTRCategorySerializer, TopicSerializer, TimeSlotSerializer, HostSerializer, UserSerializer from program.utils import tofirstdayinisoweek, get_cached_shows