164 lines
6.5 KiB
Python
164 lines
6.5 KiB
Python
import logging
|
||
import os.path
|
||
import sys
|
||
|
||
logging.basicConfig(
|
||
level=logging.INFO,
|
||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||
handlers=[
|
||
logging.FileHandler('app.log', encoding='utf-8'),
|
||
logging.StreamHandler(sys.stdout)
|
||
]
|
||
)
|
||
|
||
|
||
from colorama import Fore # noqa: E402
|
||
|
||
from api import ClockifyAPI, RedmineAPI # noqa: E402
|
||
from config import arg_parser, config, db # noqa: E402
|
||
from utils import format_date, str_to_date, today_start, today_end, parse_task_id # noqa: E402
|
||
|
||
|
||
WORKSPACE_ID = config.WORKSPACE_ID
|
||
USER_ID = config.USER_ID
|
||
|
||
|
||
def main():
|
||
args = arg_parser.parse_args()
|
||
|
||
if args.debug:
|
||
logging.getLogger().setLevel(logging.DEBUG)
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
start, end = None, None
|
||
if args.start:
|
||
start = str_to_date(args.start)
|
||
if args.end:
|
||
end = str_to_date(args.end)
|
||
if args.start is None and args.end is None:
|
||
logger.info("Парсим задачи за сегодняшний день")
|
||
start = today_start()
|
||
end = today_end()
|
||
else:
|
||
if start:
|
||
from_ = f"{start.day} {config.MONTHS.get(start.month)} {start.year} г."
|
||
|
||
if end:
|
||
to_ = f"{end.day} {config.MONTHS.get(end.month)} {end.year} г."
|
||
|
||
if start == end:
|
||
logger.info(f"{Fore.YELLOW}Парсим задачи за {from_}{Fore.RESET}")
|
||
else:
|
||
logger.info(Fore.YELLOW + "Парсим задачи" + (f" с {from_} " if start else " ") + (f"до {to_}" if end else "") + Fore.RESET)
|
||
|
||
clock = ClockifyAPI(
|
||
token=config.CLOCKIFY_TOKEN,
|
||
workspace_id=WORKSPACE_ID,
|
||
user_id=USER_ID
|
||
)
|
||
if not WORKSPACE_ID or not USER_ID:
|
||
if not os.path.exists(config.ENV_TXT):
|
||
logger.info(f"{Fore.YELLOW}Необходимые переменные не были обнаружены. Попытка получения...{Fore.RESET}")
|
||
clock.getenvs()
|
||
else:
|
||
logger.info(f'{Fore.YELLOW}Проверьте файл "{config.ENV_TXT}". Если необходимых переменных в нём нет, то просто удалите его.{Fore.RESET}')
|
||
return
|
||
red = RedmineAPI(config.REDMINE_TOKEN)
|
||
user = clock.get_user()
|
||
clock_user = {
|
||
"clockify_user_id": user["id"],
|
||
"clockify_email": user["email"],
|
||
"clockify_username": user["username"],
|
||
}
|
||
user = red.get_user()
|
||
red_user = {
|
||
"redmine_user_id": user["id"],
|
||
"redmine_email": user["email"],
|
||
"first_name": user["first_name"],
|
||
"last_name": user["last_name"],
|
||
"redmine_username": user["username"]
|
||
}
|
||
db.insert_user(**clock_user, **red_user)
|
||
if args.init_db:
|
||
logger.info(Fore.YELLOW + "Обновление базы данных..." + Fore.RESET)
|
||
|
||
try:
|
||
# Обновление Тегов
|
||
logger.info(f"{Fore.YELLOW}Обновление Тегов...\n{Fore.RESET}")
|
||
|
||
clock_tags = clock.get_tags(is_updating=True, **{"page-size": clock.tags_count})
|
||
db_tags = db.get_tags()
|
||
new_tags = [tag for tag in clock_tags if tag not in db_tags]
|
||
|
||
if new_tags:
|
||
try:
|
||
db.insert_tags(new_tags)
|
||
logger.info(f"{Fore.GREEN}Обновлено тегов: {len(new_tags)}{Fore.RESET}")
|
||
except Exception as e:
|
||
logger.error(f"{Fore.RED}Ошибка при сохранении тегов!{Fore.RESET}")
|
||
else:
|
||
logger.info(f"{Fore.YELLOW}Обновление тегов не требуется.\n{Fore.RESET}")
|
||
|
||
|
||
# Обновление Задач
|
||
logger.info(f"{Fore.YELLOW}Обновление Задач...\n{Fore.RESET}")
|
||
|
||
db_tasks = db.get_tasks()
|
||
red_tasks = red.get_issues()
|
||
clock_tasks = [task for task in red_tasks if task.id in [parse_task_id(tag.title) for tag in [*db_tags, *new_tags]]]
|
||
new_tasks = [task for task in clock_tasks if task not in db_tasks]
|
||
|
||
if new_tasks:
|
||
try:
|
||
db.insert_tasks(new_tasks)
|
||
logger.info(f"{Fore.GREEN}Обновлено задач: {len(new_tasks)}{Fore.RESET}")
|
||
except Exception as e:
|
||
logger.error(f"{Fore.RED}Ошибка при сохранении задач!{Fore.RESET}")
|
||
else:
|
||
logger.info(f"{Fore.YELLOW}Обновление задач не требуется\n{Fore.RESET}")
|
||
|
||
# # Обновление Проектов Ветро
|
||
# logger.info(f"{Fore.YELLOW}Получение Проектов Ветро{Fore.RESET}")
|
||
# vetro_projects = clock.get_vetro_projects()
|
||
|
||
# logger.info(f"{Fore.YELLOW}Получение Типов деятельности{Fore.RESET}")
|
||
# activity_types = red.get_time_entry_activities()
|
||
|
||
# if vetro_projects:
|
||
# logger.info(f"{Fore.YELLOW}Сохранение Проектов Ветро{Fore.RESET}")
|
||
# db.insert_vetro_projects(vetro_projects)
|
||
|
||
# if activity_types:
|
||
# logger.info(f"{Fore.YELLOW}Сохранение Типов деятелности{Fore.RESET}")
|
||
# db.insert_activity_types(activity_types)
|
||
except Exception as e:
|
||
logger.error(Fore.RED + f"Ошибка при обновлении базы данных: {e}" + Fore.RESET)
|
||
else:
|
||
logger.info(Fore.GREEN + "База данных теперь актуальна." + Fore.RESET)
|
||
|
||
activities = sorted(clock.get_activities(
|
||
**{
|
||
"start": format_date(start),
|
||
"end": format_date(end),
|
||
"page-size": args.page_size,
|
||
},
|
||
), key=lambda x: x.date_start)
|
||
if not activities:
|
||
logger.info(Fore.YELLOW + "Нет задач для занесения трудочасов" + Fore.RESET)
|
||
return
|
||
db.insert_activities(activities)
|
||
if args.debug:
|
||
logger.debug("Пропускаем этап загрузки трудочасов")
|
||
return
|
||
try:
|
||
tracked_activities = red.track_activities(activities)
|
||
clock.mark_tracked(tracked_activities)
|
||
db.insert_time_entries(tracked_activities)
|
||
db.insert_activities(tracked_activities)
|
||
except Exception as e:
|
||
logger.error(e)
|
||
|
||
if __name__ == "__main__":
|
||
main()
|