Exemple #1
0
    def really_send(self, model_instance, raise_errors=False):
        """
        Actually send an email to a particular model instance (i.e. a particular attendee).

        Doesn't perform any kind of checks at all if we should be sending this, just immediately sends the email
        no matter what.

        NOTE: use send_if_should() instead of calling this method unless you 100% know what you're doing.
        NOTE: send_email() fails if c.SEND_EMAILS is False
        """
        try:
            subject = self.computed_subject(model_instance)
            format = 'text' if self.template.endswith('.txt') else 'html'
            send_email(self.sender,
                       model_instance.email,
                       subject,
                       self.render(model_instance),
                       format,
                       model=model_instance,
                       cc=self.cc,
                       ident=self.ident)
        except Exception:
            log.error('error sending {!r} email to {}',
                      self.subject,
                      model_instance.email,
                      exc_info=True)
            if raise_errors:
                raise
    def process_group_payment(self, session, payment_id, stripeToken):
        charge = Charge.get(payment_id)
        [group] = charge.groups
        message = charge.charge_cc(session, stripeToken)
        if message:
            raise HTTPRedirect('group_members?id={}&message={}', group.id,
                               message)
        else:
            group.amount_paid += charge.dollar_amount

            session.merge(group)
            if group.is_dealer:
                try:
                    send_email.delay(
                        c.MARKETPLACE_EMAIL,
                        c.MARKETPLACE_EMAIL,
                        'Dealer Payment Completed',
                        render('emails/dealers/payment_notification.txt',
                               {'group': group},
                               encoding=None),
                        model=group.to_dict('id'))
                except Exception:
                    log.error(
                        'unable to send dealer payment confirmation email',
                        exc_info=True)
            raise HTTPRedirect('group_members?id={}&message={}', group.id,
                               'Your payment has been accepted!')
Exemple #3
0
 def swallow_exception(*args, **kwargs):
     try:
         return func(*args, **kwargs)
     except Exception:
         log.error(
             "Exception raised, but we're going to ignore it and continue.",
             exc_info=True)
Exemple #4
0
    def attendees_by_state(self, out, session):
        # Result of set(map(lambda x: x.state, SearchEngine(db_file_dir="/srv/reggie/data").ses.query(SimpleZipcode))) -- literally all the states uszipcode knows about
        states = [
            'SD', 'IL', 'WY', 'NV', 'NJ', 'NM', 'UT', 'OR', 'TX', 'NE', 'MS',
            'FL', 'VA', 'HI', 'KY', 'MO', 'NY', 'WV', 'DC', 'AR', 'MT', 'MD',
            'SC', 'NC', 'KS', 'OH', 'PR', 'CO', 'IN', 'VT', 'LA', 'ND', 'AZ',
            'AK', 'AL', 'CT', 'TN', 'PA', 'IA', 'WA', 'ME', 'NH', 'MA', 'ID',
            'OK', 'WI', 'GA', 'CA', 'DE', 'MN', 'MI', 'RI'
        ]
        total_count = session.attendees_with_badges().count()

        out.writerow(['# of Attendees', 'State', '% of Total Attendees'])

        for state in states:
            try:
                zip_codes = list(
                    map(
                        lambda x: x.zipcode,
                        SearchEngine(db_file_dir="/srv/reggie/data").by_state(
                            state, returns=None)))
            except Exception as e:
                log.error("Error calling SearchEngine: " + e)
            else:
                current_count = session.attendees_with_badges().filter(
                    Attendee.zip_code.in_(zip_codes)).count()
                if current_count:
                    out.writerow([
                        current_count, state,
                        "%.2f" % float(current_count / total_count * 100)
                    ])
Exemple #5
0
def check_id_for_model(model, **params):
    message = None
    session = params['session']
    model_id = params.get('id')

    if not model_id:
        message = "No ID provided. Try using a different link or going back."
    elif model_id == 'None':
        # Some pages use the string 'None' is indicate that a new model should be created, so this is a valid ID
        pass
    else:
        try:
            if not isinstance(model_id, uuid.UUID):
                uuid.UUID(model_id)
        except ValueError:
            message = "That ID is not a valid format. Did you enter or edit it manually or paste it incorrectly?"
        else:
            if not session.query(model).filter(model.id == model_id).first():
                message = "The ID provided was not found in our database."

    if message:
        log.error("check_id {} error: {}: id={}", model.__name__, message,
                  model_id)
        raise HTTPRedirect('../preregistration/not_found?id={}&message={}',
                           model_id, message)
Exemple #6
0
 def radial_zip_data(self, out, session, **params):
     if params.get('radius'):
         try:
             res = SearchEngine(
                 db_file_dir="/srv/reggie/data").by_coordinates(
                     self.center.lat,
                     self.center.lng,
                     radius=int(params['radius']),
                     returns=None)
         except Exception as e:
             log.error("Error calling SearchEngine: " + e)
         else:
             out.writerow([
                 '# of Attendees', 'City', 'State', 'Zipcode',
                 'Miles from Event', '% of Total Attendees'
             ])
             if len(res) > 0:
                 keys = self.zips.keys()
                 center_coord = (self.center.lat, self.center.lng)
                 total_count = session.attendees_with_badges().count()
                 for x in res:
                     if x.zipcode in keys:
                         out.writerow([
                             self.zips_counter[x.zipcode], x.city, x.state,
                             x.zipcode,
                             VincentyDistance((x.lat, x.lng),
                                              center_coord).miles,
                             "%.2f" % float(self.zips_counter[x.zipcode] /
                                            total_count * 100)
                         ])
    def unset_group_member(self, session, id):
        attendee = session.attendee(id)
        try:
            send_email.delay(
                c.REGDESK_EMAIL,
                attendee.email,
                '{} group registration dropped'.format(c.EVENT_NAME),
                render('emails/reg_workflow/group_member_dropped.txt', {'attendee': attendee}, encoding=None),
                model=attendee.to_dict('id'))
        except Exception:
            log.error('unable to send group unset email', exc_info=True)

        session.assign_badges(
            attendee.group,
            attendee.group.badges + 1,
            new_badge_type=attendee.badge_type,
            new_ribbon_type=attendee.ribbon,
            registered=attendee.registered,
            paid=attendee.paid)

        session.delete_from_group(attendee, attendee.group)
        raise HTTPRedirect(
            'group_members?id={}&message={}',
            attendee.group_id,
            'Attendee unset; you may now assign their badge to someone else')
    def unset_group_member(self, session, id):
        attendee = session.attendee(id)
        try:
            send_email.delay(
                c.REGDESK_EMAIL,
                attendee.email,
                '{} group registration dropped'.format(c.EVENT_NAME),
                render('emails/reg_workflow/group_member_dropped.txt', {'attendee': attendee}, encoding=None),
                model=attendee.to_dict('id'))
        except Exception:
            log.error('unable to send group unset email', exc_info=True)

        session.assign_badges(
            attendee.group,
            attendee.group.badges + 1,
            new_badge_type=attendee.badge_type,
            new_ribbon_type=attendee.ribbon,
            registered=attendee.registered,
            paid=attendee.paid)

        session.delete_from_group(attendee, attendee.group)
        raise HTTPRedirect(
            'group_members?id={}&message={}',
            attendee.group_id,
            'Attendee unset; you may now assign their badge to someone else')
    def link_badge(self, session, applicant_id, attendee_id):
        ids = []
        try:
            attendee = session.attendee(attendee_id)
            if attendee.badge_type != c.GUEST_BADGE:
                attendee.ribbon = add_opt(attendee.ribbon_ints,
                                          c.PANELIST_RIBBON)

            pa = session.panel_applicant(applicant_id)
            applicants = session.query(PanelApplicant).filter_by(
                first_name=pa.first_name,
                last_name=pa.last_name,
                email=pa.email)
            for applicant in applicants:
                ids.append(applicant.id)
                applicant.attendee_id = attendee_id

            session.commit()
        except Exception:
            log.error('unexpected error linking panelist to a badge',
                      exc_info=True)
            return {
                'error': 'Unexpected error: unable to link applicant to badge.'
            }
        else:
            return {'linked': ids, 'name': pa.full_name}
    def create_badge(self, session, applicant_id):
        ids = []
        try:
            pa = session.panel_applicant(applicant_id)
            attendee = Attendee(placeholder=True,
                                paid=c.NEED_NOT_PAY,
                                ribbon=c.PANELIST_RIBBON,
                                badge_type=c.ATTENDEE_BADGE,
                                first_name=pa.first_name,
                                last_name=pa.last_name,
                                email=pa.email,
                                cellphone=pa.cellphone)
            session.add(attendee)

            applicants = session.query(PanelApplicant).filter_by(
                first_name=pa.first_name,
                last_name=pa.last_name,
                email=pa.email)
            for applicant in applicants:
                ids.append(applicant.id)
                applicant.attendee_id = attendee.id
            session.commit()
        except Exception:
            log.error('unexpected error adding new panelist', exc_info=True)
            return {'error': 'Unexpected error: unable to add attendee'}
        else:
            return {'added': ids}
Exemple #11
0
    def charge_cc(self, session, token):
        try:
            log.debug(
                'PAYMENT: !!! attempting to charge stripeToken {} {} cents for {}',
                token, self.amount, self.description)

            self.response = stripe.Charge.create(
                card=token,
                currency='usd',
                amount=self.amount,
                description=self.description,
                receipt_email=self.receipt_email)

            log.info(
                'PAYMENT: !!! SUCCESS: charged stripeToken {} {} cents for {}, responseID={}',
                token, self.amount, self.description,
                getattr(self.response, 'id', None))

        except stripe.CardError as e:
            msg = 'Your card was declined with the following error from our processor: ' + str(
                e)
            log.error('PAYMENT: !!! FAIL: {}', msg)
            return msg
        except stripe.StripeError as e:
            error_txt = 'Got an error while calling charge_cc(self, token={!r})'.format(
                token)
            report_critical_exception(
                msg=error_txt,
                subject='ERROR: MAGFest Stripe invalid request error')
            return 'An unexpected problem occurred while processing your card: ' + str(
                e)
        else:
            if self.models:
                session.add(self.stripe_transaction_from_charge())
Exemple #12
0
    def _jsonrpc_handler(self=None):
        id = None

        def error(status, code, message):
            response = {'jsonrpc': '2.0', 'id': id, 'error': {'code': code, 'message': message}}
            log.debug('Returning error message: {}', repr(response).encode('utf-8'))
            cherrypy.response.status = status
            return response

        def success(result):
            response = {'jsonrpc': '2.0', 'id': id, 'result': result}
            log.debug('Returning success message: {}', {
                'jsonrpc': '2.0', 'id': id, 'result': len(result) if is_listy(result) else str(result).encode('utf-8')})
            cherrypy.response.status = 200
            return response

        request_body = cherrypy.request.json
        if not isinstance(request_body, dict):
            return error(400, ERR_INVALID_JSON, 'Invalid json input: {!r}'.format(request_body))

        log.debug('jsonrpc request body: {}', repr(request_body).encode('utf-8'))

        id, params = request_body.get('id'), request_body.get('params', [])
        if 'method' not in request_body:
            return error(400, ERR_INVALID_RPC, '"method" field required for jsonrpc request')

        method = request_body['method']
        if method.count('.') != 1:
            return error(404, ERR_MISSING_FUNC, 'Invalid method ' + method)

        module, function = method.split('.')
        if module not in services:
            return error(404, ERR_MISSING_FUNC, 'No module ' + module)

        service = services[module]
        if not hasattr(service, function):
            return error(404, ERR_MISSING_FUNC, 'No function ' + method)

        if not isinstance(params, (list, dict)):
            return error(400, ERR_INVALID_PARAMS, 'Invalid parameter list: {!r}'.format(params))

        args, kwargs = (params, {}) if isinstance(params, list) else ([], params)

        precall(request_body)
        try:
            return success(getattr(service, function)(*args, **kwargs))
        except HTTPError as http_error:
            return error(http_error.code, ERR_FUNC_EXCEPTION, http_error._message)
        except Exception as e:
            log.error('Unexpected error', exc_info=True)
            message = 'Unexpected error: {}'.format(e)
            if debug:
                message += '\n' + traceback.format_exc()
            return error(500, ERR_FUNC_EXCEPTION, message)
        finally:
            trigger_delayed_notifications()
Exemple #13
0
    def _jsonrpc_handler(self=None):
        id = None

        def error(status, code, message):
            response = {'jsonrpc': '2.0', 'id': id, 'error': {'code': code, 'message': message}}
            log.debug('Returning error message: {}', repr(response).encode('utf-8'))
            cherrypy.response.status = status
            return response

        def success(result):
            response = {'jsonrpc': '2.0', 'id': id, 'result': result}
            log.debug('Returning success message: {}', {
                'jsonrpc': '2.0', 'id': id, 'result': len(result) if is_listy(result) else str(result).encode('utf-8')})
            cherrypy.response.status = 200
            return response

        request_body = cherrypy.request.json
        if not isinstance(request_body, dict):
            return error(400, ERR_INVALID_JSON, 'Invalid json input: {!r}'.format(request_body))

        log.debug('jsonrpc request body: {}', repr(request_body).encode('utf-8'))

        id, params = request_body.get('id'), request_body.get('params', [])
        if 'method' not in request_body:
            return error(400, ERR_INVALID_RPC, '"method" field required for jsonrpc request')

        method = request_body['method']
        if method.count('.') != 1:
            return error(404, ERR_MISSING_FUNC, 'Invalid method ' + method)

        module, function = method.split('.')
        if module not in services:
            return error(404, ERR_MISSING_FUNC, 'No module ' + module)

        service = services[module]
        if not hasattr(service, function):
            return error(404, ERR_MISSING_FUNC, 'No function ' + method)

        if not isinstance(params, (list, dict)):
            return error(400, ERR_INVALID_PARAMS, 'Invalid parameter list: {!r}'.format(params))

        args, kwargs = (params, {}) if isinstance(params, list) else ([], params)

        precall(request_body)
        try:
            return success(getattr(service, function)(*args, **kwargs))
        except HTTPError as http_error:
            return error(http_error.code, ERR_FUNC_EXCEPTION, http_error._message)
        except Exception as e:
            log.error('Unexpected error', exc_info=True)
            message = 'Unexpected error: {}'.format(e)
            if debug:
                message += '\n' + traceback.format_exc()
            return error(500, ERR_FUNC_EXCEPTION, message)
        finally:
            trigger_delayed_notifications()
Exemple #14
0
 def wrapper(*args, **kwargs):
     try:
         a = [str(x)[:255] for x in args]
         kw = dict([(k[:255], str(v)[:255]) for k, v in kwargs.items()])
         log.trace('Calling %s.%s %r %r', fn.__module__, fn.__name__, a, kw)
         return fn(*args, **kwargs)
     except Exception as e:
         log.error('Error calling function %s: %s' % (fn.__name__, e))
         log.exception(e)
         raise
    def transfer_badge(self, session, message='', **params):
        old = session.attendee(params['id'])

        assert old.is_transferable, 'This badge is not transferrable.'
        session.expunge(old)
        attendee = session.attendee(params, restricted=True)

        if 'first_name' in params:
            message = check(attendee, prereg=True)
            if (old.first_name == attendee.first_name and old.last_name == attendee.last_name) \
                    or (old.legal_name and old.legal_name == attendee.legal_name):
                message = 'You cannot transfer your badge to yourself.'
            elif not message and (not params['first_name']
                                  and not params['last_name']):
                message = check(attendee, prereg=True)
            if not message and (not params['first_name']
                                and not params['last_name']):
                message = 'First and Last names are required.'

            if not message:
                subject = c.EVENT_NAME + ' Registration Transferred'
                body = render('emails/reg_workflow/badge_transfer.txt', {
                    'new': attendee,
                    'old': old
                },
                              encoding=None)

                try:
                    send_email.delay(
                        c.REGDESK_EMAIL,
                        [old.email, attendee.email, c.REGDESK_EMAIL],
                        subject,
                        body,
                        model=attendee.to_dict('id'))
                except Exception:
                    log.error('unable to send badge change email',
                              exc_info=True)

                if attendee.amount_unpaid:
                    raise HTTPRedirect('attendee_donation_form?id={}',
                                       attendee.id)
                else:
                    raise HTTPRedirect(
                        'badge_updated?id={}&message={}', attendee.id,
                        'Your registration has been transferred')
        else:
            for attr in c.UNTRANSFERABLE_ATTRS:
                setattr(attendee, attr, getattr(Attendee(), attr))

        return {
            'old': old,
            'attendee': attendee,
            'message': message,
            'affiliates': session.affiliates()
        }
    def drop(self, session, attendee_id, tournament_id):
        try:
            session.delete(session.tabletop_entrant(attendee_id=attendee_id, tournament_id=tournament_id))
            session.commit()
        except Exception:
            log.error('unable to drop tournament entrant', exc_info=True)

        return {
            'message': 'Entrant dropped; if re-added they will be re-texted',
            'state': _state(session)
        }
Exemple #17
0
 def wrapped(*args, **kwargs):
     try:
         return fn(*args, **kwargs)
     except Exception:
         a = [x for x in (args or [])]
         kw = {k: v for k, v in (kwargs or {}).items()}
         log.error('Error calling {}.{} {!r} {!r}'.format(
             fn.__module__, fn.__name__, a, kw),
                   exc_info=True)
         exc_class, exc, tb = sys.exc_info()
         raise six.reraise(CrudException, CrudException(str(exc)), tb)
Exemple #18
0
def get_twilio_client(twilio_sid, twilio_token):
    if c.SEND_SMS:
        try:
            if twilio_sid and twilio_token:
                return TwilioRestClient(twilio_sid, twilio_token)
            else:
                log.info('Twilio: could not create twilio client. Missing twilio {}.'.format(
                    readable_join(['' if twilio_sid else 'SID', '' if twilio_token else 'TOKEN'])))
        except Exception:
            log.error('Twilio: could not create twilio client', exc_info=True)
    return None
Exemple #19
0
 def invalid_notification(self):
     if self.staffing and self.badge_status == c.INVALID_STATUS \
             and self.badge_status != self.orig_value_of('badge_status'):
         try:
             send_email.delay(
                 c.STAFF_EMAIL,
                 c.STAFF_EMAIL,
                 'Volunteer invalidated',
                 render('emails/invalidated_volunteer.txt', {'attendee': self}, encoding=None),
                 model=self.to_dict('id'))
         except Exception:
             log.error('unable to send invalid email', exc_info=True)
Exemple #20
0
def send_sms(to, body, from_=c.TABLETOP_TWILIO_NUMBER):
    to = normalize_phone(to, c.TABLETOP_PHONE_COUNTRY or 'US')
    if not twilio_client:
        log.error('no twilio client configured')
    elif c.DEV_BOX and to not in c.TESTING_PHONE_NUMBERS:
        log.info('We are in dev box mode, so we are not sending {!r} to {!r}',
                 body, to)
    else:
        return twilio_client.messages.create(
            to=to,
            body=body,
            from_=normalize_phone(from_, c.TABLETOP_PHONE_COUNTRY or 'US'))
Exemple #21
0
 def set_center(self, session, **params):
     if params.get("zip"):
         try:
             self.center = SearchEngine(
                 db_file_dir="/srv/reggie/data").by_zipcode(
                     int(params["zip"]))
         except Exception as e:
             log.error("Error calling SearchEngine: " + e)
         else:
             return "Set to %s, %s - %s" % (
                 self.center.city, self.center.state, self.center.zipcode)
     return False
Exemple #22
0
 def invalid_notification(self):
     if self.staffing and self.badge_status == c.INVALID_STATUS \
             and self.badge_status != self.orig_value_of('badge_status'):
         try:
             send_email.delay(c.STAFF_EMAIL,
                              c.STAFF_EMAIL,
                              'Volunteer invalidated',
                              render('emails/invalidated_volunteer.txt',
                                     {'attendee': self},
                                     encoding=None),
                              model=self.to_dict('id'))
         except Exception:
             log.error('unable to send invalid email', exc_info=True)
    def drop(self, session, attendee_id, tournament_id):
        try:
            session.delete(
                session.tabletop_entrant(attendee_id=attendee_id,
                                         tournament_id=tournament_id))
            session.commit()
        except Exception:
            log.error('unable to drop tournament entrant', exc_info=True)

        return {
            'message': 'Entrant dropped; if re-added they will be re-texted',
            'state': _state(session)
        }
Exemple #24
0
def send_sms(to, body, from_=c.PANELS_TWILIO_NUMBER):
    message = None
    sid = 'Unable to send sms'
    try:
        to = normalize_phone(to)
        if not twilio_client:
            log.error('no twilio client configured')
        elif c.DEV_BOX and to not in c.TESTING_PHONE_NUMBERS:
            log.info(
                'We are in dev box mode, so we are not sending {!r} to {!r}',
                body, to)
        else:
            message = twilio_client.messages.create(
                to=to, from_=normalize_phone(from_), body=body)

            # Avoid hitting rate limit.
            # NOTE: the send_email() implementation already does this.
            sleep(0.1)
        if message:
            sid = message.sid if not message.error_code else message.error_text
    except TwilioRestException as e:
        if e.code == 21211:  # https://www.twilio.com/docs/api/errors/21211
            log.error('Invalid cellphone number', exc_info=True)
        else:
            log.error('Unable to send SMS notification', exc_info=True)
            raise
    except Exception:
        log.error('Unexpected error sending SMS', exc_info=True)
        raise
    return sid
 def link_badge(self, session, applicant_id, attendee_id):
     attendee = session.attendee(attendee_id)
     try:
         applicant = session.mits_applicant(applicant_id)
         applicant.attendee = attendee
         add_opt(attendee.ribbon_ints, c.MIVS)
         session.commit()
     except Exception:
         log.error('unexpected error linking applicant to a badge', exc_info=True)
         return {'error': 'Unexpected error: unable to link applicant to badge.'}
     else:
         return {
             'name': applicant.full_name,
             'comp_count': applicant.team.comped_badge_count
         }
Exemple #26
0
    def mark_paid_from_stripe_id(stripe_id):
        from uber.tasks.email import send_email
        from uber.decorators import render
        
        with uber.models.Session() as session:
            matching_stripe_txns = session.query(uber.models.StripeTransaction).filter_by(stripe_id=stripe_id)
            dealers_paid = []

            for txn in matching_stripe_txns:
                txn.type = c.PAYMENT
                session.add(txn)

                for item in txn.receipt_items:
                    item.txn_type = c.PAYMENT
                    session.add(item)

                for group_log in txn.groups:
                    group = group_log.group
                    if not group.amount_pending:
                        group.paid = c.HAS_PAID
                        session.add(group)
                        if group.is_dealer:
                            dealers_paid.append(group)

                for attendee_log in txn.attendees:
                    attendee = attendee_log.attendee
                    if not attendee.amount_pending:
                        if attendee.badge_status == c.PENDING_STATUS:
                            attendee.badge_status = c.NEW_STATUS
                        if attendee.paid in [c.NOT_PAID, c.PENDING]:
                            attendee.paid = c.HAS_PAID
                        session.add(attendee)

            session.commit()

            for group in dealers_paid:
                try:
                    send_email.delay(
                        c.MARKETPLACE_EMAIL,
                        c.MARKETPLACE_EMAIL,
                        '{} Payment Completed'.format(c.DEALER_TERM.title()),
                        render('emails/dealers/payment_notification.txt', {'group': group}, encoding=None),
                        model=group.to_dict('id'))
                except Exception:
                    log.error('unable to send {} payment confirmation email'.format(c.DEALER_TERM), exc_info=True)

            return matching_stripe_txns
 def create_badge(self, session, applicant_id):
     try:
         applicant = session.mits_applicant(applicant_id)
         applicant.attendee = Attendee(placeholder=True,
                                       paid=c.NEED_NOT_PAY,
                                       badge_type=c.ATTENDEE_BADGE,
                                       first_name=applicant.first_name,
                                       last_name=applicant.last_name,
                                       email=applicant.email,
                                       cellphone=applicant.cellphone)
         session.add(applicant.attendee)
         session.commit()
     except Exception:
         log.error('unexpected error adding new applicant', exc_info=True)
         return {'error': 'Unexpected error: unable to add attendee'}
     else:
         return {'comp_count': applicant.team.comped_badge_count}
Exemple #28
0
    def transfer_badge(self, session, message='', **params):
        old = session.attendee(params['id'])

        assert old.is_transferable, 'This badge is not transferrable.'
        session.expunge(old)
        attendee = session.attendee(params, restricted=True)

        if 'first_name' in params:
            message = check(attendee, prereg=True)
            if (old.first_name == attendee.first_name and old.last_name == attendee.last_name) \
                    or (old.legal_name and old.legal_name == attendee.legal_name):
                message = 'You cannot transfer your badge to yourself.'
            elif not message and (not params['first_name'] and not params['last_name']):
                message = check(attendee, prereg=True)
            if not message and (not params['first_name'] and not params['last_name']):
                message = 'First and Last names are required.'

            if not message:
                subject = c.EVENT_NAME + ' Registration Transferred'
                body = render('emails/reg_workflow/badge_transfer.txt', {'new': attendee, 'old': old}, encoding=None)

                try:
                    send_email.delay(
                        c.REGDESK_EMAIL,
                        [old.email, attendee.email, c.REGDESK_EMAIL],
                        subject,
                        body,
                        model=attendee.to_dict('id'))
                except Exception:
                    log.error('unable to send badge change email', exc_info=True)

                if attendee.amount_unpaid:
                    raise HTTPRedirect('attendee_donation_form?id={}', attendee.id)
                else:
                    raise HTTPRedirect(
                        'badge_updated?id={}&message={}', attendee.id, 'Your registration has been transferred')
        else:
            for attr in c.UNTRANSFERABLE_ATTRS:
                setattr(attendee, attr, getattr(Attendee(), attr))

        return {
            'old':      old,
            'attendee': attendee,
            'message':  message,
            'affiliates': session.affiliates()
        }
Exemple #29
0
    def differences(cls, instance):
        diff = {}
        for attr, column in instance.__table__.columns.items():
            new_val = getattr(instance, attr)
            old_val = instance.orig_value_of(attr)
            if old_val != new_val:
                """
                Important note: here we try and show the old vs new value for
                something that has been changed so that we can report it in the
                tracking page.

                Sometimes, however, if we changed the type of the value in the
                database (via a database migration) the old value might not be
                able to be shown as the new type (i.e. it used to be a string,
                now it's int).

                In that case, we won't be able to show a representation of the
                old value and instead we'll log it as '<ERROR>'. In theory the
                database migration SHOULD be the thing handling this, but if it
                doesn't, it becomes our problem to deal with.

                We are overly paranoid with exception handling here because the
                tracking code should be made to never, ever, ever crash, even
                if it encounters insane/old data that really shouldn't be our
                problem.
                """
                try:
                    old_val_repr = cls.repr(column, old_val)
                except Exception:
                    log.error(
                        'Tracking repr({}) failed on old value'.format(attr),
                        exc_info=True)
                    old_val_repr = '<ERROR>'

                try:
                    new_val_repr = cls.repr(column, new_val)
                except Exception:
                    log.error(
                        'Tracking repr({}) failed on new value'.format(attr),
                        exc_info=True)
                    new_val_repr = '<ERROR>'

                diff[attr] = "'{} -> {}'".format(old_val_repr, new_val_repr)
        return diff
 def sign_up(self, session, tournament_id, attendee_id, cellphone):
     from uber import model_checks as umc
     if umc._invalid_phone_number(cellphone):
         return {'error': 'That is not a valid phone number'}
     try:
         attendee = session.attendee(attendee_id)
         attendee.cellphone = cellphone
         session.add(TabletopEntrant(attendee_id=attendee_id, tournament_id=tournament_id))
         session.commit()
     except Exception:
         session.rollback()
         log.error(
             'unable to add tournament entrant tournament={} attendee={}', tournament_id, attendee_id, exc_info=True)
         return {'error': 'That attendee is already signed up for that tournament'}
     else:
         return {
             'message': 'Attendee signed up',
             'state': _state(session)
         }
Exemple #31
0
def send_email(source,
               dest,
               subject,
               body,
               format='text',
               cc=(),
               bcc=(),
               model=None,
               ident=None):
    subject = subject.format(EVENT_NAME=c.EVENT_NAME)
    to, cc, bcc = map(listify, [dest, cc, bcc])
    ident = ident or subject
    if c.DEV_BOX:
        for xs in [to, cc, bcc]:
            xs[:] = [email for email in xs if _is_dev_email(email)]

    if c.SEND_EMAILS and to:
        msg_kwargs = {'bodyText' if format == 'text' else 'bodyHtml': body}
        message = EmailMessage(subject=subject, **msg_kwargs)
        AmazonSES(c.AWS_ACCESS_KEY,
                  c.AWS_SECRET_KEY).sendEmail(source=source,
                                              toAddresses=to,
                                              ccAddresses=cc,
                                              bccAddresses=bcc,
                                              message=message)
        sleep(0.1)  # Avoid hitting rate limit
    else:
        log.error('email sending turned off, so unable to send {}', locals())

    if model and dest:
        body = body.decode('utf-8') if isinstance(body, bytes) else body
        if model == 'n/a':
            fk_kwargs = {'model': 'n/a'}
        else:
            fk_kwargs = {'fk_id': model.id, 'model': model.__class__.__name__}

        _record_email_sent(
            uber.models.email.Email(subject=subject,
                                    dest=','.join(listify(dest)),
                                    body=body,
                                    ident=ident,
                                    **fk_kwargs))
Exemple #32
0
    def _should_send(self, model_inst, raise_errors=False):
        """
        If True, we should generate an actual email created from our email category
        and send it to a particular model instance.

        This is determined based on a few things like:
        1) whether we have sent this exact email out yet or not
        2) whether the email category has been approved
        3) whether the model instance passed in is the same type as what we want to process
        4) do any date-based filters exist on this email category? (i.e. send 7 days before magfest)
        5) do any other filters exist on this email category? (i.e. only if attendee.staffing == true)

        Example #1 of a model instance to check:
          self.ident: "You {attendee.name} have registered for our event!"
          model_inst:  class Attendee: id #4532, name: "John smith"

        Example #2 of a model instance to check:
          self.ident: "Your group {group.name} owes money"
          model_inst:  class Group: id #1251, name: "The Fighting Mongooses"

        :param model_inst: The model we've been requested to use (i.e. Attendee, Group, etc)

        :return: True if we should send this email to this model instance, False if not.
        """

        try:
            return all(condition() for condition in [
                lambda: not c.AT_THE_CON or self.allow_during_con,
                lambda: isinstance(model_inst, self.model),
                lambda: getattr(model_inst, 'email', None),
                lambda: not self._already_sent(model_inst),
                lambda: self.filters_run(model_inst),
                lambda: self.approved,
            ])
        except Exception:
            log.error('error determining whether to send {!r} email to {}',
                      self.subject,
                      model_inst.email,
                      exc_info=True)
            if raise_errors:
                raise
            return False
Exemple #33
0
    def refresh(self, session, **params):
        zips = {}
        self.zips_counter = Counter()
        attendees = session.query(Attendee).all()
        for person in attendees:
            if person.zip_code:
                self.zips_counter[person.zip_code] += 1

        for z in self.zips_counter.keys():
            try:
                found = SearchEngine(
                    db_file_dir="/srv/reggie/data").by_zipcode(int(z))
            except Exception as e:
                log.error("Error calling SearchEngine: " + e)
            else:
                if found.zipcode:
                    zips[z] = found

        self.zips = zips
        return True
Exemple #34
0
    def process_group_payment(self, session, payment_id, stripeToken):
        charge = Charge.get(payment_id)
        [group] = charge.groups
        message = charge.charge_cc(session, stripeToken)
        if message:
            raise HTTPRedirect('group_members?id={}&message={}', group.id, message)
        else:
            group.amount_paid += charge.dollar_amount

            session.merge(group)
            if group.is_dealer:
                try:
                    send_email.delay(
                        c.MARKETPLACE_EMAIL,
                        c.MARKETPLACE_EMAIL,
                        'Dealer Payment Completed',
                        render('emails/dealers/payment_notification.txt', {'group': group}, encoding=None),
                        model=group.to_dict('id'))
                except Exception:
                    log.error('unable to send dealer payment confirmation email', exc_info=True)
            raise HTTPRedirect('group_members?id={}&message={}', group.id, 'Your payment has been accepted!')
Exemple #35
0
    def differences(cls, instance):
        diff = {}
        for attr, column in instance.__table__.columns.items():
            new_val = getattr(instance, attr)
            old_val = instance.orig_value_of(attr)
            if old_val != new_val:
                """
                Important note: here we try and show the old vs new value for
                something that has been changed so that we can report it in the
                tracking page.

                Sometimes, however, if we changed the type of the value in the
                database (via a database migration) the old value might not be
                able to be shown as the new type (i.e. it used to be a string,
                now it's int).

                In that case, we won't be able to show a representation of the
                old value and instead we'll log it as '<ERROR>'. In theory the
                database migration SHOULD be the thing handling this, but if it
                doesn't, it becomes our problem to deal with.

                We are overly paranoid with exception handling here because the
                tracking code should be made to never, ever, ever crash, even
                if it encounters insane/old data that really shouldn't be our
                problem.
                """
                try:
                    old_val_repr = cls.repr(column, old_val)
                except Exception:
                    log.error('Tracking repr({}) failed on old value'.format(attr), exc_info=True)
                    old_val_repr = '<ERROR>'

                try:
                    new_val_repr = cls.repr(column, new_val)
                except Exception:
                    log.error('Tracking repr({}) failed on new value'.format(attr), exc_info=True)
                    new_val_repr = '<ERROR>'

                diff[attr] = "'{} -> {}'".format(old_val_repr, new_val_repr)
        return diff
Exemple #36
0
def check_id_for_model(model, **params):
    message = None
    session = params['session']
    model_id = params.get('id')

    if not model_id:
        message = "No ID provided. Try using a different link or going back."
    elif model_id == 'None':
        # Some pages use the string 'None' is indicate that a new model should be created, so this is a valid ID
        pass
    else:
        try:
            if not isinstance(model_id, uuid.UUID):
                uuid.UUID(model_id)
        except ValueError:
            message = "That ID is not a valid format. Did you enter or edit it manually or paste it incorrectly?"
        else:
            if not session.query(model).filter(model.id == model_id).first():
                message = "The ID provided was not found in our database."

    if message:
        log.error("check_id {} error: {}: id={}", model.__name__, message, model_id)
        raise HTTPRedirect('../preregistration/not_found?id={}&message={}', model_id, message)
Exemple #37
0
def test_eager_formatting_adapter(log_stream):
    log = AutoLogger(EagerFormattingAdapter)
    log.log(0, 'suppressed')
    log.debug('a %(a)d b %(b)s', {'a': 1, 'b': 2})
    log.trace('TEST NO INTERPOLATION')
    log.trace('TEST %s', 'MSG')
    log.debug('TEST %s', 'MSG')
    log.info('TEST %s%s%s', 'M', 'S', 'G')
    log.warn('TEST %s', 'MSG')
    log.warning('TEST %s', 'MSG')
    log.error('TEST %s', 'MSG')
    try:
        assert False
    except Exception:
        log.exception('TEST %s', 'MSG')
    log.critical('TEST %s', 'MSG')
    log.fatal('TEST %s', 'MSG')
    result = log_stream.getvalue()

    assert result.startswith("""\
[DEBUG] tests.test_logging: a 1 b 2
[TRACE] tests.test_logging: TEST NO INTERPOLATION
[TRACE] tests.test_logging: TEST MSG
[DEBUG] tests.test_logging: TEST MSG
[INFO] tests.test_logging: TEST MSG
[WARNING] tests.test_logging: TEST MSG
[WARNING] tests.test_logging: TEST MSG
[ERROR] tests.test_logging: TEST MSG
[ERROR] tests.test_logging: TEST MSG
  Traceback (most recent call last):
""")

    assert result.endswith("""\
  AssertionError: assert False
[CRITICAL] tests.test_logging: TEST MSG
[CRITICAL] tests.test_logging: TEST MSG
""")
Exemple #38
0
 def send_to(self, model_instance, delay=True, raise_errors=False):
     try:
         from uber.tasks.email import send_email
         data = self.renderable_data(model_instance)
         send_func = send_email.delay if delay else send_email
         send_func(self.sender,
                   model_instance.email_to_address,
                   self.render_template(self.subject, data),
                   self.render_template(self.body, data),
                   self.format,
                   model=model_instance.to_dict('id'),
                   cc=self.cc,
                   bcc=self.bcc,
                   ident=self.ident,
                   automated_email=self.to_dict('id'))
         return True
     except Exception:
         log.error('Error sending {!r} email to {}',
                   self.subject,
                   model_instance.email_to_address,
                   exc_info=True)
         if raise_errors:
             raise
     return False
 def sign_up(self, session, tournament_id, attendee_id, cellphone):
     from uber import model_checks as umc
     if umc._invalid_phone_number(cellphone):
         return {'error': 'That is not a valid phone number'}
     try:
         attendee = session.attendee(attendee_id)
         attendee.cellphone = cellphone
         session.add(
             TabletopEntrant(attendee_id=attendee_id,
                             tournament_id=tournament_id))
         session.commit()
     except Exception:
         session.rollback()
         log.error(
             'unable to add tournament entrant tournament={} attendee={}',
             tournament_id,
             attendee_id,
             exc_info=True)
         return {
             'error':
             'That attendee is already signed up for that tournament'
         }
     else:
         return {'message': 'Attendee signed up', 'state': _state(session)}
Exemple #40
0
def send_sms_with_client(twilio_client, to, body, from_):
    message = None
    sid = 'Unable to send SMS'
    try:
        to = normalize_phone(to)
        if not twilio_client:
            log.error('No twilio client configured')
        elif c.DEV_BOX and to not in c.TESTING_PHONE_NUMBERS:
            log.info('We are in DEV BOX mode, so we are not sending {!r} to {!r}', body, to)
        else:
            message = twilio_client.messages.create(to=to, body=body, from_=normalize_phone(from_))
            sleep(0.1)  # Avoid hitting rate limit.
        if message:
            sid = message.sid if not message.error_code else message.error_text
    except TwilioRestException as e:
        if e.code == 21211:  # https://www.twilio.com/docs/api/errors/21211
            log.error('Invalid cellphone number', exc_info=True)
        else:
            log.error('Unable to send SMS notification', exc_info=True)
            raise
    except Exception:
        log.error('Unexpected error sending SMS', exc_info=True)
        raise
    return sid
Exemple #41
0
c.STORE_ITEM_NAMES = [desc for val, desc in c.STORE_PRICE_OPTS]
c.FEE_ITEM_NAMES = [desc for val, desc in c.FEE_PRICE_OPTS]

c.WRISTBAND_COLORS = defaultdict(lambda: c.WRISTBAND_COLORS[c.DEFAULT_WRISTBAND], c.WRISTBAND_COLORS)

c.SAME_NUMBER_REPEATED = r'^(\d)\1+$'

# Allows 0-9, a-z, A-Z, and a handful of punctuation characters
c.INVALID_BADGE_PRINTED_CHARS = r'[^a-zA-Z0-9!"#$%&\'()*+,\-\./:;<=>?@\[\\\]^_`\{|\}~ "]'
c.EVENT_QR_ID = c.EVENT_QR_ID or c.EVENT_NAME_AND_YEAR.replace(' ', '_').lower()


try:
    _items = sorted([int(step), url] for step, url in _config['volunteer_checklist'].items() if url)
except ValueError:
    log.error('[volunteer_checklist] config options must have integer option names')
    raise
else:
    c.VOLUNTEER_CHECKLIST = [url for step, url in _items]

stripe.api_key = c.STRIPE_SECRET_KEY


# plugins can use this to append paths which will be included as <script> tags, e.g. if a plugin
# appends '../static/foo.js' to this list, that adds <script src="../static/foo.js"></script> to
# all of the pages on the site except for preregistration pages (for performance)
c.JAVASCRIPT_INCLUDES = []


# A list of models that have properties defined for exporting for Guidebook
c.GUIDEBOOK_MODELS = [
Exemple #42
0
def log_with_verbose_context(msg, exc_info=False):
    full_msg = '\n'.join([msg, get_verbose_request_context()])
    log.error(full_msg, exc_info=exc_info)
Exemple #43
0
def attractions_send_notifications():
    twilio_client = get_twilio_client(c.PANELS_TWILIO_SID, c.PANELS_TWILIO_TOKEN)

    with Session() as session:
        for attraction in session.query(Attraction):
            now = datetime.now(pytz.UTC)
            from_time = now - timedelta(seconds=300)
            to_time = now + timedelta(seconds=300)
            signups = attraction.signups_requiring_notification(session, from_time, to_time, [
                subqueryload(
                    AttractionSignup.attendee).subqueryload(
                        Attendee.attraction_notifications),
                subqueryload(
                    AttractionSignup.event).subqueryload(
                        AttractionEvent.feature)])

            for signup, advance_notices in signups.items():
                attendee = signup.attendee
                if not attendee.first_name or not attendee.email:
                    try:
                        log.error(
                            'ERROR: Unassigned attendee signed up for an attraction, deleting signup:\n'
                            '\tAttendee.id: {}\n'
                            '\tAttraction.id: {}\n'
                            '\tAttractionEvent.id: {}\n'
                            '\tAttractionSignup.id: {}'.format(
                                attendee.id,
                                signup.attraction_id,
                                signup.attraction_event_id,
                                signup.id))

                        session.delete(signup)
                        session.commit()
                    except Exception:
                        log.error('ERROR: Failed to delete signup with unassigned attendee', exc_info=True)
                    continue

                # The first time someone signs up for an attractions, they always
                # receive the welcome email (even if they've chosen SMS or None
                # for their notification prefs). If they've chosen to receive SMS
                # notifications, they'll also get a text message.
                is_first_signup = not(attendee.attraction_notifications)

                if not is_first_signup and attendee.notification_pref == Attendee._NOTIFICATION_NONE:
                    continue

                use_text = twilio_client \
                    and c.PANELS_TWILIO_NUMBER \
                    and attendee.cellphone \
                    and attendee.notification_pref == Attendee._NOTIFICATION_TEXT

                event = signup.event

                # If we overlap multiple notices, we only want to send a single
                # notification. So if we have both "5 minutes before checkin" and
                # "when checkin starts", we only want to send the notification
                # for "when checkin starts".
                advance_notice = min(advance_notices)
                if advance_notice == -1 or advance_notice > 1800:
                    checkin = 'is at {}'.format(event.checkin_start_time_label)
                else:
                    checkin = humanize_timedelta(
                        event.time_remaining_to_checkin,
                        granularity='minutes',
                        separator=' ',
                        prefix='is in ',
                        now='is right now',
                        past_prefix='was ',
                        past_suffix=' ago')

                ident = AttractionEvent.get_ident(event.id, advance_notice)
                try:
                    if use_text:
                        type_ = Attendee._NOTIFICATION_TEXT
                        type_str = 'TEXT'
                        from_ = c.PANELS_TWILIO_NUMBER
                        to_ = attendee.cellphone
                        body = TEXT_TEMPLATE.format(signup=signup, checkin=checkin)
                        subject = ''
                        sid = send_sms_with_client(twilio_client, to_, body, from_)

                    if not use_text or is_first_signup:
                        type_ = Attendee._NOTIFICATION_EMAIL
                        type_str = 'EMAIL'
                        from_ = c.ATTRACTIONS_EMAIL
                        to_ = attendee.email
                        if is_first_signup:
                            template = 'emails/panels/attractions_welcome.html'
                            subject = 'Welcome to {} Attractions'.format(c.EVENT_NAME)
                        else:
                            template = 'emails/panels/attractions_notification.html'
                            subject = 'Checkin for {} is at {}'.format(event.name, event.checkin_start_time_label)

                        body = render(template, {
                            'signup': signup,
                            'checkin': checkin,
                            'c': c}).decode('utf-8')
                        sid = ident
                        send_email(from_, to_, subject=subject, body=body, format='html', model=attendee, ident=ident)
                except Exception:
                    log.error(
                        'Error sending notification\n'
                        '\tfrom: {}\n'
                        '\tto: {}\n'
                        '\tsubject: {}\n'
                        '\tbody: {}\n'
                        '\ttype: {}\n'
                        '\tattendee: {}\n'
                        '\tident: {}\n'.format(
                            from_,
                            to_,
                            subject,
                            body,
                            type_str,
                            attendee.id,
                            ident), exc_info=True)
                else:
                    session.add(AttractionNotification(
                        attraction_event_id=event.id,
                        attraction_id=event.attraction_id,
                        attendee_id=attendee.id,
                        notification_type=type_,
                        ident=ident,
                        sid=sid,
                        sent_time=datetime.now(pytz.UTC),
                        subject=subject,
                        body=body))
                    session.commit()
Exemple #44
0
 def swallow_exception(*args, **kwargs):
     try:
         return func(*args, **kwargs)
     except Exception:
         log.error('Unexpected error', exc_info=True)
Exemple #45
0
    def form(self, session, message='', edit_id=None, **params):
        """
        Our production NGINX config caches the page at /preregistration/form.
        Since it's cached, we CAN'T return a session cookie with the page. We
        must POST to a different URL in order to bypass the cache and get a
        valid session cookie. Thus, this page is also exposed as "post_form".
        """
        params['id'] = 'None'   # security!
        group = Group()

        if edit_id is not None:
            attendee = self._get_unsaved(
                edit_id,
                if_not_found=HTTPRedirect('form?message={}', 'That preregistration has already been finalized'))
            attendee.apply(params, restricted=True)
            params.setdefault('pii_consent', True)
        else:
            attendee = session.attendee(params, ignore_csrf=True, restricted=True)

            if attendee.badge_type == c.PSEUDO_DEALER_BADGE:
                if not c.DEALER_REG_OPEN:
                    return render('static_views/dealer_reg_closed.html') if c.AFTER_DEALER_REG_START \
                        else render('static_views/dealer_reg_not_open.html')

                # Both the Attendee class and Group class have identically named
                # address fields. In order to distinguish the two sets of address
                # fields in the params, the Group fields are prefixed with "group_"
                # when the form is submitted. To prevent instantiating the Group object
                # with the Attendee's address fields, we must clone the params and
                # rename all the "group_" fields.
                group_params = dict(params)
                for field_name in ['country', 'region', 'zip_code', 'address1', 'address2', 'city']:
                    group_params[field_name] = params.get('group_{}'.format(field_name), '')
                    if params.get('copy_address'):
                        params[field_name] = group_params[field_name]

                group = session.group(group_params, ignore_csrf=True, restricted=True)

        if c.PAGE == 'post_dealer':
            attendee.badge_type = c.PSEUDO_DEALER_BADGE
        elif not attendee.badge_type:
            attendee.badge_type = c.ATTENDEE_BADGE

        if cherrypy.request.method == 'POST' or edit_id is not None:
            message = check_pii_consent(params, attendee) or message
            if not message and attendee.badge_type not in c.PREREG_BADGE_TYPES:
                message = 'Invalid badge type!'
            if not message and c.BADGE_PROMO_CODES_ENABLED and params.get('promo_code'):
                message = session.add_promo_code_to_attendee(attendee, params.get('promo_code'))

        if message:
            return {
                'message':    message,
                'attendee':   attendee,
                'group':      group,
                'edit_id':    edit_id,
                'affiliates': session.affiliates(),
                'cart_not_empty': Charge.unpaid_preregs,
                'copy_address': params.get('copy_address'),
                'promo_code': params.get('promo_code', ''),
                'pii_consent': params.get('pii_consent'),
            }

        if 'first_name' in params:
            message = check(attendee, prereg=True)
            if not message and attendee.badge_type == c.PSEUDO_DEALER_BADGE:
                message = check(group, prereg=True)

            if attendee.badge_type in [c.PSEUDO_GROUP_BADGE, c.PSEUDO_DEALER_BADGE]:
                message = "Please enter a group name" if not params.get('name') else ''
            else:
                params['badges'] = 0
                params['name'] = ''

            if not message:
                if attendee.badge_type == c.PSEUDO_DEALER_BADGE:
                    attendee.paid = c.PAID_BY_GROUP
                    group.attendees = [attendee]
                    session.assign_badges(group, params['badges'])
                    group.status = c.WAITLISTED if c.DEALER_REG_SOFT_CLOSED else c.UNAPPROVED
                    attendee.ribbon = add_opt(attendee.ribbon_ints, c.DEALER_RIBBON)
                    attendee.badge_type = c.ATTENDEE_BADGE

                    session.add_all([attendee, group])
                    session.commit()
                    try:
                        send_email.delay(
                            c.MARKETPLACE_EMAIL,
                            c.MARKETPLACE_EMAIL,
                            'Dealer Application Received',
                            render('emails/dealers/reg_notification.txt', {'group': group}, encoding=None),
                            model=group.to_dict('id'))
                        send_email.delay(
                            c.MARKETPLACE_EMAIL,
                            attendee.email,
                            'Dealer Application Received',
                            render('emails/dealers/application.html', {'group': group}, encoding=None),
                            'html',
                            model=group.to_dict('id'))
                    except Exception:
                        log.error('unable to send marketplace application confirmation email', exc_info=True)
                    raise HTTPRedirect('dealer_confirmation?id={}', group.id)
                else:
                    track_type = c.UNPAID_PREREG
                    if attendee.id in Charge.unpaid_preregs:
                        track_type = c.EDITED_PREREG
                        # Clear out any previously cached targets, in case the unpaid badge
                        # has been edited and changed from a single to a group or vice versa.
                        del Charge.unpaid_preregs[attendee.id]

                    Charge.unpaid_preregs[attendee.id] = Charge.to_sessionized(attendee,
                                                                               params.get('name'),
                                                                               params.get('badges'))
                    Tracking.track(track_type, attendee)

                if session.attendees_with_badges().filter_by(
                        first_name=attendee.first_name, last_name=attendee.last_name, email=attendee.email).count():

                    raise HTTPRedirect('duplicate?id={}', group.id if attendee.paid == c.PAID_BY_GROUP else attendee.id)

                if attendee.banned:
                    raise HTTPRedirect('banned?id={}', group.id if attendee.paid == c.PAID_BY_GROUP else attendee.id)

                if c.PREREG_REQUEST_HOTEL_INFO_OPEN:
                    hotel_page = 'hotel?edit_id={}' if edit_id else 'hotel?id={}'
                    raise HTTPRedirect(hotel_page, group.id if attendee.paid == c.PAID_BY_GROUP else attendee.id)
                else:
                    raise HTTPRedirect('index')

        else:
            if edit_id is None:
                if attendee.badge_type == c.PSEUDO_DEALER_BADGE:
                    # All new dealer signups should default to receiving the
                    # hotel info email, even if the deadline has passed.
                    # There's a good chance some dealers will apply for a table
                    # AFTER the hotel booking deadline, but BEFORE the hotel
                    # booking is sent out. This ensures they'll still receive
                    # the email, as requested by the Marketplace Department.
                    attendee.requested_hotel_info = True

            if attendee.badge_type == c.PSEUDO_DEALER_BADGE and c.DEALER_REG_SOFT_CLOSED:
                message = 'Dealer registration is closed, but you can ' \
                    'fill out this form to add yourself to our waitlist'

        promo_code_group = None
        if attendee.promo_code:
            promo_code_group = session.query(PromoCode).filter_by(code=attendee.promo_code.code).first().group

        return {
            'message':    message,
            'attendee':   attendee,
            'group':      group,
            'promo_code_group': promo_code_group,
            'edit_id':    edit_id,
            'affiliates': session.affiliates(),
            'cart_not_empty': Charge.unpaid_preregs,
            'copy_address': params.get('copy_address'),
            'promo_code': params.get('promo_code', ''),
            'pii_consent': params.get('pii_consent'),
        }
Exemple #46
0
def send_email(
        sender,
        to,
        subject,
        body,
        format='text',
        cc=(),
        bcc=(),
        model=None,
        ident=None,
        automated_email=None,
        session=None):

    to, cc, bcc = map(lambda x: listify(x if x else []), [to, cc, bcc])
    original_to, original_cc, original_bcc = to, cc, bcc
    ident = ident or subject
    if c.DEV_BOX:
        to, cc, bcc = map(lambda xs: list(filter(_is_dev_email, xs)), [to, cc, bcc])

    if c.SEND_EMAILS and to:
        msg_kwargs = {'bodyText' if format == 'text' else 'bodyHtml': body}
        message = EmailMessage(subject=subject, **msg_kwargs)
        AmazonSES(c.AWS_ACCESS_KEY, c.AWS_SECRET_KEY).sendEmail(
            source=sender,
            toAddresses=to,
            ccAddresses=cc,
            bccAddresses=bcc,
            message=message)
        sleep(0.1)  # Avoid hitting rate limit
    else:
        log.error('Email sending turned off, so unable to send {}', locals())

    if original_to:
        body = body.decode('utf-8') if isinstance(body, bytes) else body
        if isinstance(model, MagModel):
            fk_kwargs = {'fk_id': model.id, 'model': model.__class__.__name__}
        elif isinstance(model, Mapping):
            fk_kwargs = {'fk_id': model.get('id', None), 'model': model.get('_model', model.get('__type__', 'n/a'))}
        else:
            fk_kwargs = {'model': 'n/a'}

        if automated_email:
            if isinstance(automated_email, MagModel):
                fk_kwargs['automated_email_id'] = automated_email.id
            elif isinstance(model, Mapping):
                fk_kwargs['automated_email_id'] = automated_email.get('id', None)

        email = Email(
            subject=subject,
            body=body,
            sender=sender,
            to=','.join(original_to),
            cc=','.join(original_cc),
            bcc=','.join(original_bcc),
            ident=ident,
            **fk_kwargs)

        session = session or getattr(model, 'session', getattr(automated_email, 'session', None))
        if session:
            session.add(email)
        else:
            with Session() as session:
                session.add(email)
Exemple #47
0
    def import_model(self, session, model_import, selected_model='', date_format="%Y-%m-%d"):
        model = Session.resolve_model(selected_model)
        message = ''

        cols = {col.name: getattr(model, col.name) for col in model.__table__.columns}
        result = csv.DictReader(model_import.file.read().decode('utf-8').split('\n'))
        id_list = []

        for row in result:
            if 'id' in row:
                id = row.pop('id')  # id needs special treatment

                try:
                    # get the instance if it already exists
                    model_instance = getattr(session, selected_model)(id, allow_invalid=True)
                except Exception:
                    session.rollback()
                    # otherwise, make a new one and add it to the session for when we commit
                    model_instance = model()
                    session.add(model_instance)

            for colname, val in row.items():
                col = cols[colname]
                if not val:
                    # in a lot of cases we'll just have the empty string, so we'll just
                    # do nothing for those cases
                    continue
                if isinstance(col.type, Boolean):
                    if isinstance(val, six.string_types):
                        val = val.strip().lower() not in ('f', 'false', 'n', 'no', '0')
                    else:
                        val = bool(val)
                elif isinstance(col.type, Choice):
                    # the export has labels, and we want to convert those back into their
                    # integer values, so let's look that up (note: we could theoretically
                    # modify the Choice class to do this automatically in the future)
                    label_lookup = {val: key for key, val in col.type.choices.items()}
                    val = label_lookup[val]
                elif isinstance(col.type, MultiChoice):
                    # the export has labels separated by ' / ' and we want to convert that
                    # back into a comma-separate list of integers
                    label_lookup = {val: key for key, val in col.type.choices}
                    vals = [label_lookup[label] for label in val.split(' / ')]
                    val = ','.join(map(str, vals))
                elif isinstance(col.type, UTCDateTime):
                    # we'll need to make sure we use whatever format string we used to
                    # export this date in the first place
                    try:
                        val = UTC.localize(datetime.strptime(val, date_format + ' %H:%M:%S'))
                    except Exception:
                        val = UTC.localize(datetime.strptime(val, date_format))
                elif isinstance(col.type, Date):
                    val = datetime.strptime(val, date_format).date()
                elif isinstance(col.type, Integer):
                    val = int(val)

                # now that we've converted val to whatever it actually needs to be, we
                # can just set it on the model
                setattr(model_instance, colname, val)

            try:
                session.commit()
            except Exception:
                log.error('ImportError', exc_info=True)
                session.rollback()
                message = 'Import unsuccessful'

            id_list.append(model_instance.id)

        all_instances = session.query(model).filter(model.id.in_(id_list)).all() if id_list else None

        return self.index(message, all_instances)