Beispiel #1
0
 def requested_depts_ids(self, value):
     values = set(s for s in listify(value) if s)
     self.requested_any_dept = 'All' in values
     if self.requested_any_dept:
         values.remove('All')
     from uber.models.department import Department
     self._set_relation_ids('requested_depts', Department, list(values))
Beispiel #2
0
 def __init__(self, hostnames, rpc_method, *args, **kwargs):
     from sideboard.lib import listify
     self.hostnames, self.method, self.args, self.kwargs = listify(
         hostnames), rpc_method, args, kwargs
     self.results, self.websockets, self._client_ids = {}, {}, {}
     on_startup(self._subscribe)
     on_shutdown(self._unsubscribe)
Beispiel #3
0
 def assigned_depts_ids(self, value):
     values = set(s for s in listify(value) if s)
     for membership in list(self.dept_memberships):
         if membership.department_id not in values:
             # Manually remove dept_memberships to ensure the associated
             # rows in the dept_membership_dept_role table are deleted.
             self.dept_memberships.remove(membership)
     from uber.models.department import Department
     self._set_relation_ids('assigned_depts', Department, list(values))
Beispiel #4
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 ''
Beispiel #5
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])
Beispiel #6
0
    def requested_depts_ids(self, value):
        from uber.models.department import DeptMembershipRequest
        values = set(None if s in ('None', 'All') else s
                     for s in listify(value) if s != '')

        for membership in list(self.dept_membership_requests):
            if membership.department_id not in values:
                self.dept_membership_requests.remove(membership)
        department_ids = set(
            str(d.department_id) for d in self.dept_membership_requests)
        for department_id in values:
            if department_id not in department_ids:
                self.dept_membership_requests.append(
                    DeptMembershipRequest(department_id=department_id,
                                          attendee_id=self.id))
Beispiel #7
0
def ldap_auth(username, password):
    if not username or not password:
        return False

    try:
        ssl_material = (
            config['ldap.cacert'], config['ldap.cert'], config['ldap.key']
        )
        server_kwargs = {}
        tls_kwargs = {}

        if config['ldap.url'].startswith('ldaps') or any(ssl_material):
            server_kwargs['use_ssl'] = True
        else:
            server_kwargs['use_ssl'] = False
        server_kwargs['host'] = config['ldap.url']

        if config['ldap.cacert']:
            tls_kwargs['ca_certs_file'] = config['ldap.cacert']
            # if we specify a CA certs file, assume we want to validate it
            tls_kwargs['validate'] = ssl.CERT_REQUIRED

        if tls_kwargs:
            server_kwargs['tls'] = ldap3.Tls(**tls_kwargs)

        server = ldap3.Server(**server_kwargs)

    except:
        log.error('Error initializing LDAP server', exc_info=True)
        raise

    # attempt to bind on each base DN that was configured
    for basedn in listify(config['ldap.basedn']):
        dn = '{}={},{}'.format(config['ldap.userattr'], username, basedn)
        log.debug('attempting to bind with dn {}', dn)
        try:
            connection = ldap3.Connection(server, user=dn, password=password)
            connection.start_tls()
            is_bound = connection.bind()
        except:
            log.warning("Error binding to LDAP server with dn", exc_info=True)
            raise

        if is_bound:
            return True

    # we couldn't auth on anything
    return False
Beispiel #8
0
def ldap_auth(username, password):
    if not username or not password:
        return False

    try:
        conn = ldap.initialize(config['ldap.url'])

        force_start_tls = False
        if config['ldap.cacert']:
            ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, config['ldap.cacert'])
            force_start_tls = True

        if config['ldap.cert']:
            ldap.set_option(ldap.OPT_X_TLS_CERTFILE, config['ldap.cert'])
            force_start_tls = True

        if config['ldap.key']:
            ldap.set_option(ldap.OPT_X_TLS_KEYFILE, config['ldap.key'])
            force_start_tls = True

        if force_start_tls:
            conn.start_tls_s()
        else:
            conn.set_option(ldap.OPT_X_TLS_DEMAND, config['ldap.start_tls'])
    except:
        log.error('Error initializing LDAP connection', exc_info=True)
        raise

    for basedn in listify(config['ldap.basedn']):
        dn = '{}={},{}'.format(config['ldap.userattr'], username, basedn)
        log.debug('attempting to bind with dn {}', dn)
        try:
            conn.simple_bind_s(dn, password)
        except ldap.INVALID_CREDENTIALS as x:
            continue
        except:
            log.warning("Error binding to LDAP server with dn", exc_info=True)
            raise
        else:
            return True
Beispiel #9
0
def ldap_auth(username, password):
    if not username or not password:
        return False
    
    try:
        conn = ldap.initialize(config['ldap.url'])
        
        force_start_tls = False
        if config['ldap.cacert']:
            ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, config['ldap.cacert'])
            force_start_tls = True
            
        if config['ldap.cert']:
            ldap.set_option(ldap.OPT_X_TLS_CERTFILE, config['ldap.cert'])
            force_start_tls = True
            
        if config['ldap.key']:
            ldap.set_option(ldap.OPT_X_TLS_KEYFILE, config['ldap.key'])
            force_start_tls = True
    
        if force_start_tls:
            conn.start_tls_s()
        else:
            conn.set_option(ldap.OPT_X_TLS_DEMAND, config['ldap.start_tls'])
    except:
        log.error('Error initializing LDAP connection', exc_info=True)
        raise
    
    for basedn in listify(config['ldap.basedn']):
        dn = '{}={},{}'.format(config['ldap.userattr'], username, basedn)
        log.debug('attempting to bind with dn {}', dn)
        try:
            conn.simple_bind_s(dn, password)
        except ldap.INVALID_CREDENTIALS as x:
            continue
        except:
            log.warning("Error binding to LDAP server with dn", exc_info=True)
            raise
        else:
            return True
Beispiel #10
0
 def assert_read_result(self, expected, query, data=None):
     expected = listify(expected)
     actual = Session.crud.read(query, data)
     assert len(expected) == actual['total']
     assert sorted(expected, key=lambda m: m.get('id', m.get('_model'))) \
        ==  sorted(actual['results'], key=lambda m: m.get('id', m.get('_model')))
Beispiel #11
0
 def extract(self, models, *fields):
     return [{f: m[f] for f in fields if f in m} for m in listify(models)]
Beispiel #12
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
        Column('social_media', JSON(), table=None, nullable=False, default=ColumnDefault({}), 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.

    """  # noqa: E501
    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
Beispiel #13
0
 def assert_read_result(self, expected, query, data=None):
     expected = listify(expected)
     actual = Session.crud.read(query, data)
     self.assertEqual(len(expected), actual['total'])
     self.assertEqual(sorted(expected, key=lambda m: m.get('id', m.get('_model'))),
                      sorted(actual['results'],key=lambda m: m.get('id', m.get('_model'))))
Beispiel #14
0
 def banned(self):
     return listify(self.watch_list or self.watchlist_guess)
Beispiel #15
0
def groupify(items, keys, val_key=None):
    """
    Groups a list of items into nested OrderedDicts based on the given keys.

    `keys` may be a string, a callable, or a list thereof.

    `val_key` may be `None`, a string, or a callable. Defaults to `None`.

    Examples::

        >>> from json import dumps
        >>>
        >>> class Reminder:
        ...   def __init__(self, when, where, what):
        ...     self.when = when
        ...     self.where = where
        ...     self.what = what
        ...   def __repr__(self):
        ...     return 'Reminder({0.when}, {0.where}, {0.what})'.format(self)
        ...
        >>> reminders = [
        ...   Reminder('Fri', 'Home', 'Eat cereal'),
        ...   Reminder('Fri', 'Work', 'Feed Ivan'),
        ...   Reminder('Sat', 'Home', 'Sleep in'),
        ...   Reminder('Sat', 'Home', 'Play Zelda'),
        ...   Reminder('Sun', 'Home', 'Sleep in'),
        ...   Reminder('Sun', 'Work', 'Reset database')]
        >>>
        >>> print(dumps(groupify(reminders, None), indent=2, default=repr))
        ... [
        ...   "Reminder(Fri, Home, Eat cereal)",
        ...   "Reminder(Fri, Work, Feed Ivan)",
        ...   "Reminder(Sat, Home, Sleep in)",
        ...   "Reminder(Sat, Home, Play Zelda)",
        ...   "Reminder(Sun, Home, Sleep in)",
        ...   "Reminder(Sun, Work, Reset database)"
        ... ]
        >>>
        >>> print(dumps(groupify(reminders, 'when'), indent=2, default=repr))
        ... {
        ...   "Fri": [
        ...     "Reminder(Fri, Home, Eat cereal)",
        ...     "Reminder(Fri, Work, Feed Ivan)"
        ...   ],
        ...   "Sat": [
        ...     "Reminder(Sat, Home, Sleep in)",
        ...     "Reminder(Sat, Home, Play Zelda)"
        ...   ],
        ...   "Sun": [
        ...     "Reminder(Sun, Home, Sleep in)",
        ...     "Reminder(Sun, Work, Reset database)"
        ...   ]
        ... }
        >>>
        >>> print(dumps(groupify(reminders, ['when', 'where']),
        ...             indent=2, default=repr))
        ... {
        ...   "Fri": {
        ...     "Home": [
        ...       "Reminder(Fri, Home, Eat cereal)"
        ...     ],
        ...     "Work": [
        ...       "Reminder(Fri, Work, Feed Ivan)"
        ...     ]
        ...   },
        ...   "Sat": {
        ...     "Home": [
        ...       "Reminder(Sat, Home, Sleep in)",
        ...       "Reminder(Sat, Home, Play Zelda)"
        ...     ]
        ...   },
        ...   "Sun": {
        ...     "Home": [
        ...       "Reminder(Sun, Home, Sleep in)"
        ...     ],
        ...     "Work": [
        ...       "Reminder(Sun, Work, Reset database)"
        ...     ]
        ...   }
        ... }
        >>>
        >>> print(dumps(groupify(reminders, ['when', 'where'], 'what'),
        ...             indent=2))
        ... {
        ...   "Fri": {
        ...     "Home": [
        ...       "Eat cereal"
        ...     ],
        ...     "Work": [
        ...       "Feed Ivan"
        ...     ]
        ...   },
        ...   "Sat": {
        ...     "Home": [
        ...       "Sleep in",
        ...       "Play Zelda"
        ...     ]
        ...   },
        ...   "Sun": {
        ...     "Home": [
        ...       "Sleep in"
        ...     ],
        ...     "Work": [
        ...       "Reset database"
        ...     ]
        ...   }
        ... }
        >>>
        >>> print(dumps(groupify(reminders,
        ...                      lambda r: '{0.when} - {0.where}'.format(r),
        ...                      'what'), indent=2))
        ... {
        ...   "Fri - Home": [
        ...     "Eat cereal"
        ...   ],
        ...   "Fri - Work": [
        ...     "Feed Ivan"
        ...   ],
        ...   "Sat - Home": [
        ...     "Sleep in",
        ...     "Play Zelda"
        ...   ],
        ...   "Sun - Home": [
        ...     "Sleep in"
        ...   ],
        ...   "Sun - Work": [
        ...     "Reset database"
        ...   ]
        ... }
        >>>

    """
    if not keys:
        return items
    keys = listify(keys)
    last_key = keys[-1]
    call_val_key = callable(val_key)
    groupified = OrderedDict()
    for item in items:
        current = groupified
        for key in keys:
            attr = key(item) if callable(key) else getattr(item, key)
            if attr not in current:
                current[attr] = [] if key is last_key else OrderedDict()
            current = current[attr]
        if val_key:
            value = val_key(item) if call_val_key else getattr(item, val_key)
        else:
            value = item
        current.append(value)
    return groupified
Beispiel #16
0
 def __init__(self, hostnames, rpc_method, *args, **kwargs):
     from sideboard.lib import listify
     self.hostnames, self.method, self.args, self.kwargs = listify(hostnames), rpc_method, args, kwargs
     self.results, self.websockets, self._client_ids = {}, {}, {}
     on_startup(self._subscribe)
     on_shutdown(self._unsubscribe)