Exemple #1
0
 async def execute(self, m: Model):
     res = Reservation(**decrypt_json(self.app, m.booking_token, ttl=self.settings.ticket_ttl))
     assert self.session['user_id'] == res.user_id, "user ids don't match"
     async with self.conn.transaction():
         await self.conn.execute('DELETE FROM tickets WHERE reserve_action=$1', res.action_id)
         await self.conn.execute('SELECT check_tickets_remaining($1, $2)', res.event_id, self.settings.ticket_ttl)
         await record_action(self.request, self.session['user_id'], ActionTypes.cancel_reserved_tickets)
Exemple #2
0
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',
    }
Exemple #3
0
async def authenticate_token(request):
    m = await parse_request(request, AuthTokenModel)
    auth_session = decrypt_json(request.app, m.token, ttl=10)
    session = await new_session(request)
    session.update(auth_session)

    await record_action(request, session['user_id'], ActionTypes.login)
    return json_response(status='success')
Exemple #4
0
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',
    }
Exemple #5
0
async def set_password(request):
    conn = request['conn']
    m = await parse_request(request,
                            PasswordModel,
                            headers_=HEADER_CROSS_ORIGIN)
    user_id = decrypt_json(request.app,
                           m.token.encode(),
                           ttl=3600 * 24 * 7,
                           headers_=HEADER_CROSS_ORIGIN)
    nonce = m.token[:20]

    already_used = await conn.fetchval(
        """
        SELECT 1 FROM actions
        WHERE user_id=$1 AND type='password-reset' AND now() - ts < interval '7 days' AND extra->>'nonce'=$2
        """,
        user_id,
        nonce,
    )
    if already_used:
        raise JsonErrors.HTTP470(
            message='This password reset link has already been used.',
            headers_=HEADER_CROSS_ORIGIN)

    user = await conn.fetchrow(
        'SELECT id, first_name, last_name, email, role, status, company FROM users WHERE id=$1',
        user_id)
    user = dict(user)
    if user.pop('company') != request['company_id']:
        # should not happen
        raise JsonErrors.HTTPBadRequest(
            message='company and user do not match')
    if user['status'] == 'suspended':
        raise JsonErrors.HTTP470(
            message='user suspended, password update not allowed.',
            headers_=HEADER_CROSS_ORIGIN)

    pw_hash = mk_password(m.password1, request.app['settings'])
    del m

    await conn.execute(
        "UPDATE users SET password_hash=$1, status='active' WHERE id=$2",
        pw_hash, user_id)
    await record_action(request,
                        user_id,
                        ActionTypes.password_reset,
                        nonce=nonce)
    return successful_login(user, request.app, HEADER_CROSS_ORIGIN)
Exemple #6
0
 async def execute(self, m: Model):
     # no ttl since a user may try to cancel a reservation after it has expired
     res = Reservation(**decrypt_json(self.app, m.booking_token))
     async with self.conn.transaction():
         user_id = await self.conn.fetchval(
             'SELECT user_id FROM actions WHERE id=$1', res.action_id)
         v = await self.conn.execute(
             "DELETE FROM tickets WHERE reserve_action=$1 AND status='reserved'",
             res.action_id)
         if v == 'DELETE 0':
             # no tickets were deleted
             raise JsonErrors.HTTPBadRequest(message='no tickets deleted')
         await self.conn.execute('SELECT check_tickets_remaining($1, $2)',
                                 res.event_id, self.settings.ticket_ttl)
         await record_action(self.request,
                             user_id,
                             ActionTypes.cancel_reserved_tickets,
                             event_id=res.event_id)
Exemple #7
0
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',
    }
Exemple #8
0
async def set_password(request):
    h = {'Access-Control-Allow-Origin': 'null'}
    conn = request['conn']
    m = await parse_request(request, PasswordModel, error_headers=h)
    data = decrypt_json(request.app, m.token, ttl=3600 * 24 * 7)
    user_id, nonce = data['user_id'], data['nonce']

    already_used = await conn.fetchval(
        """
        SELECT 1 FROM actions
        WHERE user_id=$1 AND type='password-reset' AND now() - ts < interval '7 days' AND extra->>'nonce'=$2
        """, user_id, nonce)
    if already_used:
        raise JsonErrors.HTTP470(
            message='This password reset link has already been used.')

    company_id, status = await conn.fetchrow(
        'SELECT company, status FROM users WHERE id=$1', user_id)
    if company_id != request['company_id']:
        # should not happen
        raise JsonErrors.HTTPBadRequest(
            message='company and user do not match')
    if status == 'suspended':
        raise JsonErrors.HTTP470(
            message='user suspended, password update not allowed.')

    pw_hash = mk_password(m.password1, request.app['settings'])
    del m

    await conn.execute(
        "UPDATE users SET password_hash=$1, status='active' WHERE id=$2",
        pw_hash, user_id)
    await record_action(request,
                        user_id,
                        ActionTypes.password_reset,
                        nonce=nonce)
    return json_response(status='success', headers_=h)
Exemple #9
0
    assert r.status == 200, await r.text()
    data = await r.json()
    assert data == {
        'booking_token': RegexStr('.+'),
        'ticket_count': 2,
        'item_price_cent': 10_00,
        'total_price_cent': 20_00,
        'user': {
            'id': factory.user_id,
            'name': 'Ticket Buyer',
            'email': '*****@*****.**',
            'role': 'admin',
        },
        'timeout': 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',
    }

    users = [
        dict(r) for r in await db_conn.fetch(
            'SELECT first_name, last_name, email, role FROM users ORDER BY id')
    ]