Commit graph

6723 commits

Author SHA1 Message Date
AI-scor
fa523af857
[Docs] Correct the settings folder paths (#7883) 2026-11-10 20:42:11 +01:00
AI-scor
c27b5e9fcf
Apply else-after-return across the tree (#7884) 2026-11-10 20:41:46 +01:00
AI-scor
e97d3e5519
[Server] Clarify the guards in Server::loginUser (#7886) 2026-11-10 20:40:00 +01:00
AI-scor
105cba6a1c
[Docs] Document TappedOutInterface::analyzeDeck lifecycle (#7887) 2026-11-10 20:38:41 +01:00
AI-scor
77bac3481c
[Docs] List every service in the deck export menu (#7888) 2026-11-10 20:37:54 +01:00
AI-scor
50c9fdb0a2
[Docs] Correct the protocol buffer folder path (#7889) 2026-11-10 20:37:25 +01:00
AI-scor
5c7ac6412e
[Docs] Document what ReleaseChannel::getTargetVersionForCurrentOS returns (#7882) 2026-11-10 18:52:09 +01:00
AI-scor
223ab844a0
[Server] Clarify pingClockTimeout rate limits and idle timeout (#7881) 2026-11-10 18:51:54 +01:00
AI-scor
12884c94dc
Apply typedef across the tree (#7880) 2026-11-10 18:51:43 +01:00
BruebachL
de2ca8d56b
[CI] Keep the benchmark tests out of the per-distro ctest run (#7868)
DeckHashTest.RepeatTest exceeds the per-test 60 s timeout on the Arch
image while finishing in under a second everywhere else, so the Arch leg
is red on every pull request. The suite is labelled `bench` and documented
as kept out of the default run; ctest now skips that label outside the
coverage leg, which still wants those lines exercised.
2026-11-10 18:46:38 +01:00
AI-scor
a0113d0e8a
[Refactor] Name the gates in Server_AbstractPlayer::moveCard (#7879) 2026-11-10 18:25:24 +01:00
AI-scor
58ca953926
[Docs] Document what CrashReporter::sendReport returns (#7877) 2026-11-10 18:04:58 +01:00
AI-scor
7344c96c0a
[Docs] Correct the CUSTOM folder index refresh interval (#7878) 2026-11-10 18:04:29 +01:00
AI-scor
9dc6483f1c
[Refactor] Clarify the restriction checks in Server_Game::checkJoin (#7876) 2026-11-10 16:21:50 +01:00
AI-scor
c1549ed7f5
[Refactor] Extract the per-mode checks from deriveFilterMode (#7875) 2026-11-10 15:50:26 +01:00
AI-scor
60c8e14112
[Docs] Document MoxfieldJsonParser::parse (#7874) 2026-11-10 15:41:01 +01:00
AI-scor
62cb7016f7
refactor: replace NULL with nullptr in the filter builder (#7873) 2026-11-10 15:11:56 +01:00
BruebachL
214b284814
[Server] Add per-run configuration overrides (#7820)
Some checks are pending
CodeQL / Analyze (cpp) (push) Waiting to run
CodeQL / Analyze (actions) (push) Waiting to run
Build Desktop / Configure (push) Waiting to run
Build Desktop / vcpkg baseline (push) Waiting to run
Build Desktop / Debian 13 (push) Blocked by required conditions
Build Desktop / Fedora 45 release (push) Blocked by required conditions
Build Desktop / Fedora 45 debug (push) Blocked by required conditions
Build Desktop / Servatrice_Debian 12 (push) Blocked by required conditions
Build Desktop / Ubuntu 26.04 (push) Blocked by required conditions
Build Desktop / Arch (push) Blocked by required conditions
Build Desktop / Debian 12 (push) Blocked by required conditions
Build Desktop / Fedora 44 (push) Blocked by required conditions
Build Desktop / Ubuntu 24.04 (push) Blocked by required conditions
Build Desktop / Ubuntu 26.04 sanitize (push) Blocked by required conditions
Build Desktop / Ubuntu 26.04 cover (push) Blocked by required conditions
Build Desktop / macOS 14 (push) Blocked by required conditions
Build Desktop / macOS 15 (push) Blocked by required conditions
Build Desktop / macOS 27 Debug (push) Blocked by required conditions
Build Desktop / Windows 10 (push) Blocked by required conditions
Build Desktop / macOS 13 Intel (push) Blocked by required conditions
Build Desktop / Prune caches (push) Waiting to run
Build Docker / Servatrice (arm) (push) Waiting to run
Build Docker / Servatrice (x86) (push) Waiting to run
Build Docker / Publish multi-platform Servatrice image (push) Blocked by required conditions
Add --set key=value to override a section-qualified scalar configuration key for a single run and --print-config to print the effective configuration, with secrets redacted. SettingsCache owns the override map, so reads see the override without rewriting the ini file, and rebuilds the disallowed-name regexps when users/disallowedregexp is overridden. Bare keys and array-scoped keys are rejected because array loops read them relative to the active group, where a full-key override would either be ignored or rewrite every entry.

Cover the ini, default, override, override-only-key, regexp-rebuild, secret-redaction, and parse paths with a server-labelled gtest.
2026-11-10 12:29:45 +01:00
BruebachL
ccda73fe5c
[Server] Smoke-test the dev server end to end (#7865)
* [Server] Smoke-test the dev server end to end

Spawns servatrice-dev on an ephemeral port and drives a real RemoteClient through login, room list, room join and game creation, asserting each response and the Event_GameJoined payload. The test is WITH_SERVER-gated, links only the client remote library, and keeps the dev server's throwaway settings inside a temporary directory.

* [Server] Publish the dev server's port through a file

The smoke test parsed the listening port out of the dev server's stdout,
but the server announces it from the main thread while the logger thread
writes to the same stream. A log line can land inside the announcement —
Arch CI caught it — leaving the digits on the next line, so the test read
nothing and failed.

Add --port-file, written through QSaveFile once the server listens, and
read the port from there instead of from the log. The file is either
absent or complete, so logging cannot corrupt the handshake.

* [Tests] Tick the event loop while waiting for the port file

The port-file wait loop slept with QThread::msleep and never reached the
event dispatcher. QProcess fills its read buffers and flips its state only
from its socket notifiers, so drainProcessOutput() was a no-op and a child
that died before publishing its port went unnoticed until the full 15 s
startup timeout, with empty stdout and stderr in the failure message.

Pump the event loop instead, as the previous waitForReadyRead loop did.
2026-11-10 12:16:36 +01:00
BruebachL
15d69eb929
[Server] Add a servatrice-dev executable on the in-memory database (#7864) 2026-11-10 12:16:36 +01:00
BruebachL
a6d5dd5275
[Server] Build the server startup once for every server executable (#7863) 2026-11-10 12:16:35 +01:00
BruebachL
9315a4aa6d
[Server] Share one in-memory database interface across the server tests (#7862) 2026-11-10 12:16:35 +01:00
BruebachL
3a1238a467
[Server] Create the main database interface through a virtual factory (#7861) 2026-11-10 12:16:34 +01:00
BruebachL
c4ac80e282
[Server] Create the worker database interfaces through the factory (#7860) 2026-11-10 12:16:34 +01:00
BruebachL
0caacb27c1
[Server] Move the database lifecycle calls onto the interface (#7859) 2026-11-10 12:16:34 +01:00
BruebachL
526d528e96
[Server] Serve the e-mail queue through the database interface (#7858) 2026-11-10 12:16:33 +01:00
BruebachL
9087d0d3fe
[Server] Serve the bootstrap rooms through the database interface (#7857) 2026-11-10 12:16:33 +01:00
BruebachL
09d0bed997
[Server] Record uptime through the database interface (#7856) 2026-11-10 12:16:33 +01:00
BruebachL
f1ee6bdc2d
[Server] Serve the server list through the database interface (#7855) 2026-11-10 12:16:32 +01:00
BruebachL
f8f8fffa6b
[Server] Serve the login message through the database interface (#7854) 2026-11-10 12:16:32 +01:00
BruebachL
ec3ad812f0
[Server] Accept the database interface in the connection pool (#7853)
Servatrice_ConnectionPool stored and returned a concrete
Servatrice_DatabaseInterface pointer, so the pool that decides which database a
socket handler runs against could not hold any other Server_DatabaseInterface.
Retype the constructor, member and accessor, and include the interface header
instead of the Servatrice one. The shipped path still builds MySQL pools and
converts implicitly; behaviour is unchanged.
2026-11-10 12:16:31 +01:00
BruebachL
35232cbcf1
[Server] Accept the database interface in the socket handler constructors (#7852)
AbstractServerSocketInterface and its Tcp and Websocket subclasses still took a
concrete Servatrice_DatabaseInterface pointer, so the handler could not be
constructed with anything but the MySQL implementation even though its body now
speaks only Server_DatabaseInterface. Retype the three constructors and drop the
now-unused servatrice_database_interface.h include. Callers pass the pool's
Servatrice_DatabaseInterface, which converts to the base pointer, so behaviour
is unchanged.
2026-11-10 12:16:31 +01:00
BruebachL
99bdcebf2e
[Server] Serve deck storage listings through the database interface (#7851)
deckListHelper still prepared the folder and deck-file statements inline through
Servatrice_DatabaseInterface, and the four deck commands reached checkSql,
getUserIdInDB and getDeckFromDatabase through a concrete pointer. Add
DeckListFolderRecord, DeckListFileRecord, getDeckListFolders and
getDeckListFiles to Server_DatabaseInterface with fail-closed defaults, serve
all four commands from the injected interface, and drop the sqlInterface member
so the handler no longer holds a database implementation at all. Folder
ordering, recursion order, public-only pruning and every response code are
unchanged.
2026-11-10 12:16:30 +01:00
BruebachL
1822d16a72
[Server] Serve card-art rules and params through the database interface (#7850)
The four card-art commands still prepared their statements inline through
Servatrice_DatabaseInterface: the two card_art_params updates in
cmdSetCardArtParams, the rule upsert and delete, and the rule listing that
mapped rows to protocol entries. Add CardArtRuleRecord, upsertCardArtRule,
removeCardArtRule, getCardArtRules, setCardArtParams and clearCardArtParams to
Server_DatabaseInterface with fail-closed defaults, implement them with the
previous statements, and keep the validation, clamping, in-memory userInfo sync
and broadcast in the handler.
2026-11-10 12:16:30 +01:00
BruebachL
2608228bdd
[Server] Serve account moderation through the database interface (#7849)
The moderator account commands still reached Servatrice_DatabaseInterface through
its concrete class: cmdResetUserPassword ran the privilege lookup inline and
called the concrete-only changeUserPasswordWithLegacyBackup, while the avatar,
banner and blacklisted-banner commands called concrete-only helpers. Promote
those four methods to Server_DatabaseInterface, move RemoveUserBannerResult into
the interface, and add getUserAdminFlags for the reset privilege lookup. The
escalation guard, audit records, had_banner response field and every response
code stay in the handler.
2026-11-10 12:16:29 +01:00
BruebachL
f7c6e81347
[Server] Serve account self-service updates through the database interface (#7848)
cmdAccountEdit assembled a dynamic UPDATE for the real name, email and country
columns in the socket handler, and cmdAccountImage wrote the avatar blob there
too. Add AccountUpdateRecord, updateUserAccount and setUserAvatar to
Server_DatabaseInterface with fail-closed defaults, implement them with the
previous query text and bind values, and keep the password gate, the email
permission check, the empty-edit early return and the in-memory userInfo updates
in the handler.
2026-11-10 12:16:29 +01:00
BruebachL
8c8dd0c072
[Server] Serve admin actions through the database interface (#7847)
cmdBanFromServer, the admin-flag helpers, cmdForceActivateUser and the
admin-notes commands still prepared their statements inline through
Servatrice_DatabaseInterface, and addWarning was only reachable through the
concrete Servatrice class. Add setAdminFlag, getUserToken, getAdminNotes,
setAdminNotes, addBan and getUserNamesByClientId to Server_DatabaseInterface
with fail-closed defaults, promote addWarning, and model the outcomes as
UserFieldResult and AdminFlagUpdateResult. Notifications, the audit record,
the ban disconnect fan-out and every response code stay in the handler.
2026-11-10 12:16:28 +01:00
BruebachL
948035af06
[Server] Serve report mutations through the database interface (#7846)
cmdReportAssign, cmdReportResolve, cmdReportReopen and cmdReportAddComment still
ran their lookups and updates inline through Servatrice_DatabaseInterface. Add
assignReport, resolveReport, reopenReport, getUserNameById,
getReportNotificationTarget, countReportCommentsInLastHour,
getReportCommentTarget and addReportComment to Server_DatabaseInterface with
fail-closed defaults, and model the outcomes as ReportAssignResult and
ReportUpdateResult so "no such report", "wrong state" and "query failed" stay
distinguishable. Authorization checks, audit records, notification recipients
and every response code stay in the handler.
2026-11-10 12:16:28 +01:00
BruebachL
a54e13756c
[Server] Serve report aggregates through the database interface (#7845)
cmdReportStats and cmdReportUserInfo still ran their queries inline through
Servatrice_DatabaseInterface and built the response in the socket handler. Add
ReportStatsRecord, ReportUserInfoRecord and their count records to
Server_DatabaseInterface with fail-closed defaults, implement getReportStats and
getReportUserInfo with the previous statements and query order, and keep
presence flags for the fields the old code set only on a successful query so
the proto2 wire output is unchanged. The stats cache decision and every response
code stay in the handler.
2026-11-10 12:16:28 +01:00
BruebachL
2ba80cb61d
[Server] Serve report list views through the database interface (#7844)
cmdReportList, cmdReportMyList and cmdReportDetails still prepared their SELECTs
inline through Servatrice_DatabaseInterface and mapped the result columns to
protocol records in the socket handler. Add getReportList,
getReportsSubmittedBy, getReportForDetails and getReportComments to
Server_DatabaseInterface with fail-closed defaults and a ReportLookupResult
outcome, implement them with the previous statements, joins and null handling,
and keep the detail authorization check and the tolerated comment-query failure
in the handler in the same order. Response codes are unchanged.
2026-11-10 12:16:27 +01:00
BruebachL
fb836c6e0c
[Server] Serve report submission through the database interface (#7843)
cmdReport and sendPendingReportNotifications still issued their SQL inline
through Servatrice_DatabaseInterface: the daily report cap, the reported-user
lookup, the report insert, both pending-notification selects and the notified
flips. Add the two notification records and seven report methods to
Server_DatabaseInterface with fail-closed defaults, implement them with the
previous statements and binds, and let both functions ask the injected
interface. Check order, response codes and notification payloads are unchanged.
2026-11-10 12:16:27 +01:00
BruebachL
9b00972b4d
[Server] Serve password reset from the database interface (#7842)
cmdForgotPasswordRequest, continuePasswordRequest, cmdForgotPasswordReset,
cmdForgotPasswordChallenge, cmdRequestPasswordSalt and cmdSubmitPasswordVerifier
still called Servatrice_DatabaseInterface, and two of them validated the account
token and email through the generic validateTableColumnStringData helper. Add
doesForgotPasswordExist, addForgotPassword and getUsableLegacyBackup to
Server_DatabaseInterface with fail-closed defaults, replace the table/column
probes with userTokenMatches and userEmailMatches using the same statement and
case-insensitive comparison, and let the commands ask the injected interface.
Audit records, check order and every response code are unchanged.
2026-11-10 12:16:26 +01:00
BruebachL
d05198101d
[Server] Serve account registration from the database interface (#7841)
cmdRegisterAccount and cmdActivateAccount still called
Servatrice_DatabaseInterface for username validation, user existence, the
per-email account limit, ban checks, registration and activation, and
cmdRegisterAccount issued the activation-email insert inline. Add
addActivationEmail to Server_DatabaseInterface with a false default, implement
it with the same statement and bind value, and let both commands ask the
injected interface. Validation order and every response code are unchanged.
2026-11-10 12:16:26 +01:00
BruebachL
7719ff021c
[Server] Expose the latest uptime snapshot on the database interface (#7840)
cmdGetServerStats reached through Servatrice_DatabaseInterface for checkSql and
getLatestUptimeSnapshot, a concrete-only method. Move the UptimeSnapshot record
to Server_DatabaseInterface with an invalid default for non-SQL stores, mark the
Servatrice implementation as an override, and let the command ask the injected
interface. The statement, its bind value and the invalid-snapshot response are
unchanged.
2026-11-10 12:16:25 +01:00
BruebachL
03adbd9787
[Server] Move replay code exchange into the database interface (#7839)
createHashForReplay, cmdReplayGetCode, cmdReplaySubmitCode,
cmdReplayDownloadByGameId and cmdGrantReplayAccess still issued their own SQL
through Servatrice_DatabaseInterface. Add checkReplayAccess, getReplayName,
getReplayHashSource, addReplayAccess, getLatestReplayForGame and
grantReplayAccessByName to Server_DatabaseInterface, implement them with the
same statements, bind order and response mapping, and let the commands ask the
injected interface. Hashing and code parsing stay in the handler; the shared
insert is reused by both grant paths.
2026-11-10 12:16:25 +01:00
BruebachL
b2e69d3443
[Server] Move replay access reads and writes into the database interface (#7838)
cmdReplayList, cmdReplayDownload, cmdReplayModifyMatch and cmdReplayDeleteMatch issued their own SQL through Servatrice_DatabaseInterface. Add ReplayMatchRecord/ReplayEntry and the ReplayAccessResult/ReplayWriteResult enums to Server_DatabaseInterface, implement the list, data, do-not-hide and delete operations with the same statements and response mapping, and let the commands ask the injected interface. checkSql stays in the two write commands where it already was.
2026-11-10 12:16:24 +01:00
BruebachL
ba037cbf04
[Server] Move deck share storage into the database interface (#7837)
The five deck-share commands reached through Servatrice_DatabaseInterface for share lookups, and cmdDeckShareCreate still issued the per-user rate-limit count and the folder deck listing inline. Move DeckShareItemRecord and DeckShareSummaryRecord to Server_DatabaseInterface, declare the share operations plus getDeckSharesCreatedToday and getDeckFilesInFolder there with failing defaults, and switch the commands to the injected interface. The MySQL statements and every response code stay as they were, including the -1-on-failure sentinel for the count.
2026-11-10 12:16:24 +01:00
BruebachL
417e7f7db4
[Server] Expose the audit log on the database interface (#7835)
addAuditRecord existed only on Servatrice_DatabaseInterface, so 37 moderator and admin commands reached through the concrete class just to append a log row. Declare it on Server_DatabaseInterface with an empty default, mark the Servatrice implementation as an override, and switch the handler's call sites to the injected interface. No SQL moves; the argument hashes are unchanged.
2026-11-10 12:16:24 +01:00
BruebachL
7734a94f83
[Server] Move deck file writes into the database interface (#7834)
Deleting a deck, inserting an uploaded deck, and updating one in place were SQL statements in the socket handler, including the dynamic is_public clause and the follow-up visibility read. Add DeckFileData and DeckFileWriteResult to Server_DatabaseInterface with create/update/delete operations, implement them in Servatrice_DatabaseInterface with the same statements and bind order, and let cmdDeckUpload and cmdDeckDel ask the injected interface.
2026-11-10 12:16:23 +01:00
BruebachL
23781af1f0
[Server] Move deck folder writes into the database interface (#7833)
Setting a deck or folder public, creating a folder, and deleting a folder tree were SQL statements in the socket handler. Declare them on Server_DatabaseInterface with a DeckStorageResult so the caller can still tell a missing row from a failed write, implement them in Servatrice_DatabaseInterface with the same statements, and let the three folder commands ask the injected interface. Readiness probing keeps its previous ignore-the-result shape.
2026-11-10 12:16:23 +01:00