diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..d10e3b6 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +__pycache__ +*.pyc +env/ \ No newline at end of file diff --git a/.gitignore b/.gitignore index 038d34b..e8d996a 100644 --- a/.gitignore +++ b/.gitignore @@ -210,4 +210,6 @@ dist .yarn/unplugged .yarn/build-state.yml .yarn/install-state.gz -.pnp.* \ No newline at end of file +.pnp.* + +.env diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..4799d8f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +FROM python:3.9.5 + +ENV PYTHONUNBUFFERED=1 + +WORKDIR /code + +COPY backup/docker-requirements.txt /code/ +RUN pip install -r docker-requirements.txt + +COPY . /code/ + +RUN chmod au+x release +RUN ./release \ No newline at end of file diff --git a/Procfile b/Procfile index 5bdd6e8..14418e7 100644 --- a/Procfile +++ b/Procfile @@ -1,5 +1,8 @@ -release: chmod au+x release && ./release -web: gunicorn gusbemacbe.wsgi --log-file - +# Traditional +# release: chmod au+x release && ./release +# web: gunicorn gusbemacbe.wsgi --log-file - # Docker -# worker: python manage.py rqworker default \ No newline at end of file +release: chmod au+x release && ./release +web: gunicorn gusbemacbe.wsgi --log-file - +worker: python manage.py rqworker default \ No newline at end of file diff --git a/backup/docker-requirements.txt b/backup/docker-requirements.txt new file mode 100644 index 0000000..10636b6 --- /dev/null +++ b/backup/docker-requirements.txt @@ -0,0 +1,20 @@ +asgiref==3.3.4 +dj-database-url==0.5.0 +Django==3.2.4 +django-dbbackup==3.3.0 +django-extensions==3.1.3 +django-heroku==0.3.1 +django-redis-cache==3.0.0 +django-rq==2.4.1 +django-smuggler==1.0.2 +django-sslserver==0.22 +djangorestframework==3.12.4 +forex-python==1.6 +gunicorn==20.1.0 +pandas==1.2.4 +psycopg2-binary==2.9.1 +pymdown-extensions==8.2 +python-decouple==3.4 +pytz==2021.1 +sqlparse==0.4.1 +whitenoise==5.2.0 \ No newline at end of file diff --git a/backup/requirements.txt b/backup/requirements.txt index 53bc197..52241a9 100644 --- a/backup/requirements.txt +++ b/backup/requirements.txt @@ -1,4 +1,3 @@ -# ipychart dj-database-url Django # django-chartjs @@ -11,7 +10,8 @@ django-sslserver djangorestframework forex-python gunicorn -# pandas +# ipychart +pandas # psycopg2 psycopg2-binary pymdown-extensions diff --git a/contrib/env_gen.py b/contrib/env_gen.py index 3074462..d9e5329 100755 --- a/contrib/env_gen.py +++ b/contrib/env_gen.py @@ -14,7 +14,7 @@ CONFIG_STRING = """ DEBUG = True SECRET_KEY = %s -ALLOWED_HOSTS = 127.0.0.1, localhost, localhost:1984, 0.0.0.0 +ALLOWED_HOSTS = *, 127.0.0.1, localhost, localhost:1980, localhost:1984, 0.0.0.0 DATABASE_URL = sqlite:///db.sqlite3 # POSTGRES_DB_URL = postgres://USER:PASSWORD@HOST:PORT/NAME diff --git a/db.sqlite3 b/db.sqlite3 index 7e91154..b28ed57 100644 Binary files a/db.sqlite3 and b/db.sqlite3 differ diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..25c6931 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,40 @@ +version: '3.9' + +services: + db: + image: postgres + restart: always + volumes: + - pgdata:/var/lib/postgresql/data/ + environment: + - POSTGRES_DB=postgres + - POSTGRES_USER=postgres + - POSTGRES_PASSWORD=postgres + web: + build: . + command: python manage.py runserver 0.0.0.0:8000 + environment: + DEBUG: 1 + volumes: + - .:/app + ports: + - 8000:8000 + depends_on: + - db + - redis + + worker: + build: . + command: python manage.py rqworker default + environment: + DEBUG: 1 + volumes: + - .:/app + depends_on: + - web + + redis: + image: redis:latest + +volumes: + pgdata: \ No newline at end of file diff --git a/docker/dockerfiles/arch b/docker/dockerfiles/arch index 0633bd8..8455138 100644 --- a/docker/dockerfiles/arch +++ b/docker/dockerfiles/arch @@ -1,8 +1,7 @@ # Pull base image FROM archlinux/archlinux:latest -# Install psql so that "python manage.py dbshell" works -RUN yes | pacman -Syu +RUN yes | pacman -Syyu # Set environment variables ENV PYTHONDONTWRITEBYTECODE 1 @@ -12,12 +11,10 @@ ENV PYTHONUNBUFFERED 1 WORKDIR /app # Install dependencies -RUN yes | pacman -S neofetch postgresql postgresql-libs python python-pip python-psycopg2 python-pytz tidy -RUN neofetch -RUN python --version +RUN yes | pacman -S --needed gcc postgresql postgresql-libs python python-pip -COPY requirements.txt /app/requirements.txt -RUN pip install --user -r /app/requirements.txt +COPY pyproject.toml /app/pyproject.toml +RUN poetry install # Copy project COPY . /app/ \ No newline at end of file diff --git a/gusbemacbe/settings.py b/gusbemacbe/settings.py index 8cbfc9b..f6da726 100644 --- a/gusbemacbe/settings.py +++ b/gusbemacbe/settings.py @@ -58,6 +58,7 @@ # third-party apps # 'chartjs', 'dbbackup', + 'django_rq', 'django_extensions', 'smuggler', 'sslserver', @@ -75,7 +76,7 @@ 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', - # 'tidy.middleware.TidyMiddleware', + # 'tidy.middleware.TidyMiddleware' ] # ROOT_URLCONF = '{{ project_name }}.urls' @@ -110,11 +111,13 @@ # } # } -default_dburl = 'sqlite:///' + str(BASE_DIR / 'db.sqlite3') - -DATABASES = { - 'default': config('DATABASE_URL', default = default_dburl, cast = dburl), -} +# DATABASES = { +# # If DATABASE_URL environment variable isn't set, use Docker Compose Postgres database. +# 'default': dj_database_url.config( +# default = 'postgres://postgres:postgres@db:5432/gusbemacbe', +# conn_max_age = 600, +# ) +# } # DATABASES = { # 'default': { @@ -127,6 +130,12 @@ # } # } +default_dburl = 'sqlite:///' + str(BASE_DIR / 'db.sqlite3') + +DATABASES = { + 'default': config('DATABASE_URL', default = default_dburl, cast = dburl), +} + DBBACKUP_STORAGE = 'django.core.files.storage.FileSystemStorage' DBBACKUP_STORAGE_OPTIONS = {'location': 'backup/'} @@ -193,6 +202,27 @@ # Add configuration for static files storage using whitenoise STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' +# Configure Redis cache and Django-RQ. + +# https://django-redis-cache.readthedocs.io/en/latest/intro_quick_start.html#quick-start +CACHES = { + 'default': { + 'BACKEND': 'redis_cache.RedisCache', + # By default use Docker Compose Redis instance. + 'LOCATION': os.getenv('REDIS_URL', 'redis:6379'), + }, +} + +# https://github.com/rq/django-rq#support-for-django-redis-and-django-redis-cache +RQ_QUEUES = { + 'default': { + 'USE_REDIS_CACHE': 'default', + 'DEFAULT_TIMEOUT': 360, + }, +} + +RQ_SHOW_ADMIN_LINK = True + # Default primary key field type # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' diff --git a/gusbemacbe/src/gusbemacbe.co.nz/__init__.py b/gusbemacbe/src/gusbemacbe.co.nz/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/gusbemacbe/src/gusbemacbe.co.nz/main.py b/gusbemacbe/src/gusbemacbe.co.nz/main.py new file mode 100644 index 0000000..e69de29 diff --git a/gusbemacbe/urls.py b/gusbemacbe/urls.py index 7beaaab..aef0966 100644 --- a/gusbemacbe/urls.py +++ b/gusbemacbe/urls.py @@ -28,6 +28,7 @@ path('admin/', include('smuggler.urls')), # before admin url patterns! path('', home_view, name = 'home'), path('admin/', admin.site.urls), + path('django-rq/', include('django_rq.urls')), # Pages path('aparecida-covid-19-tracker/', include('AparecidaCovidTracker.urls')), diff --git a/heroku.yml b/heroku.yml new file mode 100644 index 0000000..8eec25b --- /dev/null +++ b/heroku.yml @@ -0,0 +1,3 @@ +build: + docker: + web: Dockerfile diff --git a/poetry.lock b/poetry.lock index 1dc21a7..f897212 100644 --- a/poetry.lock +++ b/poetry.lock @@ -25,6 +25,25 @@ category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +[[package]] +name = "click" +version = "8.0.1" +description = "Composable command line interface toolkit" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.4" +description = "Cross-platform colored terminal text." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + [[package]] name = "dj-database-url" version = "0.5.0" @@ -88,6 +107,34 @@ django = "*" psycopg2 = "*" whitenoise = "*" +[[package]] +name = "django-redis-cache" +version = "3.0.0" +description = "Redis Cache Backend for Django" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +redis = "<4.0" + +[[package]] +name = "django-rq" +version = "2.4.1" +description = "An app that provides django integration for RQ (Redis Queue)" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +django = ">=2.0" +redis = ">=3" +rq = ">=1.2" + +[package.extras] +Sentry = ["raven (>=6.1.0)"] +testing = ["mock (>=2.0.0)"] + [[package]] name = "django-smuggler" version = "1.0.2" @@ -187,6 +234,17 @@ pytz = ">=2017.3" [package.extras] test = ["pytest (>=5.0.1)", "pytest-xdist", "hypothesis (>=3.58)"] +[[package]] +name = "poetry-lock-package" +version = "0.4.0" +description = "Poetry lock package generator" +category = "dev" +optional = false +python-versions = ">=3.6.2,<4.0.0" + +[package.dependencies] +toml = ">=0.10.1,<0.11.0" + [[package]] name = "psycopg2" version = "2.9.1" @@ -234,23 +292,23 @@ optional = false python-versions = "*" [[package]] -name = "python-dotenv" -version = "0.17.1" -description = "Read key-value pairs from a .env file and set them as environment variables" +name = "pytz" +version = "2021.1" +description = "World timezone definitions, modern and historical" category = "main" optional = false python-versions = "*" -[package.extras] -cli = ["click (>=5.0)"] - [[package]] -name = "pytz" -version = "2021.1" -description = "World timezone definitions, modern and historical" +name = "redis" +version = "3.5.3" +description = "Python client for Redis key-value store" category = "main" optional = false -python-versions = "*" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.extras] +hiredis = ["hiredis (>=0.1.3)"] [[package]] name = "requests" @@ -270,6 +328,18 @@ urllib3 = ">=1.21.1,<1.27" security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] +[[package]] +name = "rq" +version = "1.8.1" +description = "RQ is a simple, lightweight, library for creating background jobs, and processing them." +category = "main" +optional = false +python-versions = ">=3.5" + +[package.dependencies] +click = ">=5.0.0" +redis = ">=3.5.0" + [[package]] name = "simplejson" version = "3.17.2" @@ -294,6 +364,14 @@ category = "main" optional = false python-versions = ">=3.5" +[[package]] +name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +category = "dev" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" + [[package]] name = "urllib3" version = "1.26.5" @@ -321,7 +399,7 @@ brotli = ["brotli"] [metadata] lock-version = "1.1" python-versions = "^3.9" -content-hash = "79150afdead32d88dfea6fd2773bedaf1dd5b294c07484ec1a2beea570c76d9e" +content-hash = "e0227fa27c768f1c91567520c4be2c5bcfd4cdcfd4c3b90927870f0a213ca55a" [metadata.files] asgiref = [ @@ -336,6 +414,14 @@ chardet = [ {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"}, {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"}, ] +click = [ + {file = "click-8.0.1-py3-none-any.whl", hash = "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6"}, + {file = "click-8.0.1.tar.gz", hash = "sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a"}, +] +colorama = [ + {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, + {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, +] dj-database-url = [ {file = "dj-database-url-0.5.0.tar.gz", hash = "sha256:4aeaeb1f573c74835b0686a2b46b85990571159ffc21aa57ecd4d1e1cb334163"}, {file = "dj_database_url-0.5.0-py2.py3-none-any.whl", hash = "sha256:851785365761ebe4994a921b433062309eb882fedd318e1b0fcecc607ed02da9"}, @@ -355,6 +441,13 @@ django-heroku = [ {file = "django-heroku-0.3.1.tar.gz", hash = "sha256:6af4bc3ae4a9b55eaad6dbe5164918982d2762661aebc9f83d9fa49f6009514e"}, {file = "django_heroku-0.3.1-py2.py3-none-any.whl", hash = "sha256:2bc690aab89eedbe01311752320a9a12e7548e3b0ed102681acc5736a41a4762"}, ] +django-redis-cache = [ + {file = "django-redis-cache-3.0.0.tar.gz", hash = "sha256:9a2eebef421d996a82098a19d17ff6b321265cd73178fa398913019764e8394a"}, +] +django-rq = [ + {file = "django-rq-2.4.1.tar.gz", hash = "sha256:f09059ab37403a47c7933bca396fabb7f3058732d132462eade5333bc4bcac5f"}, + {file = "django_rq-2.4.1-py2.py3-none-any.whl", hash = "sha256:23981f83c537178cbbf730f192c13e99cede2204e9d917b1c1c80c42215dd227"}, +] django-smuggler = [ {file = "django-smuggler-1.0.2.tar.gz", hash = "sha256:6bae0fae3b1cc2cb389f057d34d90b521f4099878b24791fc4ec7be1dc870a35"}, {file = "django_smuggler-1.0.2-py2.py3-none-any.whl", hash = "sha256:ad8cfdce1ae6ea48a54d8d896ad1e51caafb7035a5f4750e0cc058bd4c141eb6"}, @@ -426,6 +519,10 @@ pandas = [ {file = "pandas-1.2.4-cp39-cp39-win_amd64.whl", hash = "sha256:2b063d41803b6a19703b845609c0b700913593de067b552a8b24dd8eeb8c9895"}, {file = "pandas-1.2.4.tar.gz", hash = "sha256:649ecab692fade3cbfcf967ff936496b0cfba0af00a55dfaacd82bdda5cb2279"}, ] +poetry-lock-package = [ + {file = "poetry-lock-package-0.4.0.tar.gz", hash = "sha256:ff406686d9763da53a0dacb26736d0ea93354cb02758b4e8f34859963e69ebb1"}, + {file = "poetry_lock_package-0.4.0-py3-none-any.whl", hash = "sha256:f82dbdf58b92e81055ba02791cecd5288c2f01372035f5c861c3a5720d9e112d"}, +] psycopg2 = [ {file = "psycopg2-2.9.1-cp36-cp36m-win32.whl", hash = "sha256:7f91312f065df517187134cce8e395ab37f5b601a42446bdc0f0d51773621854"}, {file = "psycopg2-2.9.1-cp36-cp36m-win_amd64.whl", hash = "sha256:830c8e8dddab6b6716a4bf73a09910c7954a92f40cf1d1e702fb93c8a919cc56"}, @@ -480,18 +577,22 @@ python-decouple = [ {file = "python-decouple-3.4.tar.gz", hash = "sha256:2e5adb0263a4f963b58d7407c4760a2465d464ee212d733e2a2c179e54c08d8f"}, {file = "python_decouple-3.4-py3-none-any.whl", hash = "sha256:a8268466e6389a639a20deab9d880faee186eb1eb6a05e54375bdf158d691981"}, ] -python-dotenv = [ - {file = "python-dotenv-0.17.1.tar.gz", hash = "sha256:b1ae5e9643d5ed987fc57cc2583021e38db531946518130777734f9589b3141f"}, - {file = "python_dotenv-0.17.1-py2.py3-none-any.whl", hash = "sha256:00aa34e92d992e9f8383730816359647f358f4a3be1ba45e5a5cefd27ee91544"}, -] pytz = [ {file = "pytz-2021.1-py2.py3-none-any.whl", hash = "sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798"}, {file = "pytz-2021.1.tar.gz", hash = "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da"}, ] +redis = [ + {file = "redis-3.5.3-py2.py3-none-any.whl", hash = "sha256:432b788c4530cfe16d8d943a09d40ca6c16149727e4afe8c2c9d5580c59d9f24"}, + {file = "redis-3.5.3.tar.gz", hash = "sha256:0e7e0cfca8660dea8b7d5cd8c4f6c5e29e11f31158c0b0ae91a397f00e5a05a2"}, +] requests = [ {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"}, {file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"}, ] +rq = [ + {file = "rq-1.8.1-py2.py3-none-any.whl", hash = "sha256:2c7f795a2c85d84125314e49853ed66ca9acf062e997ada16e259c1c284f525f"}, + {file = "rq-1.8.1.tar.gz", hash = "sha256:feec0f914e69cae2380e2f46d82901e2abbd6fb09db320acb295f486a338f89f"}, +] simplejson = [ {file = "simplejson-3.17.2-cp27-cp27m-macosx_10_13_x86_64.whl", hash = "sha256:2d3eab2c3fe52007d703a26f71cf649a8c771fcdd949a3ae73041ba6797cfcf8"}, {file = "simplejson-3.17.2-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:813846738277729d7db71b82176204abc7fdae2f566e2d9fcf874f9b6472e3e6"}, @@ -547,6 +648,10 @@ sqlparse = [ {file = "sqlparse-0.4.1-py3-none-any.whl", hash = "sha256:017cde379adbd6a1f15a61873f43e8274179378e95ef3fede90b5aa64d304ed0"}, {file = "sqlparse-0.4.1.tar.gz", hash = "sha256:0f91fd2e829c44362cbcfab3e9ae12e22badaa8a29ad5ff599f9ec109f0454e8"}, ] +toml = [ + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] urllib3 = [ {file = "urllib3-1.26.5-py2.py3-none-any.whl", hash = "sha256:753a0374df26658f99d826cfe40394a686d05985786d946fbe4165b5148f5a7c"}, {file = "urllib3-1.26.5.tar.gz", hash = "sha256:a7acd0977125325f516bda9735fa7142b909a8d01e8b2e4c8108d0984e6e0098"}, diff --git a/pyproject.toml b/pyproject.toml index 535c4d0..675e5a1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "gusbemacbe.co.nz" -version = "1.2.4" +version = "1.3.1" description = "My personal and professional website" authors = ["Gustavo Costa "] license = "MIT" @@ -13,6 +13,8 @@ Django = "^3.2.4" django-dbbackup = "^3.3.0" django-extensions = "^3.1.3" django-heroku = "^0.3.1" +django-redis-cache = "^3.0.0" +django-rq = "^2.4.1" django-smuggler = "^1.0.2" django-sslserver = "^0.22" djangorestframework = "^3.12.4" @@ -22,12 +24,12 @@ pandas = "^1.2.4" psycopg2-binary = "^2.9.1" pymdown-extensions = "^8.2" python-decouple = "^3.4" -python-dotenv = "^0.17.1" pytz = "^2021.1" sqlparse = "^0.4.1" whitenoise = "^5.2.0" [tool.poetry.dev-dependencies] +poetry-lock-package = "^0.4.0" [build-system] requires = ["poetry-core>=1.0.0"]