diff --git a/core/settings_base.py b/core/settings_base.py index 916c8ef..cd9dc92 100644 --- a/core/settings_base.py +++ b/core/settings_base.py @@ -37,6 +37,7 @@ "custom_auth", "allauth", "allauth.account", + "sponsors", ] MIDDLEWARE = [ @@ -75,7 +76,9 @@ STORAGES = { - # ... + "default": { + "BACKEND": "django.core.files.storage.FileSystemStorage" + }, "staticfiles": { "BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage", }, @@ -100,6 +103,12 @@ }, ] +# MEDIA +# ------------------------------------------------------------------------------ +# https://docs.djangoproject.com/en/dev/ref/settings/#media-root +MEDIA_ROOT = BASE_DIR / "media" +# https://docs.djangoproject.com/en/dev/ref/settings/#media-url +MEDIA_URL = "/media/" # Internationalization # https://docs.djangoproject.com/en/3.2/topics/i18n/ @@ -166,19 +175,16 @@ "signup": "custom_auth.forms.CustomSignupForm", } -SITE_ID = 1 # new ACCOUNT_EMAIL_VERIFICATION = True ACCOUNT_EMAIL_REQUIRED = True ACCOUNT_EMAIL_CONFIRMATION_EXPIRE_DAYS = 1 -ACCOUNT_EMAIL_REQUIRED = True ACCOUNT_USER_MODEL_USERNAME_FIELD = None -ACCOUNT_EMAIL_REQUIRED = True ACCOUNT_USERNAME_REQUIRED = False ACCOUNT_AUTHENTICATION_METHOD = "email" ACCOUNT_UNIQUE_EMAIL = True ACCOUNT_LOGOUT_REDIRECT_URL = "/accounts/login/" LOGIN_REDIRECT_URL = "/" -ACCOUNT_LOGIN_ON_PASSWORD_RESET = True # logged automatiquely when success +ACCOUNT_LOGIN_ON_PASSWORD_RESET = True # logged automatically when success ACCOUNT_LOGOUT_ON_GET = True diff --git a/core/urls.py b/core/urls.py index 577cbf2..8b14195 100644 --- a/core/urls.py +++ b/core/urls.py @@ -13,9 +13,10 @@ 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ - +from django.conf import settings from django.conf.urls.i18n import i18n_patterns from django.contrib import admin +from django.conf.urls.static import static from django.urls import path, include @@ -23,14 +24,19 @@ path("", include("website.urls")), path("accounts/", include("allauth.urls")), path("proposals/", include("proposals.urls")), + path("sponsors/", include("sponsors.urls")), path("admin/", admin.site.urls), path("__reload__/", include("django_browser_reload.urls")), path('i18n/', include('django.conf.urls.i18n')), ] +# Media and static files +urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) + urlpatterns += i18n_patterns( path("", include("website.urls")), path("accounts/", include("allauth.urls")), path("proposals/", include("proposals.urls")), + path("sponsors/", include("sponsors.urls")), path("admin/", admin.site.urls), ) \ No newline at end of file diff --git a/sponsors/__init__.py b/sponsors/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/sponsors/admin.py b/sponsors/admin.py new file mode 100644 index 0000000..76bae0b --- /dev/null +++ b/sponsors/admin.py @@ -0,0 +1,20 @@ +from django.contrib import admin + +from sponsors.models import Sponsor, SponsorshipPackage, File, TaggedFile + + +@admin.register(Sponsor) +class SponsorAdmin(admin.ModelAdmin): + pass + +@admin.register(SponsorshipPackage) +class SponsorshipPackageAdmin(admin.ModelAdmin): + pass + +@admin.register(File) +class FileAdmin(admin.ModelAdmin): + pass + +@admin.register(TaggedFile) +class TaggedFileAdmin(admin.ModelAdmin): + pass \ No newline at end of file diff --git a/sponsors/apps.py b/sponsors/apps.py new file mode 100644 index 0000000..c0183c4 --- /dev/null +++ b/sponsors/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class SponsorsConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'sponsors' diff --git a/sponsors/migrations/0001_initial.py b/sponsors/migrations/0001_initial.py new file mode 100644 index 0000000..a2ac1ca --- /dev/null +++ b/sponsors/migrations/0001_initial.py @@ -0,0 +1,54 @@ +# Generated by Django 4.2.16 on 2025-01-05 10:44 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='SponsorshipFile', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255)), + ('description', models.TextField(blank=True, help_text='A Description of the file.')), + ('item', models.FileField(upload_to='sponsors_files')), + ], + ), + migrations.CreateModel( + name='SponsorshipPackage', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('order', models.IntegerField(default=1)), + ('name', models.CharField(help_text='The name of the sponsorship package.', max_length=255)), + ('number_available', models.IntegerField(null=True, validators=[django.core.validators.MinValueValidator(0)])), + ('currency', models.CharField(default='$', help_text='Currency symbol of the sponsorship package.', max_length=20)), + ('amount', models.DecimalField(decimal_places=2, help_text='The amount of the sponsorship package.', max_digits=12)), + ('short_description', models.TextField(help_text='A short description of the sponsorship package.')), + ('files', models.ManyToManyField(blank=True, help_text='The files of the sponsorship package.', related_name='packages', to='sponsors.sponsorshipfile')), + ], + options={ + 'ordering': ['order', '-amount', 'name'], + }, + ), + migrations.CreateModel( + name='Sponsor', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('order', models.IntegerField(default=1)), + ('name', models.CharField(max_length=255)), + ('description', models.TextField(help_text='A description of the sponsor.')), + ('url', models.URLField(blank=True, default='', help_text='The URL of the sponsor if needed.')), + ('packages', models.ManyToManyField(related_name='sponsors', to='sponsors.sponsorshippackage')), + ], + options={ + 'ordering': ['order', 'name', 'id'], + }, + ), + ] diff --git a/sponsors/migrations/0002_rename_sponsorshipfile_file_taggedfile.py b/sponsors/migrations/0002_rename_sponsorshipfile_file_taggedfile.py new file mode 100644 index 0000000..2cc6b93 --- /dev/null +++ b/sponsors/migrations/0002_rename_sponsorshipfile_file_taggedfile.py @@ -0,0 +1,27 @@ +# Generated by Django 4.2.16 on 2025-01-12 12:23 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('sponsors', '0001_initial'), + ] + + operations = [ + migrations.RenameModel( + old_name='SponsorshipFile', + new_name='File', + ), + migrations.CreateModel( + name='TaggedFile', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('tag_name', models.CharField(help_text='The name of the tag.', max_length=255)), + ('sponsor', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='files', to='sponsors.sponsor')), + ('tagged_file', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='sponsors.file')), + ], + ), + ] diff --git a/sponsors/migrations/0003_sponsor_hiring.py b/sponsors/migrations/0003_sponsor_hiring.py new file mode 100644 index 0000000..b1d4e17 --- /dev/null +++ b/sponsors/migrations/0003_sponsor_hiring.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.16 on 2025-01-17 15:05 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('sponsors', '0002_rename_sponsorshipfile_file_taggedfile'), + ] + + operations = [ + migrations.AddField( + model_name='sponsor', + name='hiring', + field=models.BooleanField(default=False, help_text='Whether the sponsor is hiring or not.'), + ), + ] diff --git a/sponsors/migrations/0004_sponsorshippackage_symbol.py b/sponsors/migrations/0004_sponsorshippackage_symbol.py new file mode 100644 index 0000000..d939b9d --- /dev/null +++ b/sponsors/migrations/0004_sponsorshippackage_symbol.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.16 on 2025-01-21 08:24 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('sponsors', '0003_sponsor_hiring'), + ] + + operations = [ + migrations.AddField( + model_name='sponsorshippackage', + name='symbol', + field=models.CharField(blank=True, help_text='The symbol of the sponsorship package.', max_length=1), + ), + ] diff --git a/sponsors/migrations/0005_alter_sponsorshippackage_symbol.py b/sponsors/migrations/0005_alter_sponsorshippackage_symbol.py new file mode 100644 index 0000000..1acfc22 --- /dev/null +++ b/sponsors/migrations/0005_alter_sponsorshippackage_symbol.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.16 on 2025-01-21 08:30 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('sponsors', '0004_sponsorshippackage_symbol'), + ] + + operations = [ + migrations.AlterField( + model_name='sponsorshippackage', + name='symbol', + field=models.CharField(blank=True, help_text='The symbol of the sponsorship package.', max_length=100), + ), + ] diff --git a/sponsors/migrations/__init__.py b/sponsors/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/sponsors/models.py b/sponsors/models.py new file mode 100644 index 0000000..4e81611 --- /dev/null +++ b/sponsors/models.py @@ -0,0 +1,116 @@ +from django.db import models +from django.core.validators import MinValueValidator +from django.utils.translation import gettext_lazy as _ + + +class File(models.Model): + """File for use in sponsor and sponsorship package description.""" + name = models.CharField(max_length=255) + description = models.TextField( + blank=True, + help_text=_("A Description of the file.") + ) + item = models.FileField( + upload_to='sponsors_files' + ) + + def __str__(self): + return u"%s (%s)" % (self.name, self.item.url) + + +class SponsorshipPackage(models.Model): + """A description of a sponsorship package.""" + order = models.IntegerField(default=1) + name = models.CharField( + max_length=255, + help_text=_("The name of the sponsorship package.") + ) + number_available = models.IntegerField( + null=True, + validators=[MinValueValidator(0)] + ) + currency = models.CharField( + max_length=20, + default="$", + help_text=_("Currency symbol of the sponsorship package.") + ) + amount = models.DecimalField( + max_digits=12, + decimal_places=2, + help_text=_("The amount of the sponsorship package.") + ) + short_description = models.TextField( + help_text=_("A short description of the sponsorship package.") + ) + files = models.ManyToManyField( + File, + related_name="packages", + blank=True, + help_text=_("The files of the sponsorship package.") + ) + symbol = models.CharField( + max_length=100, + blank=True, + help_text=_("The symbol of the sponsorship package.") + ) + + class Meta: + ordering = ["order", "-amount", "name"] + + def __str__(self): + return u"%s (amount: %.0f)" % (self.name, self.amount,) + + +class Sponsor(models.Model): + """A conference sponsor.""" + order = models.IntegerField(default=1) + name = models.CharField(max_length=255) + packages = models.ManyToManyField( + SponsorshipPackage, + related_name="sponsors", + ) + description = models.TextField( + help_text=_("A description of the sponsor.") + ) + url = models.URLField( + default="", + blank=True, + help_text=_("The URL of the sponsor if needed.") + ) + hiring = models.BooleanField( + default=False, + help_text=_("Whether the sponsor is hiring or not.") + ) + hiring_url = models.URLField( + default="", + blank=True, + help_text=_("Hiring URL of the sponsor.") + ) + + def __str__(self): + return u"%s" % (self.name,) + + class Meta: + ordering = ["order", "name", "id"] + + +class TaggedFile(models.Model): + """Tags for files associated with a given sponsor""" + tag_name = models.CharField( + max_length=255, + null=False, + help_text=_("The name of the tag.") + ) + tagged_file = models.ForeignKey( + File, + on_delete=models.CASCADE + ) + sponsor = models.ForeignKey( + Sponsor, + related_name="files", + on_delete=models.CASCADE + ) + + def __str__(self): + return u"%s - (%s)" % (self.sponsor.name, self.tag_name,) + diff --git a/sponsors/templates/sponsors/sponsors.html b/sponsors/templates/sponsors/sponsors.html new file mode 100644 index 0000000..dbdfec0 --- /dev/null +++ b/sponsors/templates/sponsors/sponsors.html @@ -0,0 +1,42 @@ +{% load sponsors %} +{% sponsors as all_sponsors %} +{% packages as all_packages %} + +