""" Views for viewing, adding, updating and deleting course updates. Current db representation: { "_id" : locationjson, "definition" : { "data" : "<ol>[<li><h2>date</h2>content</li>]</ol>"}, "items" : [{"id": ID, "date": DATE, "content": CONTENT}] "metadata" : ignored } } """ import logging import re from django.http import HttpResponseBadRequest from django.utils.translation import ugettext as _ from cms.djangoapps.contentstore.push_notification import enqueue_push_course_update from openedx.core.lib.xblock_utils import get_course_update_items from xmodule.html_module import CourseInfoModule from xmodule.modulestore.django import modulestore from xmodule.modulestore.exceptions import ItemNotFoundError # # This should be in a class which inherits from XmlDescriptor log = logging.getLogger(__name__) def get_course_updates(location, provided_id, user_id): """ Retrieve the relevant course_info updates and unpack into the model which the client expects: [{id : index, date : string, content : html string}] """ try: course_updates = modulestore().get_item(location) except ItemNotFoundError: course_updates = modulestore().create_item(user_id, location.course_key, location.block_type, location.block_id) course_update_items = get_course_update_items(course_updates, _get_index(provided_id)) return _get_visible_update(course_update_items) def update_course_updates(location, update, passed_id=None, user=None): """ Either add or update the given course update. Add: If the passed_id is absent or None, the course update is added. If push_notification_selected is set in the update, a celery task for the push notification is created. Update: It will update it if it has a passed_id which has a valid value. Until updates have distinct values, the passed_id is the location url + an index into the html structure. """ try: course_updates = modulestore().get_item(location) except ItemNotFoundError: course_updates = modulestore().create_item(user.id, location.course_key, location.block_type, location.block_id) course_update_items = list(reversed(get_course_update_items(course_updates))) if passed_id is not None: passed_index = _get_index(passed_id) # oldest update at start of list if 0 < passed_index <= len(course_update_items): course_update_dict = course_update_items[passed_index - 1] course_update_dict["date"] = update["date"] course_update_dict["content"] = update["content"] course_update_items[passed_index - 1] = course_update_dict else: return HttpResponseBadRequest(_("Invalid course update id.")) else: course_update_dict = { "id": len(course_update_items) + 1, "date": update["date"], "content": update["content"], "status": CourseInfoModule.STATUS_VISIBLE } course_update_items.append(course_update_dict) enqueue_push_course_update(update, location.course_key) # update db record save_course_update_items(location, course_updates, course_update_items, user) # remove status key if "status" in course_update_dict: del course_update_dict["status"] return course_update_dict def _make_update_dict(update): """ Return course update item as a dictionary with required keys ('id', "date" and "content"). """ return { "id": update["id"], "date": update["date"], "content": update["content"], } def _get_visible_update(course_update_items): """ Filter course update items which have status "deleted". """ if isinstance(course_update_items, dict): # single course update item if course_update_items.get("status") != CourseInfoModule.STATUS_DELETED: return _make_update_dict(course_update_items) else: # requested course update item has been deleted (soft delete) return {"error": _("Course update not found."), "status": 404} return ([_make_update_dict(update) for update in course_update_items if update.get("status") != CourseInfoModule.STATUS_DELETED]) # pylint: disable=unused-argument def delete_course_update(location, update, passed_id, user): """ Don't delete course update item from db. Delete the given course_info update by settings "status" flag to 'deleted'. Returns the resulting course_updates. """ if not passed_id: return HttpResponseBadRequest() try: course_updates = modulestore().get_item(location) except ItemNotFoundError: return HttpResponseBadRequest() course_update_items = list(reversed(get_course_update_items(course_updates))) passed_index = _get_index(passed_id) # delete update item from given index if 0 < passed_index <= len(course_update_items): course_update_item = course_update_items[passed_index - 1] # soft delete course update item course_update_item["status"] = CourseInfoModule.STATUS_DELETED course_update_items[passed_index - 1] = course_update_item # update db record save_course_update_items(location, course_updates, course_update_items, user) return _get_visible_update(course_update_items) else: return HttpResponseBadRequest(_("Invalid course update id.")) def _get_index(passed_id=None): """ From the url w/ index appended, get the index. """ if passed_id: index_matcher = re.search(r'.*?/?(\d+)$', passed_id) if index_matcher: return int(index_matcher.group(1)) # return 0 if no index found return 0 def save_course_update_items(location, course_updates, course_update_items, user=None): """ Save list of course_updates data dictionaries in new field ("course_updates.items") and html related to course update in 'data' ("course_updates.data") field. """ course_updates.items = course_update_items course_updates.data = "" # update db record modulestore().update_item(course_updates, user.id) return course_updates