forked from rc/aircox
admin
This commit is contained in:
parent
8d8bc71572
commit
7a18847702
|
@ -1,7 +1,9 @@
|
||||||
import copy
|
import copy
|
||||||
|
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
import programs.models as models
|
from django.forms import Textarea
|
||||||
|
from django.db import models
|
||||||
|
from programs.models import *
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -9,26 +11,24 @@ import programs.models as models
|
||||||
#
|
#
|
||||||
# TODO: inherits from the corresponding admin view
|
# TODO: inherits from the corresponding admin view
|
||||||
class SoundFileInline (admin.TabularInline):
|
class SoundFileInline (admin.TabularInline):
|
||||||
model = models.SoundFile
|
model = SoundFile
|
||||||
|
raw_id_fields=('parent',)
|
||||||
|
fields = ('title', 'private', 'tags', 'file', 'duration', 'fragment')
|
||||||
extra = 1
|
extra = 1
|
||||||
|
|
||||||
|
|
||||||
class EpisodeInline (admin.StackedInline):
|
|
||||||
model = models.Episode
|
|
||||||
extra = 0
|
|
||||||
|
|
||||||
|
|
||||||
class ScheduleInline (admin.TabularInline):
|
class ScheduleInline (admin.TabularInline):
|
||||||
model = models.Schedule
|
model = Schedule
|
||||||
extra = 0
|
extra = 1
|
||||||
|
|
||||||
|
|
||||||
|
class DiffusionInline (admin.TabularInline):
|
||||||
|
model = Diffusion
|
||||||
|
raw_id_fields=('parent',)
|
||||||
|
fields = ('parent', 'type', 'date')
|
||||||
|
extra = 1
|
||||||
|
|
||||||
|
|
||||||
class EventInline (admin.StackedInline):
|
|
||||||
model = models.Event
|
|
||||||
extra = 0
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Parents
|
# Parents
|
||||||
#
|
#
|
||||||
|
@ -37,14 +37,13 @@ class MetadataAdmin (admin.ModelAdmin):
|
||||||
( None, {
|
( None, {
|
||||||
'fields': [ 'title', 'tags' ]
|
'fields': [ 'title', 'tags' ]
|
||||||
}),
|
}),
|
||||||
( 'metadata', {
|
( None, {
|
||||||
'fields': [ 'date' ],
|
'fields': [ 'date' ],
|
||||||
'classes': ['collapse']
|
|
||||||
}),
|
}),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def save_model(self, request, obj, form, change):
|
def save_model (self, request, obj, form, change):
|
||||||
if not obj.author:
|
if not obj.author:
|
||||||
obj.author = request.user
|
obj.author = request.user
|
||||||
obj.save()
|
obj.save()
|
||||||
|
@ -52,38 +51,31 @@ class MetadataAdmin (admin.ModelAdmin):
|
||||||
|
|
||||||
|
|
||||||
class PublicationAdmin (MetadataAdmin):
|
class PublicationAdmin (MetadataAdmin):
|
||||||
|
formfield_overrides = {
|
||||||
|
models.TextField: {'widget': Textarea(attrs={'style':'width:calc(100% - 12px);'})},
|
||||||
|
}
|
||||||
|
|
||||||
fieldsets = copy.deepcopy(MetadataAdmin.fieldsets)
|
fieldsets = copy.deepcopy(MetadataAdmin.fieldsets)
|
||||||
|
|
||||||
list_display = ('id', 'title', 'date', 'public')
|
list_display = ('id', 'title', 'date', 'private')
|
||||||
list_filter = ['date', 'public']
|
list_filter = ['date', 'private']
|
||||||
search_fields = ['title', 'content']
|
search_fields = ['title', 'content']
|
||||||
|
|
||||||
|
|
||||||
def __init__ (self, *args, **kwargs):
|
fieldsets[0][1]['fields'].insert(1, 'subtitle')
|
||||||
self.fieldsets[0][1]['fields'].insert(1, 'subtitle')
|
fieldsets[0][1]['fields'] += [ 'img', 'content' ]
|
||||||
self.fieldsets[0][1]['fields'] += [ 'img', 'content' ]
|
fieldsets[1][1]['fields'] += [ 'parent', 'private', 'can_comment' ] #, 'meta' ],
|
||||||
self.fieldsets[1][1]['fields'] += [ 'parent', 'public', 'can_comment', 'meta' ],
|
|
||||||
return super(PublicationAdmin, self).__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# ModelAdmin list
|
# ModelAdmin list
|
||||||
#
|
#
|
||||||
#class TrackAdmin (MetadataAdmin):
|
|
||||||
# fieldsets = [
|
|
||||||
# (None, { 'fields': [ 'title', 'artist', 'version', 'tags'] } )
|
|
||||||
# ]
|
|
||||||
|
|
||||||
class SoundFileAdmin (MetadataAdmin):
|
class SoundFileAdmin (MetadataAdmin):
|
||||||
fieldsets = [
|
fieldsets = [
|
||||||
(None, { 'fields': ['title', 'tags', 'file', 'embed' ] } ),
|
(None, { 'fields': ['title', 'tags', 'file', 'embed' ] } ),
|
||||||
('metadata', { 'fields': ['duration', 'date', 'podcastable', 'fragment' ] } )
|
('metadata', { 'fields': ['duration', 'date', 'podcastable', 'fragment' ] } )
|
||||||
]
|
]
|
||||||
|
|
||||||
#inlines = [ EpisodeInline ]
|
|
||||||
#inlines = [ EventInline ]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ArticleAdmin (PublicationAdmin):
|
class ArticleAdmin (PublicationAdmin):
|
||||||
fieldsets = copy.deepcopy(PublicationAdmin.fieldsets)
|
fieldsets = copy.deepcopy(PublicationAdmin.fieldsets)
|
||||||
|
@ -91,13 +83,11 @@ class ArticleAdmin (PublicationAdmin):
|
||||||
fieldsets[1][1]['fields'] += ['static_page']
|
fieldsets[1][1]['fields'] += ['static_page']
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ProgramAdmin (PublicationAdmin):
|
class ProgramAdmin (PublicationAdmin):
|
||||||
fieldsets = copy.deepcopy(PublicationAdmin.fieldsets)
|
fieldsets = copy.deepcopy(PublicationAdmin.fieldsets)
|
||||||
inlines = [ EpisodeInline, ScheduleInline ]
|
inlines = [ ScheduleInline ]
|
||||||
|
|
||||||
fieldsets[1][1]['fields'] += ['email', 'url', 'non_stop']
|
|
||||||
|
|
||||||
|
fieldsets[1][1]['fields'] += ['email', 'url']
|
||||||
|
|
||||||
|
|
||||||
class EpisodeAdmin (PublicationAdmin):
|
class EpisodeAdmin (PublicationAdmin):
|
||||||
|
@ -105,15 +95,16 @@ class EpisodeAdmin (PublicationAdmin):
|
||||||
inlines = [ SoundFileInline ]
|
inlines = [ SoundFileInline ]
|
||||||
list_filter = ['parent'] + PublicationAdmin.list_filter
|
list_filter = ['parent'] + PublicationAdmin.list_filter
|
||||||
|
|
||||||
|
# FIXME later: when we have thousands of tracks
|
||||||
fieldsets[0][1]['fields'] += ['tracks']
|
fieldsets[0][1]['fields'] += ['tracks']
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(models.Track)
|
admin.site.register(Track)
|
||||||
admin.site.register(models.SoundFile, SoundFileAdmin)
|
admin.site.register(SoundFile, SoundFileAdmin)
|
||||||
admin.site.register(models.Schedule)
|
admin.site.register(Schedule)
|
||||||
admin.site.register(models.Article, ArticleAdmin)
|
admin.site.register(Article, ArticleAdmin)
|
||||||
admin.site.register(models.Program, ProgramAdmin)
|
admin.site.register(Program, ProgramAdmin)
|
||||||
admin.site.register(models.Episode, EpisodeAdmin)
|
admin.site.register(Episode, EpisodeAdmin)
|
||||||
admin.site.register(models.Event)
|
admin.site.register(Diffusion)
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ from django.utils.html import strip_tags
|
||||||
|
|
||||||
# extensions
|
# extensions
|
||||||
from taggit.managers import TaggableManager
|
from taggit.managers import TaggableManager
|
||||||
|
from sortedm2m.fields import SortedManyToManyField
|
||||||
|
|
||||||
import programs.settings as settings
|
import programs.settings as settings
|
||||||
|
|
||||||
|
@ -48,7 +49,7 @@ ugettext_lazy('second and fourth')
|
||||||
ugettext_lazy('one on two')
|
ugettext_lazy('one on two')
|
||||||
|
|
||||||
|
|
||||||
EventType = {
|
DiffusionType = {
|
||||||
'diffuse': 0x01 # the diffusion is planified or done
|
'diffuse': 0x01 # the diffusion is planified or done
|
||||||
, 'cancel': 0x03 # the diffusion has been canceled from grid; useful to give
|
, 'cancel': 0x03 # the diffusion has been canceled from grid; useful to give
|
||||||
# the info to the users
|
# the info to the users
|
||||||
|
@ -107,10 +108,10 @@ class Metadata (Model):
|
||||||
_('date')
|
_('date')
|
||||||
, default = timezone.datetime.now
|
, default = timezone.datetime.now
|
||||||
)
|
)
|
||||||
public = models.BooleanField(
|
private = models.BooleanField(
|
||||||
_('public')
|
_('private')
|
||||||
, default = False
|
, default = False
|
||||||
, help_text = _('publication is public')
|
, help_text = _('publication is private')
|
||||||
)
|
)
|
||||||
# FIXME: add a field to specify if the element should be listed or not
|
# FIXME: add a field to specify if the element should be listed or not
|
||||||
meta = models.TextField(
|
meta = models.TextField(
|
||||||
|
@ -250,6 +251,14 @@ class Track (Model):
|
||||||
|
|
||||||
|
|
||||||
class SoundFile (Metadata):
|
class SoundFile (Metadata):
|
||||||
|
def get_upload_path (self, filename):
|
||||||
|
if self.parent and self.parent.parent:
|
||||||
|
path = self.parent.parent.path
|
||||||
|
else:
|
||||||
|
path = settings.AIRCOX_SOUNDFILE_DEFAULT_DIR
|
||||||
|
return os.path.join(path, filename)
|
||||||
|
|
||||||
|
|
||||||
parent = models.ForeignKey(
|
parent = models.ForeignKey(
|
||||||
'Episode'
|
'Episode'
|
||||||
, verbose_name = _('episode')
|
, verbose_name = _('episode')
|
||||||
|
@ -258,7 +267,7 @@ class SoundFile (Metadata):
|
||||||
)
|
)
|
||||||
file = models.FileField( #FIXME: filefield
|
file = models.FileField( #FIXME: filefield
|
||||||
_('file')
|
_('file')
|
||||||
, upload_to = lambda i, f: SoundFile.__upload_path(i,f)
|
, upload_to = get_upload_path
|
||||||
)
|
)
|
||||||
duration = models.TimeField(
|
duration = models.TimeField(
|
||||||
_('duration')
|
_('duration')
|
||||||
|
@ -297,14 +306,6 @@ class SoundFile (Metadata):
|
||||||
super(SoundFile, self).save(*args, **kwargs)
|
super(SoundFile, self).save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def __upload_path (self, filename):
|
|
||||||
if self.parent and self.parent.parent:
|
|
||||||
path = self.parent.parent.path
|
|
||||||
else:
|
|
||||||
path = settings.AIRCOX_SOUNDFILE_DEFAULT_DIR
|
|
||||||
return os.path.join(path, filename)
|
|
||||||
|
|
||||||
|
|
||||||
def __str__ (self):
|
def __str__ (self):
|
||||||
return str(self.id) + ': ' + self.file.name
|
return str(self.id) + ': ' + self.file.name
|
||||||
|
|
||||||
|
@ -482,11 +483,6 @@ class Program (Publication):
|
||||||
, blank = True
|
, blank = True
|
||||||
, null = True
|
, null = True
|
||||||
)
|
)
|
||||||
non_stop = models.SmallIntegerField(
|
|
||||||
_('non-stop priority')
|
|
||||||
, help_text = _('this program can be used as non-stop')
|
|
||||||
, default = -1
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def path (self):
|
def path (self):
|
||||||
|
@ -526,10 +522,9 @@ class Episode (Publication):
|
||||||
Program
|
Program
|
||||||
, verbose_name = _('parent')
|
, verbose_name = _('parent')
|
||||||
)
|
)
|
||||||
tracks = models.ManyToManyField(
|
tracks = SortedManyToManyField(
|
||||||
Track
|
Track
|
||||||
, verbose_name = _('playlist')
|
, verbose_name = _('tracks')
|
||||||
, blank = True
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -539,11 +534,11 @@ class Episode (Publication):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Event (Model):
|
class Diffusion (Model):
|
||||||
"""
|
"""
|
||||||
Event logs and planifications.
|
Diffusion logs and planifications.
|
||||||
|
|
||||||
An event is:
|
A diffusion is:
|
||||||
- scheduled: when it has been generated following programs' Schedule
|
- scheduled: when it has been generated following programs' Schedule
|
||||||
- planified: when it has been generated manually/ponctually or scheduled
|
- planified: when it has been generated manually/ponctually or scheduled
|
||||||
"""
|
"""
|
||||||
|
@ -556,23 +551,29 @@ class Event (Model):
|
||||||
Program
|
Program
|
||||||
)
|
)
|
||||||
type = models.SmallIntegerField(
|
type = models.SmallIntegerField(
|
||||||
_('type')
|
verbose_name = _('type')
|
||||||
, choices = [ (y, x) for x,y in EventType.items() ]
|
, choices = [ (y, x) for x,y in DiffusionType.items() ]
|
||||||
)
|
)
|
||||||
date = models.DateTimeField( _('date of event start') )
|
date = models.DateTimeField( _('date of diffusion start') )
|
||||||
stream = models.SmallIntegerField(
|
stream = models.SmallIntegerField(
|
||||||
_('stream')
|
verbose_name = _('stream')
|
||||||
, default = 0
|
, default = 0
|
||||||
, help_text = 'stream id on which the event happens'
|
, help_text = 'stream id on which the diffusion happens'
|
||||||
)
|
)
|
||||||
scheduled = models.BooleanField(
|
scheduled = models.BooleanField(
|
||||||
_('automated')
|
verbose_name = _('automated')
|
||||||
, default = False
|
, default = False
|
||||||
, help_text = 'event generated automatically'
|
, help_text = 'diffusion generated automatically'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def save (self, *args, **kwargs):
|
||||||
|
if self.parent:
|
||||||
|
self.program = self.parent.parent
|
||||||
|
super(Diffusion, self).save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _('Event')
|
verbose_name = _('Diffusion')
|
||||||
verbose_name_plural = _('Events')
|
verbose_name_plural = _('Diffusions')
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
Django>=1.9.0
|
Django>=1.9.0
|
||||||
taggit
|
taggit>=0.12.1
|
||||||
|
sortedm2m>=1.0.2
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ ensure('AIRCOX_SOUNDFILE_DEFAULT_DIR',
|
||||||
ensure('AIRCOX_SOUNDFILE_EXT',
|
ensure('AIRCOX_SOUNDFILE_EXT',
|
||||||
('ogg','flac','wav','mp3','opus'))
|
('ogg','flac','wav','mp3','opus'))
|
||||||
|
|
||||||
# Stream for the scheduled events
|
# Stream for the scheduled diffusions
|
||||||
ensure('AIRCOX_SCHEDULED_STREAM', 0)
|
ensure('AIRCOX_SCHEDULED_STREAM', 0)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,31 +1,31 @@
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from programs.models import Schedule, Event, Episode,\
|
from programs.models import Schedule, Diffusion, Episode,\
|
||||||
EventType
|
DiffusionType
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def scheduled_month_events (date = None, unsaved_only = False):
|
def scheduled_month_diffusions (date = None, unsaved_only = False):
|
||||||
"""
|
"""
|
||||||
Return a list of scheduled events for the month of the given date. For the
|
Return a list of scheduled diffusions for the month of the given date. For the
|
||||||
non existing events, a program attribute to the corresponding program is
|
non existing diffusions, a program attribute to the corresponding program is
|
||||||
set.
|
set.
|
||||||
"""
|
"""
|
||||||
if not date:
|
if not date:
|
||||||
date = timezone.datetime.today()
|
date = timezone.datetime.today()
|
||||||
|
|
||||||
schedules = Schedule.objects.all()
|
schedules = Schedule.objects.all()
|
||||||
events = []
|
diffusions = []
|
||||||
|
|
||||||
for schedule in schedules:
|
for schedule in schedules:
|
||||||
dates = schedule.dates_of_month()
|
dates = schedule.dates_of_month()
|
||||||
for date in dates:
|
for date in dates:
|
||||||
event = Event.objects \
|
diffusion = Diffusion.objects \
|
||||||
.filter(date = date, parent__parent = schedule.parent)
|
.filter(date = date, parent__parent = schedule.parent)
|
||||||
|
|
||||||
if event.count():
|
if diffusion.count():
|
||||||
if not unsaved_only:
|
if not unsaved_only:
|
||||||
events.append(event)
|
diffusions.append(diffusion)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# get episode
|
# get episode
|
||||||
|
@ -37,16 +37,16 @@ def scheduled_month_events (date = None, unsaved_only = False):
|
||||||
, parent = schedule.parent )
|
, parent = schedule.parent )
|
||||||
episode = episode[0] if episode.count() else None
|
episode = episode[0] if episode.count() else None
|
||||||
|
|
||||||
# make event
|
# make diffusion
|
||||||
event = Event( parent = episode
|
diffusion = Diffusion( parent = episode
|
||||||
, program = schedule.parent
|
, program = schedule.parent
|
||||||
, type = EventType['diffuse']
|
, type = DiffusionType['diffuse']
|
||||||
, date = date
|
, date = date
|
||||||
, stream = settings.AIRCOX_SCHEDULED_STREAM
|
, stream = settings.AIRCOX_SCHEDULED_STREAM
|
||||||
, scheduled = True
|
, scheduled = True
|
||||||
)
|
)
|
||||||
event.program = schedule.program
|
diffusion.program = schedule.program
|
||||||
events.append(event)
|
diffusions.append(diffusion)
|
||||||
return events
|
return diffusions
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import programs.settings
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class EventList:
|
class DiffusionList:
|
||||||
type = None
|
type = None
|
||||||
next = None
|
next = None
|
||||||
prev = None
|
prev = None
|
||||||
|
@ -22,29 +22,29 @@ class EventList:
|
||||||
|
|
||||||
|
|
||||||
def get_queryset (self):
|
def get_queryset (self):
|
||||||
events = models.Event.objects;
|
diffusions = models.Diffusion.objects;
|
||||||
|
|
||||||
if self.next: events = events.filter( date_end__ge = timezone.now() )
|
if self.next: diffusions = diffusions.filter( date_end__ge = timezone.now() )
|
||||||
elif self.prev: events = events.filter( date_end__le = timezone.now() )
|
elif self.prev: diffusions = diffusions.filter( date_end__le = timezone.now() )
|
||||||
else: events = events.all()
|
else: diffusions = diffusions.all()
|
||||||
|
|
||||||
events = events.extra(order_by = ['date'])
|
diffusions = diffusions.extra(order_by = ['date'])
|
||||||
if self.at: events = events[self.at:]
|
if self.at: diffusions = diffusions[self.at:]
|
||||||
if self.count: events = events[:self.count]
|
if self.count: diffusions = diffusions[:self.count]
|
||||||
|
|
||||||
self.events = events
|
self.diffusions = diffusions
|
||||||
|
|
||||||
|
|
||||||
def raw_string():
|
def raw_string():
|
||||||
"""
|
"""
|
||||||
Return a string with events rendered as raw
|
Return a string with diffusions rendered as raw
|
||||||
"""
|
"""
|
||||||
res = []
|
res = []
|
||||||
for event in events:
|
for diffusion in diffusions:
|
||||||
r = [ dateformat.format(event.date, "Y/m/d H:i:s")
|
r = [ dateformat.format(diffusion.date, "Y/m/d H:i:s")
|
||||||
, str(event.type)
|
, str(diffusion.type)
|
||||||
, event.parent.file.path
|
, diffusion.parent.file.path
|
||||||
, event.parent.file.url
|
, diffusion.parent.file.url
|
||||||
]
|
]
|
||||||
|
|
||||||
res.push(' '.join(r))
|
res.push(' '.join(r))
|
||||||
|
@ -56,13 +56,13 @@ class EventList:
|
||||||
import json
|
import json
|
||||||
|
|
||||||
res = []
|
res = []
|
||||||
for event in events:
|
for diffusion in diffusions:
|
||||||
r = {
|
r = {
|
||||||
'date': dateformat.format(event.date, "Y/m/d H:i:s")
|
'date': dateformat.format(diffusion.date, "Y/m/d H:i:s")
|
||||||
, 'date_end': dateformat.format(event.date_end, "Y/m/d H:i:s")
|
, 'date_end': dateformat.format(diffusion.date_end, "Y/m/d H:i:s")
|
||||||
, 'type': str(event.type)
|
, 'type': str(diffusion.type)
|
||||||
, 'file_path': event.parent.file.path
|
, 'file_path': diffusion.parent.file.path
|
||||||
, 'file_url': event.parent.file.url
|
, 'file_url': diffusion.parent.file.url
|
||||||
}
|
}
|
||||||
|
|
||||||
res.push(json.dumps(r))
|
res.push(json.dumps(r))
|
||||||
|
|
Loading…
Reference in New Issue
Block a user