добавил предпросмотр и защиту от повторной отправки трудочасов
This commit is contained in:
@@ -1,4 +1,10 @@
|
||||
"""Константы API-клиентов."""
|
||||
|
||||
from enums import ActivityTypes
|
||||
|
||||
REQUEST_TIMEOUT = 30
|
||||
REDMINE_ISSUES_LIMIT = 100
|
||||
REDMINE_TIME_ENTRIES_LIMIT = 100
|
||||
CLOCKIFY_ACTIVITY_COMMENT_PREFIX = "Clockify activity ID:"
|
||||
ACTIVITY_TYPE_BY_VETRO_PROJECT = {}
|
||||
DEFAULT_ACTIVITY_TYPE = ActivityTypes.DEVELOPMENT
|
||||
|
||||
@@ -6,9 +6,15 @@ import requests
|
||||
from classes.classes import Task
|
||||
from config import RedmineConfig, config
|
||||
from classes import Activity, ActivityType
|
||||
from enums import ActivityTypes
|
||||
from exceptions import InvalidToken
|
||||
from .constants import REDMINE_ISSUES_LIMIT, REQUEST_TIMEOUT
|
||||
from .constants import (
|
||||
ACTIVITY_TYPE_BY_VETRO_PROJECT,
|
||||
CLOCKIFY_ACTIVITY_COMMENT_PREFIX,
|
||||
DEFAULT_ACTIVITY_TYPE,
|
||||
REDMINE_ISSUES_LIMIT,
|
||||
REDMINE_TIME_ENTRIES_LIMIT,
|
||||
REQUEST_TIMEOUT,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -37,6 +43,13 @@ class RedmineAPI(RedmineConfig):
|
||||
]
|
||||
for activity in activities_to_track:
|
||||
try:
|
||||
if not config.is_debug and self.has_time_entry_for_activity(activity):
|
||||
activity.is_tracked = True
|
||||
if on_success:
|
||||
on_success(activity)
|
||||
tracked.append(activity)
|
||||
logger.info(f"{Fore.GREEN}{activity}: уже есть в Redmine {Fore.RESET}".ljust(100) + "✅")
|
||||
continue
|
||||
if not config.is_debug:
|
||||
resp = requests.post(
|
||||
self.base_url + self.time_entries_url,
|
||||
@@ -45,8 +58,8 @@ class RedmineAPI(RedmineConfig):
|
||||
"time_entry": {
|
||||
"issue_id": activity.task_id,
|
||||
"hours": activity.time_spent / (2 if is_beginner else 1),
|
||||
"activity_id": ActivityTypes.DEVELOPMENT,
|
||||
"comments": activity.description,
|
||||
"activity_id": self.get_activity_type_id(activity),
|
||||
"comments": self.get_comment(activity),
|
||||
"spent_on": activity.date_start.strftime(self.datetime_format)
|
||||
}
|
||||
},
|
||||
@@ -79,6 +92,38 @@ class RedmineAPI(RedmineConfig):
|
||||
for activity in failed_activities:
|
||||
logger.info(f"{Fore.RED}{activity}{Fore.RESET}".ljust(60) + "❌")
|
||||
return tracked
|
||||
|
||||
def get_comment(self, activity: Activity) -> str:
|
||||
"""Формирует комментарий Redmine с внешним id активности Clockify."""
|
||||
return f"{activity.description}\n{CLOCKIFY_ACTIVITY_COMMENT_PREFIX} {activity.id}"
|
||||
|
||||
def get_activity_type_id(self, activity: Activity) -> int:
|
||||
"""Возвращает тип деятельности Redmine для активности Clockify."""
|
||||
return ACTIVITY_TYPE_BY_VETRO_PROJECT.get(
|
||||
activity.vetro_project_id,
|
||||
DEFAULT_ACTIVITY_TYPE,
|
||||
)
|
||||
|
||||
def has_time_entry_for_activity(self, activity: Activity) -> bool:
|
||||
"""Проверяет, была ли активность Clockify уже перенесена в Redmine."""
|
||||
resp = requests.get(
|
||||
self.base_url + self.time_entries_url,
|
||||
headers={"X-Redmine-Api-Key": self.token},
|
||||
params={
|
||||
"issue_id": activity.task_id,
|
||||
"spent_on": activity.date_start.strftime(self.datetime_format),
|
||||
"limit": REDMINE_TIME_ENTRIES_LIMIT,
|
||||
},
|
||||
timeout=REQUEST_TIMEOUT,
|
||||
)
|
||||
if not resp.ok:
|
||||
logger.error(f"Ошибка RedmineAPI: {resp.text} {resp.status_code}")
|
||||
return False
|
||||
marker = f"{CLOCKIFY_ACTIVITY_COMMENT_PREFIX} {activity.id}"
|
||||
return any(
|
||||
marker in time_entry.get("comments", "")
|
||||
for time_entry in resp.json().get("time_entries", [])
|
||||
)
|
||||
|
||||
def get_time_entry_activities(self) -> list[ActivityType]:
|
||||
"""Получает виды Деятельности с сервера Redmine"""
|
||||
|
||||
Reference in New Issue
Block a user