chg: [chats] improve UI + fix importer

This commit is contained in:
terrtia 2023-11-06 14:08:23 +01:00
parent 9125119764
commit 789210bcba
No known key found for this signature in database
GPG key ID: 1E1B1F50D84613D0
8 changed files with 179 additions and 43 deletions

View file

@ -265,6 +265,11 @@ def get_subchannels_meta_from_global_id(subchannels):
meta.append(subchannel.get_meta({'nb_messages'})) meta.append(subchannel.get_meta({'nb_messages'}))
return meta return meta
def get_chat_meta_from_global_id(chat_global_id):
_, instance_uuid, chat_id = chat_global_id.split(':', 2)
chat = Chats.Chat(chat_id, instance_uuid)
return chat.get_meta()
def api_get_chat_service_instance(chat_instance_uuid): def api_get_chat_service_instance(chat_instance_uuid):
chat_instance = ChatServiceInstance(chat_instance_uuid) chat_instance = ChatServiceInstance(chat_instance_uuid)
if not chat_instance.exists(): if not chat_instance.exists():
@ -277,15 +282,18 @@ def api_get_chat(chat_id, chat_instance_uuid):
return {"status": "error", "reason": "Unknown chat"}, 404 return {"status": "error", "reason": "Unknown chat"}, 404
meta = chat.get_meta({'img', 'subchannels', 'username'}) meta = chat.get_meta({'img', 'subchannels', 'username'})
if meta['subchannels']: if meta['subchannels']:
print(meta['subchannels'])
meta['subchannels'] = get_subchannels_meta_from_global_id(meta['subchannels']) meta['subchannels'] = get_subchannels_meta_from_global_id(meta['subchannels'])
else:
meta['messages'], meta['tags_messages'] = chat.get_messages()
return meta, 200 return meta, 200
def api_get_subchannel(chat_id, chat_instance_uuid): def api_get_subchannel(chat_id, chat_instance_uuid):
subchannel = ChatSubChannels.ChatSubChannel(chat_id, chat_instance_uuid) subchannel = ChatSubChannels.ChatSubChannel(chat_id, chat_instance_uuid)
if not subchannel.exists(): if not subchannel.exists():
return {"status": "error", "reason": "Unknown chat"}, 404 return {"status": "error", "reason": "Unknown chat"}, 404
meta = subchannel.get_meta({'img', 'nb_messages'}) meta = subchannel.get_meta({'chat', 'img', 'nb_messages'})
if meta['chat']:
meta['chat'] = get_chat_meta_from_global_id(meta['chat'])
meta['messages'], meta['tags_messages'] = subchannel.get_messages() meta['messages'], meta['tags_messages'] = subchannel.get_messages()
return meta, 200 return meta, 200

View file

@ -80,8 +80,10 @@ class ChatSubChannel(AbstractChatObject):
meta = self._get_meta(options=options) meta = self._get_meta(options=options)
meta['tags'] = self.get_tags(r_list=True) meta['tags'] = self.get_tags(r_list=True)
meta['name'] = self.get_name() meta['name'] = self.get_name()
if 'chat' in options:
meta['chat'] = self.get_chat()
if 'img' in options: if 'img' in options:
meta['sub'] = self.get_img() meta['img'] = self.get_img()
if 'nb_messages': if 'nb_messages':
meta['nb_messages'] = self.get_nb_messages() meta['nb_messages'] = self.get_nb_messages()
return meta return meta

View file

@ -63,6 +63,7 @@ class AbstractChatObject(AbstractSubtypeObject, ABC):
def get_chat(self): # require ail object TODO ## def get_chat(self): # require ail object TODO ##
if self.type != 'chat': if self.type != 'chat':
parent = self.get_parent() parent = self.get_parent()
if parent:
obj_type, _ = parent.split(':', 1) obj_type, _ = parent.split(':', 1)
if obj_type == 'chat': if obj_type == 'chat':
return parent return parent
@ -70,9 +71,7 @@ class AbstractChatObject(AbstractSubtypeObject, ABC):
def get_subchannels(self): def get_subchannels(self):
subchannels = [] subchannels = []
if self.type == 'chat': # category ??? if self.type == 'chat': # category ???
print(self.get_childrens())
for obj_global_id in self.get_childrens(): for obj_global_id in self.get_childrens():
print(obj_global_id)
obj_type, _ = obj_global_id.split(':', 1) obj_type, _ = obj_global_id.split(':', 1)
if obj_type == 'chat-subchannel': if obj_type == 'chat-subchannel':
subchannels.append(obj_global_id) subchannels.append(obj_global_id)
@ -125,12 +124,11 @@ class AbstractChatObject(AbstractSubtypeObject, ABC):
def get_message_meta(self, message, parent=True, mess_datetime=None): # TODO handle file message def get_message_meta(self, message, parent=True, mess_datetime=None): # TODO handle file message
obj = Message(message[9:]) obj = Message(message[9:])
mess_dict = obj.get_meta(options={'content', 'link', 'parent', 'user-account'}) mess_dict = obj.get_meta(options={'content', 'link', 'parent', 'user-account'})
print(mess_dict) # print(mess_dict)
if mess_dict.get('parent') and parent: if mess_dict.get('parent') and parent:
mess_dict['reply_to'] = self.get_message_meta(mess_dict['parent'], parent=False) mess_dict['reply_to'] = self.get_message_meta(mess_dict['parent'], parent=False)
if mess_dict.get('user-account'): if mess_dict.get('user-account'):
_, user_account_subtype, user_account_id = mess_dict['user-account'].split(':', 3) _, user_account_subtype, user_account_id = mess_dict['user-account'].split(':', 3)
print(mess_dict['user-account'])
user_account = UserAccount(user_account_id, user_account_subtype) user_account = UserAccount(user_account_id, user_account_subtype)
mess_dict['user-account'] = {} mess_dict['user-account'] = {}
mess_dict['user-account']['type'] = user_account.get_type() mess_dict['user-account']['type'] = user_account.get_type()
@ -224,8 +222,6 @@ class AbstractChatObjects(ABC):
return r_object.zcard(f'{self.type}_all:{subtype}') return r_object.zcard(f'{self.type}_all:{subtype}')
def get_ids_by_subtype(self, subtype): def get_ids_by_subtype(self, subtype):
print(subtype)
print(f'{self.type}_all:{subtype}')
return r_object.zrange(f'{self.type}_all:{subtype}', 0, -1) return r_object.zrange(f'{self.type}_all:{subtype}', 0, -1)
def get_all_id_iterator_iter(self, subtype): def get_all_id_iterator_iter(self, subtype):

View file

@ -298,6 +298,7 @@ class AbstractObject(ABC):
obj_subtype = '' obj_subtype = ''
obj_global_id = f'{obj_type}:{obj_subtype}:{obj_id}' obj_global_id = f'{obj_type}:{obj_subtype}:{obj_id}'
r_object.hset(f'meta:{self.type}:{self.get_subtype(r_str=True)}:{self.id}', 'parent', obj_global_id) r_object.hset(f'meta:{self.type}:{self.get_subtype(r_str=True)}:{self.id}', 'parent', obj_global_id)
r_object.sadd(f'child:{obj_global_id}', self.get_global_id())
def add_children(self, obj_type=None, obj_subtype=None, obj_id=None, obj_global_id=None): # TODO # REMOVE ITEM DUP def add_children(self, obj_type=None, obj_subtype=None, obj_id=None, obj_global_id=None): # TODO # REMOVE ITEM DUP
if not obj_global_id: if not obj_global_id:
@ -305,6 +306,7 @@ class AbstractObject(ABC):
obj_subtype = '' obj_subtype = ''
obj_global_id = f'{obj_type}:{obj_subtype}:{obj_id}' obj_global_id = f'{obj_type}:{obj_subtype}:{obj_id}'
r_object.sadd(f'child:{self.type}:{self.get_subtype(r_str=True)}:{self.id}', obj_global_id) r_object.sadd(f'child:{self.type}:{self.get_subtype(r_str=True)}:{self.id}', obj_global_id)
r_object.hset(f'meta:{obj_global_id}', 'parent', self.get_global_id())
## others objects ## ## others objects ##
def add_obj_children(self, parent_global_id, son_global_id): def add_obj_children(self, parent_global_id, son_global_id):

View file

@ -80,7 +80,7 @@ def chats_explorer_chat():
return create_json_response(chat[0], chat[1]) return create_json_response(chat[0], chat[1])
else: else:
chat = chat[0] chat = chat[0]
return render_template('chat_viewer.html', chat=chat) return render_template('chat_viewer.html', chat=chat, bootstrap_label=bootstrap_label)
@chats_explorer.route("/chats/explorer/subchannel", methods=['GET']) @chats_explorer.route("/chats/explorer/subchannel", methods=['GET'])
@login_required @login_required
@ -95,18 +95,6 @@ def objects_subchannel_messages():
subchannel = subchannel[0] subchannel = subchannel[0]
return render_template('SubChannelMessages.html', subchannel=subchannel) return render_template('SubChannelMessages.html', subchannel=subchannel)
@chats_explorer.route("/chats/explorer/subchannel", methods=['GET'])
@login_required
@login_read_only
def objects_message():
message_id = request.args.get('id')
message = chats_viewer.api_get_message(message_id)
if message[1] != 200:
return create_json_response(message[0], message[1])
else:
message = message[0]
return render_template('ChatMessage.html', message=message)
############################################################################################# #############################################################################################
############################################################################################# #############################################################################################
############################################################################################# #############################################################################################

View file

@ -32,6 +32,13 @@
flex-direction: row-reverse; flex-direction: row-reverse;
margin-left: auto margin-left: auto
} }
.divider:after,
.divider:before {
content: "";
flex: 1;
height: 2px;
background: #eee;
}
</style> </style>
</head> </head>
<body> <body>
@ -47,7 +54,7 @@
<div class="card my-3"> <div class="card my-3">
<div class="card-header" style="background-color:#d9edf7;font-size: 15px"> <div class="card-header" style="background-color:#d9edf7;font-size: 15px">
<h3 class="text-secondary">{{ subchannel["id"] }} :</h3> <h3 class="text-secondary">{% if subchannel['chat']['name'] %}{{ subchannel['chat']['name'] }} {% else %} {{ subchannel['chat']['id'] }}{% endif %} - {% if subchannel['username'] %}{{ subchannel["username"] }} {% else %} {{ subchannel['name'] }}{% endif %} :</h3> {{ subchannel["id"] }}
<ul class="list-group mb-2"> <ul class="list-group mb-2">
<li class="list-group-item py-0"> <li class="list-group-item py-0">
<div class="row"> <div class="row">
@ -55,7 +62,8 @@
<table class="table"> <table class="table">
<thead> <thead>
<tr> <tr>
<th>Chat Instance</th> <th>Name</th>
{# <th>Chat Instance</th>#}
<th>First seen</th> <th>First seen</th>
<th>Last seen</th> <th>Last seen</th>
<th>Username</th> <th>Username</th>
@ -65,10 +73,19 @@
<tbody> <tbody>
<tr> <tr>
<td> <td>
{{ subchannel["subtype"] }} {# {{ subchannel["subtype"] }}#}
{{ subchannel['name'] }}
</td>
<td>
{% if subchannel['first_seen'] %}
{{ subchannel['first_seen'][0:4] }}-{{ subchannel['first_seen'][4:6] }}-{{ subchannel['first_seen'][6:8] }}
{% endif %}
</td>
<td>
{% if subchannel['last_seen'] %}
{{ subchannel['last_seen'][0:4] }}-{{ subchannel['last_seen'][4:6] }}-{{ subchannel['last_seen'][6:8] }}
{% endif %}
</td> </td>
<td>{{ subchannel['first_seen'] }}</td>
<td>{{ subchannel['last_seen'] }}</td>
<td> <td>
{% if 'username' in subchannel %} {% if 'username' in subchannel %}
{{ subchannel['username'] }} {{ subchannel['username'] }}
@ -108,8 +125,8 @@
</div> </div>
</div> </div>
{% for tag in mess_tags %} {% for tag in subchannel['tags_messages'] %}
<span class="badge badge-{{ bootstrap_label[loop.index0 % 5] }}">{{ tag }} <span class="badge badge-light">{{ mess_tags[tag] }}</span></span> <span class="badge badge-{{ bootstrap_label[loop.index0 % 5] }}">{{ tag }} <span class="badge badge-light">{{ subchannel['tags_messages'][tag] }}</span></span>
{% endfor %} {% endfor %}
<div> <div>
@ -121,10 +138,16 @@
</div> </div>
<div class="position-relative"> <div class="position-relative">
<div class="chat-messages p-4"> <div class="chat-messages p-2">
{% for date in subchannel['messages'] %} {% for date in subchannel['messages'] %}
<h2 id="date_section_{{ date }}"><span class="badge badge-secondary mb-2">{{ date }}</span></h2>
<div class="divider d-flex align-items-center mb-4">
<p class="text-center h2 mx-3 mb-0" style="color: #a2aab7;">
<span class="badge badge-secondary mb-2" id="date_section_{{ date }}">{{ date }}</span>
</p>
</div>
{% for mess in subchannel['messages'][date] %} {% for mess in subchannel['messages'][date] %}
<div class="chat-message-left pb-1"> <div class="chat-message-left pb-1">

View file

@ -75,11 +75,21 @@
<tbody style="font-size: 15px;"> <tbody style="font-size: 15px;">
{% for chat in chat_instance["chats"] %} {% for chat in chat_instance["chats"] %}
<tr> <tr>
<td></td> <td>
<img src="{{ url_for('static', filename='image/ail-icon.png') }}" class="rounded-circle mr-1" alt="{{ chat['id'] }}" width="40" height="40">
</td>
<td>{{ chat['name'] }}</td> <td>{{ chat['name'] }}</td>
<td><a href="{{ url_for('chats_explorer.chats_explorer_chat') }}?uuid={{ chat_instance['uuid'] }}&id={{ chat['id'] }}">{{ chat['id'] }}</a></td> <td><a href="{{ url_for('chats_explorer.chats_explorer_chat') }}?uuid={{ chat_instance['uuid'] }}&id={{ chat['id'] }}">{{ chat['id'] }}</a></td>
<td>{{ chat['first_seen'] }}</td> <td>
<td>{{ chat['last_seen'] }}</td> {% if chat['first_seen'] %}
{{ chat['first_seen'][0:4] }}-{{ chat['first_seen'][4:6] }}-{{ chat['first_seen'][6:8] }}
{% endif %}
</td>
<td>
{% if chat['last_seen'] %}
{{ chat['last_seen'][0:4] }}-{{ chat['last_seen'][4:6] }}-{{ chat['last_seen'][6:8] }}
{% endif %}
</td>
<td>{{ chat['nb_subchannels'] }}</td> <td>{{ chat['nb_subchannels'] }}</td>
</tr> </tr>
{% endfor %} {% endfor %}

View file

@ -17,6 +17,25 @@
<script src="{{ url_for('static', filename='js/jquery.dataTables.min.js')}}"></script> <script src="{{ url_for('static', filename='js/jquery.dataTables.min.js')}}"></script>
<script src="{{ url_for('static', filename='js/dataTables.bootstrap.min.js')}}"></script> <script src="{{ url_for('static', filename='js/dataTables.bootstrap.min.js')}}"></script>
<style>
.chat-message-left,
.chat-message-right {
display: flex;
flex-shrink: 0;
}
.chat-message-right {
flex-direction: row-reverse;
margin-left: auto
}
.divider:after,
.divider:before {
content: "";
flex: 1;
height: 2px;
background: #eee;
}
</style>
</head> </head>
<body> <body>
@ -32,11 +51,11 @@
<div class="card my-3"> <div class="card my-3">
<div class="card-header" style="background-color:#d9edf7;font-size: 15px"> <div class="card-header" style="background-color:#d9edf7;font-size: 15px">
<h4 class="text-secondary">{{ chat["username"] }} {{ chat["id"] }} :</h4> <h4 class="text-secondary">{% if chat['username'] %}{{ chat["username"] }} {% else %} {{ chat['name'] }}{% endif %} :</h4> {{ chat["id"] }}
<ul class="list-group mb-2"> <ul class="list-group mb-2">
<li class="list-group-item py-0"> <li class="list-group-item py-0">
<table class="table"> <table class="table">
<thead class="bg-dark text-white"> <thead class="">
<tr> <tr>
<th>Icon</th> <th>Icon</th>
<th>Name</th> <th>Name</th>
@ -51,8 +70,16 @@
<td></td> <td></td>
<td>{{ chat['name'] }}</td> <td>{{ chat['name'] }}</td>
<td>{{ chat['id'] }}</td> <td>{{ chat['id'] }}</td>
<td>{{ chat['first_seen'] }}</td> <td>
<td>{{ chat['last_seen'] }}</td> {% if chat['first_seen'] %}
{{ chat['first_seen'][0:4] }}-{{ chat['first_seen'][4:6] }}-{{ chat['first_seen'][6:8] }}
{% endif %}
</td>
<td>
{% if chat['last_seen'] %}
{{ chat['last_seen'][0:4] }}-{{ chat['last_seen'][4:6] }}-{{ chat['last_seen'][6:8] }}
{% endif %}
</td>
<td>{{ chat['nb_subchannels'] }}</td> <td>{{ chat['nb_subchannels'] }}</td>
</tr> </tr>
</tbody> </tbody>
@ -63,6 +90,10 @@
</div> </div>
</div> </div>
{% for tag in chat['tags_messages'] %}
<span class="badge badge-{{ bootstrap_label[loop.index0 % 5] }}">{{ tag }} <span class="badge badge-light">{{ chat['tags_messages'][tag] }}</span></span>
{% endfor %}
{% if chat['subchannels'] %} {% if chat['subchannels'] %}
<h4>Sub-Channels:</h4> <h4>Sub-Channels:</h4>
<table id="tablesubchannels" class="table"> <table id="tablesubchannels" class="table">
@ -84,8 +115,16 @@
</td> </td>
<td><b>{{ meta['name'] }}</b></td> <td><b>{{ meta['name'] }}</b></td>
<td><a href="{{ url_for('chats_explorer.objects_subchannel_messages') }}?uuid={{ meta['subtype'] }}&id={{ meta['id'] }}">{{ meta['id'] }}</a></td> <td><a href="{{ url_for('chats_explorer.objects_subchannel_messages') }}?uuid={{ meta['subtype'] }}&id={{ meta['id'] }}">{{ meta['id'] }}</a></td>
<td>{{ meta['first_seen'] }}</td> <td>
<td>{{ meta['last_seen'] }}</td> {% if meta['first_seen'] %}
{{ meta['first_seen'][0:4] }}-{{ meta['first_seen'][4:6] }}-{{ meta['first_seen'][6:8] }}
{% endif %}
</td>
<td>
{% if meta['last_seen'] %}
{{ meta['last_seen'][0:4] }}-{{ meta['last_seen'][4:6] }}-{{ meta['last_seen'][6:8] }}
{% endif %}
</td>
<td>{{ meta['nb_messages'] }}</td> <td>{{ meta['nb_messages'] }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
@ -94,6 +133,74 @@
{% endif %} {% endif %}
{% if chat['messages'] %}
<div class="position-relative">
<div class="chat-messages p-2">
{% for date in chat['messages'] %}
<div class="divider d-flex align-items-center mb-4">
<p class="text-center h2 mx-3 mb-0" style="color: #a2aab7;">
<span class="badge badge-secondary mb-2" id="date_section_{{ date }}">{{ date }}</span>
</p>
</div>
{% for mess in chat['messages'][date] %}
<div class="chat-message-left pb-1">
<div>
<img src="{{ url_for('static', filename='image/ail-icon.png') }}" class="rounded-circle mr-1" alt="{{ mess['user-account']['id'] }}" width="40" height="40">
<div class="text-muted small text-nowrap mt-2">{{ mess['hour'] }}</div>
</div>
<div class="flex-shrink-1 bg-light rounded py-2 px-3 ml-4 pb-4" style="overflow-x: auto">
<div class="font-weight-bold mb-1">
{% if mess['user-account']['username'] %}
{{ mess['user-account']['username']['id'] }}
{% else %}
{{ mess['user-account']['id'] }}
{% endif %}
</div>
{% if mess['reply_to'] %}
<div class="flex-shrink-1 border rounded py-2 px-3 ml-4 mb-3" style="overflow-x: auto">
<div class="font-weight-bold mb-1">
{% if mess['reply_to']['user-account']['username'] %}
{{ mess['reply_to']['user-account']['username']['id'] }}
{% else %}
{{ mess['reply_to']['user-account']['id'] }}
{% endif %}
</div>
<pre class="my-0">{{ mess['reply_to']['content'] }}</pre>
{% for tag in mess['reply_to']['tags'] %}
<span class="badge badge-{{ bootstrap_label[loop.index0 % 5] }}">{{ tag }}</span>
{% endfor %}
<div class="text-muted small text-nowrap">{{ mess['reply_to']['date'] }}</div>
{# <div class="">#}
{# <a class="btn btn-light btn-sm text-secondary py-0" href="{{ url_for('correlation.show_correlation')}}?type={{ mess['reply_to']['type'] }}&subtype={{ mess['reply_to']['subtype'] }}&id={{ mess['reply_to']['id'] }}"><i class="fas fa-project-diagram"></i></a>#}
{# <a class="btn btn-light btn-sm text-secondary py-0" href="{{ mess['reply_to']['link'] }}"><i class="fas fa-eye"></i></a>#}
{# </div>#}
</div>
{% endif %}
<pre class="my-0">{{ mess['content'] }}</pre>
{% for tag in mess['tags'] %}
<span class="badge badge-{{ bootstrap_label[loop.index0 % 5] }}">{{ tag }}</span>
{% endfor %}
<div class="">
<a class="btn btn-light btn-sm text-secondary px-1" href="{{ url_for('correlation.show_correlation')}}?type={{ mess['type'] }}&subtype={{ mess['subtype'] }}&id={{ mess['id'] }}"><i class="fas fa-project-diagram"></i></a>
<a class="btn btn-light btn-sm text-secondary px-1" href="{{ mess['link'] }}"><i class="fas fa-eye"></i></a>
</div>
</div>
</div>
{% endfor %}
<br>
{% endfor %}
</div>
</div>
{% endif %}
</div> </div>
</div> </div>