awork_tasks.py 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. import datetime
  2. import json
  3. from pathlib import Path
  4. import requests
  5. import typer
  6. from credentials import Client
  7. from model import AworkProjekt, Comment, User
  8. from sqlalchemy import create_engine, text
  9. from sqlalchemy.orm import Session
  10. app = typer.Typer()
  11. DSN = "mysql+pymysql://gaps:Gcbs12ma@192.168.2.41/tasks"
  12. awork_api_url = "https://api.awork.com/api/v1"
  13. token_expires_in = 24 * 60 * 60
  14. header = {"Authorization": ""}
  15. token_json_file = Path(__file__).parent.joinpath("token.json")
  16. access_token_file = Path(__file__).parent.joinpath("access_token.txt")
  17. def main():
  18. # bearer_token = login()
  19. bearer_token = access_token_file.read_text()
  20. header["Authorization"] = f"Bearer {bearer_token}"
  21. # users = get_users()
  22. # companies = get_companies()
  23. # import_projects()
  24. # create_task(73849)
  25. def get_companies():
  26. res = requests.get(awork_api_url + "/companies", headers=header)
  27. data = res.json()
  28. json.dump(data, Path(__file__).parent.joinpath("companies.json").open("w"), indent=2)
  29. return data
  30. def get_users():
  31. res = requests.get(awork_api_url + "/users", headers=header)
  32. data = res.json()
  33. json.dump(data, Path(__file__).parent.joinpath("users.json").open("w"), indent=2)
  34. return data
  35. @app.command()
  36. def import_projects():
  37. projects = get_projects()
  38. p = convert_projects(projects)
  39. with Session(create_engine(DSN)) as db_session:
  40. db_session.execute(text("TRUNCATE TABLE awork_projekte"))
  41. db_session.add_all(p)
  42. db_session.commit()
  43. def get_projects():
  44. res = requests.get(awork_api_url + "/projects?pageSize=1000", headers=header)
  45. data = res.json()
  46. json.dump(data, Path(__file__).parent.joinpath("projects.json").open("w"), indent=2)
  47. return data
  48. def update_project(project_id, data):
  49. res = requests.put(awork_api_url + f"/projects/{project_id}", headers=header, json=data)
  50. return res.json()
  51. def convert_projects(projects):
  52. res = []
  53. for p in projects:
  54. if "companyId" not in p:
  55. continue
  56. p_allgemein = 1 if "Allgemein" in p["name"] else 0
  57. p_typ = p["projectType"]["name"] if "projectType" in p else "Unbekannt"
  58. entry = AworkProjekt(
  59. **{
  60. "awork_project_id": p["id"],
  61. "awork_company_id": p["companyId"],
  62. "projekt_name": p["name"],
  63. "projekt_status": p["projectStatus"]["name"],
  64. "projekt_typ": p_typ,
  65. "projekt_allgemein": p_allgemein,
  66. "kunde_name": p["company"]["name"],
  67. "tasks_count": p["tasksCount"],
  68. "tracked_duration": p["trackedDuration"],
  69. }
  70. )
  71. res.append(entry)
  72. return res
  73. @app.command()
  74. def create_task(comment_id: int):
  75. with Session(create_engine(DSN)) as db_session:
  76. comment = db_session.get(Comment, comment_id)
  77. if comment.awork_task_id:
  78. return comment.awork_task_id
  79. datum = comment.datum.strftime("%d.%m.%Y")
  80. link = f"http://gc-server1/fehlerbericht/#/report/{comment.kunde}/{comment.datum}/{comment.start}"
  81. res = requests.get(awork_api_url + "/projects/" + comment.awork_project_id + "/taskstatuses", headers=header)
  82. data = res.json()
  83. task_status = [s["id"] for s in data if s["type"] == "progress"]
  84. if len(task_status) == 0:
  85. return 0
  86. task_status_id = task_status[0]
  87. task = {
  88. "name": f"{comment.kunde} - Fehlerbericht vom {datum} - {comment.fehler} Fehler",
  89. "description": (
  90. f'<p><a target="_blank" rel="noopener noreferrer nofollow" href="{link}">Fehlerbericht-Portal</a></p>'
  91. + f"<p>{comment.benutzer}: {comment.kommentar}</p>"
  92. ),
  93. "isPrio": False,
  94. # "startOn": "2021-03-03T17:00:00Z",
  95. "dueOn": f"{comment.datum}T16:00:00Z",
  96. # "laneOrder": 0,
  97. "plannedDuration": 3600,
  98. # "remainingDuration": 0,
  99. "typeOfWorkId": "1854242b-8d9a-44c6-a98e-f17b89b6bed8",
  100. "taskStatusId": task_status_id,
  101. # "order": 0,
  102. # "subtaskOrder": 1,
  103. "entityId": comment.awork_project_id,
  104. "baseType": "projecttask",
  105. # "parentId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  106. # "lists": [{"id": "94166142-b5f9-4bd0-968d-a6a3474ee705", "order": 0}],
  107. }
  108. res = requests.post(awork_api_url + "/tasks", json=task, headers=header)
  109. data = res.json()
  110. task_id = data["id"]
  111. res = requests.post(
  112. awork_api_url + f"/tasks/{task_id}/addtags", json=[{"name": "Fehlerprotokolle"}], headers=header
  113. )
  114. user1 = db_session.get(User, comment.benutzer)
  115. user_comment = {
  116. "message": comment.kommentar,
  117. "userId": user1.awork_user_id,
  118. }
  119. res = requests.post(awork_api_url + f"/tasks/{task_id}/comments", json=user_comment, headers=header)
  120. res = requests.post(
  121. awork_api_url + f"/tasks/{task_id}/setassignees", json=[user1.awork_user_id], headers=header
  122. )
  123. user2 = user1
  124. if comment.benutzer2:
  125. user2 = db_session.get(User, comment.benutzer2)
  126. res = requests.post(
  127. awork_api_url + f"/tasks/{task_id}/setassignees", json=[user2.awork_user_id], headers=header
  128. )
  129. comment.awork_task_id = task_id
  130. db_session.commit()
  131. def login():
  132. # token_file = Path(__file__).parent.joinpath("access_token.txt")
  133. timestamp = datetime.datetime.now().timestamp()
  134. if not token_json_file.exists():
  135. return token(authorize())
  136. token_dict = json.loads(token_json_file.read_text())
  137. if timestamp < token_dict["expires_at"]:
  138. return token_dict["access_token"]
  139. res = refresh(token_dict["refresh_token"])
  140. if res:
  141. return res
  142. token_json_file.unlink()
  143. return token(authorize())
  144. def refresh(refresh_token):
  145. header = {
  146. "Authorization": "Basic Base64(" + Client.authorization_base64() + ")",
  147. "Content-Type": "application/x-www-form-urlencoded",
  148. }
  149. params = {
  150. "client_id": Client.CLIENT_ID,
  151. "client_secret": Client.CLIENT_SECRET,
  152. "grant_type": "refresh_token",
  153. "redirect_uri": "http://gc-server1/fehlerbericht/",
  154. "refresh_token": refresh_token,
  155. }
  156. r = requests.post(awork_api_url + "/accounts/token", headers=header, data=params)
  157. if r.status_code == 400:
  158. return False
  159. token_dict = r.json()
  160. if "refresh_token" not in token_dict:
  161. token_dict["refresh_token"] = refresh_token
  162. write_token_file(token_dict)
  163. return token_dict["access_token"]
  164. def token(code):
  165. header = {
  166. "Authorization": "Basic Base64(" + Client.authorization_base64() + ")",
  167. "Content-Type": "application/x-www-form-urlencoded",
  168. }
  169. params = {
  170. "client_id": Client.CLIENT_ID,
  171. "client_secret": Client.CLIENT_SECRET,
  172. "grant_type": "authorization_code",
  173. "redirect_uri": "http://gc-server1/fehlerbericht/",
  174. "code": code,
  175. }
  176. r = requests.post(awork_api_url + "/accounts/token", headers=header, data=params)
  177. if r.status_code == 400:
  178. return False
  179. token_dict = r.json()
  180. write_token_file(token_dict)
  181. return token_dict["access_token"]
  182. def write_token_file(token_dict):
  183. timestamp = datetime.datetime.now().timestamp()
  184. token_dict["expires_at"] = token_dict["expires_in"] + timestamp
  185. token_json_file.write_text(json.dumps(token_dict))
  186. def authorize():
  187. params = {
  188. "client_id": Client.CLIENT_ID,
  189. "response_type": "code",
  190. "grant_type": "authorization_code",
  191. "redirect_uri": "http://gc-server1/fehlerbericht/",
  192. "state": "",
  193. "scope": "offline_access",
  194. }
  195. r = requests.get(awork_api_url + "/accounts/authorize", params=params)
  196. print(r.url)
  197. print("code: ", end="")
  198. code = input()
  199. return code
  200. def set_projects_billable():
  201. billable_types = ["Auftrag GC", "Auftrag Keyloop", "Premium-Support"]
  202. projects = get_projects()
  203. for p in projects:
  204. p["isBillableByDefault"] = p["projectType"]["name"] in billable_types
  205. p["deductNonBillableHours"] = False
  206. update_project(p["id"], p)
  207. return len(projects)
  208. def set_project_timeentries_billable(project_id: str, is_billable: bool):
  209. res = requests.get(awork_api_url + f"/projects/{project_id}/timeentries", headers=header)
  210. timeentries = res.json()
  211. for t in timeentries:
  212. t["isBillable"] = is_billable
  213. requests.put(awork_api_url + f"/timeentries/{t['id']}", headers=header, json=t)
  214. return len(timeentries)
  215. def set_all_timeentries_billable():
  216. projects = get_projects()
  217. found = False
  218. for p in projects:
  219. if not found and p["id"] != "49a2db08-e654-448c-bd75-ba43a00fac41":
  220. continue
  221. found = True
  222. count = set_project_timeentries_billable(p["id"], p["isBillableByDefault"])
  223. print(f"{p['name']}: {count} Timeentries gesetzt")
  224. if __name__ == "__main__":
  225. main()
  226. # app()
  227. # create_task(74715)
  228. import_projects()
  229. # set_all_timeentries_billable()