summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--yaksh/forms.py28
-rw-r--r--yaksh/static/yaksh/js/lesson.js198
-rw-r--r--yaksh/templates/yaksh/add_lesson.html6
-rw-r--r--yaksh/templates/yaksh/add_topic.html2
-rw-r--r--yaksh/templates/yaksh/add_video_quiz.html2
-rw-r--r--yaksh/templates/yaksh/show_toc.html39
-rw-r--r--yaksh/templatetags/custom_filters.py3
-rw-r--r--yaksh/urls.py19
-rw-r--r--yaksh/views.py115
9 files changed, 269 insertions, 143 deletions
diff --git a/yaksh/forms.py b/yaksh/forms.py
index eedd809..ba8b7d5 100644
--- a/yaksh/forms.py
+++ b/yaksh/forms.py
@@ -652,6 +652,7 @@ class TopicForm(forms.ModelForm):
timer = forms.CharField()
def __init__(self, *args, **kwargs):
+ time = kwargs.pop("time") if "time" in kwargs else None
super(TopicForm, self).__init__(*args, **kwargs)
self.fields['name'].widget.attrs.update(
{'class': form_input_class, 'placeholder': 'Topic Name'}
@@ -659,11 +660,23 @@ class TopicForm(forms.ModelForm):
self.fields['timer'].widget.attrs.update(
{'class': form_input_class, 'placeholder': 'Topic Time'}
)
+ self.fields['timer'].initial = time
class Meta:
model = Topic
fields = "__all__"
+ def clean_timer(self):
+ timer = self.cleaned_data.get("timer")
+ if timer:
+ try:
+ hh, mm, ss = timer.split(":")
+ except ValueError:
+ raise forms.ValidationError(
+ "Marker time should be in the format hh:mm:ss"
+ )
+ return timer
+
class VideoQuizForm(forms.ModelForm):
@@ -676,6 +689,7 @@ class VideoQuizForm(forms.ModelForm):
question_type = kwargs.pop('question_type')
else:
question_type = "mcq"
+ time = kwargs.pop("time") if "time" in kwargs else None
super(VideoQuizForm, self).__init__(*args, **kwargs)
self.fields['summary'].widget.attrs.update(
{'class': form_input_class, 'placeholder': 'Summary'}
@@ -690,7 +704,7 @@ class VideoQuizForm(forms.ModelForm):
{'class': form_input_class, 'placeholder': 'Points'}
)
self.fields['type'].widget.attrs.update(
- {'class': form_input_class, 'readonly': True}
+ {'class': form_input_class}
)
self.fields['type'].initial = question_type
self.fields['description'].widget.attrs.update(
@@ -699,8 +713,20 @@ class VideoQuizForm(forms.ModelForm):
self.fields['timer'].widget.attrs.update(
{'class': form_input_class, 'placeholder': 'Quiz Time'}
)
+ self.fields['timer'].initial = time
class Meta:
model = Question
fields = ['summary', 'description', 'points',
'language', 'type', 'topic']
+
+ def clean_timer(self):
+ timer = self.cleaned_data.get("timer")
+ if timer:
+ try:
+ hh, mm, ss = timer.split(":")
+ except ValueError:
+ raise forms.ValidationError(
+ "Marker time should be in the format hh:mm:ss"
+ )
+ return timer \ No newline at end of file
diff --git a/yaksh/static/yaksh/js/lesson.js b/yaksh/static/yaksh/js/lesson.js
index 38db7d2..92038c9 100644
--- a/yaksh/static/yaksh/js/lesson.js
+++ b/yaksh/static/yaksh/js/lesson.js
@@ -16,10 +16,6 @@ $(document).ready(function() {
seconds = seconds < 10 ? "0" + seconds : seconds;
timer.val(hours + ":" + minutes + ":" + seconds);
});
- function csrfSafeMethod(method) {
- // these HTTP methods do not require CSRF protection
- return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
- }
$("#vtimer").on("change keyup paste", function() {
player.pause();
@@ -50,95 +46,7 @@ $(document).ready(function() {
ajax_call($(this).attr("action"), $(this).attr("method"), $(this).serialize(), csrf);
});
- function ajax_call(url, method, data, csrf) {
- $.ajax({
- url: url,
- timeout: 15000,
- method: method,
- data: data,
- beforeSend: function(xhr, settings) {
- if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
- xhr.setRequestHeader("X-CSRFToken", csrf);
- }
- },
- success: function(msg) {
- unlock_screen();
- if (msg.success) {
- if (msg.status) $("#lesson-content").html(msg.data);
- if (msg.content_type === '1') {
- add_topic();
- }
- else {
- add_question();
- }
- }
- if (msg.toc) show_toc(msg.toc);
- if (msg.message) alert(msg.message)
- },
- error: function(xhr, data) {
- switch(xhr.status) {
- case 400: {
- unlock_screen();
- console.log(data.responseJSON);
- break;
- }
- case 500: {
- unlock_screen();
- alert('500 status code! server error');
- break;
- }
- case 404: {
- unlock_screen();
- alert('404 status code! server error');
- break;
- }
- }
- }
- });
- }
-
- function add_topic() {
- if (!$("#id_timer").val()) {
- $("#id_timer").val($("#vtimer").val());
- }
- $("#topic-form").submit(function(e) {
- e.preventDefault();
- lock_screen();
- var csrf = document.getElementById("topic-form").elements[0].value;
- ajax_call($(this).attr("action"), $(this).attr("method"), $(this).serialize(), csrf);
- });
- }
-
- function add_question() {
- if (!$("#id_timer").val()) {
- $("#id_timer").val($("#vtimer").val());
- }
- $("#question-form").submit(function(e) {
- e.preventDefault();
- lock_screen();
- var csrf = document.getElementById("question-form").elements[0].value;
- ajax_call($(this).attr("action"), $(this).attr("method"), $(this).serialize(), csrf);
- });
- }
-
- function lock_screen() {
- document.getElementById("ontop").style.display = "block";
- }
-
- function unlock_screen() {
- document.getElementById("ontop").style.display = "none";
- }
-
- function show_error() {
-
- }
-
- function show_toc(toc) {
- $("#lesson-content").empty();
- $("#toc").html(toc);
- }
-
- $('#id_video_file').on('change',function(){
+ $('#id_video_file').on('change',function() {
//get the file name
var files = [];
for (var i = 0; i < $(this)[0].files.length; i++) {
@@ -147,7 +55,7 @@ $(document).ready(function() {
$(this).next('.custom-file-label').html(files.join(', '));
});
- $('#id_Lesson_files').on('change',function(){
+ $('#id_Lesson_files').on('change',function() {
//get the file name
var files = [];
for (var i = 0; i < $(this)[0].files.length; i++) {
@@ -156,3 +64,105 @@ $(document).ready(function() {
$(this).next('.custom-file-label').html(files.join(', '));
});
});
+
+
+function add_topic() {
+ if (!$("#id_timer").val()) {
+ $("#id_timer").val($("#vtimer").val());
+ }
+ $("#topic-form").submit(function(e) {
+ e.preventDefault();
+ lock_screen();
+ var csrf = document.getElementById("topic-form").elements[0].value;
+ ajax_call($(this).attr("action"), $(this).attr("method"), $(this).serialize(), csrf);
+ });
+}
+
+function add_question() {
+ if (!$("#id_timer").val()) {
+ $("#id_timer").val($("#vtimer").val());
+ }
+ $("#question-form").submit(function(e) {
+ e.preventDefault();
+ lock_screen();
+ var csrf = document.getElementById("question-form").elements[0].value;
+ ajax_call($(this).attr("action"), $(this).attr("method"), $(this).serialize(), csrf);
+ });
+}
+
+function lock_screen() {
+ document.getElementById("ontop").style.display = "block";
+}
+
+function unlock_screen() {
+ document.getElementById("ontop").style.display = "none";
+}
+
+function show_error(error) {
+ var err_msg = "\n";
+ Object.keys(err).forEach(function(key) {
+ var value = err[key];
+ err_msg = err_msg + key + " : " + value[0].message + "\n";
+ });
+ alert(err_msg);
+}
+
+function show_toc(toc) {
+ $("#lesson-content").empty();
+ $("#toc").html(toc);
+}
+
+function csrfSafeMethod(method) {
+ // these HTTP methods do not require CSRF protection
+ return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
+}
+
+function ajax_call(url, method, data, csrf) {
+ $.ajax({
+ url: url,
+ timeout: 15000,
+ method: method,
+ data: data,
+ beforeSend: function(xhr, settings) {
+ if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
+ xhr.setRequestHeader("X-CSRFToken", csrf);
+ }
+ },
+ success: function(msg) {
+ unlock_screen();
+ if (msg.success) {
+ if (msg.status) $("#lesson-content").html(msg.data);
+ if (parseInt(msg.content_type) === 1) {
+ add_topic();
+ }
+ else {
+ add_question();
+ }
+ }
+ if (msg.toc) show_toc(msg.toc);
+ if (msg.message) alert(msg.message)
+ },
+ error: function(xhr, data) {
+ unlock_screen();
+ switch(xhr.status) {
+ case 400: {
+ err = JSON.parse(xhr.responseJSON.message);
+ show_error(err);
+ break;
+ }
+ case 500: {
+ alert('500 status code! server error');
+ break;
+ }
+ case 404: {
+ alert('404 status code! server error');
+ break;
+ }
+ default: {
+ alert('Unable to perform action. Please try again');
+ break;
+ }
+ }
+ }
+ });
+}
diff --git a/yaksh/templates/yaksh/add_lesson.html b/yaksh/templates/yaksh/add_lesson.html
index 62aa881..6018e54 100644
--- a/yaksh/templates/yaksh/add_lesson.html
+++ b/yaksh/templates/yaksh/add_lesson.html
@@ -158,7 +158,13 @@
<div class="card-body">
{% if lesson_form.instance and lesson_form.instance.video_path %}
{% with lesson_form.instance.video_path|video_name as video %}
+ {% if video.1 == "others" %}
+ <video id="player" playsinline controls>
+ <source src="{{video.0}}" />
+ </video>
+ {% else %}
<div id="player" data-plyr-provider="{{video.1}}" data-plyr-embed-id="{{video.0}}"></div>
+ {% endif %}
<br>
<form action="{% url 'yaksh:add_marker' course_id lesson_form.instance.id %}" method="POST" id="marker-form" name="marker-form">
{% csrf_token %}
diff --git a/yaksh/templates/yaksh/add_topic.html b/yaksh/templates/yaksh/add_topic.html
index 8c8fdb3..52923e7 100644
--- a/yaksh/templates/yaksh/add_topic.html
+++ b/yaksh/templates/yaksh/add_topic.html
@@ -1,5 +1,5 @@
{% if topic_id %}
-<form class="form-group" method="POST" action="{% url 'yaksh:edit_topic' content_type course_id lesson_id topic_id %}" id="topic-form">
+<form class="form-group" method="POST" action="{% url 'yaksh:edit_topic' content_type course_id lesson_id toc_id topic_id %}" id="topic-form">
{% else %}
<form class="form-group" method="POST" action="{% url 'yaksh:add_topic' content_type course_id lesson_id %}" id="topic-form">
{% endif %}
diff --git a/yaksh/templates/yaksh/add_video_quiz.html b/yaksh/templates/yaksh/add_video_quiz.html
index cf59fcb..ad087bc 100644
--- a/yaksh/templates/yaksh/add_video_quiz.html
+++ b/yaksh/templates/yaksh/add_video_quiz.html
@@ -3,7 +3,7 @@
<script type="text/javascript" src="{% static 'yaksh/js/mathjax/MathJax.js' %}?config=TeX-MML-AM_CHTML">
</script>
{% if question_id %}
-<form class="form-group" method="POST" action="{% url 'yaksh:edit_marker_quiz' content_type course_id lesson_id question_id %}" id="question-form">
+<form class="form-group" method="POST" action="{% url 'yaksh:edit_marker_quiz' content_type course_id lesson_id toc_id question_id %}" id="question-form">
{% else %}
<form class="form-group" method="POST" action="{% url 'yaksh:add_marker_quiz' content_type course_id lesson_id %}" id="question-form">
{% endif %}
diff --git a/yaksh/templates/yaksh/show_toc.html b/yaksh/templates/yaksh/show_toc.html
index 85bcf40..b263652 100644
--- a/yaksh/templates/yaksh/show_toc.html
+++ b/yaksh/templates/yaksh/show_toc.html
@@ -1,8 +1,9 @@
<table class="table table-responsive-sm">
{% for toc in contents %}
+ {% with toc.get_toc_text as toc_name %}
<tr>
<td>
- {{ toc.get_toc_text }}
+ {{ toc_name }}
</td>
<td>
{{toc.get_content_display}}
@@ -12,18 +13,42 @@
</td>
<td>
{% if toc.content == 1 %}
- <a href="#" class="btn btn-outline-primary" data-url="{% url 'yaksh:edit_topic' toc.content toc.course_id toc.lesson_id toc.object_id %}">
+ <a href="#" class="btn btn-outline-info" data-url="{% url 'yaksh:edit_topic' toc.content toc.course_id toc.lesson_id toc.id toc.object_id %}" id="edit-toc" onclick="edit_toc(this)">
{% else %}
- <a href="#" class="btn btn-outline-primary" data-url="{% url 'yaksh:edit_marker_quiz' toc.content toc.course_id toc.lesson_id toc.object_id %}">
+ <a href="#" class="btn btn-outline-info" data-url="{% url 'yaksh:edit_marker_quiz' toc.content toc.course_id toc.lesson_id toc.id toc.object_id %}" id="edit-toc" onclick="edit_toc(this)">
{% endif %}
- <i class="fa fa-edit">&nbsp;Edit</i>
+ <i class="fa fa-edit"></i>&nbsp;Edit
</a>
</td>
<td>
- <a href="#" class="btn btn-outline-danger">
- <i class="fa fa-trash">&nbsp;Delete</i>
- </a>
+ <form action="{% url 'yaksh:delete_toc' toc.course_id toc.id %}" method="POST">
+ {% csrf_token %}
+ <input type="hidden" name="redirect_url" id="redirect_url" class="hidden">
+ <button class="btn btn-outline-danger" type="submit" onclick="return confirm('Are you sure you want to remove {{toc_name|capfirst}}?')">
+ <i class="fa fa-trash"></i>&nbsp;Remove
+ </button>
+ </form>
</td>
</tr>
+ {% endwith %}
+{% empty %}
+ <center>
+ <span class="badge badge-warning">No Table of contents added</span>
+ </center>
{% endfor %}
+<script type="text/javascript">
+ $(document).ready(function() {
+ var divs = document.getElementsByClassName("hidden");
+ for(var i = 0; i < divs.length; i++)
+ {
+ divs[i].value = window.location.pathname;
+ }
+ });
+
+ function edit_toc(obj) {
+ var url = obj.getAttribute("data-url");
+ lock_screen();
+ ajax_call(url, "GET");
+ }
+</script>
</table> \ No newline at end of file
diff --git a/yaksh/templatetags/custom_filters.py b/yaksh/templatetags/custom_filters.py
index 712df09..81c7b71 100644
--- a/yaksh/templatetags/custom_filters.py
+++ b/yaksh/templatetags/custom_filters.py
@@ -133,6 +133,5 @@ def video_name(text):
elif 'vimeo' in video.keys():
name, vformat = video.get('vimeo'), 'vimeo'
else:
- filename = os.path.basename(video.get("others"))
- name, vformat = os.path.split(filename)
+ name, vformat = video.get('others'), 'others'
return name, vformat
diff --git a/yaksh/urls.py b/yaksh/urls.py
index 2c462b3..d7fd410 100644
--- a/yaksh/urls.py
+++ b/yaksh/urls.py
@@ -241,18 +241,13 @@ urlpatterns = [
name='add_marker'),
path('manage/add/lesson/topic/<int:content_type>/<int:course_id>/<int:lesson_id>',
views.add_topic, name='add_topic'),
- path('manage/edit/lesson/topic/<int:content_type>/<int:course_id>/<int:lesson_id>/<int:topic_id>',
- views.add_topic, name='edit_topic'),
+ path('manage/edit/lesson/topic/<int:content_type>/<int:course_id>/<int:lesson_id>/'
+ '<int:toc_id>/<int:topic_id>', views.add_topic, name='edit_topic'),
path('manage/add/lesson/quiz/<int:content_type>/<int:course_id>/<int:lesson_id>',
views.add_marker_quiz, name='add_marker_quiz'),
- path('manage/edit/lesson/quiz/<int:content_type>/<int:course_id>/<int:lesson_id>/<int:question_id>',
- views.add_marker_quiz, name='edit_marker_quiz'),
- path('manage/add/lesson/exercise/<int:content_type>/<int:course_id>/<int:lesson_id>',
- views.add_marker_quiz, name='add_marker_quiz'),
- path('manage/edit/lesson/exercise/<int:content_type>/<int:course_id>/<int:lesson_id>/<int:question_id>',
- views.add_marker_quiz, name='edit_marker_quiz'),
- path('manage/add/lesson/poll/<int:content_type>/<int:course_id>/<int:lesson_id>',
- views.add_marker_quiz, name='add_marker_quiz'),
- path('manage/edit/lesson/poll/<int:content_type>/<int:course_id>/<int:lesson_id>/<int:question_id>',
- views.add_marker_quiz, name='edit_marker_quiz')
+ path('manage/edit/lesson/quiz/<int:content_type>/<int:course_id>/<int:lesson_id>/'
+ '<int:toc_id>/<int:question_id>', views.add_marker_quiz,
+ name='edit_marker_quiz'),
+ path('manage/remove/lesson/toc/<int:course_id>/<int:toc_id>',
+ views.delete_toc, name='delete_toc'),
]
diff --git a/yaksh/views.py b/yaksh/views.py
index db46d90..60d72e9 100644
--- a/yaksh/views.py
+++ b/yaksh/views.py
@@ -2686,6 +2686,9 @@ def show_lesson(request, lesson_id, module_id, course_id):
# update course status with current unit
_update_unit_status(course_id, user, learn_unit)
+ toc = TableOfContents.objects.filter(
+ course_id=course_id, lesson_id=lesson_id
+ )
all_modules = course.get_learning_modules()
if learn_unit.has_prerequisite():
@@ -2695,7 +2698,7 @@ def show_lesson(request, lesson_id, module_id, course_id):
context = {'lesson': learn_unit.lesson, 'user': user,
'course': course, 'state': "lesson", "all_modules": all_modules,
'learning_units': learning_units, "current_unit": learn_unit,
- 'learning_module': learn_module}
+ 'learning_module': learn_module, 'toc': toc}
return my_render_to_response(request, 'yaksh/show_video.html', context)
@@ -3478,14 +3481,26 @@ def get_tc_formset(question_type, post=None, question=None):
Question, tc, form=TestcaseForm, extra=1, fields="__all__",
)
formset = TestcaseFormset(
- post, initial=[{'type': tc_class}], instance=question
+ post, initial=[{'type': tc_class}], instance=question
)
return formset, tc_class
+def get_toc_contents(request, course_id, lesson_id):
+ contents = TableOfContents.objects.filter(
+ course_id=course_id, lesson_id=lesson_id
+ )
+ data = loader.render_to_string(
+ "yaksh/show_toc.html", context={'contents': contents},
+ request=request
+ )
+ return data
+
+
@login_required
@email_verified
-def add_topic(request, content_type, course_id, lesson_id, topic_id=None):
+def add_topic(request, content_type, course_id, lesson_id, toc_id=None,
+ topic_id=None):
user = request.user
course = get_object_or_404(Course, pk=course_id)
if (not is_moderator(user) or
@@ -3495,25 +3510,26 @@ def add_topic(request, content_type, course_id, lesson_id, topic_id=None):
topic = get_object_or_404(Topic, pk=topic_id)
else:
topic = None
+ if toc_id:
+ toc = get_object_or_404(TableOfContents, pk=toc_id)
+ else:
+ toc = None
context = {}
if request.method == "POST":
form = TopicForm(request.POST, instance=topic)
if form.is_valid():
form.save()
+ time = request.POST.get("timer")
if not topic:
TableOfContents.objects.create(
content_object=form.instance, course_id=course_id,
lesson_id=lesson_id, content=content_type,
- time=request.POST.get("timer")
- )
- contents = TableOfContents.objects.filter(
- course_id=course_id, lesson_id=lesson_id
- )
- data = loader.render_to_string(
- "yaksh/show_toc.html", context={'contents': contents},
- request=request
+ time=time
)
- context['toc'] = data
+ context['toc'] = get_toc_contents(request, course_id, lesson_id)
+ if toc:
+ toc.time = time
+ toc.save()
status_code = 200
context['success'] = True
context['message'] = 'Added topic successfully'
@@ -3521,13 +3537,26 @@ def add_topic(request, content_type, course_id, lesson_id, topic_id=None):
status_code = 400
context['success'] = False
context['message'] = form.errors.as_json()
+ else:
+ form = TopicForm(instance=topic, time=toc.time)
+ template_context = {'form': form, 'course_id': course.id,
+ 'lesson_id': lesson_id, 'content_type': content_type,
+ 'topic_id': topic_id, 'toc_id': toc_id}
+ data = loader.render_to_string(
+ "yaksh/add_topic.html", context=template_context, request=request
+ )
+ context['success'] = True
+ context['data'] = data
+ context['content_type'] = content_type
+ context['status'] = 1
+ status_code = 200
return JsonResponse(context, status=status_code)
@login_required
@email_verified
def add_marker_quiz(request, content_type, course_id, lesson_id,
- question_id=None):
+ toc_id=None, question_id=None):
user = request.user
course = get_object_or_404(Course, pk=course_id)
if (not is_moderator(user) or
@@ -3537,32 +3566,34 @@ def add_marker_quiz(request, content_type, course_id, lesson_id,
question = get_object_or_404(Question, pk=question_id)
else:
question = None
+ if toc_id:
+ toc = get_object_or_404(TableOfContents, pk=toc_id)
+ else:
+ toc = None
context = {}
if request.method == "POST":
qform = VideoQuizForm(request.POST, instance=question)
if qform.is_valid():
- qform.save(commit=False)
- qform.instance.user = user
+ if not question_id:
+ qform.save(commit=False)
+ qform.instance.user = user
qform.save()
formset, tc_class = get_tc_formset(
qform.instance.type, request.POST, qform.instance
)
if formset.is_valid():
formset.save()
+ time = request.POST.get("timer")
if not question:
TableOfContents.objects.create(
content_object=qform.instance, course_id=course_id,
lesson_id=lesson_id, content=content_type,
- time=request.POST.get("timer")
+ time=time
)
- contents = TableOfContents.objects.filter(
- course_id=course_id, lesson_id=lesson_id
- )
- data = loader.render_to_string(
- "yaksh/show_toc.html", context={'contents': contents},
- request=request
- )
- context['toc'] = data
+ context['toc'] = get_toc_contents(request, course_id, lesson_id)
+ if toc:
+ toc.time = time
+ toc.save()
status_code = 200
context['success'] = True
context['message'] = 'Added question successfully'
@@ -3570,9 +3601,43 @@ def add_marker_quiz(request, content_type, course_id, lesson_id,
else:
status_code = 400
context['success'] = False
- context['message'] = formset.errors.as_json()
+ context['message'] = "Error in saving form"
else:
status_code = 400
context['success'] = False
context['message'] = qform.errors.as_json()
+ else:
+ form = VideoQuizForm(instance=question, time=toc.time)
+ formset, tc_class = get_tc_formset(question.type, question=question)
+ template_context = {
+ 'form': form, 'course_id': course.id, 'lesson_id': lesson_id,
+ 'formset': formset, 'tc_class': tc_class, 'toc_id': toc_id,
+ 'content_type': content_type, 'question_id': question_id
+ }
+ data = loader.render_to_string(
+ "yaksh/add_video_quiz.html", context=template_context,
+ request=request
+ )
+ context['success'] = True
+ context['data'] = data
+ context['content_type'] = content_type
+ context['status'] = 2
+ status_code = 200
return JsonResponse(context, status=status_code)
+
+
+@login_required
+@email_verified
+def delete_toc(request, course_id, toc_id):
+ user = request.user
+ course = get_object_or_404(Course, pk=course_id)
+ if (not is_moderator(user) or
+ not course.is_creator(user) or not course.is_creator(user)):
+ raise Http404("You are not allowed to view this page")
+ toc = get_object_or_404(TableOfContents, pk=toc_id)
+ redirect_url = request.POST.get("redirect_url")
+ if toc.content == 1:
+ get_object_or_404(Topic, pk=toc.object_id).delete()
+ else:
+ get_object_or_404(Question, id=toc.object_id).delete()
+ return redirect(redirect_url)