Skip to content

Commit 8f70ad2

Browse files
committed
First implementation of Gogs client
1 parent 2232be5 commit 8f70ad2

File tree

11 files changed

+607
-0
lines changed

11 files changed

+607
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,6 @@ ENV/
8888
# Rope project settings
8989
.ropeproject
9090

91+
# IDE files
92+
.idea/
93+

gogs_client/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from gogs_client.auth import GogsAuthentication, GogsToken, GogsUsernamePassword
2+
from gogs_client.entities import GogsUser, GogsRepo
3+
from gogs_client.interface import GogsApi
4+
from gogs_client.updates import GogsUserUpdate

gogs_client/auth.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
"""
2+
Various classes for Gogs authentication
3+
"""
4+
5+
6+
class GogsAuthentication(object):
7+
"""
8+
An "abstract" parent class for GogsAuthentication objects. Represents a
9+
means of authenticating oneself to Gogs
10+
"""
11+
def update_kwargs(self, kwargs):
12+
"""
13+
Updates kwargs to include this object's authentication information
14+
:param kwargs: dictionary of keyword arguments to pass to a function from
15+
the requests module
16+
:return: Updated kwargs
17+
"""
18+
raise NotImplementedError() # must be implemented by subclasses
19+
20+
21+
class GogsToken(GogsAuthentication):
22+
def __init__(self, token):
23+
self._token = token
24+
25+
@property
26+
def token(self): return self._token
27+
28+
def update_kwargs(self, kwargs):
29+
if "params" in kwargs:
30+
kwargs["params"]["token"] = self._token
31+
else:
32+
kwargs["params"] = {"token": self._token}
33+
34+
35+
class GogsUsernamePassword(GogsAuthentication):
36+
def __init__(self, username, password):
37+
self._username = username
38+
self._password = password
39+
40+
@property
41+
def username(self): return self._username
42+
43+
@property
44+
def password(self): return self._password
45+
46+
def update_kwargs(self, kwargs):
47+
kwargs["auth"] = (self._username, self._password)

gogs_client/entities.py

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
"""
2+
Various immutable classes that represent Gogs entities.
3+
"""
4+
5+
6+
def json_get(parsed_json, key):
7+
"""
8+
Retrieves the key from a parsed_json dictionary, or raises an exception if the
9+
key is not present
10+
"""
11+
if key not in parsed_json:
12+
raise ValueError("JSON does not contain a {} field".format(key))
13+
return parsed_json[key]
14+
15+
16+
class GogsUser(object):
17+
def __init__(self, user_id, username, full_name, email, avatar_url):
18+
self._id = user_id
19+
self._username = username
20+
self._full_name = full_name
21+
self._email = email
22+
self._avatar_url = avatar_url
23+
24+
@staticmethod
25+
def from_json(parsed_json):
26+
user_id = json_get(parsed_json, "id")
27+
username = json_get(parsed_json, "username")
28+
full_name = json_get(parsed_json, "full_name")
29+
email = parsed_json.get("email", None)
30+
avatar_url = parsed_json.get("avatar_url", None)
31+
return GogsUser(user_id=user_id, username=username, full_name=full_name,
32+
email=email, avatar_url=avatar_url)
33+
34+
@property # named user_id to avoid conflict with built-in id
35+
def user_id(self): return self._id
36+
37+
@property
38+
def username(self): return self._username
39+
40+
@property
41+
def full_name(self): return self._full_name
42+
43+
@property
44+
def email(self): return self._email
45+
46+
@property
47+
def avatar_url(self): return self._avatar_url
48+
49+
50+
class GogsRepo(object):
51+
def __init__(self, repo_id, owner, full_name, private, fork, urls, permissions):
52+
self._repo_id = repo_id
53+
self._owner = owner
54+
self._full_name = full_name
55+
self._private = private
56+
self._fork = fork
57+
self._urls = urls
58+
self._permissions = permissions
59+
60+
@staticmethod
61+
def from_json(parsed_json):
62+
repo_id = json_get(parsed_json, "id")
63+
owner = GogsUser.from_json(json_get(parsed_json, "owner"))
64+
full_name = json_get(parsed_json, "full_name")
65+
private = json_get(parsed_json, "private")
66+
fork = json_get(parsed_json, "fork")
67+
urls = GogsRepo.Urls(json_get(parsed_json, "html_url"), json_get(parsed_json, "clone_url"),
68+
json_get(parsed_json, "ssh_url"))
69+
permissions = GogsRepo.Permissions.from_json(json_get(parsed_json, "permissions"))
70+
return GogsRepo(repo_id=repo_id, owner=owner, full_name=full_name, private=private, fork=fork,
71+
urls=urls, permissions=permissions)
72+
73+
@property # named repo_id to avoid conflict with built-in id
74+
def repo_id(self): return self._repo_id
75+
76+
@property
77+
def owner(self): return self._owner
78+
79+
@property
80+
def full_name(self): return self._full_name
81+
82+
@property
83+
def private(self): return self._private
84+
85+
@property
86+
def fork(self): return self._fork
87+
88+
@property
89+
def urls(self): return self._urls
90+
91+
@property
92+
def permissions(self): return self._permissions
93+
94+
class Urls(object):
95+
def __init__(self, html_url, clone_url, ssh_url):
96+
self._html_url = html_url
97+
self._clone_url = clone_url
98+
self._ssh_url = ssh_url
99+
100+
@property
101+
def html_url(self): return self._html_url
102+
103+
@property
104+
def clone_url(self): return self._clone_url
105+
106+
@property
107+
def ssh_url(self): return self._ssh_url
108+
109+
class Permissions(object):
110+
def __init__(self, admin, push, pull):
111+
self._admin = admin
112+
self._push = push
113+
self._pull = pull
114+
115+
@staticmethod
116+
def from_json(parsed_json):
117+
admin = parsed_json.get("admin", False)
118+
push = parsed_json.get("push", False)
119+
pull = parsed_json.get("pull", False)
120+
return GogsRepo.Permissions(admin, push, pull)
121+
122+
@property
123+
def admin(self): return self._admin
124+
125+
@property
126+
def push(self): return self._push
127+
128+
@property
129+
def pull(self): return self._pull

gogs_client/http_utils.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
"""
2+
Various HTTP utilities
3+
"""
4+
5+
import requests
6+
from future.moves.urllib.parse import urljoin
7+
8+
9+
class RelativeHttpRequestor(object):
10+
"""
11+
A thin wrapper around the requests module that allows for endpoint paths
12+
to be given relative to a fixed base URL
13+
"""
14+
def __init__(self, base_url):
15+
self.base_url = base_url
16+
17+
def absolute_url(self, relative_path):
18+
"""
19+
:param relative_path: relative URL
20+
:return: absolute URL of relative_path, relative to this object's base URL
21+
"""
22+
return append_url(self.base_url, relative_path)
23+
24+
# The below methods are identical to the corresponding functions in requests module,
25+
# except that they expect relative paths
26+
27+
def delete(self, relative_path, **kwargs):
28+
return requests.delete(self.absolute_url(relative_path), **kwargs)
29+
30+
def get(self, relative_path, params=None, **kwargs):
31+
return requests.get(self.absolute_url(relative_path), params=params, **kwargs)
32+
33+
def options(self, relative_path, params=None, **kwargs):
34+
return requests.options(self.absolute_url(relative_path), params=params, **kwargs)
35+
36+
def patch(self, relative_path, data=None, **kwargs):
37+
return requests.patch(self.absolute_url(relative_path), data=data, **kwargs)
38+
39+
def post(self, relative_path, data=None, **kwargs):
40+
return requests.post(self.absolute_url(relative_path), data=data, **kwargs)
41+
42+
def put(self, relative_path, params=None, data=None, **kwargs):
43+
return requests.put(self.absolute_url(relative_path), params=params, data=data, **kwargs)
44+
45+
46+
def append_url(base_url, path):
47+
"""
48+
Append path to base_url in a sensible way.
49+
"""
50+
if base_url[-1] != "/":
51+
base_url += "/"
52+
if path[0] == "/":
53+
path = path[1:]
54+
return urljoin(base_url, path)

0 commit comments

Comments
 (0)