diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index 465cb648169..175743e79aa 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -1067,3 +1067,28 @@ var/gamma_ship_location = 1 // 0 = station , 1 = space
continue
result[1]++
return result
+
+//Discord duplications
+/datum/admins/proc/discord_duplicates()
+ if(!usr.client.holder)
+ return
+ var/dat = "
Discord Duplicates"
+ dat += "Discord IDs with more than one ckey linked are shown below
| Discord ID | CKEYs | Unlink | "
+ // If anyone reads this, I spent a whole 30 minutes writing just this fucking query. It is the messiest SQL statement I have ever written
+ // If anyone even thinks about touching this I will impale you on a railroad spike
+ // It hurts to wake up in the morning, -aa07
+ var/DBQuery/discord_ids = dbcon.NewQuery("SELECT a.* FROM [format_table_name("discord")] a JOIN (SELECT discord_id, ckey, COUNT(*) FROM [format_table_name("discord")] GROUP BY discord_id HAVING count(*) > 1 ) b ON a.discord_id = b.discord_id ORDER BY a.discord_id")
+ if(!discord_ids.Execute())
+ var/err = discord_ids.ErrorMsg()
+ log_game("SQL ERROR while selecting discord accounts. Error : \[[err]\]\n")
+ return
+ while(discord_ids.NextRow())
+ var/ckey = discord_ids.item[1]
+ var/id = discord_ids.item[2]
+ dat += "
|---|
| " + id + " | "
+ dat += "" + ckey + " | "
+ dat += "Unlink |
"
+
+ dat += "
"
+
+ usr << browse(dat, "window=duplicates;size=500x480")
\ No newline at end of file
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index 5130f6ff2c1..0c4dd38ef5f 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -79,6 +79,7 @@ var/list/admin_verbs_admin = list(
/client/proc/list_ssds,
/client/proc/cmd_admin_headset_message,
/client/proc/spawn_floor_cluwne,
+ /client/proc/show_discord_duplicates,
)
var/list/admin_verbs_ban = list(
/client/proc/unban_panel,
@@ -1045,3 +1046,12 @@ var/list/admin_verbs_ticket = list(
log_admin("[key_name(usr)] has [advanced_admin_interaction ? "activated" : "deactivated"] their advanced admin interaction.")
message_admins("[key_name_admin(usr)] has [advanced_admin_interaction ? "activated" : "deactivated"] their advanced admin interaction.")
+
+/client/proc/show_discord_duplicates()
+ set name = "Show Duplicate Discord Links"
+ set category = "Admin"
+
+ if(!check_rights(R_ADMIN))
+ return
+
+ holder.discord_duplicates()
\ No newline at end of file
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index 5dbaf81bf6b..03d2940b32d 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -3349,6 +3349,20 @@
// Refresh the page
src.view_flagged_books()
+ // Force unlink a discord key
+ else if(href_list["force_discord_unlink"])
+ if(!check_rights(R_ADMIN))
+ return
+ var/target_ckey = href_list["force_discord_unlink"]
+ var/DBQuery/admin_unlink_discord_id = dbcon.NewQuery("DELETE FROM [format_table_name("discord")] WHERE ckey = '[target_ckey]'")
+ if(!admin_unlink_discord_id.Execute())
+ var/err = admin_unlink_discord_id.ErrorMsg()
+ log_game("SQL ERROR while admin-unlinking discord account. Error : \[[err]\]\n")
+ return
+ to_chat(src, "Successfully forcefully unlinked discord account from [target_ckey]")
+ message_admins("[key_name_admin(usr)] forcefully unlinked the discord account belonging to [target_ckey]")
+ log_admin("[key_name_admin(usr)] forcefully unlinked the discord account belonging to [target_ckey]")
+
/client/proc/create_eventmob_for(var/mob/living/carbon/human/H, var/killthem = 0)
if(!check_rights(R_EVENT))
return