diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 79098719bc..fef8967d26 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,40 +1,14 @@ -// For format details, see https://aka.ms/devcontainer.json. For config options, see the -// README at: https://github.com/devcontainers/templates/tree/main/src/postgres { - "name": "Python 3 & PostgreSQL", - "dockerComposeFile": "docker-compose.yml", - "service": "app", - "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", - "features": { - "ghcr.io/devcontainers/features/github-cli:1": { - "installDirectlyFromGitHubRelease": true, - "version": "latest" - }, - "ghcr.io/devcontainers/features/node:1": { - "nodeGypDependencies": true, - "version": "lts" - } - }, - - // Features to add to the dev container. More info: https://containers.dev/features. - // "features": {}, - - // Use 'forwardPorts' to make a list of ports inside the container available locally. - // This can be used to network with other containers or the host. - "forwardPorts": [3000, 3001], - - "onCreateCommand": "(cp .env.example .env || echo \".env creation failed\"); (pipenv install || echo \"pipenv install failed\"); (bash database.sh || echo \"database.sh failed\");", - // Use 'postCreateCommand' to run commands after the container is created. - "postCreateCommand": "python docs/assets/greeting.py both > /workspaces/.codespaces/shared/first-run-notice.txt && npm install", - "customizations": { - "vscode": { - "extensions": [ - "esbenp.prettier-vscode", - "ms-python.autopep8" - ] - } - }, - - // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. - // "remoteUser": "root" + "name": "autenticacion-abell", + "forwardPorts": [3000, 3001], + "portsAttributes": { + "3001": { + "label": "Backend (Flask)", + "onAutoForward": "openBrowser" + }, + "3000": { + "label": "Frontend (Vite)", + "onAutoForward": "openBrowser" + } + } } diff --git a/.env.example b/.env.example index 05a32a5146..6bf0a26454 100644 --- a/.env.example +++ b/.env.example @@ -1,14 +1,9 @@ -# This file includes global variables that will be available inside your project -# 1. In the front end code you can access this variables like this: console.log(import.meta.env.VARIABLE_NAME) -# 1. In the back end code you access the variable by importing os and then typing print(os.getenv('VARIABLE_NAME')) - -# Back-End Variables -DATABASE_URL=postgres://gitpod:postgres@localhost:5432/example -FLASK_APP_KEY="any key works" -FLASK_APP=src/app.py +FLASK_APP=src.app FLASK_DEBUG=1 -DEBUG=TRUE +DEBUG=True +PORT=3001 + +JWT_SECRET_KEY=super-secret-key -# Front-End Variables -VITE_BASENAME=/ -#VITE_BACKEND_URL= +VITE_BACKEND_URL=http://localhost:3001 +VITE_FRONTEND_URL=http://localhost:3000 diff --git a/.gitignore b/.gitignore index 80704f4378..7916db8854 100755 --- a/.gitignore +++ b/.gitignore @@ -1,55 +1,34 @@ -# ignore all files starting with . -.* -# track this file .gitignore (i.e. do NOT ignore it) -!.gitignore -!.github -php_errorlog -.log +# env +.env +.env.local -# do not ignore gitpod and render files -!.gitpod.Dockerfile -!.welcome -!.devcontainer -!.devcontainer/* -!Dockerfile.render -!.gitpod.yml -!render.yml -!.render-buildpacks.json +# frontend +node_modules/ -# track webpack configs (i.e. do NOT ignore it) -!composer.json -!webpack.config.js -!package.json -!webpack.production.js -!webpack.development.js -# track readme.md in the root (i.e. do NOT ignore it) -!README.md +# python +__pycache__/ +*.pyc +.pytest_cache/ -# ignore OS generated files +# logs +*.log + +# otros ehthumbs.db Thumbs.db - -# ignore Editor files *.sublime-project *.sublime-workspace *.komodoproject - -# ignore log files and databases -*.log *.sql *.sqlite - -# ignore compiled files *.com *.class *.dll *.exe *.o *.so - -# ignore packaged files *.7z *.dmg *.gz @@ -58,25 +37,8 @@ Thumbs.db *.rar *.tar *.zip - -# ignore node/grunt dependency directories -node_modules/ - -# webpack output -dist/* -!public/ -!public/* - -# ignore the dist directory were our bundle files are going to be -!.gitkeep -!.htaccess -!.eslintrc -!.env.example -.now - -# backend stuff .venv database.database database.db diagram.png -__pycache__/ +# ignore compiled files diff --git a/.gitpod.Dockerfile b/.gitpod.Dockerfile deleted file mode 100644 index 542a325977..0000000000 --- a/.gitpod.Dockerfile +++ /dev/null @@ -1,27 +0,0 @@ -FROM gitpod/workspace-postgres:latest - -SHELL ["/bin/bash", "-c"] - -RUN sudo apt-get update \ - && sudo apt-get update \ - && sudo apt-get install -y redis-server \ - && sudo apt-get clean \ - && sudo rm -rf /var/cache/apt/* /var/lib/apt/lists/* /tmp/* - -# That Gitpod install pyenv for me? no, thanks -WORKDIR /home/gitpod/ -RUN rm .pyenv -Rf -RUN rm .gp_pyenv.d -Rf -RUN curl https://pyenv.run | bash - - -RUN pyenv update && pyenv install 3.10.7 && pyenv global 3.10.7 -RUN pip install pipenv yapf -RUN npm i heroku -g - -# remove PIP_USER environment -USER gitpod -RUN if ! grep -q "export PIP_USER=no" "$HOME/.bashrc"; then printf '%s\n' "export PIP_USER=no" >> "$HOME/.bashrc"; fi -RUN echo "" >> $HOME/.bashrc -RUN echo "unset DATABASE_URL" >> $HOME/.bashrc -RUN echo "export DATABASE_URL" >> $HOME/.bashrc diff --git a/.gitpod.yml b/.gitpod.yml deleted file mode 100644 index 8d80dd7bf2..0000000000 --- a/.gitpod.yml +++ /dev/null @@ -1,28 +0,0 @@ -image: - file: .gitpod.Dockerfile -ports: - - port: 3000 - onOpen: open-browser - visibility: public - - port: 3001 - onOpen: open-preview - visibility: public - - port: 5432 - onOpen: ignore -tasks: - - init: > - (cp .env.example .env || true) && - pipenv install && - psql -U gitpod -c 'CREATE DATABASE example;' && - psql -U gitpod -c 'CREATE EXTENSION unaccent;' -d example && - psql -c "ALTER USER gitpod PASSWORD 'postgres';" && - bash database.sh && - python docs/assets/greeting.py back - - command: > - npm install && - python docs/assets/greeting.py front - openMode: split-right - -vscode: - extensions: - - esbenp.prettier-vscode diff --git a/.vscode/settings.json b/.vscode/settings.json index 246b0419d0..aa8fd4d93e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,5 +6,7 @@ }, "[javascriptreact]": { "editor.defaultFormatter": "vscode.typescript-language-features" - } + }, + "python-envs.defaultEnvManager": "ms-python.python:system", + "python-envs.pythonProjects": [] } diff --git a/Dockerfile.render b/Dockerfile.render deleted file mode 100644 index ed38677ebe..0000000000 --- a/Dockerfile.render +++ /dev/null @@ -1,13 +0,0 @@ -FROM node:16 - -RUN apt update \ - && apt install software-properties-common \ - && add-apt-repository ppa:deadsnakes/ppa \ - && apt update \ - && apt install python3.10 - -WORKDIR /opt/app -COPY --from=build /opt/app/venv /venv - -ENV PATH="/opt/app/venv/bin:$PATH" -ENV NODE_ENV=container \ No newline at end of file diff --git a/Pipfile b/Pipfile index 4d377014ae..4644feb3d6 100644 --- a/Pipfile +++ b/Pipfile @@ -6,13 +6,9 @@ verify_ssl = true [dev-packages] [packages] -flask = "*" -flask-sqlalchemy = "*" -flask-migrate = "*" flask-swagger = "*" psycopg2-binary = "*" python-dotenv = "*" -flask-cors = "*" gunicorn = "*" cloudinary = "*" flask-admin = "==2.0.0" @@ -20,17 +16,24 @@ typing-extensions = "*" flask-jwt-extended = "==4.6.0" wtforms = "==3.1.2" sqlalchemy = "*" +flask = "*" +flask-cors = "*" +flask-migrate = "*" +flask-sqlalchemy = "*" +pyjwt = "*" +werkzeug = "*" [requires] -python_version = "3.13" +python_version = "3.11" [scripts] -start="flask run -p 3001 -h 0.0.0.0" -init="flask db init" -migrate="flask db migrate" -local="heroku local" -upgrade="flask db upgrade" -downgrade="flask db downgrade" -insert-test-data="flask insert-test-data" -reset_db="bash ./docs/assets/reset_migrations.bash" -deploy="echo 'Please follow this 3 steps to deploy: https://github.com/4GeeksAcademy/flask-rest-hello/blob/master/README.md#deploy-your-website-to-heroku' " +start = "bash -lc 'PYTHONPATH=src FLASK_APP=src.app FLASK_DEBUG=1 bash ./bin/start.sh'" +prod = "bash -lc 'fuser -k 3001/tcp || true; sleep 0.5; PYTHONPATH=src gunicorn -w 2 -b 0.0.0.0:3001 src.app:app'" +init = "flask db init" +migrate = "flask db migrate" +local = "heroku local" +upgrade = "flask db upgrade" +downgrade = "flask db downgrade" +insert-test-data = "flask insert-test-data" +reset_db = "bash ./docs/assets/reset_migrations.bash" +deploy = "echo 'Please follow this 3 steps to deploy: https://github.com/4GeeksAcademy/flask-rest-hello/blob/master/README.md#deploy-your-website-to-heroku' " diff --git a/Pipfile.lock b/Pipfile.lock index d9e474e972..bb52b8bc04 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,11 +1,11 @@ { "_meta": { "hash": { - "sha256": "ffbfb32d0afa5e4bcaba5c2d08c81381a97abd90f22284d2b76647365df5dc50" + "sha256": "0cd88d734b2e79df89a674c6c0e607e7748212a83e03e65763a184576c9d3081" }, "pipfile-spec": 6, "requires": { - "python_version": "3.13" + "python_version": "3.11" }, "sources": [ { @@ -18,11 +18,11 @@ "default": { "alembic": { "hashes": [ - "sha256:8a289f6778262df31571d29cca4c7fbacd2f0f582ea0816f4c399b6da7528486", - "sha256:cbc2386e60f89608bb63f30d2d6cc66c7aaed1fe105bd862828600e5ad167023" + "sha256:bbe9751705c5e0f14877f02d46c53d10885e377e3d90eda810a016f9baa19e8e", + "sha256:f483dd1fe93f6c5d49217055e4d15b905b425b6af906746abb35b69c1996c4e6" ], "markers": "python_version >= '3.10'", - "version": "==1.17.1" + "version": "==1.17.2" }, "blinker": { "hashes": [ @@ -34,19 +34,19 @@ }, "certifi": { "hashes": [ - "sha256:0f212c2744a9bb6de0c56639a6f68afe01ecd92d91f14ae897c4fe7bbeeef0de", - "sha256:47c09d31ccf2acf0be3f701ea53595ee7e0b8fa08801c6624be771df09ae7b43" + "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b", + "sha256:d8ab5478f2ecd78af242878415affce761ca6bc54a22a27e026d7c25357c3316" ], "markers": "python_version >= '3.7'", - "version": "==2025.10.5" + "version": "==2025.11.12" }, "click": { "hashes": [ - "sha256:9b9f285302c6e3064f4330c05f05b81945b2a39544279343e6e7c5f27a9baddc", - "sha256:e7b8232224eba16f4ebe410c25ced9f7875cb5f3263ffc93cc3e8da705e229c4" + "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", + "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6" ], "markers": "python_version >= '3.10'", - "version": "==8.3.0" + "version": "==8.3.1" }, "cloudinary": { "hashes": [ @@ -76,12 +76,12 @@ }, "flask-cors": { "hashes": [ - "sha256:c7b2cbfb1a31aa0d2e5341eea03a6805349f7a61647daee1a15c46bbe981494c", - "sha256:d81bcb31f07b0985be7f48406247e9243aced229b7747219160a0559edd678db" + "sha256:6e118f3698249ae33e429760db98ce032a8bf9913638d085ca0f4c5534ad2423", + "sha256:e57544d415dfd7da89a9564e1e3a9e515042df76e12130641ca6f3f2f03b699a" ], "index": "pypi", "markers": "python_version >= '3.9' and python_version < '4.0'", - "version": "==6.0.1" + "version": "==6.0.2" }, "flask-jwt-extended": { "hashes": [ @@ -120,63 +120,57 @@ }, "greenlet": { "hashes": [ - "sha256:00fadb3fedccc447f517ee0d3fd8fe49eae949e1cd0f6a611818f4f6fb7dc83b", - "sha256:061dc4cf2c34852b052a8620d40f36324554bc192be474b9e9770e8c042fd735", - "sha256:0db5594dce18db94f7d1650d7489909b57afde4c580806b8d9203b6e79cdc079", - "sha256:0dca0d95ff849f9a364385f36ab49f50065d76964944638be9691e1832e9f86d", - "sha256:16458c245a38991aa19676900d48bd1a6f2ce3e16595051a4db9d012154e8433", - "sha256:18d9260df2b5fbf41ae5139e1be4e796d99655f023a636cd0e11e6406cca7d58", - "sha256:1987de92fec508535687fb807a5cea1560f6196285a4cde35c100b8cd632cc52", - "sha256:1a921e542453fe531144e91e1feedf12e07351b1cf6c9e8a3325ea600a715a31", - "sha256:1ee8fae0519a337f2329cb78bd7a8e128ec0f881073d43f023c7b8d4831d5246", - "sha256:20fb936b4652b6e307b8f347665e2c615540d4b42b3b4c8a321d8286da7e520f", - "sha256:23768528f2911bcd7e475210822ffb5254ed10d71f4028387e5a99b4c6699671", - "sha256:2523e5246274f54fdadbce8494458a2ebdcdbc7b802318466ac5606d3cded1f8", - "sha256:27890167f55d2387576d1f41d9487ef171849ea0359ce1510ca6e06c8bece11d", - "sha256:299fd615cd8fc86267b47597123e3f43ad79c9d8a22bebdce535e53550763e2f", - "sha256:3b3812d8d0c9579967815af437d96623f45c0f2ae5f04e366de62a12d83a8fb0", - "sha256:3b67ca49f54cede0186854a008109d6ee71f66bd57bb36abd6d0a0267b540cdd", - "sha256:44358b9bf66c8576a9f57a590d5f5d6e72fa4228b763d0e43fee6d3b06d3a337", - "sha256:49a30d5fda2507ae77be16479bdb62a660fa51b1eb4928b524975b3bde77b3c0", - "sha256:4d1378601b85e2e5171b99be8d2dc85f594c79967599328f95c1dc1a40f1c633", - "sha256:554b03b6e73aaabec3745364d6239e9e012d64c68ccd0b8430c64ccc14939a8b", - "sha256:55e9c5affaa6775e2c6b67659f3a71684de4c549b3dd9afca3bc773533d284fa", - "sha256:58b97143c9cc7b86fc458f215bd0932f1757ce649e05b640fea2e79b54cedb31", - "sha256:5c9320971821a7cb77cfab8d956fa8e39cd07ca44b6070db358ceb7f8797c8c9", - "sha256:65458b409c1ed459ea899e939f0e1cdb14f58dbc803f2f93c5eab5694d32671b", - "sha256:671df96c1f23c4a0d4077a325483c1503c96a1b7d9db26592ae770daa41233d4", - "sha256:710638eb93b1fa52823aa91bf75326f9ecdfd5e0466f00789246a5280f4ba0fc", - "sha256:73f49b5368b5359d04e18d15828eecc1806033db5233397748f4ca813ff1056c", - "sha256:81701fd84f26330f0d5f4944d4e92e61afe6319dcd9775e39396e39d7c3e5f98", - "sha256:8854167e06950ca75b898b104b63cc646573aa5fef1353d4508ecdd1ee76254f", - "sha256:8c68325b0d0acf8d91dde4e6f930967dd52a5302cd4062932a6b2e7c2969f47c", - "sha256:94385f101946790ae13da500603491f04a76b6e4c059dab271b3ce2e283b2590", - "sha256:94abf90142c2a18151632371140b3dba4dee031633fe614cb592dbb6c9e17bc3", - "sha256:96378df1de302bc38e99c3a9aa311967b7dc80ced1dcc6f171e99842987882a2", - "sha256:9c40adce87eaa9ddb593ccb0fa6a07caf34015a29bf8d344811665b573138db9", - "sha256:9fe0a28a7b952a21e2c062cd5756d34354117796c6d9215a87f55e38d15402c5", - "sha256:a7d4e128405eea3814a12cc2605e0e6aedb4035bf32697f72deca74de4105e02", - "sha256:abbf57b5a870d30c4675928c37278493044d7c14378350b3aa5d484fa65575f0", - "sha256:b4a1870c51720687af7fa3e7cda6d08d801dae660f75a76f3845b642b4da6ee1", - "sha256:b6a7c19cf0d2742d0809a4c05975db036fdff50cd294a93632d6a310bf9ac02c", - "sha256:b90654e092f928f110e0007f572007c9727b5265f7632c2fa7415b4689351594", - "sha256:c17b6b34111ea72fc5a4e4beec9711d2226285f0386ea83477cbb97c30a3f3a5", - "sha256:c2ca18a03a8cfb5b25bc1cbe20f3d9a4c80d8c3b13ba3df49ac3961af0b1018d", - "sha256:c5111ccdc9c88f423426df3fd1811bfc40ed66264d35aa373420a34377efc98a", - "sha256:c60a6d84229b271d44b70fb6e5fa23781abb5d742af7b808ae3f6efd7c9c60f6", - "sha256:c8c9e331e58180d0d83c5b7999255721b725913ff6bc6cf39fa2a45841a4fd4b", - "sha256:c9913f1a30e4526f432991f89ae263459b1c64d1608c0d22a5c79c287b3c70df", - "sha256:cd3c8e693bff0fff6ba55f140bf390fa92c994083f838fece0f63be121334945", - "sha256:d25c5091190f2dc0eaa3f950252122edbbadbb682aa7b1ef2f8af0f8c0afefae", - "sha256:d2e685ade4dafd447ede19c31277a224a239a0a1a4eca4e6390efedf20260cfb", - "sha256:d76383238584e9711e20ebe14db6c88ddcedc1829a9ad31a584389463b5aa504", - "sha256:ddf9164e7a5b08e9d22511526865780a576f19ddd00d62f8a665949327fde8bb", - "sha256:e37ab26028f12dbb0ff65f29a8d3d44a765c61e729647bf2ddfbbed621726f01", - "sha256:f10fd42b5ee276335863712fa3da6608e93f70629c631bf77145021600abc23c", - "sha256:f28588772bb5fb869a8eb331374ec06f24a83a9c25bfa1f38b6993afe9c1e968" + "sha256:047ab3df20ede6a57c35c14bf5200fcf04039d50f908270d3f9a7a82064f543b", + "sha256:087ea5e004437321508a8d6f20efc4cfec5e3c30118e1417ea96ed1d93950527", + "sha256:0a5d554d0712ba1de0a6c94c640f7aeba3f85b3a6e1f2899c11c2c0428da9365", + "sha256:2662433acbca297c9153a4023fe2161c8dcfdcc91f10433171cf7e7d94ba2221", + "sha256:286d093f95ec98fdd92fcb955003b8a3d054b4e2cab3e2707a5039e7b50520fd", + "sha256:2d9ad37fc657b1102ec880e637cccf20191581f75c64087a549e66c57e1ceb53", + "sha256:2de5a0b09eab81fc6a382791b995b1ccf2b172a9fec934747a7a23d2ff291794", + "sha256:30a6e28487a790417d036088b3bcb3f3ac7d8babaa7d0139edbaddebf3af9492", + "sha256:349345b770dc88f81506c6861d22a6ccd422207829d2c854ae2af8025af303e3", + "sha256:39b28e339fc3c348427560494e28d8a6f3561c8d2bcf7d706e1c624ed8d822b9", + "sha256:3a898b1e9c5f7307ebbde4102908e6cbfcb9ea16284a3abe15cab996bee8b9b3", + "sha256:3c6e9b9c1527a78520357de498b0e709fb9e2f49c3a513afd5a249007261911b", + "sha256:4243050a88ba61842186cb9e63c7dfa677ec146160b0efd73b855a3d9c7fcf32", + "sha256:4449a736606bd30f27f8e1ff4678ee193bc47f6ca810d705981cfffd6ce0d8c5", + "sha256:5375d2e23184629112ca1ea89a53389dddbffcf417dad40125713d88eb5f96e8", + "sha256:5773edda4dc00e173820722711d043799d3adb4f01731f40619e07ea2750b955", + "sha256:60c2ef0f578afb3c8d92ea07ad327f9a062547137afe91f38408f08aacab667f", + "sha256:670d0f94cd302d81796e37299bcd04b95d62403883b24225c6b5271466612f45", + "sha256:6c10513330af5b8ae16f023e8ddbfb486ab355d04467c4679c5cfe4659975dd9", + "sha256:6cb3a8ec3db4a3b0eb8a3c25436c2d49e3505821802074969db017b87bc6a948", + "sha256:6f8496d434d5cb2dce025773ba5597f71f5410ae499d5dd9533e0653258cdb3d", + "sha256:73631cd5cccbcfe63e3f9492aaa664d278fda0ce5c3d43aeda8e77317e38efbd", + "sha256:73f51dd0e0bdb596fb0417e475fa3c5e32d4c83638296e560086b8d7da7c4170", + "sha256:7652ee180d16d447a683c04e4c5f6441bae7ba7b17ffd9f6b3aff4605e9e6f71", + "sha256:7d2d9fd66bfadf230b385fdc90426fcd6eb64db54b40c495b72ac0feb5766c54", + "sha256:7dee147740789a4632cace364816046e43310b59ff8fb79833ab043aefa72fd5", + "sha256:83cd0e36932e0e7f36a64b732a6f60c2fc2df28c351bae79fbaf4f8092fe7614", + "sha256:87e63ccfa13c0a0f6234ed0add552af24cc67dd886731f2261e46e241608bee3", + "sha256:9ee1942ea19550094033c35d25d20726e4f1c40d59545815e1128ac58d416d38", + "sha256:9f515a47d02da4d30caaa85b69474cec77b7929b2e936ff7fb853d42f4bf8808", + "sha256:a1e41a81c7e2825822f4e068c48cb2196002362619e2d70b148f20a831c00739", + "sha256:a687205fb22794e838f947e2194c0566d3812966b41c78709554aa883183fb62", + "sha256:a7a34b13d43a6b78abf828a6d0e87d3385680eaf830cd60d20d52f249faabf39", + "sha256:a82bb225a4e9e4d653dd2fb7b8b2d36e4fb25bc0165422a11e48b88e9e6f78fb", + "sha256:ab97cf74045343f6c60a39913fa59710e4bd26a536ce7ab2397adf8b27e67c39", + "sha256:ac0549373982b36d5fd5d30beb8a7a33ee541ff98d2b502714a09f1169f31b55", + "sha256:b01548f6e0b9e9784a2c99c5651e5dc89ffcbe870bc5fb2e5ef864e9cc6b5dcb", + "sha256:b299a0cb979f5d7197442dccc3aee67fce53500cd88951b7e6c35575701c980b", + "sha256:b3c374782c2935cc63b2a27ba8708471de4ad1abaa862ffdb1ef45a643ddbb7d", + "sha256:b49e7ed51876b459bd645d83db257f0180e345d3f768a35a85437a24d5a49082", + "sha256:b96dc7eef78fd404e022e165ec55327f935b9b52ff355b067eb4a0267fc1cffb", + "sha256:c024b1e5696626890038e34f76140ed1daf858e37496d33f2af57f06189e70d7", + "sha256:d198d2d977460358c3b3a4dc844f875d1adb33817f0613f663a656f463764ccc", + "sha256:d6ed6f85fae6cdfdb9ce04c9bf7a08d666cfcfb914e7d006f44f840b46741931", + "sha256:d9125050fcf24554e69c4cacb086b87b3b55dc395a8b3ebe6487b045b2614388", + "sha256:dcd2bdbd444ff340e8d6bdf54d2f206ccddbb3ccfdcd3c25bf4afaa7b8f0cf45", + "sha256:e29f3018580e8412d6aaf5641bb7745d38c85228dacf51a73bd4e26ddf2a6a8e", + "sha256:e8e18ed6995e9e2c0b4ed264d2cf89260ab3ac7e13555b8032b25a74c6d18655" ], - "markers": "python_version >= '3.9'", - "version": "==3.2.4" + "markers": "python_version >= '3.10'", + "version": "==3.3.0" }, "gunicorn": { "hashes": [ @@ -393,6 +387,7 @@ "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953", "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb" ], + "index": "pypi", "markers": "python_version >= '3.9'", "version": "==2.10.1" }, @@ -494,67 +489,62 @@ }, "sqlalchemy": { "hashes": [ - "sha256:0765e318ee9179b3718c4fd7ba35c434f4dd20332fbc6857a5e8df17719c24d7", - "sha256:0ae7454e1ab1d780aee69fd2aae7d6b8670a581d8847f2d1e0f7ddfbf47e5a22", - "sha256:0b1af8392eb27b372ddb783b317dea0f650241cea5bd29199b22235299ca2e45", - "sha256:0fe3917059c7ab2ee3f35e77757062b1bea10a0b6ca633c58391e3f3c6c488dd", - "sha256:119dc41e7a7defcefc57189cfa0e61b1bf9c228211aba432b53fb71ef367fda1", - "sha256:11bac86b0deada30b6b5f93382712ff0e911fe8d31cb9bf46e6b149ae175eff0", - "sha256:15f3326f7f0b2bfe406ee562e17f43f36e16167af99c4c0df61db668de20002d", - "sha256:17835885016b9e4d0135720160db3095dc78c583e7b902b6be799fb21035e749", - "sha256:19de7ca1246fbef9f9d1bff8f1ab25641569df226364a0e40457dc5457c54b05", - "sha256:1df4763760d1de0dfc8192cc96d8aa293eb1a44f8f7a5fbe74caf1b551905c5e", - "sha256:1e77faf6ff919aa8cd63f1c4e561cac1d9a454a191bb864d5dd5e545935e5a40", - "sha256:22be14009339b8bc16d6b9dc8780bacaba3402aa7581658e246114abbd2236e3", - "sha256:253e2f29843fb303eca6b2fc645aca91fa7aa0aa70b38b6950da92d44ff267f3", - "sha256:2b61188657e3a2b9ac4e8f04d6cf8e51046e28175f79464c67f2fd35bceb0976", - "sha256:2bf4bb6b3d6228fcf3a71b50231199fb94d2dd2611b66d33be0578ea3e6c2726", - "sha256:2e7b5b079055e02d06a4308d0481658e4f06bc7ef211567edc8f7d5dce52018d", - "sha256:2f19644f27c76f07e10603580a47278abb2a70311136a7f8fd27dc2e096b9013", - "sha256:2fc44e5965ea46909a416fff0af48a219faefd5773ab79e5f8a5fcd5d62b2667", - "sha256:2fcc4901a86ed81dc76703f3b93ff881e08761c63263c46991081fd7f034b165", - "sha256:3255d821ee91bdf824795e936642bbf43a4c7cedf5d1aed8d24524e66843aa74", - "sha256:329aa42d1be9929603f406186630135be1e7a42569540577ba2c69952b7cf399", - "sha256:357bade0e46064f88f2c3a99808233e67b0051cdddf82992379559322dfeb183", - "sha256:3caef1ff89b1caefc28f0368b3bde21a7e3e630c2eddac16abd9e47bd27cc36a", - "sha256:3cf6872a23601672d61a68f390e44703442639a12ee9dd5a88bbce52a695e46e", - "sha256:3fe166c7d00912e8c10d3a9a0ce105569a31a3d0db1a6e82c4e0f4bf16d5eca9", - "sha256:471733aabb2e4848d609141a9e9d56a427c0a038f4abf65dd19d7a21fd563632", - "sha256:4848395d932e93c1595e59a8672aa7400e8922c39bb9b0668ed99ac6fa867822", - "sha256:48bf7d383a35e668b984c805470518b635d48b95a3c57cb03f37eaa3551b5f9f", - "sha256:4c26ef74ba842d61635b0152763d057c8d48215d5be9bb8b7604116a059e9985", - "sha256:4d18cd0e9a0f37c9f4088e50e3839fcb69a380a0ec957408e0b57cff08ee0a26", - "sha256:585c0c852a891450edbb1eaca8648408a3cc125f18cf433941fa6babcc359e29", - "sha256:70e03833faca7166e6a9927fbee7c27e6ecde436774cd0b24bbcc96353bce06b", - "sha256:72fea91746b5890f9e5e0997f16cbf3d53550580d76355ba2d998311b17b2250", - "sha256:78e6c137ba35476adb5432103ae1534f2f5295605201d946a4198a0dea4b38e7", - "sha256:7a8694107eb4308a13b425ca8c0e67112f8134c846b6e1f722698708741215d5", - "sha256:7c77f3080674fc529b1bd99489378c7f63fcb4ba7f8322b79732e0258f0ea3ce", - "sha256:7cbcb47fd66ab294703e1644f78971f6f2f1126424d2b300678f419aa73c7b6e", - "sha256:846541e58b9a81cce7dee8329f352c318de25aa2f2bbe1e31587eb1f057448b4", - "sha256:8e0e4e66fd80f277a8c3de016a81a554e76ccf6b8d881ee0b53200305a8433f6", - "sha256:9919e77403a483ab81e3423151e8ffc9dd992c20d2603bf17e4a8161111e55f5", - "sha256:9b94843a102efa9ac68a7a30cd46df3ff1ed9c658100d30a725d10d9c60a2f44", - "sha256:9e9018544ab07614d591a26c1bd4293ddf40752cc435caf69196740516af7100", - "sha256:b87e7b91a5d5973dda5f00cd61ef72ad75a1db73a386b62877d4875a8840959c", - "sha256:c1c80faaee1a6c3428cecf40d16a2365bcf56c424c92c2b6f0f9ad204b899e9e", - "sha256:c3678a0fb72c8a6a29422b2732fe423db3ce119c34421b5f9955873eb9b62c1e", - "sha256:cbe4f85f50c656d753890f39468fcd8190c5f08282caf19219f684225bfd5fd2", - "sha256:cc2856d24afa44295735e72f3c75d6ee7fdd4336d8d3a8f3d44de7aa6b766df2", - "sha256:d733dec0614bb8f4bcb7c8af88172b974f685a31dc3a65cca0527e3120de5606", - "sha256:dc8b3850d2a601ca2320d081874033684e246d28e1c5e89db0864077cfc8f5a9", - "sha256:de4387a354ff230bc979b46b2207af841dc8bf29847b6c7dbe60af186d97aefa", - "sha256:e998cf7c29473bd077704cea3577d23123094311f59bdc4af551923b168332b1", - "sha256:ebac3f0b5732014a126b43c2b7567f2f0e0afea7d9119a3378bde46d3dcad88e", - "sha256:ee51625c2d51f8baadf2829fae817ad0b66b140573939dd69284d2ba3553ae73", - "sha256:f4a172b31785e2f00780eccab00bc240ccdbfdb8345f1e6063175b3ff12ad1b0", - "sha256:f7027414f2b88992877573ab780c19ecb54d3a536bef3397933573d6b5068be4", - "sha256:f9480c0740aabd8cb29c329b422fb65358049840b34aba0adf63162371d2a96e", - "sha256:ff486e183d151e51b1d694c7aa1695747599bb00b9f5f604092b54b74c64a8e1" + "sha256:0209d9753671b0da74da2cfbb9ecf9c02f72a759e4b018b3ab35f244c91842c7", + "sha256:040f6f0545b3b7da6b9317fc3e922c9a98fc7243b2a1b39f78390fc0942f7826", + "sha256:0c9f6ada57b58420a2c0277ff853abe40b9e9449f8d7d231763c6bc30f5c4953", + "sha256:0f02325709d1b1a1489f23a39b318e175a171497374149eae74d612634b234c0", + "sha256:107029bf4f43d076d4011f1afb74f7c3e2ea029ec82eb23d8527d5e909e97aa6", + "sha256:12c694ed6468333a090d2f60950e4250b928f457e4962389553d6ba5fe9951ac", + "sha256:13e27397a7810163440c6bfed6b3fe46f1bfb2486eb540315a819abd2c004128", + "sha256:1632a4bda8d2d25703fdad6363058d882541bdaaee0e5e3ddfa0cd3229efce88", + "sha256:1d8b4a7a8c9b537509d56d5cd10ecdcfbb95912d72480c8861524efecc6a3fff", + "sha256:215f0528b914e5c75ef2559f69dca86878a3beeb0c1be7279d77f18e8d180ed4", + "sha256:2c0b74aa79e2deade948fe8593654c8ef4228c44ba862bb7c9585c8e0db90f33", + "sha256:2e90a344c644a4fa871eb01809c32096487928bd2038bf10f3e4515cb688cc56", + "sha256:3c5f76216e7b85770d5bb5130ddd11ee89f4d52b11783674a662c7dd57018177", + "sha256:470daea2c1ce73910f08caf10575676a37159a6d16c4da33d0033546bddebc9b", + "sha256:4748601c8ea959e37e03d13dcda4a44837afcd1b21338e637f7c935b8da06177", + "sha256:4b6bec67ca45bc166c8729910bd2a87f1c0407ee955df110d78948f5b5827e8a", + "sha256:5225a288e4c8cc2308dbdd874edad6e7d0fd38eac1e9e5f23503425c8eee20d0", + "sha256:56ead1f8dfb91a54a28cd1d072c74b3d635bcffbd25e50786533b822d4f2cde2", + "sha256:5964f832431b7cdfaaa22a660b4c7eb1dfcd6ed41375f67fd3e3440fd95cb3cc", + "sha256:59a8b8bd9c6bedf81ad07c8bd5543eedca55fe9b8780b2b628d495ba55f8db1e", + "sha256:672c45cae53ba88e0dad74b9027dddd09ef6f441e927786b05bec75d949fbb2e", + "sha256:6d0beadc2535157070c9c17ecf25ecec31e13c229a8f69196d7590bde8082bf1", + "sha256:7ae64ebf7657395824a19bca98ab10eb9a3ecb026bf09524014f1bb81cb598d4", + "sha256:7f46ec744e7f51275582e6a24326e10c49fbdd3fc99103e01376841213028774", + "sha256:830d434d609fe7bfa47c425c445a8b37929f140a7a44cdaf77f6d34df3a7296a", + "sha256:83d7009f40ce619d483d26ac1b757dfe3167b39921379a8bd1b596cf02dab4a6", + "sha256:883c600c345123c033c2f6caca18def08f1f7f4c3ebeb591a63b6fceffc95cce", + "sha256:8a420169cef179d4c9064365f42d779f1e5895ad26ca0c8b4c0233920973db74", + "sha256:8defe5737c6d2179c7997242d6473587c3beb52e557f5ef0187277009f73e5e1", + "sha256:9a62b446b7d86a3909abbcd1cd3cc550a832f99c2bc37c5b22e1925438b9367b", + "sha256:9c6378449e0940476577047150fd09e242529b761dc887c9808a9a937fe990c8", + "sha256:a15b98adb7f277316f2c276c090259129ee4afca783495e212048daf846654b2", + "sha256:afbf47dc4de31fa38fd491f3705cac5307d21d4bb828a4f020ee59af412744ee", + "sha256:b3ee2aac15169fb0d45822983631466d60b762085bc4535cd39e66bea362df5f", + "sha256:b8c8b41b97fba5f62349aa285654230296829672fc9939cd7f35aab246d1c08b", + "sha256:ba547ac0b361ab4f1608afbc8432db669bd0819b3e12e29fb5fa9529a8bba81d", + "sha256:c1c2091b1489435ff85728fafeb990f073e64f6f5e81d5cd53059773e8521eb6", + "sha256:c64772786d9eee72d4d3784c28f0a636af5b0a29f3fe26ff11f55efe90c0bd85", + "sha256:cd337d3526ec5298f67d6a30bbbe4ed7e5e68862f0bf6dd21d289f8d37b7d60b", + "sha256:d29b2b99d527dbc66dd87c3c3248a5dd789d974a507f4653c969999fc7c1191b", + "sha256:d2c3684fca8a05f0ac1d9a21c1f4a266983a7ea9180efb80ffeb03861ecd01a0", + "sha256:d62e47f5d8a50099b17e2bfc1b0c7d7ecd8ba6b46b1507b58cc4f05eefc3bb1c", + "sha256:d8a2ca754e5415cde2b656c27900b19d50ba076aa05ce66e2207623d3fe41f5a", + "sha256:db6834900338fb13a9123307f0c2cbb1f890a8656fcd5e5448ae3ad5bbe8d312", + "sha256:e057f928ffe9c9b246a55b469c133b98a426297e1772ad24ce9f0c47d123bd5b", + "sha256:e50dcb81a5dfe4b7b4a4aa8f338116d127cb209559124f3694c70d6cd072b68f", + "sha256:ebd300afd2b62679203435f596b2601adafe546cb7282d5a0cd3ed99e423720f", + "sha256:ed3635353e55d28e7f4a95c8eda98a5cdc0a0b40b528433fbd41a9ae88f55b3d", + "sha256:ee580ab50e748208754ae8980cec79ec205983d8cf8b3f7c39067f3d9f2c8e22", + "sha256:f7d27a1d977a1cfef38a0e2e1ca86f09c4212666ce34e6ae542f3ed0a33bc606", + "sha256:fd93c6f5d65f254ceabe97548c709e073d6da9883343adaa51bf1a913ce93f8e", + "sha256:fe187fc31a54d7fd90352f34e8c008cf3ad5d064d08fedd3de2e8df83eb4a1cf" ], "index": "pypi", "markers": "python_version >= '3.7'", - "version": "==2.0.44" + "version": "==2.0.45" }, "typing-extensions": { "hashes": [ @@ -567,19 +557,20 @@ }, "urllib3": { "hashes": [ - "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", - "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc" + "sha256:016f9c98bb7e98085cb2b4b17b87d2c702975664e4f060c6532e64d1c1a5e797", + "sha256:ec21cddfe7724fc7cb4ba4bea7aa8e2ef36f607a4bab81aa6ce42a13dc3f03dd" ], "markers": "python_version >= '3.9'", - "version": "==2.5.0" + "version": "==2.6.2" }, "werkzeug": { "hashes": [ - "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e", - "sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746" + "sha256:2ad50fb9ed09cc3af22c54698351027ace879a0b60a3b5edf5730b2f7d876905", + "sha256:cd3cd98b1b92dc3b7b3995038826c68097dcb16f9baa63abe35f20eafeb9fe5e" ], + "index": "pypi", "markers": "python_version >= '3.9'", - "version": "==3.1.3" + "version": "==3.1.4" }, "wtforms": { "hashes": [ diff --git a/Procfile b/Procfile deleted file mode 100644 index 6675c695d7..0000000000 --- a/Procfile +++ /dev/null @@ -1,2 +0,0 @@ -release: pipenv run upgrade -web: gunicorn wsgi --chdir ./src/ diff --git a/bin/start.sh b/bin/start.sh new file mode 100644 index 0000000000..0db3bf123e --- /dev/null +++ b/bin/start.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +fuser -k 3001/tcp || true +sleep 0.5 +PY=$(pipenv --py 2>/dev/null || true) +if [ -z "$PY" ]; then + PY=$(which python || true) +fi +"$PY" -m flask run --host=0.0.0.0 --port=3001 diff --git a/dist/index.html b/dist/index.html deleted file mode 100644 index 1e8cb81dfe..0000000000 --- a/dist/index.html +++ /dev/null @@ -1,14 +0,0 @@ - - -
- - -P(o,n))void 0!==u&&0>P(u,o)?(e[r]=u,e[i]=n,r=i):(e[r]=o,e[a]=n,r=a);else{if(!(void 0!==u&&0>P(u,n)))break e;e[r]=u,e[i]=n,r=i}}}return t}return null}function P(e,t){var n=e.sortIndex-t.sortIndex;return 0!==n?n:e.id-t.id}var _=[],N=[],O=1,z=null,R=3,M=!1,I=!1,L=!1;function F(e){for(var t=S(N);null!==t;){if(null===t.callback)C(N);else{if(!(t.startTime<=e))break;C(N),t.sortIndex=t.expirationTime,T(_,t)}t=S(N)}}function D(e){if(L=!1,F(e),!I)if(null!==S(_))I=!0,n(j);else{var t=S(N);null!==t&&r(D,t.startTime-e)}}function j(e,n){I=!1,L&&(L=!1,l()),M=!0;var o=R;try{for(F(n),z=S(_);null!==z&&(!(z.expirationTime>n)||e&&!a());){var i=z.callback;if(null!==i){z.callback=null,R=z.priorityLevel;var u=i(z.expirationTime<=n);n=t.unstable_now(),"function"==typeof u?z.callback=u:z===S(_)&&C(_),F(n)}else C(_);z=S(_)}if(null!==z)var c=!0;else{var s=S(N);null!==s&&r(D,s.startTime-n),c=!1}return c}finally{z=null,R=o,M=!1}}function A(e){switch(e){case 1:return-1;case 2:return 250;case 5:return 1073741823;case 4:return 1e4;default:return 5e3}}var U=o;t.unstable_IdlePriority=5,t.unstable_ImmediatePriority=1,t.unstable_LowPriority=4,t.unstable_NormalPriority=3,t.unstable_Profiling=null,t.unstable_UserBlockingPriority=2,t.unstable_cancelCallback=function(e){e.callback=null},t.unstable_continueExecution=function(){I||M||(I=!0,n(j))},t.unstable_getCurrentPriorityLevel=function(){return R},t.unstable_getFirstCallbackNode=function(){return S(_)},t.unstable_next=function(e){switch(R){case 1:case 2:case 3:var t=3;break;default:t=R}var n=R;R=t;try{return e()}finally{R=n}},t.unstable_pauseExecution=function(){},t.unstable_requestPaint=U,t.unstable_runWithPriority=function(e,t){switch(e){case 1:case 2:case 3:case 4:case 5:break;default:e=3}var n=R;R=e;try{return t()}finally{R=n}},t.unstable_scheduleCallback=function(e,a,o){var i=t.unstable_now();if("object"==typeof o&&null!==o){var u=o.delay;u="number"==typeof u&&0i?(e.sortIndex=u,T(N,e),null===S(_)&&e===S(N)&&(L?l():L=!0,r(D,u-i))):(e.sortIndex=o,T(_,e),I||M||(I=!0,n(j))),e},t.unstable_shouldYield=function(){var e=t.unstable_now();F(e);var n=S(_);return n!==z&&null!==z&&null!==n&&null!==n.callback&&n.startTime<=e&&n.expirationTime API HOST: Start working on your project by following the Quick Start Remember to specify a real endpoint path like: Note: If you are publishing your website to Heroku, Render.com or any other hosting you probably need to follow other steps.
diff --git a/src/app.py b/src/app.py
index 1b3340c0fa..39b3cf3bca 100644
--- a/src/app.py
+++ b/src/app.py
@@ -1,7 +1,15 @@
"""
This module takes care of starting the API Server, Loading the DB and Adding the endpoints
"""
+from flask_cors import CORS as _CORS
+from datetime import datetime, timedelta
+import jwt
+from werkzeug.security import generate_password_hash, check_password_hash
+from flask_sqlalchemy import SQLAlchemy
+from flask_cors import CORS
+from flask import Flask, request, jsonify
import os
+from dotenv import load_dotenv
from flask import Flask, request, jsonify, url_for, send_from_directory
from flask_migrate import Migrate
from flask_swagger import swagger
@@ -11,62 +19,173 @@
from api.admin import setup_admin
from api.commands import setup_commands
-# from models import Person
-
ENV = "development" if os.getenv("FLASK_DEBUG") == "1" else "production"
static_file_dir = os.path.join(os.path.dirname(
os.path.realpath(__file__)), '../dist/')
app = Flask(__name__)
app.url_map.strict_slashes = False
-# database condiguration
+load_dotenv()
+if not os.path.exists('.env'):
+ load_dotenv('.env.example')
+
+_CORS(app)
db_url = os.getenv("DATABASE_URL")
if db_url is not None:
app.config['SQLALCHEMY_DATABASE_URI'] = db_url.replace(
"postgres://", "postgresql://")
else:
- app.config['SQLALCHEMY_DATABASE_URI'] = "sqlite:////tmp/test.db"
+ app.config['SQLALCHEMY_DATABASE_URI'] = "sqlite:///database.db"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
MIGRATE = Migrate(app, db, compare_type=True)
db.init_app(app)
-
-# add the admin
setup_admin(app)
-
-# add the admin
setup_commands(app)
-
-# Add all endpoints form the API with a "api" prefix
-app.register_blueprint(api, url_prefix='/api')
-
-# Handle/serialize errors like a JSON object
+app.register_blueprint(api)
@app.errorhandler(APIException)
def handle_invalid_usage(error):
return jsonify(error.to_dict()), error.status_code
-# generate sitemap with all your endpoints
-
+app.config['SECRET_KEY'] = os.getenv('JWT_SECRET_KEY') or os.getenv('JWT_SECRET', 'super-secret-key')
+
+
+@app.route('/signup', methods=['POST'])
+def signup():
+ data = request.get_json() or {}
+ email = data.get('email')
+ password = data.get('password')
+ first_name = data.get('first_name')
+ last_name = data.get('last_name')
+ from api.models import User
+ if User.query.filter_by(email=email).first():
+ return jsonify({'msg': 'Usuario ya existe'}), 400
+ hashed_password = generate_password_hash(password, method='pbkdf2:sha256')
+ user = User(email=email, password=hashed_password,
+ first_name=first_name, last_name=last_name, is_active=True)
+ db.session.add(user)
+ db.session.commit()
+ return jsonify({'msg': 'Usuario creado'}), 201
+
+
+@app.route('/login', methods=['POST'])
+def login():
+ data = request.get_json()
+ email = data.get('email')
+ password = data.get('password')
+ from api.models import User
+ user = User.query.filter_by(email=email).first()
+ if not user or not check_password_hash(user.password, password):
+ return jsonify({'msg': 'Credenciales inválidas'}), 401
+ access_token = jwt.encode({
+ 'user_id': user.id,
+ 'exp': datetime.utcnow() + timedelta(minutes=15)
+ }, app.config['SECRET_KEY'], algorithm='HS256')
+
+ refresh_token = jwt.encode({
+ 'user_id': user.id,
+ 'exp': datetime.utcnow() + timedelta(days=7),
+ 'type': 'refresh'
+ }, app.config['SECRET_KEY'], algorithm='HS256')
+
+ if isinstance(access_token, bytes):
+ access_token = access_token.decode('utf-8')
+ if isinstance(refresh_token, bytes):
+ refresh_token = refresh_token.decode('utf-8')
+
+ return jsonify({'token': access_token, 'refresh_token': refresh_token})
+
+
+@app.route('/refresh', methods=['POST'])
+def refresh():
+ data = request.get_json() or {}
+ refresh_token = data.get('refresh_token')
+ if not refresh_token:
+ return jsonify({'msg': 'Refresh token requerido'}), 400
+ try:
+ payload = jwt.decode(
+ refresh_token, app.config['SECRET_KEY'], algorithms=['HS256'])
+ if payload.get('type') != 'refresh':
+ return jsonify({'msg': 'Token inválido'}), 401
+ from api.models import User
+ user = User.query.get(payload.get('user_id'))
+ if not user:
+ return jsonify({'msg': 'Usuario no encontrado'}), 404
+ access_token = jwt.encode({
+ 'user_id': user.id,
+ 'exp': datetime.utcnow() + timedelta(minutes=15)
+ }, app.config['SECRET_KEY'], algorithm='HS256')
+ if isinstance(access_token, bytes):
+ access_token = access_token.decode('utf-8')
+ return jsonify({'token': access_token})
+ except jwt.ExpiredSignatureError:
+ return jsonify({'msg': 'Refresh token expirado'}), 401
+ except Exception:
+ return jsonify({'msg': 'Refresh token inválido'}), 401
+
+
+# La ruta /private está implementada en el blueprint `api`.
@app.route('/')
-def sitemap():
- if ENV == "development":
- return generate_sitemap(app)
- return send_from_directory(static_file_dir, 'index.html')
-
-# any other endpoint will try to serve it like a static file
-@app.route('/Rigo welcomes you to your API!!
+ Missing BACKEND_URL env variable
@@ -16,7 +16,7 @@ export const BackendURL = () => (
+