forked from rc/aircox
		
	update sections, work a bit on style
This commit is contained in:
		@ -3,8 +3,8 @@ Platform to manage radio programs, schedules, cms, etc. -- main test repo
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# Applications
 | 
					# Applications
 | 
				
			||||||
* **programs**: programs, episodes, schedules, sounds and tracks;
 | 
					* **programs**: programs, episodes, schedules, sounds and tracks;
 | 
				
			||||||
* **streams**:  streams and diffusions, links with LiquidSoap;
 | 
					* **cms**: cms renderer
 | 
				
			||||||
* **website**: website rendering, using models defined by the previous apps;
 | 
					* **website**: the website using the cms and the programs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Code and names conventions and uses
 | 
					# Code and names conventions and uses
 | 
				
			||||||
 | 
				
			|||||||
@ -12,57 +12,18 @@ from django.dispatch import receiver
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
from taggit.managers import TaggableManager
 | 
					from taggit.managers import TaggableManager
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Thread (models.Model):
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
    Object assigned to any Post and children that can be used to have parent and
 | 
					 | 
				
			||||||
    children relationship between posts of different kind.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    We use this system instead of having directly a GenericForeignKey into the
 | 
					 | 
				
			||||||
    Post because it avoids having to define the relationship with two models for
 | 
					 | 
				
			||||||
    routing (one for the parent and one for the children).
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
    post_type = models.ForeignKey(ContentType)
 | 
					 | 
				
			||||||
    post_id = models.PositiveIntegerField()
 | 
					 | 
				
			||||||
    post = GenericForeignKey('post_type', 'post_id')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    __initial_post = None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @classmethod
 | 
					 | 
				
			||||||
    def __get_query_set (cl, function, model, post, kwargs):
 | 
					 | 
				
			||||||
        if post:
 | 
					 | 
				
			||||||
            model = type(post)
 | 
					 | 
				
			||||||
            kwargs['post_id'] = post.id
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        kwargs['post_type'] = ContentType.objects.get_for_model(model)
 | 
					 | 
				
			||||||
        return getattr(cl.objects, function)(**kwargs)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @classmethod
 | 
					 | 
				
			||||||
    def get (cl, model = None, post = None, **kwargs):
 | 
					 | 
				
			||||||
        return cl.__get_query_set('get', model, post, kwargs)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @classmethod
 | 
					 | 
				
			||||||
    def filter (cl, model = None, post = None, **kwargs):
 | 
					 | 
				
			||||||
        return self.__get_query_set('filter', model, post, kwargs)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @classmethod
 | 
					 | 
				
			||||||
    def exclude (cl, model = None, post = None, **kwargs):
 | 
					 | 
				
			||||||
        return self.__get_query_set('exclude', model, post, kwargs)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def save (self, *args, **kwargs):
 | 
					 | 
				
			||||||
        self.post = self.__initial_post or self.post
 | 
					 | 
				
			||||||
        super().save(*args, **kwargs)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __str__ (self):
 | 
					 | 
				
			||||||
        return self.post_type.name + ': ' + str(self.post)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Post (models.Model):
 | 
					class Post (models.Model):
 | 
				
			||||||
    thread = models.ForeignKey(
 | 
					    thread_type = models.ForeignKey(
 | 
				
			||||||
        Thread,
 | 
					        ContentType,
 | 
				
			||||||
        on_delete=models.SET_NULL,
 | 
					        on_delete=models.SET_NULL,
 | 
				
			||||||
        blank = True, null = True,
 | 
					        blank = True, null = True
 | 
				
			||||||
        help_text = _('the publication is posted on this thread'),
 | 
					 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					    thread_pk = models.PositiveIntegerField(
 | 
				
			||||||
 | 
					        blank = True, null = True
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    thread = GenericForeignKey('thread_type', 'thread_pk')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    author = models.ForeignKey(
 | 
					    author = models.ForeignKey(
 | 
				
			||||||
        User,
 | 
					        User,
 | 
				
			||||||
        verbose_name = _('author'),
 | 
					        verbose_name = _('author'),
 | 
				
			||||||
@ -94,7 +55,7 @@ class Post (models.Model):
 | 
				
			|||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def detail_url (self):
 | 
					    def detail_url (self):
 | 
				
			||||||
        return reverse(self._meta.verbose_name_plural.lower() + '_detail',
 | 
					        return reverse(self._meta.verbose_name.lower() + '_detail',
 | 
				
			||||||
                       kwargs = { 'pk': self.pk,
 | 
					                       kwargs = { 'pk': self.pk,
 | 
				
			||||||
                                  'slug': slugify(self.title) })
 | 
					                                  'slug': slugify(self.title) })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -151,7 +112,6 @@ class RelatedPost (Post, metaclass = RelatedPostBase):
 | 
				
			|||||||
        mapping = None          # dict of related mapping values
 | 
					        mapping = None          # dict of related mapping values
 | 
				
			||||||
        bind_mapping = False    # update fields of related data on save
 | 
					        bind_mapping = False    # update fields of related data on save
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def get_attribute (self, attr):
 | 
					    def get_attribute (self, attr):
 | 
				
			||||||
        attr = self._relation.mappings.get(attr)
 | 
					        attr = self._relation.mappings.get(attr)
 | 
				
			||||||
        return self.related.__dict__[attr] if attr else None
 | 
					        return self.related.__dict__[attr] if attr else None
 | 
				
			||||||
@ -163,32 +123,10 @@ class RelatedPost (Post, metaclass = RelatedPostBase):
 | 
				
			|||||||
        if self._relation.bind_mapping:
 | 
					        if self._relation.bind_mapping:
 | 
				
			||||||
            self.related.__dict__.update({
 | 
					            self.related.__dict__.update({
 | 
				
			||||||
                rel_attr: self.__dict__[attr]
 | 
					                rel_attr: self.__dict__[attr]
 | 
				
			||||||
                for attr, rel_attr in self.Relation.mapping
 | 
					                for attr, rel_attr in self.Relation.mapping.items()
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
 | 
					 | 
				
			||||||
            self.related.save()
 | 
					            self.related.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        super().save(*args, **kwargs)
 | 
					        super().save(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@receiver(post_init)
 | 
					 | 
				
			||||||
def on_thread_init (sender, instance, **kwargs):
 | 
					 | 
				
			||||||
    if not issubclass(Thread, sender):
 | 
					 | 
				
			||||||
        return
 | 
					 | 
				
			||||||
    instance.__initial_post = instance.post
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@receiver(post_save)
 | 
					 | 
				
			||||||
def on_post_save (sender, instance, created, *args, **kwargs):
 | 
					 | 
				
			||||||
    if not issubclass(sender, Post) or not created:
 | 
					 | 
				
			||||||
        return
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    thread = Thread(post = instance)
 | 
					 | 
				
			||||||
    thread.save()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@receiver(post_delete)
 | 
					 | 
				
			||||||
def on_post_delete (sender, instance, using, *args, **kwargs):
 | 
					 | 
				
			||||||
    try:
 | 
					 | 
				
			||||||
        Thread.get(sender, post = instance).delete()
 | 
					 | 
				
			||||||
    except:
 | 
					 | 
				
			||||||
        pass
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										4
									
								
								aircox_cms/requirements.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								aircox_cms/requirements.txt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					Django>=1.9.0
 | 
				
			||||||
 | 
					django-taggit>=0.12.1
 | 
				
			||||||
 | 
					easy_thumbnails
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1,4 +1,5 @@
 | 
				
			|||||||
from django.conf.urls import url
 | 
					from django.conf.urls import url
 | 
				
			||||||
 | 
					from django.contrib.contenttypes.models import ContentType
 | 
				
			||||||
from django.utils import timezone
 | 
					from django.utils import timezone
 | 
				
			||||||
from django.utils.translation import ugettext as _, ugettext_lazy
 | 
					from django.utils.translation import ugettext as _, ugettext_lazy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -27,9 +28,9 @@ class Route:
 | 
				
			|||||||
    """
 | 
					    """
 | 
				
			||||||
    Base class for routing. Given a model, we generate url specific for each
 | 
					    Base class for routing. Given a model, we generate url specific for each
 | 
				
			||||||
    route type. The generated url takes this form:
 | 
					    route type. The generated url takes this form:
 | 
				
			||||||
        base_name + '/' + route_name + '/' + '/'.join(route_url_args)
 | 
					        model_name + '/' + route_name + '/' + '/'.join(route_url_args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Where base_name by default is the given model's verbose_name (uses plural if
 | 
					    Where model_name by default is the given model's verbose_name (uses plural if
 | 
				
			||||||
    Route is for a list).
 | 
					    Route is for a list).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    The given view is considered as a django class view, and has view_
 | 
					    The given view is considered as a django class view, and has view_
 | 
				
			||||||
@ -38,14 +39,14 @@ class Route:
 | 
				
			|||||||
    url_args = []       # arguments passed from the url [ (name : regex),... ]
 | 
					    url_args = []       # arguments passed from the url [ (name : regex),... ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
    def get_queryset (cl, model, request, **kwargs):
 | 
					    def get_queryset (cl, website, model, request, **kwargs):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Called by the view to get the queryset when it is needed
 | 
					        Called by the view to get the queryset when it is needed
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        pass
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
    def get_object (cl, model, request, **kwargs):
 | 
					    def get_object (cl, website, model, request, **kwargs):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Called by the view to get the object when it is needed
 | 
					        Called by the view to get the object when it is needed
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
@ -56,10 +57,8 @@ class Route:
 | 
				
			|||||||
        return ''
 | 
					        return ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
    def as_url (cl, model, view, view_kwargs = None):
 | 
					    def as_url (cl, model, model_name, view, view_kwargs = None):
 | 
				
			||||||
        base_name = model._meta.verbose_name_plural.lower()
 | 
					        pattern = '^{}/{}'.format(model_name, cl.name)
 | 
				
			||||||
 | 
					 | 
				
			||||||
        pattern = '^{}/{}'.format(base_name, cl.name)
 | 
					 | 
				
			||||||
        if cl.url_args:
 | 
					        if cl.url_args:
 | 
				
			||||||
            url_args = '/'.join([
 | 
					            url_args = '/'.join([
 | 
				
			||||||
                '(?P<{}>{}){}'.format(
 | 
					                '(?P<{}>{}){}'.format(
 | 
				
			||||||
@ -78,7 +77,7 @@ class Route:
 | 
				
			|||||||
            kwargs.update(view_kwargs)
 | 
					            kwargs.update(view_kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return url(pattern, view, kwargs = kwargs,
 | 
					        return url(pattern, view, kwargs = kwargs,
 | 
				
			||||||
                   name = base_name + '_' + cl.name)
 | 
					                   name = model_name + '_' + cl.name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DetailRoute (Route):
 | 
					class DetailRoute (Route):
 | 
				
			||||||
@ -89,7 +88,7 @@ class DetailRoute (Route):
 | 
				
			|||||||
    ]
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
    def get_object (cl, model, request, pk, **kwargs):
 | 
					    def get_object (cl, website, model, request, pk, **kwargs):
 | 
				
			||||||
        return model.objects.get(pk = int(pk))
 | 
					        return model.objects.get(pk = int(pk))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -97,7 +96,7 @@ class AllRoute (Route):
 | 
				
			|||||||
    name = 'all'
 | 
					    name = 'all'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
    def get_queryset (cl, model, request, **kwargs):
 | 
					    def get_queryset (cl, website, model, request, **kwargs):
 | 
				
			||||||
        return model.objects.all()
 | 
					        return model.objects.all()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
@ -108,14 +107,32 @@ class AllRoute (Route):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ThreadRoute (Route):
 | 
					class ThreadRoute (Route):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Select posts using by their assigned thread.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    - "thread_model" can be a string with the name of a registered item on
 | 
				
			||||||
 | 
					    website or a model.
 | 
				
			||||||
 | 
					    - "pk" is the pk of the thread item.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
    name = 'thread'
 | 
					    name = 'thread'
 | 
				
			||||||
    url_args = [
 | 
					    url_args = [
 | 
				
			||||||
 | 
					        ('thread_model', '(\w|_|-)+'),
 | 
				
			||||||
        ('pk', '[0-9]+'),
 | 
					        ('pk', '[0-9]+'),
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
    def get_queryset (cl, model, request, pk, **kwargs):
 | 
					    def get_queryset (cl, website, model, request, thread_model, pk, **kwargs):
 | 
				
			||||||
        return model.objects.filter(thread__pk = int(pk))
 | 
					        if type(thread_model) is str:
 | 
				
			||||||
 | 
					            thread_model = website.registry.get(thread_model).model
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not thread_model:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        thread_model = ContentType.objects.get_for_model(thread_model)
 | 
				
			||||||
 | 
					        return model.objects.filter(
 | 
				
			||||||
 | 
					            thread_type = thread_model,
 | 
				
			||||||
 | 
					            thread_pk = int(pk)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DateRoute (Route):
 | 
					class DateRoute (Route):
 | 
				
			||||||
@ -127,7 +144,7 @@ class DateRoute (Route):
 | 
				
			|||||||
    ]
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
    def get_queryset (cl, model, request, year, month, day, **kwargs):
 | 
					    def get_queryset (cl, website, model, request, year, month, day, **kwargs):
 | 
				
			||||||
        return model.objects.filter(
 | 
					        return model.objects.filter(
 | 
				
			||||||
            date__year = int(year),
 | 
					            date__year = int(year),
 | 
				
			||||||
            date__month = int(month),
 | 
					            date__month = int(month),
 | 
				
			||||||
@ -139,7 +156,7 @@ class SearchRoute (Route):
 | 
				
			|||||||
    name = 'search'
 | 
					    name = 'search'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
    def get_queryset (cl, model, request, **kwargs):
 | 
					    def get_queryset (cl, website, model, request, **kwargs):
 | 
				
			||||||
        q = request.GET.get('q') or ''
 | 
					        q = request.GET.get('q') or ''
 | 
				
			||||||
        qs = model.objects
 | 
					        qs = model.objects
 | 
				
			||||||
        for search_field in model.search_fields or []:
 | 
					        for search_field in model.search_fields or []:
 | 
				
			||||||
@ -151,4 +168,3 @@ class SearchRoute (Route):
 | 
				
			|||||||
        return qs
 | 
					        return qs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -20,9 +20,13 @@ body {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.section {
 | 
				
			||||||
 | 
					    vertical-align: top;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
main .section {
 | 
					main .section {
 | 
				
			||||||
    width: calc(50% - 1em);
 | 
					    width: calc(50% - 2em);
 | 
				
			||||||
    float: left;
 | 
					    display: inline-block;
 | 
				
			||||||
    padding: 0.5em;
 | 
					    padding: 0.5em;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -39,3 +43,8 @@ main .section {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.post_item {
 | 
				
			||||||
 | 
					    display: block;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -12,23 +12,23 @@
 | 
				
			|||||||
        <time datetime="{{ post.date }}" class="post_datetime">
 | 
					        <time datetime="{{ post.date }}" class="post_datetime">
 | 
				
			||||||
            {% if 'date' in view.fields %}
 | 
					            {% if 'date' in view.fields %}
 | 
				
			||||||
            <span class="post_date">
 | 
					            <span class="post_date">
 | 
				
			||||||
                {{ post.date|date:'D. d F' }},
 | 
					                {{ post.date|date:'D. d F' }}
 | 
				
			||||||
            </span>
 | 
					            </span>
 | 
				
			||||||
            {% endif %}
 | 
					            {% endif %}
 | 
				
			||||||
            {% if 'time' in view.fields %}
 | 
					            {% if 'time' in view.fields %}
 | 
				
			||||||
            <span class="post_time">
 | 
					            <span class="post_time">
 | 
				
			||||||
                {{ post.date|date:'H:i' }},
 | 
					                {{ post.date|date:'H:i' }}
 | 
				
			||||||
            </span>
 | 
					            </span>
 | 
				
			||||||
            {% endif %}
 | 
					            {% endif %}
 | 
				
			||||||
        </time>
 | 
					        </time>
 | 
				
			||||||
        {% endif %}
 | 
					        {% endif %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        {% if 'image' in view.fields %}
 | 
					        {% if 'image' in view.fields %}
 | 
				
			||||||
        <img src="{% thumbnail post.image "64x64" crop %}" class="post_image">
 | 
					        <img src="{% thumbnail post.image view.icon_size crop %}" class="post_image">
 | 
				
			||||||
        {% endif %}
 | 
					        {% endif %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        {% if 'title' in view.fields %}
 | 
					        {% if 'title' in view.fields %}
 | 
				
			||||||
        <h4 class="post_title">{{ post.title }}</h4>
 | 
					        <h3 class="post_title">{{ post.title }}</h3>
 | 
				
			||||||
        {% endif %}
 | 
					        {% endif %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        {% if 'content' in view.fields %}
 | 
					        {% if 'content' in view.fields %}
 | 
				
			||||||
 | 
				
			|||||||
@ -6,6 +6,9 @@
 | 
				
			|||||||
<ul style="padding:0; margin:0">
 | 
					<ul style="padding:0; margin:0">
 | 
				
			||||||
    {% for item in object_list %}
 | 
					    {% for item in object_list %}
 | 
				
			||||||
    <li>
 | 
					    <li>
 | 
				
			||||||
 | 
					        {% if item.url %}
 | 
				
			||||||
 | 
					        <a href="{{item.url}}">
 | 
				
			||||||
 | 
					        {% endif %}
 | 
				
			||||||
        {% if use_icons and item.icon %}
 | 
					        {% if use_icons and item.icon %}
 | 
				
			||||||
        <img src="{% thumbnail item.icon icon_size crop %}" class="icon">
 | 
					        <img src="{% thumbnail item.icon icon_size crop %}" class="icon">
 | 
				
			||||||
        {% endif %}
 | 
					        {% endif %}
 | 
				
			||||||
@ -15,6 +18,9 @@
 | 
				
			|||||||
        {% if item.text %}
 | 
					        {% if item.text %}
 | 
				
			||||||
            <small>{{ item.text }}</small>
 | 
					            <small>{{ item.text }}</small>
 | 
				
			||||||
        {% endif %}
 | 
					        {% endif %}
 | 
				
			||||||
 | 
					        {% if item.url %}
 | 
				
			||||||
 | 
					        </a>
 | 
				
			||||||
 | 
					        {% endif %}
 | 
				
			||||||
    </li>
 | 
					    </li>
 | 
				
			||||||
    {% endfor %}
 | 
					    {% endfor %}
 | 
				
			||||||
</ul>
 | 
					</ul>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,5 @@
 | 
				
			|||||||
import re
 | 
					import re
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
from django.templatetags.static import static
 | 
					from django.templatetags.static import static
 | 
				
			||||||
from django.shortcuts import render
 | 
					from django.shortcuts import render
 | 
				
			||||||
from django.template.loader import render_to_string
 | 
					from django.template.loader import render_to_string
 | 
				
			||||||
@ -19,7 +18,7 @@ class PostBaseView:
 | 
				
			|||||||
    embed = False   # page is embed (if True, only post content is printed
 | 
					    embed = False   # page is embed (if True, only post content is printed
 | 
				
			||||||
    classes = ''    # extra classes for the content
 | 
					    classes = ''    # extra classes for the content
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_base_context (self):
 | 
					    def get_base_context (self, **kwargs):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Return a context with all attributes of this classe plus 'view' set
 | 
					        Return a context with all attributes of this classe plus 'view' set
 | 
				
			||||||
        to self.
 | 
					        to self.
 | 
				
			||||||
@ -32,7 +31,7 @@ class PostBaseView:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        if not self.embed:
 | 
					        if not self.embed:
 | 
				
			||||||
            context['menus'] = {
 | 
					            context['menus'] = {
 | 
				
			||||||
                k: v.get(self.request)
 | 
					                k: v.get(self.request, **kwargs)
 | 
				
			||||||
                for k, v in {
 | 
					                for k, v in {
 | 
				
			||||||
                    k: self.website.get_menu(k)
 | 
					                    k: self.website.get_menu(k)
 | 
				
			||||||
                    for k in self.website.menu_layouts
 | 
					                    for k in self.website.menu_layouts
 | 
				
			||||||
@ -70,10 +69,12 @@ class PostListView (PostBaseView, ListView):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    template_name = 'aircox_cms/list.html'
 | 
					    template_name = 'aircox_cms/list.html'
 | 
				
			||||||
    allow_empty = True
 | 
					    allow_empty = True
 | 
				
			||||||
 | 
					    model = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    route = None
 | 
					    route = None
 | 
				
			||||||
    query = None
 | 
					    query = None
 | 
				
			||||||
    fields = [ 'date', 'time', 'image', 'title', 'content' ]
 | 
					    fields = [ 'date', 'time', 'image', 'title', 'content' ]
 | 
				
			||||||
 | 
					    icon_size = '64x64'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__ (self, *args, **kwargs):
 | 
					    def __init__ (self, *args, **kwargs):
 | 
				
			||||||
        super().__init__(*args, **kwargs)
 | 
					        super().__init__(*args, **kwargs)
 | 
				
			||||||
@ -84,7 +85,11 @@ class PostListView (PostBaseView, ListView):
 | 
				
			|||||||
        return super().dispatch(request, *args, **kwargs)
 | 
					        return super().dispatch(request, *args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_queryset (self):
 | 
					    def get_queryset (self):
 | 
				
			||||||
        qs = self.route.get_queryset(self.model, self.request, **self.kwargs)
 | 
					        if self.route:
 | 
				
			||||||
 | 
					            qs = self.route.get_queryset(self.website, self.model, self.request,
 | 
				
			||||||
 | 
					                                         **self.kwargs)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            qs = self.queryset or self.model.objects.all()
 | 
				
			||||||
        query = self.query
 | 
					        query = self.query
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        query.update(self.request.GET)
 | 
					        query.update(self.request.GET)
 | 
				
			||||||
@ -156,7 +161,7 @@ class PostDetailView (DetailView, PostBaseView):
 | 
				
			|||||||
        context.update(self.get_base_context())
 | 
					        context.update(self.get_base_context())
 | 
				
			||||||
        context.update({
 | 
					        context.update({
 | 
				
			||||||
            'sections': [
 | 
					            'sections': [
 | 
				
			||||||
                section.get(self.request, object = self.object)
 | 
					                section.get(self.request, **kwargs)
 | 
				
			||||||
                    for section in self.sections
 | 
					                    for section in self.sections
 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
@ -184,7 +189,7 @@ class Menu (View):
 | 
				
			|||||||
            'classes': self.classes,
 | 
					            'classes': self.classes,
 | 
				
			||||||
            'position': self.position,
 | 
					            'position': self.position,
 | 
				
			||||||
            'sections': [
 | 
					            'sections': [
 | 
				
			||||||
                section.get(self.request, object = None)
 | 
					                section.get(self.request, object = None, **kwargs)
 | 
				
			||||||
                    for section in self.sections
 | 
					                    for section in self.sections
 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -202,36 +207,48 @@ class BaseSection (View):
 | 
				
			|||||||
    in order to have extra content about a post, or in menus.
 | 
					    in order to have extra content about a post, or in menus.
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    template_name = 'aircox_cms/base_section.html'
 | 
					    template_name = 'aircox_cms/base_section.html'
 | 
				
			||||||
 | 
					    kwargs = None   # kwargs argument passed to get
 | 
				
			||||||
    tag = 'div'     # container tags
 | 
					    tag = 'div'     # container tags
 | 
				
			||||||
    classes = ''    # container classes
 | 
					    classes = ''    # container classes
 | 
				
			||||||
    attrs = ''      # container extra attributes
 | 
					    attrs = ''      # container extra attributes
 | 
				
			||||||
    content = ''    # content
 | 
					    content = ''    # content
 | 
				
			||||||
 | 
					    visible = True  # if false renders an empty string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_context_data (self, **kwargs):
 | 
					    def get_context_data (self):
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
 | 
					            'view': self,
 | 
				
			||||||
            'tag': self.tag,
 | 
					            'tag': self.tag,
 | 
				
			||||||
            'classes': self.classes,
 | 
					            'classes': self.classes,
 | 
				
			||||||
            'attrs': self.attrs,
 | 
					            'attrs': self.attrs,
 | 
				
			||||||
 | 
					            'visible': self.visible,
 | 
				
			||||||
            'content': self.content,
 | 
					            'content': self.content,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get (self, request, **kwargs):
 | 
					    def get (self, request, **kwargs):
 | 
				
			||||||
        self.request = request
 | 
					        self.request = request
 | 
				
			||||||
        context = self.get_context_data(**kwargs)
 | 
					        self.kwargs = kwargs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        context = self.get_context_data()
 | 
				
			||||||
 | 
					        # get_context_data may call extra function that can change visibility
 | 
				
			||||||
 | 
					        if self.visible:
 | 
				
			||||||
            return render_to_string(self.template_name, context)
 | 
					            return render_to_string(self.template_name, context)
 | 
				
			||||||
 | 
					        return ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Section (BaseSection):
 | 
					class Section (BaseSection):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    A Section that can be related to an object.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
    template_name = 'aircox_cms/section.html'
 | 
					    template_name = 'aircox_cms/section.html'
 | 
				
			||||||
    require_object = False
 | 
					 | 
				
			||||||
    object = None
 | 
					    object = None
 | 
				
			||||||
 | 
					    object_required = False
 | 
				
			||||||
    title = ''
 | 
					    title = ''
 | 
				
			||||||
    header = ''
 | 
					    header = ''
 | 
				
			||||||
    bottom = ''
 | 
					    bottom = ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_context_data (self, **kwargs):
 | 
					    def get_context_data (self):
 | 
				
			||||||
        context = super().get_context_data(**kwargs)
 | 
					        context = super().get_context_data()
 | 
				
			||||||
        context.update({
 | 
					        context.update({
 | 
				
			||||||
            'title': self.title,
 | 
					            'title': self.title,
 | 
				
			||||||
            'header': self.header,
 | 
					            'header': self.header,
 | 
				
			||||||
@ -239,14 +256,20 @@ class Section (BaseSection):
 | 
				
			|||||||
        })
 | 
					        })
 | 
				
			||||||
        return context
 | 
					        return context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get (self, request, **kwargs):
 | 
					    def get (self, request, object = None, **kwargs):
 | 
				
			||||||
        self.object = kwargs.get('object') or self.object
 | 
					        self.object = object or self.object
 | 
				
			||||||
 | 
					        if self.object_required and not self.object:
 | 
				
			||||||
 | 
					            raise ValueError('object is required by this Section but not given')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return super().get(request, **kwargs)
 | 
					        return super().get(request, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Sections:
 | 
					class Sections:
 | 
				
			||||||
    class Image (BaseSection):
 | 
					    class Image (BaseSection):
 | 
				
			||||||
        url = None # relative url to the image
 | 
					        """
 | 
				
			||||||
 | 
					        Render an image with the given relative url.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        url = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        @property
 | 
					        @property
 | 
				
			||||||
        def content (self):
 | 
					        def content (self):
 | 
				
			||||||
@ -256,6 +279,10 @@ class Sections:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class PostContent (Section):
 | 
					    class PostContent (Section):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Render the content of the Post (format the text a bit and escape HTML
 | 
				
			||||||
 | 
					        tags).
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
        @property
 | 
					        @property
 | 
				
			||||||
        def content (self):
 | 
					        def content (self):
 | 
				
			||||||
            content = escape(self.object.content)
 | 
					            content = escape(self.object.content)
 | 
				
			||||||
@ -265,6 +292,9 @@ class Sections:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class PostImage (Section):
 | 
					    class PostImage (Section):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Render the image of the Post
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
        @property
 | 
					        @property
 | 
				
			||||||
        def content (self):
 | 
					        def content (self):
 | 
				
			||||||
            return '<img src="{}" class="post_image">'.format(
 | 
					            return '<img src="{}" class="post_image">'.format(
 | 
				
			||||||
@ -281,59 +311,78 @@ class Sections:
 | 
				
			|||||||
            icon = None
 | 
					            icon = None
 | 
				
			||||||
            title = None
 | 
					            title = None
 | 
				
			||||||
            text = None
 | 
					            text = None
 | 
				
			||||||
 | 
					            url = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            def __init__ (self, icon, title = None, text = None):
 | 
					            def __init__ (self, icon, title = None, text = None, url = None):
 | 
				
			||||||
                self.icon = icon
 | 
					                self.icon = icon
 | 
				
			||||||
                self.title = title
 | 
					                self.title = title
 | 
				
			||||||
                self.text = text
 | 
					                self.text = text
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        use_icons = True
 | 
					        hide_empty = False      # hides the section if the list is empty
 | 
				
			||||||
        icon_size = '32x32'
 | 
					        use_icons = True        # print icons
 | 
				
			||||||
 | 
					        icon_size = '32x32'     # icons size
 | 
				
			||||||
        template_name = 'aircox_cms/section_list.html'
 | 
					        template_name = 'aircox_cms/section_list.html'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        def get_object_list (self):
 | 
					        def get_object_list (self):
 | 
				
			||||||
            return []
 | 
					            return []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        def get_context_data (self, **kwargs):
 | 
					        def get_context_data (self, **kwargs):
 | 
				
			||||||
 | 
					            object_list = self.get_object_list()
 | 
				
			||||||
 | 
					            self.visibility = True
 | 
				
			||||||
 | 
					            if not object_list and hide_empty:
 | 
				
			||||||
 | 
					                self.visibility = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            context = super().get_context_data(**kwargs)
 | 
					            context = super().get_context_data(**kwargs)
 | 
				
			||||||
            context.update({
 | 
					            context.update({
 | 
				
			||||||
                'classes': context.get('classes') + ' section_list',
 | 
					                'classes': context.get('classes') + ' section_list',
 | 
				
			||||||
                'icon_size': self.icon_size,
 | 
					                'icon_size': self.icon_size,
 | 
				
			||||||
                'object_list': self.get_object_list(),
 | 
					                'object_list': object_list,
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
            return context
 | 
					            return context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class UrlList (List):
 | 
					    class Urls (List):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Render a list of urls of targets that are Posts
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
        classes = 'section_urls'
 | 
					        classes = 'section_urls'
 | 
				
			||||||
        targets = None
 | 
					        targets = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        def get_object_list (self, request, **kwargs):
 | 
					        def get_object_list (self):
 | 
				
			||||||
            return [
 | 
					            return [
 | 
				
			||||||
                List.Item(
 | 
					                List.Item(
 | 
				
			||||||
                    target.image or None,
 | 
					                    target.image or None,
 | 
				
			||||||
                    '<a href="{}">{}</a>'.format(target.detail_url(), target.title)
 | 
					                    target.title,
 | 
				
			||||||
 | 
					                    url = target.detail_url(),
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
                for target in self.targets
 | 
					                for target in self.targets
 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class Posts (PostBaseView, Section):
 | 
				
			||||||
    class PostList (PostListView):
 | 
					        """
 | 
				
			||||||
        route = None
 | 
					        Render a list using PostListView's template.
 | 
				
			||||||
        model = None
 | 
					        """
 | 
				
			||||||
        embed = True
 | 
					        embed = True
 | 
				
			||||||
 | 
					        icon_size = '64x64'
 | 
				
			||||||
 | 
					        fields = [ 'date', 'time', 'image', 'title', 'content' ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        def __init__ (self, *args, **kwargs):
 | 
					        def get_object_list (self):
 | 
				
			||||||
            super().__init__(*args, **kwargs)
 | 
					            return []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        def get_kwargs (self, request, **kwargs):
 | 
					        def render_list (self):
 | 
				
			||||||
            return kwargs
 | 
					            self.embed = True
 | 
				
			||||||
 | 
					            context = self.get_base_context(**self.kwargs)
 | 
				
			||||||
        def dispatch (self, request, *args, **kwargs):
 | 
					            context.update({
 | 
				
			||||||
            kwargs = self.get_kwargs(kwargs)
 | 
					                'object_list': self.get_object_list(),
 | 
				
			||||||
            response = super().dispatch(request, *args, **kwargs)
 | 
					                'embed': True,
 | 
				
			||||||
            return str(response.content)
 | 
					            })
 | 
				
			||||||
 | 
					            print(context['object_list'][0].image)
 | 
				
			||||||
 | 
					            return render_to_string(PostListView.template_name, context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def get_context_data (self, **kwargs):
 | 
				
			||||||
 | 
					            context = super().get_context_data(**kwargs)
 | 
				
			||||||
 | 
					            context['content'] = self.render_list()
 | 
				
			||||||
 | 
					            return context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ViewSet:
 | 
					class ViewSet:
 | 
				
			||||||
@ -348,15 +397,25 @@ class ViewSet:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    detail_view = PostDetailView
 | 
					    detail_view = PostDetailView
 | 
				
			||||||
    detail_sections = [
 | 
					    detail_sections = [
 | 
				
			||||||
        Sections.PostContent,
 | 
					        Sections.PostContent(),
 | 
				
			||||||
        Sections.PostImage,
 | 
					        Sections.PostImage(),
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__ (self, website = None):
 | 
					
 | 
				
			||||||
        self.detail_sections = [
 | 
					    def get_list_name (self):
 | 
				
			||||||
            section()
 | 
					        """
 | 
				
			||||||
                for section in self.detail_sections
 | 
					        Return a string with the name to use in the route for the lists
 | 
				
			||||||
        ]
 | 
					        """
 | 
				
			||||||
 | 
					        return self.model._meta.verbose_name_plural.lower()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def get_detail_name (cl):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Return a string with the name to use in the route for the details
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        return cl.model._meta.verbose_name.lower()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def connect (self, website = None):
 | 
				
			||||||
        self.detail_view = self.detail_view.as_view(
 | 
					        self.detail_view = self.detail_view.as_view(
 | 
				
			||||||
            model = self.model,
 | 
					            model = self.model,
 | 
				
			||||||
            sections = self.detail_sections,
 | 
					            sections = self.detail_sections,
 | 
				
			||||||
@ -367,8 +426,9 @@ class ViewSet:
 | 
				
			|||||||
            website = website,
 | 
					            website = website,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.urls = [ route.as_url(self.model, self.list_view)
 | 
					        self.urls = [ route.as_url(self.model, self.get_list_name(),
 | 
				
			||||||
                            for route in self.list_routes ] + \
 | 
					                            self.list_view) for route in self.list_routes ] + \
 | 
				
			||||||
                      [ routes.DetailRoute.as_url(self.model, self.detail_view ) ]
 | 
					                      [ routes.DetailRoute.as_url(self.model,
 | 
				
			||||||
 | 
					                          self.get_detail_name(), self.detail_view ) ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -12,6 +12,7 @@ class Website:
 | 
				
			|||||||
                    'right', 'bottom',
 | 
					                    'right', 'bottom',
 | 
				
			||||||
                    'header', 'footer']
 | 
					                    'header', 'footer']
 | 
				
			||||||
    router = None
 | 
					    router = None
 | 
				
			||||||
 | 
					    registry = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def urls (self):
 | 
					    def urls (self):
 | 
				
			||||||
@ -27,7 +28,9 @@ class Website:
 | 
				
			|||||||
        Register a ViewSet (or subclass) to the router,
 | 
					        Register a ViewSet (or subclass) to the router,
 | 
				
			||||||
        and connect it to self.
 | 
					        and connect it to self.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        view_set = view_set(website = self)
 | 
					        view_set = view_set()
 | 
				
			||||||
 | 
					        view_set.connect(website = self)
 | 
				
			||||||
 | 
					        self.registry[view_set.get_detail_name()] = view_set
 | 
				
			||||||
        self.router.register_set(view_set)
 | 
					        self.router.register_set(view_set)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_menu (self, position):
 | 
					    def get_menu (self, position):
 | 
				
			||||||
 | 
				
			|||||||
@ -71,7 +71,7 @@ class ProgramAdmin (NameableAdmin):
 | 
				
			|||||||
@admin.register(Episode)
 | 
					@admin.register(Episode)
 | 
				
			||||||
class EpisodeAdmin (NameableAdmin):
 | 
					class EpisodeAdmin (NameableAdmin):
 | 
				
			||||||
    list_filter = ['program'] + NameableAdmin.list_filter
 | 
					    list_filter = ['program'] + NameableAdmin.list_filter
 | 
				
			||||||
    fields = NameableAdmin.fields + ['sounds']
 | 
					    fields = NameableAdmin.fields + ['sounds', 'program']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    inlines = (TrackInline, DiffusionInline)
 | 
					    inlines = (TrackInline, DiffusionInline)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -20,7 +20,7 @@ def add_inline (base_model, post_model, prepend = False):
 | 
				
			|||||||
                    'fields': ['title', 'content', 'image', 'tags']
 | 
					                    'fields': ['title', 'content', 'image', 'tags']
 | 
				
			||||||
                }),
 | 
					                }),
 | 
				
			||||||
                (None, {
 | 
					                (None, {
 | 
				
			||||||
                    'fields': ['date', 'published', 'author', 'thread']
 | 
					                    'fields': ['date', 'published', 'author', 'thread_pk', 'thread_type']
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -40,6 +40,8 @@ def add_inline (base_model, post_model, prepend = False):
 | 
				
			|||||||
add_inline(programs.Program, Program, True)
 | 
					add_inline(programs.Program, Program, True)
 | 
				
			||||||
add_inline(programs.Episode, Episode, True)
 | 
					add_inline(programs.Episode, Episode, True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					admin.site.register(Program)
 | 
				
			||||||
 | 
					admin.site.register(Episode)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#class ArticleAdmin (DescriptionAdmin):
 | 
					#class ArticleAdmin (DescriptionAdmin):
 | 
				
			||||||
#    fieldsets = copy.deepcopy(DescriptionAdmin.fieldsets)
 | 
					#    fieldsets = copy.deepcopy(DescriptionAdmin.fieldsets)
 | 
				
			||||||
 | 
				
			|||||||
@ -6,6 +6,7 @@ import aircox_programs.models as programs
 | 
				
			|||||||
class Program (RelatedPost):
 | 
					class Program (RelatedPost):
 | 
				
			||||||
    class Relation:
 | 
					    class Relation:
 | 
				
			||||||
        related_model = programs.Program
 | 
					        related_model = programs.Program
 | 
				
			||||||
 | 
					        bind_mapping = True
 | 
				
			||||||
        mapping = {
 | 
					        mapping = {
 | 
				
			||||||
            'title': 'name',
 | 
					            'title': 'name',
 | 
				
			||||||
            'content': 'description',
 | 
					            'content': 'description',
 | 
				
			||||||
@ -14,6 +15,7 @@ class Program (RelatedPost):
 | 
				
			|||||||
class Episode (RelatedPost):
 | 
					class Episode (RelatedPost):
 | 
				
			||||||
    class Relation:
 | 
					    class Relation:
 | 
				
			||||||
        related_model = programs.Episode
 | 
					        related_model = programs.Episode
 | 
				
			||||||
 | 
					        bind_mapping = True
 | 
				
			||||||
        mapping = {
 | 
					        mapping = {
 | 
				
			||||||
            'title': 'name',
 | 
					            'title': 'name',
 | 
				
			||||||
            'content': 'description',
 | 
					            'content': 'description',
 | 
				
			||||||
 | 
				
			|||||||
@ -9,36 +9,87 @@ h1, h2, h3 {
 | 
				
			|||||||
    font-family: "Myriad Pro",Calibri,Helvetica,Arial,sans-serif
 | 
					    font-family: "Myriad Pro",Calibri,Helvetica,Arial,sans-serif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					time {
 | 
				
			||||||
 | 
					    font-size: 0.9em;
 | 
				
			||||||
 | 
					    color: #616161;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					a {
 | 
				
			||||||
 | 
					    text-decoration: none;
 | 
				
			||||||
 | 
					    color: #616161;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					a:hover {
 | 
				
			||||||
 | 
					    color: #818181;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
nav.menu {
 | 
					nav.menu {
 | 
				
			||||||
    padding: 0.5em;
 | 
					    padding: 0.5em;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
nav.menu_top {
 | 
					    nav.menu_top {
 | 
				
			||||||
        background-color: #212121;
 | 
					        background-color: #212121;
 | 
				
			||||||
        color: #007EDF;
 | 
					        color: #007EDF;
 | 
				
			||||||
        font-size: 1.1em;
 | 
					        font-size: 1.1em;
 | 
				
			||||||
}
 | 
					        box-shadow: 0em 0.2em 0.5em 0.1em black
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    header {
 | 
					    header.menu {
 | 
				
			||||||
 | 
					        padding: 0.2em;
 | 
				
			||||||
        height: 9em;
 | 
					        height: 9em;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    header img {
 | 
					        header.menu img {
 | 
				
			||||||
            height: 100%;
 | 
					            height: 100%;
 | 
				
			||||||
            float: left;
 | 
					            float: left;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    header .colony {
 | 
					        #colony img {
 | 
				
			||||||
 | 
					            height: auto;
 | 
				
			||||||
            position: fixed;
 | 
					            position: fixed;
 | 
				
			||||||
        top: 0em;
 | 
					            top: 1em;
 | 
				
			||||||
            right: 0;
 | 
					            right: 0;
 | 
				
			||||||
            z-index: -1;
 | 
					            z-index: -1;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.page {
 | 
					.page {
 | 
				
			||||||
    width: 100%;
 | 
					    width: 100%;
 | 
				
			||||||
 | 
					    padding: 1.5em 0em;
 | 
				
			||||||
    background-color: rgba(255, 255, 255, 0.8);
 | 
					    background-color: rgba(255, 255, 255, 0.8);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .page img {
 | 
				
			||||||
 | 
					        box-shadow: 0em 0em 0.2em 0.01em black;
 | 
				
			||||||
 | 
					        border-radius: 0.2em;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.post_list {
 | 
				
			||||||
 | 
					    background-color: #F2F2F2;
 | 
				
			||||||
 | 
					    box-shadow: inset 0.2em 0.2em 0.2em 0.01em black;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .post_list .post_item {
 | 
				
			||||||
 | 
					        min-height: 64px;
 | 
				
			||||||
 | 
					        padding: 0.2em;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .post_list .post_item:hover {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .post_list h3 {
 | 
				
			||||||
 | 
					        margin: 0.2em;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .post_list time {
 | 
				
			||||||
 | 
					        float: right;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .post_list img {
 | 
				
			||||||
 | 
					        float: left;
 | 
				
			||||||
 | 
					        margin-right: 0.5em;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -18,7 +18,8 @@ class ProgramSet (ViewSet):
 | 
				
			|||||||
    ]
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    detail_sections = ViewSet.detail_sections + [
 | 
					    detail_sections = ViewSet.detail_sections + [
 | 
				
			||||||
        ScheduleSection,
 | 
					        ScheduleSection(),
 | 
				
			||||||
 | 
					        EpisodesSection(),
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class EpisodeSet (ViewSet):
 | 
					class EpisodeSet (ViewSet):
 | 
				
			||||||
@ -49,7 +50,7 @@ website = Website(
 | 
				
			|||||||
            position = 'header',
 | 
					            position = 'header',
 | 
				
			||||||
            sections = [
 | 
					            sections = [
 | 
				
			||||||
                Sections.Image(url = 'website/logo.png'),
 | 
					                Sections.Image(url = 'website/logo.png'),
 | 
				
			||||||
                Sections.Image(url = 'website/colony.png', classes='colony'),
 | 
					                Sections.Image(url = 'website/colony.png', attrs = { 'id': 'colony' }),
 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -8,6 +8,9 @@ from django.utils.translation import ugettext as _, ugettext_lazy
 | 
				
			|||||||
import aircox_programs.models as programs
 | 
					import aircox_programs.models as programs
 | 
				
			||||||
from aircox_cms.views import Sections
 | 
					from aircox_cms.views import Sections
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from website.models import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PlayListSection (Sections.List):
 | 
					class PlayListSection (Sections.List):
 | 
				
			||||||
    title = _('Playlist')
 | 
					    title = _('Playlist')
 | 
				
			||||||
@ -34,4 +37,10 @@ class ScheduleSection (Sections.List):
 | 
				
			|||||||
        ]
 | 
					        ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class EpisodesSection (Sections.Posts):
 | 
				
			||||||
 | 
					    title = _('Episodes')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_object_list (self):
 | 
				
			||||||
 | 
					        return Episode.objects.filter(related__program = self.object.pk)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user