summaryrefslogtreecommitdiff
path: root/src/leap/mx/couchdbhelper.py
diff options
context:
space:
mode:
authordrebs <drebs@leap.se>2015-04-09 17:18:37 -0300
committerdrebs <drebs@leap.se>2015-04-09 18:20:00 -0300
commitb0ef529cc882a96903597fb5279919969fa286c3 (patch)
tree2243cd550e3e0769880b350184b5f5a3653c362a /src/leap/mx/couchdbhelper.py
parent45adb4d6cfdb8b9ed11e3efc398d00ec6dbdc0b0 (diff)
[refactor] use couch reduced views for lookups
The way uuid and pgp key were being queried by means of couch views was not efficient because they weren't using the reduce function and were filtering the views results in the python code. Also, the uuid is not actually needed to find out either if the address exists or if there's a pgp public key for that address. This commit refactors the couch helper to make use of the reduce functions in queried views and to get rid of the intermediate uuid querying.
Diffstat (limited to 'src/leap/mx/couchdbhelper.py')
-rw-r--r--src/leap/mx/couchdbhelper.py139
1 files changed, 30 insertions, 109 deletions
diff --git a/src/leap/mx/couchdbhelper.py b/src/leap/mx/couchdbhelper.py
index f20f1dd..7bcb5aa 100644
--- a/src/leap/mx/couchdbhelper.py
+++ b/src/leap/mx/couchdbhelper.py
@@ -15,24 +15,15 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
"""
Classes for working with CouchDB or BigCouch instances which store email alias
maps, user UUIDs, and GPG keyIDs.
"""
-from functools import partial
-
-try:
- from paisley import client
-except ImportError:
- print "This software requires paisley. Please see the README file"
- print "for instructions on getting required dependencies."
-try:
- from twisted.python import log
-except ImportError:
- print "This software requires Twisted. Please see the README file"
- print "for instructions on getting required dependencies."
+from paisley import client
+from twisted.python import log
class ConnectedCouchDB(client.CouchDB):
@@ -66,24 +57,8 @@ class ConnectedCouchDB(client.CouchDB):
username=username,
password=password,
*args, **kwargs)
-
self._cache = {}
- if dbName is None:
- databases = self.listDB()
- databases.addCallback(self._print_databases)
-
- def _print_databases(self, data):
- """
- Callback for listDB that prints the available databases
-
- :param data: response from the listDB command
- :type data: array
- """
- log.msg("Available databases:")
- for database in data:
- log.msg(" * %s" % (database,))
-
def createDB(self, dbName):
"""
Overrides ``paisley.client.CouchDB.createDB``.
@@ -100,106 +75,52 @@ class ConnectedCouchDB(client.CouchDB):
"""
Check to see if a particular email or alias exists.
- :param alias: A string representing the email or alias to check.
- :type alias: str
+ :param address: A string representing the email or alias to check.
+ :type address: str
:return: a deferred for this query
:rtype twisted.defer.Deferred
"""
- assert isinstance(address, (str, unicode)), "Email or alias queries must be string"
-
# TODO: Cache results
-
d = self.openView(docId="Identity",
viewId="by_address/",
key=address,
- reduce=False,
- include_docs=True)
+ reduce=True,
+ include_docs=False)
- d.addCallbacks(partial(self._get_uuid, address), log.err)
+ def _callback(result):
+ if len(result["rows"]):
+ return address
+ return None
+
+ d.addCallbacks(_callback, log.err)
return d
- def _get_uuid(self, address, result):
- """
- Parses the result of the by_address query and gets the uuid
-
- :param address: alias looked up
- :type address: string
- :param result: result dictionary
- :type result: dict
- :return: The uuid for alias if available
- :rtype: str
- """
- for row in result["rows"]:
- if row["key"] == address:
- uuid = row["doc"].get("user_id", None)
- if uuid is None:
- log.msg("ERROR: Found doc for %s but there's not user_id!"
- % (address,))
- return uuid
- return None
-
- def getPubKey(self, uuid):
+ def getPubKey(self, address):
"""
- Returns a deferred that will return the pubkey for the uuid provided
+ Returns a deferred that will fire with the pubkey for the address.
- :param uuid: uuid for the user to query
- :type uuid: str
+ :param address: email address to query
+ :type address: str
:rtype: Deferred
"""
d = self.openView(docId="Identity",
viewId="pgp_key_by_email/",
- user_id=uuid,
+ key=address,
reduce=False,
- include_docs=True)
-
- d.addCallbacks(partial(self._get_pgp_key, uuid), log.err)
+ include_docs=False)
- return d
-
- def _get_pgp_key(self, uuid, result):
- """
- Callback used to filter the correct pubkey from the result of
- the query to the couchdb
+ def _callback(result):
+ if not result["rows"]:
+ log.msg("No PGP public key found for %s." % address)
+ return None
+ if len(result["rows"]) > 1:
+ log.msg("More than one PGP public key found for %s, "
+ "will pick the first one found." % address)
+ row = result["rows"].pop(0)
+ return row["value"]
- :param uuid: uuid for the user that was queried
- :type uuid: str
- :param result: result dictionary for the db query
- :type result: dict
+ d.addCallbacks(_callback, log.err)
- :rtype: str or None
- """
- for row in result["rows"]:
- user_id = row["doc"].get("user_id")
- if not user_id:
- print("User %s is in an inconsistent state")
- continue
- if user_id == uuid:
- return row["value"]
- return None
-
-if __name__ == "__main__":
- from twisted.internet import reactor
- cdb = ConnectedCouchDB("localhost",
- port=6666,
- dbName="users",
- username="",
- password="")
-
- d = cdb.queryByLoginOrAlias("test1")
-
- @d.addCallback
- def right(result):
- print "Should be an actual uuid:", result
- print "Public Key:"
- print cdb.getPubKey(result)
-
- d2 = cdb.queryByLoginOrAlias("asdjaoisdjoiqwjeoi")
-
- @d2.addCallback
- def wrong(result):
- print "Should be None:", result
-
- reactor.callLater(5, reactor.stop)
- reactor.run()
+ return d