mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 02:43:44 +00:00
feat: online players get grant changes at once
Adding or removing a grant sends the existing PLAYER_ACTION refresh through master to every world: REFRESH_ACCOUNT for an account's grants, REFRESH_CHARACTER for a character's. A world with that account's sessions (or the loaded character) drops the grants it kept, so the next command reads them again: no relog. The dashboard toasts whether the player was online. The dashboard's own open pages already get the new rights on their next request, and their WebSockets are checked again. Check: with a character in game, grant it /spawn on the dashboard (toast: "Applied in game at once") and use /spawn without relogging; remove the grant and /spawn is refused again at once. With the player offline the toast says it applies when they next play. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,8 @@
|
||||
#include "eHTTPMethod.h"
|
||||
#include "Game.h"
|
||||
#include "GeneralUtils.h"
|
||||
#include "master/PlayerAction.h"
|
||||
#include "PlayerActions.h"
|
||||
#include "HTTPContext.h"
|
||||
#include "PermissionGrants.h"
|
||||
#include "Permissions.h"
|
||||
@@ -168,10 +170,23 @@ namespace {
|
||||
std::map<uint32_t, bool> manageable;
|
||||
};
|
||||
|
||||
// Grants apply at once: the dashboard's open pages get their account's rights again
|
||||
void Applied(const Target& target) {
|
||||
/**
|
||||
* Grants apply at once: the dashboard's open pages get their account's rights again, and the world servers read the
|
||||
* grants of the account's online sessions (or the character, if it is loaded) again, as for a GM level change.
|
||||
* Returns the request ID of the refresh (the page shows its result).
|
||||
*/
|
||||
uint32_t Applied(const HTTPContext& context, const Target& target) {
|
||||
Game::web.RecheckWebSockets(target.accountId);
|
||||
BroadcastTableChanged("grants", std::to_string(target.accountId));
|
||||
PlayerActionRequest request;
|
||||
const bool account = target.type == PermissionGrants::ACCOUNT;
|
||||
request.action = account ? ePlayerAction::REFRESH_ACCOUNT : ePlayerAction::REFRESH_CHARACTER;
|
||||
request.accountId = target.accountId;
|
||||
request.characterId = account ? 0 : target.id;
|
||||
return PlayerActions::Request(request, context.accountId, [account](const PlayerActionResult& result) {
|
||||
if (result.affected == 0) return PlayerActions::Outcome{ true, account ? "The account isn't online; it applies when they next play" : "The character isn't online; it applies when they next play" };
|
||||
return PlayerActions::Outcome{ true, "Applied in game at once" };
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,8 +302,8 @@ void GrantRoutes::RegisterRoutes() {
|
||||
const auto description = std::string(deny ? "Took away " : "Granted ") + what + (deny ? " from " : " to ") + target->Describe() +
|
||||
(expiresAt ? " until " + UtcTime(expiresAt) : "") + (note.empty() ? "" : ": " + note) + OwnAccountNote(context.accountId, target->accountId);
|
||||
Audit(context, deny ? "deny_permission" : "grant_permission", description, target->Audit());
|
||||
Applied(*target);
|
||||
JsonSuccess(reply, { {"id", grant.id}, {"message", std::string(deny ? "Took away " : "Granted ") + what} });
|
||||
const auto requestId = Applied(context, *target);
|
||||
JsonSuccess(reply, { {"id", grant.id}, {"requestId", requestId}, {"message", std::string(deny ? "Took away " : "Granted ") + what} });
|
||||
});
|
||||
|
||||
Route(eHTTPMethod::POST, "/api/grants/:id/remove", Perm(MANAGE),
|
||||
@@ -311,7 +326,7 @@ void GrantRoutes::RegisterRoutes() {
|
||||
const auto what = PermissionGrants::Describe(*kind, grant->name);
|
||||
Audit(context, "remove_grant", std::string("Removed the ") + (grant->deny ? "deny of " : "grant of ") + what + (grant->deny ? " from " : " to ") +
|
||||
target->Describe() + " (given by " + grant->grantedBy + ")" + OwnAccountNote(context.accountId, target->accountId), target->Audit());
|
||||
Applied(*target);
|
||||
JsonSuccess(reply, { {"message", std::string("Removed the ") + (grant->deny ? "deny of " : "grant of ") + what} });
|
||||
const auto requestId = Applied(context, *target);
|
||||
JsonSuccess(reply, { {"requestId", requestId}, {"message", std::string("Removed the ") + (grant->deny ? "deny of " : "grant of ") + what} });
|
||||
});
|
||||
}
|
||||
|
||||
@@ -48,10 +48,12 @@ namespace {
|
||||
return static_cast<uint32_t>(users.size());
|
||||
}
|
||||
|
||||
// Pick up a GM level change: lower the in-game level if it now exceeds the account's maximum
|
||||
// Pick up a GM level change: lower the in-game level if it now exceeds the account's maximum. Also a change of the
|
||||
// account's permission grants: they are read again the next time a command is used
|
||||
uint32_t RefreshAccount(uint32_t accountId) {
|
||||
const auto users = UserManager::Instance()->GetUsersForAccount(accountId);
|
||||
if (users.empty()) return 0;
|
||||
for (auto* user : users) user->ForgetGrants();
|
||||
|
||||
const auto info = Database::Get()->GetAccountInfo(users.front()->GetUsername());
|
||||
if (!info) return 0;
|
||||
@@ -83,10 +85,12 @@ namespace {
|
||||
return static_cast<uint32_t>(users.size());
|
||||
}
|
||||
|
||||
// Restrictions or permission grants of a character changed
|
||||
uint32_t RefreshCharacter(LWOOBJID characterId) {
|
||||
auto* entity = PlayerManager::GetPlayer(characterId);
|
||||
auto* character = entity ? entity->GetCharacter() : nullptr;
|
||||
if (!character) return 0;
|
||||
if (auto* user = character->GetParentUser()) user->ForgetGrants();
|
||||
|
||||
const auto info = Database::Get()->GetCharacterInfo(characterId);
|
||||
if (!info) return 0;
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
*/
|
||||
enum class ePlayerAction : uint8_t {
|
||||
KICK_ACCOUNT, // Disconnect every session of accountId
|
||||
REFRESH_ACCOUNT, // Reload account data (GM level) for online sessions of accountId
|
||||
REFRESH_CHARACTER, // Reload character data (restrictions) for characterId if loaded
|
||||
REFRESH_ACCOUNT, // Reload account data (GM level, permission grants) for online sessions of accountId
|
||||
REFRESH_CHARACTER, // Reload character data (restrictions, permission grants) for characterId if loaded
|
||||
RESCUE_CHARACTER, // Transfer characterId to zoneId if it is loaded in a world, landing on spawn point `text` (empty: the zone's default)
|
||||
// Tell a player a moderator decided on something they asked for (approved = yes/no, text = name or reason)
|
||||
NAME_MODERATED, // characterId's requested name; text is the name
|
||||
|
||||
Reference in New Issue
Block a user