Fix "add many" and csv import and export
This commit is contained in:
+7
-1
@@ -1,6 +1,6 @@
|
|||||||
from django import forms
|
from django import forms
|
||||||
|
|
||||||
from members.models import Member, Payment
|
from members.models import Member, Payment, Request
|
||||||
|
|
||||||
|
|
||||||
class MemberForm(forms.ModelForm):
|
class MemberForm(forms.ModelForm):
|
||||||
@@ -15,3 +15,9 @@ class PaymentForm(forms.ModelForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Payment
|
model = Payment
|
||||||
fields = ['date', 'source', 'member']
|
fields = ['date', 'source', 'member']
|
||||||
|
|
||||||
|
class ApplicationForm(forms.ModelForm):
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Request
|
||||||
|
fields = ['first_name', 'last_name', 'email', 'AYY', 'jas', 'POR']
|
||||||
+60
-1
@@ -3,6 +3,11 @@ from django.utils import timezone
|
|||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
import csv
|
||||||
|
import logging
|
||||||
|
|
||||||
|
memberlogger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class BaseMember(models.Model):
|
class BaseMember(models.Model):
|
||||||
'''
|
'''
|
||||||
@@ -21,6 +26,41 @@ class BaseMember(models.Model):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "{} {}, {}".format(self.last_name, self.first_name, self.email)
|
return "{} {}, {}".format(self.last_name, self.first_name, self.email)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_csv(data):
|
||||||
|
print("Imported CSV data: {}".format(data))
|
||||||
|
clean_data = data.strip().split('\n')
|
||||||
|
csv_reader = csv.reader(clean_data)
|
||||||
|
|
||||||
|
members = []
|
||||||
|
for line in csv_reader:
|
||||||
|
try:
|
||||||
|
line = list(map(lambda x: x.strip(), line))
|
||||||
|
print(line)
|
||||||
|
|
||||||
|
member = Member.from_array([
|
||||||
|
line[0], line[1], line[2], line[3],
|
||||||
|
bool(int(line[4])), bool(int(line[5]))
|
||||||
|
])
|
||||||
|
members.append(member)
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
|
for member in members:
|
||||||
|
member.save()
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def as_array(self):
|
||||||
|
return [
|
||||||
|
self.first_name,
|
||||||
|
self.last_name,
|
||||||
|
self.email,
|
||||||
|
self.POR,
|
||||||
|
int(self.AYY),
|
||||||
|
int(self.jas)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class Request(BaseMember):
|
class Request(BaseMember):
|
||||||
'''
|
'''
|
||||||
@@ -28,6 +68,11 @@ class Request(BaseMember):
|
|||||||
'''
|
'''
|
||||||
submitted = models.DateTimeField(default=timezone.now)
|
submitted = models.DateTimeField(default=timezone.now)
|
||||||
|
|
||||||
|
def to_member(self):
|
||||||
|
member = Member.from_array(self.as_array())
|
||||||
|
|
||||||
|
return member
|
||||||
|
|
||||||
|
|
||||||
class Payment(models.Model):
|
class Payment(models.Model):
|
||||||
'''
|
'''
|
||||||
@@ -50,4 +95,18 @@ class Member(BaseMember):
|
|||||||
'''
|
'''
|
||||||
Member model represets one member on the registry.
|
Member model represets one member on the registry.
|
||||||
'''
|
'''
|
||||||
created = models.DateTimeField(default=timezone.now)
|
created = models.DateTimeField(default=timezone.now)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_array(array):
|
||||||
|
if len(array) != 6:
|
||||||
|
raise Exception("Invalid array length for member instantiation")
|
||||||
|
|
||||||
|
return Member.objects.create(
|
||||||
|
first_name=array[0],
|
||||||
|
last_name=array[1],
|
||||||
|
email=array[2],
|
||||||
|
POR=array[3],
|
||||||
|
AYY=bool(array[4]),
|
||||||
|
jas=bool(array[5]),
|
||||||
|
)
|
||||||
@@ -206,4 +206,10 @@ input {
|
|||||||
|
|
||||||
.readonly {
|
.readonly {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.large-textarea {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
height: 10rem !important;
|
||||||
}
|
}
|
||||||
@@ -1,40 +1,24 @@
|
|||||||
{% extends "members_base.html" %}
|
{% extends "members_base.html" %}
|
||||||
|
|
||||||
|
{% load i18n %}
|
||||||
|
{% load bootstrap3 %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<script>
|
<div>
|
||||||
var memberId = {{ member_id }};
|
<div>
|
||||||
</script>
|
<h3>{% trans "Edit application" %}</h3>
|
||||||
<div ng-controller="applEditController">
|
</div>
|
||||||
<h1> Muokkaa hakemuksen jäsentietoja </h1>
|
|
||||||
|
|
||||||
<div id="input_form">
|
<div id="input_form">
|
||||||
<form name="applicationForm">
|
<form name="applicationForm" action="/members/accept_application" method="post" class="form">{% csrf_token %}
|
||||||
<div class="form-group">
|
<input type="hidden" name="id" value="{{ application_id }}">
|
||||||
<label>Etunimi: </label>
|
{% bootstrap_form form %}
|
||||||
<input id="firstNameField" required type="text" placeholder="Sähkö" class="form-control" ng-model="member.first_name"></input>
|
{% buttons %}
|
||||||
</div>
|
<button type="submit" class="btn btn-primary">
|
||||||
<div class="form-group">
|
{% trans "Accept" %}
|
||||||
<label>Sukunimi: </label>
|
</button>
|
||||||
<input id="lastNameField" required type="text" placeholder="Insinööri" class="form-control" ng-model="member.last_name"></input>
|
<a href="/members/delete_application_confirm/{{ application_id }}" class="btn btn-danger">{% trans "Decline" %}</a>
|
||||||
</div>
|
{% endbuttons %}
|
||||||
<div class="form-group">
|
|
||||||
<label>Sähköposti: </label>
|
|
||||||
<input id="emailField" required type="text" placeholder="sahko.insinoori@aalto.fi" class="form-control" ng-model="member.email"></input>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label>AYY jäsen: </label>
|
|
||||||
<input type="checkbox" id="AYY" ng-model="member.AYY"></input>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label>JAS-listaan: </label>
|
|
||||||
<input type="checkbox" id="jas" ng-model="member.jas"></input>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label>Asuinkunta: </label>
|
|
||||||
<input id="PORField" required type="text" placeholder="Otaniemi" class="form-control" ng-model="member.POR"></input>
|
|
||||||
</div>
|
|
||||||
<button class="btn btn-success" ng-click="applicationForm.$valid && sendappl()" type="submit" id="sendmember">Tallenna</button>
|
|
||||||
<button class="btn btn-warning" ng-click="cancelappl()" type="submit" id="sendmember">Peruuta</button>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,31 +1,36 @@
|
|||||||
{% extends "members_base.html" %}
|
{% extends "members_base.html" %}
|
||||||
|
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container" style="align:middle;" ng-controller="addManyController">
|
<div>
|
||||||
<div class="instructions">
|
<div>
|
||||||
<h3> Lisää useampi jäsen </h3>
|
<h3> Lisää useampi jäsen </h3>
|
||||||
<h5>
|
|
||||||
Syötä jäsentiedot pilkuilla erotettuina formaatissa <b>Etunimi, Sukunimi, Sähköposti, Asuinkunta, AYY-jäsen(0 tai 1), JAS-listaan(0 tai 1)</b>
|
|
||||||
<br>
|
|
||||||
<br>
|
|
||||||
Erota jäsenet rivinvaihdoilla toisistaan.
|
|
||||||
</h5>
|
|
||||||
<!--<img src="/static/img/members_example.png" alt="exampleImg" style="max-width:100%; height:auto; margin-bottom:10px; opacity:0.7;">-->
|
|
||||||
</div>
|
</div>
|
||||||
<form name="memberTextForm">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-4">
|
|
||||||
<textarea ng-model="memberData" rows=5 cols=80 placeholder="Salli, Vahvonen, salli.vahvonen@notmail.dom, Kerava, 0, 0" style="border:solid 3px #c9c9c9; transition:box-shadow 0.3s, border 0.3s; align:middle;"></textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-4">
|
|
||||||
<button ng-click="sendCSV()" type="submit" class="btn btn-success" id="sendMembers">Lähetä</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="footer-div"/>
|
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
{% blocktrans %}
|
||||||
|
Enter member information in CSV format, separate members on separate lines.
|
||||||
|
{% endblocktrans %}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
{% blocktrans %}
|
||||||
|
first_name, last_name, email_address and place_of_origin should be given string values.
|
||||||
|
ayy_member and jas_recipient should be given the value 0 (off) or 1 (on).
|
||||||
|
{% endblocktrans %}
|
||||||
|
</p>
|
||||||
|
<h4>{% trans "Syntax" %}</h4>
|
||||||
|
<pre>first_name, last_name, email_address, place_of_origin, ayy_member, jas_recipient</pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<form name="memberTextForm" action="/members/import_csv" method="POST">{% csrf_token %}
|
||||||
|
<div>
|
||||||
|
<textarea name="textfield" class="form-control large-textarea" placeholder="Teemu, Teekkari, teemu.teekkari@notmail.dom, Otaniemi, 0, 0"></textarea>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button type="submit" class="btn btn-primary">{% trans "Send" %}</button>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
@@ -20,49 +20,7 @@
|
|||||||
{{ table|safe }}
|
{{ table|safe }}
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<a id="download-csv" class="btn btn-info">{% trans "Download CSV" %}</a>
|
<a href="/members/export_csv" class="btn btn-info">{% trans "Download CSV" %}</a>
|
||||||
</div>
|
|
||||||
|
|
||||||
<form action="/members/list" method="POST" id="collapse-filters" class="collapse filter-form">
|
|
||||||
<div class="filter-row">
|
|
||||||
<div class="filter-group">
|
|
||||||
<div class="filter-field">
|
|
||||||
<input class="form-control" type="text" id="search-filter" placeholder="{% trans "Search" %}" >
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="filter-group">
|
|
||||||
<div class="filter-field">
|
|
||||||
<h5>{% trans "Added after" %}</h5>
|
|
||||||
<input type="datetime-local" id="addedAfterDatePicker">
|
|
||||||
</div>
|
|
||||||
<div class="filter-field">
|
|
||||||
<h5>{% trans "Added before" %}</h5>
|
|
||||||
<input type="datetime-local" class="filter-field" id="addedBeforeDatePicker">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="filter-group">
|
|
||||||
<div class="filter-field">
|
|
||||||
<h5>{% trans "Paid after" %}</h5>
|
|
||||||
<input type="datetime-local" class="filter-field" id="paidAfterDatePicker">
|
|
||||||
</div>
|
|
||||||
<div class="filter-field">
|
|
||||||
<h5>{% trans "Paid before" %}</h5>
|
|
||||||
<input type="datetime-local" class="filter-field" id="paidBeforeDatePicker">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="filter-group">
|
|
||||||
<div class="filter-field">
|
|
||||||
<input type="button" value="{% trans "Filter" %}" class="filter-button btn btn-success">
|
|
||||||
<input type="button" value="{% trans "Reset" %}" class="filter-button btn btn-warning">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<a id="filter-collapser" href="#collapse-filters" data-toggle="collapse" class="btn btn-info">
|
|
||||||
{% trans "Show filters" %}
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
@@ -15,51 +15,5 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{{ table|safe }}
|
{{ table|safe }}
|
||||||
|
|
||||||
<div>
|
|
||||||
<a id="download-csv" class="btn btn-info">{% trans "Download CSV" %}</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form action="/members/list" method="POST" id="collapse-filters" class="collapse filter-form">
|
|
||||||
<div class="filter-row">
|
|
||||||
<div class="filter-group">
|
|
||||||
<div class="filter-field">
|
|
||||||
<input class="form-control" type="text" id="search-filter" placeholder="{% trans "Search" %}" >
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="filter-group">
|
|
||||||
<div class="filter-field">
|
|
||||||
<h5>{% trans "Added after" %}</h5>
|
|
||||||
<input type="datetime-local" id="addedAfterDatePicker">
|
|
||||||
</div>
|
|
||||||
<div class="filter-field">
|
|
||||||
<h5>{% trans "Added before" %}</h5>
|
|
||||||
<input type="datetime-local" class="filter-field" id="addedBeforeDatePicker">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="filter-group">
|
|
||||||
<div class="filter-field">
|
|
||||||
<h5>{% trans "Paid after" %}</h5>
|
|
||||||
<input type="datetime-local" class="filter-field" id="paidAfterDatePicker">
|
|
||||||
</div>
|
|
||||||
<div class="filter-field">
|
|
||||||
<h5>{% trans "Paid before" %}</h5>
|
|
||||||
<input type="datetime-local" class="filter-field" id="paidBeforeDatePicker">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="filter-group">
|
|
||||||
<div class="filter-field">
|
|
||||||
<input type="button" value="{% trans "Filter" %}" class="filter-button btn btn-success">
|
|
||||||
<input type="button" value="{% trans "Reset" %}" class="filter-button btn btn-warning">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<a id="filter-collapser" href="#collapse-filters" data-toggle="collapse" class="btn btn-info">
|
|
||||||
{% trans "Show filters" %}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
+13
-1
@@ -2,7 +2,8 @@ from django.conf.urls import url
|
|||||||
from django.views.generic.base import RedirectView
|
from django.views.generic.base import RedirectView
|
||||||
|
|
||||||
# members
|
# members
|
||||||
from members.views import member_list, payment_add, payment_submit
|
from members.views import member_list, payment_add, payment_submit, application_delete_confirm, application_delete, \
|
||||||
|
application_accept, import_csv, export_csv
|
||||||
from members.views import settings_page, payment_edit
|
from members.views import settings_page, payment_edit
|
||||||
from members.views import payment_delete_confirm
|
from members.views import payment_delete_confirm
|
||||||
from members.views import payment_delete, payment_update
|
from members.views import payment_delete, payment_update
|
||||||
@@ -54,6 +55,8 @@ urlpatterns = [
|
|||||||
url(r'^submit_payment$', payment_submit),
|
url(r'^submit_payment$', payment_submit),
|
||||||
url(r'^update_payment$', payment_update),
|
url(r'^update_payment$', payment_update),
|
||||||
url(r'^delete_payment$', payment_delete),
|
url(r'^delete_payment$', payment_delete),
|
||||||
|
url(r'^accept_application$', application_accept),
|
||||||
|
url(r'^delete_application$', application_delete),
|
||||||
|
|
||||||
# the actual member application form
|
# the actual member application form
|
||||||
url(r'^application/$', application_form),
|
url(r'^application/$', application_form),
|
||||||
@@ -61,6 +64,9 @@ urlpatterns = [
|
|||||||
# success page for the application
|
# success page for the application
|
||||||
url(r'^application/success$', application_form_success),
|
url(r'^application/success$', application_form_success),
|
||||||
|
|
||||||
|
# delete confirmation view for applications
|
||||||
|
url(r'^delete_application_confirm/(?P<index>\d+)$', application_delete_confirm),
|
||||||
|
|
||||||
# list all payment events
|
# list all payment events
|
||||||
url(r'^payments$', payment_list),
|
url(r'^payments$', payment_list),
|
||||||
|
|
||||||
@@ -76,6 +82,12 @@ urlpatterns = [
|
|||||||
# settings page
|
# settings page
|
||||||
url(r'^settings$', settings_page),
|
url(r'^settings$', settings_page),
|
||||||
|
|
||||||
|
# send CSV member data by POST
|
||||||
|
url(r'^import_csv', import_csv),
|
||||||
|
|
||||||
|
# download CSV member data
|
||||||
|
url(r'^export_csv', export_csv),
|
||||||
|
|
||||||
# favourite icon
|
# favourite icon
|
||||||
url(r'^favicon\.ico$', favicon_view),
|
url(r'^favicon\.ico$', favicon_view),
|
||||||
]
|
]
|
||||||
|
|||||||
+71
-21
@@ -11,9 +11,10 @@ import json
|
|||||||
import requests
|
import requests
|
||||||
import logging
|
import logging
|
||||||
import html
|
import html
|
||||||
|
import csv
|
||||||
|
|
||||||
from members.models import Member, Request, Payment
|
from members.models import Member, Request, Payment
|
||||||
from members.forms import MemberForm, PaymentForm
|
from members.forms import MemberForm, PaymentForm, ApplicationForm
|
||||||
|
|
||||||
# Logger function, you can use the same idea when implementing other loggers to other apps
|
# Logger function, you can use the same idea when implementing other loggers to other apps
|
||||||
from members.tables import MemberTable, PaymentTable, RequestTable
|
from members.tables import MemberTable, PaymentTable, RequestTable
|
||||||
@@ -169,7 +170,7 @@ def member_delete(request, *args, **kwargs):
|
|||||||
try:
|
try:
|
||||||
id = request.POST['id']
|
id = request.POST['id']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return HttpResponse(401)
|
return render(request, 'error.html', {'error': _('No member id specified')})
|
||||||
|
|
||||||
try:
|
try:
|
||||||
member = Member.objects.get(id=id)
|
member = Member.objects.get(id=id)
|
||||||
@@ -224,7 +225,61 @@ def application_edit(request, *args, **kwargs):
|
|||||||
if i is None:
|
if i is None:
|
||||||
return render(request, 'error.html', {'error': _('No application id specified')})
|
return render(request, 'error.html', {'error': _('No application id specified')})
|
||||||
else:
|
else:
|
||||||
return render(request, 'application_edit.html', {'member_id': i})
|
application = Request.objects.get(id=i)
|
||||||
|
form = ApplicationForm(instance=application)
|
||||||
|
return render(request, 'application_edit.html', {'application_id': i, 'form': form})
|
||||||
|
|
||||||
|
|
||||||
|
@ensure_csrf_cookie
|
||||||
|
@require_http_methods(["POST"])
|
||||||
|
@permission_required('members.change_member', login_url='/login')
|
||||||
|
def application_accept(request, *args, **kwargs):
|
||||||
|
form = ApplicationForm(request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
id = request.POST['id']
|
||||||
|
application = Request.objects.get(id=id)
|
||||||
|
|
||||||
|
member = application.to_member()
|
||||||
|
member.save()
|
||||||
|
application.delete()
|
||||||
|
|
||||||
|
memberlogger.info("Accepted application in member register with the following info: {}".format(form))
|
||||||
|
notification = "{} {}.".format(_("Successfully accepted application"), str(application))
|
||||||
|
return HttpResponseRedirect('/members/list?notification={}'.format(html.escape(notification)))
|
||||||
|
else:
|
||||||
|
return render(request, 'error.html', {'error': _('Could not accept application object')})
|
||||||
|
|
||||||
|
|
||||||
|
@ensure_csrf_cookie
|
||||||
|
@require_http_methods(["POST"])
|
||||||
|
@permission_required('members.change_member', login_url='/login')
|
||||||
|
def application_delete(request, *args, **kwargs):
|
||||||
|
try:
|
||||||
|
id = request.POST['id']
|
||||||
|
except KeyError:
|
||||||
|
return render(request, 'error.html', {'error': _('No application id specified')})
|
||||||
|
|
||||||
|
try:
|
||||||
|
application = Request.objects.get(id=id)
|
||||||
|
notification = "{} {}.".format(_("Successfully deleted application"), str(application))
|
||||||
|
application.delete()
|
||||||
|
memberlogger.info("Delete application in member register with the following id: {}".format(id))
|
||||||
|
return HttpResponseRedirect('/members/applications?notification={}'.format(html.escape(notification)))
|
||||||
|
except:
|
||||||
|
return render(request, 'error.html', {'error': _('Could not delete application object')})
|
||||||
|
|
||||||
|
|
||||||
|
@ensure_csrf_cookie
|
||||||
|
@require_http_methods(["GET"])
|
||||||
|
@permission_required('members.change_member', login_url='/login')
|
||||||
|
def application_delete_confirm(request, *args, **kwargs):
|
||||||
|
i = kwargs.pop('index', None)
|
||||||
|
if i is None:
|
||||||
|
return render(request, 'error.html', {'error': _('No application id specified')})
|
||||||
|
else:
|
||||||
|
application = Request.objects.get(id=i)
|
||||||
|
form = ApplicationForm(instance=application)
|
||||||
|
return render(request, 'application_delete_confirm.html', {'application_id': i, 'form': form})
|
||||||
|
|
||||||
|
|
||||||
@ensure_csrf_cookie
|
@ensure_csrf_cookie
|
||||||
@@ -315,7 +370,7 @@ def payment_delete(request, *args, **kwargs):
|
|||||||
try:
|
try:
|
||||||
id = request.POST['id']
|
id = request.POST['id']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return HttpResponse(401)
|
return render(request, 'error.html', {'error': _('No payment id specified')})
|
||||||
|
|
||||||
try:
|
try:
|
||||||
payment = Payment.objects.get(id=id)
|
payment = Payment.objects.get(id=id)
|
||||||
@@ -355,29 +410,25 @@ def settings_page(request, *args, **kwargs):
|
|||||||
@ensure_csrf_cookie
|
@ensure_csrf_cookie
|
||||||
@require_http_methods(["POST"])
|
@require_http_methods(["POST"])
|
||||||
@permission_required('members.change_member', login_url='/login')
|
@permission_required('members.change_member', login_url='/login')
|
||||||
def csv_import(request, *args, **kwargs):
|
def import_csv(request, *args, **kwargs):
|
||||||
data = request.body.decode("utf-8")
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
payload = json.loads(data)
|
data = request.POST['textfield']
|
||||||
except:
|
except:
|
||||||
return HttpResponse(json.dumps({'error': 'Malformed request'}), 400)
|
return render(request, 'error.html', {'error': _('Missing "textfield" POST request field')})
|
||||||
|
|
||||||
resp_data = Member.import_csv(payload['csv'])
|
success = Member.from_csv(data)
|
||||||
resp = HttpResponse(json.dumps(resp_data))
|
if success:
|
||||||
if resp_data['status'] == 'failure':
|
memberlogger.info('Imported CSV data:\n'.format(data))
|
||||||
resp.status_code = 400
|
notification = "{}.".format(_("Successfully imported multiple members"))
|
||||||
memberlogger.warning('POST request failed with status code {}'.format(resp.status_code))
|
return HttpResponseRedirect('/members/list?notification={}'.format(html.escape(notification)))
|
||||||
|
else:
|
||||||
return resp
|
return render(request, 'error.html', {'error': _('Failed to import members')})
|
||||||
|
|
||||||
|
|
||||||
@ensure_csrf_cookie
|
@ensure_csrf_cookie
|
||||||
@require_http_methods(["GET"])
|
@require_http_methods(["GET"])
|
||||||
@permission_required('members.change_member', login_url='/login')
|
@permission_required('members.change_member', login_url='/login')
|
||||||
def export_csv(request, *args, **kwargs):
|
def export_csv(request, *args, **kwargs):
|
||||||
import csv
|
|
||||||
|
|
||||||
response = HttpResponse()
|
response = HttpResponse()
|
||||||
response['Content-type'] = 'text/csv'
|
response['Content-type'] = 'text/csv'
|
||||||
response['Accept'] = 'text/csv'
|
response['Accept'] = 'text/csv'
|
||||||
@@ -385,9 +436,8 @@ def export_csv(request, *args, **kwargs):
|
|||||||
writer = csv.writer(response, csv.excel)
|
writer = csv.writer(response, csv.excel)
|
||||||
response.write(u'\ufeff'.encode('utf8')) # BOM (optional...Excel needs it to open UTF-8 file properly)
|
response.write(u'\ufeff'.encode('utf8')) # BOM (optional...Excel needs it to open UTF-8 file properly)
|
||||||
for obj in Member.objects.all():
|
for obj in Member.objects.all():
|
||||||
data = obj.get_dict()
|
data = obj.as_array()
|
||||||
field_list = map(lambda s: str(data[s]),
|
field_list = map(lambda d: str(d), data)
|
||||||
['id', 'first_name', 'last_name', 'email', 'POR', 'AYY', 'jas', 'created', 'paid'])
|
|
||||||
|
|
||||||
writer.writerow(field_list)
|
writer.writerow(field_list)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user