4410c4f24614d37375d5d8513d3da1a8677f2746
7 from diaspy
.streams
import Outer
8 from diaspy
.models
import Aspect
9 from diaspy
import errors
10 from diaspy
import search
13 def sephandle(handle
):
14 """Separate Diaspora* handle into pod pod and user.
16 :returns: two-tuple (pod, user)
18 if re
.match('^[a-zA-Z]+[a-zA-Z0-9_-]*@[a-z0-9.]+\.[a-z]+$', handle
) is None:
19 raise errors
.InvalidHandleError('{0}'.format(handle
))
20 handle
= handle
.split('@')
21 pod
, user
= handle
[1], handle
[0]
26 """This class abstracts a D* user.
27 This object goes around the limitations of current D* API and will
28 extract user data using black magic.
29 However, no chickens are harmed when you use it.
31 The parameter fetch should be either 'posts', 'data' or 'none'. By
32 default it is 'posts' which means in addition to user data, stream
33 will be fetched. If user has not posted yet diaspy will not be able
34 to extract the information from his/her posts. Since there is no official
35 way to do it we rely on user posts. If this will be the case user
36 will be notified with appropriate exception message.
38 If fetch is 'data', only user data will be fetched. If the user is
39 not found, no exception will be returned.
41 When creating new User() one can pass either guid, handle and/or id as
42 optional parameters. GUID takes precedence over handle when fetching
43 user stream. When fetching user data, handle is required.
46 def parse(cls
, connection
, data
):
47 person
= data
.get('person')
49 raise errors
.KeyMissingFromFetchedData('person', data
)
51 guid
= person
.get('guid')
53 raise errors
.KeyMissingFromFetchedData('guid', person
)
55 handle
= person
.get('diaspora_id')
57 raise errors
.KeyMissingFromFetchedData('diaspora_id', person
)
59 person_id
= person
.get('id')
61 raise errors
.KeyMissingFromFetchedData('id', person
)
63 return User(connection
, guid
, handle
, id)
65 def __init__(self
, connection
, guid
='', handle
='', fetch
='posts', id=0):
66 self
._connection
= connection
75 def __getitem__(self
, key
):
82 return '{0} ({1})'.format(self
['handle'], self
['guid'])
84 def _fetchstream(self
):
85 self
.stream
= Outer(self
._connection
, location
='people/{0}.json'.format(self
['guid']))
87 def _fetch(self
, fetch
):
88 """Fetch user posts or data.
91 if self
['handle'] and not self
['guid']: self
.fetchhandle()
92 else: self
.fetchguid()
93 elif fetch
== 'data' and self
['handle']:
96 def _finalize_data(self
, data
):
97 """Adjustments are needed to have similar results returned
98 by search feature and fetchguid()/fetchhandle().
100 names
= [('id', 'id'),
103 ('avatar', 'avatar'),
104 ('handle', 'diaspora_id'),
111 def _postproc(self
, request
):
112 """Makes necessary modifications to user data and
115 :param request: request object
116 :type request: request
118 if request
.status_code
!= 200: raise Exception('wrong error code: {0}'.format(request
.status_code
))
119 request
= request
.json()
120 if not len(request
): raise errors
.UserError('cannot extract user data: no posts to analyze')
121 self
.data
= self
._finalize
_data
(request
[0]['author'])
123 def fetchhandle(self
, protocol
='https'):
124 """Fetch user data and posts using Diaspora handle.
126 pod
, user
= sephandle(self
['handle'])
127 request
= self
._connection
.get('{0}://{1}/u/{2}.json'.format(protocol
, pod
, user
), direct
=True)
128 self
._postproc
(request
)
132 """Fetch user data and posts using guid.
135 request
= self
._connection
.get('people/{0}.json'.format(self
['guid']))
136 self
._postproc
(request
)
139 raise errors
.UserError('GUID not set')
141 def fetchprofile(self
):
142 """Fetches user data.
144 data
= search
.Search(self
._connection
).user(self
['handle'])
146 raise errors
.UserError('user with handle "{0}" has not been found on pod "{1}"'.format(self
['handle'], self
._connection
.pod
))
151 """Returns XML string containing user HCard.
153 request
= self
._connection
.get('hcard/users/{0}'.format(self
['guid']))
154 if request
.status_code
!= 200: raise errors
.UserError('could not fetch hcard for user: {0}'.format(self
['guid']))
159 """Object represetnting current user.
161 _userinfo_regex
= re
.compile(r
'window.current_user_attributes = ({.*})')
162 _userinfo_regex_2
= re
.compile(r
'gon.user=({.*});gon.preloads')
164 def __init__(self
, connection
):
165 self
._connection
= connection
168 """This function returns the current user's attributes.
172 request
= self
._connection
.get('bookmarklet')
173 userdata
= self
._userinfo
_regex
.search(request
.text
)
174 if userdata
is None: userdata
= self
._userinfo
_regex
_2.search(request
.text
)
175 if userdata
is None: raise errors
.DiaspyError('cannot find user data')
176 userdata
= userdata
.group(1)
177 return json
.loads(userdata
)
181 """This class represents user's list of contacts.
183 def __init__(self
, connection
):
184 self
._connection
= connection
186 def add(self
, user_id
, aspect_ids
):
187 """Add user to aspects of given ids.
189 :param user_id: user guid
191 :param aspect_ids: list of aspect ids
192 :type aspect_ids: list
194 for aid
in aspect_ids
: Aspect(self
._connection
, aid
).addUser(user_id
)
196 def remove(self
, user_id
, aspect_ids
):
197 """Remove user from aspects of given ids.
199 :param user_id: user guid
201 :param aspect_ids: list of aspect ids
202 :type aspect_ids: list
204 for aid
in aspect_ids
: Aspect(self
._connection
, aid
).removeUser(user_id
)
206 def get(self
, set=''):
207 """Returns list of user contacts.
208 Contact is a User() who is in one or more of user's
211 By default, it will return list of users who are in
214 If `set` is `all` it will also include users who only share
215 with logged user and are not in his/hers aspects.
217 If `set` is `only_sharing` it will return users who are only
218 sharing with logged user and ARE NOT in his/hers aspects.
220 :param set: if passed could be 'all' or 'only_sharing'
224 if set: params
['set'] = set
226 request
= self
._connection
.get('contacts.json', params
=params
)
227 if request
.status_code
!= 200:
228 raise Exception('status code {0}: cannot get contacts'.format(request
.status_code
))
229 return [User
.parse(self
._connection
, each
) for each
in request
.json()]