def fetch(self, userid_or_username, authority=None): """ Fetch a user by userid or by username and authority. Takes *either* a userid *or* a username and authority as arguments. For example:: user_service.fetch('acct:[email protected]') or:: user_service.fetch('foo', 'example.com') :returns: a user instance, if found :rtype: h.models.User or None """ if authority is not None: username = userid_or_username else: userid = userid_or_username parts = split_user(userid) username = parts['username'] authority = parts['domain'] # The cache is keyed by (username, authority) tuples. cache_key = (username, authority) if cache_key not in self._cache: self._cache[cache_key] = (self.session.query(User) .filter_by(username=username) .filter_by(authority=authority) .one_or_none()) return self._cache[cache_key]
def asdict(self): docpresenter = DocumentSearchIndexPresenter(self.annotation.document) userid_parts = split_user(self.annotation.userid) result = { 'authority': userid_parts['domain'], 'id': self.annotation.id, 'created': self.created, 'updated': self.updated, 'user': self.annotation.userid, 'user_raw': self.annotation.userid, 'uri': self.annotation.target_uri, 'text': self.text, 'tags': self.tags, 'tags_raw': self.tags, 'group': self.annotation.groupid, 'shared': self.annotation.shared, 'target': self.target, 'document': docpresenter.asdict(), 'thread_ids': self.annotation.thread_ids } result['target'][0]['scope'] = [self.annotation.target_uri_normalized] if self.annotation.references: result['references'] = self.annotation.references return result
def asdict(self): docpresenter = DocumentSearchIndexPresenter(self.annotation.document) userid_parts = split_user(self.annotation.userid) result = { "authority": userid_parts["domain"], "id": self.annotation.id, "created": self.created, "updated": self.updated, "user": self.annotation.userid, "user_raw": self.annotation.userid, "uri": self.annotation.target_uri, "text": self.text, "tags": self.tags, "tags_raw": self.tags, "group": self.annotation.groupid, "shared": self.annotation.shared, "target": self.target, "document": docpresenter.asdict(), "thread_ids": self.annotation.thread_ids, } result["target"][0]["scope"] = [self.annotation.target_uri_normalized] if self.annotation.references: result["references"] = self.annotation.references self._add_hidden(result) self._add_nipsa(result, self.annotation.userid) return result
def fetch(self, userid_or_username, authority=None): """ Fetch a user by userid or by username and authority. Takes *either* a userid *or* a username and authority as arguments. For example:: user_service.fetch('acct:[email protected]') or:: user_service.fetch('foo', 'example.com') :returns: a user instance, if found :rtype: h.models.User or None """ if authority is not None: username = userid_or_username else: userid = userid_or_username parts = split_user(userid) username = parts['username'] authority = parts['domain'] return self._cached_fetch(username, authority)
def __eq__(self, other): """ Compare the userid for equality with `other`. `other` can be anything plausibly on the RHS of a comparison, which can include other SQL clause elements or expressions, as in User.userid == sa.tuple_(User.username, Group.authority) or literals, as in User.userid == 'acct:[email protected]' We treat the literal case specially, and split the string into username and authority ourselves. If the string is not a well-formed userid, the comparison will always return False. """ if isinstance(other, str): try: val = split_user(other) except InvalidUserId: # The value being compared isn't a valid userid return False else: other = sa.tuple_(_normalise_username(val["username"]), val["domain"]) return self.__clause_element__() == other
def __eq__(self, other): """ Compare the userid for equality with `other`. `other` can be anything plausibly on the RHS of a comparison, which can include other SQL clause elements or expressions, as in User.userid == sa.tuple_(User.username, Group.authority) or literals, as in User.userid == 'acct:[email protected]' We treat the literal case specially, and split the string into username and authority ourselves. If the string is not a well-formed userid, the comparison will always return False. """ if isinstance(other, string_types): try: val = split_user(other) except ValueError: # The value being compared isn't a valid userid return False else: other = sa.tuple_(_normalise_username(val['username']), val['domain']) return self.__clause_element__() == other
def asdict(self): docpresenter = DocumentSearchIndexPresenter(self.annotation.document) userid_parts = split_user(self.annotation.userid) result = { 'authority': userid_parts['domain'], 'id': self.annotation.id, 'created': self.created, 'updated': self.updated, 'user': self.annotation.userid, 'user_raw': self.annotation.userid, 'uri': self.annotation.target_uri, 'text': self.text, 'tags': self.tags, 'tags_raw': self.tags, 'group': self.annotation.groupid, 'shared': self.annotation.shared, 'target': self.target, 'document': docpresenter.asdict(), 'thread_ids': self.annotation.thread_ids } result['target'][0]['scope'] = [self.annotation.target_uri_normalized] if self.annotation.references: result['references'] = self.annotation.references # Mark an annotation as hidden if it and all of it's children have been # moderated and hidden. parents_and_replies = [self.annotation.id] + self.annotation.thread_ids ann_mod_svc = self.request.find_service(name='annotation_moderation') result['hidden'] = len(ann_mod_svc.all_hidden(parents_and_replies)) == len(parents_and_replies) return result
def fetch(self, userid_or_username, authority=None): """ Fetch a user by userid or by username and authority. Takes *either* a userid *or* a username and authority as arguments. For example:: user_service.fetch('acct:[email protected]') or:: user_service.fetch('foo', 'example.com') :returns: a user instance, if found :raises InvalidUserId: If the userid cannot be parsed :rtype: h.models.User or None """ if authority is not None: username = userid_or_username else: userid = userid_or_username parts = split_user(userid) username = parts["username"] authority = parts["domain"] # The cache is keyed by (username, authority) tuples. cache_key = (username, authority) if cache_key not in self._cache: self._cache[cache_key] = (self.session.query(User).filter_by( username=username).filter_by( authority=authority).one_or_none()) return self._cache[cache_key]
def __eq__(self, other): try: val = split_user(other) except ValueError: # The value being compared isn't a valid userid return False return sa.and_(val['username'] == self.username, val['domain'] == self.authority)
def upgrade(): bind = op.get_bind() session = Session(bind=bind) op.execute(user.update().values(nipsa=False)) # Fetch all the existing NIPSA'd userids and set the NIPSA flag on the # corresponding rows in the user table, if they exist. for (userid, ) in session.query(nipsa): val = split_user(userid) op.execute(user.update().where( sa.and_(user.c.username == val['username'], user.c.authority == val['domain'])).values(nipsa=True))
def stream_user_redirect(request): """ Redirect to a user's activity page. """ user = request.matchdict['user'] # The client generates /u/ links which include the full account ID if user.startswith('acct:'): user = split_user(user)['username'] location = request.route_url('activity.user_search', username=user) raise httpexceptions.HTTPFound(location=location)
def in_(self, userids): others = [] for userid in userids: try: val = split_user(userid) except InvalidUserId: continue other = sa.tuple_(_normalise_username(val["username"]), val["domain"]) others.append(other) if not others: return False return self.__clause_element__().in_(others)
def in_(self, userids): others = [] for userid in userids: try: val = split_user(userid) except ValueError: continue other = sa.tuple_(_normalise_username(val["username"]), val["domain"]) others.append(other) if not others: return False return self.__clause_element__().in_(others)
def upgrade(): bind = op.get_bind() session = Session(bind=bind) op.execute(user.update().values(nipsa=False)) # Fetch all the existing NIPSA'd userids and set the NIPSA flag on the # corresponding rows in the user table, if they exist. for (userid,) in session.query(nipsa): val = split_user(userid) op.execute(user .update() .where(sa.and_(user.c.username == val['username'], user.c.authority == val['domain'])) .values(nipsa=True))
def in_(self, userids): # pylint: disable=arguments-renamed others = [] for userid in userids: try: val = split_user(userid) except InvalidUserId: continue other = sa.tuple_(_normalise_username(val["username"]), val["domain"]) others.append(other) if not others: return False return self.expression.in_(others)
def in_(self, userids): others = [] for userid in userids: try: val = split_user(userid) except ValueError: continue other = sa.tuple_(_normalise_username(val['username']), val['domain']) others.append(other) if not others: return False return self.__clause_element__().in_(others)
def authority(self): """ Return the authority of the user and group this annotation belongs to. For example, returns "hypothes.is" for Hypothesis first-party annotations, or "elifesciences.org" for eLife third-party annotations. If this annotation doesn't have a userid (which is possible for annotations that haven't been saved to the DB yet) then return None. :raises ValueError: if the annotation's userid is invalid """ if self.userid is None: return None return split_user(self.userid)['domain']
def authority(self): """ Return the authority of the user and group this annotation belongs to. For example, returns "hypothes.is" for Hypothesis first-party annotations, or "elifesciences.org" for eLife third-party annotations. If this annotation doesn't have a userid (which is possible for annotations that haven't been saved to the DB yet) then return None. :raises ValueError: if the annotation's userid is invalid """ if self.userid is None: return None return split_user(self.userid)["domain"]
def stream_user_redirect(request): """Redirect to a user's activity page.""" user = request.matchdict["user"] # The client generates /u/ links which include the full account ID if user.startswith("acct:"): try: user = split_user(user)["username"] except InvalidUserId: # If it's not a valid userid, catch the exception and just treat # the parameter as a literal username. pass location = request.route_url("activity.user_search", username=user) raise httpexceptions.HTTPFound(location=location)
def fetch_all(self, userids): """ Fetch a list of users by their userids. This function fetches users based on the list, adds them to the internal cache and then returns the list of users. This is especially useful when needing to access multiple user objects without loading them one-by-one. It will only attempt to load the users that aren't already cached. Userids that cannot be found will not be in the cache, so subsequent calls to `.fetch` are trying to load them again. :param userids: a list of userid strings. :returns: a list with the found user instances :rtype: list of h.models.User """ if not userids: return [] cache_keys = {} for userid in userids: try: val = split_user(userid) key = (val['username'], val['domain']) cache_keys[key] = userid except ValueError: continue userid_tuples = set(cache_keys.keys()) missing_tuples = userid_tuples - set(self._cache.keys()) missing_ids = [ v for k, v in cache_keys.iteritems() if k in missing_tuples ] if missing_ids: users = self.session.query(User).filter( User.userid.in_(missing_ids)) for user in users: cache_key = (user.username, user.authority) self._cache[cache_key] = user return [ v for k, v in self._cache.iteritems() if k in cache_keys.keys() ]
def stream_user_redirect(request): """ Redirect to a user's activity page. """ user = request.matchdict["user"] # The client generates /u/ links which include the full account ID if user.startswith("acct:"): user = split_user(user)["username"] if request.feature("search_page"): location = request.route_url("activity.user_search", username=user) else: query = {"q": "user:{}".format(user)} location = request.route_url("stream", _query=query) raise httpexceptions.HTTPFound(location=location)
def stream_user_redirect(request): """ Redirect to a user's activity page. """ user = request.matchdict['user'] # The client generates /u/ links which include the full account ID if user.startswith('acct:'): user = split_user(user)['username'] if request.feature('search_page'): location = request.route_url('activity.user_search', username=user) else: query = {'q': 'user:{}'.format(user)} location = request.route_url('stream', _query=query) raise httpexceptions.HTTPFound(location=location)
def stream_user_redirect(request): """ Redirect to a user's activity page. """ user = request.matchdict['user'] # The client generates /u/ links which include the full account ID if user.startswith('acct:'): try: user = split_user(user)['username'] except ValueError: # If it's not a valid userid, catch the exception and just treat # the parameter as a literal username. pass location = request.route_url('activity.user_search', username=user) raise httpexceptions.HTTPFound(location=location)
def fetch_all(self, userids): """ Fetch a list of users by their userids. This function fetches users based on the list, adds them to the internal cache and then returns the list of users. This is especially useful when needing to access multiple user objects without loading them one-by-one. It will only attempt to load the users that aren't already cached. Userids that cannot be found will not be in the cache, so subsequent calls to `.fetch` are trying to load them again. :param userids: a list of userid strings. :returns: a list with the found user instances :rtype: list of h.models.User """ if not userids: return [] cache_keys = {} for userid in userids: try: val = split_user(userid) key = (val["username"], val["domain"]) cache_keys[key] = userid except ValueError: continue userid_tuples = set(cache_keys.keys()) missing_tuples = userid_tuples - set(self._cache.keys()) missing_ids = [v for k, v in cache_keys.items() if k in missing_tuples] if missing_ids: users = self.session.query(User).filter(User.userid.in_(missing_ids)) for user in users: cache_key = (user.username, user.authority) self._cache[cache_key] = user return [v for k, v in self._cache.items() if k in cache_keys.keys()]
def asdict(self): docpresenter = DocumentSearchIndexPresenter(self.annotation.document) userid_parts = split_user(self.annotation.userid) result = { "authority": userid_parts["domain"], "id": self.annotation.id, "created": self.created, "updated": self.updated, "user": self.annotation.userid, "user_raw": self.annotation.userid, "uri": self.annotation.target_uri, "text": self.text, "tags": self.tags, "tags_raw": self.tags, "group": self.annotation.groupid, "shared": self.annotation.shared, "target": self.target, "document": docpresenter.asdict(), "thread_ids": self.annotation.thread_ids, } result["target"][0]["scope"] = [self.annotation.target_uri_normalized] if self.annotation.references: result["references"] = self.annotation.references # Mark an annotation as hidden if it and all of it's children have been # moderated and hidden. parents_and_replies = [self.annotation.id] + self.annotation.thread_ids ann_mod_svc = self.request.find_service(name="annotation_moderation") result["hidden"] = len(ann_mod_svc.all_hidden(parents_and_replies)) == len( parents_and_replies ) return result
def asdict(self): docpresenter = DocumentSearchIndexPresenter(self.annotation.document) userid_parts = split_user(self.annotation.userid) result = { "authority": userid_parts["domain"], "id": self.annotation.id, "created": self.created, "updated": self.updated, "user": self.annotation.userid, "user_raw": self.annotation.userid, "uri": self.annotation.target_uri, "text": self.text, "tags": self.tags, "tags_raw": self.tags, "group": self.annotation.groupid, "shared": self.annotation.shared, "target": self.target, "document": docpresenter.asdict(), "thread_ids": self.annotation.thread_ids, } result["target"][0]["scope"] = [self.annotation.target_uri_normalized] if self.annotation.references: result["references"] = self.annotation.references # Mark an annotation as hidden if it and all of it's children have been # moderated and hidden. parents_and_replies = [self.annotation.id] + self.annotation.thread_ids ann_mod_svc = self.request.find_service(name="annotation_moderation") result["hidden"] = len(ann_mod_svc.all_hidden( parents_and_replies)) == len(parents_and_replies) return result
def test_split_user(): parts = user_util.split_user("acct:[email protected]") assert parts == {'username': '******', 'domain': 'hypothes.is'}
def test_split_user_no_match(): with pytest.raises(InvalidUserId): user_util.split_user("donkeys")
def test_split_user(): parts = user_util.split_user("acct:[email protected]") assert parts == {"username": "******", "domain": "hypothes.is"}
def test_split_user_no_match(): with pytest.raises(ValueError): user_util.split_user("donkeys")
def username_from_id(userid): parts = split_user(userid) return parts['username']
def username_from_id(userid): parts = split_user(userid) return parts["username"]