From 38ef495120ea0be75c04c2a824d9ff74c350faa0 Mon Sep 17 00:00:00 2001 From: Sanchit Balchandani Date: Sun, 9 Apr 2023 15:01:10 +0530 Subject: [PATCH 1/9] Initial commit for Dockerization --- .env | 20 +++++++++++ Dockerfile | 27 ++++++++++++++ Dockerfile.celery | 23 ++++++++++++ docker-compose.prod.yml | 0 docker-compose.test.yml | 11 ++++++ docker-compose.yml | 50 ++++++++++++++++++++++++++ junction/conferences/models.py | 2 +- junction/conferences/urls.py | 4 +-- junction/profiles/urls.py | 6 ++-- junction/proposals/urls.py | 43 +++++++++++----------- junction/schedule/urls.py | 4 +-- junction/tickets/urls.py | 4 +-- junction/urls.py | 65 +++++++++++++++++----------------- settings/common.py | 39 ++++++++++---------- wait-for-it.sh | 17 +++++++++ 15 files changed, 233 insertions(+), 82 deletions(-) create mode 100644 .env create mode 100644 Dockerfile create mode 100644 Dockerfile.celery create mode 100644 docker-compose.prod.yml create mode 100644 docker-compose.test.yml create mode 100644 docker-compose.yml create mode 100755 wait-for-it.sh diff --git a/.env b/.env new file mode 100644 index 00000000..7d0a57d6 --- /dev/null +++ b/.env @@ -0,0 +1,20 @@ +POSTGRES_USER=postgres +POSTGRES_PASSWORD=junction +POSTGRES_DB=junction +HOST_NAME=db +PORT=5432 +BROKER_URL=redis://redis:6379/0 +CELERY_RESULT_BACKEND=redis://redis:6379/0 +TESTING=FALSE +SITE_URL=https://in.pycon.org/junction +SITE_NAME=junction +GOOGLE_ANALYTICS_ID=dummy +FACEBOOK_APP_ID=dummy +EMAIL_HOST_USER=dummy +EMAIL_HOST_PASSWORD=dummy +SECRET_KEY=dummy +TWITTER_CONSUMER_KEY=dummy +TWITTER_CONSUMER_SECRET=dummy +TWITTER_ACCESS_TOKEN_KEY=dummy +TWITTER_ACCESS_TOKEN_SECRET=dummy +USE_ASYNC_FOR_EMAIL=dummy \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..f7aa055d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,27 @@ +FROM python:3.10-slim-buster + +WORKDIR /code + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc \ + postgresql-client \ + build-essential \ + libpq-dev && \ + rm -rf /var/lib/apt/lists/* + +COPY requirements.txt /code/ +RUN pip install --no-cache-dir -r requirements.txt + +# Install requirements for running tests +COPY ./tools/requirements-test.txt /code/ +RUN pip install --no-cache-dir -r requirements-test.txt + +COPY . /code/ +# not getting used at this moment +RUN chmod +x wait-for-it.sh + +ENV DJANGO_SETTINGS_MODULE=settings.dev +ENV PYTHONUNBUFFERED=1 + +EXPOSE 8888 \ No newline at end of file diff --git a/Dockerfile.celery b/Dockerfile.celery new file mode 100644 index 00000000..718934cc --- /dev/null +++ b/Dockerfile.celery @@ -0,0 +1,23 @@ +FROM python:3.10-slim-buster + +# Install system dependencies +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc \ + libc-dev \ + libffi-dev \ + make \ + postgresql-client \ + && rm -rf /var/lib/apt/lists/* + +# Install Python dependencies +COPY requirements.txt /app/ +RUN pip install --no-cache-dir -r /app/requirements.txt + +# Copy the application code +COPY . /app/ +WORKDIR /app + +# Set environment variables +ENV PYTHONUNBUFFERED 1 + diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml new file mode 100644 index 00000000..e69de29b diff --git a/docker-compose.test.yml b/docker-compose.test.yml new file mode 100644 index 00000000..75cb7f76 --- /dev/null +++ b/docker-compose.test.yml @@ -0,0 +1,11 @@ +version: '3.8' + +services: + web: + build: + context: . + dockerfile: Dockerfile + command: sh -c pytest --cov=unit --cov=integrations --cov-report=html + +volumes: + postgres_data: \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..e7e720f0 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,50 @@ +version: '3.8' + +services: + db: + image: postgres:15-alpine + environment: + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_DB: ${POSTGRES_DB} + ports: + - "5432:5432" + volumes: + - postgres_data:/var/lib/postgresql/data/ + + redis: + image: redis:latest + ports: + - "6379:6379" + + celery: + build: + context: . + dockerfile: Dockerfile.celery + volumes: + - .:/code + depends_on: + - db + - redis + env_file: + - .env + command: sh -c 'celery -A junction worker -l info -E' + + web: + build: + context: . + dockerfile: Dockerfile + volumes: + - .:/code + ports: + - "8888:8888" + depends_on: + - db + - redis + - celery + env_file: + - .env + command: sh -c 'python manage.py migrate && python manage.py runsslserver 0.0.0.0:8888' + +volumes: + postgres_data: diff --git a/junction/conferences/models.py b/junction/conferences/models.py index 91e8cc8a..a104cd2d 100644 --- a/junction/conferences/models.py +++ b/junction/conferences/models.py @@ -7,7 +7,7 @@ from django.db import models from six import python_2_unicode_compatible from django.utils.timezone import now -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from django_extensions.db.fields import AutoSlugField from simple_history.models import HistoricalRecords from slugify import slugify diff --git a/junction/conferences/urls.py b/junction/conferences/urls.py index e4f048e2..158ce1fb 100644 --- a/junction/conferences/urls.py +++ b/junction/conferences/urls.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- -from django.conf.urls import url +from django.urls import re_path from . import views -urlpatterns = [url(r"^$", views.get_conference, name="get-conference")] +urlpatterns = [re_path(r"^$", views.get_conference, name="get-conference")] diff --git a/junction/profiles/urls.py b/junction/profiles/urls.py index f7f1ab7e..feb0135b 100644 --- a/junction/profiles/urls.py +++ b/junction/profiles/urls.py @@ -1,10 +1,10 @@ -from django.conf.urls import url +from django.urls import re_path from . import views app_name = "junction.profiles" urlpatterns = [ - url(r"^$", views.dashboard, name="dashboard"), - url(r"^edit/$", views.profile, name="profile"), + re_path(r"^$", views.dashboard, name="dashboard"), + re_path(r"^edit/$", views.profile, name="profile"), ] diff --git a/junction/proposals/urls.py b/junction/proposals/urls.py index 4b5ab6fa..80004598 100644 --- a/junction/proposals/urls.py +++ b/junction/proposals/urls.py @@ -2,31 +2,32 @@ from __future__ import absolute_import, unicode_literals from django.conf.urls import include, url +from django.urls import re_path from . import comments_views, dashboard, views, votes_views comment_urls = [ - url( + re_path( r"^(?P[\w-]+)/create/$", comments_views.create_proposal_comment, name="proposal-comment-create", ), - url( + re_path( r"^(?P[\w-]+)/comments/(?P\d+)/up-vote/$", votes_views.proposal_comment_up_vote, name="proposal-comment-up-vote", ), - url( + re_path( r"^(?P[\w-]+)/comments/(?P\d+)/down-vote/$", votes_views.proposal_comment_down_vote, name="proposal-comment-down-vote", ), - url( + re_path( r"^(?P[\w-]+)/comments/(?P\d+)/mark_spam/$", comments_views.mark_comment_as_spam, name="comment_mark_spam", ), - url( + re_path( r"^(?P[\w-]+)/comments/(?P\d+)/unmark_spam/$", comments_views.unmark_comment_as_spam, name="comment_unmark_spam", @@ -35,56 +36,56 @@ urlpatterns = [ # proposal urls - url(r"^$", views.list_proposals, name="proposals-list"), - url(r"^create/$", views.create_proposal, name="proposal-create"), - url(r"^to_review/$", views.proposals_to_review, name="proposals-to-review"), - url( + re_path(r"^$", views.list_proposals, name="proposals-list"), + re_path(r"^create/$", views.create_proposal, name="proposal-create"), + re_path(r"^to_review/$", views.proposals_to_review, name="proposals-to-review"), + re_path( r"^second_phase_voting/$", dashboard.second_phase_voting, name="second-phase-voting", ), - url(r"^(?P[\w-]+)/$", views.detail_proposal, name="proposal-detail"), - url( + re_path(r"^(?P[\w-]+)/$", views.detail_proposal, name="proposal-detail"), + re_path( r"^(?P[\w-]+)~(?P.*)/$", views.detail_proposal, name="proposal-detail", ), - url(r"^(?P[\w-]+)/delete/$", views.delete_proposal, name="proposal-delete"), - url(r"^(?P[\w-]+)/update/$", views.update_proposal, name="proposal-update"), - url( + re_path(r"^(?P[\w-]+)/delete/$", views.delete_proposal, name="proposal-delete"), + re_path(r"^(?P[\w-]+)/update/$", views.update_proposal, name="proposal-update"), + re_path( r"^(?P[\w-]+)/upload-content/$", views.proposal_upload_content, name="proposal-upload-content", ), - url( + re_path( r"^(?P[\w-]+)/change-proposal-review-state/$", views.review_proposal, name="proposal-review", ), # comment urls - url(r"^comment/", include(comment_urls)), + re_path(r"^comment/", include(comment_urls)), # Voting - url( + re_path( r"^(?P[\w-]+)/down-vote/$", votes_views.proposal_vote_down, name="proposal-vote-down", ), - url( + re_path( r"^(?P[\w-]+)/up-vote/$", votes_views.proposal_vote_up, name="proposal-vote-up", ), - url( + re_path( r"^(?P[\w-]+)/remove-vote/$", votes_views.proposal_vote_remove, name="proposal-vote-remove", ), - url( + re_path( r"^(?P[\w-]+)/vote/$", votes_views.proposal_reviewer_vote, name="proposal-reviewer-vote", ), - url( + re_path( r"^(?P[\w-]+)/second-vote/$", votes_views.proposal_reviewer_secondary_vote, name="proposal-reviewer-secondary-vote", diff --git a/junction/schedule/urls.py b/junction/schedule/urls.py index 520bf150..34589b78 100644 --- a/junction/schedule/urls.py +++ b/junction/schedule/urls.py @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import, unicode_literals -from django.conf.urls import url +from django.urls import re_path from . import views urlpatterns = [ # schedule urls - url(r"^dummy_schedule/$", views.dummy_schedule, name="dummy_schedule"), + re_path(r"^dummy_schedule/$", views.dummy_schedule, name="dummy_schedule"), ] diff --git a/junction/tickets/urls.py b/junction/tickets/urls.py index 85bd246c..139d8c45 100644 --- a/junction/tickets/urls.py +++ b/junction/tickets/urls.py @@ -1,10 +1,10 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import, unicode_literals -from django.conf.urls import url +from django.urls import re_path from . import views urlpatterns = [ - url(r"^sync_data/$", views.sync_data, name="sync_data"), + re_path(r"^sync_data/$", views.sync_data, name="sync_data"), ] diff --git a/junction/urls.py b/junction/urls.py index 614305c6..c60746eb 100644 --- a/junction/urls.py +++ b/junction/urls.py @@ -4,6 +4,7 @@ import django.views.defaults from django.conf import settings from django.conf.urls import include, url +from django.urls import re_path from django.conf.urls.static import static from django.contrib import admin from django.views.generic.base import RedirectView, TemplateView @@ -42,108 +43,108 @@ urlpatterns = [ - url(r"^$", HomePageView.as_view(), name="page-home"), + re_path(r"^$", HomePageView.as_view(), name="page-home"), # Django Admin - url(r"^nimda/", admin.site.urls), + re_path(r"^nimda/", admin.site.urls), # Third Party Stuff - url(r"^accounts/", include("allauth.urls")), + re_path(r"^accounts/", include("allauth.urls")), # Tickets - url(r"^tickets/", include("junction.tickets.urls")), - url( + re_path(r"^tickets/", include("junction.tickets.urls")), + re_path( r"^feedback/(?P\d+)/$", view_feedback, name="feedback-detail" ), - url( + re_path( r"^schedule_item/(?P\d+)/$", non_proposal_schedule_item_view, name="schedule-item", ), - url(r"^api/v1/", include(router.urls)), + re_path(r"^api/v1/", include(router.urls)), # Device - url(r"^api/v1/devices/$", DeviceListApiView.as_view(), name="device-list"), - url( + re_path(r"^api/v1/devices/$", DeviceListApiView.as_view(), name="device-list"), + re_path( r"^api/v1/devices/(?P<_uuid>[\w-]+)/$", DeviceDetailApiView.as_view(), name="device-detail", ), # Feedback - url( + re_path( "^api/v1/feedback_questions/$", FeedbackQuestionListApiView.as_view(), name="feedback-questions-list", ), - url("^api/v1/feedback/$", FeedbackListApiView.as_view(), name="feedback-list"), + re_path("^api/v1/feedback/$", FeedbackListApiView.as_view(), name="feedback-list"), # User Dashboard - url(r"^profiles/", include("junction.profiles.urls", namespace="profiles")), + re_path(r"^profiles/", include("junction.profiles.urls", namespace="profiles")), # Static Pages. TODO: to be refactored - url( + re_path( r"^speakers/$", TemplateView.as_view(template_name="static-content/speakers.html",), name="speakers-static", ), - url( + re_path( r"^schedule/$", TemplateView.as_view(template_name="static-content/schedule.html",), name="schedule-static", ), - url( + re_path( r"^venue/$", TemplateView.as_view(template_name="static-content/venue.html",), name="venue-static", ), - url( + re_path( r"^sponsors/$", TemplateView.as_view(template_name="static-content/sponsors.html",), name="sponsors-static", ), - url( + re_path( r"^blog/$", TemplateView.as_view(template_name="static-content/blog-archive.html",), name="blog-archive", ), - url( + re_path( r"^coc/$", TemplateView.as_view(template_name="static-content/coc.html",), name="coc-static", ), - url( + re_path( r"^faq/$", TemplateView.as_view(template_name="static-content/faq.html",), name="faq-static", ), # Conference Pages - url(r"^(?P[\w-]+)/", include("junction.conferences.urls")), + re_path(r"^(?P[\w-]+)/", include("junction.conferences.urls")), # Proposals related - url(r"^(?P[\w-]+)/proposals/", include("junction.proposals.urls")), - url( + re_path(r"^(?P[\w-]+)/proposals/", include("junction.proposals.urls")), + re_path( r"^(?P[\w-]+)/dashboard/reviewers/", junction.proposals.dashboard.reviewer_comments_dashboard, name="proposal-reviewers-dashboard", ), - url( + re_path( r"^(?P[\w-]+)/dashboard/proposal_state/$", junction.proposals.dashboard.proposal_state, name="proposal-state", ), - url( + re_path( r"^(?P[\w-]+)/dashboard/$", junction.proposals.dashboard.proposals_dashboard, name="proposal-dashboard", ), - url( + re_path( r"^(?P[\w-]+)/dashboard/votes/$", junction.proposals.dashboard.reviewer_votes_dashboard, name="proposal-reviewer-votes-dashboard", ), - url( + re_path( r"^(?P[\w-]+)/dashboard/votes/export/$", junction.proposals.dashboard.export_reviewer_votes, name="export-reviewer-votes", ), # Schedule related - url(r"^(?P[\w-]+)/schedule/", include("junction.schedule.urls")), + re_path(r"^(?P[\w-]+)/schedule/", include("junction.schedule.urls")), # Proposals as conference home page. TODO: Needs to be enhanced - url( + re_path( r"^(?P[\w-]+)/", RedirectView.as_view(pattern_name="proposals-list"), name="conference-detail", @@ -153,8 +154,8 @@ if settings.DEBUG: urlpatterns += [ - url(r"^400/$", django.views.defaults.bad_request), # noqa - url(r"^403/$", django.views.defaults.permission_denied), - url(r"^404/$", django.views.defaults.page_not_found), - url(r"^500/$", django.views.defaults.server_error), + re_path(r"^400/$", django.views.defaults.bad_request), # noqa + re_path(r"^403/$", django.views.defaults.permission_denied), + re_path(r"^404/$", django.views.defaults.page_not_found), + re_path(r"^500/$", django.views.defaults.server_error), ] diff --git a/settings/common.py b/settings/common.py index 97265cff..7c521133 100644 --- a/settings/common.py +++ b/settings/common.py @@ -5,7 +5,7 @@ import os from os.path import dirname, join -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ DEBUG = True @@ -57,7 +57,7 @@ "django.contrib.staticfiles", "django.contrib.sites", ) - + THIRD_PARTY_APPS = ( "allauth", "allauth.account", @@ -71,7 +71,7 @@ "rest_framework", "django_filters", "simple_history", - #"sslserver", used in development server only + # "sslserver", used in development server only ) OUR_APPS = ( @@ -86,7 +86,7 @@ ) INSTALLED_APPS = CORE_APPS + THIRD_PARTY_APPS + OUR_APPS -SITE_ID = 1 +SITE_ID = 1 # Provider specific settings SOCIALACCOUNT_PROVIDERS = { @@ -107,11 +107,11 @@ # credentials, or list them here: 'SCOPE': { 'profile', - 'email', + 'email', }, 'APP': { - 'client_id': 'enter your google client_id', - 'secret': 'enter your google secret key', + 'client_id': 'enter your gogole oauth client_id', + 'secret': 'enter your google oauth secret ', 'key': '', }, } @@ -157,7 +157,8 @@ EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend" EMAIL_HOST = "smtp.gmail.com" EMAIL_HOST_USER = DEFAULT_FROM_EMAIL = (os.environ.get("EMAIL_HOST_USER", "enter gmail id"),) -EMAIL_HOST_PASSWORD = (os.environ.get("EMAIL_HOST_PASSWORD", "enter App password"),) #turn on 2-step verification in your gmail account and add App password +# turn on 2-step verification in your gmail account and add App password +EMAIL_HOST_PASSWORD = (os.environ.get("EMAIL_HOST_PASSWORD", "enter App password"),) EMAIL_PORT = 587 EMAIL_USE_TLS = True # DEFAULT_FROM_EMAIL = SITE_VARIABLES["site_name"] + " " @@ -176,7 +177,7 @@ "filters": ["require_debug_false"], "class": "django.utils.log.AdminEmailHandler", }, - "console": {"level": "DEBUG", "class": "logging.StreamHandler",}, + "console": {"level": "DEBUG", "class": "logging.StreamHandler", }, "file": { "level": "DEBUG", "class": "logging.FileHandler", @@ -185,11 +186,11 @@ }, "loggers": { "django.request": { - "handlers": ["mail_admins",], + "handlers": ["mail_admins", ], "level": "ERROR", "propagate": True, }, - "django.db.backends": {"level": "DEBUG", "handlers": ["file",],}, + "django.db.backends": {"level": "DEBUG", "handlers": ["file", ], }, }, } @@ -215,13 +216,13 @@ DATABASES = { - "default": { + "default": { "ENGINE": "django.db.backends.postgresql_psycopg2", - "NAME": os.environ.get("DB_NAME", "enter postgres db name"), - "USER": os.environ.get("DB_USER", "postgres"), - "PASSWORD": os.environ.get("DB_PASSWORD", "enter postgres password"), - "HOST": os.environ.get("DB_HOST", "localhost"), - "PORT": os.environ.get("DB_PORT", "5432"), + "NAME": os.environ.get("POSTGRES_DB", "junction"), + "USER": os.environ.get("POSTGRES_USER", "postgres"), + "PASSWORD": os.environ.get("POSTGRES_PASSWORD", "junction"), + "HOST": os.environ.get("HOST_NAME", "db"), + "PORT": os.environ.get("PORT", "5432"), } # "default": { # "ENGINE": "django.db.backends.sqlite3", @@ -234,7 +235,7 @@ ) -ALLOWED_HOSTS = ["*"] +ALLOWED_HOSTS = ["*"] SITE_PROTOCOL = "http" @@ -267,4 +268,4 @@ ENABLE_SECOND_PHASE_VOTING = False -ENABLE_UPLOAD_CONTENT = False \ No newline at end of file +ENABLE_UPLOAD_CONTENT = False diff --git a/wait-for-it.sh b/wait-for-it.sh new file mode 100755 index 00000000..cd9e315f --- /dev/null +++ b/wait-for-it.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# wait-for-it.sh: Wait for a service to be ready. + +set -e + +host="$1" +port="$2" +shift 2 +cmd="$@" + +until PGPASSWORD="$POSTGRES_PASSWORD" psql -h "$host" -U "$POSTGRES_USER" -c '\q'; do + >&2 echo "Postgres is unavailable - sleeping" + sleep 1 +done + +>&2 echo "Postgres is up - executing command" +exec $cmd From ad98f4fdf75453df13d2a140a2f796604c64ce04 Mon Sep 17 00:00:00 2001 From: Sanchit Balchandani Date: Tue, 18 Apr 2023 10:53:47 +0530 Subject: [PATCH 2/9] Fix review comments and dockerignore --- .dockerignore | 50 +++++++++++++++++++++++++++++++++++++++++ .env | 20 ----------------- .env.sample | 21 +++++++++++++++++ .gitignore | 5 ++++- Dockerfile | 2 +- Dockerfile.celery | 1 - docker-compose.test.yml | 14 ++++++++++-- docker-compose.yml | 6 ++--- settings/common.py | 6 +---- 9 files changed, 91 insertions(+), 34 deletions(-) create mode 100644 .dockerignore delete mode 100644 .env create mode 100644 .env.sample diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..f2a5aece --- /dev/null +++ b/.dockerignore @@ -0,0 +1,50 @@ +# .dockerignore + +# Ignore Python bytecode files +__pycache__/ +*.pyc +*.pyo +*.pyd + +# Ignore virtual environment directories +venv/ +*.virtualenv/ +.env/ + +# Ignore Django migration files +*/migrations/*.pyc +*/migrations/__pycache__/ + +# Ignore logs +logs/ +*.log + +# Ignore configuration files +*.ini + +# Ignore user-specific files (e.g., editor settings) +*.swp +*.swo +*.swn +*.bak +*.tmp +*.sublime* +*.vscode/ + +# Ignore local media files +media/ + +# Ignore local database files (SQLite) +*.sqlite3 +*.sqlite3-journal + +# Ignore test coverage reports +.coverage +htmlcov/ + +# Ignore build artifacts and distribution files +build/ +dist/ +*.egg-info/ +*.egg +*.wheel diff --git a/.env b/.env deleted file mode 100644 index 7d0a57d6..00000000 --- a/.env +++ /dev/null @@ -1,20 +0,0 @@ -POSTGRES_USER=postgres -POSTGRES_PASSWORD=junction -POSTGRES_DB=junction -HOST_NAME=db -PORT=5432 -BROKER_URL=redis://redis:6379/0 -CELERY_RESULT_BACKEND=redis://redis:6379/0 -TESTING=FALSE -SITE_URL=https://in.pycon.org/junction -SITE_NAME=junction -GOOGLE_ANALYTICS_ID=dummy -FACEBOOK_APP_ID=dummy -EMAIL_HOST_USER=dummy -EMAIL_HOST_PASSWORD=dummy -SECRET_KEY=dummy -TWITTER_CONSUMER_KEY=dummy -TWITTER_CONSUMER_SECRET=dummy -TWITTER_ACCESS_TOKEN_KEY=dummy -TWITTER_ACCESS_TOKEN_SECRET=dummy -USE_ASYNC_FOR_EMAIL=dummy \ No newline at end of file diff --git a/.env.sample b/.env.sample new file mode 100644 index 00000000..b806baba --- /dev/null +++ b/.env.sample @@ -0,0 +1,21 @@ +DEBUG=FALASE +POSTGRES_USER=username +POSTGRES_PASSWORD=password +POSTGRES_DB=dbname +HOST_NAME=hostname +PORT=portnumber +BROKER_URL=redis://redis:6379/0 +CELERY_RESULT_BACKEND=redis://redis:6379/0 +TESTING=FALSE +SITE_URL=http://0.0.0.0:8888 +SITE_NAME=junction +GOOGLE_ANALYTICS_ID=google_analytics_id +FACEBOOK_APP_ID=fb_app_id +EMAIL_HOST_USER=email_host_user +EMAIL_HOST_PASSWORD=email_host_pass +SECRET_KEY=secret_key +TWITTER_CONSUMER_KEY=twitter_consume_key +TWITTER_CONSUMER_SECRET=twitter_consume_secret +TWITTER_ACCESS_TOKEN_KEY=twitter_access_token +TWITTER_ACCESS_TOKEN_SECRET=twitter_access_token_secret +USE_ASYNC_FOR_EMAIL=boolean diff --git a/.gitignore b/.gitignore index 740ade66..117e414c 100644 --- a/.gitignore +++ b/.gitignore @@ -90,4 +90,7 @@ qr_files/ #VSCode .vscode/ -tmp/ \ No newline at end of file +tmp/ + +# Env +.env \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index f7aa055d..88e7d8eb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,4 +24,4 @@ RUN chmod +x wait-for-it.sh ENV DJANGO_SETTINGS_MODULE=settings.dev ENV PYTHONUNBUFFERED=1 -EXPOSE 8888 \ No newline at end of file +EXPOSE 8888 diff --git a/Dockerfile.celery b/Dockerfile.celery index 718934cc..534189b6 100644 --- a/Dockerfile.celery +++ b/Dockerfile.celery @@ -20,4 +20,3 @@ WORKDIR /app # Set environment variables ENV PYTHONUNBUFFERED 1 - diff --git a/docker-compose.test.yml b/docker-compose.test.yml index 75cb7f76..4cd8fd98 100644 --- a/docker-compose.test.yml +++ b/docker-compose.test.yml @@ -1,11 +1,21 @@ version: '3.8' services: + db: + image: postgres:15-alpine + ports: + - "5432:5432" + volumes: + - postgres_data:/var/lib/postgresql/data/ + env_file: + - .env web: build: context: . dockerfile: Dockerfile - command: sh -c pytest --cov=unit --cov=integrations --cov-report=html + command: sh -c pytest --cov=unit --cov=integrations --cov-report=html -v + depends_on: + - db volumes: - postgres_data: \ No newline at end of file + postgres_data: diff --git a/docker-compose.yml b/docker-compose.yml index e7e720f0..b0103958 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,14 +3,12 @@ version: '3.8' services: db: image: postgres:15-alpine - environment: - POSTGRES_USER: ${POSTGRES_USER} - POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} - POSTGRES_DB: ${POSTGRES_DB} ports: - "5432:5432" volumes: - postgres_data:/var/lib/postgresql/data/ + env_file: + - .env redis: image: redis:latest diff --git a/settings/common.py b/settings/common.py index 7c521133..adafc0c6 100644 --- a/settings/common.py +++ b/settings/common.py @@ -8,7 +8,7 @@ from django.utils.translation import gettext_lazy as _ -DEBUG = True +DEBUG = os.environ.get("DEBUG", False) # Build paths inside the project like this: os.path.join(ROOT_DIR, ...) ROOT_DIR = dirname(dirname(__file__)) APP_DIR = join(ROOT_DIR, "junction") @@ -224,10 +224,6 @@ "HOST": os.environ.get("HOST_NAME", "db"), "PORT": os.environ.get("PORT", "5432"), } - # "default": { - # "ENGINE": "django.db.backends.sqlite3", - # "NAME": os.path.join(ROOT_DIR, "test.sqlite3"), - # } } SECRET_KEY = os.environ.get( From 6575a213b80bd35e6c00f14ac9ab43459fe6f0db Mon Sep 17 00:00:00 2001 From: Sanchit Balchandani Date: Wed, 19 Apr 2023 00:15:40 +0530 Subject: [PATCH 3/9] Update dev.py.sample with runsslserver --- .gitignore | 2 +- wait-for-it.sh => bin/wait-for-it.sh | 0 settings/dev.py.sample | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename wait-for-it.sh => bin/wait-for-it.sh (100%) diff --git a/.gitignore b/.gitignore index 117e414c..2484b3fe 100644 --- a/.gitignore +++ b/.gitignore @@ -93,4 +93,4 @@ qr_files/ tmp/ # Env -.env \ No newline at end of file +.env diff --git a/wait-for-it.sh b/bin/wait-for-it.sh similarity index 100% rename from wait-for-it.sh rename to bin/wait-for-it.sh diff --git a/settings/dev.py.sample b/settings/dev.py.sample index d41d0829..ce6ad6ff 100644 --- a/settings/dev.py.sample +++ b/settings/dev.py.sample @@ -23,7 +23,7 @@ TEMPLATES[0]['OPTIONS']['context_processors'].extend([ EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' -INSTALLED_APPS += ('django_extensions',) +INSTALLED_APPS += ('django_extensions', 'sslserver') # settings for celery BROKER_URL = os.environ.get("BROKER_URL", "redis://127.0.0.1:6379/0") From 3e1b41c33942c882527e1816af1ab0e3e395c5e8 Mon Sep 17 00:00:00 2001 From: Ananya Maiti Date: Thu, 20 Apr 2023 18:06:37 +0530 Subject: [PATCH 4/9] Fixes for using default settings module --- .env.sample | 3 +-- Dockerfile | 3 +-- settings/common.py | 9 +++++++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/.env.sample b/.env.sample index b806baba..a645c0d6 100644 --- a/.env.sample +++ b/.env.sample @@ -1,4 +1,4 @@ -DEBUG=FALASE +DEBUG=TRUE POSTGRES_USER=username POSTGRES_PASSWORD=password POSTGRES_DB=dbname @@ -6,7 +6,6 @@ HOST_NAME=hostname PORT=portnumber BROKER_URL=redis://redis:6379/0 CELERY_RESULT_BACKEND=redis://redis:6379/0 -TESTING=FALSE SITE_URL=http://0.0.0.0:8888 SITE_NAME=junction GOOGLE_ANALYTICS_ID=google_analytics_id diff --git a/Dockerfile b/Dockerfile index 88e7d8eb..8ef08536 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,9 +19,8 @@ RUN pip install --no-cache-dir -r requirements-test.txt COPY . /code/ # not getting used at this moment -RUN chmod +x wait-for-it.sh +RUN chmod +x bin/wait-for-it.sh -ENV DJANGO_SETTINGS_MODULE=settings.dev ENV PYTHONUNBUFFERED=1 EXPOSE 8888 diff --git a/settings/common.py b/settings/common.py index adafc0c6..2c24f2de 100644 --- a/settings/common.py +++ b/settings/common.py @@ -7,8 +7,10 @@ from django.utils.translation import gettext_lazy as _ +DEBUG = False +if os.environ.get("DEBUG", False) == "TRUE": + DEBUG = True -DEBUG = os.environ.get("DEBUG", False) # Build paths inside the project like this: os.path.join(ROOT_DIR, ...) ROOT_DIR = dirname(dirname(__file__)) APP_DIR = join(ROOT_DIR, "junction") @@ -68,12 +70,15 @@ "pagedown", "markdown_deux", "django_bootstrap_breadcrumbs", + "django_extensions", "rest_framework", "django_filters", "simple_history", - # "sslserver", used in development server only ) +if DEBUG: + THIRD_PARTY_APPS += ("sslserver",) + OUR_APPS = ( "junction.base", "junction.conferences", From 6be717f6ec33a8634b21c6508429c470855c6a4e Mon Sep 17 00:00:00 2001 From: Ananya Maiti Date: Thu, 20 Apr 2023 18:36:54 +0530 Subject: [PATCH 5/9] Remove Dockerfile.celery and use image from junction web image --- Dockerfile.celery | 22 ---------------------- docker-compose.yml | 24 ++++++++++-------------- settings/common.py | 2 +- 3 files changed, 11 insertions(+), 37 deletions(-) delete mode 100644 Dockerfile.celery diff --git a/Dockerfile.celery b/Dockerfile.celery deleted file mode 100644 index 534189b6..00000000 --- a/Dockerfile.celery +++ /dev/null @@ -1,22 +0,0 @@ -FROM python:3.10-slim-buster - -# Install system dependencies -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc \ - libc-dev \ - libffi-dev \ - make \ - postgresql-client \ - && rm -rf /var/lib/apt/lists/* - -# Install Python dependencies -COPY requirements.txt /app/ -RUN pip install --no-cache-dir -r /app/requirements.txt - -# Copy the application code -COPY . /app/ -WORKDIR /app - -# Set environment variables -ENV PYTHONUNBUFFERED 1 diff --git a/docker-compose.yml b/docker-compose.yml index b0103958..2761d17a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,34 +15,30 @@ services: ports: - "6379:6379" - celery: + web: build: context: . - dockerfile: Dockerfile.celery + dockerfile: Dockerfile + image: junction_local volumes: - .:/code + ports: + - "8888:8888" depends_on: - db - - redis env_file: - .env - command: sh -c 'celery -A junction worker -l info -E' + command: sh -c 'python manage.py migrate && python manage.py runsslserver 0.0.0.0:8888' - web: - build: - context: . - dockerfile: Dockerfile - volumes: - - .:/code - ports: - - "8888:8888" + celery: + image: junction_local depends_on: - db - redis - - celery + - web env_file: - .env - command: sh -c 'python manage.py migrate && python manage.py runsslserver 0.0.0.0:8888' + command: sh -c 'celery -A junction worker -l info -E' volumes: postgres_data: diff --git a/settings/common.py b/settings/common.py index 2c24f2de..17882d62 100644 --- a/settings/common.py +++ b/settings/common.py @@ -115,7 +115,7 @@ 'email', }, 'APP': { - 'client_id': 'enter your gogole oauth client_id', + 'client_id': 'enter your google oauth client_id', 'secret': 'enter your google oauth secret ', 'key': '', }, From ceecde3acf97619a2010a937ae210f4d17b364cc Mon Sep 17 00:00:00 2001 From: Ananya Maiti Date: Thu, 20 Apr 2023 18:52:02 +0530 Subject: [PATCH 6/9] Update docker-compose.test.yml to not depend on postgres db --- docker-compose.test.yml | 15 +-------------- settings/dev.py.sample | 2 -- settings/test_settings.py | 2 -- 3 files changed, 1 insertion(+), 18 deletions(-) diff --git a/docker-compose.test.yml b/docker-compose.test.yml index 4cd8fd98..59c0f48c 100644 --- a/docker-compose.test.yml +++ b/docker-compose.test.yml @@ -1,21 +1,8 @@ version: '3.8' services: - db: - image: postgres:15-alpine - ports: - - "5432:5432" - volumes: - - postgres_data:/var/lib/postgresql/data/ - env_file: - - .env - web: + test: build: context: . dockerfile: Dockerfile command: sh -c pytest --cov=unit --cov=integrations --cov-report=html -v - depends_on: - - db - -volumes: - postgres_data: diff --git a/settings/dev.py.sample b/settings/dev.py.sample index ce6ad6ff..72784104 100644 --- a/settings/dev.py.sample +++ b/settings/dev.py.sample @@ -23,8 +23,6 @@ TEMPLATES[0]['OPTIONS']['context_processors'].extend([ EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' -INSTALLED_APPS += ('django_extensions', 'sslserver') - # settings for celery BROKER_URL = os.environ.get("BROKER_URL", "redis://127.0.0.1:6379/0") CELERY_RESULT_BACKEND = os.environ.get("CELERY_RESULT_BACKEND", 'redis://127.0.0.1:6379/0') diff --git a/settings/test_settings.py b/settings/test_settings.py index 78e09c47..22aabe8d 100644 --- a/settings/test_settings.py +++ b/settings/test_settings.py @@ -21,6 +21,4 @@ EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" -INSTALLED_APPS += ("django_extensions",) - DEVICE_VERIFICATION_CODE = 11111 From c15891c182713163ed64ef834c475c1f5e7f1028 Mon Sep 17 00:00:00 2001 From: Ananya Maiti Date: Mon, 24 Apr 2023 11:54:26 +0530 Subject: [PATCH 7/9] Add static asset compilation in Docker image --- Dockerfile | 8 ++++++++ bin/install-static.sh | 5 +++++ 2 files changed, 13 insertions(+) create mode 100644 bin/install-static.sh diff --git a/Dockerfile b/Dockerfile index 8ef08536..1e755f30 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,6 +7,8 @@ RUN apt-get update && \ gcc \ postgresql-client \ build-essential \ + nodejs \ + npm \ libpq-dev && \ rm -rf /var/lib/apt/lists/* @@ -17,7 +19,13 @@ RUN pip install --no-cache-dir -r requirements.txt COPY ./tools/requirements-test.txt /code/ RUN pip install --no-cache-dir -r requirements-test.txt +RUN npm install -g yarn +RUN npm install -g grunt-cli + COPY . /code/ + +RUN chmod +x bin/install-static.sh +RUN bin/install-static.sh # not getting used at this moment RUN chmod +x bin/wait-for-it.sh diff --git a/bin/install-static.sh b/bin/install-static.sh new file mode 100644 index 00000000..1294e028 --- /dev/null +++ b/bin/install-static.sh @@ -0,0 +1,5 @@ +#!/bin/bash +cd junction/static +yarn install +grunt less +cd ../.. From 183be6722b20ec21b3cc391ccda45fc33f40ae22 Mon Sep 17 00:00:00 2001 From: Ananya Maiti Date: Mon, 24 Apr 2023 17:43:19 +0530 Subject: [PATCH 8/9] Add docker-compose.prod.yml and update server port configuration in application --- .env.sample | 12 ++++++------ Dockerfile | 2 -- docker-compose.prod.yml | 41 +++++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 4 ++-- gunicorn.conf.py | 5 ++++- settings/common.py | 2 +- 6 files changed, 54 insertions(+), 12 deletions(-) diff --git a/.env.sample b/.env.sample index a645c0d6..e0cc46e1 100644 --- a/.env.sample +++ b/.env.sample @@ -1,13 +1,13 @@ DEBUG=TRUE -POSTGRES_USER=username -POSTGRES_PASSWORD=password -POSTGRES_DB=dbname -HOST_NAME=hostname -PORT=portnumber +POSTGRES_USER=postgres +POSTGRES_PASSWORD=junction +POSTGRES_DB=junction +HOST_NAME=db +DB_PORT=5432 BROKER_URL=redis://redis:6379/0 CELERY_RESULT_BACKEND=redis://redis:6379/0 -SITE_URL=http://0.0.0.0:8888 SITE_NAME=junction +SERVER_PORT=8888 GOOGLE_ANALYTICS_ID=google_analytics_id FACEBOOK_APP_ID=fb_app_id EMAIL_HOST_USER=email_host_user diff --git a/Dockerfile b/Dockerfile index 1e755f30..42e6a179 100644 --- a/Dockerfile +++ b/Dockerfile @@ -30,5 +30,3 @@ RUN bin/install-static.sh RUN chmod +x bin/wait-for-it.sh ENV PYTHONUNBUFFERED=1 - -EXPOSE 8888 diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index e69de29b..489d84f2 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -0,0 +1,41 @@ +version: '3.8' + +services: + db: + image: postgres:15-alpine + ports: + - "5432:5432" + volumes: + - postgres_data:/var/lib/postgresql/data/ + env_file: + - .env + + redis: + image: redis:latest + ports: + - "6379:6379" + + web: + image: ananyo2012/junction:1.1 + volumes: + - .:/code + ports: + - "${SERVER_PORT}:${SERVER_PORT}" + depends_on: + - db + env_file: + - .env + command: sh -c 'python manage.py migrate && python manage.py collectstatic --noinput --clear && gunicorn -c gunicorn.conf.py' + + celery: + image: ananyo2012/junction:1.1 + depends_on: + - db + - redis + - web + env_file: + - .env + command: sh -c 'celery -A junction worker -l info -E' + +volumes: + postgres_data: diff --git a/docker-compose.yml b/docker-compose.yml index 2761d17a..efe055ff 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -23,12 +23,12 @@ services: volumes: - .:/code ports: - - "8888:8888" + - "${SERVER_PORT}:${SERVER_PORT}" depends_on: - db env_file: - .env - command: sh -c 'python manage.py migrate && python manage.py runsslserver 0.0.0.0:8888' + command: sh -c 'python manage.py migrate && python manage.py runsslserver 0.0.0.0:${SERVER_PORT}' celery: image: junction_local diff --git a/gunicorn.conf.py b/gunicorn.conf.py index a8b6b91f..5e469558 100644 --- a/gunicorn.conf.py +++ b/gunicorn.conf.py @@ -1,4 +1,7 @@ +import os +port = os.environ.get("SERVER_PORT", "8888") + wsgi_app = "wsgi" -bind = "0.0.0.0:8001" +bind = f"0.0.0.0:{port}" workers = 2 loglevel = "debug" diff --git a/settings/common.py b/settings/common.py index 17882d62..9864c7e9 100644 --- a/settings/common.py +++ b/settings/common.py @@ -227,7 +227,7 @@ "USER": os.environ.get("POSTGRES_USER", "postgres"), "PASSWORD": os.environ.get("POSTGRES_PASSWORD", "junction"), "HOST": os.environ.get("HOST_NAME", "db"), - "PORT": os.environ.get("PORT", "5432"), + "PORT": os.environ.get("DB_PORT", "5432"), } } From dabc5d6dd5ae8edbdd07b1f0dad3d8dfcfd1e42e Mon Sep 17 00:00:00 2001 From: Ananya Maiti Date: Mon, 24 Apr 2023 18:34:37 +0530 Subject: [PATCH 9/9] Add social oauth env vars --- .env.sample | 4 ++++ settings/common.py | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.env.sample b/.env.sample index e0cc46e1..b2c9da52 100644 --- a/.env.sample +++ b/.env.sample @@ -13,6 +13,10 @@ FACEBOOK_APP_ID=fb_app_id EMAIL_HOST_USER=email_host_user EMAIL_HOST_PASSWORD=email_host_pass SECRET_KEY=secret_key +GITHUB_CLIENT_ID=github_client_id +GITHUB_CLIENT_SECRET=github_client_secret +GOOGLE_CLIENT_ID=google_oauth_client_id +GOOGLE_CLIENT_SECRET=google_oauth_client_secret TWITTER_CONSUMER_KEY=twitter_consume_key TWITTER_CONSUMER_SECRET=twitter_consume_secret TWITTER_ACCESS_TOKEN_KEY=twitter_access_token diff --git a/settings/common.py b/settings/common.py index 9864c7e9..1f6945b3 100644 --- a/settings/common.py +++ b/settings/common.py @@ -101,8 +101,8 @@ # interpreted as verified. 'VERIFIED_EMAIL': True, 'APP': { - 'client_id': 'enter your github client_id', - 'secret': 'enter your github secret key', + 'client_id': os.environ.get("GITHUB_CLIENT_ID", ""), + 'secret': os.environ.get("GITHUB_CLIENT_SECRET", ""), 'key': '', }, }, @@ -115,8 +115,8 @@ 'email', }, 'APP': { - 'client_id': 'enter your google oauth client_id', - 'secret': 'enter your google oauth secret ', + 'client_id': os.environ.get("GOOGLE_CLIENT_ID", ""), + 'secret': os.environ.get("GOOGLE_CLIENT_SECRET", ""), 'key': '', }, }