def add_user(account_id, user_id): """ Adds a user to the account. Args: account_id: The id of the account the user will belong to. user_id: The id of the user to add to the account. Raises: AccountNotFoundError: No account was found matching the account_id UserNotFoundError: No user was found matching the user_id UserAssociationError: The user is already associated wit the account """ # lookup account account = lookup_account_by_id(account_id) # lookup user user = lookup_user_by_id(user_id) # add the user to the account assoc = UserAccountAssociation() assoc.user = user account.users.append(assoc) try: Session.flush() except FlushError: raise ex.UserAssociationError("The user is already associated wit the account")
def user_update(user_id, user_info): """ Replaces a user's data with the information located in user_info """ user = lookup_user_by_id(user_id) for (key, value) in user_info.iteritems(): if key == "first_name" and value is not None: user.first_name = value elif key == "last_name" and value is not None: user.last_name = value elif key == "email" and value is not None: try: lookup_user_by_email(value) except: user.email = value elif key == "password" and value is not None: user.set_password(value) elif key == "active" and value is not None: if value: user.activate() else: user.deactivate() send_activation_mail.delay(user_id) elif key == "social" and value is not None: user.meta['social'] = value elif key == "address" and value is not None: user.meta['address'] = value elif key == "crm" and value is not None: user.meta['crm'] = value elif key == "local" and value is not None: user.meta['local'] = value return user_to_dict(user)
def single_notification_mail(event_id, user_id): """Sends a notification mail informing an attendee to bring his or her tickets""" user = lookup_user_by_id(user_id) event = lookup_event_by_id(event_id) # do not send if user already received one if 'received_event_notification' in user.meta: blogger.info( 'skipping event notification since user already has received one.') return subject = "Reminder: %s (%s)" % (event.name, event.account.name) html_content = env.get_template('event_in_48_hours.html').render( user=user, event=event) plain_content = env.get_template('event_in_48_hours.txt').render( user=user, event=event) blogger.info('sending event notification mail to user %s' % user_id) success = mail_user(user_id, subject, html_content, plain_content) # success = random.choice([True, True, True, True, True, False]) if not success: single_notification_mail.retry(countdown=120 + random.randint(1, 60)) else: user.meta['received_event_notification'] = False transaction.commit()
def mail_user(user_id, subject, html_content, plain_content="", fake=False): """ Sends the user a templated mail with a specific content. """ try: user = lookup_user_by_id(user_id) html_template = env.get_template('base.html').render( user=user, content=html_content) plain_template = env.get_template('base.txt').render( user=user, plain_content=plain_content) if user.email is None: raise Exception('user has no email address') blogger.info('sending mail to user %s (%s)' % (user.id, user.email)) sender = "Tickee <*****@*****.**>" if not fake: send_email(sender, user.email, subject, html_template, plain_template, noreply=True) except: blogger.exception('failed sending user mail to user %s' % user_id) return False else: return True
def paper(client_id, order_key, user_id): """ Skips the payment provider and finishes the order as a paper ticket """ order = lookup_order_by_key(order_key) user = lookup_user_by_id(user_id) order.checkout(user) order.meta['paper'] = True result = order_to_dict(order, include_ordered_tickets=True) finish_order(order, send_mail=False) return result
def ticket_update(ticket_code, ticket_info): """Updates a ticket, supports the following updates: - user changes """ user_id = ticket_info.get('user_id') ticket = lookup_ticket_by_code(ticket_code) user = lookup_user_by_id(user_id) ticket.user_id = user.id return ticket_to_dict(ticket)
def user_details(user_id, activation_token): """ Returns information about the user. If an activation token is added, it will return a NoUserFound exception if the token does not match. """ user = lookup_user_by_id(user_id) if activation_token is not None: if user.activation_key == activation_token or\ user.is_valid_recovery_code(activation_token): return user_to_dict(user, include_name=True) else: raise ex.UserNotFoundError() return user_to_dict(user, include_name=True, include_active=True)
def account_create(user_id, account_info): """ Entrypoint for creating an account and returning its information back as a dictionary. Args: user_id: Id of the user who will own the account account_info: Dictionary containing the following keys: - short_name (required) - email (required) - name - url - vat - subtitle - handling_fee """ # create account account = create_account(account_info.get('short_name'), account_info.get('email')) # add optional information account.full_name = account_info.get('name') account.website = account_info.get('url') account.vat_percentage = account_info.get('vat') account.meta['subtitle'] = account_info.get('subtitle') account.meta['theme'] = account_info.get('theme') account.set_handling_fee(account_info.get('handling_fee') or 0) # add default subscription account.subscription = Subscription(FREE) # create default oauth2 client client = create_oauth_client() account.client_id = client.id # connect user to account user = lookup_user_by_id(user_id) assoc = UserAccountAssociation() assoc.user = user assoc.account_id = account.id account.users.append(assoc) # set preferred payment service provider account.meta['preferred_psp'] = account_info.get('preferred_psp') # create psp object create_payment_provider(account, {}, account_info.get('preferred_psp')) # set currency account.set_currency(account_info.get('currency')) # send account welcome mail send_account_welcome_mail.apply_async(args=[user.id, account.id], countdown=10) account_info = account_to_dict(account) return account_info
def gift(client_id, order_key, user_id=None): """ Skips the payment provider and finishes the order as a gift """ order = lookup_order_by_key(order_key) if user_id is not None: user = lookup_user_by_id(user_id) else: user = None order.checkout(user) order.meta['gifted'] = True result = order_to_dict(order, include_ordered_tickets=True) finish_order(order, as_guest=True) return result
def from_user(client_id, user_id, include_failed=False): """ Lists all tickets of a user. If client_id is None, all tickets will be returned. Otherwise only tickets related to that account will be shown. """ user = lookup_user_by_id(user_id) tickets = user.tickets if client_id is not None: account = lookup_account_for_client(client_id) tickets = tickets.join("ticket_order", "order", "account").filter(Account.id == account.id) return map(ticket_to_dict, tickets.all())
def from_user(client_id, user_id, include_failed=False): """ Lists all orders of a user """ user = lookup_user_by_id(user_id) orders = user.orders if client_id is not None: account = lookup_account_for_client(client_id) orders = orders.filter_by(account_id=account.id) if not include_failed: orders = orders.filter(Order.status == states.PURCHASED) return map( lambda o: order_to_dict2(o, fields=['account', 'key', 'events']), orders.all())
def order_new(client_id, user_id, tickettype_id, amount, account_short=None, as_guest=False, as_paper=False): """ Starts a new order session or retrieves one that was still active. Args: client_id user_id: Id of the user to start a session for. """ timeout_sessions(600) # assert permission to order tickettype if client_id is not None: require_tickettype_owner(client_id, tickettype_id) # get account to create order for. if account_short is not None: account = lookup_account_by_name(account_short) else: account = lookup_account_for_client(client_id) # start an order or get current one. if user_id is not None: user = lookup_user_by_id(user_id) order = start_order(user, account) else: order = start_order(None, account) # set order as guest (optional) if as_guest: order.meta['gifted'] = True # set order as paper ticket (optional) if as_paper: order.meta['paper'] = True add_tickets(order, tickettype_id, amount) # build successful order order_info = order_to_dict(order) return order_info
def validate_password(user_id, password): """ Entrypoint for verifying if there exists a user matching email & password """ user = lookup_user_by_id(user_id) # valid password if user.check_password(password): user.last_login = datetime.datetime.utcnow() result = dict( user=user_to_dict(user), accounts=map( lambda a: account_to_dict2(a, fields=["short_name", "name"]), lookup_accounts_of_user(user))) return result # invalid password else: raise ex.UserNotFoundError()
def send_account_welcome_mail(user_id, account_id): """Sends an email to the account owner welcoming him to tickee and provides him a link to activate his user account""" user = lookup_user_by_id(user_id) account = lookup_account_by_id(account_id) subject = "Your tickee account has been created" html_content = env.get_template('account_welcome.html').render( user=user, account=account) plain_content = env.get_template('account_welcome.txt').render( user=user, account=account) blogger.info('sending event notification mail to user %s' % user_id) success = mail_user(user_id, subject, html_content, plain_content) # success = random.choice([True, True, True, True, True, False]) if not success: send_account_welcome_mail.retry(countdown=120) else: transaction.commit()
def checkout_order(client_id, order_key, payment_required=True, redirect_url=None, user_id=None): """ Checks out the order and returns the redirect url necessary for the payment. """ """ Locks an order so no other ticket orders can be added to it and links the accounts payment provider to it. Args: order_key: Key of the order payment_required Skips payment provider if set to False, defaults to True redirect_url URL used by paymentprovider to redirect user after purchase user_id Allows late-binding of user to the order during checkout phase. Only gets bound when the order previously did not have a user connected to it. Returns: The payment information necessary to complete the order. Raises: OrderLockedError if the order has already been checked out. """ result = dict() try: order = om.lookup_order_by_key(order_key) # assure order has not been locked before if order.is_locked(): raise ex.OrderLockedError("the order has already been checked out.") if user_id is not None: user = lookup_user_by_id(user_id) else: user = None order.checkout(user) order.touch() order.meta['redirect_url'] = redirect_url # payment is necessary when total is not zero and not a gift if payment_required and order.get_total() > 0: # the organising account has no psp set up if len(order.account.paymentproviders) == 0: raise ex.PaymentError("the account has no payment provider configured to handle an order.") # tickettype has currency allowed by psp # order_currency = order.account.paymentproviders[0].get_info("currency") # if order_currency != tickettype.currency_id: # raise ex.CurrencyError("not allowed to order with this currency.") # link payment provider to order account = order.account psp = lookup_payment_provider(account.id) # DEFAULT PSP HACK! if psp is None: psp = lookup_payment_provider(21) order.payment_provider_id = psp.get_provider_info().id payment_info = psp.checkout_order(order) if payment_info is None: raise ex.PaymentError("received error from payment service provider.") result['payment_info'] = payment_info result['status'] = order.status # no payment necessary, mark as purchased. else: result['status'] = order.status finish_order(order) except ex.TickeeError as e: blogger.error("failed checking out order %s: %s" % (order_key, e)) transaction.abort() return marshalling.error(e) else: order = om.lookup_order_by_key(order_key) result['order'] = order_to_dict(order, include_ordered_tickets=True, include_total=True) transaction.commit() return result
def list_accounts(user_id=None, include_inactive=False): """ Returns a list of all accounts connected to the user.""" user = lookup_user_by_id(user_id) accounts = lookup_accounts_of_user(user, include_inactive=include_inactive) return map(account_to_dict, accounts)
def recover_password(user_id): """ Generates a recovery key and mails it to the user """ user = lookup_user_by_id(user_id) user.create_recovery_code() send_recovery_mail(user.id)
def user_deactivate(user_id): """ deactivates the user """ user = lookup_user_by_id(user_id) user.deactivate() return user_to_dict(user)