Exemple #1
0
 def assign(self, session, game_id, judge_id, return_to):
     return_to = return_to + '&message={}'
     for gid in listify(game_id):
         for jid in listify(judge_id):
             if not session.query(IndieGameReview).filter_by(game_id=gid, judge_id=jid).first():
                 session.add(IndieGameReview(game_id=gid, judge_id=jid))
     raise HTTPRedirect(return_to, 'Assignment successful')
Exemple #2
0
 def assign(self, session, game_id, judge_id, return_to):
     return_to = return_to + '&message={}'
     for gid in listify(game_id):
         for jid in listify(judge_id):
             if not session.query(IndieGameReview).filter_by(game_id=gid, judge_id=jid).first():
                 session.add(IndieGameReview(game_id=gid, judge_id=jid))
     raise HTTPRedirect(return_to, 'Assignment successful')
Exemple #3
0
 def remove(self, session, game_id, judge_id, return_to):
     return_to = return_to + '&message={}'
     for gid in listify(game_id):
         for jid in listify(judge_id):
             review = session.query(IndieGameReview).filter_by(game_id=gid, judge_id=jid).first()
             if review:
                 session.delete(review)
     raise HTTPRedirect(return_to, 'Removal successful')
Exemple #4
0
 def remove(self, session, game_id, judge_id, return_to):
     return_to = return_to + '&message={}'
     for gid in listify(game_id):
         for jid in listify(judge_id):
             review = session.query(IndieGameReview).filter_by(game_id=gid, judge_id=jid).first()
             if review:
                 session.delete(review)
     raise HTTPRedirect(return_to, 'Removal successful')
Exemple #5
0
    def __init__(self, href=None, access=None, submenu=None, name=None):
        assert submenu or href, "menu items must contain ONE nonempty: href or submenu"
        assert not submenu or not href, "menu items must not contain both a href and submenu"

        if submenu:
            self.submenu = listify(submenu)
        else:
            self.href = href

        self.name = name
        self.access = set(listify(access)) if access else set()
Exemple #6
0
    def __init__(self, href=None, access=None, submenu=None, name=None):
        assert submenu or href, "menu items must contain ONE nonempty: href or submenu"
        assert not submenu or not href, "menu items must not contain both a href and submenu"

        if submenu:
            self.submenu = listify(submenu)
        else:
            self.href = href

        self.name = name
        self.access = set(listify(access)) if access else set()
Exemple #7
0
    def __init__(self,
                 model,
                 subject,
                 template,
                 filter,
                 ident,
                 *,
                 query=(),
                 query_options=(),
                 when=(),
                 sender=None,
                 cc=(),
                 bcc=(),
                 needs_approval=True,
                 allow_at_the_con=False,
                 allow_post_con=False,
                 extra_data=None):

        assert ident, 'AutomatedEmail ident may not be empty.'
        assert ident not in AutomatedEmail._fixtures, 'AutomatedEmail ident "{}" already registered.'.format(
            ident)

        AutomatedEmail._fixtures[ident] = self

        self.model = model
        self.subject = subject \
            .replace('{EVENT_NAME}', c.EVENT_NAME) \
            .replace('{EVENT_YEAR}', c.EVENT_YEAR) \
            .replace('{EVENT_DATE}', c.EPOCH.strftime('%b %Y'))
        self.template = template
        self.format = 'text' if template.endswith('.txt') else 'html'
        self.filter = lambda x: (x.gets_emails and filter(x))
        self.ident = ident
        self.query = listify(query)
        self.query_options = listify(query_options)
        self.sender = sender or c.REGDESK_EMAIL
        self.cc = listify(cc)
        self.bcc = listify(bcc)
        self.needs_approval = needs_approval
        self.allow_at_the_con = allow_at_the_con
        self.allow_post_con = allow_post_con
        self.extra_data = extra_data or {}

        when = listify(when)

        after = [d.active_after for d in when if d.active_after]
        self.active_after = min(after) if after else None

        before = [d.active_before for d in when if d.active_before]
        self.active_before = max(before) if before else None
    def __init__(
            self,
            model,
            subject,
            template,
            filter,
            ident,
            *,
            query=(),
            query_options=(),
            when=(),
            sender=None,
            cc=(),
            bcc=(),
            needs_approval=True,
            allow_at_the_con=False,
            allow_post_con=False,
            extra_data=None):

        assert ident, 'AutomatedEmail ident may not be empty.'
        assert ident not in AutomatedEmail._fixtures, 'AutomatedEmail ident "{}" already registered.'.format(ident)

        AutomatedEmail._fixtures[ident] = self

        self.model = model
        self.subject = subject \
            .replace('{EVENT_NAME}', c.EVENT_NAME) \
            .replace('{EVENT_YEAR}', c.EVENT_YEAR) \
            .replace('{EVENT_DATE}', c.EPOCH.strftime('%b %Y'))
        self.template = template
        self.format = 'text' if template.endswith('.txt') else 'html'
        self.filter = filter or (lambda x: True)
        self.ident = ident
        self.query = listify(query)
        self.query_options = listify(query_options)
        self.sender = sender or c.REGDESK_EMAIL
        self.cc = listify(cc)
        self.bcc = listify(bcc)
        self.needs_approval = needs_approval
        self.allow_at_the_con = allow_at_the_con
        self.allow_post_con = allow_post_con
        self.extra_data = extra_data or {}

        when = listify(when)

        after = [d.active_after for d in when if d.active_after]
        self.active_after = min(after) if after else None

        before = [d.active_before for d in when if d.active_before]
        self.active_before = max(before) if before else None
Exemple #9
0
    def multi_merch_pickup(self, session, message="", csrf_token=None, picker_upper=None, badges=(), **shirt_sizes):
        picked_up = []
        if csrf_token:
            check_csrf(csrf_token)
            try:
                picker_upper = session.query(Attendee).filter_by(badge_num=int(picker_upper)).one()
            except Exception:
                message = 'Please enter a valid badge number for the person picking up the merch: ' \
                    '{} is not in the system'.format(picker_upper)
            else:
                for badge_num in set(badges):
                    if badge_num:
                        try:
                            attendee = session.query(Attendee).filter_by(badge_num=int(badge_num)).one()
                        except Exception:
                            picked_up.append('{!r} is not a valid badge number'.format(badge_num))
                        else:
                            if attendee.got_merch:
                                picked_up.append(
                                    '{a.full_name} (badge {a.badge_num}) already got their merch'.format(a=attendee))
                            else:
                                attendee.got_merch = True
                                shirt_key = 'shirt_{}'.format(attendee.badge_num)
                                if shirt_key in shirt_sizes:
                                    attendee.shirt = int(listify(shirt_sizes.get(shirt_key, c.SIZE_UNKNOWN))[0])
                                picked_up.append('{a.full_name} (badge {a.badge_num}): {a.merch}'.format(a=attendee))
                                session.add(MerchPickup(picked_up_by=picker_upper, picked_up_for=attendee))
                session.commit()

        return {
            'message': message,
            'picked_up': picked_up,
            'picker_upper': picker_upper
        }
Exemple #10
0
    def multi_merch_pickup(self, session, message="", csrf_token=None, picker_upper=None, badges=(), **shirt_sizes):
        picked_up = []
        if csrf_token:
            check_csrf(csrf_token)
            try:
                picker_upper = session.query(Attendee).filter_by(badge_num=int(picker_upper)).one()
            except Exception:
                message = 'Please enter a valid badge number for the person picking up the merch: ' \
                    '{} is not in the system'.format(picker_upper)
            else:
                for badge_num in set(badges):
                    if badge_num:
                        try:
                            attendee = session.query(Attendee).filter_by(badge_num=int(badge_num)).one()
                        except Exception:
                            picked_up.append('{!r} is not a valid badge number'.format(badge_num))
                        else:
                            if attendee.got_merch:
                                picked_up.append(
                                    '{a.full_name} (badge {a.badge_num}) already got their merch'.format(a=attendee))
                            else:
                                attendee.got_merch = True
                                shirt_key = 'shirt_{}'.format(attendee.badge_num)
                                if shirt_key in shirt_sizes:
                                    attendee.shirt = int(listify(shirt_sizes.get(shirt_key, c.SIZE_UNKNOWN))[0])
                                picked_up.append('{a.full_name} (badge {a.badge_num}): {a.merch}'.format(a=attendee))
                                session.add(MerchPickup(picked_up_by=picker_upper, picked_up_for=attendee))
                session.commit()

        return {
            'message': message,
            'picked_up': picked_up,
            'picker_upper': picker_upper
        }
Exemple #11
0
    def get_unpaid_promo_code_uses_count(cls, id, already_counted_attendee_ids=None):
        attendees_with_promo_code = set()
        if already_counted_attendee_ids:
            attendees_with_promo_code.update(listify(already_counted_attendee_ids))

        promo_code_count = 0

        targets = [t for t in cls.unpaid_preregs.values() if '_model' in t]
        for target in targets:
            if target['_model'] == 'Attendee':
                if target.get('id') not in attendees_with_promo_code \
                        and target.get('promo_code') \
                        and target['promo_code'].get('id') == id:
                    attendees_with_promo_code.add(target.get('id'))
                    promo_code_count += 1

            elif target['_model'] == 'Group':
                for attendee in target.get('attendees', []):
                    if attendee.get('id') not in attendees_with_promo_code \
                            and attendee.get('promo_code') \
                            and attendee['promo_code'].get('id') == id:
                        attendees_with_promo_code.add(attendee.get('id'))
                        promo_code_count += 1

            elif target['_model'] == 'PromoCode' and target.get('id') == id:
                # Should never get here
                promo_code_count += 1

        return promo_code_count
Exemple #12
0
    def new(self, session, message='', **params):
        if params.get('id', 'None') != 'None':
            raise HTTPRedirect('form?id={}', params['id'])

        if 'advance_notices' in params:
            ns = listify(params.get('advance_notices', []))
            params['advance_notices'] = [int(n) for n in ns if n != '']

        admin_account = session.current_admin_account()
        attraction = session.attraction(params,
                                        bools=Attraction.all_bools,
                                        checkgroups=Attraction.all_checkgroups)
        if not attraction.department_id:
            attraction.department_id = None

        if cherrypy.request.method == 'POST':
            message = check(attraction)
            if not message:
                attraction.owner = admin_account
                session.add(attraction)
                raise HTTPRedirect('form?id={}', attraction.id)

        return {
            'admin_account': admin_account,
            'attraction': attraction,
            'message': message,
        }
def options(options, default='""'):
    """
    We do need to accomodate explicitly passing in other options though
    (include None), so make sure to check all the client calls for that info.
    """
    if isinstance(default, datetime):
        default = default.astimezone(c.EVENT_TIMEZONE)

    results = []
    for opt in options:
        if len(listify(opt)) == 1:
            opt = [opt, opt]
        val, desc = opt
        if isinstance(val, datetime):
            selected = 'selected="selected"' if val == default else ''
            val = val.strftime(c.TIMESTAMP_FORMAT)
        else:
            selected = 'selected="selected"' if str(val) == str(
                default) else ''
        val = html.escape(str(val),
                          quote=False).replace('"',
                                               '"').replace('\n', '')
        desc = html.escape(str(desc),
                           quote=False).replace('"',
                                                '"').replace('\n', '')
        results.append('<option value="{}" {}>{}</option>'.format(
            val, selected, desc))
    return safe_string('\n'.join(results))
    def new(self, session, message='', **params):
        if params.get('id', 'None') != 'None':
            raise HTTPRedirect('form?id={}', params['id'])

        if 'advance_notices' in params:
            ns = listify(params.get('advance_notices', []))
            params['advance_notices'] = [int(n) for n in ns if n != '']

        admin_account = session.current_admin_account()
        attraction = session.attraction(
            params,
            bools=Attraction.all_bools,
            checkgroups=Attraction.all_checkgroups)
        if not attraction.department_id:
            attraction.department_id = None

        if cherrypy.request.method == 'POST':
            message = check(attraction)
            if not message:
                attraction.owner = admin_account
                session.add(attraction)
                raise HTTPRedirect('form?id={}', attraction.id)

        return {
            'admin_account': admin_account,
            'attraction': attraction,
            'message': message,
        }
Exemple #15
0
 def access_groups_ids(self, value):
     values = set(s for s in listify(value) if s)
     for group in list(self.access_groups):
         if group.id not in values:
             # Manually remove the group to ensure the associated
             # rows in the admin_access_group table are deleted.
             self.access_groups.remove(group)
     self._set_relation_ids('access_groups', AccessGroup, list(values))
 def index(self, message=''):
     if not Charge.unpaid_preregs:
         raise HTTPRedirect('form?message={}',
                            message) if message else HTTPRedirect('form')
     else:
         return {
             'message': message,
             'charge': Charge(listify(Charge.unpaid_preregs.values()))
         }
Exemple #17
0
 def send_reviews(self, session, game_id, review_id=None):
     game = session.indie_game(id=game_id)
     for review in game.reviews:
         if review.id in listify(review_id):
             review.send_to_studio = True
         elif review.send_to_studio:
             review.send_to_studio = False
         session.add(review)
     raise HTTPRedirect('game_results?id={}&message={}', game_id, 'Reviews marked for sending!')
Exemple #18
0
 def send_reviews(self, session, game_id, review_id=None):
     game = session.indie_game(id=game_id)
     for review in game.reviews:
         if review.id in listify(review_id):
             review.send_to_studio = True
         elif review.send_to_studio:
             review.send_to_studio = False
         session.add(review)
     raise HTTPRedirect('game_results?id={}&message={}', game_id, 'Reviews marked for sending!')
Exemple #19
0
 def __init__(self,
              targets=(),
              amount=None,
              description=None,
              receipt_email=None):
     self._targets = listify(targets)
     self._amount = amount
     self._description = description
     self._receipt_email = receipt_email
Exemple #20
0
    def form(self, session, message='', panelists=(), **params):
        event = session.event(params, allowed=['location', 'start_time'])
        if 'name' in params:
            session.add(event)

            # Associate a panel app with this event, and if the event is new, use the panel app's name and title
            if 'panel_id' in params and params['panel_id']:
                add_panel = session.panel_application(id=params['panel_id'])
                add_panel.event_id = event.id
                session.add(add_panel)
                if event.is_new:
                    event.name = add_panel.name
                    event.description = add_panel.description
                    for pa in add_panel.applicants:
                        if pa.attendee_id:
                            assigned_panelist = AssignedPanelist(
                                attendee_id=pa.attendee.id, event_id=event.id)
                            session.add(assigned_panelist)

            message = check(event)
            if not message:
                new_panelist_ids = set(listify(panelists))
                old_panelist_ids = {
                    ap.attendee_id
                    for ap in event.assigned_panelists
                }
                for ap in event.assigned_panelists:
                    if ap.attendee_id not in new_panelist_ids:
                        session.delete(ap)
                for attendee_id in new_panelist_ids:
                    if attendee_id not in old_panelist_ids:
                        attendee = session.attendee(id=attendee_id)
                        session.add(
                            AssignedPanelist(event=event, attendee=attendee))
                raise HTTPRedirect('edit#{}', event.start_slot
                                   and (event.start_slot - 1))

        assigned_panelists = sorted(event.assigned_panelists,
                                    reverse=True,
                                    key=lambda a: a.attendee.first_name)

        all_panelists = session.query(Attendee).filter(
            or_(Attendee.ribbon.contains(c.PANELIST_RIBBON),
                Attendee.badge_type == c.GUEST_BADGE)).order_by(
                    Attendee.full_name).all()

        approved_panel_apps = session.query(PanelApplication).filter(
            PanelApplication.status == c.ACCEPTED).order_by('applied')

        return {
            'message': message,
            'event': event,
            'assigned': [ap.attendee_id for ap in assigned_panelists],
            'panelists': [(a.id, a.full_name) for a in all_panelists],
            'approved_panel_apps': approved_panel_apps
        }
    def signups_requiring_notification(self,
                                       session,
                                       from_time,
                                       to_time,
                                       options=None):
        """
        Returns a dict of AttractionSignups that require notification.

        The keys of the returned dict are the amount of advanced notice, given
        in seconds. A key of -1 indicates confirmation notices after a signup.

        The query generated by this method looks horrific, but is surprisingly
        efficient.
        """
        advance_checkin = max(0, self.advance_checkin)
        subqueries = []
        for advance_notice in sorted(set([-1] + self.advance_notices)):
            event_filters = [AttractionEvent.attraction_id == self.id]
            if advance_notice == -1:
                notice_ident = cast(AttractionSignup.attraction_event_id,
                                    UnicodeText)
                notice_param = bindparam(
                    'confirm_notice', advance_notice).label('advance_notice')
            else:
                advance_notice = max(0, advance_notice) + advance_checkin
                notice_delta = timedelta(seconds=advance_notice)
                event_filters += [
                    AttractionEvent.start_time >= from_time + notice_delta,
                    AttractionEvent.start_time < to_time + notice_delta
                ]
                notice_ident = func.concat(
                    AttractionSignup.attraction_event_id,
                    '_{}'.format(advance_notice))
                notice_param = bindparam(
                    'advance_notice_{}'.format(advance_notice),
                    advance_notice).label('advance_notice')

            subquery = session.query(AttractionSignup, notice_param).filter(
                AttractionSignup.is_unchecked_in,
                AttractionSignup.attraction_event_id.in_(
                    session.query(AttractionEvent.id).filter(*event_filters)),
                not_(exists().where(
                    and_(
                        AttractionNotification.ident == notice_ident,
                        AttractionNotification.attraction_event_id ==
                        AttractionSignup.attraction_event_id,
                        AttractionNotification.attendee_id ==
                        AttractionSignup.attendee_id)))).with_labels()
            subqueries.append(subquery)

        query = subqueries[0].union(*subqueries[1:])
        if options:
            query = query.options(*listify(options))
        query.order_by(AttractionSignup.id)
        return groupify(query, lambda x: x[0], lambda x: x[1])
Exemple #22
0
 def index(self, session, message=''):
     if not Charge.unpaid_preregs:
         raise HTTPRedirect('form?message={}',
                            message) if message else HTTPRedirect('form')
     else:
         charge = Charge(listify(Charge.unpaid_preregs.values()))
         for attendee in charge.attendees:
             if attendee.promo_code and attendee.promo_code.group:
                 attendee.group_name = session.query(PromoCode).filter_by(
                     code=attendee.promo_code.code).first().group.name
         return {'message': message, 'charge': charge}
Exemple #23
0
 def process_bind_param(self, value, dialect):
     """
     Our MultiChoice options may be in one of three forms: a single string,
     a single integer, or a list of strings. We want to end up with a single
     comma-separated string. We also want to make sure an object has only
     unique values in its MultiChoice columns. Therefore, we listify() the
     object to make sure it's in list form, we convert it to a set to
     make all the values unique, and we map the values inside it to strings
     before joining them with commas because the join function can't handle
     a list of integers.
     """
     return ','.join(map(str, list(set(listify(value))))) if value else ''
Exemple #24
0
def normalize_data(data, count=1):
    """
    Normalizes a CrudApi data parameter.

    A singular data can be a string, a list of strings, or a dict::

        'attr'
        ['attr1', 'attr2']
        {'attr1':True, 'attr2':True}


    A plural data must be specified as a list of lists or a list of dicts::

        [['attr1', 'attr2'], ['attr1', 'attr2']]
        [{'attr1':True, 'attr2':True}, {'attr1':True, 'attr2':True}]


    Note that if data is specified as a list of strings, it is
    considered to be singular. Only a list of lists or a list of
    dicts is considered plural.

    Returns the plural form of data as the comprehensive form of a list of
    dictionaries mapping <keyname> to True, extended to count length. If a
    singular data is given, the result will be padded by repeating
    that value. If a plural data is given, it will be padded with
    None, for example::

        >>> normalize_data('attr', 1)
        [{'attr': True}]
        >>> normalize_data('attr', 3)
        [{'attr': True}, {'attr': True}, {'attr': True}]

    """
    if not data:
        return listify(None, minlen=count)

    if isinstance(data, six.string_types):
        data = [{data: True}]
    elif isinstance(data, collections.Mapping):
        data = [data]
    elif isinstance(data, collections.Iterable):
        if any(isinstance(element, six.string_types) for element in data):
            data = [data]
        data = [mappify(v) for v in data]
    else:
        raise TypeError('Unknown datatype: {}: {!r}', type(data), data)

    if len(data) < count:
        if len(data) == 1:
            data.extend([deepcopy(data[0]) for i in range(count - len(data))])
        else:
            data.extend([None for i in range(count - len(data))])
    return data
Exemple #25
0
 def process_bind_param(self, value, dialect):
     """
     Our MultiChoice options may be in one of three forms: a single string,
     a single integer, or a list of strings. We want to end up with a single
     comma-separated string. We also want to make sure an object has only
     unique values in its MultiChoice columns. Therefore, we listify() the
     object to make sure it's in list form, we convert it to a set to
     make all the values unique, and we map the values inside it to strings
     before joining them with commas because the join function can't handle
     a list of integers.
     """
     return ','.join(map(str, list(set(listify(value))))) if value else ''
Exemple #26
0
 def convert_if_labels(self, value):
     try:
         int(listify(value)[0])
     except ValueError:
         # This is a string list, is it the labels?
         label_lookup = {val: key for key, val in self.choices}
         try:
             vals = [label_lookup[label] for label in re.split('; |, |\*|\n| / ',value)]
         except KeyError:
             # It's probably just a string list of the int values
             return value
         value = ','.join(map(str, vals))
     return value
Exemple #27
0
 def index(self, session, message=''):
     if not Charge.unpaid_preregs:
         raise HTTPRedirect('form?message={}', message) if message else HTTPRedirect('form')
     else:
         charge = Charge(listify(Charge.unpaid_preregs.values()))
         for attendee in charge.attendees:
             if attendee.promo_code:
                 real_code = session.query(PromoCode).filter_by(code=attendee.promo_code.code).first()
                 if real_code and real_code.group:
                     attendee.group_name = real_code.group.name
         return {
             'message': message,
             'charge': charge
         }
Exemple #28
0
    def process_free_prereg(self, session):
        charge = Charge(listify(Charge.unpaid_preregs.values()))
        if charge.total_cost <= 0:
            for attendee in charge.attendees:
                session.add(attendee)

            for group in charge.groups:
                session.add(group)

            Charge.unpaid_preregs.clear()
            Charge.paid_preregs.extend(charge.targets)
            raise HTTPRedirect('paid_preregistrations?payment_received={}', charge.dollar_amount)
        else:
            message = "These badges aren't free! Please pay for them."
            raise HTTPRedirect('index?message={}', message)
    def process_free_prereg(self, session):
        charge = Charge(listify(Charge.unpaid_preregs.values()))
        if charge.total_cost <= 0:
            for attendee in charge.attendees:
                session.add(attendee)

            for group in charge.groups:
                session.add(group)

            Charge.unpaid_preregs.clear()
            Charge.paid_preregs.extend(charge.targets)
            raise HTTPRedirect('paid_preregistrations?payment_received={}', charge.dollar_amount)
        else:
            message = "These badges aren't free! Please pay for them."
            raise HTTPRedirect('index?message={}', message)
Exemple #30
0
def remove_opt(opts, other):
    """
    Remove an option from an _ints property, converting it to a comma-separated string.
    This is for use with our MultiChoice columns.

    Args:
        opts: An integer or list of integers, such as when using attendee.ribbon_ints
        other: An integer to remove, such as c.VOLUNTEER_RIBBON

    Returns: A comma-separated string representing all options in the list, with the option
    removed.

    """
    other = listify(other) if other else []

    return ','.join(map(str, set(opts).difference(other)))
Exemple #31
0
def add_opt(opts, other):
    """
    Add an option to an integer or list of integers, converting it to a comma-separated string.
    This is for use with our MultiChoice columns.

    Args:
        opts: An integer or list of integers, such as when using attendee.ribbon_ints
        other: An integer to add, such as c.VOLUNTEER_RIBBON

    Returns: A comma-separated string representing all options in the list, with the new
    option added.

    """
    other = listify(other) if other else []
    opts.extend(other)
    return ','.join(set(map(str, opts)))
Exemple #32
0
def check_all(models, *, prereg=False):
    """
    Runs all default validations against multiple model instances.

    Args:
        models (list): A single model instance or a list of instances.
        prereg (bool): True if this is an ephemeral model used in the
            preregistration workflow.

    Returns:
        str: None for success, or the first failure message encountered.
    """
    models = listify(models) if models else []
    for model in models:
        message = check(model, prereg=prereg)
        if message:
            return message
Exemple #33
0
    def form(self, session, message='', panelists=(), **params):
        event = session.event(params, allowed=['location', 'start_time'])
        if 'name' in params:
            session.add(event)

            # Associate a panel app with this event, and if the event is new, use the panel app's name and title
            if 'panel_id' in params and params['panel_id']:
                add_panel = session.panel_application(id=params['panel_id'])
                add_panel.event_id = event.id
                session.add(add_panel)
                if event.is_new:
                    event.name = add_panel.name
                    event.description = add_panel.description
                    for pa in add_panel.applicants:
                        if pa.attendee_id:
                            assigned_panelist = AssignedPanelist(attendee_id=pa.attendee.id, event_id=event.id)
                            session.add(assigned_panelist)

            message = check(event)
            if not message:
                new_panelist_ids = set(listify(panelists))
                old_panelist_ids = {ap.attendee_id for ap in event.assigned_panelists}
                for ap in event.assigned_panelists:
                    if ap.attendee_id not in new_panelist_ids:
                        session.delete(ap)
                for attendee_id in new_panelist_ids:
                    if attendee_id not in old_panelist_ids:
                        attendee = session.attendee(id=attendee_id)
                        session.add(AssignedPanelist(event=event, attendee=attendee))
                raise HTTPRedirect('edit#{}', event.start_slot and (event.start_slot - 1))

        assigned_panelists = sorted(event.assigned_panelists, reverse=True, key=lambda a: a.attendee.first_name)

        approved_panel_apps = session.query(PanelApplication).filter(
            PanelApplication.status == c.ACCEPTED,
            PanelApplication.event_id == None).order_by('applied')  # noqa: E711

        return {
            'message': message,
            'event':   event,
            'assigned': [ap.attendee_id for ap in assigned_panelists],
            'panelists': [(a.id, a.full_name) for a in session.all_panelists()],
            'approved_panel_apps': approved_panel_apps
        }
Exemple #34
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 #35
0
    def __init__(self,
                 model,
                 subject,
                 template,
                 filter,
                 ident,
                 *,
                 when=(),
                 sender=None,
                 extra_data=None,
                 cc=None,
                 bcc=None,
                 post_con=False,
                 needs_approval=True,
                 allow_during_con=False):

        self.subject = subject.format(EVENT_NAME=c.EVENT_NAME,
                                      EVENT_DATE=c.EPOCH.strftime("(%b %Y)"))
        self.ident = ident
        self.model = model

        assert self.ident, 'error: automated email ident may not be empty.'
        assert self.ident not in self.instances, \
            'error: automated email ident "{}" is registered twice.'.format(self.ident)

        self.instances[self.ident] = self
        self.instances_by_model[self.model].append(self)

        self.template, self.needs_approval, self.allow_during_con = template, needs_approval, allow_during_con
        self.cc = cc or []
        self.bcc = bcc or []
        self.extra_data = extra_data or {}
        self.sender = sender or c.REGDESK_EMAIL
        self.when = listify(when)

        assert filter is not None

        if post_con:
            self.filter = lambda model_inst: c.POST_CON and filter(model_inst)
        else:
            self.filter = lambda model_inst: not c.POST_CON and filter(
                model_inst)
Exemple #36
0
    def signups_requiring_notification(self, session, from_time, to_time, options=None):
        """
        Returns a dict of AttractionSignups that require notification.

        The keys of the returned dict are the amount of advanced notice, given
        in seconds. A key of -1 indicates confirmation notices after a signup.

        The query generated by this method looks horrific, but is surprisingly
        efficient.
        """
        advance_checkin = max(0, self.advance_checkin)
        subqueries = []
        for advance_notice in sorted(set([-1] + self.advance_notices)):
            event_filters = [AttractionEvent.attraction_id == self.id]
            if advance_notice == -1:
                notice_ident = cast(AttractionSignup.attraction_event_id, UnicodeText)
                notice_param = bindparam('confirm_notice', advance_notice).label('advance_notice')
            else:
                advance_notice = max(0, advance_notice) + advance_checkin
                notice_delta = timedelta(seconds=advance_notice)
                event_filters += [
                    AttractionEvent.start_time >= from_time + notice_delta,
                    AttractionEvent.start_time < to_time + notice_delta]
                notice_ident = func.concat(AttractionSignup.attraction_event_id, '_{}'.format(advance_notice))
                notice_param = bindparam(
                    'advance_notice_{}'.format(advance_notice), advance_notice).label('advance_notice')

            subquery = session.query(AttractionSignup, notice_param).filter(
                AttractionSignup.is_unchecked_in,
                AttractionSignup.attraction_event_id.in_(
                    session.query(AttractionEvent.id).filter(*event_filters)),
                not_(exists().where(and_(
                    AttractionNotification.ident == notice_ident,
                    AttractionNotification.attraction_event_id == AttractionSignup.attraction_event_id,
                    AttractionNotification.attendee_id == AttractionSignup.attendee_id)))).with_labels()
            subqueries.append(subquery)

        query = subqueries[0].union(*subqueries[1:])
        if options:
            query = query.options(*listify(options))
        query.order_by(AttractionSignup.id)
        return groupify(query, lambda x: x[0], lambda x: x[1])
Exemple #37
0
    def emails_by_interest_csv(self, out, session, **params):
        """
        Generate a list of emails of attendees who match one of c.INTEREST_OPTS
        (interests are like "LAN", "music", "gameroom", etc)

        This is intended for use to export emails to a third-party email system, like MadMimi or Mailchimp
        """
        if 'interests' not in params:
            raise HTTPRedirect('emails_by_interest?message={}', 'You must select at least one interest')

        interests = [int(i) for i in listify(params['interests'])]
        assert all(k in c.INTERESTS for k in interests)

        attendees = session.query(Attendee).filter_by(can_spam=True).order_by('email').all()

        out.writerow(["fullname", "email", "zipcode"])

        for a in attendees:
            if set(interests).intersection(a.interests_ints):
                out.writerow([a.full_name, a.email, a.zip_code])
Exemple #38
0
    def hotel_requests(self, session, message='', **params):
        team = session.logged_in_mits_team()
        if cherrypy.request.method == 'POST':
            for applicant in team.applicants:
                applicant.declined_hotel_space = '{}-declined'.format(
                    applicant.id) in params
                applicant.requested_room_nights = ','.join(
                    listify(params.get('{}-night'.format(applicant.id), [])))
                if not applicant.declined_hotel_space and not applicant.requested_room_nights:
                    message = '{} must either declined hotel space or ' \
                        'indicate which room nights they need'.format(applicant.full_name)
                    break
                elif applicant.declined_hotel_space and applicant.requested_room_nights:
                    message = '{} cannot both decline hotel space and ' \
                        'request specific room nights'.format(applicant.full_name)
                    break

            if not message:
                raise HTTPRedirect('index?message={}', 'Room nights uploaded')

        return {'team': team, 'message': message}
Exemple #39
0
 def _collect_models(cls, query):
     models = set()
     for d in listify(query):
         try:
             model = Session.resolve_model(d['_model'])
         except Exception:
             log.debug('unable to resolve model {} in query {}',
                       d.get('_model'), d)
         else:
             models.add(model)
             for attr_name in _collect_fields(d):
                 curr_model = model
                 for prop_name in attr_name.split('.'):
                     if hasattr(curr_model, prop_name):
                         prop = getattr(curr_model, prop_name)
                         if isinstance(
                                 prop,
                                 InstrumentedAttribute) and hasattr(
                                     prop.property, 'mapper'):
                             curr_model = prop.property.mapper.class_
                             models.update([curr_model])
                             if prop_name in d:
                                 subquery = deepcopy(d[prop_name])
                                 if isinstance(subquery, (list, set, tuple)) \
                                         and not filter(lambda x: isinstance(x, dict), subquery):
                                     subquery = {
                                         i: True
                                         for i in subquery
                                     }
                                 elif isinstance(
                                         subquery, six.string_types):
                                     subquery = {subquery: True}
                                 if isinstance(subquery, dict):
                                     subquery[
                                         '_model'] = curr_model.__name__
                                 models.update(
                                     cls._collect_models(subquery))
                     else:
                         break
     return models
Exemple #40
0
def _extract_sort_field(model, value, index=0):
    field = None
    fields = listify(value)
    for f in fields:
        if isinstance(f, six.string_types):
            parts = f.split('.')
            if len(parts) == 1 and field is None:
                if not model or (model and hasattr(model, parts[0])):
                    field = parts[0]
            elif len(parts) > 1 and model and parts[0] == model.__name__:
                field = parts[1]
        else:
            field = f

    if field and isinstance(field, six.string_types) and model:
        attr = getattr(model, field)
        if not (isinstance(attr, InstrumentedAttribute) and isinstance(attr.property, ColumnProperty)) \
                and not isinstance(attr, ClauseElement):
            raise ValueError(
                'SQLAlchemy model classes may only be sorted by columns that exist in the database. '
                'Provided: {}.{}'.format(model.__name__, field))
    return field or 'id'
Exemple #41
0
    def emails_by_interest_csv(self, out, session, **params):
        """
        Generate a list of emails of attendees who match one of c.INTEREST_OPTS
        (interests are like "LAN", "music", "gameroom", etc)

        This is intended for use to export emails to a third-party email system, like MadMimi or Mailchimp
        """
        if 'interests' not in params:
            raise HTTPRedirect('emails_by_interest?message={}',
                               'You must select at least one interest')

        interests = [int(i) for i in listify(params['interests'])]
        assert all(k in c.INTERESTS for k in interests)

        attendees = session.query(Attendee).filter_by(
            can_spam=True).order_by('email').all()

        out.writerow(["fullname", "email", "zipcode"])

        for a in attendees:
            if set(interests).intersection(a.interests_ints):
                out.writerow([a.full_name, a.email, a.zip_code])
    def hotel_requests(self, session, message='', **params):
        team = session.logged_in_mits_team()
        if cherrypy.request.method == 'POST':
            for applicant in team.applicants:
                applicant.declined_hotel_space = '{}-declined'.format(applicant.id) in params
                applicant.requested_room_nights = ','.join(listify(params.get('{}-night'.format(applicant.id), [])))
                if not applicant.declined_hotel_space and not applicant.requested_room_nights:
                    message = '{} must either declined hotel space or ' \
                        'indicate which room nights they need'.format(applicant.full_name)
                    break
                elif applicant.declined_hotel_space and applicant.requested_room_nights:
                    message = '{} cannot both decline hotel space and ' \
                        'request specific room nights'.format(applicant.full_name)
                    break

            if not message:
                raise HTTPRedirect('index?message={}', 'Room nights uploaded')

        return {
            'team': team,
            'message': message
        }
Exemple #43
0
def options(options, default='""'):
    """
    We do need to accomodate explicitly passing in other options though
    (include None), so make sure to check all the client calls for that info.
    """
    if isinstance(default, datetime):
        default = default.astimezone(c.EVENT_TIMEZONE)

    results = []
    for opt in options:
        if len(listify(opt)) == 1:
            opt = [opt, opt]
        val, desc = opt
        if isinstance(val, datetime):
            selected = 'selected="selected"' if val == default else ''
            val = val.strftime(c.TIMESTAMP_FORMAT)
        else:
            selected = 'selected="selected"' if str(val) == str(default) else ''
        val = html.escape(str(val), quote=False).replace('"',  '&quot;').replace('\n', '')
        desc = html.escape(str(desc), quote=False).replace('"', '&quot;').replace('\n', '')
        results.append('<option value="{}" {}>{}</option>'.format(val, selected, desc))
    return safe_string('\n'.join(results))
    def form(self, session, message='', **params):
        attraction_id = params.get('id')
        if not attraction_id or attraction_id == 'None':
            raise HTTPRedirect('index')

        if cherrypy.request.method == 'POST':
            if 'advance_notices' in params:
                ns = listify(params.get('advance_notices', []))
                params['advance_notices'] = [int(n) for n in ns if n != '']

            attraction = session.attraction(
                params,
                bools=Attraction.all_bools,
                checkgroups=Attraction.all_checkgroups)
            message = check(attraction)
            if not message:
                if not attraction.department_id:
                    attraction.department_id = None
                session.add(attraction)
                raise HTTPRedirect(
                    'form?id={}&message={}',
                    attraction.id,
                    '{} updated successfully'.format(attraction.name))
        else:
            attraction = session.query(Attraction) \
                .filter_by(id=attraction_id) \
                .options(
                    subqueryload(Attraction.department),
                    subqueryload(Attraction.features)
                    .subqueryload(AttractionFeature.events)
                    .subqueryload(AttractionEvent.attendees)) \
                .order_by(Attraction.id).one()

        return {
            'admin_account': session.current_admin_account(),
            'message': message,
            'attraction': attraction
        }
Exemple #45
0
    def form(self, session, message='', **params):
        attraction_id = params.get('id')
        if not attraction_id or attraction_id == 'None':
            raise HTTPRedirect('index')

        if cherrypy.request.method == 'POST':
            if 'advance_notices' in params:
                ns = listify(params.get('advance_notices', []))
                params['advance_notices'] = [int(n) for n in ns if n != '']

            attraction = session.attraction(
                params,
                bools=Attraction.all_bools,
                checkgroups=Attraction.all_checkgroups)
            message = check(attraction)
            if not message:
                if not attraction.department_id:
                    attraction.department_id = None
                session.add(attraction)
                raise HTTPRedirect(
                    'form?id={}&message={}', attraction.id,
                    '{} updated successfully'.format(attraction.name))
        else:
            attraction = session.query(Attraction) \
                .filter_by(id=attraction_id) \
                .options(
                    subqueryload(Attraction.department),
                    subqueryload(Attraction.features)
                    .subqueryload(AttractionFeature.events)
                    .subqueryload(AttractionEvent.attendees)) \
                .order_by(Attraction.id).one()

        return {
            'admin_account': session.current_admin_account(),
            'message': message,
            'attraction': attraction
        }
Exemple #46
0
    def confirm_attendees(self, session, badge_type, admin_notes, target_server, api_token, query, attendee_ids):
        if cherrypy.request.method != 'POST':
            raise HTTPRedirect('attendees?target_server={}&api_token={}&query={}', target_server, api_token, query)

        target_url, target_host, remote_api_token = _format_import_params(target_server, api_token)
        results = {}
        try:
            uri = '{}/jsonrpc/'.format(target_url)
            service = ServerProxy(uri=uri, extra_headers={'X-Auth-Token': remote_api_token})
            results = service.attendee.export(query=','.join(listify(attendee_ids)), full=True)
        except Exception as ex:
            raise HTTPRedirect(
                'attendees?target_server={}&api_token={}&query={}&message={}',
                target_server, remote_api_token, query, str(ex))

        depts = {}

        def _guess_dept(id_name):
            id, name = id_name
            if id in depts:
                return (id, depts[id])

            dept = session.query(Department).filter(or_(
                Department.id == id,
                Department.normalized_name == Department.normalize_name(name))).first()

            if dept:
                depts[id] = dept
                return (id, dept)
            return None

        badge_type = int(badge_type)
        badge_label = c.BADGES[badge_type].lower()

        attendees = results.get('attendees', [])
        for d in attendees:
            import_from_url = '{}/registration/form?id={}\n\n'.format(target_url, d['id'])
            new_admin_notes = '{}\n\n'.format(admin_notes) if admin_notes else ''
            old_admin_notes = 'Old Admin Notes:\n{}\n'.format(d['admin_notes']) if d['admin_notes'] else ''

            d.update({
                'badge_type': badge_type,
                'badge_status': c.NEW_STATUS,
                'paid': c.NEED_NOT_PAY,
                'placeholder': True,
                'requested_hotel_info': True,
                'admin_notes': 'Imported {} from {}{}{}'.format(
                    badge_label, import_from_url, new_admin_notes, old_admin_notes),
                'past_years': d['all_years'],
            })
            del d['id']
            del d['all_years']

            if badge_type != c.STAFF_BADGE:
                attendee = Attendee().apply(d, restricted=False)

            else:
                assigned_depts = {d[0]: d[1] for d in map(_guess_dept, d.pop('assigned_depts', {}).items()) if d}
                checklist_admin_depts = d.pop('checklist_admin_depts', {})
                dept_head_depts = d.pop('dept_head_depts', {})
                poc_depts = d.pop('poc_depts', {})
                requested_depts = d.pop('requested_depts', {})

                d.update({
                    'staffing': True,
                    'ribbon': str(c.DEPT_HEAD_RIBBON) if dept_head_depts else '',
                })

                attendee = Attendee().apply(d, restricted=False)

                for id, dept in assigned_depts.items():
                    attendee.dept_memberships.append(DeptMembership(
                        department=dept,
                        attendee=attendee,
                        is_checklist_admin=bool(id in checklist_admin_depts),
                        is_dept_head=bool(id in dept_head_depts),
                        is_poc=bool(id in poc_depts),
                    ))

                requested_anywhere = requested_depts.pop('All', False)
                requested_depts = {d[0]: d[1] for d in map(_guess_dept, requested_depts.items()) if d}

                if requested_anywhere:
                    attendee.dept_membership_requests.append(DeptMembershipRequest(attendee=attendee))
                for id, dept in requested_depts.items():
                    attendee.dept_membership_requests.append(DeptMembershipRequest(
                        department=dept,
                        attendee=attendee,
                    ))

            session.add(attendee)

        attendee_count = len(attendees)
        raise HTTPRedirect(
            'attendees?target_server={}&api_token={}&query={}&message={}',
            target_server,
            api_token,
            query,
            '{count} attendee{s} imported with {a}{badge_label} badge{s}'.format(
                count=attendee_count,
                s=pluralize(attendee_count),
                a=pluralize(attendee_count, singular='an ' if badge_label.startswith('a') else 'a ', plural=''),
                badge_label=badge_label,
            )
        )
Exemple #47
0
    def confirm_staff(self, session, target_server, api_token, query,
                      attendee_ids):
        if cherrypy.request.method != 'POST':
            raise HTTPRedirect('staff?target_server={}&api_token={}&query={}',
                               target_server, api_token, query)

        target_url = _server_to_url(target_server)
        results = {}
        try:
            uri = '{}/jsonrpc/'.format(target_url)
            service = ServerProxy(
                uri=uri, extra_headers={'X-Auth-Token': api_token.strip()})
            results = service.attendee.export(query=','.join(
                listify(attendee_ids)),
                                              full=True)
        except Exception as ex:
            raise HTTPRedirect(
                'staff?target_server={}&api_token={}&query={}&message={}',
                target_server, api_token, query, str(ex))

        depts = {}

        def _guess_dept(id_name):
            id, name = id_name
            if id in depts:
                return (id, depts[id])

            dept = session.query(Department).filter(
                or_(
                    Department.id == id, Department.normalized_name ==
                    Department.normalize_name(name))).first()

            if dept:
                depts[id] = dept
                return (id, dept)
            return None

        attendees = results.get('attendees', [])
        for d in attendees:
            import_from_url = '{}/registration/form?id={}'.format(
                target_url, d['id'])
            old_admin_notes = '\n\nOld Admin Notes:\n{}'.format(
                d['admin_notes']) if d['admin_notes'] else ''
            assigned_depts = {
                d[0]: d[1]
                for d in map(_guess_dept,
                             d.pop('assigned_depts', {}).items()) if d
            }
            checklist_admin_depts = d.pop('checklist_admin_depts', {})
            dept_head_depts = d.pop('dept_head_depts', {})
            poc_depts = d.pop('poc_depts', {})
            requested_depts = d.pop('requested_depts', {})

            d.update({
                'badge_type':
                c.STAFF_BADGE,
                'paid':
                c.NEED_NOT_PAY,
                'placeholder':
                True,
                'staffing':
                True,
                'requested_hotel_info':
                True,
                'admin_notes':
                'Imported staff from {}{}'.format(import_from_url,
                                                  old_admin_notes),
                'ribbon':
                str(c.DEPT_HEAD_RIBBON) if dept_head_depts else '',
                'past_years':
                d['all_years'],
            })
            del d['id']
            del d['all_years']

            attendee = Attendee().apply(d, restricted=False)

            for id, dept in assigned_depts.items():
                attendee.dept_memberships.append(
                    DeptMembership(
                        department=dept,
                        attendee=attendee,
                        is_checklist_admin=bool(id in checklist_admin_depts),
                        is_dept_head=bool(id in dept_head_depts),
                        is_poc=bool(id in poc_depts),
                    ))

            requested_anywhere = requested_depts.pop('All', False)
            requested_depts = {
                d[0]: d[1]
                for d in map(_guess_dept, requested_depts.items()) if d
            }

            if requested_anywhere:
                attendee.dept_membership_requests.append(
                    DeptMembershipRequest(attendee=attendee))
            for id, dept in requested_depts.items():
                attendee.dept_membership_requests.append(
                    DeptMembershipRequest(
                        department=dept,
                        attendee=attendee,
                    ))

            session.add(attendee)

        attendee_count = len(attendees)
        raise HTTPRedirect(
            'staff?target_server={}&api_token={}&query={}&message={}',
            target_server, api_token, query,
            '{} attendee{} imported'.format(attendee_count,
                                            pluralize(attendee_count)))
Exemple #48
0
def JSONColumnMixin(column_name, fields, admin_only=False):
    """
    Creates a new mixin class with a JSON column named column_name.

    The newly created mixin class will have a SQLAlchemy JSON Column, named
    `column_name`, along with two other attributes column_name_fields and
    column_name_qualified_fields which describe the fields that the JSON
    Column is expected to hold.

    For example::

        >>> SocialMediaMixin = JSONColumnMixin('social_media', ['Twitter', 'LinkedIn'])
        >>> SocialMediaMixin.social_media # doctest: +ELLIPSIS
        Column('social_media', JSON(), ... server_default=DefaultClause('{}', for_update=False))
        >>> SocialMediaMixin._social_media_fields
        OrderedDict([('twitter', 'Twitter'), ('linked_in', 'LinkedIn')])
        >>> SocialMediaMixin._social_media_qualified_fields
        OrderedDict([('social_media__twitter', 'twitter'), ('social_media__linked_in', 'linked_in')])

    Instances of the newly created mixin class have convenience accessors for
    the attributes defined by `fields`, both directly and using their fully
    qualified forms::

        >>> sm = SocialMediaMixin()
        >>> sm.twitter = 'https://twitter.com/MAGFest'  # Get and set "twitter" directly
        >>> sm.twitter
        'https://twitter.com/MAGFest'
        >>> sm.social_media__twitter  # Get and set qualified "social_media__twitter"
        'https://twitter.com/MAGFest'
        >>> sm.social_media__twitter = '@MAGFest'
        >>> sm.social_media__twitter
        '@MAGFest'
        >>> sm.social_media  # Actual column updated appropriately
        {'linked_in': '', 'twitter': '@MAGFest'}


    Args:
        column_name (str): The name of the column.
        fields (list): A list of field names you expect the column to hold.
            This can be:
              - A single string, if you're only expecting the column to hold a
                single field.
              - A list of strings, which will be treated as the column labels,
                and converted from CamelCase to under_score for the fields.
              - A map of {string: string}, which will be treated as a mapping
                of field names to field labels.

    Returns:
        type: A new mixin class with a JSON column named column_name.

    """

    fields_name = '_{}_fields'.format(column_name)
    qualified_fields_name = '_{}_qualified_fields'.format(column_name)
    if isinstance(fields, Mapping):
        fields = OrderedDict([(fieldify(k), v) for k, v in fields.items()])
    else:
        fields = OrderedDict([(fieldify(s), s) for s in listify(fields)])

    qualified_fields = OrderedDict([(column_name + '__' + s, s) for s in fields.keys()])
    column = Column(column_name, JSON, default={}, server_default='{}')
    attrs = {
        column_name: column,
        fields_name: fields,
        qualified_fields_name: qualified_fields
    }

    _Mixin = type(camel(column_name) + 'Mixin', (object,), attrs)

    def _Mixin__init__(self, *args, **kwargs):
        setattr(self, column_name, {})
        for attr in getattr(self.__class__, fields_name).keys():
            setattr(self, attr, kwargs.pop(attr, ''))
        super(_Mixin, self).__init__(*args, **kwargs)
    _Mixin.__init__ = _Mixin__init__

    def _Mixin__declare_last__(cls):
        setattr(getattr(cls, column_name), 'admin_only', admin_only)
        column = cls.__table__.columns.get(column_name)
        setattr(column, 'admin_only', admin_only)
    _Mixin.__declare_last__ = classmethod(_Mixin__declare_last__)

    def _Mixin__unqualify(cls, name):
        if name in getattr(cls, qualified_fields_name):
            return getattr(cls, qualified_fields_name)[name]
        else:
            return name
    _Mixin.unqualify = classmethod(_Mixin__unqualify)

    def _Mixin__getattr__(self, name):
        name = self.unqualify(name)
        if name in getattr(self.__class__, fields_name):
            return getattr(self, column_name).get(name, '')
        else:
            return super(_Mixin, self).__getattr__(name)
    _Mixin.__getattr__ = _Mixin__getattr__

    def _Mixin__setattr__(self, name, value):
        name = self.unqualify(name)
        if name in getattr(self.__class__, fields_name):
            fields = getattr(self, column_name)
            if fields.get(name) != value:
                fields[name] = value
                super(_Mixin, self).__setattr__(column_name, dict(fields))
        else:
            super(_Mixin, self).__setattr__(name, value)
    _Mixin.__setattr__ = _Mixin__setattr__

    return _Mixin
Exemple #49
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 #50
0
 def _render_empty(template_name_list):
     if listify(template_name_list)[0].endswith('.txt'):
         return '{{ attendee.full_name }}\n{{ c.EVENT_NAME }}\n{{ extra_data }}'
     return '<html><body>{{ attendee.full_name }}<br>{{ c.EVENT_NAME }}<br>{{ extra_data }}</body></html>'