def _save_history_records(self, book, chapter, kind='chapter_create'): """ Save history records for chapter and book. It saves a revision of the chapter :Args: - book: `booki.edit.models.Book` Django model instance - chapter: `booki.edit.models.Chapter` Django model instance - kind: `str` the chapter history type. See booki.editor.models.HISTORY_CHOICES """ rev = chapter.revision if kind != 'chapter_create': rev = chapter.revision + 1 # time to save revisions correctly history = logChapterHistory(chapter=chapter, content=chapter.content, user=book.owner, comment='', revision=rev) if history: logBookHistory(book=book, version=book.version, chapter=chapter, chapter_history=history, user=book.owner, kind=kind)
def test_log_book_history(self): history = logBookHistory( book=self.book, version=self.book_version, chapter=self.chapter, user=self.user ) # check returned object self.assertTrue( isinstance(history, BookHistory), "Returned object should be instance of BookHistory" ) # checl some values also self.assertEqual(history.book, self.book) self.assertEqual(history.chapter, self.chapter) # test with some bad values none_history = logBookHistory( book=self.book, version=self.book_version, chapter=self.chapter, user='' ) # check returned values for bad params self.assertEqual( none_history, None, "It should return None in case of bad parameters" )
def remote_chapters_changed(request, message, bookid, version): lst = [chap[5:] for chap in message["chapters"]] lstHold = [chap[5:] for chap in message["hold"]] book = models.Book.objects.get(id=bookid) book_version = getVersion(book, version) weight = len(lst) logBookHistory(book = book, version = book_version, user = request.user, kind = "chapter_reorder") for chap in lst: if chap[0] == 's': m = models.BookToc.objects.get(id__exact=int(chap[1:])) m.weight = weight m.save() else: try: m = models.BookToc.objects.get(chapter__id__exact=int(chap)) m.weight = weight m.save() except: chptr = models.Chapter.objects.get(id__exact=int(chap)) m = models.BookToc(book = book, version = book_version, name = "SOMETHING", chapter = chptr, weight = weight, typeof=1) m.save() weight -= 1 if message["kind"] == "remove": if type(message["chapter_id"]) == type(u' ') and message["chapter_id"][0] == 's': m = models.BookToc.objects.get(id__exact=message["chapter_id"][1:]) m.delete() else: m = models.BookToc.objects.get(chapter__id__exact=int(message["chapter_id"])) m.delete() # addMessageToChannel(request, "/chat/%s/%s/" % (projectid, bookid), {"command": "message_info", "from": request.user.username, "message": 'User %s has rearranged chapters.' % request.user.username}) sputnik.addMessageToChannel(request, "/booki/book/%s/%s/" % (bookid, version), {"command": "chapters_changed", "ids": lst, "hold_ids": lstHold, "kind": message["kind"], "chapter_id": message["chapter_id"]}) # TODO # this should be changed, to check for errors transaction.commit() return {}
def remote_chapter_save(request, message, bookid, version): # TODO # put this outside in common module # or maybe even betterm put it in the Model book = models.Book.objects.get(id=bookid) book_version = getVersion(book, version) chapter = models.Chapter.objects.get(id=int(message["chapterID"])) if message.get("minor", False) != True: history = logChapterHistory(chapter = chapter, content = message["content"], user = request.user, comment = message.get("comment", ""), revision = chapter.revision+1) logBookHistory(book = chapter.book, version = book_version, chapter = chapter, chapter_history = history, user = request.user, args = {"comment": message.get("comment", ""), "author": message.get("author", ""), "authorcomment": message.get("authorcomment", "")}, kind = 'chapter_save') chapter.revision += 1 chapter.content = message["content"]; try: chapter.save() sputnik.addMessageToChannel(request, "/chat/%s/" % bookid, {"command": "message_info", "from": request.user.username, "message": 'User %s has saved chapter "%s".' % (request.user.username, chapter.title)}, myself=True) except: transaction.rollback() else: transaction.commit() if not message['continue']: sputnik.addMessageToChannel(request, "/booki/book/%s/%s/" % (bookid, version), {"command": "chapter_status", "chapterID": message["chapterID"], "status": "normal", "username": request.user.username}) sputnik.rdelete("booki:%s:locks:%s:%s" % (bookid, message["chapterID"], request.user.username)) # fire the signal import booki.editor.signals booki.editor.signals.chapter_modified.send(sender = book_version, chapter = chapter, user = request.user) return {}
def upload_attachment(request, bookid, version=None): """ Uploades attachments. Used from Upload dialog. @param request: Django Request @param bookid: Book ID @param version: Book version or None """ try: book = models.Book.objects.get(url_title__iexact=bookid) except models.Book.DoesNotExist: return pages.ErrorPage(request, "errors/book_does_not_exist.html", {"book_name": bookid}) book_version = getVersion(book, version) stat = models.BookStatus.objects.filter(book = book)[0] # check this for transactions for name, fileData in request.FILES.items(): from booki.utils import log log.logBookHistory(book = book, version = book_version, args = {'filename': request.FILES[name].name}, user = request.user, kind = 'attachment_upload') att = models.Attachment(version = book_version, # must remove this reference book = book, status = stat) att.save() att.attachment.save(request.FILES[name].name, fileData, save = False) att.save() # TODO: # must write info about this to log! # maybe check file name now and save with new name transaction.commit() if request.POST.get("attachmenttab", "") == "": return HttpResponse('<html><body><script> parent.closeAttachmentUpload(); </script></body></html>') if request.POST.get("attachmenttab", "") == "2": return HttpResponse('<html><body><script> parent.FileBrowserDialogue.loadAttachments(); parent.FileBrowserDialogue.showUpload(); parent.mcTabs.displayTab("browse_tab","browse_panel");</script></body></html>') # should not call showAttachmentsTab, but it works for now return HttpResponse('<html><body><script> parent.jQuery.booki.editor.showAttachmentsTab(); parent.jQuery("#tabattachments FORM")[0].reset(); </script></body></html>')
def upload_attachment(request, bookid, version=None): """ Uploades attachments. Used from Upload dialog. @param request: Django Request @param bookid: Book ID @param version: Book version or None """ try: book = models.Book.objects.get(url_title__iexact=bookid) except models.Book.DoesNotExist: return pages.ErrorPage(request, "errors/book_does_not_exist.html", {"book_name": bookid}) book_version = getVersion(book, version) stat = models.BookStatus.objects.filter(book = book)[0] # check this for transactions for name, fileData in request.FILES.items(): from booki.utils import log log.logBookHistory(book = book, version = book_version, args = {'filename': request.FILES[name].name}, user = request.user, kind = 'attachment_upload') att = models.Attachment(version = book_version, # must remove this reference book = book, status = stat) att.save() att.attachment.save(request.FILES[name].name, fileData, save = False) att.save() # TODO: # must write info about this to log! # maybe check file name now and save with new name transaction.commit() if request.POST.get("attachmenttab", "") == "": return HttpResponse('<html><body><script> parent.closeAttachmentUpload(); </script></body></html>') # should not call showAttachmentsTab, but it works for now return HttpResponse('<html><body><script> parent.jQuery.booki.editor.showAttachmentsTab(); parent.jQuery("#tabattachments FORM")[0].reset(); </script></body></html>')
def createBook(user, bookTitle, status = "imported", bookURL = None): """ Create book and sets status. TODO: status? """ if bookURL: url_title = bookURL else: url_title = slugify(bookTitle) book = models.Book(url_title = url_title, title = bookTitle, owner = user, published = datetime.datetime.now()) book.save() # put this in settings file status_default = ["published", "not published", "imported"] n = len(status_default) for statusName in status_default: status = models.BookStatus(book=book, name=statusName, weight=n) status.save() n -= 1 book.status = models.BookStatus.objects.get(book=book, name="not published") book.save() version = models.BookVersion(book = book, major = 1, minor = 0, name = 'initial', description = '') version.save() book.version = version book.save() logBookHistory(book = book, version = version, user = user, kind = 'book_create') import booki.editor.signals booki.editor.signals.book_created.send(sender = user, book = book) return book
def remote_create_section(request, message, bookid, version): import datetime book = models.Book.objects.get(id=bookid) book_version = getVersion(book, version) ch = models.BookToc.objects.filter(book=book, version=book_version, name=message['chapter'], typeof=0) if len(list(ch)) > 0: return {"created": False} c = models.BookToc(book = book, version = book_version, name = message["chapter"], chapter = None, weight = 0, typeof=0) result = True try: c.save() except: result = False transaction.rollback() else: logBookHistory(book = book, version = book_version, user = request.user, args = {"title": message["chapter"]}, kind = 'section_create') transaction.commit() result = ("s%s" % c.id, c.name, None, c.typeof) sputnik.addMessageToChannel(request, "/chat/%s/" % bookid, {"command": "message_info", "from": request.user.username, "message": 'User %s has created new section "%s".' % (request.user.username, message["chapter"])}, myself=True) sputnik.addMessageToChannel(request, "/booki/book/%s/%s/" % (bookid, version), {"command": "chapter_create", "chapter": result, "typeof": c.typeof}, myself = True) return {"created": result}
def upload_attachment(request, bookid, version=None): """ Uploades attachments. Used from Upload dialog. @param request: Django Request @param bookid: Book ID @param version: Book version or None """ try: book = models.Book.objects.get(url_title__iexact=bookid) except models.Book.DoesNotExist: return pages.ErrorPage(request, "errors/book_does_not_exist.html", {"book_name": bookid}) book_version = getVersion(book, version) stat = models.BookStatus.objects.filter(book = book)[0] # check this for transactions for name, fileData in request.FILES.items(): from booki.utils import log log.logBookHistory(book = book, version = book_version, args = {'filename': request.FILES[name].name}, user = request.user, kind = 'attachment_upload') att = models.Attachment(version = book_version, # must remove this reference book = book, status = stat) att.save() att.attachment.save(request.FILES[name].name, fileData, save = False) att.save() # TODO: # must write info about this to log! # maybe check file name now and save with new name transaction.commit() return HttpResponse('<html><body><script> parent.closeAttachmentUpload(); </script></body></html>')
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 delete(self, request, *args, **kwargs): book_security = BookSecurity(request.user, self._get_book()) if book_security.has_perm('api.delete_chapters'): self._chapter = self.get_object() respone = super(ChapterRetrieveUpdateDestroy, self).delete(request, *args, **kwargs) if respone.status_code is status.HTTP_204_NO_CONTENT: self._delete_notifications() logBookHistory(book=self._book, version=self._book.version, args={'chapter': self._chapter.title}, user=self.request.user, kind='chapter_delete') return respone raise PermissionDenied
def remote_revert_revision(request, message, bookid, version): from booki.editor.views import getVersion book = models.Book.objects.get(id=bookid) book_ver = getVersion(book, version) chapter = models.Chapter.objects.get(version=book_ver, url_title=message["chapter"]) revision = models.ChapterHistory.objects.get(revision=message["revision"], chapter__url_title=message["chapter"], chapter__version=book_ver.id) # TODO # does chapter history really needs to keep content or it can only keep reference to chapter history = logChapterHistory(chapter = chapter, content = revision.content, user = request.user, comment = "Reverted to revision %s." % message["revision"], revision = chapter.revision+1) logBookHistory(book = book, version = book_ver, chapter = chapter, chapter_history = history, user = request.user, args = {}, kind = 'chapter_save') chapter.revision += 1 chapter.content = revision.content; try: chapter.save() except: transaction.rollback() else: transaction.commit() sputnik.addMessageToChannel(request, "/chat/%s/" % bookid, {"command": "message_info", "from": request.user.username, "message": 'User %s has reverted chapter "%s" to revision %s.' % (request.user.username, chapter.title, message["revision"])}, myself=True) return {}
def remote_create_major_version(request, message, bookid, version): from booki.editor.views import getVersion book = models.Book.objects.get(id=bookid) book_ver = getVersion(book, version) try: new_version = create_new_version(book, book_ver, message, book_ver.major+1, 0) except: transaction.rollback() else: logBookHistory(book = book, version = new_version, chapter = None, chapter_history = None, user = request.user, args = {"version": new_version.getVersion()}, kind = 'major_version') transaction.commit() return {"version": new_version.getVersion()}
def remote_chapter_rename(request, message, bookid, version): book = models.Book.objects.get(id=bookid) book_version = getVersion(book, version) chapter = models.Chapter.objects.get(id=int(message["chapterID"])) oldTitle = chapter.title chapter.title = message["chapter"]; try: chapter.save() except: transaction.rollback() else: logBookHistory(book = chapter.book, version = book_version, chapter = chapter, user = request.user, args = {"old": oldTitle, "new": message["chapter"]}, kind = "chapter_rename") sputnik.addMessageToChannel(request, "/chat/%s/" % bookid, {"command": "message_info", "from": request.user.username, "message": 'User %s has renamed chapter "%s" to "%s".' % (request.user.username, oldTitle, message["chapter"])}, myself=True) sputnik.addMessageToChannel(request, "/booki/book/%s/%s/" % (bookid, version), {"command": "chapter_status", "chapterID": message["chapterID"], "status": "normal", "username": request.user.username}) sputnik.addMessageToChannel(request, "/booki/book/%s/%s/" % (bookid, version), {"command": "chapter_rename", "chapterID": message["chapterID"], "chapter": message["chapter"]}) transaction.commit() return {}
def test_log_book_history(self): history = logBookHistory(book=self.book, version=self.book_version, chapter=self.chapter, user=self.user) # check returned object self.assertTrue(isinstance(history, BookHistory), "Returned object should be instance of BookHistory") # checl some values also self.assertEqual(history.book, self.book) self.assertEqual(history.chapter, self.chapter) # test with some bad values none_history = logBookHistory(book=self.book, version=self.book_version, chapter=self.chapter, user='') # check returned values for bad params self.assertEqual(none_history, None, "It should return None in case of bad parameters")
def _import_chapters(self, book, chapters): now = datetime.datetime.now() stat = models.BookStatus.objects.filter(book=book, name="new")[0] n = 100 for chapter_title, chapter_content in chapters: if len(chapter_title) > 100: chapter_title = u'{}...'.format(chapter_title[:100]) if chapter_title == '': if n == 100: chapter_title = _('Title Page') else: chapter_title = _('Title') chapter_n = 0 possible_title = chapter_title while True: does_exists = models.Chapter.objects.filter( book=book, version=book.version, url_title=booktype_slugify(possible_title) ).exists() if does_exists: chapter_n += 1 possible_title = u'{} - {}'.format( chapter_title, chapter_n) else: break if chapter_content[6:-8].strip() == '': continue chapter_content = unidecode(self._parse_chapter(chapter_content)) chapter = models.Chapter( book=book, version=book.version, url_title=booktype_slugify(possible_title), title=possible_title, status=stat, content=chapter_content[6:-8], created=now, modified=now ) chapter.save() toc_item = models.BookToc( book=book, version=book.version, name=chapter.title, chapter=chapter, weight=n, typeof=1 ) toc_item.save() n -= 1 # time to save revisions correctly history = logChapterHistory( chapter=chapter, content=chapter.content, user=book.owner, comment='', revision=chapter.revision ) if history: logBookHistory( book=book, version=book.version, chapter=chapter, chapter_history=history, user=book.owner, kind='chapter_create' )
def remote_chapter_split(request, message, bookid, version): book = models.Book.objects.get(id=bookid) book_version = getVersion(book, version) logBookHistory(book = book, version = book_version, user = request.user, kind = 'chapter_split') allChapters = [] try: originalChapter = models.Chapter.objects.get(id=int(message["chapterID"])) except: originalChapter = None try: tocChapter = models.BookToc.objects.get(book=book, chapter__id__exact=message["chapterID"]) except: tocChapter = None import datetime from django.template.defaultfilters import slugify if tocChapter: allChapters = [chap for chap in models.BookToc.objects.filter(book=book).order_by("-weight")] initialPosition = len(allChapters)-tocChapter.weight else: initialPosition = 0 s = models.BookStatus.objects.filter(book=book).order_by("weight")[0] n = 0 for chap in message["chapters"]: chapter = models.Chapter(book = book, url_title = slugify(chap[0]), title = chap[0], status = s, content = '<h1>%s</h1>%s' % (chap[0], chap[1]), created = datetime.datetime.now(), modified = datetime.datetime.now()) chapter.save() if tocChapter: m = models.BookToc(book = book, chapter = chapter, name = chap[0], weight = 0, typeof = 1) m.save() allChapters.insert(1+initialPosition+n, m) n += 1 if originalChapter: sputnik.addMessageToChannel(request, "/chat/%s/" % bookid, {"command": "message_info", "from": request.user.username, "message": 'User %s has split chapter "%s".' % (request.user.username, originalChapter.title)}, myself=True) originalChapter.delete() if tocChapter: tocChapter.delete() n = len(allChapters) for chap in allChapters: try: chap.weight = n chap.save() n -= 1 except: pass ## get chapters chapters = getTOCForBook(book_version) holdChapters = getHoldChapters(book_version) sputnik.addMessageToChannel(request, "/booki/book/%s/%s/" % (bookid, version), {"command": "chapter_split", "chapterID": message["chapterID"], "chapters": chapters, "hold": holdChapters, "username": request.user.username}, myself = True) transaction.commit() return {}
def createBook(user, bookTitle, status="imported", bookURL=None): """ Creates book. @todo: Do something about status. @type user: C{django.contrib.auth.models.User} @param user: Booki user who will be book owner @type bookTitle: C{string} @param bookTitle: Title for the book. If bookURL is omitted it will slugify title for the url version @type status: C{string} @param status: String name for the status (optional) @type bookURL: C{string} @param bookURL: URL title for the book (optional) @rtype: C{booki.editor.models.Book} @return: Returns book object """ if bookURL: url_title = bookURL else: url_title = bookiSlugify(bookTitle) book = models.Book(url_title=url_title, title=bookTitle, owner=user, published=datetime.datetime.now()) book.save() # put this in settings file status_default = ["published", "not published", "imported"] n = len(status_default) for statusName in status_default: status = models.BookStatus(book=book, name=statusName, weight=n) status.save() n -= 1 # not use "not published" but first in the list maybe, or just status book.status = models.BookStatus.objects.get(book=book, name="not published") book.save() version = models.BookVersion(book=book, major=1, minor=0, name='initial', description='') version.save() book.version = version book.save() logBookHistory(book=book, version=version, user=user, kind='book_create') import booki.editor.signals booki.editor.signals.book_created.send(sender=user, book=book) return book
def create(self, validated_data): chapter = super(ChapterListCreateSerializer, self).create(validated_data) # create toc book = self.context['view']._book book_version = self.context['view']._book.version weight = len(book_version.get_toc()) + 1 for itm in BookToc.objects.filter(version=book_version, book=book).order_by("-weight"): itm.weight = weight itm.save() weight -= 1 toc_item = BookToc( version=book_version, book=book, name=chapter.title, chapter=chapter, weight=1, typeof=1 ) toc_item.save() # create chapter history history = logChapterHistory( chapter=chapter, content=chapter.content, user=self.context['request'].user, comment="created via api", revision=chapter.revision ) # create book history if history: logBookHistory( book=book, version=book_version, chapter=chapter, chapter_history=history, user=self.context['request'].user, kind='chapter_create' ) # TODO # this is just playground # we must create separate tool to push messages through the sputnik channel from API endpoints # without having clientID in request # message_info channel_name = "/chat/{}/".format(book.id) clnts = sputnik.smembers("sputnik:channel:{}:channel".format(channel_name)) message = { 'channel': channel_name, "command": "message_info", "from": self.context['request'].user.username, "email": self.context['request'].user.email, "message_id": "user_new_chapter", "message_args": [self.context['request'].user.username, chapter.title] } for c in clnts: if c.strip() != '': sputnik.push("ses:%s:messages" % c, json.dumps(message)) # chapter_create channel_name = "/booktype/book/{}/{}/".format(book.id, book_version.get_version()) clnts = sputnik.smembers("sputnik:channel:{}:channel".format(channel_name)) message = { 'channel': channel_name, "command": "chapter_create", "chapter": (chapter.id, chapter.title, chapter.url_title, 1, chapter.status.id, chapter.lock_type, chapter.lock_username, "root", toc_item.id, "normal", None) } for c in clnts: if c.strip() != '': sputnik.push("ses:%s:messages" % c, json.dumps(message)) # notificatoin message message = { 'channel': channel_name, 'command': 'notification', 'message': 'notification_chapter_was_created', 'username': self.context['request'].user.username, 'message_args': (chapter.title,) } for c in clnts: if c.strip() != '': sputnik.push("ses:%s:messages" % c, json.dumps(message)) return chapter
def upload_cover(request, bookid, version=None): """ Uploades attachments. Used from Upload dialog. @param request: Django Request @param bookid: Book ID @param version: Book version or None """ import datetime 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}) book_version = book.getVersion(version) stat = models.BookStatus.objects.filter(book = book)[0] operationResult = True # check this for transactions try: for name, fileData in request.FILES.items(): if True: import hashlib h = hashlib.sha1() h.update(name) h.update(request.POST.get('format', '')) h.update(request.POST.get('license', '')) h.update(str(datetime.datetime.now())) license = models.License.objects.get(abbrevation=request.POST.get('license', '')) frm = request.POST.get('format', '').split(',') try: width = int(request.POST.get('width', '0')) except ValueError: width = 0 try: height = int(request.POST.get('height', '0')) except ValueError: height = 0 import unidecode try: filename = unidecode.unidecode(request.FILES[name].name) except: filename = '' title = request.POST.get('title', '').strip()[:250] cov = models.BookCover(book = book, user = request.user, cid = h.hexdigest(), title = title, filename = filename[:250], width = width, height = height, 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 = 'book' in frm, is_ebook = 'ebook' in frm, is_pdf = 'pdf' in frm, created = datetime.datetime.now()) cov.save() cov.attachment.save(request.FILES[name].name, fileData, save = False) cov.save() from booki.utils import log log.logBookHistory(book = book, version = book_version, args = {'filename': filename[:250], 'title': title, 'cid': cov.pk}, user = request.user, kind = 'cover_upload' ) # TODO: # must write info about this to log! except IOError: operationResult = False transaction.rollback() except: from booki.utils import log log.printStack() oprerationResult = False transaction.rollback() else: # maybe check file name now and save with new name transaction.commit() return HttpResponse('<html><body><script> parent.jQuery.booki.editor.showCovers(); </script></body></html>')
def upload_cover(request, bookid, version=None): """ Uploades attachments. Used from Upload dialog. @param request: Django Request @param bookid: Book ID @param version: Book version or None """ import datetime 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}) book_version = book.getVersion(version) stat = models.BookStatus.objects.filter(book=book)[0] operationResult = True # check this for transactions try: for name, fileData in request.FILES.items(): if True: import hashlib h = hashlib.sha1() h.update(name) h.update(request.POST.get('format', '')) h.update(request.POST.get('license', '')) h.update(str(datetime.datetime.now())) license = models.License.objects.get( abbrevation=request.POST.get('license', '')) frm = request.POST.get('format', '').split(',') try: width = int(request.POST.get('width', '0')) except ValueError: width = 0 try: height = int(request.POST.get('height', '0')) except ValueError: height = 0 import unidecode try: filename = unidecode.unidecode(request.FILES[name].name) except: filename = '' title = request.POST.get('title', '').strip()[:250] cov = models.BookCover( book=book, user=request.user, cid=h.hexdigest(), title=title, filename=filename[:250], width=width, height=height, 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='book' in frm, is_ebook='ebook' in frm, is_pdf='pdf' in frm, created=datetime.datetime.now()) cov.save() cov.attachment.save(request.FILES[name].name, fileData, save=False) cov.save() from booki.utils import log log.logBookHistory(book=book, version=book_version, args={ 'filename': filename[:250], 'title': title, 'cid': cov.pk }, user=request.user, kind='cover_upload') # TODO: # must write info about this to log! except IOError: operationResult = False transaction.rollback() except: from booki.utils import log log.printStack() oprerationResult = False transaction.rollback() else: # maybe check file name now and save with new name transaction.commit() return HttpResponse( '<html><body><script> parent.jQuery.booki.editor.showCovers(); </script></body></html>' )
def _import_book(self, epub_book, book): titles = {} toc = [] def _parse_toc(elements, parent=None): for _elem in elements: # used later to get parent of an elem unique_id = uuid.uuid4().hex if isinstance(_elem, tuple): toc.append((1, _elem[0].title, unique_id, parent)) _parse_toc(_elem[1]) elif isinstance(_elem, ebooklib.epub.Section): pass elif isinstance(_elem, ebooklib.epub.Link): _urlp = urlparse.urlparse(_elem.href) _name = os.path.normpath(urllib.unquote(_urlp.path)) # check in case _name is an empty string if not _name: _name = _elem.title if _name not in titles: titles[_name] = _elem.title toc.append((0, _name, unique_id, parent)) _parse_toc(epub_book.toc) self.notifier.debug( "TOC structure: \n{}".format(pprint.pformat(toc, indent=4))) now = datetime.datetime.utcnow().replace(tzinfo=utc) stat = models.BookStatus.objects.filter(book=book, name="new")[0] # assign cover image if there is one cover_image = get_cover_image(epub_book) if cover_image: self._set_cover(book, cover_image) # import all images in the EPUB for image in epub_book.get_items_of_type(ebooklib.ITEM_IMAGE): if image == cover_image: continue if not self.delegate.should_import_image(image): continue name = os.path.normpath(image.file_name) att = models.Attachment(book=book, version=book.version, status=stat) with ContentFile(image.get_content()) as content_file: attName, attExt = os.path.splitext(os.path.basename(name)) att.attachment.save( '{}{}'.format(booktype_slugify(attName), attExt), content_file, save=False ) att.save() self._attachments[name] = att self.notifier.debug("Imported image: {} -> {}".format(image, att)) # URL titles assigned so far url_titles = [] def _make_url_title(title, i=0): url_title = booktype_slugify(title) if i > 0: url_title += "_" + str(i) if url_title not in url_titles: url_titles.append(url_title) return url_title else: return _make_url_title(title, i + 1) # import all document items from the EPUB for document in epub_book.get_items_of_type(ebooklib.ITEM_DOCUMENT): # Nav and Cover are not imported if not document.is_chapter(): continue if not self.delegate.should_import_document(document): continue name = os.path.normpath(document.file_name) title = '' # maybe this part has to go to the plugin # but you can not get title from <title> if name in titles: title = titles[name] else: title = convert_file_name(name) if title.rfind('.') != -1: title = title[:title.rfind('.')] title = title.replace('.', '') url_title = _make_url_title(title) content = self._create_content(document, title) chapter = models.Chapter( book=book, version=book.version, url_title=url_title, title=title, status=stat, content=content, created=now, modified=now ) chapter.save() # time to save revisions correctly history = logChapterHistory( chapter=chapter, content=chapter.content, user=book.owner, comment='', revision=chapter.revision ) if history: logBookHistory( book=book, version=book.version, chapter=chapter, chapter_history=history, user=book.owner, kind='chapter_create' ) self._chapters[name] = chapter self.notifier.debug( "Imported chapter: {} -> {}".format(document, chapter)) # fix links to chapters for file_name, chapter in self._chapters.iteritems(): self._fix_links(chapter, base_path=os.path.dirname(file_name)) # create TOC objects self._make_toc(book, toc)
def _import_chapters(self, book, chapters): now = datetime.datetime.now() stat = models.BookStatus.objects.filter(book=book, name="new")[0] n = 100 for chapter_title, chapter_content in chapters: if len(chapter_title) > 100: chapter_title = u'{}...'.format(chapter_title[:100]) if chapter_title == '': if n == 100: chapter_title = _('Title Page') else: chapter_title = _('Title') chapter_n = 0 possible_title = chapter_title while True: does_exists = models.Chapter.objects.filter( book=book, version=book.version, url_title=booktype_slugify(possible_title)).exists() if does_exists: chapter_n += 1 possible_title = u'{} - {}'.format(chapter_title, chapter_n) else: break if chapter_content[6:-8].strip() == '': continue chapter_content = self._parse_chapter(chapter_content) chapter = models.Chapter( book=book, version=book.version, url_title=booktype_slugify(possible_title), title=possible_title, status=stat, content=chapter_content[6:-8], created=now, modified=now) chapter.save() toc_item = models.BookToc(book=book, version=book.version, name=chapter.title, chapter=chapter, weight=n, typeof=1) toc_item.save() n -= 1 # time to save revisions correctly history = logChapterHistory(chapter=chapter, content=chapter.content, user=book.owner, comment='', revision=chapter.revision) if history: logBookHistory(book=book, version=book.version, chapter=chapter, chapter_history=history, user=book.owner, kind='chapter_create')
def _import_book(self, epub_book, book): titles = {} toc = [] def _parse_toc(elements, parent=None): for _elem in elements: # used later to get parent of an elem unique_id = uuid.uuid4().hex if isinstance(_elem, tuple): toc.append((1, _elem[0].title, unique_id, parent)) _parse_toc(_elem[1], unique_id) elif isinstance(_elem, ebooklib.epub.Link): _urlp = urlparse.urlparse(_elem.href) _name = os.path.normpath(urllib.unquote(_urlp.path)) # check in case _name is an empty string if not _name: _name = _elem.title if _name not in titles: titles[_name] = _elem.title toc.append((0, _name, unique_id, parent)) _parse_toc(epub_book.toc) self.notifier.debug("TOC structure: \n{}".format( pprint.pformat(toc, indent=4))) now = datetime.datetime.utcnow().replace(tzinfo=utc) default_status = get_default_book_status() stat = models.BookStatus.objects.filter(book=book, name=default_status)[0] # assign cover image if there is one cover_image = get_cover_image(epub_book) if cover_image: self._set_cover(book, cover_image) # import all images in the EPUB for image in epub_book.get_items_of_type(ebooklib.ITEM_IMAGE): if image == cover_image: continue if not self.delegate.should_import_image(image): continue name = os.path.normpath(image.file_name) att = models.Attachment(book=book, version=book.version, status=stat) with ContentFile(image.get_content()) as content_file: attName, attExt = os.path.splitext(os.path.basename(name)) att.attachment.save('{}{}'.format(booktype_slugify(attName), attExt), content_file, save=False) att.save() self._attachments[name] = att self.notifier.debug("Imported image: {} -> {}".format(image, att)) # URL titles assigned so far url_titles = [] def _make_url_title(title, i=0): url_title = booktype_slugify(title) if i > 0: url_title += "_" + str(i) if url_title not in url_titles: url_titles.append(url_title) return url_title else: return _make_url_title(title, i + 1) # import all document items from the EPUB for document in epub_book.get_items_of_type(ebooklib.ITEM_DOCUMENT): # Nav and Cover are not imported if not document.is_chapter(): continue if not self.delegate.should_import_document(document): continue name = os.path.normpath(document.file_name) title = '' # maybe this part has to go to the plugin # but you can not get title from <title> if name in titles: title = titles[name] else: title = convert_file_name(name) if title.rfind('.') != -1: title = title[:title.rfind('.')] title = title.replace('.', '') url_title = _make_url_title(title) content = self._create_content(document, title) chapter = models.Chapter(book=book, version=book.version, url_title=url_title, title=title, status=stat, content=content, created=now, modified=now) chapter.save() # time to save revisions correctly history = logChapterHistory(chapter=chapter, content=chapter.content, user=book.owner, comment='', revision=chapter.revision) if history: logBookHistory(book=book, version=book.version, chapter=chapter, chapter_history=history, user=book.owner, kind='chapter_create') self._chapters[name] = chapter self.notifier.debug("Imported chapter: {} -> {}".format( document, chapter)) # fix links to chapters for file_name, chapter in self._chapters.iteritems(): self._fix_links(chapter, base_path=os.path.dirname(file_name)) # create TOC objects self._make_toc(book, toc)
def create_book(user, book_title, status=None, book_url=None): """ Creates book. @type user: C{django.contrib.auth.models.User} @param user: Booktype user who will be book owner @type book_title: C{string} @param book_title: Title for the book. If book_url is omitted it will slugify title for the url version @type status: C{string} @param status: String name for the status (optional) @type book_url: C{string} @param book_url: URL title for the book (optional) @rtype: C{booki.editor.models.Book} @return: Returns book object """ if book_url: url_title = book_url[:100] else: url_title = booktype_slugify(book_title[:100]) book = models.Book(url_title=url_title, title=book_title, owner=user, created=datetime.datetime.now(), published=datetime.datetime.now(), hidden=False, description='', cover=None) book.save() status_list = config.get_configuration('CHAPTER_STATUS_LIST') n = len(status_list) default_status = status if status else get_default_book_status() for status_elem in status_list: status = models.BookStatus(book=book, name=status_elem['name'], weight=n, color=status_elem['color']) status.save() n -= 1 # not use "not published" but first in the list maybe, or just status book.status = models.BookStatus.objects.get(book=book, name=default_status) book.save() track_changes = config.get_configuration('BOOK_TRACK_CHANGES', False) version = models.BookVersion(book=book, major=1, minor=0, name='initial', description='', created=datetime.datetime.now(), track_changes=track_changes) version.save() book.version = version book.save() logBookHistory(book=book, version=version, user=user, kind='book_create') booki.editor.signals.book_created.send(sender=user, book=book) return book
def upload_attachment(request, bookid, version=None): """ Uploades attachments. Used from Upload dialog. @param request: Django Request @param bookid: Book ID @param version: Book version or None """ import datetime try: book = models.Book.objects.get(url_title__iexact=bookid) except models.Book.DoesNotExist: return pages.ErrorPage(request, "errors/book_does_not_exist.html", {"book_name": bookid}) book_version = book.getVersion(version) stat = models.BookStatus.objects.filter(book = book)[0] operationResult = True # check this for transactions try: for name, fileData in request.FILES.items(): from booki.utils import log log.logBookHistory(book = book, version = book_version, args = {'filename': request.FILES[name].name}, user = request.user, kind = 'attachment_upload' ) att = models.Attachment(version = book_version, # must remove this reference created = datetime.datetime.now(), book = book, status = stat) att.save() att.attachment.save(request.FILES[name].name, fileData, save = False) att.save() # TODO: # must write info about this to log! except IOError: operationResult = False transaction.rollback() except: oprerationResult = False transaction.rollback() else: # maybe check file name now and save with new name transaction.commit() if request.POST.get("attachmenttab", "") == "": return HttpResponse('<html><body><script> parent.closeAttachmentUpload(); </script></body></html>') if request.POST.get("attachmenttab", "") == "2": return HttpResponse('<html><body><script> parent.FileBrowserDialogue.loadAttachments(); parent.FileBrowserDialogue.displayBrowseTab(); parent.FileBrowserDialogue.showUpload(); </script></body></html>') # return HttpResponse('<html><body><script> console.debug("load attachments"); parent.FileBrowserDialogue.loadAttachments(); console.debug("show upload"); parent.FileBrowserDialogue.showUpload(); parent.FileBrowserDialogue.displayBrowseTab(); console.debug("after show browse panel");</script></body></html>') # should not call showAttachmentsTab, but it works for now if operationResult: return HttpResponse('<html><body><script> parent.jQuery.booki.editor.showAttachmentsTab(); parent.jQuery("#tabattachments FORM")[0].reset(); </script></body></html>') else: return HttpResponse('<html><body><script> parent.jQuery.booki.editor.showAttachmentsTab(); parent.jQuery("#tabattachments FORM")[0].reset(); alert(parent.jQuery.booki._("errorupload", "Error while uploading file!"));</script></body></html>')
def remote_create_chapter(request, message, bookid, version): import datetime # BookVersion treba uzeti book = models.Book.objects.get(id=bookid) book_version = getVersion(book, version) from django.template.defaultfilters import slugify url_title = slugify(message["chapter"]) # here i should probably set it to default project status s = models.BookStatus.objects.filter(book=book).order_by("weight")[0] ch = models.Chapter.objects.filter(book=book, version=book_version, url_title=url_title) if len(list(ch)) > 0: return {"created": False} content = u'<h1>%s</h1>' % message["chapter"] chapter = models.Chapter(book = book, version = book_version, url_title = url_title, title = message["chapter"], status = s, content = content, created = datetime.datetime.now(), modified = datetime.datetime.now()) try: chapter.save() except: transaction.rollback() return {"created": False} else: # this should be solved in better way # should have createChapter in booki.utils.book module toc_items = len(book_version.getTOC())+1 for itm in models.BookToc.objects.filter(version = book_version, book = book): itm.weight = toc_items itm.save() toc_items -= 1 tc = models.BookToc(version = book_version, book = book, name = message["chapter"], chapter = chapter, weight = 1, typeof = 1) try: tc.save() except: transaction.rollback() return {"created": False} history = logChapterHistory(chapter = chapter, content = content, user = request.user, comment = message.get("comment", ""), revision = chapter.revision) logBookHistory(book = book, version = book_version, chapter = chapter, chapter_history = history, user = request.user, kind = 'chapter_create') transaction.commit() result = (chapter.id, chapter.title, chapter.url_title, 1, s.id) sputnik.addMessageToChannel(request, "/chat/%s/" % bookid, {"command": "message_info", "from": request.user.username, "message": 'User %s has created new chapter "%s".' % (request.user.username, message["chapter"])}, myself=True) sputnik.addMessageToChannel(request, "/booki/book/%s/%s/" % (bookid, version), {"command": "chapter_create", "chapter": result}, myself = True) return {"created": True}
def create_book(user, book_title, status=None, book_url=None): """ Creates book. @type user: C{django.contrib.auth.models.User} @param user: Booktype user who will be book owner @type book_title: C{string} @param book_title: Title for the book. If book_url is omitted it will slugify title for the url version @type status: C{string} @param status: String name for the status (optional) @type book_url: C{string} @param book_url: URL title for the book (optional) @rtype: C{booki.editor.models.Book} @return: Returns book object """ if book_url: url_title = book_url[:100] else: url_title = booktype_slugify(book_title[:100]) book = models.Book( url_title=url_title, title=book_title, owner=user, created=datetime.datetime.now(), published=datetime.datetime.now(), hidden=False, description='', cover=None ) book.save() status_list = config.get_configuration('CHAPTER_STATUS_LIST') n = len(status_list) default_status = status if status else get_default_book_status() for status_elem in status_list: status = models.BookStatus( book=book, name=status_elem['name'], weight=n, color=status_elem['color'] ) status.save() n -= 1 # not use "not published" but first in the list maybe, or just status book.status = models.BookStatus.objects.get(book=book, name=default_status) book.save() track_changes = config.get_configuration('BOOK_TRACK_CHANGES', False) version = models.BookVersion( book=book, major=1, minor=0, name='initial', description='', created=datetime.datetime.now(), track_changes=track_changes ) version.save() book.version = version book.save() logBookHistory( book=book, version=version, user=user, kind='book_create' ) booki.editor.signals.book_created.send(sender=user, book=book) return book
def upload_attachment(request, bookid, version=None): """ Uploades attachments. Used from Upload dialog. @param request: Django Request @param bookid: Book ID @param version: Book version or None """ import datetime try: book = models.Book.objects.get(url_title__iexact=bookid) except models.Book.DoesNotExist: return pages.ErrorPage(request, "errors/book_does_not_exist.html", {"book_name": bookid}) book_version = book.getVersion(version) stat = models.BookStatus.objects.filter(book=book)[0] operationResult = True # check this for transactions try: for name, fileData in request.FILES.items(): from booki.utils import log log.logBookHistory(book=book, version=book_version, args={'filename': request.FILES[name].name}, user=request.user, kind='attachment_upload') att = models.Attachment( version=book_version, # must remove this reference created=datetime.datetime.now(), book=book, status=stat) att.save() att.attachment.save(request.FILES[name].name, fileData, save=False) att.save() # TODO: # must write info about this to log! except IOError: operationResult = False transaction.rollback() except: oprerationResult = False transaction.rollback() else: # maybe check file name now and save with new name transaction.commit() if request.POST.get("attachmenttab", "") == "": return HttpResponse( '<html><body><script> parent.closeAttachmentUpload(); </script></body></html>' ) if request.POST.get("attachmenttab", "") == "2": return HttpResponse( '<html><body><script> parent.FileBrowserDialogue.loadAttachments(); parent.FileBrowserDialogue.displayBrowseTab(); parent.FileBrowserDialogue.showUpload(); </script></body></html>' ) # return HttpResponse('<html><body><script> console.debug("load attachments"); parent.FileBrowserDialogue.loadAttachments(); console.debug("show upload"); parent.FileBrowserDialogue.showUpload(); parent.FileBrowserDialogue.displayBrowseTab(); console.debug("after show browse panel");</script></body></html>') # should not call showAttachmentsTab, but it works for now if operationResult: return HttpResponse( '<html><body><script> parent.jQuery.booki.editor.showAttachmentsTab(); parent.jQuery("#tabattachments FORM")[0].reset(); </script></body></html>' ) else: return HttpResponse( '<html><body><script> parent.jQuery.booki.editor.showAttachmentsTab(); parent.jQuery("#tabattachments FORM")[0].reset(); alert(parent.jQuery.booki._("errorupload", "Error while uploading file!"));</script></body></html>' )
def createBook(user, bookTitle, userip = "", status = "new", bookURL = None): """ Creates book. @todo: Do something about status. @type user: C{django.contrib.auth.models.User} @param user: Booki user who will be book owner @type bookTitle: C{string} @param bookTitle: Title for the book. If bookURL is omitted it will slugify title for the url version @type status: C{string} @param status: String name for the status (optional) @type bookURL: C{string} @param bookURL: URL title for the book (optional) @rtype: C{booki.editor.models.Book} @return: Returns book object """ import datetime if bookURL: url_title = bookURL else: url_title = bookiSlugify(bookTitle) book = models.Book(url_title = url_title, title = bookTitle, owner = user, created = datetime.datetime.now(), published = datetime.datetime.now()) book.save() # put this in settings file status_default = ["new", "needs content", "completed", "to be proofed"] n = len(status_default) for statusName in status_default: status = models.BookStatus(book=book, name=statusName, weight=n) status.save() n -= 1 # not use "not published" but first in the list maybe, or just status book.status = models.BookStatus.objects.get(book=book, name="new") book.save() version = models.BookVersion(book = book, major = 1, minor = 0, name = 'initial', description = '', created=datetime.datetime.now()) version.save() book.version = version book.save() logBookHistory(book = book, version = version, user = user, kind = 'book_create') eventlog = models.EventsLog(username = user.username, access_ip = userip, event_name = "create_book", event_timestamp=datetime.datetime.now(), book=book, comment=bookTitle) eventlog.save() import booki.editor.signals booki.editor.signals.book_created.send(sender = user, book = book) return book
def _import_chapters(self, book, chapters): now = datetime.datetime.now() default_status = get_default_book_status() stat = models.BookStatus.objects.filter(book=book, name=default_status)[0] n = 100 for chapter_title, chapter_content in chapters: if len(chapter_title) > 100: chapter_title = u'{}...'.format(chapter_title[:100]) if chapter_title == '': if n == 100: chapter_title = _('Title Page') else: chapter_title = _('Title') chapter_n = 0 possible_title = chapter_title while True: does_exists = models.Chapter.objects.filter( book=book, version=book.version, url_title=booktype_slugify(possible_title)).exists() if does_exists: chapter_n += 1 possible_title = u'{} - {}'.format(chapter_title, chapter_n) else: break if chapter_content[6:-8].strip() == '': continue _content = self._parse_chapter(chapter_content) try: chapter_content = unidecode(_content)[6:-8] except UnicodeDecodeError: chapter_content = _content.decode('utf-8', errors='ignore')[6:-8] except Exception as err: chapter_content = 'Error parsing chapter content' logger.exception( "Error while decoding chapter content {0}".format(err)) chapter = models.Chapter( book=book, version=book.version, url_title=booktype_slugify(possible_title), title=possible_title, status=stat, content=chapter_content, created=now, modified=now) chapter.save() toc_item = models.BookToc(book=book, version=book.version, name=chapter.title, chapter=chapter, weight=n, typeof=1) toc_item.save() n -= 1 # time to save revisions correctly history = logChapterHistory(chapter=chapter, content=chapter.content, user=book.owner, comment='', revision=chapter.revision) if history: logBookHistory(book=book, version=book.version, chapter=chapter, chapter_history=history, user=book.owner, kind='chapter_create')