diff --git a/Pipfile b/Pipfile index 1c32131..64e3eb9 100644 --- a/Pipfile +++ b/Pipfile @@ -23,6 +23,7 @@ python-dotenv = "*" flask-migrate = "*" gunicorn = "*" requests = "*" +python-slugify = "*" [requires] python_version = "3.8" diff --git a/Pipfile.lock b/Pipfile.lock index e38f7bb..a6b5183 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "310d4c46b57ab0c77827c9060910b5e9d0408c96edc0a8bcc87ae8ab67d0414e" + "sha256": "a173b01cae7656ecc57f0002fd3bbe63c7168b40a0b114c3b716ca372234b0a0" }, "pipfile-spec": 6, "requires": { @@ -68,25 +68,24 @@ }, "boto3": { "hashes": [ - "sha256:57397f9ad3e9afc17e6100a38c6e631b6545aabc7f8c38b86ff2c6f5931d0ebf", - "sha256:911994ef46595e8ab9f08eee6b666caea050937b96d54394292e958330cd7ad5" + "sha256:4f7f11e7489c267f9ea0c6193bfbe20ef1a8dd639d780aea0ac61a769de722e1" ], "index": "pypi", - "version": "==1.12.36" + "version": "==1.12.46" }, "botocore": { "hashes": [ - "sha256:5fc5e8629b5375d591a47d05baaff6ccdf5c3b617aad1e14286be458092c9e53", - "sha256:d2233e19b6a60792185b15fe4cd8f92c5579298e5079daf17f66f6e639585e3a" + "sha256:ae39899dc450570968e3e128d2c8a011e5f8d4f6fd07a7d1f01df10a11ef332d", + "sha256:b609e2373dccb728b34555af28fd8bd87cc57295cafa32f8a5b8044bb58b9ea8" ], - "version": "==1.15.36" + "version": "==1.15.46" }, "certifi": { "hashes": [ - "sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3", - "sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f" + "sha256:1d987a998c75633c40847cc966fcf5904906c920a7f17ef374f5aa4282abd304", + "sha256:51fcb31174be6e6664c5f69e3e1691a2d72a1a12e90f872cbdb1567eb47b6519" ], - "version": "==2019.11.28" + "version": "==2020.4.5.1" }, "cffi": { "hashes": [ @@ -135,6 +134,13 @@ ], "version": "==7.1.1" }, + "deprecated": { + "hashes": [ + "sha256:0cf37d293a96805c6afd8b5fc525cb40f23a2cac9b2d066ac3bd4b04e72ceccc", + "sha256:55b41a15bda04c6a2c0d27dd4c2b7b81ffa6348c9cad8f077ac1978c59927ab9" + ], + "version": "==1.2.9" + }, "dnspython": { "hashes": [ "sha256:36c5e8e38d4369a08b6780b7f27d790a292b2b08eea01607865bf0936c558e01", @@ -160,10 +166,10 @@ }, "flask-buzz": { "hashes": [ - "sha256:b3347ae16b0716c4beab40fa4722771080c31e3c25925afc1c974d0df8382e48", - "sha256:eb2d4dbb42bfa9a46f174a026caa0b49b9cc582fb79377b52425551e586d4e1c" + "sha256:5d1158170c62c62a55e294f531091b261e5f9b272f9e4054e497e0fb68a6cf45", + "sha256:bd15f6c28807cad1fa7bdfa997f6722ac234271f72a0f7976d6100d64af864b9" ], - "version": "==0.1.14" + "version": "==0.1.15" }, "flask-cors": { "hashes": [ @@ -235,6 +241,12 @@ ], "version": "==2.9" }, + "inflection": { + "hashes": [ + "sha256:18ea7fb7a7d152853386523def08736aa8c32636b047ade55f7578c4edeb16ca" + ], + "version": "==0.3.1" + }, "itsdangerous": { "hashes": [ "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19", @@ -244,10 +256,10 @@ }, "jinja2": { "hashes": [ - "sha256:93187ffbc7808079673ef52771baa950426fd664d3aad1d0fa3e95644360e250", - "sha256:b0eaf100007721b5c16c1fc1eecb87409464edc10469ddc9a22a27a99123be49" + "sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0", + "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035" ], - "version": "==2.11.1" + "version": "==2.11.2" }, "jmespath": { "hashes": [ @@ -434,10 +446,10 @@ }, "py-buzz": { "hashes": [ - "sha256:4b7a89bebad927c69e069ca43399a1b965c15f3b08998cf0d68101cc059efad8", - "sha256:d5147db6aab9ff52060f2810648003a6b4bdc91b8b16b50c23668ece632e15c2" + "sha256:07ff75c14182cb07d88372b6dc5e74e3588174189c8fd43b262317d38b8e49bd", + "sha256:21f72d3e160eb403dce76f9011c4614f3e0608bb7f91673e9fb7bfee7859a9a0" ], - "version": "==0.3.7" + "version": "==1.0.3" }, "pycparser": { "hashes": [ @@ -468,11 +480,11 @@ }, "python-dotenv": { "hashes": [ - "sha256:81822227f771e0cab235a2939f0f265954ac4763cafd806d845801c863bf372f", - "sha256:92b3123fb2d58a284f76cc92bfe4ee6c502c32ded73e8b051c4f6afc8b6751ed" + "sha256:25c0ff1a3e12f4bde8d592cc254ab075cfe734fc5dd989036716fd17ee7e5ec7", + "sha256:3b9909bc96b0edc6b01586e1eed05e71174ef4e04c71da5786370cebea53ad74" ], "index": "pypi", - "version": "==0.12.0" + "version": "==0.13.0" }, "python-editor": { "hashes": [ @@ -482,6 +494,13 @@ ], "version": "==1.0.4" }, + "python-slugify": { + "hashes": [ + "sha256:a8fc3433821140e8f409a9831d13ae5deccd0b033d4744d94b31fea141bdd84c" + ], + "index": "pypi", + "version": "==4.0.0" + }, "pytz": { "hashes": [ "sha256:1c557d7d0e871de1f5ccd5833f60fb2550652da6be2693c1e02300743d21500d", @@ -520,17 +539,42 @@ }, "sqlalchemy": { "hashes": [ - "sha256:c4cca4aed606297afbe90d4306b49ad3a4cd36feb3f87e4bfd655c57fd9ef445" - ], - "version": "==1.3.15" + "sha256:083e383a1dca8384d0ea6378bd182d83c600ed4ff4ec8247d3b2442cf70db1ad", + "sha256:0a690a6486658d03cc6a73536d46e796b6570ac1f8a7ec133f9e28c448b69828", + "sha256:114b6ace30001f056e944cebd46daef38fdb41ebb98f5e5940241a03ed6cad43", + "sha256:128f6179325f7597a46403dde0bf148478f868df44841348dfc8d158e00db1f9", + "sha256:13d48cd8b925b6893a4e59b2dfb3e59a5204fd8c98289aad353af78bd214db49", + "sha256:211a1ce7e825f7142121144bac76f53ac28b12172716a710f4bf3eab477e730b", + "sha256:2dc57ee80b76813759cccd1a7affedf9c4dbe5b065a91fb6092c9d8151d66078", + "sha256:3e625e283eecc15aee5b1ef77203bfb542563fa4a9aa622c7643c7b55438ff49", + "sha256:43078c7ec0457387c79b8d52fff90a7ad352ca4c7aa841c366238c3e2cf52fdf", + "sha256:5b1bf3c2c2dca738235ce08079783ef04f1a7fc5b21cf24adaae77f2da4e73c3", + "sha256:6056b671aeda3fc451382e52ab8a753c0d5f66ef2a5ccc8fa5ba7abd20988b4d", + "sha256:68d78cf4a9dfade2e6cf57c4be19f7b82ed66e67dacf93b32bb390c9bed12749", + "sha256:7025c639ce7e170db845e94006cf5f404e243e6fc00d6c86fa19e8ad8d411880", + "sha256:7224e126c00b8178dfd227bc337ba5e754b197a3867d33b9f30dc0208f773d70", + "sha256:7d98e0785c4cd7ae30b4a451416db71f5724a1839025544b4edbd92e00b91f0f", + "sha256:8d8c21e9d4efef01351bf28513648ceb988031be4159745a7ad1b3e28c8ff68a", + "sha256:bbb545da054e6297242a1bb1ba88e7a8ffb679f518258d66798ec712b82e4e07", + "sha256:d00b393f05dbd4ecd65c989b7f5a81110eae4baea7a6a4cdd94c20a908d1456e", + "sha256:e18752cecaef61031252ca72031d4d6247b3212ebb84748fc5d1a0d2029c23ea" + ], + "version": "==1.3.16" + }, + "text-unidecode": { + "hashes": [ + "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8", + "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93" + ], + "version": "==1.3" }, "urllib3": { "hashes": [ - "sha256:2f3db8b19923a873b3e5256dc9c2dedfa883e33d87c690d9c7913e1f40673cdc", - "sha256:87716c2d2a7121198ebcb7ce7cccf6ce5e9ba539041cfbaeecfb641dc0bf6acc" + "sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527", + "sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115" ], "markers": "python_version != '3.4'", - "version": "==1.25.8" + "version": "==1.25.9" }, "werkzeug": { "hashes": [ @@ -538,6 +582,12 @@ "sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c" ], "version": "==1.0.1" + }, + "wrapt": { + "hashes": [ + "sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7" + ], + "version": "==1.12.1" } }, "develop": { @@ -613,9 +663,9 @@ }, "wrapt": { "hashes": [ - "sha256:565a021fd19419476b9362b05eeaa094178de64f8361e44468f9e9d7843901e1" + "sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7" ], - "version": "==1.11.2" + "version": "==1.12.1" } } } diff --git a/api/v1/games.py b/api/v1/games.py index e6ebdd0..e4c407a 100644 --- a/api/v1/games.py +++ b/api/v1/games.py @@ -3,7 +3,7 @@ from flask_restx import Namespace, Resource, Api, fields from extensions import guard, db, upload_img, delete_img from marshmallow import ValidationError, INCLUDE -from utilities import get_auto_increment, base64_to_pillow_img, pillow_img_to_bytes +from utilities import get_auto_increment, base64_to_pillow_img, pillow_img_to_bytes, slugify_text from sqlalchemy.exc import SQLAlchemyError from sqlalchemy import or_, and_ @@ -99,7 +99,8 @@ def post(self): # Set Authenticated User current_user = flask_praetorian.current_user() req['user'] = user_schema.dump(current_user) - + req['slug'] = slugify_text(req['title']) + # Validate try: new_game = game_schema.load(req) @@ -153,7 +154,7 @@ def get(self, id): db.session.commit() except SQLAlchemyError: return { 'error': 'Unable to update view count' }, 500 - + return game_schema.dump(game) @flask_praetorian.roles_required('admin') @@ -171,6 +172,7 @@ def put(self, id): icon_name = game.icon banner_name = game.banner + req['slug'] = slugify_text(req['title']) # Validate try: diff --git a/api/v1/schemas.py b/api/v1/schemas.py index 06dedc2..30b2df6 100644 --- a/api/v1/schemas.py +++ b/api/v1/schemas.py @@ -136,11 +136,11 @@ class GameSchema(ma.ModelSchema): class Meta: model = Game sqla_session = db.session - fields = ("id", "title", "synopsis", "icon", "banner", "developer", "genres", "releases", "score", "library_count", "score_rank", "popularity_rank", "trending_page_views", "user") + fields = ("id", "title", "slug", "synopsis", "icon", "banner", "developer", "genres", "releases", "score", "library_count", "score_rank", "popularity_rank", "trending_page_views", "user") game_schema = GameSchema(exclude=['user']) games_schema = GameSchema(many=True, exclude=['releases']) -nested_game_schema = GameSchema(only=("id", "title", "synopsis", "icon", "banner", "developer")) +nested_game_schema = GameSchema(only=("id", "title", "slug", "synopsis", "icon", "banner", "developer")) # LibraryEntrySchema class LibraryEntrySchema(ma.ModelSchema): diff --git a/models/game.py b/models/game.py index 4ace031..7c86ea3 100644 --- a/models/game.py +++ b/models/game.py @@ -15,6 +15,7 @@ class Game(db.Model): id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String, unique=True, nullable=False) + slug = db.Column(db.String, unique=True, nullable=False) synopsis = db.Column(db.Text, nullable=False) icon = db.Column(db.String, unique=True, nullable=False) banner = db.Column(db.String, unique=True, nullable=False) diff --git a/utilities.py b/utilities.py index af4a772..c02421b 100644 --- a/utilities.py +++ b/utilities.py @@ -3,6 +3,7 @@ from PIL import Image from io import BytesIO import base64 +from slugify import slugify def get_auto_increment(table_name): """ @@ -91,4 +92,7 @@ def base64_validation(base64_string, max_file_size): if file_type != 'jpeg' and file_type != 'png': return False - return True \ No newline at end of file + return True + +def slugify_text(text): + return slugify(text, replacements=([['\'', '']])) \ No newline at end of file