diff --git a/examples/members.txt b/examples/members.txt index 67eb1ee..87969b0 100644 --- a/examples/members.txt +++ b/examples/members.txt @@ -88,3 +88,15 @@ POST /members/api/request/:id //reject member request (== delete request and delete member) DELETE /members/api/request/:id + + +// mass import from csv +POST /members/api/csvimport +//csvformat first_name,last_name,email,POR,AYY,JAS +// example data +Pekka,Pöytä,pekka.p.pouta@mosh.pit,Tuska,1,0 + +// example response on success +{"status": "success", "errors": []} +// example response on failure (code will be 400) +{"status": "failure", "errors": ["failure adding item Pekka, P\u00f6yt\u00e42, pekka.p.pouta@mosh.pit, Tuska, Eip"]} diff --git a/members/models.py b/members/models.py index 436a73d..97398e0 100644 --- a/members/models.py +++ b/members/models.py @@ -1,5 +1,7 @@ from django.db import models from django.utils import timezone +from io import StringIO +import csv class Member(models.Model): ''' @@ -45,9 +47,33 @@ class Member(models.Model): except KeyError: pass self.save() + @classmethod + def import_csv(cls, csv_string): + reader = csv.reader(StringIO(csv_string.strip())) + response = {"status": "success", "errors": []}; + try: + data = list(reader) + except ValueError: + return {"status": "failure", "errors": ["could not parse csv file"]} + for row in data: + try: + obj = cls.objects.create( + first_name=row[0], + last_name=row[1], + email=row[2], + POR=row[3], + AYY=row[4].lower() in ['yes','y','1','true',"kyllä", "khyl"], + jas=row[5].lower() in ['yes','y','1','true',"kyllä", "khyl"], + ) + print("added obj {}".format(obj)) + except: + response["status"] = "failure" + response["errors"].append("failure adding item {}".format(", ".join(row))) + + return response def __str__(self): - return "{} {}".format(first_name, last_name) + return "{} {}".format(self.first_name, self.last_name) class MemberRequest(models.Model): member = models.ForeignKey(Member) diff --git a/members/static/html/rekisteri.html b/members/static/html/rekisteri.html deleted file mode 100644 index c8b0e7b..0000000 --- a/members/static/html/rekisteri.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - Haku - - - - - - - - -
-

Jäsenrekisteri

-

Hae jäsen

-

Syötä jäsenen nimi:

-
-
- - -
- -
- - - \ No newline at end of file diff --git a/members/static/js/appconfig.js b/members/static/js/appconfig.js new file mode 100644 index 0000000..382521e --- /dev/null +++ b/members/static/js/appconfig.js @@ -0,0 +1,6 @@ +var app = angular.module('memberApp', ['ngRoute']); + +app.config(['$httpProvider', function ($httpProvider) { + $httpProvider.defaults.xsrfCookieName = 'csrftoken'; + $httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken'; +}]); \ No newline at end of file diff --git a/members/static/js/jquery.noty.packaged.js b/members/static/js/jquery.noty.packaged.js new file mode 100644 index 0000000..c799814 --- /dev/null +++ b/members/static/js/jquery.noty.packaged.js @@ -0,0 +1,1442 @@ +!function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['jquery'], factory); + } else if (typeof exports === 'object') { + module.exports = factory(require('jquery')); + } else { + factory(root.jQuery); + } +}(this, function($) { + +/*! + @package noty - jQuery Notification Plugin + @version version: 2.3.8 + @contributors https://github.com/needim/noty/graphs/contributors + + @documentation Examples and Documentation - http://needim.github.com/noty/ + + @license Licensed under the MIT licenses: http://www.opensource.org/licenses/mit-license.php + */ + + if(typeof Object.create !== 'function') { + Object.create = function(o) { + function F() { + } + + F.prototype = o; + return new F(); + }; + } + + var NotyObject = { + + init: function(options) { + + // Mix in the passed in options with the default options + this.options = $.extend({}, $.noty.defaults, options); + + this.options.layout = (this.options.custom) ? $.noty.layouts['inline'] : $.noty.layouts[this.options.layout]; + + if($.noty.themes[this.options.theme]) + this.options.theme = $.noty.themes[this.options.theme]; + else + this.options.themeClassName = this.options.theme; + + this.options = $.extend({}, this.options, this.options.layout.options); + this.options.id = 'noty_' + (new Date().getTime() * Math.floor(Math.random() * 1000000)); + + // Build the noty dom initial structure + this._build(); + + // return this so we can chain/use the bridge with less code. + return this; + }, // end init + + _build: function() { + + // Generating noty bar + var $bar = $('
').attr('id', this.options.id); + $bar.append(this.options.template).find('.noty_text').html(this.options.text); + + this.$bar = (this.options.layout.parent.object !== null) ? $(this.options.layout.parent.object).css(this.options.layout.parent.css).append($bar) : $bar; + + if(this.options.themeClassName) + this.$bar.addClass(this.options.themeClassName).addClass('noty_container_type_' + this.options.type); + + // Set buttons if available + if(this.options.buttons) { + + // If we have button disable closeWith & timeout options + this.options.closeWith = []; + this.options.timeout = false; + + var $buttons = $('
').addClass('noty_buttons'); + + (this.options.layout.parent.object !== null) ? this.$bar.find('.noty_bar').append($buttons) : this.$bar.append($buttons); + + var self = this; + + $.each(this.options.buttons, function(i, button) { + var $button = $('
diff --git a/members/views.py b/members/views.py index 994c418..589a913 100644 --- a/members/views.py +++ b/members/views.py @@ -62,6 +62,15 @@ def member_requests(request, *args, **kwargs): reqs = list(map(lambda r: r.get_dict(),MemberRequest.objects.all())) return HttpResponse(json.dumps(reqs)) +@ensure_csrf_cookie +def csv_import(request, *args, **kwargs): + data = request.body.decode("utf-8") + resp_data = Member.import_csv(data) + resp = HttpResponse(json.dumps(resp_data)) + if resp_data['status'] == 'failure': + resp.status_code = 400 + return resp + @ensure_csrf_cookie def new_member_request(request, *args, **kwargs): try: diff --git a/sikweb/urls.py b/sikweb/urls.py index df7ca9f..d3af1d4 100644 --- a/sikweb/urls.py +++ b/sikweb/urls.py @@ -21,6 +21,7 @@ from members.views import index as mindex from members.views import members as mems from members.views import member as mem from members.views import handle_mem_request +from members.views import csv_import as mem_csv_import from members.views import new_member_request from members.views import member_requests @@ -34,7 +35,7 @@ urlpatterns = [ url(r'^members/api/members$', mems), url(r'^members/api/member/(?P\d+)$', mem), url(r'^members/api/member/$', mem), - url(r'^members/api/member/$', mem), + url(r'^members/api/csvimport$', mem_csv_import), url(r'^members/api/requests$', member_requests), url(r'^members/api/request$', new_member_request), url(r'^members/api/request/(?P\d+)$', handle_mem_request),