django-beta 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
beta/__init__.py ADDED
@@ -0,0 +1 @@
1
+ VERSION = (0, 1, 0)
beta/admin.py ADDED
@@ -0,0 +1,12 @@
1
+ from django.contrib import admin
2
+
3
+ from beta.models import BetaSignup
4
+
5
+
6
+ class BetaSignupAdmin(admin.ModelAdmin):
7
+ model = BetaSignup
8
+ list_filter = ("contacted", "registered")
9
+ search_fields = ("email", "first_name", "last_name")
10
+
11
+
12
+ admin.site.register(BetaSignup, BetaSignupAdmin)
beta/apps.py ADDED
@@ -0,0 +1,11 @@
1
+ from django.apps import AppConfig
2
+
3
+
4
+ class BetaConfig(AppConfig):
5
+ name = "beta"
6
+ verbose_name = "Beta"
7
+ default_auto_field = "django.db.models.AutoField"
8
+
9
+ def ready(self):
10
+ # Importing the module connects the post_save signal handler.
11
+ from beta import listeners # noqa: F401
beta/forms.py ADDED
@@ -0,0 +1,26 @@
1
+ from django import forms
2
+ from django.conf import settings
3
+
4
+ from beta.models import BetaSignup
5
+
6
+
7
+ class BetaSignupForm(forms.ModelForm):
8
+ def __init__(self, *args, **kwargs):
9
+ super().__init__(*args, **kwargs)
10
+ self.capture_first = getattr(settings, "BETA_CAPTURE_FIRST", False)
11
+ self.capture_both = getattr(settings, "BETA_CAPTURE_BOTH", False)
12
+
13
+ if self.capture_first:
14
+ self.fields.pop("last_name")
15
+ self.fields["first_name"].required = True
16
+
17
+ elif not self.capture_both:
18
+ self.fields.pop("first_name")
19
+ self.fields.pop("last_name")
20
+ else:
21
+ self.fields["first_name"].required = True
22
+ self.fields["last_name"].required = True
23
+
24
+ class Meta:
25
+ model = BetaSignup
26
+ exclude = ("contacted", "registered", "created")
beta/listeners.py ADDED
@@ -0,0 +1,17 @@
1
+ from django.contrib.auth.models import User
2
+ from django.db.models.signals import post_save
3
+
4
+ from beta.models import BetaSignup
5
+
6
+
7
+ def user_post_save_callback(sender, instance, created, **kwargs):
8
+ """Mark a user as registered if a real User object is created"""
9
+ if created:
10
+ matches = BetaSignup.objects.filter(email=instance.email)
11
+
12
+ if matches:
13
+ matches[0].registered = True
14
+ matches[0].save()
15
+
16
+
17
+ post_save.connect(user_post_save_callback, sender=User)
beta/managers.py ADDED
@@ -0,0 +1,15 @@
1
+ from django.db import models
2
+
3
+
4
+ class BetaManager(models.Manager):
5
+ def contacted(self):
6
+ return self.get_queryset().filter(contacted=True)
7
+
8
+ def not_contacted(self):
9
+ return self.get_queryset().filter(contacted=False)
10
+
11
+ def registered(self):
12
+ return self.get_queryset().filter(registered=True)
13
+
14
+ def not_registered(self):
15
+ return self.get_queryset().filter(registered=False)
@@ -0,0 +1,29 @@
1
+ # Generated by Django 5.2.16 on 2026-07-30 20:52
2
+
3
+ import django.utils.timezone
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+ initial = True
9
+
10
+ dependencies = []
11
+
12
+ operations = [
13
+ migrations.CreateModel(
14
+ name="BetaSignup",
15
+ fields=[
16
+ ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
17
+ ("first_name", models.CharField(blank=True, max_length=50, verbose_name="First Name")),
18
+ ("last_name", models.CharField(blank=True, max_length=75, verbose_name="Last Name")),
19
+ ("email", models.EmailField(max_length=254, unique=True, verbose_name="Email Address")),
20
+ ("contacted", models.BooleanField(default=False, verbose_name="Contacted")),
21
+ ("registered", models.BooleanField(default=False, verbose_name="Registered")),
22
+ ("created", models.DateTimeField(default=django.utils.timezone.now, verbose_name="Created")),
23
+ ],
24
+ options={
25
+ "verbose_name": "Beta Signup",
26
+ "verbose_name_plural": "Beta Signups",
27
+ },
28
+ ),
29
+ ]
File without changes
beta/models.py ADDED
@@ -0,0 +1,29 @@
1
+ from django.db import models
2
+ from django.utils import timezone
3
+ from django.utils.translation import gettext_lazy as _
4
+
5
+ from beta.managers import BetaManager
6
+
7
+
8
+ class BetaSignup(models.Model):
9
+ """
10
+ Model to store our pre-beta signups
11
+ """
12
+
13
+ first_name = models.CharField(_("First Name"), max_length=50, blank=True)
14
+ last_name = models.CharField(_("Last Name"), max_length=75, blank=True)
15
+ email = models.EmailField(_("Email Address"), unique=True)
16
+
17
+ contacted = models.BooleanField(_("Contacted"), default=False)
18
+ registered = models.BooleanField(_("Registered"), default=False)
19
+
20
+ created = models.DateTimeField(_("Created"), default=timezone.now)
21
+
22
+ objects = BetaManager()
23
+
24
+ class Meta:
25
+ verbose_name = _("Beta Signup")
26
+ verbose_name_plural = _("Beta Signups")
27
+
28
+ def __str__(self):
29
+ return f"Beta Signup - {self.email}"
@@ -0,0 +1,3 @@
1
+ {% block content %}
2
+ <h1>You have registered.</h1>
3
+ {% endblock %}
@@ -0,0 +1,5 @@
1
+ {% block content %}
2
+ <form method="POST" action=".">{% csrf_token %}
3
+ {{ form }}
4
+ </form>
5
+ {% endblock %}
beta/urls.py ADDED
@@ -0,0 +1,8 @@
1
+ from django.urls import path
2
+
3
+ from beta.views import Confirmation, Signup
4
+
5
+ urlpatterns = [
6
+ path("signup/", Signup.as_view(), name="beta_signup"),
7
+ path("signup/confirmed/", Confirmation.as_view(), name="beta_confirmation"),
8
+ ]
beta/views.py ADDED
@@ -0,0 +1,20 @@
1
+ from django.urls import reverse
2
+ from django.views import generic
3
+
4
+ from beta.forms import BetaSignupForm
5
+
6
+
7
+ class Signup(generic.CreateView):
8
+ """View to handle beta signup"""
9
+
10
+ template_name = "beta/signup.html"
11
+ form_class = BetaSignupForm
12
+
13
+ def get_success_url(self):
14
+ return reverse("beta_confirmation")
15
+
16
+
17
+ class Confirmation(generic.TemplateView):
18
+ """Confirmation Page"""
19
+
20
+ template_name = "beta/confirmation.html"
@@ -0,0 +1,102 @@
1
+ Metadata-Version: 2.4
2
+ Name: django-beta
3
+ Version: 0.2.0
4
+ Summary: django-beta is a reusable Django application for handling pre-beta signups.
5
+ Project-URL: Homepage, https://github.com/revsys/django-beta/
6
+ Author-email: Frank Wiles <frank@revsys.com>, Jeff Triplett <jeff@revsys.com>
7
+ License-File: AUTHORS.txt
8
+ License-File: LICENSE.txt
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Environment :: Web Environment
11
+ Classifier: Framework :: Django
12
+ Classifier: Framework :: Django :: 4.2
13
+ Classifier: Framework :: Django :: 5.0
14
+ Classifier: Framework :: Django :: 5.1
15
+ Classifier: Framework :: Django :: 5.2
16
+ Classifier: Framework :: Django :: 6.0
17
+ Classifier: Framework :: Django :: 6.1
18
+ Classifier: Intended Audience :: Developers
19
+ Classifier: License :: OSI Approved :: BSD License
20
+ Classifier: Operating System :: OS Independent
21
+ Classifier: Programming Language :: Python :: 3
22
+ Classifier: Programming Language :: Python :: 3.10
23
+ Classifier: Programming Language :: Python :: 3.11
24
+ Classifier: Programming Language :: Python :: 3.12
25
+ Classifier: Programming Language :: Python :: 3.13
26
+ Classifier: Programming Language :: Python :: 3.14
27
+ Classifier: Programming Language :: Python :: Free Threading :: 3 - Stable
28
+ Requires-Python: >=3.10
29
+ Provides-Extra: lint
30
+ Requires-Dist: prek; extra == 'lint'
31
+ Provides-Extra: test
32
+ Requires-Dist: pytest; extra == 'test'
33
+ Requires-Dist: pytest-cov; extra == 'test'
34
+ Requires-Dist: pytest-django; extra == 'test'
35
+ Provides-Extra: testing
36
+ Requires-Dist: pytest; extra == 'testing'
37
+ Requires-Dist: pytest-cov; extra == 'testing'
38
+ Requires-Dist: pytest-django; extra == 'testing'
39
+ Description-Content-Type: text/markdown
40
+
41
+ # django-beta
42
+
43
+ `django-beta` is a simple application to help you capture pre-beta interest
44
+ with your sites.
45
+
46
+ By default `django-beta` only captures a user's email address, however you
47
+ can alternately set one of these two configuration options:
48
+
49
+ - `BETA_CAPTURE_FIRST = True` will use a form and require the user to enter
50
+ their first name and email address.
51
+ - `BETA_CAPTURE_BOTH = True` will use a form and require the user to enter
52
+ their first name, last name, and email address.
53
+
54
+ ## Installation
55
+
56
+ Add `beta` to your `INSTALLED_APPS` and run migrations.
57
+
58
+ Add the following to your `urls.py`:
59
+
60
+ ```python
61
+ from django.urls import include, path
62
+
63
+ urlpatterns = [
64
+ path("beta/", include("beta.urls")),
65
+ ]
66
+ ```
67
+
68
+ Using the example templates provided in the code, create your customized beta
69
+ signup templates.
70
+
71
+ ## Managers
72
+
73
+ The `BetaSignup` model has the following manager methods to help out:
74
+
75
+ ```python
76
+ BetaSignup.objects.contacted()
77
+ BetaSignup.objects.not_contacted()
78
+ BetaSignup.objects.registered()
79
+ BetaSignup.objects.not_registered()
80
+ ```
81
+
82
+ ## Side Effects
83
+
84
+ `django-beta` listens for a signal on User creation and marks the
85
+ corresponding `BetaSignup` entry as `registered`.
86
+
87
+ ## Development
88
+
89
+ This project uses [nox](https://nox.thea.codes/) and
90
+ [just](https://github.com/casey/just) for testing and linting across a matrix
91
+ of Python and Django versions.
92
+
93
+ ```shell
94
+ just lint # run pre-commit / ruff via prek
95
+ just test # run the full nox test matrix
96
+ just test-latest # run against the latest Python and Django
97
+ ```
98
+
99
+ ## TODO
100
+
101
+ - Admin views to show beta registrations over time
102
+ - Management commands to simplify emailing the interested users
@@ -0,0 +1,18 @@
1
+ beta/__init__.py,sha256=mlI_y0X-IT2W5YNCpifdqxRIOLiENCSyne4ULTKm044,20
2
+ beta/admin.py,sha256=UACQoG2px9hr4GOBTZtIAAFKwod5FjjAGMMYQJYivwU,289
3
+ beta/apps.py,sha256=5ZZgvc32EVGin566btu3xv77BuT8bUOhezfXCjNNTN8,304
4
+ beta/forms.py,sha256=KhOZadiaOkTGQARV4OcHWv_K3PzNUvYGC7oVdxt5z9c,837
5
+ beta/listeners.py,sha256=y6mpyi0BBSWtxD3nInIgmcaO6_VmTef9sN1_hmEajpI,496
6
+ beta/managers.py,sha256=U61jWX8b90dZfVczw18T73EmwqsiruBUqli0dgzJhs0,415
7
+ beta/models.py,sha256=20YOFnAdughi-CL1elZnV0ZM-cUH5qQsyBKh2jcnw8g,877
8
+ beta/urls.py,sha256=l4LgdGsXN0Kfb87iYB6UnSmFS7Cmghl6U3_hz_Xm5wI,233
9
+ beta/views.py,sha256=3wDd1Z48mQAo6A0I1Bs-FLS2tqNGwy6qkqkLOPQ1Iqc,443
10
+ beta/migrations/0001_initial.py,sha256=HrN-wVMsTY7WRhvbfspDeFa-w_HUmwKtvA0Tf1zYfEQ,1202
11
+ beta/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ beta/templates/beta/confirmation.html,sha256=SSjcZeIdZSspnu4PRD1yuR6VZRvkdR89AVeqdwoqGPA,65
13
+ beta/templates/beta/signup.html,sha256=7N1BI2MNR9NHbIBqEs4XT0GfmxJ3dKuswEkz2gVuAnU,106
14
+ django_beta-0.2.0.dist-info/METADATA,sha256=3m7vBoURLHfL9UfOW-WbhPkYc34sLUu8iK4jEPpiHLM,3292
15
+ django_beta-0.2.0.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
16
+ django_beta-0.2.0.dist-info/licenses/AUTHORS.txt,sha256=-r87Jb1s2eRnqrW2gwWky-l0MC1fD594VdJmnKfJtiI,69
17
+ django_beta-0.2.0.dist-info/licenses/LICENSE.txt,sha256=b8ociThOjvtXY17Pt31eVPz7zGdtT3Pv1FWnunVY3Hk,1554
18
+ django_beta-0.2.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.31.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1 @@
1
+ django-beta was originally created by Frank Wiles <frank@revsys.com>
@@ -0,0 +1,27 @@
1
+ Copyright (c) Revolution Systems, LLC and individual contributors.
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification,
5
+ are permitted provided that the following conditions are met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright notice,
8
+ this list of conditions and the following disclaimer.
9
+
10
+ 2. Redistributions in binary form must reproduce the above copyright
11
+ notice, this list of conditions and the following disclaimer in the
12
+ documentation and/or other materials provided with the distribution.
13
+
14
+ 3. Neither the name of django-beta nor the names of its contributors
15
+ may be used to endorse or promote products derived from this software
16
+ without specific prior written permission.
17
+
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
22
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.