Browse Source

Merge branch 'feature/membership-form' into development

feature/python-error-tracking
Drew Larson 8 years ago
parent
commit
2ec33ee31e
  1. 2
      bikeshop_project/core/admin.py
  2. 77
      bikeshop_project/core/forms.py
  3. 31
      bikeshop_project/core/migrations/0007_auto_20160501_2253.py
  4. 25
      bikeshop_project/core/migrations/0008_auto_20160526_0059.py
  5. 19
      bikeshop_project/core/migrations/0009_remove_membership_member.py
  6. 23
      bikeshop_project/core/migrations/0010_membership_member.py
  7. 22
      bikeshop_project/core/migrations/0011_auto_20160531_0233.py
  8. 25
      bikeshop_project/core/migrations/0012_auto_20160531_0234.py
  9. 25
      bikeshop_project/core/migrations/0013_auto_20160531_0236.py
  10. 20
      bikeshop_project/core/migrations/0014_payment_paid.py
  11. 20
      bikeshop_project/core/migrations/0015_auto_20160531_0413.py
  12. 24
      bikeshop_project/core/migrations/0016_auto_20160531_0416.py
  13. 41
      bikeshop_project/core/models.py
  14. 1
      bikeshop_project/core/static/scss/screen.scss
  15. 192
      bikeshop_project/core/templates/membership_form.html
  16. 5
      bikeshop_project/core/urls.py
  17. 39
      bikeshop_project/core/views.py
  18. 3
      bikeshop_project/registration/admin.py
  19. 20
      bikeshop_project/registration/forms.py
  20. 22
      bikeshop_project/registration/migrations/0005_member_membership.py
  21. 19
      bikeshop_project/registration/migrations/0006_remove_member_membership.py
  22. 198
      bikeshop_project/registration/templates/edit_member_form.html
  23. 57
      bikeshop_project/registration/templates/member_form.html
  24. 1
      bikeshop_project/registration/urls.py
  25. 44
      bikeshop_project/registration/views.py
  26. 3
      bower.json
  27. 1
      provision/roles/supervisor/development/supervisor-program.conf

2
bikeshop_project/core/admin.py

@ -1,3 +1,5 @@
from django.contrib import admin
from .models import Membership, Payment
# Register your models here.
admin.site.register([Membership, Payment])

77
bikeshop_project/core/forms.py

@ -0,0 +1,77 @@
import logging
from django.forms import BooleanField, CharField, CheckboxInput, RadioSelect, ModelForm, TextInput, HiddenInput, ChoiceField
from registration.models import Member
from .models import Membership, Payment
logger = logging.getLogger('bikeshop')
class MembershipForm(ModelForm):
member = CharField(required=True, widget=HiddenInput())
self_ident_other = CharField(required=False, label='Self identification',
widget=TextInput(attrs={'class': 'mdl-textfield__input'}))
gender_other = CharField(required=False, label='Other', widget=TextInput(attrs={'class': 'mdl-textfield__input'}))
safe_space = BooleanField(required=True, widget=CheckboxInput(
attrs={'class': 'mdl-checkbox__input'}
))
respect_community = BooleanField(required=True, widget=CheckboxInput(
attrs={'class': 'mdl-checkbox__input'}
))
give_back = BooleanField(required=True, widget=CheckboxInput(
attrs={'class': 'mdl-checkbox__input'}
))
respect_shop = BooleanField(required=True, widget=CheckboxInput(
attrs={'class': 'mdl-checkbox__input'}
))
class Meta:
model = Membership
fields = ['renewed_at', 'self_identification', 'gender']
self_ident_choices = (
('First Nations; Métis; or Inuit', 'First Nations; Métis; or Inuit'),
('visible minority', 'Visible Minority'),
('caucasian', 'Caucasian'),
('other', 'Other')
)
gender_choices = (
('male', 'Male'),
('female', 'Female'),
('other', 'Other')
)
widgets = {
'self_identification': RadioSelect(choices=self_ident_choices, attrs={'class': 'mdl-radio__button'}),
'gender': RadioSelect(choices=gender_choices, attrs={'class': 'mdl-radio__button'}),
'renewed_at': TextInput(attrs={'class': 'mdl-textfield__input'}),
}
def save(self, commit=True):
instance = super(MembershipForm, self).save(commit=False)
member = Member.objects.get(id=self.cleaned_data['member'])
instance.member = member
logger.debug(self.cleaned_data['self_identification'])
logger.debug(self.cleaned_data['gender'])
if self.cleaned_data['gender_other']:
instance.gender = self.cleaned_data['gender_other']
if self.cleaned_data['self_ident_other']:
instance.self_identification = self.cleaned_data['self_ident_other']
if commit:
instance.save()
return instance
class PaymentForm(ModelForm):
class Meta:
model = Payment
fields = ['type']
widgets = {
'type': RadioSelect(attrs={'class': 'mdl-radio__button'})
}

31
bikeshop_project/core/migrations/0007_auto_20160501_2253.py

@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-05-01 22:53
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('core', '0006_auto_20160410_1833'),
]
operations = [
migrations.RemoveField(
model_name='membership',
name='acknowledgement',
),
migrations.RemoveField(
model_name='membership',
name='community',
),
migrations.RemoveField(
model_name='membership',
name='give_back',
),
migrations.RemoveField(
model_name='membership',
name='safe_space',
),
]

25
bikeshop_project/core/migrations/0008_auto_20160526_0059.py

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-05-26 00:59
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('core', '0007_auto_20160501_2253'),
]
operations = [
migrations.RemoveField(
model_name='payment',
name='membership',
),
migrations.AddField(
model_name='membership',
name='payment',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='core.Payment'),
),
]

19
bikeshop_project/core/migrations/0009_remove_membership_member.py

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-05-26 01:50
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('core', '0008_auto_20160526_0059'),
]
operations = [
migrations.RemoveField(
model_name='membership',
name='member',
),
]

23
bikeshop_project/core/migrations/0010_membership_member.py

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-05-31 02:31
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('core', '0009_remove_membership_member'),
]
operations = [
migrations.AddField(
model_name='membership',
name='member',
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='membership', to=settings.AUTH_USER_MODEL),
),
]

22
bikeshop_project/core/migrations/0011_auto_20160531_0233.py

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-05-31 02:33
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('core', '0010_membership_member'),
]
operations = [
migrations.AlterField(
model_name='membership',
name='member',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='memberships', to=settings.AUTH_USER_MODEL),
),
]

25
bikeshop_project/core/migrations/0012_auto_20160531_0234.py

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-05-31 02:34
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('core', '0011_auto_20160531_0233'),
]
operations = [
migrations.RemoveField(
model_name='membership',
name='payment',
),
migrations.AddField(
model_name='payment',
name='membership',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='payments', to='core.Membership'),
),
]

25
bikeshop_project/core/migrations/0013_auto_20160531_0236.py

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-05-31 02:36
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('core', '0012_auto_20160531_0234'),
]
operations = [
migrations.RemoveField(
model_name='payment',
name='membership',
),
migrations.AddField(
model_name='membership',
name='payment',
field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='membership', to='core.Payment'),
),
]

20
bikeshop_project/core/migrations/0014_payment_paid.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-05-31 02:38
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0013_auto_20160531_0236'),
]
operations = [
migrations.AddField(
model_name='payment',
name='paid',
field=models.BooleanField(default=False),
),
]

20
bikeshop_project/core/migrations/0015_auto_20160531_0413.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-05-31 04:13
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0014_payment_paid'),
]
operations = [
migrations.AlterField(
model_name='payment',
name='type',
field=models.CharField(choices=[('CASH', 'cash'), ('CHEQUE', 'cheque'), ('VOLUNTEERING', 'volunteering'), ('STRIPE', 'stripe'), ('PAYPAL', 'paypal')], default='None', max_length=12),
),
]

24
bikeshop_project/core/migrations/0016_auto_20160531_0416.py

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-05-31 04:16
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0015_auto_20160531_0413'),
]
operations = [
migrations.RemoveField(
model_name='payment',
name='paid',
),
migrations.AlterField(
model_name='payment',
name='type',
field=models.CharField(choices=[('NONE', 'None'), ('CASH', 'Cash'), ('CHEQUE', 'Cheque'), ('VOLUNTEERING', 'Volunteering'), ('STRIPE', 'Stripe'), ('PAYPAL', 'PayPal')], default='NONE', max_length=12),
),
]

41
bikeshop_project/core/models.py

@ -6,34 +6,35 @@ class Membership(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
modified_at = models.DateTimeField(auto_now=True)
renewed_at = models.DateTimeField(default=timezone.now)
member = models.OneToOneField(
'registration.Member',
on_delete=models.CASCADE,
related_name='membership'
)
safe_space = models.BooleanField(default=False)
community = models.BooleanField(default=False)
give_back = models.BooleanField(default=False)
# this should be a form field that requires the new member to type out there full name
acknowledgement = models.BooleanField(default=False)
self_identification = models.CharField(max_length=255, null=True, blank=True)
gender = models.CharField(max_length=255, null=True, blank=True)
involvement = models.CharField(max_length=255, null=True, blank=True)
member = models.ForeignKey(
'registration.Member',
on_delete=models.CASCADE,
related_name='memberships',
blank=True,
null=True
)
payment = models.OneToOneField(
'Payment',
on_delete=models.CASCADE,
related_name='membership',
blank=False,
null=True
)
class Payment(models.Model):
membership = models.ForeignKey(
'Membership',
on_delete=models.CASCADE,
)
payment_choices = (
('CASH', 'cash'),
('CHEQUE', 'cheque'),
('VOLUNTEERING', 'volunteering'),
('STRIPE', 'stripe'),
('PAYPAL', 'paypal')
('NONE', 'None'),
('CASH', 'Cash'),
('CHEQUE', 'Cheque'),
('VOLUNTEERING', 'Volunteering'),
('STRIPE', 'Stripe'),
('PAYPAL', 'PayPal')
)
type = models.CharField(max_length=12, choices=payment_choices)
type = models.CharField(max_length=12, choices=payment_choices, default='NONE')
created_at = models.DateTimeField(auto_now_add=True)

1
bikeshop_project/core/static/scss/screen.scss

@ -7,6 +7,7 @@
@import "vendor/material-design-lite/src/layout/layout";
@import "vendor/material-design-lite/src/footer/mega_footer";
@import "vendor/material-design-lite/src/checkbox/checkbox";
@import "vendor/material-design-lite/src/radio/radio";
@import "vendor/material-design-lite/src/button/button";
@import "vendor/material-design-lite/src/palette/palette";
@import "vendor/material-design-lite/src/menu/menu";

192
bikeshop_project/core/templates/membership_form.html

@ -0,0 +1,192 @@
{% extends 'base.html' %}
{% load staticfiles %}
{% block styles %}
<link rel="stylesheet" href="{% static 'vendor/md-date-time-picker/dist/css/mdDateTimePicker.min.css' %}">
{% endblock %}
{% block content %}
<div class="mdl-cell mdl-cell--8-col">
<h1>New Membership</h1>
<form method="post">
<formset>
{% csrf_token %}
{{ membership_form.member }}
<p>The Bridge City Bicycle Co­operative aims to be a safe and respectful environment geared towards education, empowerment and community­building. In order to do so we need your input and support.</p>
<h4>Member Privileges</h4>
<ul>
<li>Access to the BCBC tools, stands, and workspace</li>
<li>Access to friendly mechanical assistance and education when available</li>
<li>Opportunity to engage in decisions and help to build and develop the community's vision</li>
<li>The Bridge City Bicycle Co­operative (BCBC) values the trust of its volunteers, staff and members and is committed to protecting the privacy of all personal information entrusted to it. As such, collected information will be used in accordance with our privacy policy outlined on our website and in our shop.</li>
</ul>
{% if membership_form.non_field_errors %}
<div>
<span class="error">{{ membership_form.errors }}</span>
</div>
{% endif %}
<div>
<h4>Member Responsibilities</h4>
<h5>Respect and Maintaining a Safe Space</h5>
<ul>
<li>Respect others and self</li>
<li>Help others</li>
<li>Racist, ableist, ageist, homophobic, sexist, and classist behavior and language will not be tolerated</li>
<li>The BCBC seeks to build a healthy lifestyle community, and behavior seen as hindering this objective will not be tolerated</li>
<li>Ask for help: With tools, processes, and even emotions</li>
</ul>
<label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect" for="{{ membership_form.safe_space.id_for_label }}">
{{ membership_form.safe_space }}
<span class="mdl-checkbox__label">I acknowledge the BCBC is a safe space and agree to maintain it.</span>
</label>
</div>
<div>
<h5>Respect the Community</h5>
<ul>
<li>Build positive relationships with Community Members</li>
<li>Build positive relationships with CNYC employees, volunteers, and patrons</li>
</ul>
<label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect" for="{{ membership_form.respect_community.id_for_label }}">
{{ membership_form.respect_community }}
<span class="mdl-checkbox__label">I will respect the community.</span>
</label>
</div>
<div>
<h5>Giving back</h5>
<p>
Our services are free and Members are encouraged to contribute in any way they can. Our vibrancy comes from the volunteer work of a large community with diverse skills and passions. There are so many ways to be a part of this community, regardless of whether or not you know how to change a tire (yet!). Ask how you can help out or get in touch with our volunteer coordinator (<a href="mailto:volunteer@bridgecitybicyclecoop.com">volunteer@bridgecitybicyclecoop.com</a>)
</p>
<label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect" for="{{ membership_form.give_back.id_for_label }}">
{{ membership_form.give_back }}
<span class="mdl-checkbox__label">I acknowledge that giving back is important</span>
</label>
</div>
<div>
<h5>Respect the Space</h5>
<ul>
<li>Replace tools when not using them so that others can play too.</li>
<li>Do not steal or borrow articles within the space for personal use.</li>
<li>If you don't know what it is, how to use it, or where it goes, ask someone</li>
<li>Ensure you always leave time to clean up after yourself and others, and then do so</li>
<li>If you have to leave in the middle of a project, put pieces into a small bag and attach it to the bike</li>
<li>Personal projects may be kept at the BCBC for a maximum of one day; however, this is highly discouraged due to lack of space and the concern for theft.</li>
<li>Label your bike with your name, phone number, and the last date you worked on it.</li>
<li>Do not force tools and use them only for their intended use. If you need help or guidance, ask someone! It’s what we’re here for!</li>
</ul>
<label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect" for="{{ membership_form.respect_shop.id_for_label }}">
{{ membership_form.respect_shop }}
<span class="mdl-checkbox__label">I will respect the shop.</span>
</label>
</div>
<div class="">
<h2 class="template__header mdl-typography--title">Voluntary Self Identification</h2>
<p>We want to make sure that all members of our community, regardless of race, ethnicity, and gender
are able to participate fully in the BCBC. Please share information about your race and/or
ethnicity so that we can track how well we are including all communities and whether there may be
barriers to certain groups’ participation. Thank you! Do you identify as: (In each category, check
all that apply)</p>
{% for checkbox in membership_form.self_identification %}
<label class="mdl-radio mdl-js-radio mdl-js-ripple-effect" for="{{ checkbox.id_for_label }}">
{{ checkbox }}
<span class="mdl-radio__label">{{ checkbox.label }}</span>
</label>
{% endfor %}
{% if membership_form.self_identification.errors %}
<span class="mdl-textfield__error">{{ membership_form.self_identification.errors }}</span>
{% else %}
<span class="mdl-textfield__error">Hmm</span>
{% endif %}
</div>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label {% if membership_form.gender_other.errors %}is-invalid{% endif %}">
{{ membership_form.self_ident_other }}
<label class="mdl-textfield__label" for="{{ membership_form.self_ident_other.id_for_label }}">{{ membership_form.self_ident_other.label }}</label>
{% if membership_form.self_ident_other.errors %}
<span class="mdl-textfield__error">{{ membership_form.self_ident_other.errors }}</span>
{% endif %}
</div>
<div class="">
<h3 class="template__header mdl-typography--body-2">Gender Identification</h3>
{% for checkbox in membership_form.gender %}
<label class="mdl-radio mdl-js-radio mdl-js-ripple-effect" for="{{ checkbox.id_for_label }}">
{{ checkbox }}
<span class="mdl-radio__label">{{ checkbox.label }}</span>
</label>
{% endfor %}
</div>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label {% if membership_form.gender_other.errors %}is-invalid{% endif %}">
{{ membership_form.gender_other }}
<label class="mdl-textfield__label" for="{{ membership_form.gender_other.id_for_label }}">{{ membership_form.gender_other.label }}</label>
{% if membership_form.gender_other.errors %}
<span class="mdl-textfield__error">{{ membership_form.gender_other.errors }}</span>
{% endif %}
</div>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label {% if membership_form.renewed_at.errors %}is-invalid{% endif %}">
{{ membership_form.renewed_at }}
<label class="mdl-textfield__label" for="{{ membership_form.renewed_at.id_for_label }}">{{ membership_form.renewed_at.label }}</label>
{% if membership_form.renewed_at %}
<span class="mdl-textfield__error">{{ membership_form.renewed_at.errors }}</span>
{% else %}
<span class="mdl-textfield__error">Incorrect date.</span>
{% endif %}
</div>
</formset>
<formset>
<div class="">
<h3 class="template__header">Payment Type</h3>
{% for checkbox in payment_form.type %}
<label class="mdl-radio mdl-js-radio mdl-js-ripple-effect" for="{{ checkbox.id_for_label }}">
{{ checkbox }}
<span class="mdl-radio__label">{{ checkbox.label }}</span>
</label>
{% endfor %}
</div>
</formset>
<div>
<button disabled="true" id="submit" type="submit" class="mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect mdl-button--colored">Submit</button>
</div>
</form>
</div>
{% endblock %}
{% block scripts %}
<script src="{% static 'vendor/moment/min/moment.min.js' %}"></script>
<script src="{% static 'vendor/draggabilly/dist/draggabilly.pkgd.min.js' %}"></script>
<script src="{% static 'vendor/md-date-time-picker/dist/js/mdDateTimePicker.min.js' %}"></script>
<script>
var renewedAt = new mdDateTimePicker.default({
type: 'date',
past: moment().subtract(100, 'years'),
trigger: document.getElementById('{{ form.renewed_at.id_for_label }}')
});
document.getElementById('{{ membership_form.renewed_at.id_for_label }}').addEventListener('focus', function() {
console.log('Toggle!');
renewedAt.toggle();
});
document.getElementById('{{ membership_form.renewed_at.id_for_label }}').addEventListener('onOk', function () {
console.log('onOk');
this.parentNode.classList.add('is-dirty');
this.value = renewedAt.time.format('YYYY-MM-DD');
})
var responsibilities = [
document.getElementById('{{ membership_form.safe_space.id_for_label }}'),
document.getElementById('{{ membership_form.respect_community.id_for_label }}'),
document.getElementById('{{ membership_form.give_back.id_for_label }}'),
document.getElementById('{{ membership_form.respect_shop.id_for_label }}')
];
var checkResponsiblities = function () {
allAgreed = responsibilities.every(function (checkbox) {
return checkbox.checked
});
var submitButton = document.getElementById('submit');
submitButton.disabled = !allAgreed;
};
document.addEventListener("DOMContentLoaded", checkResponsiblities);
responsibilities.forEach(function (checkbox) {
checkbox.addEventListener('click', checkResponsiblities)
})
</script>
{% endblock %}

5
bikeshop_project/core/urls.py

@ -1,6 +1,7 @@
from django.conf.urls import url
from .views import DashboardView
from .views import DashboardView, NewMembershipView
urlpatterns = [
url(r'^$', DashboardView.as_view()),
url(r'^member/(?P<member_id>[0-9]+)/membership/new/$', NewMembershipView.as_view(), name='new_membership'),
url(r'^$', DashboardView.as_view())
]

39
bikeshop_project/core/views.py

@ -1,7 +1,42 @@
import logging
from django.contrib import messages
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
from django.template.response import TemplateResponse
from django.views.generic import View
from django.views.generic import TemplateView, View
from registration.models import Member
from .forms import MembershipForm, PaymentForm
logger = logging.getLogger(__name__)
class DashboardView(View):
def get(self, request):
return TemplateResponse(request, 'dashboard.html')
return TemplateResponse(request, 'dashboard.html')
class NewMembershipView(TemplateView):
template_name = 'membership_form.html'
def get(self, request, member_id):
membership_form = MembershipForm(initial=dict(member=member_id))
payment_form = PaymentForm()
return self.render_to_response(dict(membership_form=membership_form, payment_form=payment_form))
def post(self, request, member_id):
membership_form = MembershipForm(request.POST, initial=dict(member=member_id))
payment_form = PaymentForm(request.POST)
member = Member.objects.get(id=member_id)
if membership_form.is_valid() and payment_form.is_valid():
new_payment = payment_form.save()
new_membership = membership_form.save()
new_membership.payment = new_payment
new_membership.save()
messages.add_message(request, messages.SUCCESS, 'Successfully created our newest member, {first} {last}'
.format(first=member.first_name, last=member.last_name))
return HttpResponseRedirect(reverse('member_edit', kwargs=dict(member_id=member_id)))
return self.render_to_response(dict(membership_form=membership_form, payment_form=payment_form))

3
bikeshop_project/registration/admin.py

@ -1,3 +1,6 @@
from django.contrib import admin
from .models import Member
# Register your models here.
admin.site.register(Member)

20
bikeshop_project/registration/forms.py

@ -4,24 +4,11 @@ from registration.models import Member
class MemberForm(ModelForm):
# self_ident_other = CharField(required=False, label='Self identification', widget=TextInput(attrs={'class': 'mdl-textfield__input'}))
# gender_other = CharField(required=False, label='Other', widget=TextInput(attrs={'class': 'mdl-textfield__input'}))
# priveleges = BooleanField(label='I acknowledge', widget=CheckboxInput(attrs={'class': 'mdl-checkbox__input'}))
waiver_substitute = BooleanField(label='I have read and agree to the above terms & conditions.', widget=CheckboxInput(attrs={'class': 'mdl-checkbox__input'}))
waiver_substitute = BooleanField(required=False, label='I have read and agree to the above terms & conditions.', widget=CheckboxInput(attrs={'class': 'mdl-checkbox__input'}))
class Meta:
model = Member
self_ident_choices = (
('First Nations; Métis; or Inuit', 'First Nations; Métis; or Inuit'),
('visible minority', 'Visible Minority'),
('caucasian', 'Caucasian'),
('Other', 'Other')
)
gender_choices = (
('male', 'Male'),
('female', 'Female'),
('other', 'other')
)
exclude = ('waiver',)
fields = ['email', 'email_consent', 'first_name', 'last_name', 'preferred_name', 'date_of_birth',
'guardian_name', 'phone', 'street', 'city', 'province', 'country', 'post_code', 'waiver']
@ -40,9 +27,6 @@ class MemberForm(ModelForm):
'country': TextInput(attrs={'class': 'mdl-textfield__input'}),
'post_code': TextInput(attrs={'class': 'mdl-textfield__input',
'pattern': '[A-Za-z][0-9][A-Za-z] [0-9][A-Za-z][0-9]'}),
# 'self_identification': CheckboxSelectMultiple(choices=self_ident_choices,
# attrs={'class': 'mdl-checkbox__input'}),
# 'gender': CheckboxSelectMultiple(choices=gender_choices, attrs={'class': 'mdl-checkbox__input'}),
}
labels = {

22
bikeshop_project/registration/migrations/0005_member_membership.py

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-05-26 01:50
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('core', '0009_remove_membership_member'),
('registration', '0004_auto_20160410_1816'),
]
operations = [
migrations.AddField(
model_name='member',
name='membership',
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='member', to='core.Membership'),
),
]

19
bikeshop_project/registration/migrations/0006_remove_member_membership.py

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-05-31 02:31
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('registration', '0005_member_membership'),
]
operations = [
migrations.RemoveField(
model_name='member',
name='membership',
),
]

198
bikeshop_project/registration/templates/edit_member_form.html

@ -0,0 +1,198 @@
{% extends 'base.html' %}
{% load staticfiles %}
{% block styles %}
<link rel="stylesheet" href="{% static 'vendor/md-date-time-picker/dist/css/mdDateTimePicker.min.css' %}">
{% endblock %}
{% block scripts %}
<script src="{% static 'vendor/moment/min/moment.min.js' %}"></script>
<script src="{% static 'vendor/object.observe/dist/object-observe-lite.min.js' %}"></script>
<script src="{% static 'vendor/draggabilly/dist/draggabilly.pkgd.min.js' %}"></script>
<script src="{% static 'vendor/md-date-time-picker/dist/js/mdDateTimePicker.min.js' %}"></script>
<script>
var dateOfBirth = new mdDateTimePicker.default({
type: 'date',
past: moment().subtract(100, 'years')
});
document.getElementById('{{ form.date_of_birth.id_for_label }}').addEventListener('focus', function() {
dateOfBirth.toggle();
});
Object.observe(dateOfBirth, function(changes) {
var input = document.getElementById('{{ form.date_of_birth.id_for_label }}');
input.value = dateOfBirth.time().format('YYYY-MM-DD');
input.parentNode.classList.add('is-dirty');
var threshold = moment.duration(18, 'years');
var dob = dateOfBirth.time().clone();
if (dob.add(threshold).isAfter(moment())) {
document.getElementById('{{ form.guardian_name.id_for_label }}').disabled = false;
document.getElementById('{{ form.guardian_name.id_for_label }}').parentNode.classList.remove('is-disabled');
} else {
document.getElementById('{{ form.guardian_name.id_for_label }}').disabled = true;
document.getElementById('{{ form.guardian_name.id_for_label }}').parentNode.classList.add('is-disabled');
}
});
var waiverCheckBox = document.getElementById('{{ form.waiver_substitute.id_for_label }}');
var submitButton = document.getElementById('submit');
var requiredCheckboxes = function() {
return waiverCheckBox.checked;
};
waiverCheckBox.addEventListener('change', function() {
if (requiredCheckboxes()) {
submitButton.disabled = false;
}
else {
submitButton.disabled = true;
}
});
// On page load check on the check boxes
if (requiredCheckboxes()) {
submitButton.disabled = false;
}
</script>
{% endblock %}
{% block content %}
<div class="mdl-cell mdl-cell--8-col">
<h1>{{ form.instance.first_name }} {{ form.instance.last_name }}</h1>
<p>
The Bridge City Bicycle Co-operative (herein referred to as The BCBC and The Community) is a nonprofit,
community bicycle repair education and resource co-operative. We offer our members nonjudgmental repair
space, tools and instruction during business hours (hours on website) by donation, and educational
workshops. We also offer reconditioned/recycled low cost bikes and parts for sale.
The BCBC is operated by volunteers; a medley of professionals, students, bike enthusiasts, activists,
and other community members who share a love for cycling in Saskatoon. Membership is open to all
individuals and costs $20 per year. A receipt will be issued to you once your membership fee has been paid.
</p>
<form method="post">
{% csrf_token %}
{% if form.non_field_errors %}
<div>
<span class="error">{{ form.errors }}</span>
</div>
{% endif %}
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label {% if form.email.errors %}is-invalid{% endif %}">
{{ form.email }}
<label class="mdl-textfield__label" for="{{ form.email.id_for_label }}">{{ form.email.label }}</label>
{% if form.email.errors %}
<span class="mdl-textfield__error">{{ form.email.errors }}</span>
{% else %}
<span class="mdl-textfield__error">Invalid email.</span>
{% endif %}
</div>
<div>
<label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect" for="{{ form.email_consent.id_for_label }}">
{{ form.email_consent }}
<span class="mdl-checkbox__label">{{ form.email_consent.label }}</span>
</label>
</div>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label {% if form.first_name.errors %}is-invalid{% endif %}">
{{ form.first_name }}
<label class="mdl-textfield__label" for="{{ form.first_name.id_for_label }}">{{ form.first_name.label }}</label>
{% if form.first_name.errors %}
<span class="mdl-textfield__error">{{ form.first_name.errors }}</span>
{% else %}
<span class="mdl-textfield__error">Name too long.</span>
{% endif %}
</div>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label {% if form.last_name.errors %}is-invalid{% endif %}">
{{ form.last_name }}
<label class="mdl-textfield__label" for="{{ form.last_name.id_for_label }}">{{ form.last_name.label }}</label>
{% if form.last_name.errors %}
<span class="mdl-textfield__error">{{ form.last_name.errors }}</span>
{% else %}
<span class="mdl-textfield__error">Name too long.</span>
{% endif %}
</div>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label {% if form.preferred_name.errors %}is-invalid{% endif %}">
{{ form.preferred_name }}
<label class="mdl-textfield__label" for="{{ form.preferred_name.id_for_label }}">{{ form.preferred_name.label }}</label>
{% if form.preferred_name.errors %}
<span class="mdl-textfield__error">{{ form.preferred_name.errors }}</span>
{% else %}
<span class="mdl-textfield__error">Name too long.</span>
{% endif %}
</div>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label {% if form.date_of_birth.errors %}is-invalid{% endif %}">
{{ form.date_of_birth }}
<label class="mdl-textfield__label" for="{{ form.date_of_birth.id_for_label }}">{{ form.date_of_birth.label }}</label>
{% if form.date_of_birth.errors %}
<span class="mdl-textfield__error">{{ form.date_of_birth.errors }}</span>
{% else %}
<span class="mdl-textfield__error">Incorrect date.</span>
{% endif %}
</div>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label {% if form.guardian_name.errors %}is-invalid{% endif %}">
{{ form.guardian_name }}
<label class="mdl-textfield__label" for="{{ form.guardian_name.id_for_label }}">{{ form.guardian_name.label }}</label>
{% if form.guardian_name.errors %}
<span class="mdl-textfield__error">{{ form.guardian_name.errors }}</span>
{% else %}
<span class="mdl-textfield__error">Name too long.</span>
{% endif %}
</div>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label {% if form.phone.errors %}is-invalid{% endif %}">
{{ form.phone }}
<label class="mdl-textfield__label" for="{{ form.phone.id_for_label }}">{{ form.phone.label }}</label>
{% if form.phone.errors %}
<span class="mdl-textfield__error">{{ form.phone.errors }}</span>
{% else %}
<span class="mdl-textfield__error">Digits only.</span>
{% endif %}
</div>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label {% if form.post_code.errors %}is-invalid{% endif %}">
{{ form.post_code }}
<label class="mdl-textfield__label" for="{{ form.post_code.id_for_label }}">{{ form.post_code.label }}</label>
{% if form.post_code.errors %}
<span class="mdl-textfield__error">{{ form.post_code.errors }}</span>
{% else %}
<span class="mdl-textfield__error">Format: A0A 0A0</span>
{% endif %}
</div>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label {% if form.street.errors %}is-invalid{% endif %}">
{{ form.street }}
<label class="mdl-textfield__label" for="{{ form.street.id_for_label }}">{{ form.street.label }}</label>
{% if form.street.errors %}
<span class="mdl-textfield__error">{{ form.street.errors }}</span>
{% endif %}
</div>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label {% if form.city.errors %}is-invalid{% endif %}">
{{ form.city }}
<label class="mdl-textfield__label" for="{{ form.city.id_for_label }}">{{ form.city.label }}</label>
{% if form.city.errors %}
<span class="mdl-textfield__error">{{ form.city.errors }}</span>
{% endif %}
</div>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label {% if form.province.errors %}is-invalid{% endif %}">
{{ form.province }}
<label class="mdl-textfield__label" for="{{ form.province.id_for_label }}">{{ form.province.label }}</label>
{% if form.province.errors %}
<span class="mdl-textfield__error">{{ form.province.errors }}</span>
{% endif %}
</div>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label {% if form.country.errors %}is-invalid{% endif %}">
{{ form.country }}
<label class="mdl-textfield__label" for="{{ form.country.id_for_label }}">{{ form.country.label }}</label>
{% if form.country.errors %}
<span class="mdl-textfield__error">{{ form.country.errors }}</span>
{% endif %}
</div>
<div>
<button id="submit" type="submit" class="mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect mdl-button--colored">Submit</button>
</div>
</form>
</div>
{% if not form.instance.membership %}
<div class="mdl-cell mdl-cell--8-col">
<h3>No membership found.</h3>
<a class="mdl-button mdl-js-button mdl-button--flat mdl-js-ripple-effect mdl-button--colored" href="{% url 'new_membership' member_id=member.id %}">Add membership</a>
</div>
{% endif %}
{% endblock %}

57
bikeshop_project/registration/templates/member_form.html

@ -2,16 +2,16 @@
{% load staticfiles %}
{% block styles %}
<link rel="stylesheet" href="{% static 'vendor/md-date-time-picker/dist/css/md-date-time-picker.min.css' %}">
<link rel="stylesheet" href="{% static 'vendor/md-date-time-picker/dist/css/mdDateTimePicker.min.css' %}">
{% endblock %}
{% block scripts %}
<script src="{% static 'vendor/moment/min/moment.min.js' %}"></script>
<script src="{% static 'vendor/object.observe/dist/object-observe-lite.min.js' %}"></script>
<script src="{% static 'vendor/draggabilly/dist/draggabilly.pkgd.min.js' %}"></script>
<script src="{% static 'vendor/md-date-time-picker/dist/js/md-date-time-picker.js' %}"></script>
<script src="{% static 'vendor/md-date-time-picker/dist/js/mdDateTimePicker.min.js' %}"></script>
<script>
var dateOfBirth = new mdDateTimePicker({
var dateOfBirth = new mdDateTimePicker.default({
type: 'date',
past: moment().subtract(100, 'years')
});
@ -20,11 +20,11 @@
});
Object.observe(dateOfBirth, function(changes) {
var input = document.getElementById('{{ form.date_of_birth.id_for_label }}');
input.value = dateOfBirth.time().format('YYYY-MM-DD');
input.value = dateOfBirth.time.format('YYYY-MM-DD');
input.parentNode.classList.add('is-dirty');
var threshold = moment.duration(18, 'years');
var dob = dateOfBirth.time().clone();
var dob = dateOfBirth.time.clone();
if (dob.add(threshold).isAfter(moment())) {
document.getElementById('{{ form.guardian_name.id_for_label }}').disabled = false;
@ -75,7 +75,9 @@
{% if form.non_field_errors %}
<div>
<span class="error">{{ form.errors }}</span>
{% for errors in form.non_field_errors %}
<span class="mdl-textfield__error">{{ error }}</span>
{% endfor %}
</div>
{% endif %}
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label {% if form.email.errors %}is-invalid{% endif %}">
@ -184,48 +186,7 @@
<span class="mdl-textfield__error">{{ form.country.errors }}</span>
{% endif %}
</div>
{# <div class="">#}
{# <h2 class="template__header mdl-typography--title">Voluntary Self Identification</h2>#}
{# <p>We want to make sure that all members of our community, regardless of race, ethnicity, and gender#}
{# are able to participate fully in the BCBC. Please share information about your race and/or#}
{# ethnicity so that we can track how well we are including all communities and whether there may be#}
{# barriers to certain groups’ participation. Thank you! Do you identify as: (In each category, check#}
{# all that apply)</p>#}
{# {% for checkbox in form.self_identification %}#}
{# <label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect" for="{{ checkbox.id_for_label }}">#}
{# {{ checkbox }}#}
{# <span class="mdl-checkbox__label">{{ checkbox.label }}</span>#}
{# </label>#}
{# {% endfor %}#}
{# {% if form.self_identification.errors %}#}
{# <span class="mdl-textfield__error">{{ form.self_identification.errors }}</span>#}
{# {% else %}#}
{# <span class="mdl-textfield__error">Hmm</span>#}
{# {% endif %}#}
{# </div>#}
{# <div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label {% if form.gender_other.errors %}is-invalid{% endif %}">#}
{# {{ form.self_ident_other }}#}
{# <label class="mdl-textfield__label" for="{{ form.self_ident_other.id_for_label }}">{{ form.self_ident_other.label }}</label>#}
{# {% if form.self_ident_other.errors %}#}
{# <span class="mdl-textfield__error">{{ form.self_ident_other.errors }}</span>#}
{# {% endif %}#}
{# </div>#}
{# <div class="">#}
{# <h3 class="template__header mdl-typography--body-2">Gender Identification</h3>#}
{# {% for checkbox in form.gender %}#}
{# <label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect" for="{{ checkbox.id_for_label }}">#}
{# {{ checkbox }}#}
{# <span class="mdl-checkbox__label">{{ checkbox.label }}</span>#}
{# </label>#}
{# {% endfor %}#}
{# </div>#}
{# <div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label {% if form.gender_other.errors %}is-invalid{% endif %}">#}
{# {{ form.gender_other }}#}
{# <label class="mdl-textfield__label" for="{{ form.gender_other.id_for_label }}">{{ form.gender_other.label }}</label>#}
{# {% if form.gender_other.errors %}#}
{# <span class="mdl-textfield__error">{{ form.gender_other.errors }}</span>#}
{# {% endif %}#}
{# </div>#}
<div class="">
<h6 class="template__header mdl-typography--title">Liability Waiver</h6>
<p><strong>Children under the age of 18 must have a parent or guardian co-sign the following waiver form.

1
bikeshop_project/registration/urls.py

@ -3,4 +3,5 @@ from django.conf.urls import url
from .views import MemberFormView
urlpatterns = [
url(r'^new/$', MemberFormView.as_view(), name='signup'),
url(r'^edit/(?P<member_id>[0-9]+)/$', MemberFormView.as_view(), name='member_edit')
]

44
bikeshop_project/registration/views.py

@ -1,22 +1,48 @@
from django.contrib import messages
from django.http import HttpResponseRedirect
from django.template.response import TemplateResponse
from django.utils import timezone
from django.views.generic import View
from django.core.urlresolvers import reverse
from .forms import MemberForm
from .models import Member
import logging
logger = logging.getLogger('bikeshop')
class MemberFormView(View):
def get(self, request):
form = MemberForm()
context = {'form': form}
return TemplateResponse(request, 'member_form.html', context=context)
def get(self, request, member_id=None):
try:
logger.debug(member_id)
member = Member.objects.get(id=member_id)
form = MemberForm(instance=member)
except Member.DoesNotExist:
form = MemberForm()
member = None
def post(self, request):
form = MemberForm(request.POST)
context = dict(form=form)
if member:
context['member'] = member
return TemplateResponse(request, 'edit_member_form.html', context=context)
return TemplateResponse(request, 'member_form.html', context=context)
def post(self, request, member_id=None):
try:
logger.debug(member_id)
member = Member.objects.get(id=member_id)
form = MemberForm(request.POST, instance=member)
except Member.DoesNotExist:
member = None
form = MemberForm(request.POST)
logger.debug(form)
if form.is_valid():
form.save()
return TemplateResponse(request, 'member_created.html')
member_instance = form.save()
logger.debug(member_instance)
return HttpResponseRedirect(reverse('member_edit', kwargs=dict(member_id=member_instance.id)))
logger.debug(form)
context = {'form': form}
if member:
context['member'] = member
return TemplateResponse(request, 'member_form.html', context=context)

3
bower.json

@ -17,6 +17,7 @@
"tests"
],
"dependencies": {
"material-design-lite": "^1.1.3"
"material-design-lite": "^1.1.3",
"md-date-time-picker": "https://github.com/puranjayjain/md-date-time-picker.git#master"
}
}

1
provision/roles/supervisor/development/supervisor-program.conf

@ -8,3 +8,4 @@ autostart=true
autorestart=true
redirect_stderr=true
user=vagrant
startretries=100000

Loading…
Cancel
Save