Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
dudanogueira committed Apr 23, 2023
2 parents 41e36fe + dad8a12 commit 053d958
Show file tree
Hide file tree
Showing 10 changed files with 330 additions and 26 deletions.
37 changes: 18 additions & 19 deletions local.yml
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ services:


rocketchat:
image: registry.rocket.chat/rocketchat/rocket.chat:${RELEASE:-6.1.0}
image: registry.rocket.chat/rocketchat/rocket.chat:${RELEASE:-develop}
restart: on-failure
environment:
MONGO_URL: "${MONGO_URL:-\
Expand Down Expand Up @@ -197,24 +197,23 @@ services:
ports:
- "21465:21465"

quepasa:
image: sufficit/quepasa
mem_limit: 4096M
ports:
- 31000:31000
extra_hosts:
- "host.docker.internal:host-gateway"
restart: always
stdin_open: true
tty: true
environment:
- WEBSOCKETSSL=false
- WEBAPIPORT=31000
- APP_ENV=production
- MIGRATIONS=/opt/quepasa/migrations
- DEBUGJSONMESSAGES=false
- HTTPLOGS=false

# quepasa:
# image: sufficit/quepasa
# mem_limit: 4096M
# ports:
# - 31000:31000
# extra_hosts:
# - "host.docker.internal:host-gateway"
# restart: always
# stdin_open: true
# tty: true
# environment:
# - WEBSOCKETSSL=false
# - WEBAPIPORT=31000
# - APP_ENV=production
# - MIGRATIONS=/opt/quepasa/migrations
# - DEBUGJSONMESSAGES=false
# - HTTPLOGS=false

apache:
image: 'php:apache'
Expand Down
2 changes: 1 addition & 1 deletion rocket_connect/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = "1.1.20"
__version__ = "1.1.21"
__version_info__ = tuple(
int(num) if num.isdigit() else num
for num in __version__.replace("-", ".", 1).split(".")
Expand Down
20 changes: 19 additions & 1 deletion rocket_connect/instance/forms.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
from django.forms import CharField, ChoiceField, ModelForm
from django.forms import (
CharField,
ChoiceField,
Form,
ModelChoiceField,
ModelForm,
Textarea,
)
from instance.models import Connector, Server


Expand All @@ -16,6 +23,17 @@ class Meta:
]


class NewInboundForm(Form):
number = CharField(label="Number", max_length=100, help_text="eg. 553199851212")
destination = ChoiceField(choices=[])
text = CharField(
label="Text",
max_length=100,
widget=Textarea(attrs={"rows": 4, "cols": 15}),
)
connector = ModelChoiceField(queryset=Connector.objects.all())


class NewConnectorForm(ModelForm):
def __init__(self, *args, **kwargs):
server = kwargs.pop("server")
Expand Down
56 changes: 54 additions & 2 deletions rocket_connect/instance/models.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import datetime
import json
import uuid

import requests
from django.apps import apps
from django.conf import settings
from django.db import models
from django.utils import timezone
from django_celery_beat.models import CrontabSchedule, PeriodicTask
from envelope.models import Message
from rocketchat_API.APIExceptions.RocketExceptions import RocketAuthenticationException
from rocketchat_API.rocketchat import RocketChat

Expand Down Expand Up @@ -145,6 +148,18 @@ def room_sync(self, execute=False):
response["executed"] = close_room_response
return response

def delete_delivered_messages(self, age=None, execute=False):
if age and type(age) == int:
now = timezone.now()
target_date = now - datetime.timedelta(days=age)
messages = Message.objects.filter(
room__connector__server=self, delivered=True, created__lte=target_date
)
if execute:
return messages.delete()
else:
return messages

def force_delivery(self):
"""
this method will force the intake of every undelivered message
Expand Down Expand Up @@ -195,10 +210,16 @@ def install_server_tasks(self):
crontab = CrontabSchedule.objects.first()
task = PeriodicTask.objects.create(
enabled=False,
name=f"General Maintenance for {self.name} (ID {self.id})",
name=f"General Maintenance for {self.name} (ID {self.id})."
+ "Sync rooms and Remove delivered messages (Age in days).",
crontab=crontab,
task="instance.tasks.server_maintenance",
kwargs=json.dumps({"server_token": self.external_token}),
kwargs=json.dumps(
{
"server_token": self.external_token,
"delete_delivered_messages_age": 15,
}
),
)
self.tasks.add(task)
added_tasks.append(task)
Expand Down Expand Up @@ -333,6 +354,37 @@ def install_server_tasks(self):
)
self.tasks.add(task)
added_tasks.append(task)
#
# T7 manage_abandoned_chats
#
task = PeriodicTask.objects.filter(
task="instance.tasks.manage_abandoned_chats",
kwargs__contains=self.external_token,
)
if not task.exists():
crontab = CrontabSchedule.objects.first()
task = PeriodicTask.objects.create(
enabled=False,
name=f"Manage Abandoned Calls for {self.name} (ID {self.id})",
description="""This task can transfer to department or agent"""
+ """, close or just alert the user on abandoned chats""",
crontab=crontab,
task="instance.tasks.manage_abandoned_chats",
kwargs=json.dumps(
{
"server_token": self.external_token,
"excluded_departments": [],
"message_template": "This chat is abandoned",
"last_message_seconds": 10,
"last_message_users": "*",
"action": "transfer|close|alert",
"target_department_id": None,
"target_agent_user_id": None,
}
),
)
self.tasks.add(task)
added_tasks.append(task)
# return added tasks
return added_tasks

Expand Down
91 changes: 90 additions & 1 deletion rocket_connect/instance/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,19 @@ def intake_unread_messages(connector_id):
retry_kwargs={"max_retries": 7, "countdown": 5},
autoretry_for=(requests.ConnectionError,),
)
def server_maintenance(server_token):
def server_maintenance(server_token, delete_delivered_messages_age=None):
"""do all sorts of server maintenance"""
server = Server.objects.get(external_token=server_token)
response = {}
# sync room
response["room_sync"] = server.room_sync(execute=True)
# delete delivered messages
if delete_delivered_messages_age:
response["delete_delivered_messages"] = server.delete_delivered_messages(
age=delete_delivered_messages_age, execute=True
)
# return results

return response


Expand Down Expand Up @@ -248,3 +254,86 @@ def alert_undelivered_messages(

responses = {"targets": targets, "sent_messages": sent_messages}
return responses


# T7
@celery_app.task(retry_kwargs={"max_retries": 7, "countdown": 5})
def manage_abandoned_chats(
server_token,
excluded_departments,
message_template,
last_message_seconds,
last_message_users,
action="close",
target_department_id=None,
target_agent_user_id=None,
):
# get server
server = Server.objects.get(external_token=server_token)
# get rocket
rocket = server.get_rocket_client()
# list all open messages
open_rooms = server.get_open_rooms()
# create returns
output = {"action": action, "rooms": []}

if open_rooms:
for room in open_rooms.get("rooms"):
# do not close for configured rooms
if room.get("departmentId") not in excluded_departments:
if room.get("lastMessage", False):
# get last message
last_message = room["lastMessage"]
# define last message users or all
if (
last_message["u"]["username"] in last_message_users
or last_message_users == "*"
):
ts = dateutil.parser.parse(last_message["ts"])
now = timezone.now()
delta = now - ts
if delta.total_seconds() >= last_message_seconds:
if message_template:
rocket.chat_post_message(
room_id=room["_id"], text=message_template
).json()
if action == "close":
# close messages on this situation
room_close_options = {
"rid": room["_id"],
"token": room["v"]["token"],
}
close = rocket.call_api_post(
"livechat/room.close", **room_close_options
)
output["rooms"].append(close.json())
elif action == "transfer":
if target_department_id and not target_agent_user_id:
# transfer messages on this situation to department
room_transfer_options = {
"rid": room["_id"],
"token": room["v"]["token"],
"department": target_department_id,
}
transfer = rocket.call_api_post(
"livechat/room.transfer",
**room_transfer_options
)
output["rooms"].append(transfer.json())
if target_agent_user_id and not target_department_id:
# forward messages on this situation to agent
room_transfer_options = {
"roomId": room["_id"],
"userId": target_agent_user_id,
}
transfer = rocket.call_api_post(
"livechat/room.forward", **room_transfer_options
)
output["rooms"].append(
{
"room_id": room["_id"],
"response": transfer.json(),
}
)

return output
6 changes: 6 additions & 0 deletions rocket_connect/instance/urls.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.urls import re_path

from rocket_connect.instance.views import (
active_chat,
connector_analyze,
new_connector,
new_server,
Expand All @@ -18,6 +19,11 @@
re_path(
r"^server/(?P<server_id>\w+)/?$", view=server_detail_view, name="server_detail"
),
re_path(
r"^server/(?P<server_id>\w+)/active-chat/?$",
view=active_chat,
name="active_chat",
),
re_path(
r"^server/(?P<server_id>\w+)/analyze/(?P<connector_id>\w+)/?$",
view=connector_analyze,
Expand Down
47 changes: 47 additions & 0 deletions rocket_connect/instance/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
from instance.forms import NewConnectorForm, NewServerForm
from instance.models import Connector, Server

from .forms import NewInboundForm


@csrf_exempt
def connector_endpoint(request, connector_id):
Expand Down Expand Up @@ -136,11 +138,44 @@ def server_messages_endpoint(request, server_id):
return JsonResponse(list(messages), safe=False)


@login_required(login_url="/accounts/login/")
@must_be_yours
def active_chat(request, server_id):
server = get_object_or_404(Server.objects, external_token=server_id)
form = NewInboundForm(request.POST or None)
# get online agents and departments
rocket = server.get_rocket_client()
departments_raw = rocket.call_api_get("livechat/department").json()
departments_choice = [
("@" + d["name"], "Department: " + d["name"])
for d in departments_raw["departments"]
]
destinations = departments_choice
# now get online agents
agents = rocket.livechat_get_users(user_type="agent").json()
available_agents = [
agent["username"]
for agent in agents["users"]
if agent["status"] == "online" and agent["statusLivechat"] == "available"
]
print(available_agents)
for agent in available_agents:
destinations.append(("@" + agent, "Agent: " + agent))
connectors = server.connectors.filter(enabled=True)
form.fields["connector"].queryset = connectors
form.fields["destination"].choices = destinations
if form.is_valid():
pass
context = {"server": server, "form": form}
return render(request, "instance/active_chat.html", context)


@login_required(login_url="/accounts/login/")
@must_be_yours
def server_detail_view(request, server_id):
server = get_object_or_404(Server.objects, external_token=server_id)
room_sync = None
delivered_messages_to_delete = None
# get server status
status = server.status()
if request.GET.get("force_connector_delivery"):
Expand Down Expand Up @@ -176,6 +211,17 @@ def server_detail_view(request, server_id):
messages.success(request, "Sync Executed!")
room_sync = server.room_sync()

if request.GET.get("delete-delivered-messages"):
if request.GET.get("do-delete-delivered-messages"):
delivered_messages_to_delete = server.delete_delivered_messages(
age=10, execute=True
)
messages.success(
request, f"Delivered messages deleted: {delivered_messages_to_delete}"
)
else:
delivered_messages_to_delete = server.delete_delivered_messages(age=10)

if request.GET.get("install-default-tasks"):
added_tasks = server.install_server_tasks()
for added_task in added_tasks:
Expand Down Expand Up @@ -221,6 +267,7 @@ def server_detail_view(request, server_id):
"connectors": connectors,
"status": status,
"room_sync": room_sync,
"delivered_messages_to_delete": delivered_messages_to_delete,
"tasks": tasks,
}
return render(request, "instance/server_detail_view.html", context)
Expand Down
Loading

0 comments on commit 053d958

Please sign in to comment.