def createBookiGroup(groupName, groupDescription, owner): """ Create Booki Group. @type groupName: C{string} @param groupName: Group name @type groupDescription: C{string} @param groupDescription: Group name @type owner: C{django.contrib.auth.models.User} @param owner: Group owner @rtype: C{booki.editor.models.BookiGroup} @return: Returns group object """ import datetime try: bg = models.BookiGroup.objects.get(url_name = bookiSlugify(groupName)) except models.BookiGroup.MultipleObjectsReturned: raise BookiGroupExist(groupName) except models.BookiGroup.DoesNotExist: group = models.BookiGroup(name = groupName, url_name = bookiSlugify(groupName), description = groupDescription, owner = owner, created = datetime.datetime.now()) group.save() return group raise BookiGroupExist(groupName)
def createBookiGroup(groupName, groupDescription, owner): """ Create Booki Group. @type groupName: C{string} @param groupName: Group name @type groupDescription: C{string} @param groupDescription: Group name @type owner: C{django.contrib.auth.models.User} @param owner: Group owner @rtype: C{booki.editor.models.BookiGroup} @return: Returns group object """ import datetime try: bg = models.BookiGroup.objects.get(url_name=bookiSlugify(groupName)) except models.BookiGroup.MultipleObjectsReturned: raise BookiGroupExist(groupName) except models.BookiGroup.DoesNotExist: group = models.BookiGroup(name=groupName, url_name=bookiSlugify(groupName), description=groupDescription, owner=owner, created=datetime.datetime.now()) group.save() return group raise BookiGroupExist(groupName)
def remote_edit_discussion(request, message, bookid, version): """ Function to edit the discussion theme in the model """ import datetime discussiontheme = models.DiscussionTheme.objects.get(title = message["old_title"]) discussiontheme.title = message["new_title"] url_title = bookiSlugify(message["new_title"]) discussiontheme.url_title = url_title discussiontheme.message = message["new_message"] discussiontheme.labels = message["new_labels"] discussiontheme.access = message["new_access"] try: # Elgg Integration elgg = discussions_mysql.Update_Discussion_Theme(discussiontheme) # discussiontheme.save() except: transaction.rollback() return {"edited": False} else: transaction.commit() discussion = [] discussion.append({"title": discussiontheme.title, "message": discussiontheme.message, "labels": discussiontheme.labels, "access": discussiontheme.access, "user": discussiontheme.user.username, "created": discussiontheme.created.strftime("%d %b. %Y, %H:%M")}) return {"edited": True, "discussion": discussion}
def createBookiGroup(groupName, groupDescription, request): """ Create Booki Group. @type groupName: C{string} @param groupName: Group name @type groupDescription: C{string} @param groupDescription: Group name @type owner: C{django.contrib.auth.models.User} @param owner: Group owner @rtype: C{booki.editor.models.BookiGroup} @return: Returns group object """ import datetime owner = request.user try: bg = models.BookiGroup.objects.get(url_name = bookiSlugify(groupName)) except models.BookiGroup.MultipleObjectsReturned: raise BookiGroupExist(groupName) except models.BookiGroup.DoesNotExist: group = models.BookiGroup(name = groupName, url_name = bookiSlugify(groupName), description = groupDescription, owner = owner, created = datetime.datetime.now()) group.save() x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') if x_forwarded_for: ip = x_forwarded_for.split(',')[-1].strip() else: ip = request.META.get('REMOTE_ADDR') eventlog = models.EventsLog(username = owner.username, access_ip = ip, event_name = "create_group", event_timestamp=datetime.datetime.now(), #book=0, comment=group.id) eventlog.save() return group raise BookiGroupExist(groupName)
def rename_book(request, bookid): 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(None) if request.method == "POST": frm = BookRenameForm(request.POST, request.FILES) if request.POST["submit"] == _("Cancel"): return HttpResponseRedirect(reverse("control_book", args=[book.url_title])) if frm.is_valid(): from booki.utils.book import renameBook from booki.utils.misc import bookiSlugify title = frm.cleaned_data["title"] URLTitle = frm.cleaned_data["url_title"] if URLTitle.strip() == "": URLTitle = bookiSlugify(title) # this is not the nice way to solve this if book.url_title != URLTitle: try: b = models.Book.objects.get(url_title__iexact=URLTitle) except models.Book.DoesNotExist: renameBook(book, title, URLTitle) book.save() messages.success(request, _("Successfuly renamed book.")) return HttpResponseRedirect(reverse("control_book", args=[book.url_title])) else: renameBook(book, title, URLTitle) book.save() messages.success(request, _("Successfuly renamed book.")) return HttpResponseRedirect(reverse("control_book", args=[book.url_title])) else: frm = BookRenameForm(initial={"title": book.title, "url_title": book.url_title}) return render_to_response( "booktypecontrol/rename_book.html", {"request": request, "admin_options": ADMIN_OPTIONS, "form": frm, "book": book}, context_instance=RequestContext(request), )
def makeTitleUnique(requestedTitle): """If <requestedTitle> is unused, return that. Otherwise, return a title in the form `u'%s - %d' % (requestedTitle, n)` where n is the lowest non-clashing positive integer. """ n = 0 name = requestedTitle while True: titles = models.Book.objects.filter(title=name).count() urls = models.Book.objects.filter(url_title=bookiSlugify(name)).count() if not titles and not urls: return name n += 1 name = u"%s - %d" % (requestedTitle, n)
def makeTitleUnique(requestedTitle): """If <requestedTitle> is unused, return that. Otherwise, return a title in the form `u'%s - %d' % (requestedTitle, n)` where n is the lowest non-clashing positive integer. """ n = 0 name = requestedTitle while True: titles = models.Book.objects.filter(title=name).count() urls = models.Book.objects.filter(url_title=bookiSlugify(name)).count() if not titles and not urls: return name n += 1 name = u'%s - %d' % (requestedTitle, n)
def remote_create_discussion(request, message, bookid, version): """ Function to create the discussion theme in the model """ import datetime book = models.Book.objects.get(id=bookid) user = request.user url_title = bookiSlugify(message["discussion"]) title = message["discussion"] lmessage = message["message"] state = "1" labels = message["labels"] access = message["access"] try: # Elgg Integration guid = discussions_mysql.Get_Object_Entity() # discussiontheme = models.DiscussionTheme(id = int(guid), book = book, user = user, url_title = url_title, title = title, message = lmessage, state = state, labels = labels, access = access, created = datetime.datetime.now()) discussiontheme.save() # Elgg Integration elgg = discussions_mysql.Save_Discussion_Theme(discussiontheme) except: transaction.rollback() return {"created": False} else: transaction.commit() discussion = [] discussion.append({"title": discussiontheme.title, "message": discussiontheme.message, "user": discussiontheme.user.username, "created": discussiontheme.created.strftime("%d %b. %Y, %H:%M")}) return {"created": True, "discussion": discussion}
def checkBookAvailability(bookTitle): """ Checks if the book name is available or not. @type bookTitle: C{string} @param bookTitle: Title for the book. @rtype: C{bool} @return: Returns true or false """ url_title = bookiSlugify(bookTitle) if url_title == '': return False try: book = models.Book.objects.get(Q(title=bookTitle) | Q(url_title = url_title)) except models.Book.DoesNotExist: return True return False
def checkGroupAvailability(groupName): """ Checks if the group name is available or not. @type bookName: C{string} @param bookName: Name of the group. @rtype: C{bool} @return: Returns true or false """ url_name = bookiSlugify(groupName) if url_name == '': return False try: group = models.BookiGroup.objects.get(Q(name=groupName) | Q(url_name = url_name)) except models.BookiGroup.DoesNotExist: return True return False
parser.error("You must specify a file name for Wordpress export") # parse the export file # don't really care about validation document = feedparser.parse(args[0]) try: user = User.objects.get(username=options.owner) except User.DoesNotExist: print "No such user %s" % options.owner sys.exit(-1) if options.title: bookTitle = options.title bookTitleURL = bookiSlugify(options.title) else: bookTitle = document["feed"]["title"] if options.url: bookTitleURL = options.url elif not options.title: bookTitleURL = bookiSlugify(document["feed"]["title"]) # So we don't spend best years of our lives waiting import socket socket.setdefaulttimeout(10) # Import the feed
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 importFeed(document, conf): """ Imports content of Wordpress export into Booktype. """ # To create a book we use "createBook" function. It will do good part of magic for us in the background. # We have to provide: # - owner of the book; every book must have an owner # - book title; this is full book name # - book status; every book has a status, let us just use "new" for now # - book url; book must have unique name and in Booktype world it is book url name from booki.utils.book import createBook book = createBook(conf["user"], conf["bookTitle"], status="new", bookURL=conf["bookTitleURL"]) # We use config API to check if books are by default visible or not isVisible = config.getConfiguration("CREATE_BOOK_VISIBLE", True) book.hidden = not isVisible book.save() # "createBook" function has already created default list of statuses. Let's just fetch "new" status because # we will need it for Chapters later stat = models.BookStatus.objects.filter(book=book, name="new")[0] # What is default URL for Wordpress blog wpLink = document["feed"]["link"] attachments = [] for item in document["items"]: # We only care about posts which have "publish" status. Ignore everything else for now. if item["wp_status"] != u"publish": continue chapterTitle = item["title"] print ">> ", chapterTitle # So... let's clean our Wordpress post a bit. Here we ASSUME that empty line is used to separate paragraphs in Wordpress post. content = item["content"][0]["value"].replace("\r\n", "\n") content = "\n".join(["<p>%s</p>" % p for p in content.split("\n\n") if p.strip() != ""]) # Every Booktype chapter starts with Chapter title embded in H2 tag. content = u"<h2>%s</h2>%s" % (chapterTitle, content) tree = html.document_fromstring(content) for e in tree.iter(): # We only care about images now if e.tag == "img": src = e.get("src") if src: if src.startswith("/"): src = wpLink + src # We don't need to download picture if it was already downloaed if not src in attachments: attachments.append(src) u = urlparse.urlsplit(src) # Get the file name and take care of funny stuff like %20 in file names fileName = os.path.basename(urllib.unquote(u.path)) print " >> ", fileName # Download image data = downloadFile(src) # Let us create this attachment if we managed to download something if data: # Create new Attachment. "book" argument is part of legacy here, we really should care only about "version". # Expect this to be removed in the future. Also, every Attachment can have different status. Not that it is # used anywhere at the moment, but it has to be here. att = models.Attachment(book=book, version=book.version, status=stat) # We use standard method for saving the data. f2 = File(StringIO(data)) f2.size = len(data) att.attachment.save(fileName, f2, save=True) # If filename with the same name already exists then Django will add prefix to the name. # For instance: Image.jpg would become Image_1.jpg. That is why we check the new name. fileName = os.path.basename(att.attachment.path) # Set whatever we got as a new attachment name. Also notice all images are referenced as # "static/image.jpg" in Booktype so we have to change the source also. e.set("src", "static/%s" % fileName) content = etree.tostring(tree, encoding="UTF-8", method="html") # Create new chapter. New chapter will be in "Hold chapters". If you want it to be in "Table of contents" you would # need to do some extra magic. But we don't care about it now. We also don't really care about writing anything to # log files... now = datetime.datetime.now() chapter = models.Chapter( book=book, version=book.version, url_title=bookiSlugify(chapterTitle), title=chapterTitle, status=stat, content=content, created=now, modified=now, ) chapter.save()
def exportBook(book_version): from booki import bookizip import time starttime = time.time() (zfile, zname) = tempfile.mkstemp() spine = [] toc_top = [] toc_current = toc_top waiting_for_url = [] info = { "version": 1, "TOC": toc_top, "spine": spine, "metadata": _format_metadata(book_version.book), "manifest": {}, } bzip = bookizip.BookiZip(zname, info=info) chapter_n = 1 for i, chapter in enumerate(models.BookToc.objects.filter(version=book_version).order_by("-weight")): if chapter.chapter: # It's a real chapter! With content! try: content = _fix_content(book_version.book, chapter, chapter_n) except: continue chapter_n += 1 ID = "ch%03d_%s" % (i, chapter.chapter.url_title.encode("utf-8")) filename = ID + ".html" toc_current.append({"title": chapter.chapter.title, "url": filename, "type": "chapter", "role": "text"}) # If this is the first chapter in a section, lend our url # to the section, which has no content and thus no url of # its own. If this section was preceded by an empty # section, it will be waiting too, hence "while" rather # than "if". while waiting_for_url: section = waiting_for_url.pop() section["url"] = filename bzip.add_to_package(ID, filename, content, "text/html") spine.append(ID) else: # A new top level section. title = chapter.name.encode("utf-8") ID = "s%03d_%s" % (i, bookiSlugify(title)) toc_current = [] section = {"title": title, "url": "", "type": "booki-section", "children": toc_current} toc_top.append(section) waiting_for_url.append(section) # Attachments are images (and perhaps more). They do not know # whether they are currently in use, or what chapter they belong # to, so we add them all. # XXX scan for img links while adding chapters, and only add those. for i, attachment in enumerate(models.Attachment.objects.filter(version=book_version)): try: f = open(attachment.attachment.name, "rb") blob = f.read() f.close() except (IOError, OSError), e: msg = "couldn't read attachment %s" % e logWarning(msg) continue fn = os.path.basename(attachment.attachment.name.encode("utf-8")) ID = "att%03d_%s" % (i, bookiSlugify(fn)) if "." in fn: _, ext = fn.rsplit(".", 1) mediatype = bookizip.MEDIATYPES.get(ext.lower(), bookizip.MEDIATYPES[None]) else: mediatype = bookizip.MEDIATYPES[None] bzip.add_to_package(ID, "static/%s" % fn, blob, mediatype)
def importBookFromFile(user, zname, createTOC=False, **extraOptions): """Create a new book from a bookizip filename""" from booki.utils.log import logChapterHistory # unzip it zf = zipfile.ZipFile(zname) # load info.json info = json.loads(zf.read("info.json")) logWarning("Loaded json file %r" % info) metadata = info["metadata"] manifest = info["manifest"] TOC = info["TOC"] if extraOptions.get("book_title", None): bookTitle = extraOptions["book_title"] else: bookTitle = get_metadata(metadata, "title", ns=DC)[0] bookTitle = makeTitleUnique(bookTitle) logWarning("Chose unique book title %r" % bookTitle) if extraOptions.get("book_url", None): bookURL = extraOptions["book_url"] else: bookURL = None book = createBook(user, bookTitle, status="new", bookURL=bookURL) if extraOptions.get("hidden"): book.hidden = True book.save() # this is for Table of Contents p = re.compile('\ssrc="(.*)"') # what if it does not have status "new" stat = models.BookStatus.objects.filter(book=book, name="new")[0] chapters = getChaptersFromTOC(TOC) n = len(chapters) + 1 # is +1 necessary? now = datetime.datetime.now() for chapterName, chapterFile, is_section in chapters: urlName = bookiSlugify(chapterName) if is_section: # create section if createTOC: c = models.BookToc(book=book, version=book.version, name=chapterName, chapter=None, weight=n, typeof=2) c.save() n -= 1 else: # create chapter # check if i can open this file at all content = zf.read(chapterFile) # content = p.sub(r' src="../\1"', content) chapter = models.Chapter( book=book, version=book.version, url_title=urlName, title=chapterName, status=stat, content=content, created=now, modified=now, ) chapter.save() history = logChapterHistory( chapter=chapter, content=content, user=user, comment="", revision=chapter.revision ) if createTOC: c = models.BookToc( book=book, version=book.version, name=chapterName, chapter=chapter, weight=n, typeof=1 ) c.save() n -= 1 stat = models.BookStatus.objects.filter(book=book, name="new")[0] from django.core.files import File for item in manifest.values(): if item["mimetype"] != "text/html": attachmentName = item["url"] if attachmentName.startswith("static/"): att = models.Attachment(book=book, version=book.version, status=stat) s = zf.read(attachmentName) f = StringIO(s) f2 = File(f) f2.size = len(s) att.attachment.save(os.path.basename(attachmentName), f2, save=False) att.save() f.close() # metadata for namespace in metadata: # namespace is something like "http://purl.org/dc/elements/1.1/" or "" # in the former case, preepend it to the name, in {}. ns = "{%s}" % namespace if namespace else "" for keyword, schemes in metadata[namespace].iteritems(): for scheme, values in schemes.iteritems(): # schema, if it is set, describes the value's format. # for example, an identifier might be an ISBN. sc = "{%s}" % scheme if scheme else "" key = "%s%s%s" % (ns, keyword, sc) for v in values: if not v: continue try: info = models.Info(book=book, name=key) if len(v) >= 2500: info.value_text = v info.kind = 2 else: info.value_string = v info.kind = 0 info.save() except: # For now just ignore any kind of error here. # Considering we don't handle metadata as we # should it is not such a problem. pass zf.close() return book
def create_book(request, username): """ Django View. Show content for Create Book dialog and creates book. @type request: C{django.http.HttpRequest} @param request: Django Request @type username: C{string} @param username: Username. """ import os from glob import glob import datetime from xml.dom import minidom from django.contrib.auth.models import User from booki.utils.misc import isBookLimitReached try: user = User.objects.get(username=username) except User.DoesNotExist: try: resp = pages.ErrorPage(request, "errors/user_does_not_exist.html", {"username": username}) except: transaction.rollback() raise else: transaction.commit() return resp if isBookLimitReached() or not request.user.is_authenticated(): try: resp = pages.ErrorPage(request, "errors/no_permissions.html") except: transaction.rollback() raise else: transaction.commit() return resp from booki.utils.book import checkBookAvailability, createBook from booki.editor import models book_visible = config.getConfiguration('CREATE_BOOK_VISIBLE') book_license = config.getConfiguration('CREATE_BOOK_LICENSE') admin_create = config.getConfiguration('ADMIN_CREATE_BOOKS') templates_source = config.getConfiguration('BOOK_TYPES_DIR') if request.user.is_superuser: admin_create = False if request.GET.get("q", "") == "check": from booki.utils.json_wrapper import json data = {"available": checkBookAvailability(request.GET.get('bookname', '').strip())} try: resp = HttpResponse(json.dumps(data), "text/plain") except: transaction.rollback() raise else: transaction.commit() return resp if request.method == 'POST' and admin_create == False: book = None try: # hidden on # description # license # title # cover x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') if x_forwarded_for: ip = x_forwarded_for.split(',')[-1].strip() else: ip = request.META.get('REMOTE_ADDR') book = createBook(request.user, request.POST.get('title'), ip) lic = models.License.objects.get(abbrevation=request.POST.get('license')) book.license = lic book.description = request.POST.get('description', '') if request.POST.get("hidden", "") == "on": is_hidden = True else: is_hidden = False book.hidden = is_hidden from django.core.files import File if request.FILES.has_key('cover'): # TODO: Show some kind of error message to the user from booki.utils import misc import os try: fh, fname = misc.saveUploadedAsFile(request.FILES['cover']) book.setCover(fname) os.unlink(fname) except: pass book.save() book_version = book.getVersion() tf = request.POST.get('template', '') try: xmldoc = minidom.parse(tf) chapters = xmldoc.getElementsByTagName('chapter') except: chapters = [] for chapter in chapters: chapter_title = chapter.attributes['title'].value chapter_content = u'<h1>{}</h1>'.format(chapter.attributes['content'].value) url_title = bookiSlugify(chapter_title) status = models.BookStatus.objects.filter(book=book).order_by("-weight")[0] chapter_o = models.Chapter(book=book, version = book_version, url_title = url_title, title = chapter_title, status = status, content = chapter_content, created = datetime.datetime.now(), modified = datetime.datetime.now()) chapter_o.save() toc_items = len(book_version.getTOC()) + 1 for itm in models.BookToc.objects.filter(version=book_version, book=book).order_by("-weight"): itm.weight = toc_items itm.save() toc_items -= 1 tc = models.BookToc(version=book_version, book = book, name = chapter_title, chapter = chapter_o, weight = 1, typeof = 1) tc.save() except: lines = traceback.format_exc().split('\n') for line in lines: print line transaction.rollback() else: transaction.commit() try: resp = render_to_response('account/create_book_redirect.html', {"request": request, "user": user, "book": book}) except: transaction.rollback() raise else: transaction.commit() return resp from booki.editor.models import License licenses = License.objects.all().order_by('name') try: template_files = glob(os.path.join(templates_source, '*.xml')) except: template_files = [] templates = [{'name': 'Vac\xc3\xado', 'file': '/'}] for tf in template_files: print 'parse ' + tf xmldoc = minidom.parse(tf) print 'ok' tpltag = xmldoc.getElementsByTagName('template')[0] template = {} template['name'] = tpltag.attributes['title'].value template['file'] = tf templates.append(template) try: resp = render_to_response('account/create_book.html', {"request": request, "book_visible": book_visible, "book_license": book_license, "admin_create": admin_create, "licenses": licenses, 'templates': templates, "user": user}) except: transaction.rollback() raise else: transaction.commit() return resp
def importFeed(document, conf): """ Imports content of Wordpress export into Booktype. """ # To create a book we use "createBook" function. It will do good part of magic for us in the background. # We have to provide: # - owner of the book; every book must have an owner # - book title; this is full book name # - book status; every book has a status, let us just use "new" for now # - book url; book must have unique name and in Booktype world it is book url name from booki.utils.book import createBook book = createBook(conf['user'], conf['bookTitle'], status="new", bookURL=conf['bookTitleURL']) # We use config API to check if books are by default visible or not isVisible = config.getConfiguration('CREATE_BOOK_VISIBLE', True) book.hidden = not isVisible book.save() # "createBook" function has already created default list of statuses. Let's just fetch "new" status because # we will need it for Chapters later stat = models.BookStatus.objects.filter(book=book, name="new")[0] # What is default URL for Wordpress blog wpLink = document['feed']['link'] attachments = [] for item in document['items']: # We only care about posts which have "publish" status. Ignore everything else for now. if item['wp_status'] != u'publish': continue chapterTitle = item['title'] print '>> ', chapterTitle # So... let's clean our Wordpress post a bit. Here we ASSUME that empty line is used to separate paragraphs in Wordpress post. content = item['content'][0]['value'].replace('\r\n', '\n') content = '\n'.join([ '<p>%s</p>' % p for p in content.split('\n\n') if p.strip() != '' ]) # Every Booktype chapter starts with Chapter title embded in H2 tag. content = u'<h2>%s</h2>%s' % (chapterTitle, content) tree = html.document_fromstring(content) for e in tree.iter(): # We only care about images now if e.tag == 'img': src = e.get('src') if src: if src.startswith('/'): src = wpLink + src # We don't need to download picture if it was already downloaed if not src in attachments: attachments.append(src) u = urlparse.urlsplit(src) # Get the file name and take care of funny stuff like %20 in file names fileName = os.path.basename(urllib.unquote(u.path)) print ' >> ', fileName # Download image data = downloadFile(src) # Let us create this attachment if we managed to download something if data: # Create new Attachment. "book" argument is part of legacy here, we really should care only about "version". # Expect this to be removed in the future. Also, every Attachment can have different status. Not that it is # used anywhere at the moment, but it has to be here. att = models.Attachment(book=book, version=book.version, status=stat) # We use standard method for saving the data. f2 = File(StringIO(data)) f2.size = len(data) att.attachment.save(fileName, f2, save=True) # If filename with the same name already exists then Django will add prefix to the name. # For instance: Image.jpg would become Image_1.jpg. That is why we check the new name. fileName = os.path.basename(att.attachment.path) # Set whatever we got as a new attachment name. Also notice all images are referenced as # "static/image.jpg" in Booktype so we have to change the source also. e.set('src', 'static/%s' % fileName) content = etree.tostring(tree, encoding='UTF-8', method='html') # Create new chapter. New chapter will be in "Hold chapters". If you want it to be in "Table of contents" you would # need to do some extra magic. But we don't care about it now. We also don't really care about writing anything to # log files... now = datetime.datetime.now() chapter = models.Chapter(book=book, version=book.version, url_title=bookiSlugify(chapterTitle), title=chapterTitle, status=stat, content=content, created=now, modified=now) chapter.save()
def importBookFromFile(user, zname, createTOC=False, **extraOptions): """Create a new book from a bookizip filename""" from booki.utils.log import logChapterHistory # unzip it zf = zipfile.ZipFile(zname) # load info.json info = json.loads(zf.read('info.json')) logWarning("Loaded json file %r" % info) metadata = info['metadata'] manifest = info['manifest'] TOC = info['TOC'] if extraOptions.get('book_title', None): bookTitle = extraOptions['book_title'] else: bookTitle = get_metadata(metadata, 'title', ns=DC)[0] bookTitle = makeTitleUnique(bookTitle) logWarning("Chose unique book title %r" % bookTitle) if extraOptions.get('book_url', None): bookURL = extraOptions['book_url'] else: bookURL = None book = createBook(user, bookTitle, status="new", bookURL=bookURL) if extraOptions.get("hidden"): book.hidden = True book.save() # this is for Table of Contents p = re.compile('\ssrc="(.*)"') # what if it does not have status "new" stat = models.BookStatus.objects.filter(book=book, name="new")[0] chapters = getChaptersFromTOC(TOC) n = len(chapters) + 1 #is +1 necessary? now = datetime.datetime.now() for chapterName, chapterFile, is_section in chapters: urlName = bookiSlugify(chapterName) if is_section: # create section if createTOC: c = models.BookToc(book=book, version=book.version, name=chapterName, chapter=None, weight=n, typeof=2) c.save() n -= 1 else: # create chapter # check if i can open this file at all content = zf.read(chapterFile) #content = p.sub(r' src="../\1"', content) chapter = models.Chapter(book=book, version=book.version, url_title=urlName, title=chapterName, status=stat, content=content, created=now, modified=now) chapter.save() history = logChapterHistory(chapter=chapter, content=content, user=user, comment="", revision=chapter.revision) if createTOC: c = models.BookToc(book=book, version=book.version, name=chapterName, chapter=chapter, weight=n, typeof=1) c.save() n -= 1 stat = models.BookStatus.objects.filter(book=book, name="new")[0] from django.core.files import File for item in manifest.values(): if item["mimetype"] != 'text/html': attachmentName = item['url'] if attachmentName.startswith("static/"): att = models.Attachment(book=book, version=book.version, status=stat) s = zf.read(attachmentName) f = StringIO(s) f2 = File(f) f2.size = len(s) att.attachment.save(os.path.basename(attachmentName), f2, save=False) att.save() f.close() # metadata for namespace in metadata: # namespace is something like "http://purl.org/dc/elements/1.1/" or "" # in the former case, preepend it to the name, in {}. ns = ('{%s}' % namespace if namespace else '') for keyword, schemes in metadata[namespace].iteritems(): for scheme, values in schemes.iteritems(): #schema, if it is set, describes the value's format. #for example, an identifier might be an ISBN. sc = ('{%s}' % scheme if scheme else '') key = "%s%s%s" % (ns, keyword, sc) for v in values: if not v: continue try: info = models.Info(book=book, name=key) if len(v) >= 2500: info.value_text = v info.kind = 2 else: info.value_string = v info.kind = 0 info.save() except: # For now just ignore any kind of error here. # Considering we don't handle metadata as we # should it is not such a problem. pass zf.close() return book
def exportBook(book_version): from booki import bookizip import time starttime = time.time() (zfile, zname) = tempfile.mkstemp() spine = [] toc_top = [] toc_current = toc_top waiting_for_url = [] info = { "version": 1, "TOC": toc_top, "spine": spine, "metadata": _format_metadata(book_version.book), "manifest": {} } bzip = bookizip.BookiZip(zname, info=info) chapter_n = 1 for i, chapter in enumerate( models.BookToc.objects.filter( version=book_version).order_by("-weight")): if chapter.chapter: # It's a real chapter! With content! try: content = _fix_content(book_version.book, chapter, chapter_n) except: continue chapter_n += 1 ID = "ch%03d_%s" % (i, chapter.chapter.url_title.encode('utf-8')) filename = ID + '.html' toc_current.append({ "title": chapter.chapter.title, "url": filename, "type": "chapter", "role": "text" }) # If this is the first chapter in a section, lend our url # to the section, which has no content and thus no url of # its own. If this section was preceded by an empty # section, it will be waiting too, hence "while" rather # than "if". while waiting_for_url: section = waiting_for_url.pop() section["url"] = filename bzip.add_to_package(ID, filename, content, "text/html") spine.append(ID) else: #A new top level section. title = chapter.name.encode("utf-8") ID = "s%03d_%s" % (i, bookiSlugify(title)) toc_current = [] section = { "title": title, "url": '', "type": "booki-section", "children": toc_current } toc_top.append(section) waiting_for_url.append(section) #Attachments are images (and perhaps more). They do not know #whether they are currently in use, or what chapter they belong #to, so we add them all. #XXX scan for img links while adding chapters, and only add those. for i, attachment in enumerate( models.Attachment.objects.filter(version=book_version)): try: f = open(attachment.attachment.name, "rb") blob = f.read() f.close() except (IOError, OSError), e: msg = "couldn't read attachment %s" % e logWarning(msg) continue fn = os.path.basename(attachment.attachment.name.encode("utf-8")) ID = "att%03d_%s" % (i, bookiSlugify(fn)) if '.' in fn: _, ext = fn.rsplit('.', 1) mediatype = bookizip.MEDIATYPES.get(ext.lower(), bookizip.MEDIATYPES[None]) else: mediatype = bookizip.MEDIATYPES[None] bzip.add_to_package(ID, "static/%s" % fn, blob, mediatype)
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
parser.error("You must specify a file name for Wordpress export") # parse the export file # don't really care about validation document = feedparser.parse(args[0]) try: user = User.objects.get(username=options.owner) except User.DoesNotExist: print 'No such user %s' % options.owner sys.exit(-1) if options.title: bookTitle = options.title bookTitleURL = bookiSlugify(options.title) else: bookTitle = document['feed']['title'] if options.url: bookTitleURL = options.url elif not options.title: bookTitleURL = bookiSlugify(document['feed']['title']) # So we don't spend best years of our lives waiting import socket socket.setdefaulttimeout(10) # Import the feed