You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

475 lines
26 KiB

  1. /client/proc/edit_admin_permissions()
  2. set category = "Admin"
  3. set name = "Permissions Panel"
  4. set desc = "Edit admin permissions"
  5. if(!check_rights(R_PERMISSIONS))
  6. return
  7. usr.client.holder.edit_admin_permissions()
  8. /datum/admins/proc/edit_admin_permissions(action, target, operation, page)
  9. if(!check_rights(R_PERMISSIONS))
  10. return
  11. var/list/output = list("<link rel='stylesheet' type='text/css' href='panels.css'><a href='?_src_=holder;[HrefToken()];editrightsbrowser=1'>\[Permissions\]</a>")
  12. if(action)
  13. output += " | <a href='?_src_=holder;[HrefToken()];editrightsbrowserlog=1;editrightspage=0'>\[Log\]</a> | <a href='?_src_=holder;[HrefToken()];editrightsbrowsermanage=1'>\[Management\]</a><hr style='background:#000000; border:0; height:3px'>"
  14. else
  15. output += "<br><a href='?_src_=holder;[HrefToken()];editrightsbrowserlog=1;editrightspage=0'>\[Log\]</a><br><a href='?_src_=holder;[HrefToken()];editrightsbrowsermanage=1'>\[Management\]</a>"
  16. if(action == 1)
  17. var/list/searchlist = list(" WHERE ")
  18. if(target)
  19. searchlist += "ckey = '[sanitizeSQL(target)]'"
  20. if(operation)
  21. if(target)
  22. searchlist += " AND "
  23. searchlist += "operation = '[sanitizeSQL(operation)]'"
  24. var/search
  25. if(searchlist.len > 1)
  26. search = searchlist.Join("")
  27. var/logcount = 0
  28. var/logssperpage = 20
  29. var/pagecount = 0
  30. page = text2num(page)
  31. var/datum/DBQuery/query_count_admin_logs = SSdbcore.NewQuery("SELECT COUNT(id) FROM [format_table_name("admin_log")][search]")
  32. if(!query_count_admin_logs.warn_execute())
  33. qdel(query_count_admin_logs)
  34. return
  35. if(query_count_admin_logs.NextRow())
  36. logcount = text2num(query_count_admin_logs.item[1])
  37. qdel(query_count_admin_logs)
  38. if(logcount > logssperpage)
  39. output += "<br><b>Page: </b>"
  40. while(logcount > 0)
  41. output += "|<a href='?_src_=holder;[HrefToken()];editrightsbrowserlog=1;editrightstarget=[target];editrightsoperation=[operation];editrightspage=[pagecount]'>[pagecount == page ? "<b>\[[pagecount]\]</b>" : "\[[pagecount]\]"]</a>"
  42. logcount -= logssperpage
  43. pagecount++
  44. output += "|"
  45. var/limit = " LIMIT [logssperpage * page], [logssperpage]"
  46. var/datum/DBQuery/query_search_admin_logs = SSdbcore.NewQuery("SELECT datetime, round_id, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE ckey = adminckey), adminckey), operation, IF(ckey IS NULL, target, byond_key), log FROM [format_table_name("admin_log")] LEFT JOIN [format_table_name("player")] ON target = ckey[search] ORDER BY datetime DESC[limit]")
  47. if(!query_search_admin_logs.warn_execute())
  48. qdel(query_search_admin_logs)
  49. return
  50. while(query_search_admin_logs.NextRow())
  51. var/datetime = query_search_admin_logs.item[1]
  52. var/round_id = query_search_admin_logs.item[2]
  53. var/admin_key = query_search_admin_logs.item[3]
  54. operation = query_search_admin_logs.item[4]
  55. target = query_search_admin_logs.item[5]
  56. var/log = query_search_admin_logs.item[6]
  57. output += "<p style='margin:0px'><b>[datetime] | Round ID [round_id] | Admin [admin_key] | Operation [operation] on [target]</b><br>[log]</p><hr style='background:#000000; border:0; height:3px'>"
  58. qdel(query_search_admin_logs)
  59. if(action == 2)
  60. output += "<h3>Admin ckeys with invalid ranks</h3>"
  61. var/datum/DBQuery/query_check_admin_errors = SSdbcore.NewQuery("SELECT IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("admin")].ckey), ckey), [format_table_name("admin")].`rank` FROM [format_table_name("admin")] LEFT JOIN [format_table_name("admin_ranks")] ON [format_table_name("admin_ranks")].`rank` = [format_table_name("admin")].`rank` WHERE [format_table_name("admin_ranks")].`rank` IS NULL")
  62. if(!query_check_admin_errors.warn_execute())
  63. qdel(query_check_admin_errors)
  64. return
  65. while(query_check_admin_errors.NextRow())
  66. var/admin_key = query_check_admin_errors.item[1]
  67. var/admin_rank = query_check_admin_errors.item[2]
  68. output += "[admin_key] has non-existent rank [admin_rank] | <a href='?_src_=holder;[HrefToken()];editrightsbrowsermanage=1;editrightschange=[admin_key]'>\[Change Rank\]</a> | <a href='?_src_=holder;[HrefToken()];editrightsbrowsermanage=1;editrightsremove=[admin_key]'>\[Remove\]</a>"
  69. output += "<hr style='background:#000000; border:0; height:1px'>"
  70. qdel(query_check_admin_errors)
  71. output += "<h3>Unused ranks</h3>"
  72. var/datum/DBQuery/query_check_unused_rank = SSdbcore.NewQuery("SELECT [format_table_name("admin_ranks")].`rank`, flags, exclude_flags, can_edit_flags FROM [format_table_name("admin_ranks")] LEFT JOIN [format_table_name("admin")] ON [format_table_name("admin")].`rank` = [format_table_name("admin_ranks")].`rank` WHERE [format_table_name("admin")].`rank` IS NULL")
  73. if(!query_check_unused_rank.warn_execute())
  74. qdel(query_check_unused_rank)
  75. return
  76. while(query_check_unused_rank.NextRow())
  77. var/admin_rank = query_check_unused_rank.item[1]
  78. output += {"Rank [admin_rank] is not held by any admin | <a href='?_src_=holder;[HrefToken()];editrightsbrowsermanage=1;editrightsremoverank=[admin_rank]'>\[Remove\]</a>
  79. <br>Permissions: [rights2text(text2num(query_check_unused_rank.item[2])," ")]
  80. <br>Denied: [rights2text(text2num(query_check_unused_rank.item[3])," ", "-")]
  81. <br>Allowed to edit: [rights2text(text2num(query_check_unused_rank.item[4])," ", "*")]
  82. <hr style='background:#000000; border:0; height:1px'>"}
  83. qdel(query_check_unused_rank)
  84. else if(!action)
  85. output += {"
  86. <head>
  87. <meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>
  88. <title>Permissions Panel</title>
  89. <script type='text/javascript' src='search.js'></script>
  90. </head>
  91. <body onload='selectTextField();updateSearch();'>
  92. <div id='main'><table id='searchable' cellspacing='0'>
  93. <tr class='title'>
  94. <th style='width:150px;'>CKEY <a class='small' href='?src=[REF(src)];[HrefToken()];editrights=add'>\[+\]</a></th>
  95. <th style='width:125px;'>RANK</th>
  96. <th style='width:40%;'>PERMISSIONS</th>
  97. <th style='width:20%;'>DENIED</th>
  98. <th style='width:40%;'>ALLOWED TO EDIT</th>
  99. </tr>
  100. "}
  101. for(var/adm_ckey in GLOB.admin_datums+GLOB.deadmins)
  102. var/datum/admins/D = GLOB.admin_datums[adm_ckey]
  103. if(!D)
  104. D = GLOB.deadmins[adm_ckey]
  105. if (!D)
  106. continue
  107. var/deadminlink = ""
  108. if(D.owner)
  109. adm_ckey = D.owner.key
  110. if (D.deadmined)
  111. deadminlink = " <a class='small' href='?src=[REF(src)];[HrefToken()];editrights=activate;key=[adm_ckey]'>\[RA\]</a>"
  112. else
  113. deadminlink = " <a class='small' href='?src=[REF(src)];[HrefToken()];editrights=deactivate;key=[adm_ckey]'>\[DA\]</a>"
  114. output += "<tr>"
  115. output += "<td style='text-align:center;'>[adm_ckey]<br>[deadminlink]<a class='small' href='?src=[REF(src)];[HrefToken()];editrights=remove;key=[adm_ckey]'>\[-\]</a><a class='small' href='?src=[REF(src)];[HrefToken()];editrights=sync;key=[adm_ckey]'>\[SYNC TGDB\]</a></td>"
  116. output += "<td><a href='?src=[REF(src)];[HrefToken()];editrights=rank;key=[adm_ckey]'>[D.rank.name]</a></td>"
  117. output += "<td><a class='small' href='?src=[REF(src)];[HrefToken()];editrights=permissions;key=[adm_ckey]'>[rights2text(D.rank.include_rights," ")]</a></td>"
  118. output += "<td><a class='small' href='?src=[REF(src)];[HrefToken()];editrights=permissions;key=[adm_ckey]'>[rights2text(D.rank.exclude_rights," ", "-")]</a></td>"
  119. output += "<td><a class='small' href='?src=[REF(src)];[HrefToken()];editrights=permissions;key=[adm_ckey]'>[rights2text(D.rank.can_edit_rights," ", "*")]</a></td>"
  120. output += "</tr>"
  121. output += "</table></div><div id='top'><b>Search:</b> <input type='text' id='filter' value='' style='width:70%;' onkeyup='updateSearch();'></div></body>"
  122. if(QDELETED(usr))
  123. return
  124. usr << browse("<!DOCTYPE html><html>[jointext(output, "")]</html>","window=editrights;size=1000x650")
  125. /datum/admins/proc/edit_rights_topic(list/href_list)
  126. if(!check_rights(R_PERMISSIONS))
  127. message_admins("[key_name_admin(usr)] attempted to edit admin permissions without sufficient rights.")
  128. log_admin("[key_name(usr)] attempted to edit admin permissions without sufficient rights.")
  129. return
  130. if(IsAdminAdvancedProcCall())
  131. to_chat(usr, "<span class='admin prefix'>Admin Edit blocked: Advanced ProcCall detected.</span>", confidential = TRUE)
  132. return
  133. var/datum/asset/permissions_assets = get_asset_datum(/datum/asset/simple/permissions)
  134. permissions_assets.send(src)
  135. var/admin_key = href_list["key"]
  136. var/admin_ckey = ckey(admin_key)
  137. var/datum/admins/D = GLOB.admin_datums[admin_ckey]
  138. var/use_db
  139. var/task = href_list["editrights"]
  140. var/skip
  141. var/legacy_only
  142. if(task == "activate" || task == "deactivate" || task == "sync")
  143. skip = TRUE
  144. if(!CONFIG_GET(flag/admin_legacy_system) && CONFIG_GET(flag/protect_legacy_admins) && task == "rank")
  145. if(admin_ckey in GLOB.protected_admins)
  146. to_chat(usr, "<span class='admin prefix'>Editing the rank of this admin is blocked by server configuration.</span>", confidential = TRUE)
  147. return
  148. if(!CONFIG_GET(flag/admin_legacy_system) && CONFIG_GET(flag/protect_legacy_ranks) && task == "permissions")
  149. if(D.rank in GLOB.protected_ranks)
  150. to_chat(usr, "<span class='admin prefix'>Editing the flags of this rank is blocked by server configuration.</span>", confidential = TRUE)
  151. return
  152. if(CONFIG_GET(flag/load_legacy_ranks_only) && (task == "add" || task == "rank" || task == "permissions"))
  153. to_chat(usr, "<span class='admin prefix'>Database rank loading is disabled, only temporary changes can be made to a rank's permissions and permanently creating a new rank is blocked.</span>", confidential = TRUE)
  154. legacy_only = TRUE
  155. if(check_rights(R_DBRANKS, FALSE))
  156. if(!skip)
  157. if(!SSdbcore.Connect())
  158. to_chat(usr, "<span class='danger'>Unable to connect to database, changes are temporary only.</span>", confidential = TRUE)
  159. use_db = FALSE
  160. else
  161. use_db = alert("Permanent changes are saved to the database for future rounds, temporary changes will affect only the current round", "Permanent or Temporary?", "Permanent", "Temporary", "Cancel")
  162. if(use_db == "Cancel")
  163. return
  164. if(use_db == "Permanent")
  165. use_db = TRUE
  166. admin_ckey = sanitizeSQL(admin_ckey)
  167. else
  168. use_db = FALSE
  169. if(QDELETED(usr))
  170. return
  171. if(task != "add")
  172. D = GLOB.admin_datums[admin_ckey]
  173. if(!D)
  174. D = GLOB.deadmins[admin_ckey]
  175. if(!D)
  176. return
  177. if((task != "sync") && !check_if_greater_rights_than_holder(D))
  178. message_admins("[key_name_admin(usr)] attempted to change the rank of [admin_key] without sufficient rights.")
  179. log_admin("[key_name(usr)] attempted to change the rank of [admin_key] without sufficient rights.")
  180. return
  181. switch(task)
  182. if("add")
  183. admin_ckey = add_admin(admin_ckey, admin_key, use_db)
  184. if(!admin_ckey)
  185. return
  186. change_admin_rank(admin_ckey, admin_key, use_db, null, legacy_only)
  187. if("remove")
  188. remove_admin(admin_ckey, admin_key, use_db, D)
  189. if("rank")
  190. change_admin_rank(admin_ckey, admin_key, use_db, D, legacy_only)
  191. if("permissions")
  192. change_admin_flags(admin_ckey, admin_key, use_db, D, legacy_only)
  193. if("activate")
  194. force_readmin(admin_key, D)
  195. if("deactivate")
  196. force_deadmin(admin_key, D)
  197. if("sync")
  198. sync_lastadminrank(admin_ckey, admin_key, D)
  199. edit_admin_permissions()
  200. /datum/admins/proc/add_admin(admin_ckey, admin_key, use_db)
  201. if(admin_ckey)
  202. . = admin_ckey
  203. else
  204. admin_key = input("New admin's key","Admin key") as text|null
  205. . = ckey(admin_key)
  206. if(!.)
  207. return FALSE
  208. if(!admin_ckey && (. in GLOB.admin_datums+GLOB.deadmins))
  209. to_chat(usr, "<span class='danger'>[admin_key] is already an admin.</span>", confidential = TRUE)
  210. return FALSE
  211. if(use_db)
  212. . = sanitizeSQL(.)
  213. //if an admin exists without a datum they won't be caught by the above
  214. var/datum/DBQuery/query_admin_in_db = SSdbcore.NewQuery("SELECT 1 FROM [format_table_name("admin")] WHERE ckey = '[.]'")
  215. if(!query_admin_in_db.warn_execute())
  216. qdel(query_admin_in_db)
  217. return FALSE
  218. if(query_admin_in_db.NextRow())
  219. qdel(query_admin_in_db)
  220. to_chat(usr, "<span class='danger'>[admin_key] already listed in admin database. Check the Management tab if they don't appear in the list of admins.</span>", confidential = TRUE)
  221. return FALSE
  222. qdel(query_admin_in_db)
  223. var/datum/DBQuery/query_add_admin = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin")] (ckey, `rank`) VALUES ('[.]', 'NEW ADMIN')")
  224. if(!query_add_admin.warn_execute())
  225. qdel(query_add_admin)
  226. return FALSE
  227. qdel(query_add_admin)
  228. var/datum/DBQuery/query_add_admin_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) VALUES ('[SQLtime()]', '[GLOB.round_id]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'add admin', '[.]', 'New admin added: [.]')")
  229. if(!query_add_admin_log.warn_execute())
  230. qdel(query_add_admin_log)
  231. return FALSE
  232. qdel(query_add_admin_log)
  233. /datum/admins/proc/remove_admin(admin_ckey, admin_key, use_db, datum/admins/D)
  234. if(alert("Are you sure you want to remove [admin_ckey]?","Confirm Removal","Do it","Cancel") == "Do it")
  235. GLOB.admin_datums -= admin_ckey
  236. GLOB.deadmins -= admin_ckey
  237. if(D)
  238. D.disassociate()
  239. var/m1 = "[key_name_admin(usr)] removed [admin_key] from the admins list [use_db ? "permanently" : "temporarily"]"
  240. var/m2 = "[key_name(usr)] removed [admin_key] from the admins list [use_db ? "permanently" : "temporarily"]"
  241. if(use_db)
  242. var/datum/DBQuery/query_add_rank = SSdbcore.NewQuery("DELETE FROM [format_table_name("admin")] WHERE ckey = '[admin_ckey]'")
  243. if(!query_add_rank.warn_execute())
  244. qdel(query_add_rank)
  245. return
  246. qdel(query_add_rank)
  247. var/datum/DBQuery/query_add_rank_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) VALUES ('[SQLtime()]', '[GLOB.round_id]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'remove admin', '[admin_ckey]', 'Admin removed: [admin_ckey]')")
  248. if(!query_add_rank_log.warn_execute())
  249. qdel(query_add_rank_log)
  250. return
  251. qdel(query_add_rank_log)
  252. sync_lastadminrank(admin_ckey, admin_key)
  253. message_admins(m1)
  254. log_admin(m2)
  255. /datum/admins/proc/force_readmin(admin_key, datum/admins/D)
  256. if(!D || !D.deadmined)
  257. return
  258. D.activate()
  259. message_admins("[key_name_admin(usr)] forcefully readmined [admin_key]")
  260. log_admin("[key_name(usr)] forcefully readmined [admin_key]")
  261. /datum/admins/proc/force_deadmin(admin_key, datum/admins/D)
  262. if(!D || D.deadmined)
  263. return
  264. message_admins("[key_name_admin(usr)] forcefully deadmined [admin_key]")
  265. log_admin("[key_name(usr)] forcefully deadmined [admin_key]")
  266. D.deactivate() //after logs so the deadmined admin can see the message.
  267. /datum/admins/proc/auto_deadmin()
  268. to_chat(owner, "<span class='interface'>You are now a normal player.</span>", confidential = TRUE)
  269. var/old_owner = owner
  270. deactivate()
  271. message_admins("[old_owner] deadmined via auto-deadmin config.")
  272. log_admin("[old_owner] deadmined via auto-deadmin config.")
  273. return TRUE
  274. /datum/admins/proc/change_admin_rank(admin_ckey, admin_key, use_db, datum/admins/D, legacy_only)
  275. var/datum/admin_rank/R
  276. var/list/rank_names = list()
  277. if(!use_db || (use_db && !legacy_only))
  278. rank_names += "*New Rank*"
  279. for(R in GLOB.admin_ranks)
  280. if((R.rights & usr.client.holder.rank.can_edit_rights) == R.rights)
  281. rank_names[R.name] = R
  282. var/new_rank = input("Please select a rank", "New rank") as null|anything in rank_names
  283. if(new_rank == "*New Rank*")
  284. new_rank = input("Please input a new rank", "New custom rank") as text|null
  285. if(!new_rank)
  286. return
  287. R = rank_names[new_rank]
  288. if(!R) //rank with that name doesn't exist yet - make it
  289. if(D)
  290. R = new(new_rank, D.rank.rights) //duplicate our previous admin_rank but with a new name
  291. else
  292. R = new(new_rank) //blank new admin_rank
  293. GLOB.admin_ranks += R
  294. var/m1 = "[key_name_admin(usr)] edited the admin rank of [admin_key] to [new_rank] [use_db ? "permanently" : "temporarily"]"
  295. var/m2 = "[key_name(usr)] edited the admin rank of [admin_key] to [new_rank] [use_db ? "permanently" : "temporarily"]"
  296. if(use_db)
  297. new_rank = sanitizeSQL(new_rank)
  298. //if a player was tempminned before having a permanent change made to their rank they won't yet be in the db
  299. var/old_rank
  300. var/datum/DBQuery/query_admin_in_db = SSdbcore.NewQuery("SELECT `rank` FROM [format_table_name("admin")] WHERE ckey = '[admin_ckey]'")
  301. if(!query_admin_in_db.warn_execute())
  302. qdel(query_admin_in_db)
  303. return
  304. if(!query_admin_in_db.NextRow())
  305. add_admin(admin_ckey, admin_key, TRUE)
  306. old_rank = "NEW ADMIN"
  307. else
  308. old_rank = query_admin_in_db.item[1]
  309. qdel(query_admin_in_db)
  310. //similarly if a temp rank is created it won't be in the db if someone is permanently changed to it
  311. var/datum/DBQuery/query_rank_in_db = SSdbcore.NewQuery("SELECT 1 FROM [format_table_name("admin_ranks")] WHERE `rank` = '[new_rank]'")
  312. if(!query_rank_in_db.warn_execute())
  313. qdel(query_rank_in_db)
  314. return
  315. if(!query_rank_in_db.NextRow())
  316. QDEL_NULL(query_rank_in_db)
  317. var/datum/DBQuery/query_add_rank = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_ranks")] (`rank`, flags, exclude_flags, can_edit_flags) VALUES ('[new_rank]', '0', '0', '0')")
  318. if(!query_add_rank.warn_execute())
  319. qdel(query_add_rank)
  320. return
  321. qdel(query_add_rank)
  322. var/datum/DBQuery/query_add_rank_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) VALUES ('[SQLtime()]', '[GLOB.round_id]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'add rank', '[new_rank]', 'New rank added: [new_rank]')")
  323. if(!query_add_rank_log.warn_execute())
  324. qdel(query_add_rank_log)
  325. return
  326. qdel(query_add_rank_log)
  327. qdel(query_rank_in_db)
  328. var/datum/DBQuery/query_change_rank = SSdbcore.NewQuery("UPDATE [format_table_name("admin")] SET `rank` = '[new_rank]' WHERE ckey = '[admin_ckey]'")
  329. if(!query_change_rank.warn_execute())
  330. qdel(query_change_rank)
  331. return
  332. qdel(query_change_rank)
  333. var/datum/DBQuery/query_change_rank_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) VALUES ('[SQLtime()]', '[GLOB.round_id]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'change admin rank', '[admin_ckey]', 'Rank of [admin_ckey] changed from [old_rank] to [new_rank]')")
  334. if(!query_change_rank_log.warn_execute())
  335. qdel(query_change_rank_log)
  336. return
  337. qdel(query_change_rank_log)
  338. if(D) //they were previously an admin
  339. D.disassociate() //existing admin needs to be disassociated
  340. D.rank = R //set the admin_rank as our rank
  341. var/client/C = GLOB.directory[admin_ckey]
  342. D.associate(C)
  343. else
  344. D = new(R, admin_ckey, TRUE) //new admin
  345. message_admins(m1)
  346. log_admin(m2)
  347. /datum/admins/proc/change_admin_flags(admin_ckey, admin_key, use_db, datum/admins/D, legacy_only)
  348. var/new_flags = input_bitfield(usr, "Include permission flags<br>[use_db ? "This will affect ALL admins with this rank." : "This will affect only the current admin [admin_key]"]", "admin_flags", D.rank.include_rights, 350, 590, allowed_edit_list = usr.client.holder.rank.can_edit_rights)
  349. if(isnull(new_flags))
  350. return
  351. var/new_exclude_flags = input_bitfield(usr, "Exclude permission flags<br>Flags enabled here will be removed from a rank.<br>Note these take precedence over included flags.<br>[use_db ? "This will affect ALL admins with this rank." : "This will affect only the current admin [admin_key]"]", "admin_flags", D.rank.exclude_rights, 350, 670, "red", usr.client.holder.rank.can_edit_rights)
  352. if(isnull(new_exclude_flags))
  353. return
  354. var/new_can_edit_flags = input_bitfield(usr, "Editable permission flags<br>These are the flags this rank is allowed to edit if they have access to the permissions panel.<br>They will be unable to modify admins to a rank that has a flag not included here.<br>[use_db ? "This will affect ALL admins with this rank." : "This will affect only the current admin [admin_key]"]", "admin_flags", D.rank.can_edit_rights, 350, 710, allowed_edit_list = usr.client.holder.rank.can_edit_rights)
  355. if(isnull(new_can_edit_flags))
  356. return
  357. var/m1 = "[key_name_admin(usr)] edited the permissions of [use_db ? " rank [D.rank.name] permanently" : "[admin_key] temporarily"]"
  358. var/m2 = "[key_name(usr)] edited the permissions of [use_db ? " rank [D.rank.name] permanently" : "[admin_key] temporarily"]"
  359. if(use_db || legacy_only)
  360. var/rank_name = sanitizeSQL(D.rank.name)
  361. var/old_flags
  362. var/old_exclude_flags
  363. var/old_can_edit_flags
  364. var/datum/DBQuery/query_get_rank_flags = SSdbcore.NewQuery("SELECT flags, exclude_flags, can_edit_flags FROM [format_table_name("admin_ranks")] WHERE `rank` = '[rank_name]'")
  365. if(!query_get_rank_flags.warn_execute())
  366. qdel(query_get_rank_flags)
  367. return
  368. if(query_get_rank_flags.NextRow())
  369. old_flags = text2num(query_get_rank_flags.item[1])
  370. old_exclude_flags = text2num(query_get_rank_flags.item[2])
  371. old_can_edit_flags = text2num(query_get_rank_flags.item[3])
  372. qdel(query_get_rank_flags)
  373. var/datum/DBQuery/query_change_rank_flags = SSdbcore.NewQuery("UPDATE [format_table_name("admin_ranks")] SET flags = '[new_flags]', exclude_flags = '[new_exclude_flags]', can_edit_flags = '[new_can_edit_flags]' WHERE `rank` = '[rank_name]'")
  374. if(!query_change_rank_flags.warn_execute())
  375. qdel(query_change_rank_flags)
  376. return
  377. qdel(query_change_rank_flags)
  378. var/datum/DBQuery/query_change_rank_flags_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) VALUES ('[SQLtime()]', '[GLOB.round_id]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'change rank flags', '[rank_name]', 'Permissions of [rank_name] changed from[rights2text(old_flags," ")][rights2text(old_exclude_flags," ", "-")][rights2text(old_can_edit_flags," ", "*")] to[rights2text(new_flags," ")][rights2text(new_exclude_flags," ", "-")][rights2text(new_can_edit_flags," ", "*")]')")
  379. if(!query_change_rank_flags_log.warn_execute())
  380. qdel(query_change_rank_flags_log)
  381. return
  382. qdel(query_change_rank_flags_log)
  383. for(var/datum/admin_rank/R in GLOB.admin_ranks)
  384. if(R.name != D.rank.name)
  385. continue
  386. R.rights = new_flags &= ~new_exclude_flags
  387. R.exclude_rights = new_exclude_flags
  388. R.include_rights = new_flags
  389. R.can_edit_rights = new_can_edit_flags
  390. for(var/i in GLOB.admin_datums+GLOB.deadmins)
  391. var/datum/admins/A = GLOB.admin_datums[i]
  392. if(!A)
  393. A = GLOB.deadmins[i]
  394. if (!A)
  395. continue
  396. if(A.rank.name != D.rank.name)
  397. continue
  398. var/client/C = GLOB.directory[A.target]
  399. A.disassociate()
  400. A.associate(C)
  401. else
  402. D.disassociate()
  403. if(!findtext(D.rank.name, "([admin_ckey])")) //not a modified subrank, need to duplicate the admin_rank datum to prevent modifying others too
  404. D.rank = new("[D.rank.name]([admin_ckey])", new_flags, new_exclude_flags, new_can_edit_flags) //duplicate our previous admin_rank but with a new name
  405. //we don't add this clone to the admin_ranks list, as it is unique to that ckey
  406. else
  407. D.rank.rights = new_flags &= ~new_exclude_flags
  408. D.rank.include_rights = new_flags
  409. D.rank.exclude_rights = new_exclude_flags
  410. D.rank.can_edit_rights = new_can_edit_flags
  411. var/client/C = GLOB.directory[admin_ckey] //find the client with the specified ckey (if they are logged in)
  412. D.associate(C) //link up with the client and add verbs
  413. message_admins(m1)
  414. log_admin(m2)
  415. /datum/admins/proc/remove_rank(admin_rank)
  416. if(!admin_rank)
  417. return
  418. for(var/datum/admin_rank/R in GLOB.admin_ranks)
  419. if(R.name == admin_rank && (!(R.rights & usr.client.holder.rank.can_edit_rights) == R.rights))
  420. to_chat(usr, "<span class='admin prefix'>You don't have edit rights to all the rights this rank has, rank deletion not permitted.</span>", confidential = TRUE)
  421. return
  422. if(!CONFIG_GET(flag/admin_legacy_system) && CONFIG_GET(flag/protect_legacy_ranks) && (admin_rank in GLOB.protected_ranks))
  423. to_chat(usr, "<span class='admin prefix'>Deletion of protected ranks is not permitted, it must be removed from admin_ranks.txt.</span>", confidential = TRUE)
  424. return
  425. if(CONFIG_GET(flag/load_legacy_ranks_only))
  426. to_chat(usr, "<span class='admin prefix'>Rank deletion not permitted while database rank loading is disabled.</span>", confidential = TRUE)
  427. return
  428. admin_rank = sanitizeSQL(admin_rank)
  429. var/datum/DBQuery/query_admins_with_rank = SSdbcore.NewQuery("SELECT 1 FROM [format_table_name("admin")] WHERE `rank` = '[admin_rank]'")
  430. if(!query_admins_with_rank.warn_execute())
  431. qdel(query_admins_with_rank)
  432. return
  433. if(query_admins_with_rank.NextRow())
  434. qdel(query_admins_with_rank)
  435. to_chat(usr, "<span class='danger'>Error: Rank deletion attempted while rank still used; Tell a coder, this shouldn't happen.</span>", confidential = TRUE)
  436. return
  437. qdel(query_admins_with_rank)
  438. if(alert("Are you sure you want to remove [admin_rank]?","Confirm Removal","Do it","Cancel") == "Do it")
  439. var/m1 = "[key_name_admin(usr)] removed rank [admin_rank] permanently"
  440. var/m2 = "[key_name(usr)] removed rank [admin_rank] permanently"
  441. var/datum/DBQuery/query_add_rank = SSdbcore.NewQuery("DELETE FROM [format_table_name("admin_ranks")] WHERE `rank` = '[admin_rank]'")
  442. if(!query_add_rank.warn_execute())
  443. qdel(query_add_rank)
  444. return
  445. qdel(query_add_rank)
  446. var/datum/DBQuery/query_add_rank_log = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_log")] (datetime, round_id, adminckey, adminip, operation, target, log) VALUES ('[SQLtime()]', '[GLOB.round_id]', '[sanitizeSQL(usr.ckey)]', INET_ATON('[sanitizeSQL(usr.client.address)]'), 'remove rank', '[admin_rank]', 'Rank removed: [admin_rank]')")
  447. if(!query_add_rank_log.warn_execute())
  448. qdel(query_add_rank_log)
  449. return
  450. qdel(query_add_rank_log)
  451. message_admins(m1)
  452. log_admin(m2)
  453. /datum/admins/proc/sync_lastadminrank(admin_ckey, admin_key, datum/admins/D)
  454. var/sqlrank = "Player"
  455. if (D)
  456. sqlrank = sanitizeSQL(D.rank.name)
  457. admin_ckey = sanitizeSQL(admin_ckey)
  458. var/datum/DBQuery/query_sync_lastadminrank = SSdbcore.NewQuery("UPDATE [format_table_name("player")] SET lastadminrank = '[sqlrank]' WHERE ckey = '[admin_ckey]'")
  459. if(!query_sync_lastadminrank.warn_execute())
  460. qdel(query_sync_lastadminrank)
  461. return
  462. qdel(query_sync_lastadminrank)
  463. to_chat(usr, "<span class='admin'>Sync of [admin_key] successful.</span>", confidential = TRUE)