def test__mail__MailAssignmentPreview_1(browser): """It can send Fehlende Arbeitsstunden.""" from sw.allotmentclub import Message, User, Member, Assignment from sw.allotmentclub import AssignmentAttendee from sw.allotmentclub.conftest import import_members import_members() assignment = Assignment.find_or_create( day=datetime.now(), accounting_year=datetime.now().year ) AssignmentAttendee.find_or_create( assignment=assignment, member=Member.query().filter(Member.lastname == 'Wehrmann').one(), hours=5) # No letter AssignmentAttendee.find_or_create( assignment=assignment, member=Member.query().filter(Member.lastname == 'Hennig').one(), hours=3) # Needs to pay less verein = Member.find_or_create(lastname="Verein") Message.create(id=245, members=[verein], user=User.create(), accounting_year=2018, subject="Fehlende Arbeitsstunden", body=MISSING_ASSIGMENT_BODY) transaction.commit() browser.login() with mock.patch('sw.allotmentclub.browser.letter.datetime') as dt: dt.now.return_value = datetime(2016, 3, 25) browser.open('http://localhost/mail/245/preview') assertFileEqual(browser.contents, 'test_mail_fehlarbeitsstunden_1.pdf')
def setUp(): from sw.allotmentclub import Depot, User user = User.create(username='******') Depot.create(date=datetime.datetime(2014, 11, 27, 7, 21, 45), size=15, data=b'GIF89a????!?,D;', mimetype='image/gif', name='test.gif', user=user) transaction.commit()
def test__mail__get_recipient_3(database, setUp): """It returns lastname and firstname of external recipient.""" from sw.allotmentclub import ExternalRecipient, Message, User from ..mail import get_recipient muster = ExternalRecipient.create(lastname="Muster", firstname="Max") Message.create(id=300, externals=[muster], user=User.get(1)) assert get_recipient(300) == "Muster, Max"
def __call__(self): result = super(HomeView, self).__call__() last = None timeline = [] for date, user_id, type_, msg in sw.allotmentclub.json_result( result['data']['data']): if timeline: last = timeline[-1] time = format_date(date) user = User.get(user_id) username = user.username if last and last['username'] == username and last['time'] == time: if msg == last['detail'][-1]: continue last['detail'].append(msg) else: item = { 'time': time, 'username': username, 'firstname': user.vorname, 'lastname': user.nachname, 'detail': [msg] } if username == 'system': item['fa_icon'] = 'fa-gear' else: item['gravatar_url'] = ( 'https://www.gravatar.com/avatar/%s' % ( hashlib.md5( user.email.encode('utf-8')).hexdigest())) timeline.append(item) result['data']['timeline'] = timeline return result
def test__mail__get_recipient_4(database, setUp): """It returns Mehrere Empfänger if multiple recipients.""" from sw.allotmentclub import ExternalRecipient, Message, User from ..mail import get_recipient muster = ExternalRecipient.create(lastname="Muster", firstname="Max") muster2 = ExternalRecipient.create(lastname="Mustermann", firstname="Max") Message.create(id=300, externals=[muster, muster2], user=User.get(1)) assert get_recipient(300) == "Mehrere Empfänger"
def test__mail__MailPreviewView_3(browser): """It does not print address and date if no member assigned to message.""" from sw.allotmentclub import Message, User Message.create(id=244, user=User.create(), accounting_year=2015, subject="Info-Brief", body="**Info** an alle Mitglieder") transaction.commit() browser.login() browser.open('http://localhost/mail/244/preview') assertFileEqual(browser.contents, 'test_mail_preview_3.pdf')
def user(request, organization, database): """Fixture creating a user with no role.""" user = User.find_or_create(username='******', password='******', nachname='Mittag', position='Vorsitzender', ort='Leuna', organization_id=1) database.session.flush() return user
def test_displays_list_of_log_entries(browser): from sw.allotmentclub import Log, User User.create(id=2, username='******', vorname='Sebastian', nachname='Wehrmann') Log.create(user_id=2, name='user data', level='INFO', created=datetime.datetime.now(), msg='Test-Log-Eintrag') transaction.commit() browser.login() browser.open('http://localhost/') assert { 'username': '******', 'firstname': 'Sebastian', 'lastname': 'Wehrmann', 'gravatar_url': 'https://www.gravatar.com/avatar/' 'd41d8cd98f00b204e9800998ecf8427e', 'detail': ['Test-Log-Eintrag'], 'time': 'gerade eben' } in browser.json['data']['timeline']
def setUp(): from sw.allotmentclub import Member, Message, User, SentMessageInfo mustermann = Member.create(lastname="Mustermann", firstname="Max", email='*****@*****.**') user = User.create(username='******') msg = Message.create(id=242, members=[mustermann], user=user, accounting_year=2016, subject="Test", body="") SentMessageInfo.create(message=msg, tag='*****@*****.**', address='*****@*****.**') transaction.commit()
def verwalter(request, organization, database): """Fixture creating a user with role Administrator.""" user = User.find_or_create(username='******', password='******', vorname='Admin', nachname='istrator', unrestricted_access=True, organization_id=1) database.session.flush() transaction.commit() return user
def test_fa_icon_if_system_user(browser): from sw.allotmentclub import Log, User user = User.find_or_create(username='******') Log.create(user=user, name='user data', level='INFO', created=datetime.datetime.now(), msg='Test-Log-Eintrag') transaction.commit() browser.login() browser.open('http://localhost/') timeline = browser.json['data']['timeline'][0] assert timeline['fa_icon'] == 'fa-gear' assert 'gravatar_url' not in timeline
def test__mail__MailPreviewView_4(browser, setUp): """It renders attachments to the message.""" from sw.allotmentclub import Attachment, User import pkg_resources data = pkg_resources.resource_stream( 'sw.allotmentclub.browser.tests', 'test_protocol_print.pdf').read() Attachment.create(message_id=243, data=data, mimetype='application/pdf', user=User.get(1)) transaction.commit() browser.login() with mock.patch('sw.allotmentclub.browser.letter.datetime') as dt: dt.now.return_value = datetime(2016, 3, 25) browser.open('http://localhost/mail/243/preview') assertFileEqual(browser.contents, 'test_mail_preview_4.pdf')
def test_send_mail_sends_text_mail(mailer, database): from ..letter import send_mail user = User.create(username='******', vorname='Hans', nachname='Wurst') send_mail('*****@*****.**', 'Betreff', 'Dies ist der Inhalt', user) assert 1 == len(mailer.outbox) message = mailer.outbox[0] assert ('Vorstand Leuna-Bungalowgemeinschaft Roter See ' '<*****@*****.**>' == message.sender) assert ['*****@*****.**'] == message.recipients assert message.body == ( '\nDies ist der Inhalt\n\nMit freundlichen Grüßen,\n' 'Im Auftrag des Vorstandes\n\nHans Wurst (None)\n\n') assert message.html is None assert 'Anschreiben.pdf' == message.attachments[0].filename
def test__mail__MailElectricityPreview_1(browser): """It can send Energieabrechnungen.""" from sw.allotmentclub import Message, User, Member from sw.allotmentclub.conftest import import_energy_meters, import_members import_members() import_energy_meters() verein = Member.find_or_create(lastname="Verein") Message.create(id=245, members=[verein], user=User.create(), accounting_year=2014, subject="Energieabrechnung", body=ENERGIEABRECHNUNG_BODY) transaction.commit() browser.login() with mock.patch('sw.allotmentclub.browser.letter.datetime') as dt: dt.now.return_value = datetime(2016, 3, 25) browser.open('http://localhost/mail/245/preview') assertFileEqual(browser.contents, 'test_mail_energieabrechnung_1.pdf')
def setUp(): from sw.allotmentclub import Member, Message, User verein = Member.create(lastname="Verein") mustermann = Member.create(lastname="Mustermann", firstname="Max") user = User.create(username='******') greeting = ('Sehr geehrte{{deflection}} {{appellation}} ' '{{title}} {{lastname}},\n\n') Message.create(id=242, members=[verein], user=user, accounting_year=2015, subject="Info-Brief", body=greeting+"**Info** an alle Mitglieder") Message.create(id=243, members=[mustermann], user=user, accounting_year=2015, subject="Willkommen", body=greeting+"Willkommen im Verein.") Message.create(id=244, members=[mustermann], user=user, accounting_year=2016, subject="Beitragsabrechnung", body=greeting) transaction.commit()
def login(login, password): """Try to verify the user. Returns (User, authenticated?) User will be None if password is missing or user does not exist, otherwise the object will be retrieved from the database. authenticated? will be True iff check_password succeeds and False otherwise. """ user = None if login: user = User.by_username(login) if user and password: return (user, user.check_password(password)) return (None, False)
def setUp(): from sw.allotmentclub import Bulletin, User user = User.create(username='******') Bulletin.create( date=datetime.datetime(2015, 3, 7, 10), subject='Ruhezeiten im Verein', user=user, content=""" ### Mittagsruhe - täglich 13.00 - 15.00 Uhr (ganzjährig) ### Nachtruhe - Montag bis Freitag: 22.00 - 08.00 Uhr - Samstag & Sonntag: 24.00 - 08.00 Uhr ### Genereller Baustop - jährlich vom 15. Juni bis 31. August.""") transaction.commit()
def import_transactions(): parser = gocept.logging.ArgumentParser( description="Import banking transactions.") parser.add_argument('-c', '--config', default='portal.ini', help='Specify the config file. (default: portal.ini)') options = parser.parse_args() app = Application.from_filename(options.config) registry = pyramid.registry.Registry( bases=(zope.component.getGlobalSiteManager(), )) config = pyramid.config.Configurator(settings=app.settings, registry=registry) config.setup_registry(settings=app.settings) request = pyramid.testing.DummyRequest(_registry=registry) request.client_addr = '127.0.0.1' context = pyramid.threadlocal.manager.get().copy() context['request'] = request context['registry'] = registry pyramid.threadlocal.manager.push(context) user = User.by_username('system') import_transactions_from_fints(user)
def send_report(self): org_id = self.request.user.organization_id current_year = get_selected_year() price = (EnergyPrice.query().filter( EnergyValue.organization_id == org_id).filter( EnergyPrice.year == current_year).one()) data = json.loads(json.dumps(price)) data['phases'] = self.phases data['price'] = format_eur(data['price']) data['bill'] = format_eur(data['bill']) data['normal_fee'] = format_eur(data['normal_fee']) data['power_fee'] = format_eur(data['power_fee']) subject = "Bericht Energieabrechnung {year}".format(**data) body = """ <p>Sehr geehrter Vorstand,</p> <p>anbei die Kennzahlen zur diesjährigen Energieabrechnung:</p> <table> <tr><td>Verbrauch Hauptzähler: </td><td>{usage_hauptzaehler} kWh</td></tr> <tr><td>Verbrauch der Mitglieder (inkl. SAT-Anlage und Vereinsgebäude): </td><td>{usage_members} kWh</td></tr> <tr><td colspan=2></td></tr> <tr><td>Verluststrom: </td><td>{usage_hauptzaehler} kWh - {usage_members} kWh = {leakage_current} kWh</td></tr> <tr><td colspan=2></td></tr> <tr><td>Preis pro kWh: </td><td>{bill} / {usage_hauptzaehler} kWh = {price}/kWh</td></tr> <tr><td colspan=2></td></tr> <tr><td>Grundgebühr 1 Phase ({phases} insgesamt): </td><td>{leakage_current} kWh * {price}/kWh / {phases} = {normal_fee}</td></tr> <tr><td>Grundgebühr einfacher Zähler (1 Phase): </td><td>{normal_fee}</td></tr> <tr><td>Grundgebühr Kraftstromzähler (3 Phase): </td><td>{power_fee}</td></tr> </table><br /><br />""".format(**data) # noqa send_mail("*****@*****.**", subject, body, User.by_username('system'))
def __call__(self): data = self.request.json sender = data['FromFull']['Email'].lower() if sender == '*****@*****.**': return Response('ok') if data['Subject'].startswith('***** SPAM'): return Response('ok') message = Message.create(inbound=True, organization_id=self.organization_id, user=User.by_username('system')) member = Member.query().filter(Member.email == sender).first() if member: message.members.append(member) message.organization_id = member.organization_id else: external = (ExternalRecipient.query().filter( ExternalRecipient.email == sender).first()) if not external: external = ExternalRecipient.create(email=sender) external.lastname = data['FromFull']['Name'] external.organization_id = self.organization_id message.externals.append(external) message.organization_id = external.organization_id message.subject = data['Subject'] message.body = (data['HtmlBody'] if data['HtmlBody'] else data['TextBody']) message.sent = self.sent_date(data) message.accounting_year = message.sent.year for attachment in data['Attachments']: Attachment.create(message=message, organization_id=message.organization_id, filename=attachment["Name"], mimetype=attachment["ContentType"], size=attachment["ContentLength"], data=base64.b64decode(attachment["Content"])) return Response('ok')
def export_events_ics(): import sw.allotmentclub.browser.calendar parser = gocept.logging.ArgumentParser( description="Export events in ics format.") parser.add_argument('-c', '--config', default='portal.ini', help='Specify the config file. (default: portal.ini)') parser.add_argument('-t', '--type', help='The type (Mitglied|Vorstand)') options = parser.parse_args() assert options.type in ('Mitglied', 'Vorstand') queries = { 'Mitglied': sw.allotmentclub.browser.calendar.MitgliederQuery, 'Vorstand': sw.allotmentclub.browser.calendar.VorstandQuery } Application.from_filename(options.config) name = ('Mitgliederliste' if options.type == 'Mitglied' else 'Vorstandsliste') output = f"""\ BEGIN:VCALENDAR VERSION:2.0 PRODID:VerwaltungLeunaBundalow X-WR-CALNAME:Leuna-Siedlung {name} NAME:Leuna-Siedlung Mitgliederliste CALSCALE:GREGORIAN BEGIN:VTIMEZONE TZID:Europe/Berlin TZURL:http://tzurl.org/zoneinfo-outlook/Europe/Berlin X-LIC-LOCATION:Europe/Berlin BEGIN:DAYLIGHT TZOFFSETFROM:+0100 TZOFFSETTO:+0200 TZNAME:CEST DTSTART:19700329T020000 RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU END:DAYLIGHT BEGIN:STANDARD TZOFFSETFROM:+0200 TZOFFSETTO:+0100 TZNAME:CET DTSTART:19701025T030000 RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU END:STANDARD END:VTIMEZONE """ db = zope.component.getUtility(risclog.sqlalchemy.interfaces.IDatabase) query = queries[options.type](db, User.by_username('system')).select() for event in query: m = hashlib.md5() m.update('-'.join(str(i) for i in event).encode()) uid = m.hexdigest() if event[-2]: timestamp = event[4].strftime('%Y%m%dT000000Z') start = end = event[4].strftime('%Y%m%d') if event[5]: end = event[5].strftime('%Y%m%d') else: timestamp = event[4].strftime('%Y%m%dT%H%M%SZ') start = end = event[4].strftime('%Y%m%dT%H%M%S') if event[5]: end = event[5].strftime('%Y%m%dT%H%M%S') output += f"""\ BEGIN:VEVENT DTSTAMP:{timestamp} UID:{uid}@roter-see.de DTSTART;TZID=Europe/Berlin:{start} DTEND;TZID=Europe/Berlin:{end} SUMMARY:{event[2]} LOCATION:{event[3]} END:VEVENT """ output += "END:VCALENDAR" print(output)
def get_user(request): user_id = request.authenticated_userid if user_id: return User.get(user_id)
def test__mail__postmark_inbound_webhook_1(browser): """It creates an inbound email for every request.""" from sw.allotmentclub import Message, User user = User.find_or_create(username='******') browser.post( 'http://localhost/mail/postmark_inbound_webhook', data={"FromName": "Postmarkapp Support", "From": "*****@*****.**", "FromFull": { "Email": "*****@*****.**", "Name": "Postmarkapp Support", "MailboxHash": "" }, "To": ("\"Firstname Lastname\" " "<*****@*****.**>"), "ToFull": [ { "Email": "*****@*****.**", "Name": "Firstname Lastname", "MailboxHash": "SampleHash" } ], "Cc": ("\"First Cc\" " "<*****@*****.**>, [email protected]>"), "CcFull": [ { "Email": "*****@*****.**", "Name": "First Cc", "MailboxHash": "" }, { "Email": "*****@*****.**", "Name": "", "MailboxHash": "" } ], "OriginalRecipient": "*****@*****.**", "Subject": "Test subject", "MessageID": "73e6d360-66eb-11e1-8e72-a8904824019b", "ReplyTo": "*****@*****.**", "MailboxHash": "SampleHash", # "Date": "Fri, 1 Aug 2014 16:45:32 -04:00", "Date": "Sat, 19 Aug 2017 19:37:23 +0200 (Mitteleurop?ische", "TextBody": "This is a test text body.", "HtmlBody": ("<html><body><p>" "This is a test html body." "</p></body></html>"), "StrippedTextReply": "This is the reply text", "Tag": "TestTag", "Headers": [ { "Name": "X-Header-Test", "Value": "" }, { "Name": "X-Spam-Status", "Value": "No" }, { "Name": "X-Spam-Score", "Value": "-0.1" }, { "Name": "X-Spam-Tests", "Value": "DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,SPF_PASS" } ], "Attachments": [ { "Name": "test.pdf", "Content": MINIMAL_TEST_PDF_CONTENTS, "ContentType": "application/pdf", "ContentLength": 739 } ]}) mail = Message.query().one() assert '*****@*****.**' == mail.externals[0].email assert 'Postmarkapp Support' == mail.externals[0].lastname assert [] == mail.members assert "Test subject" == mail.subject assert user == mail.user assert mail.inbound is True assert ("<html><body><p>" "This is a test html body." "</p></body></html>" == mail.body) assert 1 == len(mail.attachments) assert MINIMAL_TEST_PDF_CONTENTS.encode() == base64.b64encode( mail.attachments[0].data) assert 'application/pdf' == mail.attachments[0].mimetype assert 'test.pdf' == mail.attachments[0].filename assert int(mail.attachments[0].size) == len(mail.attachments[0].data)