Skip to content

Commit

Permalink
Merge pull request #332 from weni-ai/feature/refactoring-in-dashboard…
Browse files Browse the repository at this point in the history
…-rooms-info-endpoint

Feature/refactoring in dashboard rooms info endpoint
  • Loading branch information
AlanJaeger authored Jan 31, 2024
2 parents e44c7ec + cd3b8b4 commit cd59d11
Show file tree
Hide file tree
Showing 7 changed files with 383 additions and 63 deletions.
15 changes: 15 additions & 0 deletions chats/apps/api/utils.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import uuid
from typing import List

from rest_framework.authtoken.models import Token

from chats.apps.accounts.models import User
from chats.apps.api.v1.dashboard.dto import RoomData
from chats.apps.api.v1.dashboard.serializers import DashboardRoomSerializer
from chats.apps.contacts.models import Contact
from chats.apps.msgs.models import Message as ChatMessage

Expand All @@ -29,3 +32,15 @@ def create_contact(
custom_fields=custom_fields,
external_id=str(uuid.uuid4()),
)


def create_room_dto(rooms_data) -> List[DashboardRoomSerializer]:
room_data = [
RoomData(
interact_time=rooms_data.get("interact_time", None),
response_time=rooms_data.get("response_time", None),
waiting_time=rooms_data.get("waiting_time", None),
)
]
serialized_data = DashboardRoomSerializer(room_data, many=True)
return serialized_data.data
18 changes: 15 additions & 3 deletions chats/apps/api/v1/dashboard/dto.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from dataclasses import dataclass

from chats.apps.projects.models import ProjectPermission
from chats.apps.projects.models import Project, ProjectPermission


@dataclass
Expand Down Expand Up @@ -29,7 +29,14 @@ class Filters:
tag: str = None
is_weni_admin: bool = None
user_request: ProjectPermission = None
project: str = None
project: Project = None


@dataclass
class RoomData:
interact_time: int = None
response_time: int = None
waiting_time: int = None


@dataclass
Expand All @@ -39,9 +46,14 @@ class ClosedRoomData:

@dataclass
class TransferRoomData:
transfer_count: dict = None
transfer_count: int = None


@dataclass
class QueueRoomData:
queue_rooms: dict = None


@dataclass
class ActiveRoomData:
active_rooms: int = None
26 changes: 26 additions & 0 deletions chats/apps/api/v1/dashboard/interfaces.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from abc import ABC, abstractmethod
from typing import List

from .dto import Filters, RoomData


class RoomsDataRepository(ABC):
@abstractmethod
def get_cache_key(self, filters: Filters) -> str:
pass

@abstractmethod
def get_rooms_data(self, filters: Filters) -> List["RoomData"]:
pass


class CacheRepository(ABC):
@abstractmethod
def get(self, key: str, default=None):
"""Obtém dados do cache com base na chave."""
pass

@abstractmethod
def set(self, key: str, data):
"""Define dados no cache com uma chave associada."""
pass
192 changes: 178 additions & 14 deletions chats/apps/api/v1/dashboard/repository.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
import json
from typing import List
from urllib import parse

from django.conf import settings
from django.db.models import Avg, Count, F, OuterRef, Q, Subquery, Sum
from django.utils import timezone
from django_redis import get_redis_connection
from pendulum.parser import parse as pendulum_parse

from chats.apps.accounts.models import User
from chats.apps.dashboard.models import RoomMetrics
from chats.apps.projects.models import ProjectPermission
from chats.apps.rooms.models import Room

from .dto import Agent, ClosedRoomData, Filters, QueueRoomData, Sector, TransferRoomData
from .dto import (
ActiveRoomData,
Agent,
ClosedRoomData,
Filters,
QueueRoomData,
Sector,
TransferRoomData,
)
from .interfaces import CacheRepository, RoomsDataRepository


class AgentRepository:
Expand Down Expand Up @@ -107,19 +120,19 @@ def _filter_date_range(self, filters, tz):

def _filter_sector(self, filters):
if filters.sector:
self.rooms_filter["queue__sector"] = filters.get("sector")
self.rooms_filter["queue__sector"] = filters.sector
if filters.tag:
self.rooms_filter["tags__uuid"] = filters.get("tag")
self.rooms_filter["tags__uuid"] = filters.tag
if filters.queue:
self.rooms_filter["queue"] = filters.get("queue")
self.rooms_filter["queue"] = filters.queue
return self.rooms_filter

self.rooms_filter["queue__sector__project"] = filters.project
return self.rooms_filter

def _filter_agents(self, filters):
if filters.agent:
self.rooms_filter["user"] = filters.get("agent")
self.rooms_filter["user"] = filters.agent
return self.rooms_filter

def closed_rooms(self, filters):
Expand Down Expand Up @@ -164,11 +177,11 @@ def _filter_date_range(self, filters, tz):

def _filter_sector(self, filters):
if filters.sector:
self.rooms_filter["queue__sector"] = filters.get("sector")
self.rooms_filter["queue__sector"] = filters.sector
if filters.tag:
self.rooms_filter["tags__uuid"] = filters.get("tag")
self.rooms_filter["tags__uuid"] = filters.tag
if filters.queue:
self.rooms_filter["queue"] = filters.get("queue")
self.rooms_filter["queue"] = filters.queue
return self.rooms_filter

self.rooms_filter["queue__sector__project"] = filters.project
Expand All @@ -189,6 +202,8 @@ def transfer_count(self, filters):
transfer_metric = rooms_query.filter(**self.rooms_filter).aggregate(
transfer_count=Sum("metric__transfer_count")
)["transfer_count"]
if transfer_metric is None:
transfer_metric = 0

transfer_count = [TransferRoomData(transfer_count=transfer_metric)]
return transfer_count
Expand All @@ -213,7 +228,7 @@ def _filter_date_range(self, filters, tz):

def _filter_sector(self, filters):
if filters.sector:
self.rooms_filter["queue__sector"] = filters.get("sector")
self.rooms_filter["queue__sector"] = filters.sector
return self.rooms_filter

self.rooms_filter["queue__sector__project"] = filters.project
Expand All @@ -237,6 +252,66 @@ def queue_rooms(self, filters):
return queue_rooms


class ActiveChatsRepository:
def __init__(self) -> None:
self.model = Room.objects
self.rooms_filter = {}

def _filter_date_range(self, filters, tz):
initial_datetime = (
timezone.now()
.astimezone(tz)
.replace(hour=0, minute=0, second=0, microsecond=0)
)
if filters.start_date and filters.end_date:
start_time = pendulum_parse(filters.start_date, tzinfo=tz)
end_time = pendulum_parse(filters.end_date + " 23:59:59", tzinfo=tz)
self.rooms_filter["created_on__range"] = [start_time, end_time]
self.rooms_filter["is_active"] = False
self.rooms_filter["user__isnull"] = False
else:
self.rooms_filter["created_on__range"] = [
initial_datetime,
initial_datetime,
]
self.rooms_filter["user__isnull"] = False
self.rooms_filter["is_active"] = True

def _filter_agents(self, filters):
if filters.agent:
self.rooms_filter["user"] = filters.agent

def _filter_sector(self, filters):
if filters.sector:
self.rooms_filter["queue__sector"] = filters.sector
# rooms_query = Room.objects
if filters.tag:
self.rooms_filter["tags__uuid"] = filters.tag
else:
self.rooms_filter["queue__sector__project"] = filters.project

def active_chats(self, filters):
tz = filters.project.timezone
self._filter_date_range(filters, tz)
self._filter_agents(filters)
self._filter_sector(filters)

if self.rooms_filter.get("created_on__gte"):
self.rooms_filter.pop("created_on__gte")

active_rooms = []

if filters.user_request:
rooms_query = self.model.filter(
queue__sector__in=filters.user_request.manager_sectors()
)
active_chats_count = rooms_query.filter(**self.rooms_filter).count()
active_rooms = [ActiveRoomData(active_rooms=active_chats_count)]
return active_rooms

return active_rooms


class SectorRepository:
def __init__(self) -> None:
self.model = RoomMetrics.objects
Expand Down Expand Up @@ -264,21 +339,22 @@ def _filter_sector(self, filters):

if filters.sector:
self.division_level = "room__queue"
self.rooms_filter["room__queue__sector"] = filters.get("sector")
if filters.get("tag"):
self.rooms_filter["room__tags__uuid"] = filters.get("tag")
self.rooms_filter["room__queue__sector"] = filters.sector
if filters.tag:
self.rooms_filter["room__tags__uuid"] = filters.tag
else:
self.rooms_filter["room__queue__sector__project"] = filters.project

def _filter_agents(self, filters):
if filters.get("agent"):
self.rooms_filter["room__user"] = filters.get("agent")
if filters.agent:
self.rooms_filter["room__user"] = filters.agent

def division_data(self, filters):
tz = filters.project.timezone

self._filter_date_range(filters, tz)
self._filter_sector(filters)
self._filter_agents(filters)

room_metric_query = self.model.filter(
room__queue__sector__in=filters.user_request.manager_sectors()
Expand Down Expand Up @@ -307,3 +383,91 @@ def division_data(self, filters):
]

return sectors


class ORMRoomsDataRepository(RoomsDataRepository):
def __init__(self) -> None:
self.model = Room.objects
self.rooms_filter = {}

def _filter_date_range(self, filters, tz):
initial_datetime = (
timezone.now()
.astimezone(tz)
.replace(hour=0, minute=0, second=0, microsecond=0)
)
if filters.start_date and filters.end_date:
start_time = pendulum_parse(filters.start_date, tzinfo=tz)
end_time = pendulum_parse(filters.end_date + " 23:59:59", tzinfo=tz)
self.rooms_filter["created_on__range"] = [start_time, end_time]
self.rooms_filter["user__isnull"] = False
else:
self.rooms_filter["created_on__range"] = [
initial_datetime,
initial_datetime,
]

def _filter_agents(self, filters):
if filters.agent:
self.rooms_filter["user"] = filters.agent

def _filter_sector(self, filters):
if filters.sector:
self.rooms_filter["queue__sector"] = filters.sector
if filters.tag:
self.rooms_filter["tags__uuid"] = filters.tag
else:
self.rooms_filter["queue__sector__project"] = filters.project

def get_cache_key(self, filters):
DASHBOARD_ROOMS_CACHE_KEY = "dashboard:{filter}:{metric}"

tz = filters.project.timezone

self._filter_date_range(filters, tz)
self._filter_agents(filters)
self._filter_sector(filters)

cache_key = DASHBOARD_ROOMS_CACHE_KEY.format(
filter=parse.urlencode(self.rooms_filter), metric="rooms_metrics"
)
return cache_key

def get_rooms_data(self, filters):
tz = filters.project.timezone

self._filter_date_range(filters, tz)
self._filter_agents(filters)
self._filter_sector(filters)

interact_time_agg = Avg("metric__interaction_time")
message_response_time_agg = Avg("metric__message_response_time")
waiting_time_agg = Avg("metric__waiting_time")

if filters.user_request:
rooms_query = self.model.filter(
queue__sector__in=filters.user_request.manager_sectors()
)

general_data = rooms_query.filter(**self.rooms_filter).aggregate(
interact_time=interact_time_agg,
response_time=message_response_time_agg,
waiting_time=waiting_time_agg,
)
return general_data


class RoomsCacheRepository(CacheRepository):
def get(self, key: str, default=None):
with get_redis_connection() as redis_connection:
try:
redis_general_time_value = redis_connection.get(key)
rooms_data = json.loads(redis_general_time_value)
return rooms_data
except (json.JSONDecodeError, TypeError):
return default

def set(self, key, data):
with get_redis_connection() as redis_connection:
serialized_data = json.dumps(data)
redis_connection.set(key, serialized_data, settings.CHATS_CACHE_TIME)
Loading

0 comments on commit cd59d11

Please sign in to comment.