second pass at fixing psql compat while maintaining sqlite functionality

This commit is contained in:
William Kray
2025-06-29 10:14:54 -07:00
parent b8e3c0cc19
commit f4e4440122
2 changed files with 47 additions and 39 deletions
+46 -38
View File
@@ -1035,6 +1035,25 @@ class CommunityBot(Plugin):
f"Phrase does not match, you have {state['attempts']} tries remaining." f"Phrase does not match, you have {state['attempts']} tries remaining."
) )
async def upsert_user_timestamp(self, mxid: str, timestamp: int) -> None:
"""Database-agnostic upsert for user timestamp updates."""
try:
# Try insert first
await self.database.execute(
"INSERT INTO user_events(mxid, last_message_timestamp) VALUES ($1, $2)",
mxid, timestamp
)
except Exception as e:
# If insert fails due to existing record, update instead
if "UNIQUE constraint failed" in str(e) or "duplicate key" in str(e).lower():
await self.database.execute(
"UPDATE user_events SET last_message_timestamp = $2 WHERE mxid = $1",
mxid, timestamp
)
else:
# Re-raise if it's not a constraint violation
raise
@event.on(EventType.ROOM_MESSAGE) @event.on(EventType.ROOM_MESSAGE)
async def update_message_timestamp(self, evt: MessageEvent) -> None: async def update_message_timestamp(self, evt: MessageEvent) -> None:
power_levels = await self.client.get_state_event( power_levels = await self.client.get_state_event(
@@ -1085,13 +1104,7 @@ class CommunityBot(Plugin):
if evt.room_id not in rooms_to_manage: if evt.room_id not in rooms_to_manage:
return return
else: else:
q = """ await self.upsert_user_timestamp(evt.sender, evt.timestamp)
INSERT INTO user_events(mxid, last_message_timestamp)
VALUES ($1, $2)
ON CONFLICT(mxid)
DO UPDATE SET last_message_timestamp=$2
"""
await self.database.execute(q, evt.sender, evt.timestamp)
@event.on(EventType.REACTION) @event.on(EventType.REACTION)
async def update_reaction_timestamp(self, evt: MessageEvent) -> None: async def update_reaction_timestamp(self, evt: MessageEvent) -> None:
@@ -1104,13 +1117,7 @@ class CommunityBot(Plugin):
if evt.room_id not in rooms_to_manage: if evt.room_id not in rooms_to_manage:
return return
else: else:
q = """ await self.upsert_user_timestamp(evt.sender, evt.timestamp)
INSERT INTO user_events(mxid, last_message_timestamp)
VALUES ($1, $2)
ON CONFLICT(mxid)
DO UPDATE SET last_message_timestamp=$2
"""
await self.database.execute(q, evt.sender, evt.timestamp)
@command.new("community", help="manage rooms and members of a space") @command.new("community", help="manage rooms and members of a space")
async def community(self) -> None: async def community(self) -> None:
@@ -2146,29 +2153,8 @@ class CommunityBot(Plugin):
async def store_verification_state(self, dm_room_id: str, state: dict) -> None: async def store_verification_state(self, dm_room_id: str, state: dict) -> None:
"""Store verification state in the database.""" """Store verification state in the database."""
# First try to update # Try to insert first, if it fails due to existing record, then update
update_query = """UPDATE verification_states try:
SET verification_phrase = $4, \
attempts_remaining = $5, \
required_power_level = $6, \
user_id = $2, \
target_room_id = $3 \
WHERE dm_room_id = $1"""
self.log.debug(f"Attempting update for verification state begin, specifically for {dm_room_id}")
result = await self.database.execute(update_query, dm_room_id,
state["user"],
state["target_room"],
state["phrase"],
state["attempts"],
state["required_level"]
)
self.log.debug(f"Result is: {result}")
# If no rows were updated, insert a new record
# postgresql response is "UPDATE 0"
# sqllite response is ???
if result == "UPDATE 0": # No rows affected
self.log.debug("No rows updated, so doing insert!")
insert_query = """INSERT INTO verification_states insert_query = """INSERT INTO verification_states
(dm_room_id, user_id, target_room_id, verification_phrase, attempts_remaining, \ (dm_room_id, user_id, target_room_id, verification_phrase, attempts_remaining, \
required_power_level) required_power_level)
@@ -2180,7 +2166,29 @@ class CommunityBot(Plugin):
state["attempts"], state["attempts"],
state["required_level"] state["required_level"]
) )
self.log.debug("Should be done with verification state storage, should've updated or inserted!") self.log.debug(f"Inserted new verification state for {dm_room_id}")
except Exception as e:
# If insert fails (likely due to existing record), try update
if "UNIQUE constraint failed" in str(e) or "duplicate key" in str(e).lower():
self.log.debug(f"Record exists for {dm_room_id}, updating instead")
update_query = """UPDATE verification_states
SET verification_phrase = $4, \
attempts_remaining = $5, \
required_power_level = $6, \
user_id = $2, \
target_room_id = $3 \
WHERE dm_room_id = $1"""
await self.database.execute(update_query, dm_room_id,
state["user"],
state["target_room"],
state["phrase"],
state["attempts"],
state["required_level"]
)
self.log.debug(f"Updated verification state for {dm_room_id}")
else:
# Re-raise if it's not a constraint violation
raise
async def get_verification_state(self, dm_room_id: str) -> Optional[dict]: async def get_verification_state(self, dm_room_id: str) -> Optional[dict]:
"""Retrieve verification state from the database.""" """Retrieve verification state from the database."""
+1 -1
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env bash #!/usr/bin/env bash
docker run \ docker run --rm \
-v "$PWD"/data:/data \ -v "$PWD"/data:/data \
-v "$PWD":/opt/communitybot \ -v "$PWD":/opt/communitybot \
--user $UID:$GID \ --user $UID:$GID \