From a28de54405a12d68c9d9917701c2a6642e04c376 Mon Sep 17 00:00:00 2001
From: Jordie <4343468+Jordie0608@users.noreply.github.com>
Date: Wed, 5 Dec 2018 06:48:37 +1100
Subject: [PATCH] Ban system and interface update (#41176)
Spiritual successor and extension to #17798, an almost entire rebuild of the SQL ban system backend and interface.
Bantypes are removed per #8584 and #6174. All bans are now 'role bans', server bans are when a ban's role is server. Admin bans are a column, meaning it's possible to ban admins from jobs.
Bans now have only an expiry datetime, duration is calculated from this when queried.
unbanned column is removed as it's superfluous, checking unban status is now done through checking unban_datetime. unban_round_id column added. Each ip and computerid columns rearranged so ip is always first, like in other tables. Bans now permit a null ckey, ip and computerid.
Ban checking is split into two procs now is_banned_from() does a check if a ckey is banned from one or more roles and returns true or false. This effectively replaces jobban_isbanned() used in simple if() statements. If connected a client's ban cache is checked rather than querying the DB. This makes it possible for a client connected to two or more servers to ignore any bans made on one server until their ban cache is rebuilt on the others. Could be avoided with cross-server calls to update ban caches or just the removal of the ban cache but as is I've done neither since I think it's enough of an edge case to not be worth it.
The second proc is is_banned_from_with_details(), this queries the DB for a role ban on a player's ckey, ip or CID and returns the details. This replaces direct queries in IsBanned.dm and the preferences menu.
The legacy ban system is removed.
The interfaces for banning, unbanning and editing bans have been remade to require less clicking and easier simultaneous operations. The banning and jobban panel are combined. They also store player connection details when opened so a client disconnecting no longer stops a ban being placed.
New banning panel:
Key, IP and CID can all be toggled to allow excluding them from a ban.
Checking Use IP and CID from last connection lets you enter only a ckey and have the DB fill these fields in for you, if possible.
Temporary bans have a drop-menu which lets you select between seconds, minutes, hours, days, weeks, months and years so you don't need to calculate how many minutes a long ban would be. The ban is still converted into minutes on the DB however.
Checking any of the head roles will check both of the boxes for you.
The red role box indicates there is already a ban on that role for this ckey. You can apply additional role bans to stack them.
New unbanning panel:
Unbanning panel is now separate from the banning panel but otherwise functionally the same.
Ban editing panel:
Actually just a modified banning panel, all the features from it work the same here.
You can now edit almost all parameters of a ban instead of just the reason.
You can't edit severity as it's not really part of the ban.
The panels have been tested but I've not been able to get my local server to be accessible so ban functionality isn't properly confirmed. Plenty of testing will be required as I'd rather not break bans.
cl
admin: Ban interface rework. The banning and unbanning panels have received a new design which is easier to use and allows multiple role bans to be made at once.
prefix: Ban search and unbanning moved to unbanning panel, which is now a separate panel to the old banning panel.
/cl
---
SQL/ban_conversion_2018-10-28.py | 174 +++++
SQL/database_changelog.txt | 42 +-
SQL/tgstation_schema.sql | 53 +-
SQL/tgstation_schema_prefixed.sql | 53 +-
code/__DEFINES/role_preferences.dm | 32 +
code/__DEFINES/subsystems.dm | 4 +-
code/__HELPERS/game.dm | 4 +-
code/__HELPERS/unsorted.dm | 2 +-
.../configuration/entries/general.dm | 3 -
code/controllers/subsystem/job.dm | 12 +-
code/datums/diseases/transformation.dm | 2 +-
code/game/gamemodes/changeling/changeling.dm | 2 +-
.../game/gamemodes/changeling/traitor_chan.dm | 2 +-
code/game/gamemodes/game_mode.dm | 7 +-
code/game/gamemodes/traitor/traitor.dm | 4 +-
code/game/objects/items/robot/robot_parts.dm | 2 +-
code/game/objects/structures/ai_core.dm | 2 +-
code/game/world.dm | 3 +
code/modules/admin/IsBanned.dm | 42 +-
code/modules/admin/NewBan.dm | 235 ------
code/modules/admin/admin.dm | 17 +-
code/modules/admin/admin_verbs.dm | 24 +-
code/modules/admin/sql_ban_system.dm | 713 ++++++++++++++++++
code/modules/admin/topic.dm | 62 ++
code/modules/admin/verbs/one_click_antag.dm | 2 +-
.../antagonists/_common/antag_datum.dm | 2 +-
code/modules/antagonists/cult/runes.dm | 2 +-
code/modules/awaymissions/corpse.dm | 2 +-
code/modules/client/client_defines.dm | 7 +-
code/modules/client/preferences.dm | 37 +-
code/modules/client/verbs/ooc.dm | 2 +-
.../modules/mob/dead/new_player/new_player.dm | 4 +-
code/modules/mob/living/brain/posibrain.dm | 2 +-
code/modules/mob/living/emote.dm | 2 +-
.../friendly/drone/drones_as_items.dm | 2 +-
code/modules/mob/say.dm | 2 +-
.../research/xenobiology/xenobiology.dm | 2 +-
config/config.txt | 3 -
html/admin/banpanel.css | 182 +++++
html/admin/banpanel.js | 16 +
html/admin/unbanpanel.css | 61 ++
tgstation.dme | 4 +-
42 files changed, 1448 insertions(+), 382 deletions(-)
create mode 100644 SQL/ban_conversion_2018-10-28.py
delete mode 100644 code/modules/admin/NewBan.dm
create mode 100644 code/modules/admin/sql_ban_system.dm
create mode 100644 html/admin/banpanel.css
create mode 100644 html/admin/banpanel.js
create mode 100644 html/admin/unbanpanel.css
diff --git a/SQL/ban_conversion_2018-10-28.py b/SQL/ban_conversion_2018-10-28.py
new file mode 100644
index 000000000000..26d928bfd167
--- /dev/null
+++ b/SQL/ban_conversion_2018-10-28.py
@@ -0,0 +1,174 @@
+#Python 3+ Script for converting ban table format as of 2018-10-28 made by Jordie0608
+#
+#Before starting ensure you have installed the mysqlclient package https://github.com/PyMySQL/mysqlclient-python
+#It can be downloaded from command line with pip:
+#pip install mysqlclient
+#
+#You will also have to create a new ban table for inserting converted data to per the schema:
+#CREATE TABLE `ban` (
+# `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
+# `bantime` DATETIME NOT NULL,
+# `server_ip` INT(10) UNSIGNED NOT NULL,
+# `server_port` SMALLINT(5) UNSIGNED NOT NULL,
+# `round_id` INT(11) UNSIGNED NOT NULL,
+# `role` VARCHAR(32) NULL DEFAULT NULL,
+# `expiration_time` DATETIME NULL DEFAULT NULL,
+# `applies_to_admins` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0',
+# `reason` VARCHAR(2048) NOT NULL,
+# `ckey` VARCHAR(32) NULL DEFAULT NULL,
+# `ip` INT(10) UNSIGNED NULL DEFAULT NULL,
+# `computerid` VARCHAR(32) NULL DEFAULT NULL,
+# `a_ckey` VARCHAR(32) NOT NULL,
+# `a_ip` INT(10) UNSIGNED NOT NULL,
+# `a_computerid` VARCHAR(32) NOT NULL,
+# `who` VARCHAR(2048) NOT NULL,
+# `adminwho` VARCHAR(2048) NOT NULL,
+# `edits` TEXT NULL DEFAULT NULL,
+# `unbanned_datetime` DATETIME NULL DEFAULT NULL,
+# `unbanned_ckey` VARCHAR(32) NULL DEFAULT NULL,
+# `unbanned_ip` INT(10) UNSIGNED NULL DEFAULT NULL,
+# `unbanned_computerid` VARCHAR(32) NULL DEFAULT NULL,
+# `unbanned_round_id` INT(11) UNSIGNED NULL DEFAULT NULL,
+# PRIMARY KEY (`id`),
+# KEY `idx_ban_isbanned` (`ckey`,`role`,`unbanned_datetime`,`expiration_time`),
+# KEY `idx_ban_isbanned_details` (`ckey`,`ip`,`computerid`,`role`,`unbanned_datetime`,`expiration_time`),
+# KEY `idx_ban_count` (`bantime`,`a_ckey`,`applies_to_admins`,`unbanned_datetime`,`expiration_time`)
+#) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+#This is to prevent the destruction of existing data and allow rollbacks to be performed in the event of an error during conversion
+#Once conversion is complete remember to rename the old and new ban tables; it's up to you if you want to keep the old table
+#
+#To view the parameters for this script, execute it with the argument --help
+#All the positional arguments are required, remember to include prefixes in your table names if you use them
+#An example of the command used to execute this script from powershell:
+#python ban_conversion_2018-10-28.py "localhost" "root" "password" "feedback" "SS13_ban" "SS13_ban_new"
+#I found that this script would complete conversion of 35000 rows in approximately 20 seconds, results will depend on the size of your ban table and computer used
+#
+#The script has been tested to complete with tgstation's ban table as of 2018-09-02 02:19:56
+#In the event of an error the new ban table is automatically truncated
+#The source table is never modified so you don't have to worry about losing any data due to errors
+#Some additional error correction is performed to fix problems specific to legacy and invalid data in tgstation's ban table, these operations are tagged with a 'TG:' comment
+#Even if you don't have any of these specific problems in your ban table the operations won't have matter as they have an insignificant effect on runtime
+#
+#While this script is safe to run with your game server(s) active, any bans created after the script has started won't be converted
+#You will also have to ensure that the code and table names are updated between rounds as neither will be compatible
+
+import MySQLdb
+import argparse
+import sys
+from datetime import datetime
+
+def parse_role(bantype, job):
+ if bantype in ("PERMABAN", "TEMPBAN", "ADMIN_PERMABAN", "ADMIN_TEMPBAN"):
+ role = "Server"
+ else:
+ #TG: Some legacy jobbans are missing the last character from their job string.
+ job_name_fixes = {"A":"AI", "Captai":"Captain", "Cargo Technicia":"Cargo Technician", "Chaplai":"Chaplain", "Che":"Chef", "Chemis":"Chemist", "Chief Enginee":"Chief Engineer", "Chief Medical Office":"Chief Medical Officer", "Cybor":"Cyborg", "Detectiv":"Detective", "Head of Personne":"Head of Personnel", "Head of Securit":"Head of Security", "Mim":"Mime", "pA":"pAI", "Quartermaste":"Quartermaster", "Research Directo":"Research Director", "Scientis":"Scientist", "Security Office":"Security Officer", "Station Enginee":"Station Engineer", "Syndicat":"Syndicate", "Warde":"Warden"}
+ keep_job_names = ("AI", "Head of Personnel", "Head of Security", "OOC", "pAI")
+ if job in job_name_fixes:
+ role = job_name_fixes[job]
+ #Some job names we want to keep the same as .title() would return a different string.
+ elif job in keep_job_names:
+ role = job
+ #And then there's this asshole.
+ elif job == "servant of Ratvar":
+ role = "Servant of Ratvar"
+ else:
+ role = job.title()
+ return role
+
+def parse_admin(bantype):
+ if bantype in ("ADMIN_PERMABAN", "ADMIN_TEMPBAN"):
+ return 1
+ else:
+ return 0
+
+def parse_datetime(bantype, expiration_time):
+ if bantype in ("PERMABAN", "JOB_PERMABAN", "ADMIN_PERMABAN"):
+ expiration_time = None
+ #TG: two bans with an invalid expiration_time due to admins setting the duration to approx. 19 billion years, I'm going to count them as permabans.
+ elif expiration_time == "0000-00-00 00:00:00":
+ expiration_time = None
+ elif not expiration_time:
+ expiration_time = None
+ return expiration_time
+
+def parse_not_null(field):
+ if not field:
+ field = 0
+ return field
+
+def parse_for_empty(field):
+ if not field:
+ field = None
+ #TG: Several bans from 2012, probably from clients disconnecting while a ban was being made.
+ elif field == "BLANK CKEY ERROR":
+ field = None
+ return field
+
+if sys.version_info[0] < 3:
+ raise Exception("Python must be at least version 3 for this script.")
+current_round = 0
+parser = argparse.ArgumentParser()
+parser.add_argument("address", help="MySQL server address (use localhost for the current computer)")
+parser.add_argument("username", help="MySQL login username")
+parser.add_argument("password", help="MySQL login username")
+parser.add_argument("database", help="Database name")
+parser.add_argument("curtable", help="Name of the current ban table (remember prefixes if you use them)")
+parser.add_argument("newtable", help="Name of the new table to insert to, can't be same as the source table (remember prefixes)")
+args = parser.parse_args()
+db=MySQLdb.connect(host=args.address, user=args.username, passwd=args.password, db=args.database)
+cursor=db.cursor()
+current_table = args.curtable
+new_table = args.newtable
+#TG: Due to deleted rows and a legacy ban import being inserted from id 3140 id order is not contiguous or in line with date order. While technically valid, it's confusing and I don't like that.
+#TG: So instead of just running through to MAX(id) we're going to reorder the records by bantime as we go.
+cursor.execute("SELECT id FROM " + current_table + " ORDER BY bantime ASC")
+id_list = cursor.fetchall()
+start_time = datetime.now()
+print("Beginning conversion at {0}".format(start_time.strftime("%Y-%m-%d %H:%M:%S")))
+try:
+ for current_id in id_list:
+ if current_id[0] % 5000 == 0:
+ cur_time = datetime.now()
+ print("Reached row ID {0} Duration: {1}".format(current_id[0], cur_time - start_time))
+ cursor.execute("SELECT * FROM " + current_table + " WHERE id = %s", [current_id[0]])
+ query_row = cursor.fetchone()
+ if not query_row:
+ continue
+ else:
+ #TG: bans with an empty reason which were somehow created with almost every field being null or empty, we can't do much but skip this
+ if not query_row[6]:
+ continue
+ bantime = query_row[1]
+ server_ip = query_row[2]
+ server_port = query_row[3]
+ round_id = query_row[4]
+ applies_to_admins = parse_admin(query_row[5])
+ reason = query_row[6]
+ role = parse_role(query_row[5], query_row[7])
+ expiration_time = parse_datetime(query_row[5], query_row[9])
+ ckey = parse_for_empty(query_row[10])
+ computerid = parse_for_empty(query_row[11])
+ ip = parse_for_empty(query_row[12])
+ a_ckey = parse_not_null(query_row[13])
+ a_computerid = parse_not_null(query_row[14])
+ a_ip = parse_not_null(query_row[15])
+ who = query_row[16]
+ adminwho = query_row[17]
+ edits = parse_for_empty(query_row[18])
+ unbanned_datetime = parse_datetime(None, query_row[20])
+ unbanned_ckey = parse_for_empty(query_row[21])
+ unbanned_computerid = parse_for_empty(query_row[22])
+ unbanned_ip = parse_for_empty(query_row[23])
+ cursor.execute("INSERT INTO " + new_table + " (bantime, server_ip, server_port, round_id, role, expiration_time, applies_to_admins, reason, ckey, ip, computerid, a_ckey, a_ip, a_computerid, who, adminwho, edits, unbanned_datetime, unbanned_ckey, unbanned_ip, unbanned_computerid) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)", (bantime, server_ip, server_port, round_id, role, expiration_time, applies_to_admins, reason, ckey, ip, computerid, a_ckey, a_ip, a_computerid, who, adminwho, edits, unbanned_datetime, unbanned_ckey, unbanned_ip, unbanned_computerid))
+ db.commit()
+ end_time = datetime.now()
+ print("Conversion completed at {0}".format(datetime.now().strftime("%Y-%m-%d %H:%M:%S")))
+ print("Script duration: {0}".format(end_time - start_time))
+except Exception as e:
+ end_time = datetime.now()
+ print("Error encountered on row ID {0} at {1}".format(current_id[0], datetime.now().strftime("%Y-%m-%d %H:%M:%S")))
+ print("Script duration: {0}".format(end_time - start_time))
+ cursor.execute("TRUNCATE {0} ".format(new_table))
+ raise e
+cursor.close()
diff --git a/SQL/database_changelog.txt b/SQL/database_changelog.txt
index 56f05e84f108..24ad3f1a659a 100644
--- a/SQL/database_changelog.txt
+++ b/SQL/database_changelog.txt
@@ -2,14 +2,52 @@ Any time you make a change to the schema files, remember to increment the databa
The latest database version is 4.7; The query to update the schema revision table is:
-INSERT INTO `schema_revision` (`major`, `minor`) VALUES (4, 7);
+INSERT INTO `schema_revision` (`major`, `minor`) VALUES (5, 0);
or
-INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (4, 7);
+INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (5, 0);
In any query remember to add a prefix to the table names if you use one.
----------------------------------------------------
+Version 5.0, 28 October 2018, by Jordie0608
+Modified ban table to remove the need for the `bantype` column, a python script is used to migrate data to this new format.
+
+See the file 'ban_conversion_2018-10-28.py' for instructions on how to use the script.
+
+A new ban table can be created with the query:
+CREATE TABLE `ban` (
+ `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
+ `bantime` DATETIME NOT NULL,
+ `server_ip` INT(10) UNSIGNED NOT NULL,
+ `server_port` SMALLINT(5) UNSIGNED NOT NULL,
+ `round_id` INT(11) UNSIGNED NOT NULL,
+ `role` VARCHAR(32) NULL DEFAULT NULL,
+ `expiration_time` DATETIME NULL DEFAULT NULL,
+ `applies_to_admins` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0',
+ `reason` VARCHAR(2048) NOT NULL,
+ `ckey` VARCHAR(32) NULL DEFAULT NULL,
+ `ip` INT(10) UNSIGNED NULL DEFAULT NULL,
+ `computerid` VARCHAR(32) NULL DEFAULT NULL,
+ `a_ckey` VARCHAR(32) NOT NULL,
+ `a_ip` INT(10) UNSIGNED NOT NULL,
+ `a_computerid` VARCHAR(32) NOT NULL,
+ `who` VARCHAR(2048) NOT NULL,
+ `adminwho` VARCHAR(2048) NOT NULL,
+ `edits` TEXT NULL DEFAULT NULL,
+ `unbanned_datetime` DATETIME NULL DEFAULT NULL,
+ `unbanned_ckey` VARCHAR(32) NULL DEFAULT NULL,
+ `unbanned_ip` INT(10) UNSIGNED NULL DEFAULT NULL,
+ `unbanned_computerid` VARCHAR(32) NULL DEFAULT NULL,
+ `unbanned_round_id` INT(11) UNSIGNED NULL DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ KEY `idx_ban_isbanned` (`ckey`,`role`,`unbanned_datetime`,`expiration_time`),
+ KEY `idx_ban_isbanned_details` (`ckey`,`ip`,`computerid`,`role`,`unbanned_datetime`,`expiration_time`),
+ KEY `idx_ban_count` (`bantime`,`a_ckey`,`applies_to_admins`,`unbanned_datetime`,`expiration_time`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+
+----------------------------------------------------
+
Version 4.7, 18 August 2018, by CitrusGender
Modified table `messages`, adding column `severity` to classify notes based on their severity.
diff --git a/SQL/tgstation_schema.sql b/SQL/tgstation_schema.sql
index e4808fcfec2c..ad91ec1110fd 100644
--- a/SQL/tgstation_schema.sql
+++ b/SQL/tgstation_schema.sql
@@ -67,34 +67,33 @@ DROP TABLE IF EXISTS `ban`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `ban` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `bantime` datetime NOT NULL,
- `server_ip` int(10) unsigned NOT NULL,
- `server_port` smallint(5) unsigned NOT NULL,
- `round_id` int(11) NOT NULL,
- `bantype` enum('PERMABAN','TEMPBAN','JOB_PERMABAN','JOB_TEMPBAN','ADMIN_PERMABAN','ADMIN_TEMPBAN') NOT NULL,
- `reason` varchar(2048) NOT NULL,
- `job` varchar(32) DEFAULT NULL,
- `duration` int(11) NOT NULL,
- `expiration_time` datetime NOT NULL,
- `ckey` varchar(32) NOT NULL,
- `computerid` varchar(32) NOT NULL,
- `ip` int(10) unsigned NOT NULL,
- `a_ckey` varchar(32) NOT NULL,
- `a_computerid` varchar(32) NOT NULL,
- `a_ip` int(10) unsigned NOT NULL,
- `who` varchar(2048) NOT NULL,
- `adminwho` varchar(2048) NOT NULL,
- `edits` text,
- `unbanned` tinyint(3) unsigned DEFAULT NULL,
- `unbanned_datetime` datetime DEFAULT NULL,
- `unbanned_ckey` varchar(32) DEFAULT NULL,
- `unbanned_computerid` varchar(32) DEFAULT NULL,
- `unbanned_ip` int(10) unsigned DEFAULT NULL,
+ `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
+ `bantime` DATETIME NOT NULL,
+ `server_ip` INT(10) UNSIGNED NOT NULL,
+ `server_port` SMALLINT(5) UNSIGNED NOT NULL,
+ `round_id` INT(11) UNSIGNED NOT NULL,
+ `role` VARCHAR(32) NULL DEFAULT NULL,
+ `expiration_time` DATETIME NULL DEFAULT NULL,
+ `applies_to_admins` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0',
+ `reason` VARCHAR(2048) NOT NULL,
+ `ckey` VARCHAR(32) NULL DEFAULT NULL,
+ `ip` INT(10) UNSIGNED NULL DEFAULT NULL,
+ `computerid` VARCHAR(32) NULL DEFAULT NULL,
+ `a_ckey` VARCHAR(32) NOT NULL,
+ `a_ip` INT(10) UNSIGNED NOT NULL,
+ `a_computerid` VARCHAR(32) NOT NULL,
+ `who` VARCHAR(2048) NOT NULL,
+ `adminwho` VARCHAR(2048) NOT NULL,
+ `edits` TEXT NULL DEFAULT NULL,
+ `unbanned_datetime` DATETIME NULL DEFAULT NULL,
+ `unbanned_ckey` VARCHAR(32) NULL DEFAULT NULL,
+ `unbanned_ip` INT(10) UNSIGNED NULL DEFAULT NULL,
+ `unbanned_computerid` VARCHAR(32) NULL DEFAULT NULL,
+ `unbanned_round_id` INT(11) UNSIGNED NULL DEFAULT NULL,
PRIMARY KEY (`id`),
- KEY `idx_ban_checkban` (`ckey`,`bantype`,`expiration_time`,`unbanned`,`job`),
- KEY `idx_ban_isbanned` (`ckey`,`ip`,`computerid`,`bantype`,`expiration_time`,`unbanned`),
- KEY `idx_ban_count` (`id`,`a_ckey`,`bantype`,`expiration_time`,`unbanned`)
+ KEY `idx_ban_isbanned` (`ckey`,`role`,`unbanned_datetime`,`expiration_time`),
+ KEY `idx_ban_isbanned_details` (`ckey`,`ip`,`computerid`,`role`,`unbanned_datetime`,`expiration_time`),
+ KEY `idx_ban_count` (`bantime`,`a_ckey`,`applies_to_admins`,`unbanned_datetime`,`expiration_time`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
diff --git a/SQL/tgstation_schema_prefixed.sql b/SQL/tgstation_schema_prefixed.sql
index 5407fc462c1c..e36a7cde9fbb 100644
--- a/SQL/tgstation_schema_prefixed.sql
+++ b/SQL/tgstation_schema_prefixed.sql
@@ -67,34 +67,33 @@ DROP TABLE IF EXISTS `SS13_ban`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `SS13_ban` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `bantime` datetime NOT NULL,
- `server_ip` int(10) unsigned NOT NULL,
- `server_port` smallint(5) unsigned NOT NULL,
- `round_id` int(11) NOT NULL,
- `bantype` enum('PERMABAN','TEMPBAN','JOB_PERMABAN','JOB_TEMPBAN','ADMIN_PERMABAN','ADMIN_TEMPBAN') NOT NULL,
- `reason` varchar(2048) NOT NULL,
- `job` varchar(32) DEFAULT NULL,
- `duration` int(11) NOT NULL,
- `expiration_time` datetime NOT NULL,
- `ckey` varchar(32) NOT NULL,
- `computerid` varchar(32) NOT NULL,
- `ip` int(10) unsigned NOT NULL,
- `a_ckey` varchar(32) NOT NULL,
- `a_computerid` varchar(32) NOT NULL,
- `a_ip` int(10) unsigned NOT NULL,
- `who` varchar(2048) NOT NULL,
- `adminwho` varchar(2048) NOT NULL,
- `edits` text,
- `unbanned` tinyint(3) unsigned DEFAULT NULL,
- `unbanned_datetime` datetime DEFAULT NULL,
- `unbanned_ckey` varchar(32) DEFAULT NULL,
- `unbanned_computerid` varchar(32) DEFAULT NULL,
- `unbanned_ip` int(10) unsigned DEFAULT NULL,
+ `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
+ `bantime` DATETIME NOT NULL,
+ `server_ip` INT(10) UNSIGNED NOT NULL,
+ `server_port` SMALLINT(5) UNSIGNED NOT NULL,
+ `round_id` INT(11) UNSIGNED NOT NULL,
+ `role` VARCHAR(32) NULL DEFAULT NULL,
+ `expiration_time` DATETIME NULL DEFAULT NULL,
+ `applies_to_admins` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0',
+ `reason` VARCHAR(2048) NOT NULL,
+ `ckey` VARCHAR(32) NULL DEFAULT NULL,
+ `ip` INT(10) UNSIGNED NULL DEFAULT NULL,
+ `computerid` VARCHAR(32) NULL DEFAULT NULL,
+ `a_ckey` VARCHAR(32) NOT NULL,
+ `a_ip` INT(10) UNSIGNED NOT NULL,
+ `a_computerid` VARCHAR(32) NOT NULL,
+ `who` VARCHAR(2048) NOT NULL,
+ `adminwho` VARCHAR(2048) NOT NULL,
+ `edits` TEXT NULL DEFAULT NULL,
+ `unbanned_datetime` DATETIME NULL DEFAULT NULL,
+ `unbanned_ckey` VARCHAR(32) NULL DEFAULT NULL,
+ `unbanned_ip` INT(10) UNSIGNED NULL DEFAULT NULL,
+ `unbanned_computerid` VARCHAR(32) NULL DEFAULT NULL,
+ `unbanned_round_id` INT(11) UNSIGNED NULL DEFAULT NULL,
PRIMARY KEY (`id`),
- KEY `idx_ban_checkban` (`ckey`,`bantype`,`expiration_time`,`unbanned`,`job`),
- KEY `idx_ban_isbanned` (`ckey`,`ip`,`computerid`,`bantype`,`expiration_time`,`unbanned`),
- KEY `idx_ban_count` (`id`,`a_ckey`,`bantype`,`expiration_time`,`unbanned`)
+ KEY `idx_ban_isbanned` (`ckey`,`role`,`unbanned_datetime`,`expiration_time`),
+ KEY `idx_ban_isbanned_details` (`ckey`,`ip`,`computerid`,`role`,`unbanned_datetime`,`expiration_time`),
+ KEY `idx_ban_count` (`bantime`,`a_ckey`,`applies_to_admins`,`unbanned_datetime`,`expiration_time`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm
index 8b9ec53004b7..9490e45cd5ef 100644
--- a/code/__DEFINES/role_preferences.dm
+++ b/code/__DEFINES/role_preferences.dm
@@ -6,6 +6,7 @@
//These are synced with the Database, if you change the values of the defines
//then you MUST update the database!
+<<<<<<< HEAD
#define ROLE_SYNDICATE "Syndicate"
#define ROLE_TRAITOR "traitor"
#define ROLE_OPERATIVE "operative"
@@ -37,6 +38,37 @@
#define ROLE_LAVALAND "lavaland"
#define ROLE_SHADOWLING "shadowling" // Yogs
#define ROLE_INTERNAL_AFFAIRS "internal affairs agent"
+=======
+#define ROLE_SYNDICATE "Syndicate"
+#define ROLE_TRAITOR "Traitor"
+#define ROLE_OPERATIVE "Operative"
+#define ROLE_CHANGELING "Changeling"
+#define ROLE_WIZARD "Wizard"
+#define ROLE_MALF "Malf AI"
+#define ROLE_REV "Revolutionary"
+#define ROLE_REV_HEAD "Head Revolutionary"
+#define ROLE_ALIEN "Xenomorph"
+#define ROLE_PAI "pAI"
+#define ROLE_CULTIST "Cultist"
+#define ROLE_BLOB "Blob"
+#define ROLE_NINJA "Space Ninja"
+#define ROLE_MONKEY "Monkey"
+#define ROLE_ABDUCTOR "Abductor"
+#define ROLE_REVENANT "Revenant"
+#define ROLE_DEVIL "Devil"
+#define ROLE_SERVANT_OF_RATVAR "Servant of Ratvar"
+#define ROLE_BROTHER "Blood Brother"
+#define ROLE_BRAINWASHED "Brainwashed Victim"
+#define ROLE_OVERTHROW "Syndicate Mutineer"
+#define ROLE_HIVE "Hivemind Host"
+#define ROLE_SENTIENCE "Sentience Potion Spawn"
+#define ROLE_MIND_TRANSFER "Mind Transfer Potion"
+#define ROLE_POSIBRAIN "Posibrain"
+#define ROLE_DRONE "Drone"
+#define ROLE_DEATHSQUAD "Deathsquad"
+#define ROLE_LAVALAND "Lavaland"
+#define ROLE_INTERNAL_AFFAIRS "Internal Affairs Agent"
+>>>>>>> 8a66665e95... Ban system and interface update (#41176)
//Missing assignment means it's not a gamemode specific role, IT'S NOT A BUG OR ERROR.
//The gamemode specific ones are just so the gamemodes can query whether a player is old enough
diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm
index 39da6d14099a..89f281678a8e 100644
--- a/code/__DEFINES/subsystems.dm
+++ b/code/__DEFINES/subsystems.dm
@@ -1,7 +1,7 @@
//Update this whenever the db schema changes
//make sure you add an update to the schema_version stable in the db changelog
-#define DB_MAJOR_VERSION 4
-#define DB_MINOR_VERSION 7
+#define DB_MAJOR_VERSION 5
+#define DB_MINOR_VERSION 0
//Timing subsystem
//Don't run if there is an identical unique timer active
diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm
index 0655e8f53e82..62cff3e6bb78 100644
--- a/code/__HELPERS/game.dm
+++ b/code/__HELPERS/game.dm
@@ -433,7 +433,7 @@
if(!gametypeCheck.age_check(M.client))
continue
if(jobbanType)
- if(jobban_isbanned(M, jobbanType) || QDELETED(M) || jobban_isbanned(M, ROLE_SYNDICATE) || QDELETED(M))
+ if(is_banned_from(M.ckey, list(jobbanType, ROLE_SYNDICATE)) || QDELETED(M))
continue
showCandidatePollWindow(M, poll_time, Question, result, ignore_category, time_passed, flashwindow)
@@ -494,7 +494,7 @@
if(!C || (!C.prefs.windowflashing && !ignorepref))
return
winset(C, "mainwindow", "flash=5")
-
+
//Recursively checks if an item is inside a given type, even through layers of storage. Returns the atom if it finds it.
/proc/recursive_loc_check(atom/movable/target, type)
var/atom/A = target
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index f37269a1024b..27b7eb75a940 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -203,7 +203,7 @@ Turf and target are separate in case you want to teleport some distance from a t
var/loop = 1
var/safety = 0
- var/banned = jobban_isbanned(src, "appearance")
+ var/banned = is_banned_from(C.ckey, "Appearance")
while(loop && safety < 5)
if(C && C.prefs.custom_names[role] && !safety && !banned)
diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm
index f2df7787fb49..a543b4e3bbba 100644
--- a/code/controllers/configuration/entries/general.dm
+++ b/code/controllers/configuration/entries/general.dm
@@ -153,9 +153,6 @@
/datum/config_entry/flag/usewhitelist
-/datum/config_entry/flag/ban_legacy_system //Defines whether the server uses the legacy banning system with the files in /data or the SQL system.
- protection = CONFIG_ENTRY_LOCKED
-
/datum/config_entry/flag/use_age_restriction_for_jobs //Do jobs use account age restrictions? --requires database
/datum/config_entry/flag/use_account_age_for_jobs //Uses the time they made the account for the job restriction stuff. New player joining alerts should be unaffected.
diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm
index 46f759329db7..03d04273999b 100644
--- a/code/controllers/subsystem/job.dm
+++ b/code/controllers/subsystem/job.dm
@@ -79,7 +79,7 @@ SUBSYSTEM_DEF(job)
var/datum/job/job = GetJob(rank)
if(!job)
return FALSE
- if(jobban_isbanned(player, rank) || QDELETED(player))
+ if(is_banned_from(player.ckey, rank) || QDELETED(player))
return FALSE
if(!job.player_old_enough(player.client))
return FALSE
@@ -101,7 +101,7 @@ SUBSYSTEM_DEF(job)
JobDebug("Running FOC, Job: [job], Level: [level], Flag: [flag]")
var/list/candidates = list()
for(var/mob/dead/new_player/player in unassigned)
- if(jobban_isbanned(player, job.title) || QDELETED(player))
+ if(is_banned_from(player.ckey, job.title) || QDELETED(player))
JobDebug("FOC isbanned failed, Player: [player]")
continue
if(!job.player_old_enough(player.client))
@@ -139,7 +139,7 @@ SUBSYSTEM_DEF(job)
if(job.title in GLOB.command_positions) //If you want a command position, select it!
continue
- if(jobban_isbanned(player, job.title) || QDELETED(player))
+ if(is_banned_from(player.ckey, job.title) || QDELETED(player))
if(QDELETED(player))
JobDebug("GRJ isbanned failed, Player deleted")
break
@@ -316,7 +316,7 @@ SUBSYSTEM_DEF(job)
if(!job)
continue
- if(jobban_isbanned(player, job.title))
+ if(is_banned_from(player.ckey, job.title))
JobDebug("DO isbanned failed, Player: [player], Job:[job.title]")
continue
@@ -365,7 +365,7 @@ SUBSYSTEM_DEF(job)
if(PopcapReached())
RejectPlayer(player)
else if(player.client.prefs.joblessrole == BEOVERFLOW)
- var/allowed_to_be_a_loser = !jobban_isbanned(player, SSjob.overflow_role)
+ var/allowed_to_be_a_loser = !is_banned_from(player.ckey, SSjob.overflow_role)
if(QDELETED(player) || !allowed_to_be_a_loser)
RejectPlayer(player)
else
@@ -497,7 +497,7 @@ SUBSYSTEM_DEF(job)
for(var/mob/dead/new_player/player in GLOB.player_list)
if(!(player.ready == PLAYER_READY_TO_PLAY && player.mind && !player.mind.assigned_role))
continue //This player is not ready
- if(jobban_isbanned(player, job.title) || QDELETED(player))
+ if(is_banned_from(player.ckey, job.title) || QDELETED(player))
banned++
continue
if(!job.player_old_enough(player.client))
diff --git a/code/datums/diseases/transformation.dm b/code/datums/diseases/transformation.dm
index cd071d9808f0..c639b6e3390a 100644
--- a/code/datums/diseases/transformation.dm
+++ b/code/datums/diseases/transformation.dm
@@ -61,7 +61,7 @@
affected_mob.dropItemToGround(I)
var/mob/living/new_mob = new new_form(affected_mob.loc)
if(istype(new_mob))
- if(bantype && jobban_isbanned(affected_mob, bantype))
+ if(bantype && is_banned_from(affected_mob.ckey, bantype))
replace_banned_player(new_mob)
new_mob.a_intent = INTENT_HARM
if(affected_mob.mind)
diff --git a/code/game/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm
index 286b1a6374d6..da85296e7a36 100644
--- a/code/game/gamemodes/changeling/changeling.dm
+++ b/code/game/gamemodes/changeling/changeling.dm
@@ -84,7 +84,7 @@ GLOBAL_VAR(changeling_team_objective_type) //If this is not null, we hand our th
return
if(changelings.len <= (changelingcap - 2) || prob(100 - (csc * 2)))
if(ROLE_CHANGELING in character.client.prefs.be_special)
- if(!jobban_isbanned(character, ROLE_CHANGELING) && !QDELETED(character) && !jobban_isbanned(character, ROLE_SYNDICATE) && !QDELETED(character))
+ if(!is_banned_from(character.ckey, list(ROLE_CHANGELING, ROLE_SYNDICATE)) && !QDELETED(character))
if(age_check(character.client))
if(!(character.job in restricted_jobs))
character.mind.make_Changeling()
diff --git a/code/game/gamemodes/changeling/traitor_chan.dm b/code/game/gamemodes/changeling/traitor_chan.dm
index 9f6fe524cbe3..70c04cb008f0 100644
--- a/code/game/gamemodes/changeling/traitor_chan.dm
+++ b/code/game/gamemodes/changeling/traitor_chan.dm
@@ -70,7 +70,7 @@
return
if(changelings.len <= (changelingcap - 2) || prob(100 / (csc * 4)))
if(ROLE_CHANGELING in character.client.prefs.be_special)
- if(!jobban_isbanned(character, ROLE_CHANGELING) && !QDELETED(character) && !jobban_isbanned(character, ROLE_SYNDICATE) && !QDELETED(character))
+ if(!is_banned_from(character.ckey, list(ROLE_CHANGELING, ROLE_SYNDICATE)) && !QDELETED(character))
if(age_check(character.client))
if(!(character.job in restricted_jobs))
character.mind.make_Changeling()
diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm
index 5eaf31a72c17..f1edf669038b 100644
--- a/code/game/gamemodes/game_mode.dm
+++ b/code/game/gamemodes/game_mode.dm
@@ -371,8 +371,13 @@
for(var/mob/dead/new_player/player in players)
if(player.client && player.ready == PLAYER_READY_TO_PLAY)
+<<<<<<< HEAD
if(role in player.client.prefs.be_special ) //&& !(player.mind.quiet_round)) // yogs - Donor features, quiet round
if(!jobban_isbanned(player, ROLE_SYNDICATE) && !QDELETED(player) && !jobban_isbanned(player, role) && !QDELETED(player)) //Nodrak/Carn: Antag Job-bans
+=======
+ if(role in player.client.prefs.be_special)
+ if(!is_banned_from(player.ckey, list(role, ROLE_SYNDICATE)) && !QDELETED(player))
+>>>>>>> 8a66665e95... Ban system and interface update (#41176)
if(age_check(player.client)) //Must be older than the minimum age
candidates += player.mind // Get a list of all the people who want to be the antagonist for this round
@@ -386,7 +391,7 @@
for(var/mob/dead/new_player/player in players)
if(player.client && player.ready == PLAYER_READY_TO_PLAY)
if(!(role in player.client.prefs.be_special)) // We don't have enough people who want to be antagonist, make a separate list of people who don't want to be one
- if(!jobban_isbanned(player, ROLE_SYNDICATE) && !QDELETED(player) && !jobban_isbanned(player, role) && !QDELETED(player) ) //Nodrak/Carn: Antag Job-bans
+ if(!is_banned_from(player.ckey, list(role, ROLE_SYNDICATE)) && !QDELETED(player))
drafted += player.mind
/* yogs start - Donor features, quiet round
if(player.mind.quiet_round)
diff --git a/code/game/gamemodes/traitor/traitor.dm b/code/game/gamemodes/traitor/traitor.dm
index 099a717e4831..34ceb718d2fe 100644
--- a/code/game/gamemodes/traitor/traitor.dm
+++ b/code/game/gamemodes/traitor/traitor.dm
@@ -86,7 +86,7 @@
return
if((SSticker.mode.traitors.len + pre_traitors.len) <= (traitorcap - 2) || prob(100 / (tsc * 2)))
if(antag_flag in character.client.prefs.be_special)
- if(!jobban_isbanned(character, ROLE_TRAITOR) && !QDELETED(character) && !jobban_isbanned(character, ROLE_SYNDICATE) && !QDELETED(character))
+ if(!is_banned_from(character.ckey, list(ROLE_TRAITOR, ROLE_SYNDICATE)) && !QDELETED(character))
if(age_check(character.client))
if(!(character.job in restricted_jobs))
add_latejoin_traitor(character.mind)
@@ -97,4 +97,4 @@
/datum/game_mode/traitor/generate_report()
return "Although more specific threats are commonplace, you should always remain vigilant for Syndicate agents aboard your station. Syndicate communications have implied that many \
- Nanotrasen employees are Syndicate agents with hidden memories that may be activated at a moment's notice, so it's possible that these agents might not even know their positions."
\ No newline at end of file
+ Nanotrasen employees are Syndicate agents with hidden memories that may be activated at a moment's notice, so it's possible that these agents might not even know their positions."
diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm
index 5538493d7170..e4d7c3384d82 100644
--- a/code/game/objects/items/robot/robot_parts.dm
+++ b/code/game/objects/items/robot/robot_parts.dm
@@ -262,7 +262,7 @@
to_chat(user, "The MMI indicates that the brain is damaged!")
return
- if(jobban_isbanned(BM, "Cyborg") || QDELETED(src) || QDELETED(BM) || QDELETED(user) || QDELETED(M) || !Adjacent(user))
+ if(is_banned_from(BM.ckey, "Cyborg") || QDELETED(src) || QDELETED(BM) || QDELETED(user) || QDELETED(M) || !Adjacent(user))
if(!QDELETED(M))
to_chat(user, "This [M.name] does not seem to fit!")
return
diff --git a/code/game/objects/structures/ai_core.dm b/code/game/objects/structures/ai_core.dm
index fd71fb26aee1..390e28893d8d 100644
--- a/code/game/objects/structures/ai_core.dm
+++ b/code/game/objects/structures/ai_core.dm
@@ -195,7 +195,7 @@
to_chat(user, "Sticking an inactive [M.name] into the frame would sort of defeat the purpose.")
return
- if(!CONFIG_GET(flag/allow_ai) || (jobban_isbanned(M.brainmob, "AI") && !QDELETED(src) && !QDELETED(user) && !QDELETED(M) && !QDELETED(user) && Adjacent(user)))
+ if(!CONFIG_GET(flag/allow_ai) || (is_banned_from(M.brainmob.ckey, "AI") && !QDELETED(src) && !QDELETED(user) && !QDELETED(M) && !QDELETED(user) && Adjacent(user)))
if(!QDELETED(M))
to_chat(user, "This [M.name] does not seem to fit!")
return
diff --git a/code/game/world.dm b/code/game/world.dm
index b57d0f4bf25b..07f15371c927 100644
--- a/code/game/world.dm
+++ b/code/game/world.dm
@@ -38,8 +38,11 @@ GLOBAL_VAR_INIT(bypass_tgs_reboot, world.system_type == UNIX && world.byond_buil
LoadVerbs(/datum/verbs/menu)
if(CONFIG_GET(flag/usewhitelist))
load_whitelist()
+<<<<<<< HEAD
LoadBans()
setup_pretty_filter() //yogs
+=======
+>>>>>>> 8a66665e95... Ban system and interface update (#41176)
GLOB.timezoneOffset = text2num(time2text(0,"hh")) * 36000
diff --git a/code/modules/admin/IsBanned.dm b/code/modules/admin/IsBanned.dm
index 69ca385cbcdc..cbb52851c2a6 100644
--- a/code/modules/admin/IsBanned.dm
+++ b/code/modules/admin/IsBanned.dm
@@ -46,25 +46,12 @@
if(!real_bans_only && extreme_popcap && living_player_count() >= extreme_popcap && !admin)
log_access("Failed Login: [key] - Population cap reached")
return list("reason"="popcap", "desc"= "\nReason: [CONFIG_GET(string/extreme_popcap_message)]")
-
- if(CONFIG_GET(flag/ban_legacy_system))
-
- //Ban Checking
- . = CheckBan(ckey, computer_id, address )
- if(.)
- if (admin)
- log_admin("The admin [key] has been allowed to bypass a matching ban on [.["key"]]")
- message_admins("The admin [key] has been allowed to bypass a matching ban on [.["key"]]")
- addclientmessage(ckey,"You have been allowed to bypass a matching ban on [.["key"]]")
- else
- log_access("Failed Login: [key] [computer_id] [address] - Banned [.["reason"]]")
- return .
-
- else
+ if(CONFIG_GET(flag/sql_enabled))
if(!SSdbcore.Connect())
var/msg = "Ban database connection failure. Key [ckey] not checked"
log_world(msg)
message_admins(msg)
+<<<<<<< HEAD
return
var/ipquery = ""
@@ -119,6 +106,31 @@
return .
qdel(query_ban_check)
+=======
+ else
+ var/list/ban_details = is_banned_from_with_details(ckey, address, computer_id, "Server")
+ for(var/i in ban_details)
+ if(admin)
+ if(text2num(i["applies_to_admins"]))
+ var/msg = "Admin [key] is admin banned, and has been disallowed access."
+ log_admin(msg)
+ message_admins(msg)
+ else
+ var/msg = "Admin [key] has been allowed to bypass a matching non-admin ban on [i["key"]] [i["ip"]]-[i["computerid"]]."
+ log_admin(msg)
+ message_admins(msg)
+ addclientmessage(ckey,"Admin [key] has been allowed to bypass a matching non-admin ban on [i["key"]] [i["ip"]]-[i["computerid"]].")
+ continue
+ var/expires = "This is a permanent ban."
+ if(i["expiration_time"])
+ expires = " The ban is for [DisplayTimeText(text2num(i["duration"]) MINUTES)] and expires on [i["expiration_time"]] (server time)."
+ var/desc = {"You, or another user of this computer or connection ([i["key"]]) is banned from playing here.
+ The ban reason is: [i["reason"]]
+ This ban (BanID #[i["id"]]) was applied by [i["admin_key"]] on [i["bantime"]] during round ID [i["round_id"]].
+ [expires]"}
+ log_access("Failed Login: [key] [computer_id] [address] - Banned (#[i["id"]])")
+ return list("reason"="Banned","desc"="[desc]")
+>>>>>>> 8a66665e95... Ban system and interface update (#41176)
var/list/ban = ..() //default pager ban stuff
if (ban)
var/bannedckey = "ERROR"
diff --git a/code/modules/admin/NewBan.dm b/code/modules/admin/NewBan.dm
deleted file mode 100644
index 94e52ef3c9b0..000000000000
--- a/code/modules/admin/NewBan.dm
+++ /dev/null
@@ -1,235 +0,0 @@
-GLOBAL_VAR(CMinutes)
-GLOBAL_DATUM(Banlist, /savefile)
-GLOBAL_PROTECT(Banlist)
-
-
-/proc/CheckBan(ckey, id, address)
- if(!GLOB.Banlist) // if Banlist cannot be located for some reason
- LoadBans() // try to load the bans
- if(!GLOB.Banlist) // uh oh, can't find bans!
- return 0 // ABORT ABORT ABORT
-
- . = list()
- var/appeal
- var/bran = CONFIG_GET(string/banappeals)
- if(bran)
- appeal = "\nFor more information on your ban, or to appeal, head to [bran]"
- GLOB.Banlist.cd = "/base"
- if( "[ckey][id]" in GLOB.Banlist.dir )
- GLOB.Banlist.cd = "[ckey][id]"
- if (GLOB.Banlist["temp"])
- if (!GetExp(GLOB.Banlist["minutes"]))
- ClearTempbans()
- return 0
- else
- .["desc"] = "\nReason: [GLOB.Banlist["reason"]]\nExpires: [GetExp(GLOB.Banlist["minutes"])]\nBy: [GLOB.Banlist["bannedby"]] during round ID [GLOB.Banlist["roundid"]][appeal]"
- else
- GLOB.Banlist.cd = "/base/[ckey][id]"
- .["desc"] = "\nReason: [GLOB.Banlist["reason"]]\nExpires: PERMANENT\nBy: [GLOB.Banlist["bannedby"]] during round ID [GLOB.Banlist["roundid"]][appeal]"
- .["reason"] = "ckey/id"
- return .
- else
- for (var/A in GLOB.Banlist.dir)
- GLOB.Banlist.cd = "/base/[A]"
- var/matches
- if( ckey == GLOB.Banlist["key"] )
- matches += "ckey"
- if( id == GLOB.Banlist["id"] )
- if(matches)
- matches += "/"
- matches += "id"
- if( address == GLOB.Banlist["ip"] )
- if(matches)
- matches += "/"
- matches += "ip"
-
- if(matches)
- if(GLOB.Banlist["temp"])
- if (!GetExp(GLOB.Banlist["minutes"]))
- ClearTempbans()
- return 0
- else
- .["desc"] = "\nReason: [GLOB.Banlist["reason"]]\nExpires: [GetExp(GLOB.Banlist["minutes"])]\nBy: [GLOB.Banlist["bannedby"]] during round ID [GLOB.Banlist["roundid"]][appeal]"
- else
- .["desc"] = "\nReason: [GLOB.Banlist["reason"]]\nExpires: PERMENANT\nBy: [GLOB.Banlist["bannedby"]] during round ID [GLOB.Banlist["roundid"]][appeal]"
- .["reason"] = matches
- return .
- return 0
-
-/proc/UpdateTime() //No idea why i made this a proc.
- GLOB.CMinutes = (world.realtime / 10) / 60
- return 1
-
-/proc/LoadBans()
- if(!CONFIG_GET(flag/ban_legacy_system))
- return
-
- GLOB.Banlist = new("data/banlist.bdb")
- log_admin("Loading Banlist")
-
- if (!length(GLOB.Banlist.dir))
- log_admin("Banlist is empty.")
-
- if (!GLOB.Banlist.dir.Find("base"))
- log_admin("Banlist missing base dir.")
- GLOB.Banlist.dir.Add("base")
- GLOB.Banlist.cd = "/base"
- else if (GLOB.Banlist.dir.Find("base"))
- GLOB.Banlist.cd = "/base"
-
- ClearTempbans()
- return 1
-
-/proc/ClearTempbans()
- UpdateTime()
-
- GLOB.Banlist.cd = "/base"
- for (var/A in GLOB.Banlist.dir)
- GLOB.Banlist.cd = "/base/[A]"
- if (!GLOB.Banlist["key"] || !GLOB.Banlist["id"])
- RemoveBan(A)
- log_admin("Invalid Ban.")
- message_admins("Invalid Ban.")
- continue
-
- if (!GLOB.Banlist["temp"])
- continue
- if (GLOB.CMinutes >= GLOB.Banlist["minutes"])
- RemoveBan(A)
-
- return 1
-
-
-/proc/AddBan(key, computerid, reason, bannedby, temp, minutes, address)
- if(!CONFIG_GET(flag/ban_legacy_system))
- return
- var/bantimestamp
- var/ban_ckey = ckey(key)
- if (temp)
- UpdateTime()
- bantimestamp = GLOB.CMinutes + minutes
-
- GLOB.Banlist.cd = "/base"
- if ( GLOB.Banlist.dir.Find("[ban_ckey][computerid]") )
- to_chat(usr, text("Ban already exists."))
- return 0
- else
- GLOB.Banlist.dir.Add("[ban_ckey][computerid]")
- GLOB.Banlist.cd = "/base/[ban_ckey][computerid]"
- WRITE_FILE(GLOB.Banlist["key"], ban_ckey)
- WRITE_FILE(GLOB.Banlist["id"], computerid)
- WRITE_FILE(GLOB.Banlist["ip"], address)
- WRITE_FILE(GLOB.Banlist["reason"], reason)
- WRITE_FILE(GLOB.Banlist["bannedby"], bannedby)
- WRITE_FILE(GLOB.Banlist["temp"], temp)
- WRITE_FILE(GLOB.Banlist["roundid"], GLOB.round_id)
- if (temp)
- WRITE_FILE(GLOB.Banlist["minutes"], bantimestamp)
- return 1
-
-/proc/RemoveBan(foldername)
- var/key
- var/id
-
- GLOB.Banlist.cd = "/base/[foldername]"
- GLOB.Banlist["key"] >> key
- GLOB.Banlist["id"] >> id
- GLOB.Banlist.cd = "/base"
-
- if (!GLOB.Banlist.dir.Remove(foldername))
- return 0
-
- if(!usr)
- log_admin_private("Ban Expired: [key]")
- message_admins("Ban Expired: [key]")
- else
- ban_unban_log_save("[key_name(usr)] unbanned [key]")
- log_admin_private("[key_name(usr)] unbanned [key]")
- message_admins("[key_name_admin(usr)] unbanned: [key]")
- usr.client.holder.DB_ban_unban( ckey(key), BANTYPE_ANY_FULLBAN)
- for (var/A in GLOB.Banlist.dir)
- GLOB.Banlist.cd = "/base/[A]"
- if (key == GLOB.Banlist["key"] /*|| id == Banlist["id"]*/)
- GLOB.Banlist.cd = "/base"
- GLOB.Banlist.dir.Remove(A)
- continue
-
- return 1
-
-/proc/GetExp(minutes as num)
- UpdateTime()
- var/exp = minutes - GLOB.CMinutes
- if (exp <= 0)
- return 0
- else
- var/timeleftstring
- if (exp >= 1440) //1440 = 1 day in minutes
- timeleftstring = "[round(exp / 1440, 0.1)] Days"
- else if (exp >= 60) //60 = 1 hour in minutes
- timeleftstring = "[round(exp / 60, 0.1)] Hours"
- else
- timeleftstring = "[exp] Minutes"
- return timeleftstring
-
-/datum/admins/proc/unbanpanel()
- var/count = 0
- var/dat
- GLOB.Banlist.cd = "/base"
- for (var/A in GLOB.Banlist.dir)
- count++
- GLOB.Banlist.cd = "/base/[A]"
- var/ref = "[REF(src)]"
- var/key = GLOB.Banlist["key"]
- var/id = GLOB.Banlist["id"]
- var/ip = GLOB.Banlist["ip"]
- var/reason = GLOB.Banlist["reason"]
- var/by = GLOB.Banlist["bannedby"]
- var/expiry
- if(GLOB.Banlist["temp"])
- expiry = GetExp(GLOB.Banlist["minutes"])
- if(!expiry)
- expiry = "Removal Pending"
- else
- expiry = "Permaban"
-
- dat += text("
"
+ unban_panel.set_content(jointext(output, ""))
+ unban_panel.open()
+
+/datum/admins/proc/unban(ban_id, player_key, player_ip, player_cid, role, page, admin_key)
+ if(!check_rights(R_BAN))
+ return
+ if(!SSdbcore.Connect())
+ to_chat(usr, "Failed to establish database connection.")
+ return
+ if(alert(usr, "Please confirm unban of [player_key] from [role].", "Unban confirmation", "Yes", "No") == "No")
+ return
+ ban_id = sanitizeSQL(ban_id)
+ var/admin_ckey = sanitizeSQL(usr.client.ckey)
+ var/admin_ip = sanitizeSQL(usr.client.address)
+ var/admin_cid = sanitizeSQL(usr.client.computer_id)
+ var/kn = key_name(usr)
+ var/kna = key_name_admin(usr)
+ var/datum/DBQuery/query_unban = SSdbcore.NewQuery("UPDATE [format_table_name("ban")] SET unbanned_datetime = NOW(), unbanned_ckey = '[admin_ckey]', unbanned_ip = INET_ATON('[admin_ip]'), unbanned_computerid = '[admin_cid]', unbanned_round_id = '[GLOB.round_id]' WHERE id = [ban_id]")
+ if(!query_unban.warn_execute())
+ qdel(query_unban)
+ return
+ qdel(query_unban)
+ log_admin_private("[kn] has unbanned [player_key] from [role].")
+ message_admins("[kna] has unbanned [player_key] from [role].")
+ var/client/C = GLOB.directory[player_key]
+ if(C)
+ build_ban_cache(C)
+ to_chat(C, "[usr.client.key] has removed a ban from [role] for your key.")
+ for(var/client/i in GLOB.clients - C)
+ if(i.address == player_ip || i.computer_id == player_cid)
+ build_ban_cache(i)
+ to_chat(i, "[usr.client.key] has removed a ban from [role] for your IP or CID.")
+ unban_panel(player_key, admin_key, player_ip, player_cid, page)
+
+/datum/admins/proc/edit_ban(ban_id, player_key, player_ip, player_cid, use_last_connection, applies_to_admins, duration, interval, reason, mirror_edit, old_key, old_ip, old_cid, old_applies, admin_key, page, list/changes)
+ if(!check_rights(R_BAN))
+ return
+ if(!SSdbcore.Connect())
+ to_chat(usr, "Failed to establish database connection.")
+ return
+ ban_id = sanitizeSQL(ban_id)
+ var/player_ckey = sanitizeSQL(ckey(player_key))
+ player_ip = sanitizeSQL(player_ip)
+ player_cid = sanitizeSQL(player_cid)
+ var/bantime
+ var/datum/DBQuery/query_edit_ban_get_player = SSdbcore.NewQuery("SELECT byond_key, (SELECT bantime FROM [format_table_name("ban")] WHERE id = [ban_id]), ip, computerid FROM [format_table_name("player")] WHERE ckey = '[player_ckey]'")
+ if(!query_edit_ban_get_player.warn_execute())
+ qdel(query_edit_ban_get_player)
+ return
+ if(query_edit_ban_get_player.NextRow())
+ player_key = query_edit_ban_get_player.item[1]
+ bantime = query_edit_ban_get_player.item[2]
+ if(use_last_connection)
+ player_ip = query_edit_ban_get_player.item[3]
+ player_cid = query_edit_ban_get_player.item[4]
+ else
+ if(use_last_connection)
+ to_chat(usr, "Ban not edited. [player_key]/([player_ckey]) hasn't been seen before, unable to use IP and CID from last connection.")
+ qdel(query_edit_ban_get_player)
+ return
+ qdel(query_edit_ban_get_player)
+ if(applies_to_admins && (applies_to_admins != old_applies))
+ var/admin_ckey = sanitizeSQL(usr.client.ckey)
+ var/datum/DBQuery/query_check_adminban_count = SSdbcore.NewQuery("SELECT COUNT(DISTINCT bantime) FROM [format_table_name("ban")] WHERE a_ckey = '[admin_ckey]' AND applies_to_admins = 1 AND unbanned_datetime IS NULL AND (expiration_time IS NULL OR expiration_time > NOW())")
+ if(!query_check_adminban_count.warn_execute()) //count distinct bantime to treat rolebans made at the same time as one ban
+ qdel(query_check_adminban_count)
+ return
+ if(query_check_adminban_count.NextRow())
+ var/adminban_count = text2num(query_check_adminban_count.item[1])
+ var/max_adminbans = MAX_ADMINBANS_PER_ADMIN
+ if(R_EVERYTHING && !(R_EVERYTHING & rank.can_edit_rights)) //edit rights are a more effective way to check hierarchical rank since many non-headmins have R_PERMISSIONS now
+ max_adminbans = MAX_ADMINBANS_PER_HEADMIN
+ if(adminban_count >= max_adminbans)
+ to_chat(usr, "You've already logged [max_adminbans] admin ban(s) or more. Do not abuse this function!")
+ qdel(query_check_adminban_count)
+ return
+ qdel(query_check_adminban_count)
+ applies_to_admins = sanitizeSQL(applies_to_admins)
+ duration = sanitizeSQL(duration)
+ if(interval)
+ interval = sanitizeSQL(interval)
+ else
+ interval = "MINUTE"
+ reason = sanitizeSQL(reason)
+ var/kn = key_name(usr)
+ var/kna = key_name_admin(usr)
+ var/list/changes_text= list()
+ var/list/changes_keys = list()
+ for(var/i in changes)
+ changes_text += "[i]: [changes[i]]"
+ changes_keys += i
+ var/where = "id = [sanitizeSQL(ban_id)]"
+ if(text2num(mirror_edit))
+ var/list/wherelist = list("bantime = '[bantime]'")
+ if(old_key)
+ wherelist += "ckey = '[sanitizeSQL(ckey(old_key))]'"
+ if(old_ip)
+ old_ip = sanitizeSQL(old_ip)
+ wherelist += "ip = INET_ATON(IF('[old_ip]' LIKE '', NULL, '[old_ip]'))"
+ if(old_cid)
+ wherelist += "computerid = '[sanitizeSQL(old_cid)]'"
+ where = wherelist.Join(" AND ")
+ var/datum/DBQuery/query_edit_ban = SSdbcore.NewQuery("UPDATE [format_table_name("ban")] SET expiration_time = IF('[duration]' LIKE '', NULL, bantime + INTERVAL [duration ? "[duration]" : "0"] [interval]), applies_to_admins = [applies_to_admins], reason = '[reason]', ckey = IF('[player_ckey]' LIKE '', NULL, '[player_ckey]'), ip = INET_ATON(IF('[player_ip]' LIKE '', NULL, '[player_ip]')), computerid = IF('[player_cid]' LIKE '', NULL, '[player_cid]'), edits = CONCAT(IFNULL(edits,''),'[sanitizeSQL(usr.client.key)] edited the following [jointext(changes_text, ", ")]') WHERE [where]")
+ if(!query_edit_ban.warn_execute())
+ qdel(query_edit_ban)
+ return
+ qdel(query_edit_ban)
+ var/changes_keys_text = jointext(changes_keys, ", ")
+ log_admin_private("[kn] has edited the [changes_keys_text] of a ban for [old_key ? "[old_key]" : "[old_ip]-[old_cid]"].") //if a ban doesn't have a key it must have an ip and/or a cid to have reached this point normally
+ message_admins("[kna] has edited the [changes_keys_text] of a ban for [old_key ? "[old_key]" : "[old_ip]-[old_cid]"].")
+ if(changes["Applies to admins"])
+ send2irc("BAN ALERT","[kn] has edited a ban for [old_key ? "[old_key]" : "[old_ip]-[old_cid]"] to [applies_to_admins ? "" : "not"]affect admins")
+ var/client/C = GLOB.directory[old_key]
+ if(C)
+ build_ban_cache(C)
+ to_chat(C, "[usr.client.key] has edited the [changes_keys_text] of a ban for your key.")
+ for(var/client/i in GLOB.clients - C)
+ if(i.address == old_ip || i.computer_id == old_cid)
+ build_ban_cache(i)
+ to_chat(i, "[usr.client.key] has edited the [changes_keys_text] of a ban for your IP or CID.")
+ unban_panel(player_key, null, null, null, page)
+
+/datum/admins/proc/ban_log(ban_id)
+ if(!check_rights(R_BAN))
+ return
+ if(!SSdbcore.Connect())
+ to_chat(usr, "Failed to establish database connection.")
+ return
+ ban_id = sanitizeSQL(ban_id)
+ var/datum/DBQuery/query_get_ban_edits = SSdbcore.NewQuery("SELECT edits FROM [format_table_name("ban")] WHERE id = '[ban_id]'")
+ if(!query_get_ban_edits.warn_execute())
+ qdel(query_get_ban_edits)
+ return
+ if(query_get_ban_edits.NextRow())
+ var/edits = query_get_ban_edits.item[1]
+ var/datum/browser/edit_log = new(usr, "baneditlog", "Ban edit log")
+ edit_log.set_content(edits)
+ edit_log.open()
+ qdel(query_get_ban_edits)
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index d0f4472652ff..cceecf562d62 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -216,6 +216,7 @@
log_admin("[key_name(usr)] has triggered an event. ([E.name])")
return
+<<<<<<< HEAD
else if(href_list["dbsearchckey"] || href_list["dbsearchadmin"] || href_list["dbsearchip"] || href_list["dbsearchcid"])
var/adminckey = href_list["dbsearchadmin"]
var/playerckey = href_list["dbsearchckey"]
@@ -305,6 +306,8 @@
//create_message("note", bankey, null, banreason, null, null, 0, 0, null, 0, banseverity)
create_message("note", bankey, null, banreason, null, null, 0, 0, null, 0) //yogs - remove severity
+=======
+>>>>>>> 8a66665e95... Ban system and interface update (#41176)
else if(href_list["editrightsbrowser"])
edit_admin_permissions(0)
@@ -536,6 +539,7 @@
if("shade")
M.change_mob_type( /mob/living/simple_animal/shade , null, null, delmob )
+<<<<<<< HEAD
/////////////////////////////////////new ban stuff
else if(href_list["unbanf"])
@@ -1117,6 +1121,8 @@
return 1
return 0 //we didn't do anything!
+=======
+>>>>>>> 8a66665e95... Ban system and interface update (#41176)
else if(href_list["boot2"])
if(!check_rights(R_ADMIN))
return
@@ -1292,6 +1298,7 @@
usr << browse(edit_log,"window=noteedits") //yogs
qdel(query_get_message_edits)
+<<<<<<< HEAD
else if(href_list["newban"])
if(!check_rights(R_BAN))
return
@@ -1366,6 +1373,8 @@
if("Cancel")
return
+=======
+>>>>>>> 8a66665e95... Ban system and interface update (#41176)
else if(href_list["mute"])
if(!check_rights(R_ADMIN))
return
@@ -2613,6 +2622,59 @@
removeMentor(href_list["removementor"])
// yogs end
+ else if(href_list["newbankey"])
+ var/player_key = href_list["newbankey"]
+ var/player_ip = href_list["newbanip"]
+ var/player_cid = href_list["newbancid"]
+ ban_panel(player_key, player_ip, player_cid)
+
+ else if(href_list["intervaltype"]) //check for ban panel, intervaltype is used as it's the only value which will always be present
+ if(href_list["roleban_delimiter"])
+ ban_parse_href(href_list)
+ else
+ ban_parse_href(href_list, TRUE)
+
+ else if(href_list["searchunbankey"] || href_list["searchunbanadminkey"] || href_list["searchunbanip"] || href_list["searchunbancid"])
+ var/player_key = href_list["searchunbankey"]
+ var/admin_key = href_list["searchunbanadminkey"]
+ var/player_ip = href_list["searchunbanip"]
+ var/player_cid = href_list["searchunbancid"]
+ unban_panel(player_key, admin_key, player_ip, player_cid)
+
+ else if(href_list["unbanpagecount"])
+ var/page = href_list["unbanpagecount"]
+ var/player_key = href_list["unbankey"]
+ var/admin_key = href_list["unbanadminkey"]
+ var/player_ip = href_list["unbanip"]
+ var/player_cid = href_list["unbancid"]
+ unban_panel(player_key, admin_key, player_ip, player_cid, page)
+
+ else if(href_list["editbanid"])
+ var/edit_id = href_list["editbanid"]
+ var/player_key = href_list["editbankey"]
+ var/player_ip = href_list["editbanip"]
+ var/player_cid = href_list["editbancid"]
+ var/role = href_list["editbanrole"]
+ var/duration = href_list["editbanduration"]
+ var/applies_to_admins = text2num(href_list["editbanadmins"])
+ var/reason = href_list["editbanreason"]
+ var/page = href_list["editbanpage"]
+ var/admin_key = href_list["editbanadminkey"]
+ ban_panel(player_key, player_ip, player_cid, role, duration, applies_to_admins, reason, edit_id, page, admin_key)
+
+ else if(href_list["unbanid"])
+ var/ban_id = href_list["unbanid"]
+ var/player_key = href_list["unbankey"]
+ var/player_ip = href_list["unbanip"]
+ var/player_cid = href_list["unbancid"]
+ var/role = href_list["unbanrole"]
+ var/page = href_list["unbanpage"]
+ var/admin_key = href_list["unbanadminkey"]
+ unban(ban_id, player_key, player_ip, player_cid, role, page, admin_key)
+
+ else if(href_list["unbanlog"])
+ var/ban_id = href_list["unbanlog"]
+ ban_log(ban_id)
/datum/admins/proc/HandleCMode()
if(!check_rights(R_ADMIN))
diff --git a/code/modules/admin/verbs/one_click_antag.dm b/code/modules/admin/verbs/one_click_antag.dm
index 79a3c06b0231..f67c41fedea9 100644
--- a/code/modules/admin/verbs/one_click_antag.dm
+++ b/code/modules/admin/verbs/one_click_antag.dm
@@ -42,7 +42,7 @@
return FALSE
if(!considered_alive(applicant.mind) || considered_afk(applicant.mind)) //makes sure the player isn't a zombie, brain, or just afk all together
return FALSE
- return (!jobban_isbanned(applicant, targetrole) && !jobban_isbanned(applicant, ROLE_SYNDICATE))
+ return !is_banned_from(applicant.ckey, list(targetrole, ROLE_SYNDICATE))
/datum/admins/proc/makeTraitors()
diff --git a/code/modules/antagonists/_common/antag_datum.dm b/code/modules/antagonists/_common/antag_datum.dm
index ad4851e0c3fe..d1c15b15dc0f 100644
--- a/code/modules/antagonists/_common/antag_datum.dm
+++ b/code/modules/antagonists/_common/antag_datum.dm
@@ -76,7 +76,7 @@ GLOBAL_LIST_EMPTY(antagonists)
/datum/antagonist/proc/is_banned(mob/M)
if(!M)
return FALSE
- . = (jobban_isbanned(M, ROLE_SYNDICATE) || QDELETED(M) || (job_rank && (jobban_isbanned(M,job_rank) || QDELETED(M))))
+ . = (is_banned_from(M.ckey, list(ROLE_SYNDICATE, job_rank)) || QDELETED(M))
/datum/antagonist/proc/replace_banned_player()
set waitfor = FALSE
diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm
index 9a6b425a03b2..0b2a622b5025 100644
--- a/code/modules/antagonists/cult/runes.dm
+++ b/code/modules/antagonists/cult/runes.dm
@@ -848,7 +848,7 @@ structure_check() searches for nearby cultist structures required for the invoca
notify_ghosts("Manifest rune invoked in [get_area(src)].", 'sound/effects/ghost2.ogg', source = src)
var/list/ghosts_on_rune = list()
for(var/mob/dead/observer/O in T)
- if(O.client && !jobban_isbanned(O, ROLE_CULTIST) && !QDELETED(src) && !QDELETED(O))
+ if(O.client && !is_banned_from(O.ckey, ROLE_CULTIST) && !QDELETED(src) && !QDELETED(O))
ghosts_on_rune += O
if(!ghosts_on_rune.len)
to_chat(user, "There are no spirits near [src]!")
diff --git a/code/modules/awaymissions/corpse.dm b/code/modules/awaymissions/corpse.dm
index a5ac3998c2a0..a3b08e4ed533 100644
--- a/code/modules/awaymissions/corpse.dm
+++ b/code/modules/awaymissions/corpse.dm
@@ -37,7 +37,7 @@
if(!uses)
to_chat(user, "This spawner is out of charges!")
return
- if(jobban_isbanned(user, banType))
+ if(is_banned_from(user.key, banType))
to_chat(user, "You are jobanned!")
return
if(QDELETED(src) || QDELETED(user))
diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm
index 9abf44a7423e..0df912232301 100644
--- a/code/modules/client/client_defines.dm
+++ b/code/modules/client/client_defines.dm
@@ -11,7 +11,7 @@
var/datum/click_intercept = null // Needs to implement InterceptClickOn(user,params,atom) proc
var/AI_Interact = 0
- var/jobbancache = null //Used to cache this client's jobbans to save on DB queries
+ var/ban_cache = null //Used to cache this client's bans to save on DB queries
var/last_message = "" //Contains the last message sent by this client - used to protect against copy-paste spamming.
var/last_message_count = 0 //contins a number of how many times a message identical to last_message was sent.
var/ircreplyamount = 0
@@ -73,5 +73,8 @@
var/list/credits //lazy list of all credit object bound to this client
var/datum/player_details/player_details //these persist between logins/logouts during the same round.
+<<<<<<< HEAD
- var/encoding = "1252" // yogs - LibVG
\ No newline at end of file
+ var/encoding = "1252" // yogs - LibVG
+=======
+>>>>>>> 8a66665e95... Ban system and interface update (#41176)
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 066b365c0289..d603fb484f7f 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -203,7 +203,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "
Current Quirks: [all_quirks.len ? all_quirks.Join(", ") : "None"]
"
dat += "
Identity
"
dat += "
"
- if(jobban_isbanned(user, "appearance"))
+ if(is_banned_from(user.ckey, "Appearance"))
dat += "You are banned from using custom names and appearances. You can continue to adjust your characters, but you will be randomised once you join the game. "
dat += "Random Name "
dat += "Always Random Name: [be_random_name ? "Yes" : "No"] "
@@ -553,14 +553,14 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "
Special Role Settings
"
- if(jobban_isbanned(user, ROLE_SYNDICATE))
- dat += "You are banned from antagonist roles."
+ if(is_banned_from(user.ckey, ROLE_SYNDICATE))
+ dat += "You are banned from antagonist roles. "
src.be_special = list()
for (var/i in GLOB.special_roles)
- if(jobban_isbanned(user, i))
- dat += "Be [capitalize(i)]:BANNED "
+ if(is_banned_from(user.ckey, i))
+ dat += "Be [capitalize(i)]:BANNED "
else
var/days_remaining = null
if(ispath(GLOB.special_roles[i]) && CONFIG_GET(flag/use_age_restriction_for_jobs)) //If it's a game mode antag, check if the player meets the minimum age
@@ -781,8 +781,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
HTML += "