async def test_upload_image(cli, url, factory: Factory, login, db_conn, dummy_server): await factory.create_company() await factory.create_user() await login() assert 'https://www.example.org/main.png' == await db_conn.fetchval( 'SELECT image FROM companies') data = FormData() data.add_field('image', create_image(), filename='testing.png', content_type='application/octet-stream') r = await cli.post(url('company-upload', field='image'), data=data, headers={ 'Referer': f'http://127.0.0.1:{cli.server.port}/foobar/', 'Origin': f'http://127.0.0.1:{cli.server.port}', }) assert r.status == 200, await r.text() # debug(dummy_server.app['log']) assert sorted(dummy_server.app['log']) == [ 'DELETE aws_endpoint_url/testingbucket.example.org/main.png', 'DELETE aws_endpoint_url/testingbucket.example.org/thumb.png', RegexStr( r'PUT aws_endpoint_url/testingbucket.example.org/tests/testing/co/image/\w+/main.png' ), RegexStr( r'PUT aws_endpoint_url/testingbucket.example.org/tests/testing/co/image/\w+/thumb.png' ), ] logo = await db_conn.fetchval('SELECT image FROM companies') assert logo.startswith( 'https://testingbucket.example.org/tests/testing/co/image/')
async def test_upload_image(cli, url, factory: Factory, login, dummy_server): await factory.create_company() await factory.create_user() await factory.create_cat() await login() data = FormData() data.add_field('image', create_image(), filename='testing.png', content_type='application/octet-stream') r = await cli.post(url('categories-add-image', cat_id=factory.category_id), data=data, headers={ 'Referer': f'http://127.0.0.1:{cli.server.port}/foobar/', 'Origin': f'http://127.0.0.1:{cli.server.port}', }) assert r.status == 200, await r.text() assert sorted(dummy_server.app['log']) == [ RegexStr( r'PUT aws_endpoint_url/testingbucket.example.org/tests/testing/supper-clubs/option/\w+/main.png' ), RegexStr( r'PUT aws_endpoint_url/testingbucket.example.org/tests/testing/supper-clubs/option/\w+/thumb.png' ), ]
def test_inline_css_dev(tmpdir): mktree( tmpdir, { 'pages': { 'foo.html': '{{inline_css("theme/main.css")}}', 'bar.html': "{{ url('theme/main.css') }}", }, 'theme': { 'sass/main.scss': 'body {width: 10px + 10px;}', }, }) build(tmpdir, mode=Mode.development) assert gettree(tmpdir.join('dist')) == { 'foo': { 'index.html': ('body {\n' ' width: 20px; }\n' '\n' '/*# sourceMappingURL=/theme/main.css.map */\n'), }, 'bar': { 'index.html': RegexStr(r'/theme/main.css\?t=\d+\n'), }, 'theme': { 'main.css.map': RegexStr('{.*'), 'main.css': ('body {\n' ' width: 20px; }\n' '\n' '/*# sourceMappingURL=main.css.map */'), '.src': { 'main.scss': 'body {width: 10px + 10px;}', }, }, }
async def test_real_intent(cli, url, login, db_conn, factory: Factory): await factory.create_company(stripe_public_key=stripe_public_key, stripe_secret_key=stripe_secret_key) await factory.create_cat() await factory.create_user() await factory.create_event(status='published', price=123.45) await login() data = { 'tickets': [ { 't': True, 'first_name': 'Ticket', 'last_name': 'Buyer', 'email': '*****@*****.**' }, { 't': True, 'email': '*****@*****.**' }, ], 'ticket_type': factory.ticket_type_id, } r = await cli.json_post(url('event-reserve-tickets', id=factory.event_id), data=data) assert r.status == 200, await r.text() response_data = await r.json() assert response_data == { 'booking_token': RegexStr(r'.+'), 'ticket_count': 2, 'extra_donated': None, 'item_price': 123.45, 'total_price': 246.90, 'timeout': AnyInt(), 'client_secret': RegexStr(r'pi_.*'), 'action_id': AnyInt(), } customer_id = await db_conn.fetchval( 'SELECT stripe_customer_id FROM users WHERE id=$1', factory.user_id) assert customer_id is not None assert customer_id.startswith('cus_') app = cli.app['main_app'] r = await StripeClient(app, stripe_secret_key).get( f'payment_intents?limit=3&customer={customer_id}') assert len(r['data']) == 1 payment_intent = r['data'][0] assert payment_intent['amount'] == 246_90 assert payment_intent[ 'description'] == f'2 tickets for The Event Name ({factory.event_id})' assert payment_intent['metadata'] == { 'purpose': 'buy-tickets', 'event_id': str(factory.event_id), 'tickets_bought': '2', 'reserve_action_id': str(response_data['action_id']), 'user_id': str(factory.user_id), }
async def test_event_export(cli, url, login, factory: Factory): await factory.create_company() await factory.create_cat() await factory.create_user() await factory.create_event( price=12.34, status='published', location_name='Testing Location', location_lat=51.5, location_lng=-0.5, start_ts=datetime(2032, 6, 1, 1, 13, 12, tzinfo=timezone.utc), duration=timedelta(hours=2, minutes=45), youtube_video_id='abcxyz', ) # two tickets await factory.buy_tickets(await factory.create_reservation()) await factory.buy_tickets(await factory.create_reservation()) await login() r = await cli.get(url('export', type='events')) assert r.status == 200 assert r.headers['Content-Disposition'] == RegexStr( r'attachment;filename=nosht_events_\d{4}-\d\d-\d\dT.+\.csv') text = await r.text() data = [dict(r) for r in DictReader(StringIO(text))] assert data == [ { 'id': str(factory.event_id), 'name': 'The Event Name', 'slug': 'the-event-name', 'status': 'published', 'start_time': '2032-06-01T02:13:12+01', 'timezone': 'Europe/London', 'duration_hours': '2.75', 'youtube_video_id': 'abcxyz', 'short_description': RegexStr(r'.*'), 'long_description': RegexStr(r'.*'), 'description_intro': RegexStr(r'.*'), 'description_image': '', 'is_public': 'true', 'location_name': 'Testing Location', 'location_lat': '51.5000000', 'location_lng': '-0.5000000', 'ticket_limit': '', 'image': '', 'ticket_price': '12.34,12.34', 'tickets_booked': '2', 'total_raised': '24.68', 'category_id': str(factory.category_id), 'category_slug': 'supper-clubs', }, ]
async def test_reserve_tickets(cli, url, db_conn, factory: Factory, login): await factory.create_company() await factory.create_cat() await factory.create_user(first_name=None, last_name=None, email='*****@*****.**') await factory.create_event(status='published', price=10) await login(email='*****@*****.**') data = { 'tickets': [ { 't': True, 'first_name': 'Ticket', 'last_name': 'Buyer', 'email': '*****@*****.**', 'allow_marketing': True, }, { 't': True, 'first_name': 'Other', 'last_name': 'Person', 'email': '*****@*****.**', 'extra_info': 'I love to party', 'cover_costs': None, 'allow_marketing': None, }, ], 'ticket_type': factory.ticket_type_id, } r = await cli.json_post(url('event-reserve-tickets', id=factory.event_id), data=data) assert r.status == 200, await r.text() data = await r.json() assert data == { 'booking_token': RegexStr(r'.+'), 'ticket_count': 2, 'extra_donated': None, 'item_price': 10.0, 'total_price': 20.0, 'timeout': AnyInt(), 'client_secret': RegexStr(r'payment_intent_secret_\d+'), 'action_id': AnyInt(), } booking_token = decrypt_json(cli.app['main_app'], data['booking_token'].encode()) reserve_action_id = await db_conn.fetchval("SELECT id FROM actions WHERE type='reserve-tickets'") assert booking_token == { 'user_id': factory.user_id, 'action_id': reserve_action_id, 'event_id': factory.event_id, 'price_cent': 20_00, 'ticket_count': 2, 'event_name': 'The Event Name', }
async def test_cat_event_list(cli, url, db_conn, factory: Factory): await factory.create_company() await factory.create_cat() await factory.create_user() await factory.create_event(status='published') slug = await db_conn.fetchval('SELECT slug FROM categories WHERE id=$1', factory.category_id) r = await cli.get(url('category', category=slug)) assert r.status == 200, await r.text() data = await r.json() assert data == { 'events': [ { 'id': factory.event_id, 'name': 'The Event Name', 'cat_slug': 'supper-clubs', 'slug': 'the-event-name', 'image': 'https://www.example.org/main.png', 'short_description': RegexStr(r'.*'), 'start_ts': '2032-06-28T19:00:00', 'duration': 3600, 'sold_out': False, 'allow_donations': False, 'allow_tickets': True, }, ], } await db_conn.execute("update events set secondary_image='second-image', location_name='loc-name'") r = await cli.get(url('category', category=slug)) assert r.status == 200, await r.text() data = await r.json() assert data == { 'events': [ { 'id': factory.event_id, 'name': 'The Event Name', 'cat_slug': 'supper-clubs', 'slug': 'the-event-name', 'image': 'https://www.example.org/main.png', 'secondary_image': 'second-image', 'short_description': RegexStr(r'.*'), 'location_name': 'loc-name', 'start_ts': '2032-06-28T19:00:00', 'duration': 3600, 'sold_out': False, 'allow_donations': False, 'allow_tickets': True, }, ], }
def test_resolve_sass_path_dev(tmpdir): mktree( tmpdir, { 'pages/foobar.md': '# hello', 'theme': { 'assets/assets/image.png': '*', 'sass/main.scss': 'body {content: resolve_path("/assets/image.png")}', }, }) config = get_config(str(tmpdir)) config.mode = Mode.development assets_grablib(config) mtime = tmpdir.join('theme/sass/main.scss').stat().mtime assert gettree(tmpdir.join('dist')) == { 'assets': { 'image.png': '*', }, 'theme': { 'main.css.map': RegexStr('{.*'), 'main.css': ("body {\n" " content: '/assets/image.png?t=%0.0f'; }\n" "\n" "/*# sourceMappingURL=main.css.map */") % mtime, '.src': { 'main.scss': 'body {content: resolve_path("/assets/image.png")}', }, }, }
async def test_event_ticket_export_host(cli, url, login, factory: Factory, db_conn): await factory.create_company() await factory.create_cat() await factory.create_user(role='host') await factory.create_event(status='published') await factory.book_free(await factory.create_reservation()) await db_conn.execute( "UPDATE tickets SET first_name='foo', last_name='bar'") await login() r = await cli.get(url('event-tickets-export', id=factory.event_id)) assert r.status == 200 text = await r.text() data = [dict(r) for r in DictReader(StringIO(text))] assert data == [ { 'ticket_id': RegexStr(r'.{7}-\d+'), 'ticket_status': 'booked', 'booking_type': 'book-free-tickets', 'booked_at': CloseToNow(delta=3), 'price': '', 'extra_donated': '', 'extra_info': '', 'guest_name': 'foo bar', 'buyer_name': 'foo bar', 'ticket_type_name': 'Standard', }, ]
async def test_event_donations_export(cli, url, login, factory: Factory, db_conn): await factory.create_company() await factory.create_cat() await factory.create_user() await factory.create_donation_option() await factory.create_event(status='published') await factory.create_donation(gift_aid=True) await login() r = await cli.get(url('event-donations-export', id=factory.event_id)) assert r.status == 200 text = await r.text() data = [dict(r) for r in DictReader(StringIO(text))] assert len(data) == 1 assert data[0] == { 'donation_id': RegexStr(r'.{7}-\d+'), 'amount': '20.0', 'user_id': str(factory.user_id), 'user_email': '*****@*****.**', 'donation_option': str(factory.donation_option_id), 'gift_aid': 'True', 'name': 'Frank Spencer', 'timestamp': CloseToNow(delta=3), }
async def test_send(client: AsyncClient, aws: DummyServer): ses = SesClient(client, SesConfig('test_access_key', 'test_secret_key', 'testing-region-1')) message_id = await ses.send_email( '*****@*****.**', 'test email', ['*****@*****.**'], 'this is a test email', html_body='This is a <b>test</b> email.', ) assert message_id == '123-message-id' assert len(aws.app['emails']) == 1 eml = aws.app['emails'][0] assert eml['body'] == { 'Action': 'SendRawEmail', 'Source': '*****@*****.**', 'RawMessage.Data': RegexStr('.+'), 'Destination.ToAddresses.member.1': '*****@*****.**', } assert eml['email'] == { 'Subject': 'test email', 'From': '*****@*****.**', 'MIME-Version': '1.0', 'To': '*****@*****.**', 'payload': [ {'Content-Type': 'text/plain', 'payload': 'this is a test email\n'}, {'Content-Type': 'text/html', 'payload': 'This is a <b>test</b> email.\n'}, ], }
async def test_with_def(email_actor: EmailActor, factory: Factory, dummy_server, db_conn): await factory.create_company() await factory.create_user(email='*****@*****.**') await db_conn.execute_b( 'INSERT INTO email_definitions (:values__names) VALUES :values', values=Values( company=factory.company_id, trigger=Triggers.password_reset.value, subject='{{{ company_name}}} xxx', body='DEBUG:\n{{{ __debug_context__ }}}', ) ) await email_actor.send_emails(factory.company_id, Triggers.password_reset, [UserEmail(id=factory.user_id)]) assert dummy_server.app['log'] == [ ('email_send_endpoint', 'Subject: "Testing xxx", To: "Frank Spencer <*****@*****.**>"'), ] assert len(dummy_server.app['emails']) == 1 email = dummy_server.app['emails'][0] # debug(email) email_context = json.loads(re.search('```(.*?)```', email['part:text/plain'], flags=re.S).group(1)) assert email_context == { 'company_name': 'Testing', 'company_logo': None, 'base_url': 'https://127.0.0.1', 'first_name': 'Frank', 'full_name': 'Frank Spencer', 'unsubscribe_link': RegexStr(r'https://127\.0\.0\.1/api/unsubscribe/\d+/\?sig=[0-9a-f]+'), }
async def test_cat_event_list(cli, url, db_conn, factory: Factory): await factory.create_company() await factory.create_cat() await factory.create_user() await factory.create_event(status='published') slug = await db_conn.fetchval('SELECT slug FROM categories WHERE id=$1', factory.category_id) r = await cli.get(url('category', category=slug)) assert r.status == 200, await r.text() data = await r.json() assert data == { 'events': [ { 'id': factory.event_id, 'name': 'The Event Name', 'cat_slug': 'supper-clubs', 'slug': 'the-event-name', 'image': None, 'short_description': RegexStr('.*'), 'location_name': None, 'start_ts': '2020-01-28T19:00:00', 'duration': None, }, ], }
async def test_set_password(cli, url, factory: Factory, db_conn, login): await factory.create_company() await factory.create_user() pw_before = await db_conn.fetchval('SELECT password_hash FROM users WHERE id=$1', factory.user_id) with pytest.raises(AssertionError): await login(password='******') data = { 'password1': 'testing-new-password', 'password2': 'testing-new-password', 'token': encrypt_json(cli.app['main_app'], factory.user_id), } r = await cli.json_post(url('set-password'), data=data, origin_null=True) assert r.status == 200, await r.text() data = await r.json() assert data == { 'status': 'success', 'auth_token': RegexStr(r'.+'), 'user': { 'id': factory.user_id, 'first_name': 'Frank', 'last_name': 'Spencer', 'email': '*****@*****.**', 'role': 'admin', 'status': 'active', }, } pw_after = await db_conn.fetchval('SELECT password_hash FROM users WHERE id=$1', factory.user_id) assert pw_after != pw_before await login(password='******', captcha=True)
async def test_reserve_tickets_free(cli, url, factory: Factory, login): await factory.create_company() await factory.create_cat() await factory.create_user() await factory.create_event(status='published') await login() data = { 'tickets': [{'t': True, 'first_name': 'Ticket', 'last_name': 'Buyer', 'email': '*****@*****.**'}], 'ticket_type': factory.ticket_type_id, } r = await cli.json_post(url('event-reserve-tickets', id=factory.event_id), data=data) assert r.status == 200, await r.text() data = await r.json() assert data == { 'booking_token': RegexStr(r'.+'), 'ticket_count': 1, 'extra_donated': None, 'item_price': None, 'total_price': None, 'timeout': AnyInt(), 'client_secret': None, 'action_id': AnyInt(), } assert decrypt_json(cli.app['main_app'], data['booking_token'].encode()) == { 'user_id': factory.user_id, 'action_id': AnyInt(), 'event_id': factory.event_id, 'price_cent': None, 'ticket_count': 1, 'event_name': 'The Event Name', }
async def test_upload_logo(cli, url, factory: Factory, db_conn, login, dummy_server): await factory.create_company() await factory.create_user() await login() assert None is await db_conn.fetchval('SELECT logo FROM companies') data = FormData() data.add_field('image', create_image(400, 300), filename='testing.png', content_type='application/octet-stream') r = await cli.post(url('company-upload', field='logo'), data=data, headers={ 'Referer': f'http://127.0.0.1:{cli.server.port}/foobar/', 'Origin': f'http://127.0.0.1:{cli.server.port}', }) assert r.status == 200, await r.text() assert dummy_server.app['images'] == [ ( RegexStr( r'/aws_endpoint_url/testingbucket.example.org/tests/testing/co/logo/\w+/main.png' ), 341, 256, ), ] assert None is not await db_conn.fetchval('SELECT logo FROM companies')
async def test_user_list(cli, settings, send_email, db_conn): expected_msg_ids = [] for i in range(4): uid = str(uuid.uuid4()) await send_email(uid=uid, company_code='whoever', recipients=[{'address': f'{i}@t.com'}]) expected_msg_ids.append(f'{uid}-{i}tcom') await send_email(uid=str(uuid.uuid4()), company_code='different1') await send_email(uid=str(uuid.uuid4()), company_code='different2') r = await cli.get(modify_url('/user/email-test/messages.json', settings, 'whoever')) assert r.status == 200, await r.text() assert r.headers['Access-Control-Allow-Origin'] == '*' data = await r.json() # debug(data) assert data['count'] == 4 msg_ids = [h['external_id'] for h in data['items']] assert msg_ids == list(reversed(expected_msg_ids)) first_item = data['items'][0] assert first_item == { 'id': await db_conn.fetchval('select id from messages where external_id=$1', expected_msg_ids[3]), 'external_id': expected_msg_ids[3], 'send_ts': RegexStr(r'\d{4}-\d{2}-\d{2}.*'), 'update_ts': RegexStr(r'\d{4}-\d{2}-\d{2}.*'), 'status': 'send', 'to_first_name': None, 'to_last_name': None, 'to_user_link': None, 'to_address': '*****@*****.**', 'company_id': await db_conn.fetchval('select id from companies where code=$1', 'whoever'), 'method': 'email-test', 'subject': 'test message', 'tags': [expected_msg_ids[3][:-6]], 'from_name': 'Sender Name', 'cost': None, 'extra': None, } r = await cli.get(modify_url('/user/email-test/messages.json', settings, '__all__')) assert r.status == 200, await r.text() data = await r.json() assert data['count'] == 6 r = await cli.get(modify_url('/user/email-test/messages.html', settings, '__all__')) assert r.status == 200, await r.text() text = await r.text() assert '<caption>Results: <b>6</b></caption>' in text assert text.count('.com</a>') == 6
async def test_event_host_updates(email_actor: EmailActor, factory: Factory, dummy_server): await factory.create_company() await factory.create_cat() await factory.create_user() await factory.create_event( start_ts=offset_from_now(days=5), price=10, status='published', ) anne = await factory.create_user(first_name='anne', email='*****@*****.**') await factory.buy_tickets(await factory.create_reservation(anne)) assert len(dummy_server.app['emails']) == 1 assert 1 == await email_actor.send_event_host_updates.direct() assert len(dummy_server.app['emails']) == 2 email = dummy_server.app['emails'][1] # debug(email) # from pathlib import Path # Path('email.html').write_text(email['part:text/html']) assert email['Subject'] == 'The Event Name Update from Testing' assert email['To'] == 'Frank Spencer <*****@*****.**>' html = email['part:text/html'] assert 'The Event Name is coming up in <strong>5</strong>' in html assert ( '<div class="stat-label">Tickets Booked in the last day</div>\n' '<div class="stat-value">\n' ' <span class="large">1</span>\n' '</div>\n' '\n' '<div class="stat-label">Tickets Booked Total</div>\n' '<div class="stat-value">\n' ' <span class="large">1</span>\n' '</div>\n' '\n' '<div class="stat-label">Total made from ticket sales</div>\n' '<div class="stat-value">\n' ' <span class="large">£10.00</span>\n' '</div>\n' '\n' '<p>Guests can book your event by going to</p>\n' '\n' '<div class="text-center highlighted">https://127.0.0.1/supper-clubs/the-event-name/</div>\n' ) in html assert '<strong>Congratulations, all tickets have been booked - your event is full.</strong>' not in html assert ( f'<a href="https://127.0.0.1/dashboard/events/{factory.event_id}/"><span>Event Dashboard</span></a>' ) in html assert RegexStr( '.*The Event Name is coming up in <strong>5</strong> days on <strong>.*' ) == html
async def test_osm_error(cli, dummy_server, caplog): r = await cli.get('/map.jpg?lat=45&lng=0&zoom=6&width=200&height=100') content = await r.read() assert r.status == 200, content image = Image.open(BytesIO(content)) assert image.size == (200, 100) assert len(caplog.records) == 4 r = caplog.records[0] assert r.getMessage() == RegexStr(r"unexpected status 429 from 'http://localhost:\d+/osm/6/\d\d/\d\d\.png'")
async def test_reserve_tickets_cover_costs(cli, url, factory: Factory, login): await factory.create_company() await factory.create_cat(cover_costs_message='Help!', cover_costs_percentage=12.5) await factory.create_user(first_name=None, last_name=None, email='*****@*****.**') await factory.create_event(status='published', price=10) await login(email='*****@*****.**') data = { 'tickets': [ { 't': True, 'first_name': 'Ticket', 'last_name': 'Buyer', 'email': '*****@*****.**', 'cover_costs': True, }, { 't': True, }, ], 'ticket_type': factory.ticket_type_id, } r = await cli.json_post(url('event-reserve-tickets', id=factory.event_id), data=data) assert r.status == 200, await r.text() data = await r.json() assert data == { 'booking_token': RegexStr(r'.+'), 'ticket_count': 2, 'extra_donated': 2.5, 'item_price': 10.0, 'total_price': 22.50, 'timeout': AnyInt(), 'client_secret': RegexStr(r'payment_intent_secret_\d+'), 'action_id': AnyInt(), } assert decrypt_json(cli.app['main_app'], data['booking_token'].encode()) == { 'user_id': factory.user_id, 'action_id': AnyInt(), 'event_id': factory.event_id, 'price_cent': 22_50, 'ticket_count': 2, 'event_name': 'The Event Name', }
async def test_event_public(cli, url, factory: Factory, db_conn): await factory.create_company() await factory.create_cat() await factory.create_user() await factory.create_event(status='published', location_name='Testing Location', location_lat=51.5, location_lng=-0.5) cat_slug, event_slug = await db_conn.fetchrow( """ SELECT cat.slug, e.slug FROM events AS e JOIN categories cat on e.category = cat.id WHERE e.id=$1 """, factory.event_id) r = await cli.get(url('event-get', category=cat_slug, event=event_slug)) assert r.status == 200, await r.text() data = await r.json() # debug(data) assert data == { 'event': { 'id': factory.event_id, 'name': 'The Event Name', 'image': None, 'short_description': RegexStr('.*'), 'long_description': RegexStr('.*'), 'category_content': None, 'location': { 'name': 'Testing Location', 'lat': 51.5, 'lng': -0.5, }, 'price': None, 'start_ts': '2020-01-28T19:00:00', 'duration': None, 'tickets_available': None, 'host_id': factory.user_id, 'host_name': 'Frank Spencer', 'stripe_key': None, 'currency': 'gbp', }, }
async def test_add_image(cli, url, factory: Factory, db_conn, login, dummy_server): await factory.create_company() await factory.create_cat() await factory.create_user() await factory.create_donation_option() await login() assert None is await db_conn.fetchval('SELECT image FROM donation_options') data = FormData() data.add_field('image', create_image(700, 500), filename='testing.png', content_type='application/octet-stream') r = await cli.post(url('donation-image-upload', pk=factory.donation_option_id), data=data, headers={ 'Referer': f'http://127.0.0.1:{cli.server.port}/foobar/', 'Origin': f'http://127.0.0.1:{cli.server.port}', }) assert r.status == 200, await r.text() assert sorted(dummy_server.app['images']) == [ ( RegexStr( r'/aws_endpoint_url/testingbucket.example.org/tests/testing/supper-clubs/\d+/\w+/main.png' ), 672, 480, ), ( RegexStr( r'/aws_endpoint_url/testingbucket.example.org/tests/testing/supper-clubs/\d+/\w+/thumb.png' ), 400, 200, ), ] assert None is not await db_conn.fetchval( 'SELECT image FROM donation_options') assert sum('DELETE aws_endpoint_url/' in e for e in dummy_server.app['log']) == 0
async def test_book_multiple(donorfy: DonorfyActor, factory: Factory, dummy_server, cli, url, login): await factory.create_company() await factory.create_user() await factory.create_cat() await factory.create_user(first_name='T', last_name='B', email='*****@*****.**') await factory.create_event(status='published', price=10) await login(email='*****@*****.**') data = { 'tickets': [ { 't': True, 'email': '*****@*****.**' }, { 't': True, 'email': '*****@*****.**' }, ], 'ticket_type': factory.ticket_type_id, } r = await cli.json_post(url('event-reserve-tickets', id=factory.event_id), data=data) assert r.status == 200, await r.text() action_id = (await r.json())['action_id'] await factory.fire_stripe_webhook(action_id) trans_data = dummy_server.app['post_data'][ 'POST donorfy_api_root/standard/transactions'] assert len(trans_data) == 1 assert trans_data[0] == { 'ExistingConstituentId': '123456', 'Channel': 'nosht-supper-clubs', 'Currency': 'gbp', 'Campaign': 'supper-clubs:the-event-name', 'PaymentMethod': 'Payment Card via Stripe', 'Product': 'Event Ticket(s)', 'Fund': 'Unrestricted General', 'Department': '220 Ticket Sales', 'BankAccount': 'Unrestricted Account', 'DatePaid': CloseToNow(), 'Amount': 20.0, 'ProcessingCostsAmount': 0.5, 'Quantity': 2, 'Acknowledgement': 'supper-clubs-thanks', 'AcknowledgementText': RegexStr('Ticket ID: .*'), 'Reference': 'Events.HUF:supper-clubs the-event-name', 'AddGiftAidDeclaration': False, 'GiftAidClaimed': False, }
async def test_user_export(cli, url, login, factory: Factory): await factory.create_company() await factory.create_cat() await factory.create_user(receive_emails=False) await factory.create_event(status='published', price=10) await login() data = { 'tickets': [{ 't': True, 'email': '*****@*****.**' }], 'ticket_type': factory.ticket_type_id, } r = await cli.json_post(url('event-reserve-tickets', id=factory.event_id), data=data) assert r.status == 200, await r.text() await factory.buy_tickets(await factory.create_reservation()) r = await cli.get(url('export', type='users')) assert r.status == 200 text = await r.text() data = [dict(r) for r in DictReader(StringIO(text))] assert data == [ { 'id': str(factory.user_id), 'role': 'admin', 'status': 'active', 'first_name': 'Frank', 'last_name': 'Spencer', 'email': '*****@*****.**', 'phone_number': '', 'stripe_customer_id': 'customer-id', 'receive_emails': 'false', 'allow_marketing': 'false', 'created_ts': RegexStr(r'\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\+00'), 'active_ts': RegexStr(r'\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\+00'), 'tickets': '2', }, ]
async def test_host_signup_email(cli, url, factory: Factory, db_conn, dummy_server, settings): await factory.create_company() assert 0 == await db_conn.fetchval('SELECT COUNT(*) FROM users') data = { 'email': '*****@*****.**', 'name': 'Jane Doe', 'grecaptcha_token': '__ok__', } r = await cli.post(url('signup-host', site='email'), data=json.dumps(data)) assert r.status == 200, await r.text() response_data = await r.json() assert 1 == await db_conn.fetchval('SELECT COUNT(*) FROM users') user = await db_conn.fetchrow( 'SELECT id, company, first_name, last_name, email, role, status FROM users' ) assert response_data == { 'user': { 'id': user['id'], 'name': 'Jane Doe', 'email': '*****@*****.**', 'role': 'host', }, } assert dict(user) == { 'id': AnyInt(), 'company': factory.company_id, 'first_name': 'Jane', 'last_name': 'Doe', 'email': '*****@*****.**', 'role': 'host', 'status': 'pending', } assert dummy_server.app['log'] == [ ('grecaptcha', '__ok__'), ( 'email_send_endpoint', 'Subject: "Testing Account Created (Action required)", To: "Jane Doe <*****@*****.**>"', ), ] email = dummy_server.app['emails'][0]['part:text/plain'] assert 'Confirm Email' in email assert 'Create & Publish Events' not in email token = re.search('/set-password/\?sig=([^"]+)', email).group(1) token_data = json.loads( fernet.Fernet(settings.auth_key).decrypt(token.encode()).decode()) assert token_data == { 'user_id': user['id'], 'nonce': RegexStr('.{20}'), }
async def test_user_actions(cli, url, login, factory: Factory, db_conn): await factory.create_company() await factory.create_user() await login() r = await cli.get(url('user-actions', pk=factory.user_id)) assert r.status == 200, await r.text() data = await r.json() assert data == { 'actions': [ { 'id': await db_conn.fetchval('SELECT id FROM actions'), 'ts': CloseToNow(), 'type': 'login', 'extra': { 'ip': '127.0.0.1', 'ua': RegexStr(r'Python.*'), 'url': RegexStr(r'http://127.0.0.1:\d+/api/auth-token/'), }, }, ], }
async def test_send_names(client: AsyncClient, aws: DummyServer): ses = SesClient( client, SesConfig('test_access_key', 'test_secret_key', 'testing-region-1')) await ses.send_email( '*****@*****.**', 'test email', [SesRecipient('*****@*****.**', 'John', 'Doe')], 'this is a test email', cc=[ SesRecipient('*****@*****.**'), SesRecipient('*****@*****.**', 'CC2'), SesRecipient('*****@*****.**', None, 'CC3'), SesRecipient('*****@*****.**', 'Anna, Bob', 'CC4'), ], bcc=['*****@*****.**'], ) assert len(aws.app['emails']) == 1 eml = aws.app['emails'][0] assert eml['body'] == { 'Action': 'SendRawEmail', 'Source': '*****@*****.**', 'RawMessage.Data': RegexStr('.+'), 'Destination.ToAddresses.member.1': '*****@*****.**', 'Destination.CcAddresses.member.1': '*****@*****.**', 'Destination.CcAddresses.member.2': '*****@*****.**', 'Destination.CcAddresses.member.3': '*****@*****.**', 'Destination.CcAddresses.member.4': '*****@*****.**', 'Destination.BccAddresses.member.1': '*****@*****.**', } assert eml['email'] == { 'Subject': 'test email', 'From': '*****@*****.**', 'Content-Transfer-Encoding': '7bit', 'MIME-Version': '1.0', 'To': 'John Doe <*****@*****.**>', 'Cc': '[email protected], CC2 <*****@*****.**>, CC3 <*****@*****.**>,\n "Anna, Bob CC4" <*****@*****.**>', 'Bcc': '*****@*****.**', 'payload': [{ 'Content-Type': 'text/plain', 'payload': 'this is a test email\n' }], }
async def test_stripe_existing_customer_card(cli, db_conn, stripe_factory: Factory): await stripe_factory.create_company(stripe_public_key=stripe_public_key, stripe_secret_key=stripe_secret_key) await stripe_factory.create_cat() await stripe_factory.create_user() await stripe_factory.create_event(ticket_limit=10) res: Reservation = await stripe_factory.create_reservation() app = cli.app['main_app'] customers = await stripe_request(app, BasicAuth(stripe_secret_key), 'get', 'customers?limit=1') customer = customers['data'][0] customer_id = customer['id'] await db_conn.execute('UPDATE users SET stripe_customer_id=$1 WHERE id=$2', customer_id, stripe_factory.user_id) m = StripePayModel( stripe_token='tok_visa', stripe_client_ip='0.0.0.0', stripe_card_ref='{last4}-{exp_year}-{exp_month}'.format(**customer['sources']['data'][0]), booking_token=encrypt_json(app, res.dict()), ) await stripe_pay(m, stripe_factory.company_id, stripe_factory.user_id, app, db_conn) new_customer_id = await db_conn.fetchval('SELECT stripe_customer_id FROM users WHERE id=$1', stripe_factory.user_id) assert new_customer_id == customer_id extra = await db_conn.fetchval("SELECT extra FROM actions WHERE type='buy-tickets'") extra = json.loads(extra) assert extra == { 'new_card': False, 'new_customer': False, 'charge_id': RegexStr('ch_.+'), 'card_expiry': RegexStr('\d+/\d+'), 'card_last4': '4242', }
async def test_root(cli, url, factory: Factory): await factory.create_company() await factory.create_cat() await factory.create_user() await factory.create_event(highlight=True, status='published', location_name='Testing Location') r = await cli.get(url('index')) assert r.status == 200, await r.text() data = await r.json() assert data == { 'categories': [ { 'id': factory.category_id, 'name': 'Supper Clubs', 'slug': 'supper-clubs', 'image': 'https://www.example.org/main.png', 'description': None, }, ], 'highlight_events': [ { 'id': factory.event_id, 'name': 'The Event Name', 'cat_slug': 'supper-clubs', 'slug': 'the-event-name', 'image': 'https://www.example.org/main.png', 'secondary_image': None, 'short_description': RegexStr(r'.*'), 'location_name': 'Testing Location', 'start_ts': '2032-06-28T19:00:00', 'duration': 3600, 'sold_out': False, 'allow_donations': False, 'allow_tickets': True, }, ], 'company': { 'id': factory.company_id, 'name': 'Testing', 'image': 'https://www.example.org/main.png', 'currency': 'gbp', 'stripe_public_key': 'stripe_key_xxx', 'footer_links': None, }, 'user': None, }
async def test_retrieve_missing_email_defs(cli, url, login, factory: Factory): await factory.create_company() await factory.create_user() await login() r = await cli.get(url('email-defs-retrieve', trigger=Triggers.event_reminder.value)) assert r.status == 200, await r.text() data = await r.json() assert data == { 'trigger': 'event-reminder', 'customised': False, 'active': True, 'subject': '{{{ event_name }}} Upcoming', 'title': '{{ company_name }}', 'body': RegexStr(r'.*'), }