From c6a07837c8d4ee4bfa82e9e99915ba5673538351 Mon Sep 17 00:00:00 2001 From: Mitesh Ashar Date: Wed, 9 Aug 2023 00:03:58 +0530 Subject: [PATCH 01/10] Add .python-version to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 927e184b2..38f335d13 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ test.db .project .pydevproject .vscode +.python-version .settings .sass-cache .webassets-cache From c44877713bc58349e27b33b275929b8cfaf671cd Mon Sep 17 00:00:00 2001 From: Mitesh Ashar Date: Wed, 9 Aug 2023 00:06:54 +0530 Subject: [PATCH 02/10] Set hasjob to load config from .env files and override instance config --- hasjob/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hasjob/__init__.py b/hasjob/__init__.py index f05d99f8e..12ec9e35f 100644 --- a/hasjob/__init__.py +++ b/hasjob/__init__.py @@ -38,7 +38,7 @@ from .models import db # isort:skip # Configure the app -coaster.app.init_app(app) +coaster.app.init_app(app, ['py', 'env'], env_prefix=['FLASK']) db.init_app(app) db.app = app migrate = Migrate(app, db) From 612f69397c56205abe60b59c8b56bfc20caa0a01 Mon Sep 17 00:00:00 2001 From: Kiran Jonnalagadda Date: Wed, 9 Aug 2023 01:05:07 +0530 Subject: [PATCH 03/10] Load .env files in wsgi module --- hasjob/__init__.py | 2 +- wsgi.py | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/hasjob/__init__.py b/hasjob/__init__.py index 12ec9e35f..abf1d8725 100644 --- a/hasjob/__init__.py +++ b/hasjob/__init__.py @@ -38,7 +38,7 @@ from .models import db # isort:skip # Configure the app -coaster.app.init_app(app, ['py', 'env'], env_prefix=['FLASK']) +coaster.app.init_app(app, ['py', 'env'], env_prefix=['FLASK', 'APP_HASJOB']) db.init_app(app) db.app = app migrate = Migrate(app, db) diff --git a/wsgi.py b/wsgi.py index d8b419756..cb68fbf75 100644 --- a/wsgi.py +++ b/wsgi.py @@ -1,7 +1,14 @@ import os.path import sys +from flask.cli import load_dotenv +from flask.helpers import get_load_dotenv + __all__ = ['application'] sys.path.insert(0, os.path.dirname(__file__)) +if get_load_dotenv(): + load_dotenv() + +# pylint: disable=wrong-import-position from hasjob import app as application # isort:skip From bc90b953f0781ccd1cc7195124f014ddff3c4d66 Mon Sep 17 00:00:00 2001 From: Kiran Jonnalagadda Date: Wed, 9 Aug 2023 01:51:57 +0530 Subject: [PATCH 04/10] Fix Pillow 10 compatibility --- hasjob/uploads.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hasjob/uploads.py b/hasjob/uploads.py index 68ab86cb3..77edf7c84 100644 --- a/hasjob/uploads.py +++ b/hasjob/uploads.py @@ -42,7 +42,7 @@ def process_image(requestfile, maxsize=(170, 130)): raise UploadNotAllowed("This image is too large to process") img.load() if img.size[0] > maxsize[0] or img.size[1] > maxsize[1]: - img.thumbnail(maxsize, Image.ANTIALIAS) + img.thumbnail(maxsize, Image.LANCZOS) boximg = Image.new(img.mode, maxsize, '#fff0') boximg.paste( img, ((boximg.size[0] - img.size[0]) // 2, (boximg.size[1] - img.size[1]) // 2) From b7bce1045c53508ce66bb0721260fe090961599a Mon Sep 17 00:00:00 2001 From: Kiran Jonnalagadda Date: Wed, 9 Aug 2023 02:24:23 +0530 Subject: [PATCH 05/10] Drop version numbers --- requirements.txt | 51 ++++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/requirements.txt b/requirements.txt index 8e5f6c636..d6c29256a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,30 +1,29 @@ git+https://github.com/hasgeek/baseframe#egg=baseframe -bleach==6.0.0 +bleach git+https://github.com/hasgeek/coaster#egg=coaster -coverage==7.2.5 -dnspython==2.3.0 -Flask==2.2.5 -Flask-Assets==2.0 +coverage +dnspython +Flask +Flask-Assets git+https://github.com/hasgeek/flask-lastuser#egg=Flask-Lastuser -Flask-Mail==0.9.1 -Flask-Migrate==4.0.4 -Flask-Redis==0.4.0 -Flask-RQ2==18.3 -Flask-SQLAlchemy==3.0.3 -Flask-Testing==0.8.1 +Flask-Mail +Flask-Migrate +Flask-Redis +Flask-RQ2 +Flask-SQLAlchemy +Flask-Testing git+https://github.com/maxcountryman/flask-uploads.git#egg=Flask-Uploads -Flask-WTF==1.1.1 -geoip2==4.6.0 -html2text==2020.1.16 -jsmin==3.0.1 -langid==1.1.6 -Markdown==3.4.3 -Pillow==9.5.0 -premailer==3.10.0 -progressbar2==4.2.0 -psycopg2==2.9.6 -pytz==2023.3 -SQLAlchemy==2.0.12 -SQLAlchemy-Utils==0.41.1 -tldextract==3.4.1 -tweepy==4.14.0 +Flask-WTF +geoip2 +html2text +jsmin +langid +Pillow +premailer +progressbar2 +psycopg2 +pytz +SQLAlchemy +SQLAlchemy-Utils +tldextract +tweepy From 37f0706c161f3331ce049bebe98a87e5a560f031 Mon Sep 17 00:00:00 2001 From: Mitesh Ashar Date: Wed, 9 Aug 2023 02:56:55 +0530 Subject: [PATCH 06/10] .flaskenv and sample.env --- .flaskenv | 17 +++++ instance/settings.py | 70 --------------------- sample.env | 146 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 163 insertions(+), 70 deletions(-) create mode 100644 .flaskenv create mode 100644 sample.env diff --git a/.flaskenv b/.flaskenv new file mode 100644 index 000000000..6e2a9f08e --- /dev/null +++ b/.flaskenv @@ -0,0 +1,17 @@ +# The settings in this file are secondary to .env, which overrides + +# Assume production by default, unset debug and testing state +FLASK_DEBUG=false +FLASK_DEBUG_TB_ENABLED=false +FLASK_TESTING=false + +# To only support HTTPS, set Secure Cookies to True +FLASK_SESSION_COOKIE_SECURE=True + +# --- App configuration +# Default timezone when user timezone is not known +FLASK_TIMEZONE='Asia/Kolkata' +FLASK_ASSET_MANIFEST_PATH=static/build/manifest.json +# Asset base path – without a trailing slash +FLASK_ASSET_BASE_PATH=/static/build +FLASK_STATIC_SUBDOMAIN=static diff --git a/instance/settings.py b/instance/settings.py index 25f13e413..2f5704eb9 100644 --- a/instance/settings.py +++ b/instance/settings.py @@ -1,69 +1,5 @@ import re -#: The title of this site -SITE_TITLE = 'Job Board' -#: TypeKit code for fonts -TYPEKIT_CODE = '' -#: Google Analytics code UA-XXXXXX-X -GA_CODE = '' -#: Database backend -SQLALCHEMY_DATABASE_URI = 'sqlite:///' -#: Secret key -SECRET_KEY = 'make this something random' # nosec B105 -#: Timezone -TIMEZONE = 'Asia/Kolkata' -#: Static resource subdomain (defaults to 'static') -STATIC_SUBDOMAIN = 'static' -#: Upload path -UPLOADED_LOGOS_DEST = '/tmp/uploads' # nosec B108 -#: Cache settings -CACHE_TYPE = 'redis' -#: RQ settings -RQ_REDIS_URL = 'redis://localhost:6379/0' -RQ_SCHEDULER_INTERVAL = 1 -#: GeoIP database file (GeoIP2 or GeoLite2 city mmdb) -#: On Ubuntu: /usr/share/GeoIP/GeoLite2-City.mmdb -#: On Homebrew: /usr/local/var/GeoIP/GeoLite2-City.mmdb -GEOIP_PATH = '/usr/share/GeoIP/GeoLite2-City.mmdb' -#: Mail settings -#: MAIL_FAIL_SILENTLY : default True -#: MAIL_SERVER : default 'localhost' -#: MAIL_PORT : default 25 -#: MAIL_USE_TLS : default False -#: MAIL_USE_SSL : default False -#: MAIL_USERNAME : default None -#: MAIL_PASSWORD : default None -#: DEFAULT_MAIL_SENDER : default None -MAIL_FAIL_SILENTLY = False -MAIL_SERVER = 'localhost' -# Mail sender for crash reports and other automated mail -DEFAULT_MAIL_SENDER = 'Hasjob ' -MAIL_DEFAULT_SENDER = DEFAULT_MAIL_SENDER -# Mail sender for job application responses (email address only) -MAIL_SENDER = 'test@example.com' -#: Logging: recipients of error emails -ADMINS = [] -#: Log file -LOGFILE = 'error.log' -#: Use SSL for some URLs -USE_SSL = False -#: Twitter integration (register as a "client" app) -TWITTER_ENABLED = False -TWITTER_CONSUMER_KEY = '' -TWITTER_CONSUMER_SECRET = '' # nosec B105 -TWITTER_ACCESS_KEY = '' -TWITTER_ACCESS_SECRET = '' # nosec B105 -#: Bit.ly integration for short URLs -BITLY_USER = '' -BITLY_KEY = '' -#: Access key for periodic server-only tasks -PERIODIC_KEY = '' -#: Throttle limit for email domain -THROTTLE_LIMIT = 5 -#: Don't show year for dates within this many days -SHORTDATE_THRESHOLD_DAYS = 60 -#: Email address to display when asking users to contact support -SUPPORT_EMAIL = 'support@hasgeek.com' #: Words banned in the title and their error messages BANNED_WORDS = [ [ @@ -119,9 +55,3 @@ "Candidates must apply via Hasjob", ) ] -#: LastUser server -LASTUSER_SERVER = 'https://hasgeek.com/' -#: LastUser client id -LASTUSER_CLIENT_ID = '' -#: LastUser client secret -LASTUSER_CLIENT_SECRET = '' # nosec B105 diff --git a/sample.env b/sample.env new file mode 100644 index 000000000..fab18bcbb --- /dev/null +++ b/sample.env @@ -0,0 +1,146 @@ +# Sample configuration for the `.env` settings file. These values are interpeted as +# JSON, falling back to plain strings. This file must be a valid shell script, so +# values using shell glob characters '*?[]' must be enclosed in single quotes + +# --- Development mode (remove these three in production) +# Coaster uses this value; Flask 2.2's deprecation warning can be ignored +FLASK_ENV=development +# Flask >=2.2 requires this value +FLASK_DEBUG=1 +# Flask-DebugToolbar (optional) is useful for dev, but MUST NOT BE enabled in production +FLASK_DEBUG_TB_ENABLED=true + +# --- Domain configuration (these must point to 127.0.0.1 in /etc/hosts in dev and test) +# Hasjob app's server name (Hasjob uses 'hasjob.co' in production) +FLASK_SERVER_NAME=hasjob.test:5001 +# Auth cookie domain (auth cookie is shared across apps in subdomains) +FLASK_LASTUSER_COOKIE_DOMAIN=.hasjob.test +FLASK_SESSION_COOKIE_DOMAIN=.hasjob.test +# For dev, uncomment to override secure cookies, when not using HTTPS +# FLASK_SESSION_COOKIE_SECURE=false + +# --- Secrets +# Secret keys with key rotation -- put older keys further down the list. Older keys will +# be used to decode tokens as fallback, but will not be used to encode. Remove old keys +# when they are considered expired +FLASK_SECRET_KEYS='["make-this-something-random", "older-secret-keys-here"]' +# Secret key for sitemap URLs submitted to Google +SITEMAP_KEY=make-this-something-random + +# --- Analytics +# Google Analytics code +FLASK_GA_CODE=null +# Matomo analytics (shared config across apps; URL must have trailing slash) +FLASK_MATOMO_URL=https://... +# MATOMO_JS and MATOMO_FILE have default values; override if your installation varies +# FLASK_MATOMO_JS=matomo.js +# FLASK_MATOMO_FILE=matomo.php +# Matomo API key, used in funnel.cli.periodic.stats +FLASK_MATOMO_TOKEN=null +# Matomo site id (app-specific) +FLASK_MATOMO_ID= + +# --- Statsd logging (always enabled, emits to UDP) +# Support for tagging varies between implementations: +# Etsy's statsd doesn't support tagging (default `false` merges tags into metric name) +# Telegraf uses `,` as a tag separator +# Prometheus uses `;` as a tag separator +FLASK_STATSD_TAGS=, +# Other statsd settings have default values: +# FLASK_STATSD_HOST=127.0.0.1 +# FLASK_STATSD_PORT=8125 +# FLASK_STATSD_MAXUDPSIZE=512 +# FLASK_STATSD_IPV6=false +# Sampling rate, 0.0-1.0, default 1 logs 100% +# FLASK_STATSD_RATE=1 +# FLASK_STATSD_TAGS=false +# Log all Flask requests (time to serve, response status code) +# FLASK_STATSD_REQUEST_LOG=true +# Log all WTForms validations (when using baseframe.forms.Form subclass) +# FLASK_STATSD_FORM_LOG=true + +# --- Redis Queue and Redis cache (use separate dbs to isolate) +# Redis server host +REDIS_HOST=localhost +# RQ and cache +FLASK_RQ_REDIS_URL=redis://${REDIS_HOST}:6379/1 +FLASK_CACHE_TYPE=flask_caching.backends.RedisCache +FLASK_CACHE_REDIS_URL=redis://${REDIS_HOST}:6379/0 + +# --- Database configuration +DB_HOST=localhost +FLASK_SQLALCHEMY_DATABASE_URI='postgresql:///hasjob' + +# --- Email configuration +# SMTP mail server ('localhost' if Postfix is configured as a relay email server) +FLASK_MAIL_SERVER=localhost +# If not using localhost, SMTP will need authentication +# Port number (25 is default, but 587 is more likely for non-localhost) +FLASK_MAIL_PORT=25 +# Port 25 uses neither TLS nor SSL. Port 587 uses TLS and port 465 uses SSL (obsolete) +FLASK_MAIL_USE_TLS=false +FLASK_MAIL_USE_SSL=false +# Authentication if using port 587 or 465 +FLASK_MAIL_USERNAME=null +FLASK_MAIL_PASSWORD=null +# Default "From:" address in email +FLASK_MAIL_DEFAULT_SENDER="Hasjob " + +# --- App configuration +# Support email and phone numbers (must be syntactically valid) +FLASK_SITE_SUPPORT_EMAIL=support@example.com +# Posting throttle limit +FLASK_THROTTLE_LIMIT=5 + +# --- GeoIP databases for IP address geolocation (used in account settings) +# Obtain a free license key from Maxmind, install geoipupdate, place the account id and +# key in GeoIP.conf and enable the GeoLite2-ASN database. The location of GeoIP.conf +# varies between Ubuntu and macOS. +# https://support.maxmind.com/hc/en-us/articles/4407111582235-Generate-a-License-Key + +# Ubuntu: +# sudo add-apt-repository ppa:maxmind/ppa +# sudo apt install geoipupdate +# vim /etc/GeoIP.conf +# sudo geoipupdate -f /etc/GeoIP.conf +# FLASK_GEOIP_PATH=/usr/share/GeoIP/GeoLite2-City.mmdb + +# macOS with Homebrew on Apple Silicon: +# brew install geoipupdate +# vim /opt/homebrew/etc/GeoIP.conf +# geoipupdate -f /opt/homebrew/etc/GeoIP.conf +# FLASK_GEOIP_PATH=/opt/homebrew/var/GeoIP/GeoLite2-City.mmdb + +# --- Logging +# Optional path to log file, or default null to disable file logging +FLASK_LOG_FILE=null +# Optional config for file logging: +# FLASK_LOG_FILE_LEVEL accepts NOTSET, DEBUG, INFO, WARNING (default), ERROR, CRITICAL +# FLASK_LOG_FILE_DELAY (bool, default true, delays log file creation until first log) +# FLASK_LOG_FILE_ROTATE (bool, default true, controls logrotate on the basis of time) +# FLASK_LOG_FILE_ROTATE_WHEN (default "midnight", other options: S, M, H, D, W0-W6) +# FLASK_LOG_FILE_ROTATE_COUNT (count of old files to keep, default 7 for a week's worth) +# FLASK_LOG_FILE_ROTATE_UTC (default false, if set uses UTC for midnight and W0-W6) + +# List of email addresses to send error reports with traceback and local var dump +# This requires SMTP config (above) +FLASK_LOG_EMAIL_TO='["webmaster@example.com"]' +# Additional options: FLASK_LOG_EMAIL_FROM, defaults to FLASK_MAIL_DEFAULT_SENDER + +# Send error reports to a Telegram chat +FLASK_LOG_TELEGRAM_CHATID=null +# Use these bot API credentials (configure your bot at https://t.me/botfather) +FLASK_LOG_TELEGRAM_APIKEY=null +# Optional settings: +# FLASK_LOG_TELEGRAM_THREADID (if the chat has topic threads, use a specific thread) +# FLASK_LOG_TELEGRAM_LEVEL=NOTSET, DEBUG, INFO, WARNING (default), ERROR, CRITICAL + +# --- Hasgeek app integrations +FLASK_LASTUSER_SERVER=http://funnel.test:3000 +FLASK_LASTUSER_CLIENT_ID=client_id_from_funnel +FLASK_LASTUSER_CLIENT_SECRET=client_secret_from_funnel + +# --- External app integrations + + +# --- OAuth2 login integrations From 3e5ebc0489ce7fc6f8d9395d3fdd82db054220d4 Mon Sep 17 00:00:00 2001 From: Mitesh Ashar Date: Wed, 9 Aug 2023 04:19:38 +0530 Subject: [PATCH 07/10] Add gunicorn and python-dotenv to requirements --- requirements.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/requirements.txt b/requirements.txt index d6c29256a..0b0206525 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,6 +15,7 @@ Flask-Testing git+https://github.com/maxcountryman/flask-uploads.git#egg=Flask-Uploads Flask-WTF geoip2 +gunicorn html2text jsmin langid @@ -22,6 +23,7 @@ Pillow premailer progressbar2 psycopg2 +python-dotenv pytz SQLAlchemy SQLAlchemy-Utils From 9441f8d7a1f12f21c663740d3bff3682e02a44e0 Mon Sep 17 00:00:00 2001 From: Kiran Jonnalagadda Date: Wed, 9 Aug 2023 04:51:32 +0530 Subject: [PATCH 08/10] Use ProxyFix for WSGI --- wsgi.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/wsgi.py b/wsgi.py index cb68fbf75..9cf9dbe9f 100644 --- a/wsgi.py +++ b/wsgi.py @@ -3,6 +3,7 @@ from flask.cli import load_dotenv from flask.helpers import get_load_dotenv +from werkzeug.middleware.proxy_fix import ProxyFix __all__ = ['application'] @@ -12,3 +13,5 @@ # pylint: disable=wrong-import-position from hasjob import app as application # isort:skip + +application.wsgi_app = ProxyFix(application.wsgi_app) # type: ignore[method-assign] From 8080dc029b84649f527dad9f1b5d43ffa7adadef Mon Sep 17 00:00:00 2001 From: Mitesh Ashar Date: Wed, 9 Aug 2023 06:35:51 +0530 Subject: [PATCH 09/10] Use psycopg2-binary instaed of psycopg2 in requirements --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 0b0206525..8eee7d600 100644 --- a/requirements.txt +++ b/requirements.txt @@ -22,7 +22,7 @@ langid Pillow premailer progressbar2 -psycopg2 +psycopg2-binary python-dotenv pytz SQLAlchemy From 6777700f60bf1488680f8b84e0a87b904e9cea4b Mon Sep 17 00:00:00 2001 From: Kiran Jonnalagadda Date: Wed, 9 Aug 2023 06:57:01 +0530 Subject: [PATCH 10/10] Fix casing --- .flaskenv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.flaskenv b/.flaskenv index 6e2a9f08e..80b056327 100644 --- a/.flaskenv +++ b/.flaskenv @@ -6,7 +6,7 @@ FLASK_DEBUG_TB_ENABLED=false FLASK_TESTING=false # To only support HTTPS, set Secure Cookies to True -FLASK_SESSION_COOKIE_SECURE=True +FLASK_SESSION_COOKIE_SECURE=true # --- App configuration # Default timezone when user timezone is not known