diff --git a/api/.env.example b/api/.env.example index 501c942a..68dee251 100644 --- a/api/.env.example +++ b/api/.env.example @@ -1,4 +1,23 @@ -# Django Configuration -# Generated with: +# Configuração Django +# Gerar secret key: # python3 -c 'from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())' -DJANGO_SECRET_KEY="your_secret_key" \ No newline at end of file +DJANGO_SECRET_KEY="your_secret_key" +SETTINGS_FILE_PATH="core.settings.base" + +# Banco de Dados +DB_ENGINE="django.db.backends.postgresql" +DB_NAME="postgres" +DB_USERNAME="suagradeunb" +DB_PASSWORD="suagradeunb" +DB_HOSTNAME=db +DB_PORT=5432 + +# PostgreSQL +POSTGRES_DB="postgres" +POSTGRES_USER="suagradeunb" +POSTGRES_PASSWORD="suagradeunb" + + +# Credenciais de acesso ao admin +ADMIN_NAME="admin" +ADMIN_PASS="admin" \ No newline at end of file diff --git a/api/api/admin.py b/api/api/admin.py new file mode 100644 index 00000000..8c38f3f3 --- /dev/null +++ b/api/api/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/api/api/apps.py b/api/api/apps.py new file mode 100644 index 00000000..66656fd2 --- /dev/null +++ b/api/api/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class ApiConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'api' diff --git a/api/api/management/__init__.py b/api/api/management/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/api/api/management/commands/__init__.py b/api/api/management/commands/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/api/api/management/commands/initadmin.py b/api/api/management/commands/initadmin.py new file mode 100644 index 00000000..f6db34d3 --- /dev/null +++ b/api/api/management/commands/initadmin.py @@ -0,0 +1,19 @@ +from django.core.management.base import BaseCommand +from django.contrib.auth.models import User +from decouple import config + + +class Command(BaseCommand): + + def handle(self, *args, **options): + username = config("ADMIN_NAME") + if not len(User.objects.all().filter(username=username)): + password = config("ADMIN_PASS") + print(f'Conta do usuário {username} será criada!') + admin = User.objects.create_superuser( + username=username, password=password) + admin.is_active = True + admin.is_staff = True + admin.save() + else: + print('Conta de administrador já existe!') diff --git a/api/api/migrations/__init__.py b/api/api/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/api/api/models.py b/api/api/models.py new file mode 100644 index 00000000..71a83623 --- /dev/null +++ b/api/api/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/api/api/tests.py b/api/api/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/api/api/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/api/api/views.py b/api/api/views.py new file mode 100644 index 00000000..91ea44a2 --- /dev/null +++ b/api/api/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/api/core/__init__.py b/api/core/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/api/api/asgi.py b/api/core/asgi.py similarity index 75% rename from api/api/asgi.py rename to api/core/asgi.py index 07b75458..81d226b2 100644 --- a/api/api/asgi.py +++ b/api/core/asgi.py @@ -8,9 +8,10 @@ """ import os +from decouple import config from django.core.asgi import get_asgi_application -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'api.settings') +os.environ.setdefault('DJANGO_SETTINGS_MODULE', config('SETTINGS_FILE_PATH')) application = get_asgi_application() diff --git a/api/api/settings.py b/api/core/settings/base.py similarity index 82% rename from api/api/settings.py rename to api/core/settings/base.py index 56efaf15..60d732d2 100644 --- a/api/api/settings.py +++ b/api/core/settings/base.py @@ -12,6 +12,7 @@ from pathlib import Path from decouple import config +import os # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent @@ -26,18 +27,20 @@ # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -ALLOWED_HOSTS = [] +ALLOWED_HOSTS = ["*"] # Application definition INSTALLED_APPS = [ + 'api.apps.ApiConfig', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + 'rest_framework', ] MIDDLEWARE = [ @@ -50,7 +53,7 @@ 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] -ROOT_URLCONF = 'api.urls' +ROOT_URLCONF = 'core.urls' TEMPLATES = [ { @@ -68,20 +71,23 @@ }, ] -WSGI_APPLICATION = 'api.wsgi.application' +WSGI_APPLICATION = 'core.wsgi.application' # Database # https://docs.djangoproject.com/en/4.2/ref/settings/#databases DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': BASE_DIR / 'db.sqlite3', + "default": { + "ENGINE": "django.db.backends.postgresql", + "NAME": config("DB_NAME"), + "USER": config("DB_USERNAME"), + "PASSWORD": config("DB_PASSWORD"), + "HOST": config("DB_HOSTNAME"), + "PORT": config("DB_PORT", cast=int), } } - # Password validation # https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators @@ -106,7 +112,7 @@ LANGUAGE_CODE = 'en-us' -TIME_ZONE = 'UTC' +TIME_ZONE = 'America/Sao_Paulo' USE_I18N = True @@ -116,7 +122,11 @@ # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/4.2/howto/static-files/ -STATIC_URL = 'static/' +STATIC_URL = '/static/' +STATIC_ROOT = os.path.join(BASE_DIR, "../", "staticfiles") + +MEDIA_URL = "/media/" +MEDIA_ROOT = os.path.join(BASE_DIR, "../", "mediafiles") # Default primary key field type # https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field diff --git a/api/core/settings/dev.py b/api/core/settings/dev.py new file mode 100644 index 00000000..98dd39a5 --- /dev/null +++ b/api/core/settings/dev.py @@ -0,0 +1,11 @@ +from .base import * + +# Database +# https://docs.djangoproject.com/en/4.2/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'db.sqlite3', + } +} diff --git a/api/core/settings/prod.py b/api/core/settings/prod.py new file mode 100644 index 00000000..dd7be20e --- /dev/null +++ b/api/core/settings/prod.py @@ -0,0 +1,6 @@ +from .base import * + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = False + +ALLOWED_HOSTS = ["0.0.0.0:8000", "localhost:8000", "127.0.0.1:8000"] \ No newline at end of file diff --git a/api/api/urls.py b/api/core/urls.py similarity index 100% rename from api/api/urls.py rename to api/core/urls.py diff --git a/api/api/wsgi.py b/api/core/wsgi.py similarity index 75% rename from api/api/wsgi.py rename to api/core/wsgi.py index fba7ca86..4f194c0a 100644 --- a/api/api/wsgi.py +++ b/api/core/wsgi.py @@ -8,9 +8,10 @@ """ import os +from decouple import config from django.core.wsgi import get_wsgi_application -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'api.settings') +os.environ.setdefault('DJANGO_SETTINGS_MODULE', config('SETTINGS_FILE_PATH')) application = get_wsgi_application() diff --git a/api/manage.py b/api/manage.py index 8c45ccf3..41e1701e 100755 --- a/api/manage.py +++ b/api/manage.py @@ -2,11 +2,12 @@ """Django's command-line utility for administrative tasks.""" import os import sys +from decouple import config def main(): """Run administrative tasks.""" - os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'api.settings') + os.environ.setdefault('DJANGO_SETTINGS_MODULE', config('SETTINGS_FILE_PATH')) try: from django.core.management import execute_from_command_line except ImportError as exc: diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..114abf91 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,25 @@ +services: + db: + image: postgres:16 + volumes: + - postgres_data:/var/lib/postgresql/data/ + env_file: + - ./api/.env + + api: + restart: unless-stopped + build: + context: . + dockerfile: ./docker/Dockerfile + command: python3 manage.py runserver 0.0.0.0:8000 + volumes: + - .:/code/ + env_file: + - ./api/.env + ports: + - 8000:8000 + depends_on: + - db + +volumes: + postgres_data: \ No newline at end of file diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 00000000..9e82c1d9 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,28 @@ +FROM python:3.11.5-alpine3.18 + +# definir o diretório de trabalho +WORKDIR /usr/src/app + +# definir variáveis de ambiente +ENV PYTHONDONTWRITEBYTECODE 1 +ENV PYTHONUNBUFFERED 1 + +# instalar dependências do poastgres +RUN apk update && apk add postgresql-dev gcc python3-dev musl-dev + +# copiar os requisitos python +COPY ./requirements.txt /usr/src/app/requirements.txt + +# instalação das dependências +RUN pip install --upgrade pip && \ + pip install -r /usr/src/app/requirements.txt + +# copiar entrypoint.sh e dar permissão de execução +COPY ./docker/entrypoint.sh /usr/src/app/entrypoint.sh +RUN chmod +x /usr/src/app/entrypoint.sh + +# copiar o projeto +COPY ./api /usr/src/app/ + +# executar o arquivo de inicialização +ENTRYPOINT ["/usr/src/app/entrypoint.sh"] \ No newline at end of file diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh new file mode 100644 index 00000000..02262b51 --- /dev/null +++ b/docker/entrypoint.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +echo 'Esperando o PostgreSQL iniciar...' + +while ! nc -z $DB_HOSTNAME $DB_PORT; do + sleep 0.1 +done + +echo 'PostgreSQL iniciado' + +echo 'Migrando banco de dados...' +python3 manage.py migrate + +echo 'Criando usuário admin...' +python3 manage.py initadmin + +echo 'Coletando arquivos estáticos...' +python3 manage.py collectstatic --no-input + +exec "$@" \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index ccd7f1be..63139657 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,8 +4,8 @@ certifi==2023.7.22 charset-normalizer==3.2.0 click==8.1.7 colorama==0.4.6 -decouple==0.0.7 Django==4.2.5 +djangorestframework==3.14.0 ghp-import==2.1.0 idna==3.4 Jinja2==3.1.2 @@ -19,14 +19,18 @@ packaging==23.1 paginate==0.5.6 pathspec==0.11.2 platformdirs==3.10.0 +psycopg2-binary==2.9.7 Pygments==2.16.1 pymdown-extensions==10.3 python-dateutil==2.8.2 +python-decouple==3.8 +pytz==2023.3.post1 PyYAML==6.0.1 pyyaml_env_tag==0.1 regex==2023.8.8 requests==2.31.0 six==1.16.0 sqlparse==0.4.4 +typing_extensions==4.8.0 urllib3==2.0.5 watchdog==3.0.0