mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-09 16:05:07 +00:00
Adds admin panel for achievement metadata cleanup (#92345)
This commit is contained in:
@@ -161,3 +161,6 @@
|
||||
|
||||
#define CHEF_TOURISTS_SERVED "Tourists Served As Chef"
|
||||
#define BARTENDER_TOURISTS_SERVED "Tourists Served As Bartender"
|
||||
|
||||
/// Value in metadata version that signifies the achievement is archived
|
||||
#define ACHIEVEMENT_ARCHIVED_VERSION 9999
|
||||
|
||||
@@ -101,3 +101,36 @@ SUBSYSTEM_DEF(achievements)
|
||||
|
||||
if(to_update.len)
|
||||
SSdbcore.MassInsert(format_table_name("achievement_metadata"),to_update,duplicate_key = TRUE)
|
||||
|
||||
var/list/orphaned_keys = get_orphaned_keys(FALSE)
|
||||
if(orphaned_keys.len)
|
||||
message_admins("Achievement metadata found without matching achievement, use Achievement-Admin-Panel verb to cleanup if necessary")
|
||||
|
||||
/// returns list of metadata keys and versions in db with no matching achievement datum, either deleted achievements, or from server with code ahead of us.
|
||||
/datum/controller/subsystem/achievements/proc/get_orphaned_keys(include_archived = TRUE)
|
||||
. = list()
|
||||
var/list/current_metadata = list()
|
||||
// Fetch all keys from the db
|
||||
var/datum/db_query/Q = SSdbcore.NewQuery("SELECT achievement_key,achievement_version FROM [format_table_name("achievement_metadata")]")
|
||||
if(!Q.Execute(async = TRUE))
|
||||
qdel(Q)
|
||||
return
|
||||
else
|
||||
while(Q.NextRow())
|
||||
current_metadata[Q.item[1]] = Q.item[2]
|
||||
qdel(Q)
|
||||
|
||||
var/list/achievements_by_db_id = list()
|
||||
for(var/datum/award/award as anything in subtypesof(/datum/award))
|
||||
if(!initial(award.database_id)) // abstract type
|
||||
continue
|
||||
achievements_by_db_id[award.database_id] = TRUE
|
||||
|
||||
for(var/key in current_metadata)
|
||||
if(achievements_by_db_id[key])
|
||||
continue
|
||||
if(!include_archived && current_metadata[key] == ACHIEVEMENT_ARCHIVED_VERSION)
|
||||
continue
|
||||
.[key] = current_metadata[key]
|
||||
|
||||
|
||||
|
||||
73
code/datums/achievements/admin_panel.dm
Normal file
73
code/datums/achievements/admin_panel.dm
Normal file
@@ -0,0 +1,73 @@
|
||||
// Panel for achievement management
|
||||
/datum/achievement_admin_panel
|
||||
var/list/orphaned_keys
|
||||
|
||||
/datum/achievement_admin_panel/proc/reload_data()
|
||||
if(!SSachievements.achievements_enabled)
|
||||
return
|
||||
orphaned_keys = SSachievements.get_orphaned_keys()
|
||||
|
||||
/datum/achievement_admin_panel/ui_data()
|
||||
. = list()
|
||||
var/list/orphaned_only = list()
|
||||
var/list/archived_only = list()
|
||||
for(var/key in orphaned_keys)
|
||||
if(orphaned_keys[key] == ACHIEVEMENT_ARCHIVED_VERSION)
|
||||
archived_only += key
|
||||
else
|
||||
orphaned_only += key
|
||||
.["orphaned_keys"] = orphaned_only
|
||||
.["archived_keys"] = archived_only
|
||||
|
||||
/datum/achievement_admin_panel/ui_state(mob/user)
|
||||
return ADMIN_STATE(R_ADMIN)
|
||||
|
||||
/datum/achievement_admin_panel/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "AchievementsAdminPanel")
|
||||
ui.open()
|
||||
|
||||
/datum/achievement_admin_panel/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
switch (action)
|
||||
if("archive")
|
||||
var/achievement_key = params["key"]
|
||||
archive_achievement(achievement_key)
|
||||
reload_data()
|
||||
return TRUE
|
||||
if("cleanup_orphan")
|
||||
var/achievement_key = params["key"]
|
||||
cleanup_outdated_achievement(achievement_key)
|
||||
reload_data()
|
||||
return TRUE
|
||||
|
||||
|
||||
|
||||
/datum/achievement_admin_panel/proc/cleanup_outdated_achievement(achievement_key)
|
||||
// ensure key is actually orphaned just in case
|
||||
if(!(achievement_key in orphaned_keys))
|
||||
return
|
||||
log_admin("[key_name_admin(usr)] has deleted orphaned achievement metadata for key [achievement_key].")
|
||||
message_admins("[key_name_admin(usr)] has deleted orphaned achievement metadata for key [achievement_key].")
|
||||
SSdbcore.QuerySelect(list(
|
||||
SSdbcore.NewQuery("DELETE FROM [format_table_name("achievement_metadata")] WHERE achievement_key = :key", list("key" = achievement_key)),
|
||||
SSdbcore.NewQuery("DELETE FROM [format_table_name("achievements")] WHERE achievement_key = :key", list("key" = achievement_key)),
|
||||
), warn = TRUE, qdel = TRUE)
|
||||
|
||||
/datum/achievement_admin_panel/proc/archive_achievement(achievement_key)
|
||||
// ensure key is actually orphaned just in case
|
||||
if(!(achievement_key in orphaned_keys))
|
||||
return
|
||||
log_admin("[key_name_admin(usr)] has archived orphaned achievement metadata for key [achievement_key].")
|
||||
message_admins("[key_name_admin(usr)] has archived orphaned achievement metadata for key [achievement_key].")
|
||||
SSdbcore.QuerySelect(list(
|
||||
SSdbcore.NewQuery("UPDATE [format_table_name("achievement_metadata")] SET achievement_version = :version WHERE achievement_key = :key", list("key" = achievement_key, "version" = ACHIEVEMENT_ARCHIVED_VERSION)),
|
||||
), warn = TRUE, qdel = TRUE)
|
||||
|
||||
ADMIN_VERB(achievements_cleanup, R_ADMIN, "Achievements Admin Panel", "View achievements management panel.", ADMIN_CATEGORY_MAIN)
|
||||
var/datum/achievement_admin_panel/panel = new /datum/achievement_admin_panel()
|
||||
panel.reload_data()
|
||||
panel.ui_interact(user.mob)
|
||||
@@ -866,6 +866,7 @@
|
||||
#include "code\datums\world_topic.dm"
|
||||
#include "code\datums\achievements\_achievement_data.dm"
|
||||
#include "code\datums\achievements\_awards.dm"
|
||||
#include "code\datums\achievements\admin_panel.dm"
|
||||
#include "code\datums\achievements\boss_achievements.dm"
|
||||
#include "code\datums\achievements\boss_scores.dm"
|
||||
#include "code\datums\achievements\job_achievements.dm"
|
||||
|
||||
72
tgui/packages/tgui/interfaces/AchievementsAdminPanel.tsx
Normal file
72
tgui/packages/tgui/interfaces/AchievementsAdminPanel.tsx
Normal file
@@ -0,0 +1,72 @@
|
||||
import { Button, LabeledList, NoticeBox, Section } from 'tgui-core/components';
|
||||
import { useBackend } from '../backend';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
type Data = {
|
||||
orphaned_keys: string[];
|
||||
archived_keys: string[];
|
||||
};
|
||||
|
||||
export const AchievementsAdminPanel = (props) => {
|
||||
const { act, data } = useBackend<Data>();
|
||||
const { orphaned_keys } = data;
|
||||
return (
|
||||
<Window title="Achievements Admin Panel" width={540} height={680}>
|
||||
<Window.Content scrollable>
|
||||
<Section title="Orphaned achievements">
|
||||
<NoticeBox>
|
||||
These achievements are present in the database but are missing
|
||||
definitions in code. Most likely these were removed and can be
|
||||
cleaned up safely. If you're sharing the same database on multiple
|
||||
servers it's possible these come from a server with later version of
|
||||
the code than this one.
|
||||
</NoticeBox>
|
||||
<LabeledList>
|
||||
{orphaned_keys.map((key) => (
|
||||
<LabeledList.Item
|
||||
key={key}
|
||||
label=""
|
||||
buttons={
|
||||
<>
|
||||
<Button.Confirm
|
||||
onClick={() => act('archive', { key: key })}
|
||||
>
|
||||
Archive
|
||||
</Button.Confirm>
|
||||
<Button.Confirm
|
||||
onClick={() => act('cleanup_orphan', { key: key })}
|
||||
>
|
||||
Cleanup
|
||||
</Button.Confirm>
|
||||
</>
|
||||
}
|
||||
>
|
||||
{key}
|
||||
</LabeledList.Item>
|
||||
))}
|
||||
</LabeledList>
|
||||
</Section>
|
||||
<Section title="Archived achievements">
|
||||
<NoticeBox>Archived achievements in the database.</NoticeBox>
|
||||
<LabeledList>
|
||||
{orphaned_keys.map((key) => (
|
||||
<LabeledList.Item
|
||||
key={key}
|
||||
label=""
|
||||
buttons={
|
||||
<Button.Confirm
|
||||
onClick={() => act('cleanup_orphan', { key: key })}
|
||||
>
|
||||
Cleanup
|
||||
</Button.Confirm>
|
||||
}
|
||||
>
|
||||
{key}
|
||||
</LabeledList.Item>
|
||||
))}
|
||||
</LabeledList>
|
||||
</Section>
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user