{"id":16526249,"url":"https://github.com/sbathgate/flask-react-aws","last_synced_at":"2025-03-03T03:45:21.244Z","repository":{"id":39841595,"uuid":"269788507","full_name":"sbathgate/flask-react-aws","owner":"sbathgate","description":null,"archived":false,"fork":false,"pushed_at":"2023-01-06T08:03:09.000Z","size":8618,"stargazers_count":0,"open_issues_count":23,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-01-13T15:15:21.592Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sbathgate.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-06-05T21:56:46.000Z","updated_at":"2020-06-15T19:28:20.000Z","dependencies_parsed_at":"2023-02-05T16:32:01.351Z","dependency_job_id":null,"html_url":"https://github.com/sbathgate/flask-react-aws","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sbathgate%2Fflask-react-aws","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sbathgate%2Fflask-react-aws/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sbathgate%2Fflask-react-aws/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sbathgate%2Fflask-react-aws/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sbathgate","download_url":"https://codeload.github.com/sbathgate/flask-react-aws/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241605740,"owners_count":19989608,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-11T17:26:47.177Z","updated_at":"2025-03-03T03:45:21.221Z","avatar_url":"https://github.com/sbathgate.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Authentication with Flask, React, and Docker\r\n\r\n## Quick start\r\n* Clone GitLab Repo: `$ git clone https://gitlab.com/sbathgate/flask-tdd-docker.git`\r\n* Switch to project root: `$ cd flask-tdd-docker/`\r\n* Build the images: `$ docker-compose build`\r\n* Run the containers: `$ docker-compose up -d`\r\n* Create the database: `$ docker-compose exec users python manage.py recreate_db`\r\n* Seed the database: `$ docker-compose exec users python manage.py seed_db`\r\n\r\n\r\n## File Structure\r\n#### Within the download you'll find the following directories and files:\r\n```\r\n├── .gitignore\r\n├── .gitlab-ci.yml\r\n├── Dockerfile.deploy\r\n├── README.md\r\n├── docker-compose.yml\r\n├── makefile\r\n├── release.sh\r\n└── services\r\n    ├── client\r\n    │   ├── .dockerignore\r\n    │   ├── .eslintrc.json\r\n    │   ├── .gitignore\r\n    │   ├── Dockerfile\r\n    │   ├── Dockerfile.ci\r\n    │   ├── README.md\r\n    │   ├── coverage\r\n    │   ├── package-lock.json\r\n    │   ├── package.json\r\n    │   ├── public\r\n    │   │   ├── favicon.ico\r\n    │   │   ├── index.html\r\n    │   │   ├── logo192.png\r\n    │   │   ├── logo512.png\r\n    │   │   ├── manifest.json\r\n    │   │   └── robots.txt\r\n    │   └── src\r\n    │       ├── App.jsx\r\n    │       ├── components\r\n    │       │   ├── About.jsx\r\n    │       │   ├── AddUser.jsx\r\n    │       │   ├── LoginForm.jsx\r\n    │       │   ├── Message.jsx\r\n    │       │   ├── NavBar.css\r\n    │       │   ├── NavBar.jsx\r\n    │       │   ├── RegisterForm.jsx\r\n    │       │   ├── UserStatus.jsx\r\n    │       │   ├── UsersList.jsx\r\n    │       │   ├── __tests__\r\n    │       │   │   ├── About.test.jsx\r\n    │       │   │   ├── AddUser.test.jsx\r\n    │       │   │   ├── App.test.jsx\r\n    │       │   │   ├── LoginForm.test.jsx\r\n    │       │   │   ├── Message.test.jsx\r\n    │       │   │   ├── NavBar.test.jsx\r\n    │       │   │   ├── RegisterForm.test.jsx\r\n    │       │   │   ├── UserStatus.test.jsx\r\n    │       │   │   ├── UsersList.test.jsx\r\n    │       │   │   └── __snapshots__\r\n    │       │   │       ├── About.test.jsx.snap\r\n    │       │   │       ├── AddUser.test.jsx.snap\r\n    │       │   │       ├── App.test.jsx.snap\r\n    │       │   │       ├── LoginForm.test.jsx.snap\r\n    │       │   │       ├── Message.test.jsx.snap\r\n    │       │   │       ├── NavBar.test.jsx.snap\r\n    │       │   │       ├── RegisterForm.test.jsx.snap\r\n    │       │   │       ├── UserStatus.test.jsx.snap\r\n    │       │   │       └── UsersList.test.jsx.snap\r\n    │       │   └── form.css\r\n    │       ├── index.js\r\n    │       └── setupTests.js\r\n    └── users\r\n        ├── .coverage\r\n        ├── .coveragerc\r\n        ├── .dockerignore\r\n        ├── .flake8\r\n        ├── Dockerfile\r\n        ├── Dockerfile.prod\r\n        ├── entrypoint.sh\r\n        ├── htmlcov\r\n        ├── manage.py\r\n        ├── project\r\n        │   ├── __init__.py\r\n        │   ├── .isort.cfg\r\n        │   ├── api\r\n        │   │   ├── __init__.py\r\n        │   │   ├── auth.py\r\n        │   │   ├── ping.py\r\n        │   │   └── users\r\n        │   │       ├── __init__.py\r\n        │   │       ├── admin.py\r\n        │   │       ├── crud.py\r\n        │   │       ├── models.py\r\n        │   │       └── views.py\r\n        │   ├── config.py\r\n        │   ├── db\r\n        │   │   ├── Dockerfile\r\n        │   │   └── create.sql\r\n        │   └── tests\r\n        │       ├── __init__.py\r\n        │       ├── conftest.py\r\n        │       ├── pytest.ini\r\n        │       ├── test_admin.py\r\n        │       ├── test_auth.py\r\n        │       ├── test_config.py\r\n        │       ├── test_ping.py\r\n        │       ├── test_user_model.py\r\n        │       ├── test_users.py\r\n        │       └── test_users_unit.py\r\n        ├── requirements-dev.txt\r\n        ├── requirements.txt\r\n        └── setup.cfg\r\n```\r\n\r\n## Common Commands\r\n### Docker Compose\r\n#### Set the `REACT_APP_USERS_SERVICE_URL` environment variable:\r\n```$ export REACT_APP_USERS_SERVICE_URL=http://localhost:5001```\r\n\r\n#### Build the images:\r\n```$ docker-compose build```\r\n\r\n#### Build and spin up the new containers:\r\n```$ docker-compose up -d --build```\r\n\r\n#### To stop the containers:\r\n```$ docker-compose stop```\r\n\r\n#### To bring down the containers:\r\n```$ docker-compose down```\r\n\r\n### Client\r\n#### Run the tests without coverage:\r\n```$ docker-compose exec client npm test```\r\n\r\n#### Run the tests with coverage:\r\n```$ docker-compose exec client npm test --coverage```\r\n\r\n#### Check formatting with Prettier:\r\n```$ docker-compose exec client npm run prettier:check```\r\n\r\n#### Lint with eslint:\r\n```$ docker-compose exec client npm run lint```\r\n\r\n### Server\r\n#### Create the database:\r\n```$ docker-compose exec users python manage.py recreate_db```\r\n\r\n#### Seed the database:\r\n```$ docker-compose exec users python manage.py seed_db```\r\n\r\n#### Run the tests without coverage:\r\n```$ docker-compose exec users python -m pytest \"project/tests\" -p no:warnings```\r\n\r\n#### Run the tests with coverage:\r\n```$ docker-compose exec users python -m pytest \"project/tests\" -p no:warnings --cov=\"project\"```\r\n\r\n#### Lint with Flake8:\r\n```$ docker-compose exec users flake8 project```\r\n\r\n#### Run Black and isort with check options:\r\n```$ docker-compose exec users black project --check```\r\n\r\n```$ docker-compose exec users /bin/sh -c \"isort project/**/*.py --check-only\"```\r\n\r\n#### Make code changes with Black and isort:\r\n```$ docker-compose exec users black project```\r\n\r\n```$ docker-compose exec users /bin/sh -c \"isort project/**/*.py\"```\r\n\r\n### Postgres\r\n#### Want to access the database via psql?\r\n```$ docker-compose exec users-db psql -U postgres```\r\n\r\n##### Then, you can connect to the database and run SQL queries. For example:\r\n```# \\c users_dev```\r\n```# select * from users;```\r\n\r\n### Other Commands\r\n#### Want to force a build?\r\n```$ docker-compose build --no-cache```\r\n\r\n#### Remove images:\r\n```$ docker rmi $(docker images -q)```\r\n\r\n## TODO:\r\n#### My notes:\r\n- [ ] Configure singular setup.cfg for flake8, black and isort.\r\n\r\n#### Test-Driven Development with Python, Flask and Docker\r\n- [ ] Test coverage: Add more tests to increase the overall test coverage.\r\n- [ ] DRY out the code: There's plenty of places in the code base that could be refactored.\r\n- [x] Flask-CORS: Use Flask-CORS to handle cross-origin requests -- e.g., requests that originate from a different protocol, IP address, domain name, or port.\r\n- [ ] Caching: Add caching (where appropriate) with Flask-Cache.\r\n- [ ] Database migrations: Manage changes to the database through SQLAlchemy database migrations with the Flask-Migrate extension.\r\n\r\n#### Authentication with Flask, React, and Docker\r\n##### Part 2: Auth Routes\r\n- [ ] Try to increase the test coverage. Add tests for the remaining edge cases.\r\n- [ ] Add unit tests as well in a new file called test_auth_unit.py. Use monkeypatch like we did in test_users_unit.py.\r\n- [ ] We're currently allowing duplicate usernames. Is this okay? Probably not. Practice TDD on your own and add a test for this and then implement the code.\r\n- [ ] We should probably invalidate refresh tokens. We could create a new database table for this and only store a single refresh token per user.\r\n##### Part 3: React Auth - Part 2\r\n- [ ] Write test to ensure UserStatus redirects to login if invalid token.\r\n- [ ] Revoke/Blacklist tokens in order to prevent abuse\r\n- [ ] Adding email confirmation between user registration and login\r\n- [ ] EXPLORE: For added protection, instead of storing refresh tokens in LocalStorage, how would you return tokens from the server in HttpOnly cookies? The Flask-JWT-Extended extension may be worth looking at.\r\n##### Part 3: React Alert Messages\r\n- [ ] Add test to ensure message disappears when 1: a user click the 'x', 2: a new message is flashed, 3: three seconds pass\r\n##### Part 3: Update Components\r\n- [ ] Add ability to update user. Reuse same modal.\r\n- [ ] Prevent currently logged in person from deleting themselves.\r\n\r\n## Valuable Notes\r\nIf you get a compilation error due to Module not found: Can't resolve 'temp'; try installing temp in the running container:\r\n```$ docker-compose exec client npm install react-router-dom```\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsbathgate%2Fflask-react-aws","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsbathgate%2Fflask-react-aws","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsbathgate%2Fflask-react-aws/lists"}