Skip to content
Snippets Groups Projects
Commit ef77b158 authored by Ingo Leindecker's avatar Ingo Leindecker
Browse files

Restricted read/write permissions to common users

See #23

- Let them only edit their own user profile and only certain fields
- Let them only edit shows they own and only certain fields
- Let them only edit own notes and only assign them to shows and timeslots they own

Removed some unused code and added some help texts to form fields.
parent b7e10ced
No related branches found
No related tags found
No related merge requests found
...@@ -10,19 +10,29 @@ class ProfileInline(admin.StackedInline): ...@@ -10,19 +10,29 @@ class ProfileInline(admin.StackedInline):
verbose_name_plural = 'Profile' verbose_name_plural = 'Profile'
fk_name = 'user' fk_name = 'user'
class ProfileUserAdmin(UserAdmin): class ProfileUserAdmin(UserAdmin):
inlines = (ProfileInline, ) inlines = (ProfileInline, )
def get_queryset(self, request): def get_queryset(self, request):
# Users can only edit their own profile '''Let common users only edit their own profile'''
if not request.user.is_superuser: if not request.user.is_superuser:
return super(UserAdmin, self).get_queryset(request).filter(pk=request.user.id) return super(UserAdmin, self).get_queryset(request).filter(pk=request.user.id)
return super(UserAdmin, self).get_queryset(request) return super(UserAdmin, self).get_queryset(request)
def get_readonly_fields(self, request, obj=None):
'''Limit field access for common users'''
if not request.user.is_superuser:
return ('username', 'is_staff', 'is_superuser', 'is_active', 'date_joined', 'last_login', 'groups', 'user_permissions')
return list()
def get_inline_instances(self, request, obj=None): def get_inline_instances(self, request, obj=None):
'''Append profile fields to UserAdmin'''
if not obj: if not obj:
return list() return list()
return super(ProfileUserAdmin, self).get_inline_instances(request, obj) return super(ProfileUserAdmin, self).get_inline_instances(request, obj)
admin.site.unregister(User) admin.site.unregister(User)
......
...@@ -12,21 +12,21 @@ from tinymce import models as tinymce_models ...@@ -12,21 +12,21 @@ from tinymce import models as tinymce_models
class Profile(models.Model): class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE) user = models.OneToOneField(User, on_delete=models.CASCADE)
biography = tinymce_models.HTMLField(_("Biography"), blank=True, null=True) 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) website = models.URLField(_("Website"), blank=True, help_text=_("URL to your personal website."))
googleplus_url = models.URLField(_("Google+ URL"), blank=True) googleplus_url = models.URLField(_("Google+ URL"), blank=True, help_text=_("URL to your Google+ profile."))
facebook_url = models.URLField(_("Facebook URL"), blank=True) facebook_url = models.URLField(_("Facebook URL"), blank=True, help_text=_("URL to your Facebook profile."))
twitter_url = models.URLField(_("Twitter URL"), blank=True) twitter_url = models.URLField(_("Twitter URL"), blank=True, help_text=_("URL to your Twitter profile."))
linkedin_url = models.URLField(_("LinkedIn URL"), blank=True) linkedin_url = models.URLField(_("LinkedIn URL"), blank=True, help_text=_("URL to your LinkedIn profile."))
youtube_url = models.URLField(_("Youtube URL"), blank=True) youtube_url = models.URLField(_("Youtube URL"), blank=True, help_text=_("URL to your Youtube channel."))
dorftv_url = models.URLField(_("DorfTV URL"), blank=True) dorftv_url = models.URLField(_("DorfTV URL"), blank=True, help_text=_("URL to your dorfTV channel."))
cba_url = models.URLField(_("CBA URL"), blank=True) 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) 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) 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') ppoi = PPOIField('Image PPOI')
height = models.PositiveIntegerField('Image Height', blank=True, null=True, editable=False) height = models.PositiveIntegerField('Image Height', blank=True, null=True, editable=False)
width = models.PositiveIntegerField('Image Width', 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') 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): def __str__(self):
return self.user.username return self.user.username
......
...@@ -5,7 +5,7 @@ from django.shortcuts import render ...@@ -5,7 +5,7 @@ from django.shortcuts import render
from django.conf import settings from django.conf import settings
from .models import Language, Type, MusicFocus, Category, Topic, RTRCategory, Host, Note, RRule, Schedule, Show, TimeSlot from .models import Language, Type, MusicFocus, Category, Topic, RTRCategory, Host, Note, RRule, Schedule, Show, TimeSlot
from .forms import MusicFocusForm, CollisionForm from .forms import MusicFocusForm
from datetime import date, datetime, time, timedelta from datetime import date, datetime, time, timedelta
...@@ -202,6 +202,14 @@ class ShowAdmin(admin.ModelAdmin): ...@@ -202,6 +202,14 @@ class ShowAdmin(admin.ModelAdmin):
'musicfocus', 'fallback_pool', 'cba_series_id', 'musicfocus', 'fallback_pool', 'cba_series_id',
) )
class Media:
js = [ settings.MEDIA_URL + 'js/calendar/lib/moment.min.js',
settings.MEDIA_URL + 'js/show_change.js', ]
css = { 'all': ('/program/styles.css',) }
def get_queryset(self, request): def get_queryset(self, request):
if request.user.is_superuser: if request.user.is_superuser:
# Superusers see all shows # Superusers see all shows
...@@ -212,11 +220,12 @@ class ShowAdmin(admin.ModelAdmin): ...@@ -212,11 +220,12 @@ class ShowAdmin(admin.ModelAdmin):
return super(ShowAdmin, self).get_queryset(request).filter(pk__in=shows) return super(ShowAdmin, self).get_queryset(request).filter(pk__in=shows)
class Media:
js = [ settings.MEDIA_URL + 'js/calendar/lib/moment.min.js',
settings.MEDIA_URL + 'js/show_change.js', ]
css = { 'all': ('/program/styles.css',) } def get_readonly_fields(self, request, obj=None):
'''Limit field access for common users'''
if not request.user.is_superuser:
return ('predecessor', 'type', 'hosts', 'owners', 'language', 'category', 'topic', 'musicfocus', 'rtrcategory')
return list()
def formfield_for_foreignkey(self, db_field, request=None, **kwargs): def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
...@@ -490,13 +499,16 @@ class ShowAdmin(admin.ModelAdmin): ...@@ -490,13 +499,16 @@ class ShowAdmin(admin.ModelAdmin):
Displays the collision form for the current schedule otherwise Displays the collision form for the current schedule otherwise
""" """
# Never check for collisions if not superuser
# Common users can't edit the formset, so save_formset() will never be called thus end_reached wasn't set yet
if not request.user.is_superuser:
self.end_reached = True
if self.end_reached: if self.end_reached:
return super(ShowAdmin, self).response_change(request, obj) return super(ShowAdmin, self).response_change(request, obj)
timeslots_to_collisions = list(zip(self.timeslots, self.collisions)) timeslots_to_collisions = list(zip(self.timeslots, self.collisions))
# myform = CollisionForm(self.timeslots, self.collisions)
return render(request, 'collisions.html', {'self' : self, 'obj': obj, 'request': request, return render(request, 'collisions.html', {'self' : self, 'obj': obj, 'request': request,
'timeslots': self.timeslots, 'timeslots': self.timeslots,
'collisions': self.collisions, 'collisions': self.collisions,
......
...@@ -5,16 +5,6 @@ from django.core.files.images import get_image_dimensions ...@@ -5,16 +5,6 @@ from django.core.files.images import get_image_dimensions
from program.models import MusicFocus, Category, Topic from program.models import MusicFocus, Category, Topic
# Couldn't manage call/validation for collision usecase.
class CollisionForm(forms.Form):
def __init__(self, timeslots, collisions, *args, **kwargs):
super(CollisionForm, self).__init__(*args, **kwargs)
for i in range(min(len(timeslots), len(timeslots))):
self.fields['resolved_' + str(i)] = forms.ChoiceField(widget=forms.RadioSelect,choices=((timeslots[i], timeslots[i]),(collisions[i], collisions[i])))
class FormWithButton(ModelForm): class FormWithButton(ModelForm):
def clean_button(self): def clean_button(self):
button = self.cleaned_data.get('button') button = self.cleaned_data.get('button')
......
...@@ -268,18 +268,18 @@ class Show(models.Model): ...@@ -268,18 +268,18 @@ class Show(models.Model):
rtrcategory = models.ForeignKey(RTRCategory, related_name='shows', verbose_name=_("RTR Category")) rtrcategory = models.ForeignKey(RTRCategory, related_name='shows', verbose_name=_("RTR Category"))
topic = models.ManyToManyField(Topic, blank=True, related_name='shows', verbose_name=_("Topic")) topic = models.ManyToManyField(Topic, blank=True, related_name='shows', verbose_name=_("Topic"))
musicfocus = models.ManyToManyField(MusicFocus, blank=True, related_name='shows', verbose_name=_("Music focus")) musicfocus = models.ManyToManyField(MusicFocus, blank=True, related_name='shows', verbose_name=_("Music focus"))
name = models.CharField(_("Name"), max_length=255) name = models.CharField(_("Name"), max_length=255, help_text=_("The show's name. Avoid a subtitle."))
slug = models.CharField(_("Slug"), max_length=255, unique=True) slug = models.CharField(_("Slug"), max_length=255, unique=True, help_text=_("A simple to read URL for your show"))
ppoi = PPOIField('Image PPOI') ppoi = PPOIField('Image PPOI')
height = models.PositiveIntegerField('Image Height', blank=True, null=True, editable=False) height = models.PositiveIntegerField('Image Height', blank=True, null=True, editable=False)
width = models.PositiveIntegerField('Image Width', blank=True, null=True,editable=False) width = models.PositiveIntegerField('Image Width', blank=True, null=True,editable=False)
image = VersatileImageField(_("Image"), blank=True, null=True, upload_to='show_images', width_field='width', height_field='height', ppoi_field='ppoi') image = VersatileImageField(_("Image"), blank=True, null=True, upload_to='show_images', width_field='width', height_field='height', ppoi_field='ppoi', help_text=_("Upload an image to your show. Images are automatically cropped around the 'Primary Point of Interest'. Click in the image to change it and press Save."))
logo = models.ImageField(_("Logo"), blank=True, null=True, upload_to='show_images') logo = models.ImageField(_("Logo"), blank=True, null=True, upload_to='show_images')
short_description = models.CharField(_("Short description"), max_length=64) short_description = models.TextField(_("Short description"), help_text=_("Describe your show in some sentences. Avoid technical data like airing times and contact information. They will be added automatically."))
description = tinymce_models.HTMLField(_("Description"), blank=True, null=True) description = tinymce_models.HTMLField(_("Description"), blank=True, null=True, help_text=_("Describe your show in detail."))
email = models.EmailField(_("E-Mail"), blank=True, null=True) email = models.EmailField(_("E-Mail"), blank=True, null=True, help_text=_("The main contact email address for your show."))
website = models.URLField(_("Website"), blank=True, null=True) website = models.URLField(_("Website"), blank=True, null=True, help_text=_("Is there a website to your show? Type in its URL."))
cba_series_id = models.IntegerField(_("CBA Series ID"), blank=True, null=True) cba_series_id = models.IntegerField(_("CBA Series ID"), blank=True, null=True, help_text=_("Link your show to a CBA series by giving its ID. This will enable CBA upload and will automatically link your show to your CBA archive. Find out your ID under https://cba.fro.at/series"))
fallback_pool = models.CharField(_("Fallback Pool"), max_length=255, blank=True) fallback_pool = models.CharField(_("Fallback Pool"), max_length=255, blank=True)
created = models.DateTimeField(auto_now_add=True, editable=False) created = models.DateTimeField(auto_now_add=True, editable=False)
last_updated = models.DateTimeField(auto_now=True, editable=False) last_updated = models.DateTimeField(auto_now=True, editable=False)
...@@ -602,18 +602,18 @@ class Note(models.Model): ...@@ -602,18 +602,18 @@ class Note(models.Model):
(2, _("Repetition")), (2, _("Repetition")),
) )
timeslot = models.OneToOneField(TimeSlot, verbose_name=_("Time slot"), unique=True) timeslot = models.OneToOneField(TimeSlot, verbose_name=_("Time slot"), unique=True)
title = models.CharField(_("Title"), max_length=128) title = models.CharField(_("Title"), max_length=128, help_text=_("Give your note a good headline. What will your upcoming show be about? Try to arouse interest to listen to it!<br>Avoid technical data like the show's name, its airing times or its episode number. These data are added automatically."))
slug = models.SlugField(_("Slug"), max_length=32, unique=True) slug = models.SlugField(_("Slug"), max_length=32, unique=True, help_text=_("A simple to read URL for your show."))
summary = tinymce_models.HTMLField(_("Summary"), blank=True) summary = tinymce_models.HTMLField(_("Summary"), blank=True, help_text=_("Describe your upcoming show in some sentences. Avoid technical data like airing times and contact information. They will be added automatically."))
content = tinymce_models.HTMLField(_("Content")) content = tinymce_models.HTMLField(_("Content"), help_text=_("Describe your upcoming show in detail."))
ppoi = PPOIField('Image PPOI') ppoi = PPOIField('Image PPOI')
height = models.PositiveIntegerField('Image Height', blank=True, null=True, editable=False) height = models.PositiveIntegerField('Image Height', blank=True, null=True, editable=False)
width = models.PositiveIntegerField('Image Width', blank=True, null=True,editable=False) width = models.PositiveIntegerField('Image Width', blank=True, null=True,editable=False)
image = VersatileImageField(_("Featured image"), blank=True, null=True, upload_to='note_images', width_field='width', height_field='height', ppoi_field='ppoi') image = VersatileImageField(_("Featured image"), blank=True, null=True, upload_to='note_images', width_field='width', height_field='height', ppoi_field='ppoi', help_text=_("Upload an image to your show. Images are automatically cropped around the 'Primary Point of Interest'. Click in the image to change it and press Save."))
status = models.IntegerField(_("Status"), choices=STATUS_CHOICES, default=1) status = models.IntegerField(_("Status"), choices=STATUS_CHOICES, default=1)
start = models.DateTimeField(editable=False) start = models.DateTimeField(editable=False)
show = models.ForeignKey(Show, related_name='notes', editable=True) # User chooses the show. Timeslots are loaded via ajax. show = models.ForeignKey(Show, related_name='notes', editable=True)
cba_id = models.IntegerField(_("CBA ID"), blank=True, null=True) cba_id = models.IntegerField(_("CBA ID"), blank=True, null=True, help_text=_("Link the note to a certain CBA post by giving its ID. (E.g. if your post's CBA URL is https://cba.fro.at/1234, then your CBA ID is 1234)"))
created = models.DateTimeField(auto_now_add=True, editable=False) created = models.DateTimeField(auto_now_add=True, editable=False)
last_updated = models.DateTimeField(auto_now=True, editable=False) last_updated = models.DateTimeField(auto_now=True, editable=False)
user = models.ForeignKey(User, editable=False, related_name='users', default=1) user = models.ForeignKey(User, editable=False, related_name='users', default=1)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment