Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Feature/pkgdb #29

Merged
merged 4 commits into from

2 participants

@ralphbean
Owner

This should fix #28.

fedbadges/utils.py
((34 lines not shown))
+ if not req.status_code == 200:
+ return set()
+ data = json.loads(req.text)
+ packages = set()
+ for pkgacl in data['acls']:
+ if pkgacl['status'] != 'Approved':
+ continue
+ packages.add(pkgacl['packagelist']['package']['name'])
+ log.debug("done talking with pkgdb2 for now.")
+ return packages
+
+
+# TODO -- delete this once pkgdb2 goes live.
+def _get_pkgdb1_packages_for(config, username):
+ log.debug("Requesting pkgdb1 packages for user %r" % username)
+ pkgdb1_base_url = 'https://admin.fedoraproject.org/pkgdb'
@pypingou Owner
pypingou added a note

just a thought, not sure worth patching, but since we have fedbadges.rules.utils.use_pkgdb2 couldn't we store the pkgdb_url in the config regardless of pkgdb1/2 ?

@ralphbean Owner

Yes, good catch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@pypingou
Owner

One small question but it looks sane, :+1:
Is there a way to add tests for this code?

@ralphbean
Owner

Is there a way to add tests for this code?

Yes, but we'd either need to mock out the requests library, or allow network communication. But I'd rather not. ;)

@ralphbean ralphbean merged commit 8320d71 into from
@ralphbean ralphbean deleted the branch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 4, 2014
  1. @ralphbean

    Add a negation operator.

    ralphbean authored
  2. @ralphbean
  3. @ralphbean

    PEP8.

    ralphbean authored
  4. @ralphbean
This page is out of date. Refresh to see the latest.
View
64 fedbadges/rules.py
@@ -21,11 +21,15 @@
import datanommer.models
from fedbadges.utils import (
+ # These are all in-process utilities
construct_substitutions,
format_args,
single_argument_lambda_factory,
recursive_lambda_factory,
graceful,
+
+ # This makes a network API call
+ get_pkgdb_packages_for,
)
import logging
@@ -42,7 +46,7 @@
operators = set([
"all",
"any",
- #"not",
+ "not",
])
lambdas = set([
"lambda",
@@ -51,6 +55,7 @@
operator_lookup = {
"any": any,
"all": all,
+ "not": lambda x: all([not item for item in x])
}
fedmsg_config = fedmsg.config.load_config()
@@ -243,7 +248,13 @@ def __init__(self, *args, **kwargs):
self.attribute = self._d.keys()[0]
self.expected_value = self._d[self.attribute]
- # Check if we should we recursively nest Trigger/Criteria?
+ ### Check if we should we recursively nest Trigger/Criteria?
+
+ # First, trick negation into thinking it is not a unary operator.
+ if self.attribute == 'not':
+ self.expected_value = [self.expected_value]
+
+ # Then, treat everything as if it accepts an arbitrary # of args.
if self.attribute in operators:
if not isinstance(self.expected_value, list):
raise TypeError("Operators only accept lists, not %r" %
@@ -281,6 +292,7 @@ def matches(self, msg):
class Criteria(AbstractTopLevelComparator):
possible = set([
'datanommer',
+ 'pkgdb',
]).union(operators)
def __init__(self, *args, **kwargs):
@@ -293,6 +305,8 @@ def __init__(self, *args, **kwargs):
def _specialize(self):
if self.attribute == 'datanommer':
self.specialization = DatanommerCriteria(self.expected_value)
+ elif self.attribute == 'pkgdb':
+ self.specialization = PkgdbCriteria(self.expected_value)
# TODO -- expand this with other "backends" as necessary
#elif self.attribute == 'fas'
else:
@@ -312,6 +326,52 @@ class AbstractSpecializedComparator(AbstractComparator):
pass
+class PkgdbCriteria(AbstractSpecializedComparator):
+ required = possible = set([
+ 'owns',
+ ])
+
+ def __init__(self, *args, **kwargs):
+ super(PkgdbCriteria, self).__init__(*args, **kwargs)
+
+ # Validate the owns dict
+ if not isinstance(self._d['owns'], dict):
+ raise ValueError("'owns' must be a dict")
+
+ owns_fields = set(['user', 'packages'])
+ argued_fields = set(self._d['owns'].keys())
+
+ if not argued_fields.issubset(owns_fields):
+ raise KeyError(
+ "%r are not possible fields. Choose from %r" % (
+ argued_fields.difference(owns_fields),
+ owns_fields,
+ ))
+
+ if not owns_fields.issubset(argued_fields):
+ raise KeyError(
+ "%r are missing required fields." % (
+ owns_fields.difference(argued_fields),
+ ))
+
+ if not isinstance(self._d['owns']['packages'], list):
+ raise ValueError("'packages' must be a list")
+
+ def matches(self, msg):
+ """ A pkgdb criteria check checks if a user owns some packages. """
+
+ subs = construct_substitutions(msg)
+ expectation = format_args(copy.copy(self._d['owns']), subs)
+ expectation = recursive_lambda_factory(expectation, msg, name='msg')
+
+ actual_packages = get_pkgdb_packages_for(
+ config=fedmsg_config,
+ user=expectation['user'],
+ )
+
+ return set(expectation['packages']).issubset(actual_packages)
+
+
class DatanommerCriteria(AbstractSpecializedComparator):
required = possible = set([
'filter',
View
62 fedbadges/utils.py
@@ -1,15 +1,21 @@
""" Utilities for fedbadges that don't quite fit anywhere else. """
+import json
import types
import logging
log = logging.getLogger("moksha.hub")
import fedmsg
+import requests
+
+# This is used for our queries against pkgdb
+from dogpile.cache import make_region
+_cache = make_region()
+
# These are here just so they're available in globals()
# for compiling lambda expressions
-import json
import re
import fedmsg.config
import fedmsg.encoding
@@ -109,3 +115,57 @@ def notification_callback(topic, msg):
topic=topic,
msg=msg,
)
+
+
+def get_pkgdb_packages_for(config, username):
+ """ Retrieve the list of packages where the specified user some acl.
+
+ :arg config: a dict containing the fedmsg config
+ :arg username: the fas username of the packager whose packages are of
+ interest.
+ :return: a set listing all the packages where the specified user has
+ some ACL.
+
+ """
+
+ if not hasattr(_cache, 'backend'):
+ _cache.configure(**config['fedbadges.rules.cache'])
+
+ @_cache.cache_on_arguments()
+ def _getter(username):
+ if config.get('fedbadges.rules.utils.use_pkgdb2', True):
+ return _get_pkgdb2_packages_for(config, username)
+ else:
+ return _get_pkgdb1_packages_for(config, username)
+
+ return _getter(username)
+
+
+def _get_pkgdb2_packages_for(config, username):
+ log.debug("Requesting pkgdb2 packages for user %r" % username)
+ req = requests.get('{0}/packager/acl/{1}'.format(
+ config['fedbadges.rules.utils.pkgdb_url'], username))
+ if not req.status_code == 200:
+ return set()
+ data = json.loads(req.text)
+ packages = set()
+ for pkgacl in data['acls']:
+ if pkgacl['status'] != 'Approved':
+ continue
+ packages.add(pkgacl['packagelist']['package']['name'])
+ log.debug("done talking with pkgdb2 for now.")
+ return packages
+
+
+# TODO -- delete this once pkgdb2 goes live.
+def _get_pkgdb1_packages_for(config, username):
+ log.debug("Requesting pkgdb1 packages for user %r" % username)
+ pkgdb1_base_url = config['fedbadges.rules.utils.pkgdb_url']
+ req = requests.get('{0}/users/packages/{1}?tg_format=json'.format(
+ pkgdb1_base_url, username))
+ if not req.status_code == 200:
+ return set()
+ data = json.loads(req.text)
+ packages = set([pkg['name'] for pkg in data['pkgs']])
+ log.debug("done talking with pkgdb1 for now.")
+ return packages
View
12 fedmsg.d/badges-global.py
@@ -28,4 +28,16 @@
issuer_contact='badges@fedoraproject.org',
),
},
+
+ # Some configuration for the pkgdb criteria handler
+ "fedbadges.rules.utils.use_pkgdb2": False,
+ "fedbadges.rules.utils.pkgdb_url": 'https://admin.fedoraproject.org/pkgdb',
+ #"fedbadges.rules.utils.pkgdb_url": "http://209.132.184.188/api/",
+ "fedbadges.rules.cache": {
+ "backend": "dogpile.cache.dbm",
+ "expiration_time": 300,
+ "arguments": {
+ "filename": "/var/tmp/fedbadges-cache.dbm",
+ },
+ },
}
View
2  requirements.txt
@@ -4,3 +4,5 @@ fedmsg_meta_fedora_infrastructure
PyYAML
datanommer.models
zope.sqlalchemy
+requests
+dogpile.cache
View
0  tests/test_criteria.py → tests/test_criteria_datanommer.py
File renamed without changes
View
12 tests/test_rule_matching.py
@@ -235,8 +235,7 @@ def count(self):
"title": "gnome-settings-daemon-3.6.1-1.fc18," +
"control-center-3.6.1-1.fc18",
"nagged": None,
- "comments": [
- {
+ "comments": [{
"group": None,
"author": "bodhi",
"text": "This update has been submitted for "
@@ -246,8 +245,7 @@ def count(self):
"timestamp": 1349718539.0,
"update_title": "gnome-settings-daemon-3.6.1-1.fc18," +
"control-center-3.6.1-1.fc18"
- }
- ],
+ }],
"updateid": None,
"type": "bugfix",
"close_bugs": True,
@@ -261,8 +259,7 @@ def count(self):
"id_prefix": "FEDORA"
},
"approved": None,
- "builds": [
- {
+ "builds": [{
"nvr": "gnome-settings-daemon-3.6.1-1.fc18",
"package": {
"suggest_reboot": False,
@@ -298,8 +295,7 @@ def count(self):
],
"name": "control-center"
}
- }
- ],
+ }],
"date_modified": None,
"notes": "This update fixes numerous bugs in the new Input " +
"Sources support, the Network panel and adds a help " +
Something went wrong with that request. Please try again.