Updated karma 1 hour per target rate limit. Updated requirements.txt and README.md
This commit is contained in:
+32
-34
@@ -37,13 +37,14 @@ from datetime import datetime, timedelta
|
||||
import re
|
||||
import asyncio
|
||||
import traceback
|
||||
import time
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Configuration
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Prevent spam: minimum seconds between karma changes to same target by same user
|
||||
COOLDOWN_SECONDS = 5
|
||||
# Global cooldown: one karma point per hour per voter
|
||||
COOLDOWN_SECONDS = 3600
|
||||
|
||||
# Database file
|
||||
DB_FILE = "karma.db"
|
||||
@@ -55,7 +56,6 @@ display_name_cache = {}
|
||||
# Last time we refreshed the cache (per room)
|
||||
cache_timestamp = {}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Helper: pluralize "point" vs "points"
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -130,37 +130,31 @@ async def refresh_display_name_cache(bot, room_id):
|
||||
logging.info(f"Refreshing display name cache for room {room_id}")
|
||||
|
||||
try:
|
||||
# Try to get room members from the bot's state
|
||||
if hasattr(bot, 'async_client') and bot.async_client:
|
||||
# Get the room state
|
||||
room = bot.async_client.rooms.get(room_id)
|
||||
if room and hasattr(room, 'users'):
|
||||
# Build mapping of display names to user IDs
|
||||
resp = await bot.async_client.joined_members(room_id)
|
||||
if resp.members is not None:
|
||||
name_map = {}
|
||||
for user_id, user_info in room.users.items():
|
||||
# Get display name - try different attributes
|
||||
display_name = None
|
||||
if hasattr(user_info, 'display_name') and user_info.display_name:
|
||||
display_name = user_info.display_name
|
||||
elif hasattr(user_info, 'name') and user_info.name:
|
||||
display_name = user_info.name
|
||||
|
||||
for member in resp.members:
|
||||
display_name = (member.display_name or "").strip()
|
||||
if display_name:
|
||||
name_map[display_name.lower()] = user_id
|
||||
# Also store without emojis for easier matching
|
||||
name_map[display_name.lower()] = member.user_id
|
||||
# Also store without emojis
|
||||
clean_name = re.sub(r'[^\w\s]', '', display_name).strip().lower()
|
||||
if clean_name and clean_name != display_name.lower():
|
||||
name_map[clean_name] = user_id
|
||||
|
||||
name_map[clean_name] = member.user_id
|
||||
display_name_cache[room_id] = name_map
|
||||
cache_timestamp[room_id] = now
|
||||
logging.info(f"Cached {len(name_map)} display names for room {room_id}")
|
||||
# DEBUG: show first 5 names
|
||||
sample = list(name_map.items())[:5]
|
||||
logging.debug(f"Sample display names: {sample}")
|
||||
return
|
||||
|
||||
else:
|
||||
logging.warning(f"joined_members returned None members for room {room_id}")
|
||||
except Exception as e:
|
||||
logging.warning(f"Could not refresh display name cache: {e}")
|
||||
|
||||
# If we couldn't get members, initialize empty cache
|
||||
# init empty cache on failure
|
||||
display_name_cache[room_id] = {}
|
||||
cache_timestamp[room_id] = now
|
||||
|
||||
@@ -176,7 +170,10 @@ def resolve_display_name(room_id, display_name, bot=None):
|
||||
Returns None if the input is a Matrix ID (rejected) or if the name
|
||||
cannot be resolved.
|
||||
"""
|
||||
# Reject Matrix IDs outright
|
||||
# Strip HTML tags (Matrix mention pills)
|
||||
clean = re.sub(r'<[^>]+>', '', display_name).strip()
|
||||
|
||||
# Reject Matrix IDs outright (only if the raw input is an ID, not the cleaned one)
|
||||
if is_matrix_id(display_name):
|
||||
return None
|
||||
|
||||
@@ -184,21 +181,16 @@ def resolve_display_name(room_id, display_name, bot=None):
|
||||
if room_id in display_name_cache:
|
||||
name_map = display_name_cache[room_id]
|
||||
|
||||
# Try exact match (case-insensitive)
|
||||
key = display_name.lower()
|
||||
# Try exact match (case‑insensitive)
|
||||
key = clean.lower()
|
||||
if key in name_map:
|
||||
return name_map[key]
|
||||
|
||||
# Try without emojis/special characters
|
||||
clean_key = re.sub(r'[^\w\s]', '', display_name).strip().lower()
|
||||
clean_key = re.sub(r'[^\w\s]', '', clean).strip().lower()
|
||||
if clean_key and clean_key in name_map:
|
||||
return name_map[clean_key]
|
||||
|
||||
# Try partial match (if display name is contained in a cached name)
|
||||
for cached_name, user_id in name_map.items():
|
||||
if key in cached_name or cached_name in key:
|
||||
return user_id
|
||||
|
||||
return None
|
||||
|
||||
|
||||
@@ -567,7 +559,13 @@ async def process_karma_vote(room, display_name, action, voter, bot):
|
||||
# Check cooldown
|
||||
if is_on_cooldown(room_id, user_id, voter_str):
|
||||
remaining = get_cooldown_remaining(room_id, user_id, voter_str)
|
||||
await bot.api.send_markdown_message(room.room_id, f"⏳ You're doing that too fast! Wait {remaining} seconds.")
|
||||
hours = remaining // 3600
|
||||
minutes = (remaining % 3600) // 60
|
||||
if hours > 0:
|
||||
time_str = f"{hours}h {minutes}m"
|
||||
else:
|
||||
time_str = f"{minutes}m"
|
||||
await bot.api.send_markdown_message(room.room_id, f"⏳ Slow down! You can give karma to that user again in {time_str}.")
|
||||
return
|
||||
|
||||
# Update karma
|
||||
@@ -635,7 +633,7 @@ async def handle_karma_command(room, message, bot, config):
|
||||
<strong>Notes:</strong>
|
||||
<ul>
|
||||
<li>You cannot modify your own karma</li>
|
||||
<li>There is a {COOLDOWN_SECONDS} second cooldown between votes</li>
|
||||
<li>There is a 1‑hour cooldown per user you give karma to</li>
|
||||
<li>Karma is tracked separately per room</li>
|
||||
<li>Display names with emojis are supported</li>
|
||||
</ul>
|
||||
@@ -784,7 +782,7 @@ async def handle_inline_karma(room, message, bot):
|
||||
if not matches:
|
||||
return
|
||||
|
||||
logging.info(f"Found inline karma matches: {matches}")
|
||||
logging.debug(f"Found inline karma matches: {matches}")
|
||||
|
||||
responses = []
|
||||
for display_name, operator in matches:
|
||||
|
||||
Reference in New Issue
Block a user