9 """This module abstracts connection to pod.
13 class LoginError(Exception):
17 class TokenError(Exception):
22 """Object representing connection with the pod.
24 _token_regex
= re
.compile(r
'content="(.*?)"\s+name="csrf-token')
25 _userinfo_regex
= re
.compile(r
'window.current_user_attributes = ({.*})')
27 def __init__(self
, pod
, username
='', password
='', schema
='https'):
29 :param pod: The complete url of the diaspora pod to use.
31 :param username: The username used to log in.
33 :param password: The password used to log in.
37 self
.session
= requests
.Session()
40 try: self
._setlogin
(username
, password
)
41 except requests
.exceptions
.MissingSchema
:
42 self
.pod
= '{0}://{1}'.format(schema
, self
.pod
)
43 warnings
.warn('schema was missing')
45 try: self
._setlogin
(username
, password
)
46 except Exception as e
: raise LoginError('cannot create login data (caused by: {0})'.format(e
))
49 """Returns token string.
50 It will be easier to change backend if programs will just use:
52 instead of calling a specified method.
54 return self
.get_token()
56 def get(self
, string
, headers
={}, params
={}):
57 """This method gets data from session.
58 Performs additional checks if needed.
61 To obtain 'foo' from pod one should call `get('foo')`.
63 :param string: URL to get without the pod's URL and slash eg. 'stream'.
66 return self
.session
.get('{0}/{1}'.format(self
.pod
, string
), params
=params
, headers
=headers
)
68 def post(self
, string
, data
, headers
={}, params
={}):
69 """This method posts data to session.
70 Performs additional checks if needed.
73 To post to 'foo' one should call `post('foo', data={})`.
75 :param string: URL to post without the pod's URL and slash eg. 'status_messages'.
77 :param data: Data to post.
78 :param headers: Headers (optional).
80 :param params: Parameters (optional).
83 string
= '{0}/{1}'.format(self
.pod
, string
)
84 request
= self
.session
.post(string
, data
, headers
=headers
, params
=params
)
87 def put(self
, string
, data
=None, headers
={}, params
={}):
88 """This method PUTs to session.
90 string
= '{0}/{1}'.format(self
.pod
, string
)
91 if data
is not None: request
= self
.session
.put(string
, data
, headers
=headers
, params
=params
)
92 else: request
= self
.session
.put(string
, headers
=headers
, params
=params
)
95 def delete(self
, string
, data
, headers
={}):
96 """This method lets you send delete request to session.
97 Performs additional checks if needed.
99 :param string: URL to use.
101 :param data: Data to use.
102 :param headers: Headers to use (optional).
105 string
= '{0}/{1}'.format(self
.pod
, string
)
106 request
= self
.session
.delete(string
, data
=data
, headers
=headers
)
109 def _setlogin(self
, username
, password
):
110 """This function is used to set data for login.
113 It should be called before _login() function.
115 self
.username
, self
.password
= username
, password
116 self
.login_data
= {'user[username]': self
.username
,
117 'user[password]': self
.password
,
118 'authenticity_token': self
._fetchtoken
()}
121 """Handles actual login request.
122 Raises LoginError if login failed.
124 request
= self
.post('users/sign_in',
125 data
=self
.login_data
)
126 if request
.status_code
!= 200:
128 raise LoginError('{0}: login failed'.format(request
.status_code
))
130 def login(self
, username
='', password
=''):
131 """This function is used to log in to a pod.
132 Will raise LoginError if password or username was not specified.
134 if username
and password
: self
._setlogin
(username
, password
)
135 if not self
.username
or not self
.password
: raise LoginError('password or username not specified')
139 """Logs out from a pod.
140 When logged out you can't do anything.
142 self
.get('users/sign_out')
147 def podswitch(self
, pod
):
148 """Switches pod from current to another one.
153 def getUserInfo(self
):
154 """This function returns the current user's attributes.
156 :returns: dict -- json formatted user info.
158 request
= self
.get('bookmarklet')
160 userdata
= json
.loads(self
._userinfo
_regex
.search(request
.text
).group(1))
161 except AttributeError:
162 raise errors
.DiaspyError('cannot find user data')
165 def _fetchtoken(self
):
166 """This method tries to get token string needed for authentication on D*.
168 :returns: token string
170 request
= self
.get('stream')
171 token
= self
._token
_regex
.search(request
.text
).group(1)
175 def get_token(self
, fetch
=True):
176 """This function returns a token needed for authentication in most cases.
177 Each time it is run a _fetchtoken() is called and refreshed token is stored.
179 It is more safe to use than _fetchtoken().
180 By setting new you can request new token or decide to get stored one.
181 If no token is stored new one will be fetched anyway.
183 :returns: string -- token used to authenticate
186 if fetch
: self
._fetchtoken
()
187 if not self
.token
: self
._fetchtoken
()
188 except requests
.exceptions
.ConnectionError
as e
:
189 warnings
.warn('{0} was cought: reusing old token'.format(e
))
191 if not self
.token
: raise TokenError('cannot obtain token and no previous token found for reuse')