Skip to content

Commit 18215bd

Browse files
committed
Main skeleton
Added get user, group, journal and cli.
1 parent 06c1d7a commit 18215bd

12 files changed

Lines changed: 413 additions & 0 deletions

File tree

.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,13 @@ dmypy.json
127127

128128
# Pyre type checker
129129
.pyre/
130+
131+
# Pycharm
132+
.idea
133+
134+
# VS Code
135+
.vscode/
136+
137+
# Custom
138+
.secrets/
139+
.bugout/

bugout/__init__.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
"""
2+
Bugout Python API
3+
"""
4+
__author__ = "Bugout"
5+
__maintainer__ = __author__
6+
7+
__email__ = "neeraj@bugout.dev"
8+
__license__ = "MIT"
9+
__version__ = "0.0.1"
10+
11+
__all__ = (
12+
"__author__",
13+
"__email__",
14+
"__license__",
15+
"__maintainer__",
16+
"__version__",
17+
)

bugout/__main__.py

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
import argparse
2+
import logging
3+
import textwrap
4+
5+
from .app import Bugout
6+
from .user import User
7+
8+
logging.basicConfig(level=logging.INFO)
9+
logger = logging.getLogger(__name__)
10+
11+
12+
def user_get_handler(args: argparse.Namespace) -> None:
13+
"""
14+
Handler for "users get" subcommand.
15+
"""
16+
bugout = Bugout(url=args.url, port=args.port)
17+
user_obj = User(bugout)
18+
19+
result = user_obj.get_user(token=args.token)
20+
21+
print(result)
22+
23+
24+
def user_create_handler(args: argparse.Namespace) -> None:
25+
"""
26+
Handler for "users create" subcommand.
27+
"""
28+
bugout = Bugout(url=args.url, port=args.port)
29+
user_obj = User(bugout)
30+
31+
result = user_obj.create_user(
32+
username=args.username,
33+
email=args.email,
34+
password=args.password,
35+
autogenerated_token=args.autogenerated_token,
36+
)
37+
38+
print(result)
39+
40+
41+
def main() -> None:
42+
bugout_description = textwrap.dedent(
43+
"""\
44+
Bugout API: Tools for helping with Bugout API.
45+
"""
46+
)
47+
parser = argparse.ArgumentParser(prog="bugout", description=bugout_description)
48+
parser.set_defaults(func=lambda _: parser.print_help())
49+
subcommands = parser.add_subparsers(description="Journal commands")
50+
51+
parser.add_argument(
52+
"--url",
53+
default="localhost",
54+
help="Dest url",
55+
)
56+
parser.add_argument(
57+
"--port",
58+
default="443",
59+
help="Dest port",
60+
)
61+
62+
# Users handler
63+
parser_users = subcommands.add_parser(
64+
"users", description="Work with Bugout users API handlers"
65+
)
66+
parser_users.set_defaults(
67+
func=lambda _: parser_users.print_help(), subparser="users"
68+
)
69+
subcommands_users = parser_users.add_subparsers(description="Users commands")
70+
71+
parser_user_get = subcommands_users.add_parser("get", description="Get user")
72+
parser_user_get.set_defaults(subcommand="get")
73+
parser_user_get.add_argument(
74+
"-t",
75+
"--token",
76+
required=True,
77+
help="User token",
78+
)
79+
parser_user_get.set_defaults(func=user_get_handler)
80+
81+
parser_user_create = subcommands_users.add_parser(
82+
"create", description="Create user"
83+
)
84+
parser_user_create.set_defaults(subcommand="create")
85+
parser_user_create.add_argument(
86+
"-u",
87+
"--username",
88+
required=True,
89+
help="Username",
90+
)
91+
parser_user_create.add_argument(
92+
"-e",
93+
"--email",
94+
required=True,
95+
help="Email",
96+
)
97+
parser_user_create.add_argument(
98+
"-p",
99+
"--password",
100+
required=True,
101+
help="Password",
102+
)
103+
parser_user_create.add_argument(
104+
"-a",
105+
"--autogenerated_token",
106+
help="Token",
107+
)
108+
parser_user_create.set_defaults(func=user_create_handler)
109+
110+
args = parser.parse_args()
111+
args.func(args)
112+
113+
114+
if __name__ == "__main__":
115+
main()

bugout/app.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from .data import Method
2+
from .calls import ApiCalls
3+
4+
5+
class Bugout:
6+
def __init__(self, url, port) -> None:
7+
self.url = url
8+
self.port = port
9+
10+
def _call(self, method: Method, path: str, **kwargs):
11+
url = f"{self.url.rstrip('/')}:{self.port}/{path.rstrip('/')}"
12+
13+
result = ApiCalls.make_request(method=method, url=url, **kwargs)
14+
15+
return result

bugout/calls.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import logging
2+
from typing import Any, Dict, List, Optional, Tuple
3+
4+
import requests
5+
6+
from .data import Method
7+
8+
logger = logging.getLogger(__name__)
9+
10+
11+
class BugoutUnexpectedResponse(Exception):
12+
"""
13+
Raised when Bugout server response is unexpected (e.g. unparseable).
14+
"""
15+
16+
17+
class ApiCalls:
18+
"""
19+
Handle REST API requests.
20+
"""
21+
22+
@staticmethod
23+
def make_request(method: Method, url: str, **kwargs) -> Optional[Dict[str, Any]]:
24+
response_body = None
25+
26+
try:
27+
r = requests.request(method.value, url=url, **kwargs)
28+
r.raise_for_status()
29+
response_body = r.json()
30+
except Exception as e:
31+
logger.error(f"Exception {str(e)}")
32+
raise
33+
34+
return response_body

bugout/data.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
from enum import Enum, unique
2+
from typing import Any, Dict, List, Optional, Tuple
3+
import uuid
4+
5+
from pydantic import BaseModel
6+
7+
8+
@unique
9+
class Method(Enum):
10+
get = "get"
11+
post = "post"
12+
delete = "delete"
13+
14+
15+
class BroodUser(BaseModel):
16+
id: uuid.UUID
17+
username: Optional[str]
18+
email: Optional[str]
19+
token: Optional[uuid.UUID]
20+
21+
22+
class BroodGroup(BaseModel):
23+
id: uuid.UUID
24+
group_name: Optional[str]

bugout/group.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import logging
2+
from typing import Any, Dict, List, Optional, Tuple
3+
4+
from .app import Bugout
5+
from .data import Method
6+
7+
logger = logging.getLogger(__name__)
8+
9+
10+
class GroupNotFound(Exception):
11+
"""
12+
Raised on actions that involve group which are not present in the database.
13+
"""
14+
15+
16+
class Group(Bugout):
17+
"""
18+
Represent a group from Bugout.
19+
"""
20+
21+
def __init__(self, bugout: Bugout) -> None:
22+
super().__init__(bugout.url, bugout.port)
23+
24+
def get_group(self, group_id: str, token: str) -> Optional[Dict[str, Any]]:
25+
get_group_path = f"groups/{group_id}"
26+
27+
headers = {
28+
"Authorization": f"Bearer {token}",
29+
}
30+
31+
result = super()._call(method=Method.get, path=get_group_path, headers=headers)
32+
return result

bugout/journals.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import logging
2+
from typing import Any, Dict, List, Optional, Tuple
3+
4+
from .app import Bugout
5+
from .data import Method
6+
7+
logger = logging.getLogger(__name__)
8+
9+
10+
class JournalNotFound(Exception):
11+
"""
12+
Raised on actions that involve journal which are not present in the database.
13+
"""
14+
15+
16+
class Journal(Bugout):
17+
"""
18+
Represent a journal from Bugout.
19+
"""
20+
21+
def __init__(self, bugout: Bugout) -> None:
22+
super().__init__(bugout.url, bugout.port)
23+
24+
def get_journal(self, journal_id: str, token: str) -> Optional[Dict[str, Any]]:
25+
get_journal_path = f"journals/{journal_id}"
26+
27+
headers = {
28+
"Authorization": f"Bearer {token}",
29+
}
30+
31+
result = super()._call(
32+
method=Method.get, path=get_journal_path, headers=headers
33+
)
34+
return result

bugout/user.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import logging
2+
from typing import Any, Dict, List, Optional, Tuple
3+
import uuid
4+
5+
from .app import Bugout
6+
from .data import Method
7+
8+
logger = logging.getLogger(__name__)
9+
10+
11+
class UserNotFound(Exception):
12+
"""
13+
Raised on actions that involve user which are not present in the database.
14+
"""
15+
16+
17+
class User(Bugout):
18+
"""
19+
Represent a user from Bugout.
20+
"""
21+
22+
def __init__(self, bugout: Bugout) -> None:
23+
super().__init__(bugout.url, bugout.port)
24+
25+
def get_user(self, token: str) -> Optional[Dict[str, Any]]:
26+
get_user_path = "user"
27+
28+
headers = {
29+
"Authorization": f"Bearer {token}",
30+
}
31+
32+
result = super()._call(method=Method.get, path=get_user_path, headers=headers)
33+
return result
34+
35+
def create_user(
36+
self,
37+
username: str,
38+
email: str,
39+
password: str,
40+
autogenerated_token: Optional[str],
41+
):
42+
create_user_path = "user"
43+
44+
data = {
45+
"username": username,
46+
"email": email,
47+
"password": password,
48+
}
49+
headers = None
50+
51+
if autogenerated_token:
52+
headers = {
53+
"x-bugout-installation-token": autogenerated_token,
54+
}
55+
56+
result = super()._call(
57+
method=Method.post, path=create_user_path, headers=headers, data=data
58+
)
59+
return result

requirements.dev.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
appdirs==1.4.4
2+
black==20.8b1
3+
click==7.1.2
4+
mypy==0.790
5+
mypy-extensions==0.4.3
6+
pathspec==0.8.1
7+
regex==2020.11.13
8+
toml==0.10.2
9+
typed-ast==1.4.1
10+
typing-extensions==3.7.4.3

0 commit comments

Comments
 (0)