Use poetry for managing dependencies #9

Merged
benjaoming merged 3 commits from use_poetry into master 2019-09-02 11:58:18 +00:00
18 changed files with 590 additions and 300 deletions
Showing only changes of commit c4596c25c6 - Show all commits

View file

@ -7,22 +7,25 @@ from . import models
@admin.register(models.Order) @admin.register(models.Order)
class OrderAdmin(admin.ModelAdmin): class OrderAdmin(admin.ModelAdmin):
list_display = ('who', 'description', 'created', 'is_paid',) list_display = ("who", "description", "created", "is_paid")
def who(self, instance): def who(self, instance):
return instance.user.get_full_name() return instance.user.get_full_name()
who.short_description = _("Customer") who.short_description = _("Customer")
@admin.register(models.Payment) @admin.register(models.Payment)
class PaymentAdmin(admin.ModelAdmin): class PaymentAdmin(admin.ModelAdmin):
list_display = ('who', 'description', 'order_id', 'created',) list_display = ("who", "description", "order_id", "created")
def who(self, instance): def who(self, instance):
return instance.order.user.get_full_name() return instance.order.user.get_full_name()
who.short_description = _("Customer") who.short_description = _("Customer")
def order_id(self, instance): def order_id(self, instance):
return instance.order.id return instance.order.id
order_id.short_description = _("Order ID") order_id.short_description = _("Order ID")

View file

@ -2,4 +2,4 @@ from django.apps import AppConfig
class AccountingConfig(AppConfig): class AccountingConfig(AppConfig):
name = 'accounting' name = "accounting"

View file

@ -12,73 +12,222 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [migrations.swappable_dependency(settings.AUTH_USER_MODEL)]
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='Account', name="Account",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('modified', models.DateTimeField(auto_now=True, verbose_name='modified')), "id",
('created', models.DateTimeField(auto_now_add=True, verbose_name='created')), models.AutoField(
('owner', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)), auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"modified",
models.DateTimeField(auto_now=True, verbose_name="modified"),
),
(
"created",
models.DateTimeField(auto_now_add=True, verbose_name="created"),
),
(
"owner",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
to=settings.AUTH_USER_MODEL,
),
),
], ],
options={ options={"abstract": False},
'abstract': False,
},
), ),
migrations.CreateModel( migrations.CreateModel(
name='Order', name="Order",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('modified', models.DateTimeField(auto_now=True, verbose_name='modified')), "id",
('created', models.DateTimeField(auto_now_add=True, verbose_name='created')), models.AutoField(
('description', models.CharField(max_length=1024, verbose_name='description')), auto_created=True,
('price_currency', djmoney.models.fields.CurrencyField(choices=[('DKK', 'DKK')], default='XYZ', editable=False, max_length=3)), primary_key=True,
('price', djmoney.models.fields.MoneyField(decimal_places=2, default=Decimal('0.0'), max_digits=16, verbose_name='price (excl. VAT)')), serialize=False,
('vat_currency', djmoney.models.fields.CurrencyField(choices=[('DKK', 'DKK')], default='XYZ', editable=False, max_length=3)), verbose_name="ID",
('vat', djmoney.models.fields.MoneyField(decimal_places=2, default=Decimal('0.0'), max_digits=16, verbose_name='VAT')), ),
('is_paid', models.BooleanField(default=False, verbose_name='is paid')), ),
('account', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='accounting.Account')), (
('user', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)), "modified",
models.DateTimeField(auto_now=True, verbose_name="modified"),
),
(
"created",
models.DateTimeField(auto_now_add=True, verbose_name="created"),
),
(
"description",
models.CharField(max_length=1024, verbose_name="description"),
),
(
"price_currency",
djmoney.models.fields.CurrencyField(
choices=[("DKK", "DKK")],
default="XYZ",
editable=False,
max_length=3,
),
),
(
"price",
djmoney.models.fields.MoneyField(
decimal_places=2,
default=Decimal("0.0"),
max_digits=16,
verbose_name="price (excl. VAT)",
),
),
(
"vat_currency",
djmoney.models.fields.CurrencyField(
choices=[("DKK", "DKK")],
default="XYZ",
editable=False,
max_length=3,
),
),
(
"vat",
djmoney.models.fields.MoneyField(
decimal_places=2,
default=Decimal("0.0"),
max_digits=16,
verbose_name="VAT",
),
),
("is_paid", models.BooleanField(default=False, verbose_name="is paid")),
(
"account",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
to="accounting.Account",
),
),
(
"user",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
to=settings.AUTH_USER_MODEL,
),
),
], ],
options={ options={"verbose_name": "Order", "verbose_name_plural": "Orders"},
'verbose_name': 'Order',
'verbose_name_plural': 'Orders',
},
), ),
migrations.CreateModel( migrations.CreateModel(
name='Payment', name="Payment",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('modified', models.DateTimeField(auto_now=True, verbose_name='modified')), "id",
('created', models.DateTimeField(auto_now_add=True, verbose_name='created')), models.AutoField(
('amount_currency', djmoney.models.fields.CurrencyField(choices=[('DKK', 'DKK')], default='XYZ', editable=False, max_length=3)), auto_created=True,
('amount', djmoney.models.fields.MoneyField(decimal_places=2, default=Decimal('0.0'), max_digits=16)), primary_key=True,
('description', models.CharField(max_length=1024, verbose_name='description')), serialize=False,
('stripe_charge_id', models.CharField(blank=True, max_length=255, null=True)), verbose_name="ID",
('order', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='accounting.Order')), ),
),
(
"modified",
models.DateTimeField(auto_now=True, verbose_name="modified"),
),
(
"created",
models.DateTimeField(auto_now_add=True, verbose_name="created"),
),
(
"amount_currency",
djmoney.models.fields.CurrencyField(
choices=[("DKK", "DKK")],
default="XYZ",
editable=False,
max_length=3,
),
),
(
"amount",
djmoney.models.fields.MoneyField(
decimal_places=2, default=Decimal("0.0"), max_digits=16
),
),
(
"description",
models.CharField(max_length=1024, verbose_name="description"),
),
(
"stripe_charge_id",
models.CharField(blank=True, max_length=255, null=True),
),
(
"order",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
to="accounting.Order",
),
),
], ],
options={ options={"verbose_name": "payment", "verbose_name_plural": "payments"},
'verbose_name': 'payment',
'verbose_name_plural': 'payments',
},
), ),
migrations.CreateModel( migrations.CreateModel(
name='Transaction', name="Transaction",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('modified', models.DateTimeField(auto_now=True, verbose_name='modified')), "id",
('created', models.DateTimeField(auto_now_add=True, verbose_name='created')), models.AutoField(
('amount_currency', djmoney.models.fields.CurrencyField(choices=[('DKK', 'DKK')], default='XYZ', editable=False, max_length=3)), auto_created=True,
('amount', djmoney.models.fields.MoneyField(decimal_places=2, default=Decimal('0.0'), help_text='This will include VAT', max_digits=16, verbose_name='amount')), primary_key=True,
('description', models.CharField(max_length=1024, verbose_name='description')), serialize=False,
('account', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='transactions', to='accounting.Account')), verbose_name="ID",
),
),
(
"modified",
models.DateTimeField(auto_now=True, verbose_name="modified"),
),
(
"created",
models.DateTimeField(auto_now_add=True, verbose_name="created"),
),
(
"amount_currency",
djmoney.models.fields.CurrencyField(
choices=[("DKK", "DKK")],
default="XYZ",
editable=False,
max_length=3,
),
),
(
"amount",
djmoney.models.fields.MoneyField(
decimal_places=2,
default=Decimal("0.0"),
help_text="This will include VAT",
max_digits=16,
verbose_name="amount",
),
),
(
"description",
models.CharField(max_length=1024, verbose_name="description"),
),
(
"account",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
related_name="transactions",
to="accounting.Account",
),
),
], ],
options={ options={"abstract": False},
'abstract': False,
},
), ),
] ]

View file

@ -11,14 +11,8 @@ from djmoney.models.fields import MoneyField
class CreatedModifiedAbstract(models.Model): class CreatedModifiedAbstract(models.Model):
modified = models.DateTimeField( modified = models.DateTimeField(auto_now=True, verbose_name=_("modified"))
auto_now=True, created = models.DateTimeField(auto_now_add=True, verbose_name=_("created"))
verbose_name=_("modified"),
)
created = models.DateTimeField(
auto_now_add=True,
verbose_name=_("created"),
)
class Meta: class Meta:
abstract = True abstract = True
@ -34,7 +28,7 @@ class Account(CreatedModifiedAbstract):
@property @property
def balance(self): def balance(self):
return self.transactions.all().aggregate(Sum('amount')).get('amount', 0) return self.transactions.all().aggregate(Sum("amount")).get("amount", 0)
class Transaction(CreatedModifiedAbstract): class Transaction(CreatedModifiedAbstract):
@ -44,20 +38,15 @@ class Transaction(CreatedModifiedAbstract):
""" """
account = models.ForeignKey( account = models.ForeignKey(
Account, Account, on_delete=models.PROTECT, related_name="transactions"
on_delete=models.PROTECT,
related_name="transactions",
) )
amount = MoneyField( amount = MoneyField(
verbose_name=_("amount"), verbose_name=_("amount"),
max_digits=16, max_digits=16,
decimal_places=2, decimal_places=2,
help_text=_("This will include VAT") help_text=_("This will include VAT"),
)
description = models.CharField(
max_length=1024,
verbose_name=_("description")
) )
description = models.CharField(max_length=1024, verbose_name=_("description"))
class Order(CreatedModifiedAbstract): class Order(CreatedModifiedAbstract):
@ -71,26 +60,14 @@ class Order(CreatedModifiedAbstract):
account = models.ForeignKey(Account, on_delete=models.PROTECT) account = models.ForeignKey(Account, on_delete=models.PROTECT)
is_paid = models.BooleanField(default=False) is_paid = models.BooleanField(default=False)
description = models.CharField( description = models.CharField(max_length=1024, verbose_name=_("description"))
max_length=1024,
verbose_name=_("description")
)
price = MoneyField( price = MoneyField(
verbose_name=_("price (excl. VAT)"), verbose_name=_("price (excl. VAT)"), max_digits=16, decimal_places=2
max_digits=16,
decimal_places=2,
)
vat = MoneyField(
verbose_name=_("VAT"),
max_digits=16,
decimal_places=2,
) )
vat = MoneyField(verbose_name=_("VAT"), max_digits=16, decimal_places=2)
is_paid = models.BooleanField( is_paid = models.BooleanField(default=False, verbose_name=_("is paid"))
default=False,
verbose_name=_("is paid"),
)
@property @property
def total(self): def total(self):
@ -105,7 +82,7 @@ class Order(CreatedModifiedAbstract):
pk = str(self.pk).encode("utf-8") pk = str(self.pk).encode("utf-8")
x = md5() x = md5()
x.update(pk) x.update(pk)
extra_hash = (settings.SECRET_KEY + 'blah').encode('utf-8') extra_hash = (settings.SECRET_KEY + "blah").encode("utf-8")
x.update(extra_hash) x.update(extra_hash)
return x.hexdigest() return x.hexdigest()
@ -119,22 +96,12 @@ class Order(CreatedModifiedAbstract):
class Payment(CreatedModifiedAbstract): class Payment(CreatedModifiedAbstract):
amount = MoneyField( amount = MoneyField(max_digits=16, decimal_places=2)
max_digits=16,
decimal_places=2,
)
order = models.ForeignKey(Order, on_delete=models.PROTECT) order = models.ForeignKey(Order, on_delete=models.PROTECT)
description = models.CharField( description = models.CharField(max_length=1024, verbose_name=_("description"))
max_length=1024,
verbose_name=_("description")
)
stripe_charge_id = models.CharField( stripe_charge_id = models.CharField(max_length=255, null=True, blank=True)
max_length=255,
null=True,
blank=True,
)
@property @property
def display_id(self): def display_id(self):

View file

@ -7,10 +7,9 @@ from . import models
# def test(): # def test():
# do stuff # do stuff
@pytest.mark.django_db @pytest.mark.django_db
def test_balance(): def test_balance():
user = User.objects.create_user("test", "lala@adas.com", "1234") user = User.objects.create_user("test", "lala@adas.com", "1234")
account = models.Account.objects.create( account = models.Account.objects.create(owner=user)
owner=user
)
assert account.balance == 0 assert account.balance == 0

View file

@ -6,7 +6,7 @@ if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings") os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings")
try: try:
from django.core.management import execute_from_command_line from django.core.management import execute_from_command_line
except ImportError as exc: except ImportError:
raise ImportError( raise ImportError(
"Couldn't import Django. Are you sure it's installed and " "Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you " "available on your PYTHONPATH environment variable? Did you "

View file

@ -2,4 +2,4 @@ from django.apps import AppConfig
class MembershipConfig(AppConfig): class MembershipConfig(AppConfig):
name = 'membership' name = "membership"

View file

@ -12,90 +12,216 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [migrations.swappable_dependency(settings.AUTH_USER_MODEL)]
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='Membership', name="Membership",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('modified', models.DateTimeField(auto_now=True, verbose_name='modified')), "id",
('created', models.DateTimeField(auto_now_add=True, verbose_name='created')), models.AutoField(
('can_vote', models.BooleanField(default=False, help_text='Indicates that the user has a democratic membership of the organization.', verbose_name='can vote')), auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"modified",
models.DateTimeField(auto_now=True, verbose_name="modified"),
),
(
"created",
models.DateTimeField(auto_now_add=True, verbose_name="created"),
),
(
"can_vote",
models.BooleanField(
default=False,
help_text="Indicates that the user has a democratic membership of the organization.",
verbose_name="can vote",
),
),
], ],
options={ options={
'verbose_name': 'membership', "verbose_name": "membership",
'verbose_name_plural': 'memberships', "verbose_name_plural": "memberships",
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
name='Organization', name="Organization",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('modified', models.DateTimeField(auto_now=True, verbose_name='modified')), "id",
('created', models.DateTimeField(auto_now_add=True, verbose_name='created')), models.AutoField(
('name', models.CharField(max_length=64, verbose_name='name')), auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"modified",
models.DateTimeField(auto_now=True, verbose_name="modified"),
),
(
"created",
models.DateTimeField(auto_now_add=True, verbose_name="created"),
),
("name", models.CharField(max_length=64, verbose_name="name")),
], ],
options={ options={
'verbose_name': 'organization', "verbose_name": "organization",
'verbose_name_plural': 'organizations', "verbose_name_plural": "organizations",
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
name='Subscription', name="Subscription",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('modified', models.DateTimeField(auto_now=True, verbose_name='modified')), "id",
('created', models.DateTimeField(auto_now_add=True, verbose_name='created')), models.AutoField(
('active', models.BooleanField(default=False, help_text='Automatically set by payment system.', verbose_name='active')), auto_created=True,
('starts', models.DateField()), primary_key=True,
('ends', models.DateField()), serialize=False,
('renewed_subscription', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='membership.Subscription', verbose_name='renewed subscription')), verbose_name="ID",
),
),
(
"modified",
models.DateTimeField(auto_now=True, verbose_name="modified"),
),
(
"created",
models.DateTimeField(auto_now_add=True, verbose_name="created"),
),
(
"active",
models.BooleanField(
default=False,
help_text="Automatically set by payment system.",
verbose_name="active",
),
),
("starts", models.DateField()),
("ends", models.DateField()),
(
"renewed_subscription",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.PROTECT,
to="membership.Subscription",
verbose_name="renewed subscription",
),
),
], ],
options={ options={
'verbose_name': 'subscription', "verbose_name": "subscription",
'verbose_name_plural': 'subscriptions', "verbose_name_plural": "subscriptions",
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
name='SubscriptionType', name="SubscriptionType",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('modified', models.DateTimeField(auto_now=True, verbose_name='modified')), "id",
('created', models.DateTimeField(auto_now_add=True, verbose_name='created')), models.AutoField(
('name', models.CharField(max_length=64, verbose_name='name')), auto_created=True,
('fee_currency', djmoney.models.fields.CurrencyField(choices=[('DKK', 'DKK')], default='XYZ', editable=False, max_length=3)), primary_key=True,
('fee', djmoney.models.fields.MoneyField(decimal_places=2, default=Decimal('0.0'), max_digits=16)), serialize=False,
('fee_vat_currency', djmoney.models.fields.CurrencyField(choices=[('DKK', 'DKK')], default='XYZ', editable=False, max_length=3)), verbose_name="ID",
('fee_vat', djmoney.models.fields.MoneyField(decimal_places=2, default=Decimal('0'), max_digits=16)), ),
('duration', models.PositiveSmallIntegerField(choices=[(1, 'annual')], default=1, verbose_name='duration')), ),
('organization', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='membership.Organization')), (
"modified",
models.DateTimeField(auto_now=True, verbose_name="modified"),
),
(
"created",
models.DateTimeField(auto_now_add=True, verbose_name="created"),
),
("name", models.CharField(max_length=64, verbose_name="name")),
(
"fee_currency",
djmoney.models.fields.CurrencyField(
choices=[("DKK", "DKK")],
default="XYZ",
editable=False,
max_length=3,
),
),
(
"fee",
djmoney.models.fields.MoneyField(
decimal_places=2, default=Decimal("0.0"), max_digits=16
),
),
(
"fee_vat_currency",
djmoney.models.fields.CurrencyField(
choices=[("DKK", "DKK")],
default="XYZ",
editable=False,
max_length=3,
),
),
(
"fee_vat",
djmoney.models.fields.MoneyField(
decimal_places=2, default=Decimal("0"), max_digits=16
),
),
(
"duration",
models.PositiveSmallIntegerField(
choices=[(1, "annual")], default=1, verbose_name="duration"
),
),
(
"organization",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
to="membership.Organization",
),
),
], ],
options={ options={
'verbose_name': 'subscription type', "verbose_name": "subscription type",
'verbose_name_plural': 'subscription types', "verbose_name_plural": "subscription types",
}, },
), ),
migrations.AddField( migrations.AddField(
model_name='subscription', model_name="subscription",
name='subscription_type', name="subscription_type",
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='memberships', to='membership.SubscriptionType', verbose_name='subscription type'), field=models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
related_name="memberships",
to="membership.SubscriptionType",
verbose_name="subscription type",
),
), ),
migrations.AddField( migrations.AddField(
model_name='subscription', model_name="subscription",
name='user', name="user",
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL), field=models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL
),
), ),
migrations.AddField( migrations.AddField(
model_name='membership', model_name="membership",
name='organization', name="organization",
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='membership.Organization'), field=models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
to="membership.Organization",
),
), ),
migrations.AddField( migrations.AddField(
model_name='membership', model_name="membership",
name='user', name="user",
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL), field=models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL
),
), ),
] ]

View file

@ -6,14 +6,8 @@ from djmoney.models.fields import MoneyField
class CreatedModifiedAbstract(models.Model): class CreatedModifiedAbstract(models.Model):
modified = models.DateTimeField( modified = models.DateTimeField(auto_now=True, verbose_name=_("modified"))
auto_now=True, created = models.DateTimeField(auto_now_add=True, verbose_name=_("created"))
verbose_name=_("modified"),
)
created = models.DateTimeField(
auto_now_add=True,
verbose_name=_("created"),
)
class Meta: class Meta:
abstract = True abstract = True
@ -24,10 +18,8 @@ class Organization(CreatedModifiedAbstract):
This holds the data of the organization that someone is a member of. It is This holds the data of the organization that someone is a member of. It is
possible that we'll create more advanced features here. possible that we'll create more advanced features here.
""" """
name = models.CharField(
verbose_name=_("name"), name = models.CharField(verbose_name=_("name"), max_length=64)
max_length=64,
)
def __str__(self): def __str__(self):
return self.name return self.name
@ -56,14 +48,13 @@ class Membership(CreatedModifiedAbstract):
help_text=_( help_text=_(
"Indicates that the user has a democratic membership of the " "Indicates that the user has a democratic membership of the "
"organization." "organization."
) ),
) )
def __str__(self): def __str__(self):
return _("{} is a member of {}").format( return _("{} is a member of {}").format(
self.user.get_full_name(), self.user.get_full_name(), self.organization.name
self.organization.name,
) )
class Meta: class Meta:
@ -79,26 +70,14 @@ class SubscriptionType(CreatedModifiedAbstract):
organization = models.ForeignKey(Organization, on_delete=models.PROTECT) organization = models.ForeignKey(Organization, on_delete=models.PROTECT)
name = models.CharField( name = models.CharField(verbose_name=_("name"), max_length=64)
verbose_name=_("name"),
max_length=64,
)
fee = MoneyField( fee = MoneyField(max_digits=16, decimal_places=2)
max_digits=16,
decimal_places=2,
)
fee_vat = MoneyField( fee_vat = MoneyField(max_digits=16, decimal_places=2, default=0)
max_digits=16,
decimal_places=2,
default=0,
)
duration = models.PositiveSmallIntegerField( duration = models.PositiveSmallIntegerField(
default=1, default=1, choices=[(1, _("annual"))], verbose_name=_("duration")
choices=[(1, _("annual"))],
verbose_name=_("duration"),
) )
class Meta: class Meta:
@ -116,7 +95,7 @@ class Subscription(CreatedModifiedAbstract):
subscription_type = models.ForeignKey( subscription_type = models.ForeignKey(
SubscriptionType, SubscriptionType,
related_name='memberships', related_name="memberships",
verbose_name=_("subscription type"), verbose_name=_("subscription type"),
on_delete=models.PROTECT, on_delete=models.PROTECT,
) )
@ -125,14 +104,14 @@ class Subscription(CreatedModifiedAbstract):
active = models.BooleanField( active = models.BooleanField(
default=False, default=False,
verbose_name=_("active"), verbose_name=_("active"),
help_text=_("Automatically set by payment system.") help_text=_("Automatically set by payment system."),
) )
starts = models.DateField() starts = models.DateField()
ends = models.DateField() ends = models.DateField()
renewed_subscription = models.ForeignKey( renewed_subscription = models.ForeignKey(
'self', "self",
null=True, null=True,
blank=True, blank=True,
verbose_name=_("renewed subscription"), verbose_name=_("renewed subscription"),

View file

@ -4,6 +4,4 @@ from django.contrib.sites.shortcuts import get_current_site
def current_site(request): def current_site(request):
"""Include the current site in the context.""" """Include the current site in the context."""
return { return {"site": get_current_site(request)}
'site': get_current_site(request)
}

View file

@ -26,63 +26,62 @@ ALLOWED_HOSTS = []
# Application definition # Application definition
INSTALLED_APPS = [ INSTALLED_APPS = [
'django.contrib.admin', "django.contrib.admin",
'django.contrib.auth', "django.contrib.auth",
'django.contrib.contenttypes', "django.contrib.contenttypes",
'django.contrib.sessions', "django.contrib.sessions",
'django.contrib.messages', "django.contrib.messages",
'django.contrib.staticfiles', "django.contrib.staticfiles",
'django.contrib.sites', "django.contrib.sites",
"users",
'users', "accounting",
'accounting', "membership",
'membership',
] ]
MIDDLEWARE = [ MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware', "django.middleware.security.SecurityMiddleware",
'django.contrib.sessions.middleware.SessionMiddleware', "django.contrib.sessions.middleware.SessionMiddleware",
'django.middleware.common.CommonMiddleware', "django.middleware.common.CommonMiddleware",
'django.middleware.csrf.CsrfViewMiddleware', "django.middleware.csrf.CsrfViewMiddleware",
'django.contrib.auth.middleware.AuthenticationMiddleware', "django.contrib.auth.middleware.AuthenticationMiddleware",
'django.contrib.messages.middleware.MessageMiddleware', "django.contrib.messages.middleware.MessageMiddleware",
'django.middleware.clickjacking.XFrameOptionsMiddleware', "django.middleware.clickjacking.XFrameOptionsMiddleware",
] ]
ROOT_URLCONF = 'project.urls' ROOT_URLCONF = "project.urls"
TEMPLATES = [ TEMPLATES = [
{ {
'BACKEND': 'django.template.backends.django.DjangoTemplates', "BACKEND": "django.template.backends.django.DjangoTemplates",
'DIRS': [os.path.join("project", "templates")], "DIRS": [os.path.join("project", "templates")],
'APP_DIRS': True, "APP_DIRS": True,
'OPTIONS': { "OPTIONS": {
'context_processors': [ "context_processors": [
'django.template.context_processors.debug', "django.template.context_processors.debug",
'django.template.context_processors.request', "django.template.context_processors.request",
'django.contrib.auth.context_processors.auth', "django.contrib.auth.context_processors.auth",
'django.contrib.messages.context_processors.messages', "django.contrib.messages.context_processors.messages",
'project.context_processors.current_site', "project.context_processors.current_site",
], ]
}, },
}, }
] ]
AUTHENTICATION_BACKENDS = ( AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend', "django.contrib.auth.backends.ModelBackend",
'allauth.account.auth_backends.AuthenticationBackend', "allauth.account.auth_backends.AuthenticationBackend",
) )
WSGI_APPLICATION = 'project.wsgi.application' WSGI_APPLICATION = "project.wsgi.application"
# Database # Database
# https://docs.djangoproject.com/en/2.0/ref/settings/#databases # https://docs.djangoproject.com/en/2.0/ref/settings/#databases
DATABASES = { DATABASES = {
'default': { "default": {
'ENGINE': 'django.db.backends.sqlite3', "ENGINE": "django.db.backends.sqlite3",
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), "NAME": os.path.join(BASE_DIR, "db.sqlite3"),
} }
} }
@ -92,28 +91,24 @@ DATABASES = {
AUTH_PASSWORD_VALIDATORS = [ AUTH_PASSWORD_VALIDATORS = [
{ {
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', # noqa "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator" # noqa
}, },
{"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator"}, # noqa
{"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"}, # noqa
{ {
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', # noqa "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator" # noqa
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', # noqa
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', # noqa
}, },
] ]
AUTH_USER_MODEL = 'users.User' AUTH_USER_MODEL = "users.User"
# Internationalization # Internationalization
# https://docs.djangoproject.com/en/2.0/topics/i18n/ # https://docs.djangoproject.com/en/2.0/topics/i18n/
LANGUAGE_CODE = 'en-us' LANGUAGE_CODE = "en-us"
TIME_ZONE = 'UTC' TIME_ZONE = "UTC"
USE_I18N = True USE_I18N = True
@ -125,13 +120,13 @@ USE_TZ = True
# Static files (CSS, JavaScript, Images) # Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.0/howto/static-files/ # https://docs.djangoproject.com/en/2.0/howto/static-files/
STATIC_URL = '/static/' STATIC_URL = "/static/"
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')] STATICFILES_DIRS = [os.path.join(BASE_DIR, "static")]
SITE_ID = 1 SITE_ID = 1
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
CURRENCIES = ('DKK',) CURRENCIES = ("DKK",)
CURRENCY_CHOICES = [('DKK', 'DKK')] CURRENCY_CHOICES = [("DKK", "DKK")]

View file

@ -6,7 +6,7 @@ from django.urls import path
from . import views from . import views
urlpatterns = [ urlpatterns = [
path('', views.index), path("", views.index),
path("users/", include("users.urls")), path("users/", include("users.urls")),
path('admin/', admin.site.urls), path("admin/", admin.site.urls),
] ]

View file

@ -1,3 +1 @@
from django.contrib import admin from django.contrib import admin # noqa
# Register your models here.

View file

@ -2,4 +2,4 @@ from django.apps import AppConfig
class UsersConfig(AppConfig): class UsersConfig(AppConfig):
name = 'users' name = "users"

View file

@ -9,28 +9,65 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [("auth", "0011_update_proxy_permissions")]
('auth', '0011_update_proxy_permissions'),
]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='User', name="User",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('password', models.CharField(max_length=128, verbose_name='password')), "id",
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), models.AutoField(
('nick', models.CharField(blank=True, max_length=60, null=True)), auto_created=True,
('email', models.EmailField(help_text='Your email address will be used for password resets and notification about your event/submissions.', max_length=254, unique=True, verbose_name='E-Mail')), primary_key=True,
('is_active', models.BooleanField(default=True)), serialize=False,
('is_staff', models.BooleanField(default=False)), verbose_name="ID",
('is_superuser', models.BooleanField(default=False)), ),
('token_uuid', models.UUIDField(default=uuid.uuid4, editable=False)), ),
('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')), ("password", models.CharField(max_length=128, verbose_name="password")),
('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')), (
"last_login",
models.DateTimeField(
blank=True, null=True, verbose_name="last login"
),
),
("nick", models.CharField(blank=True, max_length=60, null=True)),
(
"email",
models.EmailField(
help_text="Your email address will be used for password resets and notification about your event/submissions.",
max_length=254,
unique=True,
verbose_name="E-Mail",
),
),
("is_active", models.BooleanField(default=True)),
("is_staff", models.BooleanField(default=False)),
("is_superuser", models.BooleanField(default=False)),
("token_uuid", models.UUIDField(default=uuid.uuid4, editable=False)),
(
"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={ options={"verbose_name": "User"},
'verbose_name': 'User', )
},
),
] ]

View file

@ -20,23 +20,23 @@ class UserManager(BaseUserManager):
user = self.create_user(password=password, **kwargs) user = self.create_user(password=password, **kwargs)
user.is_staff = True user.is_staff = True
user.is_superuser = True user.is_superuser = True
user.save(update_fields=['is_staff', 'is_superuser']) user.save(update_fields=["is_staff", "is_superuser"])
return user return user
class User(PermissionsMixin, AbstractBaseUser): class User(PermissionsMixin, AbstractBaseUser):
EMAIL_FIELD = 'email' EMAIL_FIELD = "email"
USERNAME_FIELD = 'email' USERNAME_FIELD = "email"
objects = UserManager() objects = UserManager()
nick = models.CharField(max_length=60, null=True, blank=True) nick = models.CharField(max_length=60, null=True, blank=True)
email = models.EmailField( email = models.EmailField(
unique=True, unique=True,
verbose_name=_('E-Mail'), verbose_name=_("E-Mail"),
help_text=_( help_text=_(
'Your email address will be used for password resets and notification about your event/submissions.' "Your email address will be used for password resets and notification about your event/submissions."
), ),
) )
@ -54,7 +54,7 @@ class User(PermissionsMixin, AbstractBaseUser):
return self.get_display_name() return self.get_display_name()
def get_display_name(self) -> str: def get_display_name(self) -> str:
return self.nick if self.nick else str(_('Unnamed user')) return self.nick if self.nick else str(_("Unnamed user"))
class Meta: class Meta:
verbose_name = _("User") verbose_name = _("User")

View file

@ -3,20 +3,59 @@ from django.urls import path
from . import views from . import views
app_name = 'users' app_name = "users"
urlpatterns = [ urlpatterns = [
path('signup/', views.SignupView.as_view(), name='signup'), path("signup/", views.SignupView.as_view(), name="signup"),
path('signup/confirm/', views.SignupConfirmView.as_view(), name='signup_confirm'), path("signup/confirm/", views.SignupConfirmView.as_view(), name="signup_confirm"),
path(
path('login/', auth_views.LoginView.as_view(template_name="users/login.html"), name='login'), "login/",
path('logout/', auth_views.LogoutView.as_view(template_name="users/logged_out.html"), name='logout'), auth_views.LoginView.as_view(template_name="users/login.html"),
name="login",
path('password_change/', views.PasswordChangeView.as_view(template_name="users/password_change_form.html"), name='password_change'), ),
path('password_change/done/', auth_views.PasswordChangeDoneView.as_view(template_name="users/password_change_done.html"), name='password_change_done'), path(
"logout/",
path('password_reset/', views.PasswordResetView.as_view(template_name="users/password_reset_form.html"), name='password_reset'), auth_views.LogoutView.as_view(template_name="users/logged_out.html"),
path('password_reset/done/', auth_views.PasswordResetDoneView.as_view(template_name="users/password_reset_done.html"), name='password_reset_done'), name="logout",
path('reset/<uidb64>/<token>/', views.PasswordResetConfirmView.as_view(template_name="users/password_reset_confirm.html"), name='password_reset_confirm'), ),
path('reset/done/', auth_views.PasswordResetCompleteView.as_view(template_name="users/password_reset_complete.html"), name='password_reset_complete'), path(
"password_change/",
views.PasswordChangeView.as_view(
template_name="users/password_change_form.html"
),
name="password_change",
),
path(
"password_change/done/",
auth_views.PasswordChangeDoneView.as_view(
template_name="users/password_change_done.html"
),
name="password_change_done",
),
path(
"password_reset/",
views.PasswordResetView.as_view(template_name="users/password_reset_form.html"),
name="password_reset",
),
path(
"password_reset/done/",
auth_views.PasswordResetDoneView.as_view(
template_name="users/password_reset_done.html"
),
name="password_reset_done",
),
path(
"reset/<uidb64>/<token>/",
views.PasswordResetConfirmView.as_view(
template_name="users/password_reset_confirm.html"
),
name="password_reset_confirm",
),
path(
"reset/done/",
auth_views.PasswordResetCompleteView.as_view(
template_name="users/password_reset_complete.html"
),
name="password_reset_complete",
),
] ]

View file

@ -6,20 +6,21 @@ from django.views.generic.base import TemplateView
from django.views.generic.edit import FormView from django.views.generic.edit import FormView
from . import forms from . import forms
# from . import email # from . import email
class PasswordResetView(auth_views.PasswordResetView): class PasswordResetView(auth_views.PasswordResetView):
email_template_name = 'users/password_reset_email.html' email_template_name = "users/password_reset_email.html"
success_url = reverse_lazy('users:password_reset_done') success_url = reverse_lazy("users:password_reset_done")
class PasswordResetConfirmView(auth_views.PasswordResetConfirmView): class PasswordResetConfirmView(auth_views.PasswordResetConfirmView):
success_url = reverse_lazy('users:password_reset_complete') success_url = reverse_lazy("users:password_reset_complete")
class PasswordChangeView(auth_views.PasswordChangeView): class PasswordChangeView(auth_views.PasswordChangeView):
success_url = reverse_lazy('users:password_change_done') success_url = reverse_lazy("users:password_change_done")
class SignupView(FormView): class SignupView(FormView):
@ -31,7 +32,7 @@ class SignupView(FormView):
user = form.save(commit=False) user = form.save(commit=False)
user.is_active = False user.is_active = False
user.set_password(form.cleaned_data['password1']) user.set_password(form.cleaned_data["password1"])
user.save() user.save()
# mail = email.UserConfirm(user=user) # mail = email.UserConfirm(user=user)
@ -48,10 +49,9 @@ class SignupConfirmView(TemplateView):
class SignupConfirmRedirectView(RedirectView): class SignupConfirmRedirectView(RedirectView):
def get_redirect_url(self): def get_redirect_url(self):
uuid = self.kwargs['uuid'] uuid = self.kwargs["uuid"]
if self.kwargs["token"] == forms.get_confirm_code(uuid): if self.kwargs["token"] == forms.get_confirm_code(uuid):
redirect("users:confirmed") # TODO redirect("users:confirmed") # TODO