#!/usr/bin/env python
# -*- coding:utf8 -*-
# Copyright (C) 2012 FinalsClub Foundation
-
-from django.forms import ModelForm
+from django.forms import ModelForm, IntegerField, HiddenInput, Form
from django.forms import TextInput
-
-from django_filepicker.forms import FPFileField
from django_filepicker.widgets import FPFileWidget
from karmaworld.apps.notes.models import Note
+
class NoteForm(ModelForm):
class Meta:
model = Note
- fields = ('name', 'tags', 'year',)
+ fields = ('name', 'tags',)
widgets = {
'name': TextInput()
}
+
+class NoteDeleteForm(Form):
+ note = IntegerField(widget=HiddenInput())
+
+
class FileUploadForm(ModelForm):
auto_id = False
class Meta:
import traceback
import logging
+from django.contrib import messages
from django.core import serializers
+from django.core.exceptions import ValidationError
from django.forms.formsets import formset_factory
from karmaworld.apps.courses.models import Course
from karmaworld.apps.notes.search import SearchIndex
from django.views.generic.detail import SingleObjectMixin
from karmaworld.apps.notes.models import Note
-from karmaworld.apps.notes.forms import NoteForm
+from karmaworld.apps.notes.forms import NoteForm, NoteDeleteForm
logger = logging.getLogger(__name__)
def note_page_context_helper(note, request, context):
+
+ if request.method == 'POST':
+ context['note_edit_form'] = NoteForm(request.POST)
+ else:
+ tags_string = ','.join([str(tag) for tag in note.tags.all()])
+ context['note_edit_form'] = NoteForm(initial={'name': note.name,
+ 'tags': tags_string})
+
+ context['note_delete_form'] = NoteDeleteForm(initial={'note': note.id})
+
if note.is_pdf():
context['pdf_controls'] = True
model = Note
template_name = 'notes/note_detail.html'
+ def post(self, request, *args, **kwargs):
+ self.object = self.get_object()
+ if self.object.user != request.user:
+ raise ValidationError("Only the owner of a note can edit it.")
+ return super(NoteSaveView, self).post(request, *args, **kwargs)
+
+ def get_success_url(self):
+ return self.object.get_absolute_url()
+
def get_context_data(self, **kwargs):
context = {
'object': self.get_object(),
}
return super(NoteSaveView, self).get_context_data(**context)
- def get_success_url(self):
- """ On form submission success, redirect to what url """
- #TODO: redirect to note slug if possible (auto-slugify)
- return u'/{school_slug}/{course_slug}?url=/{school_slug}/{course_slug}/{pk}&name={name}&thankyou'.format(
- school_slug=self.object.course.school.slug,
- course_slug=self.object.course.slug,
- pk=self.object.pk,
- name=self.object.name
- )
-
def form_valid(self, form):
""" Actions to take if the submitted form is valid
namely, saving the new data to the existing note object
"""
- self.object = self.get_object()
if len(form.cleaned_data['name'].strip()) > 0:
self.object.name = form.cleaned_data['name']
- self.object.year = form.cleaned_data['year']
# use *arg expansion to pass tags a list of tags
- self.object.tags.add(*form.cleaned_data['tags'])
+ self.object.tags.set(*form.cleaned_data['tags'])
# User has submitted this form, so set the SHOW flag
self.object.is_hidden = False
self.object.save()
return view(request, *args, **kwargs)
+class NoteDeleteView(FormView):
+ form_class = NoteDeleteForm
+
+ def form_valid(self, form):
+ self.note = Note.objects.get(id=form.cleaned_data['note'])
+ self.note.is_hidden = True
+ self.note.save()
+
+ messages.success(self.request, 'The note "{0}" was deleted successfully.'.format(self.note.name))
+
+ return super(FormView, self).form_valid(form)
+
+ def get_success_url(self):
+ return self.note.course.get_absolute_url()
+
+
class NoteKeywordsView(FormView, SingleObjectMixin):
""" Class-based view for the note html page """
model = Note
return super(NoteSearchView, self).get_context_data(**kwargs)
+def handle_edit_note(request):
+ course = Course.objects.get(pk=pk)
+ original_name = course.name
+ course_form = CourseForm(request.POST or None, instance=course)
+
+ if course_form.is_valid():
+ course_form.save()
+
+ course_json = serializers.serialize('json', [course,])
+ resp = json.loads(course_json)[0]
+
+ if (course.name != original_name):
+ course.set_slug()
+ resp['fields']['new_url'] = course.get_absolute_url()
+
+ return HttpResponse(json.dumps(resp), mimetype="application/json")
+ else:
+ return HttpResponseBadRequest(json.dumps({'status': 'fail', 'message': 'Validation error',
+ 'errors': course_form.errors}),
+ mimetype="application/json")
+
+def edit_note(request, pk):
+ """
+ Saves the edited note metadata
+ """
+ ajax_base(request, edit_note, ['POST'])
+
+
def process_note_thank_events(request_user, note):
# Give points to the person who uploaded this note
if note.user != request_user and note.user:
display: inline;
}
+button.scary {
+ background-color: #F12A2A;
+}
+
.joyride-content-wrapper .button {
background-color: #008CBA;
}
};
});
+ $('#delete-note-button').click(function (event) {
+ if (!confirm("Are you sure you want to delete this note?")) {
+ event.preventDefault();
+ }
+ });
+
// Embed the converted markdown if it is on the page, else default to the iframe
if ($('#note-markdown').length > 0) {
var note_markdown = $('#note-markdown');
var annotator_js_url = "{{ STATIC_URL }}js/annotator-full.min.js";
var annotator_css_url = "{{ STATIC_URL }}css/annotator.min.css";
var setup_ajax_url = "{{ STATIC_URL }}js/setup-ajax.js";
- var empty_js = "{{ STATIC_URL }}js/empty.js";
+ var note_edit_url = "{% url 'edit_note' note.id %}";
</script>
{% compress js %}
<script src="{{ STATIC_URL }}js/setup-ajax.js"></script>
<i class="fa fa-download"></i> Download Note</button>
{% endif %}
- {% if user.get_profile.can_edit_items %}
+ {% if user.get_profile.can_edit_items and note.user != user %}
<button id="edit-note-tags" class="modify-button" data-reveal-id="note-tag-dialog">
<i class="fa fa-pencil-square-o"></i> Edit Tags
</button>
{% endif %}
+
+ {% if note.user == request.user %}
+ <button id="edit-button" data-reveal-id="note-edit-dialog" class="modify-button"> <i class="fa fa-edit"></i> Edit This Note</button>
+ {% endif %}
+
+ {% if note.license %}
+ {{ note.license.html|safe }} {% if note.upstream_link %}<a href="{{ note.upstream_link }}" target="_blank">{{ note.upstream_link|slice:":80" }}</a>{% endif %}
+ {% endif %}
</span>
</span>
</div>
<strong>Tags: </strong>
<span class="tags">
{% for tag in note.tags.all %}
- <span class="tag-span">{{ tag.name }}</span>
+ <span class="tag-span">
+ {{ tag.name }}{% if not forloop.last %}, {% endif %}
+ </span>
{% endfor %}
</span>
</div><!-- /note_tags -->
<a class="close-reveal-modal">×</a>
<div class="row">
<div class="small-12 columns">
- <p>Edit this note's tags:
- <input id="note_tags_input" type="text" value="{% for tag in note.tags.all %}{{ tag.name }}{% if not forloop.last %}, {% endif %}{% endfor %}"></p>
+ <h3>Edit this note's tags</h3>
+ <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="submit" value="tags-form"><i class="fa fa-save"></i> Save</button>
</div>
</div>
</div>
- {% if note.license %}
+ <div id="note-edit-dialog" class="reveal-modal" data-reveal>
+ <a class="close-reveal-modal">×</a>
<div class="row">
- <div id="note_pedigree" class="twelve columns activity_details_status">
- {{ note.license.html|safe }} {% if note.upstream_link %}<a href="{{ note.upstream_link }}" target="_blank">{{ note.upstream_link|slice:":80" }}</a>{% endif %}
- </div><!-- /note_pedigree -->
+ <div class="small-8 columns">
+ <h3>Edit Your Note</h3>
+ </div>
+ <div class="small-4 columns text-right">
+ <form method="POST" action="{% url 'note_delete' %}">
+ {% csrf_token %}
+ {{ note_delete_form }}
+ <button id="delete-note-button" type="submit" class="scary"><i class="fa fa-trash-o"></i> Delete Note</button>
+ </form>
+ </div>
</div>
- {% endif %}
+ <div class="row">
+ <form method="POST" action="{{ note.get_absolute_url }}">
+ {% csrf_token %}
+ <div class="small-12 large-6 columns">
+ {% with note_edit_form.name as field %}
+ {{ field.errors|safe }}
+ <label for="{{ field.id_for_label }}">{{ field.label }}:</label>
+ {{ field }}
+ <p>{{ field.help_text }}</p>
+ {% endwith %}
+ </div>
+ <div class="small-12 large-6 columns">
+ {% with note_edit_form.tags as field %}
+ {{ field.errors|safe }}
+ <label for="{{ field.id_for_label }}">{{ field.label }}:</label>
+ {{ field }}
+ <p>{{ field.help_text }}</p>
+ {% endwith %}
+ </div>
+ <div class="small-12 columns text-center">
+ <button type="submit"><i class="fa fa-save"></i> Save</button>
+ </div>
+ </form>
+ </div>
+ </div>
</div><!-- /note header -->
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, edit_note_tags, \
- NoteKeywordsView
+ NoteKeywordsView, edit_note, NoteDeleteView
from karmaworld.apps.moderation import moderator
from karmaworld.apps.document_upload.views import save_fp_upload
from karmaworld.apps.quizzes.views import QuizView, KeywordEditView, quiz_answer, get_keywords_annotator, \
url(r'^ajax/course/flag/(?P<pk>[\d]+)/$', flag_course, name='flag_course'),
# Ajax endpoint to edit a course
url(r'^ajax/course/edit/(?P<pk>[\d]+)/$', edit_course, name='edit_course'),
+ url(r'^ajax/note/edit/(?P<pk>[\d]+)/$', edit_note, name='edit_note'),
# Check if a quiz answer is correct
url(r'^ajax/quiz/check/$', quiz_answer, name='quiz_answer'),
url(r'^note/' + SLUG.format('school_') + '/' + SLUG.format('course_') +'/'+ SLUG.format('') +'/keywords/$',
NoteKeywordsView.as_view(), name='note_keywords'),
+ url(r'note/delete/$', NoteDeleteView.as_view(), name='note_delete'),
+
# Quizzes
url(r'^quiz/(?P<pk>[\d]+)/$',
QuizView.as_view(), name='quiz'),