Module src.font
Expand source code
from flask_restful import Resource
from werkzeug.utils import secure_filename
import globals
import os
from src import auth
from fontTools import ttLib
from contextlib import redirect_stderr
from webargs.flaskparser import use_kwargs, parser, abort
from webargs import fields
from bson import json_util, ObjectId
import json
fontsDB = globals.fontsDB
auth_args = {"Authorization": fields.Str(required=True)}
def font_name(font_path):
"""
It takes a font file path as an argument, opens the font file, reads the name table, and returns the
font name.
:param font_path: The path to the font file
:return: The name of the font.
"""
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] = x.toUnicode()
except UnicodeDecodeError:
details[x.nameID] = x.string.decode(errors='ignore')
return details[4]
# class Uploads
# I want to upload a font file and save it to a folder
class FontUpload(Resource):
# A dictionary that contains a key called fonts. The value of the fonts key is a field object. The
# field object has a validate method that takes a function as an argument. The function takes a
# file as an argument and returns a boolean value. The boolean value is true if the file extension
# is one of the extensions in the list. The field object also has a required method that takes a
# boolean value as an argument. The boolean value is true if the file is required.
files_args = {"fonts": fields.Field(validate=lambda file: file.filename.split(
".")[-1].lower() in ["ttf", "otf", "woff", "woff2", "eot", "fnt"], required=True)}
fontName = {"fontname": fields.Str(required=True)}
# A decorator that is used to validate the files that are being uploaded.
@use_kwargs(files_args, location="files")
# A decorator that is used to validate the Authorization header.
@use_kwargs(auth_args, location="headers")
# A decorator that is used to validate the fontName argument.
@use_kwargs(fontName, location="form")
def post(self, Authorization, fonts, fontname):
"""
It takes a file, saves it to a temporary folder, checks if the file already exists in the
database, if it doesn't, it moves the file to the main folder, and then adds it to the database
:param Authorization: This is the token that is generated when the user logs in
:param fonts: The file that is being uploaded
:param fontname: The name of the font you want to use
:return: The return value is a tuple of the form (response, status, headers)
"""
if auth.verify(str(Authorization).split(" ")[1]):
savefonts = []
filename = secure_filename(fonts.filename)
tmpFilepath = os.path.join(globals.FONT_FOLDER, "tmp", filename)
if not os.path.exists(tmpFilepath):
fonts.save(tmpFilepath)
fontName = font_name(tmpFilepath)
existing = fontsDB.find_one({"name": fontName})
if not existing:
filepath = os.path.join(globals.FONT_FOLDER, filename)
os.rename(tmpFilepath, filepath)
if fontname:
inserted_id = str(fontsDB.insert_one(
{"name": fontName, "path": filepath, "alias": [fontName, fontname]}).inserted_id)
return {"id": inserted_id, "name": fontName, "path": filepath}, 200
else:
inserted_id = str(fontsDB.insert_one(
{"name": fontName, "path": filepath, "alias": [fontName]}).inserted_id)
return {"id": inserted_id, "name": fontName, "path": filepath}, 200
else:
return {"msg": "Files Already Exist"}, 201
else:
return {"msg": "Files Already Exist"}, 201
else:
return "Unauthorized! Access Denied", 401
# It's a class that inherits from the Resource class of the Flask-RESTful library. It has a get method
# that takes in two arguments: Authorization and searchPhase. The Authorization argument is a header
# that is passed in the request. The searchPhase argument is a query parameter that is passed in the
# request. The get method returns a JSON response
class GetFont(Resource):
# A dictionary that contains a key called searchPhase. The value of the searchPhase key is a field
# object. The field object has a required method that takes a boolean value as an argument. The
# boolean value is true if the searchPhase is required.
search_arg = {"searchPhase": fields.Str(required=True)}
@use_kwargs(auth_args, location="headers")
@use_kwargs(search_arg, location="query")
def get(self, Authorization, searchPhase):
"""
It searches for a font in the database and returns it if it exists
:param Authorization: Bearer
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaWF0IjoxNTg0
:param searchPhase: the search term
:return: A list of fonts that match the searchPhase.
"""
if auth.verify(str(Authorization).split(" ")[1]):
fonts = list(fontsDB.find({"$or": [
{'name': {'$regex': searchPhase, "$options": 'i'}},
{'alias': {'$regex': searchPhase, "$options": 'i'}}
]}))
return json.loads(json_util.dumps(fonts)), 200, {'Access-Control-Allow-Origin': '*'}
else:
return "Unauthorized! Access Denied", 401, {'Access-Control-Allow-Origin': '*'}
# This class is used to delete a font from the database
class deleteFont(Resource):
# A dictionary that contains a key called id. The value of the id key is a field object. The field
# object has a required method that takes a boolean value as an argument. The boolean value is
# true if the id is required.
search_arg = {"id": fields.Str(required=True)}
# A decorator that is used to validate the Authorization header.
@use_kwargs(auth_args, location="headers")
# A decorator that is used to validate the searchPhase argument.
@use_kwargs(search_arg, location="query")
def delete(self, Authorization, id):
"""
It deletes a font from the database
:param Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NzUwMzUwMjIsIm5iZ
:param id: The id of the font to be deleted
:return: The response is a JSON object with the following properties:
"""
if auth.verify(str(Authorization).split(" ")[1]):
fonts = fontsDB.delete_one({"_id": ObjectId(id)})
return json.loads(json_util.dumps(fonts)), 200
else:
return "Unauthorized! Access Denied", 401
# This error handler is necessary for usage with Flask-RESTful
@parser.error_handler
def handle_request_parsing_error(err, req, schema, *, error_status_code, error_headers):
"""webargs error handler that uses Flask-RESTful's abort function to return
a JSON error response to the client.
"""
if not error_status_code:
abort(400, errors=err.messages)
else:
abort(error_status_code, errors=err.messages)
Functions
def font_name(font_path)-
It takes a font file path as an argument, opens the font file, reads the name table, and returns the font name.
:param font_path: The path to the font file :return: The name of the font.
Expand source code
def font_name(font_path): """ It takes a font file path as an argument, opens the font file, reads the name table, and returns the font name. :param font_path: The path to the font file :return: The name of the font. """ 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] = x.toUnicode() except UnicodeDecodeError: details[x.nameID] = x.string.decode(errors='ignore') return details[4] def handle_request_parsing_error(err, req, schema, *, error_status_code, error_headers)-
webargs error handler that uses Flask-RESTful's abort function to return a JSON error response to the client.
Expand source code
@parser.error_handler def handle_request_parsing_error(err, req, schema, *, error_status_code, error_headers): """webargs error handler that uses Flask-RESTful's abort function to return a JSON error response to the client. """ if not error_status_code: abort(400, errors=err.messages) else: abort(error_status_code, errors=err.messages)
Classes
class FontUpload-
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 FontUpload(Resource): # A dictionary that contains a key called fonts. The value of the fonts key is a field object. The # field object has a validate method that takes a function as an argument. The function takes a # file as an argument and returns a boolean value. The boolean value is true if the file extension # is one of the extensions in the list. The field object also has a required method that takes a # boolean value as an argument. The boolean value is true if the file is required. files_args = {"fonts": fields.Field(validate=lambda file: file.filename.split( ".")[-1].lower() in ["ttf", "otf", "woff", "woff2", "eot", "fnt"], required=True)} fontName = {"fontname": fields.Str(required=True)} # A decorator that is used to validate the files that are being uploaded. @use_kwargs(files_args, location="files") # A decorator that is used to validate the Authorization header. @use_kwargs(auth_args, location="headers") # A decorator that is used to validate the fontName argument. @use_kwargs(fontName, location="form") def post(self, Authorization, fonts, fontname): """ It takes a file, saves it to a temporary folder, checks if the file already exists in the database, if it doesn't, it moves the file to the main folder, and then adds it to the database :param Authorization: This is the token that is generated when the user logs in :param fonts: The file that is being uploaded :param fontname: The name of the font you want to use :return: The return value is a tuple of the form (response, status, headers) """ if auth.verify(str(Authorization).split(" ")[1]): savefonts = [] filename = secure_filename(fonts.filename) tmpFilepath = os.path.join(globals.FONT_FOLDER, "tmp", filename) if not os.path.exists(tmpFilepath): fonts.save(tmpFilepath) fontName = font_name(tmpFilepath) existing = fontsDB.find_one({"name": fontName}) if not existing: filepath = os.path.join(globals.FONT_FOLDER, filename) os.rename(tmpFilepath, filepath) if fontname: inserted_id = str(fontsDB.insert_one( {"name": fontName, "path": filepath, "alias": [fontName, fontname]}).inserted_id) return {"id": inserted_id, "name": fontName, "path": filepath}, 200 else: inserted_id = str(fontsDB.insert_one( {"name": fontName, "path": filepath, "alias": [fontName]}).inserted_id) return {"id": inserted_id, "name": fontName, "path": filepath}, 200 else: return {"msg": "Files Already Exist"}, 201 else: return {"msg": "Files Already Exist"}, 201 else: return "Unauthorized! Access Denied", 401Ancestors
- flask_restful.Resource
- flask.views.MethodView
- flask.views.View
Class variables
var files_argsvar fontNamevar methods : Optional[List[str]]
Methods
def post(self, Authorization, fonts, fontname)-
It takes a file, saves it to a temporary folder, checks if the file already exists in the database, if it doesn't, it moves the file to the main folder, and then adds it to the database
:param Authorization: This is the token that is generated when the user logs in :param fonts: The file that is being uploaded :param fontname: The name of the font you want to use :return: The return value is a tuple of the form (response, status, headers)
Expand source code
@use_kwargs(files_args, location="files") # A decorator that is used to validate the Authorization header. @use_kwargs(auth_args, location="headers") # A decorator that is used to validate the fontName argument. @use_kwargs(fontName, location="form") def post(self, Authorization, fonts, fontname): """ It takes a file, saves it to a temporary folder, checks if the file already exists in the database, if it doesn't, it moves the file to the main folder, and then adds it to the database :param Authorization: This is the token that is generated when the user logs in :param fonts: The file that is being uploaded :param fontname: The name of the font you want to use :return: The return value is a tuple of the form (response, status, headers) """ if auth.verify(str(Authorization).split(" ")[1]): savefonts = [] filename = secure_filename(fonts.filename) tmpFilepath = os.path.join(globals.FONT_FOLDER, "tmp", filename) if not os.path.exists(tmpFilepath): fonts.save(tmpFilepath) fontName = font_name(tmpFilepath) existing = fontsDB.find_one({"name": fontName}) if not existing: filepath = os.path.join(globals.FONT_FOLDER, filename) os.rename(tmpFilepath, filepath) if fontname: inserted_id = str(fontsDB.insert_one( {"name": fontName, "path": filepath, "alias": [fontName, fontname]}).inserted_id) return {"id": inserted_id, "name": fontName, "path": filepath}, 200 else: inserted_id = str(fontsDB.insert_one( {"name": fontName, "path": filepath, "alias": [fontName]}).inserted_id) return {"id": inserted_id, "name": fontName, "path": filepath}, 200 else: return {"msg": "Files Already Exist"}, 201 else: return {"msg": "Files Already Exist"}, 201 else: return "Unauthorized! Access Denied", 401
class GetFont-
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 GetFont(Resource): # A dictionary that contains a key called searchPhase. The value of the searchPhase key is a field # object. The field object has a required method that takes a boolean value as an argument. The # boolean value is true if the searchPhase is required. search_arg = {"searchPhase": fields.Str(required=True)} @use_kwargs(auth_args, location="headers") @use_kwargs(search_arg, location="query") def get(self, Authorization, searchPhase): """ It searches for a font in the database and returns it if it exists :param Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaWF0IjoxNTg0 :param searchPhase: the search term :return: A list of fonts that match the searchPhase. """ if auth.verify(str(Authorization).split(" ")[1]): fonts = list(fontsDB.find({"$or": [ {'name': {'$regex': searchPhase, "$options": 'i'}}, {'alias': {'$regex': searchPhase, "$options": 'i'}} ]})) return json.loads(json_util.dumps(fonts)), 200, {'Access-Control-Allow-Origin': '*'} else: return "Unauthorized! Access Denied", 401, {'Access-Control-Allow-Origin': '*'}Ancestors
- flask_restful.Resource
- flask.views.MethodView
- flask.views.View
Class variables
var methods : Optional[List[str]]var search_arg
Methods
def get(self, Authorization, searchPhase)-
It searches for a font in the database and returns it if it exists
:param Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaWF0IjoxNTg0 :param searchPhase: the search term :return: A list of fonts that match the searchPhase.
Expand source code
@use_kwargs(auth_args, location="headers") @use_kwargs(search_arg, location="query") def get(self, Authorization, searchPhase): """ It searches for a font in the database and returns it if it exists :param Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaWF0IjoxNTg0 :param searchPhase: the search term :return: A list of fonts that match the searchPhase. """ if auth.verify(str(Authorization).split(" ")[1]): fonts = list(fontsDB.find({"$or": [ {'name': {'$regex': searchPhase, "$options": 'i'}}, {'alias': {'$regex': searchPhase, "$options": 'i'}} ]})) return json.loads(json_util.dumps(fonts)), 200, {'Access-Control-Allow-Origin': '*'} else: return "Unauthorized! Access Denied", 401, {'Access-Control-Allow-Origin': '*'}
class deleteFont-
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 deleteFont(Resource): # A dictionary that contains a key called id. The value of the id key is a field object. The field # object has a required method that takes a boolean value as an argument. The boolean value is # true if the id is required. search_arg = {"id": fields.Str(required=True)} # A decorator that is used to validate the Authorization header. @use_kwargs(auth_args, location="headers") # A decorator that is used to validate the searchPhase argument. @use_kwargs(search_arg, location="query") def delete(self, Authorization, id): """ It deletes a font from the database :param Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NzUwMzUwMjIsIm5iZ :param id: The id of the font to be deleted :return: The response is a JSON object with the following properties: """ if auth.verify(str(Authorization).split(" ")[1]): fonts = fontsDB.delete_one({"_id": ObjectId(id)}) return json.loads(json_util.dumps(fonts)), 200 else: return "Unauthorized! Access Denied", 401Ancestors
- flask_restful.Resource
- flask.views.MethodView
- flask.views.View
Class variables
var methods : Optional[List[str]]var search_arg
Methods
def delete(self, Authorization, id)-
It deletes a font from the database
:param Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NzUwMzUwMjIsIm5iZ :param id: The id of the font to be deleted :return: The response is a JSON object with the following properties:
Expand source code
@use_kwargs(auth_args, location="headers") # A decorator that is used to validate the searchPhase argument. @use_kwargs(search_arg, location="query") def delete(self, Authorization, id): """ It deletes a font from the database :param Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NzUwMzUwMjIsIm5iZ :param id: The id of the font to be deleted :return: The response is a JSON object with the following properties: """ if auth.verify(str(Authorization).split(" ")[1]): fonts = fontsDB.delete_one({"_id": ObjectId(id)}) return json.loads(json_util.dumps(fonts)), 200 else: return "Unauthorized! Access Denied", 401