Compare commits
No commits in common. "aebdf2d7c9f157b9c6050aaa2bc6c49b0b9de863" and "32621bcc87ea665e1ab9972f1f7aa901c3770b32" have entirely different histories.
aebdf2d7c9
...
32621bcc87
@ -7,7 +7,7 @@ from collections.abc import MutableMapping
|
||||
from copy import deepcopy
|
||||
from datetime import datetime, date, timedelta
|
||||
from threading import Thread, Event
|
||||
from typing import List, Tuple, Dict, Union
|
||||
from typing import List, Tuple, Dict
|
||||
|
||||
try:
|
||||
from PySide6 import QtCore
|
||||
@ -290,11 +290,22 @@ class Log:
|
||||
return None
|
||||
return log[-1][1]
|
||||
|
||||
def report(self):
|
||||
return Report(self._data)
|
||||
|
||||
def worklog(self):
|
||||
return Worklog(self._data)
|
||||
|
||||
|
||||
# TODO remove
|
||||
dEV = False
|
||||
|
||||
|
||||
def summary(lcd: LogCommentsData, pdate: date) -> Tuple[Dict[str, timedelta], timedelta]:
|
||||
log = lcd.get_log(pdate)
|
||||
if pdate == date.today():
|
||||
log.append((datetime.now(), "End"))
|
||||
if dEV:
|
||||
if pdate == date.today():
|
||||
log.append((datetime.now(), "End"))
|
||||
tasks_sums = {}
|
||||
total_sum = timedelta()
|
||||
for i, le in enumerate(log):
|
||||
@ -319,27 +330,27 @@ def duration_to_str(duration: timedelta) -> str:
|
||||
class PrevNextable:
|
||||
def __init__(self, data: LogCommentsData):
|
||||
self._data = data
|
||||
self.date = date.today()
|
||||
self._date = date.today()
|
||||
self._prev = None
|
||||
self._next = None
|
||||
self._update_prev_next()
|
||||
|
||||
def _update_prev_next(self):
|
||||
self._prev, self._next = self._data.get_prev_next_avail(self.date)
|
||||
self._prev, self._next = self._data.get_prev_next_avail(self._date)
|
||||
|
||||
def prev_next_avail(self) -> Tuple[bool, bool]:
|
||||
return self._prev is not None, self._next is not None
|
||||
|
||||
def previous(self):
|
||||
self.date = self._prev
|
||||
self._date = self._prev
|
||||
self._update_prev_next()
|
||||
|
||||
def next(self):
|
||||
self.date = self._next
|
||||
self._date = self._next
|
||||
self._update_prev_next()
|
||||
|
||||
def date_str(self) -> str:
|
||||
return self.date.strftime("%Y-%m-%d")
|
||||
def date(self) -> str:
|
||||
return self._date.strftime("%Y-%m-%d")
|
||||
|
||||
|
||||
class Report(PrevNextable):
|
||||
@ -348,8 +359,8 @@ class Report(PrevNextable):
|
||||
self._not_log_len = 0
|
||||
|
||||
def report(self) -> Tuple[List[List[str]], int]:
|
||||
log = self._data.get_log(self.date)
|
||||
if self.date == date.today():
|
||||
log = self._data.get_log(self._date)
|
||||
if self._date == date.today():
|
||||
log.append((datetime.now(), "End"))
|
||||
ret = []
|
||||
for i, t in enumerate(log):
|
||||
@ -364,12 +375,12 @@ class Report(PrevNextable):
|
||||
ret.append(["", "", ""])
|
||||
ret.append(["", "Sums", ""])
|
||||
|
||||
tasks_summary, total_sum = summary(self._data, self.date)
|
||||
tasks_summary, total_sum = summary(self._data, self._date)
|
||||
for task, duration in tasks_summary.items():
|
||||
ret.append([task, "", duration_to_str(duration)])
|
||||
ret.append(["Total sum", "", duration_to_str(total_sum)])
|
||||
self._not_log_len = 3 + len(tasks_summary)
|
||||
if self.date == date.today():
|
||||
if self._date == date.today():
|
||||
self._not_log_len += 1
|
||||
editable_len = len(ret) - (4 + len(tasks_summary))
|
||||
|
||||
@ -380,10 +391,10 @@ class Report(PrevNextable):
|
||||
if not report:
|
||||
return
|
||||
report = list(map(
|
||||
lambda x: (datetime.combine(self.date, datetime.strptime(x[1], "%H:%M").time()), x[0]),
|
||||
lambda x: (datetime.combine(self._date, datetime.strptime(x[1], "%H:%M").time()), x[0]),
|
||||
report
|
||||
))
|
||||
self._data.set_log(self.date, report)
|
||||
self._data.set_log(self._date, report)
|
||||
|
||||
|
||||
class Worklog(PrevNextable):
|
||||
@ -392,22 +403,22 @@ class Worklog(PrevNextable):
|
||||
self._worklog = []
|
||||
|
||||
@property
|
||||
def worklog(self) -> List[List[Union[str, timedelta]]]:
|
||||
tasks_summary, total_sum = summary(self._data, self.date)
|
||||
comments = self._data.get_comments(self.date)
|
||||
def worklog(self) -> List[List[str]]:
|
||||
tasks_summary, total_sum = summary(self._data, self._date)
|
||||
comments = self._data.get_comments(self._date)
|
||||
self._worklog = []
|
||||
for task, duration in tasks_summary.items():
|
||||
self._worklog.append([task, comments.setdefault(task, ""), duration])
|
||||
self._worklog.append(["Total sum", "", total_sum])
|
||||
self._worklog.append([task, comments.setdefault(task, ""), duration_to_str(duration)])
|
||||
self._worklog.append(["Total sum", "", duration_to_str(total_sum)])
|
||||
return deepcopy(self._worklog)
|
||||
|
||||
@worklog.setter
|
||||
def worklog(self, worklog: List[List[str]]):
|
||||
log = self._data.get_log(self.date)
|
||||
log = self._data.get_log(self._date)
|
||||
set_comments = dict()
|
||||
for i, (task, comment, duration) in enumerate(worklog[:-1]):
|
||||
set_comments[task] = comment
|
||||
if self._worklog[i][0] != task:
|
||||
log = list(map(lambda x: (x[0], x[1].replace(self._worklog[i][0], task)), log))
|
||||
self._data.set_comments(self.date, set_comments)
|
||||
self._data.set_log(self.date, log)
|
||||
self._data.set_comments(self._date, set_comments)
|
||||
self._data.set_log(self._date, log)
|
||||
|
@ -4,7 +4,6 @@ import sys
|
||||
from functools import partial
|
||||
|
||||
from fime.config import Config
|
||||
from fime.worklog import WorklogDialog
|
||||
|
||||
try:
|
||||
from PySide6 import QtCore, QtWidgets
|
||||
@ -13,10 +12,10 @@ except ImportError:
|
||||
from PySide2 import QtCore, QtWidgets
|
||||
PYSIDE_6 = False
|
||||
|
||||
from fime.data import Tasks, Log, Data, LogCommentsData, Worklog, Report
|
||||
from fime.data import Tasks, Log, Data, LogCommentsData
|
||||
from fime.exceptions import FimeException
|
||||
from fime.import_task import ImportTask
|
||||
from fime.report import ReportDialog
|
||||
from fime.report import Report
|
||||
from fime.task_edit import TaskEdit
|
||||
from fime.util import get_screen_height, get_icon
|
||||
|
||||
@ -32,25 +31,22 @@ class App:
|
||||
self.log = Log(lcd)
|
||||
self._active_task = self.log.last_log() or "Nothing"
|
||||
|
||||
config = Config()
|
||||
if config.tray_theme == "light":
|
||||
self.config = Config()
|
||||
if self.config.tray_theme == "light":
|
||||
icon = get_icon("appointment-new-light")
|
||||
else:
|
||||
icon = get_icon("appointment-new")
|
||||
|
||||
self.menu = QtWidgets.QMenu(None)
|
||||
|
||||
self.import_task = ImportTask(config, None)
|
||||
self.import_task = ImportTask(self.config, None)
|
||||
self.import_task.accepted.connect(self.new_task_imported)
|
||||
|
||||
self.taskEdit = TaskEdit(None)
|
||||
self.taskEdit.accepted.connect(self.tasks_edited)
|
||||
|
||||
self.reportDialog = ReportDialog(self.tasks, Report(lcd), None)
|
||||
self.reportDialog.accepted.connect(self.log_edited)
|
||||
|
||||
self.worklogDialog = WorklogDialog(config, Worklog(lcd), None)
|
||||
self.worklogDialog.accepted.connect(self.log_edited)
|
||||
self.reportDialog = Report(self.tasks, None)
|
||||
self.reportDialog.accepted.connect(self.report_done)
|
||||
|
||||
self.tray = QtWidgets.QSystemTrayIcon()
|
||||
self.tray.setIcon(icon)
|
||||
@ -71,7 +67,7 @@ class App:
|
||||
self.update_tray_menu()
|
||||
|
||||
@QtCore.Slot()
|
||||
def log_edited(self):
|
||||
def report_done(self):
|
||||
self.active_task = self.log.last_log() or "Nothing"
|
||||
|
||||
@property
|
||||
@ -122,10 +118,7 @@ class App:
|
||||
edit_action.triggered.connect(self.edit_tasks)
|
||||
|
||||
report_action = self.menu.addAction("Report")
|
||||
report_action.triggered.connect(self.reportDialog.show)
|
||||
|
||||
worklog_action = self.menu.addAction("Worklog")
|
||||
worklog_action.triggered.connect(self.worklogDialog.show)
|
||||
report_action.triggered.connect(self.report)
|
||||
|
||||
self.menu.addSeparator()
|
||||
|
||||
@ -148,6 +141,11 @@ class App:
|
||||
else:
|
||||
self.app.exec_()
|
||||
|
||||
@QtCore.Slot()
|
||||
def report(self):
|
||||
self.reportDialog.set_data(self.log.report())
|
||||
self.reportDialog.show()
|
||||
|
||||
@QtCore.Slot()
|
||||
def new_task_slot(self):
|
||||
self.import_task.reset_task_text()
|
||||
@ -159,21 +157,14 @@ class App:
|
||||
self.taskEdit.show()
|
||||
|
||||
|
||||
def excepthook(original, e_type, e_value, tb_obj):
|
||||
if e_type is FimeException:
|
||||
QtWidgets.QMessageBox.critical(None, "Error", str(e_value), QtWidgets.QMessageBox.Ok)
|
||||
else:
|
||||
original(e_type, e_value, tb_obj)
|
||||
|
||||
|
||||
def main():
|
||||
# important for QStandardPath to be correct
|
||||
QtCore.QCoreApplication.setApplicationName("fime")
|
||||
# also catches exceptions in other threads
|
||||
original_excepthook = sys.excepthook
|
||||
sys.excepthook = partial(excepthook, original_excepthook)
|
||||
app = App()
|
||||
app.run()
|
||||
try:
|
||||
# important for QStandardPath to be correct
|
||||
QtCore.QCoreApplication.setApplicationName("fime")
|
||||
app = App()
|
||||
app.run()
|
||||
except FimeException as e:
|
||||
QtWidgets.QMessageBox.critical(None, "Error", str(e), QtWidgets.QMessageBox.Ok)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -11,7 +11,7 @@ from fime.data import Tasks, Report
|
||||
from fime.util import get_screen_height, get_icon, EditStartedDetector
|
||||
|
||||
|
||||
class ReportDialog(QtWidgets.QDialog):
|
||||
class Report(QtWidgets.QDialog):
|
||||
class TaskItemCompleter(EditStartedDetector):
|
||||
def __init__(self, tasks: Tasks, parent=None):
|
||||
super().__init__(parent)
|
||||
@ -25,9 +25,9 @@ class ReportDialog(QtWidgets.QDialog):
|
||||
editor.setCompleter(completer)
|
||||
return editor
|
||||
|
||||
def __init__(self, tasks: Tasks, report: Report, parent, *args, **kwargs):
|
||||
def __init__(self, tasks: Tasks, parent, *args, **kwargs):
|
||||
super().__init__(parent, *args, **kwargs)
|
||||
self._report = report
|
||||
self._report: Optional[Report] = None
|
||||
self._report_data: Optional[List[List[str]]] = None
|
||||
self._changing_items = False
|
||||
self._new_log_task = ""
|
||||
@ -41,7 +41,7 @@ class ReportDialog(QtWidgets.QDialog):
|
||||
self.tableWidget.setColumnCount(3)
|
||||
self.tableWidget.setHorizontalHeaderLabels(["Task", "Start time", "Duration"])
|
||||
self.tableWidget.cellChanged.connect(self.cell_changed)
|
||||
taskItemCompleter = ReportDialog.TaskItemCompleter(tasks, self)
|
||||
taskItemCompleter = Report.TaskItemCompleter(tasks, self)
|
||||
taskItemCompleter.editStarted.connect(self.disable_buttons)
|
||||
taskItemCompleter.editFinished.connect(self.enable_buttons)
|
||||
self.tableWidget.setItemDelegateForColumn(0, taskItemCompleter)
|
||||
@ -97,7 +97,8 @@ class ReportDialog(QtWidgets.QDialog):
|
||||
layout.addLayout(blayout)
|
||||
self.setLayout(layout)
|
||||
|
||||
def showEvent(self, _):
|
||||
def set_data(self, data: Report):
|
||||
self._report = data
|
||||
self.update_title()
|
||||
self.refresh_table()
|
||||
self.update_prev_next()
|
||||
@ -106,7 +107,7 @@ class ReportDialog(QtWidgets.QDialog):
|
||||
self._report.save(self._report_data)
|
||||
|
||||
def update_title(self):
|
||||
self.setWindowTitle(f"Report {self._report.date_str()}")
|
||||
self.setWindowTitle(f"Report {self._report.date()}")
|
||||
|
||||
def refresh_table(self):
|
||||
self._report_data, self._edit_len = self._report.report()
|
||||
|
@ -1,8 +1,7 @@
|
||||
from functools import reduce, partial
|
||||
from typing import Optional, List, Tuple
|
||||
|
||||
from fime.config import Config
|
||||
from fime.data import Worklog, duration_to_str
|
||||
from fime.data import Worklog
|
||||
from fime.progressindicator import ProgressIndicator
|
||||
from fime.task_completer import TaskCompleter
|
||||
from fime.util import get_icon, EditStartedDetector, Status
|
||||
@ -93,13 +92,13 @@ class WorklogDialog(QtWidgets.QDialog):
|
||||
if not self.return_:
|
||||
self.edit_finished_row.emit(row)
|
||||
|
||||
def __init__(self, config: Config, worklog: Worklog, parent, *args, **kwargs):
|
||||
def __init__(self, config, parent, *args, **kwargs):
|
||||
super().__init__(parent, *args, **kwargs)
|
||||
|
||||
self.rest = WorklogRest(config)
|
||||
|
||||
self._changing_items = False
|
||||
self._worklog = worklog
|
||||
self._worklog: Optional[Worklog] = None
|
||||
self._worklog_data: List[List[str]] = []
|
||||
self._statuses: List[Tuple[Status, str]] = []
|
||||
self.row_height = None
|
||||
@ -144,7 +143,7 @@ class WorklogDialog(QtWidgets.QDialog):
|
||||
self.upload_button = QtWidgets.QPushButton()
|
||||
self.upload_button.setText("Upload")
|
||||
self.upload_button.setIcon(get_icon("cloud-upload"))
|
||||
self.upload_button.pressed.connect(self.upload)
|
||||
#self.upload_button.pressed.connect(self.del_log)
|
||||
self.upload_button.setAutoDefault(False)
|
||||
self.upload_button.setMinimumWidth(self.upload_button.minimumSizeHint().width() * 1.33)
|
||||
self.upload_button.setEnabled(False)
|
||||
@ -171,8 +170,8 @@ class WorklogDialog(QtWidgets.QDialog):
|
||||
self.update_timer.setInterval(500)
|
||||
self.update_timer.timeout.connect(self.update_statuses)
|
||||
|
||||
def showEvent(self, _):
|
||||
self.rest.purge_cache()
|
||||
def set_data(self, worklog: Worklog):
|
||||
self._worklog = worklog
|
||||
self.update_all()
|
||||
|
||||
def update_all(self):
|
||||
@ -202,7 +201,7 @@ class WorklogDialog(QtWidgets.QDialog):
|
||||
self._worklog.worklog = self._worklog_data
|
||||
|
||||
def update_title(self):
|
||||
self.setWindowTitle(f"Worklog {self._worklog.date_str()}")
|
||||
self.setWindowTitle(f"Worklog {self._worklog.date()}")
|
||||
|
||||
def refresh_table(self):
|
||||
self._worklog_data = self._worklog.worklog
|
||||
@ -232,7 +231,7 @@ class WorklogDialog(QtWidgets.QDialog):
|
||||
if row == 0 and not self._focussed:
|
||||
text_edit.setFocus()
|
||||
self._focussed = True
|
||||
item2 = QtWidgets.QTableWidgetItem(duration_to_str(self._worklog_data[row][2]))
|
||||
item2 = QtWidgets.QTableWidgetItem(self._worklog_data[row][2])
|
||||
self.tableWidget.setItem(row, 2, item2)
|
||||
item2.setFlags(item2.flags() & QtCore.Qt.ItemIsEnabled)
|
||||
self._changing_items = False
|
||||
@ -299,7 +298,6 @@ class WorklogDialog(QtWidgets.QDialog):
|
||||
self._worklog.previous()
|
||||
self._focussed = False
|
||||
self.update_all()
|
||||
self.upload_button.setEnabled(False)
|
||||
|
||||
@QtCore.Slot()
|
||||
def next(self):
|
||||
@ -307,14 +305,6 @@ class WorklogDialog(QtWidgets.QDialog):
|
||||
self._worklog.next()
|
||||
self._focussed = False
|
||||
self.update_all()
|
||||
self.upload_button.setEnabled(False)
|
||||
|
||||
@QtCore.Slot()
|
||||
def upload(self):
|
||||
issues = list(map(lambda x: (x[0].split()[0], x[1], x[2]), self._worklog_data[:-1]))
|
||||
self.rest.upload(issues, self._worklog.date)
|
||||
self.update_statuses()
|
||||
self.update_timer.start()
|
||||
|
||||
@QtCore.Slot()
|
||||
def cell_changed(self, row, _):
|
||||
@ -323,7 +313,6 @@ class WorklogDialog(QtWidgets.QDialog):
|
||||
self._worklog_data[row][0] = self.tableWidget.item(row, 0).text()
|
||||
self.save()
|
||||
self.update_all()
|
||||
self.upload_button.setEnabled(False)
|
||||
|
||||
@QtCore.Slot()
|
||||
def text_edit_changed(self, text, row):
|
||||
|
@ -1,10 +1,8 @@
|
||||
import os
|
||||
import sys
|
||||
import traceback
|
||||
from concurrent.futures import Future
|
||||
from datetime import date, datetime, timedelta, time
|
||||
from datetime import date, datetime
|
||||
from functools import partial
|
||||
from textwrap import dedent
|
||||
from threading import Lock
|
||||
from typing import List, Dict, Tuple
|
||||
|
||||
@ -22,51 +20,44 @@ class WorklogRest:
|
||||
self.user_url = os.path.join(config.jira_url, "rest/api/2/myself")
|
||||
self.issue_url = os.path.join(config.jira_url, "rest/api/2/issue/{}")
|
||||
self.worklog_url = os.path.join(config.jira_url, "rest/api/2/issue/{}/worklog")
|
||||
self.worklog_update_url = os.path.join(config.jira_url, "rest/api/2/issue/{issue_key}/worklog/{worklog_id}")
|
||||
self.worklog_update_url = os.path.join(config.jira_url, "rest/api/2/issue/{issue}/worklog/{worklog}")
|
||||
self.session = FuturesSession()
|
||||
self._user = None
|
||||
self._issue_state: Dict[str, Tuple[Status, str]] = dict()
|
||||
self.user = self._req_user()
|
||||
self._issue_state: Dict[str, Tuple[Status, str]] = {}
|
||||
self._issue_state_lock = Lock()
|
||||
self._req_user()
|
||||
|
||||
def _req_user(self):
|
||||
future = self.session.get(
|
||||
return self.session.get(
|
||||
self.user_url,
|
||||
headers={
|
||||
"Authorization": f"Bearer {self.config.jira_token}",
|
||||
"Accept": "application/json",
|
||||
},
|
||||
)
|
||||
future.add_done_callback(self._resp_user)
|
||||
|
||||
def _resp_user(self, future):
|
||||
def _get_user(self):
|
||||
try:
|
||||
self._user = future.result().json()["key"]
|
||||
return self.user.result().json()["key"]
|
||||
except Exception:
|
||||
print("Could not get user key:\n", file=sys.stderr)
|
||||
print(traceback.format_exc(), file=sys.stderr)
|
||||
raise FimeException("Could not get user key:\n" + traceback.format_exc())
|
||||
|
||||
def get_issues_state(self, issue_keys: List[str]):
|
||||
ret = []
|
||||
with self._issue_state_lock:
|
||||
for issue_key in issue_keys:
|
||||
if issue_key not in self._issue_state:
|
||||
self._issue_state[issue_key] = (Status.PROGRESS, "Working")
|
||||
self._issue_state[issue_key] = (Status.PROGRESS, "Fetching")
|
||||
self._req_issue(issue_key)
|
||||
ret.append(self._issue_state[issue_key])
|
||||
return ret
|
||||
|
||||
def purge_cache(self):
|
||||
self._issue_state = dict()
|
||||
|
||||
def _req_issue(self, issue_key: str):
|
||||
future = self.session.get(
|
||||
self.issue_url.format(issue_key),
|
||||
headers={
|
||||
"Authorization": f"Bearer {self.config.jira_token}",
|
||||
"Accept": "application/json",
|
||||
},
|
||||
)
|
||||
future = self.session.get(self.issue_url.format(issue_key),
|
||||
headers={
|
||||
"Authorization": f"Bearer {self.config.jira_token}",
|
||||
"Accept": "application/json",
|
||||
},
|
||||
)
|
||||
future.add_done_callback(partial(self._resp_issue, issue_key))
|
||||
|
||||
def _resp_issue(self, issue_key: str, future: Future):
|
||||
@ -78,95 +69,28 @@ class WorklogRest:
|
||||
else:
|
||||
self._issue_state[issue_key] = (Status.ERROR, "Could not find specified issue")
|
||||
|
||||
def _upload_sanity_check(self, issue_keys: List[str]):
|
||||
if not self._user:
|
||||
raise FimeException("Could not get user key")
|
||||
for issue_key in issue_keys:
|
||||
if issue_key not in self._issue_state or self._issue_state[issue_key] is not Status.OK:
|
||||
raise FimeException(f"Issue with key {issue_key} in unexpected state")
|
||||
|
||||
def upload(self, issues: List[Tuple[str, str, timedelta]], pdate: date):
|
||||
"""@:param issues: [(
|
||||
"ISS-1234",
|
||||
"I did some stuff",
|
||||
timedelta(seconds=300),
|
||||
), ... ]
|
||||
"""
|
||||
self._upload_sanity_check(list(map(lambda x: x[0], issues)))
|
||||
for issue in issues:
|
||||
future = self.session.get(
|
||||
self.worklog_url.format(issue[0]),
|
||||
headers={
|
||||
"Authorization": f"Bearer {self.config.jira_token}",
|
||||
"Accept": "application/json",
|
||||
}
|
||||
)
|
||||
future.add_done_callback(partial(self._worklog_check_resp, issue[0], issue[1], issue[2], pdate))
|
||||
self._issue_state[issue[0]] = (Status.PROGRESS, "Working")
|
||||
|
||||
def _worklog_check_resp(self, issue_key: str, comment: str, time_spent: timedelta, pdate: date, future: Future):
|
||||
resp = future.result()
|
||||
def get(self, issue_key: str, date: date):
|
||||
resp = requests.get(self.issue_url.format(issue_key),
|
||||
headers={
|
||||
"Authorization": f"Bearer {self.config.jira_token}",
|
||||
"Accept": "application/json",
|
||||
},
|
||||
)
|
||||
if resp.status_code != 200:
|
||||
raise RuntimeError("issue does not exist")
|
||||
resp = requests.get(self.worklog_url.format(issue_key),
|
||||
headers={
|
||||
"Authorization": f"Bearer {self.config.jira_token}",
|
||||
"Accept": "application/json",
|
||||
},
|
||||
)
|
||||
worklogs = resp.json()["worklogs"]
|
||||
worklog_id = None
|
||||
found = False
|
||||
for log in worklogs:
|
||||
if log["author"]["key"] == self._user \
|
||||
and datetime.strptime(log["started"], "%Y-%m-%dT%H:%M:%S.%f%z").date() == pdate:
|
||||
worklog_id = log["id"]
|
||||
if log["author"]["key"] == self.user \
|
||||
and datetime.strptime(log["started"], "%Y-%m-%dT%H:%M:%S.%f%z").date() == date:
|
||||
print(log["id"])
|
||||
print(log["comment"])
|
||||
found = True
|
||||
break
|
||||
if worklog_id:
|
||||
print(f"Found existing worklog for issue {issue_key} with id {worklog_id}")
|
||||
self._worklog_update(issue_key, worklog_id, comment, time_spent, pdate)
|
||||
else:
|
||||
print(f"Did not find existing worklog for issue {issue_key}")
|
||||
self._worklog_create(issue_key, comment, time_spent, pdate)
|
||||
|
||||
def _worklog_create(self, issue_key: str, comment: str, time_spent: timedelta, pdate: date):
|
||||
future = self.session.post(
|
||||
self.worklog_url.format(issue_key),
|
||||
headers={
|
||||
"Authorization": f"Bearer {self.config.jira_token}",
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
json={
|
||||
"started": datetime.combine(
|
||||
pdate, time(8, 0), datetime.now().astimezone().tzinfo).strftime("%Y-%m-%dT%H:%M:%S.000%z"),
|
||||
"timeSpentSeconds": time_spent.seconds,
|
||||
"comment": comment,
|
||||
}
|
||||
)
|
||||
future.add_done_callback(partial(self._worklog_resp, issue_key))
|
||||
|
||||
def _worklog_update(self, issue_key: str, worklog_id: str, comment: str, time_spent: timedelta, pdate: date):
|
||||
future = self.session.put(
|
||||
self.worklog_update_url.format(issue_key=issue_key, worklog_id=worklog_id),
|
||||
headers={
|
||||
"Authorization": f"Bearer {self.config.jira_token}",
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
json={
|
||||
"started": datetime.combine(
|
||||
pdate, time(8, 0), datetime.now().astimezone().tzinfo).strftime("%Y-%m-%dT%H:%M:%S.000%z"),
|
||||
"timeSpentSeconds": time_spent.seconds,
|
||||
"comment": comment,
|
||||
}
|
||||
)
|
||||
future.add_done_callback(partial(self._worklog_resp, issue_key))
|
||||
|
||||
def _worklog_resp(self, issue_key: str, future: Future):
|
||||
resp: requests.Response = future.result()
|
||||
with self._issue_state_lock:
|
||||
if resp.status_code == 200:
|
||||
self._issue_state[issue_key] = (Status.OK, "Successfully uploaded")
|
||||
print(f"Successfully uploaded issue {issue_key}")
|
||||
else:
|
||||
msg = dedent(f"""\
|
||||
Worklog upload failed:
|
||||
Method: {resp.request.method}
|
||||
URL: {resp.request.url}
|
||||
Response code: {resp.status_code}
|
||||
Response: {resp.text}
|
||||
""")
|
||||
self._issue_state[issue_key] = (Status.ERROR, msg)
|
||||
print(msg, file=sys.stderr)
|
||||
print(found)
|
||||
|
Loading…
Reference in New Issue
Block a user