Added model UrlResource with FK to Room
This will make it easier to support audio and video streaming links which vary by meeting, but are fixed by Room. Also added migrations, resource, admin support, supporting methods, and a bit of refactoring. - Legacy-Id: 11644
This commit is contained in:
parent
14e97a732c
commit
7bc8e043f1
ietf/meeting
|
@ -1,11 +1,21 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from ietf.meeting.models import (Meeting, Room, Session, TimeSlot, Constraint, Schedule,
|
||||
SchedTimeSessAssignment, ResourceAssociation, FloorPlan)
|
||||
SchedTimeSessAssignment, ResourceAssociation, FloorPlan, UrlResource)
|
||||
|
||||
|
||||
class UrlResourceAdmin(admin.ModelAdmin):
|
||||
list_display = ['name', 'room', 'url', ]
|
||||
raw_id_fields = ['room', ]
|
||||
admin.site.register(UrlResource, UrlResourceAdmin)
|
||||
|
||||
class UrlResourceInline(admin.TabularInline):
|
||||
model = UrlResource
|
||||
|
||||
class RoomAdmin(admin.ModelAdmin):
|
||||
list_display = ["id", "meeting", "name", "capacity", "functional_name", "x1", "y1", "x2", "y2", ]
|
||||
list_filter = ["meeting"]
|
||||
inlines = [UrlResourceInline, ]
|
||||
ordering = ["-meeting"]
|
||||
|
||||
admin.site.register(Room, RoomAdmin)
|
||||
|
@ -97,7 +107,7 @@ admin.site.register(SchedTimeSessAssignment, SchedTimeSessAssignmentAdmin)
|
|||
|
||||
|
||||
class ResourceAssociationAdmin(admin.ModelAdmin):
|
||||
list_display = ["desc", "icon", "desc", ]
|
||||
list_display = ["name", "icon", "desc", ]
|
||||
admin.site.register(ResourceAssociation, ResourceAssociationAdmin)
|
||||
|
||||
class FloorPlanAdmin(admin.ModelAdmin):
|
||||
|
|
27
ietf/meeting/migrations/0027_urlresource.py
Normal file
27
ietf/meeting/migrations/0027_urlresource.py
Normal file
|
@ -0,0 +1,27 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('name', '0013_add_group_type_verbose_name_data'),
|
||||
('meeting', '0026_add_floorplan_data'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='UrlResource',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('url', models.URLField(null=True, blank=True)),
|
||||
('name', models.ForeignKey(to='name.RoomResourceName')),
|
||||
('room', models.ForeignKey(to='meeting.Room')),
|
||||
],
|
||||
options={
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
]
|
48
ietf/meeting/migrations/0028_add_audio_stream_data.py
Normal file
48
ietf/meeting/migrations/0028_add_audio_stream_data.py
Normal file
|
@ -0,0 +1,48 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
rooms = [
|
||||
("Bellevue", "http://ietf96streaming.dnsalias.net/ietf/ietf961.m3u"),
|
||||
("Charlottenburg I", "http://ietf96streaming.dnsalias.net/ietf/ietf962.m3u"),
|
||||
("Charlottenburg II/III", "http://ietf96streaming.dnsalias.net/ietf/ietf963.m3u"),
|
||||
("Lincke", "http://ietf96streaming.dnsalias.net/ietf/ietf964.m3u"),
|
||||
("Potsdam I", "http://ietf96streaming.dnsalias.net/ietf/ietf965.m3u"),
|
||||
("Potsdam II", "http://ietf96streaming.dnsalias.net/ietf/ietf966.m3u"),
|
||||
("Potsdam III", "http://ietf96streaming.dnsalias.net/ietf/ietf967.m3u"),
|
||||
("Schoeneberg", "http://ietf96streaming.dnsalias.net/ietf/ietf968.m3u"),
|
||||
("Tiergarten", "http://ietf96streaming.dnsalias.net/ietf/ietf969.m3u"),
|
||||
]
|
||||
|
||||
def forward(apps, schema_editor):
|
||||
Room = apps.get_model('meeting','Room')
|
||||
Meeting = apps.get_model('meeting','Meeting')
|
||||
UrlResource = apps.get_model('meeting','UrlResource')
|
||||
RoomResourceName = apps.get_model('name','RoomResourceName')
|
||||
|
||||
meeting = Meeting.objects.get(number='96')
|
||||
|
||||
audiostream, _ = RoomResourceName.objects.get_or_create(slug='audiostream', name='Audio Stream', desc='Audio streaming support')
|
||||
|
||||
for item in rooms:
|
||||
name, url = item
|
||||
try:
|
||||
room = Room.objects.get(name=name, meeting=meeting)
|
||||
urlres, _ = UrlResource.objects.get_or_create(name=audiostream, room=room, url=url)
|
||||
except Room.DoesNotExist:
|
||||
import sys
|
||||
sys.stderr.write("\nNo such room: %s" % name)
|
||||
|
||||
def backward(apps, schema_editor):
|
||||
pass
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('meeting', '0027_urlresource'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(forward,backward)
|
||||
]
|
|
@ -280,7 +280,6 @@ class Meeting(models.Model):
|
|||
|
||||
class ResourceAssociation(models.Model):
|
||||
name = models.ForeignKey(RoomResourceName)
|
||||
#url = models.UrlField() # not sure what this was for.
|
||||
icon = models.CharField(max_length=64) # icon to be found in /static/img
|
||||
desc = models.CharField(max_length=256)
|
||||
|
||||
|
@ -344,7 +343,7 @@ class Room(models.Model):
|
|||
'name': self.name,
|
||||
'capacity': self.capacity,
|
||||
}
|
||||
|
||||
# floorplan support
|
||||
def left(self):
|
||||
return min(self.x1, self.x2) if (self.x1 and self.x2) else 0
|
||||
def top(self):
|
||||
|
@ -361,9 +360,24 @@ class Room(models.Model):
|
|||
if self.functional_name[0].isdigit():
|
||||
return ""
|
||||
return self.functional_name
|
||||
# audio stream support
|
||||
def audio_stream_url(self):
|
||||
urlresource = self.urlresource_set.filter(name_id='audiostream').first()
|
||||
return urlresource.url if urlresource else None
|
||||
def video_stream_url(self):
|
||||
urlresource = self.urlresource_set.filter(name_id__in=['meetecho', ]).first()
|
||||
return urlresource.url if urlresource else None
|
||||
#
|
||||
class Meta:
|
||||
ordering = ["-meeting", "name"]
|
||||
|
||||
|
||||
class UrlResource(models.Model):
|
||||
"For things like audio stream urls, meetecho stream urls"
|
||||
name = models.ForeignKey(RoomResourceName)
|
||||
room = models.ForeignKey(Room)
|
||||
url = models.URLField(null=True, blank=True)
|
||||
|
||||
def floorplan_path(instance, filename):
|
||||
root, ext = os.path.splitext(filename)
|
||||
return u"%s/floorplan-%s-%s%s" % (settings.FLOORPLAN_MEDIA_DIR, instance.meeting.number, xslugify(instance.name), ext)
|
||||
|
@ -373,6 +387,9 @@ class FloorPlan(models.Model):
|
|||
meeting = models.ForeignKey(Meeting)
|
||||
order = models.SmallIntegerField()
|
||||
image = models.ImageField(storage=NoLocationMigrationFileSystemStorage(), upload_to=floorplan_path, blank=True, default=None)
|
||||
#
|
||||
def __unicode__(self):
|
||||
return 'floorplan-%s-%s' % (self.meeting.number, xslugify(self.name))
|
||||
|
||||
# === Schedules, Sessions, Timeslots and Assignments ===========================
|
||||
|
||||
|
@ -423,6 +440,7 @@ class TimeSlot(models.Model):
|
|||
location = "(no location)"
|
||||
|
||||
return u"%s: %s-%s %s, %s" % (self.meeting.number, self.time.strftime("%m-%d %H:%M"), (self.time + self.duration).strftime("%H:%M"), self.name, location)
|
||||
|
||||
def end_time(self):
|
||||
return self.time + self.duration
|
||||
|
||||
|
@ -452,26 +470,28 @@ class TimeSlot(models.Model):
|
|||
name_parts.append(location)
|
||||
return ' - '.join(name_parts)
|
||||
|
||||
@property
|
||||
def tz(self):
|
||||
if self.meeting.time_zone:
|
||||
return pytz.timezone(self.meeting.time_zone)
|
||||
else:
|
||||
return None
|
||||
if not hasattr(self, '_cached_tz'):
|
||||
if self.meeting.time_zone:
|
||||
self._cached_tz = pytz.timezone(self.meeting.time_zone)
|
||||
else:
|
||||
self._cached_tz = None
|
||||
return self._cached_tz
|
||||
|
||||
def tzname(self):
|
||||
if self.tz:
|
||||
return self.tz.tzname(self.time)
|
||||
if self.tz():
|
||||
return self.tz().tzname(self.time)
|
||||
else:
|
||||
return ""
|
||||
def utc_start_time(self):
|
||||
if self.tz:
|
||||
local_start_time = self.tz.localize(self.time)
|
||||
if self.tz():
|
||||
local_start_time = self.tz().localize(self.time)
|
||||
return local_start_time.astimezone(pytz.utc)
|
||||
else:
|
||||
return None
|
||||
def utc_end_time(self):
|
||||
if self.tz:
|
||||
local_end_time = self.tz.localize(self.end_time())
|
||||
if self.tz():
|
||||
local_end_time = self.tz().localize(self.end_time())
|
||||
return local_end_time.astimezone(pytz.utc)
|
||||
else:
|
||||
return None
|
||||
|
|
|
@ -8,7 +8,8 @@ from tastypie.cache import SimpleCache
|
|||
from ietf import api
|
||||
|
||||
from ietf.meeting.models import ( Meeting, ResourceAssociation, Constraint, Room, Schedule, Session,
|
||||
TimeSlot, SchedTimeSessAssignment, SessionPresentation, FloorPlan )
|
||||
TimeSlot, SchedTimeSessAssignment, SessionPresentation, FloorPlan,
|
||||
UrlResource)
|
||||
|
||||
from ietf.name.resources import MeetingTypeNameResource
|
||||
class MeetingResource(ModelResource):
|
||||
|
@ -252,3 +253,22 @@ class SessionPresentationResource(ModelResource):
|
|||
}
|
||||
api.meeting.register(SessionPresentationResource())
|
||||
|
||||
|
||||
|
||||
from ietf.name.resources import RoomResourceNameResource
|
||||
class UrlResourceResource(ModelResource):
|
||||
name = ToOneField(RoomResourceNameResource, 'name')
|
||||
room = ToOneField(RoomResource, 'room')
|
||||
class Meta:
|
||||
queryset = UrlResource.objects.all()
|
||||
serializer = api.Serializer()
|
||||
cache = SimpleCache()
|
||||
#resource_name = 'urlresource'
|
||||
filtering = {
|
||||
"id": ALL,
|
||||
"url": ALL,
|
||||
"name": ALL_WITH_RELATIONS,
|
||||
"room": ALL_WITH_RELATIONS,
|
||||
}
|
||||
api.meeting.register(UrlResourceResource())
|
||||
|
||||
|
|
Loading…
Reference in a new issue