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_resourcefor 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"}, 401Ancestors
- 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