Karma fixes

This commit is contained in:
2026-05-07 13:48:54 -05:00
parent 972f34a25a
commit 4b10c13b29
+68 -30
View File
@@ -4,7 +4,7 @@ Advanced Karma Plugin for Funguy Bot
Provides comprehensive karma tracking with leaderboards, trends, and statistics. Provides comprehensive karma tracking with leaderboards, trends, and statistics.
Features: Features:
* Give/take karma points from users using display names or Matrix IDs * Give/take karma points from users using display names ONLY (Matrix IDs are rejected)
* Track karma history with timestamps * Track karma history with timestamps
* View karma leaderboards (top/bottom) * View karma leaderboards (top/bottom)
* Rate limiting to prevent spam * Rate limiting to prevent spam
@@ -12,7 +12,7 @@ Features:
Commands: Commands:
!karma - Show this help !karma - Show this help
!karma <user> - Show karma for a user !karma <user> - Show karma for a user (display name only)
!karma++ <user> - Give +1 karma !karma++ <user> - Give +1 karma
!karma-- <user> - Give -1 karma !karma-- <user> - Give -1 karma
!karma top [n] - Show top karma entries !karma top [n] - Show top karma entries
@@ -26,6 +26,8 @@ Shortcuts:
!-- <user> - Same as !karma-- <user> !-- <user> - Same as !karma-- <user>
<user>++ - Give +1 karma (inline) <user>++ - Give +1 karma (inline)
<user>-- - Give -1 karma (inline) <user>-- - Give -1 karma (inline)
NOTE: Matrix IDs (e.g., @user:server) are NOT accepted. Use display names only.
""" """
import sqlite3 import sqlite3
@@ -113,7 +115,7 @@ def get_connection():
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Display Name Resolution # Display Name Resolution (Matrix IDs are rejected)
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
async def refresh_display_name_cache(bot, room_id): async def refresh_display_name_cache(bot, room_id):
@@ -163,13 +165,20 @@ async def refresh_display_name_cache(bot, room_id):
cache_timestamp[room_id] = now cache_timestamp[room_id] = now
def resolve_display_name(room_id, display_name, bot=None): def is_matrix_id(name):
"""Resolve a display name to a Matrix user ID.""" """Return True if the string looks like a Matrix ID (starts with @ and contains :)."""
global display_name_cache return name.startswith('@') and ':' in name
# If it's already a valid Matrix ID, return it
if display_name.startswith('@') and ':' in display_name: def resolve_display_name(room_id, display_name, bot=None):
return display_name """Resolve a display name to a Matrix user ID.
Returns None if the input is a Matrix ID (rejected) or if the name
cannot be resolved.
"""
# Reject Matrix IDs outright
if is_matrix_id(display_name):
return None
# Check the cache # Check the cache
if room_id in display_name_cache: if room_id in display_name_cache:
@@ -477,7 +486,7 @@ async def handle_command(room, message, bot, prefix, config):
# !karma++ username # !karma++ username
args = match.args() args = match.args()
if not args: if not args:
await bot.api.send_markdown_message(room.room_id, "Usage: !karma++ <username>") await bot.api.send_markdown_message(room.room_id, "Usage: !karma++ <username> (display name only, no Matrix ID)")
return return
display_name = ' '.join(args) display_name = ' '.join(args)
await process_karma_vote(room, display_name, '++', message.sender, bot) await process_karma_vote(room, display_name, '++', message.sender, bot)
@@ -487,7 +496,7 @@ async def handle_command(room, message, bot, prefix, config):
# !karma-- username # !karma-- username
args = match.args() args = match.args()
if not args: if not args:
await bot.api.send_markdown_message(room.room_id, "Usage: !karma-- <username>") await bot.api.send_markdown_message(room.room_id, "Usage: !karma-- <username> (display name only, no Matrix ID)")
return return
display_name = ' '.join(args) display_name = ' '.join(args)
await process_karma_vote(room, display_name, '--', message.sender, bot) await process_karma_vote(room, display_name, '--', message.sender, bot)
@@ -500,7 +509,7 @@ async def handle_command(room, message, bot, prefix, config):
# !karma ++ username (space between) # !karma ++ username (space between)
action = args[0] action = args[0]
if len(args) < 2: if len(args) < 2:
await bot.api.send_markdown_message(room.room_id, f"Usage: !karma {action} <username>") await bot.api.send_markdown_message(room.room_id, f"Usage: !karma {action} <username> (display name only)")
return return
display_name = ' '.join(args[1:]) display_name = ' '.join(args[1:])
await process_karma_vote(room, display_name, action, message.sender, bot) await process_karma_vote(room, display_name, action, message.sender, bot)
@@ -514,7 +523,7 @@ async def handle_command(room, message, bot, prefix, config):
elif full_cmd in ['++', '--']: elif full_cmd in ['++', '--']:
args = match.args() args = match.args()
if not args: if not args:
await bot.api.send_markdown_message(room.room_id, f"Usage: !{full_cmd} <username>\nExample: !{full_cmd} Nexilva") await bot.api.send_markdown_message(room.room_id, f"Usage: !{full_cmd} <username> (display name only)\nExample: !{full_cmd} Nexilva")
return return
display_name = ' '.join(args) display_name = ' '.join(args)
await process_karma_vote(room, display_name, full_cmd, message.sender, bot) await process_karma_vote(room, display_name, full_cmd, message.sender, bot)
@@ -533,11 +542,18 @@ async def process_karma_vote(room, display_name, action, voter, bot):
logging.info(f"Karma vote: {voter_str} -> '{display_name}' ({action}, change={change:+d}) in room {room_id}") logging.info(f"Karma vote: {voter_str} -> '{display_name}' ({action}, change={change:+d}) in room {room_id}")
# Reject Matrix IDs
if is_matrix_id(display_name):
await bot.api.send_markdown_message(room.room_id,
"❌ Please use the user's **display name** (e.g., 'Nexilva') Matrix IDs (like @user:server) are not allowed.")
return
# Resolve display name to user ID # Resolve display name to user ID
user_id = resolve_display_name(room_id, display_name, bot) user_id = resolve_display_name(room_id, display_name, bot)
if not user_id: if not user_id:
await bot.api.send_markdown_message(room.room_id, f"❌ Could not find user '{display_name}'. Please use their display name or Matrix ID (e.g., @username:server)") await bot.api.send_markdown_message(room.room_id,
f"❌ Could not find user with display name '{display_name}'. Make sure they are in this room and that the name is spelled correctly (emojifriendly).")
return return
# Prevent self-modification # Prevent self-modification
@@ -574,14 +590,14 @@ async def handle_karma_command(room, message, bot, config):
room_id = room.room_id room_id = room.room_id
if not args: if not args:
# Show help for !karma command in collapsible details tag with proper HTML lists # Show help for !karma command (unchanged, but note in help that Matrix IDs are rejected)
help_text = f"""<details> help_text = f"""<details>
<summary>💗 <strong>Karma Plugin Help</strong> (click to expand)</summary> <summary>💗 <strong>Karma Plugin Help</strong> (click to expand)</summary>
<strong>Commands:</strong> <strong>Commands:</strong>
<ul> <ul>
<li><code>!karma</code> - Show this help</li> <li><code>!karma</code> - Show this help</li>
<li><code>!karma &lt;user&gt;</code> - Show karma for a user (use display name or @user:server)</li> <li><code>!karma &lt;user&gt;</code> - Show karma for a user (use display name ONLY, no Matrix ID)</li>
<li><code>!karma++ &lt;user&gt;</code> - Give +1 karma to a user</li> <li><code>!karma++ &lt;user&gt;</code> - Give +1 karma to a user</li>
<li><code>!karma-- &lt;user&gt;</code> - Give -1 karma to a user</li> <li><code>!karma-- &lt;user&gt;</code> - Give -1 karma to a user</li>
<li><code>!karma top [n]</code> - Show top karma leaders</li> <li><code>!karma top [n]</code> - Show top karma leaders</li>
@@ -599,10 +615,16 @@ async def handle_karma_command(room, message, bot, config):
<li><code>&lt;user&gt;--</code> - Give -1 karma (inline)</li> <li><code>&lt;user&gt;--</code> - Give -1 karma (inline)</li>
</ul> </ul>
<strong>Important:</strong>
<ul>
<li>❌ <strong>Matrix IDs (e.g., @user:server) are NOT accepted.</strong> Use the person's display name (what you see in chat).</li>
<li>✅ Examples: <code>!karma++ Nexilva</code> or <code>Nexilva++</code></li>
</ul>
<strong>Examples:</strong> <strong>Examples:</strong>
<ul> <ul>
<li><code>!karma Nexilva</code> - Check Nexilva's karma</li> <li><code>!karma Nexilva</code> - Check Nexilva's karma</li>
<li><code>!karma++ @hb:matrix.org</code> - Give HB +1 karma</li> <li><code>!karma++ "🍄 HB🍄"</code> - Give HB +1 karma</li>
<li><code>!karma top 5</code> - Show top 5 leaders</li> <li><code>!karma top 5</code> - Show top 5 leaders</li>
<li><code>Nexilva++</code> - Give Nexilva +1 karma (inline)</li> <li><code>Nexilva++</code> - Give Nexilva +1 karma (inline)</li>
</ul> </ul>
@@ -622,7 +644,7 @@ async def handle_karma_command(room, message, bot, config):
subcommand = args[0].lower() subcommand = args[0].lower()
# !karma top [n] # !karma top [n] - unchanged
if subcommand == "top": if subcommand == "top":
limit = 10 limit = 10
if len(args) > 1 and args[1].isdigit(): if len(args) > 1 and args[1].isdigit():
@@ -640,7 +662,7 @@ async def handle_karma_command(room, message, bot, config):
await bot.api.send_markdown_message(room.room_id, "No karma entries found in this room.") await bot.api.send_markdown_message(room.room_id, "No karma entries found in this room.")
return return
# !karma bottom [n] # !karma bottom [n] - unchanged
if subcommand == "bottom": if subcommand == "bottom":
limit = 10 limit = 10
if len(args) > 1 and args[1].isdigit(): if len(args) > 1 and args[1].isdigit():
@@ -657,13 +679,16 @@ async def handle_karma_command(room, message, bot, config):
await bot.api.send_markdown_message(room.room_id, "No karma entries found in this room.") await bot.api.send_markdown_message(room.room_id, "No karma entries found in this room.")
return return
# !karma rank <user> # !karma rank <user> - reject Matrix ID
if subcommand == "rank" and len(args) >= 2: if subcommand == "rank" and len(args) >= 2:
display_name = ' '.join(args[1:]) display_name = ' '.join(args[1:])
if is_matrix_id(display_name):
await bot.api.send_markdown_message(room.room_id, "❌ Please use a display name, not a Matrix ID.")
return
user_id = resolve_display_name(room_id, display_name, bot) user_id = resolve_display_name(room_id, display_name, bot)
if not user_id: if not user_id:
await bot.api.send_markdown_message(room.room_id, f"❌ Could not find user '{display_name}'") await bot.api.send_markdown_message(room.room_id, f"❌ Could not find user with display name '{display_name}'")
return return
rank, total = get_rank(room_id, user_id) rank, total = get_rank(room_id, user_id)
@@ -678,13 +703,16 @@ async def handle_karma_command(room, message, bot, config):
await bot.api.send_markdown_message(room.room_id, f"{display_name_resolved} has no karma yet in this room.") await bot.api.send_markdown_message(room.room_id, f"{display_name_resolved} has no karma yet in this room.")
return return
# !karma history <user> # !karma history <user> - reject Matrix ID
if subcommand == "history" and len(args) >= 2: if subcommand == "history" and len(args) >= 2:
display_name = ' '.join(args[1:]) display_name = ' '.join(args[1:])
if is_matrix_id(display_name):
await bot.api.send_markdown_message(room.room_id, "❌ Please use a display name, not a Matrix ID.")
return
user_id = resolve_display_name(room_id, display_name, bot) user_id = resolve_display_name(room_id, display_name, bot)
if not user_id: if not user_id:
await bot.api.send_markdown_message(room.room_id, f"❌ Could not find user '{display_name}'") await bot.api.send_markdown_message(room.room_id, f"❌ Could not find user with display name '{display_name}'")
return return
history = get_recent_history(room_id, user_id, bot, 5) history = get_recent_history(room_id, user_id, bot, 5)
@@ -706,7 +734,7 @@ async def handle_karma_command(room, message, bot, config):
await bot.api.send_markdown_message(room.room_id, f"No karma history for {display_name_resolved} in this room.") await bot.api.send_markdown_message(room.room_id, f"No karma history for {display_name_resolved} in this room.")
return return
# !karma stats # !karma stats - unchanged
if subcommand == "stats": if subcommand == "stats":
stats = get_stats(room_id) stats = get_stats(room_id)
response = f"📊 **Karma System Statistics for this Room**\n\n" response = f"📊 **Karma System Statistics for this Room**\n\n"
@@ -719,12 +747,15 @@ async def handle_karma_command(room, message, bot, config):
await bot.api.send_markdown_message(room.room_id, response) await bot.api.send_markdown_message(room.room_id, response)
return return
# !karma <user> (show karma for specific user) # !karma <user> (show karma for specific user) - reject Matrix ID
display_name = ' '.join(args) display_name = ' '.join(args)
if is_matrix_id(display_name):
await bot.api.send_markdown_message(room.room_id, "❌ Please use a display name, not a Matrix ID.")
return
user_id = resolve_display_name(room_id, display_name, bot) user_id = resolve_display_name(room_id, display_name, bot)
if not user_id: if not user_id:
await bot.api.send_markdown_message(room.room_id, f"❌ Could not find user '{display_name}'") await bot.api.send_markdown_message(room.room_id, f"❌ Could not find user with display name '{display_name}'")
return return
points = get_karma(room_id, user_id) points = get_karma(room_id, user_id)
@@ -755,6 +786,12 @@ async def handle_inline_karma(room, message, bot):
responses = [] responses = []
for display_name, operator in matches: for display_name, operator in matches:
display_name = display_name.strip() display_name = display_name.strip()
# Reject Matrix IDs inline as well
if is_matrix_id(display_name):
logging.debug(f"Skipping inline Matrix ID: '{display_name}'")
continue
change = 1 if operator == '++' else -1 change = 1 if operator == '++' else -1
# Resolve display name to user ID # Resolve display name to user ID
@@ -808,7 +845,7 @@ def setup(bot):
init_db() init_db()
logging.info("Advanced Karma plugin loaded successfully") logging.info("Advanced Karma plugin loaded successfully")
logging.info("Supports display names (e.g., 'Nexilva' or '🍄 HB🍄') and Matrix IDs") logging.info("Matrix IDs are now rejected use display names only.")
logging.info("Commands: !karma, !karma++, !karma--, !++, !--, and inline ++/--") logging.info("Commands: !karma, !karma++, !karma--, !++, !--, and inline ++/--")
logging.info("=" * 50) logging.info("=" * 50)
@@ -817,14 +854,14 @@ def setup(bot):
# Plugin Metadata # Plugin Metadata
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
__version__ = "1.0.0" __version__ = "1.0.1"
__author__ = "Funguy Bot" __author__ = "Funguy Bot"
__description__ = "Room karma tracking system" __description__ = "Room karma tracking system (display names only, no Matrix IDs)"
__help__ = """ __help__ = """
<details> <details>
<summary><strong>!karma</strong> Karma system</summary> <summary><strong>!karma</strong> Karma system</summary>
<ul> <ul>
<li><code>!karma &lt;user&gt;</code> Show points</li> <li><code>!karma &lt;user&gt;</code> Show points (use display name, not Matrix ID)</li>
<li><code>!karma++ &lt;user&gt;</code> / <code>!-- &lt;user&gt;</code> Modify karma</li> <li><code>!karma++ &lt;user&gt;</code> / <code>!-- &lt;user&gt;</code> Modify karma</li>
<li><code>!karma top [n]</code> / <code>!karma bottom [n]</code> Leaderboard</li> <li><code>!karma top [n]</code> / <code>!karma bottom [n]</code> Leaderboard</li>
<li><code>!karma rank &lt;user&gt;</code> Position</li> <li><code>!karma rank &lt;user&gt;</code> Position</li>
@@ -832,5 +869,6 @@ __help__ = """
<li><code>!karma history &lt;user&gt;</code> Recent votes</li> <li><code>!karma history &lt;user&gt;</code> Recent votes</li>
</ul> </ul>
<p>Shortcuts: <code>!++ user</code>, <code>!-- user</code>, and inline <code>user++</code> / <code>user--</code>.</p> <p>Shortcuts: <code>!++ user</code>, <code>!-- user</code>, and inline <code>user++</code> / <code>user--</code>.</p>
<p><strong>Important:</strong> Matrix IDs (like @user:server) are <strong>not accepted</strong>. Use the person's display name exactly as you see it in chat.</p>
</details> </details>
""" """