Merge pull request #329 from FinalsClub/315-editable-note-tags
authorCharles Connell <charles@connells.org>
Tue, 11 Feb 2014 22:14:11 +0000 (17:14 -0500)
committerCharles Connell <charles@connells.org>
Tue, 11 Feb 2014 22:14:11 +0000 (17:14 -0500)
Add ability to edit tags on notes

karmaworld/apps/document_upload/models.py
karmaworld/apps/document_upload/views.py
karmaworld/apps/notes/views.py
karmaworld/apps/users/models.py
karmaworld/assets/css/global.css
karmaworld/assets/css/note_course_pages.css
karmaworld/assets/js/note-detail.js
karmaworld/templates/courses/course_detail.html
karmaworld/templates/notes/note_detail.html
karmaworld/urls.py
reqs/common.txt

index 8d26b241350b9f4f9d8eacd36dfb64f0bfc3f0a8..ccf8e81944b91468558db36977bdfa7188cb2aa9 100644 (file)
@@ -67,6 +67,8 @@ class RawDocument(Document):
 
     def save(self, user=None, *args, **kwargs):
         super(RawDocument, self).save(*args, **kwargs)
+
+    def process_document(self, user=None):
         if not self.is_processed:
             tasks.process_raw_document.delay(self, user)
 
index b0195efe8d8e774ce7ccc7e22a8d079b9774a376..a8c85b28e66fdd668ecb9b70007526ac26b0b785 100644 (file)
@@ -13,6 +13,7 @@ def save_fp_upload(request):
     """ ajax endpoint for saving a FilePicker uploaded file form
     """
     r_d_f = RawDocumentForm(request.POST)
+
     if r_d_f.is_valid():
         raw_document = r_d_f.save(commit=False)
 
@@ -33,6 +34,9 @@ def save_fp_upload(request):
             raw_document.save()
         # save the tags to the database, too. don't forget those guys.
         r_d_f.save_m2m()
+        # Proccess document after the tags are saved so that it isn't converted
+        # to a note before the tags are attached to the document
+        raw_document.process_document()
 
         return HttpResponse({'success'})
     else:
index e970655ed7140688e1eefc1c627b04876345d0e3..30633c4b935565684ad5a2b0cb9645f0d21b2e6d 100644 (file)
@@ -5,6 +5,8 @@
 import json
 import traceback
 import logging
+
+from django.core import serializers
 from django.core.exceptions import ObjectDoesNotExist
 from karmaworld.apps.courses.models import Course
 from karmaworld.apps.notes.search import SearchIndex
@@ -279,4 +281,20 @@ def downloaded_note(request, pk):
     """Record that somebody has flagged a note."""
     return ajax_base(Note, request, pk, process_downloaded_note)
 
+def edit_note_tags(request, pk):
+    """
+    Saves the posted string of tags
+    """
+    if request.method == "POST" and request.is_ajax() and request.user.is_authenticated() and request.user.get_profile().can_edit_items():
+        note = Note.objects.get(pk=pk)
+        note.tags.set(request.body)
+
+        note_json = serializers.serialize('json', [note,])
+        resp = json.loads(note_json)[0]
+        resp['fields']['tags'] = list(note.tags.names())
+
+        return HttpResponse(json.dumps(resp), mimetype="application/json")
+    else:
+        return HttpResponseBadRequest(json.dumps({'status': 'fail', 'message': 'Invalid request'}),
+                                      mimetype="application/json")
 
index af2638b1eae4f37978a4e7c6a01b33c5dc1d239b..f4a329dff719fced9b5e792b0f47c9734be14299 100644 (file)
@@ -40,7 +40,7 @@ class UserProfile(models.Model):
 
         return sum
 
-    def can_edit_courses(self):
+    def can_edit_items(self):
         return (self.get_points() >= 20)
 
     NO_BADGE = 0
index 6386b43c3d404c8d12e9f3ab6004202df1c2153c..6426f4377b52759e066c04678c0c53a8f4664a16 100644 (file)
@@ -614,10 +614,11 @@ a.activity_target:hover
 #add-course-btn,
 #existing-course-btn,
 #save-btn,
+#save_note_tags,
 #edit-save-btn
 {
   border: none;
-  background-color: white;
+  background-color: transparent;
   color: #f05a28;
   cursor: pointer;
   font: 30px/1.2em "MuseoSlab-300", serif;
index bf17df4757f67a1365cc32a99a9070e124bbe7eb..c23bedd34d3041c440ab1baf54abebd872918d4a 100644 (file)
@@ -12,7 +12,7 @@
   margin-right: 3px;
 }
 
-#note_status, #note_pedigree
+#note_status, #note_pedigree, #note_tags
 {
   text-align: center;
   padding-top: 10px;
   padding-bottom: 20px;
   margin-bottom: 20px;
 }
+
+.tag-span:after
+{
+  content: ', ';
+}
+
+.tag-span:last-child:after
+{
+  content: '';
+}
+
+#note_tags_form
+{
+  text-align: center;
+}
+
+#note_tags_input
+{
+  margin-left: 25%;
+  width: 50%;
+}
index 28ece64a7bdbec31fbf137deff88f5f2c615e5b1..1392c77376a5638d21cdf929bb730d0e21e270e8 100644 (file)
@@ -6,8 +6,8 @@ function autoResize(id){
   var newwidth;
 
   if(document.getElementById){
-    newheight = document.getElementById(id).contentWindow.document .body.scrollHeight;
-    newwidth = document.getElementById(id).contentWindow.document .body.scrollWidth;
+    newheight = document.getElementById(id).contentWindow.document.body.scrollHeight;
+    newwidth = document.getElementById(id).contentWindow.document.body.scrollWidth;
   }
 
   document.getElementById(id).height = (newheight + 10) + "px";
@@ -130,25 +130,44 @@ $(function() {
     };
   });
 
-  $.ajax(note_contents_url,
-    {
-      type: 'GET',
-      xhrFields: {
-        onprogress: function (progress) {
-          var percentage = Math.floor((progress.loaded / progress.total) * 100);
-          writeNoteFrame("<h3 style='text-align: center'>" + percentage + "%</h3>");
-        }
-      },
-      success: function(data, textStatus, jqXHR) {
-        writeNoteFrame(data);
-        autoResize('noteframe');
-        if (pdfControls == true) {
-          setupPdfViewer();
-        }
-      },
-      error: function(data, textStatus, jqXHR) {
-        writeNoteFrame("<h3 style='text-align: center'>Sorry, your note could not be retrieved.</h3>");
+  $.ajax(note_contents_url, {
+    type: 'GET',
+    xhrFields: {
+      onprogress: function (progress) {
+        var percentage = Math.floor((progress.loaded / progress.total) * 100);
+        writeNoteFrame("<h3 style='text-align: center'>" + percentage + "%</h3>");
+      }
+    },
+    success: function(data, textStatus, jqXHR) {
+      writeNoteFrame(data);
+      autoResize('noteframe');
+      if (pdfControls == true) {
+        setupPdfViewer();
+      }
+    },
+    error: function(data, textStatus, jqXHR) {
+      writeNoteFrame("<h3 style='text-align: center'>Sorry, your note could not be retrieved.</h3>");
+    }
+  });
+
+  $('#edit_note_tags').click(function(event) {
+    $('#note_tags_form').slideToggle();
+  });
+
+  $('#save_note_tags').click(function(event) {
+    $.ajax({
+      url: edit_note_tags_url,
+      dataType: 'json',
+      data: $('#note_tags_input').val(),
+      type: 'POST',
+      success: function(data) {
+        $('#note_tags_form').slideUp();
+        $('.tags').empty();
+        $.each(data.fields.tags, function(index, tag) {
+          $('.tags').append($('<span>', { class: 'tag-span', text: tag }));
+        });
       }
     });
+  });
 
 });
index 151419012be40251588b4d19acc12aeb867ad5e7..d3d6bd80adb9dc1e4fd133153f30ceaeb746169c 100644 (file)
@@ -68,7 +68,7 @@
           <div class="row">
             <div class="small-12 column center">
               {% if user.is_authenticated %}
-                {% if user.get_profile.can_edit_courses %}
+                {% if user.get_profile.can_edit_items %}
                   <a href="#" id="edit-button"><img src="{{ STATIC_URL }}img/edit.png" alt="edit_flag" width="25" height="35"/></a>
                 {% endif %}
 
       </div>
     </div><!-- /course_header -->
 
-    {% if user.get_profile.can_edit_courses %}
+    {% if user.get_profile.can_edit_items %}
       <section id="edit-course-form">
         <form>
           {% csrf_token %}
index f2ea776f7362de64cdc40c45fc829f9f14f4a0c7..4d20454f1ebb13b200ca1cb59a53729a40faf73f 100644 (file)
@@ -13,6 +13,7 @@
   <script type="text/javascript">
     var note_thank_url = "{% url 'thank_note' note.id %}"
     var note_flag_url = "{% url 'flag_note' note.id %}"
+    var edit_note_tags_url = "{% url 'edit_note_tags' note.id %}"
     var note_downloaded_url = "{% url 'downloaded_note' note.id %}"
     var note_contents_url = "{{ S3_URL }}{{ note.get_relative_s3_path }}"
     {% if pdf_controls %}
         </div><!-- /note_name -->
       </div>
 
+      <div class="row">
+        <div id="note_tags" class="twelve columns activity_details_context">
+          <span>Tags: </span>
+          <span class="tags">
+            {% for tag in note.tags.all %}
+              <span class="tag-span">{{ tag.name }}</span>
+            {% endfor %}
+          </span>
+          {% if user.get_profile.can_edit_items %}
+            <i id="edit_note_tags" class="fa fa-pencil-square-o"></i>
+          {% endif %}
+        </div><!-- /note_tags -->
+      </div>
+
+      {% if user.get_profile.can_edit_items %}
+        <div class="row">
+          <div id="note_tags_form" class="twelve columns activity_details_context hide">
+            <input id="note_tags_input" type="text" value="{% for tag in note.tags.all %}{{ tag.name }}{% if not forloop.last %}, {% endif %}{% endfor %}">
+            <button id="save_note_tags" type=button><i class="fa fa-save"></i> Save</button>
+          </div>
+        </div>
+      {% endif %}
+
       <div class="row">
         <div id="note_status" class="twelve columns">
           <div class="activity_details_status">
index 339bbd50c9829d09770e1c6dd667d92b77b37cad..cbac3d003908dbedb3b6a1f6115e9050c55845d3 100644 (file)
@@ -15,7 +15,7 @@ from karmaworld.apps.courses.views import CourseListView
 from karmaworld.apps.courses.views import school_list
 from karmaworld.apps.courses.views import school_course_list
 from karmaworld.apps.courses.views import school_course_instructor_list
-from karmaworld.apps.notes.views import NoteView, thank_note, NoteSearchView, flag_note, downloaded_note
+from karmaworld.apps.notes.views import NoteView, thank_note, NoteSearchView, flag_note, downloaded_note, edit_note_tags
 from karmaworld.apps.notes.views import RawNoteDetailView
 from karmaworld.apps.notes.views import PDFView
 from karmaworld.apps.moderation import moderator
@@ -96,6 +96,8 @@ urlpatterns = patterns('',
     url(r'^ajax/note/thank/(?P<pk>[\d]+)/$', thank_note, name='thank_note'),
     # Ajax endpoint to flag a note
     url(r'^ajax/note/flag/(?P<pk>[\d]+)/$', flag_note, name='flag_note'),
+    # Ajax endpoint to update a notes tags
+    url(r'^ajax/note/tags/(?P<pk>[\d]+)/$', edit_note_tags, name='edit_note_tags'),
     # Ajax endpoint to record that somebody downloaded a note
     url(r'^ajax/note/downloaded/(?P<pk>[\d]+)/$', downloaded_note, name='downloaded_note'),
     # Ajax endpoint to flag a course
index 9a058cf9cada881b67628e85a23ecb8e8d92af1e..7e0ec2c5072959e6ca0d962cf71d061327d39826 100644 (file)
@@ -8,7 +8,7 @@ oauth2client==1.0
 urllib3==1.5
 google-api-python-client==1.0
 django-grappelli==2.4.8
-git+https://github.com/FinalsClub/django-taggit.git
+django-taggit
 git+https://github.com/btbonval/django-filepicker.git
 filemagic==1.6
 requests