Merge branch 'fladrian-patch-for-d-0.2.0.0' into devel
authorMarek Marecki <marekjm@taistelu.com>
Mon, 2 Sep 2013 15:36:56 +0000 (17:36 +0200)
committerMarek Marecki <marekjm@taistelu.com>
Mon, 2 Sep 2013 15:36:56 +0000 (17:36 +0200)
Conflicts:
diaspy/connection.py

1  2 
Changelog.markdown
diaspy/__init__.py
diaspy/connection.py
diaspy/people.py
diaspy/streams.py
tests.py

index eaa2c1a53440e87e325147917a6ecde2f861958e,790cc0c9b9d0c950b53ff0547b21b6604405b217..fcd40925461dd3073faaa5b4a9713ac235f83f0c
@@@ -21,34 -21,14 +21,42 @@@ up-to-date than manual and if conflict
  
  ----
  
--#### Version `0.4.1` (2013-08-):
++#### Version `0.4.1` (2013-09-):
 +
 +Login and authentication procedure backend received major changes in this version.
 +There are no longer `username` and `password` variables in `Connection` object.
 +Instead, credentials are stored (together with the token) in single variable `_login_data`.
 +This is preserved until you call `login()` at which point credentials are erased and
 +only token is left -- it can be obtained by calling `repr(Connection)`.
 +
++Also, this release is compatible with DIASPORA\* 0.2.0.0 but should still support
++pods running on older versions.
++
++And the test suite was updated. Yay!
++
++**`0.4.1-rc.1` (2013-09-02):**
  
  * __new__:  `__getitem__()` in `diaspy.models.Post`,
 +* __new__:  `__dict__()` in `diaspy.models.Post`,
 +* __new__:  `guid` argument in `diaspy.models.Post.__init__()`,
  * __new__:  `json()` method in `diaspy.streams.Generic` adds the possibility to export streams to JSON,
  * __new__:  `full()` method in `diaspy.streams.Generic` will try to fetch full stream (containing all posts),
  * __new__:  `setEmail()` method in `diaspy.settings.Settings`,
  * __new__:  `setLanguage()` method in `diaspy.settings.Settings`,
  * __new__:  `downloadPhotos()` method in `diaspy.settings.Settings`,
- * __new__:  `getSessionToken()` method in `diaspy.connection.Connection`,
 +* __new__:  `backtime` argument in `more()` method in `diaspy.streams.Generic`,
 +* __new__:  `DiaspyError` will be raised when connection is created with empty password and/or username,
++* __new__:  `getSessionToken()` method in `diaspy.connection.Connection` returns string from `_diaspora_session` cookie,
++* __new__:  `direct` parameter in `diaspy.connection.Connection().get()` allowing to disable pod expansion,
 +
 +* __upd__:  if `Post()` is created with fetched comments, data will also be fetched as a dependency,
 +* __upd__:  `id` argument type is now `int` (`diaspy.models.Post.__init__()`),
 +* __upd__:  `Search().lookup_user()` renamed to `Search().lookupUser()`,
 +* __upd__:  `diaspy.messages` renamed to `diaspy.conversations` (but will be accessible under both names for this and next release),
 +* __upd__:  `LoginError` moved to `diaspy.errors`,
 +* __upd__:  `TokenError` moved to `diaspy.errors`,
 +* __upd__:  `diaspy.connection.Connection.podswitch()` gained two new positional arguments: `username` and `password`,
++* __upd__:  `aspect_id` renamed to `id` in `diaspy.streams.Aspects().remove()`,
  
  * __fix__:  fixed some bugs in regular expressions used by `diaspy` internals
              (html tag removal, so you get nicer notifications),
index aabd59fdd562aa18613cc19ca97e1a8335e6e466,7e12ab610dcd0c046d5722efa57471ccf188f759..dbc2b60e71a1e6cf3bf1e89f3e70bb1de0883369
@@@ -8,4 -7,4 +8,4 @@@ import diaspy.notifications as notifica
  import diaspy.settings as settings
  
  
- __version__ = '0.4.1'
 -__version__ = '0.4.0.1'
++__version__ = '0.4.1-rc.1'
index 51f344940b7278bcd677bcced6c8b15a59cb7ff6,5d0b1829c4f03310b266157462d9b1686ada4f06..e0d435230991168f848375d6d4dcb6840597dc3a
@@@ -52,9 -51,9 +52,9 @@@ class Connection()
              repr(connection)
          instead of calling a specified method.
          """
 -        return self.get_token()
 +        return self._token
  
--    def get(self, string, headers={}, params={}):
++    def get(self, string, headers={}, params={}, direct=False):
          """This method gets data from session.
          Performs additional checks if needed.
  
  
          :param string: URL to get without the pod's URL and slash eg. 'stream'.
          :type string: str
++        :param direct: if passed as True it will not be expanded
++        :type direct: bool
          """
-         return self._session.get('{0}/{1}'.format(self.pod, string), params=params, headers=headers)
 -        return self.session.get('{0}/{1}'.format(self.pod, string), params=params, headers=headers)
++        if not direct: url = '{0}/{1}'.format(self.pod, string)
++        else: url = string
++        return self._session.get(url, params=params, headers=headers)
  
      def post(self, string, data, headers={}, params={}):
          """This method posts data to session.
          Raises LoginError if login failed.
          """
          request = self.post('users/sign_in',
-                             data=self._login_data,
-                             headers={'accept': 'application/json,text/html'})
 -                            data=self.login_data)
 -        if request.status_code != 200:
 -            print(request)
 -            raise LoginError('{0}: login failed'.format(request.status_code))
++                            data=self._login_data)
 +        if request.status_code not in [200, 201]:
 +            raise errors.LoginError('{0}: login failed'.format(request.status_code))
-         print(request.headers)
++        self._diaspora_session = request.cookies['_diaspora_session']
  
      def login(self, username='', password=''):
          """This function is used to log in to a pod.
  
          :returns: dict -- json formatted user info.
          """
-         if self._userdata == {} or fetch:
-             request = self.get('bookmarklet')
-             userdata = self._userinfo_regex.search(request.text)
-             if userdata is None: userdata = self._userinfo_regex_2.search(request.text)
-             if userdata is None: raise errors.DiaspyError('cannot find user data')
-             userdata = userdata.group(1)
-             print(userdata)
-             self._userdata = json.loads(userdata)
-         return self._userdata
+         request = self.get('bookmarklet')
 -        try:
 -            userdata = json.loads(self._userinfo_regex.search(request.text).group(1))
 -        except AttributeError:
 -            raise errors.DiaspyError('cannot find user data')
 -        return userdata
++        userdata = self._userinfo_regex.search(request.text)
++        if userdata is None: userdata = self._userinfo_regex_2.search(request.text)
++        if userdata is None: raise errors.DiaspyError('cannot find user data')
++        userdata = userdata.group(1)
++        warnings.warn(userdata)
++        return json.loads(userdata)
  
      def _fetchtoken(self):
          """This method tries to get token string needed for authentication on D*.
          """
          request = self.get('stream')
          token = self._token_regex.search(request.text).group(1)
 -        self.token = token
 +        self._token = token
          return token
  
-     def get_token(self, fetch=False):
+     def get_token(self, fetch=True):
          """This function returns a token needed for authentication in most cases.
 +        **Notice:** using repr() is recommended method for getting token.
 +
+         Each time it is run a _fetchtoken() is called and refreshed token is stored.
+         It is more safe to use than _fetchtoken().
+         By setting new you can request new token or decide to get stored one.
+         If no token is stored new one will be fetched anyway.
          :returns: string -- token used to authenticate
          """
          try:
index c86067da1dd2b183b8e12f49c4c7a3c22a0e57bb,c86067da1dd2b183b8e12f49c4c7a3c22a0e57bb..c20283f5d70592024cd275f2dd8c0e2668c0caa9
@@@ -99,7 -99,7 +99,7 @@@ class User()
          """Fetch user data and posts using Diaspora handle.
          """
          pod, user = sephandle(self.handle)
--        request = self._connection.session.get('{0}://{1}/u/{2}.json'.format(protocol, pod, user))
++        request = self._connection.get('{0}://{1}/u/{2}.json'.format(protocol, pod, user), direct=True)
          self._postproc(request)
  
      def fetchguid(self):
index d6ffaedd80f29b824bf1db12043baa5f6e70fdfc,1d06a50a1ea0b5702ef4fd0cf4ebdf4cf56e0dd6..66036c7dbde30117c57d5faaef83adb72bebcbd5
@@@ -356,7 -322,7 +356,7 @@@ class Aspects(Generic)
          id = self.getAspectID(aspect_name)
          return Aspect(self._connection, id)
  
--    def remove(self, aspect_id=-1, name=''):
++    def remove(self, id=-1, name=''):
          """This method removes an aspect.
          You can give it either id or name of the aspect.
          When both are specified, id takes precedence over name.
          :param name: name of aspect to remove
          :type name: str
          """
--        if aspect_id == -1 and name: aspect_id = self.getAspectID(name)
++        if id == -1 and name: id = self.getAspectID(name)
          data = {'_method': 'delete',
                  'authenticity_token': self._connection.get_token()}
--        request = self._connection.post('aspects/{0}'.format(aspect_id), data=data)
++        request = self._connection.post('aspects/{0}'.format(id), data=data)
          if request.status_code not in [200, 302, 500]:
              raise Exception('wrong status code: {0}: cannot remove aspect'.format(request.status_code))
  
diff --cc tests.py
index 500a62ff444053b7091579019b7e59239cf60452,83c9e39cf2d76b3f1416e034b69b343f57fe8f34..2eade928b6028f40e887098ed10edf696933b643
+++ b/tests.py
@@@ -40,6 -40,6 +40,15 @@@ test_connection = diaspy.connection.Con
  test_connection.login()
  print('[ CONNECTED ]\n')
  
++# Setup test aspects
++print('Adding test aspects...\t', end='')
++diaspy.streams.Aspects(test_connection).add(testconf.test_aspect_name_fake)
++testconf.test_aspect_id = diaspy.streams.Aspects(test_connection).add(testconf.test_aspect_name).id
++print('OK')
++
++print([i['name'] for i in test_connection.getUserInfo()['aspects']])
++
++
  post_text = '#diaspy test no. {0}'.format(test_count)
  
  
@@@ -68,6 -68,6 +77,32 @@@ class MessagesTests(unittest.TestCase)
                  self.assertEqual(diaspy.models.Conversation, type(mailbox[i]))
  
  
++class AspectsTests(unittest.TestCase):
++    def testAspectsGettingID(self):
++        aspects = diaspy.streams.Aspects(test_connection)
++        id = aspects.getAspectID(testconf.test_aspect_name)
++        self.assertEqual(testconf.test_aspect_id, id)
++
++    def testAspectsRemoveById(self):
++        aspects = diaspy.streams.Aspects(test_connection)
++        for i in test_connection.getUserInfo()['aspects']:
++            if i['name'] == testconf.test_aspect_name:
++                print(i['id'], end=' ')
++                aspects.remove(id=i['id'])
++                break
++        names = [i['name'] for i in test_connection.getUserInfo()['aspects']]
++        print(names)
++        self.assertNotIn(testconf.test_aspect_name, names)
++
++    def testAspectsRemoveByName(self):
++        aspects = diaspy.streams.Aspects(test_connection)
++        print(testconf.test_aspect_name_fake, end=' ')
++        aspects.remove(name=testconf.test_aspect_name_fake)
++        names = [i['name'] for i in test_connection.getUserInfo()['aspects']]
++        print(names)
++        self.assertNotIn(testconf.test_aspect_name_fake, names)
++
++
  class StreamTest(unittest.TestCase):
      def testGetting(self):
          stream = diaspy.streams.Generic(test_connection)
          ft = diaspy.streams.FollowedTags(test_connection)
          ft.add('test')
  
--    def testAspectsAdd(self):
--        aspects = diaspy.streams.Aspects(test_connection)
--        aspects.add(testconf.test_aspect_name_fake)
--        testconf.test_aspect_id = aspects.add(testconf.test_aspect_name).id
--
--    def testAspectsGettingID(self):
--        aspects = diaspy.streams.Aspects(test_connection)
--        id = aspects.getAspectID(testconf.test_aspect_name)
--        self.assertEqual(testconf.test_aspect_id, id)
--
--    def testAspectsRemoveById(self):
--        aspects = diaspy.streams.Aspects(test_connection)
--        aspects.remove(testconf.test_aspect_id)
--        self.assertEqual(-1, aspects.getAspectID(testconf.test_aspect_name))
--
--    def testAspectsRemoveByName(self):
--        aspects = diaspy.streams.Aspects(test_connection)
--        aspects.remove(name=testconf.test_aspect_name_fake)
--        self.assertEqual(-1, aspects.getAspectID(testconf.test_aspect_name_fake))
--
      def testActivity(self):
          activity = diaspy.streams.Activity(test_connection)