----
--#### 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),
import diaspy.settings as settings
- __version__ = '0.4.1'
-__version__ = '0.4.0.1'
++__version__ = '0.4.1-rc.1'
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:
"""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):
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))
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)
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)