diff --git a/aircox/templates/aircox/episode_detail.html b/aircox/templates/aircox/episode_detail.html
index 8ad5be2..abc06a9 100644
--- a/aircox/templates/aircox/episode_detail.html
+++ b/aircox/templates/aircox/episode_detail.html
@@ -3,6 +3,18 @@
{% load i18n aircox %}
+{% block top-nav-tools %}
+{% has_perm page page.program.change_permission_codename simple=True as can_edit %}
+{% if can_edit %}
+
+
+
+
+ {% translate "Edit" %}
+
+{% endif %}
+{% endblock %}
+
{% block content-container %}
diff --git a/aircox/templates/aircox/episode_form.html b/aircox/templates/aircox/episode_form.html
new file mode 100644
index 0000000..e86f672
--- /dev/null
+++ b/aircox/templates/aircox/episode_form.html
@@ -0,0 +1,30 @@
+{% extends "aircox/basepage_detail.html" %}
+{% load static i18n humanize honeypot aircox %}
+
+
+{% block head_extra %}
+ {{ form.media }}
+{% endblock %}
+
+{% block init-scripts %}
+{% endblock %}
+
+{% block top-nav-tools %}
+
+
+
+
+ {% translate "View" %}
+
+{% endblock %}
+
+{% block main %}
+
+{% endblock %}
diff --git a/aircox/templates/aircox/widgets/episode_item.html b/aircox/templates/aircox/widgets/episode_item.html
index 57648b4..02f23a1 100644
--- a/aircox/templates/aircox/widgets/episode_item.html
+++ b/aircox/templates/aircox/widgets/episode_item.html
@@ -25,12 +25,31 @@
{% endblock %}
-{% block content %}
-{% if not object.content %}
- {% with object.parent.content as content %}
- {{ block.super }}
- {% endwith %}
-{% else %}
- {{ block.super }}
+{% block actions %}
+{% if object.sound_set.public.count %}
+
+{% endif %}
+{% endblock %}
+
+{% block actions %}
+{% has_perm page object.program.change_permission_codename simple=True as can_edit %}
+{% if can_edit %}
+
+
+
+{% endif %}
+
+{% if object.sound_set.public.count %}
+
{% endif %}
{% endblock %}
diff --git a/aircox/urls.py b/aircox/urls.py
index c7085b1..7f2b79b 100755
--- a/aircox/urls.py
+++ b/aircox/urls.py
@@ -114,6 +114,11 @@ urls = [
views.EpisodeDetailView.as_view(),
name="episode-detail",
),
+ path(
+ _("programs/episodes//edit/"),
+ views.EpisodeUpdateView.as_view(),
+ name="episode-edit",
+ ),
path(_("podcasts/"), views.PodcastListView.as_view(), name="podcast-list"),
path(_("podcasts/c//"), views.PodcastListView.as_view(), name="podcast-list"),
# ---- others
diff --git a/aircox/views/__init__.py b/aircox/views/__init__.py
index d9c2010..9029130 100644
--- a/aircox/views/__init__.py
+++ b/aircox/views/__init__.py
@@ -2,7 +2,7 @@ from . import admin, errors
from .article import ArticleDetailView, ArticleListView
from .base import BaseAPIView, BaseView
from .diffusion import DiffusionListView, TimeTableView
-from .episode import EpisodeDetailView, EpisodeListView, PodcastListView
+from .episode import EpisodeDetailView, EpisodeListView, PodcastListView, EpisodeUpdateView
from .home import HomeView
from .log import LogListAPIView, LogListView
from .page import (
@@ -32,6 +32,7 @@ __all__ = (
"EpisodeDetailView",
"EpisodeListView",
"PodcastListView",
+ "EpisodeUpdateView",
"HomeView",
"LogListAPIView",
"LogListView",
diff --git a/aircox/views/episode.py b/aircox/views/episode.py
index 7d0c4a9..dd166b2 100644
--- a/aircox/views/episode.py
+++ b/aircox/views/episode.py
@@ -1,14 +1,24 @@
-from django.shortcuts import reverse
+from django.contrib.auth.mixins import UserPassesTestMixin
+from django.forms import ModelForm, FileField
+from django.urls import reverse
+
+from ckeditor.fields import RichTextField
+from filer.models.filemodels import File
+
+from aircox.controllers.sound_file import SoundFile
from ..filters import EpisodeFilters
from ..models import Episode, Program, StaticPage
from .page import PageListView
-from .program import ProgramPageDetailView
+from .program import ProgramPageDetailView, BaseProgramMixin
+from .page import PageUpdateView
+
__all__ = (
"EpisodeDetailView",
"EpisodeListView",
"PodcastListView",
+ "EpisodeUpdateView",
)
@@ -39,3 +49,36 @@ class EpisodeListView(PageListView):
class PodcastListView(EpisodeListView):
attach_to_value = StaticPage.Target.PODCASTS
queryset = Episode.objects.published().with_podcasts().order_by("-pub_date")
+
+
+class EpisodeForm(ModelForm):
+ content = RichTextField()
+ new_podcast = FileField(required=False)
+
+ class Meta:
+ model = Episode
+ fields = ["content"]
+
+ def save(self, commit=True):
+ file_obj = self.cleaned_data["new_podcast"]
+ if file_obj:
+ obj, _ = File.objects.get_or_create(original_filename=file_obj.name, file=file_obj)
+ sound_file = SoundFile(obj.path)
+ sound_file.sync(
+ program=self.instance.program, episode=self.instance, type=0, is_public=True, is_downloadable=True
+ )
+
+
+class EpisodeUpdateView(UserPassesTestMixin, BaseProgramMixin, PageUpdateView):
+ model = Episode
+ form_class = EpisodeForm
+
+ def get_sidebar_queryset(self):
+ return super().get_sidebar_queryset().filter(parent=self.program)
+
+ def test_func(self):
+ program = self.get_object().program
+ return self.request.user.has_perm("aircox.%s" % program.change_permission_codename)
+
+ def get_success_url(self):
+ return reverse("episode-detail", kwargs={"slug": self.get_object().slug})