Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Non-admin CRUD views for ParticipationTag and ParticipationRole #745

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
260 changes: 260 additions & 0 deletions course/enrollment.py
Original file line number Diff line number Diff line change
Expand Up @@ -1114,4 +1114,264 @@ def edit_participation(pctx, participation_id):

# }}}


# {{{ edit_participation_tag

class EditParticipationTagForm(StyledModelForm):
def __init__(self, add_new, *args, **kwargs):
# type: (bool, *Any, **Any) -> None
super(EditParticipationTagForm, self).__init__(*args, **kwargs)

if add_new:
self.helper.add_input(
Submit("submit", _("Add")))
else:
self.helper.add_input(
Submit("submit", _("Update")))

class Meta:
model = ParticipationTag
exclude = ("course",)


@course_view
def view_participation_tag_list(pctx):
if not pctx.has_permission(pperm.view_gradebook):
raise PermissionDenied(_("may not edit participation tags"))

participation_tags = list(ParticipationTag.objects.filter(course=pctx.course))

return render_course_page(pctx, "course/participation-tag-list.html", {
"participation_tags": participation_tags,

# Wrappers used by JavaScript template (tmpl) so as not to
# conflict with Django template's tag wrapper
"JQ_OPEN": "{%",
"JQ_CLOSE": "%}",
})


@course_view
def edit_participation_tag(pctx, ptag_id):
# type: (CoursePageContext, int) -> http.HttpResponse
if not pctx.has_permission(pperm.edit_participation):
raise PermissionDenied()

request = pctx.request

num_ptag_id = int(ptag_id)

if num_ptag_id == -1:
ptag = ParticipationTag(course=pctx.course)
add_new = True
else:
ptag = get_object_or_404(ParticipationTag, id=num_ptag_id)
add_new = False

if ptag.course.id != pctx.course.id:
raise SuspiciousOperation(
"may not edit participation tag in different course")

if request.method == "POST":
form = EditParticipationTagForm(add_new, request.POST, instance=ptag)
try:
if form.is_valid():
# Ref: https://stackoverflow.com/q/21458387/3437454
with transaction.atomic():
form.save()
if add_new:
msg = _("New participation tag saved.")
else:
msg = _("Changes saved.")
messages.add_message(request, messages.SUCCESS, msg)
return redirect(
"relate-view_participation_tags", pctx.course.identifier)
except IntegrityError:
messages.add_message(
request, messages.ERROR,
_("A participation tag with that name already exists."))

else:
form = EditParticipationTagForm(add_new, instance=ptag)

return render_course_page(pctx, "course/generic-course-form.html", {
"form_description": _("Edit Participation Tag"),
"form": form,
})


@course_view
def delete_participation_tag(pctx, ptag_id):
# type: (CoursePageContext, int) -> http.HttpResponse

if not pctx.has_permission(pperm.edit_participation):
raise PermissionDenied()

request = pctx.request

if not request.is_ajax() or request.method != "POST":
raise PermissionDenied(_("only AJAX POST is allowed"))

num_ptag_id = int(ptag_id)

ptag = get_object_or_404(ParticipationTag, id=num_ptag_id)

if ptag.course.id != pctx.course.id:
raise SuspiciousOperation(
"may not delete participation tag in different course")

if "delete" in request.POST:
try:
ptag.delete()
except Exception as e:
return http.JsonResponse(
{"error": _(
"Error when deleting participation tag '%(tag)s'."
" %(error_type)s: %(error)s.") % {
"tag": ptag.name,
"error_type": type(e).__name__,
"error": str(e)}},
status=400)
else:
return http.JsonResponse(
{"message": _("successfully deleted participation tag '%(tag)s'.")
% {"tag": ptag.name},
"message_level": messages.DEFAULT_TAGS[messages.SUCCESS]})

else:
raise SuspiciousOperation(_("invalid operation"))

# }}}


# {{{ edit_participation_role

class EditParticipationRoleForm(StyledModelForm):
def __init__(self, add_new, *args, **kwargs):
# type: (bool, *Any, **Any) -> None
super(EditParticipationRoleForm, self).__init__(*args, **kwargs)

if add_new:
self.helper.add_input(
Submit("submit", _("Add")))
else:
self.helper.add_input(
Submit("submit", _("Update")))

class Meta:
model = ParticipationRole
exclude = ("course",)


@course_view
def view_participation_role_list(pctx):
if not pctx.has_permission(pperm.view_gradebook):
raise PermissionDenied(_("may not edit participation tags"))

participation_roles = list(ParticipationRole.objects.filter(course=pctx.course))

return render_course_page(pctx, "course/participation-role-list.html", {
"participation_roles": participation_roles,

# Wrappers used by JavaScript template (tmpl) so as not to
# conflict with Django template's tag wrapper
"JQ_OPEN": "{%",
"JQ_CLOSE": "%}",
})


@course_view
def edit_participation_role(pctx, prole_id):
# type: (CoursePageContext, int) -> http.HttpResponse
if not pctx.has_permission(pperm.edit_participation):
raise PermissionDenied()

request = pctx.request

num_prole_id = int(prole_id)

if num_prole_id == -1:
prole = ParticipationRole(course=pctx.course)
add_new = True
else:
prole = get_object_or_404(ParticipationRole, id=num_prole_id)
add_new = False

if prole.course.id != pctx.course.id:
raise SuspiciousOperation(
"may not edit participation role in different course")

if request.method == "POST":
form = EditParticipationRoleForm(add_new, request.POST, instance=prole)
try:
if form.is_valid():
# Ref: https://stackoverflow.com/q/21458387/3437454
with transaction.atomic():
form.save()

if add_new:
msg = _("New participation role saved.")
else:
msg = _("Changes saved.")
messages.add_message(request, messages.SUCCESS, msg)
return redirect(
"relate-view_participation_roles", pctx.course.identifier)
except IntegrityError:
messages.add_message(
request, messages.ERROR,
_("A participation role with that identifier already exists."))

else:
form = EditParticipationRoleForm(add_new, instance=prole)

return render_course_page(pctx, "course/generic-course-form.html", {
"form_description": _("Edit Participation Role"),
"form": form,
})


@course_view
def delete_participation_role(pctx, prole_id):
# type: (CoursePageContext, int) -> http.HttpResponse

if not pctx.has_permission(pperm.edit_participation):
raise PermissionDenied()

request = pctx.request

if not request.is_ajax() or request.method != "POST":
raise PermissionDenied(_("only AJAX POST is allowed"))

num_prole_id = int(prole_id)

prole = get_object_or_404(ParticipationRole, id=num_prole_id)

if prole.course.id != pctx.course.id:
raise SuspiciousOperation(
"may not delete participation role in different course")

if "delete" in request.POST:
try:
prole.delete()
except Exception as e:
return http.JsonResponse(
{"error": _(
"Error when deleting participation role '%(role)s'."
" %(error_type)s: %(error)s.") % {
"role": prole.identifier,
"error_type": type(e).__name__,
"error": str(e)}},
status=400)
else:
return http.JsonResponse(
{"message": _("successfully deleted participation role '%(role)s'.")
% {"role": prole.identifier},
"message_level": messages.DEFAULT_TAGS[messages.SUCCESS]})

else:
raise SuspiciousOperation(_("invalid operation"))

# }}}


# vim: foldmethod=marker
11 changes: 8 additions & 3 deletions course/templates/course/course-base.html
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,23 @@
</li>
{% endif %}

{% if pperm.view_gradebook %}
{% if pperm.view_gradebook or pperm.edit_participation %}
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">{% trans "Grading" context "menu item" %}<b class="caret"></b></a>
<ul class="dropdown-menu">
<li role="presentation" class="dropdown-header">{% trans "Participations" %}</li>
<li><a href="{% url "relate-view_participant_list" course.identifier %}">{% trans "List of participants" %}</a></li>
{% if pperm.edit_participation %}
dzhuang marked this conversation as resolved.
Show resolved Hide resolved
<li><a href="{% url "relate-view_participation_roles" course.identifier %}">{% trans "Participation roles" %}</a></li>
<li><a href="{% url "relate-view_participation_tags" course.identifier %}">{% trans "Participation tags" %}</a></li>
<li role="presentation" class="divider"></li>
{% endif %}
{% if pperm.view_analytics %}
<li><a href="{% url "relate-flow_list" course.identifier %}">{% trans "Analytics Overview" %}</a></li>
{% endif %}

{% if pperm.view_gradebook %}
<li role="presentation" class="divider"></li>
<li role="presentation" class="dropdown-header">{% trans "Grade Book" %}</li>
<li><a href="{% url "relate-view_participant_list" course.identifier %}">{% trans "List of Participants" %}</a></li>
<li><a href="{% url "relate-view_grading_opportunity_list" course.identifier %}">{% trans "List of Grading Opportunities" %}</a></li>
<li><a href="{% url "relate-view_gradebook" course.identifier %}">{% trans "Grade book" %}</a></li>
{% if pperm.batch_export_grade %}
Expand Down
4 changes: 2 additions & 2 deletions course/templates/course/gradebook-participant-list.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
{% load static %}

{% block title %}
{% trans "List of Participants" %} - {{ relate_site_name }}
{% trans "List of participants" %} - {{ relate_site_name }}
dzhuang marked this conversation as resolved.
Show resolved Hide resolved
{% endblock %}

{% block header_extra %}
{% include "datatables-header.html" %}
{% endblock %}

{% block content %}
<h1>{% trans "List of Participants" %}</h1>
<h1>{% trans "List of participants" %}</h1>

<a href="{% url "relate-edit_participation" course.identifier -1 %}" class="btn btn-default">{% trans "Add participant" %}</a>

Expand Down
25 changes: 25 additions & 0 deletions course/templates/course/participation-role-list.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{% extends "course/course-base.html" %}
{% load i18n %}

{% load static %}

{% block title %}
{% trans "Participation roles" %} - {{ relate_site_name }}
{% endblock %}

{% block header_extra %}
{% include "datatables-header.html" %}
{% endblock %}

{% block content %}
<h1>{% trans "Participation roles" %}</h1>

<a href="{% url "relate-edit_participation_role" course.identifier -1 %}" class="btn btn-default">{% trans "Add participation role" %}</a>

{% include "course/participation-role-table.html" with participation_roles=participation_roles %}

{% endblock %}

{% block page_bottom_javascript_extra %}
<script src="{{ STATIC_URL }}blueimp-tmpl/js/tmpl.min.js"></script>
{% endblock %}
dzhuang marked this conversation as resolved.
Show resolved Hide resolved
Loading