2023-11-02 15:28:33 +00:00
|
|
|
# -*-coding:UTF-8 -*
|
|
|
|
"""
|
|
|
|
Base Class for AIL Objects
|
|
|
|
"""
|
|
|
|
|
|
|
|
##################################
|
|
|
|
# Import External packages
|
|
|
|
##################################
|
|
|
|
import os
|
|
|
|
import sys
|
|
|
|
from abc import ABC
|
|
|
|
|
|
|
|
from datetime import datetime
|
|
|
|
# from flask import url_for
|
|
|
|
|
|
|
|
sys.path.append(os.environ['AIL_BIN'])
|
|
|
|
##################################
|
|
|
|
# Import Project packages
|
|
|
|
##################################
|
|
|
|
from lib.objects.abstract_subtype_object import AbstractSubtypeObject
|
|
|
|
from lib.ail_core import get_object_all_subtypes, zscan_iter ################
|
|
|
|
from lib.ConfigLoader import ConfigLoader
|
|
|
|
from lib.objects.Messages import Message
|
|
|
|
from lib.objects.UsersAccount import UserAccount
|
|
|
|
from lib.objects.Usernames import Username
|
|
|
|
from lib.data_retention_engine import update_obj_date
|
|
|
|
|
|
|
|
from packages import Date
|
|
|
|
|
|
|
|
# LOAD CONFIG
|
|
|
|
config_loader = ConfigLoader()
|
|
|
|
r_cache = config_loader.get_redis_conn("Redis_Cache")
|
|
|
|
r_object = config_loader.get_db_conn("Kvrocks_Objects")
|
|
|
|
config_loader = None
|
|
|
|
|
|
|
|
# # FIXME: SAVE SUBTYPE NAMES ?????
|
|
|
|
|
|
|
|
class AbstractChatObject(AbstractSubtypeObject, ABC):
|
|
|
|
"""
|
|
|
|
Abstract Subtype Object
|
|
|
|
"""
|
|
|
|
|
|
|
|
def __init__(self, obj_type, id, subtype):
|
|
|
|
""" Abstract for all the AIL object
|
|
|
|
|
|
|
|
:param obj_type: object type (item, ...)
|
|
|
|
:param id: Object ID
|
|
|
|
"""
|
|
|
|
super().__init__(obj_type, id, subtype)
|
|
|
|
|
|
|
|
# get useraccount / username
|
|
|
|
# get users ?
|
|
|
|
# timeline name ????
|
|
|
|
# info
|
|
|
|
# created
|
|
|
|
# last imported/updated
|
|
|
|
|
|
|
|
# TODO get instance
|
|
|
|
# TODO get protocol
|
|
|
|
# TODO get network
|
|
|
|
# TODO get address
|
|
|
|
|
|
|
|
def get_chat(self): # require ail object TODO ##
|
|
|
|
if self.type != 'chat':
|
|
|
|
parent = self.get_parent()
|
2023-11-06 13:08:23 +00:00
|
|
|
if parent:
|
|
|
|
obj_type, _ = parent.split(':', 1)
|
|
|
|
if obj_type == 'chat':
|
|
|
|
return parent
|
2023-11-02 15:28:33 +00:00
|
|
|
|
|
|
|
def get_subchannels(self):
|
|
|
|
subchannels = []
|
|
|
|
if self.type == 'chat': # category ???
|
|
|
|
for obj_global_id in self.get_childrens():
|
|
|
|
obj_type, _ = obj_global_id.split(':', 1)
|
|
|
|
if obj_type == 'chat-subchannel':
|
|
|
|
subchannels.append(obj_global_id)
|
|
|
|
return subchannels
|
|
|
|
|
|
|
|
def get_nb_subchannels(self):
|
|
|
|
nb = 0
|
|
|
|
if self.type == 'chat':
|
|
|
|
for obj_global_id in self.get_childrens():
|
|
|
|
obj_type, _ = obj_global_id.split(':', 1)
|
|
|
|
if obj_type == 'chat-subchannel':
|
|
|
|
nb += 1
|
|
|
|
return nb
|
|
|
|
|
|
|
|
def get_threads(self):
|
|
|
|
threads = []
|
|
|
|
for obj_global_id in self.get_childrens():
|
|
|
|
obj_type, _ = obj_global_id.split(':', 1)
|
|
|
|
if obj_type == 'chat-thread':
|
|
|
|
threads.append(obj_global_id)
|
|
|
|
return threads
|
|
|
|
|
|
|
|
def get_created_at(self):
|
|
|
|
return self._get_field('created_at')
|
|
|
|
|
|
|
|
def set_created_at(self, timestamp):
|
|
|
|
self._set_field('created_at', timestamp)
|
|
|
|
|
|
|
|
def get_name(self):
|
|
|
|
name = self._get_field('name')
|
|
|
|
if not name:
|
|
|
|
name = ''
|
|
|
|
return name
|
|
|
|
|
|
|
|
def set_name(self, name):
|
|
|
|
self._set_field('name', name)
|
|
|
|
|
|
|
|
def get_img(self):
|
|
|
|
return self._get_field('img')
|
|
|
|
|
|
|
|
def set_img(self, icon):
|
|
|
|
self._set_field('img', icon)
|
|
|
|
|
2023-11-06 15:38:31 +00:00
|
|
|
def get_info(self):
|
|
|
|
return self._get_field('info')
|
|
|
|
|
|
|
|
def set_info(self, info):
|
|
|
|
self._set_field('info', info)
|
|
|
|
|
2023-11-02 15:28:33 +00:00
|
|
|
def get_nb_messages(self):
|
|
|
|
return r_object.zcard(f'messages:{self.type}:{self.subtype}:{self.id}')
|
|
|
|
|
|
|
|
def _get_messages(self): # TODO paginate
|
|
|
|
return r_object.zrange(f'messages:{self.type}:{self.subtype}:{self.id}', 0, -1, withscores=True)
|
|
|
|
|
|
|
|
def get_message_meta(self, message, parent=True, mess_datetime=None): # TODO handle file message
|
|
|
|
obj = Message(message[9:])
|
|
|
|
mess_dict = obj.get_meta(options={'content', 'link', 'parent', 'user-account'})
|
2023-11-06 13:08:23 +00:00
|
|
|
# print(mess_dict)
|
2023-11-02 15:28:33 +00:00
|
|
|
if mess_dict.get('parent') and parent:
|
|
|
|
mess_dict['reply_to'] = self.get_message_meta(mess_dict['parent'], parent=False)
|
|
|
|
if mess_dict.get('user-account'):
|
|
|
|
_, user_account_subtype, user_account_id = mess_dict['user-account'].split(':', 3)
|
|
|
|
user_account = UserAccount(user_account_id, user_account_subtype)
|
|
|
|
mess_dict['user-account'] = {}
|
|
|
|
mess_dict['user-account']['type'] = user_account.get_type()
|
|
|
|
mess_dict['user-account']['subtype'] = user_account.get_subtype(r_str=True)
|
|
|
|
mess_dict['user-account']['id'] = user_account.get_id()
|
|
|
|
username = user_account.get_username()
|
|
|
|
if username:
|
|
|
|
_, username_account_subtype, username_account_id = username.split(':', 3)
|
|
|
|
username = Username(username_account_id, username_account_subtype).get_default_meta(link=False)
|
|
|
|
mess_dict['user-account']['username'] = username # TODO get username at the given timestamp ???
|
|
|
|
else:
|
|
|
|
mess_dict['user-account'] = {'id': 'UNKNOWN'}
|
|
|
|
|
|
|
|
if not mess_datetime:
|
|
|
|
obj_mess_id = message.get_timestamp()
|
|
|
|
mess_datetime = datetime.fromtimestamp(obj_mess_id)
|
|
|
|
mess_dict['date'] = mess_datetime.isoformat(' ')
|
|
|
|
mess_dict['hour'] = mess_datetime.strftime('%H:%M:%S')
|
|
|
|
return mess_dict
|
|
|
|
|
|
|
|
def get_messages(self, start=0, page=1, nb=500, unread=False): # threads ????
|
|
|
|
# TODO return message meta
|
|
|
|
tags = {}
|
|
|
|
messages = {}
|
|
|
|
curr_date = None
|
|
|
|
for message in self._get_messages():
|
|
|
|
date = datetime.fromtimestamp(message[1])
|
|
|
|
date_day = date.strftime('%Y/%m/%d')
|
|
|
|
if date_day != curr_date:
|
|
|
|
messages[date_day] = []
|
|
|
|
curr_date = date_day
|
|
|
|
mess_dict = self.get_message_meta(message[0], parent=True, mess_datetime=date) # TODO use object
|
|
|
|
messages[date_day].append(mess_dict)
|
|
|
|
|
|
|
|
if mess_dict.get('tags'):
|
|
|
|
for tag in mess_dict['tags']:
|
|
|
|
if tag not in tags:
|
|
|
|
tags[tag] = 0
|
|
|
|
tags[tag] += 1
|
|
|
|
return messages, tags
|
|
|
|
|
|
|
|
# TODO REWRITE ADD OR ADD MESSAGE ????
|
|
|
|
# add
|
|
|
|
# add message
|
|
|
|
|
|
|
|
def get_obj_by_message_id(self, message_id):
|
|
|
|
return r_object.hget(f'messages:ids:{self.type}:{self.subtype}:{self.id}', message_id)
|
|
|
|
|
|
|
|
def add_message_cached_reply(self, reply_id, message_id):
|
|
|
|
r_cache.sadd(f'messages:ids:{self.type}:{self.subtype}:{self.id}:{reply_id}', message_id)
|
|
|
|
r_cache.expire(f'messages:ids:{self.type}:{self.subtype}:{self.id}:{reply_id}', 600)
|
|
|
|
|
|
|
|
def _get_message_cached_reply(self, message_id):
|
|
|
|
return r_cache.smembers(f'messages:ids:{self.type}:{self.subtype}:{self.id}:{message_id}')
|
|
|
|
|
|
|
|
def get_cached_message_reply(self, message_id):
|
|
|
|
objs_global_id = []
|
|
|
|
for mess_id in self._get_message_cached_reply(message_id):
|
|
|
|
obj_global_id = self.get_obj_by_message_id(mess_id) # TODO CATCH EXCEPTION
|
|
|
|
if obj_global_id:
|
|
|
|
objs_global_id.append(obj_global_id)
|
|
|
|
return objs_global_id
|
|
|
|
|
|
|
|
def add_message(self, obj_global_id, message_id, timestamp, reply_id=None):
|
|
|
|
r_object.hset(f'messages:ids:{self.type}:{self.subtype}:{self.id}', message_id, obj_global_id)
|
|
|
|
r_object.zadd(f'messages:{self.type}:{self.subtype}:{self.id}', {obj_global_id: float(timestamp)})
|
|
|
|
|
|
|
|
# MESSAGE REPLY
|
|
|
|
if reply_id:
|
|
|
|
reply_obj = self.get_obj_by_message_id(reply_id) # TODO CATCH EXCEPTION
|
|
|
|
if reply_obj:
|
|
|
|
self.add_obj_children(reply_obj, obj_global_id)
|
|
|
|
else:
|
|
|
|
self.add_message_cached_reply(reply_id, message_id)
|
|
|
|
|
|
|
|
|
|
|
|
# get_messages_meta ????
|
|
|
|
|
|
|
|
# TODO move me to abstract subtype
|
|
|
|
class AbstractChatObjects(ABC):
|
|
|
|
def __init__(self, type):
|
|
|
|
self.type = type
|
|
|
|
|
|
|
|
def add_subtype(self, subtype):
|
|
|
|
r_object.sadd(f'all_{self.type}:subtypes', subtype)
|
|
|
|
|
|
|
|
def get_subtypes(self):
|
|
|
|
return r_object.smembers(f'all_{self.type}:subtypes')
|
|
|
|
|
|
|
|
def get_nb_ids_by_subtype(self, subtype):
|
|
|
|
return r_object.zcard(f'{self.type}_all:{subtype}')
|
|
|
|
|
|
|
|
def get_ids_by_subtype(self, subtype):
|
|
|
|
return r_object.zrange(f'{self.type}_all:{subtype}', 0, -1)
|
|
|
|
|
|
|
|
def get_all_id_iterator_iter(self, subtype):
|
|
|
|
return zscan_iter(r_object, f'{self.type}_all:{subtype}')
|
|
|
|
|
|
|
|
def get_ids(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def search(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|