Beispiel #1
0
    def resend_email(self, session, id):
        """
        Resend a particular email to the model's current email address.

        This is useful for if someone had an invalid email address and did not receive an automated email.
        """
        email = session.email(id)
        if email:
            try:
                # If this was an automated email, we can send out an updated copy
                if email.automated_email and email.fk:
                    email.automated_email.send_to(email.fk,
                                                  delay=False,
                                                  raise_errors=True)
                else:
                    send_email(
                        c.ADMIN_EMAIL,
                        email.fk_email,
                        email.subject,
                        email.body,
                        format=email.format,
                        model=email.fk.to_dict('id') if email.fk_id else None,
                        ident=email.ident)
                session.commit()
            except Exception:
                return {
                    'success': False,
                    'message': 'Email not sent: unknown error.'
                }
            else:
                return {'success': True, 'message': 'Email resent.'}
        return {
            'success': False,
            'message': 'Email not sent: no email found with that ID.'
        }
def check_duplicate_registrations():
    """
    This function looks through registered attendees for attendees with the
    same names and email addresses. It first deletes any unpaid duplicates,
    then sets paid duplicates from "Completed" to "New" and sends an email to
    the registration email address. This allows us to see new duplicate
    attendees without repetitive emails.
    """
    if c.PRE_CON and (c.DEV_BOX or c.SEND_EMAILS):
        subject = c.EVENT_NAME + ' Duplicates Report for ' + localized_now().strftime('%Y-%m-%d')
        with Session() as session:
            if session.no_email(subject):
                grouped = defaultdict(list)
                for a in session.query(Attendee).filter(Attendee.first_name != '') \
                        .filter(Attendee.badge_status == c.COMPLETED_STATUS).options(joinedload(Attendee.group)) \
                        .order_by(Attendee.registered):
                    if not a.group or a.group.status not in [c.WAITLISTED, c.UNAPPROVED]:
                        grouped[a.full_name, a.email.lower()].append(a)

                dupes = {k: v for k, v in grouped.items() if len(v) > 1}

                for who, attendees in dupes.items():
                    paid = [a for a in attendees if a.paid == c.HAS_PAID]
                    unpaid = [a for a in attendees if a.paid == c.NOT_PAID]
                    if len(paid) == 1 and len(attendees) == 1 + len(unpaid):
                        for a in unpaid:
                            session.delete(a)
                        del dupes[who]
                    for a in paid:
                        a.badge_status = c.NEW_STATUS

                if dupes:
                    body = render('emails/daily_checks/duplicates.html', {'dupes': sorted(dupes.items())})
                    send_email(c.ADMIN_EMAIL, c.REGDESK_EMAIL, subject, body, format='html', model='n/a')
Beispiel #3
0
def check_pending_badges():
    if c.PRE_CON and (c.DEV_BOX or c.SEND_EMAILS):
        emails = [[
            'Staff', c.STAFF_EMAIL, Attendee.badge_type == c.STAFF_BADGE,
            'staffing_admin'
        ],
                  [
                      'Attendee', c.REGDESK_EMAIL,
                      Attendee.badge_type != c.STAFF_BADGE, 'registration'
                  ]]
        subject = c.EVENT_NAME + ' Pending {} Badge Report for ' + localized_now(
        ).strftime('%Y-%m-%d')
        with Session() as session:
            for badge_type, to, per_email_filter, site_section in emails:
                pending = session.query(Attendee).filter_by(
                    badge_status=c.PENDING_STATUS).filter(
                        per_email_filter).all()
                if pending and session.no_email(subject.format(badge_type)):
                    body = render('emails/daily_checks/pending.html', {
                        'pending': pending,
                        'site_section': site_section
                    })
                    send_email(c.ADMIN_EMAIL,
                               to,
                               subject.format(badge_type),
                               body,
                               format='html',
                               model='n/a')
def check_near_cap():
    actual_badges_left = c.ATTENDEE_BADGE_STOCK - c.ATTENDEE_BADGE_COUNT
    for badges_left in [int(num) for num in c.BADGES_LEFT_ALERTS]:
        subject = "BADGES SOLD ALERT: {} BADGES LEFT!".format(badges_left)
        with Session() as session:
            if not session.query(Email).filter_by(subject=subject).first() and actual_badges_left <= badges_left:
                body = render('emails/badges_sold_alert.txt', {'badges_left': actual_badges_left})
                send_email(c.ADMIN_EMAIL, [c.REGDESK_EMAIL, c.ADMIN_EMAIL], subject, body, model='n/a')
def check_unassigned_volunteers():
    if c.PRE_CON and (c.DEV_BOX or c.SEND_EMAILS):
        with Session() as session:
            unassigned = session.query(Attendee).filter(
                Attendee.staffing == True,
                not_(Attendee.dept_memberships.any())).order_by(Attendee.full_name).all()  # noqa: E712
            subject = c.EVENT_NAME + ' Unassigned Volunteer Report for ' + localized_now().strftime('%Y-%m-%d')
            if unassigned and session.no_email(subject):
                body = render('emails/daily_checks/unassigned.html', {'unassigned': unassigned})
                send_email(c.STAFF_EMAIL, c.STAFF_EMAIL, subject, body, format='html', model='n/a')
Beispiel #6
0
    def index(self, session, message='', **params):
        attendee = None

        if cherrypy.request.method == 'GET' and params.get('attendee_id', ''):
            try:
                attendee = session.attendee(id=params['attendee_id'])
            except Exception:
                message = \
                    'We could not find you by your confirmation number. ' \
                    'Is the URL correct?'

        if attendee and attendee.group:
            for field in MarketplaceApplication.MATCHING_DEALER_FIELDS:
                params[field] = params[field] if field in params else getattr(
                    attendee.group, field, None)

        app = session.marketplace_application(params,
                                              restricted=True,
                                              ignore_csrf=True)

        if not (c.AFTER_MARKETPLACE_REG_START
                and c.BEFORE_MARKETPLACE_DEADLINE):
            return render('static_views/marketplace_closed.html') if c.AFTER_MARKETPLACE_DEADLINE \
                else render('static_views/marketplace_not_open.html')

        if cherrypy.request.method == 'POST':
            attendee, message = session.attendee_from_marketplace_app(**params)

            message = message or check(attendee) or check(app, prereg=True)
            if not message:
                if c.AFTER_MARKETPLACE_WAITLIST:
                    app.status = c.WAITLISTED
                session.add(attendee)
                app.attendee = attendee

                session.add(app)
                send_email(c.MARKETPLACE_APP_EMAIL,
                           c.MARKETPLACE_APP_EMAIL,
                           'Marketplace Application Received',
                           render('emails/marketplace/reg_notification.txt',
                                  {'app': app}),
                           model=app)
                session.commit()
                raise HTTPRedirect('confirmation?id={}', app.id)

        return {
            'message': message,
            'app': app,
            'attendee': attendee,
            'attendee_id': app.attendee_id or params.get('attendee_id', ''),
            'logged_in_account': session.current_attendee_account(),
            'new_badge': params.get('new_badge', '')
        }
Beispiel #7
0
    def index(self, session, message='', **params):
        app = session.art_show_application(params,
                                           restricted=True,
                                           ignore_csrf=True)
        attendee = None

        if not c.ART_SHOW_OPEN:
            return render('static_views/art_show_closed.html') if c.AFTER_ART_SHOW_DEADLINE \
                else render('static_views/art_show_not_open.html')

        if cherrypy.request.method == 'GET' and params.get('attendee_id', ''):
            try:
                attendee = session.attendee(id=params['attendee_id'])
            except Exception:
                message = \
                    'We could not find you by your confirmation number. ' \
                    'Is the URL correct?'

        if cherrypy.request.method == 'POST':
            attendee, message = session.attendee_from_art_show_app(**params)

            if attendee and attendee.badge_status == c.NOT_ATTENDING \
                    and app.delivery_method == c.BRINGING_IN:
                message = 'You cannot bring your own art ' \
                          'if you are not attending.'

            message = message or check(attendee) or check(app, prereg=True)
            if not message:
                if c.AFTER_ART_SHOW_WAITLIST:
                    app.status = c.WAITLISTED
                session.add(attendee)
                app.attendee = attendee

                session.add(app)
                send_email(c.ART_SHOW_EMAIL,
                           c.ART_SHOW_EMAIL,
                           'Art Show Application Received',
                           render('emails/art_show/reg_notification.txt',
                                  {'app': app}),
                           model=app)
                session.commit()
                raise HTTPRedirect('confirmation?id={}', app.id)

        return {
            'message': message,
            'app': app,
            'attendee': attendee,
            'attendee_id': app.attendee_id or params.get('attendee_id', ''),
            'logged_in_account': session.current_attendee_account(),
            'not_attending': params.get('not_attending', ''),
            'new_badge': params.get('new_badge', '')
        }
Beispiel #8
0
def check_placeholder_registrations():
    if c.PRE_CON and c.CHECK_PLACEHOLDERS and (c.DEV_BOX or c.SEND_EMAILS):
        emails = [['Staff', c.STAFF_EMAIL, Attendee.staffing == True],
                  [
                      'Panelist', c.PANELS_EMAIL,
                      or_(Attendee.badge_type == c.GUEST_BADGE,
                          Attendee.ribbon.contains(c.PANELIST_RIBBON))
                  ],
                  [
                      'Attendee', c.REGDESK_EMAIL,
                      not_(
                          or_(Attendee.staffing == True,
                              Attendee.badge_type == c.GUEST_BADGE,
                              Attendee.ribbon.contains(c.PANELIST_RIBBON)))
                  ]]  # noqa: E712

        with Session() as session:
            for badge_type, to, per_email_filter in emails:
                weeks_until = (c.EPOCH - localized_now()).days // 7
                subject = '{} {} Placeholder Badge Report ({} weeks to go)'.format(
                    c.EVENT_NAME, badge_type, weeks_until)

                if session.no_email(subject):
                    placeholders = (session.query(Attendee).filter(
                        Attendee.placeholder == True, Attendee.registered <
                        localized_now() - timedelta(days=3),
                        Attendee.badge_status.in_(
                            [c.NEW_STATUS,
                             c.COMPLETED_STATUS]), per_email_filter).options(
                                 joinedload(Attendee.group)).order_by(
                                     Attendee.registered,
                                     Attendee.full_name).all())  # noqa: E712
                    if placeholders:
                        body = render('emails/daily_checks/placeholders.html',
                                      {'placeholders': placeholders})
                        send_email(c.ADMIN_EMAIL,
                                   to,
                                   subject,
                                   body,
                                   format='html',
                                   model='n/a')
Beispiel #9
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()
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()