Cockatrice/servatrice/src/private_chat_paging.h
SwitchOCE 7709184ecc
[Server] Let users fetch their own private chat history (#7506)
* [Server] Let users fetch their own private chat history

Players lose their private conversations on reconnect or on another
device. Servatrice can already log private messages, but only
moderators can read the logs.

Add Command_GetPrivateChatHistory / Response_PrivateChatHistory so a
registered user can page through their own logged conversation with one
other user. Operators opt in with logging/allow_user_chat_history
(default off, and log_user_msg_chat must be on). The caller is matched
by account id so reused guest or deleted-account names can't read older
messages; only time, sender name and text are returned. Pages hold
1..200 messages and never split a second, since log_time has 1-second
resolution.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* [Server] Harden private chat history identity matching

Match both participants by account id and name so a federated user's remote id cannot collide with a local account, and stop storing foreign ids in the local chat log. Extract the paging assembly into a pure helper and cover the whole-second boundary rules with gtests.

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Lukas Brübach <44814898+BruebachL@users.noreply.github.com>
2026-11-09 13:21:43 +01:00

30 lines
1.1 KiB
C

#ifndef PRIVATE_CHAT_PAGING_H
#define PRIVATE_CHAT_PAGING_H
#include <QList>
#include <libcockatrice/protocol/pb/serverinfo_private_chat_message.pb.h>
/** One page of private chat history, ready for the response. */
struct PrivateChatPage
{
/** Messages for the response, oldest first. */
QList<ServerInfo_PrivateChatMessage> messages;
/** Whether messages older than this page may still exist. */
bool hasMore = false;
/**
* Set when every fetched message belongs to the same second, so the caller
* has to fetch that whole second before it can answer. messages is empty in
* that case and boundarySecond names the second to fetch.
*/
bool needsWholeSecond = false;
quint64 boundarySecond = 0;
};
/**
* Assembles one newest-first page from up to limit + 1 messages ordered newest
* first. A second is never split across pages: when the limit would cut into a
* second, that whole second is deferred to the next page instead.
*/
PrivateChatPage assemblePrivateChatPage(const QList<ServerInfo_PrivateChatMessage> &newestFirst, int limit);
#endif // PRIVATE_CHAT_PAGING_H