Skip to content

Commit

Permalink
Merge branch 'main' into feature/refactor_room_list
Browse files Browse the repository at this point in the history
  • Loading branch information
helllllllder authored Jul 26, 2023
2 parents cd04871 + 16ddb6a commit 709b8a9
Show file tree
Hide file tree
Showing 38 changed files with 1,319 additions and 476 deletions.
9 changes: 0 additions & 9 deletions chats/apps/accounts/authentication/drf/backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,3 @@ def create_user(self, claims):
check_module_permission(claims, user)

return user

def update_user(self, user, claims):
user.email = claims.get("email", "")
user.first_name = claims.get("given_name", user.first_name)
user.last_name = claims.get("family_name", user.last_name)
user.save()
check_module_permission(claims, user)

return user
37 changes: 37 additions & 0 deletions chats/apps/accounts/tests/test_viewsets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from django.urls import reverse
from rest_framework import status
from rest_framework.authtoken.models import Token
from rest_framework.test import APITestCase

from chats.apps.accounts.models import User


class UserDataTests(APITestCase):
fixtures = ["chats/fixtures/fixture_app.json"]

def setUp(self) -> None:
self.user = User.objects.get(pk=9)
self.request_user = User.objects.get(pk=4)
self.login_token = Token.objects.get_or_create(user=self.user)[0]

def test_get_existent_user(self):
url = reverse("user_data-detail")
client = self.client
client.credentials(HTTP_AUTHORIZATION="Token " + self.login_token.key)
response = client.get(url, data={"user_email": self.request_user.email})
self.assertEqual(response.data.get("first_name"), self.request_user.first_name)
self.assertEqual(response.status_code, status.HTTP_200_OK)

def test_get_non_existent_user(self):
url = reverse("user_data-detail")
client = self.client
client.credentials(HTTP_AUTHORIZATION="Token " + self.login_token.key)
response = client.get(url, data={"user_email": "[email protected]"})
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

def test_get_without_user(self):
url = reverse("user_data-detail")
client = self.client
client.credentials(HTTP_AUTHORIZATION="Token " + self.login_token.key)
response = client.get(url)
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
8 changes: 8 additions & 0 deletions chats/apps/api/v1/accounts/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,11 @@ class Meta:
"last_name",
"email",
]

class UserNameSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = [
"first_name",
"last_name",
]
31 changes: 27 additions & 4 deletions chats/apps/api/v1/accounts/viewsets.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
from django.utils import timezone
from django.utils.decorators import method_decorator
from drf_yasg.utils import swagger_auto_schema
from rest_framework import mixins, status
from rest_framework import mixins, status, viewsets
from rest_framework.authtoken.models import Token
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet

from chats.apps.accounts.models import User
from chats.apps.api.v1.accounts.serializers import LoginSerializer
from chats.apps.api.v1.accounts.serializers import LoginSerializer, UserNameSerializer


@method_decorator(
name="create", decorator=swagger_auto_schema(responses={201: '{"token":"TOKEN"}'})
)
class LoginViewset(mixins.CreateModelMixin, GenericViewSet):
class LoginViewset(mixins.CreateModelMixin, viewsets.GenericViewSet):

"""
Login Users
Expand All @@ -39,3 +39,26 @@ def create(self, request, *args, **kwargs):
{"token": token.key},
status.HTTP_201_CREATED if created else status.HTTP_200_OK,
)


class UserDataViewset(viewsets.GenericViewSet):
queryset = User.objects.only("email", "first_name", "last_name").all()
serializer_class = UserNameSerializer
permission_classes = [IsAuthenticated]
lookup_field = None

def get_object(self):
user_email = self.request.query_params.get("user_email")
return User.objects.get(email=user_email)

def retrieve(self, request, *args, **kwargs):
try:
instance = self.get_object()
except User.DoesNotExist:
return Response(
{"Detail": "Email not found"},
status.HTTP_404_NOT_FOUND,
)

serializer = self.get_serializer(instance)
return Response(serializer.data)
48 changes: 28 additions & 20 deletions chats/apps/api/v1/dashboard/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@

import pendulum
from django.conf import settings
from django.db.models import Avg, Count, F, Q, Sum
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 rest_framework import serializers

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


Expand Down Expand Up @@ -99,43 +101,49 @@ def dashboard_agents_data(context, project):
timezone.now().astimezone(tz).replace(hour=0, minute=0, second=0, microsecond=0)
)

rooms_filter = {"user__isnull": False}
closed_rooms = {}
opened_rooms = {}
rooms_filter = {}
closed_rooms = {"rooms__queue__sector__project": project}
opened_rooms = {"rooms__queue__sector__project": project}
if context.get("start_date") and context.get("end_date"):
start_time = pendulum.parse(context.get("start_date")).replace(tzinfo=tz)
end_time = pendulum.parse(context.get("end_date") + " 23:59:59").replace(
tzinfo=tz
)

rooms_filter["created_on__range"] = [start_time, end_time]
closed_rooms["ended_at__range"] = [start_time, end_time]
rooms_filter["rooms__created_on__range"] = [start_time, end_time]
rooms_filter["rooms__is_active"] = False
closed_rooms["rooms__ended_at__range"] = [start_time, end_time]

else:
closed_rooms["ended_at__gte"] = initial_datetime
opened_rooms["is_active"] = True
closed_rooms["rooms__ended_at__gte"] = initial_datetime
opened_rooms["rooms__is_active"] = True
closed_rooms["rooms__is_active"] = False

if context.get("agent"):
rooms_filter["user"] = context.get("agent")
rooms_filter["rooms__user"] = context.get("agent")

if context.get("sector"):
rooms_filter["queue__sector"] = context.get("sector")
rooms_filter["rooms__queue__sector"] = context.get("sector")
if context.get("tag"):
rooms_filter["tags__name"] = context.get("tag")
else:
rooms_filter["queue__sector__project"] = project
rooms_filter["rooms__tags__name"] = context.get("tag")

project_permission_subquery = ProjectPermission.objects.filter(
project_id=project,
user_id=OuterRef("email"),
).values("status")[:1]

agents_query = Room.objects
agents_query = User.objects
if not context.get("is_weni_admin"):
agents_query = agents_query.exclude(user__email__endswith="weni.ai")
agents_query = agents_query.exclude(email__endswith="weni.ai")

agents_query = (
Room.objects.filter(**rooms_filter)
.values("user")
agents_query.filter(project_permissions__project=project)
.annotate(
user__first_name=F("user__first_name"),
closed_rooms=Count("uuid", filter=Q(is_active=False, **closed_rooms)),
opened_rooms=Count("uuid", filter=Q(**opened_rooms)),
agent_status=Subquery(project_permission_subquery),
closed_rooms=Count("rooms", filter=Q(**closed_rooms, **rooms_filter)),
opened_rooms=Count("rooms", filter=Q(**opened_rooms, **rooms_filter)),
)
.values("first_name", "email", "agent_status", "closed_rooms", "opened_rooms")
)

return agents_query
Expand Down
116 changes: 77 additions & 39 deletions chats/apps/api/v1/dashboard/viewsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@
from rest_framework.response import Response

from chats.apps.api.v1.dashboard.presenter import (
get_agents_data,
get_export_data,
get_general_data,
get_sector_data,
)
from chats.apps.api.v1.dashboard.serializers import (
DashboardRawDataSerializer,
Expand All @@ -19,6 +16,10 @@
from chats.apps.api.v1.permissions import HasDashboardAccess
from chats.apps.projects.models import Project

import io
from chats.core.excel_storage import ExcelStorage
import json


class DashboardLiveViewset(viewsets.GenericViewSet):
lookup_field = "uuid"
Expand Down Expand Up @@ -106,35 +107,54 @@ def export(self, request, *args, **kwargs):
project = self.get_object()
filter = request.query_params
dataset = get_export_data(project, filter)
data_frame_rooms = pandas.DataFrame(dataset)

filename = "dashboard_export_data"
filename = "dashboard_rooms_export_data"

if "xls" in filter:
response = HttpResponse(
content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
)
response["Content-Disposition"] = (
'attachment; filename="' + filename + ".xls"
excel_rooms_buffer = io.BytesIO()
with pandas.ExcelWriter(excel_rooms_buffer, engine="xlsxwriter") as writer:
data_frame_rooms.to_excel(
writer,
sheet_name="rooms_infos",
startrow=1,
startcol=0,
index=False,
)
excel_rooms_buffer.seek(0) # Move o cursor para o início do buffer
storage = ExcelStorage()

bytes_archive = excel_rooms_buffer.getvalue()

with storage.open(filename + ".xlsx", "wb") as up_file:
up_file.write(bytes_archive)
file_url = storage.url(up_file.name)

data = {"path_file": file_url}

return HttpResponse(
json.dumps(data),
content_type="application/javascript; charset=utf8",
)
else:
response = HttpResponse(content_type="text/csv")
response["Content-Disposition"] = (
'attachment; filename="' + filename + ".csv"
)

table = pandas.DataFrame(dataset)
table.rename(
columns={
0: "Queue Name",
1: "Waiting Time",
2: "Response Time",
3: "Interaction Time",
4: "Open",
},
inplace=True,
)
table.to_csv(response, encoding="utf-8", index=False)
return response
table = pandas.DataFrame(dataset)
table.rename(
columns={
0: "Queue Name",
1: "Waiting Time",
2: "Response Time",
3: "Interaction Time",
4: "Open",
},
inplace=True,
)
table.to_csv(response, encoding="utf-8", index=False)
return response

@action(
detail=True,
Expand All @@ -149,24 +169,28 @@ def export_dashboard(self, request, *args, **kwargs):
project = self.get_object()
filter = request.query_params

general_dataset = get_general_data(project, filter)
userinfo_dataset = get_agents_data(project, filter)
sector_dataset = get_sector_data(project, filter)
user_info_context = {}
user_info_context["filters"] = request.query_params

# General data
general_dataset = dashboard_general_data(context=filter, project=project)
raw_dataset = DashboardRawDataSerializer(instance=project, context=filter)
combined_dataset = {**general_dataset, **raw_dataset.data}

# Agents Data
userinfo_dataset = dashboard_agents_data(context=filter, project=project)
# # Sectors Data
sector_dataset = dashboard_division_data(context=filter, project=project)

filename = "dashboard_export_data"

data_frame = pandas.DataFrame([general_dataset])
data_frame_1 = pandas.read_json(userinfo_dataset)
data_frame_2 = pandas.read_json(sector_dataset)
data_frame = pandas.DataFrame([combined_dataset])
data_frame_1 = pandas.DataFrame(userinfo_dataset)
data_frame_2 = pandas.DataFrame(sector_dataset)

if "xls" in filter:
response = HttpResponse(
content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
)
response["Content-Disposition"] = (
'attachment; filename="' + filename + ".xlsx"
)
with pandas.ExcelWriter(response, engine="xlsxwriter") as writer:
excel_buffer = io.BytesIO()
with pandas.ExcelWriter(excel_buffer, engine="xlsxwriter") as writer:
data_frame.to_excel(
writer,
sheet_name="dashboard_infos",
Expand All @@ -188,16 +212,30 @@ def export_dashboard(self, request, *args, **kwargs):
startcol=0,
index=False,
)
return response
excel_buffer.seek(0) # Move o cursor para o início do buffer
storage = ExcelStorage()

bytes_archive = excel_buffer.getvalue()

with storage.open(filename + ".xlsx", "wb") as up_file:
up_file.write(bytes_archive)
file_url = storage.url(up_file.name)

data = {"path_file": file_url}

return HttpResponse(
json.dumps(data),
content_type="application/javascript; charset=utf8",
)

else:
response = HttpResponse(content_type="text/csv")
response["Content-Disposition"] = (
'attachment; filename="' + filename + ".csv"
)

data_frame.to_csv(response, index=False)
data_frame_1.to_csv(response, index=False, mode="a")
data_frame_2.to_csv(response, index=False, mode="a")
data_frame.to_csv(response, index=False, sep=";")
data_frame_1.to_csv(response, index=False, mode="a", sep=";")
data_frame_2.to_csv(response, index=False, mode="a", sep=";")

return response
2 changes: 1 addition & 1 deletion chats/apps/api/v1/external/msgs/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@


class AttachmentSerializer(serializers.ModelSerializer):
url = serializers.URLField(source="media_url")
url = serializers.CharField(source="media_url")

class Meta:
model = MessageMedia
Expand Down
Loading

0 comments on commit 709b8a9

Please sign in to comment.