diff --git a/CHANGESNOTES.md b/CHANGESNOTES.md new file mode 100644 index 0000000..56c9cf3 --- /dev/null +++ b/CHANGESNOTES.md @@ -0,0 +1,10 @@ +# Changes and additions made. + +## Discord +The discord plugin got a major overhaul. Before it would break the json file for the channel you were in if you sent an emoji on either end. The emoji would not display, and would break the json string, making it unreadable and unable to accept new messages, thus needing a full reset of the file. This is now fixed, hopefully soon I will also add some other features to this to make the Discord <--> Originchats client nearly seamless. + +## Logger +The logger.py file got a few more just "codes" I suppose to make it easier to program with. + +## Exampleplugin.py +An example plugin meant to make programming plugins, which are essentially like discord bots if I had to compare them to something, that simply just says, "Hello World!" whenever any user types !helloworld. \ No newline at end of file diff --git a/clients.md b/clients.md index 178ff01..bd592f6 100644 --- a/clients.md +++ b/clients.md @@ -4,6 +4,9 @@ ## mistium - origin Boot https://origin.mistium.com and open the app store, find originChats by mist and install it +## fries' client is a WIP. +MEMEMEME IM HERE TOO HI GUYS I'M GOING TO MAKE SOMETHING!!! MY OWN CLIENT!!! :D + ## allucat electron Source accessible here: https://github.com/Allucat1000/OriginChats diff --git a/db/channels.py b/db/channels.py index fc08050..cb03ada 100644 --- a/db/channels.py +++ b/db/channels.py @@ -1,4 +1,5 @@ -import json, os +import json +import os from . import users import emoji @@ -7,32 +8,18 @@ channels_db_dir = os.path.join(_MODULE_DIR, "channels") channels_index = os.path.join(_MODULE_DIR, "channels.json") + def get_channel(channel_name): - """ - Get channel data by channel name. - """ data = get_channels() for channel in data: if channel.get("name") == channel_name: return channel return None + def get_channel_messages(channel_name, start, limit): - """ - Retrieve messages from a specific channel. - - Args: - channel_name (str): The name of the channel to retrieve messages from. - start (int or str, optional): If int, the number of recent messages to skip (offset from the end). - If str, the message ID to retrieve messages before (older messages than the specified ID). - Defaults to 0. - limit (int, optional): The maximum number of messages to retrieve. Defaults to 100. - - Returns: - list: A list of messages from the specified channel, in chronological order (oldest first). - """ try: - with open(f"{channels_db_dir}/{channel_name}.json", 'r') as f: + with open(f"{channels_db_dir}/{channel_name}.json", 'r', encoding='utf-8') as f: channel_data = json.load(f) except FileNotFoundError: return [] @@ -75,109 +62,66 @@ def get_channel_messages(channel_name, start, limit): return channel_data[begin:end] + def convert_messages_to_user_format(messages): - """ - Convert messages with user IDs to messages with usernames for sending to clients. - This ensures clients never see user IDs, only usernames. - """ converted = [] for msg in messages: msg_copy = msg.copy() - - # Convert user ID to username if "user" in msg_copy: user_id = msg_copy["user"] username = users.get_username_by_id(user_id) - msg_copy["user"] = username if username else user_id # Fallback to ID if username not found - - # Convert reply_to user ID to username if present + msg_copy["user"] = username if username else user_id if "reply_to" in msg_copy and "user" in msg_copy["reply_to"]: user_id = msg_copy["reply_to"]["user"] username = users.get_username_by_id(user_id) - msg_copy["reply_to"]["user"] = username if username else user_id # Fallback to ID if username not found - - # Convert user IDs in reactions to usernames if present + msg_copy["reply_to"]["user"] = username if username else user_id if "reactions" in msg_copy: converted_reactions = {} - for emoji, user_ids in msg_copy["reactions"].items(): + for emoji_key, user_ids in msg_copy["reactions"].items(): usernames = [] for uid in user_ids: username = users.get_username_by_id(uid) - usernames.append(username if username else uid) # Fallback to ID if username not found - converted_reactions[emoji] = usernames + usernames.append(username if username else uid) + converted_reactions[emoji_key] = usernames msg_copy["reactions"] = converted_reactions - converted.append(msg_copy) - return converted -def save_channel_message(channel_name, message): - """ - Save a message to a specific channel. - - Args: - channel_name (str): The name of the channel to save the message to. - message (dict): The message to save, should contain 'user', 'content', and 'timestamp'. - Returns: - bool: True if the message was saved successfully, False otherwise. - """ - # Ensure the channels directory exists +def save_channel_message(channel_name, message): os.makedirs(channels_db_dir, exist_ok=True) - - # Load existing channel data or create a new one try: - with open(f"{channels_db_dir}/{channel_name}.json", 'r') as f: + with open(f"{channels_db_dir}/{channel_name}.json", 'r', encoding='utf-8') as f: channel_data = json.load(f) except FileNotFoundError: channel_data = [] - # Append the new message channel_data.append(message) - # Save the updated channel data with compact formatting - with open(f"{channels_db_dir}/{channel_name}.json", 'w') as f: + with open(f"{channels_db_dir}/{channel_name}.json", 'w', encoding='utf-8') as f: json.dump(channel_data, f, separators=(',', ':'), ensure_ascii=False) return True -def get_all_channels_for_roles(roles): - """ - Get all channels available for the specified roles. - - Args: - roles (list): A list of roles to filter channels by. - Returns: - list: A list of channel info dicts available for the specified roles. - """ - channels = [] +def get_all_channels_for_roles(roles): + channels_list = [] try: - with open(channels_index, 'r') as f: + with open(channels_index, 'r', encoding='utf-8') as f: all_channels = json.load(f) for channel in all_channels: permissions = channel.get("permissions", {}) view_roles = permissions.get("view", []) if any(role in view_roles for role in roles): - channels.append(channel) + channels_list.append(channel) except FileNotFoundError: return [] - return channels - -def edit_channel_message(channel_name, message_id, new_content): - """ - Edit a message in a specific channel. + return channels_list - Args: - channel_name (str): The name of the channel. - message_id (str): The ID of the message to edit. - new_content (str): The new content for the message. - Returns: - bool: True if the message was edited successfully, False otherwise. - """ +def edit_channel_message(channel_name, message_id, new_content): try: - with open(f"{channels_db_dir}/{channel_name}.json", 'r') as f: + with open(f"{channels_db_dir}/{channel_name}.json", 'r', encoding='utf-8') as f: channel_data = json.load(f) for msg in channel_data: @@ -186,31 +130,20 @@ def edit_channel_message(channel_name, message_id, new_content): msg["edited"] = True break else: - return False # Message not found + return False - # Ensure the channels directory exists os.makedirs(channels_db_dir, exist_ok=True) - - with open(f"{channels_db_dir}/{channel_name}.json", 'w') as f: + with open(f"{channels_db_dir}/{channel_name}.json", 'w', encoding='utf-8') as f: json.dump(channel_data, f, separators=(',', ':'), ensure_ascii=False) return True except FileNotFoundError: return False -def get_channel_message(channel_name, message_id): - """ - Retrieve a specific message from a channel by its ID. - - Args: - channel_name (str): The name of the channel. - message_id (str): The ID of the message to retrieve. - Returns: - dict: The message if found, None otherwise. - """ +def get_channel_message(channel_name, message_id): try: - with open(f"{channels_db_dir}/{channel_name}.json", 'r') as f: + with open(f"{channels_db_dir}/{channel_name}.json", 'r', encoding='utf-8') as f: channel_data = json.load(f) i = 0 @@ -219,98 +152,62 @@ def get_channel_message(channel_name, message_id): if msg.get("id") == message_id: msg["position"] = i return msg - return None # Message not found + return None except FileNotFoundError: - return None # Channel not found - -def does_user_have_permission(channel_name, user_roles, permission_type): - """ - Check if a user with specific roles has permission to perform an action on a channel. + return None - Args: - channel_name (str): The name of the channel. - user_roles (list): A list of roles assigned to the user. - permission_type (str): The type of permission to check (e.g., "view", "edit_own"). - Returns: - bool: True if the user has the required permission, False otherwise. - """ +def does_user_have_permission(channel_name, user_roles, permission_type): if "owner" in user_roles: return True try: - with open(channels_index, 'r') as f: + with open(channels_index, 'r', encoding='utf-8') as f: channels_data = json.load(f) for channel in channels_data: - if channel.get("name") == channel_name: - permissions = channel.get("permissions", {}) + if channel.get('name') == channel_name: + permissions = channel.get('permissions', {}) allowed_roles = permissions.get(permission_type, []) return any(role in allowed_roles for role in user_roles) except FileNotFoundError: - return False # Channel index not found + return False - return False # Channel not found - -def delete_channel_message(channel_name, message_id): - """ - Delete a message from a specific channel. + return False - Args: - channel_name (str): The name of the channel. - message_id (str): The ID of the message to delete. - Returns: - bool: True if the message was deleted successfully, False otherwise. - """ +def delete_channel_message(channel_name, message_id): try: - with open(f"{channels_db_dir}/{channel_name}.json", 'r') as f: + with open(f"{channels_db_dir}/{channel_name}.json", 'r', encoding='utf-8') as f: channel_data = json.load(f) new_data = [msg for msg in channel_data if msg.get("id") != message_id] - # Ensure the channels directory exists os.makedirs(channels_db_dir, exist_ok=True) - - with open(f"{channels_db_dir}/{channel_name}.json", 'w') as f: + with open(f"{channels_db_dir}/{channel_name}.json", 'w', encoding='utf-8') as f: json.dump(new_data, f, separators=(',', ':'), ensure_ascii=False) return True except FileNotFoundError: return False - -def get_channels(): - """ - Get all channels from the channels index. - Returns: - list: A list of channel info dicts. - """ + +def get_channels(): try: - with open(channels_index, 'r') as f: + with open(channels_index, 'r', encoding='utf-8') as f: return json.load(f) except FileNotFoundError: - return [] # No channels found - -def create_channel(channel_name, channel_type): - """ - Create a new channel. + return [] - Args: - channel_name (str): The name of the channel to create. - channel_type (str): The type of the channel (e.g., "text", "voice"). - Returns: - bool: True if the channel was created successfully, False if it already exists. - """ +def create_channel(channel_name, channel_type): try: - with open(channels_index, 'r') as f: + with open(channels_index, 'r', encoding='utf-8') as f: channels = json.load(f) except FileNotFoundError: channels = [] - # Check if the channel already exists if any(channel.get('name') == channel_name for channel in channels): - return False # Channel already exists + return False new_channel = { "name": channel_name, @@ -323,43 +220,32 @@ def create_channel(channel_name, channel_type): channels.append(new_channel) - # Save the updated channels index - with open(channels_index, 'w') as f: + with open(channels_index, 'w', encoding='utf-8') as f: json.dump(channels, f, indent=4) return True + def can_user_pin(channel_name, user_roles): - """ - Check if a user with specific roles can pin messages in a channel. - If the channel does not specify pin, only owner is allowed by default - """ try: - with open(channels_index, 'r') as f: + with open(channels_index, 'r', encoding='utf-8') as f: channels_data = json.load(f) for channel in channels_data: if channel.get("name") == channel_name: permissions = channel.get("permissions", {}) if "pin" not in permissions: - return True # Default: owner can pin + return True allowed_roles = permissions.get("pin", []) return any(role in allowed_roles for role in user_roles) except FileNotFoundError: return False - -def pin_channel_message(channel_name, message_id): - """ - Pin a message in a specific channel. - Args: - channel_name (str): The name of the channel. - message_id (str): The ID of the message to pin. + return False + - Returns: - bool: True if the message was pinned successfully, False otherwise. - """ +def pin_channel_message(channel_name, message_id): try: - with open(f"{channels_db_dir}/{channel_name}.json", 'r') as f: + with open(f"{channels_db_dir}/{channel_name}.json", 'r', encoding='utf-8') as f: channel_data = json.load(f) except FileNotFoundError: return False @@ -369,27 +255,17 @@ def pin_channel_message(channel_name, message_id): msg["pinned"] = True break else: - return False # Message not found + return False - # Save the updated channel data - with open(f"{channels_db_dir}/{channel_name}.json", 'w') as f: + with open(f"{channels_db_dir}/{channel_name}.json", 'w', encoding='utf-8') as f: json.dump(channel_data, f, separators=(",", ":"), ensure_ascii=False) return True -def unpin_channel_message(channel_name, message_id): - """ - Unpin a message in a specific channel. - - Args: - channel_name (str): The name of the channel. - message_id (str): The ID of the message to unpin. - Returns: - bool: True if the message was unpinned successfully, False otherwise. - """ +def unpin_channel_message(channel_name, message_id): try: - with open(f"{channels_db_dir}/{channel_name}.json", 'r') as f: + with open(f"{channels_db_dir}/{channel_name}.json", 'r', encoding='utf-8') as f: channel_data = json.load(f) except FileNotFoundError: return False @@ -399,27 +275,17 @@ def unpin_channel_message(channel_name, message_id): msg["pinned"] = False break else: - return False # Message not found + return False - # Save the updated channel data - with open(f"{channels_db_dir}/{channel_name}.json", 'w') as f: + with open(f"{channels_db_dir}/{channel_name}.json", 'w', encoding='utf-8') as f: json.dump(channel_data, f, separators=(",", ":"), ensure_ascii=False) return True -def get_pinned_messages(channel_name): - """ - Get the pinned messages in a specific channel. - - Args: - channel_name (str): The name of the channel. - limit (int): The maximum number of messages to retrieve. - Returns: - list: A list of all pinned messages in a channel - """ +def get_pinned_messages(channel_name): try: - with open(f"{channels_db_dir}/{channel_name}.json", 'r') as f: + with open(f"{channels_db_dir}/{channel_name}.json", 'r', encoding='utf-8') as f: messages = json.load(f) except FileNotFoundError: return [] @@ -427,20 +293,10 @@ def get_pinned_messages(channel_name): pinned = [msg for msg in messages if msg.get("pinned")] return list(reversed(pinned)) -def search_channel_messages(channel_name, query): - """ - Search for messages in a specific channel. - - Args: - channel_name (str): The name of the channel. - query (str): The search query. - limit (int): The maximum number of messages to retrieve. - Returns: - list: A list of messages that match the search query. - """ +def search_channel_messages(channel_name, query): try: - with open(f"{channels_db_dir}/{channel_name}.json", 'r') as f: + with open(f"{channels_db_dir}/{channel_name}.json", 'r', encoding='utf-8') as f: messages = json.load(f) except FileNotFoundError: return [] @@ -448,50 +304,30 @@ def search_channel_messages(channel_name, query): search_results = [msg for msg in messages if query in msg.get("content", "").lower()] return list(reversed(search_results)) -def delete_channel(channel_name): - """ - Delete a channel. - - Args: - channel_name (str): The name of the channel to delete. - Returns: - bool: True if the channel was deleted successfully, False if it does not exist. - """ +def delete_channel(channel_name): try: - with open(channels_index, 'r') as f: + with open(channels_index, 'r', encoding='utf-8') as f: channels = json.load(f) new_channels = [channel for channel in channels if channel.get('name') != channel_name] if len(new_channels) == len(channels): - return False # Channel not found + return False - # Save the updated channels index - with open(channels_index, 'w') as f: + with open(channels_index, 'w', encoding='utf-8') as f: json.dump(new_channels, f, indent=4) - # Remove the channel's message file os.remove(f"{channels_db_dir}/{channel_name}.json") return True except FileNotFoundError: - return False # Channels index not found - -def set_channel_permissions(channel_name, role, permission, allow=True): - """ - Set permissions for a specific role on a channel. + return False - Args: - channel_name (str): The name of the channel. - role (str): The role to set permissions for. - permission (str): The permission to set (e.g., "view", "edit_own", "send"). - Returns: - bool: True if permissions were set successfully, False if the channel does not exist. - """ +def set_channel_permissions(channel_name, role, permission, allow=True): try: - with open(channels_index, 'r') as f: + with open(channels_index, 'r', encoding='utf-8') as f: channels = json.load(f) for channel in channels: @@ -501,88 +337,50 @@ def set_channel_permissions(channel_name, role, permission, allow=True): if role not in channel['permissions'][permission]: if allow: channel['permissions'][permission].append(role) - else: # If removing permission, ensure the role exists before removing + else: if role in channel['permissions'][permission]: channel['permissions'][permission].remove(role) - - # Save the updated channels index - with open(channels_index, 'w') as f: + with open(channels_index, 'w', encoding='utf-8') as f: json.dump(channels, f, indent=4) - return True - - return False # Channel not found + return False except FileNotFoundError: - return False # Channels index not found - -def get_channel_permissions(channel_name): - """ - Get permissions for a specific channel. + return False - Args: - channel_name (str): The name of the channel. - Returns: - dict: A dictionary of permissions for the channel, or None if the channel does not exist. - """ +def get_channel_permissions(channel_name): try: - with open(channels_index, 'r') as f: + with open(channels_index, 'r', encoding='utf-8') as f: channels = json.load(f) for channel in channels: if channel.get('name') == channel_name: return channel.get('permissions', {}) - - return None # Channel not found + return None except FileNotFoundError: - return None # Channels index not found - -def reorder_channel(channel_name, new_position): - """ - Reorder a channel in the channels index. + return None - Args: - channel_name (str): The name of the channel to reorder. - new_position (int): The new position for the channel (0-based index). - Returns: - bool: True if the channel was reordered successfully, False if it does not exist. - """ +def reorder_channel(channel_name, new_position): try: - with open(channels_index, 'r') as f: + with open(channels_index, 'r', encoding='utf-8') as f: channels = json.load(f) for i, channel in enumerate(channels): if channel.get('name') == channel_name: - # Remove the channel from its current position channels.pop(i) - # Insert it at the new position channels.insert(int(new_position), channel) - - # Save the updated channels index - with open(channels_index, 'w') as f: + with open(channels_index, 'w', encoding='utf-8') as f: json.dump(channels, f, indent=4) - return True - - return False # Channel not found + return False except FileNotFoundError: - return False # Channels index not found - -def get_message_replies(channel_name, message_id, limit=50): - """ - Get all replies to a specific message. + return False - Args: - channel_name (str): The name of the channel. - message_id (str): The ID of the message to get replies for. - limit (int): Maximum number of replies to return. - Returns: - list: A list of messages that are replies to the specified message. - """ +def get_message_replies(channel_name, message_id, limit=50): try: - with open(f"{channels_db_dir}/{channel_name}.json", 'r') as f: + with open(f"{channels_db_dir}/{channel_name}.json", 'r', encoding='utf-8') as f: channel_data = json.load(f) replies = [] @@ -591,100 +389,80 @@ def get_message_replies(channel_name, message_id, limit=50): replies.append(msg) if len(replies) >= limit: break - return replies except FileNotFoundError: - return [] # Channel not found - -def purge_messages(channel_name, count): - """ - Purge the last 'count' messages from a channel. + return [] - Args: - channel_name (str): The name of the channel. - count (int): The number of messages to purge. - Returns: - bool: True if messages were purged successfully, False if the channel does not exist or has fewer messages. - """ +def purge_messages(channel_name, count): try: - with open(f"{channels_db_dir}/{channel_name}.json", 'r') as f: + with open(f"{channels_db_dir}/{channel_name}.json", 'r', encoding='utf-8') as f: channel_data = json.load(f) if len(channel_data) < count: - return False # Not enough messages to purge + return False - # Remove the last 'count' messages new_data = channel_data[:-count] - # Save the updated channel data - with open(f"{channels_db_dir}/{channel_name}.json", 'w') as f: + with open(f"{channels_db_dir}/{channel_name}.json", 'w', encoding='utf-8') as f: json.dump(new_data, f, separators=(',', ':'), ensure_ascii=False) return True except FileNotFoundError: - return False # Channel not found + return False + def can_user_delete_own(channel_name, user_roles): - """ - Check if a user with specific roles can delete their own message in a channel. - If the channel does not specify delete_own, all roles are allowed by default. - """ try: - with open(channels_index, 'r') as f: + with open(channels_index, 'r', encoding='utf-8') as f: channels_data = json.load(f) for channel in channels_data: if channel.get("name") == channel_name: permissions = channel.get("permissions", {}) if "delete_own" not in permissions: - return True # Default: all roles can delete their own messages + return True allowed_roles = permissions.get("delete_own", []) return any(role in allowed_roles for role in user_roles) except FileNotFoundError: - return True # Default to True if channel index not found - return True # Default to True if channel not found + return True + return True + def can_user_edit_own(channel_name, user_roles): - """ - Check if a user with specific roles can edit their own message in a channel. - If the channel does not specify edit_own, all roles are allowed by default. - """ try: - with open(channels_index, 'r') as f: + with open(channels_index, 'r', encoding='utf-8') as f: channels_data = json.load(f) for channel in channels_data: if channel.get("name") == channel_name: permissions = channel.get("permissions", {}) if "edit_own" not in permissions: - return True # Default: all roles can edit their own messages + return True allowed_roles = permissions.get("edit_own", []) return any(role in allowed_roles for role in user_roles) except FileNotFoundError: return False return False + def can_user_react(channel_name, user_roles): - """ - Check if a user with specific roles can react to messages in a channel. - If the channel does not specify react, all roles are allowed by default. - """ try: - with open(channels_index, 'r') as f: + with open(channels_index, 'r', encoding='utf-8') as f: channels_data = json.load(f) for channel in channels_data: if channel.get("name") == channel_name: permissions = channel.get("permissions", {}) if "react" not in permissions: - return True # Default: all roles can react + return True allowed_roles = permissions.get("react", []) return any(role in allowed_roles for role in user_roles) except FileNotFoundError: return False return False + def add_reaction(channel_name, message_id, emoji_str, user_id): try: - with open(f"{channels_db_dir}/{channel_name}.json") as f: + with open(f"{channels_db_dir}/{channel_name}.json", 'r', encoding='utf-8') as f: channel_data = json.load(f) for msg in channel_data: @@ -696,11 +474,11 @@ def add_reaction(channel_name, message_id, emoji_str, user_id): msg["reactions"].setdefault(emoji_str, []) if user_id in msg["reactions"][emoji_str]: - return True # already reacted + return True msg["reactions"][emoji_str].append(user_id) - with open(f"{channels_db_dir}/{channel_name}.json", "w") as f: + with open(f"{channels_db_dir}/{channel_name}.json", "w", encoding='utf-8') as f: json.dump(channel_data, f, separators=(",", ":"), ensure_ascii=False) return True @@ -710,9 +488,10 @@ def add_reaction(channel_name, message_id, emoji_str, user_id): except FileNotFoundError: return False + def remove_reaction(channel_name, message_id, emoji_str, user_id): try: - with open(f"{channels_db_dir}/{channel_name}.json") as f: + with open(f"{channels_db_dir}/{channel_name}.json", 'r', encoding='utf-8') as f: channel_data = json.load(f) for msg in channel_data: @@ -734,7 +513,7 @@ def remove_reaction(channel_name, message_id, emoji_str, user_id): if not reactions: del msg["reactions"] - with open(f"{channels_db_dir}/{channel_name}.json", "w") as f: + with open(f"{channels_db_dir}/{channel_name}.json", "w", encoding='utf-8') as f: json.dump(channel_data, f, separators=(",", ":"), ensure_ascii=False) return True @@ -744,52 +523,31 @@ def remove_reaction(channel_name, message_id, emoji_str, user_id): except FileNotFoundError: return False -def get_reactions(channel_name, message_id): - """ - Get the reactions for a specific message in a channel. - Args: - channel_name (str): The name of the channel. - message_id (str): The ID of the message to get the reactions for. - - Returns: - dict: A dictionary containing the reactions for the message, or None if the message or channel does not exist. - """ +def get_reactions(channel_name, message_id): try: - with open(f"{channels_db_dir}/{channel_name}.json", 'r') as f: + with open(f"{channels_db_dir}/{channel_name}.json", 'r', encoding='utf-8') as f: channel_data = json.load(f) for msg in channel_data: if msg.get("id") == message_id: return msg.get("reactions", {}) - return None except FileNotFoundError: return None -def get_reaction_users(channel_name, message_id, emoji): - """ - Get the users who reacted with a specific emoji to a specific message in a channel. - Args: - channel_name (str): The name of the channel. - message_id (str): The ID of the message to get the reactions for. - emoji (str): The emoji to get the users for. - - Returns: - list: A list of usernames who reacted with the specified emoji, or None if the message or channel does not exist. - """ +def get_reaction_users(channel_name, message_id, emoji): try: - with open(f"{channels_db_dir}/{channel_name}.json", 'r') as f: + with open(f"{channels_db_dir}/{channel_name}.json", 'r', encoding='utf-8') as f: channel_data = json.load(f) for msg in channel_data: if msg.get("id") == message_id: if emoji in msg.get("reactions", {}): return msg["reactions"][emoji] - return None except FileNotFoundError: return None except json.JSONDecodeError: - return None \ No newline at end of file + return None diff --git a/disabled plugins/welcome.py b/disabled plugins/welcome.py deleted file mode 100644 index b1138d2..0000000 --- a/disabled plugins/welcome.py +++ /dev/null @@ -1,87 +0,0 @@ -# Welcome Plugin for OriginChats -# Sends configurable welcome messages when new users join the server - -import os -import json -import time -import uuid -from db import channels, users -import sys -sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) -from logger import Logger - -# Default configuration -DEFAULT_CONFIG = { - "enabled": True, - "welcome_channel": "general", - "welcome_message": "Welcome {username}!", -} - -def getInfo(): - """Get information about the plugin""" - return { - "name": "Welcome Plugin", - "description": "Sends welcome messages when new users join the server, with configurable messages and channels.", - "version": "1.0.0", - "author": "OriginChats", - "handles": [ - "user_connect" - ] - } - -def send_message_to_channel(channel, content, server_data): - """Send a message to a channel through the server's broadcast system""" - import asyncio - - # Create a message object similar to how regular messages are created - out_msg = { - "user": "OriginChats", - "content": content.strip(), - "timestamp": time.time(), - "type": "message", - "pinned": False, - "id": str(uuid.uuid4()) - } - - # Save to channel - channels.save_channel_message(channel, out_msg) - - # Broadcast the message if we have server data - if server_data and "connected_clients" in server_data: - message = {"cmd": "message_new", "message": out_msg, "channel": channel, "global": True} - # Schedule this to run in the event loop - from handlers.websocket_utils import broadcast_to_all - try: - loop = asyncio.get_event_loop() - loop.create_task(broadcast_to_all(server_data["connected_clients"], message)) - except Exception as e: - Logger.error(f"Welcome Plugin: Error broadcasting message: {e}") - -def on_user_connect(ws, user_data, server_data=None): - """Handle user connection event""" - config = DEFAULT_CONFIG - - if not config.get("enabled", True): - return - - username = user_data.get("username") - if not username: - return - - # Check if this is actually a new user (first time joining) - user_obj = users.get_user(username) - if user_obj: - return - - # Send welcome message to channel - welcome_channel = config.get("welcome_channel", "general") - welcome_message = config.get("welcome_message", "Welcome {username}!") - - # Replace placeholders in message - formatted_message = welcome_message.replace("{username}", f"{username}") - - try: - send_message_to_channel(welcome_channel, formatted_message, server_data) - Logger.info(f"Welcome Plugin: Sent welcome message for {username} to #{welcome_channel}") - except Exception as e: - Logger.error(f"Welcome Plugin: Error sending welcome message: {e}") \ No newline at end of file diff --git a/handlers/message.py b/handlers/message.py index d922b80..1cb3cb3 100644 --- a/handlers/message.py +++ b/handlers/message.py @@ -69,9 +69,9 @@ def handle(ws, message, server_data=None): if not replied_message: return {"cmd": "error", "val": "The message you're trying to reply to was not found"} - # Save the message to the channel (store user ID) + # Save the message to the channel (store username, not user ID) out_msg = { - "user": user_id, + "user": users.get_username_by_id(user_id), "content": content, "timestamp": time.time(), # Use current timestamp "type": "message", diff --git a/logger.py b/logger.py index a30d319..76f82ad 100644 --- a/logger.py +++ b/logger.py @@ -4,6 +4,7 @@ class Colors: BOLD = '\033[1m' # Standard colors + DARKGREEN = '\033[32m' RED = '\033[91m' GREEN = '\033[92m' YELLOW = '\033[93m' @@ -15,7 +16,12 @@ class Colors: class Logger: """Enhanced logger with ANSI colors and symbols""" - + @staticmethod + def distinct(message: str): + """Log a distinct message with a unique symbol""" + print(f"{Colors.GREEN}[~]{Colors.RESET} {message}") + + @staticmethod def add(message: str): """Log an addition/creation action""" @@ -55,6 +61,11 @@ def error(message: str): def success(message: str): """Log success messages""" print(f"{Colors.GREEN}[✓]{Colors.RESET} {message}") + + @staticmethod + def discordupdate(message: str): + """Log Discord update messages""" + print(f"{Colors.YELLOW}[☺]{Colors.RESET} {message}") @staticmethod def discord_message(username: str, message: str): diff --git a/disabled plugins/discordBridge.py b/plugins/discordBridge.py similarity index 98% rename from disabled plugins/discordBridge.py rename to plugins/discordBridge.py index 6ebf019..1d14355 100644 --- a/disabled plugins/discordBridge.py +++ b/plugins/discordBridge.py @@ -8,6 +8,7 @@ import uuid import asyncio import aiohttp +import websocket import websockets import hashlib from typing import Dict, List, Optional @@ -333,7 +334,7 @@ async def handle_discord_message(self, message_data): discord_user_id = author['id'] rotur_username = await get_rotur_username(discord_user_id) if not rotur_username: - rotur_username = f"discord-{author['username'].lower()}" + rotur_username = getattr(websocket, "username", "") else: rotur_username = rotur_username.lower() @@ -388,7 +389,7 @@ async def handle_discord_message(self, message_data): channel_name ) - Logger.success(f"Forwarded Discord message from {rotur_username} to #{channel_name}: '{content}'") + Logger.discordupdate(f"Forwarded Discord message from {rotur_username} to #{channel_name}: '{content}'") async def api_request(self, method, endpoint, data=None): """Make Discord API request""" @@ -699,7 +700,7 @@ def load_origin_channels(): """Load OriginChats channels from channels.json""" try: channels_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'db', 'channels.json') - with open(channels_path, 'r') as f: + with open(channels_path, 'r', encoding='utf-8') as f: return json.load(f) except Exception as e: Logger.error(f"Error loading OriginChats channels: {str(e)}") @@ -709,7 +710,7 @@ def load_webhook_config(): """Load webhook configuration from file""" try: if os.path.exists(WEBHOOK_CONFIG_FILE): - with open(WEBHOOK_CONFIG_FILE, 'r') as f: + with open(WEBHOOK_CONFIG_FILE, 'r', encoding='utf-8') as f: return json.load(f) except Exception as e: Logger.error(f"Error loading webhook config: {str(e)}") @@ -720,7 +721,7 @@ def save_webhook_config(channel_name, webhook_url): try: config = load_webhook_config() config[channel_name] = webhook_url - with open(WEBHOOK_CONFIG_FILE, 'w') as f: + with open(WEBHOOK_CONFIG_FILE, 'w', encoding='utf-8') as f: json.dump(config, f, indent=2) except Exception as e: Logger.error(f"Error saving webhook config: {str(e)}") diff --git a/plugins/exampleplugin.py b/plugins/exampleplugin.py new file mode 100644 index 0000000..e70c2fd --- /dev/null +++ b/plugins/exampleplugin.py @@ -0,0 +1,68 @@ +from logger import Logger +import plugin_manager +Logger.distinct("Example Plugin loaded successfully!") +import os +import json +import time +import uuid +from db import channels, users +import sys +sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +from logger import Logger + + +def send_message_to_channel(channel, content, server_data): + """Send a message to a channel through the server's broadcast system""" + import asyncio + + # Create a message object similar to how regular messages are created + out_msg = { + "user": "OriginChats", + "content": content.strip(), + "timestamp": time.time(), + "type": "message", + "pinned": False, + "id": str(uuid.uuid4()) + } + + # Save to channel + channels.save_channel_message(channel, out_msg) + + # Broadcast the message if we have server data + if server_data and "connected_clients" in server_data: + message = {"cmd": "message_new", "message": out_msg, "channel": channel, "global": True} + # Schedule this to run in the event loop + from handlers.websocket_utils import broadcast_to_all + try: + loop = asyncio.get_event_loop() + loop.create_task(broadcast_to_all(server_data["connected_clients"], message)) + except Exception as e: + Logger.error(f"Welcome Plugin: Error broadcasting message: {e}") + +# ---------------------------------------------------------------------------------------------------------------- # +send_message_to_channel("general", "Example Plugin has been loaded!", None) + + +def getInfo(): + return { + "name": "Example Plugin", + "description": "Simple example plugin that responds to ?hello", + "version": "1.0.0", + "author": "OriginChats", + "handles": ["new_message"] + } + + +def on_new_message(ws, message_data, server_data=None): + try: + content = message_data.get('content', '').strip() + channel = message_data.get('channel') + if not content or not channel: + return + + if content.lower() == '?rtd': + # Use the helper to send a message into the channel + send_message_to_channel(channel, 'Hello World', server_data) + except Exception as e: + Logger.error(f"ExamplePlugin on_new_message error: {e}") +