Module src.generator

Expand source code
from pathlib import Path
import os
import globals
from distutils.dir_util import copy_tree
import shutil
from bson import json_util, ObjectId
import io
import pymongo
import re
from flask_restful import Resource
from webargs.flaskparser import use_kwargs
from webargs import fields
from src import auth
from marshmallow import Schema
from fontTools import ttLib
from contextlib import redirect_stderr
from zipfile import ZipFile, ZIP_DEFLATED

fileOutputFolder = ""
fileRedactedFolder = ""
fileOutputImageFolder = ""
fileOutputFontFolder = ""
fileOutputStylesFolder = ""
fileOutputTextFolder = ""
SAMPLEXHTML = ""
SAMPLECSS = ""
fileOutputOPFFile = ""
fileOutputTocNcxFile = ""
fileOutputTocFile = ""
SAMPLEXHTMLTEXT = ""
SAMPLECSSTEXT = ""
fileOutputBodtFile = ""


# COPY TEMPLATE TO STATIC FOLDER
def templateCopy(fileID):
    """
    Copy the template folder to the output folder, then copy the redacted images to the output folder.

    :param fileID: the file ID of the file being processed
    """
    global fileOutputFolder
    global fileRedactedFolder
    global fileOutputImageFolder
    global fileOutputFontFolder
    global fileOutputStylesFolder
    global fileOutputTextFolder
    global SAMPLEXHTML
    global SAMPLECSS
    global fileOutputOPFFile
    global fileOutputTocNcxFile
    global fileOutputTocFile
    global SAMPLEXHTMLTEXT
    global SAMPLECSSTEXT
    global fileOutputBodtFile

    fileOutputFolder = os.path.join(globals.FILES_FOLDER, fileID, "output")
    fileRedactedFolder = os.path.join(globals.FILES_FOLDER, fileID, "redacted")
    fileOutputImageFolder = os.path.join(
        globals.FILES_FOLDER, fileID, "output", "EPUB", "Images")
    fileOutputFontFolder = os.path.join(
        globals.FILES_FOLDER, fileID, "output", "EPUB", "Fonts")
    fileOutputStylesFolder = os.path.join(
        globals.FILES_FOLDER, fileID, "output", "EPUB", "Styles")
    fileOutputTextFolder = os.path.join(
        globals.FILES_FOLDER, fileID, "output", "EPUB", "Text")

    SAMPLEXHTML = os.path.join(fileOutputTextFolder, "SAMPLE.xhtml")
    SAMPLECSS = os.path.join(fileOutputStylesFolder, "SAMPLE.css")

    fileOutputOPFFile = os.path.join(
        globals.FILES_FOLDER, fileID, "output", "EPUB", "package.opf")
    fileOutputTocNcxFile = os.path.join(
        globals.FILES_FOLDER, fileID, "output", "EPUB", "toc.ncx")
    fileOutputTocFile = os.path.join(
        globals.FILES_FOLDER, fileID, "output", "EPUB", "TOC.xhtml")

    fileOutputBodtFile = os.path.join(fileOutputStylesFolder, "body.css")

    Path(fileOutputFolder).mkdir(parents=True, exist_ok=True)
    Path(fileOutputFontFolder).mkdir(parents=True, exist_ok=True)
    Path(fileOutputStylesFolder).mkdir(parents=True, exist_ok=True)
    Path(fileOutputTextFolder).mkdir(parents=True, exist_ok=True)

    copy_tree(globals.TEMPLATE_FOLDER, fileOutputFolder)

    # COPY REDACTED IMAGES
    copy_tree(os.path.join(globals.FILES_FOLDER,
              fileID, "images"), fileOutputImageFolder)


auth_args = {"Authorization": fields.Str(required=True)}


def valueReplacer(PageNum, pageCSS, pageImg, text, Properties, width, height, TotalPages):
    """
    It takes a string, finds all instances of {{KEY}} and replaces them with the value of the key in the
    Properties dictionary

    :param PageNum: The page number of the current page
    :param pageCSS: The path to the CSS file for the page
    :param pageImg: The path to the image file for the page
    :param text: The text to be replaced
    :param Properties: A list of dictionaries, each dictionary has a key and a value
    :param width: width of the image
    :param height: The height of the page in pixels
    :param TotalPages: Total number of pages in the book
    :return: The text with the values replaced.
    """
    matches = re.finditer(r"{{(\w+)}}", text, re.MULTILINE)
    for matchNum, match in enumerate(matches, start=1):
        for groups in match.groups():
            if groups == "WIDTH":
                value = width

            elif groups == "HEIGHT":
                value = height

            elif groups == "FILE_REL_CSS":
                value = re.sub(r"(.+)Styles", "../Styles",
                               pageCSS.replace("\\", "/"), 0, re.MULTILINE)

            elif groups == "TITLEPAGE_REL_PATH":
                titlepageList = list(
                    filter(lambda d: d['key'] in "TITLEPAGE_NO", Properties))
                titlepageNum = titlepageList[0]["value"] if len(
                    titlepageList) > 0 else ""
                value = "Text/" + \
                    f"page_{str(int(titlepageNum) - 1).zfill(3)}.xhtml"

            elif groups == "CHAPTER1_REL_PATH":
                chapter1List = list(
                    filter(lambda d: d['key'] in "CHAPTER1_NO", Properties))
                chapter1Num = chapter1List[0]["value"] if len(
                    chapter1List) > 0 else ""
                value = "Text/" + \
                    f"page_{str(int(chapter1Num) - 1).zfill(3)}.xhtml"

            elif groups == "COPYRIGHT_REL_PATH":
                copyrightList = list(
                    filter(lambda d: d['key'] in "COPYRIGHT_NO", Properties))
                copyrightNum = copyrightList[0]["value"] if len(
                    copyrightList) > 0 else ""
                value = "Text/" + \
                    f"page_{str(int(copyrightNum) - 1).zfill(3)}.xhtml"

            elif groups == "COVER_REL_PATH":
                value = "Text/cover.xhtml"

            elif groups == "TOTALPAGES":
                value = TotalPages

            elif groups == "RESOLUTION":
                value = str(width) + "x" + str(height)

            elif groups == "IMAGE_URL":
                value = re.sub(r"(.+)Images", "../Images",
                               pageImg.replace("\\", "/"), 0, re.MULTILINE)

            elif groups == "PAGENUM":
                value = int(PageNum) - 1
                if value == 0:
                    value = "cover"
                else:
                    value = str(value).zfill(3)
            elif groups == "BODY_REL_CSS":
                value = "../Styles/body.css"
            else:
                valueList = list(
                    filter(lambda d: d['key'] in groups, Properties))
                value = valueList[0]["value"] if len(valueList) > 0 else ""
            if value != "":
                text = text.replace("{{" + str(groups) + "}}", str(value))
    return text


def font_style(font_path):
    """
    It takes a font file path as an argument, opens the font file, extracts the name table, and returns
    a dictionary of the name table entries

    :param font_path: The path to the font file
    :return: A dictionary of font details.
    """
    font = ttLib.TTFont(font_path, ignoreDecompileErrors=True)
    with redirect_stderr(None):
        names = font['name'].names

    details = {}
    for x in names:
        if x.langID == 0 or x.langID == 1033:
            try:
                details[x.nameID] = str.lower(x.toUnicode())
            except UnicodeDecodeError:
                details[x.nameID] = str.lower(x.string.decode(errors='ignore'))

    return details


def suportingFilesCreation(Properties, width, height, Fonts, TotalPages):
    """
    It creates the supporting files for the EPUB.

    :param Properties: A dictionary of the book's metadata
    :param width: the width of the page in pixels
    :param height: The height of the page in pixels
    :param Fonts: A list of dictionaries, each dictionary containing the following keys:
    :param TotalPages: The number of pages in the PDF
    """
    global fileOutputFolder
    global fileRedactedFolder
    global fileOutputImageFolder
    global fileOutputFontFolder
    global fileOutputStylesFolder
    global fileOutputTextFolder
    global SAMPLEXHTML
    global SAMPLECSS
    global fileOutputOPFFile
    global fileOutputTocNcxFile
    global fileOutputTocFile
    global SAMPLEXHTMLTEXT
    global SAMPLECSSTEXT
    global fileOutputBodtFile
    # TOC.ncx
    with io.open(fileOutputTocNcxFile, 'r', encoding='utf8') as f:
        tocNcxText = f.read()

    tocNcxText = valueReplacer(
        "", "", "", tocNcxText, Properties, width, height, TotalPages)

    with io.open(fileOutputTocNcxFile, 'w', encoding='utf8', newline='\n') as f:
        f.write(tocNcxText.replace("../Text", "Text"))

    # TOC.xHTML
    with io.open(fileOutputTocFile, 'r', encoding='utf8') as f:
        tocXhtmlText = f.read()

    tocXhtmlText = valueReplacer(
        "", "", "", tocXhtmlText, Properties, width, height, TotalPages)

    with io.open(fileOutputTocFile, 'w', encoding='utf8', newline='\n') as f:
        f.write(tocXhtmlText.replace("../Text", "Text"))

    # PACKAGE.OPF
    with io.open(fileOutputOPFFile, 'r', encoding='utf8') as f:
        opfFileText = f.read()

    imgsTemplate = '<item id="{{IMG_ID}}" href="{{IMG_REL_PATH}}" media-type="image/jpeg"/>'
    bodysTemplate = '<item id="BODY{{ID}}" href="{{TEXT_REL_PATH}}" media-type="application/xhtml+xml"/>'
    fontsTemplate = '<item id="font{{FONT_ID}}" href="{{FONT_REL_PATH}}" media-type="application/vnd.ms-opentype"/>'
    bodyRefsTemplate = '<itemref idref="BODY{{ID}}" linear="yes"/>'
    csssTemplate = '<item href="{{CSS_REL_PATH}}" id="{{CSS_FILENAME}}" media-type="text/css" />'

    csss = []
    bodys = []
    imgs = []
    bodyRefs = []
    fonts = []

    for i in range(1, TotalPages + 1):
        coverPage = "cover" if i == 1 else str(i).zfill(3)
        No_of_the_pages = str(i).zfill(3)
        if coverPage == "cover":
            csss.append(csssTemplate
                        .replace("{{CSS_REL_PATH}}", "Styles/body.css")
                        .replace("{{CSS_FILENAME}}", "body.css"))
            csss.append(csssTemplate
                        .replace("{{CSS_REL_PATH}}", "Styles/" + f"{coverPage}.css")
                        .replace("{{CSS_FILENAME}}", f"{coverPage}.css"))

            imgs.append(imgsTemplate
                        .replace("{{IMG_ID}}", "cover-image")
                        .replace("{{IMG_REL_PATH}}", "Images/" + f"{coverPage}.jpg"))
            bodys.append(bodysTemplate
                         .replace("{{ID}}", f"{No_of_the_pages}")
                         .replace("{{TEXT_REL_PATH}}", "Text/" + f"{coverPage}.xhtml"))
        else:
            csss.append(csssTemplate
                        .replace("{{CSS_REL_PATH}}",
                                 "Styles/" + f"page_{str(int(coverPage) - 1).zfill(3)}.css")
                        .replace("{{CSS_FILENAME}}", f"page_{str(int(coverPage) - 1).zfill(3)}.css"))

            imgs.append(imgsTemplate
                        .replace("{{IMG_ID}}", f"img{coverPage}")
                        .replace("{{IMG_REL_PATH}}",
                                 "Images/" + f"page_{str(int(coverPage) - 1).zfill(3)}.jpg"))
            bodys.append(bodysTemplate
                         .replace("{{ID}}", f"{No_of_the_pages}")
                         .replace("{{TEXT_REL_PATH}}",
                                  "Text/" + f"page_{str(int(coverPage) - 1).zfill(3)}.xhtml"))

        bodyRefs.append(bodyRefsTemplate
                        .replace("{{ID}}", f"{No_of_the_pages}"))

    for i in range(0, len(Fonts)):
        fontName = str(Fonts[i]["fontPath"]).replace("\\", "/").split("/")[-1]
        fontOutputPath = os.path.join(fileOutputFontFolder, fontName)
        fontPath = os.path.join(globals.FONT_FOLDER, fontName)
        shutil.copy2(fontPath, fontOutputPath)
        Fonts[i]["FONT_REL_PATH"] = fontOutputPath.replace(
            "\\", "/").split("output/EPUB/")[-1]
        fonts.append(fontsTemplate
                     .replace("{{FONT_ID}}", str(i + 1))
                     .replace("{{FONT_REL_PATH}}", Fonts[i]["FONT_REL_PATH"]))

    opfFileText = opfFileText \
        .replace("<csss/>", "\n".join(csss)) \
        .replace("<imgs/>", "\n".join(imgs)) \
        .replace("<bodys/>", "\n".join(bodys)) \
        .replace("<bodyrefs/>", "\n".join(bodyRefs)) \
        .replace("<fonts/>", "\n".join(fonts))

    opfFileText = valueReplacer(
        "", "", "", opfFileText, Properties, width, height, TotalPages)

    with io.open(fileOutputOPFFile, 'w', encoding='utf8', newline='\n') as f:
        f.write(opfFileText.replace("../Text", "Text"))

    # Body.css

    with io.open(fileOutputBodtFile, 'r', encoding='utf8') as f:
        bodyCssText = f.read()

    fontsCssTemplate = "@font-face {font-family: \"{{FONT_NAME}}\";font-weight: {{FONT_WEIGHT}}; font-style: {{FONT_STYPE}}; src: url({{FONT_URL}});}"
    fontData = []

    # for font in Fonts:
    for fontIndex, font in enumerate(Fonts):
        tempFontData = fontsCssTemplate.replace(
            "{{FONT_URL}}", f'../{font["FONT_REL_PATH"]}').replace("{{FONT_NAME}}", font["fontName"])
        style = font_style(font['fontPath'])
        Fonts[fontIndex]["style"] = style
        if "bold" in style.values() and "italic" in style.values():
            tempFontData = tempFontData.replace(
                "{{FONT_WEIGHT}}", "bold").replace("{{FONT_STYPE}}", "italic")
        elif "bold" in str.lower(font["cssFontName"]) and "italic" in str.lower(font["cssFontName"]):
            tempFontData = tempFontData.replace(
                "{{FONT_WEIGHT}}", "bold").replace("{{FONT_STYPE}}", "italic")
        elif "bold" in style.values():
            tempFontData = tempFontData.replace(
                "{{FONT_WEIGHT}}", "bold").replace("{{FONT_STYPE}}", "normal")
        elif "bold" in str.lower(font["cssFontName"]):
            tempFontData = tempFontData.replace(
                "{{FONT_WEIGHT}}", "bold").replace("{{FONT_STYPE}}", "normal")
        elif "italic" in style.values():
            tempFontData = tempFontData.replace(
                "{{FONT_STYPE}}", "italic").replace("{{FONT_WEIGHT}}", "normal")
        elif "italic" in str.lower(font["cssFontName"]):
            tempFontData = tempFontData.replace(
                "{{FONT_STYPE}}", "italic").replace("{{FONT_WEIGHT}}", "normal")
        else:
            tempFontData = tempFontData.replace(
                "{{FONT_WEIGHT}}", "normal").replace("{{FONT_STYPE}}", "normal")

        fontData.append(tempFontData)

    bodyCssText = valueReplacer("", "", "", bodyCssText, Properties, width, height, TotalPages).replace("{{FONTS_CSS}}",
                                                                                                        "\n".join(fontData))

    with io.open(fileOutputBodtFile, 'w', encoding='utf8', newline='\n') as f:
        f.write(bodyCssText)


def xhtmlAndCssCreation(Properties, Fonts, TotalPages, Pages):
    """
    It takes a bunch of data from a database, and creates a bunch of files.

    :param Properties: A dictionary of properties that are used to replace values in the XHTML and CSS
    files
    :param Fonts: A list of dictionaries, each dictionary containing the following keys:
    :param TotalPages: Total number of pages in the document
    :param Pages: list of pages
    """
    global fileOutputFolder
    global fileRedactedFolder
    global fileOutputImageFolder
    global fileOutputFontFolder
    global fileOutputStylesFolder
    global fileOutputTextFolder
    global SAMPLEXHTML
    global SAMPLECSS
    global fileOutputOPFFile
    global fileOutputTocNcxFile
    global fileOutputTocFile
    global SAMPLEXHTMLTEXT
    global SAMPLECSSTEXT
    global fileOutputBodtFile

    # GENERATING TEXT AND CSS FILES
    with io.open(SAMPLEXHTML, 'r', encoding='utf8') as f:
        SAMPLEXHTMLTEXT = f.read()

    with io.open(SAMPLECSS, 'r', encoding='utf8') as f:
        SAMPLEXCSSTEXT = f.read()

    for page in Pages:
        height = page["Image"]["Height"]
        width = page["Image"]["Width"]
        pageNum = str(page['PageNum'] - 1).zfill(3)
        boxes = list(globals.boxesDB.find(
            {
                "pageId": page["PageID"]
            }
        ).sort([("boxIndex", pymongo.ASCENDING)])
        )
        pageImgTmp = os.path.join(
            fileOutputImageFolder, f"Page{page['PageNum']}.jpeg")
        pageImg = ""
        if page["PageNum"] == 1:
            coverImg = pageImgTmp.replace(
                f"Page{page['PageNum']}.jpeg", "cover.jpg")
            if not os.path.exists(coverImg):
                os.rename(pageImgTmp, coverImg)
            if os.path.exists(pageImgTmp):
                os.remove(pageImgTmp)
            pageImg = coverImg
            pageXhtml = os.path.join(fileOutputTextFolder, "cover.xhtml")
            pageCSS = os.path.join(fileOutputStylesFolder, "cover.css")
            pageXhtmlText = SAMPLEXHTMLTEXT
            pageCSSText = SAMPLEXCSSTEXT
            # coverXhtmlText = coverXhtmlText.replace()
        else:
            pageImg = pageImgTmp.replace(
                f"Page{page['PageNum']}.jpeg", f"page_{pageNum}.jpg")
            if not os.path.exists(pageImg):
                os.rename(pageImgTmp, pageImg)
            if os.path.exists(pageImgTmp):
                os.remove(pageImgTmp)
            pageXhtml = os.path.join(
                fileOutputTextFolder, f"page_{pageNum}.xhtml")
            pageCSS = os.path.join(
                fileOutputStylesFolder, f"page_{pageNum}.css")
            pageXhtmlText = SAMPLEXHTMLTEXT
            pageCSSText = SAMPLEXCSSTEXT

        bodyData = []
        cssData = []
        cssCounter = 0
        lineCssCounter = 0
        for box in boxes:
            pStyle = f'position: absolute;\n' \
                     f'top: {box["coordinates"][1]}px;\n' \
                     f'left: {box["coordinates"][0]}px;\n' \
                     f'width: {width - box["coordinates"][0]}px;\n' \
                     f'height: {box["coordinates"][3]}px;\n'
            lineCssCounter += 1
            lineCssSelector = "line" + str(lineCssCounter)
            cssData.append(f".{lineCssSelector}" + "{\n" + pStyle + "\n}")

            innerHtml = []
            for line in box["linesData"]:
                if "%" not in line["lineHeight"]:
                    line["lineHeight"] += "%"
                innerCssData = f'position: {line["position"]};\n' \
                    f'top: {line["top"]};\n'\
                    f'font-family:##fontfamily##;\n'\
                    f'left: {line["left"]};\n'\
                    f'font-size: {line["fontSize"]};\n'\
                    f'-ms-transform: rotate({line["textRotate"]}deg);\n'\
                    f'-webkit-transform: rotate({line["textRotate"]}deg);\n'\
                    f'transform: rotate({line["textRotate"]}deg);\n'\
                    f'font-weight: ##fontweight##;\n'\
                    f'line-height: {line["lineHeight"].replace("normal%","normal")};\n'\
                    f'color: {line["color"]};\n'\
                    f'word-spacing: {line["wordSpacing"]};\n'\
                    f'letter-spacing: {line["letterSpacing"]};\n'\
                    f'font-style: ##fontstyle##;\n'\
                    f'text-decoration: {line["textDecoration"]};\n'\
                    f'white-space: pre;\n'
                innerCssFontName = list(
                    filter(lambda d: d['cssFontName'] in line["fontFamily"], Fonts))
                if len(innerCssFontName) > 0:
                    if "bold" in innerCssFontName[-1]["style"].values() and "italic" in innerCssFontName[-1]["style"].values():
                        innerCssData = innerCssData.replace("##fontfamily##", innerCssFontName[-1]["fontName"])\
                            .replace("##fontweight##", "bold").replace("##fontstyle##", "italic")

                    elif "bold" in str.lower(innerCssFontName[-1]["cssFontName"]) and "italic" in str.lower(innerCssFontName[-1]["cssFontName"]):
                        innerCssData = innerCssData.replace("##fontfamily##", innerCssFontName[-1]["fontName"]) \
                            .replace("##fontweight##", "bold").replace("##fontstyle##", "italic")

                    elif "bold" in innerCssFontName[-1]["style"].values():
                        innerCssData = innerCssData.replace("##fontfamily##", innerCssFontName[-1]["fontName"]) \
                            .replace("##fontweight##", "bold").replace("##fontstyle##",
                                                                       line["fontStyle"])

                    elif "bold" in str.lower(innerCssFontName[-1]["cssFontName"]):
                        innerCssData = innerCssData.replace("##fontfamily##", innerCssFontName[-1]["fontName"]) \
                            .replace("##fontweight##", "bold").replace("##fontstyle##",
                                                                       line["fontStyle"])

                    elif "italic" in innerCssFontName[-1]["style"].values():
                        innerCssData = innerCssData.replace("##fontfamily##", innerCssFontName[-1]["fontName"]) \
                            .replace("##fontweight##", line["fontWeight"]).replace("##fontstyle##",
                                                                                   "italic")
                    elif "italic" in str.lower(innerCssFontName[-1]["cssFontName"]):
                        innerCssData = innerCssData.replace("##fontfamily##", innerCssFontName[-1]["fontName"]) \
                            .replace("##fontweight##", line["fontWeight"]).replace("##fontstyle##",
                                                                                   "italic")
                    else:
                        innerCssData = innerCssData.replace("##fontfamily##", innerCssFontName[-1]["fontName"]) \
                            .replace("##fontweight##", line["fontWeight"]).replace("##fontstyle##",
                                                                                   line["fontStyle"])
                else:
                    innerCssData = innerCssData.replace("##fontfamily##", line["fontFamily"].strip())\
                        .replace("##fontweight##", "normal").replace("##fontstyle##", "normal")
                cssCounter += 1
                innerCssSelector = "span" + str(cssCounter)
                data = line["text"].replace("\n", "<br>\n")
                line["text"] = re.sub(
                    r"\s{2,}", " ", line["text"], 0, re.MULTILINE)
                innerHtml.append(
                    f'<span class="{innerCssSelector}">{data}</span>')
                if line["br"] is True and "<br>" not in data:
                    innerHtml.append("<br>")
                cssData.append(f".{innerCssSelector}" +
                               "{\n" + innerCssData + "\n}")

            bodyData.append(
                f'<{box["tagName"]} class="{lineCssSelector}">{"".join(innerHtml)}</p>')

        pageXhtmlText = pageXhtmlText.replace(
            "<bodyData/>", "\n".join(bodyData)).replace("<br>", "<br/>")
        cssDataFinal = "\n".join(cssData)
        cssDataFinal = re.sub(
            r"font-family:(.*?);", "font-family:\"\\1\";", cssDataFinal, 0, re.MULTILINE)
        pageCSSText = pageCSSText.replace("{{BODY_CSS}}", cssDataFinal)

        if len(boxes) == 0:
            pageXhtmlText = pageXhtmlText.replace("\n<bodyData/>", "")
            pageCSSText = pageCSSText.replace(
                "{{BODY_CSS}}", "").replace("{{FONTS_CSS}}", "")

        # REPLACING PROPERTIES IN CSS AND XHTML FILES
        if page['PageNum'] == 1:
            pageNum = "cover"
        pageXhtmlText = valueReplacer(page['PageNum'], pageCSS, pageImg, pageXhtmlText, Properties, width, height,
                                      TotalPages)
        pageCSSText = valueReplacer(page['PageNum'], pageCSS, pageImg, pageCSSText, Properties, width, height,
                                    TotalPages)

        with io.open(pageXhtml, 'w', encoding='utf8', newline='\n') as f:
            f.write(pageXhtmlText)

        with io.open(pageCSS, 'w', encoding='utf8', newline='\n') as f:
            f.write(pageCSSText)

    os.remove(SAMPLEXHTML)
    os.remove(SAMPLECSS)


# It takes a fileID as a query parameter, verifies the user's authorization, then creates an epub file
# from the fileID
class GenerateFile(Resource):

    @use_kwargs(auth_args, location="headers")
    @use_kwargs({"fileID": fields.Str(required=True)}, location="query")
    def post(self, Authorization, fileID):
        """
        It takes a fileID, verifies the user's authorization, copies the template, creates supporting
        files, creates xhtml and css files, creates the epub file, and returns the path to the epub
        file.

        :param Authorization: The token that is generated by the auth.py file
        :param fileID: The ID of the file in the database
        :return: The path to the file.
        """
        if auth.verify(str(Authorization).split(" ")[1]):
            templateCopy(fileID)
            result = globals.filesDB.find_one(
                {
                    "_id": ObjectId(fileID)
                }
            )

            TotalPages = result["TotalPages"]
            Pages = result["Pages"]
            Fonts = result["Fonts"]
            Properties = result["Properties"]
            width = result["Pages"][0]["Image"]["Width"]
            height = result["Pages"][0]["Image"]["Height"]
            suportingFilesCreation(
                Properties, width, height, Fonts, TotalPages)
            xhtmlAndCssCreation(Properties, Fonts, TotalPages, Pages)
            isbn = list(filter(lambda d: d['key'] in "ISBN", Properties))
            if len(isbn) > 0:
                isbn = isbn[0]["value"]
            else:
                isbn = "undefined"

            finalFile = os.path.join(fileOutputFolder, f'{isbn}.epub')
            if os.path.exists(finalFile):
                os.remove(finalFile)

            zipobj = ZipFile(finalFile, 'w', ZIP_DEFLATED)
            rootlen = len(fileOutputFolder) + 1
            for base, dirs, files in os.walk(fileOutputFolder):
                for file in files:
                    if ".epub" not in file:
                        fn = os.path.join(base, file)
                        zipobj.write(fn, fn[rootlen:])

            return {"msg": finalFile.replace("\\", "/")}, 200
        else:
            return {"msg": "Unauthorized! Access Denied"}, 401

Functions

def font_style(font_path)

It takes a font file path as an argument, opens the font file, extracts the name table, and returns a dictionary of the name table entries

:param font_path: The path to the font file :return: A dictionary of font details.

Expand source code
def font_style(font_path):
    """
    It takes a font file path as an argument, opens the font file, extracts the name table, and returns
    a dictionary of the name table entries

    :param font_path: The path to the font file
    :return: A dictionary of font details.
    """
    font = ttLib.TTFont(font_path, ignoreDecompileErrors=True)
    with redirect_stderr(None):
        names = font['name'].names

    details = {}
    for x in names:
        if x.langID == 0 or x.langID == 1033:
            try:
                details[x.nameID] = str.lower(x.toUnicode())
            except UnicodeDecodeError:
                details[x.nameID] = str.lower(x.string.decode(errors='ignore'))

    return details
def suportingFilesCreation(Properties, width, height, Fonts, TotalPages)

It creates the supporting files for the EPUB.

:param Properties: A dictionary of the book's metadata :param width: the width of the page in pixels :param height: The height of the page in pixels :param Fonts: A list of dictionaries, each dictionary containing the following keys: :param TotalPages: The number of pages in the PDF

Expand source code
def suportingFilesCreation(Properties, width, height, Fonts, TotalPages):
    """
    It creates the supporting files for the EPUB.

    :param Properties: A dictionary of the book's metadata
    :param width: the width of the page in pixels
    :param height: The height of the page in pixels
    :param Fonts: A list of dictionaries, each dictionary containing the following keys:
    :param TotalPages: The number of pages in the PDF
    """
    global fileOutputFolder
    global fileRedactedFolder
    global fileOutputImageFolder
    global fileOutputFontFolder
    global fileOutputStylesFolder
    global fileOutputTextFolder
    global SAMPLEXHTML
    global SAMPLECSS
    global fileOutputOPFFile
    global fileOutputTocNcxFile
    global fileOutputTocFile
    global SAMPLEXHTMLTEXT
    global SAMPLECSSTEXT
    global fileOutputBodtFile
    # TOC.ncx
    with io.open(fileOutputTocNcxFile, 'r', encoding='utf8') as f:
        tocNcxText = f.read()

    tocNcxText = valueReplacer(
        "", "", "", tocNcxText, Properties, width, height, TotalPages)

    with io.open(fileOutputTocNcxFile, 'w', encoding='utf8', newline='\n') as f:
        f.write(tocNcxText.replace("../Text", "Text"))

    # TOC.xHTML
    with io.open(fileOutputTocFile, 'r', encoding='utf8') as f:
        tocXhtmlText = f.read()

    tocXhtmlText = valueReplacer(
        "", "", "", tocXhtmlText, Properties, width, height, TotalPages)

    with io.open(fileOutputTocFile, 'w', encoding='utf8', newline='\n') as f:
        f.write(tocXhtmlText.replace("../Text", "Text"))

    # PACKAGE.OPF
    with io.open(fileOutputOPFFile, 'r', encoding='utf8') as f:
        opfFileText = f.read()

    imgsTemplate = '<item id="{{IMG_ID}}" href="{{IMG_REL_PATH}}" media-type="image/jpeg"/>'
    bodysTemplate = '<item id="BODY{{ID}}" href="{{TEXT_REL_PATH}}" media-type="application/xhtml+xml"/>'
    fontsTemplate = '<item id="font{{FONT_ID}}" href="{{FONT_REL_PATH}}" media-type="application/vnd.ms-opentype"/>'
    bodyRefsTemplate = '<itemref idref="BODY{{ID}}" linear="yes"/>'
    csssTemplate = '<item href="{{CSS_REL_PATH}}" id="{{CSS_FILENAME}}" media-type="text/css" />'

    csss = []
    bodys = []
    imgs = []
    bodyRefs = []
    fonts = []

    for i in range(1, TotalPages + 1):
        coverPage = "cover" if i == 1 else str(i).zfill(3)
        No_of_the_pages = str(i).zfill(3)
        if coverPage == "cover":
            csss.append(csssTemplate
                        .replace("{{CSS_REL_PATH}}", "Styles/body.css")
                        .replace("{{CSS_FILENAME}}", "body.css"))
            csss.append(csssTemplate
                        .replace("{{CSS_REL_PATH}}", "Styles/" + f"{coverPage}.css")
                        .replace("{{CSS_FILENAME}}", f"{coverPage}.css"))

            imgs.append(imgsTemplate
                        .replace("{{IMG_ID}}", "cover-image")
                        .replace("{{IMG_REL_PATH}}", "Images/" + f"{coverPage}.jpg"))
            bodys.append(bodysTemplate
                         .replace("{{ID}}", f"{No_of_the_pages}")
                         .replace("{{TEXT_REL_PATH}}", "Text/" + f"{coverPage}.xhtml"))
        else:
            csss.append(csssTemplate
                        .replace("{{CSS_REL_PATH}}",
                                 "Styles/" + f"page_{str(int(coverPage) - 1).zfill(3)}.css")
                        .replace("{{CSS_FILENAME}}", f"page_{str(int(coverPage) - 1).zfill(3)}.css"))

            imgs.append(imgsTemplate
                        .replace("{{IMG_ID}}", f"img{coverPage}")
                        .replace("{{IMG_REL_PATH}}",
                                 "Images/" + f"page_{str(int(coverPage) - 1).zfill(3)}.jpg"))
            bodys.append(bodysTemplate
                         .replace("{{ID}}", f"{No_of_the_pages}")
                         .replace("{{TEXT_REL_PATH}}",
                                  "Text/" + f"page_{str(int(coverPage) - 1).zfill(3)}.xhtml"))

        bodyRefs.append(bodyRefsTemplate
                        .replace("{{ID}}", f"{No_of_the_pages}"))

    for i in range(0, len(Fonts)):
        fontName = str(Fonts[i]["fontPath"]).replace("\\", "/").split("/")[-1]
        fontOutputPath = os.path.join(fileOutputFontFolder, fontName)
        fontPath = os.path.join(globals.FONT_FOLDER, fontName)
        shutil.copy2(fontPath, fontOutputPath)
        Fonts[i]["FONT_REL_PATH"] = fontOutputPath.replace(
            "\\", "/").split("output/EPUB/")[-1]
        fonts.append(fontsTemplate
                     .replace("{{FONT_ID}}", str(i + 1))
                     .replace("{{FONT_REL_PATH}}", Fonts[i]["FONT_REL_PATH"]))

    opfFileText = opfFileText \
        .replace("<csss/>", "\n".join(csss)) \
        .replace("<imgs/>", "\n".join(imgs)) \
        .replace("<bodys/>", "\n".join(bodys)) \
        .replace("<bodyrefs/>", "\n".join(bodyRefs)) \
        .replace("<fonts/>", "\n".join(fonts))

    opfFileText = valueReplacer(
        "", "", "", opfFileText, Properties, width, height, TotalPages)

    with io.open(fileOutputOPFFile, 'w', encoding='utf8', newline='\n') as f:
        f.write(opfFileText.replace("../Text", "Text"))

    # Body.css

    with io.open(fileOutputBodtFile, 'r', encoding='utf8') as f:
        bodyCssText = f.read()

    fontsCssTemplate = "@font-face {font-family: \"{{FONT_NAME}}\";font-weight: {{FONT_WEIGHT}}; font-style: {{FONT_STYPE}}; src: url({{FONT_URL}});}"
    fontData = []

    # for font in Fonts:
    for fontIndex, font in enumerate(Fonts):
        tempFontData = fontsCssTemplate.replace(
            "{{FONT_URL}}", f'../{font["FONT_REL_PATH"]}').replace("{{FONT_NAME}}", font["fontName"])
        style = font_style(font['fontPath'])
        Fonts[fontIndex]["style"] = style
        if "bold" in style.values() and "italic" in style.values():
            tempFontData = tempFontData.replace(
                "{{FONT_WEIGHT}}", "bold").replace("{{FONT_STYPE}}", "italic")
        elif "bold" in str.lower(font["cssFontName"]) and "italic" in str.lower(font["cssFontName"]):
            tempFontData = tempFontData.replace(
                "{{FONT_WEIGHT}}", "bold").replace("{{FONT_STYPE}}", "italic")
        elif "bold" in style.values():
            tempFontData = tempFontData.replace(
                "{{FONT_WEIGHT}}", "bold").replace("{{FONT_STYPE}}", "normal")
        elif "bold" in str.lower(font["cssFontName"]):
            tempFontData = tempFontData.replace(
                "{{FONT_WEIGHT}}", "bold").replace("{{FONT_STYPE}}", "normal")
        elif "italic" in style.values():
            tempFontData = tempFontData.replace(
                "{{FONT_STYPE}}", "italic").replace("{{FONT_WEIGHT}}", "normal")
        elif "italic" in str.lower(font["cssFontName"]):
            tempFontData = tempFontData.replace(
                "{{FONT_STYPE}}", "italic").replace("{{FONT_WEIGHT}}", "normal")
        else:
            tempFontData = tempFontData.replace(
                "{{FONT_WEIGHT}}", "normal").replace("{{FONT_STYPE}}", "normal")

        fontData.append(tempFontData)

    bodyCssText = valueReplacer("", "", "", bodyCssText, Properties, width, height, TotalPages).replace("{{FONTS_CSS}}",
                                                                                                        "\n".join(fontData))

    with io.open(fileOutputBodtFile, 'w', encoding='utf8', newline='\n') as f:
        f.write(bodyCssText)
def templateCopy(fileID)

Copy the template folder to the output folder, then copy the redacted images to the output folder.

:param fileID: the file ID of the file being processed

Expand source code
def templateCopy(fileID):
    """
    Copy the template folder to the output folder, then copy the redacted images to the output folder.

    :param fileID: the file ID of the file being processed
    """
    global fileOutputFolder
    global fileRedactedFolder
    global fileOutputImageFolder
    global fileOutputFontFolder
    global fileOutputStylesFolder
    global fileOutputTextFolder
    global SAMPLEXHTML
    global SAMPLECSS
    global fileOutputOPFFile
    global fileOutputTocNcxFile
    global fileOutputTocFile
    global SAMPLEXHTMLTEXT
    global SAMPLECSSTEXT
    global fileOutputBodtFile

    fileOutputFolder = os.path.join(globals.FILES_FOLDER, fileID, "output")
    fileRedactedFolder = os.path.join(globals.FILES_FOLDER, fileID, "redacted")
    fileOutputImageFolder = os.path.join(
        globals.FILES_FOLDER, fileID, "output", "EPUB", "Images")
    fileOutputFontFolder = os.path.join(
        globals.FILES_FOLDER, fileID, "output", "EPUB", "Fonts")
    fileOutputStylesFolder = os.path.join(
        globals.FILES_FOLDER, fileID, "output", "EPUB", "Styles")
    fileOutputTextFolder = os.path.join(
        globals.FILES_FOLDER, fileID, "output", "EPUB", "Text")

    SAMPLEXHTML = os.path.join(fileOutputTextFolder, "SAMPLE.xhtml")
    SAMPLECSS = os.path.join(fileOutputStylesFolder, "SAMPLE.css")

    fileOutputOPFFile = os.path.join(
        globals.FILES_FOLDER, fileID, "output", "EPUB", "package.opf")
    fileOutputTocNcxFile = os.path.join(
        globals.FILES_FOLDER, fileID, "output", "EPUB", "toc.ncx")
    fileOutputTocFile = os.path.join(
        globals.FILES_FOLDER, fileID, "output", "EPUB", "TOC.xhtml")

    fileOutputBodtFile = os.path.join(fileOutputStylesFolder, "body.css")

    Path(fileOutputFolder).mkdir(parents=True, exist_ok=True)
    Path(fileOutputFontFolder).mkdir(parents=True, exist_ok=True)
    Path(fileOutputStylesFolder).mkdir(parents=True, exist_ok=True)
    Path(fileOutputTextFolder).mkdir(parents=True, exist_ok=True)

    copy_tree(globals.TEMPLATE_FOLDER, fileOutputFolder)

    # COPY REDACTED IMAGES
    copy_tree(os.path.join(globals.FILES_FOLDER,
              fileID, "images"), fileOutputImageFolder)
def valueReplacer(PageNum, pageCSS, pageImg, text, Properties, width, height, TotalPages)

It takes a string, finds all instances of {{KEY}} and replaces them with the value of the key in the Properties dictionary

:param PageNum: The page number of the current page :param pageCSS: The path to the CSS file for the page :param pageImg: The path to the image file for the page :param text: The text to be replaced :param Properties: A list of dictionaries, each dictionary has a key and a value :param width: width of the image :param height: The height of the page in pixels :param TotalPages: Total number of pages in the book :return: The text with the values replaced.

Expand source code
def valueReplacer(PageNum, pageCSS, pageImg, text, Properties, width, height, TotalPages):
    """
    It takes a string, finds all instances of {{KEY}} and replaces them with the value of the key in the
    Properties dictionary

    :param PageNum: The page number of the current page
    :param pageCSS: The path to the CSS file for the page
    :param pageImg: The path to the image file for the page
    :param text: The text to be replaced
    :param Properties: A list of dictionaries, each dictionary has a key and a value
    :param width: width of the image
    :param height: The height of the page in pixels
    :param TotalPages: Total number of pages in the book
    :return: The text with the values replaced.
    """
    matches = re.finditer(r"{{(\w+)}}", text, re.MULTILINE)
    for matchNum, match in enumerate(matches, start=1):
        for groups in match.groups():
            if groups == "WIDTH":
                value = width

            elif groups == "HEIGHT":
                value = height

            elif groups == "FILE_REL_CSS":
                value = re.sub(r"(.+)Styles", "../Styles",
                               pageCSS.replace("\\", "/"), 0, re.MULTILINE)

            elif groups == "TITLEPAGE_REL_PATH":
                titlepageList = list(
                    filter(lambda d: d['key'] in "TITLEPAGE_NO", Properties))
                titlepageNum = titlepageList[0]["value"] if len(
                    titlepageList) > 0 else ""
                value = "Text/" + \
                    f"page_{str(int(titlepageNum) - 1).zfill(3)}.xhtml"

            elif groups == "CHAPTER1_REL_PATH":
                chapter1List = list(
                    filter(lambda d: d['key'] in "CHAPTER1_NO", Properties))
                chapter1Num = chapter1List[0]["value"] if len(
                    chapter1List) > 0 else ""
                value = "Text/" + \
                    f"page_{str(int(chapter1Num) - 1).zfill(3)}.xhtml"

            elif groups == "COPYRIGHT_REL_PATH":
                copyrightList = list(
                    filter(lambda d: d['key'] in "COPYRIGHT_NO", Properties))
                copyrightNum = copyrightList[0]["value"] if len(
                    copyrightList) > 0 else ""
                value = "Text/" + \
                    f"page_{str(int(copyrightNum) - 1).zfill(3)}.xhtml"

            elif groups == "COVER_REL_PATH":
                value = "Text/cover.xhtml"

            elif groups == "TOTALPAGES":
                value = TotalPages

            elif groups == "RESOLUTION":
                value = str(width) + "x" + str(height)

            elif groups == "IMAGE_URL":
                value = re.sub(r"(.+)Images", "../Images",
                               pageImg.replace("\\", "/"), 0, re.MULTILINE)

            elif groups == "PAGENUM":
                value = int(PageNum) - 1
                if value == 0:
                    value = "cover"
                else:
                    value = str(value).zfill(3)
            elif groups == "BODY_REL_CSS":
                value = "../Styles/body.css"
            else:
                valueList = list(
                    filter(lambda d: d['key'] in groups, Properties))
                value = valueList[0]["value"] if len(valueList) > 0 else ""
            if value != "":
                text = text.replace("{{" + str(groups) + "}}", str(value))
    return text
def xhtmlAndCssCreation(Properties, Fonts, TotalPages, Pages)

It takes a bunch of data from a database, and creates a bunch of files.

:param Properties: A dictionary of properties that are used to replace values in the XHTML and CSS files :param Fonts: A list of dictionaries, each dictionary containing the following keys: :param TotalPages: Total number of pages in the document :param Pages: list of pages

Expand source code
def xhtmlAndCssCreation(Properties, Fonts, TotalPages, Pages):
    """
    It takes a bunch of data from a database, and creates a bunch of files.

    :param Properties: A dictionary of properties that are used to replace values in the XHTML and CSS
    files
    :param Fonts: A list of dictionaries, each dictionary containing the following keys:
    :param TotalPages: Total number of pages in the document
    :param Pages: list of pages
    """
    global fileOutputFolder
    global fileRedactedFolder
    global fileOutputImageFolder
    global fileOutputFontFolder
    global fileOutputStylesFolder
    global fileOutputTextFolder
    global SAMPLEXHTML
    global SAMPLECSS
    global fileOutputOPFFile
    global fileOutputTocNcxFile
    global fileOutputTocFile
    global SAMPLEXHTMLTEXT
    global SAMPLECSSTEXT
    global fileOutputBodtFile

    # GENERATING TEXT AND CSS FILES
    with io.open(SAMPLEXHTML, 'r', encoding='utf8') as f:
        SAMPLEXHTMLTEXT = f.read()

    with io.open(SAMPLECSS, 'r', encoding='utf8') as f:
        SAMPLEXCSSTEXT = f.read()

    for page in Pages:
        height = page["Image"]["Height"]
        width = page["Image"]["Width"]
        pageNum = str(page['PageNum'] - 1).zfill(3)
        boxes = list(globals.boxesDB.find(
            {
                "pageId": page["PageID"]
            }
        ).sort([("boxIndex", pymongo.ASCENDING)])
        )
        pageImgTmp = os.path.join(
            fileOutputImageFolder, f"Page{page['PageNum']}.jpeg")
        pageImg = ""
        if page["PageNum"] == 1:
            coverImg = pageImgTmp.replace(
                f"Page{page['PageNum']}.jpeg", "cover.jpg")
            if not os.path.exists(coverImg):
                os.rename(pageImgTmp, coverImg)
            if os.path.exists(pageImgTmp):
                os.remove(pageImgTmp)
            pageImg = coverImg
            pageXhtml = os.path.join(fileOutputTextFolder, "cover.xhtml")
            pageCSS = os.path.join(fileOutputStylesFolder, "cover.css")
            pageXhtmlText = SAMPLEXHTMLTEXT
            pageCSSText = SAMPLEXCSSTEXT
            # coverXhtmlText = coverXhtmlText.replace()
        else:
            pageImg = pageImgTmp.replace(
                f"Page{page['PageNum']}.jpeg", f"page_{pageNum}.jpg")
            if not os.path.exists(pageImg):
                os.rename(pageImgTmp, pageImg)
            if os.path.exists(pageImgTmp):
                os.remove(pageImgTmp)
            pageXhtml = os.path.join(
                fileOutputTextFolder, f"page_{pageNum}.xhtml")
            pageCSS = os.path.join(
                fileOutputStylesFolder, f"page_{pageNum}.css")
            pageXhtmlText = SAMPLEXHTMLTEXT
            pageCSSText = SAMPLEXCSSTEXT

        bodyData = []
        cssData = []
        cssCounter = 0
        lineCssCounter = 0
        for box in boxes:
            pStyle = f'position: absolute;\n' \
                     f'top: {box["coordinates"][1]}px;\n' \
                     f'left: {box["coordinates"][0]}px;\n' \
                     f'width: {width - box["coordinates"][0]}px;\n' \
                     f'height: {box["coordinates"][3]}px;\n'
            lineCssCounter += 1
            lineCssSelector = "line" + str(lineCssCounter)
            cssData.append(f".{lineCssSelector}" + "{\n" + pStyle + "\n}")

            innerHtml = []
            for line in box["linesData"]:
                if "%" not in line["lineHeight"]:
                    line["lineHeight"] += "%"
                innerCssData = f'position: {line["position"]};\n' \
                    f'top: {line["top"]};\n'\
                    f'font-family:##fontfamily##;\n'\
                    f'left: {line["left"]};\n'\
                    f'font-size: {line["fontSize"]};\n'\
                    f'-ms-transform: rotate({line["textRotate"]}deg);\n'\
                    f'-webkit-transform: rotate({line["textRotate"]}deg);\n'\
                    f'transform: rotate({line["textRotate"]}deg);\n'\
                    f'font-weight: ##fontweight##;\n'\
                    f'line-height: {line["lineHeight"].replace("normal%","normal")};\n'\
                    f'color: {line["color"]};\n'\
                    f'word-spacing: {line["wordSpacing"]};\n'\
                    f'letter-spacing: {line["letterSpacing"]};\n'\
                    f'font-style: ##fontstyle##;\n'\
                    f'text-decoration: {line["textDecoration"]};\n'\
                    f'white-space: pre;\n'
                innerCssFontName = list(
                    filter(lambda d: d['cssFontName'] in line["fontFamily"], Fonts))
                if len(innerCssFontName) > 0:
                    if "bold" in innerCssFontName[-1]["style"].values() and "italic" in innerCssFontName[-1]["style"].values():
                        innerCssData = innerCssData.replace("##fontfamily##", innerCssFontName[-1]["fontName"])\
                            .replace("##fontweight##", "bold").replace("##fontstyle##", "italic")

                    elif "bold" in str.lower(innerCssFontName[-1]["cssFontName"]) and "italic" in str.lower(innerCssFontName[-1]["cssFontName"]):
                        innerCssData = innerCssData.replace("##fontfamily##", innerCssFontName[-1]["fontName"]) \
                            .replace("##fontweight##", "bold").replace("##fontstyle##", "italic")

                    elif "bold" in innerCssFontName[-1]["style"].values():
                        innerCssData = innerCssData.replace("##fontfamily##", innerCssFontName[-1]["fontName"]) \
                            .replace("##fontweight##", "bold").replace("##fontstyle##",
                                                                       line["fontStyle"])

                    elif "bold" in str.lower(innerCssFontName[-1]["cssFontName"]):
                        innerCssData = innerCssData.replace("##fontfamily##", innerCssFontName[-1]["fontName"]) \
                            .replace("##fontweight##", "bold").replace("##fontstyle##",
                                                                       line["fontStyle"])

                    elif "italic" in innerCssFontName[-1]["style"].values():
                        innerCssData = innerCssData.replace("##fontfamily##", innerCssFontName[-1]["fontName"]) \
                            .replace("##fontweight##", line["fontWeight"]).replace("##fontstyle##",
                                                                                   "italic")
                    elif "italic" in str.lower(innerCssFontName[-1]["cssFontName"]):
                        innerCssData = innerCssData.replace("##fontfamily##", innerCssFontName[-1]["fontName"]) \
                            .replace("##fontweight##", line["fontWeight"]).replace("##fontstyle##",
                                                                                   "italic")
                    else:
                        innerCssData = innerCssData.replace("##fontfamily##", innerCssFontName[-1]["fontName"]) \
                            .replace("##fontweight##", line["fontWeight"]).replace("##fontstyle##",
                                                                                   line["fontStyle"])
                else:
                    innerCssData = innerCssData.replace("##fontfamily##", line["fontFamily"].strip())\
                        .replace("##fontweight##", "normal").replace("##fontstyle##", "normal")
                cssCounter += 1
                innerCssSelector = "span" + str(cssCounter)
                data = line["text"].replace("\n", "<br>\n")
                line["text"] = re.sub(
                    r"\s{2,}", " ", line["text"], 0, re.MULTILINE)
                innerHtml.append(
                    f'<span class="{innerCssSelector}">{data}</span>')
                if line["br"] is True and "<br>" not in data:
                    innerHtml.append("<br>")
                cssData.append(f".{innerCssSelector}" +
                               "{\n" + innerCssData + "\n}")

            bodyData.append(
                f'<{box["tagName"]} class="{lineCssSelector}">{"".join(innerHtml)}</p>')

        pageXhtmlText = pageXhtmlText.replace(
            "<bodyData/>", "\n".join(bodyData)).replace("<br>", "<br/>")
        cssDataFinal = "\n".join(cssData)
        cssDataFinal = re.sub(
            r"font-family:(.*?);", "font-family:\"\\1\";", cssDataFinal, 0, re.MULTILINE)
        pageCSSText = pageCSSText.replace("{{BODY_CSS}}", cssDataFinal)

        if len(boxes) == 0:
            pageXhtmlText = pageXhtmlText.replace("\n<bodyData/>", "")
            pageCSSText = pageCSSText.replace(
                "{{BODY_CSS}}", "").replace("{{FONTS_CSS}}", "")

        # REPLACING PROPERTIES IN CSS AND XHTML FILES
        if page['PageNum'] == 1:
            pageNum = "cover"
        pageXhtmlText = valueReplacer(page['PageNum'], pageCSS, pageImg, pageXhtmlText, Properties, width, height,
                                      TotalPages)
        pageCSSText = valueReplacer(page['PageNum'], pageCSS, pageImg, pageCSSText, Properties, width, height,
                                    TotalPages)

        with io.open(pageXhtml, 'w', encoding='utf8', newline='\n') as f:
            f.write(pageXhtmlText)

        with io.open(pageCSS, 'w', encoding='utf8', newline='\n') as f:
            f.write(pageCSSText)

    os.remove(SAMPLEXHTML)
    os.remove(SAMPLECSS)

Classes

class GenerateFile

Represents an abstract RESTful resource. Concrete resources should extend from this class and expose methods for each supported HTTP method. If a resource is invoked with an unsupported HTTP method, the API will return a response with status 405 Method Not Allowed. Otherwise the appropriate method is called and passed all arguments from the url rule used when adding the resource to an Api instance. See :meth:~flask_restful.Api.add_resource for details.

Expand source code
class GenerateFile(Resource):

    @use_kwargs(auth_args, location="headers")
    @use_kwargs({"fileID": fields.Str(required=True)}, location="query")
    def post(self, Authorization, fileID):
        """
        It takes a fileID, verifies the user's authorization, copies the template, creates supporting
        files, creates xhtml and css files, creates the epub file, and returns the path to the epub
        file.

        :param Authorization: The token that is generated by the auth.py file
        :param fileID: The ID of the file in the database
        :return: The path to the file.
        """
        if auth.verify(str(Authorization).split(" ")[1]):
            templateCopy(fileID)
            result = globals.filesDB.find_one(
                {
                    "_id": ObjectId(fileID)
                }
            )

            TotalPages = result["TotalPages"]
            Pages = result["Pages"]
            Fonts = result["Fonts"]
            Properties = result["Properties"]
            width = result["Pages"][0]["Image"]["Width"]
            height = result["Pages"][0]["Image"]["Height"]
            suportingFilesCreation(
                Properties, width, height, Fonts, TotalPages)
            xhtmlAndCssCreation(Properties, Fonts, TotalPages, Pages)
            isbn = list(filter(lambda d: d['key'] in "ISBN", Properties))
            if len(isbn) > 0:
                isbn = isbn[0]["value"]
            else:
                isbn = "undefined"

            finalFile = os.path.join(fileOutputFolder, f'{isbn}.epub')
            if os.path.exists(finalFile):
                os.remove(finalFile)

            zipobj = ZipFile(finalFile, 'w', ZIP_DEFLATED)
            rootlen = len(fileOutputFolder) + 1
            for base, dirs, files in os.walk(fileOutputFolder):
                for file in files:
                    if ".epub" not in file:
                        fn = os.path.join(base, file)
                        zipobj.write(fn, fn[rootlen:])

            return {"msg": finalFile.replace("\\", "/")}, 200
        else:
            return {"msg": "Unauthorized! Access Denied"}, 401

Ancestors

  • flask_restful.Resource
  • flask.views.MethodView
  • flask.views.View

Class variables

var methods : Optional[List[str]]

Methods

def post(self, Authorization, fileID)

It takes a fileID, verifies the user's authorization, copies the template, creates supporting files, creates xhtml and css files, creates the epub file, and returns the path to the epub file.

:param Authorization: The token that is generated by the auth.py file :param fileID: The ID of the file in the database :return: The path to the file.

Expand source code
@use_kwargs(auth_args, location="headers")
@use_kwargs({"fileID": fields.Str(required=True)}, location="query")
def post(self, Authorization, fileID):
    """
    It takes a fileID, verifies the user's authorization, copies the template, creates supporting
    files, creates xhtml and css files, creates the epub file, and returns the path to the epub
    file.

    :param Authorization: The token that is generated by the auth.py file
    :param fileID: The ID of the file in the database
    :return: The path to the file.
    """
    if auth.verify(str(Authorization).split(" ")[1]):
        templateCopy(fileID)
        result = globals.filesDB.find_one(
            {
                "_id": ObjectId(fileID)
            }
        )

        TotalPages = result["TotalPages"]
        Pages = result["Pages"]
        Fonts = result["Fonts"]
        Properties = result["Properties"]
        width = result["Pages"][0]["Image"]["Width"]
        height = result["Pages"][0]["Image"]["Height"]
        suportingFilesCreation(
            Properties, width, height, Fonts, TotalPages)
        xhtmlAndCssCreation(Properties, Fonts, TotalPages, Pages)
        isbn = list(filter(lambda d: d['key'] in "ISBN", Properties))
        if len(isbn) > 0:
            isbn = isbn[0]["value"]
        else:
            isbn = "undefined"

        finalFile = os.path.join(fileOutputFolder, f'{isbn}.epub')
        if os.path.exists(finalFile):
            os.remove(finalFile)

        zipobj = ZipFile(finalFile, 'w', ZIP_DEFLATED)
        rootlen = len(fileOutputFolder) + 1
        for base, dirs, files in os.walk(fileOutputFolder):
            for file in files:
                if ".epub" not in file:
                    fn = os.path.join(base, file)
                    zipobj.write(fn, fn[rootlen:])

        return {"msg": finalFile.replace("\\", "/")}, 200
    else:
        return {"msg": "Unauthorized! Access Denied"}, 401