aboutsummaryrefslogtreecommitdiffstats
path: root/alphabetlearning
diff options
context:
space:
mode:
Diffstat (limited to 'alphabetlearning')
-rw-r--r--alphabetlearning/contrib/sites/migrations/0001_initial.py47
-rw-r--r--alphabetlearning/contrib/sites/migrations/0002_alter_domain_unique.py21
-rw-r--r--alphabetlearning/contrib/sites/migrations/0003_set_site_domain_and_name.py63
-rw-r--r--alphabetlearning/contrib/sites/migrations/0004_alter_options_ordering_domain.py21
-rw-r--r--alphabetlearning/pages/apps.py4
-rw-r--r--alphabetlearning/payments/migrations/0001_initial.py138
-rw-r--r--alphabetlearning/payments/migrations/0002_initial.py46
-rw-r--r--alphabetlearning/payments/migrations/0002_subscriptionplan_and_more.py36
-rw-r--r--alphabetlearning/payments/migrations/0003_alter_price_price.py18
-rw-r--r--alphabetlearning/payments/migrations/0003_product_price.py53
-rw-r--r--alphabetlearning/payments/migrations/0004_alter_price_price.py18
-rw-r--r--alphabetlearning/payments/migrations/0004_rename_stripe_product_id_price_stripe_price_id.py18
-rw-r--r--alphabetlearning/payments/migrations/0005_remove_subscriptionplan_stripe_plan_id.py17
-rw-r--r--alphabetlearning/payments/migrations/0006_subscription_plan.py24
-rw-r--r--alphabetlearning/payments/migrations/0007_remove_cartitem_quantity_and_more.py23
-rw-r--r--alphabetlearning/payments/migrations/0008_remove_price_product_price_resource.py25
-rw-r--r--alphabetlearning/payments/migrations/0009_emailsignup_alter_price_resource.py28
-rw-r--r--alphabetlearning/payments/migrations/0010_pendingemailverification.py26
-rw-r--r--alphabetlearning/payments/migrations/0011_remove_pendingemailverification_first_name_and_more.py21
-rw-r--r--alphabetlearning/payments/migrations/0012_rename_pendingemailverification_emailverification.py17
-rw-r--r--alphabetlearning/payments/migrations/0013_alter_emailverification_email.py18
-rw-r--r--alphabetlearning/payments/models.py3
-rw-r--r--alphabetlearning/payments/tests/test_views.py6
-rw-r--r--alphabetlearning/payments/views.py155
-rw-r--r--alphabetlearning/resources/factories.py11
-rw-r--r--alphabetlearning/resources/migrations/0001_initial.py40
-rw-r--r--alphabetlearning/resources/migrations/0002_alter_resource_additional_resource_category_and_more.py24
-rw-r--r--alphabetlearning/resources/migrations/0002_resource_price.py18
-rw-r--r--alphabetlearning/resources/migrations/0003_alter_resource_description.py18
-rw-r--r--alphabetlearning/resources/migrations/0003_remove_resource_price.py17
-rw-r--r--alphabetlearning/resources/migrations/0004_resource_feature_slot_1_resource_feature_slot_2_and_more.py28
-rw-r--r--alphabetlearning/resources/migrations/0005_rename_feature_slot_1_resource_feature_slot_and_more.py26
-rw-r--r--alphabetlearning/resources/migrations/0006_resource_card_description_and_more.py23
-rw-r--r--alphabetlearning/resources/migrations/0007_alter_resource_feature_slot.py18
-rw-r--r--alphabetlearning/resources/migrations/0008_alter_resource_card_description.py18
-rw-r--r--alphabetlearning/resources/migrations/0009_alter_resource_feature_slot.py18
-rw-r--r--alphabetlearning/resources/migrations/0010_alter_resource_age_range.py18
-rw-r--r--alphabetlearning/resources/migrations/0011_alter_resource_curriculum.py18
-rw-r--r--alphabetlearning/resources/migrations/0012_resourcecategory_colour_css_class.py18
-rw-r--r--alphabetlearning/resources/migrations/0013_resourcecategory_badge_foreground_colour.py18
-rw-r--r--alphabetlearning/resources/migrations/0014_remove_resource_additional_resource_category_and_more.py27
-rw-r--r--alphabetlearning/resources/migrations/0015_resourcesubcategory.py30
-rw-r--r--alphabetlearning/resources/migrations/0016_alter_resourcesubcategory_options_and_more.py31
-rw-r--r--alphabetlearning/resources/migrations/0017_rename_additional_resource_category_resource_subcategories.py18
-rw-r--r--alphabetlearning/resources/migrations/0018_alter_resource_subcategories.py25
-rw-r--r--alphabetlearning/resources/migrations/0019_alter_pdfpagesnapshot_options_and_more.py26
-rw-r--r--alphabetlearning/resources/migrations/0020_remove_resource_price_resource_stripe_product_id.py23
-rw-r--r--alphabetlearning/resources/models.py10
-rw-r--r--alphabetlearning/resources/tests/test_forms.py10
-rw-r--r--alphabetlearning/resources/views.py26
-rw-r--r--alphabetlearning/static/images/funnel6.pngbin93993 -> 94071 bytes
-rw-r--r--alphabetlearning/templates/base.html4
-rw-r--r--alphabetlearning/users/migrations/0001_initial.py121
-rw-r--r--alphabetlearning/users/tasks.py9
-rw-r--r--alphabetlearning/users/tests/test_tasks.py17
55 files changed, 307 insertions, 1247 deletions
diff --git a/alphabetlearning/contrib/sites/migrations/0001_initial.py b/alphabetlearning/contrib/sites/migrations/0001_initial.py
index fd76afb..d6bb9e1 100644
--- a/alphabetlearning/contrib/sites/migrations/0001_initial.py
+++ b/alphabetlearning/contrib/sites/migrations/0001_initial.py
@@ -1,43 +1,32 @@
+# Generated by Django 5.1.4 on 2024-12-31 15:26
+
import django.contrib.sites.models
-from django.contrib.sites.models import _simple_domain_name_validator
-from django.db import migrations
-from django.db import models
+from django.db import migrations, models
class Migration(migrations.Migration):
- dependencies = []
+ initial = True
+
+ dependencies = [
+ ]
operations = [
migrations.CreateModel(
- name="Site",
+ name='Site',
fields=[
- (
- "id",
- models.AutoField(
- verbose_name="ID",
- serialize=False,
- auto_created=True,
- primary_key=True,
- ),
- ),
- (
- "domain",
- models.CharField(
- max_length=100,
- verbose_name="domain name",
- validators=[_simple_domain_name_validator],
- ),
- ),
- ("name", models.CharField(max_length=50, verbose_name="display name")),
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('domain', models.CharField(max_length=100, unique=True, validators=[django.contrib.sites.models._simple_domain_name_validator], verbose_name='domain name')),
+ ('name', models.CharField(max_length=50, verbose_name='display name')),
],
options={
- "ordering": ("domain",),
- "db_table": "django_site",
- "verbose_name": "site",
- "verbose_name_plural": "sites",
+ 'verbose_name': 'site',
+ 'verbose_name_plural': 'sites',
+ 'db_table': 'django_site',
+ 'ordering': ['domain'],
},
- bases=(models.Model,),
- managers=[("objects", django.contrib.sites.models.SiteManager())],
+ managers=[
+ ('objects', django.contrib.sites.models.SiteManager()),
+ ],
),
]
diff --git a/alphabetlearning/contrib/sites/migrations/0002_alter_domain_unique.py b/alphabetlearning/contrib/sites/migrations/0002_alter_domain_unique.py
deleted file mode 100644
index 4a44a6a..0000000
--- a/alphabetlearning/contrib/sites/migrations/0002_alter_domain_unique.py
+++ /dev/null
@@ -1,21 +0,0 @@
-import django.contrib.sites.models
-from django.db import migrations
-from django.db import models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [("sites", "0001_initial")]
-
- operations = [
- migrations.AlterField(
- model_name="site",
- name="domain",
- field=models.CharField(
- max_length=100,
- unique=True,
- validators=[django.contrib.sites.models._simple_domain_name_validator],
- verbose_name="domain name",
- ),
- )
- ]
diff --git a/alphabetlearning/contrib/sites/migrations/0003_set_site_domain_and_name.py b/alphabetlearning/contrib/sites/migrations/0003_set_site_domain_and_name.py
deleted file mode 100644
index f4b1cbb..0000000
--- a/alphabetlearning/contrib/sites/migrations/0003_set_site_domain_and_name.py
+++ /dev/null
@@ -1,63 +0,0 @@
-"""
-To understand why this file is here, please read:
-
-http://cookiecutter-django.readthedocs.io/en/latest/faq.html#why-is-there-a-django-contrib-sites-directory-in-cookiecutter-django
-"""
-from django.conf import settings
-from django.db import migrations
-
-
-def _update_or_create_site_with_sequence(site_model, connection, domain, name):
- """Update or create the site with default ID and keep the DB sequence in sync."""
- site, created = site_model.objects.update_or_create(
- id=settings.SITE_ID,
- defaults={
- "domain": domain,
- "name": name,
- },
- )
- if created:
- # We provided the ID explicitly when creating the Site entry, therefore the DB
- # sequence to auto-generate them wasn't used and is now out of sync. If we
- # don't do anything, we'll get a unique constraint violation the next time a
- # site is created.
- # To avoid this, we need to manually update DB sequence and make sure it's
- # greater than the maximum value.
- max_id = site_model.objects.order_by("-id").first().id
- with connection.cursor() as cursor:
- cursor.execute("SELECT last_value from django_site_id_seq")
- (current_id,) = cursor.fetchone()
- if current_id <= max_id:
- cursor.execute(
- "alter sequence django_site_id_seq restart with %s",
- [max_id + 1],
- )
-
-
-def update_site_forward(apps, schema_editor):
- """Set site domain and name."""
- Site = apps.get_model("sites", "Site")
- _update_or_create_site_with_sequence(
- Site,
- schema_editor.connection,
- "resources.joannalemon.com",
- "pyblackbird-cc",
- )
-
-
-def update_site_backward(apps, schema_editor):
- """Revert site domain and name to default."""
- Site = apps.get_model("sites", "Site")
- _update_or_create_site_with_sequence(
- Site,
- schema_editor.connection,
- "example.com",
- "example.com",
- )
-
-
-class Migration(migrations.Migration):
-
- dependencies = [("sites", "0002_alter_domain_unique")]
-
- operations = [migrations.RunPython(update_site_forward, update_site_backward)]
diff --git a/alphabetlearning/contrib/sites/migrations/0004_alter_options_ordering_domain.py b/alphabetlearning/contrib/sites/migrations/0004_alter_options_ordering_domain.py
deleted file mode 100644
index f7118ca..0000000
--- a/alphabetlearning/contrib/sites/migrations/0004_alter_options_ordering_domain.py
+++ /dev/null
@@ -1,21 +0,0 @@
-# Generated by Django 3.1.7 on 2021-02-04 14:49
-
-from django.db import migrations
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ("sites", "0003_set_site_domain_and_name"),
- ]
-
- operations = [
- migrations.AlterModelOptions(
- name="site",
- options={
- "ordering": ["domain"],
- "verbose_name": "site",
- "verbose_name_plural": "sites",
- },
- ),
- ]
diff --git a/alphabetlearning/pages/apps.py b/alphabetlearning/pages/apps.py
index cdd024b..768ce00 100644
--- a/alphabetlearning/pages/apps.py
+++ b/alphabetlearning/pages/apps.py
@@ -2,5 +2,5 @@ from django.apps import AppConfig
class PagesConfig(AppConfig):
- default_auto_field = 'django.db.models.BigAutoField'
- name = 'pages'
+ default_auto_field = "django.db.models.BigAutoField"
+ name = "alphabetlearning.pages"
diff --git a/alphabetlearning/payments/migrations/0001_initial.py b/alphabetlearning/payments/migrations/0001_initial.py
index 33b7602..136aef1 100644
--- a/alphabetlearning/payments/migrations/0001_initial.py
+++ b/alphabetlearning/payments/migrations/0001_initial.py
@@ -1,7 +1,7 @@
-# Generated by Django 5.0.4 on 2024-09-03 19:21
+# Generated by Django 5.1.4 on 2024-12-31 15:26
import django.db.models.deletion
-from django.conf import settings
+import uuid
from django.db import migrations, models
@@ -10,94 +10,78 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
- ("resources", "0019_alter_pdfpagesnapshot_options_and_more"),
- migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ('resources', '0001_initial'),
]
operations = [
migrations.CreateModel(
- name="ShoppingCart",
+ name='EmailSignup',
fields=[
- (
- "id",
- models.BigAutoField(
- auto_created=True,
- primary_key=True,
- serialize=False,
- verbose_name="ID",
- ),
- ),
- ("created_at", models.DateTimeField(auto_now_add=True)),
- ("updated_at", models.DateTimeField(auto_now=True)),
- (
- "user",
- models.OneToOneField(
- on_delete=django.db.models.deletion.CASCADE,
- to=settings.AUTH_USER_MODEL,
- ),
- ),
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('email', models.EmailField(max_length=254, unique=True)),
+ ('date_added', models.DateTimeField(auto_now_add=True)),
],
),
migrations.CreateModel(
- name="Subscription",
+ name='EmailVerification',
fields=[
- (
- "id",
- models.BigAutoField(
- auto_created=True,
- primary_key=True,
- serialize=False,
- verbose_name="ID",
- ),
- ),
- ("is_active", models.BooleanField(default=False)),
- ("start_date", models.DateTimeField(blank=True, null=True)),
- ("end_date", models.DateTimeField(blank=True, null=True)),
- (
- "stripe_subscription_id",
- models.CharField(blank=True, max_length=255, null=True),
- ),
- (
- "user",
- models.OneToOneField(
- on_delete=django.db.models.deletion.CASCADE,
- to=settings.AUTH_USER_MODEL,
- ),
- ),
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('email', models.EmailField(max_length=254, unique=True)),
+ ('verification_token', models.UUIDField(default=uuid.uuid4, editable=False)),
+ ('created_at', models.DateTimeField(auto_now_add=True)),
+ ('is_verified', models.BooleanField(default=False)),
],
),
migrations.CreateModel(
- name="CartItem",
+ name='Product',
fields=[
- (
- "id",
- models.BigAutoField(
- auto_created=True,
- primary_key=True,
- serialize=False,
- verbose_name="ID",
- ),
- ),
- ("quantity", models.PositiveIntegerField(default=1)),
- ("added_at", models.DateTimeField(auto_now_add=True)),
- (
- "resource",
- models.ForeignKey(
- on_delete=django.db.models.deletion.CASCADE,
- to="resources.resource",
- ),
- ),
- (
- "cart",
- models.ForeignKey(
- on_delete=django.db.models.deletion.CASCADE,
- related_name="items",
- to="payments.shoppingcart",
- ),
- ),
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=255)),
+ ('stripe_product_id', models.CharField(max_length=100)),
+ ],
+ ),
+ migrations.CreateModel(
+ name='ShoppingCart',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('created_at', models.DateTimeField(auto_now_add=True)),
+ ('updated_at', models.DateTimeField(auto_now=True)),
+ ],
+ ),
+ migrations.CreateModel(
+ name='Subscription',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('is_active', models.BooleanField(default=False)),
+ ('start_date', models.DateTimeField(blank=True, null=True)),
+ ('end_date', models.DateTimeField(blank=True, null=True)),
+ ],
+ ),
+ migrations.CreateModel(
+ name='SubscriptionPlan',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=255)),
+ ('price', models.DecimalField(decimal_places=2, max_digits=6)),
+ ('description', models.TextField()),
+ ('allowed_downloads', models.PositiveIntegerField()),
+ ],
+ ),
+ migrations.CreateModel(
+ name='CartItem',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('added_at', models.DateTimeField(auto_now_add=True)),
+ ('resource', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='resources.resource')),
+ ],
+ ),
+ migrations.CreateModel(
+ name='Price',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('price', models.IntegerField(default=0)),
+ ('stripe_price_id', models.CharField(max_length=100)),
+ ('resource', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='price_obj', to='resources.resource')),
],
- options={
- "unique_together": {("cart", "resource")},
- },
),
]
diff --git a/alphabetlearning/payments/migrations/0002_initial.py b/alphabetlearning/payments/migrations/0002_initial.py
new file mode 100644
index 0000000..04df889
--- /dev/null
+++ b/alphabetlearning/payments/migrations/0002_initial.py
@@ -0,0 +1,46 @@
+# Generated by Django 5.1.4 on 2024-12-31 15:26
+
+import django.db.models.deletion
+from django.conf import settings
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ('payments', '0001_initial'),
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='shoppingcart',
+ name='user',
+ field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
+ ),
+ migrations.AddField(
+ model_name='cartitem',
+ name='cart',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='items', to='payments.shoppingcart'),
+ ),
+ migrations.AddField(
+ model_name='subscription',
+ name='user',
+ field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
+ ),
+ migrations.AddField(
+ model_name='subscription',
+ name='plan',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='payments.subscriptionplan'),
+ ),
+ migrations.AlterUniqueTogether(
+ name='cartitem',
+ unique_together={('cart', 'resource')},
+ ),
+ migrations.AddConstraint(
+ model_name='subscription',
+ constraint=models.UniqueConstraint(fields=('user', 'plan'), name='unique_user_plan'),
+ ),
+ ]
diff --git a/alphabetlearning/payments/migrations/0002_subscriptionplan_and_more.py b/alphabetlearning/payments/migrations/0002_subscriptionplan_and_more.py
deleted file mode 100644
index cab49b5..0000000
--- a/alphabetlearning/payments/migrations/0002_subscriptionplan_and_more.py
+++ /dev/null
@@ -1,36 +0,0 @@
-# Generated by Django 5.0.4 on 2024-09-03 19:32
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ("payments", "0001_initial"),
- ]
-
- operations = [
- migrations.CreateModel(
- name="SubscriptionPlan",
- fields=[
- (
- "id",
- models.BigAutoField(
- auto_created=True,
- primary_key=True,
- serialize=False,
- verbose_name="ID",
- ),
- ),
- ("name", models.CharField(max_length=255)),
- ("price", models.DecimalField(decimal_places=2, max_digits=6)),
- ("description", models.TextField()),
- ("allowed_downloads", models.PositiveIntegerField()),
- ("stripe_plan_id", models.CharField(max_length=255)),
- ],
- ),
- migrations.RemoveField(
- model_name="subscription",
- name="stripe_subscription_id",
- ),
- ]
diff --git a/alphabetlearning/payments/migrations/0003_alter_price_price.py b/alphabetlearning/payments/migrations/0003_alter_price_price.py
new file mode 100644
index 0000000..3b69f8f
--- /dev/null
+++ b/alphabetlearning/payments/migrations/0003_alter_price_price.py
@@ -0,0 +1,18 @@
+# Generated by Django 5.1.4 on 2025-01-06 20:55
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('payments', '0002_initial'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='price',
+ name='price',
+ field=models.DecimalField(decimal_places=2, default=0, max_digits=3),
+ ),
+ ]
diff --git a/alphabetlearning/payments/migrations/0003_product_price.py b/alphabetlearning/payments/migrations/0003_product_price.py
deleted file mode 100644
index b12d5dc..0000000
--- a/alphabetlearning/payments/migrations/0003_product_price.py
+++ /dev/null
@@ -1,53 +0,0 @@
-# Generated by Django 5.0.4 on 2024-09-04 19:01
-
-import django.db.models.deletion
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ("payments", "0002_subscriptionplan_and_more"),
- ]
-
- operations = [
- migrations.CreateModel(
- name="Product",
- fields=[
- (
- "id",
- models.BigAutoField(
- auto_created=True,
- primary_key=True,
- serialize=False,
- verbose_name="ID",
- ),
- ),
- ("name", models.CharField(max_length=255)),
- ("stripe_product_id", models.CharField(max_length=100)),
- ],
- ),
- migrations.CreateModel(
- name="Price",
- fields=[
- (
- "id",
- models.BigAutoField(
- auto_created=True,
- primary_key=True,
- serialize=False,
- verbose_name="ID",
- ),
- ),
- ("price", models.IntegerField(default=0)),
- ("stripe_product_id", models.CharField(max_length=100)),
- (
- "product",
- models.ForeignKey(
- on_delete=django.db.models.deletion.CASCADE,
- to="payments.product",
- ),
- ),
- ],
- ),
- ]
diff --git a/alphabetlearning/payments/migrations/0004_alter_price_price.py b/alphabetlearning/payments/migrations/0004_alter_price_price.py
new file mode 100644
index 0000000..ae72dbf
--- /dev/null
+++ b/alphabetlearning/payments/migrations/0004_alter_price_price.py
@@ -0,0 +1,18 @@
+# Generated by Django 5.1.4 on 2025-01-06 20:59
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('payments', '0003_alter_price_price'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='price',
+ name='price',
+ field=models.IntegerField(default=0),
+ ),
+ ]
diff --git a/alphabetlearning/payments/migrations/0004_rename_stripe_product_id_price_stripe_price_id.py b/alphabetlearning/payments/migrations/0004_rename_stripe_product_id_price_stripe_price_id.py
deleted file mode 100644
index e5a339f..0000000
--- a/alphabetlearning/payments/migrations/0004_rename_stripe_product_id_price_stripe_price_id.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# Generated by Django 5.0.4 on 2024-09-04 19:17
-
-from django.db import migrations
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ("payments", "0003_product_price"),
- ]
-
- operations = [
- migrations.RenameField(
- model_name="price",
- old_name="stripe_product_id",
- new_name="stripe_price_id",
- ),
- ]
diff --git a/alphabetlearning/payments/migrations/0005_remove_subscriptionplan_stripe_plan_id.py b/alphabetlearning/payments/migrations/0005_remove_subscriptionplan_stripe_plan_id.py
deleted file mode 100644
index 1e642b4..0000000
--- a/alphabetlearning/payments/migrations/0005_remove_subscriptionplan_stripe_plan_id.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# Generated by Django 5.0.4 on 2024-09-08 19:23
-
-from django.db import migrations
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ("payments", "0004_rename_stripe_product_id_price_stripe_price_id"),
- ]
-
- operations = [
- migrations.RemoveField(
- model_name="subscriptionplan",
- name="stripe_plan_id",
- ),
- ]
diff --git a/alphabetlearning/payments/migrations/0006_subscription_plan.py b/alphabetlearning/payments/migrations/0006_subscription_plan.py
deleted file mode 100644
index f54b5f9..0000000
--- a/alphabetlearning/payments/migrations/0006_subscription_plan.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# Generated by Django 5.0.4 on 2024-09-08 20:21
-
-import django.db.models.deletion
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ("payments", "0005_remove_subscriptionplan_stripe_plan_id"),
- ]
-
- operations = [
- migrations.AddField(
- model_name="subscription",
- name="plan",
- field=models.ForeignKey(
- default=1,
- on_delete=django.db.models.deletion.CASCADE,
- to="payments.subscriptionplan",
- ),
- preserve_default=False,
- ),
- ]
diff --git a/alphabetlearning/payments/migrations/0007_remove_cartitem_quantity_and_more.py b/alphabetlearning/payments/migrations/0007_remove_cartitem_quantity_and_more.py
deleted file mode 100644
index e976059..0000000
--- a/alphabetlearning/payments/migrations/0007_remove_cartitem_quantity_and_more.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# Generated by Django 5.0.4 on 2024-09-14 14:40
-
-from django.conf import settings
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('payments', '0006_subscription_plan'),
- migrations.swappable_dependency(settings.AUTH_USER_MODEL),
- ]
-
- operations = [
- migrations.RemoveField(
- model_name='cartitem',
- name='quantity',
- ),
- migrations.AddConstraint(
- model_name='subscription',
- constraint=models.UniqueConstraint(fields=('user', 'plan'), name='unique_user_plan'),
- ),
- ]
diff --git a/alphabetlearning/payments/migrations/0008_remove_price_product_price_resource.py b/alphabetlearning/payments/migrations/0008_remove_price_product_price_resource.py
deleted file mode 100644
index 9d52284..0000000
--- a/alphabetlearning/payments/migrations/0008_remove_price_product_price_resource.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# Generated by Django 5.0.4 on 2024-10-19 15:11
-
-import django.db.models.deletion
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('payments', '0007_remove_cartitem_quantity_and_more'),
- ('resources', '0020_remove_resource_price_resource_stripe_product_id'),
- ]
-
- operations = [
- migrations.RemoveField(
- model_name='price',
- name='product',
- ),
- migrations.AddField(
- model_name='price',
- name='resource',
- field=models.ForeignKey(default=66, on_delete=django.db.models.deletion.CASCADE, related_name='price', to='resources.resource'),
- preserve_default=False,
- ),
- ]
diff --git a/alphabetlearning/payments/migrations/0009_emailsignup_alter_price_resource.py b/alphabetlearning/payments/migrations/0009_emailsignup_alter_price_resource.py
deleted file mode 100644
index 4be05a2..0000000
--- a/alphabetlearning/payments/migrations/0009_emailsignup_alter_price_resource.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# Generated by Django 5.0.4 on 2024-11-25 11:32
-
-import django.db.models.deletion
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('payments', '0008_remove_price_product_price_resource'),
- ('resources', '0020_remove_resource_price_resource_stripe_product_id'),
- ]
-
- operations = [
- migrations.CreateModel(
- name='EmailSignup',
- fields=[
- ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('email', models.EmailField(max_length=254, unique=True)),
- ('date_added', models.DateTimeField(auto_now_add=True)),
- ],
- ),
- migrations.AlterField(
- model_name='price',
- name='resource',
- field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='price_obj', to='resources.resource'),
- ),
- ]
diff --git a/alphabetlearning/payments/migrations/0010_pendingemailverification.py b/alphabetlearning/payments/migrations/0010_pendingemailverification.py
deleted file mode 100644
index c49a2cb..0000000
--- a/alphabetlearning/payments/migrations/0010_pendingemailverification.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# Generated by Django 5.0.4 on 2024-12-03 16:18
-
-import uuid
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('payments', '0009_emailsignup_alter_price_resource'),
- ]
-
- operations = [
- migrations.CreateModel(
- name='PendingEmailVerification',
- fields=[
- ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('email', models.EmailField(max_length=254)),
- ('first_name', models.CharField(max_length=100)),
- ('last_name', models.CharField(max_length=100)),
- ('verification_token', models.UUIDField(default=uuid.uuid4, editable=False)),
- ('created_at', models.DateTimeField(auto_now_add=True)),
- ('is_verified', models.BooleanField(default=False)),
- ],
- ),
- ]
diff --git a/alphabetlearning/payments/migrations/0011_remove_pendingemailverification_first_name_and_more.py b/alphabetlearning/payments/migrations/0011_remove_pendingemailverification_first_name_and_more.py
deleted file mode 100644
index e13f6d3..0000000
--- a/alphabetlearning/payments/migrations/0011_remove_pendingemailverification_first_name_and_more.py
+++ /dev/null
@@ -1,21 +0,0 @@
-# Generated by Django 5.0.4 on 2024-12-03 16:38
-
-from django.db import migrations
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('payments', '0010_pendingemailverification'),
- ]
-
- operations = [
- migrations.RemoveField(
- model_name='pendingemailverification',
- name='first_name',
- ),
- migrations.RemoveField(
- model_name='pendingemailverification',
- name='last_name',
- ),
- ]
diff --git a/alphabetlearning/payments/migrations/0012_rename_pendingemailverification_emailverification.py b/alphabetlearning/payments/migrations/0012_rename_pendingemailverification_emailverification.py
deleted file mode 100644
index 770aee5..0000000
--- a/alphabetlearning/payments/migrations/0012_rename_pendingemailverification_emailverification.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# Generated by Django 5.0.4 on 2024-12-03 17:23
-
-from django.db import migrations
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('payments', '0011_remove_pendingemailverification_first_name_and_more'),
- ]
-
- operations = [
- migrations.RenameModel(
- old_name='PendingEmailVerification',
- new_name='EmailVerification',
- ),
- ]
diff --git a/alphabetlearning/payments/migrations/0013_alter_emailverification_email.py b/alphabetlearning/payments/migrations/0013_alter_emailverification_email.py
deleted file mode 100644
index 5d537bb..0000000
--- a/alphabetlearning/payments/migrations/0013_alter_emailverification_email.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# Generated by Django 5.0.4 on 2024-12-05 16:16
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('payments', '0012_rename_pendingemailverification_emailverification'),
- ]
-
- operations = [
- migrations.AlterField(
- model_name='emailverification',
- name='email',
- field=models.EmailField(max_length=254, unique=True),
- ),
- ]
diff --git a/alphabetlearning/payments/models.py b/alphabetlearning/payments/models.py
index 44c8597..12c82f4 100644
--- a/alphabetlearning/payments/models.py
+++ b/alphabetlearning/payments/models.py
@@ -1,13 +1,12 @@
import uuid
from datetime import timedelta
+from alphabetlearning.resources.models import Resource
from django.conf import settings
from django.core.exceptions import ValidationError
from django.db import models
from django.utils import timezone
-from alphabetlearning.resources.models import Resource
-
class EmailVerification(models.Model):
email = models.EmailField(unique=True)
diff --git a/alphabetlearning/payments/tests/test_views.py b/alphabetlearning/payments/tests/test_views.py
index 3289c12..24bb19a 100644
--- a/alphabetlearning/payments/tests/test_views.py
+++ b/alphabetlearning/payments/tests/test_views.py
@@ -1,4 +1,5 @@
import pytest
+from alphabetlearning.payments.models import Price
from django.urls import reverse
@@ -13,7 +14,10 @@ def test_cart_view(client, user):
@pytest.mark.django_db
def test_add_resource_to_cart(client, resource, user):
+ price = Price.objects.create(resource=resource, price=1000, stripe_price_id="price_1")
+ resource.price_obj.add(price)
url = reverse("payments:add_to_basket", kwargs={"resource_id": resource.id})
client.force_login(user)
response = client.get(url)
- assert response.status_code == 200
+ # resdirects to the shopping cart
+ assert response.status_code == 302
diff --git a/alphabetlearning/payments/views.py b/alphabetlearning/payments/views.py
index 7682c35..cdfafe6 100644
--- a/alphabetlearning/payments/views.py
+++ b/alphabetlearning/payments/views.py
@@ -1,31 +1,19 @@
-import requests
import stripe
+from alphabetlearning.payments.models import EmailSignup, EmailVerification
+from alphabetlearning.resources.models import Resource
+from alphabetlearning.users.models import User
from django.conf import settings
from django.contrib.auth.decorators import login_required
-from django.core.mail import mail_admins
-from django.core.mail import send_mail
-from django.http import HttpResponse
-from django.http import HttpResponseBadRequest
-from django.shortcuts import get_object_or_404
-from django.shortcuts import redirect
-from django.shortcuts import render
-from django.urls import reverse
-from django.urls import reverse_lazy
+from django.core.mail import mail_admins, send_mail
+from django.http import HttpResponse, HttpResponseBadRequest
+from django.shortcuts import get_object_or_404, redirect, render
+from django.urls import reverse, reverse_lazy
from django.views import View
from django.views.decorators.csrf import csrf_exempt
-from django.views.generic import DeleteView
-from django.views.generic import TemplateView
-from django_ratelimit.decorators import ratelimit
-
-from alphabetlearning.payments.models import EmailSignup
-from alphabetlearning.payments.models import EmailVerification
-from alphabetlearning.resources.models import Resource
-from alphabetlearning.users.models import User
+from django.views.generic import DeleteView, TemplateView
from .forms import EmailVerificationForm
-from .models import CartItem
-from .models import Price
-from .models import ShoppingCart
+from .models import CartItem, Price, ShoppingCart
# TODO get the cart integrated with Stripe
# Steps to convert our Cart into something that can be used with Stripe:
@@ -58,11 +46,8 @@ class SuccessEmailSignupView(TemplateView):
return context
-@ratelimit(key="ip", rate="2/m", block=True)
def email_signup_verification(request):
if request.method == "POST":
- if getattr(request, "limited", False):
- return render(request, "payments/rate_limited.html", status=429)
form = EmailVerificationForm(request.POST)
if form.is_valid():
# Create pending verification
@@ -75,41 +60,27 @@ def email_signup_verification(request):
"payments:verify_email", args=[str(pending_verification.verification_token)]
)
)
- # email = process_verification_emails(
- # email=form.cleaned_data.get("email"),
- # verification_url=verification_url,
- # )
- email = send_mailgun_verification(form.cleaned_data.get("email"), verification_url)
+ email = send_verification_email(form.cleaned_data.get("email"), verification_url)
return render(request, "payments/verification_sent.html", {"email": email})
else:
- # email = process_verification_emails(email=request.POST.get("email"), warn=True)
- email = send_mailgun_verification(email=request.POST.get("email"), warn=True)
+ email = send_verification_email(email=request.POST.get("email"), warn=True)
return render(request, "payments/verification_sent.html", {"email": email})
else:
form = EmailVerificationForm()
return render(request, "pages/home.html", {"form": form}) # Adjust as necessary
-def send_mailgun_verification(
- email: str,
- verification_url: str = None,
- warn=False,
-):
+def send_verification_email(email: str, verification_url: str = None, warn=False):
if warn:
warning_message = """
You are already subscribed to our list - no further action is required.
"""
- requests.post(
- f"{settings.MAILGUN_API_URL}/{settings.MAILGUN_SENDER_DOMAIN}/messages",
- auth=("api", settings.MAILGUN_API_KEY),
- data={
- "from": f"No reply - Alphabet Learning <noreply@{settings.MAILGUN_SENDER_DOMAIN}>",
- "to": [
- email,
- ],
- "subject": "Alphabet Learning - Email Verification",
- "text": f"Thanks, {email} for signing up.\n\n{warning_message}\n\nBest regards,\n\nThe Alphabet Learning Team",
- },
+ send_mail(
+ subject="Alphabet Learning - Email Verification",
+ message=f"Thanks, {email} for signing up.\n\n{warning_message}\n\nBest regards,\n\nThe Alphabet Learning Team",
+ from_email=settings.DEFAULT_FROM_EMAIL,
+ recipient_list=[email],
+ fail_silently=False,
)
else:
warning_message = f"""
@@ -117,94 +88,16 @@ def send_mailgun_verification(
{verification_url}
If you didn't request this, please ignore this email.
"""
- requests.post(
- f"{settings.MAILGUN_API_URL}/{settings.MAILGUN_SENDER_DOMAIN}/messages",
- auth=("api", settings.MAILGUN_API_KEY),
- data={
- "from": f"No reply - Alphabet Learning <noreply@{settings.MAILGUN_SENDER_DOMAIN}>",
- "to": [
- email,
- ],
- "subject": "Alphabet Learning - Email Verification",
- "text": f"Thanks, {email} for signing up.\n\n{warning_message}\n\nBest regards,\n\nThe Alphabet Learning Team",
- },
+ send_mail(
+ subject="Alphabet Learning - Email Verification",
+ message=f"Thanks, {email} for signing up.\n\n{warning_message}\n\nBest regards,\n\nThe Alphabet Learning Team",
+ from_email=settings.DEFAULT_FROM_EMAIL,
+ recipient_list=[email],
+ fail_silently=False,
)
return email
-def process_verification_emails(
- email: str,
- verification_url: str = None,
- warn=False,
-):
- if warn is False:
- html_warning_message = f"""
- <p>Please click the following link to verify your email address within 24 hours:</p>
- <p><a href="{verification_url}">{verification_url}</a></p>
- <p>If you didn't request this, please ignore this email.</p>
- """
- warning_message = f"""
- Please click the following link to verify your email address within 24 hours:
- {verification_url}
- If you didn't request this, please ignore this email.
- """
- admin_warn = "They are not already subscribed."
- else:
- html_warning_message = """
- <p>You are already subscribed to our list - no further action is required.</p>
- """
- warning_message = """
- You are already subscribed to our list - no further action is required.
- """
- admin_warn = "They have already subscribed so have been told of this fact in their verification email. No further action required."
-
- # Send verification email
- subject = "Alphabet Learning - Email Verification"
- html_message = f"""
- <html>
- <body>
- <p>Hi!</p>
- <p>You recently requested to sign up to the Alphabet Learning contact list.</p>
- {html_warning_message}
- <p>Best regards,</p>
- <p>The Alphabet Learning Team</p>
- </body>
- </html>
- """
- message = f"""
- Hi!,
-
- You recently requested to sign up to the Alphabet Learning contact list.
-
- {warning_message}
-
- Best regards,
- The Alphabet Learning Team
- """
- send_mail(
- subject,
- message,
- settings.DEFAULT_FROM_EMAIL,
- [email],
- fail_silently=False,
- html_message=html_message,
- )
- admin_message = f"""
- Joanna/Matthew,
-
- {email} has just signed up to the Alphabet Learning contact list. They are awaiting verification.
-
- {admin_warn}
-
- I will email again if they follow through with the verification.
-
- Best regards,
- The Alphabet Learning Server
- """
- mail_admins(subject, admin_message, fail_silently=False)
- return email
-
-
def verify_email(request, token):
try:
pending = EmailVerification.objects.get(verification_token=token, is_verified=False)
diff --git a/alphabetlearning/resources/factories.py b/alphabetlearning/resources/factories.py
index 4075ab1..0f0194b 100644
--- a/alphabetlearning/resources/factories.py
+++ b/alphabetlearning/resources/factories.py
@@ -1,12 +1,10 @@
import itertools
import factory
+from alphabetlearning.payments.models import Price
-from .models import PDFPageSnapshot
-from .models import PDFResource
-from .models import Resource
-from .models import ResourceCategory
-from .models import ResourceType
+from .models import (PDFPageSnapshot, PDFResource, Resource, ResourceCategory,
+ ResourceType)
class ResourceTypeModelFactory(factory.django.DjangoModelFactory):
@@ -39,10 +37,11 @@ class ResourceModelFactory(factory.django.DjangoModelFactory):
model = Resource
name = factory.Sequence(lambda n: f"Default Resource {n}")
- price = factory.Faker("pydecimal", left_digits=4, right_digits=2, positive=True)
+ # price = factory.Faker("pydecimal", left_digits=4, right_digits=2, positive=True)
thumbnail_filenames = factory.List(
[factory.Faker("file_name", extension="jpg") for _ in range(3)]
)
+ # price_obj = factory.RelatedFactoryList("alphabetlearning.payments.factories.PriceFactory", size=1)
resource_type = factory.SubFactory(ResourceTypeModelFactory)
main_resource_category = factory.SubFactory(ResourceCategoryModelFactory)
subcategories = factory.RelatedFactoryList(ResourceCategoryModelFactory, size=2)
diff --git a/alphabetlearning/resources/migrations/0001_initial.py b/alphabetlearning/resources/migrations/0001_initial.py
index 812c98f..9112f51 100644
--- a/alphabetlearning/resources/migrations/0001_initial.py
+++ b/alphabetlearning/resources/migrations/0001_initial.py
@@ -1,4 +1,4 @@
-# Generated by Django 5.0.4 on 2024-05-13 21:41
+# Generated by Django 5.1.4 on 2024-12-31 15:26
import django.db.models.deletion
from django.db import migrations, models
@@ -19,16 +19,22 @@ class Migration(migrations.Migration):
('file_name', models.CharField(max_length=255)),
('file_size', models.IntegerField()),
],
+ options={
+ 'verbose_name_plural': 'PDF Resources',
+ },
),
migrations.CreateModel(
name='Resource',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255)),
+ ('stripe_product_id', models.CharField(max_length=100)),
('thumbnail_filenames', models.JSONField(default=list, verbose_name='Thumbnail filenames')),
- ('description', models.TextField(max_length=1000)),
- ('age_range', models.CharField(choices=[('3-5', '3-5'), ('5-7', '5-7'), ('7-11', '7-11'), ('11-14', '11-14'), ('14-16', '14-16'), ('16+', '16+'), ('Age not applicable', 'Age not applicable')], default='5-7', max_length=20)),
+ ('description', models.TextField(help_text='\n <strong>Markdown acceptable here!</strong>This is your opportunity to clearly explain what\n your resource is all about! It’s worth remembering that you are using the space to\n communicate to two different audiences. Firstly, think about what fellow teachers\n would like to know, such as exactly what the resource contains and how it could be used in\n the classroom. Secondly, the words you include on this page are also talking to internal and\n external search engines. External search engines, like Google, show the first 155 characters\n of the resource description, so make sure you take advantage\n of these characters by using lots of relevant keywords as part of an enticing pitch.\n', max_length=5000)),
+ ('card_description', models.TextField(blank=True, default='', help_text="If you enter text here, it will be used in the 'card' description box on the home page. Max 1000 characters.", max_length=1000)),
+ ('age_range', models.CharField(choices=[('Preschool (3-4yrs)', 'Preschool (3-4yrs)'), ('Nursery (2-5yrs)', 'Nursery (2-5yrs)'), ('Reception (4-5yrs)', 'Reception (4-5yrs)'), ('Year 1 (5-6yrs)', 'Year 1 (5-6yrs)'), ('Year 2 (6-7yrs)', 'Year 2 (6-7yrs)'), ('Early Years (0-5yrs)', 'Early Years (0-5yrs)'), ('Keystage 1 (5-7yrs)', 'Keystage 1 (5-7yrs)'), ('Keystage 2 (7-11yrs)', 'Keystage 2 (7-11yrs)'), ('Age not applicable', 'Age not applicable')], default='5-7', max_length=20)),
('curriculum', models.CharField(blank=True, choices=[('No curriculum', 'No curriculum'), ('English', 'English'), ('Scottish', 'Scottish')], default='English', max_length=20, null=True)),
+ ('feature_slot', models.IntegerField(blank=True, choices=[(1, 1), (2, 2), (3, 3)], default=0, null=True, unique=True)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
],
@@ -40,12 +46,26 @@ class Migration(migrations.Migration):
('name', models.CharField(max_length=255)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
+ ('colour_css_class', models.CharField(blank=True, max_length=56, null=True)),
+ ('badge_foreground_colour', models.CharField(blank=True, max_length=56, null=True)),
],
options={
'verbose_name_plural': 'Resource Categories',
},
),
migrations.CreateModel(
+ name='ResourceSubcategory',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=255)),
+ ('created_at', models.DateTimeField(auto_now_add=True)),
+ ('updated_at', models.DateTimeField(auto_now=True)),
+ ],
+ options={
+ 'verbose_name_plural': 'Resource Subcategories',
+ },
+ ),
+ migrations.CreateModel(
name='ResourceType',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
@@ -53,6 +73,9 @@ class Migration(migrations.Migration):
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
],
+ options={
+ 'verbose_name_plural': 'Resource Types',
+ },
),
migrations.CreateModel(
name='PDFPageSnapshot',
@@ -62,6 +85,9 @@ class Migration(migrations.Migration):
('file_name', models.CharField(max_length=255)),
('pdf_file', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='pdf_page_snapshots', to='resources.pdfresource')),
],
+ options={
+ 'verbose_name_plural': 'PDF Page Snapshots',
+ },
),
migrations.AddField(
model_name='pdfresource',
@@ -70,13 +96,13 @@ class Migration(migrations.Migration):
),
migrations.AddField(
model_name='resource',
- name='additional_resource_category',
- field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='additional_resource_category', to='resources.resourcecategory'),
+ name='main_resource_category',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='main_resource_category', to='resources.resourcecategory'),
),
migrations.AddField(
model_name='resource',
- name='main_resource_category',
- field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='main_resource_category', to='resources.resourcecategory'),
+ name='subcategories',
+ field=models.ManyToManyField(blank=True, related_name='additional_resource_category', to='resources.resourcesubcategory'),
),
migrations.AddField(
model_name='resource',
diff --git a/alphabetlearning/resources/migrations/0002_alter_resource_additional_resource_category_and_more.py b/alphabetlearning/resources/migrations/0002_alter_resource_additional_resource_category_and_more.py
deleted file mode 100644
index 3b70450..0000000
--- a/alphabetlearning/resources/migrations/0002_alter_resource_additional_resource_category_and_more.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# Generated by Django 5.0.4 on 2024-05-15 20:00
-
-import django.db.models.deletion
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('resources', '0001_initial'),
- ]
-
- operations = [
- migrations.AlterField(
- model_name='resource',
- name='additional_resource_category',
- field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='additional_resource_category', to='resources.resourcecategory'),
- ),
- migrations.AlterField(
- model_name='resource',
- name='curriculum',
- field=models.CharField(blank=True, choices=[('No curriculum', 'No curriculum'), ('English', 'English'), ('Scottish', 'Scottish')], default='English', max_length=20),
- ),
- ]
diff --git a/alphabetlearning/resources/migrations/0002_resource_price.py b/alphabetlearning/resources/migrations/0002_resource_price.py
new file mode 100644
index 0000000..899be2c
--- /dev/null
+++ b/alphabetlearning/resources/migrations/0002_resource_price.py
@@ -0,0 +1,18 @@
+# Generated by Django 5.1.4 on 2025-01-06 17:13
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('resources', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='resource',
+ name='price',
+ field=models.DecimalField(decimal_places=2, default=0.0, max_digits=6),
+ ),
+ ]
diff --git a/alphabetlearning/resources/migrations/0003_alter_resource_description.py b/alphabetlearning/resources/migrations/0003_alter_resource_description.py
deleted file mode 100644
index f0ed99c..0000000
--- a/alphabetlearning/resources/migrations/0003_alter_resource_description.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# Generated by Django 5.0.4 on 2024-05-16 11:33
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('resources', '0002_alter_resource_additional_resource_category_and_more'),
- ]
-
- operations = [
- migrations.AlterField(
- model_name='resource',
- name='description',
- field=models.TextField(help_text='\n <strong>Markdown acceptable here!</strong>This is your opportunity to clearly explain what\n your resource is all about! It’s worth remembering that you are using the space to\n communicate to two different audiences. Firstly, think about what fellow teachers\n would like to know, such as exactly what the resource contains and how it could be used in\n the classroom. Secondly, the words you include on this page are also talking to internal and\n external search engines. External search engines, like Google, show the first 155 characters\n of the resource description, so make sure you take advantage\n of these characters by using lots of relevant keywords as part of an enticing pitch.\n', max_length=5000),
- ),
- ]
diff --git a/alphabetlearning/resources/migrations/0003_remove_resource_price.py b/alphabetlearning/resources/migrations/0003_remove_resource_price.py
new file mode 100644
index 0000000..3bcd707
--- /dev/null
+++ b/alphabetlearning/resources/migrations/0003_remove_resource_price.py
@@ -0,0 +1,17 @@
+# Generated by Django 5.1.4 on 2025-01-06 19:40
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('resources', '0002_resource_price'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='resource',
+ name='price',
+ ),
+ ]
diff --git a/alphabetlearning/resources/migrations/0004_resource_feature_slot_1_resource_feature_slot_2_and_more.py b/alphabetlearning/resources/migrations/0004_resource_feature_slot_1_resource_feature_slot_2_and_more.py
deleted file mode 100644
index d595b62..0000000
--- a/alphabetlearning/resources/migrations/0004_resource_feature_slot_1_resource_feature_slot_2_and_more.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# Generated by Django 5.0.4 on 2024-05-22 19:24
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('resources', '0003_alter_resource_description'),
- ]
-
- operations = [
- migrations.AddField(
- model_name='resource',
- name='feature_slot_1',
- field=models.IntegerField(choices=[(1, 1), (2, 2), (3, 3)], null=True, unique=True),
- ),
- migrations.AddField(
- model_name='resource',
- name='feature_slot_2',
- field=models.IntegerField(choices=[(1, 1), (2, 2), (3, 3)], null=True, unique=True),
- ),
- migrations.AddField(
- model_name='resource',
- name='feature_slot_3',
- field=models.IntegerField(choices=[(1, 1), (2, 2), (3, 3)], null=True, unique=True),
- ),
- ]
diff --git a/alphabetlearning/resources/migrations/0005_rename_feature_slot_1_resource_feature_slot_and_more.py b/alphabetlearning/resources/migrations/0005_rename_feature_slot_1_resource_feature_slot_and_more.py
deleted file mode 100644
index 2937c50..0000000
--- a/alphabetlearning/resources/migrations/0005_rename_feature_slot_1_resource_feature_slot_and_more.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# Generated by Django 5.0.4 on 2024-05-22 19:26
-
-from django.db import migrations
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('resources', '0004_resource_feature_slot_1_resource_feature_slot_2_and_more'),
- ]
-
- operations = [
- migrations.RenameField(
- model_name='resource',
- old_name='feature_slot_1',
- new_name='feature_slot',
- ),
- migrations.RemoveField(
- model_name='resource',
- name='feature_slot_2',
- ),
- migrations.RemoveField(
- model_name='resource',
- name='feature_slot_3',
- ),
- ]
diff --git a/alphabetlearning/resources/migrations/0006_resource_card_description_and_more.py b/alphabetlearning/resources/migrations/0006_resource_card_description_and_more.py
deleted file mode 100644
index d343e76..0000000
--- a/alphabetlearning/resources/migrations/0006_resource_card_description_and_more.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# Generated by Django 5.0.4 on 2024-05-26 15:09
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('resources', '0005_rename_feature_slot_1_resource_feature_slot_and_more'),
- ]
-
- operations = [
- migrations.AddField(
- model_name='resource',
- name='card_description',
- field=models.TextField(blank=True, help_text="If you enter text here, it will be used in the 'card' description box on the home page. Max 1000 characters.", max_length=1000, null=True),
- ),
- migrations.AlterField(
- model_name='resource',
- name='feature_slot',
- field=models.IntegerField(blank=True, choices=[(1, 1), (2, 2), (3, 3)], null=True, unique=True),
- ),
- ]
diff --git a/alphabetlearning/resources/migrations/0007_alter_resource_feature_slot.py b/alphabetlearning/resources/migrations/0007_alter_resource_feature_slot.py
deleted file mode 100644
index c5c17c7..0000000
--- a/alphabetlearning/resources/migrations/0007_alter_resource_feature_slot.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# Generated by Django 5.0.4 on 2024-05-26 15:23
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('resources', '0006_resource_card_description_and_more'),
- ]
-
- operations = [
- migrations.AlterField(
- model_name='resource',
- name='feature_slot',
- field=models.IntegerField(blank=True, choices=[(0, 0), (1, 1), (2, 2), (3, 3)], default=0, null=True, unique=True),
- ),
- ]
diff --git a/alphabetlearning/resources/migrations/0008_alter_resource_card_description.py b/alphabetlearning/resources/migrations/0008_alter_resource_card_description.py
deleted file mode 100644
index 18e5739..0000000
--- a/alphabetlearning/resources/migrations/0008_alter_resource_card_description.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# Generated by Django 5.0.4 on 2024-05-26 15:42
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('resources', '0007_alter_resource_feature_slot'),
- ]
-
- operations = [
- migrations.AlterField(
- model_name='resource',
- name='card_description',
- field=models.TextField(blank=True, default='', help_text="If you enter text here, it will be used in the 'card' description box on the home page. Max 1000 characters.", max_length=1000),
- ),
- ]
diff --git a/alphabetlearning/resources/migrations/0009_alter_resource_feature_slot.py b/alphabetlearning/resources/migrations/0009_alter_resource_feature_slot.py
deleted file mode 100644
index ca082d4..0000000
--- a/alphabetlearning/resources/migrations/0009_alter_resource_feature_slot.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# Generated by Django 5.0.4 on 2024-05-26 18:17
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('resources', '0008_alter_resource_card_description'),
- ]
-
- operations = [
- migrations.AlterField(
- model_name='resource',
- name='feature_slot',
- field=models.IntegerField(blank=True, choices=[(1, 1), (2, 2), (3, 3)], default=0, null=True, unique=True),
- ),
- ]
diff --git a/alphabetlearning/resources/migrations/0010_alter_resource_age_range.py b/alphabetlearning/resources/migrations/0010_alter_resource_age_range.py
deleted file mode 100644
index 49c7a2c..0000000
--- a/alphabetlearning/resources/migrations/0010_alter_resource_age_range.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# Generated by Django 5.0.4 on 2024-07-11 14:47
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('resources', '0009_alter_resource_feature_slot'),
- ]
-
- operations = [
- migrations.AlterField(
- model_name='resource',
- name='age_range',
- field=models.CharField(choices=[('Preschool (3-4yrs)', 'Preschool (3-4yrs)'), ('Nursery (2-5yrs)', 'Nursery (2-5yrs)'), ('Reception (4-5yrs)', 'Reception (4-5yrs)'), ('Year 1 (5-6yrs)', 'Year 1 (5-6yrs)'), ('Year 2 (6-7yrs)', 'Year 2 (6-7yrs)'), ('Early Years (0-5yrs)', 'Early Years (0-5yrs)'), ('Keystage 1 (5-7yrs)', 'Keystage 1 (5-7yrs)'), ('Keystage 2 (7-11yrs)', 'Keystage 2 (7-11yrs)'), ('Age not applicable', 'Age not applicable')], default='5-7', max_length=20),
- ),
- ]
diff --git a/alphabetlearning/resources/migrations/0011_alter_resource_curriculum.py b/alphabetlearning/resources/migrations/0011_alter_resource_curriculum.py
deleted file mode 100644
index 5e1b193..0000000
--- a/alphabetlearning/resources/migrations/0011_alter_resource_curriculum.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# Generated by Django 5.0.4 on 2024-07-11 14:50
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('resources', '0010_alter_resource_age_range'),
- ]
-
- operations = [
- migrations.AlterField(
- model_name='resource',
- name='curriculum',
- field=models.CharField(blank=True, choices=[('No curriculum', 'No curriculum'), ('English', 'English'), ('Scottish', 'Scottish')], default='English', max_length=20, null=True),
- ),
- ]
diff --git a/alphabetlearning/resources/migrations/0012_resourcecategory_colour_css_class.py b/alphabetlearning/resources/migrations/0012_resourcecategory_colour_css_class.py
deleted file mode 100644
index b48ba61..0000000
--- a/alphabetlearning/resources/migrations/0012_resourcecategory_colour_css_class.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# Generated by Django 5.0.4 on 2024-07-11 15:47
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('resources', '0011_alter_resource_curriculum'),
- ]
-
- operations = [
- migrations.AddField(
- model_name='resourcecategory',
- name='colour_css_class',
- field=models.CharField(blank=True, max_length=56, null=True),
- ),
- ]
diff --git a/alphabetlearning/resources/migrations/0013_resourcecategory_badge_foreground_colour.py b/alphabetlearning/resources/migrations/0013_resourcecategory_badge_foreground_colour.py
deleted file mode 100644
index 7644a5c..0000000
--- a/alphabetlearning/resources/migrations/0013_resourcecategory_badge_foreground_colour.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# Generated by Django 5.0.4 on 2024-07-28 15:12
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ("resources", "0012_resourcecategory_colour_css_class"),
- ]
-
- operations = [
- migrations.AddField(
- model_name="resourcecategory",
- name="badge_foreground_colour",
- field=models.CharField(blank=True, max_length=56, null=True),
- ),
- ]
diff --git a/alphabetlearning/resources/migrations/0014_remove_resource_additional_resource_category_and_more.py b/alphabetlearning/resources/migrations/0014_remove_resource_additional_resource_category_and_more.py
deleted file mode 100644
index 7573bf2..0000000
--- a/alphabetlearning/resources/migrations/0014_remove_resource_additional_resource_category_and_more.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# Generated by Django 5.0.4 on 2024-07-29 14:52
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ("resources", "0013_resourcecategory_badge_foreground_colour"),
- ]
-
- operations = [
- migrations.RemoveField(
- model_name="resource",
- name="additional_resource_category",
- ),
- migrations.AddField(
- model_name="resource",
- name="additional_resource_category",
- field=models.ManyToManyField(
- blank=True,
- null=True,
- related_name="additional_resource_category",
- to="resources.resourcecategory",
- ),
- ),
- ]
diff --git a/alphabetlearning/resources/migrations/0015_resourcesubcategory.py b/alphabetlearning/resources/migrations/0015_resourcesubcategory.py
deleted file mode 100644
index 3eaada4..0000000
--- a/alphabetlearning/resources/migrations/0015_resourcesubcategory.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# Generated by Django 5.0.4 on 2024-07-29 14:55
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ("resources", "0014_remove_resource_additional_resource_category_and_more"),
- ]
-
- operations = [
- migrations.CreateModel(
- name="ResourceSubcategory",
- fields=[
- (
- "id",
- models.BigAutoField(
- auto_created=True,
- primary_key=True,
- serialize=False,
- verbose_name="ID",
- ),
- ),
- ("name", models.CharField(max_length=255)),
- ("created_at", models.DateTimeField(auto_now_add=True)),
- ("updated_at", models.DateTimeField(auto_now=True)),
- ],
- ),
- ]
diff --git a/alphabetlearning/resources/migrations/0016_alter_resourcesubcategory_options_and_more.py b/alphabetlearning/resources/migrations/0016_alter_resourcesubcategory_options_and_more.py
deleted file mode 100644
index 77a3f27..0000000
--- a/alphabetlearning/resources/migrations/0016_alter_resourcesubcategory_options_and_more.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# Generated by Django 5.0.4 on 2024-07-29 15:36
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ("resources", "0015_resourcesubcategory"),
- ]
-
- operations = [
- migrations.AlterModelOptions(
- name="resourcesubcategory",
- options={"verbose_name_plural": "Resource Subcategories"},
- ),
- migrations.AlterModelOptions(
- name="resourcetype",
- options={"verbose_name_plural": "Resource Types"},
- ),
- migrations.AlterField(
- model_name="resource",
- name="additional_resource_category",
- field=models.ManyToManyField(
- blank=True,
- null=True,
- related_name="additional_resource_category",
- to="resources.resourcesubcategory",
- ),
- ),
- ]
diff --git a/alphabetlearning/resources/migrations/0017_rename_additional_resource_category_resource_subcategories.py b/alphabetlearning/resources/migrations/0017_rename_additional_resource_category_resource_subcategories.py
deleted file mode 100644
index bc4d1e4..0000000
--- a/alphabetlearning/resources/migrations/0017_rename_additional_resource_category_resource_subcategories.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# Generated by Django 5.0.4 on 2024-08-01 14:29
-
-from django.db import migrations
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ("resources", "0016_alter_resourcesubcategory_options_and_more"),
- ]
-
- operations = [
- migrations.RenameField(
- model_name="resource",
- old_name="additional_resource_category",
- new_name="subcategories",
- ),
- ]
diff --git a/alphabetlearning/resources/migrations/0018_alter_resource_subcategories.py b/alphabetlearning/resources/migrations/0018_alter_resource_subcategories.py
deleted file mode 100644
index c981512..0000000
--- a/alphabetlearning/resources/migrations/0018_alter_resource_subcategories.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# Generated by Django 5.0.4 on 2024-08-01 15:08
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- (
- "resources",
- "0017_rename_additional_resource_category_resource_subcategories",
- ),
- ]
-
- operations = [
- migrations.AlterField(
- model_name="resource",
- name="subcategories",
- field=models.ManyToManyField(
- blank=True,
- related_name="additional_resource_category",
- to="resources.resourcesubcategory",
- ),
- ),
- ]
diff --git a/alphabetlearning/resources/migrations/0019_alter_pdfpagesnapshot_options_and_more.py b/alphabetlearning/resources/migrations/0019_alter_pdfpagesnapshot_options_and_more.py
deleted file mode 100644
index 511d747..0000000
--- a/alphabetlearning/resources/migrations/0019_alter_pdfpagesnapshot_options_and_more.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# Generated by Django 5.0.4 on 2024-09-03 19:21
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ("resources", "0018_alter_resource_subcategories"),
- ]
-
- operations = [
- migrations.AlterModelOptions(
- name="pdfpagesnapshot",
- options={"verbose_name_plural": "PDF Page Snapshots"},
- ),
- migrations.AlterModelOptions(
- name="pdfresource",
- options={"verbose_name_plural": "PDF Resources"},
- ),
- migrations.AddField(
- model_name="resource",
- name="price",
- field=models.DecimalField(decimal_places=2, default=0.0, max_digits=6),
- ),
- ]
diff --git a/alphabetlearning/resources/migrations/0020_remove_resource_price_resource_stripe_product_id.py b/alphabetlearning/resources/migrations/0020_remove_resource_price_resource_stripe_product_id.py
deleted file mode 100644
index 088556b..0000000
--- a/alphabetlearning/resources/migrations/0020_remove_resource_price_resource_stripe_product_id.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# Generated by Django 5.0.4 on 2024-10-19 15:11
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('resources', '0019_alter_pdfpagesnapshot_options_and_more'),
- ]
-
- operations = [
- migrations.RemoveField(
- model_name='resource',
- name='price',
- ),
- migrations.AddField(
- model_name='resource',
- name='stripe_product_id',
- field=models.CharField(default='baws', max_length=100),
- preserve_default=False,
- ),
- ]
diff --git a/alphabetlearning/resources/models.py b/alphabetlearning/resources/models.py
index 6881483..3f4ee8c 100644
--- a/alphabetlearning/resources/models.py
+++ b/alphabetlearning/resources/models.py
@@ -39,11 +39,11 @@ class Resource(models.Model):
name = models.CharField(max_length=255, null=False)
stripe_product_id = models.CharField(max_length=100)
# price = models.DecimalField(
- # max_digits=6,
- # decimal_places=2,
- # default=0.00,
- # null=False,
- # blank=False,
+ # max_digits=6,
+ # decimal_places=2,
+ # default=0.00,
+ # null=False,
+ # blank=False,
# )
thumbnail_filenames = models.JSONField(
null=False,
diff --git a/alphabetlearning/resources/tests/test_forms.py b/alphabetlearning/resources/tests/test_forms.py
index aebc110..465dc58 100644
--- a/alphabetlearning/resources/tests/test_forms.py
+++ b/alphabetlearning/resources/tests/test_forms.py
@@ -1,14 +1,12 @@
import pytest
+from alphabetlearning.resources.factories import ResourceModelFactory
+from alphabetlearning.resources.forms import ResourceCreateForm
+from alphabetlearning.resources.models import ResourceCategory, ResourceType
from django.core.files.uploadedfile import SimpleUploadedFile
from django.db import IntegrityError
from django.test import TestCase
from django.utils.datastructures import MultiValueDict
-from alphabetlearning.resources.factories import ResourceModelFactory
-from alphabetlearning.resources.forms import ResourceCreateForm
-from alphabetlearning.resources.models import ResourceCategory
-from alphabetlearning.resources.models import ResourceType
-
class ResourceCreateFormTest(TestCase):
def setUp(self):
@@ -55,7 +53,7 @@ class ResourceCreateFormTest(TestCase):
@pytest.mark.django_db()
def test_featured_slots_must_be_unique(self):
- r1 = ResourceModelFactory(feature_slot=1)
+ _ = ResourceModelFactory(feature_slot=1)
with pytest.raises(IntegrityError):
ResourceModelFactory(feature_slot=1)
diff --git a/alphabetlearning/resources/views.py b/alphabetlearning/resources/views.py
index 8b0f8c5..508c187 100644
--- a/alphabetlearning/resources/views.py
+++ b/alphabetlearning/resources/views.py
@@ -9,26 +9,16 @@ from django.conf import settings
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator
-from django.db import IntegrityError
-from django.db import transaction
-from django.shortcuts import get_object_or_404
-from django.shortcuts import redirect
-from django.shortcuts import render
+from django.db import IntegrityError, transaction
+from django.shortcuts import get_object_or_404, redirect, render
from . import services
-from .forms import ResourceCreateForm
-from .forms import ResourceUpdateMetadataForm
-from .forms import ResourceUpdatePDFsForm
-from .forms import ResourceUpdateThumbnailsForm
-from .models import PDFPageSnapshot
-from .models import PDFResource
-from .models import Resource
-from .models import ResourceCategory
-from .models import ResourceSubcategory
-from .s3 import get_presigned_obj_url
-from .s3 import upload_files_to_s3
-from .s3 import upload_snapshotted_pages_to_s3
-from .s3 import upload_to_s3
+from .forms import (ResourceCreateForm, ResourceUpdateMetadataForm,
+ ResourceUpdatePDFsForm, ResourceUpdateThumbnailsForm)
+from .models import (PDFPageSnapshot, PDFResource, Resource, ResourceCategory,
+ ResourceSubcategory)
+from .s3 import (get_presigned_obj_url, upload_files_to_s3,
+ upload_snapshotted_pages_to_s3, upload_to_s3)
logger = logging.getLogger(__name__)
diff --git a/alphabetlearning/static/images/funnel6.png b/alphabetlearning/static/images/funnel6.png
index 2609d38..6dc7cb9 100644
--- a/alphabetlearning/static/images/funnel6.png
+++ b/alphabetlearning/static/images/funnel6.png
Binary files differ
diff --git a/alphabetlearning/templates/base.html b/alphabetlearning/templates/base.html
index ecab232..2e28333 100644
--- a/alphabetlearning/templates/base.html
+++ b/alphabetlearning/templates/base.html
@@ -96,12 +96,12 @@
{% if request.user.is_authenticated %}
<li class="nav-item">
<a class="nav-link text-dark fw-bold"
- href="{% url "payments:cart_detail" %}">Your Basket</a>
+ href="{% url "payments:cart_detail" %}">Shopping Basket</a>
</li>
{% else %}
<li class="nav-item">
<p class="nav-link text-gray fw-bold">
- Your Basket
+ Shopping Basket
</p>
</li>
{% endif %}
diff --git a/alphabetlearning/users/migrations/0001_initial.py b/alphabetlearning/users/migrations/0001_initial.py
index 20b1233..e5caa0b 100644
--- a/alphabetlearning/users/migrations/0001_initial.py
+++ b/alphabetlearning/users/migrations/0001_initial.py
@@ -1,118 +1,41 @@
-import django.contrib.auth.models
-import django.contrib.auth.validators
-import django.utils.timezone
-from django.db import migrations
-from django.db import models
+# Generated by Django 5.1.4 on 2024-12-31 15:26
-import alphabetlearning.users.models
+import alphabetlearning.users.managers
+import django.utils.timezone
+from django.db import migrations, models
class Migration(migrations.Migration):
+
initial = True
dependencies = [
- ("auth", "0012_alter_user_first_name_max_length"),
+ ('auth', '0012_alter_user_first_name_max_length'),
]
operations = [
migrations.CreateModel(
- name="User",
+ name='User',
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",
- ),
- ),
- (
- "is_superuser",
- models.BooleanField(
- default=False,
- help_text="Designates that this user has all permissions without explicitly assigning them.",
- verbose_name="superuser status",
- ),
- ),
- (
- "email",
- models.EmailField(
- unique=True,
- max_length=254,
- verbose_name="email address",
- ),
- ),
- (
- "is_staff",
- models.BooleanField(
- default=False,
- help_text="Designates whether the user can log into this admin site.",
- verbose_name="staff status",
- ),
- ),
- (
- "is_active",
- models.BooleanField(
- default=True,
- help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.",
- verbose_name="active",
- ),
- ),
- (
- "date_joined",
- models.DateTimeField(
- default=django.utils.timezone.now,
- verbose_name="date joined",
- ),
- ),
- (
- "name",
- models.CharField(
- blank=True,
- max_length=255,
- verbose_name="Name of User",
- ),
- ),
- (
- "groups",
- models.ManyToManyField(
- blank=True,
- help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.",
- related_name="user_set",
- related_query_name="user",
- to="auth.Group",
- verbose_name="groups",
- ),
- ),
- (
- "user_permissions",
- models.ManyToManyField(
- blank=True,
- help_text="Specific permissions for this user.",
- related_name="user_set",
- related_query_name="user",
- to="auth.Permission",
- verbose_name="user permissions",
- ),
- ),
+ ('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')),
+ ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
+ ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
+ ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
+ ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
+ ('name', models.CharField(blank=True, max_length=255, verbose_name='Name of User')),
+ ('email', models.EmailField(max_length=254, unique=True, verbose_name='email address')),
+ ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
+ ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
],
options={
- "verbose_name": "user",
- "verbose_name_plural": "users",
- "abstract": False,
+ 'verbose_name': 'user',
+ 'verbose_name_plural': 'users',
+ 'abstract': False,
},
managers=[
- ("objects", alphabetlearning.users.models.UserManager()),
+ ('objects', alphabetlearning.users.managers.UserManager()),
],
),
]
diff --git a/alphabetlearning/users/tasks.py b/alphabetlearning/users/tasks.py
deleted file mode 100644
index ca51cd7..0000000
--- a/alphabetlearning/users/tasks.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from celery import shared_task
-
-from .models import User
-
-
-@shared_task()
-def get_users_count():
- """A pointless Celery task to demonstrate usage."""
- return User.objects.count()
diff --git a/alphabetlearning/users/tests/test_tasks.py b/alphabetlearning/users/tests/test_tasks.py
deleted file mode 100644
index 92f0e8a..0000000
--- a/alphabetlearning/users/tests/test_tasks.py
+++ /dev/null
@@ -1,17 +0,0 @@
-import pytest
-from celery.result import EagerResult
-
-from alphabetlearning.users.tasks import get_users_count
-from alphabetlearning.users.tests.factories import UserFactory
-
-pytestmark = pytest.mark.django_db
-
-
-def test_user_count(settings):
- """A basic test to execute the get_users_count Celery task."""
- batch_size = 3
- UserFactory.create_batch(batch_size)
- settings.CELERY_TASK_ALWAYS_EAGER = True
- task_result = get_users_count.delay()
- assert isinstance(task_result, EagerResult)
- assert task_result.result == batch_size