├── .devcontainer ├── Dockerfile ├── devcontainer.json └── docker-compose.yml ├── .env.example ├── .eslintrc ├── .github └── settings.yml ├── .gitignore ├── .gitpod.Dockerfile ├── .gitpod.yml ├── .vscode └── settings.json ├── 4geeks.ico ├── Dockerfile.render ├── Pipfile ├── Pipfile.lock ├── Procfile ├── README.md ├── database.sh ├── dist └── index.html ├── docs ├── CHANGE_LOG.md ├── HELP.md └── assets │ ├── db_config.gif │ ├── debugging.gif │ ├── debugging_icon.png │ ├── diagram.png │ ├── env-file.png │ ├── env_variables.gif │ ├── greeting.py │ ├── reset_migrations.bash │ └── rigo-baby.jpg ├── learn.json ├── package-lock.json ├── package.json ├── public ├── 4geeks.ico ├── bundle.js ├── bundle.js.LICENSE.txt ├── index.html └── rigo-baby.jpg ├── pycodestyle.cfg ├── render.yaml ├── render_build.sh ├── requirements.txt ├── src ├── api │ ├── __init__.py │ ├── admin.py │ ├── commands.py │ ├── models.py │ ├── routes.py │ └── utils.py ├── app.py ├── front │ ├── img │ │ ├── how-to.png │ │ └── rigo-baby.jpg │ ├── js │ │ ├── component │ │ │ ├── backendURL.js │ │ │ ├── footer.js │ │ │ ├── navbar.js │ │ │ └── scrollToTop.js │ │ ├── index.js │ │ ├── layout.js │ │ ├── pages │ │ │ ├── demo.js │ │ │ ├── home.js │ │ │ └── single.js │ │ └── store │ │ │ ├── appContext.js │ │ │ └── flux.js │ └── styles │ │ ├── home.css │ │ └── index.css └── wsgi.py ├── template.html ├── webpack.common.js ├── webpack.dev.js └── webpack.prod.js /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/devcontainers/python:0-3.10 2 | 3 | ENV PYTHONUNBUFFERED 1 4 | 5 | # [Optional] If your requirements rarely change, uncomment this section to add them to the image. 6 | # COPY requirements.txt /tmp/pip-tmp/ 7 | # RUN pip3 --disable-pip-version-check --no-cache-dir install -r /tmp/pip-tmp/requirements.txt \ 8 | # && rm -rf /tmp/pip-tmp 9 | 10 | #[Optional] Uncomment this section to install additional OS packages. 11 | RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ 12 | && apt-get -y install --no-install-recommends postgresql-client 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | // README at: https://github.com/devcontainers/templates/tree/main/src/postgres 3 | { 4 | "name": "Python 3 & PostgreSQL", 5 | "dockerComposeFile": "docker-compose.yml", 6 | "service": "app", 7 | "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", 8 | "features": { 9 | "ghcr.io/devcontainers/features/github-cli:1": { 10 | "installDirectlyFromGitHubRelease": true, 11 | "version": "latest" 12 | }, 13 | "ghcr.io/devcontainers/features/node:1": { 14 | "nodeGypDependencies": true, 15 | "version": "lts" 16 | } 17 | }, 18 | 19 | // Features to add to the dev container. More info: https://containers.dev/features. 20 | // "features": {}, 21 | 22 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 23 | // This can be used to network with other containers or the host. 24 | "forwardPorts": [3000, 3001], 25 | 26 | "onCreateCommand": "(cp .env.example .env || echo \".env creation failed\"); (pipenv install || echo \"pipenv install failed\"); (bash database.sh || echo \"database.sh failed\");", 27 | // Use 'postCreateCommand' to run commands after the container is created. 28 | "postCreateCommand": "python docs/assets/greeting.py both > /workspaces/.codespaces/shared/first-run-notice.txt && npm install", 29 | 30 | // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. 31 | // "remoteUser": "root" 32 | } 33 | -------------------------------------------------------------------------------- /.devcontainer/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | 3 | services: 4 | app: 5 | build: 6 | context: .. 7 | dockerfile: .devcontainer/Dockerfile 8 | 9 | volumes: 10 | - ../..:/workspaces:cached 11 | 12 | # Overrides default command so things don't shut down after the process ends. 13 | command: sleep infinity 14 | 15 | # Runs app on the same network as the database container, allows "forwardPorts" in devcontainer.json function. 16 | network_mode: service:db 17 | 18 | # Use "forwardPorts" in **devcontainer.json** to forward an app port locally. 19 | # (Adding the "ports" property to this file will not forward from a Codespace.) 20 | 21 | db: 22 | image: postgres:latest 23 | restart: unless-stopped 24 | volumes: 25 | - postgres-data:/var/lib/postgresql/data 26 | environment: 27 | POSTGRES_USER: gitpod 28 | POSTGRES_DB: example 29 | POSTGRES_PASSWORD: postgres 30 | 31 | # Add "forwardPorts": ["5432"] to **devcontainer.json** to forward PostgreSQL locally. 32 | # (Adding the "ports" property to this file will not forward from a Codespace.) 33 | 34 | volumes: 35 | postgres-data: 36 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | # This file includes global variables that will be available inside your project 2 | # 1. In the front end code you can access this variables like this: console.log(process.env.VARIABLE_NAME) 3 | # 1. In the back end code you access the variable by importing os and then typing print(os.getenv('VARIABLE_NAME')) 4 | 5 | # Back-End Variables 6 | DATABASE_URL=postgres://gitpod:postgres@localhost:5432/example 7 | FLASK_APP_KEY="any key works" 8 | FLASK_APP=src/app.py 9 | FLASK_DEBUG=1 10 | DEBUG=TRUE 11 | 12 | # Front-End Variables 13 | BASENAME=/ 14 | #BACKEND_URL= 15 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "@babel/eslint-parser", 3 | "plugins": [ 4 | "react" 5 | ], 6 | "env": { 7 | "browser": true, 8 | "es6": true 9 | }, 10 | "extends": [ "plugin:react/recommended"], 11 | "rules": { 12 | "strict":0, 13 | "no-unused-vars": 0, 14 | "no-console": 1, 15 | "no-mixed-spaces-and-tabs": 0, 16 | "no-debugger": 0, 17 | "semi": ["error", "always"], 18 | "allowImportExportEverywhere": false, 19 | "indent": "off", 20 | "react/jsx-indent": "off", 21 | "react/jsx-indent-props": "off", 22 | "comma-dangle": [1, { //when to use the last comma 23 | "arrays": "never", 24 | "objects": "never", 25 | "imports": "never", 26 | "exports": "never", 27 | "functions": "ignore", 28 | }], 29 | "react/prop-types": [2] 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /.github/settings.yml: -------------------------------------------------------------------------------- 1 | repository: 2 | has_wiki: false 3 | 4 | # Labels: define labels for Issues and Pull Requests 5 | labels: 6 | - name: "bug" 7 | color: c10000 8 | - name: ":nerd_face: 4geeks student" 9 | color: 7057ff 10 | - name: "enhancement" 11 | color: a2eeef 12 | - name: "first-timers-only" 13 | color: 69db89 14 | - name: "good first issue" 15 | color: 7057ff 16 | - name: "help wanted" 17 | color: 008672 18 | - name: ":star: P1" 19 | color: fbca04 20 | - name: ":star: P2" 21 | color: fbca04 22 | - name: ":memo: bc-writter" 23 | color: 98bde2 24 | - name: ":computer: bc-coder" 25 | color: 98bde2 26 | - name: ":beetle: bc-inspector" 27 | color: 98bde2 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ignore all files starting with . 2 | .* 3 | 4 | # track this file .gitignore (i.e. do NOT ignore it) 5 | !.gitignore 6 | !.github 7 | php_errorlog 8 | .log 9 | 10 | # do not ignore gitpod and render files 11 | !.gitpod.Dockerfile 12 | !.welcome 13 | !.devcontainer 14 | !.devcontainer/* 15 | !Dockerfile.render 16 | !.gitpod.yml 17 | !render.yml 18 | !.render-buildpacks.json 19 | 20 | # track webpack configs (i.e. do NOT ignore it) 21 | !composer.json 22 | !webpack.config.js 23 | !package.json 24 | !webpack.production.js 25 | !webpack.development.js 26 | 27 | # track readme.md in the root (i.e. do NOT ignore it) 28 | !README.md 29 | 30 | # ignore OS generated files 31 | ehthumbs.db 32 | Thumbs.db 33 | 34 | # ignore Editor files 35 | *.sublime-project 36 | *.sublime-workspace 37 | *.komodoproject 38 | 39 | # ignore log files and databases 40 | *.log 41 | *.sql 42 | *.sqlite 43 | 44 | # ignore compiled files 45 | *.com 46 | *.class 47 | *.dll 48 | *.exe 49 | *.o 50 | *.so 51 | 52 | # ignore packaged files 53 | *.7z 54 | *.dmg 55 | *.gz 56 | *.iso 57 | *.jar 58 | *.rar 59 | *.tar 60 | *.zip 61 | 62 | # ignore node/grunt dependency directories 63 | node_modules/ 64 | 65 | # webpack output 66 | dist/* 67 | !public/ 68 | !public/* 69 | 70 | # ignore the dist directory were our bundle files are going to be 71 | !.gitkeep 72 | !.htaccess 73 | !.eslintrc 74 | !.env.example 75 | .now 76 | 77 | # backend stuff 78 | .venv 79 | database.database 80 | database.db 81 | diagram.png 82 | __pycache__/ 83 | -------------------------------------------------------------------------------- /.gitpod.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM gitpod/workspace-postgres:latest 2 | 3 | SHELL ["/bin/bash", "-c"] 4 | 5 | RUN sudo apt-get update \ 6 | && sudo apt-get update \ 7 | && sudo apt-get install -y redis-server \ 8 | && sudo apt-get clean \ 9 | && sudo rm -rf /var/cache/apt/* /var/lib/apt/lists/* /tmp/* 10 | 11 | # That Gitpod install pyenv for me? no, thanks 12 | WORKDIR /home/gitpod/ 13 | RUN rm .pyenv -Rf 14 | RUN rm .gp_pyenv.d -Rf 15 | RUN curl https://pyenv.run | bash 16 | 17 | 18 | RUN pyenv update && pyenv install 3.10.7 && pyenv global 3.10.7 19 | RUN pip install pipenv yapf 20 | RUN npm i heroku -g 21 | 22 | # remove PIP_USER environment 23 | USER gitpod 24 | RUN if ! grep -q "export PIP_USER=no" "$HOME/.bashrc"; then printf '%s\n' "export PIP_USER=no" >> "$HOME/.bashrc"; fi 25 | RUN echo "" >> $HOME/.bashrc 26 | RUN echo "unset DATABASE_URL" >> $HOME/.bashrc 27 | RUN echo "export DATABASE_URL" >> $HOME/.bashrc 28 | -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | image: 2 | file: .gitpod.Dockerfile 3 | ports: 4 | - port: 3000 5 | onOpen: open-browser 6 | visibility: public 7 | - port: 3001 8 | onOpen: open-preview 9 | visibility: public 10 | - port: 5432 11 | onOpen: ignore 12 | tasks: 13 | - init: > 14 | (cp .env.example .env || true) && 15 | pipenv install && 16 | psql -U gitpod -c 'CREATE DATABASE example;' && 17 | psql -U gitpod -c 'CREATE EXTENSION unaccent;' -d example && 18 | psql -c "ALTER USER gitpod PASSWORD 'postgres';" && 19 | bash database.sh && 20 | python docs/assets/greeting.py back 21 | - command: > 22 | npm install && 23 | python docs/assets/greeting.py front 24 | openMode: split-right 25 | 26 | vscode: 27 | extensions: 28 | - esbenp.prettier-vscode 29 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true, 3 | "editor.defaultFormatter": "esbenp.prettier-vscode", 4 | "workbench.editorAssociations": { 5 | "*.md": "vscode.markdown.preview.editor" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /4geeks.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4GeeksAcademy/react-flask-hello-deprecated/f7f39286c7d1b32efdc2e308ca5721f314b013de/4geeks.ico -------------------------------------------------------------------------------- /Dockerfile.render: -------------------------------------------------------------------------------- 1 | FROM node:16 2 | 3 | RUN apt update \ 4 | && apt install software-properties-common \ 5 | && add-apt-repository ppa:deadsnakes/ppa \ 6 | && apt update \ 7 | && apt install python3.10 8 | 9 | WORKDIR /opt/app 10 | COPY --from=build /opt/app/venv /venv 11 | 12 | ENV PATH="/opt/app/venv/bin:$PATH" 13 | ENV NODE_ENV=container -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | name = "pypi" 3 | url = "https://pypi.org/simple" 4 | verify_ssl = true 5 | 6 | [dev-packages] 7 | 8 | [packages] 9 | flask = "*" 10 | sqlalchemy = "==1.4.46" 11 | flask-sqlalchemy = "*" 12 | flask-migrate = "*" 13 | flask-swagger = "*" 14 | psycopg2-binary = "*" 15 | python-dotenv = "*" 16 | flask-cors = "*" 17 | gunicorn = "*" 18 | cloudinary = "*" 19 | flask-admin = "*" 20 | typing-extensions = "*" 21 | flask-jwt-extended = "==4.6.0" 22 | wtforms = "==3.1.2" 23 | 24 | [requires] 25 | python_version = "3.10" 26 | 27 | [scripts] 28 | start="flask run -p 3001 -h 0.0.0.0" 29 | init="flask db init" 30 | migrate="flask db migrate" 31 | local="heroku local" 32 | upgrade="flask db upgrade" 33 | downgrade="flask db downgrade" 34 | insert-test-data="flask insert-test-data" 35 | reset_db="bash ./docs/assets/reset_migrations.bash" 36 | 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' " 37 | -------------------------------------------------------------------------------- /Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "74f92d76f687bb774828613a3a513123fe2ffdb429b95b351d29721dddfd3fb8" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "3.10" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "alembic": { 20 | "hashes": [ 21 | "sha256:6880dec4f28dd7bd999d2ed13fbe7c9d4337700a44d11a524c0ce0c59aaf0dbd", 22 | "sha256:e8a6ff9f3b1887e1fed68bfb8fb9a000d8f61c21bdcc85b67bb9f87fcbc4fce3" 23 | ], 24 | "markers": "python_version >= '3.7'", 25 | "version": "==1.9.2" 26 | }, 27 | "certifi": { 28 | "hashes": [ 29 | "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3", 30 | "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18" 31 | ], 32 | "markers": "python_version >= '3.6'", 33 | "version": "==2022.12.7" 34 | }, 35 | "click": { 36 | "hashes": [ 37 | "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e", 38 | "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48" 39 | ], 40 | "markers": "python_version >= '3.7'", 41 | "version": "==8.1.3" 42 | }, 43 | "cloudinary": { 44 | "hashes": [ 45 | "sha256:f52a1f5eb2c6820f13aa01c109caa5937ad3fd6caf5967817d0ef6c113403afc" 46 | ], 47 | "index": "pypi", 48 | "version": "==1.31.0" 49 | }, 50 | "flask": { 51 | "hashes": [ 52 | "sha256:642c450d19c4ad482f96729bd2a8f6d32554aa1e231f4f6b4e7e5264b16cca2b", 53 | "sha256:b9c46cc36662a7949f34b52d8ec7bb59c0d74ba08ba6cb9ce9adc1d8676d9526" 54 | ], 55 | "index": "pypi", 56 | "version": "==2.2.2" 57 | }, 58 | "flask-admin": { 59 | "hashes": [ 60 | "sha256:424ffc79b7b0dfff051555686ea12e86e48dffacac14beaa319fb4502ac40988" 61 | ], 62 | "index": "pypi", 63 | "version": "==1.6.0" 64 | }, 65 | "flask-cors": { 66 | "hashes": [ 67 | "sha256:74efc975af1194fc7891ff5cd85b0f7478be4f7f59fe158102e91abb72bb4438", 68 | "sha256:b60839393f3b84a0f3746f6cdca56c1ad7426aa738b70d6c61375857823181de" 69 | ], 70 | "index": "pypi", 71 | "version": "==3.0.10" 72 | }, 73 | "flask-migrate": { 74 | "hashes": [ 75 | "sha256:8662a9dd391ce36deeaf3265987319c20fdb4c8a45306a32ba4f8224459abed4", 76 | "sha256:a0062c8d3f32de02847086b46cfc389412f78c71c89a619ebd7097e89d72ea4b" 77 | ], 78 | "index": "pypi", 79 | "version": "==4.0.3" 80 | }, 81 | "flask-sqlalchemy": { 82 | "hashes": [ 83 | "sha256:2764335f3c9d7ebdc9ed6044afaf98aae9fa50d7a074cef55dde307ec95903ec", 84 | "sha256:add5750b2f9cd10512995261ee2aa23fab85bd5626061aa3c564b33bb4aa780a" 85 | ], 86 | "index": "pypi", 87 | "version": "==3.0.3" 88 | }, 89 | "flask-swagger": { 90 | "hashes": [ 91 | "sha256:3caddb1311388eafc86f82f8e64ba386a5df6b84e5f16dfae19ca08173eba216", 92 | "sha256:b4085f5bc36df4c20b6548cd1413adc9cf35719b0f0695367cd542065145294d" 93 | ], 94 | "index": "pypi", 95 | "version": "==0.2.14" 96 | }, 97 | "greenlet": { 98 | "hashes": [ 99 | "sha256:03a8f4f3430c3b3ff8d10a2a86028c660355ab637cee9333d63d66b56f09d52a", 100 | "sha256:0bf60faf0bc2468089bdc5edd10555bab6e85152191df713e2ab1fcc86382b5a", 101 | "sha256:18a7f18b82b52ee85322d7a7874e676f34ab319b9f8cce5de06067384aa8ff43", 102 | "sha256:18e98fb3de7dba1c0a852731c3070cf022d14f0d68b4c87a19cc1016f3bb8b33", 103 | "sha256:1a819eef4b0e0b96bb0d98d797bef17dc1b4a10e8d7446be32d1da33e095dbb8", 104 | "sha256:26fbfce90728d82bc9e6c38ea4d038cba20b7faf8a0ca53a9c07b67318d46088", 105 | "sha256:2780572ec463d44c1d3ae850239508dbeb9fed38e294c68d19a24d925d9223ca", 106 | "sha256:283737e0da3f08bd637b5ad058507e578dd462db259f7f6e4c5c365ba4ee9343", 107 | "sha256:2d4686f195e32d36b4d7cf2d166857dbd0ee9f3d20ae349b6bf8afc8485b3645", 108 | "sha256:2dd11f291565a81d71dab10b7033395b7a3a5456e637cf997a6f33ebdf06f8db", 109 | "sha256:30bcf80dda7f15ac77ba5af2b961bdd9dbc77fd4ac6105cee85b0d0a5fcf74df", 110 | "sha256:32e5b64b148966d9cccc2c8d35a671409e45f195864560829f395a54226408d3", 111 | "sha256:36abbf031e1c0f79dd5d596bfaf8e921c41df2bdf54ee1eed921ce1f52999a86", 112 | "sha256:3a06ad5312349fec0ab944664b01d26f8d1f05009566339ac6f63f56589bc1a2", 113 | "sha256:3a51c9751078733d88e013587b108f1b7a1fb106d402fb390740f002b6f6551a", 114 | "sha256:3c9b12575734155d0c09d6c3e10dbd81665d5c18e1a7c6597df72fd05990c8cf", 115 | "sha256:3f6ea9bd35eb450837a3d80e77b517ea5bc56b4647f5502cd28de13675ee12f7", 116 | "sha256:4b58adb399c4d61d912c4c331984d60eb66565175cdf4a34792cd9600f21b394", 117 | "sha256:4d2e11331fc0c02b6e84b0d28ece3a36e0548ee1a1ce9ddde03752d9b79bba40", 118 | "sha256:5454276c07d27a740c5892f4907c86327b632127dd9abec42ee62e12427ff7e3", 119 | "sha256:561091a7be172ab497a3527602d467e2b3fbe75f9e783d8b8ce403fa414f71a6", 120 | "sha256:6c3acb79b0bfd4fe733dff8bc62695283b57949ebcca05ae5c129eb606ff2d74", 121 | "sha256:703f18f3fda276b9a916f0934d2fb6d989bf0b4fb5a64825260eb9bfd52d78f0", 122 | "sha256:7492e2b7bd7c9b9916388d9df23fa49d9b88ac0640db0a5b4ecc2b653bf451e3", 123 | "sha256:76ae285c8104046b3a7f06b42f29c7b73f77683df18c49ab5af7983994c2dd91", 124 | "sha256:7cafd1208fdbe93b67c7086876f061f660cfddc44f404279c1585bbf3cdc64c5", 125 | "sha256:7efde645ca1cc441d6dc4b48c0f7101e8d86b54c8530141b09fd31cef5149ec9", 126 | "sha256:88d9ab96491d38a5ab7c56dd7a3cc37d83336ecc564e4e8816dbed12e5aaefc8", 127 | "sha256:8eab883b3b2a38cc1e050819ef06a7e6344d4a990d24d45bc6f2cf959045a45b", 128 | "sha256:910841381caba4f744a44bf81bfd573c94e10b3045ee00de0cbf436fe50673a6", 129 | "sha256:9190f09060ea4debddd24665d6804b995a9c122ef5917ab26e1566dcc712ceeb", 130 | "sha256:937e9020b514ceedb9c830c55d5c9872abc90f4b5862f89c0887033ae33c6f73", 131 | "sha256:94c817e84245513926588caf1152e3b559ff794d505555211ca041f032abbb6b", 132 | "sha256:971ce5e14dc5e73715755d0ca2975ac88cfdaefcaab078a284fea6cfabf866df", 133 | "sha256:9d14b83fab60d5e8abe587d51c75b252bcc21683f24699ada8fb275d7712f5a9", 134 | "sha256:9f35ec95538f50292f6d8f2c9c9f8a3c6540bbfec21c9e5b4b751e0a7c20864f", 135 | "sha256:a1846f1b999e78e13837c93c778dcfc3365902cfb8d1bdb7dd73ead37059f0d0", 136 | "sha256:acd2162a36d3de67ee896c43effcd5ee3de247eb00354db411feb025aa319857", 137 | "sha256:b0ef99cdbe2b682b9ccbb964743a6aca37905fda5e0452e5ee239b1654d37f2a", 138 | "sha256:b80f600eddddce72320dbbc8e3784d16bd3fb7b517e82476d8da921f27d4b249", 139 | "sha256:b864ba53912b6c3ab6bcb2beb19f19edd01a6bfcbdfe1f37ddd1778abfe75a30", 140 | "sha256:b9ec052b06a0524f0e35bd8790686a1da006bd911dd1ef7d50b77bfbad74e292", 141 | "sha256:ba2956617f1c42598a308a84c6cf021a90ff3862eddafd20c3333d50f0edb45b", 142 | "sha256:bdfea8c661e80d3c1c99ad7c3ff74e6e87184895bbaca6ee8cc61209f8b9b85d", 143 | "sha256:be4ed120b52ae4d974aa40215fcdfde9194d63541c7ded40ee12eb4dda57b76b", 144 | "sha256:c4302695ad8027363e96311df24ee28978162cdcdd2006476c43970b384a244c", 145 | "sha256:c48f54ef8e05f04d6eff74b8233f6063cb1ed960243eacc474ee73a2ea8573ca", 146 | "sha256:c9c59a2120b55788e800d82dfa99b9e156ff8f2227f07c5e3012a45a399620b7", 147 | "sha256:cd021c754b162c0fb55ad5d6b9d960db667faad0fa2ff25bb6e1301b0b6e6a75", 148 | "sha256:d27ec7509b9c18b6d73f2f5ede2622441de812e7b1a80bbd446cb0633bd3d5ae", 149 | "sha256:d5508f0b173e6aa47273bdc0a0b5ba055b59662ba7c7ee5119528f466585526b", 150 | "sha256:d75209eed723105f9596807495d58d10b3470fa6732dd6756595e89925ce2470", 151 | "sha256:db1a39669102a1d8d12b57de2bb7e2ec9066a6f2b3da35ae511ff93b01b5d564", 152 | "sha256:dbfcfc0218093a19c252ca8eb9aee3d29cfdcb586df21049b9d777fd32c14fd9", 153 | "sha256:e0f72c9ddb8cd28532185f54cc1453f2c16fb417a08b53a855c4e6a418edd099", 154 | "sha256:e7c8dc13af7db097bed64a051d2dd49e9f0af495c26995c00a9ee842690d34c0", 155 | "sha256:ea9872c80c132f4663822dd2a08d404073a5a9b5ba6155bea72fb2a79d1093b5", 156 | "sha256:eff4eb9b7eb3e4d0cae3d28c283dc16d9bed6b193c2e1ace3ed86ce48ea8df19", 157 | "sha256:f82d4d717d8ef19188687aa32b8363e96062911e63ba22a0cff7802a8e58e5f1", 158 | "sha256:fc3a569657468b6f3fb60587e48356fe512c1754ca05a564f11366ac9e306526" 159 | ], 160 | "markers": "python_version >= '3' and platform_machine == 'aarch64' or (platform_machine == 'ppc64le' or (platform_machine == 'x86_64' or (platform_machine == 'amd64' or (platform_machine == 'AMD64' or (platform_machine == 'win32' or platform_machine == 'WIN32')))))", 161 | "version": "==2.0.2" 162 | }, 163 | "gunicorn": { 164 | "hashes": [ 165 | "sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e", 166 | "sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8" 167 | ], 168 | "index": "pypi", 169 | "version": "==20.1.0" 170 | }, 171 | "itsdangerous": { 172 | "hashes": [ 173 | "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44", 174 | "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a" 175 | ], 176 | "markers": "python_version >= '3.7'", 177 | "version": "==2.1.2" 178 | }, 179 | "jinja2": { 180 | "hashes": [ 181 | "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852", 182 | "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61" 183 | ], 184 | "markers": "python_version >= '3.7'", 185 | "version": "==3.1.2" 186 | }, 187 | "mako": { 188 | "hashes": [ 189 | "sha256:c97c79c018b9165ac9922ae4f32da095ffd3c4e6872b45eded42926deea46818", 190 | "sha256:d60a3903dc3bb01a18ad6a89cdbe2e4eadc69c0bc8ef1e3773ba53d44c3f7a34" 191 | ], 192 | "markers": "python_version >= '3.7'", 193 | "version": "==1.2.4" 194 | }, 195 | "markupsafe": { 196 | "hashes": [ 197 | "sha256:0576fe974b40a400449768941d5d0858cc624e3249dfd1e0c33674e5c7ca7aed", 198 | "sha256:085fd3201e7b12809f9e6e9bc1e5c96a368c8523fad5afb02afe3c051ae4afcc", 199 | "sha256:090376d812fb6ac5f171e5938e82e7f2d7adc2b629101cec0db8b267815c85e2", 200 | "sha256:0b462104ba25f1ac006fdab8b6a01ebbfbce9ed37fd37fd4acd70c67c973e460", 201 | "sha256:137678c63c977754abe9086a3ec011e8fd985ab90631145dfb9294ad09c102a7", 202 | "sha256:1bea30e9bf331f3fef67e0a3877b2288593c98a21ccb2cf29b74c581a4eb3af0", 203 | "sha256:22152d00bf4a9c7c83960521fc558f55a1adbc0631fbb00a9471e097b19d72e1", 204 | "sha256:22731d79ed2eb25059ae3df1dfc9cb1546691cc41f4e3130fe6bfbc3ecbbecfa", 205 | "sha256:2298c859cfc5463f1b64bd55cb3e602528db6fa0f3cfd568d3605c50678f8f03", 206 | "sha256:28057e985dace2f478e042eaa15606c7efccb700797660629da387eb289b9323", 207 | "sha256:2e7821bffe00aa6bd07a23913b7f4e01328c3d5cc0b40b36c0bd81d362faeb65", 208 | "sha256:2ec4f2d48ae59bbb9d1f9d7efb9236ab81429a764dedca114f5fdabbc3788013", 209 | "sha256:340bea174e9761308703ae988e982005aedf427de816d1afe98147668cc03036", 210 | "sha256:40627dcf047dadb22cd25ea7ecfe9cbf3bbbad0482ee5920b582f3809c97654f", 211 | "sha256:40dfd3fefbef579ee058f139733ac336312663c6706d1163b82b3003fb1925c4", 212 | "sha256:4cf06cdc1dda95223e9d2d3c58d3b178aa5dacb35ee7e3bbac10e4e1faacb419", 213 | "sha256:50c42830a633fa0cf9e7d27664637532791bfc31c731a87b202d2d8ac40c3ea2", 214 | "sha256:55f44b440d491028addb3b88f72207d71eeebfb7b5dbf0643f7c023ae1fba619", 215 | "sha256:608e7073dfa9e38a85d38474c082d4281f4ce276ac0010224eaba11e929dd53a", 216 | "sha256:63ba06c9941e46fa389d389644e2d8225e0e3e5ebcc4ff1ea8506dce646f8c8a", 217 | "sha256:65608c35bfb8a76763f37036547f7adfd09270fbdbf96608be2bead319728fcd", 218 | "sha256:665a36ae6f8f20a4676b53224e33d456a6f5a72657d9c83c2aa00765072f31f7", 219 | "sha256:6d6607f98fcf17e534162f0709aaad3ab7a96032723d8ac8750ffe17ae5a0666", 220 | "sha256:7313ce6a199651c4ed9d7e4cfb4aa56fe923b1adf9af3b420ee14e6d9a73df65", 221 | "sha256:7668b52e102d0ed87cb082380a7e2e1e78737ddecdde129acadb0eccc5423859", 222 | "sha256:7df70907e00c970c60b9ef2938d894a9381f38e6b9db73c5be35e59d92e06625", 223 | "sha256:7e007132af78ea9df29495dbf7b5824cb71648d7133cf7848a2a5dd00d36f9ff", 224 | "sha256:835fb5e38fd89328e9c81067fd642b3593c33e1e17e2fdbf77f5676abb14a156", 225 | "sha256:8bca7e26c1dd751236cfb0c6c72d4ad61d986e9a41bbf76cb445f69488b2a2bd", 226 | "sha256:8db032bf0ce9022a8e41a22598eefc802314e81b879ae093f36ce9ddf39ab1ba", 227 | "sha256:99625a92da8229df6d44335e6fcc558a5037dd0a760e11d84be2260e6f37002f", 228 | "sha256:9cad97ab29dfc3f0249b483412c85c8ef4766d96cdf9dcf5a1e3caa3f3661cf1", 229 | "sha256:a4abaec6ca3ad8660690236d11bfe28dfd707778e2442b45addd2f086d6ef094", 230 | "sha256:a6e40afa7f45939ca356f348c8e23048e02cb109ced1eb8420961b2f40fb373a", 231 | "sha256:a6f2fcca746e8d5910e18782f976489939d54a91f9411c32051b4aab2bd7c513", 232 | "sha256:a806db027852538d2ad7555b203300173dd1b77ba116de92da9afbc3a3be3eed", 233 | "sha256:abcabc8c2b26036d62d4c746381a6f7cf60aafcc653198ad678306986b09450d", 234 | "sha256:b8526c6d437855442cdd3d87eede9c425c4445ea011ca38d937db299382e6fa3", 235 | "sha256:bb06feb762bade6bf3c8b844462274db0c76acc95c52abe8dbed28ae3d44a147", 236 | "sha256:c0a33bc9f02c2b17c3ea382f91b4db0e6cde90b63b296422a939886a7a80de1c", 237 | "sha256:c4a549890a45f57f1ebf99c067a4ad0cb423a05544accaf2b065246827ed9603", 238 | "sha256:ca244fa73f50a800cf8c3ebf7fd93149ec37f5cb9596aa8873ae2c1d23498601", 239 | "sha256:cf877ab4ed6e302ec1d04952ca358b381a882fbd9d1b07cccbfd61783561f98a", 240 | "sha256:d9d971ec1e79906046aa3ca266de79eac42f1dbf3612a05dc9368125952bd1a1", 241 | "sha256:da25303d91526aac3672ee6d49a2f3db2d9502a4a60b55519feb1a4c7714e07d", 242 | "sha256:e55e40ff0cc8cc5c07996915ad367fa47da6b3fc091fdadca7f5403239c5fec3", 243 | "sha256:f03a532d7dee1bed20bc4884194a16160a2de9ffc6354b3878ec9682bb623c54", 244 | "sha256:f1cd098434e83e656abf198f103a8207a8187c0fc110306691a2e94a78d0abb2", 245 | "sha256:f2bfb563d0211ce16b63c7cb9395d2c682a23187f54c3d79bfec33e6705473c6", 246 | "sha256:f8ffb705ffcf5ddd0e80b65ddf7bed7ee4f5a441ea7d3419e861a12eaf41af58" 247 | ], 248 | "markers": "python_version >= '3.7'", 249 | "version": "==2.1.2" 250 | }, 251 | "psycopg2-binary": { 252 | "hashes": [ 253 | "sha256:00475004e5ed3e3bf5e056d66e5dcdf41a0dc62efcd57997acd9135c40a08a50", 254 | "sha256:01ad49d68dd8c5362e4bfb4158f2896dc6e0c02e87b8a3770fc003459f1a4425", 255 | "sha256:024030b13bdcbd53d8a93891a2cf07719715724fc9fee40243f3bd78b4264b8f", 256 | "sha256:02551647542f2bf89073d129c73c05a25c372fc0a49aa50e0de65c3c143d8bd0", 257 | "sha256:043a9fd45a03858ff72364b4b75090679bd875ee44df9c0613dc862ca6b98460", 258 | "sha256:05b3d479425e047c848b9782cd7aac9c6727ce23181eb9647baf64ffdfc3da41", 259 | "sha256:0775d6252ccb22b15da3b5d7adbbf8cfe284916b14b6dc0ff503a23edb01ee85", 260 | "sha256:1764546ffeaed4f9428707be61d68972eb5ede81239b46a45843e0071104d0dd", 261 | "sha256:1e491e6489a6cb1d079df8eaa15957c277fdedb102b6a68cfbf40c4994412fd0", 262 | "sha256:212757ffcecb3e1a5338d4e6761bf9c04f750e7d027117e74aa3cd8a75bb6fbd", 263 | "sha256:215d6bf7e66732a514f47614f828d8c0aaac9a648c46a831955cb103473c7147", 264 | "sha256:25382c7d174c679ce6927c16b6fbb68b10e56ee44b1acb40671e02d29f2fce7c", 265 | "sha256:2abccab84d057723d2ca8f99ff7b619285d40da6814d50366f61f0fc385c3903", 266 | "sha256:2d964eb24c8b021623df1c93c626671420c6efadbdb8655cb2bd5e0c6fa422ba", 267 | "sha256:2ec46ed947801652c9643e0b1dc334cfb2781232e375ba97312c2fc256597632", 268 | "sha256:2ef892cabdccefe577088a79580301f09f2a713eb239f4f9f62b2b29cafb0577", 269 | "sha256:33e632d0885b95a8b97165899006c40e9ecdc634a529dca7b991eb7de4ece41c", 270 | "sha256:3520d7af1ebc838cc6084a3281145d5cd5bdd43fdef139e6db5af01b92596cb7", 271 | "sha256:3d790f84201c3698d1bfb404c917f36e40531577a6dda02e45ba29b64d539867", 272 | "sha256:3fc33295cfccad697a97a76dec3f1e94ad848b7b163c3228c1636977966b51e2", 273 | "sha256:422e3d43b47ac20141bc84b3d342eead8d8099a62881a501e97d15f6addabfe9", 274 | "sha256:426c2ae999135d64e6a18849a7d1ad0e1bd007277e4a8f4752eaa40a96b550ff", 275 | "sha256:46512486be6fbceef51d7660dec017394ba3e170299d1dc30928cbedebbf103a", 276 | "sha256:46850a640df62ae940e34a163f72e26aca1f88e2da79148e1862faaac985c302", 277 | "sha256:484405b883630f3e74ed32041a87456c5e0e63a8e3429aa93e8714c366d62bd1", 278 | "sha256:4e7904d1920c0c89105c0517dc7e3f5c20fb4e56ba9cdef13048db76947f1d79", 279 | "sha256:56b2957a145f816726b109ee3d4e6822c23f919a7d91af5a94593723ed667835", 280 | "sha256:5c6527c8efa5226a9e787507652dd5ba97b62d29b53c371a85cd13f957fe4d42", 281 | "sha256:5cbc554ba47ecca8cd3396ddaca85e1ecfe3e48dd57dc5e415e59551affe568e", 282 | "sha256:5d28ecdf191db558d0c07d0f16524ee9d67896edf2b7990eea800abeb23ebd61", 283 | "sha256:5fc447058d083b8c6ac076fc26b446d44f0145308465d745fba93a28c14c9e32", 284 | "sha256:63e318dbe52709ed10d516a356f22a635e07a2e34c68145484ed96a19b0c4c68", 285 | "sha256:68d81a2fe184030aa0c5c11e518292e15d342a667184d91e30644c9d533e53e1", 286 | "sha256:6e63814ec71db9bdb42905c925639f319c80e7909fb76c3b84edc79dadef8d60", 287 | "sha256:6f8a9bcab7b6db2e3dbf65b214dfc795b4c6b3bb3af922901b6a67f7cb47d5f8", 288 | "sha256:70831e03bd53702c941da1a1ad36c17d825a24fbb26857b40913d58df82ec18b", 289 | "sha256:74eddec4537ab1f701a1647214734bc52cee2794df748f6ae5908e00771f180a", 290 | "sha256:7b3751857da3e224f5629400736a7b11e940b5da5f95fa631d86219a1beaafec", 291 | "sha256:7cf1d44e710ca3a9ce952bda2855830fe9f9017ed6259e01fcd71ea6287565f5", 292 | "sha256:7d07f552d1e412f4b4e64ce386d4c777a41da3b33f7098b6219012ba534fb2c2", 293 | "sha256:7d88db096fa19d94f433420eaaf9f3c45382da2dd014b93e4bf3215639047c16", 294 | "sha256:7ee3095d02d6f38bd7d9a5358fcc9ea78fcdb7176921528dd709cc63f40184f5", 295 | "sha256:902844f9c4fb19b17dfa84d9e2ca053d4a4ba265723d62ea5c9c26b38e0aa1e6", 296 | "sha256:937880290775033a743f4836aa253087b85e62784b63fd099ee725d567a48aa1", 297 | "sha256:95076399ec3b27a8f7fa1cc9a83417b1c920d55cf7a97f718a94efbb96c7f503", 298 | "sha256:9c38d3869238e9d3409239bc05bc27d6b7c99c2a460ea337d2814b35fb4fea1b", 299 | "sha256:9e32cedc389bcb76d9f24ea8a012b3cb8385ee362ea437e1d012ffaed106c17d", 300 | "sha256:9ffdc51001136b699f9563b1c74cc1f8c07f66ef7219beb6417a4c8aaa896c28", 301 | "sha256:a0adef094c49f242122bb145c3c8af442070dc0e4312db17e49058c1702606d4", 302 | "sha256:a36a0e791805aa136e9cbd0ffa040d09adec8610453ee8a753f23481a0057af5", 303 | "sha256:a7e518a0911c50f60313cb9e74a169a65b5d293770db4770ebf004245f24b5c5", 304 | "sha256:af0516e1711995cb08dc19bbd05bec7dbdebf4185f68870595156718d237df3e", 305 | "sha256:b8104f709590fff72af801e916817560dbe1698028cd0afe5a52d75ceb1fce5f", 306 | "sha256:b911dfb727e247340d36ae20c4b9259e4a64013ab9888ccb3cbba69b77fd9636", 307 | "sha256:b9a794cef1d9c1772b94a72eec6da144c18e18041d294a9ab47669bc77a80c1d", 308 | "sha256:b9c33d4aef08dfecbd1736ceab8b7b3c4358bf10a0121483e5cd60d3d308cc64", 309 | "sha256:b9d38a4656e4e715d637abdf7296e98d6267df0cc0a8e9a016f8ba07e4aa3eeb", 310 | "sha256:bcda1c84a1c533c528356da5490d464a139b6e84eb77cc0b432e38c5c6dd7882", 311 | "sha256:bef7e3f9dc6f0c13afdd671008534be5744e0e682fb851584c8c3a025ec09720", 312 | "sha256:c15ba5982c177bc4b23a7940c7e4394197e2d6a424a2d282e7c236b66da6d896", 313 | "sha256:c5254cbd4f4855e11cebf678c1a848a3042d455a22a4ce61349c36aafd4c2267", 314 | "sha256:c5682a45df7d9642eff590abc73157c887a68f016df0a8ad722dcc0f888f56d7", 315 | "sha256:c5e65c6ac0ae4bf5bef1667029f81010b6017795dcb817ba5c7b8a8d61fab76f", 316 | "sha256:d4c7b3a31502184e856df1f7bbb2c3735a05a8ce0ade34c5277e1577738a5c91", 317 | "sha256:d892bfa1d023c3781a3cab8dd5af76b626c483484d782e8bd047c180db590e4c", 318 | "sha256:dbc332beaf8492b5731229a881807cd7b91b50dbbbaf7fe2faf46942eda64a24", 319 | "sha256:dc85b3777068ed30aff8242be2813038a929f2084f69e43ef869daddae50f6ee", 320 | "sha256:e59137cdb970249ae60be2a49774c6dfb015bd0403f05af1fe61862e9626642d", 321 | "sha256:e67b3c26e9b6d37b370c83aa790bbc121775c57bfb096c2e77eacca25fd0233b", 322 | "sha256:e72c91bda9880f097c8aa3601a2c0de6c708763ba8128006151f496ca9065935", 323 | "sha256:f95b8aca2703d6a30249f83f4fe6a9abf2e627aa892a5caaab2267d56be7ab69" 324 | ], 325 | "index": "pypi", 326 | "version": "==2.9.5" 327 | }, 328 | "python-dotenv": { 329 | "hashes": [ 330 | "sha256:1c93de8f636cde3ce377292818d0e440b6e45a82f215c3744979151fa8151c49", 331 | "sha256:41e12e0318bebc859fcc4d97d4db8d20ad21721a6aa5047dd59f090391cb549a" 332 | ], 333 | "index": "pypi", 334 | "version": "==0.21.1" 335 | }, 336 | "pyyaml": { 337 | "hashes": [ 338 | "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf", 339 | "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293", 340 | "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b", 341 | "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57", 342 | "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b", 343 | "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4", 344 | "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07", 345 | "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba", 346 | "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9", 347 | "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287", 348 | "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513", 349 | "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0", 350 | "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782", 351 | "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0", 352 | "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92", 353 | "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f", 354 | "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2", 355 | "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc", 356 | "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1", 357 | "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c", 358 | "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86", 359 | "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4", 360 | "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c", 361 | "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34", 362 | "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b", 363 | "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d", 364 | "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c", 365 | "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb", 366 | "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7", 367 | "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737", 368 | "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3", 369 | "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d", 370 | "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358", 371 | "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53", 372 | "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78", 373 | "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803", 374 | "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a", 375 | "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f", 376 | "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174", 377 | "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5" 378 | ], 379 | "markers": "python_version >= '3.6'", 380 | "version": "==6.0" 381 | }, 382 | "setuptools": { 383 | "hashes": [ 384 | "sha256:a7687c12b444eaac951ea87a9627c4f904ac757e7abdc5aac32833234af90378", 385 | "sha256:e261cdf010c11a41cb5cb5f1bf3338a7433832029f559a6a7614bd42a967c300" 386 | ], 387 | "markers": "python_version >= '3.7'", 388 | "version": "==67.1.0" 389 | }, 390 | "six": { 391 | "hashes": [ 392 | "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", 393 | "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" 394 | ], 395 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 396 | "version": "==1.16.0" 397 | }, 398 | "sqlalchemy": { 399 | "hashes": [ 400 | "sha256:07e48cbcdda6b8bc7a59d6728bd3f5f574ffe03f2c9fb384239f3789c2d95c2e", 401 | "sha256:18cafdb27834fa03569d29f571df7115812a0e59fd6a3a03ccb0d33678ec8420", 402 | "sha256:1b1e5e96e2789d89f023d080bee432e2fef64d95857969e70d3cadec80bd26f0", 403 | "sha256:315676344e3558f1f80d02535f410e80ea4e8fddba31ec78fe390eff5fb8f466", 404 | "sha256:31de1e2c45e67a5ec1ecca6ec26aefc299dd5151e355eb5199cd9516b57340be", 405 | "sha256:3d94682732d1a0def5672471ba42a29ff5e21bb0aae0afa00bb10796fc1e28dd", 406 | "sha256:3ec187acf85984263299a3f15c34a6c0671f83565d86d10f43ace49881a82718", 407 | "sha256:4847f4b1d822754e35707db913396a29d874ee77b9c3c3ef3f04d5a9a6209618", 408 | "sha256:4d112b0f3c1bc5ff70554a97344625ef621c1bfe02a73c5d97cac91f8cd7a41e", 409 | "sha256:51e1ba2884c6a2b8e19109dc08c71c49530006c1084156ecadfaadf5f9b8b053", 410 | "sha256:535377e9b10aff5a045e3d9ada8a62d02058b422c0504ebdcf07930599890eb0", 411 | "sha256:5dbf17ac9a61e7a3f1c7ca47237aac93cabd7f08ad92ac5b96d6f8dea4287fc1", 412 | "sha256:5f752676fc126edc1c4af0ec2e4d2adca48ddfae5de46bb40adbd3f903eb2120", 413 | "sha256:64cb0ad8a190bc22d2112001cfecdec45baffdf41871de777239da6a28ed74b6", 414 | "sha256:6913b8247d8a292ef8315162a51931e2b40ce91681f1b6f18f697045200c4a30", 415 | "sha256:69fac0a7054d86b997af12dc23f581cf0b25fb1c7d1fed43257dee3af32d3d6d", 416 | "sha256:7001f16a9a8e06488c3c7154827c48455d1c1507d7228d43e781afbc8ceccf6d", 417 | "sha256:7b81b1030c42b003fc10ddd17825571603117f848814a344d305262d370e7c34", 418 | "sha256:7f8267682eb41a0584cf66d8a697fef64b53281d01c93a503e1344197f2e01fe", 419 | "sha256:887865924c3d6e9a473dc82b70977395301533b3030d0f020c38fd9eba5419f2", 420 | "sha256:9167d4227b56591a4cc5524f1b79ccd7ea994f36e4c648ab42ca995d28ebbb96", 421 | "sha256:939f9a018d2ad04036746e15d119c0428b1e557470361aa798e6e7d7f5875be0", 422 | "sha256:955162ad1a931fe416eded6bb144ba891ccbf9b2e49dc7ded39274dd9c5affc5", 423 | "sha256:984ee13543a346324319a1fb72b698e521506f6f22dc37d7752a329e9cd00a32", 424 | "sha256:9883f5fae4fd8e3f875adc2add69f8b945625811689a6c65866a35ee9c0aea23", 425 | "sha256:a1ad90c97029cc3ab4ffd57443a20fac21d2ec3c89532b084b073b3feb5abff3", 426 | "sha256:a3714e5b33226131ac0da60d18995a102a17dddd42368b7bdd206737297823ad", 427 | "sha256:ae067ab639fa499f67ded52f5bc8e084f045d10b5ac7bb928ae4ca2b6c0429a5", 428 | "sha256:b33ffbdbbf5446cf36cd4cc530c9d9905d3c2fe56ed09e25c22c850cdb9fac92", 429 | "sha256:b6e4cb5c63f705c9d546a054c60d326cbde7421421e2d2565ce3e2eee4e1a01f", 430 | "sha256:b7f4b6aa6e87991ec7ce0e769689a977776db6704947e562102431474799a857", 431 | "sha256:c04144a24103135ea0315d459431ac196fe96f55d3213bfd6d39d0247775c854", 432 | "sha256:c522e496f9b9b70296a7675272ec21937ccfc15da664b74b9f58d98a641ce1b6", 433 | "sha256:c5a99282848b6cae0056b85da17392a26b2d39178394fc25700bcf967e06e97a", 434 | "sha256:c7a46639ba058d320c9f53a81db38119a74b8a7a1884df44d09fbe807d028aaf", 435 | "sha256:d4b1cc7835b39835c75cf7c20c926b42e97d074147c902a9ebb7cf2c840dc4e2", 436 | "sha256:d4d164df3d83d204c69f840da30b292ac7dc54285096c6171245b8d7807185aa", 437 | "sha256:d61e9ecc849d8d44d7f80894ecff4abe347136e9d926560b818f6243409f3c86", 438 | "sha256:d68e1762997bfebf9e5cf2a9fd0bcf9ca2fdd8136ce7b24bbd3bbfa4328f3e4a", 439 | "sha256:e3c1808008124850115a3f7e793a975cfa5c8a26ceeeb9ff9cbb4485cac556df", 440 | "sha256:f8cb80fe8d14307e4124f6fad64dfd87ab749c9d275f82b8b4ec84c84ecebdbe" 441 | ], 442 | "index": "pypi", 443 | "version": "==1.4.46" 444 | }, 445 | "typing-extensions": { 446 | "hashes": [ 447 | "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa", 448 | "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e" 449 | ], 450 | "index": "pypi", 451 | "version": "==4.4.0" 452 | }, 453 | "urllib3": { 454 | "hashes": [ 455 | "sha256:076907bf8fd355cde77728471316625a4d2f7e713c125f51953bb5b3eecf4f72", 456 | "sha256:75edcdc2f7d85b137124a6c3c9fc3933cdeaa12ecb9a6a959f22797a0feca7e1" 457 | ], 458 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", 459 | "version": "==1.26.14" 460 | }, 461 | "werkzeug": { 462 | "hashes": [ 463 | "sha256:7ea2d48322cc7c0f8b3a215ed73eabd7b5d75d0b50e31ab006286ccff9e00b8f", 464 | "sha256:f979ab81f58d7318e064e99c4506445d60135ac5cd2e177a2de0089bfd4c9bd5" 465 | ], 466 | "markers": "python_version >= '3.7'", 467 | "version": "==2.2.2" 468 | }, 469 | "wtforms": { 470 | "hashes": [ 471 | "sha256:6b351bbb12dd58af57ffef05bc78425d08d1914e0fd68ee14143b7ade023c5bc", 472 | "sha256:837f2f0e0ca79481b92884962b914eba4e72b7a2daaf1f939c890ed0124b834b" 473 | ], 474 | "markers": "python_version >= '3.7'", 475 | "version": "==3.0.1" 476 | } 477 | }, 478 | "develop": {} 479 | } 480 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | release: pipenv run upgrade 2 | web: gunicorn wsgi --chdir ./src/ 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WebApp boilerplate with React JS and Flask API 2 | 3 | Build web applications using React.js for the front end and python/flask for your backend API. 4 | 5 | - Documentation can be found here: https://start.4geeksacademy.com/starters/react-flask 6 | - Here is a video on [how to use this template](https://www.loom.com/share/f37c6838b3f1496c95111e515e83dd9b) 7 | - Integrated with Pipenv for package managing. 8 | - Fast deployment to heroku [in just a few steps here](https://start.4geeksacademy.com/backend/deploy-heroku-posgres). 9 | - Use of .env file. 10 | - SQLAlchemy integration for database abstraction. 11 | 12 | ### 1) Installation: 13 | 14 | > If you use Github Codespaces (recommended) or Gitpod this template will already come with Python, Node and the Posgres Database installed. If you are working locally make sure to install Python 3.10, Node 15 | 16 | It is recomended to install the backend first, make sure you have Python 3.8, Pipenv and a database engine (Posgress recomended) 17 | 18 | 1. Install the python packages: `$ pipenv install` 19 | 2. Create a .env file based on the .env.example: `$ cp .env.example .env` 20 | 3. Install your database engine and create your database, depending on your database you have to create a DATABASE_URL variable with one of the possible values, make sure you replace the valudes with your database information: 21 | 22 | | Engine | DATABASE_URL | 23 | | --------- | --------------------------------------------------- | 24 | | SQLite | sqlite:////test.db | 25 | | MySQL | mysql://username:password@localhost:port/example | 26 | | Postgress | postgres://username:password@localhost:5432/example | 27 | 28 | 4. Migrate the migrations: `$ pipenv run migrate` (skip if you have not made changes to the models on the `./src/api/models.py`) 29 | 5. Run the migrations: `$ pipenv run upgrade` 30 | 6. Run the application: `$ pipenv run start` 31 | 32 | > Note: Codespaces users can connect to psql by typing: `psql -h localhost -U gitpod example` 33 | 34 | ### Undo a migration 35 | 36 | You are also able to undo a migration by running 37 | 38 | ```sh 39 | $ pipenv run downgrade 40 | ``` 41 | 42 | ### Backend Populate Table Users 43 | 44 | To insert test users in the database execute the following command: 45 | 46 | ```sh 47 | $ flask insert-test-users 5 48 | ``` 49 | 50 | And you will see the following message: 51 | 52 | ``` 53 | Creating test users 54 | test_user1@test.com created. 55 | test_user2@test.com created. 56 | test_user3@test.com created. 57 | test_user4@test.com created. 58 | test_user5@test.com created. 59 | Users created successfully! 60 | ``` 61 | 62 | ### **Important note for the database and the data inside it** 63 | 64 | Every Github codespace environment will have **its own database**, so if you're working with more people eveyone will have a different database and different records inside it. This data **will be lost**, so don't spend too much time manually creating records for testing, instead, you can automate adding records to your database by editing ```commands.py``` file inside ```/src/api``` folder. Edit line 32 function ```insert_test_data``` to insert the data according to your model (use the function ```insert_test_users``` above as an example). Then, all you need to do is run ```pipenv run insert-test-data```. 65 | 66 | ### Front-End Manual Installation: 67 | 68 | - Make sure you are using node version 14+ and that you have already successfully installed and runned the backend. 69 | 70 | 1. Install the packages: `$ npm install` 71 | 2. Start coding! start the webpack dev server `$ npm run start` 72 | 73 | ## Publish your website! 74 | 75 | This boilerplate it's 100% read to deploy with Render.com and Heroku in a matter of minutes. Please read the [official documentation about it](https://start.4geeksacademy.com/deploy). 76 | 77 | ### Contributors 78 | 79 | This template was built as part of the 4Geeks Academy [Coding Bootcamp](https://4geeksacademy.com/us/coding-bootcamp) by [Alejandro Sanchez](https://twitter.com/alesanchezr) and many other contributors. Find out more about our [Full Stack Developer Course](https://4geeksacademy.com/us/coding-bootcamps/part-time-full-stack-developer), and [Data Science Bootcamp](https://4geeksacademy.com/us/coding-bootcamps/datascience-machine-learning). 80 | 81 | You can find other templates and resources like this at the [school github page](https://github.com/4geeksacademy/). 82 | -------------------------------------------------------------------------------- /database.sh: -------------------------------------------------------------------------------- 1 | creating_migration () 2 | { 3 | pipenv run init 4 | pipenv run migrate 5 | pipenv run upgrade 6 | } 7 | 8 | migrate_upgrade () 9 | { 10 | pipenv run migrate 11 | pipenv run upgrade 12 | } 13 | 14 | dir=$(pwd) 15 | 16 | if [ ! -d $dir/migrations ] 17 | then 18 | echo 'creating migration' 19 | creating_migration 20 | else 21 | echo 'migrations already created' 22 | echo 'updating migrations' 23 | migrate_upgrade 24 | fi 25 | -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Hello Rigo with React + Flux + Context.js 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /docs/CHANGE_LOG.md: -------------------------------------------------------------------------------- 1 | # CHANGE LOG 2 | 3 | Here we are tracking the previous and upcoming changes (roadmap), pull request this file or open an issue if you have any suggestions for the next version of the boilerplate. 4 | 5 | ## Roadmap v2.0 6 | 7 | - [ ] Update documentation with more examples 8 | 9 | ### August 9th, 2019 10 | - [x] Removed eralchemy from the Pipfile because its compatibility with Apply and PC computers its not clear. There is now way to create a database diagra.png anymore. 11 | - [x] Added this changelog file to keep track of changes on the boilerplate. 12 | - [x] Added documentation for [data validations](https://github.com/4GeeksAcademy/flask-rest-hello/blob/master/docs/DATA_VALIDATIONS.md) 13 | - [x] Added documentation for [SQL Alchemy operations](https://github.com/4GeeksAcademy/flask-rest-hello/edit/master/docs/MYSQL.md). 14 | 15 | ### Sep 16th, 2019 16 | - [x] Added debuging functionality 17 | -------------------------------------------------------------------------------- /docs/HELP.md: -------------------------------------------------------------------------------- 1 | You can find a comprehensive documentation about this boilerplate here: 2 | https://start.4geeksacademy.com/starters/full-stack -------------------------------------------------------------------------------- /docs/assets/db_config.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4GeeksAcademy/react-flask-hello-deprecated/f7f39286c7d1b32efdc2e308ca5721f314b013de/docs/assets/db_config.gif -------------------------------------------------------------------------------- /docs/assets/debugging.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4GeeksAcademy/react-flask-hello-deprecated/f7f39286c7d1b32efdc2e308ca5721f314b013de/docs/assets/debugging.gif -------------------------------------------------------------------------------- /docs/assets/debugging_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4GeeksAcademy/react-flask-hello-deprecated/f7f39286c7d1b32efdc2e308ca5721f314b013de/docs/assets/debugging_icon.png -------------------------------------------------------------------------------- /docs/assets/diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4GeeksAcademy/react-flask-hello-deprecated/f7f39286c7d1b32efdc2e308ca5721f314b013de/docs/assets/diagram.png -------------------------------------------------------------------------------- /docs/assets/env-file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4GeeksAcademy/react-flask-hello-deprecated/f7f39286c7d1b32efdc2e308ca5721f314b013de/docs/assets/env-file.png -------------------------------------------------------------------------------- /docs/assets/env_variables.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4GeeksAcademy/react-flask-hello-deprecated/f7f39286c7d1b32efdc2e308ca5721f314b013de/docs/assets/env_variables.gif -------------------------------------------------------------------------------- /docs/assets/greeting.py: -------------------------------------------------------------------------------- 1 | import sys 2 | def blue(_str): 3 | return f"\033[0;33m{_str}\033[0m" 4 | environment = sys.argv.pop(1) 5 | if environment == "back": 6 | print(f""" 7 | Hello 😁 ! This terminal will represent your 🐍 backend! 8 | 9 | 1. Get inside the environment {blue("$ pipenv shell")} 10 | 2. Start the server by typing {blue("$ pipenv run start")} 11 | """) 12 | if environment == "front": 13 | print(f""" 14 | This terminal is for 💻 front-end! 15 | 16 | 1. Start webpack dev server {blue("$ npm run start")} 17 | """) 18 | 19 | if environment == "both": 20 | print(f""" 21 | Welcome to the full-stack template at 4Geeks 😁. 22 | 23 | 1. Start by running your 🐍 python backend using the command {blue("$ pipenv run start")} 24 | 2. Open a new terminal to run your front-end with the following command {blue("$ npm run start")} 25 | 26 | Note: ⚠️ Please keep in mind you will always need two terminals, one for the front end, one for the back-end. 27 | 🛟 You can find documentation here: https://start.4geeksacademy.com 28 | """) -------------------------------------------------------------------------------- /docs/assets/reset_migrations.bash: -------------------------------------------------------------------------------- 1 | rm -R -f ./migrations && 2 | pipenv run init && 3 | dropdb -h localhost -U gitpod example || true && 4 | createdb -h localhost -U gitpod example || true && 5 | psql -h localhost example -U gitpod -c 'CREATE EXTENSION unaccent;' || true && 6 | pipenv run migrate && 7 | pipenv run upgrade 8 | -------------------------------------------------------------------------------- /docs/assets/rigo-baby.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4GeeksAcademy/react-flask-hello-deprecated/f7f39286c7d1b32efdc2e308ca5721f314b013de/docs/assets/rigo-baby.jpg -------------------------------------------------------------------------------- /learn.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": { 3 | "en": "WebApp Template with React JS and Flask API", 4 | "es": "Plantilla de WebApp con React JS y Flask API" 5 | }, 6 | "description": { 7 | "us": "Build web applications effortlessly with our React.js and Flask API boilerplate. Learn to deploy in minutes—discover the template now!", 8 | "es": "Crea aplicaciones web sin esfuerzo con nuestro boilerplate de React.js y Flask API. Aprende a desplegar en minutos—¡descubre la plantilla ahora!" 9 | }, 10 | "slug": "react-flask-webapp-template", 11 | "difficulty": "intermediate", 12 | "duration": "4", 13 | "projectType": "template", 14 | "repository": "https://github.com/4geeksacademy/react-flask-hello", 15 | "preview": "https://github.com/4geeksacademy/react-flask-hello/preview.png", 16 | "video": "https://www.loom.com/share/f37c6838b3f1496c95111e515e83dd9b", 17 | "technologies": ["React.js", "Flask", "Python", "SQLAlchemy","vite"] 18 | } 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-hello-webapp", 3 | "engines": { 4 | "node": "16.x" 5 | }, 6 | "version": "1.0.1", 7 | "description": "", 8 | "main": "index.js", 9 | "scripts": { 10 | "start": "webpack-dev-server --config webpack.dev.js --port 3000", 11 | "build": "webpack --config webpack.prod.js" 12 | }, 13 | "author": { 14 | "name": "Alejandro Sanchez", 15 | "url": "http://alesanchezr.com/" 16 | }, 17 | "contributors": [ 18 | { 19 | "name": "Alejandro Sanchez", 20 | "url": "http://alesanchezr.com/" 21 | }, 22 | { 23 | "name": "Ignacio Cordoba", 24 | "url": "http://github.com/nachovz" 25 | } 26 | ], 27 | "license": "ISC", 28 | "devDependencies": { 29 | "@babel/cli": "^7.16.0", 30 | "@babel/core": "^7.16.0", 31 | "@babel/plugin-proposal-class-properties": "^7.16.0", 32 | "@babel/plugin-transform-runtime": "^7.16.4", 33 | "@babel/preset-env": "^7.16.4", 34 | "@babel/preset-react": "^7.16.0", 35 | "@babel/runtime": "^7.16.3", 36 | "babel-eslint": "^10.1.0", 37 | "babel-loader": "^8.2.3", 38 | "babel-plugin-transform-class-properties": "^6.24.1", 39 | "bc-console": "0.0.2", 40 | "css-loader": "^6.5.1", 41 | "dotenv-webpack": "^7.0.3", 42 | "envfile": "^6.17.0", 43 | "error-overlay-webpack-plugin": "^1.0.0", 44 | "eslint": "^8.4.0", 45 | "eslint-plugin-react": "^7.27.1", 46 | "eslint-webpack-plugin": "^3.1.1", 47 | "file-loader": "^6.2.0", 48 | "gh-pages": "^3.2.3", 49 | "html-loader": "^3.0.1", 50 | "html-webpack-plugin": "^5.5.0", 51 | "parse-github-url": "^1.0.2", 52 | "prettier": "^2.5.1", 53 | "remote-origin-url": "^2.0.0", 54 | "style-loader": "^3.3.1", 55 | "webpack": "^5.65.0", 56 | "webpack-cli": "^4.9.1", 57 | "webpack-dev-server": "^4.6.0", 58 | "webpack-merge": "^5.8.0" 59 | }, 60 | "babel": { 61 | "presets": [ 62 | "@babel/preset-env", 63 | "@babel/preset-react" 64 | ], 65 | "plugins": [ 66 | "@babel/plugin-proposal-class-properties", 67 | [ 68 | "@babel/plugin-transform-runtime", 69 | { 70 | "regenerator": true 71 | } 72 | ] 73 | ] 74 | }, 75 | "dependencies": { 76 | "prop-types": "^15.6.1", 77 | "react": "^16.8.4", 78 | "react-dom": "^16.8.4", 79 | "react-polyfills": "0.0.1", 80 | "react-router-dom": "^6.3.0" 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /public/4geeks.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4GeeksAcademy/react-flask-hello-deprecated/f7f39286c7d1b32efdc2e308ca5721f314b013de/public/4geeks.ico -------------------------------------------------------------------------------- /public/bundle.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /* 2 | object-assign 3 | (c) Sindre Sorhus 4 | @license MIT 5 | */ 6 | 7 | /** 8 | * React Router DOM v6.3.0 9 | * 10 | * Copyright (c) Remix Software Inc. 11 | * 12 | * This source code is licensed under the MIT license found in the 13 | * LICENSE.md file in the root directory of this source tree. 14 | * 15 | * @license MIT 16 | */ 17 | 18 | /** 19 | * React Router v6.3.0 20 | * 21 | * Copyright (c) Remix Software Inc. 22 | * 23 | * This source code is licensed under the MIT license found in the 24 | * LICENSE.md file in the root directory of this source tree. 25 | * 26 | * @license MIT 27 | */ 28 | 29 | /** @license React v0.19.1 30 | * scheduler.production.min.js 31 | * 32 | * Copyright (c) Facebook, Inc. and its affiliates. 33 | * 34 | * This source code is licensed under the MIT license found in the 35 | * LICENSE file in the root directory of this source tree. 36 | */ 37 | 38 | /** @license React v16.14.0 39 | * react-dom.production.min.js 40 | * 41 | * Copyright (c) Facebook, Inc. and its affiliates. 42 | * 43 | * This source code is licensed under the MIT license found in the 44 | * LICENSE file in the root directory of this source tree. 45 | */ 46 | 47 | /** @license React v16.14.0 48 | * react.production.min.js 49 | * 50 | * Copyright (c) Facebook, Inc. and its affiliates. 51 | * 52 | * This source code is licensed under the MIT license found in the 53 | * LICENSE file in the root directory of this source tree. 54 | */ 55 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | Hello Rigo with Vanilla.js
-------------------------------------------------------------------------------- /public/rigo-baby.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4GeeksAcademy/react-flask-hello-deprecated/f7f39286c7d1b32efdc2e308ca5721f314b013de/public/rigo-baby.jpg -------------------------------------------------------------------------------- /pycodestyle.cfg: -------------------------------------------------------------------------------- 1 | [pycodestyle] 2 | ignore = E501, E302 -------------------------------------------------------------------------------- /render.yaml: -------------------------------------------------------------------------------- 1 | # This file was generated by Render's heroku-import Heroku CLI plugin 2 | # https://www.npmjs.com/package/@renderinc/heroku-import 3 | # Schema documented at https://render.com/docs/yaml-spec 4 | services: 5 | - type: web # valid values: https://render.com/docs/yaml-spec#type 6 | region: ohio 7 | name: sample-service-name 8 | env: python # valid values: https://render.com/docs/yaml-spec#environment 9 | buildCommand: "./render_build.sh" 10 | startCommand: "gunicorn wsgi --chdir ./src/" 11 | plan: free # optional; defaults to starter 12 | numInstances: 1 13 | envVars: 14 | - key: BASENAME # Imported from Heroku app 15 | value: / 16 | - key: FLASK_APP # Imported from Heroku app 17 | value: src/app.py 18 | - key: FLASK_DEBUG # Imported from Heroku app 19 | value: 0 20 | - key: FLASK_APP_KEY # Imported from Heroku app 21 | value: "any key works" 22 | - key: PYTHON_VERSION 23 | value: 3.10.6 24 | - key: DATABASE_URL # Render PostgreSQL database 25 | fromDatabase: 26 | name: postgresql-trapezoidal-42170 27 | property: connectionString 28 | 29 | databases: # Render PostgreSQL database 30 | - name: postgresql-trapezoidal-42170 31 | region: ohio 32 | ipAllowList: [] # only allow internal connections 33 | plan: free # optional; defaults to starter 34 | -------------------------------------------------------------------------------- /render_build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # exit on error 3 | set -o errexit 4 | 5 | npm install 6 | npm run build 7 | 8 | pipenv install 9 | 10 | pipenv run upgrade 11 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | -i https://pypi.org/simple 2 | alembic==1.5.4; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5' 3 | certifi==2020.12.5 4 | click==7.1.2; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' 5 | cloudinary==1.24.0 6 | flask==1.1.2 7 | flask-admin==1.5.7 8 | flask-cors==3.0.10 9 | flask-migrate==2.6.0 10 | flask-sqlalchemy==2.4.4 11 | flask-swagger==0.2.14 12 | gunicorn==20.0.4 13 | itsdangerous==1.1.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' 14 | jinja2==2.11.3; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' 15 | mako==1.1.4; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' 16 | markupsafe==1.1.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' 17 | psycopg2-binary==2.8.6 18 | python-dateutil==2.8.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' 19 | python-dotenv==0.15.0 20 | python-editor==1.0.4 21 | pyyaml==5.4.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5' 22 | six==1.15.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' 23 | sqlalchemy==1.3.23 24 | urllib3==1.26.3; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4' 25 | werkzeug==1.0.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' 26 | wtforms==2.3.3 27 | -------------------------------------------------------------------------------- /src/api/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4GeeksAcademy/react-flask-hello-deprecated/f7f39286c7d1b32efdc2e308ca5721f314b013de/src/api/__init__.py -------------------------------------------------------------------------------- /src/api/admin.py: -------------------------------------------------------------------------------- 1 | 2 | import os 3 | from flask_admin import Admin 4 | from .models import db, User 5 | from flask_admin.contrib.sqla import ModelView 6 | 7 | def setup_admin(app): 8 | app.secret_key = os.environ.get('FLASK_APP_KEY', 'sample key') 9 | app.config['FLASK_ADMIN_SWATCH'] = 'cerulean' 10 | admin = Admin(app, name='4Geeks Admin', template_mode='bootstrap3') 11 | 12 | 13 | # Add your models here, for example this is how we add a the User model to the admin 14 | admin.add_view(ModelView(User, db.session)) 15 | 16 | # You can duplicate that line to add mew models 17 | # admin.add_view(ModelView(YourModelName, db.session)) -------------------------------------------------------------------------------- /src/api/commands.py: -------------------------------------------------------------------------------- 1 | 2 | import click 3 | from api.models import db, User 4 | 5 | """ 6 | In this file, you can add as many commands as you want using the @app.cli.command decorator 7 | Flask commands are usefull to run cronjobs or tasks outside of the API but sill in integration 8 | with youy database, for example: Import the price of bitcoin every night as 12am 9 | """ 10 | def setup_commands(app): 11 | 12 | """ 13 | This is an example command "insert-test-users" that you can run from the command line 14 | by typing: $ flask insert-test-users 5 15 | Note: 5 is the number of users to add 16 | """ 17 | @app.cli.command("insert-test-users") # name of our command 18 | @click.argument("count") # argument of out command 19 | def insert_test_users(count): 20 | print("Creating test users") 21 | for x in range(1, int(count) + 1): 22 | user = User() 23 | user.email = "test_user" + str(x) + "@test.com" 24 | user.password = "123456" 25 | user.is_active = True 26 | db.session.add(user) 27 | db.session.commit() 28 | print("User: ", user.email, " created.") 29 | 30 | print("All test users created") 31 | 32 | @app.cli.command("insert-test-data") 33 | def insert_test_data(): 34 | pass -------------------------------------------------------------------------------- /src/api/models.py: -------------------------------------------------------------------------------- 1 | from flask_sqlalchemy import SQLAlchemy 2 | 3 | db = SQLAlchemy() 4 | 5 | class User(db.Model): 6 | id = db.Column(db.Integer, primary_key=True) 7 | email = db.Column(db.String(120), unique=True, nullable=False) 8 | password = db.Column(db.String(80), unique=False, nullable=False) 9 | is_active = db.Column(db.Boolean(), unique=False, nullable=False) 10 | 11 | def __repr__(self): 12 | return f'' 13 | 14 | def serialize(self): 15 | return { 16 | "id": self.id, 17 | "email": self.email, 18 | # do not serialize the password, its a security breach 19 | } -------------------------------------------------------------------------------- /src/api/routes.py: -------------------------------------------------------------------------------- 1 | """ 2 | This module takes care of starting the API Server, Loading the DB and Adding the endpoints 3 | """ 4 | from flask import Flask, request, jsonify, url_for, Blueprint 5 | from api.models import db, User 6 | from api.utils import generate_sitemap, APIException 7 | from flask_cors import CORS 8 | 9 | api = Blueprint('api', __name__) 10 | 11 | # Allow CORS requests to this API 12 | CORS(api) 13 | 14 | 15 | @api.route('/hello', methods=['POST', 'GET']) 16 | def handle_hello(): 17 | 18 | response_body = { 19 | "message": "Hello! I'm a message that came from the backend, check the network tab on the google inspector and you will see the GET request" 20 | } 21 | 22 | return jsonify(response_body), 200 23 | -------------------------------------------------------------------------------- /src/api/utils.py: -------------------------------------------------------------------------------- 1 | from flask import jsonify, url_for 2 | 3 | class APIException(Exception): 4 | status_code = 400 5 | 6 | def __init__(self, message, status_code=None, payload=None): 7 | Exception.__init__(self) 8 | self.message = message 9 | if status_code is not None: 10 | self.status_code = status_code 11 | self.payload = payload 12 | 13 | def to_dict(self): 14 | rv = dict(self.payload or ()) 15 | rv['message'] = self.message 16 | return rv 17 | 18 | def has_no_empty_params(rule): 19 | defaults = rule.defaults if rule.defaults is not None else () 20 | arguments = rule.arguments if rule.arguments is not None else () 21 | return len(defaults) >= len(arguments) 22 | 23 | def generate_sitemap(app): 24 | links = ['/admin/'] 25 | for rule in app.url_map.iter_rules(): 26 | # Filter out rules we can't navigate to in a browser 27 | # and rules that require parameters 28 | if "GET" in rule.methods and has_no_empty_params(rule): 29 | url = url_for(rule.endpoint, **(rule.defaults or {})) 30 | if "/admin/" not in url: 31 | links.append(url) 32 | 33 | links_html = "".join(["
  • " + y + "
  • " for y in links]) 34 | return """ 35 |
    36 | 37 |

    Rigo welcomes you to your API!!

    38 |

    API HOST:

    39 |

    Start working on your project by following the Quick Start

    40 |

    Remember to specify a real endpoint path like:

    41 |
    " 42 | -------------------------------------------------------------------------------- /src/app.py: -------------------------------------------------------------------------------- 1 | """ 2 | This module takes care of starting the API Server, Loading the DB and Adding the endpoints 3 | """ 4 | import os 5 | from flask import Flask, request, jsonify, url_for, send_from_directory 6 | from flask_migrate import Migrate 7 | from flask_swagger import swagger 8 | from api.utils import APIException, generate_sitemap 9 | from api.models import db 10 | from api.routes import api 11 | from api.admin import setup_admin 12 | from api.commands import setup_commands 13 | 14 | # from models import Person 15 | 16 | ENV = "development" if os.getenv("FLASK_DEBUG") == "1" else "production" 17 | static_file_dir = os.path.join(os.path.dirname( 18 | os.path.realpath(__file__)), '../public/') 19 | app = Flask(__name__) 20 | app.url_map.strict_slashes = False 21 | 22 | # database condiguration 23 | db_url = os.getenv("DATABASE_URL") 24 | if db_url is not None: 25 | app.config['SQLALCHEMY_DATABASE_URI'] = db_url.replace( 26 | "postgres://", "postgresql://") 27 | else: 28 | app.config['SQLALCHEMY_DATABASE_URI'] = "sqlite:////tmp/test.db" 29 | 30 | app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False 31 | MIGRATE = Migrate(app, db, compare_type=True) 32 | db.init_app(app) 33 | 34 | # add the admin 35 | setup_admin(app) 36 | 37 | # add the admin 38 | setup_commands(app) 39 | 40 | # Add all endpoints form the API with a "api" prefix 41 | app.register_blueprint(api, url_prefix='/api') 42 | 43 | # Handle/serialize errors like a JSON object 44 | 45 | 46 | @app.errorhandler(APIException) 47 | def handle_invalid_usage(error): 48 | return jsonify(error.to_dict()), error.status_code 49 | 50 | # generate sitemap with all your endpoints 51 | 52 | 53 | @app.route('/') 54 | def sitemap(): 55 | if ENV == "development": 56 | return generate_sitemap(app) 57 | return send_from_directory(static_file_dir, 'index.html') 58 | 59 | # any other endpoint will try to serve it like a static file 60 | @app.route('/', methods=['GET']) 61 | def serve_any_other_file(path): 62 | if not os.path.isfile(os.path.join(static_file_dir, path)): 63 | path = 'index.html' 64 | response = send_from_directory(static_file_dir, path) 65 | response.cache_control.max_age = 0 # avoid cache memory 66 | return response 67 | 68 | 69 | # this only runs if `$ python src/main.py` is executed 70 | if __name__ == '__main__': 71 | PORT = int(os.environ.get('PORT', 3001)) 72 | app.run(host='0.0.0.0', port=PORT, debug=True) 73 | -------------------------------------------------------------------------------- /src/front/img/how-to.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4GeeksAcademy/react-flask-hello-deprecated/f7f39286c7d1b32efdc2e308ca5721f314b013de/src/front/img/how-to.png -------------------------------------------------------------------------------- /src/front/img/rigo-baby.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4GeeksAcademy/react-flask-hello-deprecated/f7f39286c7d1b32efdc2e308ca5721f314b013de/src/front/img/rigo-baby.jpg -------------------------------------------------------------------------------- /src/front/js/component/backendURL.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import envFile from "../../../../docs/assets/env-file.png" 3 | 4 | const Dark = ({children}) => {children}; 5 | export const BackendURL = () => ( 6 |
    7 |

    Missing BACKEND_URL env variable

    8 |

    Here's a video tutorial on how to update your backend URL environment variable.

    9 |

    There's a file called .env that contains the environmental variables for your project.

    10 |

    There's one variable called BACKEND_URL that needs to be manually set by yourself.

    11 |
      12 |
    1. Make sure you backend is running on port 3001.
    2. 13 |
    3. Open your API and copy the API host.
    4. 14 |
    5. Open the .env file (do not open the .env.example)
    6. 15 |
    7. Add a new variable BACKEND_URL=your api host
    8. 16 |
    9. Replace your api host with the public API URL of your flask backend sever running at port 3001
    10. 17 |
    18 | 19 |

    Note: If you are publishing your website to Heroku, Render.com or any other hosting you probably need to follow other steps.

    20 |
    21 | ); 22 | -------------------------------------------------------------------------------- /src/front/js/component/footer.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | 3 | export const Footer = () => ( 4 | 10 | ); 11 | -------------------------------------------------------------------------------- /src/front/js/component/navbar.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Link } from "react-router-dom"; 3 | 4 | export const Navbar = () => { 5 | return ( 6 | 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /src/front/js/component/scrollToTop.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import PropTypes from "prop-types"; 3 | 4 | class ScrollToTop extends React.Component { 5 | componentDidUpdate(prevProps) { 6 | if (this.props.location !== prevProps.location) { 7 | window.scrollTo(0, 0); 8 | } 9 | } 10 | 11 | render() { 12 | return this.props.children; 13 | } 14 | } 15 | 16 | export default ScrollToTop; 17 | ScrollToTop.propTypes = { 18 | location: PropTypes.object, 19 | children: PropTypes.any 20 | }; 21 | -------------------------------------------------------------------------------- /src/front/js/index.js: -------------------------------------------------------------------------------- 1 | //import react into the bundle 2 | import React from "react"; 3 | import ReactDOM from "react-dom"; 4 | 5 | //include your index.scss file into the bundle 6 | import "../styles/index.css"; 7 | 8 | //import your own components 9 | import Layout from "./layout"; 10 | 11 | //render your react application 12 | ReactDOM.render(, document.querySelector("#app")); 13 | -------------------------------------------------------------------------------- /src/front/js/layout.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { BrowserRouter, Route, Routes } from "react-router-dom"; 3 | import ScrollToTop from "./component/scrollToTop"; 4 | import { BackendURL } from "./component/backendURL"; 5 | 6 | import { Home } from "./pages/home"; 7 | import { Demo } from "./pages/demo"; 8 | import { Single } from "./pages/single"; 9 | import injectContext from "./store/appContext"; 10 | 11 | import { Navbar } from "./component/navbar"; 12 | import { Footer } from "./component/footer"; 13 | 14 | //create your first component 15 | const Layout = () => { 16 | //the basename is used when your project is published in a subdirectory and not in the root of the domain 17 | // you can set the basename on the .env file located at the root of this project, E.g: BASENAME=/react-hello-webapp/ 18 | const basename = process.env.BASENAME || ""; 19 | 20 | if(!process.env.BACKEND_URL || process.env.BACKEND_URL == "") return ; 21 | 22 | return ( 23 |
    24 | 25 | 26 | 27 | 28 | } path="/" /> 29 | } path="/demo" /> 30 | } path="/single/:theid" /> 31 | Not found!} /> 32 | 33 |
    34 | 35 | 36 |
    37 | ); 38 | }; 39 | 40 | export default injectContext(Layout); 41 | -------------------------------------------------------------------------------- /src/front/js/pages/demo.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect, useContext } from "react"; 2 | import { Link } from "react-router-dom"; 3 | 4 | import { Context } from "../store/appContext"; 5 | 6 | export const Demo = () => { 7 | const { store, actions } = useContext(Context); 8 | 9 | return ( 10 |
    11 |
      12 | {store.demo.map((item, index) => { 13 | return ( 14 |
    • 18 | 19 | Link to: {item.title} 20 | 21 | {// Conditional render example 22 | // Check to see if the background is orange, if so, display the message 23 | item.background === "orange" ? ( 24 |

      25 | Check store/flux.js scroll to the actions to see the code 26 |

      27 | ) : null} 28 | 31 |
    • 32 | ); 33 | })} 34 |
    35 |
    36 | 37 | 38 | 39 |
    40 | ); 41 | }; 42 | -------------------------------------------------------------------------------- /src/front/js/pages/home.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from "react"; 2 | import { Context } from "../store/appContext"; 3 | import rigoImageUrl from "../../img/rigo-baby.jpg"; 4 | import "../../styles/home.css"; 5 | 6 | export const Home = () => { 7 | const { store, actions } = useContext(Context); 8 | 9 | return ( 10 |
    11 |

    Hello Rigo!!

    12 |

    13 | 14 |

    15 |
    16 | {store.message || "Loading message from the backend (make sure your python backend is running)..."} 17 |
    18 |

    19 | This boilerplate comes with lots of documentation:{" "} 20 | 21 | Read documentation 22 | 23 |

    24 |
    25 | ); 26 | }; 27 | -------------------------------------------------------------------------------- /src/front/js/pages/single.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect, useContext } from "react"; 2 | import PropTypes from "prop-types"; 3 | import { Link, useParams } from "react-router-dom"; 4 | import { Context } from "../store/appContext"; 5 | import rigoImageUrl from "../../img/rigo-baby.jpg"; 6 | 7 | export const Single = props => { 8 | const { store, actions } = useContext(Context); 9 | const params = useParams(); 10 | 11 | return ( 12 |
    13 |

    This will show the demo element: {store.demo[params.theid].title}

    14 | 15 |
    16 | 17 | 18 | 19 | Back home 20 | 21 | 22 |
    23 | ); 24 | }; 25 | 26 | Single.propTypes = { 27 | match: PropTypes.object 28 | }; 29 | -------------------------------------------------------------------------------- /src/front/js/store/appContext.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import getState from "./flux.js"; 3 | 4 | // Don't change, here is where we initialize our context, by default it's just going to be null. 5 | export const Context = React.createContext(null); 6 | 7 | // This function injects the global store to any view/component where you want to use it, we will inject the context to layout.js, you can see it here: 8 | // https://github.com/4GeeksAcademy/react-hello-webapp/blob/master/src/js/layout.js#L35 9 | const injectContext = PassedComponent => { 10 | const StoreWrapper = props => { 11 | //this will be passed as the contenxt value 12 | const [state, setState] = useState( 13 | getState({ 14 | getStore: () => state.store, 15 | getActions: () => state.actions, 16 | setStore: updatedStore => 17 | setState({ 18 | store: Object.assign(state.store, updatedStore), 19 | actions: { ...state.actions } 20 | }) 21 | }) 22 | ); 23 | 24 | useEffect(() => { 25 | /** 26 | * EDIT THIS! 27 | * This function is the equivalent to "window.onLoad", it only runs once on the entire application lifetime 28 | * you should do your ajax requests or fetch api requests here. Do not use setState() to save data in the 29 | * store, instead use actions, like this: 30 | **/ 31 | state.actions.getMessage(); // <---- calling this function from the flux.js actions 32 | }, []); 33 | 34 | // The initial value for the context is not null anymore, but the current state of this component, 35 | // the context will now have a getStore, getActions and setStore functions available, because they were declared 36 | // on the state of this component 37 | return ( 38 | 39 | 40 | 41 | ); 42 | }; 43 | return StoreWrapper; 44 | }; 45 | 46 | export default injectContext; 47 | -------------------------------------------------------------------------------- /src/front/js/store/flux.js: -------------------------------------------------------------------------------- 1 | const getState = ({ getStore, getActions, setStore }) => { 2 | return { 3 | store: { 4 | message: null, 5 | demo: [ 6 | { 7 | title: "FIRST", 8 | background: "white", 9 | initial: "white" 10 | }, 11 | { 12 | title: "SECOND", 13 | background: "white", 14 | initial: "white" 15 | } 16 | ] 17 | }, 18 | actions: { 19 | // Use getActions to call a function within a fuction 20 | exampleFunction: () => { 21 | getActions().changeColor(0, "green"); 22 | }, 23 | 24 | getMessage: async () => { 25 | try{ 26 | // fetching data from the backend 27 | const resp = await fetch(process.env.BACKEND_URL + "/api/hello") 28 | const data = await resp.json() 29 | setStore({ message: data.message }) 30 | // don't forget to return something, that is how the async resolves 31 | return data; 32 | }catch(error){ 33 | console.log("Error loading message from backend", error) 34 | } 35 | }, 36 | changeColor: (index, color) => { 37 | //get the store 38 | const store = getStore(); 39 | 40 | //we have to loop the entire demo array to look for the respective index 41 | //and change its color 42 | const demo = store.demo.map((elm, i) => { 43 | if (i === index) elm.background = color; 44 | return elm; 45 | }); 46 | 47 | //reset the global store 48 | setStore({ demo: demo }); 49 | } 50 | } 51 | }; 52 | }; 53 | 54 | export default getState; 55 | -------------------------------------------------------------------------------- /src/front/styles/home.css: -------------------------------------------------------------------------------- 1 | /* 2 | home.css: This website contains selectors only used in home.css 3 | 4 | All pages share the styles on index.css but you should create 5 | one more css for each page that will contain the selected used 6 | on that page only (the ones not reused in other pages). 7 | */ -------------------------------------------------------------------------------- /src/front/styles/index.css: -------------------------------------------------------------------------------- 1 | /* 2 | General Styles used on every website (Don't Repeat Yourself) 3 | */ 4 | -------------------------------------------------------------------------------- /src/wsgi.py: -------------------------------------------------------------------------------- 1 | # This file was created to run the application on heroku using gunicorn. 2 | # Read more about it here: https://devcenter.heroku.com/articles/python-gunicorn 3 | 4 | from app import app as application 5 | 6 | if __name__ == "__main__": 7 | application.run() 8 | -------------------------------------------------------------------------------- /template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Hello Rigo with Vanilla.js 7 | 8 | 9 | 10 | 11 | 12 | 13 |
    14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /webpack.common.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const path = require('path'); 3 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 4 | const Dotenv = require('dotenv-webpack'); 5 | 6 | module.exports = { 7 | entry: [ 8 | './src/front/js/index.js' 9 | ], 10 | output: { 11 | filename: 'bundle.js', 12 | path: path.resolve(__dirname, 'public'), 13 | publicPath: '/' 14 | }, 15 | module: { 16 | rules: [ 17 | { 18 | test: /\.(js|jsx)$/, 19 | exclude: /node_modules/, 20 | use: ['babel-loader'] 21 | }, 22 | { 23 | test: /\.(css|scss)$/, use: [{ 24 | loader: "style-loader" // creates style nodes from JS strings 25 | }, { 26 | loader: "css-loader" // translates CSS into CommonJS 27 | }] 28 | }, //css only files 29 | { 30 | test: /\.(png|svg|jpg|gif|jpeg|webp)$/, use: { 31 | loader: 'file-loader', 32 | options: { name: '[name].[ext]' } 33 | } 34 | }, //for images 35 | { test: /\.woff($|\?)|\.woff2($|\?)|\.ttf($|\?)|\.eot($|\?)|\.svg($|\?)/, use: ['file-loader'] } //for fonts 36 | ] 37 | }, 38 | resolve: { 39 | extensions: ['*', '.js'] 40 | }, 41 | plugins: [ 42 | new HtmlWebpackPlugin({ 43 | favicon: '4geeks.ico', 44 | template: 'template.html' 45 | }), 46 | new Dotenv({ safe: true, systemvars: true }) 47 | ] 48 | }; -------------------------------------------------------------------------------- /webpack.dev.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const path = require('path'); 3 | const { merge } = require('webpack-merge'); 4 | const common = require('./webpack.common.js'); 5 | // const ErrorOverlayPlugin = require('error-overlay-webpack-plugin'); 6 | 7 | const port = 3000; 8 | let publicUrl = `ws://localhost:${port}/ws`; 9 | 10 | //only for github 11 | if(process.env.GITPOD_WORKSPACE_URL){ 12 | const [schema, host] = process.env.GITPOD_WORKSPACE_URL.split('://'); 13 | publicUrl = `wss://${port}-${host}/ws`; 14 | } 15 | 16 | //only for codespaces 17 | if(process.env.CODESPACE_NAME){ 18 | publicUrl = `wss://${process.env.CODESPACE_NAME}-${port}.app.github.dev/ws`; 19 | } 20 | 21 | module.exports = merge(common, { 22 | mode: 'development', 23 | devtool: 'cheap-module-source-map', 24 | devServer: { 25 | port, 26 | hot: true, 27 | allowedHosts: "all", 28 | historyApiFallback: true, 29 | static: { 30 | directory: path.resolve(__dirname, "dist"), 31 | }, 32 | client: { 33 | webSocketURL: publicUrl 34 | }, 35 | }, 36 | plugins: [ 37 | // new FriendlyErrorsWebpackPlugin(), 38 | // new ErrorOverlayPlugin(), 39 | // new PrettierPlugin({ 40 | // parser: "babylon", 41 | // printWidth: 120, // Specify the length of line that the printer will wrap on. 42 | // tabWidth: 4, // Specify the number of spaces per indentation-level. 43 | // useTabs: true, // Indent lines with tabs instead of spaces. 44 | // bracketSpacing: true, 45 | // extensions: [ ".js", ".jsx" ], 46 | // jsxBracketSameLine: true, 47 | // semi: true, // Print semicolons at the ends of statements. 48 | // encoding: 'utf-8' // Which encoding scheme to use on files 49 | // }), 50 | new webpack.HotModuleReplacementPlugin() 51 | ] 52 | }); 53 | -------------------------------------------------------------------------------- /webpack.prod.js: -------------------------------------------------------------------------------- 1 | const { merge } = require('webpack-merge'); 2 | const common = require('./webpack.common.js'); 3 | const Dotenv = require('dotenv-webpack'); 4 | module.exports = merge(common, { 5 | mode: 'production', 6 | output: { 7 | publicPath: '/' 8 | }, 9 | plugins: [ 10 | new Dotenv({ 11 | safe: true, 12 | systemvars: true 13 | }) 14 | ] 15 | }); 16 | --------------------------------------------------------------------------------