Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
thalia
concrexit
Commits
b861b786
Verified
Commit
b861b786
authored
Apr 27, 2019
by
Sébastiaan Versteeg
Browse files
Make changes to members module
parent
0300c1af
Changes
17
Hide whitespace changes
Inline
Side-by-side
website/members/admin.py
View file @
b861b786
...
...
@@ -26,13 +26,12 @@ class ProfileInline(admin.StackedInline):
'address_street2'
,
'address_postal_code'
,
'address_city'
,
'address_country'
,
'student_number'
,
'phone_number'
,
'receive_optin'
,
'receive_newsletter'
,
'birthday'
,
'show_birthday'
,
'
direct_debit_authorized'
,
'bank_account
'
,
'initials'
,
'nickname'
,
'display_name_preference'
,
'profile_description'
,
'website'
,
'photo'
,
'emergency_contact'
,
'show_birthday'
,
'
auto_renew'
,
'initials
'
,
'nickname'
,
'display_name_preference'
,
'profile_description'
,
'website'
,
'photo'
,
'emergency_contact'
,
'emergency_contact_phone_number'
,
'language'
,
'event_permissions'
)
model
=
models
.
Profile
form
=
forms
.
ProfileForm
can_delete
=
False
...
...
@@ -101,7 +100,8 @@ class UserAdmin(BaseUserAdmin):
'is_superuser'
,
AgeListFilter
,
'profile__event_permissions'
,
'profile__starting_year'
)
'profile__starting_year'
,
'profile__auto_renew'
)
add_fieldsets
=
(
(
None
,
{
...
...
website/members/fixtures/members.json
View file @
b861b786
...
...
@@ -94,8 +94,7 @@
"display_name_preference"
:
"full"
,
"language"
:
"nl"
,
"receive_optin"
:
true
,
"direct_debit_authorized"
:
false
,
"bank_account"
:
""
"auto_renew"
:
false
}
},
{
...
...
@@ -121,8 +120,7 @@
"display_name_preference"
:
"full"
,
"language"
:
"nl"
,
"receive_optin"
:
true
,
"direct_debit_authorized"
:
false
,
"bank_account"
:
""
"auto_renew"
:
false
}
},
{
...
...
@@ -148,8 +146,7 @@
"display_name_preference"
:
"full"
,
"language"
:
"nl"
,
"receive_optin"
:
true
,
"direct_debit_authorized"
:
false
,
"bank_account"
:
""
"auto_renew"
:
false
}
},
{
...
...
@@ -175,8 +172,7 @@
"display_name_preference"
:
"full"
,
"language"
:
"nl"
,
"receive_optin"
:
true
,
"direct_debit_authorized"
:
false
,
"bank_account"
:
""
"auto_renew"
:
false
}
},
{
...
...
website/members/forms.py
View file @
b861b786
...
...
@@ -15,22 +15,11 @@ class ProfileForm(forms.ModelForm):
'phone_number'
,
'emergency_contact'
,
'emergency_contact_phone_number'
,
'show_birthday'
,
'website'
,
'profile_description'
,
'nickname'
,
'profile_description'
,
'nickname'
,
'initials'
,
'display_name_preference'
,
'photo'
,
'language'
,
'receive_optin'
,
'receive_newsletter'
]
model
=
Profile
def
clean
(
self
):
super
().
clean
()
errors
=
{}
direct_debit_authorized
=
self
.
cleaned_data
\
.
get
(
'direct_debit_authorized'
)
bank_account
=
self
.
cleaned_data
.
get
(
'bank_account'
)
if
direct_debit_authorized
and
not
bank_account
:
errors
.
update
({
'bank_account'
:
_
(
'Please enter a bank account'
)})
raise
forms
.
ValidationError
(
errors
)
class
UserCreationForm
(
BaseUserCreationForm
):
# Don't forget to edit the formset in admin.py!
...
...
website/members/management/commands/conscribosync.py
View file @
b861b786
...
...
@@ -45,6 +45,20 @@ class Command(BaseCommand):
code
=
current_relations
.
pop
(
member
.
pk
,
None
)
profile
=
member
.
profile
if
member
.
bank_accounts
.
exists
():
account
=
member
.
bank_accounts
.
last
()
bank_account
=
{
'name'
:
account
.
name
,
'bic'
:
account
.
bic
or
''
,
'iban'
:
account
.
iban
,
}
else
:
bank_account
=
{
'name'
:
''
,
'bic'
:
''
,
'iban'
:
''
,
}
fields
=
{
'website_id'
:
member
.
pk
,
'voornaam'
:
member
.
first_name
,
...
...
@@ -57,11 +71,7 @@ class Command(BaseCommand):
'postcode'
:
profile
.
address_postal_code
,
'plaats'
:
profile
.
address_city
,
'land'
:
profile
.
get_address_country_display
(),
'bankrekeningnummer'
:
{
'name'
:
f
'
{
profile
.
initials
}
{
member
.
last_name
}
'
,
'bic'
:
''
,
'iban'
:
profile
.
bank_account
,
},
'bankrekeningnummer'
:
bank_account
,
}
replace_commands
.
append
(
ApiCommand
(
...
...
website/members/migrations/0032_bank_account.py
deleted
100644 → 0
View file @
0300c1af
from
django.db
import
migrations
def
forwards_func
(
apps
,
schema_editor
):
Membership
=
apps
.
get_model
(
'members'
,
'membership'
)
db_alias
=
schema_editor
.
connection
.
alias
Membership
.
objects
.
using
(
db_alias
).
filter
(
type
=
'supporter'
).
update
(
type
=
'benefactor'
)
def
reverse_func
(
apps
,
schema_editor
):
Membership
=
apps
.
get_model
(
'members'
,
'membership'
)
db_alias
=
schema_editor
.
connection
.
alias
Membership
.
objects
.
using
(
db_alias
).
filter
(
type
=
'benefactor'
).
update
(
type
=
'supporter'
)
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'members'
,
'0029_profile_address_country'
),
]
operations
=
[
migrations
.
RunPython
(
forwards_func
,
reverse_func
),
]
website/members/migrations/0032_remove_profile_bank_account.py
0 → 100644
View file @
b861b786
from
django.db
import
migrations
from
django.utils
import
timezone
def
forwards_func
(
apps
,
schema_editor
):
Member
=
apps
.
get_model
(
'members'
,
'profile'
)
BankAccount
=
apps
.
get_model
(
'payments'
,
'BankAccount'
)
db_alias
=
schema_editor
.
connection
.
alias
for
profile
in
Member
.
objects
.
using
(
db_alias
).
exclude
(
bank_account
=
None
).
all
():
BankAccount
.
objects
.
using
(
db_alias
).
create
(
owner
=
profile
.
user
,
initials
=
profile
.
initials
or
profile
.
user
.
first_name
[
0
],
last_name
=
profile
.
user
.
last_name
,
valid_from
=
timezone
.
now
(),
mandate_no
=
f
'
{
profile
.
user
.
pk
}
-1'
,
signature
=
"data:image/png;base64,"
,
iban
=
profile
.
bank_account
)
def
reverse_func
(
apps
,
schema_editor
):
BankAccount
=
apps
.
get_model
(
'payments'
,
'BankAccount'
)
db_alias
=
schema_editor
.
connection
.
alias
for
account
in
BankAccount
.
objects
.
using
(
db_alias
).
all
():
account
.
owner
.
profile
.
bank_account
=
account
.
iban
account
.
owner
.
profile
.
save
()
account
.
delete
()
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'members'
,
'0031_benefactor_model_value'
),
(
'payments'
,
'0004_bankaccount'
),
]
operations
=
[
migrations
.
RunPython
(
forwards_func
,
reverse_func
),
]
website/members/models.py
View file @
b861b786
...
...
@@ -15,8 +15,6 @@ from django.db.models import Q
from
django.urls
import
reverse
from
django.utils
import
timezone
from
django.utils.translation
import
pgettext_lazy
,
gettext_lazy
as
_
from
localflavor.generic.countries.sepa
import
IBAN_SEPA_COUNTRIES
from
localflavor.generic.models
import
IBANField
from
activemembers.models
import
MemberGroup
,
MemberGroupMembership
from
utils
import
countries
...
...
@@ -404,27 +402,15 @@ class Profile(models.Model):
default
=
True
,
)
# ---
Direct debit information
----
# ---
Membership preference
----
direct_debit_authorized
=
models
.
BooleanField
(
choices
=
((
True
,
_
(
'Yes, I want Thalia to take the membership fees '
'from my bank account through direct debit for '
'each year.'
)),
(
False
,
_
(
'No, I will pay the contribution myself'
))),
verbose_name
=
_
(
'Direct debit'
),
help_text
=
_
(
'Each year, have Thalia take the membership fees from my '
'bank account'
),
auto_renew
=
models
.
BooleanField
(
choices
=
((
True
,
_
(
'Yes, enable auto renewal.'
)),
(
False
,
_
(
'No, manual renewal required.'
))),
verbose_name
=
_
(
'Automatically renew membership'
),
default
=
False
,
)
bank_account
=
IBANField
(
verbose_name
=
_
(
'Bank account'
),
help_text
=
_
(
'Bank account for direct debit'
),
include_countries
=
IBAN_SEPA_COUNTRIES
,
blank
=
True
,
null
=
True
,
)
def
display_name
(
self
):
pref
=
self
.
display_name_preference
if
pref
==
'nickname'
and
self
.
nickname
is
not
None
:
...
...
website/members/services.py
View file @
b861b786
...
...
@@ -199,7 +199,7 @@ def execute_data_minimisation(dry_run=False, members=None):
profile
.
emergency_contact_phone_number
=
None
profile
.
emergency_contact
=
None
profile
.
website
=
None
profile
.
bank_account
=
None
member
.
bank_account
s
.
all
().
delete
()
if
not
dry_run
:
profile
.
save
()
...
...
website/members/templates/members/account.html
deleted
100644 → 0
View file @
0300c1af
{% extends "base.html" %}
{% load static %}
{% load i18n %}
{% block title %}{% trans "members"|capfirst %} — {{ block.super }}{% endblock %}
{% block opengraph_title %}{% trans "members"|capfirst %} — {{ block.super }}{% endblock %}
{% block body %}
<section
class=
"page-section"
>
<div
class=
"container"
>
<h1
class=
"text-center section-title"
>
{% trans 'Account' %}
</h1>
<div
class=
"row"
>
<div
class=
"col-lg-6 offset-lg-3"
>
<p
class=
"text-center"
>
{% blocktrans trimmed with user=request.member.username %}
You’re currently logged in as
<strong>
{{ user }}
</strong>
{% endblocktrans %}.
</p>
<hr>
<div>
<a
href=
"{% url 'members:profile' request.member.pk %}"
>
{% trans "show public profile"|capfirst %}
</a>
<p>
{% blocktrans %}Take a look at your own profile.{% endblocktrans %}
</p>
</div>
<hr>
<div>
<a
href=
"{% url 'registrations:renew' %}"
>
{% trans "manage membership"|capfirst %}
</a>
<p>
{% blocktrans %}Get information about your membership or renew it.{% endblocktrans %}
</p>
</div>
<hr>
<div>
<a
href=
"{% url 'members:edit-profile' %}"
>
{% trans "edit profile"|capfirst %}
</a>
<p>
{% blocktrans %}Edit your profile and avatar.{% endblocktrans %}
</p>
</div>
<hr>
<div>
<a
href=
"{% url 'password_change' %}"
>
{% trans "change password"|capfirst %}
</a>
<p>
{% blocktrans %}Change your accounts' password.{% endblocktrans %}
</p>
</div>
<hr>
<div>
<a
href=
"{% url 'logout' %}"
>
{% trans "logout"|capfirst %}
</a>
<p>
{% blocktrans %}Leave the restricted area of the website.{% endblocktrans %}
</p>
</div>
</div>
</div>
</div>
</section>
{% endblock %}}
website/members/urls.py
View file @
b861b786
from
django.conf.urls
import
url
from
django.urls
import
path
from
django.urls
import
path
,
include
from
.
import
views
app_name
=
"members"
urlpatterns
=
[
url
(
'^profile/(?P<pk>[0-9]*)$'
,
views
.
profile
,
name
=
'profile'
),
url
(
'^profile/edit/$'
,
views
.
edit_profile
,
name
=
'edit-profile'
),
url
(
'^members/iban-export/$'
,
views
.
iban_export
,
name
=
'iban-export'
),
path
(
'profile/change-email/'
,
views
.
EmailChangeFormView
.
as_view
(),
name
=
'email-change'
),
path
(
'profile/change-email/verify/<uuid:key>/'
,
views
.
EmailChangeVerifyView
.
as_view
(),
name
=
'email-change-verify'
),
path
(
'profile/change-email/confirm/<uuid:key>/'
,
views
.
EmailChangeConfirmView
.
as_view
(),
name
=
'email-change-confirm'
),
url
(
'^$'
,
views
.
index
,
name
=
'index'
),
path
(
'iban-export/'
,
views
.
iban_export
,
name
=
'iban-export'
),
path
(
'members/'
,
include
([
path
(
''
,
views
.
index
,
name
=
'index'
),
path
(
'statistics/'
,
views
.
statistics
,
name
=
'statistics'
),
path
(
'profile/<int:pk>'
,
views
.
profile
,
name
=
'profile'
),
])),
path
(
'user/'
,
include
([
path
(
''
,
views
.
user
,
name
=
'user'
),
path
(
'edit-profile/'
,
views
.
edit_profile
,
name
=
'edit-profile'
),
path
(
'change-email/'
,
views
.
EmailChangeFormView
.
as_view
(),
name
=
'email-change'
),
path
(
'change-email/verify/<uuid:key>/'
,
views
.
EmailChangeVerifyView
.
as_view
(),
name
=
'email-change-verify'
),
path
(
'change-email/confirm/<uuid:key>/'
,
views
.
EmailChangeConfirmView
.
as_view
(),
name
=
'email-change-confirm'
),
])),
]
website/members/views.py
View file @
b861b786
...
...
@@ -168,8 +168,8 @@ def profile(request, pk=None):
@
login_required
def
account
(
request
):
return
render
(
request
,
'members/
account
.html'
)
def
user
(
request
):
return
render
(
request
,
'members/
user
.html'
)
@
login_required
...
...
@@ -191,18 +191,21 @@ def edit_profile(request):
@
permission_required
(
'auth.change_user'
)
def
iban_export
(
request
):
header_fields
=
[
'name'
,
'username'
,
'iban'
]
header_fields
=
[
'name'
,
'username'
,
'iban'
,
'bic'
]
rows
=
[]
members
=
models
.
Member
.
current_members
.
filter
(
profile__
direct_debit_authorized
=
True
)
profile__
auto_renew
=
True
)
for
member
in
members
:
if
member
.
current_membership
.
type
!=
'honorary'
:
if
(
member
.
current_membership
.
type
!=
'honorary'
and
member
.
bank_accounts
.
exists
()):
bank_account
=
member
.
bank_accounts
.
last
()
rows
.
append
({
'name'
:
member
.
get_full_
name
()
,
'name'
:
bank_account
.
name
,
'username'
:
member
.
username
,
'iban'
:
member
.
profile
.
bank_account
'iban'
:
bank_account
.
iban
,
'bic'
:
bank_account
.
bic
})
response
=
HttpResponse
(
content_type
=
'text/csv'
)
...
...
website/payments/models.py
View file @
b861b786
...
...
@@ -214,17 +214,11 @@ class BankAccount(models.Model):
@
property
def
valid
(
self
):
if
self
.
valid_from
and
self
.
valid_until
:
return
self
.
valid_from
<
timezone
.
now
().
date
()
<
self
.
valid_until
return
self
.
valid_from
and
self
.
valid_from
<
timezone
.
now
().
date
()
return
self
.
valid_from
<
=
timezone
.
now
().
date
()
<
self
.
valid_until
return
self
.
valid_from
and
self
.
valid_from
<
=
timezone
.
now
().
date
()
def
__str__
(
self
):
return
f
'
{
self
.
iban
}
-
{
self
.
owner
.
get_full_name
()
}
'
class
Meta
:
ordering
=
(
'created_at'
,)
website/payments/views.py
View file @
b861b786
...
...
@@ -47,10 +47,11 @@ class BankAccountCreateView(SuccessMessageMixin, CreateView):
return
super
().
post
(
request
,
*
args
,
**
kwargs
)
def
form_valid
(
self
,
form
):
BankAccount
.
objects
.
filter
(
mandate_no
=
None
).
delete
()
BankAccount
.
objects
.
exclude
(
mandate_no
=
None
).
update
(
valid_until
=
timezone
.
now
()
)
BankAccount
.
objects
.
filter
(
owner
=
self
.
request
.
member
,
mandate_no
=
None
).
delete
()
BankAccount
.
objects
.
filter
(
owner
=
self
.
request
.
member
).
exclude
(
mandate_no
=
None
).
update
(
valid_until
=
timezone
.
now
())
return
super
().
form_valid
(
form
)
...
...
@@ -63,7 +64,7 @@ class BankAccountRevokeView(SuccessMessageMixin, UpdateView):
def
get_queryset
(
self
):
return
super
().
get_queryset
().
filter
(
owner
=
self
.
request
.
member
)
def
get
(
self
,
**
kwargs
):
raise
Http404
...
...
website/payments/widgets.py
View file @
b861b786
"""Widgets provided by the payments package"""
import
base64
from
django.forms
import
Widget
...
...
website/thaliawebsite/menus.py
View file @
b861b786
...
...
@@ -36,7 +36,7 @@ MAIN_MENU = [
'submenu'
:
[
{
'title'
:
_
(
'Member list'
),
'name'
:
'members:index'
},
{
'title'
:
_
(
'Photos'
),
'name'
:
'photos:index'
},
{
'title'
:
_
(
'Statistics'
),
'name'
:
'statistics'
},
{
'title'
:
_
(
'Statistics'
),
'name'
:
'
members:
statistics'
},
{
'title'
:
_
(
'Styleguide'
),
'name'
:
'styleguide'
},
{
'title'
:
_
(
'Become Active'
),
'name'
:
'become-active'
},
{
'title'
:
_
(
'Nextcloud'
),
'url'
:
'https://cloud.thalia.nu/'
,
...
...
website/thaliawebsite/templates/base.html
View file @
b861b786
...
...
@@ -89,7 +89,7 @@
<a
href=
"{% url 'login' %}"
class=
"btn btn-primary"
><i
class=
"fas fa-user"
></i></a>
{% else %}
<a
href=
"{% url '
account
' %}"
class=
"btn btn-primary"
><i
<a
href=
"{% url '
members:user
' %}"
class=
"btn btn-primary"
><i
class=
"fas fa-user"
></i></a>
<button
type=
"button"
class=
"btn btn-primary dropdown-toggle dropdown-toggle-split"
...
...
website/thaliawebsite/urls.py
View file @
b861b786
...
...
@@ -36,11 +36,9 @@ from django.contrib import admin
from
django.contrib.auth.decorators
import
login_required
from
django.contrib.auth.views
import
LoginView
from
django.contrib.sitemaps.views
import
sitemap
from
django.urls
import
path
from
django.views.generic
import
TemplateView
from
django.views.i18n
import
JavaScriptCatalog
import
members
from
activemembers.sitemaps
import
sitemap
as
activemembers_sitemap
from
documents.sitemaps
import
sitemap
as
documents_sitemap
from
events.sitemaps
import
sitemap
as
events_sitemap
...
...
@@ -74,12 +72,7 @@ urlpatterns = [ # pylint: disable=invalid-name
url
(
r
'^event-registration-terms/'
,
TemplateView
.
as_view
(
template_name
=
'singlepages/event_registration_terms.html'
),
name
=
'event-registration-terms'
),
url
(
r
'^admin/'
,
admin
.
site
.
urls
),
url
(
r
'^alumni/$'
,
AlumniEventsView
.
as_view
(),
name
=
'alumni'
),
url
(
r
'^members/'
,
include
(
'members.urls'
)),
url
(
r
'^registration/'
,
include
(
'registrations.urls'
)),
url
(
r
'^account/'
,
include
([
url
(
r
'^$'
,
members
.
views
.
account
,
name
=
'account'
),
url
(
r
'^finance/'
,
include
(
'payments.urls'
))
])),
url
(
r
'^events/'
,
include
(
'events.urls'
)),
url
(
r
'^pizzas/'
,
include
(
'pizzas.urls'
)),
url
(
r
'^newsletters/'
,
include
(
'newsletters.urls'
)),
...
...
@@ -94,7 +87,6 @@ urlpatterns = [ # pylint: disable=invalid-name
url
(
r
'^'
,
include
([
# 'for members' menu
url
(
r
'^become-active/'
,
login_required
(
TemplateView
.
as_view
(
template_name
=
'singlepages/become_active.html'
)),
name
=
'become-active'
),
url
(
r
'^photos/'
,
include
(
'photos.urls'
)),
url
(
r
'^statistics/$'
,
members
.
views
.
statistics
,
name
=
'statistics'
),
url
(
r
'^styleguide/$'
,
views
.
styleguide
,
name
=
'styleguide'
),
url
(
r
'^styleguide/file/(?P<filename>[\w\-_\.]+)$'
,
views
.
styleguide_file
,
name
=
'styleguide-file'
),
])),
...
...
@@ -133,6 +125,8 @@ urlpatterns = [ # pylint: disable=invalid-name
url
(
r
'crash/$'
,
views
.
crash
),
# Custom media paths
url
(
r
'^media/generate-thumbnail/(?P<request_path>.*)'
,
generate_thumbnail
,
name
=
'generate-thumbnail'
),
url
(
r
'^media/private/(?P<request_path>.*)$'
,
private_media
,
name
=
'private-media'
)
url
(
r
'^media/private/(?P<request_path>.*)$'
,
private_media
,
name
=
'private-media'
),
url
(
''
,
include
(
'members.urls'
)),
url
(
''
,
include
(
'payments.urls'
)),
]
+
static
(
settings
.
MEDIA_URL
+
'public/'
,
document_root
=
os
.
path
.
join
(
settings
.
MEDIA_ROOT
,
'public'
))
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment