Skip to content

Commit 8fa5efb

Browse files
authored
Merge pull request #2 from pyhedgehog/feature/token
Add API for token management
2 parents da455d1 + 65e82cf commit 8fa5efb

File tree

4 files changed

+141
-2
lines changed

4 files changed

+141
-2
lines changed

docs/examples.rst

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,29 @@ Below is an example demonstrating how to update a user (requires admin privilege
4646
"username_to_update",
4747
update)
4848

49+
50+
Example 3: Creating a token
51+
---------------------------
52+
53+
Below is an example illustrating how to create a token for you application::
54+
55+
import gogs_client
56+
from getpass import getpass
57+
from platform import node
58+
59+
api = GogsApi("https://try.gogs.io/")
60+
61+
try: token_str = open("tokenfile.txt","r").read()
62+
except OSError: token_str = None
63+
if token_str:
64+
token = gogs_client.Token(token_str)
65+
else:
66+
username = input("username> ")
67+
password = getpass("password> ")
68+
login = gogs_client.UsernamePassword(username, password)
69+
token = api.ensure_token(login, "my cool app on "+node(), username)
70+
open("tokenfile.txt", "w".write(token.token))
71+
72+
username = api.authenticated_user(token)
73+
print("User {} authenticated by token {}".format(username, token_str))
74+

gogs_client/auth.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""
22
Various classes for Gogs authentication
33
"""
4+
from gogs_client.entities import json_get
45

56

67
class Authentication(object):
@@ -22,11 +23,27 @@ class Token(Authentication):
2223
"""
2324
An immutable representation of a Gogs authentication token
2425
"""
25-
def __init__(self, token):
26+
def __init__(self, token, name=None):
2627
"""
2728
:param str token: contents of Gogs authentication token
2829
"""
2930
self._token = token
31+
self._name = name
32+
33+
@staticmethod
34+
def from_json(parsed_json):
35+
name = json_get(parsed_json, "name")
36+
sha1 = json_get(parsed_json, "sha1")
37+
return Token(sha1, name)
38+
39+
@property
40+
def name(self):
41+
"""
42+
The name of the token
43+
44+
:rtype: str
45+
"""
46+
return self._name
3047

3148
@property
3249
def token(self):

gogs_client/interface.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from gogs_client._implementation.http_utils import RelativeHttpRequestor, append_url
44
from gogs_client.entities import GogsUser, GogsRepo
5+
from gogs_client.auth import Token
56

67

78
class GogsApi(object):
@@ -43,6 +44,68 @@ def authenticated_user(self, auth):
4344
response = self._get("/user", auth=auth)
4445
return GogsUser.from_json(self._check_ok(response).json())
4546

47+
def get_tokens(self, auth, username=None):
48+
"""
49+
Returns tokens defined for specified user.
50+
If no user specified uses user authenticated by the given authentication.
51+
Right now, authentication must be UsernamePassword (not Token).
52+
53+
:param auth.Authentication auth: authentication for user to retrieve
54+
:param str username: username of owner of tokens
55+
56+
:return: list of token representation
57+
:rtype: List[Token]
58+
:raises NetworkFailure: if there is an error communicating with the server
59+
:raises ApiFailure: if the request cannot be serviced
60+
"""
61+
if username is None:
62+
username = self.authenticated_user(auth).username
63+
response = self._get("/users/{u}/tokens".format(u=username), auth=auth)
64+
return [Token.from_json(o) for o in self._check_ok(response).json()]
65+
66+
def create_token(self, auth, name, username=None):
67+
"""
68+
Creates new token with specified name for specified user.
69+
If no user specified uses user authenticated by the given authentication.
70+
Right now, authentication must be UsernamePassword (not Token).
71+
72+
:param auth.Authentication auth: authentication for user to retrieve
73+
:param str name: name of new token
74+
:param str username: username of owner of new token
75+
76+
:return: new token representation
77+
:rtype: Token
78+
:raises NetworkFailure: if there is an error communicating with the server
79+
:raises ApiFailure: if the request cannot be serviced
80+
"""
81+
if username is None:
82+
username = self.authenticated_user(auth).username
83+
data = {"name": name}
84+
response = self._post("/users/{u}/tokens".format(u=username), auth=auth, data=data)
85+
return Token.from_json(self._check_ok(response).json())
86+
87+
def ensure_token(self, auth, name, username=None):
88+
"""
89+
Creates new token if token with specified name for specified user does not exists.
90+
If no user specified uses user authenticated by the given authentication.
91+
Right now, authentication must be UsernamePassword (not Token).
92+
93+
:param auth.Authentication auth: authentication for user to retrieve
94+
:param str name: name of new token
95+
:param str username: username of owner of new token
96+
97+
:return: token representation
98+
:rtype: Token
99+
:raises NetworkFailure: if there is an error communicating with the server
100+
:raises ApiFailure: if the request cannot be serviced
101+
"""
102+
if username is None:
103+
username = self.authenticated_user(auth).username
104+
tokens = [token for token in self.get_tokens(auth, username) if token.name == name]
105+
if tokens:
106+
return tokens[0]
107+
return self.create_token(auth, name, username)
108+
46109
def create_repo(self, auth, name, description=None, private=False, auto_init=False,
47110
gitignore_templates=None, license_template=None, readme_template=None):
48111
"""

tests/interface_test.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,15 @@ def setUp(self):
4343
"email": "[email protected]",
4444
"avatar_url": "/avatars/1"
4545
}"""
46-
self.token = gogs_client.Token("mytoken")
46+
self.token_json_str = """{
47+
"name": "new token",
48+
"sha1": "mytoken"
49+
}"""
4750
self.username_password = gogs_client.UsernamePassword(
4851
"auth_username", "password")
4952
self.expected_repo = gogs_client.GogsRepo.from_json(json.loads(self.repo_json_str))
5053
self.expected_user = gogs_client.GogsUser.from_json(json.loads(self.user_json_str))
54+
self.token = gogs_client.Token.from_json(json.loads(self.token_json_str))
5155

5256
@responses.activate
5357
def test_create_repo1(self):
@@ -238,6 +242,31 @@ def test_authenticated_user(self):
238242
user = self.client.authenticated_user(self.token)
239243
self.assert_users_equals(user, self.expected_user)
240244

245+
@responses.activate
246+
def test_ensure_token(self):
247+
uri = self.path("/users/{}/tokens".format(self.username_password.username))
248+
responses.add(responses.GET, uri, body="[]", status=200)
249+
responses.add(responses.POST, uri, body=self.token_json_str, status=200)
250+
responses.add(responses.GET, uri, body="["+self.token_json_str+"]", status=200)
251+
token = self.client.ensure_token(self.username_password, self.token.name, self.username_password.username)
252+
self.assert_tokens_equals(token, self.token)
253+
token = self.client.ensure_token(self.username_password, self.token.name, self.username_password.username)
254+
self.assert_tokens_equals(token, self.token)
255+
256+
@responses.activate
257+
def test_ensure_auth_token(self):
258+
uri = self.path("/user")
259+
responses.add(responses.GET, uri, body=self.user_json_str, status=200)
260+
uri = self.path("/users/{}/tokens".format(self.expected_user.username))
261+
responses.add(responses.GET, uri, body="[]", status=200)
262+
responses.add(responses.POST, uri, body=self.token_json_str, status=200)
263+
tokens = self.client.get_tokens(self.username_password)
264+
self.assertEqual(tokens, [])
265+
tokeninfo = self.client.create_token(self.username_password, self.token.name)
266+
self.assert_tokens_equals(tokeninfo, self.token)
267+
token = self.client.ensure_token(self.username_password, self.token.name)
268+
self.assert_tokens_equals(token, self.token)
269+
241270
# helper methods
242271

243272
@staticmethod
@@ -277,6 +306,10 @@ def assert_users_equals(self, user, expected):
277306
self.assertEqual(user.email, expected.email)
278307
self.assertEqual(user.avatar_url, expected.avatar_url)
279308

309+
def assert_tokens_equals(self, token, expected):
310+
self.assertEqual(token.name, expected.name)
311+
self.assertEqual(token.token, expected.token)
312+
280313

281314
if __name__ == "__main__":
282315
unittest.main()

0 commit comments

Comments
 (0)