mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-11-14 07:47:13 +00:00
feat(db): zone edit locks and zone editors
Tables for the one account holding a zone's lock and for each zone's assigned editors, on MySQL and SQLite, with the interface and the test database. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
@@ -50,6 +50,7 @@
|
||||
#include "IFeaturedProperties.h"
|
||||
#include "IMessageCaptures.h"
|
||||
#include "IContraband.h"
|
||||
#include "IZoneEditing.h"
|
||||
#include "IPropertyRent.h"
|
||||
#include "IPropertyReputation.h"
|
||||
#include "IBbbAutosave.h"
|
||||
@@ -72,7 +73,7 @@ class GameDatabase :
|
||||
public IPropertyContents, public IProperty, public IPetNames, public ICharXml,
|
||||
public IMigrationHistory, public IUgc, public IFriends, public ICharInfo,
|
||||
public IAccounts, public IActivityLog, public IAccountsRewardCodes, public IIgnoreList,
|
||||
public IBehaviors, public IUgcModularBuild, public IAuditLog, public IDashboardStats, public IAccountEmails, public IDashboardMaintenance, public IEconomyLedger, public IDashboardAdmin, public IServerConfig, public IScheduledTasks, public ICharacterSnapshots, public IAccountNotes, public IServerHealth, public IRelatedData, public IChatLog, public IChatFlags, public IClientSysInfo, public IAccountStrikes, public ISlashCommands, public IModeration, public IServerOperations, public IPlayerPositions, public IAiSuggestions, public ILiveOps, public IFeaturedProperties, public IMessageCaptures, public IContraband, public IPropertyRent, public IPropertyReputation, public IBbbAutosave, public IServerTraffic, public IApiKeys, public IUgcLookup, public IPermissionGrants, public IGuilds, public IDatabaseUsage {
|
||||
public IBehaviors, public IUgcModularBuild, public IAuditLog, public IDashboardStats, public IAccountEmails, public IDashboardMaintenance, public IEconomyLedger, public IDashboardAdmin, public IServerConfig, public IScheduledTasks, public ICharacterSnapshots, public IAccountNotes, public IServerHealth, public IRelatedData, public IChatLog, public IChatFlags, public IClientSysInfo, public IAccountStrikes, public ISlashCommands, public IModeration, public IServerOperations, public IPlayerPositions, public IAiSuggestions, public ILiveOps, public IFeaturedProperties, public IMessageCaptures, public IContraband, public IPropertyRent, public IPropertyReputation, public IBbbAutosave, public IServerTraffic, public IApiKeys, public IUgcLookup, public IPermissionGrants, public IGuilds, public IDatabaseUsage, public IZoneEditing {
|
||||
public:
|
||||
virtual ~GameDatabase() = default;
|
||||
// TODO: These should be made private.
|
||||
|
||||
45
dDatabase/GameDatabase/ITables/IZoneEditing.h
Normal file
45
dDatabase/GameDatabase/ITables/IZoneEditing.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#ifndef __IZONEEDITING__H__
|
||||
#define __IZONEEDITING__H__
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* Who may edit a zone's files (ZoneEditLock.h, docs/ZonePublish.md): each zone's assigned editors, and the one
|
||||
* account holding its lock. The rules are ZoneEditLock's; these are only the rows.
|
||||
*/
|
||||
class IZoneEditing {
|
||||
public:
|
||||
struct ZoneLock {
|
||||
uint32_t zoneId{};
|
||||
uint32_t accountId{};
|
||||
int64_t lockedAt{};
|
||||
};
|
||||
|
||||
struct ZoneEditor {
|
||||
uint32_t zoneId{};
|
||||
uint32_t accountId{};
|
||||
std::string assignedBy;
|
||||
int64_t assignedAt{};
|
||||
};
|
||||
|
||||
virtual std::optional<ZoneLock> GetZoneLock(uint32_t zoneId) = 0;
|
||||
// Every held lock, by zone
|
||||
virtual std::vector<ZoneLock> GetZoneLocks() = 0;
|
||||
// Takes the zone's lock when nobody holds it; false when someone does (one statement, so two takers can't both win)
|
||||
virtual bool TakeZoneLock(uint32_t zoneId, uint32_t accountId, int64_t time) = 0;
|
||||
// Whether there was a lock to release
|
||||
virtual bool ReleaseZoneLock(uint32_t zoneId) = 0;
|
||||
|
||||
// A zone's editors, by account; zoneId 0: every zone's, by zone then account
|
||||
virtual std::vector<ZoneEditor> GetZoneEditors(uint32_t zoneId) = 0;
|
||||
virtual bool IsZoneEditor(uint32_t zoneId, uint32_t accountId) = 0;
|
||||
// Adds the account to the zone's editors unless it is one
|
||||
virtual void AddZoneEditor(const ZoneEditor& editor) = 0;
|
||||
// Whether the account was one of the zone's editors
|
||||
virtual bool RemoveZoneEditor(uint32_t zoneId, uint32_t accountId) = 0;
|
||||
};
|
||||
|
||||
#endif //!__IZONEEDITING__H__
|
||||
@@ -287,6 +287,15 @@ public:
|
||||
void SetPropertyRent(LWOOBJID propertyId, int64_t amount, int64_t due) override;
|
||||
void SetPropertyPrivacy(LWOOBJID propertyId, int32_t privacyOption) override;
|
||||
|
||||
// IZoneEditing
|
||||
std::optional<ZoneLock> GetZoneLock(uint32_t zoneId) override;
|
||||
std::vector<ZoneLock> GetZoneLocks() override;
|
||||
bool TakeZoneLock(uint32_t zoneId, uint32_t accountId, int64_t time) override;
|
||||
bool ReleaseZoneLock(uint32_t zoneId) override;
|
||||
std::vector<ZoneEditor> GetZoneEditors(uint32_t zoneId) override;
|
||||
bool IsZoneEditor(uint32_t zoneId, uint32_t accountId) override;
|
||||
void AddZoneEditor(const ZoneEditor& editor) override;
|
||||
bool RemoveZoneEditor(uint32_t zoneId, uint32_t accountId) override;
|
||||
// IContraband
|
||||
std::vector<ContrabandItem> GetContrabandItems() override;
|
||||
void SetContrabandItem(const ContrabandItem& item) override;
|
||||
|
||||
@@ -22,6 +22,7 @@ set(DDATABASES_DATABASES_MYSQL_TABLES_SOURCES
|
||||
"LiveOps.cpp"
|
||||
"FeaturedProperties.cpp"
|
||||
"Contraband.cpp"
|
||||
"ZoneEditing.cpp"
|
||||
"PropertyRent.cpp"
|
||||
"PropertyReputation.cpp"
|
||||
"BbbAutosave.cpp"
|
||||
|
||||
46
dDatabase/GameDatabase/MySQL/Tables/ZoneEditing.cpp
Normal file
46
dDatabase/GameDatabase/MySQL/Tables/ZoneEditing.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
#include "MySQLDatabase.h"
|
||||
|
||||
std::optional<IZoneEditing::ZoneLock> MySQLDatabase::GetZoneLock(uint32_t zoneId) {
|
||||
auto result = ExecuteSelect("SELECT zone_id, account_id, locked_at FROM zone_edit_locks WHERE zone_id = ?;", zoneId);
|
||||
if (!result->next()) return std::nullopt;
|
||||
return ZoneLock{ result->getUInt("zone_id"), result->getUInt("account_id"), result->getInt64("locked_at") };
|
||||
}
|
||||
|
||||
std::vector<IZoneEditing::ZoneLock> MySQLDatabase::GetZoneLocks() {
|
||||
std::vector<ZoneLock> locks;
|
||||
auto result = ExecuteSelect("SELECT zone_id, account_id, locked_at FROM zone_edit_locks ORDER BY zone_id;");
|
||||
while (result->next()) locks.push_back({ result->getUInt("zone_id"), result->getUInt("account_id"), result->getInt64("locked_at") });
|
||||
return locks;
|
||||
}
|
||||
|
||||
bool MySQLDatabase::TakeZoneLock(uint32_t zoneId, uint32_t accountId, int64_t time) {
|
||||
return ExecuteUpdate("INSERT IGNORE INTO zone_edit_locks (zone_id, account_id, locked_at) VALUES (?, ?, ?);", zoneId, accountId, time) > 0;
|
||||
}
|
||||
|
||||
bool MySQLDatabase::ReleaseZoneLock(uint32_t zoneId) {
|
||||
return ExecuteUpdate("DELETE FROM zone_edit_locks WHERE zone_id = ?;", zoneId) > 0;
|
||||
}
|
||||
|
||||
std::vector<IZoneEditing::ZoneEditor> MySQLDatabase::GetZoneEditors(uint32_t zoneId) {
|
||||
std::vector<ZoneEditor> editors;
|
||||
auto result = ExecuteSelect(
|
||||
"SELECT zone_id, account_id, assigned_by, assigned_at FROM zone_editors WHERE (? = 0 OR zone_id = ?) ORDER BY zone_id, account_id;", zoneId, zoneId);
|
||||
while (result->next()) {
|
||||
editors.push_back({ result->getUInt("zone_id"), result->getUInt("account_id"), result->getString("assigned_by").c_str(), result->getInt64("assigned_at") });
|
||||
}
|
||||
return editors;
|
||||
}
|
||||
|
||||
bool MySQLDatabase::IsZoneEditor(uint32_t zoneId, uint32_t accountId) {
|
||||
auto result = ExecuteSelect("SELECT 1 FROM zone_editors WHERE zone_id = ? AND account_id = ?;", zoneId, accountId);
|
||||
return result->next();
|
||||
}
|
||||
|
||||
void MySQLDatabase::AddZoneEditor(const ZoneEditor& editor) {
|
||||
ExecuteInsert("INSERT IGNORE INTO zone_editors (zone_id, account_id, assigned_by, assigned_at) VALUES (?, ?, ?, ?);",
|
||||
editor.zoneId, editor.accountId, editor.assignedBy, editor.assignedAt);
|
||||
}
|
||||
|
||||
bool MySQLDatabase::RemoveZoneEditor(uint32_t zoneId, uint32_t accountId) {
|
||||
return ExecuteUpdate("DELETE FROM zone_editors WHERE zone_id = ? AND account_id = ?;", zoneId, accountId) > 0;
|
||||
}
|
||||
@@ -271,6 +271,15 @@ public:
|
||||
void SetPropertyRent(LWOOBJID propertyId, int64_t amount, int64_t due) override;
|
||||
void SetPropertyPrivacy(LWOOBJID propertyId, int32_t privacyOption) override;
|
||||
|
||||
// IZoneEditing
|
||||
std::optional<ZoneLock> GetZoneLock(uint32_t zoneId) override;
|
||||
std::vector<ZoneLock> GetZoneLocks() override;
|
||||
bool TakeZoneLock(uint32_t zoneId, uint32_t accountId, int64_t time) override;
|
||||
bool ReleaseZoneLock(uint32_t zoneId) override;
|
||||
std::vector<ZoneEditor> GetZoneEditors(uint32_t zoneId) override;
|
||||
bool IsZoneEditor(uint32_t zoneId, uint32_t accountId) override;
|
||||
void AddZoneEditor(const ZoneEditor& editor) override;
|
||||
bool RemoveZoneEditor(uint32_t zoneId, uint32_t accountId) override;
|
||||
// IContraband
|
||||
std::vector<ContrabandItem> GetContrabandItems() override;
|
||||
void SetContrabandItem(const ContrabandItem& item) override;
|
||||
|
||||
@@ -22,6 +22,7 @@ set(DDATABASES_DATABASES_SQLITE_TABLES_SOURCES
|
||||
"LiveOps.cpp"
|
||||
"FeaturedProperties.cpp"
|
||||
"Contraband.cpp"
|
||||
"ZoneEditing.cpp"
|
||||
"PropertyRent.cpp"
|
||||
"PropertyReputation.cpp"
|
||||
"BbbAutosave.cpp"
|
||||
|
||||
49
dDatabase/GameDatabase/SQLite/Tables/ZoneEditing.cpp
Normal file
49
dDatabase/GameDatabase/SQLite/Tables/ZoneEditing.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
#include "SQLiteDatabase.h"
|
||||
|
||||
std::optional<IZoneEditing::ZoneLock> SQLiteDatabase::GetZoneLock(uint32_t zoneId) {
|
||||
auto [_, result] = ExecuteSelect("SELECT zone_id, account_id, locked_at FROM zone_edit_locks WHERE zone_id = ?;", zoneId);
|
||||
if (result.eof()) return std::nullopt;
|
||||
return ZoneLock{ static_cast<uint32_t>(result.getIntField("zone_id")), static_cast<uint32_t>(result.getIntField("account_id")), result.getInt64Field("locked_at") };
|
||||
}
|
||||
|
||||
std::vector<IZoneEditing::ZoneLock> SQLiteDatabase::GetZoneLocks() {
|
||||
std::vector<ZoneLock> locks;
|
||||
auto [_, result] = ExecuteSelect("SELECT zone_id, account_id, locked_at FROM zone_edit_locks ORDER BY zone_id;");
|
||||
for (; !result.eof(); result.nextRow()) {
|
||||
locks.push_back({ static_cast<uint32_t>(result.getIntField("zone_id")), static_cast<uint32_t>(result.getIntField("account_id")), result.getInt64Field("locked_at") });
|
||||
}
|
||||
return locks;
|
||||
}
|
||||
|
||||
bool SQLiteDatabase::TakeZoneLock(uint32_t zoneId, uint32_t accountId, int64_t time) {
|
||||
return ExecuteUpdate("INSERT OR IGNORE INTO zone_edit_locks (zone_id, account_id, locked_at) VALUES (?, ?, ?);", zoneId, accountId, time) > 0;
|
||||
}
|
||||
|
||||
bool SQLiteDatabase::ReleaseZoneLock(uint32_t zoneId) {
|
||||
return ExecuteUpdate("DELETE FROM zone_edit_locks WHERE zone_id = ?;", zoneId) > 0;
|
||||
}
|
||||
|
||||
std::vector<IZoneEditing::ZoneEditor> SQLiteDatabase::GetZoneEditors(uint32_t zoneId) {
|
||||
std::vector<ZoneEditor> editors;
|
||||
auto [_, result] = ExecuteSelect(
|
||||
"SELECT zone_id, account_id, assigned_by, assigned_at FROM zone_editors WHERE (? = 0 OR zone_id = ?) ORDER BY zone_id, account_id;", zoneId, zoneId);
|
||||
for (; !result.eof(); result.nextRow()) {
|
||||
editors.push_back({ static_cast<uint32_t>(result.getIntField("zone_id")), static_cast<uint32_t>(result.getIntField("account_id")),
|
||||
result.getStringField("assigned_by"), result.getInt64Field("assigned_at") });
|
||||
}
|
||||
return editors;
|
||||
}
|
||||
|
||||
bool SQLiteDatabase::IsZoneEditor(uint32_t zoneId, uint32_t accountId) {
|
||||
auto [_, result] = ExecuteSelect("SELECT 1 FROM zone_editors WHERE zone_id = ? AND account_id = ?;", zoneId, accountId);
|
||||
return !result.eof();
|
||||
}
|
||||
|
||||
void SQLiteDatabase::AddZoneEditor(const ZoneEditor& editor) {
|
||||
ExecuteInsert("INSERT OR IGNORE INTO zone_editors (zone_id, account_id, assigned_by, assigned_at) VALUES (?, ?, ?, ?);",
|
||||
editor.zoneId, editor.accountId, editor.assignedBy, editor.assignedAt);
|
||||
}
|
||||
|
||||
bool SQLiteDatabase::RemoveZoneEditor(uint32_t zoneId, uint32_t accountId) {
|
||||
return ExecuteUpdate("DELETE FROM zone_editors WHERE zone_id = ? AND account_id = ?;", zoneId, accountId) > 0;
|
||||
}
|
||||
@@ -321,6 +321,28 @@ class TestSQLDatabase : public GameDatabase {
|
||||
void SetPropertyRent(LWOOBJID propertyId, int64_t amount, int64_t due) override {}
|
||||
void SetPropertyPrivacy(LWOOBJID propertyId, int32_t privacyOption) override {}
|
||||
|
||||
// IZoneEditing: kept in memory, so tests can use the locks and editors
|
||||
std::optional<ZoneLock> GetZoneLock(uint32_t zoneId) override {
|
||||
const auto it = m_ZoneLocks.find(zoneId);
|
||||
return it == m_ZoneLocks.end() ? std::nullopt : std::optional<ZoneLock>(it->second);
|
||||
}
|
||||
std::vector<ZoneLock> GetZoneLocks() override {
|
||||
std::vector<ZoneLock> locks;
|
||||
for (const auto& [_, lock] : m_ZoneLocks) locks.push_back(lock);
|
||||
return locks;
|
||||
}
|
||||
bool TakeZoneLock(uint32_t zoneId, uint32_t accountId, int64_t time) override {
|
||||
return m_ZoneLocks.try_emplace(zoneId, ZoneLock{ zoneId, accountId, time }).second;
|
||||
}
|
||||
bool ReleaseZoneLock(uint32_t zoneId) override { return m_ZoneLocks.erase(zoneId) > 0; }
|
||||
std::vector<ZoneEditor> GetZoneEditors(uint32_t zoneId) override {
|
||||
std::vector<ZoneEditor> editors;
|
||||
for (const auto& [key, editor] : m_ZoneEditors) if (zoneId == 0 || key.first == zoneId) editors.push_back(editor);
|
||||
return editors;
|
||||
}
|
||||
bool IsZoneEditor(uint32_t zoneId, uint32_t accountId) override { return m_ZoneEditors.contains({ zoneId, accountId }); }
|
||||
void AddZoneEditor(const ZoneEditor& editor) override { m_ZoneEditors.try_emplace({ editor.zoneId, editor.accountId }, editor); }
|
||||
bool RemoveZoneEditor(uint32_t zoneId, uint32_t accountId) override { return m_ZoneEditors.erase({ zoneId, accountId }) > 0; }
|
||||
// IContraband
|
||||
std::vector<ContrabandItem> GetContrabandItems() override { return {}; }
|
||||
void SetContrabandItem(const ContrabandItem& item) override {}
|
||||
@@ -483,6 +505,10 @@ class TestSQLDatabase : public GameDatabase {
|
||||
void DeleteAccount(const uint32_t accountId) override {};
|
||||
void InsertAuditLog(uint32_t accountId, const std::string_view accountName, const std::string_view action, const std::string_view description, uint32_t targetAccountId, LWOOBJID targetCharacterId) override {};
|
||||
std::string GetAuditLogTable(uint32_t start, uint32_t length, const std::string_view search = "", uint32_t orderColumn = 0, bool orderAsc = true) override { return "{}"; };
|
||||
|
||||
private:
|
||||
std::map<uint32_t, ZoneLock> m_ZoneLocks;
|
||||
std::map<std::pair<uint32_t, uint32_t>, ZoneEditor> m_ZoneEditors;
|
||||
};
|
||||
|
||||
#endif //!TESTSQLDATABASE_H
|
||||
|
||||
15
migrations/dlu/mysql/107_zone_editing.sql
Normal file
15
migrations/dlu/mysql/107_zone_editing.sql
Normal file
@@ -0,0 +1,15 @@
|
||||
-- Who may edit a zone's files (docs/ZonePublish.md): each zone's assigned editors, and the one account holding its
|
||||
-- lock. A lock has no expiry: its holder releases it, or an admin does.
|
||||
CREATE TABLE IF NOT EXISTS zone_edit_locks (
|
||||
zone_id INT UNSIGNED NOT NULL PRIMARY KEY,
|
||||
account_id INT NOT NULL REFERENCES accounts(id),
|
||||
locked_at BIGINT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS zone_editors (
|
||||
zone_id INT UNSIGNED NOT NULL,
|
||||
account_id INT NOT NULL REFERENCES accounts(id),
|
||||
assigned_by VARCHAR(64) NOT NULL DEFAULT '',
|
||||
assigned_at BIGINT NOT NULL,
|
||||
PRIMARY KEY (zone_id, account_id)
|
||||
);
|
||||
15
migrations/dlu/sqlite/90_zone_editing.sql
Normal file
15
migrations/dlu/sqlite/90_zone_editing.sql
Normal file
@@ -0,0 +1,15 @@
|
||||
-- Who may edit a zone's files (docs/ZonePublish.md): each zone's assigned editors, and the one account holding its
|
||||
-- lock. A lock has no expiry: its holder releases it, or an admin does.
|
||||
CREATE TABLE IF NOT EXISTS zone_edit_locks (
|
||||
zone_id INTEGER NOT NULL PRIMARY KEY,
|
||||
account_id INTEGER NOT NULL REFERENCES accounts(id),
|
||||
locked_at BIGINT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS zone_editors (
|
||||
zone_id INTEGER NOT NULL,
|
||||
account_id INTEGER NOT NULL REFERENCES accounts(id),
|
||||
assigned_by TEXT NOT NULL DEFAULT '',
|
||||
assigned_at BIGINT NOT NULL,
|
||||
PRIMARY KEY (zone_id, account_id)
|
||||
);
|
||||
@@ -455,3 +455,37 @@ TEST(DatabaseUsageSqlite, MeasuresTablesAndKeepsHistory) {
|
||||
EXPECT_TRUE(g_Db->GetDatabaseUsageTables(1000).empty());
|
||||
EXPECT_EQ(g_Db->GetDatabaseUsageTotals(0, 5000).size(), 1u);
|
||||
}
|
||||
|
||||
// A zone's lock has one holder, taken in one statement; its editors are a set (docs/ZonePublish.md)
|
||||
TEST(ZoneEditingSqliteTests, LocksAndEditors) {
|
||||
auto& db = *g_Db;
|
||||
EXPECT_FALSE(db.GetZoneLock(1900));
|
||||
EXPECT_TRUE(db.TakeZoneLock(1900, 5, 1000));
|
||||
EXPECT_FALSE(db.TakeZoneLock(1900, 6, 1001)); // held: the second taker gets nothing
|
||||
auto lock = db.GetZoneLock(1900);
|
||||
ASSERT_TRUE(lock);
|
||||
EXPECT_EQ(lock->accountId, 5u);
|
||||
EXPECT_EQ(lock->lockedAt, 1000);
|
||||
EXPECT_TRUE(db.TakeZoneLock(1901, 6, 1002));
|
||||
EXPECT_EQ(db.GetZoneLocks().size(), 2u);
|
||||
EXPECT_TRUE(db.ReleaseZoneLock(1900));
|
||||
EXPECT_FALSE(db.ReleaseZoneLock(1900));
|
||||
EXPECT_TRUE(db.TakeZoneLock(1900, 6, 1003));
|
||||
EXPECT_TRUE(db.ReleaseZoneLock(1900));
|
||||
EXPECT_TRUE(db.ReleaseZoneLock(1901));
|
||||
|
||||
db.AddZoneEditor({ 1900, 5, "admin", 2000 });
|
||||
db.AddZoneEditor({ 1900, 5, "other", 2001 });
|
||||
db.AddZoneEditor({ 1900, 6, "admin", 2002 });
|
||||
db.AddZoneEditor({ 1901, 5, "admin", 2003 });
|
||||
const auto editors = db.GetZoneEditors(1900);
|
||||
ASSERT_EQ(editors.size(), 2u);
|
||||
EXPECT_EQ(editors[0].accountId, 5u);
|
||||
EXPECT_EQ(editors[0].assignedBy, "admin");
|
||||
EXPECT_EQ(db.GetZoneEditors(0).size(), 3u);
|
||||
EXPECT_TRUE(db.IsZoneEditor(1900, 6));
|
||||
EXPECT_FALSE(db.IsZoneEditor(1901, 6));
|
||||
EXPECT_TRUE(db.RemoveZoneEditor(1900, 6));
|
||||
EXPECT_FALSE(db.RemoveZoneEditor(1900, 6));
|
||||
EXPECT_FALSE(db.IsZoneEditor(1900, 6));
|
||||
}
|
||||
|
||||
@@ -72,6 +72,8 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(IGuilds::Event, id, guildId, time, kind, char
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(IGuilds::GuildSummary, guild, memberCount, leaderId, leaderName);
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(IGuilds::GuildPage, total, filtered, guilds);
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(IApiKeys::ApiKey, id, accountId, name, note, keyHash, keyPrefix, permissions, readOnly, allowedIps, allowedPaths, rateLimit, dailyQuota, createdAt, createdBy, issuedAt, expiresAt, revokedAt, revokedBy, lastUsedAt, lastIp, requestCount, quotaDay, dayCount);
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(IZoneEditing::ZoneLock, zoneId, accountId, lockedAt);
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(IZoneEditing::ZoneEditor, zoneId, accountId, assignedBy, assignedAt);
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(ICharacterSnapshots::CharacterSnapshot, id, characterId, takenAt, reason, actor, size, hash, compressed);
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(IChatLog::ChatMessage, id, time, channel, senderId, senderName, accountId, recipientId, recipientName, zoneId, instanceId, cloneId, message, blocked, guildId, teamId, filtered);
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(IChatLog::WhisperPartner, characterId, name, messages, firstTime, lastTime);
|
||||
@@ -1414,6 +1416,26 @@ TEST_F(ParitySeeded, ApiKeys) {
|
||||
Both("RevokeAccountApiKeys", [](GameDatabase& db) { return json{ db.RevokeAccountApiKeys(2, "bob", 1700001100), db.GetApiKeys(2), db.GetApiKeys(1) }; });
|
||||
}
|
||||
|
||||
TEST_F(ParitySeeded, ZoneEditing) {
|
||||
Both("AddZoneEditor", [](GameDatabase& db) {
|
||||
db.AddZoneEditor({ 1100, 2, "alice", 1700000000 });
|
||||
db.AddZoneEditor({ 1100, 2, "again", 1700000050 }); // already one: kept as it was
|
||||
db.AddZoneEditor({ 1100, 1, "alice", 1700000100 });
|
||||
db.AddZoneEditor({ 1200, 2, "alice", 1700000200 });
|
||||
return json{ db.GetZoneEditors(1100), db.GetZoneEditors(0), db.GetZoneEditors(1300), db.IsZoneEditor(1100, 2), db.IsZoneEditor(1200, 1) };
|
||||
});
|
||||
Both("TakeZoneLock", [](GameDatabase& db) {
|
||||
return json{ db.TakeZoneLock(1100, 2, 1700000300), db.TakeZoneLock(1100, 1, 1700000400), db.TakeZoneLock(1200, 1, 1700000500),
|
||||
db.GetZoneLock(1100), db.GetZoneLock(1300), db.GetZoneLocks() };
|
||||
});
|
||||
Both("ReleaseZoneLock", [](GameDatabase& db) {
|
||||
return json{ db.ReleaseZoneLock(1100), db.ReleaseZoneLock(1100), db.GetZoneLock(1100), db.TakeZoneLock(1100, 1, 1700000600), db.GetZoneLocks() };
|
||||
});
|
||||
Both("RemoveZoneEditor", [](GameDatabase& db) {
|
||||
return json{ db.RemoveZoneEditor(1100, 2), db.RemoveZoneEditor(1100, 2), db.GetZoneEditors(0) };
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(ParitySeeded, Moderation) {
|
||||
Both("InsertPlayerReport", [](GameDatabase& db) {
|
||||
IModeration::PlayerReport report;
|
||||
|
||||
Reference in New Issue
Block a user