This commit is contained in:
2024-04-17 18:32:23 +03:00
parent 937b154c6b
commit c25d7e3ab6
39 changed files with 986 additions and 926 deletions

View File

@@ -7,8 +7,12 @@ from typing import Dict
# ga
from google.analytics.data_v1beta import BetaAnalyticsDataClient
from google.analytics.data_v1beta.types import (DateRange, Dimension, Metric,
RunReportRequest)
from google.analytics.data_v1beta.types import (
DateRange,
Dimension,
Metric,
RunReportRequest,
)
from orm.author import Author
from orm.shout import Shout, ShoutAuthor, ShoutTopic
@@ -16,9 +20,9 @@ from orm.topic import Topic
from services.db import local_session
from services.logger import root_logger as logger
GOOGLE_KEYFILE_PATH = os.environ.get('GOOGLE_KEYFILE_PATH', '/dump/google-service.json')
GOOGLE_PROPERTY_ID = os.environ.get('GOOGLE_PROPERTY_ID', '')
VIEWS_FILEPATH = '/dump/views.json'
GOOGLE_KEYFILE_PATH = os.environ.get("GOOGLE_KEYFILE_PATH", "/dump/google-service.json")
GOOGLE_PROPERTY_ID = os.environ.get("GOOGLE_PROPERTY_ID", "")
VIEWS_FILEPATH = "/dump/views.json"
class ViewedStorage:
@@ -41,17 +45,17 @@ class ViewedStorage:
# Загрузка предварительно подсчитанных просмотров из файла JSON
self.load_precounted_views()
os.environ.setdefault('GOOGLE_APPLICATION_CREDENTIALS', GOOGLE_KEYFILE_PATH)
os.environ.setdefault("GOOGLE_APPLICATION_CREDENTIALS", GOOGLE_KEYFILE_PATH)
if GOOGLE_KEYFILE_PATH and os.path.isfile(GOOGLE_KEYFILE_PATH):
# Using a default constructor instructs the client to use the credentials
# specified in GOOGLE_APPLICATION_CREDENTIALS environment variable.
self.analytics_client = BetaAnalyticsDataClient()
logger.info(' * Клиент Google Analytics успешно авторизован')
logger.info(" * Клиент Google Analytics успешно авторизован")
# Запуск фоновой задачи
_task = asyncio.create_task(self.worker())
else:
logger.info(' * Пожалуйста, добавьте ключевой файл Google Analytics')
logger.info(" * Пожалуйста, добавьте ключевой файл Google Analytics")
self.disabled = True
@staticmethod
@@ -63,44 +67,44 @@ class ViewedStorage:
self.file_modification_timestamp = os.path.getmtime(VIEWS_FILEPATH)
self.start_date = datetime.fromtimestamp(
self.file_modification_timestamp
).strftime('%Y-%m-%d')
now_date = datetime.now().strftime('%Y-%m-%d')
).strftime("%Y-%m-%d")
now_date = datetime.now().strftime("%Y-%m-%d")
if now_date == self.start_date:
logger.info(' * Данные актуализованы!')
logger.info(" * Данные актуализованы!")
else:
logger.warn(
f' * Файл просмотров {VIEWS_FILEPATH} устарел: {self.start_date}'
f" * Файл просмотров {VIEWS_FILEPATH} устарел: {self.start_date}"
)
with open(VIEWS_FILEPATH, 'r') as file:
with open(VIEWS_FILEPATH, "r") as file:
precounted_views = json.load(file)
self.views_by_shout.update(precounted_views)
logger.info(
f' * {len(precounted_views)} публикаций с просмотрами успешно загружены.'
f" * {len(precounted_views)} публикаций с просмотрами успешно загружены."
)
else:
logger.info(' * Файл просмотров не найден.')
logger.info(" * Файл просмотров не найден.")
except Exception as e:
logger.error(f'Ошибка загрузки предварительно подсчитанных просмотров: {e}')
logger.error(f"Ошибка загрузки предварительно подсчитанных просмотров: {e}")
# noinspection PyTypeChecker
@staticmethod
async def update_pages():
"""Запрос всех страниц от Google Analytics, отсортированных по количеству просмотров"""
self = ViewedStorage
logger.info(' ⎧ Обновление данных просмотров от Google Analytics ---')
logger.info(" ⎧ Обновление данных просмотров от Google Analytics ---")
if not self.disabled:
try:
start = time.time()
async with self.lock:
if self.analytics_client:
request = RunReportRequest(
property=f'properties/{GOOGLE_PROPERTY_ID}',
dimensions=[Dimension(name='pagePath')],
metrics=[Metric(name='screenPageViews')],
property=f"properties/{GOOGLE_PROPERTY_ID}",
dimensions=[Dimension(name="pagePath")],
metrics=[Metric(name="screenPageViews")],
date_ranges=[
DateRange(start_date=self.start_date, end_date='today')
DateRange(start_date=self.start_date, end_date="today")
],
)
response = self.analytics_client.run_report(request)
@@ -114,7 +118,7 @@ class ViewedStorage:
# Извлечение путей страниц из ответа Google Analytics
if isinstance(row.dimension_values, list):
page_path = row.dimension_values[0].value
slug = page_path.split('discours.io/')[-1]
slug = page_path.split("discours.io/")[-1]
views_count = int(row.metric_values[0].value)
# Обновление данных в хранилище
@@ -127,10 +131,10 @@ class ViewedStorage:
# Запись путей страниц для логирования
slugs.add(slug)
logger.info(f' ⎪ Собрано страниц: {len(slugs)} ')
logger.info(f" ⎪ Собрано страниц: {len(slugs)} ")
end = time.time()
logger.info(' ⎪ Обновление страниц заняло %fs ' % (end - start))
logger.info(" ⎪ Обновление страниц заняло %fs " % (end - start))
except Exception as error:
logger.error(error)
@@ -211,18 +215,18 @@ class ViewedStorage:
except Exception as exc:
failed += 1
logger.debug(exc)
logger.info(' - Обновление не удалось #%d, ожидание 10 секунд' % failed)
logger.info(" - Обновление не удалось #%d, ожидание 10 секунд" % failed)
if failed > 3:
logger.info(' - Больше не пытаемся обновить')
logger.info(" - Больше не пытаемся обновить")
break
if failed == 0:
when = datetime.now(timezone.utc) + timedelta(seconds=self.period)
t = format(when.astimezone().isoformat())
logger.info(
' ⎩ Следующее обновление: %s'
% (t.split('T')[0] + ' ' + t.split('T')[1].split('.')[0])
" ⎩ Следующее обновление: %s"
% (t.split("T")[0] + " " + t.split("T")[1].split(".")[0])
)
await asyncio.sleep(self.period)
else:
await asyncio.sleep(10)
logger.info(' - Попытка снова обновить данные')
logger.info(" - Попытка снова обновить данные")