diff --git a/README.md b/README.md index 508fab6..5a62d76 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ -# Aircox -Platform to manage a radio. We use the power of Django +![](/data/logo.png) + +Platform to manage a radio, schedules, website, and so on. We use the power of Django and Liquidsoap. ## Current features * **streams**: multiple random music streams when no program is played. We also can specify a time range and frequency; diff --git a/cms/models.py b/cms/models.py index aef69e3..33e538b 100644 --- a/cms/models.py +++ b/cms/models.py @@ -92,15 +92,15 @@ class RelatedPostBase (models.base.ModelBase): registry = {} @classmethod - def register (cl, key, model): + def register (cl, key, post_model): """ Register a model and return the key under which it is registered. Raise a ValueError if another model is yet associated under this key. """ - if key in cl.registry and cl.registry[key] is not model: + if key in cl.registry and cl.registry[key] is not post_model: raise ValueError('A model has yet been registered with "{}"' .format(key)) - cl.registry[key] = model + cl.registry[key] = post_model return key @classmethod @@ -137,13 +137,15 @@ class RelatedPostBase (models.base.ModelBase): return rel def __new__ (cl, name, bases, attrs): + # TODO: allow proxy models and better inheritance if name == 'RelatedPost': return super().__new__(cl, name, bases, attrs) rel = cl.make_relation(name, attrs) + field_args = rel.field_args or {} attrs['_relation'] = rel attrs.update({ x:y for x,y in { - 'related': models.ForeignKey(rel.model), + 'related': models.ForeignKey(rel.model, **field_args), '__str__': lambda self: str(self.related) }.items() if not attrs.get(x) }) @@ -207,6 +209,8 @@ class RelatedPost (Post, metaclass = RelatedPostBase): * rel_to_post: auto update the post when related object is updated * thread_model: generated by the metaclass, points to the RelatedPost model generated for the bindings.thread object. + * field_args: dict of arguments to pass to the ForeignKey constructor, + such as: ForeignKey(related_model, **field_args) Be careful with post_to_rel! * There is no check of permissions when related object is synchronised @@ -217,14 +221,15 @@ class RelatedPost (Post, metaclass = RelatedPostBase): model = None bindings = None # values to map { post_attr: rel_attr } post_to_rel = False - rel_to_post = True + rel_to_post = False thread_model = None + field_args = None def get_rel_attr(self, attr): attr = self._relation.bindings.get(attr) return getattr(self.related, attr) if attr else None - def set_rel_attr(self, attr, value) + def set_rel_attr(self, attr, value): if attr not in self._relation.bindings: raise AttributeError('attribute {} is not bound'.format(attr)) attr = self._relation.bindings.get(attr) @@ -240,13 +245,13 @@ class RelatedPost (Post, metaclass = RelatedPostBase): if not rel.bindings: return - for attr, rel_attr in rel.bindings.items() + for attr, rel_attr in rel.bindings.items(): if attr == 'thread': continue value = getattr(self, attr) if hasattr(self, attr) else None setattr(self.related, rel_attr, value) - if self.thread_model: + if rel.thread_model: thread = self.thread if not issubclass(thread, rel.thread_model) \ else None self.set_rel_attr('thread', thread.related) @@ -254,6 +259,19 @@ class RelatedPost (Post, metaclass = RelatedPostBase): if save: self.related.save() + + @classmethod + def sync_from_rel(cl, rel, save = True): + """ + Update a rel_to_post from a given rel object. Return -1 if there is no + related post to update + """ + self = cl.objects.filter(related = rel) + if not self or not self.count(): + return -1 + self[0].rel_to_post(save) + + def rel_to_post(self, save = True): """ Change the post using the related object bound values. Save the @@ -264,7 +282,7 @@ class RelatedPost (Post, metaclass = RelatedPostBase): if rel.bindings: return - for attr, rel_attr in rel.bindings.items() + for attr, rel_attr in rel.bindings.items(): if attr == 'thread': continue self.set_rel_attr @@ -272,7 +290,7 @@ class RelatedPost (Post, metaclass = RelatedPostBase): if hasattr(self.related, attr) else None setattr(self, attr, value) - if self.thread_model: + if rel.thread_model: thread = self.get_rel_attr('thread') thread = rel.thread_model.objects.filter(related = thread) \ if thread else None @@ -282,11 +300,19 @@ class RelatedPost (Post, metaclass = RelatedPostBase): if save: self.save() + def __init__ (self, *kargs, **kwargs): + super().__init__(*kargs, **kwargs) + # we use this method for sync, in order to avoid intrusive code on other + # applications, e.g. using signals. + if self._relation.rel_to_post: + self.rel_to_post(save = False) + def save (self, *args, **kwargs): + # TODO handle when related change if not self.title and self.related: self.title = self.get_rel_attr('title') if self._relation.post_to_rel: - self.post_to_rel(False) + self.post_to_rel(save = True) super().save(*args, **kwargs) diff --git a/cms/templates/aircox/cms/base_site.html b/cms/templates/aircox/cms/base_site.html index 6320787..7172f8a 100644 --- a/cms/templates/aircox/cms/base_site.html +++ b/cms/templates/aircox/cms/base_site.html @@ -8,7 +8,7 @@ - + {% if website.styles %} {% endif %} diff --git a/cms/templates/aircox/cms/detail.html b/cms/templates/aircox/cms/detail.html index c022427..2859c4b 100644 --- a/cms/templates/aircox/cms/detail.html +++ b/cms/templates/aircox/cms/detail.html @@ -1,4 +1,4 @@ -{% extends embed|yesno:"aircox_cms/base_content.html,aircox_cms/base_site.html" %} +{% extends embed|yesno:"aircox/cms/base_content.html,aircox/cms/base_site.html" %} {% block title %} {{ object.title }} diff --git a/cms/templates/aircox/cms/list.html b/cms/templates/aircox/cms/list.html index 1edd77d..abce834 100644 --- a/cms/templates/aircox/cms/list.html +++ b/cms/templates/aircox/cms/list.html @@ -1,4 +1,4 @@ -{% extends embed|yesno:"aircox_cms/base_content.html,aircox_cms/base_site.html" %} +{% extends embed|yesno:"aircox/cms/base_content.html,aircox/cms/base_site.html" %} {% load i18n %} {% load thumbnail %} diff --git a/cms/templates/aircox/cms/section.html b/cms/templates/aircox/cms/section.html index 25febd0..494006c 100644 --- a/cms/templates/aircox/cms/section.html +++ b/cms/templates/aircox/cms/section.html @@ -1,4 +1,4 @@ -{% extends "aircox_cms/base_section.html" %} +{% extends "aircox/cms/base_section.html" %} {% block content %} {% if title %} diff --git a/cms/templates/aircox/cms/section_list.html b/cms/templates/aircox/cms/section_list.html index 35589ee..f1eb561 100644 --- a/cms/templates/aircox/cms/section_list.html +++ b/cms/templates/aircox/cms/section_list.html @@ -1,4 +1,4 @@ -{% extends "aircox_cms/section.html" %} +{% extends "aircox/cms/section.html" %} {% load thumbnail %} diff --git a/cms/views.py b/cms/views.py index 0ca3e71..5ac4678 100644 --- a/cms/views.py +++ b/cms/views.py @@ -307,6 +307,8 @@ class Sections: """ @property def content (self): + if not self.object.image: + return '' return ''.format( self.object.image.url ) diff --git a/data/logo.png b/data/logo.png new file mode 100644 index 0000000..cfab672 Binary files /dev/null and b/data/logo.png differ diff --git a/data/logo.svg b/data/logo.svg new file mode 100644 index 0000000..e3fbe21 --- /dev/null +++ b/data/logo.svg @@ -0,0 +1,165 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + Aircox + + + + +