diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..ed61617 --- /dev/null +++ b/.env.example @@ -0,0 +1,5 @@ +EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend +EMAIL_HOST=127.0.0.1 +EMAIL_PORT=1025 # Mailpit default SMTP port +EMAIL_USE_TLS=False +DEFAULT_FROM_EMAIL=noreply@yourdomain.com \ No newline at end of file diff --git a/README.md b/README.md index 3178b48..40e2fda 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,42 @@ # MyRealEstate A property management application + +## Setup and Installation + +### Prerequisites +- Python 3.8+ +- Node.js and npm +- Docker (for MinIO) + +### Initial Setup + +1. Create and activate virtual environment: +``` +python +python -m venv venv +source venv/bin/activate # On Windows: venv\Scripts\activate +``` + +1. Install dependencies: +``` +pip install -r requirements.txt +``` + +1. Configure environment variables: +``` +# No variables needed for now +``` + +1. Run database migrations: +``` +python manage.py migrate +``` +### Tailwind CSS Setup + +1. Install Tailwind dependencies: + +1. Run the development server: +``` +python manage.py runserver +``` + diff --git a/myrealestate/accounts/migrations/0003_user_email_verification_token_user_email_verified.py b/myrealestate/accounts/migrations/0003_user_email_verification_token_user_email_verified.py new file mode 100644 index 0000000..ea3126a --- /dev/null +++ b/myrealestate/accounts/migrations/0003_user_email_verification_token_user_email_verified.py @@ -0,0 +1,24 @@ +# Generated by Django 5.1.3 on 2024-12-07 14:47 + +import uuid +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounts', '0002_usercompanyaccess_user_companies'), + ] + + operations = [ + migrations.AddField( + model_name='user', + name='email_verification_token', + field=models.UUIDField(default=uuid.uuid4, null=True), + ), + migrations.AddField( + model_name='user', + name='email_verified', + field=models.BooleanField(default=False), + ), + ] diff --git a/myrealestate/accounts/migrations/0004_populate_uuid_fields.py b/myrealestate/accounts/migrations/0004_populate_uuid_fields.py new file mode 100644 index 0000000..f5bf291 --- /dev/null +++ b/myrealestate/accounts/migrations/0004_populate_uuid_fields.py @@ -0,0 +1,21 @@ +# Generated by Django 5.1.3 on 2024-12-07 14:52 + +import uuid +from django.db import migrations + + +def gen_uuid(apps, schema_editor): + User = apps.get_model("accounts", "User") + for row in User.objects.all(): + row.email_verification_token = uuid.uuid4() + row.save(update_fields=["email_verification_token"]) + +class Migration(migrations.Migration): + + dependencies = [ + ('accounts', '0003_user_email_verification_token_user_email_verified'), + ] + + operations = [ + migrations.RunPython(gen_uuid, migrations.RunPython.noop), + ] diff --git a/myrealestate/accounts/migrations/0005_remove_uuid_null.py b/myrealestate/accounts/migrations/0005_remove_uuid_null.py new file mode 100644 index 0000000..b2a9c94 --- /dev/null +++ b/myrealestate/accounts/migrations/0005_remove_uuid_null.py @@ -0,0 +1,19 @@ +# Generated by Django 5.1.3 on 2024-12-07 14:52 + +import uuid +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounts', '0004_populate_uuid_fields'), + ] + + operations = [ + migrations.AlterField( + model_name='user', + name='email_verification_token', + field=models.UUIDField(default=uuid.uuid4, unique=True), + ), + ] diff --git a/myrealestate/accounts/models.py b/myrealestate/accounts/models.py index 8248f11..5322e19 100644 --- a/myrealestate/accounts/models.py +++ b/myrealestate/accounts/models.py @@ -1,3 +1,4 @@ +import uuid from django.db import models from django.contrib.auth.models import AbstractUser, BaseUserManager from django.utils.translation import gettext_lazy as _ @@ -30,6 +31,12 @@ class User(AbstractUser): related_name='users', verbose_name=_('Companies'), ) + email_verified = models.BooleanField(default=False) + email_verification_token = models.UUIDField(unique=True, default=uuid.uuid4) + + def generate_verification_token(self): + self.email_verification_token = uuid.uuid4() + self.save() USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['username'] diff --git a/myrealestate/config/settings.py b/myrealestate/config/settings.py index 4d1916b..e43e42e 100644 --- a/myrealestate/config/settings.py +++ b/myrealestate/config/settings.py @@ -11,6 +11,9 @@ """ from pathlib import Path +import django.core.mail +import os + # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent.parent @@ -198,5 +201,11 @@ MEDIA_URL = f'http://{MINIO_ENDPOINT}/{MINIO_BUCKET_NAME}/' MEDIA_ROOT = '' # MEDIA_ROOT is not used when using cloud storage +DEFAULT_FILE_STORAGE = 'myrealestate.common.storage.CustomS3Boto3Storage' + +EMAIL_BACKEND= os.getenv('EMAIL_BACKEND', 'django.core.mail.backends.smtp.EmailBackend') +EMAIL_HOST= os.getenv('EMAIL_HOST', '127.0.0.1') +EMAIL_PORT= os.getenv('EMAIL_PORT', 1025) # Mailpit default SMTP port +EMAIL_USE_TLS= os.getenv('EMAIL_USE_TLS', False) +DEFAULT_FROM_EMAIL= os.getenv('DEFAULT_FROM_EMAIL', 'noreply@yourdomain.com') -DEFAULT_FILE_STORAGE = 'myrealestate.common.storage.CustomS3Boto3Storage' \ No newline at end of file diff --git a/myrealestate/properties/views.py b/myrealestate/properties/views.py index d77d728..ed48303 100644 --- a/myrealestate/properties/views.py +++ b/myrealestate/properties/views.py @@ -27,7 +27,8 @@ def form_valid(self, form): self.object = form.save(commit=False) self.object.company = self.get_company() self.object.save() - messages.success(self.request, f"Estate created successfully.") + messages.success(self.request, "Estate created successfully.") + return super(BaseCreateView, self).form_valid(form) diff --git a/static/js/utils/patch-handler.js b/static/js/utils/patch-handler.js index 992eac7..d02356f 100644 --- a/static/js/utils/patch-handler.js +++ b/static/js/utils/patch-handler.js @@ -1,4 +1,3 @@ -// static/js/patch-handler.js document.addEventListener('DOMContentLoaded', function() { // Listen for all form submissions document.addEventListener('submit', async function(e) {