chg: [chat explorer] show message, open message in chat/subchannel/thread
Some checks are pending
CI / ail_test (3.9) (push) Waiting to run
CI / ail_test (3.10) (push) Waiting to run
CI / ail_test (3.7) (push) Waiting to run
CI / ail_test (3.8) (push) Waiting to run

This commit is contained in:
terrtia 2025-01-13 15:25:04 +01:00
parent afd0d6b7d8
commit aecf71d5a3
No known key found for this signature in database
GPG key ID: 1E1B1F50D84613D0
11 changed files with 96 additions and 31 deletions

View file

@ -786,7 +786,7 @@ def api_get_chats_selector():
selector.append({'id': chat.get_global_id(), 'name': f'{chat.get_chat_instance()}: {chat.get_label()}'})
return selector
def api_get_chat(chat_id, chat_instance_uuid, translation_target=None, nb=-1, page=-1, messages=True, heatmap=False):
def api_get_chat(chat_id, chat_instance_uuid, translation_target=None, nb=-1, page=-1, messages=True, message=None, heatmap=False):
chat = Chats.Chat(chat_id, chat_instance_uuid)
if not chat.exists():
return {"status": "error", "reason": "Unknown chat"}, 404
@ -800,7 +800,7 @@ def api_get_chat(chat_id, chat_instance_uuid, translation_target=None, nb=-1, pa
if translation_target not in Language.get_translation_languages():
translation_target = None
if messages:
meta['messages'], meta['pagination'], meta['tags_messages'] = chat.get_messages(translation_target=translation_target, nb=nb, page=page)
meta['messages'], meta['pagination'], meta['tags_messages'] = chat.get_messages(translation_target=translation_target, message=message, nb=nb, page=page)
meta['messages'] = get_chat_object_messages_meta(meta['messages'])
if heatmap:
meta['years'] = chat.get_message_years()
@ -849,7 +849,7 @@ def api_get_chat_participants(chat_type, chat_subtype, chat_id):
meta['participants'] = chat_participants
return meta, 200
def api_get_subchannel(chat_id, chat_instance_uuid, translation_target=None, nb=-1, page=-1):
def api_get_subchannel(chat_id, chat_instance_uuid, translation_target=None, message=None, nb=-1, page=-1):
subchannel = ChatSubChannels.ChatSubChannel(chat_id, chat_instance_uuid)
if not subchannel.exists():
return {"status": "error", "reason": "Unknown subchannel"}, 404
@ -861,11 +861,11 @@ def api_get_subchannel(chat_id, chat_instance_uuid, translation_target=None, nb=
meta['threads'] = get_threads_metas(meta['threads'])
if meta.get('username'):
meta['username'] = get_username_meta_from_global_id(meta['username'])
meta['messages'], meta['pagination'], meta['tags_messages'] = subchannel.get_messages(translation_target=translation_target, nb=nb, page=page)
meta['messages'], meta['pagination'], meta['tags_messages'] = subchannel.get_messages(translation_target=translation_target, message=message, nb=nb, page=page)
meta['messages'] = get_chat_object_messages_meta(meta['messages'])
return meta, 200
def api_get_thread(thread_id, thread_instance_uuid, translation_target=None, nb=-1, page=-1):
def api_get_thread(thread_id, thread_instance_uuid, translation_target=None, message=None, nb=-1, page=-1):
thread = ChatThreads.ChatThread(thread_id, thread_instance_uuid)
if not thread.exists():
return {"status": "error", "reason": "Unknown thread"}, 404
@ -873,7 +873,7 @@ def api_get_thread(thread_id, thread_instance_uuid, translation_target=None, nb=
meta = thread.get_meta({'chat', 'nb_messages', 'nb_participants'})
# if meta['chat']:
# meta['chat'] = get_chat_meta_from_global_id(meta['chat'])
meta['messages'], meta['pagination'], meta['tags_messages'] = thread.get_messages(translation_target=translation_target, nb=nb, page=page)
meta['messages'], meta['pagination'], meta['tags_messages'] = thread.get_messages(translation_target=translation_target, message=message, nb=nb, page=page)
meta['messages'] = get_chat_object_messages_meta(meta['messages'])
return meta, 200
@ -881,7 +881,7 @@ def api_get_message(message_id, translation_target=None):
message = Messages.Message(message_id)
if not message.exists():
return {"status": "error", "reason": "Unknown uuid"}, 404
meta = message.get_meta({'barcodes', 'chat', 'content', 'files-names', 'forwarded_from', 'icon', 'images', 'language', 'link', 'parent', 'parent_meta', 'qrcodes', 'reactions', 'thread', 'translation', 'user-account'}, translation_target=translation_target)
meta = message.get_meta({'barcodes', 'chat', 'container', 'content', 'files-names', 'forwarded_from', 'icon', 'images', 'language', 'link', 'parent', 'parent_meta', 'qrcodes', 'reactions', 'thread', 'translation', 'user-account'}, translation_target=translation_target)
if 'forwarded_from' in meta:
chat = get_obj_chat_from_global_id(meta['forwarded_from'])
meta['forwarded_from'] = chat.get_meta({'icon'})

View file

@ -55,9 +55,9 @@ class ChatSubChannel(AbstractChatObject):
def get_link(self, flask_context=False):
if flask_context:
url = url_for('correlation.show_correlation', type=self.type, subtype=self.subtype, id=self.id)
url = url_for('chats_explorer.objects_subchannel_messages', subtype=self.subtype, id=self.id)
else:
url = f'{baseurl}/correlation/show?type={self.type}&subtype={self.subtype}&id={self.id}'
url = f'{baseurl}/chats/explorer/subchannel?subtype={self.subtype}&id={self.id}'
return url
def get_svg_icon(self): # TODO

View file

@ -49,9 +49,9 @@ class ChatThread(AbstractChatObject):
def get_link(self, flask_context=False):
if flask_context:
url = url_for('correlation.show_correlation', type=self.type, subtype=self.subtype, id=self.id)
url = url_for('chats_explorer.objects_thread_messages', subtype=self.subtype, id=self.id)
else:
url = f'{baseurl}/correlation/show?type={self.type}&subtype={self.subtype}&id={self.id}'
url = f'{baseurl}/chats/explorer/thread?subtype={self.subtype}&id={self.id}'
return url
def get_svg_icon(self): # TODO

View file

@ -50,7 +50,7 @@ class Chat(AbstractChatObject):
if flask_context:
url = url_for('chats_explorer.chats_explorer_chat', subtype=self.subtype, id=self.id)
else:
url = f'{baseurl}/correlation/show?type={self.type}&subtype={self.subtype}&id={self.id}'
url = f'{baseurl}/chats/explorer/chat?subtype={self.subtype}&id={self.id}'
return url
def get_origin_link(self):

View file

@ -265,6 +265,8 @@ class Message(AbstractObject):
if options is None:
options = set()
meta = self.get_default_meta(tags=True)
# original_id
meta['_id'] = self.id.rsplit('/', 1)[-1]
# timestamp
if not timestamp:
@ -304,6 +306,8 @@ class Message(AbstractObject):
meta['user-account'] = self.get_user_account(meta=True)
if not meta['user-account']:
meta['user-account'] = {'id': 'UNKNOWN'}
if 'container' in options:
meta['container'] = self.get_container()
if 'chat' in options:
meta['chat'] = self.get_chat_id()
if 'thread' in options:
@ -345,7 +349,16 @@ class Message(AbstractObject):
## Language ##
def get_root_obj(self):
return self.get_objs_container(root=True)
return self.get_objs_container(root=True).pop()
def get_container(self):
thread = self.get_current_thread()
if thread:
return thread
subchannel = self.get_subchannel()
if subchannel:
return subchannel
return self.get_chat()
def get_objs_container(self, root=False):
objs_containers = set()

View file

@ -128,6 +128,12 @@ class AbstractChatObject(AbstractSubtypeObject, ABC):
def get_nb_messages(self):
return r_object.zcard(f'messages:{self.type}:{self.subtype}:{self.id}')
def get_message_page(self, message, nb):
rank = r_object.zrank(f'messages:{self.type}:{self.subtype}:{self.id}', f'message::{message}')
if not rank:
return -1
return int(rank/ nb) + 1
def _get_messages(self, nb=-1, page=-1):
if nb < 1:
messages = r_object.zrange(f'messages:{self.type}:{self.subtype}:{self.id}', 0, -1, withscores=True)
@ -273,7 +279,7 @@ class AbstractChatObject(AbstractSubtypeObject, ABC):
meta = message.get_meta(options=options, timestamp=timestamp, translation_target=translation_target)
return meta
def get_messages(self, start=0, page=-1, nb=500, unread=False, options=None, translation_target='en'): # threads ???? # TODO ADD last/first message timestamp + return page
def get_messages(self, start=0, page=-1, nb=500, message=None, unread=False, options=None, translation_target='en'): # threads ???? # TODO ADD last/first message timestamp + return page
# TODO return message meta
tags = {}
messages = {}
@ -282,12 +288,15 @@ class AbstractChatObject(AbstractSubtypeObject, ABC):
nb = int(nb)
except TypeError:
nb = 500
if not page:
page = -1
try:
page = int(page)
except TypeError:
page = 1
if message:
page = self.get_message_page(message, nb)
else:
if not page:
page = -1
try:
page = int(page)
except TypeError:
page = 1
mess, pagination = self._get_messages(nb=nb, page=page)
for message in mess:
timestamp = message[1]

View file

@ -24,6 +24,7 @@ from lib import chats_viewer
from lib import Language
from lib import Tag
from lib import module_extractor
from lib.objects import ail_objects
# ============ BLUEPRINT ============
chats_explorer = Blueprint('chats_explorer', __name__, template_folder=os.path.join(os.environ['AIL_FLASK'], 'templates/chats_explorer'))
@ -93,8 +94,16 @@ def chats_explorer_chat():
if target == "Don't Translate":
target = None
nb_messages = request.args.get('nb')
page = request.args.get('page')
chat = chats_viewer.api_get_chat(chat_id, instance_uuid, translation_target=target, nb=nb_messages, page=page, heatmap=True)
mess = request.args.get('message')
if mess:
message = mess
page = -1
message_id = message.rsplit('/', 1)[-1]
else:
message = None
message_id = None
page = request.args.get('page')
chat = chats_viewer.api_get_chat(chat_id, instance_uuid, translation_target=target, message=message, nb=nb_messages, page=page, heatmap=True)
if chat[1] != 200:
return create_json_response(chat[0], chat[1])
else:
@ -102,6 +111,7 @@ def chats_explorer_chat():
languages = Language.get_translation_languages()
return render_template('chat_viewer.html', chat=chat, bootstrap_label=bootstrap_label,
ail_tags=Tag.get_modal_add_tags(chat['id'], chat['type'], chat['subtype']),
message_id=message_id,
translation_languages=languages, translation_target=target)
@chats_explorer.route("chats/explorer/messages/stats/week", methods=['GET'])
@ -154,8 +164,16 @@ def objects_subchannel_messages():
if target == "Don't Translate":
target = None
nb_messages = request.args.get('nb')
page = request.args.get('page')
subchannel = chats_viewer.api_get_subchannel(subchannel_id, instance_uuid, translation_target=target, nb=nb_messages, page=page)
mess = request.args.get('message')
if mess:
message = mess
page = -1
message_id = message.rsplit('/', 1)[-1]
else:
message = None
message_id = None
page = request.args.get('page')
subchannel = chats_viewer.api_get_subchannel(subchannel_id, instance_uuid, translation_target=target, message=message, nb=nb_messages, page=page)
if subchannel[1] != 200:
return create_json_response(subchannel[0], subchannel[1])
else:
@ -163,6 +181,7 @@ def objects_subchannel_messages():
languages = Language.get_translation_languages()
return render_template('SubChannelMessages.html', subchannel=subchannel,
ail_tags=Tag.get_modal_add_tags(subchannel['id'], subchannel['type'], subchannel['subtype']),
message_id=message_id,
bootstrap_label=bootstrap_label, translation_languages=languages, translation_target=target)
@chats_explorer.route("/chats/explorer/thread", methods=['GET'])
@ -175,14 +194,24 @@ def objects_thread_messages():
if target == "Don't Translate":
target = None
nb_messages = request.args.get('nb')
page = request.args.get('page')
thread = chats_viewer.api_get_thread(thread_id, instance_uuid, translation_target=target, nb=nb_messages, page=page)
mess = request.args.get('message')
if mess:
message = mess
page = -1
message_id = message.rsplit('/', 1)[-1]
else:
message = None
message_id = None
page = request.args.get('page')
thread = chats_viewer.api_get_thread(thread_id, instance_uuid, translation_target=target, message=message, nb=nb_messages, page=page)
if thread[1] != 200:
return create_json_response(thread[0], thread[1])
else:
meta = thread[0]
languages = Language.get_translation_languages()
return render_template('ThreadMessages.html', meta=meta, bootstrap_label=bootstrap_label, translation_languages=languages, translation_target=target)
return render_template('ThreadMessages.html', meta=meta, bootstrap_label=bootstrap_label,
message_id=message_id,
translation_languages=languages, translation_target=target)
@chats_explorer.route("/chats/explorer/participants", methods=['GET'])
@login_required
@ -286,12 +315,13 @@ def objects_message():
else:
message = message[0]
languages = Language.get_translation_languages()
container_url = ail_objects.get_obj_from_global_id(message['container']).get_link(flask_context=True)
extracted = module_extractor.extract(current_user.get_user_id(), 'message', '', message['id'], content=message['content'])
extracted_matches = module_extractor.get_extracted_by_match(extracted)
message['extracted'] = extracted
message['extracted_matches'] = extracted_matches
return render_template('ChatMessage.html', meta=message, bootstrap_label=bootstrap_label,
translation_languages=languages, translation_target=target,
translation_languages=languages, translation_target=target, container_url=container_url,
modal_add_tags=Tag.get_modal_add_tags(message['id'], object_type='message'))
@chats_explorer.route("/objects/message/translate", methods=['POST'])

View file

@ -179,6 +179,9 @@
"order": [[ 3, "desc" ]]
});
{% endif %}
{% if message_id %}
document.location.hash = '#{{ message_id }}';
{% endif %}
});
function toggle_sidebar(){

View file

@ -196,7 +196,9 @@
$(document).ready(function(){
$("#page-Decoded").addClass("active");
$("#nav_chat").addClass("active");
{% if message_id %}
document.location.hash = '#{{ message_id }}';
{% endif %}
});
function toggle_sidebar(){

View file

@ -22,7 +22,7 @@
}
</style>
<div class="chat-message-left pb-1">
<div class="chat-message-left pb-1" id="{{ message['_id'] }}">
<div>
<a href="{{ url_for('chats_explorer.objects_user_account')}}?subtype={{ message['user-account']['subtype'] }}&id={{ message['user-account']['id'] }}">
<img src="{% if message['user-account']['icon'] %}{{ url_for('objects_image.image', filename=message['user-account']['icon'])}}{% else %}{{ url_for('static', filename='image/ail-icon.png') }}{% endif %}"
@ -199,7 +199,12 @@
</div>
<a class="btn btn-light btn-sm text-secondary px-1" href="{{ url_for('correlation.show_correlation')}}?type={{ message['type'] }}&subtype={{ message['subtype'] }}&id={{ message['id'] }}"><i class="fas fa-project-diagram"></i></a>
<a class="btn btn-light btn-sm text-secondary px-1" href="{{ message['link'] }}"><i class="fas fa-eye"></i></a>
{% if container_url %}
<a class="btn btn-light btn-sm text-secondary px-1" href="{{ container_url }}&message={{ message['id'] }}"><i class="fas fa-eye"></i></a>
{% else %}
<a class="btn btn-light btn-sm text-secondary px-1" href="{{ message['link'] }}"><i class="fas fa-eye"></i></a>
{% endif %}
</div>
</div>
</div>

View file

@ -201,6 +201,9 @@
"order": [[ 5, "desc" ]]
});
{% endif %}
{% if message_id %}
document.location.hash = '#{{ message_id }}';
{% endif %}
});
function toggle_sidebar(){