Merge branch 'users'
authorMarek Marecki <triviuss@gmail.com>
Fri, 5 Jul 2013 23:13:14 +0000 (01:13 +0200)
committerMarek Marecki <triviuss@gmail.com>
Fri, 5 Jul 2013 23:13:14 +0000 (01:13 +0200)
diaspy/errors.py
diaspy/models.py
diaspy/people.py
diaspy/streams.py

index e5a6167d4579f4b0bef3ed967121879712845179..90cc28dc3db72146cf1369b35eb04000759aed4c 100644 (file)
@@ -16,6 +16,12 @@ class LoginError(DiaspyError):
     pass
 
 
+class UserError(DiaspyError):
+    """Exception raised when something related to users goes wrong.
+    """
+    pass
+
+
 def react(r, message='', accepted=[200, 201, 202, 203, 204, 205, 206], exception=DiaspyError):
     """This method tries to decides how to react
     to a response code passed to it. If it's an
index c412d51ef461d7b5ee77194f46d6386d9c610e45..eb459f2d1140c58eb3b69e81e8f3bb2d9d7e4acf 100644 (file)
@@ -12,7 +12,7 @@ MUST NOT import anything.
 
 class Aspect():
     """This class represents an aspect.
-    
+
     Class can be initialized by passing either an id and/or name as
     parameters.
     If both are missing, an exception will be raised.
@@ -26,7 +26,7 @@ class Aspect():
             self.id = self._findid()
         elif not id and not name:
             raise Exception("Aspect must be initialized with either an id or name")
-    
+
     def _findname(self):
         """Finds name for aspect.
         """
@@ -37,7 +37,7 @@ class Aspect():
                 name = a['name']
                 break
         return name
-        
+
     def _findid(self):
         """Finds id for aspect.
         """
@@ -49,25 +49,28 @@ class Aspect():
                 break
         return id
 
-    def getUsers(self):
-        """Returns list of GUIDs of users who are listed in this aspect.
+    def _getajax(self):
+        """Returns HTML returned when editing aspects via web UI.
         """
         start_regexp = re.compile('<ul +class=["\']contacts["\'] *>')
-        userline_regexp = re.compile('<a href=["\']/people/[a-z0-9]{16,16}["\']>[a-zA-Z0-9()@. _-]+</a>')
-        personid_regexp = 'alt=["\']{0}["\'] class=["\']avatar["\'] data-person_id=["\'][0-9]+["\']'
-        method_regexp = 'data-method="delete" data-person_id="{0}"'
-
         ajax = self._connection.get('aspects/{0}/edit'.format(self.id)).text
 
         begin = ajax.find(start_regexp.search(ajax).group(0))
         end = ajax.find('</ul>')
-        ajax = ajax[begin:end]
+        return ajax[begin:end]
+
+    def _extractusernames(self, ajax):
+        """Extracts usernames and GUIDs from ajax returned by Diaspora*.
+        Returns list of two-tuples: (guid, diaspora_name).
+        """
+        userline_regexp = re.compile('<a href=["\']/people/[a-z0-9]{16,16}["\']>[\w()*@. -]+</a>')
+        return [(line[17:33], re.escape(line[35:-4])) for line in userline_regexp.findall(ajax)]
 
-        usernames = [(line[17:33], line[35:-4]) for line in userline_regexp.findall(ajax)]
-        for i, data in enumerate(usernames):
-            guid, name = data
-            for char in ['(', ')', '.']: name = name.replace(char, '\\'+char)
-            usernames[i] = (guid, name)
+    def _extractpersonids(self, ajax, usernames):
+        """Extracts `person_id`s and usernames from ajax and list of usernames.
+        Returns list of two-tuples: (username, id)
+        """
+        personid_regexp = 'alt=["\']{0}["\'] class=["\']avatar["\'] data-person_id=["\'][0-9]+["\']'
         personids = [re.compile(personid_regexp.format(name)).search(ajax).group(0) for guid, name in usernames]
         for n, line in enumerate(personids):
             i, id = -2, ''
@@ -75,22 +78,40 @@ class Aspect():
                 id = line[i] + id
                 i -= 1
             personids[n] = (usernames[n][1], id)
+        return personids
 
-        users_in_aspect = []
-        for name, id in personids:
-            if re.compile(method_regexp.format(id, self.id)).search(ajax): users_in_aspect.append(name)
-
+    def _defineusers(self, ajax, personids):
+        """Gets users contained in this aspect by getting users who have `delete` method.
+        """
+        method_regexp = 'data-method="delete" data-person_id="{0}"'
         users = []
-        for i, user in enumerate(usernames):
-            guid, name = user
-            if name in users_in_aspect: users.append(guid)
+        for name, id in personids:
+            if re.compile(method_regexp.format(id)).search(ajax): users.append(name)
         return users
 
+    def _getguids(self, users_in_aspect, usernames):
+        """Defines users contained in this aspect.
+        """
+        guids = []
+        for guid, name in usernames:
+            if name in users_in_aspect: guids.append(guid)
+        return guids
+
+    def getUsers(self):
+        """Returns list of GUIDs of users who are listed in this aspect.
+        """
+        ajax = self._getajax()
+        usernames = self._extractusernames(ajax)
+        personids = self._extractpersonids(ajax, usernames)
+        users_in_aspect = self._defineusers(ajax, personids)
+        return self._getguids(users_in_aspect, usernames)
+
     def addUser(self, user_id):
         """Add user to current aspect.
 
         :param user_id: user to add to aspect
-        :type user: int
+        :type user_id: int
+        :returns: JSON from request
         """
         data = {'authenticity_token': self._connection.get_token(),
                 'aspect_id': self.id,
index 25677fb10ea27f775a32676f155b3ac358bbf0a5..0e15076ee513da01d91f57c33b82e6b6aad0ab36 100644 (file)
@@ -1,6 +1,7 @@
 import re
 from diaspy.streams import Outer
 from diaspy.models import Aspect
+from diaspy import errors
 
 
 class User():
@@ -11,11 +12,11 @@ class User():
 
     The parameter fetch should be either 'posts', 'data' or 'none'. By
     default it is 'posts' which means in addition to user data, stream
-    will be fetched. If user has not posted yet diaspy will not be able 
-    to extract the information from his/her posts. Since there is no official 
-    way to do it we rely on user posts. If this will be the case user 
+    will be fetched. If user has not posted yet diaspy will not be able
+    to extract the information from his/her posts. Since there is no official
+    way to do it we rely on user posts. If this will be the case user
     will be notified with appropriate exception message.
-    
+
     If fetch is 'data', only user data will be fetched. If the user is
     not found, no exception will be returned.
 
@@ -62,7 +63,7 @@ class User():
         handle = self['handle'].split('@')
         pod, user = handle[1], handle[0]
         return (pod, user)
-        
+
     def _finalize_data(self, data, names):
         final = {}
         for d, f in names:
@@ -80,7 +81,7 @@ class User():
             raise Exception('wrong error code: {0}'.format(request.status_code))
         else:
             request = request.json()
-        if not len(request): raise Exception('Cannot extract user data: no posts to analyze')
+        if not len(request): raise errors.UserError('cannot extract user data: no posts to analyze')
         names = [('id', 'id'),
                  ('diaspora_id', 'diaspora_id'),
                  ('guid', 'guid'),
@@ -102,7 +103,7 @@ class User():
         """
         request = self._connection.get('people/{0}.json'.format(self['guid']))
         self._postproc(request)
-        
+
     def fetchprofile(self, protocol='https'):
         """Fetch user data using Diaspora handle.
         """
index 9b571f089b4b37e794aa83245eebfa0a8233a936..2a3c233750067df39f845dad204cbcfb398275fc 100644 (file)
@@ -105,7 +105,7 @@ class Generic():
     def update(self):
         """Updates stream.
         """
-        self._update( self._obtain())
+        self._update(self._obtain())
 
     def fill(self):
         """Fills the stream with posts.