diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9b9a95b --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +media/ +static/ diff --git a/Dockerfile b/Dockerfile index 19f9977..c19e5f2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -25,4 +25,3 @@ RUN pip3 install -r requirements.txt # launcher COPY django-launcher.sh /django-launcher.sh RUN chmod +x /django-launcher.sh - diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..97e2be6 --- /dev/null +++ b/Makefile @@ -0,0 +1,29 @@ +.DEFAULT_GOAL := help +help: + @perl -nle'print $& if m{^[a-zA-Z_-|.]+:.*?## .*$$}' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-25s\033[0m %s\n", $$1, $$2}' + +run.format: ## Format style with black + docker-compose -f docker-compose.dev.yaml exec -T django bash -c "black --exclude='/(postgres|venv|migrations|node_modules|\.git)/' ." + +docker.bash: ## Enter bash terminal + docker exec -it formacion-htmx_django_1 bash + + +docker.recreate.django: ## Recreate Django image + docker-compose down + docker-compose build --no-cache django + +run.loaddata: ## Minimal load data + # Remove database + docker-compose -f docker-compose.dev.yaml exec -T django bash -c "python3 manage.py flush --noinput" + # Remove media + sudo rm -rf media + # Migrate + docker-compose -f docker-compose.dev.yaml exec -T django bash -c "python3 manage.py migrate" + # Add provinces, towns and categories + docker-compose -f docker-compose.dev.yaml exec -T db bash -c "psql -h localhost -d kualitte -U postgres -p 5432 -a -q -f /usr/src/app/scripts/provincias.sql" + +run.server: # Run server + docker-compose -f docker-compose.dev.yaml up + + diff --git a/app/website/migrations/0001_initial.py b/app/website/migrations/0001_initial.py new file mode 100644 index 0000000..5ca77a1 --- /dev/null +++ b/app/website/migrations/0001_initial.py @@ -0,0 +1,60 @@ +# Generated by Django 3.2.7 on 2021-11-11 20:29 + +from django.db import migrations, models +import django.db.models.deletion +import tinymce.models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Category', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=100, verbose_name='Nombre')), + ], + options={ + 'verbose_name': 'Categoria', + 'verbose_name_plural': 'Categorias', + 'ordering': ('name',), + }, + ), + migrations.CreateModel( + name='Profile', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('password', models.CharField(max_length=128, verbose_name='password')), + ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), + ('email', models.EmailField(max_length=254, unique=True, verbose_name='Email')), + ('full_name', models.CharField(default='', max_length=100, verbose_name='Full name')), + ('avatar', models.ImageField(upload_to='uploads/avatars/', verbose_name='Avatar')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='Talk', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=100, verbose_name='Título')), + ('image', models.ImageField(upload_to='uploads/talks/', verbose_name='Imagen')), + ('is_draft', models.BooleanField(default=True, verbose_name='¿Es un borrador?')), + ('content', tinymce.models.HTMLField(verbose_name='Contenido')), + ('created_at', models.DateTimeField(auto_now=True, verbose_name='Creado')), + ('author', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='author', to='website.profile', verbose_name='Autor')), + ('category', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='Categoría', to='website.category', verbose_name='Categoría')), + ], + options={ + 'verbose_name': 'Charla', + 'verbose_name_plural': 'Charlas', + 'ordering': ('-created_at',), + }, + ), + ] diff --git a/app/website/models.py b/app/website/models.py index fc41821..b478eaa 100644 --- a/app/website/models.py +++ b/app/website/models.py @@ -1,4 +1,6 @@ from django.db import models +from django.contrib.auth.models import AbstractBaseUser +from tinymce import models as tinymce_models class Profile(AbstractBaseUser): @@ -7,7 +9,7 @@ class Profile(AbstractBaseUser): email = models.EmailField("Email", unique=True) full_name = models.CharField( - max_length=100, verbose_name="Nombre y apellidos", default="Sapps" + max_length=100, verbose_name="Full name", default="" ) avatar = models.ImageField(verbose_name="Avatar", upload_to="uploads/avatars/") @@ -51,7 +53,7 @@ class Talk(models.Model): related_name="author", verbose_name="Autor", ) - image = models.ImageField(verbose_name="Imagen", upload_to="uploads/articles/") + image = models.ImageField(verbose_name="Imagen", upload_to="uploads/talks/") is_draft = models.BooleanField(default=True, verbose_name="¿Es un borrador?") content = tinymce_models.HTMLField(verbose_name="Contenido") created_at = models.DateTimeField(auto_now=True, verbose_name="Creado") diff --git a/docker-compose.yaml b/docker-compose.yaml index 3d2a495..5e1752a 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,9 +1,8 @@ -version: '3.1' services: - postgresql: - image: postgres + db: + image: postgres:14-alpine restart: "no" environment: POSTGRES_USER: postgres @@ -22,13 +21,13 @@ services: - .:/usr/src/app/ environment: DEBUG: "True" - ALLOWED_HOSTS: "event.localhost" + ALLOWED_HOSTS: "event.localhost,localhost" SECRET_KEY: "my-secret" DB_ENGINE: "django.db.backends.postgresql" DB_NAME: "event" DB_USER: "postgres" DB_PASSWORD: "postgres" - DB_HOST: "postgresql" + DB_HOST: db DB_PORT: "5432" DOMAIN: "event.localhost" DOMAIN_URL: "http://event.localhost" @@ -42,12 +41,12 @@ services: EMAIL_PORT: "1025" EMAIL_USER: "" EMAIL_PASSWORD: "" - expose: - - 8000 + ports: + - 8000:8000 depends_on: - - postgresql + - db - caddy: + web: image: caddy:alpine restart: unless-stopped ports: diff --git a/requirements.txt b/requirements.txt index 3d2675e..e334034 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ # Django -django===3.2.10 +django===3.2.9 django-extensions===3.1.3 # PostgreSQL driver psycopg2===2.9.1 @@ -15,15 +15,16 @@ channels_redis===3.2.0 djangorestframework markdown django-filter +# HTTP client +Requests===2.26.0 # Template ## Componentes - https://mitchel.me/slippers/ slippers # WYSIWYG editor Python Django admin django-tinymce===3.3.0 -# Testing -pytest-django -pytest # Pillow Pillow===8.2.0 # Linter black +# Fake data +Faker===8.13.2 diff --git a/scripts/create_profiles.py b/scripts/create_profiles.py new file mode 100644 index 0000000..ec0fe00 --- /dev/null +++ b/scripts/create_profiles.py @@ -0,0 +1,27 @@ +from app.website.models import Profile +from faker import Faker + +# Get random imagen from url +from django.core.files import File +import requests +import time +from tempfile import NamedTemporaryFile +from random import randint + +def run(): + fake = Faker() + + # 30 Profiles random + for email in [fake.unique.email() for i in range(30)]: + my_profile = Profile() + my_profile.email = email + my_profile.full_name = f"{fake.first_name()} {fake.last_name()}" + my_profile.set_password("password") + my_profile.save() + # Add a profile picture + url_random_imagen = f"https://cdn.jsdelivr.net/gh/tanrax/place-image-random/images/{randint(1, 1000)}.jpg" + r = requests.get(url_random_imagen) + img_temp = NamedTemporaryFile(delete=True) + img_temp.write(r.content) + img_temp.flush() + my_profile.avatar.save(f"random_{int(time.time() * 1000)}.jpg", File(img_temp))