Cleanup some code

NOT FINISHED!
This commit is contained in:
2024-03-01 08:44:08 +00:00
parent b9b823df1f
commit 488b4b6e9e
12 changed files with 63 additions and 41 deletions
+3 -2
View File
@@ -1,4 +1,5 @@
import dataclasses import dataclasses
import json
from dataclasses import dataclass from dataclasses import dataclass
@@ -12,13 +13,13 @@ class AcAccount:
class_: str class_: str
status: str status: str
def to_dict(self): def to_dict(self) -> dict:
d = dataclasses.asdict(self) d = dataclasses.asdict(self)
d["class"] = d["class_"] d["class"] = d["class_"]
del d["class_"] del d["class_"]
return d return d
def to_json(self): def to_json(self) -> json:
return json.dumps(self.to_dict()) return json.dumps(self.to_dict())
def account_from_json(a) -> AcAccount: def account_from_json(a) -> AcAccount:
@@ -8,7 +8,7 @@ from requests import Response
from ActiveCollabAPI import AC_USER_AGENT from ActiveCollabAPI import AC_USER_AGENT
class ACAuthenticator: class AcAuthenticator:
base_url: str = "" base_url: str = ""
@@ -8,7 +8,10 @@ from ActiveCollabAPI.AcSubtask import AcSubtask
from ActiveCollabAPI.AcToken import AcToken from ActiveCollabAPI.AcToken import AcToken
class ACClient: class AcClient:
"""
Active Collab REST API Client
"""
base_url = None base_url = None
account = None account = None
token = None token = None
+2 -2
View File
@@ -49,13 +49,13 @@ class AcProject:
updated_on: int updated_on: int
url_path: str url_path: str
def to_dict(self): def to_dict(self) -> dict:
d = dataclasses.asdict(self) d = dataclasses.asdict(self)
d["class"] = d["class_"] d["class"] = d["class_"]
del d["class_"] del d["class_"]
return d return d
def to_json(self): def to_json(self) -> str:
return json.dumps(self.to_dict()) return json.dumps(self.to_dict())
+2 -2
View File
@@ -14,10 +14,10 @@ class AcSession:
cur_account: AcAccount cur_account: AcAccount
token: AcToken token: AcToken
def to_dict(self): def to_dict(self) -> dict:
d = dataclasses.asdict(self) d = dataclasses.asdict(self)
d["accounts"] = list(map(lambda a: a.to_dict(), self.accounts)) d["accounts"] = list(map(lambda a: a.to_dict(), self.accounts))
return d return d
def to_json(self): def to_json(self) -> str:
return json.dumps(self.to_dict()) return json.dumps(self.to_dict())
+2 -2
View File
@@ -30,13 +30,13 @@ class AcSubtask:
position: int = 0 position: int = 0
completed_on: int = 0 completed_on: int = 0
def to_dict(self): def to_dict(self) -> dict:
d = dataclasses.asdict(self) d = dataclasses.asdict(self)
d["class"] = d["class_"] d["class"] = d["class_"]
del d["class_"] del d["class_"]
return d return d
def to_json(self): def to_json(self) -> str:
return json.dumps(self.to_dict()) return json.dumps(self.to_dict())
@@ -6,7 +6,7 @@ from requests import Response
from ActiveCollabAPI import AC_USER_AGENT, AC_API_VERSION, AC_API_CLIENT_NAME, AC_API_CLIENT_VENDOR from ActiveCollabAPI import AC_USER_AGENT, AC_API_VERSION, AC_API_CLIENT_NAME, AC_API_CLIENT_VENDOR
class ACTokenAuthenticator: class AcTokenAuthenticator:
base_url = "" base_url = ""
+3 -3
View File
@@ -10,9 +10,9 @@ class AcUser:
last_name: str last_name: str
intent: str intent: str
def to_dict(self): def to_dict(self) -> dict:
d = dataclasses.asdict(self) d = dataclasses.asdict(self)
return d return d
def to_json(self): def to_json(self) -> str:
return json.dumps(self.to_dict()) return json.dumps(self.to_dict())
+12 -11
View File
@@ -1,10 +1,8 @@
from dataclasses import dataclass
from pprint import pprint
from ActiveCollabAPI import AC_API_VERSION from ActiveCollabAPI import AC_API_VERSION
from ActiveCollabAPI.ACAuthenticator import ACAuthenticator from ActiveCollabAPI.AcAuthenticator import AcAuthenticator
from ActiveCollabAPI.ACClient import ACClient from ActiveCollabAPI.AcClient import AcClient
from ActiveCollabAPI.ACTokenAuthenticator import ACTokenAuthenticator from ActiveCollabAPI.AcTokenAuthenticator import AcTokenAuthenticator
from ActiveCollabAPI.AcAccount import AcAccount, account_from_json from ActiveCollabAPI.AcAccount import AcAccount, account_from_json
from ActiveCollabAPI.AcLoginResponse import AcLoginResponse from ActiveCollabAPI.AcLoginResponse import AcLoginResponse
from ActiveCollabAPI.AcProject import AcProject, project_from_json from ActiveCollabAPI.AcProject import AcProject, project_from_json
@@ -15,6 +13,9 @@ from ActiveCollabAPI.AcUser import AcUser
class ActiveCollab: class ActiveCollab:
"""
Active Collab Client library comming from the use case
"""
base_url: str = "" base_url: str = ""
session: AcSession = None session: AcSession = None
@@ -30,7 +31,7 @@ class ActiveCollab:
return self.session return self.session
def user_login(self, email: str, password: str) -> AcLoginResponse: def user_login(self, email: str, password: str) -> AcLoginResponse:
auth = ACAuthenticator(self.base_url) auth = AcAuthenticator(self.base_url)
res = auth.login(email, password) res = auth.login(email, password)
if res.status_code != 200: if res.status_code != 200:
raise Exception('Login failed!') raise Exception('Login failed!')
@@ -44,7 +45,7 @@ class ActiveCollab:
return accounts[0] return accounts[0]
def create_token(self, account: AcAccount, user: AcUser) -> AcToken: def create_token(self, account: AcAccount, user: AcUser) -> AcToken:
authenticator = ACTokenAuthenticator(account.url + '/api/v%s' % AC_API_VERSION) authenticator = AcTokenAuthenticator(account.url + '/api/v%s' % AC_API_VERSION)
res = authenticator.issue_token_intent(user.intent) res = authenticator.issue_token_intent(user.intent)
if res.status_code != 200: if res.status_code != 200:
raise Exception('Request token failed!') raise Exception('Request token failed!')
@@ -54,12 +55,12 @@ class ActiveCollab:
return AcToken(res_data["token"]) return AcToken(res_data["token"])
def get_info(self): def get_info(self):
client = ACClient(self.session.cur_account, self.session.token) client = AcClient(self.session.cur_account, self.session.token)
res = client.get_info() res = client.get_info()
return res.json() return res.json()
def get_projects(self) -> list[AcProject]: def get_projects(self) -> list[AcProject]:
client = ACClient(self.session.cur_account, self.session.token) client = AcClient(self.session.cur_account, self.session.token)
res = client.get_projects() res = client.get_projects()
if res.status_code != 200: if res.status_code != 200:
raise Exception("Error %d" % res.status_code) raise Exception("Error %d" % res.status_code)
@@ -68,14 +69,14 @@ class ActiveCollab:
return projects return projects
def get_subtasks(self, project_id: int, task_id: int) -> list[AcSubtask]: def get_subtasks(self, project_id: int, task_id: int) -> list[AcSubtask]:
client = ACClient(self.session.cur_account, self.session.token) client = AcClient(self.session.cur_account, self.session.token)
res = client.get_project_task(project_id, task_id) res = client.get_project_task(project_id, task_id)
res_data = res.json() res_data = res.json()
subtasks = list(map(lambda sub: subtask_from_json(sub), res_data["subtasks"])) subtasks = list(map(lambda sub: subtask_from_json(sub), res_data["subtasks"]))
return subtasks return subtasks
def create_subtask(self, subtask: AcSubtask): def create_subtask(self, subtask: AcSubtask):
client = ACClient(self.session.cur_account, self.session.token) client = AcClient(self.session.cur_account, self.session.token)
res = client.create_subtask(subtask) res = client.create_subtask(subtask)
res_data = res.json() res_data = res.json()
return res_data return res_data
+17
View File
@@ -0,0 +1,17 @@
## Backlog
* Tests for CLI
* pack with https://python-poetry.org
* publish first version on github
* complete [API](https://developers.activecollab.com/api-documentation/index.html)
* Project list, get, create, delete
* Task list, get, create, delete
* Tasklist
* Subtask list, get, create, delete
* Attachments
* Companies
* Users
* Teams
* Notes
* support for paging
@@ -3,10 +3,10 @@ from unittest import TestCase
from unittest.mock import patch from unittest.mock import patch
from ActiveCollabAPI import AC_LOGIN_BASE_URL from ActiveCollabAPI import AC_LOGIN_BASE_URL
from ActiveCollabAPI.ACAuthenticator import ACAuthenticator from ActiveCollabAPI.AcAuthenticator import AcAuthenticator
class TestACAuthenticator(TestCase): class TestAcAuthenticator(TestCase):
def mock_login_success(self): def mock_login_success(self):
return { return {
@@ -31,13 +31,13 @@ class TestACAuthenticator(TestCase):
def test_login_success_gets_user_and_accounts_list(self): def test_login_success_gets_user_and_accounts_list(self):
with patch("ActiveCollabAPI.ACAuthenticator.requests.post") as mock_post: with patch("ActiveCollabAPI.AcAuthenticator.requests.post") as mock_post:
mock_post.return_value.status_code = 200 mock_post.return_value.status_code = 200
mock_post.return_value.json.return_value = self.mock_login_success() mock_post.return_value.json.return_value = self.mock_login_success()
email = "collab@example.com" email = "collab@example.com"
password = "VeryS3cret!" password = "VeryS3cret!"
authenticator = ACAuthenticator(AC_LOGIN_BASE_URL) authenticator = AcAuthenticator(AC_LOGIN_BASE_URL)
response = authenticator.login(email, password) response = authenticator.login(email, password)
self.assertEqual(200, response.status_code) self.assertEqual(200, response.status_code)
@@ -57,13 +57,13 @@ class TestACAuthenticator(TestCase):
} }
def test_login_failed_not_ok(self): def test_login_failed_not_ok(self):
with patch("ActiveCollabAPI.ACAuthenticator.requests.post") as mock_post: with patch("ActiveCollabAPI.AcAuthenticator.requests.post") as mock_post:
mock_post.return_value.status_code = 200 mock_post.return_value.status_code = 200
mock_post.return_value.json.return_value = self.mock_login_failed() mock_post.return_value.json.return_value = self.mock_login_failed()
email = "collab@example.com" email = "collab@example.com"
password = "VeryS3cret!" password = "VeryS3cret!"
authenticator = ACAuthenticator(AC_LOGIN_BASE_URL) authenticator = AcAuthenticator(AC_LOGIN_BASE_URL)
response = authenticator.login(email, password) response = authenticator.login(email, password)
self.assertEqual(200, response.status_code) self.assertEqual(200, response.status_code)
@@ -75,13 +75,13 @@ class TestACAuthenticator(TestCase):
return { return {
} }
def test_login_forbidden(self): def test_login_forbidden(self):
with patch("ActiveCollabAPI.ACAuthenticator.requests.post") as mock_post: with patch("ActiveCollabAPI.AcAuthenticator.requests.post") as mock_post:
mock_post.return_value.status_code = 401 mock_post.return_value.status_code = 401
mock_post.return_value.json.return_value = self.mock_login_forbidden() mock_post.return_value.json.return_value = self.mock_login_forbidden()
email = "collab@example.com" email = "collab@example.com"
password = "VeryS3cret!" password = "VeryS3cret!"
authenticator = ACAuthenticator(AC_LOGIN_BASE_URL) authenticator = AcAuthenticator(AC_LOGIN_BASE_URL)
response = authenticator.login(email, password) response = authenticator.login(email, password)
self.assertEqual(401, response.status_code) self.assertEqual(401, response.status_code)
@@ -1,10 +1,10 @@
from unittest import TestCase from unittest import TestCase
from unittest.mock import patch from unittest.mock import patch
from ActiveCollabAPI.ACTokenAuthenticator import ACTokenAuthenticator from ActiveCollabAPI.AcTokenAuthenticator import AcTokenAuthenticator
class TestACTokenAuthenticator(TestCase): class TestAcTokenAuthenticator(TestCase):
def mock_token_success(self): def mock_token_success(self):
return { return {
@@ -13,11 +13,11 @@ class TestACTokenAuthenticator(TestCase):
} }
def test_issue_token_intent_success(self): def test_issue_token_intent_success(self):
with patch("ActiveCollabAPI.ACTokenAuthenticator.requests.post") as mock_post: with patch("ActiveCollabAPI.AcTokenAuthenticator.requests.post") as mock_post:
mock_post.return_value.status_code = 200 mock_post.return_value.status_code = 200
mock_post.return_value.json.return_value = self.mock_token_success() mock_post.return_value.json.return_value = self.mock_token_success()
auth = ACTokenAuthenticator("http://mock") auth = AcTokenAuthenticator("http://mock")
res = auth.issue_token_intent("this-is-the-token-intent-string") res = auth.issue_token_intent("this-is-the-token-intent-string")
self.assertEqual(200, res.status_code) self.assertEqual(200, res.status_code)
@@ -31,11 +31,11 @@ class TestACTokenAuthenticator(TestCase):
} }
def test_issue_token_intent_not_ok(self): def test_issue_token_intent_not_ok(self):
with patch("ActiveCollabAPI.ACTokenAuthenticator.requests.post") as mock_post: with patch("ActiveCollabAPI.AcTokenAuthenticator.requests.post") as mock_post:
mock_post.return_value.status_code = 200 mock_post.return_value.status_code = 200
mock_post.return_value.json.return_value = self.mock_token_not_ok() mock_post.return_value.json.return_value = self.mock_token_not_ok()
auth = ACTokenAuthenticator("http://mock") auth = AcTokenAuthenticator("http://mock")
res = auth.issue_token_intent("this-is-the-token-intent-string") res = auth.issue_token_intent("this-is-the-token-intent-string")
self.assertEqual(200, res.status_code) self.assertEqual(200, res.status_code)
@@ -47,11 +47,11 @@ class TestACTokenAuthenticator(TestCase):
} }
def test_issue_token_intent_forbidden(self): def test_issue_token_intent_forbidden(self):
with patch("ActiveCollabAPI.ACTokenAuthenticator.requests.post") as mock_post: with patch("ActiveCollabAPI.AcTokenAuthenticator.requests.post") as mock_post:
mock_post.return_value.status_code = 401 mock_post.return_value.status_code = 401
mock_post.return_value.json.return_value = self.mock_token_forbidden() mock_post.return_value.json.return_value = self.mock_token_forbidden()
auth = ACTokenAuthenticator("http://mock") auth = AcTokenAuthenticator("http://mock")
res = auth.issue_token_intent("this-is-the-token-intent-string") res = auth.issue_token_intent("this-is-the-token-intent-string")
self.assertEqual(401, res.status_code) self.assertEqual(401, res.status_code)