Merge pull request #15 from jaywink/contacts-fetch-fix
[diaspy.git] / diaspy / people.py
CommitLineData
beaa09fb
MM
1import re
2from diaspy.streams import Outer
d589deff 3from diaspy.models import Aspect
beaa09fb
MM
4
5
6class User:
7 """This class abstracts a D* user.
8 This object goes around the limitations of current D* API and will
9 extract user data using black magic.
10 However, no chickens are harmed when you use it.
17d8f406 11
27f09973 12 If user has not posted yet diaspy will not be able to extract the information
c5d935c0
MM
13 from his/her posts. Since there is no official way to do it we rely
14 on user posts. If this will be the case user will be notified with appropriate
15 exception message.
16
27f09973 17 When creating new User() one can pass either guid or handle as
17d8f406 18 an optional parameter. GUID takes precedence over handle.
beaa09fb 19 """
dd0a4d9f
MM
20 data = {}
21 stream = []
17d8f406 22
dcd44985 23 def __init__(self, connection, guid='', handle='', fetchposts=True):
beaa09fb 24 self._connection = connection
dcd44985
JR
25 self.guid, self.handle, self.fetchposts = guid, handle, fetchposts
26 if self.fetchposts:
27 if handle and guid: self.fetchguid(guid)
28 elif guid and not handle: self.fetchguid(guid)
29 elif handle and not guid: self.fetchhandle(handle)
beaa09fb
MM
30
31 def __getitem__(self, key):
32 return self.data[key]
33
34 def _sephandle(self, handle):
35 """Separate D* handle into pod pod and user.
36
37 :param handle: diaspora id: user@pod.example.com
38 :type handle: str
39 :returns: two-tuple (pod, user)
40 """
41 if re.match('^[a-zA-Z]+[a-zA-Z0-9_-]*@[a-z0-9.]+\.[a-z]+$', handle) is None:
42 raise Exception('invalid handle: {0}'.format(handle))
43 handle = handle.split('@')
44 pod, user = handle[1], handle[0]
45 return (pod, user)
46
a8fdc14a
MM
47 def _postproc(self, request):
48 """Makes necessary modifications to user data and
49 sets up a stream.
50
51 :param request: request object
52 :type request: request
beaa09fb 53 """
141216df 54 if request.status_code != 200:
a8fdc14a 55 raise Exception('wrong error code: {0}'.format(request.status_code))
141216df
MM
56 else:
57 request = request.json()
c5d935c0 58
dcd44985 59 if not len(request): raise Exception('Cannot extract user data: no posts to analyze')
c5d935c0
MM
60 data = request[0]['author']
61 final = {}
a8fdc14a
MM
62 names = [('id', 'id'),
63 ('diaspora_id', 'diaspora_id'),
64 ('guid', 'guid'),
65 ('name', 'diaspora_name'),
66 ('avatar', 'image_urls'),
f605e88d 67 ]
a8fdc14a
MM
68 for d, f in names:
69 final[f] = data[d]
70 self.data = final
beaa09fb
MM
71 self.stream = Outer(self._connection, location='people/{0}.json'.format(self.data['guid']))
72
17d8f406
MM
73 def fetchhandle(self, diaspora_id, protocol='https'):
74 """Fetch user data using Diaspora handle.
beaa09fb
MM
75 """
76 pod, user = self._sephandle(diaspora_id)
a8fdc14a
MM
77 request = self._connection.session.get('{0}://{1}/u/{2}.json'.format(protocol, pod, user))
78 self._postproc(request)
beaa09fb 79
beaa09fb
MM
80 def fetchguid(self, guid):
81 """Fetch user data using guid.
82 """
17d8f406
MM
83 request = self._connection.get('people/{0}.json'.format(guid))
84 self._postproc(request)
dd0a4d9f
MM
85
86
87class Contacts():
88 """This class represents user's list of contacts.
89 """
90 def __init__(self, connection):
91 self._connection = connection
92
d589deff
MM
93 def add(self, user_id, aspect_ids):
94 """Add user to aspects of given ids.
dd0a4d9f 95
d589deff
MM
96 :param user_id: user guid
97 :type user_id: str
98 :param aspect_ids: list of aspect ids
99 :type aspect_ids: list
dd0a4d9f 100 """
7a818fdb 101 for aid in aspect_ids: Aspect(self._connection, aid).addUser(user_id)
27f09973 102
d589deff
MM
103 def remove(self, user_id, aspect_ids):
104 """Remove user from aspects of given ids.
27f09973 105
d589deff
MM
106 :param user_id: user guid
107 :type user_id: str
108 :param aspect_ids: list of aspect ids
109 :type aspect_ids: list
27f09973 110 """
7a818fdb 111 for aid in aspect_ids: Aspect(self._connection, aid).removeUser(user_id)
27f09973 112
d589deff 113 def get(self, set=''):
27f09973 114 """Returns list of user contacts.
d589deff
MM
115 Contact is a User() who is in one or more of user's
116 aspects.
117
7a818fdb
MM
118 By default, it will return list of users who are in
119 user's aspects.
120
d589deff
MM
121 If `set` is `all` it will also include users who only share
122 with logged user and are not in his/hers aspects.
7a818fdb 123
d589deff
MM
124 If `set` is `only_sharing` it will return users who are only
125 sharing with logged user and ARE NOT in his/hers aspects.
126
127 :param set: if passed could be 'all' or 'only_sharing'
128 :type set: str
27f09973 129 """
d589deff
MM
130 params = {}
131 if set: params['set'] = set
132
133 request = self._connection.get('contacts.json', params=params)
27f09973
MM
134 if request.status_code != 200:
135 raise Exception('status code {0}: cannot get contacts'.format(request.status_code))
dcd44985 136 contacts = [User(self._connection, user['guid'], user['handle'], False) for user in request.json()]
27f09973 137 return contacts