From: Jacob Hilker Date: Tue, 28 Jan 2014 22:37:43 +0000 (-0500) Subject: 208 - Edit course properties - first pass X-Git-Tag: release-20150131~178^2~14 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=65b39385d431d1fa3416e6e8f765aae78d09b719;p=oweals%2Fkarmaworld.git 208 - Edit course properties - first pass --- diff --git a/karmaworld/apps/courses/views.py b/karmaworld/apps/courses/views.py index bb12926..a6b9c05 100644 --- a/karmaworld/apps/courses/views.py +++ b/karmaworld/apps/courses/views.py @@ -5,6 +5,7 @@ import json +from django.core import serializers from django.core.exceptions import MultipleObjectsReturned from django.core.exceptions import ObjectDoesNotExist @@ -20,7 +21,7 @@ from karmaworld.apps.courses.models import Course from karmaworld.apps.courses.models import School from karmaworld.apps.notes.models import Note from karmaworld.apps.users.models import CourseKarmaEvent -from karmaworld.utils import ajax_increment, format_session_increment_field +from karmaworld.utils.ajax_increment import * FLAG_FIELD = 'flags' @@ -81,7 +82,6 @@ class CourseDetailView(DetailView): return kwargs - class AboutView(TemplateView): """ Display the About page with the Schools leaderboard """ template_name = "about.html" @@ -197,3 +197,29 @@ def flag_course(request, pk): """Record that somebody has flagged a note.""" return ajax_increment(Course, request, pk, FLAG_FIELD, process_course_flag_events) +def edit_course(request, pk): + """ + Saves the edited course content + """ + course = Course.objects.get(pk=pk) + course_form = CourseForm(request.POST or None, instance=course) + + if request.method == "POST" and request.is_ajax(): + if course_form.is_valid(): + + # This will fail if name and school match one that already exists + # Same happens for add, should add specialized validation? + course_form.save() + + # Make a helper for this? Kinda Ugly... + course_json = serializers.serialize('json', [course,]) + return HttpResponse(json.dumps(json.loads(course_json)[0]), + mimetype="application/json") + else: + print course_form.errors + return HttpResponseBadRequest(json.dumps({'status': 'fail', 'message': 'Validation error', + 'errors': course_form.errors}), + mimetype="application/json") + else: + return HttpResponseBadRequest(json.dumps({'status': 'fail', 'message': 'Invalid request'}), + mimetype="application/json") diff --git a/karmaworld/assets/css/global.css b/karmaworld/assets/css/global.css index 0116f23..208c14f 100644 --- a/karmaworld/assets/css/global.css +++ b/karmaworld/assets/css/global.css @@ -36,6 +36,10 @@ input[type="text"]:focus, textarea:focus border-radius: 0; } +.hidden { + display:none; +} + .half-padding { @@ -614,7 +618,8 @@ a.activity_target:hover #add-note-btn, #add-course-btn, #existing-course-btn, -#save-btn +#save-btn, +#edit-save-btn { border: none; background-color: white; @@ -628,18 +633,24 @@ a.activity_target:hover } #existing-course-btn, -#save-btn { +#save-btn, +#edit-save-btn { margin-top: 13px; } #existing-course-btn.disabled, -#save-btn.disabled +#save-btn.disabled, +#edit-save-btn.disabled { color: #afafaf; cursor: auto; } -#add-note-form, #add-course-form +.validation_error { + color:red; +} + +#add-note-form, #add-course-form, #edit-course-form { display: none; } diff --git a/karmaworld/assets/js/add-course.js b/karmaworld/assets/js/add-course.js index 5253db1..a25928a 100644 --- a/karmaworld/assets/js/add-course.js +++ b/karmaworld/assets/js/add-course.js @@ -17,7 +17,7 @@ $(function() { $('#save-btn').removeClass('disabled'); $('#existing-course-msg').hide(); } - } + }; addCourse = function() { // Show the add a course form @@ -81,26 +81,7 @@ $(function() { minLength: 3 }); - $("#id_name").autocomplete({ - source: function(request, response){ - var school_id = $('#id_school').val(); - $.ajax({ - url: json_school_course_list, - data: {q: request.term, school_id: school_id}, - success: function(data) { - if (data['status'] === 'success') { - response($.map(data['courses'], function(item) { - return { - value: item.name, - label: item.name, - }; - })); - } - }, - dataType: "json", - type: 'POST' - }); - }, + KARMAWORLD.Course.initCourseNameAutocomplete({ select: function(event, ui) { courseNameSelected = true; fieldEdited(); @@ -110,33 +91,10 @@ $(function() { courseNameSelected = false; fieldEdited(); } - }, - minLength: 3 + } }); - $("#id_instructor_name").autocomplete({ - source: function(request, response) { - var school_id = $('#id_school').val(); - var course_name = $('#id_name').val(); - $.ajax({ - url: json_school_course_instructor_list, - data: {q: request.term, school_id: school_id, course_name: course_name}, - success: function(data) { - if (data['status'] === 'success') { - // Fill in the autocomplete entries - response($.map(data['instructors'], function(item) { - return { - value: item.name, - label: item.name, - url: item.url - }; - })); - } - }, - dataType: "json", - type: 'POST' - }); - }, + KARMAWORLD.Course.initInstructorNameAutocomplete({ select: function(event, ui) { instructorSelected = true; $('#existing-course-btn').attr('href', ui.item.url); @@ -148,9 +106,7 @@ $(function() { $('#existing-course-btn').attr('href', ''); fieldEdited(); } - }, - minLength: 3 + } }); - }); diff --git a/karmaworld/assets/js/course-detail.js b/karmaworld/assets/js/course-detail.js index c0149a5..9c1d089 100644 --- a/karmaworld/assets/js/course-detail.js +++ b/karmaworld/assets/js/course-detail.js @@ -1,6 +1,5 @@ - $(function() { - $("#flag-button").click(function(event) { + $('#flag-button').click(function(event) { event.preventDefault(); if (confirm('Do you wish to flag this course for deletion?')) { @@ -14,9 +13,69 @@ $(function() { // this note $.ajax({ url: course_flag_url, - dataType: "json", + dataType: 'json', type: 'POST' }); } }); + + $('#edit-button').click(function(event) { + $('#edit-course-form').slideToggle(); + }); + + $('#edit-save-btn').click(function(event) { + $.ajax({ + url: course_edit_url, + dataType: 'json', + data: $('#edit-course-form').children().serialize(), + type: 'POST', + success: function(data) { + // We might want to use a template here instead of rehashing logic + // on both the client and server side + $('#edit-course-form').slideUp(); + $('.validation_error').remove() + $('#course_form_errors').text(''); + $('#course_name').text(data.fields.name); + $('#course_instructor_name').text(data.fields.instructor_name); + + var $externalLinkSquare = $('', {'class': 'fa fa-external-link-square'}); + $('#course_url').text(data.fields.url.slice(0, 50) + ' '); + $('#course_url').append($externalLinkSquare); + $('#course_url').attr('href', data.fields.url); + if (data.fields.url === '') { + $('#course_link').parent().hide(); + } else { + $('#course_link').parent().show(); + } + }, + error: function(resp) { + var json = JSON.parse(resp.responseText); + var errors = json.errors; + + // Delete all errors that currently exist + $('.validation_error').remove() + + // Failed responses with no errors -> display message + if (!errors) { + $('#course_form_errors').text(json.message); + } else { + if (errors.instructor_email) { + $.each(errors.instructor_email, function(index, value) { + $('#id_instructor_email').parent().children('legend').append($('', { class: 'validation_error', text: value })); + }); + } + + if (errors.url) { + $.each(errors.url, function(index, value) { + $('#id_url').parent().children('legend').append($('', { class: 'validation_error' , text: value })); + }); + } + } + } + }); + }); + + KARMAWORLD.Course.initCourseNameAutocomplete({}); + KARMAWORLD.Course.initInstructorNameAutocomplete({}); + }); diff --git a/karmaworld/assets/js/course.js b/karmaworld/assets/js/course.js new file mode 100644 index 0000000..b0ddc76 --- /dev/null +++ b/karmaworld/assets/js/course.js @@ -0,0 +1,58 @@ +window.KARMAWORLD = window.KARMAWORLD || {}; +window.KARMAWORLD.Course = { + initCourseNameAutocomplete: function(autocompleteOpts) { + var opts = $.extend( {}, autocompleteOpts, { + source: function(request, response){ + var school_id = $('#id_school').val(); + $.ajax({ + url: json_school_course_list, + data: {q: request.term, school_id: school_id}, + success: function(data) { + if (data['status'] === 'success') { + response($.map(data['courses'], function(item) { + return { + value: item.name, + label: item.name, + }; + })); + } + }, + dataType: "json", + type: 'POST' + }); + }, + minLength: 3 + }); + $("#id_name").autocomplete(opts); + }, + + initInstructorNameAutocomplete: function(autocompleteOpts) { + var opts = $.extend( {}, autocompleteOpts, { + source: function(request, response) { + var school_id = $('#id_school').val(); + var course_name = $('#id_name').val(); + $.ajax({ + url: json_school_course_instructor_list, + data: {q: request.term, school_id: school_id, course_name: course_name}, + success: function(data) { + if (data['status'] === 'success') { + // Fill in the autocomplete entries + response($.map(data['instructors'], function(item) { + return { + value: item.name, + label: item.name, + url: item.url + }; + })); + } + }, + dataType: "json", + type: 'POST' + }); + }, + minLength: 3 + }); + + $("#id_instructor_name").autocomplete(opts); + } +}; diff --git a/karmaworld/templates/courses/course_detail.html b/karmaworld/templates/courses/course_detail.html index f539f02..61ccbee 100644 --- a/karmaworld/templates/courses/course_detail.html +++ b/karmaworld/templates/courses/course_detail.html @@ -5,14 +5,17 @@ {% block pagescripts %} + {% endblock %} - {% block pagestyle %} {% endblock %} @@ -27,15 +30,16 @@
-
+
{{ course.name }} -
+
- {{ course.instructor_name }} {% if course.department %}// {{ course.department.name }}{% endif %} + {{ course.instructor_name }} + {% if course.department %}// {{ course.department.name }}{% endif %}
@@ -48,32 +52,82 @@
- {% if course.url %} - - {% endif %} + -
+
+ edit_flag note_flag note_flag
-
+
+
+
+ {% csrf_token %} + +
+
+ {{ course_form.non_field_errors }} +
+
+ + +
+
+ Course Name: + +
+
+ +
+
+ Instructor Name: + +
+ +
+ Instructor Email: + +
+
+ +
+
+ Course url: + +
+
+ +
+
+ +
+
+
+

@@ -120,5 +174,6 @@
{% endcomment %} - + + {% endblock %} diff --git a/karmaworld/templates/partial/add_course.html b/karmaworld/templates/partial/add_course.html index 3da42b5..2938f5b 100644 --- a/karmaworld/templates/partial/add_course.html +++ b/karmaworld/templates/partial/add_course.html @@ -5,7 +5,8 @@ var json_school_course_instructor_list = "{% url 'json_school_course_instructor_list' %}" var csrf_token = "{{ csrf_token }}"; - + +
@@ -38,7 +39,7 @@
- Course Name: + Course Name: {% if course_form.name.errors %} * there was an error with this field diff --git a/karmaworld/urls.py b/karmaworld/urls.py index ee571f2..339bbd5 100644 --- a/karmaworld/urls.py +++ b/karmaworld/urls.py @@ -9,7 +9,7 @@ from django.conf.urls import patterns, include, url from django.views.generic.base import TemplateView from karmaworld.apps.courses.models import Course -from karmaworld.apps.courses.views import AboutView, flag_course +from karmaworld.apps.courses.views import AboutView, flag_course, edit_course from karmaworld.apps.courses.views import CourseDetailView from karmaworld.apps.courses.views import CourseListView from karmaworld.apps.courses.views import school_list @@ -100,6 +100,8 @@ urlpatterns = patterns('', url(r'^ajax/note/downloaded/(?P[\d]+)/$', downloaded_note, name='downloaded_note'), # Ajax endpoint to flag a course url(r'^ajax/course/flag/(?P[\d]+)/$', flag_course, name='flag_course'), + # Ajax endpoint to edit a course + url(r'^ajax/course/edit/(?P[\d]+)/$', edit_course, name='edit_course'), # Valid url cases to the Note page # a: school/course/id diff --git a/karmaworld/utils/ajax_increment.py b/karmaworld/utils/ajax_increment.py index 2e6e466..9e70555 100644 --- a/karmaworld/utils/ajax_increment.py +++ b/karmaworld/utils/ajax_increment.py @@ -39,4 +39,3 @@ def ajax_increment(cls, request, pk, field, event_processor=None): request.session[format_session_increment_field(cls, pk, field)] = True return ajax_base(cls, request, pk, ajax_increment_work) -