def upload_attachment(request, bookid, version=None): try: book = models.Book.objects.get(url_title__iexact=bookid) except models.Book.DoesNotExist: return views.ErrorPage( request, "errors/book_does_not_exist.html", {"book_name": bookid}) user = request.user book_security = security.get_security_for_book(user, book) can_upload_attachment = book_security.has_perm('edit.upload_attachment') if (not user.is_superuser and not can_upload_attachment and book.owner != user): raise PermissionDenied book_version = book.get_version(version) stat = models.BookStatus.objects.filter(book=book)[0] with transaction.atomic(): file_data = request.FILES['files[]'] att = models.Attachment( version=book_version, # must remove this reference created=datetime.datetime.now(), book=book, status=stat ) att.save() attName, attExt = os.path.splitext(file_data.name) att.attachment.save( '{}{}'.format(booktype_slugify(attName), attExt), file_data, save=False ) att.save() response_data = { "files": [{ "url": "http://127.0.0.1/", "thumbnail_url": "http://127.0.0.1/", "name": "boot.png", "type": "image/png", "size": 172728, "delete_url": "", "delete_type": "DELETE" }] } # add cliendID and sputnikID to request object # this will allow us to use sputnik and addMessageToChannel request.clientID = request.POST['clientID'] request.sputnikID = "%s:%s" % (request.session.session_key, request.clientID) send_notification(request, book.id, book_version.get_version(), "notification_new_attachment_uploaded", att.get_name()) if "application/json" in request.META['HTTP_ACCEPT']: return HttpResponse(json.dumps(response_data), content_type="application/json") else: return HttpResponse(json.dumps(response_data), content_type="text/html")
def test_has_perm(self): # security for common user sec = security.get_security_for_book(self.user, self.bookrole.book) # common user, should have rights from book self.assertTrue(sec.has_perm('%s.%s' % (APP_NAME, CODE_NAME)), "If user doesn't have that role, this should be False")
def has_perm(cls, book=None, request=None): if cls.required_permission: book_security = security.get_security_for_book(request.user, book) return book_security.has_perm(cls.required_permission) # if there no required permission, then True return True
def test_user_security_is_bookowner(self): # let's create a book and set it to the role # so we can scope permissions just for that book book = factory_models.BookFactory(owner=self.user) sec = security.get_security_for_book(self.user, book) self.assertTrue(sec.is_book_owner())
def test_user_security_is_not_bookowner(self): # let's create a book and set it to the role # so we can scope permissions just for that book book = factory_models.BookFactory(owner=self.superuser) sec = security.get_security_for_book(self.user, book) self.assertFalse(sec.is_book_owner())
def test_has_perm(self): # security for common user sec = security.get_security_for_book(self.user, self.bookrole.book) # common user, should have rights from book self.assertTrue( sec.has_perm('%s.%s' % (APP_NAME, CODE_NAME)), "If user doesn't have that role, this should be False")
def render_to_response(self, context, **response_kwargs): book = self.object book_security = security.get_security_for_book(self.request.user, book) book_permissions = security.get_user_permissions(self.request.user, book) return self.render_json_response({ 'admin': book_security.is_admin(), 'permissions': book_permissions, })
def has_object_permission(self, request, view, obj): """Takes the list of required permissions from the view and check if user has them all""" required_perms = self.get_required_perms(view) if not required_perms: return True book_security = security.get_security_for_book(request.user, obj) perms_list = [book_security.has_perm(x) for x in required_perms] return all(perms_list)
def test_user_security_is_admin(self): # let's create a book and set it to the role # so we can scope permissions just for that book book = factory_models.BookFactory() self.bookrole.book = book # also put user as member of that role self.bookrole.members.add(self.superuser) self.bookrole.save() sec = security.get_security_for_book(self.superuser, book) self.assertTrue(sec.is_admin())
def post(self, *args, **kwargs): request = self.request book = self.object = self.get_object() title = request.POST.get("title", "") book_security = security.get_security_for_book(request.user, book) book_permissions = security.get_user_permissions(request.user, book) self.template_name = "reader/book_delete_error.html" if (book_security.has_perm('edit.delete_book') and title.strip() == book.title.strip()): remove_book(book) self.template_name = "reader/book_delete_redirect.html" messages.success(request, _('Book successfully deleted.')) return self.render_to_response(context=self.get_context_data())
def post(self, request, *args, **kwargs): book = self.get_object() self.object = book self.get_context_data(**kwargs) book_security = security.get_security_for_book(request.user, book) if not book_security.has_perm('edit.history_revert'): raise PermissionDenied revision = get_object_or_404( models.ChapterHistory, revision=request.POST["revert"], chapter=self.chapter, chapter__version=book.version.id ) history = logChapterHistory( chapter=self.chapter, content=revision.content, user=request.user, comment=_("Reverted to revision %s.") % revision.revision, revision=self.chapter.revision + 1 ) if history: logBookHistory( book=book, version=book.version.id, chapter=self.chapter, chapter_history=history, user=request.user, args={}, kind='chapter_save' ) self.chapter.revision += 1 self.chapter.content = revision.content try: self.chapter.save() messages.success(request, _('Chapter revision successfully reverted.')) except: messages.warning(request, _('Chapter revision could not be reverted.')) url = "{0}#history/{1}".format( reverse('edit:editor', args=[book.url_title]), self.chapter.url_title ) return HttpResponseRedirect(url)
def get_context_data(self, **kwargs): book = self.object content = None book_version = book.get_version(self.kwargs.get('version', None)) context = super(DraftChapterView, self).get_context_data(**kwargs) # check permissions book_security = security.get_security_for_book(self.request.user, book) can_edit = book_security.can_edit() can_view_draft = book_security.has_perm('reader.can_view_draft') if (book.hidden and not can_edit) or not can_view_draft: context['has_permission'] = False return context if 'chapter' in self.kwargs: try: content = get_object_or_404(Chapter, version=book_version, url_title=self.kwargs['chapter']) except Http404: self.not_found = True context = dict( not_found_object=_("Chapter"), object_name=self.kwargs['chapter'] ) return context toc_items = BookToc.objects.filter( version=book_version).order_by("-weight") for chapter in toc_items: if not content and chapter.is_chapter(): content = chapter.chapter break context['content'] = content context['toc_items'] = toc_items context['book_version'] = book_version.get_version() context['can_edit'] = ( self.request.user.is_authenticated() and book.version == book_version ) return context
def remote_message_send(request, message, bookid): """ Called when user is sending message to chat channel L{bookid}. @type request: C{django.http.HttpRequest} @param request: Client Request object @type message: C{dict} @param message: Message object @type bookid: C{string} @param bookid: Unique Book id """ try: book = Book.objects.get(id=int(bookid)) except Book.DoesNotExist: raise ObjectDoesNotExist except Book.MultipleObjectsReturned: raise ObjectDoesNotExist book_security = security.get_security_for_book(request.user, book) has_permission = book_security.can_edit() if not has_permission: raise PermissionDenied # get chat thread chat_thread, _ = ChatThread.objects.get_or_create(book=book) # create message chat_message = ChatMessage() chat_message.thread = chat_thread chat_message.sender = request.user chat_message.text = message["message"] chat_message.save() sputnik.addMessageToChannel( request, "/chat/%s/" % bookid, { "command": "message_received", "email": request.user.email, "from": request.user.username, "important": message["important"], "message": message["message"] }) return {}
def get_context_data(self, **kwargs): book = self.object context = super(FullView, self).get_context_data(**kwargs) has_permission = security.get_security_for_book(self.request.user, book).has_perm( 'reader.can_view_full_page') if not has_permission: context['has_permission'] = has_permission return context book_version = book.get_version(self.kwargs.get('version', None)) toc_items = BookToc.objects.filter( version=book_version).order_by("-weight") context['book_version'] = book_version.get_version() context['toc_items'] = toc_items return context
def get_context_data(self, **kwargs): book = self.object context = super(FullView, self).get_context_data(**kwargs) has_permission = security.get_security_for_book( self.request.user, book).has_perm('reader.can_view_full_page') if not has_permission: context['has_permission'] = has_permission return context book_version = book.get_version(self.kwargs.get('version', None)) toc_items = BookToc.objects.filter( version=book_version).order_by("-weight") context['book_version'] = book_version.get_version() context['toc_items'] = toc_items return context
def get_context_data(self, **kwargs): book = self.object content = None book_version = book.get_version(self.kwargs.get('version', None)) context = super(DraftChapterView, self).get_context_data(**kwargs) # check permissions book_security = security.get_security_for_book(self.request.user, book) can_edit = book_security.can_edit() can_view_draft = book_security.has_perm('reader.can_view_draft') if (book.hidden and not can_edit) or not can_view_draft: context['has_permission'] = False return context if 'chapter' in self.kwargs: try: content = get_object_or_404(Chapter, version=book_version, url_title=self.kwargs['chapter']) except Http404: self.not_found = True context = dict(not_found_object=_("Chapter"), object_name=self.kwargs['chapter']) return context toc_items = BookToc.objects.filter( version=book_version).order_by("-weight") for chapter in toc_items: if not content and chapter.is_chapter(): content = chapter.chapter break context['content'] = content context['toc_items'] = toc_items context['book_version'] = book_version.get_version() context['can_edit'] = (self.request.user.is_authenticated() and book.version == book_version) return context
def remote_message_send(request, message, bookid): """ Called when user is sending message to chat channel L{bookid}. @type request: C{django.http.HttpRequest} @param request: Client Request object @type message: C{dict} @param message: Message object @type bookid: C{string} @param bookid: Unique Book id """ try: book = Book.objects.get(id=int(bookid)) except Book.DoesNotExist: raise ObjectDoesNotExist except Book.MultipleObjectsReturned: raise ObjectDoesNotExist book_security = security.get_security_for_book(request.user, book) has_permission = book_security.can_edit() if not has_permission: raise PermissionDenied # get chat thread chat_thread, _ = ChatThread.objects.get_or_create(book=book) # create message chat_message = ChatMessage() chat_message.thread = chat_thread chat_message.sender = request.user chat_message.text = message["message"] chat_message.save() sputnik.addMessageToChannel(request, "/chat/%s/" % bookid, {"command": "message_received", "email": request.user.email, "from": request.user.username, "important": message["important"], "message": message["message"]}) return {}
def dispatch(self, request, *args, **kwargs): # try to create security instance try: if self.security_bridge is Security: self.security = get_security(request.user) elif self.security_bridge is BookSecurity: book = Book.objects.get(url_title__iexact=kwargs['bookid']) self.security = get_security_for_book(request.user, book) elif self.security_bridge is GroupSecurity: group = BookiGroup.objects.get(url_name=kwargs['groupid']) self.security = get_security_for_group(request.user, group) except (BookiGroup.DoesNotExist, Book.DoesNotExist): raise Http404 except KeyError as e: raise Exception('{bridge} bridge requires "{key}" in request'.format(bridge=self.security_bridge, key=e.message)) # hook for checking permissions self.check_permissions(request, *args, **kwargs) return super(SecurityMixin, self).dispatch(request, *args, **kwargs)
def test_get_security_for_book(self): # let's test helper for retrieving BookSecurity instance self.assertEqual( security.BookSecurity(self.user, self.bookrole.book).__class__, security.get_security_for_book(self.user, self.bookrole.book).__class__)
def test_get_security_for_book(self): # let's test helper for retrieving BookSecurity instance self.assertEqual(security.BookSecurity(self.user, self.bookrole.book).__class__, security.get_security_for_book(self.user, self.bookrole.book).__class__)
def upload_cover(request, bookid, version=None): try: book = models.Book.objects.get(url_title__iexact=bookid) except models.Book.DoesNotExist: return views.ErrorPage(request, "errors/book_does_not_exist.html", {"book_name": bookid}) can_upload_cover = security.get_security_for_book(request.user, book).has_perm('edit.upload_cover') if (not request.user.is_superuser and not can_upload_cover and book.owner != request.user): raise PermissionDenied with transaction.atomic(): file_data = request.FILES['files[]'] title = request.POST.get('title', '') try: filename = unidecode.unidecode(file_data.name) except: filename = uuid.uuid1().hex h = hashlib.sha1() h.update(filename) h.update(title) h.update(str(datetime.datetime.now())) license = models.License.objects.get( abbrevation=request.POST.get('license', '')) cover = models.BookCover( book=book, user=request.user, cid=h.hexdigest(), title=title, filename=filename[:250], width=0, height=0, unit=request.POST.get('unit', 'mm'), booksize=request.POST.get('booksize', ''), cover_type=request.POST.get('type', ''), creator=request.POST.get('creator', '')[:40], license=license, notes=request.POST.get('notes', '')[:500], approved=False, is_book=False, is_ebook=True, is_pdf=False, created=datetime.datetime.now() ) cover.save() # now save the attachment cover.attachment.save(filename, file_data, save=False) cover.save() response_data = { "files": [{ "url": "http://127.0.0.1/", "thumbnail_url": "http://127.0.0.1/", "name": "boot.png", "type": "image/png", "size": 172728, "delete_url": "", "delete_type": "DELETE" }] } # add cliendID and sputnikID to request object # this will allow us to use sputnik and addMessageToChannel request.clientID = request.POST['clientID'] request.sputnikID = "%s:%s" % (request.session.session_key, request.clientID) send_notification(request, book.id, book.get_version(version).get_version(), "notification_new_cover_uploaded", cover.title) if "application/json" in request.META['HTTP_ACCEPT']: return HttpResponse(json.dumps(response_data), content_type="application/json") else: return HttpResponse(json.dumps(response_data), content_type="text/html")