diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1d63ce6 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +* text=auto +*.txt text +*.json text eol=lf +*.xml text eol=lf +.gitattributes text eol=lf diff --git a/.vscode/settings.json b/.vscode/settings.json index 9452402..1eadde3 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -12,9 +12,9 @@ "python.testing.unittestArgs": [ "-v", "-s", - ".", + "./tests", "-p", - "*test.py" + "*_test.py" ], "python.testing.pytestEnabled": false, "python.testing.nosetestsEnabled": false, diff --git a/dakdata.py b/dakdata.py index 594aa90..4c0800e 100644 --- a/dakdata.py +++ b/dakdata.py @@ -1,93 +1,86 @@ # -*- coding: utf-8 -*- -import datetime - -# http://www.sverigesforeningssystem.se/dak-formatet/vad-ar-dak/ - - -class Deltagare: - def __init__(self, id, Foernamn, Efternamn, Personnummer, ledare, epost="", mobilNr="", postnummer=""): - self.id = id - self.Foernamn = Foernamn - self.Efternamn = Efternamn - self.Personnummer = Personnummer - self.Ledare = ledare - self.Epost = epost - self.MobilNr = mobilNr - self.Postnummer = postnummer +""" +Module for exporting data according to DAC format. - def IsFemale(self): - return False if int(self.Personnummer[-2])&1 == 1 else True +http://www.sverigesforeningssystem.se/dak-formatet/vad-ar-dak/ +""" +import datetime - def AgeThisSemester(self, semester): - return int(self.Personnummer[0:4]) - semester.year +class Deltagare(object): + def __init__(self, uid, foernamn, efternamn, personnummer, ledare, epost="", mobil_nr="", postnummer=""): + self.uid = uid + self.foernamn = foernamn + self.efternamn = efternamn + self.personnummer = personnummer + self.ledare = ledare + self.epost = epost + self.mobil_nr = mobil_nr + self.postnummer = postnummer + + def is_female(self): + "Return True if the person is female" + return False if int(self.personnummer[-2])&1 == 1 else True + + def age_this_semester(self, semester): + "Is the person aget this semester" + return int(self.personnummer[0:4]) - semester.year def __eq__(self, other): - return self.Personnummer == other.Personnummer + return self.personnummer == other.personnummer def __hash__(self): - return hash(self.Personnummer) + return hash(self.personnummer) -class Sammankomst: - kod = "" - datum = None - duration = 90 - Aktivitet = "Moete" # OBS en av: Traening, Match, Moete, Oevrigt - deltagare = [] - ledare = [] +class Sammankomst(object): - def __init__(self, kod, datum, duration, Aktivitet): + def __init__(self, kod, datum, duration, aktivitet): self.kod = kod self.datum = datum self.duration = duration - self.Aktivitet = Aktivitet + self.aktivitet = aktivitet # OBS en av: Traening, Match, Moete, Oevrigt self.deltagare = [] self.ledare = [] - def GetDateString(self, formatString='%Y-%m-%d'): - return self.datum.strftime(formatString) + def get_date_string(self, format_string='%Y-%m-%d'): + return self.datum.strftime(format_string) - def GetStartTimeString(self, formatString='%H:%M:%S'): - return self.datum.strftime(formatString) + def get_start_time_string(self, format_string='%H:%M:%S'): + return self.datum.strftime(format_string) - def GetStopTimeString(self, formatString='%H:%M:%S'): - maxEndTime = self.datum.replace(hour=23,minute=59,second=59) + def get_stop_time_string(self, format_string='%H:%M:%S'): + max_end_time = self.datum.replace(hour=23, minute=59, second=59) endtime = self.datum + datetime.timedelta(minutes=self.duration) - if endtime > maxEndTime: - endtime = maxEndTime # limit to the current day (to keep Stop time after Start time) - return endtime.strftime(formatString) + if endtime > max_end_time: + endtime = max_end_time # limit to the current day (to keep Stop time after Start time) + return endtime.strftime(format_string) - def GetAllPersons(self): + def get_all_persons(self): return self.ledare + self.deltagare - def IsPersonAttending(self, person): - for p in self.GetAllPersons(): - if p.Personnummer == person.Personnummer: - return p.Attending + def is_person_attending(self, person): + for person in self.get_all_persons(): + if person.Personnummer == person.Personnummer: + return person.Attending return False -class Narvarokort: - NaervarokortNummer="" - Sammankomster = [] - Aktivitet="Moete" - Lokal="Scouthuset" - NamnPaaKort="" - deltagare = [] - ledare = [] - +class Narvarokort(object): def __init__(self): self.deltagare = [] self.ledare = [] - self.Sammankomster = [] - + self.sammankomster = [] + self.naervarokort_nummer = "" + self.lokal = "Scouthuset" + self.namn_paa_kort = "" + self.aktivitet = "" # OBS en av: Traening, Match, Moete, Oevrigt -class DakData: - kommunID = "" - foreningsID = "" - foereningsNamn=u"" - organisationsnummer="" - kort = None +class DakData(object): + "Main container for DAK data" def __init__(self): self.kort = Narvarokort() + self.kommun_id = "" + self.forenings_id = "" + self.foerenings_namn = "" + self.organisationsnummer = "" diff --git a/excelreport.py b/excelreport.py index 72c2e86..912ed99 100644 --- a/excelreport.py +++ b/excelreport.py @@ -13,11 +13,11 @@ def getFilledInExcelSpreadsheet(self): numPersonRows = 64 startRowPersons = 13 ws = workbook.worksheets[0] - ws['E1'] = self.dak.kort.NaervarokortNummer + ws['E1'] = self.dak.kort.naervarokort_nummer ws['I1'] = self.semester.year - ws['D2'] = self.dak.kort.NamnPaaKort + ws['D2'] = self.dak.kort.namn_paa_kort ws['D3'] = "Scouting" - ws['D4'] = self.dak.kort.Lokal + ws['D4'] = self.dak.kort.lokal if self.semester.ht: ws['C7'] = 'X' else: @@ -27,13 +27,13 @@ def getFilledInExcelSpreadsheet(self): ledareCount = len(self.dak.kort.ledare) totalPersons = deltagareCount + ledareCount - for index, sammankomst in enumerate(self.dak.kort.Sammankomster): + for index, sammankomst in enumerate(self.dak.kort.sammankomster): aktivitetColumn = 11+index - ws.cell(row=2, column=aktivitetColumn).value = sammankomst.Aktivitet - ws.cell(row=7, column=aktivitetColumn).value = sammankomst.GetStartTimeString('%H') - ws.cell(row=9, column=aktivitetColumn).value = sammankomst.GetStopTimeString('%H') - ws.cell(row=10, column=aktivitetColumn).value = sammankomst.GetDateString('%m') - ws.cell(row=11, column=aktivitetColumn).value = sammankomst.GetDateString('%d') + ws.cell(row=2, column=aktivitetColumn).value = sammankomst.aktivitet + ws.cell(row=7, column=aktivitetColumn).value = sammankomst.get_start_time_string('%H') + ws.cell(row=9, column=aktivitetColumn).value = sammankomst.get_stop_time_string('%H') + ws.cell(row=10, column=aktivitetColumn).value = sammankomst.get_date_string('%m') + ws.cell(row=11, column=aktivitetColumn).value = sammankomst.get_date_string('%d') for deltagareindex, deltagaren in enumerate(self.dak.kort.deltagare): if deltagaren in sammankomst.deltagare: ws.cell(row=startRowPersons+deltagareindex, column=aktivitetColumn).value = 1 @@ -44,18 +44,18 @@ def getFilledInExcelSpreadsheet(self): for index, deltagaren in enumerate(self.dak.kort.deltagare): deltagarenRow = startRowPersons+index - ws.cell(row=deltagarenRow, column=2).value = deltagaren.Foernamn + " " + deltagaren.Efternamn - ws.cell(row=deltagarenRow, column=8).value = 'K' if deltagaren.IsFemale() else 'M' - ws.cell(row=deltagarenRow, column=9).value = deltagaren.Postnummer - ws.cell(row=deltagarenRow, column=10).value = deltagaren.Personnummer[0:8] + ws.cell(row=deltagarenRow, column=2).value = deltagaren.foernamn + " " + deltagaren.efternamn + ws.cell(row=deltagarenRow, column=8).value = 'K' if deltagaren.is_female() else 'M' + ws.cell(row=deltagarenRow, column=9).value = deltagaren.postnummer + ws.cell(row=deltagarenRow, column=10).value = deltagaren.personnummer[0:8] for index, ledaren in enumerate(self.dak.kort.ledare): ledarenRow = startRowPersons+index+deltagareCount ws.cell(row=ledarenRow, column=2).value = "Ledare:" - ws.cell(row=ledarenRow, column=3).value = ledaren.Foernamn + " " + ledaren.Efternamn - ws.cell(row=ledarenRow, column=8).value = 'K' if ledaren.IsFemale() else 'M' - ws.cell(row=ledarenRow, column=9).value = ledaren.Postnummer - ws.cell(row=ledarenRow, column=10).value = ledaren.Personnummer[0:8] + ws.cell(row=ledarenRow, column=3).value = ledaren.foernamn + " " + ledaren.efternamn + ws.cell(row=ledarenRow, column=8).value = 'K' if ledaren.is_female() else 'M' + ws.cell(row=ledarenRow, column=9).value = ledaren.postnummer + ws.cell(row=ledarenRow, column=10).value = ledaren.personnummer[0:8] bytesIO = io.BytesIO() workbook.save(bytesIO) diff --git a/ireport.py b/ireport.py index 3ddf7af..5773802 100644 --- a/ireport.py +++ b/ireport.py @@ -1,20 +1,20 @@ -class IReport: +class IReport(object): """Interface for attendence reports""" def __init__(self, dak, semester): pass - def getUrlName(self): + def get_url_anme(self): """Short name that can be used as a url parameter""" pass - def getMimeType(self): + def get_mime_type(self): """Mime type for this data format.""" pass - def getFilename(self): + def get_filename(self): """Returns a filename for this report.""" pass - def getReportString(self): + def get_report_string(self): """File content data from export.""" pass diff --git a/jsonreport.py b/jsonreport.py index 29d0f83..d0656a5 100644 --- a/jsonreport.py +++ b/jsonreport.py @@ -1,71 +1,24 @@ # -*- coding: utf-8 -*- - -if __name__ == '__main__': - import sys - sys.path.append('lib') # add lib to path for unit-testing - import json - import jsonpickle -import unittest -import datetime -from dakdata import DakData, Deltagare, Sammankomst from ireport import IReport - class JsonReport(IReport): def __init__(self, dak, semester): + super(JsonReport, self).__init__(dak, semester) self.dak = dak self.semester = semester - def getUrlName(self): + def get_url_anme(self): return "json" - def getMimeType(self): + def get_mime_type(self): return "text/json" - def getReportString(self): - return self.getJson() - - def getFilename(self): - return str(self.dak.kort.NamnPaaKort) + '-' + self.semester.getname() + '.json' - - def getJson(self): - return jsonpickle.encode(self.dak) - - -class TestJsonReport(unittest.TestCase): - def createDakData(self): - dak = DakData() - dak.foereningsNamn = u"Test Scoutkår" - dak.foreningsID = "1111" - dak.organisationsnummer = "556677-8899" - dak.kommunID = "0" - dak.kort.NamnPaaKort = "Testavdelning" - dak.kort.NaervarokortNummer = "1" - # - dak.kort.ledare.append(Deltagare("1234", "Adam", "Adamsson", "200501011234", True, "adam@test.com", "12345678", u"Göteborg")) - dak.kort.deltagare.append(Deltagare("1235", "Bertil", "Bertilsson", "198501011234", False, "bertil@test.com", "12345678", u"Göteborg")) - sammankomst = Sammankomst(u"123", datetime.date(2019, 1, 1), 180, u"Möte") - sammankomst.ledare.append(dak.kort.ledare[0]) - sammankomst.deltagare.append(dak.kort.deltagare[0]) - dak.kort.Sammankomster.append(sammankomst) - return dak - - def test_dakexport(self): - dak = self.createDakData() - #semester = Semester(2019, false) # 2019, vt - semester = None - json_report = JsonReport(dak, semester) - stream = json_report.getReportString() - #print(stream) - data = json.loads(stream) - - self.assertEqual(data[u'foereningsNamn'], u"Test Scoutkår") - self.assertEqual(data[u'foreningsID'], u"1111") - self.assertEqual(data[u'kort'][u'NamnPaaKort'], "Testavdelning") - self.assertEqual(data[u'kort'][u'Sammankomster'][0]['deltagare'][0]['id'], "1235") - self.assertEqual(data[u'kort'][u'Sammankomster'][0]['ledare'][0]['id'], "1234") + def get_report_string(self): + return self.get_json() + def get_filename(self): + return str(self.dak.kort.namn_paa_kort) + '-' + self.semester.getname() + '.json' -if __name__ == '__main__': - unittest.main() + def get_json(self, unpicklable=True, warn=False): + return jsonpickle.encode(self.dak, unpicklable=unpicklable, warn=warn) diff --git a/start.py b/start.py index 43777c6..40abc96 100644 --- a/start.py +++ b/start.py @@ -427,17 +427,17 @@ def show(sgroup_url=None, troop_url=None, key_url=None): if key_url == "dak" or key_url == "excel" or key_url == "json": dak = DakData() - dak.foereningsNamn = scoutgroup.getname() - dak.foreningsID = scoutgroup.foreningsID + dak.foerenings_namn = scoutgroup.getname() + dak.forenings_id = scoutgroup.foreningsID dak.organisationsnummer = scoutgroup.organisationsnummer - dak.kommunID = scoutgroup.kommunID - dak.kort.NamnPaaKort = troop.getname() + dak.kommun_id = scoutgroup.kommunID + dak.kort.namn_paa_kort = troop.getname() # hack generate an "unique" id, if there is none if troop.rapportID == None or troop.rapportID == 0: troop.rapportID = random.randint(1000, 1000000) troop.put() - dak.kort.NaervarokortNummer = str(troop.rapportID) + dak.kort.naervarokort_nummer = str(troop.rapportID) for tp in trooppersons: p = personsDict[tp.person] @@ -447,36 +447,36 @@ def show(sgroup_url=None, troop_url=None, key_url=None): dak.kort.deltagare.append(Deltagare(p.getReportID(), p.firstname, p.lastname, p.getpersonnr(), False, p.email, p.mobile, p.zip_code)) for m in meetings: - sammankomst = Sammankomst(str(m.key.id()[:50]), m.datetime, m.duration, m.getname()) + sammankomsten = Sammankomst(str(m.key.id()[:50]), m.datetime, m.duration, m.getname()) for tp in trooppersons: isAttending = tp.person in m.attendingPersons if isAttending: p = personsDict[tp.person] if tp.leader: - sammankomst.ledare.append(Deltagare(p.getReportID(), p.firstname, p.lastname, p.getpersonnr(), True, p.email, p.mobile, p.zip_code)) + sammankomsten.ledare.append(Deltagare(p.getReportID(), p.firstname, p.lastname, p.getpersonnr(), True, p.email, p.mobile, p.zip_code)) else: - sammankomst.deltagare.append(Deltagare(p.getReportID(), p.firstname, p.lastname, p.getpersonnr(), False, p.email, p.mobile, p.zip_code)) + sammankomsten.deltagare.append(Deltagare(p.getReportID(), p.firstname, p.lastname, p.getpersonnr(), False, p.email, p.mobile, p.zip_code)) - dak.kort.Sammankomster.append(sammankomst) + dak.kort.sammankomster.append(sammankomsten) if key_url == "excel": excelReport = ExcelReport(dak, semester) resultbytes = excelReport.getFilledInExcelSpreadsheet() response = make_response(resultbytes) response.headers['Content-Type'] = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' - response.headers['Content-Disposition'] = 'attachment; filename=' + urllib.quote(str(dak.kort.NamnPaaKort), safe='') + '-' + semester.getname() + '.xlsx;' + response.headers['Content-Disposition'] = 'attachment; filename=' + urllib.quote(str(dak.kort.namn_paa_kort), safe='') + '-' + semester.getname() + '.xlsx;' return response elif key_url == "json": - jsonReport = JsonReport(dak, semester) - resultbytes = jsonReport.getReportString() + jReport = JsonReport(dak, semester) + resultbytes = jReport.get_report_string() response = make_response(resultbytes) - response.headers['Content-Type'] = jsonReport.getMimeType() - response.headers['Content-Disposition'] = 'attachment; filename=' + urllib.quote(jsonReport.getFilename(), safe='') + ';' + response.headers['Content-Type'] = jReport.get_mime_type() + response.headers['Content-Disposition'] = 'attachment; filename=' + urllib.quote(jReport.get_filename(), safe='') + ';' return response else: result = render_template('dak.xml', dak=dak) response = make_response(result) response.headers['Content-Type'] = 'application/xml' - response.headers['Content-Disposition'] = 'attachment; filename=' + urllib.quote(str(dak.kort.NamnPaaKort), safe='') + '-' + semester.getname() + '.xml;' + response.headers['Content-Disposition'] = 'attachment; filename=' + urllib.quote(str(dak.kort.namn_paa_kort), safe='') + '-' + semester.getname() + '.xml;' return response elif key_url == "sensus": leaders = [] diff --git a/templates/dak.xml b/templates/dak.xml index 793a7b9..e6d4e92 100644 --- a/templates/dak.xml +++ b/templates/dak.xml @@ -1,60 +1,60 @@ - - - - - - {{dak.kort.Aktivitet}} - {{dak.kort.Lokal}} - {{dak.kort.NamnPaaKort}} - - {% for sammankomst in dak.kort.Sammankomster %} - - {{sammankomst.GetStartTimeString()}} - {{sammankomst.GetStopTimeString()}} - {{sammankomst.Aktivitet}} - {{dak.kort.Lokal}} - {{dak.kort.Aktivitet}} - Add - - {% for deltagare in sammankomst.deltagare %} - - false - true - - {% endfor %} - - - {% for deltagare in sammankomst.ledare %} - - false - true - - {% endfor %} - - - {% endfor%} - - - - - - {% for deltagare in dak.kort.deltagare %} - - {{deltagare.Foernamn}} - {{deltagare.Efternamn}} - {{deltagare.Personnummer}} - - {% endfor %} - - - {% for deltagare in dak.kort.ledare %} - - {{deltagare.Foernamn}} - {{deltagare.Efternamn}} - {{deltagare.Personnummer}} - {{deltagare.Epost}} - {{deltagare.MobilNr}} - - {% endfor %} - + + + + + + {{dak.kort.aktivitet}} + {{dak.kort.lokal}} + {{dak.kort.namn_paa_kort}} + + {% for sammankomst in dak.kort.sammankomster %} + + {{sammankomst.get_start_time_string()}} + {{sammankomst.get_stop_time_string()}} + {{sammankomst.aktivitet}} + {{dak.kort.lokal}} + {{dak.kort.aktivitet}} + Add + + {% for deltagare in sammankomst.deltagare %} + + false + true + + {% endfor %} + + + {% for deltagare in sammankomst.ledare %} + + false + true + + {% endfor %} + + + {% endfor%} + + + + + + {% for deltagare in dak.kort.deltagare %} + + {{deltagare.foernamn}} + {{deltagare.efternamn}} + {{deltagare.personnummer}} + + {% endfor %} + + + {% for deltagare in dak.kort.ledare %} + + {{deltagare.foernamn}} + {{deltagare.efternamn}} + {{deltagare.personnummer}} + {{deltagare.epost}} + {{deltagare.mobil_nr}} + + {% endfor %} + \ No newline at end of file diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 0000000..6d7eaf8 --- /dev/null +++ b/tests/README.md @@ -0,0 +1,11 @@ +# Unit tests + +Run from parent directory as + + python2 tests/dak_test.py + +Alternatively from this directory as + + python2 dak_test.py + +Has been tested with Windows and MacOS. diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..21d63d5 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1,6 @@ +import unittest + +def my_test_suite(): + testLoader = unittest.TestLoader() + testSuite = testLoader.discover('.', pattern='*_test.py') + return testSuite diff --git a/tests/dak_test.py b/tests/dak_test.py new file mode 100644 index 0000000..04c42bf --- /dev/null +++ b/tests/dak_test.py @@ -0,0 +1,250 @@ +# -*- coding: utf-8 -*- +""" +Tests of DAK handling. +""" +import sys +import shutil +import time +import platform +import os +import json +import unittest +import datetime + +# Disable all import warnings since the imports are pretty hacky +#pylint: disable=import-error,wrong-import-order,wrong-import-position +sys.path.append('../lib') # add lib to path for unit-testing +sys.path.append('..') # add parent to path for unit-testing +sys.path.append('./lib') # add lib to path for unit-testing +sys.path.append('.') # add current dir to path for unit-testing +import xmlschema +import jsonpickle +from openpyxl import load_workbook +from flask import Flask, render_template +from jsonreport import JsonReport +from dakdata import DakData, Deltagare, Sammankomst +if platform.system() == 'Windows': + # Add app engine paths on windows. + sys.path.append("C:/Program Files (x86)/Google/google_appengine") + sys.path.append("C:/Program Files (x86)/Google/google_appengine/lib") + sys.path.append("c:/Program Files (x86)/Google/google_appengine/google/appengine/api") + sys.path.append("c:/Program Files (x86)/Google/google_appengine/google/appengine") +elif platform.system() == 'Darwin': # i.e. MacOS + BASE = "/usr/local/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/" + sys.path.append(BASE + "platform/google_appengine/lib/fancy_urllib") + sys.path.append(BASE + "platform/google_appengine/lib") + sys.path.append(BASE + "platform/google_appengine/api") + sys.path.append(BASE + "platform/google_appengine") + sys.path.append(BASE + "lib/third_party") + +from google.appengine.ext import ndb +from google.appengine.ext import testbed +from excelreport import ExcelReport +from data import Semester + + +class XmlValidator(): + "XML validation" + def __init__(self, xsdPath): + self.xmlschema = xmlschema.XMLSchema(xsdPath) + + def validate(self, xml): + "Run the validator" + self.xmlschema.validate(xml) + +def create_dak_data(): + "Creates test DAK data" + dak = DakData() + dak.foerenings_namn = u"Test Scoutkår" + dak.forenings_id = "1111" + dak.organisationsnummer = "556677-8899" + dak.kommun_id = "0" + dak.kort.namn_paa_kort = "Testavdelning" + dak.kort.naervarokort_nummer = "1" + dak.kort.aktivitet = u'Moete' + # + dak.kort.ledare.append(Deltagare("1234", "Adam", "Adamsson", u"198501011234", True, "adam@test.com", "12345678", u"Göteborg")) + dak.kort.deltagare.append(Deltagare("1235", "Bertil", "Bertilsson", u"200501011234", False, "bertil@test.com", "12345678", u"Göteborg")) + dak.kort.deltagare.append(Deltagare("1236", "Ada", "Adasson", u"200601011244", False, "ada@test.com", "12345679", u"Göteborg")) + dak.kort.deltagare.append(Deltagare("1237", "Ceda", "Cedasson", u"200701011244", False, "ada@test.com", "12345679", u"Göteborg")) + + sammankomst1 = Sammankomst(u"123", datetime.datetime(2019, 1, 1, 18, 30), 90, u"Möte") + sammankomst1.ledare.append(dak.kort.ledare[0]) + sammankomst1.deltagare.append(dak.kort.deltagare[0]) + sammankomst1.deltagare.append(dak.kort.deltagare[1]) + sammankomst1.deltagare.append(dak.kort.deltagare[2]) + dak.kort.sammankomster.append(sammankomst1) + + sammankomst2 = Sammankomst(u"123", datetime.datetime(2019, 1, 7, 18, 30), 90, u"Möte") + sammankomst2.ledare.append(dak.kort.ledare[0]) + sammankomst2.deltagare.append(dak.kort.deltagare[0]) + sammankomst2.deltagare.append(dak.kort.deltagare[1]) + sammankomst2.deltagare.append(dak.kort.deltagare[2]) + dak.kort.sammankomster.append(sammankomst2) + + sammankomst3 = Sammankomst(u"123", datetime.datetime(2019, 1, 14, 18, 30), 90, u"Möte") + sammankomst3.ledare.append(dak.kort.ledare[0]) + sammankomst3.deltagare.append(dak.kort.deltagare[0]) + sammankomst3.deltagare.append(dak.kort.deltagare[2]) + dak.kort.sammankomster.append(sammankomst3) + + return dak + +def create_flask_app(cfg=None): + "Creates small app for the unit test" + template_path = os.path.join(os.path.dirname(__file__), '..', 'templates') + app = Flask(cfg, template_folder=template_path) + # app.config['DEBUG'] = True + # app.config['SERVER_NAME'] = 'localhost' + return app + + +class TestJsonReport(unittest.TestCase): + "DAK handling tests" + + outputDir = 'derived' + expectedDir = 'expected' + + @classmethod + def setUpClass(cls): + output_dir_full = os.path.join(os.path.dirname(__file__), cls.outputDir) + if not os.path.exists(output_dir_full): + os.makedirs(output_dir_full) + time.sleep(0.05) + + @classmethod + def tearDownClass(cls): + output_dir_full = os.path.join(os.path.dirname(__file__), cls.outputDir) + os.rmdir(output_dir_full) + + def save_and_check(self, generated_data, expected_file, generated_file, check_xsd=False, force=False): + "Save the data and read it back and check with expected file" + expected_path = os.path.join(os.path.dirname(__file__), TestJsonReport.expectedDir, expected_file) + generated_path = os.path.join(os.path.dirname(__file__), TestJsonReport.outputDir, generated_file) + + with open(generated_path, "wb") as filep: + filep.write(generated_data) + + if check_xsd: + self.validate.validate(generated_path) + + if force: + shutil.copyfile(generated_path, expected_path) + + with open(expected_path, "rb") as filep: + expected_text = filep.read() + + with open(generated_path, "rb") as filep: + generated_text = filep.read() + + self.assertEqual(expected_text, generated_text) + + os.remove(generated_path) + + def setUp(self): + # Google app engine testbed setup. + # First, create an instance of the Testbed class. + self.testbed = testbed.Testbed() + # Then activate the testbed, which prepares the service stubs for use. + self.testbed.activate() + # Next, declare which service stubs you want to use. + self.testbed.init_datastore_v3_stub() + self.testbed.init_memcache_stub() + # Clear ndb's in-context cache between tests. + # This prevents data from leaking between tests. + # Alternatively, you could disable caching by + # using ndb.get_context().set_cache_policy(False) + ndb.get_context().clear_cache() + + # Flask app test setup. + xsd_path = os.path.join(os.path.dirname(__file__), '..', 'templates', 'importSchema.xsd') + self.validate = XmlValidator(xsd_path) + self.dak = create_dak_data() + self.app = create_flask_app('mytest') + # self.app_context = self.app.app_context() + # self.app_context.push() + self.client = self.app.test_client() + + @self.app.route("/") + def hello(): # pylint: disable=unused-variable + return render_template('dak.xml', dak=self.dak) + + def tearDown(self): + self.testbed.deactivate() + + def test_dak_json_export(self): + "Test json report of DAK data" + semester = Semester.create(2019, False) # 2019, vt + jsonpickle.set_encoder_options('json', indent=4) + jsonreport = JsonReport(self.dak, semester) + stream = jsonreport.get_json(unpicklable=False, warn=True) + data = json.loads(stream) + + self.assertEqual(data[u'foerenings_namn'], u"Test Scoutkår") + self.assertEqual(data[u'forenings_id'], u"1111") + self.assertEqual(data[u'kort'][u'namn_paa_kort'], "Testavdelning") + self.assertEqual(data[u'kort'][u'sammankomster'][0]['deltagare'][0]['uid'], "1235") + self.assertEqual(data[u'kort'][u'sammankomster'][0]['deltagare'][1]['uid'], "1236") + self.assertEqual(data[u'kort'][u'sammankomster'][0]['ledare'][0]['uid'], "1234") + self.assertEqual(data[u'kort'][u'naervarokort_nummer'], "1") + self.save_and_check(stream, 'dak_json_export.json', 'dak_json_export.json') + + stream = jsonreport.get_report_string() + data = jsonpickle.decode(stream) + + self.assertEqual(data.foerenings_namn, u"Test Scoutkår") + self.assertEqual(data.forenings_id, u"1111") + self.assertEqual(data.kort.namn_paa_kort, "Testavdelning") + self.assertEqual(data.kort.sammankomster[0].deltagare[0].uid, "1235") + self.assertEqual(data.kort.sammankomster[0].deltagare[1].uid, "1236") + self.assertEqual(data.kort.sammankomster[0].ledare[0].uid, "1234") + self.assertEqual(data.kort.naervarokort_nummer, "1") + self.save_and_check(stream, 'dak_json_pickable_export.json', 'dak_json_pickable_export.json', force=True) + + def test_dak_xml_export(self): + "Test XML report of DAK data" + response = self.client.get('/') + self.save_and_check(response.data, 'dak_xml_export.xml', 'dak_xml_export.xml', check_xsd=True) + + def test_dak_excel_export(self): + "Test excel report of DAK data" + current_semester = Semester.create(2019, False) # 2019, vt + excel_report = ExcelReport(self.dak, current_semester) + result_bytes = excel_report.getFilledInExcelSpreadsheet() + + generated_path = os.path.join(os.path.dirname(__file__), TestJsonReport.outputDir, 'dak_excel_export.xlsx') + + with open(generated_path, "wb") as filep: + filep.write(result_bytes) + + workbook = load_workbook(generated_path) + worksheets = workbook.worksheets[0] + self.assertEqual(self.dak.kort.naervarokort_nummer, worksheets['E1'].value) + self.assertEqual(current_semester.year, worksheets['I1'].value) + self.assertEqual(self.dak.kort.namn_paa_kort, worksheets['D2'].value) + self.assertEqual("Scouting", worksheets['D3'].value) + self.assertEqual(self.dak.kort.lokal, worksheets['D4'].value) + if current_semester.ht: + self.assertEqual(worksheets['C6'].value, None) + self.assertEqual(worksheets['C7'].value, 'X') + else: + self.assertEqual(worksheets['C6'].value, 'X') + self.assertEqual(worksheets['C7'].value, None) + + row = 13 + for deltagaren in self.dak.kort.deltagare: + self.assertEqual(deltagaren.foernamn + " " + deltagaren.efternamn, worksheets['B' + str(row)].value) + self.assertEqual('K' if deltagaren.is_female() else 'M', worksheets['H' + str(row)].value) + self.assertEqual(deltagaren.personnummer[0:8], worksheets['J' + str(row)].value) + self.assertEqual(1, worksheets['K' + str(row)].value) + self.assertEqual(1, worksheets['L' + str(row)].value) + row += 1 + self.assertEqual(1, worksheets['M13'].value) + self.assertEqual(None, worksheets['M14'].value) + self.assertEqual(1, worksheets['M15'].value) + + os.remove(generated_path) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/expected/dak_json_export.json b/tests/expected/dak_json_export.json new file mode 100644 index 0000000..e4dd8e2 --- /dev/null +++ b/tests/expected/dak_json_export.json @@ -0,0 +1,198 @@ +{ + "kort": { + "deltagare": [ + { + "postnummer": "G\u00f6teborg", + "personnummer": "200501011234", + "uid": "1235", + "ledare": false, + "mobil_nr": "12345678", + "foernamn": "Bertil", + "efternamn": "Bertilsson", + "epost": "bertil@test.com" + }, + { + "postnummer": "G\u00f6teborg", + "personnummer": "200601011244", + "uid": "1236", + "ledare": false, + "mobil_nr": "12345679", + "foernamn": "Ada", + "efternamn": "Adasson", + "epost": "ada@test.com" + }, + { + "postnummer": "G\u00f6teborg", + "personnummer": "200701011244", + "uid": "1237", + "ledare": false, + "mobil_nr": "12345679", + "foernamn": "Ceda", + "efternamn": "Cedasson", + "epost": "ada@test.com" + } + ], + "ledare": [ + { + "postnummer": "G\u00f6teborg", + "personnummer": "198501011234", + "uid": "1234", + "ledare": true, + "mobil_nr": "12345678", + "foernamn": "Adam", + "efternamn": "Adamsson", + "epost": "adam@test.com" + } + ], + "namn_paa_kort": "Testavdelning", + "naervarokort_nummer": "1", + "lokal": "Scouthuset", + "sammankomster": [ + { + "deltagare": [ + { + "postnummer": "G\u00f6teborg", + "personnummer": "200501011234", + "uid": "1235", + "ledare": false, + "mobil_nr": "12345678", + "foernamn": "Bertil", + "efternamn": "Bertilsson", + "epost": "bertil@test.com" + }, + { + "postnummer": "G\u00f6teborg", + "personnummer": "200601011244", + "uid": "1236", + "ledare": false, + "mobil_nr": "12345679", + "foernamn": "Ada", + "efternamn": "Adasson", + "epost": "ada@test.com" + }, + { + "postnummer": "G\u00f6teborg", + "personnummer": "200701011244", + "uid": "1237", + "ledare": false, + "mobil_nr": "12345679", + "foernamn": "Ceda", + "efternamn": "Cedasson", + "epost": "ada@test.com" + } + ], + "ledare": [ + { + "postnummer": "G\u00f6teborg", + "personnummer": "198501011234", + "uid": "1234", + "ledare": true, + "mobil_nr": "12345678", + "foernamn": "Adam", + "efternamn": "Adamsson", + "epost": "adam@test.com" + } + ], + "datum": "2019-01-01 18:30:00", + "kod": "123", + "duration": 90, + "aktivitet": "M\u00f6te" + }, + { + "deltagare": [ + { + "postnummer": "G\u00f6teborg", + "personnummer": "200501011234", + "uid": "1235", + "ledare": false, + "mobil_nr": "12345678", + "foernamn": "Bertil", + "efternamn": "Bertilsson", + "epost": "bertil@test.com" + }, + { + "postnummer": "G\u00f6teborg", + "personnummer": "200601011244", + "uid": "1236", + "ledare": false, + "mobil_nr": "12345679", + "foernamn": "Ada", + "efternamn": "Adasson", + "epost": "ada@test.com" + }, + { + "postnummer": "G\u00f6teborg", + "personnummer": "200701011244", + "uid": "1237", + "ledare": false, + "mobil_nr": "12345679", + "foernamn": "Ceda", + "efternamn": "Cedasson", + "epost": "ada@test.com" + } + ], + "ledare": [ + { + "postnummer": "G\u00f6teborg", + "personnummer": "198501011234", + "uid": "1234", + "ledare": true, + "mobil_nr": "12345678", + "foernamn": "Adam", + "efternamn": "Adamsson", + "epost": "adam@test.com" + } + ], + "datum": "2019-01-07 18:30:00", + "kod": "123", + "duration": 90, + "aktivitet": "M\u00f6te" + }, + { + "deltagare": [ + { + "postnummer": "G\u00f6teborg", + "personnummer": "200501011234", + "uid": "1235", + "ledare": false, + "mobil_nr": "12345678", + "foernamn": "Bertil", + "efternamn": "Bertilsson", + "epost": "bertil@test.com" + }, + { + "postnummer": "G\u00f6teborg", + "personnummer": "200701011244", + "uid": "1237", + "ledare": false, + "mobil_nr": "12345679", + "foernamn": "Ceda", + "efternamn": "Cedasson", + "epost": "ada@test.com" + } + ], + "ledare": [ + { + "postnummer": "G\u00f6teborg", + "personnummer": "198501011234", + "uid": "1234", + "ledare": true, + "mobil_nr": "12345678", + "foernamn": "Adam", + "efternamn": "Adamsson", + "epost": "adam@test.com" + } + ], + "datum": "2019-01-14 18:30:00", + "kod": "123", + "duration": 90, + "aktivitet": "M\u00f6te" + } + ], + "aktivitet": "Moete" + }, + "forenings_id": "1111", + "kommun_id": "0", + "foerenings_namn": "Test Scoutk\u00e5r", + "organisationsnummer": "556677-8899" +} \ No newline at end of file diff --git a/tests/expected/dak_json_pickable_export.json b/tests/expected/dak_json_pickable_export.json new file mode 100644 index 0000000..aa46300 --- /dev/null +++ b/tests/expected/dak_json_pickable_export.json @@ -0,0 +1,160 @@ +{ + "py/object": "dakdata.DakData", + "foerenings_namn": "Test Scoutk\u00e5r", + "organisationsnummer": "556677-8899", + "forenings_id": "1111", + "kommun_id": "0", + "kort": { + "py/object": "dakdata.Narvarokort", + "deltagare": [ + { + "py/object": "dakdata.Deltagare", + "postnummer": "G\u00f6teborg", + "personnummer": "200501011234", + "uid": "1235", + "ledare": false, + "mobil_nr": "12345678", + "foernamn": "Bertil", + "efternamn": "Bertilsson", + "epost": "bertil@test.com" + }, + { + "py/object": "dakdata.Deltagare", + "postnummer": "G\u00f6teborg", + "personnummer": "200601011244", + "uid": "1236", + "ledare": false, + "mobil_nr": "12345679", + "foernamn": "Ada", + "efternamn": "Adasson", + "epost": "ada@test.com" + }, + { + "py/object": "dakdata.Deltagare", + "postnummer": "G\u00f6teborg", + "personnummer": "200701011244", + "uid": "1237", + "ledare": false, + "mobil_nr": "12345679", + "foernamn": "Ceda", + "efternamn": "Cedasson", + "epost": "ada@test.com" + } + ], + "ledare": [ + { + "py/object": "dakdata.Deltagare", + "postnummer": "G\u00f6teborg", + "personnummer": "198501011234", + "uid": "1234", + "ledare": true, + "mobil_nr": "12345678", + "foernamn": "Adam", + "efternamn": "Adamsson", + "epost": "adam@test.com" + } + ], + "namn_paa_kort": "Testavdelning", + "naervarokort_nummer": "1", + "lokal": "Scouthuset", + "sammankomster": [ + { + "py/object": "dakdata.Sammankomst", + "deltagare": [ + { + "py/id": 3 + }, + { + "py/id": 4 + }, + { + "py/id": 5 + } + ], + "ledare": [ + { + "py/id": 7 + } + ], + "datum": { + "py/object": "datetime.datetime", + "__reduce__": [ + { + "py/type": "datetime.datetime" + }, + [ + "B+MBARIeAAAAAA==" + ] + ] + }, + "kod": "123", + "duration": 90, + "aktivitet": "M\u00f6te" + }, + { + "py/object": "dakdata.Sammankomst", + "deltagare": [ + { + "py/id": 3 + }, + { + "py/id": 4 + }, + { + "py/id": 5 + } + ], + "ledare": [ + { + "py/id": 7 + } + ], + "datum": { + "py/object": "datetime.datetime", + "__reduce__": [ + { + "py/type": "datetime.datetime" + }, + [ + "B+MBBxIeAAAAAA==" + ] + ] + }, + "kod": "123", + "duration": 90, + "aktivitet": "M\u00f6te" + }, + { + "py/object": "dakdata.Sammankomst", + "deltagare": [ + { + "py/id": 3 + }, + { + "py/id": 5 + } + ], + "ledare": [ + { + "py/id": 7 + } + ], + "datum": { + "py/object": "datetime.datetime", + "__reduce__": [ + { + "py/type": "datetime.datetime" + }, + [ + "B+MBDhIeAAAAAA==" + ] + ] + }, + "kod": "123", + "duration": 90, + "aktivitet": "M\u00f6te" + } + ], + "aktivitet": "Moete" + } +} \ No newline at end of file diff --git a/tests/expected/dak_xml_export.xml b/tests/expected/dak_xml_export.xml new file mode 100644 index 0000000..3518bca --- /dev/null +++ b/tests/expected/dak_xml_export.xml @@ -0,0 +1,147 @@ + + + + + + Moete + Scouthuset + Testavdelning + + + + 18:30:00 + 20:00:00 + Möte + Scouthuset + Moete + Add + + + + false + true + + + + false + true + + + + false + true + + + + + + + false + true + + + + + + + 18:30:00 + 20:00:00 + Möte + Scouthuset + Moete + Add + + + + false + true + + + + false + true + + + + false + true + + + + + + + false + true + + + + + + + 18:30:00 + 20:00:00 + Möte + Scouthuset + Moete + Add + + + + false + true + + + + false + true + + + + + + + false + true + + + + + + + + + + + + + Bertil + Bertilsson + 200501011234 + + + + Ada + Adasson + 200601011244 + + + + Ceda + Cedasson + 200701011244 + + + + + + + Adam + Adamsson + 198501011234 + adam@test.com + 12345678 + + + + \ No newline at end of file