{"id":15858988,"url":"https://github.com/nitrocode/fweather","last_synced_at":"2025-04-01T19:46:26.728Z","repository":{"id":84691094,"uuid":"131097394","full_name":"nitrocode/Fweather","owner":"nitrocode","description":" Fun weather in Django, jQuery, and Bootstrap using lots of APIs and deployable using docker","archived":false,"fork":false,"pushed_at":"2018-05-24T23:03:59.000Z","size":255,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-07T12:49:05.221Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nitrocode.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-04-26T03:54:31.000Z","updated_at":"2019-01-23T01:38:05.000Z","dependencies_parsed_at":null,"dependency_job_id":"ea88ba37-271d-4314-855f-7f1391963393","html_url":"https://github.com/nitrocode/Fweather","commit_stats":{"total_commits":12,"total_committers":1,"mean_commits":12.0,"dds":0.0,"last_synced_commit":"c643dd0ed3742d0c05fa31e42fa23ac464324af0"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nitrocode%2FFweather","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nitrocode%2FFweather/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nitrocode%2FFweather/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nitrocode%2FFweather/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nitrocode","download_url":"https://codeload.github.com/nitrocode/Fweather/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246705503,"owners_count":20820742,"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-05T21:02:34.308Z","updated_at":"2025-04-01T19:46:26.704Z","avatar_url":"https://github.com/nitrocode.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Fweather\n\nThe name is a portmanteau of fun and weather! Pronounced fwe-ther This was made using Django, world weather online api, giphy api, gmail api, and sqlite.\n\nTODO: heroku demo link\n\nSubscribing an email in Washington, DC\n\n![subscribe](images/subscribe.png)\n\nReceiving an email for subscriber in Woburn, MA after verification.\n\n![subscribe](images/email.png)\n\n## Requirements\n\n* [pipenv](https://docs.pipenv.org) - setup environment vars\n* [pyenv](https://github.com/pyenv/pyenv) or python 3 - cause python 2 will die soon\n* [npm](https://www.npmjs.com/get-npm) - to install js / css dependencies\n* Sign up for the [world weather online api](https://developer.worldweatheronline.com) to get historical weather for free for 60 days\n* Sign up for the [giphy api](https://developers.giphy.com) to get gifs\n* Sign up for the [gmail api]() to send emails\n    * Purposely didn't use Klaviyo or MailChimp because that would make the app WAY too easy ;)\n* Insert tokens in the [`.env`](https://medium.com/@thejasonfile/using-dotenv-package-to-create-environment-variables-33da4ac4ea8f) file to keep sensitive information stored as environment variables\n    * `.env` is committed so do not upload a personal one by mistake. Run the command below to ignore local changes.\n    * `git update-index --assume-unchanged .env`\n\n## Quick start\n\n### Dependencies\n\npython 3.6\n\n    pyenv install 3.6.5\n    pyenv local 3.6.5\n\npip dependencies\n\n    pipenv install\n\nsqlite database schema\n\n    python manage.py makemigrations fweather\n    python manage.py migrate --run-syncdb\n\njs and css\n\n    npm i\n    python manage.py collectstatic\n\n### Run\n\n    python manage.py runserver --noreload\n\nNote: The `--noreload` is important as it will prevent the app from running the overriden `ready()` function twice. The app gets the gmail refresh token on django start.\n\nIn production environments, it's better to run it using `gunicorn`.\n\n    gunicorn fweather.wsgi\n\nIt's also runable in docker if using ECS or Docker Swarm / Kubernetes to deploy.\n\n    # build\n    docker build -t fweather .\n    # run daemonized\n    docker run -p 8000:8000 -d fweather\n\n## Admin panel\n\nRegister\n\n    python manage.py createsuperuser\n\nLogin on http://localhost:8000/admin\n\n## Management commands\n\n    python manage.py send\n        --email EMAIL         Send to a particular email\n        --email-all           Send to all emails in database\n\n## TODO\n\n### Essential\n\n- [x] read info from .env file\n- [x] django skeleton\n- [x] sign up to get giphy api\n- [x] sign up to get openweathermap api\n- [x] sign up page with email and ~~country~~ zip code\n- [x] sign up form submittal using jquery to hit api\n- [x] api checks for email that's already signed\n- [x] api sanitizes input\n- [x] api upserts tiny db with email and country\n- [x] ui always looks like the submission works so no one can see who signed up\n- [x] admin interface\n- [x] foreign key constraint on email\n- [x] admin interface allows editing foreign key\n- [x] use the gmail api to send email\n- [x] get gmail token on boot and check if the token exists already\n- [x] email is sent asynchronously\n- [x] use weather api to get weather for a location\n- [x] verify subscriber using email and `uuid.v4()`\n- [x] django management command to send out email to every person\n- [x] email contains current weather from the location provided\n- [x] use giphy api to get a related weather gif\n- [x] email contains a gif\n- [x] prompt \"are you sure?\" before sending email to everyone on the list\n- [x] Replace `print` statements with `logging`\n\n## Extra\n\n- [ ] \\[deploy\\] heroku\n    - [ ] research postgresql integration since heroku does not persist sqlite dbs\n    - [x] installed whitenoise middleware to deliver static files while `debug=True`\n\n- [ ] \\[feature\\] unsubscribe - would have to generate another temp id that only gets sent in emails\n- [ ] \\[feature\\] email can be written in markdown template\n- [ ] \\[feature\\] email contains fahrenheit and celsius\n- [ ] \\[feature\\] email forecasts the week\n- [ ] \\[feature\\] email is sexy using zurb\n- [ ] \\[feature\\] curses\n- [ ] \\[sec\\] recaptcha on subscribe\n- [ ] \\[sec\\] encrypt email data in database and store key in file or separate database\n- [ ] \\[maint\\] django tests\n- [ ] \\[doc\\] sphinx autodoc\n\n## Notes\n\n### Security\n\n- Zip codes and emails are validated\n- Only zip codes converted to city, state are returned and printed client side\n- Always returned a successful message (unless bad zip or email) in case someone is guessing at the database for who's already using my fun weather email service\n- Validated emails that subscribed before sending them emails\n- To increase security more, I could add a recaptcha, encrypt email data (or offload emails to mailchimp / klaviyo), and add additional security headers using securityheaders.io as a reference\n\n### Re-inventing the wheel\n\n- I used zipcodes and email_validator instead of recreating my own validation\n- I used bootstrap to make the sign up page formatted and look more appealing\n\nI could have...\n\n- used MailChimp / klaviyo\n    - used API to add the email addresses (less than 2000 are free) and custom text field like zip code or location\n    - used API again to send the emails using the custom django manage command\n    - e.g. http://eepurl.com/dsmv2P\n- Used flask (soooo much easier) instead of django but then I wouldn't have learned django\n- The above steps would remove the overhead of the database, input injection, PII / GPDR, styles, javascript... so much stuff\n\n### Usability\n\n- Sign up page is using bootstrap so everything looks OK\n- Additional things to add would be a background, maybe a nice navbar at the top, a form rounded edge border\n\n### Learned\n\n- Django basics such as setting up a project, creating a database\n- Django admin section is pretty cool\n- Debugging django in pycharm\n\n### Other\n\n- I could not sign up for Weather Underground because they have a bug on their sign up page\n- I thought if I provided a location for weather it would be too easy for users to fake their location with a simple dropdown. Instead I used zip codes.\n\n    For convenience, here are some sample zip codes\n\n    | Location | Zip |\n    |---|---|\n    | Anchorage, AK  | 99501  |\n    | Austin, TX  | 73301  |\n    | Boston, MA  | 02111  |\n    | Seattle, WA  | 98101  |\n    | Washington, DC  | 20001  |\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnitrocode%2Ffweather","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnitrocode%2Ffweather","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnitrocode%2Ffweather/lists"}