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
This commit is contained in:
Jordie
2018-12-05 06:48:37 +11:00
committed by yogstation13-bot
parent dc78fd228c
commit a28de54405
42 changed files with 1448 additions and 382 deletions

View File

@@ -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()

View File

@@ -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: 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 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. 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 Version 4.7, 18 August 2018, by CitrusGender
Modified table `messages`, adding column `severity` to classify notes based on their severity. Modified table `messages`, adding column `severity` to classify notes based on their severity.

View File

@@ -67,34 +67,33 @@ DROP TABLE IF EXISTS `ban`;
/*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */; /*!40101 SET character_set_client = utf8 */;
CREATE TABLE `ban` ( CREATE TABLE `ban` (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`bantime` datetime NOT NULL, `bantime` DATETIME NOT NULL,
`server_ip` int(10) unsigned NOT NULL, `server_ip` INT(10) UNSIGNED NOT NULL,
`server_port` smallint(5) unsigned NOT NULL, `server_port` SMALLINT(5) UNSIGNED NOT NULL,
`round_id` int(11) NOT NULL, `round_id` INT(11) UNSIGNED NOT NULL,
`bantype` enum('PERMABAN','TEMPBAN','JOB_PERMABAN','JOB_TEMPBAN','ADMIN_PERMABAN','ADMIN_TEMPBAN') NOT NULL, `role` VARCHAR(32) NULL DEFAULT NULL,
`reason` varchar(2048) NOT NULL, `expiration_time` DATETIME NULL DEFAULT NULL,
`job` varchar(32) DEFAULT NULL, `applies_to_admins` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0',
`duration` int(11) NOT NULL, `reason` VARCHAR(2048) NOT NULL,
`expiration_time` datetime NOT NULL, `ckey` VARCHAR(32) NULL DEFAULT NULL,
`ckey` varchar(32) NOT NULL, `ip` INT(10) UNSIGNED NULL DEFAULT NULL,
`computerid` varchar(32) NOT NULL, `computerid` VARCHAR(32) NULL DEFAULT NULL,
`ip` int(10) unsigned NOT NULL, `a_ckey` VARCHAR(32) NOT NULL,
`a_ckey` varchar(32) NOT NULL, `a_ip` INT(10) UNSIGNED NOT NULL,
`a_computerid` varchar(32) NOT NULL, `a_computerid` VARCHAR(32) NOT NULL,
`a_ip` int(10) unsigned NOT NULL, `who` VARCHAR(2048) NOT NULL,
`who` varchar(2048) NOT NULL, `adminwho` VARCHAR(2048) NOT NULL,
`adminwho` varchar(2048) NOT NULL, `edits` TEXT NULL DEFAULT NULL,
`edits` text, `unbanned_datetime` DATETIME NULL DEFAULT NULL,
`unbanned` tinyint(3) unsigned DEFAULT NULL, `unbanned_ckey` VARCHAR(32) NULL DEFAULT NULL,
`unbanned_datetime` datetime DEFAULT NULL, `unbanned_ip` INT(10) UNSIGNED NULL DEFAULT NULL,
`unbanned_ckey` varchar(32) DEFAULT NULL, `unbanned_computerid` VARCHAR(32) NULL DEFAULT NULL,
`unbanned_computerid` varchar(32) DEFAULT NULL, `unbanned_round_id` INT(11) UNSIGNED NULL DEFAULT NULL,
`unbanned_ip` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `idx_ban_checkban` (`ckey`,`bantype`,`expiration_time`,`unbanned`,`job`), KEY `idx_ban_isbanned` (`ckey`,`role`,`unbanned_datetime`,`expiration_time`),
KEY `idx_ban_isbanned` (`ckey`,`ip`,`computerid`,`bantype`,`expiration_time`,`unbanned`), KEY `idx_ban_isbanned_details` (`ckey`,`ip`,`computerid`,`role`,`unbanned_datetime`,`expiration_time`),
KEY `idx_ban_count` (`id`,`a_ckey`,`bantype`,`expiration_time`,`unbanned`) KEY `idx_ban_count` (`bantime`,`a_ckey`,`applies_to_admins`,`unbanned_datetime`,`expiration_time`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1; ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;

View File

@@ -67,34 +67,33 @@ DROP TABLE IF EXISTS `SS13_ban`;
/*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */; /*!40101 SET character_set_client = utf8 */;
CREATE TABLE `SS13_ban` ( CREATE TABLE `SS13_ban` (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`bantime` datetime NOT NULL, `bantime` DATETIME NOT NULL,
`server_ip` int(10) unsigned NOT NULL, `server_ip` INT(10) UNSIGNED NOT NULL,
`server_port` smallint(5) unsigned NOT NULL, `server_port` SMALLINT(5) UNSIGNED NOT NULL,
`round_id` int(11) NOT NULL, `round_id` INT(11) UNSIGNED NOT NULL,
`bantype` enum('PERMABAN','TEMPBAN','JOB_PERMABAN','JOB_TEMPBAN','ADMIN_PERMABAN','ADMIN_TEMPBAN') NOT NULL, `role` VARCHAR(32) NULL DEFAULT NULL,
`reason` varchar(2048) NOT NULL, `expiration_time` DATETIME NULL DEFAULT NULL,
`job` varchar(32) DEFAULT NULL, `applies_to_admins` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0',
`duration` int(11) NOT NULL, `reason` VARCHAR(2048) NOT NULL,
`expiration_time` datetime NOT NULL, `ckey` VARCHAR(32) NULL DEFAULT NULL,
`ckey` varchar(32) NOT NULL, `ip` INT(10) UNSIGNED NULL DEFAULT NULL,
`computerid` varchar(32) NOT NULL, `computerid` VARCHAR(32) NULL DEFAULT NULL,
`ip` int(10) unsigned NOT NULL, `a_ckey` VARCHAR(32) NOT NULL,
`a_ckey` varchar(32) NOT NULL, `a_ip` INT(10) UNSIGNED NOT NULL,
`a_computerid` varchar(32) NOT NULL, `a_computerid` VARCHAR(32) NOT NULL,
`a_ip` int(10) unsigned NOT NULL, `who` VARCHAR(2048) NOT NULL,
`who` varchar(2048) NOT NULL, `adminwho` VARCHAR(2048) NOT NULL,
`adminwho` varchar(2048) NOT NULL, `edits` TEXT NULL DEFAULT NULL,
`edits` text, `unbanned_datetime` DATETIME NULL DEFAULT NULL,
`unbanned` tinyint(3) unsigned DEFAULT NULL, `unbanned_ckey` VARCHAR(32) NULL DEFAULT NULL,
`unbanned_datetime` datetime DEFAULT NULL, `unbanned_ip` INT(10) UNSIGNED NULL DEFAULT NULL,
`unbanned_ckey` varchar(32) DEFAULT NULL, `unbanned_computerid` VARCHAR(32) NULL DEFAULT NULL,
`unbanned_computerid` varchar(32) DEFAULT NULL, `unbanned_round_id` INT(11) UNSIGNED NULL DEFAULT NULL,
`unbanned_ip` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `idx_ban_checkban` (`ckey`,`bantype`,`expiration_time`,`unbanned`,`job`), KEY `idx_ban_isbanned` (`ckey`,`role`,`unbanned_datetime`,`expiration_time`),
KEY `idx_ban_isbanned` (`ckey`,`ip`,`computerid`,`bantype`,`expiration_time`,`unbanned`), KEY `idx_ban_isbanned_details` (`ckey`,`ip`,`computerid`,`role`,`unbanned_datetime`,`expiration_time`),
KEY `idx_ban_count` (`id`,`a_ckey`,`bantype`,`expiration_time`,`unbanned`) KEY `idx_ban_count` (`bantime`,`a_ckey`,`applies_to_admins`,`unbanned_datetime`,`expiration_time`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1; ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;

View File

@@ -6,6 +6,7 @@
//These are synced with the Database, if you change the values of the defines //These are synced with the Database, if you change the values of the defines
//then you MUST update the database! //then you MUST update the database!
<<<<<<< HEAD
#define ROLE_SYNDICATE "Syndicate" #define ROLE_SYNDICATE "Syndicate"
#define ROLE_TRAITOR "traitor" #define ROLE_TRAITOR "traitor"
#define ROLE_OPERATIVE "operative" #define ROLE_OPERATIVE "operative"
@@ -37,6 +38,37 @@
#define ROLE_LAVALAND "lavaland" #define ROLE_LAVALAND "lavaland"
#define ROLE_SHADOWLING "shadowling" // Yogs #define ROLE_SHADOWLING "shadowling" // Yogs
#define ROLE_INTERNAL_AFFAIRS "internal affairs agent" #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. //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 //The gamemode specific ones are just so the gamemodes can query whether a player is old enough

View File

@@ -1,7 +1,7 @@
//Update this whenever the db schema changes //Update this whenever the db schema changes
//make sure you add an update to the schema_version stable in the db changelog //make sure you add an update to the schema_version stable in the db changelog
#define DB_MAJOR_VERSION 4 #define DB_MAJOR_VERSION 5
#define DB_MINOR_VERSION 7 #define DB_MINOR_VERSION 0
//Timing subsystem //Timing subsystem
//Don't run if there is an identical unique timer active //Don't run if there is an identical unique timer active

View File

@@ -433,7 +433,7 @@
if(!gametypeCheck.age_check(M.client)) if(!gametypeCheck.age_check(M.client))
continue continue
if(jobbanType) 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 continue
showCandidatePollWindow(M, poll_time, Question, result, ignore_category, time_passed, flashwindow) showCandidatePollWindow(M, poll_time, Question, result, ignore_category, time_passed, flashwindow)
@@ -494,7 +494,7 @@
if(!C || (!C.prefs.windowflashing && !ignorepref)) if(!C || (!C.prefs.windowflashing && !ignorepref))
return return
winset(C, "mainwindow", "flash=5") 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. //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) /proc/recursive_loc_check(atom/movable/target, type)
var/atom/A = target var/atom/A = target

View File

@@ -203,7 +203,7 @@ Turf and target are separate in case you want to teleport some distance from a t
var/loop = 1 var/loop = 1
var/safety = 0 var/safety = 0
var/banned = jobban_isbanned(src, "appearance") var/banned = is_banned_from(C.ckey, "Appearance")
while(loop && safety < 5) while(loop && safety < 5)
if(C && C.prefs.custom_names[role] && !safety && !banned) if(C && C.prefs.custom_names[role] && !safety && !banned)

View File

@@ -153,9 +153,6 @@
/datum/config_entry/flag/usewhitelist /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_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. /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.

View File

@@ -79,7 +79,7 @@ SUBSYSTEM_DEF(job)
var/datum/job/job = GetJob(rank) var/datum/job/job = GetJob(rank)
if(!job) if(!job)
return FALSE return FALSE
if(jobban_isbanned(player, rank) || QDELETED(player)) if(is_banned_from(player.ckey, rank) || QDELETED(player))
return FALSE return FALSE
if(!job.player_old_enough(player.client)) if(!job.player_old_enough(player.client))
return FALSE return FALSE
@@ -101,7 +101,7 @@ SUBSYSTEM_DEF(job)
JobDebug("Running FOC, Job: [job], Level: [level], Flag: [flag]") JobDebug("Running FOC, Job: [job], Level: [level], Flag: [flag]")
var/list/candidates = list() var/list/candidates = list()
for(var/mob/dead/new_player/player in unassigned) 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]") JobDebug("FOC isbanned failed, Player: [player]")
continue continue
if(!job.player_old_enough(player.client)) 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! if(job.title in GLOB.command_positions) //If you want a command position, select it!
continue continue
if(jobban_isbanned(player, job.title) || QDELETED(player)) if(is_banned_from(player.ckey, job.title) || QDELETED(player))
if(QDELETED(player)) if(QDELETED(player))
JobDebug("GRJ isbanned failed, Player deleted") JobDebug("GRJ isbanned failed, Player deleted")
break break
@@ -316,7 +316,7 @@ SUBSYSTEM_DEF(job)
if(!job) if(!job)
continue continue
if(jobban_isbanned(player, job.title)) if(is_banned_from(player.ckey, job.title))
JobDebug("DO isbanned failed, Player: [player], Job:[job.title]") JobDebug("DO isbanned failed, Player: [player], Job:[job.title]")
continue continue
@@ -365,7 +365,7 @@ SUBSYSTEM_DEF(job)
if(PopcapReached()) if(PopcapReached())
RejectPlayer(player) RejectPlayer(player)
else if(player.client.prefs.joblessrole == BEOVERFLOW) 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) if(QDELETED(player) || !allowed_to_be_a_loser)
RejectPlayer(player) RejectPlayer(player)
else else
@@ -497,7 +497,7 @@ SUBSYSTEM_DEF(job)
for(var/mob/dead/new_player/player in GLOB.player_list) for(var/mob/dead/new_player/player in GLOB.player_list)
if(!(player.ready == PLAYER_READY_TO_PLAY && player.mind && !player.mind.assigned_role)) if(!(player.ready == PLAYER_READY_TO_PLAY && player.mind && !player.mind.assigned_role))
continue //This player is not ready 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++ banned++
continue continue
if(!job.player_old_enough(player.client)) if(!job.player_old_enough(player.client))

View File

@@ -61,7 +61,7 @@
affected_mob.dropItemToGround(I) affected_mob.dropItemToGround(I)
var/mob/living/new_mob = new new_form(affected_mob.loc) var/mob/living/new_mob = new new_form(affected_mob.loc)
if(istype(new_mob)) 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) replace_banned_player(new_mob)
new_mob.a_intent = INTENT_HARM new_mob.a_intent = INTENT_HARM
if(affected_mob.mind) if(affected_mob.mind)

View File

@@ -84,7 +84,7 @@ GLOBAL_VAR(changeling_team_objective_type) //If this is not null, we hand our th
return return
if(changelings.len <= (changelingcap - 2) || prob(100 - (csc * 2))) if(changelings.len <= (changelingcap - 2) || prob(100 - (csc * 2)))
if(ROLE_CHANGELING in character.client.prefs.be_special) 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(age_check(character.client))
if(!(character.job in restricted_jobs)) if(!(character.job in restricted_jobs))
character.mind.make_Changeling() character.mind.make_Changeling()

View File

@@ -70,7 +70,7 @@
return return
if(changelings.len <= (changelingcap - 2) || prob(100 / (csc * 4))) if(changelings.len <= (changelingcap - 2) || prob(100 / (csc * 4)))
if(ROLE_CHANGELING in character.client.prefs.be_special) 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(age_check(character.client))
if(!(character.job in restricted_jobs)) if(!(character.job in restricted_jobs))
character.mind.make_Changeling() character.mind.make_Changeling()

View File

@@ -371,8 +371,13 @@
for(var/mob/dead/new_player/player in players) for(var/mob/dead/new_player/player in players)
if(player.client && player.ready == PLAYER_READY_TO_PLAY) 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(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(!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 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 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) for(var/mob/dead/new_player/player in players)
if(player.client && player.ready == PLAYER_READY_TO_PLAY) 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(!(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 drafted += player.mind
/* yogs start - Donor features, quiet round /* yogs start - Donor features, quiet round
if(player.mind.quiet_round) if(player.mind.quiet_round)

View File

@@ -86,7 +86,7 @@
return return
if((SSticker.mode.traitors.len + pre_traitors.len) <= (traitorcap - 2) || prob(100 / (tsc * 2))) if((SSticker.mode.traitors.len + pre_traitors.len) <= (traitorcap - 2) || prob(100 / (tsc * 2)))
if(antag_flag in character.client.prefs.be_special) 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(age_check(character.client))
if(!(character.job in restricted_jobs)) if(!(character.job in restricted_jobs))
add_latejoin_traitor(character.mind) add_latejoin_traitor(character.mind)
@@ -97,4 +97,4 @@
/datum/game_mode/traitor/generate_report() /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 \ 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." 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."

View File

@@ -262,7 +262,7 @@
to_chat(user, "<span class='warning'>The MMI indicates that the brain is damaged!</span>") to_chat(user, "<span class='warning'>The MMI indicates that the brain is damaged!</span>")
return 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)) if(!QDELETED(M))
to_chat(user, "<span class='warning'>This [M.name] does not seem to fit!</span>") to_chat(user, "<span class='warning'>This [M.name] does not seem to fit!</span>")
return return

View File

@@ -195,7 +195,7 @@
to_chat(user, "<span class='warning'>Sticking an inactive [M.name] into the frame would sort of defeat the purpose.</span>") to_chat(user, "<span class='warning'>Sticking an inactive [M.name] into the frame would sort of defeat the purpose.</span>")
return 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)) if(!QDELETED(M))
to_chat(user, "<span class='warning'>This [M.name] does not seem to fit!</span>") to_chat(user, "<span class='warning'>This [M.name] does not seem to fit!</span>")
return return

View File

@@ -38,8 +38,11 @@ GLOBAL_VAR_INIT(bypass_tgs_reboot, world.system_type == UNIX && world.byond_buil
LoadVerbs(/datum/verbs/menu) LoadVerbs(/datum/verbs/menu)
if(CONFIG_GET(flag/usewhitelist)) if(CONFIG_GET(flag/usewhitelist))
load_whitelist() load_whitelist()
<<<<<<< HEAD
LoadBans() LoadBans()
setup_pretty_filter() //yogs setup_pretty_filter() //yogs
=======
>>>>>>> 8a66665e95... Ban system and interface update (#41176)
GLOB.timezoneOffset = text2num(time2text(0,"hh")) * 36000 GLOB.timezoneOffset = text2num(time2text(0,"hh")) * 36000

View File

@@ -46,25 +46,12 @@
if(!real_bans_only && extreme_popcap && living_player_count() >= extreme_popcap && !admin) if(!real_bans_only && extreme_popcap && living_player_count() >= extreme_popcap && !admin)
log_access("Failed Login: [key] - Population cap reached") log_access("Failed Login: [key] - Population cap reached")
return list("reason"="popcap", "desc"= "\nReason: [CONFIG_GET(string/extreme_popcap_message)]") return list("reason"="popcap", "desc"= "\nReason: [CONFIG_GET(string/extreme_popcap_message)]")
if(CONFIG_GET(flag/sql_enabled))
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("<span class='adminnotice'>The admin [key] has been allowed to bypass a matching ban on [.["key"]]</span>")
addclientmessage(ckey,"<span class='adminnotice'>You have been allowed to bypass a matching ban on [.["key"]]</span>")
else
log_access("Failed Login: [key] [computer_id] [address] - Banned [.["reason"]]")
return .
else
if(!SSdbcore.Connect()) if(!SSdbcore.Connect())
var/msg = "Ban database connection failure. Key [ckey] not checked" var/msg = "Ban database connection failure. Key [ckey] not checked"
log_world(msg) log_world(msg)
message_admins(msg) message_admins(msg)
<<<<<<< HEAD
return return
var/ipquery = "" var/ipquery = ""
@@ -119,6 +106,31 @@
return . return .
qdel(query_ban_check) 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,"<span class='adminnotice'>Admin [key] has been allowed to bypass a matching non-admin ban on [i["key"]] [i["ip"]]-[i["computerid"]].</span>")
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 var/list/ban = ..() //default pager ban stuff
if (ban) if (ban)
var/bannedckey = "ERROR" var/bannedckey = "ERROR"

View File

@@ -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 <a href='[bran]'>[bran]</a>"
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: <B>PERMANENT</B>\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: <B>PERMENANT</B>\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("<span class='danger'>Ban already exists.</span>"))
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("<tr><td><A href='?src=[ref];unbanf=[key][id]'>(U)</A><A href='?src=[ref];unbane=[key][id]'>(E)</A> Key: <B>[key]</B></td><td>ComputerID: <B>[id]</B></td><td>IP: <B>[ip]</B></td><td> [expiry]</td><td>(By: [by])</td><td>(Reason: [reason])</td></tr>")
dat += "</table>"
dat = "<HR><B>Bans:</B> <FONT COLOR=blue>(U) = Unban , (E) = Edit Ban</FONT> - <FONT COLOR=green>([count] Bans)</FONT><HR><table border=1 rules=all frame=void cellspacing=0 cellpadding=3 >[dat]"
usr << browse(dat, "window=unbanp;size=875x400")
//////////////////////////////////// DEBUG ////////////////////////////////////
/proc/CreateBans()
UpdateTime()
var/i
var/last
for(i=0, i<1001, i++)
var/a = pick(1,0)
var/b = pick(1,0)
if(b)
GLOB.Banlist.cd = "/base"
GLOB.Banlist.dir.Add("trash[i]trashid[i]")
GLOB.Banlist.cd = "/base/trash[i]trashid[i]"
WRITE_FILE(GLOB.Banlist["key"], "trash[i]")
else
GLOB.Banlist.cd = "/base"
GLOB.Banlist.dir.Add("[last]trashid[i]")
GLOB.Banlist.cd = "/base/[last]trashid[i]"
WRITE_FILE(GLOB.Banlist["key"], last)
WRITE_FILE(GLOB.Banlist["id"], "trashid[i]")
WRITE_FILE(GLOB.Banlist["reason"], "Trashban[i].")
WRITE_FILE(GLOB.Banlist["temp"], a)
WRITE_FILE(GLOB.Banlist["minutes"], GLOB.CMinutes + rand(1,2000))
WRITE_FILE(GLOB.Banlist["bannedby"], "trashmin")
last = "trash[i]"
GLOB.Banlist.cd = "/base"
/proc/ClearAllBans()
GLOB.Banlist.cd = "/base"
for (var/A in GLOB.Banlist.dir)
RemoveBan(A)

View File

@@ -85,22 +85,7 @@
body += "<b>Mob type</b> = [M.type]<br><br>" body += "<b>Mob type</b> = [M.type]<br><br>"
body += "<A href='?_src_=holder;[HrefToken()];boot2=[REF(M)]'>Kick</A> | " body += "<A href='?_src_=holder;[HrefToken()];boot2=[REF(M)]'>Kick</A> | "
body += "<A href='?_src_=holder;[HrefToken()];newban=[REF(M)]'>Ban</A> | " body += "<A href='?_src_=holder;[HrefToken()];newbankey=[M.client.key];newbanip=[M.client.address];newbancid=[M.client.computer_id]'>Ban</A> | "
body += "<A href='?_src_=holder;[HrefToken()];jobban2=[REF(M)]'>Jobban</A> | "
body += "<A href='?_src_=holder;[HrefToken()];appearanceban=[REF(M)]'>Identity Ban</A> | "
var/rm = REF(M)
if(jobban_isbanned(M, "OOC"))
body+= "<A href='?_src_=holder;[HrefToken()];jobban3=OOC;jobban4=[rm]'><font color=red>OOCBan</font></A> | "
else
body+= "<A href='?_src_=holder;[HrefToken()];jobban3=OOC;jobban4=[rm]'>OOCBan</A> | "
if(QDELETED(M) || QDELETED(usr))
return
if(jobban_isbanned(M, "emote"))
body+= "<A href='?_src_=holder;[HrefToken()];jobban3=emote;jobban4=[rm]'><font color=red>EmoteBan</font></A> | "
else
body+= "<A href='?_src_=holder;[HrefToken()];jobban3=emote;jobban4=[rm]'>Emoteban</A> | "
if(QDELETED(M) || QDELETED(usr))
return
body += "<A href='?_src_=holder;[HrefToken()];showmessageckey=[M.ckey]'>Notes | Messages | Watchlist</A> | " body += "<A href='?_src_=holder;[HrefToken()];showmessageckey=[M.ckey]'>Notes | Messages | Watchlist</A> | "
if(M.client) if(M.client)

View File

@@ -83,7 +83,7 @@ GLOBAL_LIST_INIT(admin_verbs_admin, world.AVerbsAdmin())
/client/proc/show_mentors // yogs - mentors /client/proc/show_mentors // yogs - mentors
) )
GLOBAL_PROTECT(admin_verbs_ban) GLOBAL_PROTECT(admin_verbs_ban)
GLOBAL_LIST_INIT(admin_verbs_ban, list(/client/proc/unban_panel, /client/proc/DB_ban_panel, /client/proc/stickybanpanel)) GLOBAL_LIST_INIT(admin_verbs_ban, list(/client/proc/unban_panel, /client/proc/ban_panel, /client/proc/stickybanpanel))
GLOBAL_PROTECT(admin_verbs_sounds) GLOBAL_PROTECT(admin_verbs_sounds)
GLOBAL_LIST_INIT(admin_verbs_sounds, list(/client/proc/play_local_sound, /client/proc/play_sound, /client/proc/set_round_end_sound)) GLOBAL_LIST_INIT(admin_verbs_sounds, list(/client/proc/play_local_sound, /client/proc/play_sound, /client/proc/set_round_end_sound))
GLOBAL_PROTECT(admin_verbs_fun) GLOBAL_PROTECT(admin_verbs_fun)
@@ -393,15 +393,21 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list(
SSblackbox.record_feedback("tally", "admin_verb", 1, "Check Antagonists") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! SSblackbox.record_feedback("tally", "admin_verb", 1, "Check Antagonists") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
// yogs end // yogs end
/client/proc/unban_panel() /client/proc/ban_panel()
set name = "Unban Panel" set name = "Banning Panel"
set category = "Admin" set category = "Admin"
if(holder) if(!check_rights(R_BAN))
if(CONFIG_GET(flag/ban_legacy_system)) return
holder.unbanpanel() holder.ban_panel()
else SSblackbox.record_feedback("tally", "admin_verb", 1, "Banning Panel") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
holder.DB_ban_panel()
SSblackbox.record_feedback("tally", "admin_verb", 1, "Unban Panel") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/unban_panel()
set name = "Unbanning Panel"
set category = "Admin"
if(!check_rights(R_BAN))
return
holder.unban_panel()
SSblackbox.record_feedback("tally", "admin_verb", 1, "Unbanning Panel") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/game_panel() /client/proc/game_panel()
set name = "Game Panel" set name = "Game Panel"

View File

@@ -0,0 +1,713 @@
#define MAX_ADMINBANS_PER_ADMIN 1
#define MAX_ADMINBANS_PER_HEADMIN 3
//checks client ban cache or DB ban table if ckey is banned from one or more roles
//doesn't return any details, use only for if statements
/proc/is_banned_from(player_ckey, roles)
if(!player_ckey)
return
var/client/C = GLOB.directory[player_ckey]
if(C)
if(!C.ban_cache)
build_ban_cache(C)
if(islist(roles))
for(var/R in roles)
if(R in C.ban_cache)
return TRUE //they're banned from at least one role, no need to keep checking
else if(roles in C.ban_cache)
return TRUE
else
player_ckey = sanitizeSQL(player_ckey)
var/admin_where
if(GLOB.admin_datums[player_ckey] || GLOB.deadmins[player_ckey])
admin_where = " AND applies_to_admins = 1"
var/sql_roles
if(islist(roles))
sql_roles = jointext(roles, "', '")
else
sql_roles = roles
sql_roles = sanitizeSQL(sql_roles)
var/datum/DBQuery/query_check_ban = SSdbcore.NewQuery("SELECT 1 FROM [format_table_name("ban")] WHERE ckey = '[player_ckey]' AND role IN ('[sql_roles]') AND unbanned_datetime IS NULL AND (expiration_time IS NULL OR expiration_time > NOW())[admin_where]")
if(!query_check_ban.warn_execute())
qdel(query_check_ban)
return
if(query_check_ban.NextRow())
qdel(query_check_ban)
return TRUE
qdel(query_check_ban)
//checks DB ban table if a ckey, ip and/or cid is banned from a specific role
//returns an associative nested list of each matching row's ban id, bantime, ban round id, expiration time, ban duration, applies to admins, reason, key, ip, cid and banning admin's key in that order
/proc/is_banned_from_with_details(player_ckey, player_ip, player_cid, role)
if(!player_ckey && !player_ip && !player_cid)
return
role = sanitizeSQL(role)
var/list/where_list = list()
if(player_ckey)
player_ckey = sanitizeSQL(player_ckey)
where_list += "ckey = '[player_ckey]'"
if(player_ip)
player_ip = sanitizeSQL(player_ip)
where_list += "ip = INET_ATON('[player_ip]')"
if(player_cid)
player_cid = sanitizeSQL(player_cid)
where_list += "computerid = '[player_cid]'"
var/where = "([where_list.Join(" OR ")])"
var/datum/DBQuery/query_check_ban = SSdbcore.NewQuery("SELECT id, bantime, round_id, expiration_time, TIMESTAMPDIFF(MINUTE, bantime, expiration_time), applies_to_admins, reason, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].ckey), ckey), INET_NTOA(ip), computerid, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].a_ckey), a_ckey) FROM [format_table_name("ban")] WHERE role = '[role]' AND [where] AND unbanned_datetime IS NULL AND (expiration_time IS NULL OR expiration_time > NOW()) ORDER BY bantime DESC")
if(!query_check_ban.warn_execute())
qdel(query_check_ban)
return
. = list()
while(query_check_ban.NextRow())
. += list(list("id" = query_check_ban.item[1], "bantime" = query_check_ban.item[2], "round_id" = query_check_ban.item[3], "expiration_time" = query_check_ban.item[4], "duration" = query_check_ban.item[5], "applies_to_admins" = query_check_ban.item[6], "reason" = query_check_ban.item[7], "key" = query_check_ban.item[8], "ip" = query_check_ban.item[9], "computerid" = query_check_ban.item[10], "admin_key" = query_check_ban.item[11]))
qdel(query_check_ban)
/proc/build_ban_cache(client/C)
if(!SSdbcore.Connect())
return
if(C && istype(C))
C.ban_cache = list()
var/player_key = sanitizeSQL(C.ckey)
var/is_admin = FALSE
if(GLOB.admin_datums[C.ckey] || GLOB.deadmins[C.ckey])
is_admin = TRUE
var/datum/DBQuery/query_build_ban_cache = SSdbcore.NewQuery("SELECT role, applies_to_admins FROM [format_table_name("ban")] WHERE ckey = '[player_key]' AND unbanned_datetime IS NULL AND (expiration_time IS NULL OR expiration_time > NOW())")
if(!query_build_ban_cache.warn_execute())
qdel(query_build_ban_cache)
return
while(query_build_ban_cache.NextRow())
if(is_admin && !text2num(query_build_ban_cache.item[2]))
continue
C.ban_cache[query_build_ban_cache.item[1]] = TRUE
qdel(query_build_ban_cache)
/datum/admins/proc/ban_panel(player_key, player_ip, player_cid, role, duration = 1440, applies_to_admins, reason, edit_id, page, admin_key)
var/panel_height = 620
if(edit_id)
panel_height = 240
var/datum/browser/panel = new(usr, "banpanel", "Banning Panel", 910, panel_height)
panel.add_stylesheet("banpanelcss", 'html/admin/banpanel.css')
panel.add_script("banpaneljs", 'html/admin/banpanel.js')
var/list/output = list("<form method='get' action='?src=[REF(src)]'>[HrefTokenFormField()]")
output += {"<input type='hidden' name='src' value='[REF(src)]'>
<label class='inputlabel checkbox'>Key:
<input type='checkbox' id='keycheck' name='keycheck' value='1'[player_key ? " checked": ""]>
<div class='inputbox'></div></label>
<input type='text' name='keytext' size='26' value='[player_key]'>
<label class='inputlabel checkbox'>IP:
<input type='checkbox' id='ipcheck' name='ipcheck' value='1'[player_ip ? " checked": ""]>
<div class='inputbox'></div></label>
<input type='text' name='iptext' size='18' value='[player_ip]'>
<label class='inputlabel checkbox'>CID:
<input type='checkbox' id='cidcheck' name='cidcheck' value='1'[player_cid ? " checked": ""]>
<div class='inputbox'></div></label>
<input type='text' name='cidtext' size='14' value='[player_cid]'>
<br>
<label class='inputlabel checkbox'>Use IP and CID from last connection of key
<input type='checkbox' id='lastconn' name='lastconn' value='1'>
<div class='inputbox'></div></label>
<label class='inputlabel checkbox'>Applies to Admins
<input type='checkbox' id='applyadmins' name='applyadmins' value='1'[applies_to_admins ? " checked": ""]>
<div class='inputbox'></div></label>
<input type='submit' value='Submit'>
<br>
<div class='row'>
<div class='column left'>
Duration type
<br>
<label class='inputlabel radio'>Permanent
<input type='radio' id='permanent' name='radioduration' value='permanent'[isnull(duration) ? " checked" : ""]>
<div class='inputbox'></div></label>
<br>
<label class='inputlabel radio'>Temporary
<input type='radio' id='temporary' name='radioduration' value='temporary'[duration ? " checked" : ""]>
<div class='inputbox'></div></label>
<input type='text' name='duration' size='7' value='[duration]'>
<div class="select">
<select name='intervaltype'>
<option value='SECOND'>Seconds</option>
<option value='MINUTE' selected>Minutes</option>
<option value='HOUR'>Hours</option>
<option value='DAY'>Days</option>
<option value='WEEK'>Weeks</option>
<option value='MONTH'>Months</option>
<option value='YEAR'>Years</option>
</select>
</div>
</div>
<div class='column middle'>
Ban type
<br>
<label class='inputlabel radio'>Server
<input type='radio' id='server' name='radioban' value='server'[role == "Server" ? " checked" : ""][edit_id ? " onclick='return false' onkeydown='return false'" : ""]>
<div class='inputbox'></div></label>
<br>
<label class='inputlabel radio'>Role
<input type='radio' id='role' name='radioban' value='role'[role == "Server" ? "" : " checked"][edit_id ? " onclick='return false' onkeydown='return false'" : ""]>
<div class='inputbox'></div></label>
</div>
<div class='column right'>
Severity
<br>
<label class='inputlabel radio'>None
<input type='radio' id='none' name='radioseverity' value='none'[edit_id ? " disabled" : ""]>
<div class='inputbox'></div></label>
<label class='inputlabel radio'>Medium
<input type='radio' id='medium' name='radioseverity' value='medium'[edit_id ? " disabled" : ""]>
<div class='inputbox'></div></label>
<br>
<label class='inputlabel radio'>Minor
<input type='radio' id='minor' name='radioseverity' value='minor'[edit_id ? " disabled" : ""]>
<div class='inputbox'></div></label>
<label class='inputlabel radio'>High
<input type='radio' id='high' name='radioseverity' value='high'[edit_id ? " disabled" : ""]>
<div class='inputbox'></div></label>
</div>
<div class='column'>
Reason
<br>
<textarea class='reason' name='reason'>[reason]</textarea>
</div>
</div>
"}
if(edit_id)
output += {"<label class='inputlabel checkbox'>Mirror edits to matching bans
<input type='checkbox' id='mirroredit' name='mirroredit' value='1'>
<div class='inputbox'></div></label>
<input type='hidden' name='editid' value='[edit_id]'>
<input type='hidden' name='oldkey' value='[player_key]'>
<input type='hidden' name='oldip' value='[player_ip]'>
<input type='hidden' name='oldcid' value='[player_cid]'>
<input type='hidden' name='oldapplies' value='[applies_to_admins]'>
<input type='hidden' name='oldduration' value='[duration]'>
<input type='hidden' name='oldreason' value='[reason]'>
<input type='hidden' name='page' value='[page]'>
<input type='hidden' name='adminkey' value='[admin_key]'>
<br>
When ticked, edits here will also affect bans created with matching ckey, IP, CID and time. Use this to edit all role bans which were made at the same time.
"}
else
output += "<input type='hidden' name='roleban_delimiter' value='1'>"
//there's not always a client to use the bancache of so to avoid many individual queries from using is_banned_form we'll build a cache to use here
var/banned_from = list()
if(player_key)
var/player_ckey = sanitizeSQL(ckey(player_key))
var/datum/DBQuery/query_get_banned_roles = SSdbcore.NewQuery("SELECT role FROM [format_table_name("ban")] WHERE ckey = '[player_ckey]' AND role <> 'server' AND unbanned_datetime IS NULL AND (expiration_time IS NULL OR expiration_time > NOW())")
if(!query_get_banned_roles.warn_execute())
qdel(query_get_banned_roles)
return
while(query_get_banned_roles.NextRow())
banned_from += query_get_banned_roles.item[1]
qdel(query_get_banned_roles)
var/break_counter = 0
output += "<div class='row'><div class='column'><label class='rolegroup command'><input type='checkbox' name='Command' class='hidden' onClick='toggle_checkboxes(this, \"_dep\")'>Command</label><div class='content'>"
//all heads are listed twice so have a javascript call to toggle both their checkboxes when one is pressed
//for simplicity this also includes the captain even though it doesn't do anything
for(var/job in GLOB.command_positions)
if(break_counter > 0 && (break_counter % 3 == 0))
output += "<br>"
output += {"<label class='inputlabel checkbox'>[job]
<input type='checkbox' id='[job]_com' name='[job]' class='Command' onClick='toggle_head(this, \"_dep\")' value='1'>
<div class='inputbox[(job in banned_from) ? " banned" : ""]'></div></label>
"}
break_counter++
output += "</div></div>"
//standard deparments all have identical handling
var/list/job_lists = list("Security" = GLOB.security_positions,
"Engineering" = GLOB.engineering_positions,
"Medical" = GLOB.medical_positions,
"Science" = GLOB.science_positions,
"Supply" = GLOB.supply_positions,
"Silicon" = GLOB.nonhuman_positions) //another cheat for simplicity
for(var/department in job_lists)
//the first element is the department head so they need the same javascript call as above
output += "<div class='column'><label class='rolegroup [ckey(department)]'><input type='checkbox' name='[department]' class='hidden' onClick='toggle_checkboxes(this, \"_com\")'>[department]</label><div class='content'>"
output += {"<label class='inputlabel checkbox'>[job_lists[department][1]]
<input type='checkbox' id='[job_lists[department][1]]_dep' name='[job_lists[department][1]]' class='[department]' onClick='toggle_head(this, \"_com\")' value='1'>
<div class='inputbox[(job_lists[department][1] in banned_from) ? " banned" : ""]'></div></label>
"}
break_counter = 1
for(var/job in job_lists[department] - job_lists[department][1]) //skip the first element since it's already been done
if(break_counter % 3 == 0)
output += "<br>"
output += {"<label class='inputlabel checkbox'>[job]
<input type='checkbox' name='[job]' class='[department]' value='1'>
<div class='inputbox[(job in banned_from) ? " banned" : ""]'></div></label>
"}
break_counter++
output += "</div></div>"
var/list/long_job_lists = list("Civilian" = GLOB.civilian_positions,
"Ghost and Other Roles" = list("Appearance", ROLE_BRAINWASHED, ROLE_DEATHSQUAD, ROLE_DRONE, "Emote", ROLE_LAVALAND, ROLE_MIND_TRANSFER, "OOC", ROLE_POSIBRAIN, ROLE_SENTIENCE),
"Antagonist Positions" = list(ROLE_ABDUCTOR, ROLE_ALIEN, ROLE_BLOB,
ROLE_BROTHER, ROLE_CHANGELING, ROLE_CULTIST,
ROLE_DEVIL, ROLE_INTERNAL_AFFAIRS, ROLE_MALF,
ROLE_MONKEY, ROLE_NINJA, ROLE_OPERATIVE,
ROLE_OVERTHROW, ROLE_REV, ROLE_REVENANT,
ROLE_REV_HEAD, ROLE_SERVANT_OF_RATVAR, ROLE_SYNDICATE,
ROLE_TRAITOR, ROLE_WIZARD)) //ROLE_REV_HEAD is excluded from this because rev jobbans are handled by ROLE_REV
for(var/department in long_job_lists)
output += "<div class='column'><label class='rolegroup long [ckey(department)]'><input type='checkbox' name='[department]' class='hidden' onClick='toggle_checkboxes(this, \"_com\")'>[department]</label><div class='content'>"
break_counter = 0
for(var/job in long_job_lists[department])
if(break_counter > 0 && (break_counter % 10 == 0))
output += "<br>"
output += {"<label class='inputlabel checkbox'>[job]
<input type='checkbox' name='[job]' class='[department]' value='1'>
<div class='inputbox[(job in banned_from) ? " banned" : ""]'></div></label>
"}
break_counter++
output += "</div></div>"
output += "</div>"
output += "</form>"
panel.set_content(jointext(output, ""))
panel.open()
/datum/admins/proc/ban_parse_href(list/href_list)
if(!check_rights(R_BAN))
return
if(!SSdbcore.Connect())
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>")
return
var/list/error_state = list()
var/player_key
var/player_ip
var/player_cid
var/use_last_connection = FALSE
var/applies_to_admins = FALSE
var/duration
var/interval
var/severity
var/reason
var/mirror_edit
var/edit_id
var/old_key
var/old_ip
var/old_cid
var/old_applies
var/page
var/admin_key
var/list/changes = list()
var/list/roles_to_ban = list()
if(href_list["keycheck"])
player_key = href_list["keytext"]
if(!player_key)
error_state += "Key was ticked but none was provided."
if(href_list["lastconn"])
use_last_connection = TRUE
if(!player_key)
error_state += "A key must be provided to use IP and CID from last connection."
else
if(href_list["ipcheck"])
player_ip = href_list["iptext"]
if(!player_ip)
error_state += "IP was ticked but none was provided."
if(href_list["cidcheck"])
player_cid = href_list["cidtext"]
if(!player_cid)
error_state += "CID was ticked but none was provided."
if(!use_last_connection && !player_ip && !player_cid && !player_key)
error_state += "At least a key, IP or CID must be provided."
if(href_list["applyadmins"])
applies_to_admins = TRUE
switch(href_list["radioduration"])
if("permanent")
duration = null
if("temporary")
duration = href_list["duration"]
interval = href_list["intervaltype"]
if(!duration)
error_state += "Temporary ban was selected but no duration was provided."
else
error_state += "No duration was selected."
reason = href_list["reason"]
if(!reason)
error_state += "No reason was provided."
if(href_list["editid"])
edit_id = href_list["editid"]
if(href_list["mirroredit"])
mirror_edit = TRUE
old_key = href_list["oldkey"]
old_ip = href_list["oldip"]
old_cid = href_list["oldcid"]
page = href_list["page"]
admin_key = href_list["adminkey"]
if(player_key != old_key)
changes += list("Key" = "[old_key] to [player_key]")
if(player_ip != old_ip)
changes += list("IP" = "[old_ip] to [player_ip]")
if(player_cid != old_cid)
changes += list("CID" = "[old_cid] to [player_cid]")
old_applies = text2num(href_list["oldapplies"])
if(applies_to_admins != old_applies)
changes += list("Applies to admins" = "[old_applies] to [applies_to_admins]")
if(duration != href_list["oldduration"])
changes += list("Duration" = "[href_list["oldduration"]] MINUTE to [duration] [interval]")
if(reason != href_list["oldreason"])
changes += list("Reason" = "[href_list["oldreason"]]<br>to<br>[reason]")
if(!changes.len)
error_state += "No changes were detected."
else
severity = href_list["radioseverity"]
if(!severity)
error_state += "No severity was selected."
switch(href_list["radioban"])
if("server")
roles_to_ban += "Server"
if("role")
if(href_list[href_list.len] == "roleban_delimiter")
error_state += "Role ban was selected but no roles to ban were selected."
else
href_list.Remove("Command", "Security", "Engineering", "Medical", "Science", "Supply", "Silicon", "Civilian", "Ghost and Other Roles", "Antagonist Positions") //remove the role banner hidden input values
var/delimiter_pos = href_list.Find("roleban_delimiter")
href_list.Cut(1, delimiter_pos+1)//remove every list element before and including roleban_delimiter so we have a list of only the roles to ban
for(var/key in href_list) //flatten into a list of only unique keys
roles_to_ban |= key
else
error_state += "No ban type was selected."
if(error_state.len)
to_chat(usr, "<span class='danger'>Ban not [edit_id ? "edited" : "created"] because the following errors were present:\n[error_state.Join("\n")]</span>")
return
if(edit_id)
edit_ban(edit_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, page, admin_key, changes)
else
create_ban(player_key, player_ip, player_cid, use_last_connection, applies_to_admins, duration, interval, severity, reason, roles_to_ban)
/datum/admins/proc/create_ban(player_key, player_ip, player_cid, use_last_connection, applies_to_admins, duration, interval, severity, reason, list/roles_to_ban)
if(!check_rights(R_BAN))
return
if(!SSdbcore.Connect())
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>")
return
var/player_ckey = sanitizeSQL(ckey(player_key))
player_ip = sanitizeSQL(player_ip)
player_cid = sanitizeSQL(player_cid)
var/datum/DBQuery/query_create_ban_get_player = SSdbcore.NewQuery("SELECT byond_key, INET_NTOA(ip), computerid FROM [format_table_name("player")] WHERE ckey = '[player_ckey]'")
if(!query_create_ban_get_player.warn_execute())
qdel(query_create_ban_get_player)
return
if(query_create_ban_get_player.NextRow())
player_key = query_create_ban_get_player.item[1]
if(use_last_connection)
player_ip = query_create_ban_get_player.item[2]
player_cid = query_create_ban_get_player.item[3]
else
if(use_last_connection)
to_chat(usr, "<span class='danger'>Ban not created. [player_key]/([player_ckey]) hasn't been seen before, unable to use IP and CID from last connection.</span>")
qdel(query_create_ban_get_player)
return
else
if(alert(usr, "[player_key]/([player_ckey]) has not been seen before, are you sure you want to create a ban for them?", "Unknown key", "Yes", "No", "Cancel") != "Yes")
qdel(query_create_ban_get_player)
return
qdel(query_create_ban_get_player)
var/admin_ckey = sanitizeSQL(usr.client.ckey)
if(applies_to_admins)
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, "<span class='danger'>You've already logged [max_adminbans] admin ban(s) or more. Do not abuse this function!</span>")
qdel(query_check_adminban_count)
return
qdel(query_check_adminban_count)
var/admin_ip = sanitizeSQL(usr.client.address)
var/admin_cid = sanitizeSQL(usr.client.computer_id)
duration = text2num(duration)
if(interval)
interval = sanitizeSQL(interval)
else
interval = "MINUTE"
reason = sanitizeSQL(reason)
var/list/clients_online = GLOB.clients.Copy()
var/list/admins_online = list()
for(var/client/C in clients_online)
if(C.holder) //deadmins aren't included since they wouldn't show up on adminwho
admins_online += C
var/who = clients_online.Join(", ")
var/adminwho = admins_online.Join(", ")
var/kn = key_name(usr)
var/kna = key_name_admin(usr)
var/sql_ban
for(var/role in roles_to_ban)
sql_ban += list(list("bantime" = "NOW()",
"server_ip" = "INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]'))",
"server_port" = sanitizeSQL(world.port),
"round_id" = sanitizeSQL(GLOB.round_id),
"role" = "'[sanitizeSQL(role)]'",
"expiration_time" = "IF('[duration]' LIKE '', NULL, NOW() + INTERVAL [duration ? "[duration]" : "0"] [interval])",
"applies_to_admins" = sanitizeSQL(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]')",
"a_ckey" = "'[admin_ckey]'",
"a_ip" = "INET_ATON(IF('[admin_ip]' LIKE '', NULL, '[admin_ip]'))",
"a_computerid" = "'[admin_cid]'",
"who" = "'[who]'",
"adminwho" = "'[adminwho]'"
))
if(!SSdbcore.MassInsert(format_table_name("ban"), sql_ban, warn = 1))
return
var/time_message = "[duration] [lowertext(interval)]" //no DisplayTimeText because our duration is of variable interval type
if(duration > 1) //pluralize the interval if necessary
time_message += "s"
var/msg = "has created a [isnull(duration) ? "permanent" : "temporary [time_message]"] [applies_to_admins ? "admin " : ""][roles_to_ban[1] == "Server" ? "server ban" : "role ban from [roles_to_ban.len] roles"] for [player_key]."
log_admin_private("[kn] [msg][roles_to_ban[1] == "Server" ? "" : " Roles: [roles_to_ban.Join(", ")]"]")
message_admins("[kna] [msg][roles_to_ban[1] == "Server" ? "" : " Roles: [roles_to_ban.Join("\n")]"]")
if(applies_to_admins)
send2irc("BAN ALERT","[kn] [msg]")
create_message("note", player_ckey, null, reason, null, null, 0, 0, null, 0, severity)
var/client/C = GLOB.directory[player_ckey]
var/datum/admin_help/AH = admin_ticket_log(player_ckey, msg)
var/appeal_url = "No ban appeal url set!"
appeal_url = CONFIG_GET(string/banappeals)
if(C)
build_ban_cache(C)
to_chat(C, "<span class='boldannounce'>You have been [applies_to_admins ? "admin " : ""]banned by [usr.client.key] from [roles_to_ban[1] == "Server" ? "the server" : " Roles: [roles_to_ban.Join(", ")]"].\nReason: [reason]</span><br><span class='danger'>This ban is [isnull(duration) ? "permanent." : "temporary, it will be removed in [time_message]."] The round ID is [GLOB.round_id].</span><br><span class='danger'>To appeal this ban go to [appeal_url]</span>")
if(roles_to_ban[1] == "Server")
if(AH)
AH.Resolve()
qdel(C)
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, "<span class='boldannounce'>You have been [applies_to_admins ? "admin " : ""]banned by [usr.client.key] from [roles_to_ban[1] == "Server" ? "the server" : " Roles: [roles_to_ban.Join(", ")]"].\nReason: [reason]</span><br><span class='danger'>This ban is [isnull(duration) ? "permanent." : "temporary, it will be removed in [time_message]."] The round ID is [GLOB.round_id].</span><br><span class='danger'>To appeal this ban go to [appeal_url]</span>")
if(roles_to_ban[1] == "Server")
qdel(i)
/datum/admins/proc/unban_panel(player_key, admin_key, player_ip, player_cid, page = 0)
if(!check_rights(R_BAN))
return
if(!SSdbcore.Connect())
to_chat(usr, "<span class='danger'>Failed to establish database connection.</span>")
return
var/datum/browser/unban_panel = new(usr, "unbanpanel", "Unbanning Panel", 850, 600)
unban_panel.add_stylesheet("unbanpanelcss", 'html/admin/unbanpanel.css')
var/list/output = list("<div class='searchbar'>")
output += {"<form method='get' action='?src=[REF(src)]'>[HrefTokenFormField()]
<input type='hidden' name='src' value='[REF(src)]'>
Key:<input type='text' name='searchunbankey' size='18' value='[player_key]'>
Admin Key:<input type='text' name='searchunbanadminkey' size='18' value='[admin_key]'>
IP:<input type='text' name='searchunbanip' size='12' value='[player_ip]'>
CID:<input type='text' name='searchunbancid' size='10' value='[player_cid]'>
<input type='submit' value='Search'>
</form>
</div>
<div class='main'>
"}
if(player_key || admin_key || player_ip || player_cid)
var/list/searchlist = list()
if(player_key)
searchlist += "ckey = '[sanitizeSQL(ckey(player_key))]'"
if(admin_key)
searchlist += "a_ckey = '[sanitizeSQL(ckey(admin_key))]'"
if(player_ip)
searchlist += "ip = INET_ATON('[sanitizeSQL(player_ip)]')"
if(player_cid)
searchlist += "computerid = '[sanitizeSQL(player_cid)]'"
var/search = searchlist.Join(" AND ")
var/bancount = 0
var/bansperpage = 10
page = text2num(page)
var/datum/DBQuery/query_unban_count_bans = SSdbcore.NewQuery("SELECT COUNT(id) FROM [format_table_name("ban")] WHERE [search]")
if(!query_unban_count_bans.warn_execute())
qdel(query_unban_count_bans)
return
if(query_unban_count_bans.NextRow())
bancount = text2num(query_unban_count_bans.item[1])
qdel(query_unban_count_bans)
if(bancount > bansperpage)
output += "<b>Page: </b>"
var/pagecount = 1
var/list/pagelist = list()
while(bancount > 0)
pagelist += "<a href='?_src_=holder;[HrefToken()];unbanpagecount=[pagecount - 1];unbankey=[player_key];unbanadminkey=[admin_key];unbanip=[player_ip];unbancid=[player_cid]'>[pagecount == page ? "<b>\[[pagecount]\]</b>" : "\[[pagecount]\]"]</a>"
bancount -= bansperpage
pagecount++
output += pagelist.Join(" | ")
var/limit = " LIMIT [bansperpage * page], [bansperpage]"
var/datum/DBQuery/query_unban_search_bans = SSdbcore.NewQuery({"SELECT id, bantime, round_id, role, expiration_time, TIMESTAMPDIFF(MINUTE, bantime, expiration_time), IF(expiration_time < NOW(), 1, NULL), applies_to_admins, reason, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].ckey), ckey), INET_NTOA(ip), computerid, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].a_ckey), a_ckey), IF(edits IS NOT NULL, 1, NULL), unbanned_datetime, IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].unbanned_ckey), unbanned_ckey), unbanned_round_id FROM [format_table_name("ban")] WHERE [search] ORDER BY id DESC[limit]"})
if(!query_unban_search_bans.warn_execute())
qdel(query_unban_search_bans)
return
while(query_unban_search_bans.NextRow())
var/ban_id = query_unban_search_bans.item[1]
var/ban_datetime = query_unban_search_bans.item[2]
var/ban_round_id = query_unban_search_bans.item[3]
var/role = query_unban_search_bans.item[4]
//make the href for unban here so only the search parameters are passed
var/unban_href = "<a href='?_src_=holder;[HrefToken()];unbanid=[ban_id];unbankey=[player_key];unbanadminkey=[admin_key];unbanip=[player_ip];unbancid=[player_cid];unbanrole=[role];unbanpage=[page]'>Unban</a>"
var/expiration_time = query_unban_search_bans.item[5]
//we don't cast duration as num because if the duration is large enough to be converted to scientific notation by byond then the + character gets lost when passed through href causing SQL to interpret '4.321e 007' as '4'
var/duration = query_unban_search_bans.item[6]
var/expired = query_unban_search_bans.item[7]
var/applies_to_admins = text2num(query_unban_search_bans.item[8])
var/reason = query_unban_search_bans.item[9]
player_key = query_unban_search_bans.item[10]
player_ip = query_unban_search_bans.item[11]
player_cid = query_unban_search_bans.item[12]
admin_key = query_unban_search_bans.item[13]
var/edits = query_unban_search_bans.item[14]
var/unban_datetime = query_unban_search_bans.item[15]
var/unban_key = query_unban_search_bans.item[16]
var/unban_round_id = query_unban_search_bans.item[17]
output += "<div class='banbox'><div class='header [unban_datetime ? "unbanned" : "banned"]'><b>[player_key]</b>[applies_to_admins ? " <b>ADMIN</b>" : ""] banned by <b>[admin_key]</b> from <b>[role]</b> on <b>[ban_datetime]</b> during round <b>#[ban_round_id]</b>.<br>"
if(!expiration_time)
output += "<b>Permanent ban</b>."
else
output += "Duration of <b>[DisplayTimeText(text2num(duration) MINUTES)]</b>, <b>[expired ? "expired" : "expires"]</b> on <b>[expiration_time]</b>."
if(unban_datetime)
output += "<br>Unbanned by <b>[unban_key]</b> on <b>[unban_datetime]</b> during round <b>#[unban_round_id]</b>."
output += "</div><div class='container'><div class='reason'>[reason]</div><div class='edit'>"
if(!expired && !unban_datetime)
output += "<a href='?_src_=holder;[HrefToken()];editbanid=[ban_id];editbankey=[player_key];editbanip=[player_ip];editbancid=[player_cid];editbanrole=[role];editbanduration=[duration];editbanadmins=[applies_to_admins];editbanreason=[reason];editbanpage=[page];editbanadminkey=[admin_key]'>Edit</a><br>[unban_href]"
if(edits)
output += "<br><a href='?_src_=holder;[HrefToken()];unbanlog=[ban_id]'>Edit log</a>"
output += "</div></div></div>"
qdel(query_unban_search_bans)
output += "</div>"
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, "<span class='danger'>Failed to establish database connection.</span>")
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, "<span class='boldannounce'>[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, "<span class='boldannounce'>[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, "<span class='danger'>Failed to establish database connection.</span>")
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, "<span class='danger'>Ban not edited. [player_key]/([player_ckey]) hasn't been seen before, unable to use IP and CID from last connection.</span>")
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, "<span class='danger'>You've already logged [max_adminbans] admin ban(s) or more. Do not abuse this function!</span>")
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, ", ")]<hr>') 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, "<span class='boldannounce'>[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, "<span class='boldannounce'>[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, "<span class='danger'>Failed to establish database connection.</span>")
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)

View File

@@ -216,6 +216,7 @@
log_admin("[key_name(usr)] has triggered an event. ([E.name])") log_admin("[key_name(usr)] has triggered an event. ([E.name])")
return return
<<<<<<< HEAD
else if(href_list["dbsearchckey"] || href_list["dbsearchadmin"] || href_list["dbsearchip"] || href_list["dbsearchcid"]) else if(href_list["dbsearchckey"] || href_list["dbsearchadmin"] || href_list["dbsearchip"] || href_list["dbsearchcid"])
var/adminckey = href_list["dbsearchadmin"] var/adminckey = href_list["dbsearchadmin"]
var/playerckey = href_list["dbsearchckey"] 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, banseverity)
create_message("note", bankey, null, banreason, null, null, 0, 0, null, 0) //yogs - remove severity 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"]) else if(href_list["editrightsbrowser"])
edit_admin_permissions(0) edit_admin_permissions(0)
@@ -536,6 +539,7 @@
if("shade") if("shade")
M.change_mob_type( /mob/living/simple_animal/shade , null, null, delmob ) M.change_mob_type( /mob/living/simple_animal/shade , null, null, delmob )
<<<<<<< HEAD
/////////////////////////////////////new ban stuff /////////////////////////////////////new ban stuff
else if(href_list["unbanf"]) else if(href_list["unbanf"])
@@ -1117,6 +1121,8 @@
return 1 return 1
return 0 //we didn't do anything! return 0 //we didn't do anything!
=======
>>>>>>> 8a66665e95... Ban system and interface update (#41176)
else if(href_list["boot2"]) else if(href_list["boot2"])
if(!check_rights(R_ADMIN)) if(!check_rights(R_ADMIN))
return return
@@ -1292,6 +1298,7 @@
usr << browse(edit_log,"window=noteedits") //yogs usr << browse(edit_log,"window=noteedits") //yogs
qdel(query_get_message_edits) qdel(query_get_message_edits)
<<<<<<< HEAD
else if(href_list["newban"]) else if(href_list["newban"])
if(!check_rights(R_BAN)) if(!check_rights(R_BAN))
return return
@@ -1366,6 +1373,8 @@
if("Cancel") if("Cancel")
return return
=======
>>>>>>> 8a66665e95... Ban system and interface update (#41176)
else if(href_list["mute"]) else if(href_list["mute"])
if(!check_rights(R_ADMIN)) if(!check_rights(R_ADMIN))
return return
@@ -2613,6 +2622,59 @@
removeMentor(href_list["removementor"]) removeMentor(href_list["removementor"])
// yogs end // 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() /datum/admins/proc/HandleCMode()
if(!check_rights(R_ADMIN)) if(!check_rights(R_ADMIN))

View File

@@ -42,7 +42,7 @@
return FALSE 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 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 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() /datum/admins/proc/makeTraitors()

View File

@@ -76,7 +76,7 @@ GLOBAL_LIST_EMPTY(antagonists)
/datum/antagonist/proc/is_banned(mob/M) /datum/antagonist/proc/is_banned(mob/M)
if(!M) if(!M)
return FALSE 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() /datum/antagonist/proc/replace_banned_player()
set waitfor = FALSE set waitfor = FALSE

View File

@@ -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) notify_ghosts("Manifest rune invoked in [get_area(src)].", 'sound/effects/ghost2.ogg', source = src)
var/list/ghosts_on_rune = list() var/list/ghosts_on_rune = list()
for(var/mob/dead/observer/O in T) 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 ghosts_on_rune += O
if(!ghosts_on_rune.len) if(!ghosts_on_rune.len)
to_chat(user, "<span class='cultitalic'>There are no spirits near [src]!</span>") to_chat(user, "<span class='cultitalic'>There are no spirits near [src]!</span>")

View File

@@ -37,7 +37,7 @@
if(!uses) if(!uses)
to_chat(user, "<span class='warning'>This spawner is out of charges!</span>") to_chat(user, "<span class='warning'>This spawner is out of charges!</span>")
return return
if(jobban_isbanned(user, banType)) if(is_banned_from(user.key, banType))
to_chat(user, "<span class='warning'>You are jobanned!</span>") to_chat(user, "<span class='warning'>You are jobanned!</span>")
return return
if(QDELETED(src) || QDELETED(user)) if(QDELETED(src) || QDELETED(user))

View File

@@ -11,7 +11,7 @@
var/datum/click_intercept = null // Needs to implement InterceptClickOn(user,params,atom) proc var/datum/click_intercept = null // Needs to implement InterceptClickOn(user,params,atom) proc
var/AI_Interact = 0 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 = "" //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/last_message_count = 0 //contins a number of how many times a message identical to last_message was sent.
var/ircreplyamount = 0 var/ircreplyamount = 0
@@ -73,5 +73,8 @@
var/list/credits //lazy list of all credit object bound to this client 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. var/datum/player_details/player_details //these persist between logins/logouts during the same round.
<<<<<<< HEAD
var/encoding = "1252" // yogs - LibVG var/encoding = "1252" // yogs - LibVG
=======
>>>>>>> 8a66665e95... Ban system and interface update (#41176)

View File

@@ -203,7 +203,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<center><b>Current Quirks:</b> [all_quirks.len ? all_quirks.Join(", ") : "None"]</center>" dat += "<center><b>Current Quirks:</b> [all_quirks.len ? all_quirks.Join(", ") : "None"]</center>"
dat += "<h2>Identity</h2>" dat += "<h2>Identity</h2>"
dat += "<table width='100%'><tr><td width='75%' valign='top'>" dat += "<table width='100%'><tr><td width='75%' valign='top'>"
if(jobban_isbanned(user, "appearance")) if(is_banned_from(user.ckey, "Appearance"))
dat += "<b>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.</b><br>" dat += "<b>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.</b><br>"
dat += "<a href='?_src_=prefs;preference=name;task=random'>Random Name</A> " dat += "<a href='?_src_=prefs;preference=name;task=random'>Random Name</A> "
dat += "<a href='?_src_=prefs;preference=name'>Always Random Name: [be_random_name ? "Yes" : "No"]</a><BR>" dat += "<a href='?_src_=prefs;preference=name'>Always Random Name: [be_random_name ? "Yes" : "No"]</a><BR>"
@@ -553,14 +553,14 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<h2>Special Role Settings</h2>" dat += "<h2>Special Role Settings</h2>"
if(jobban_isbanned(user, ROLE_SYNDICATE)) if(is_banned_from(user.ckey, ROLE_SYNDICATE))
dat += "<font color=red><b>You are banned from antagonist roles.</b></font>" dat += "<font color=red><b>You are banned from antagonist roles.</b></font><br>"
src.be_special = list() src.be_special = list()
for (var/i in GLOB.special_roles) for (var/i in GLOB.special_roles)
if(jobban_isbanned(user, i)) if(is_banned_from(user.ckey, i))
dat += "<b>Be [capitalize(i)]:</b> <a href='?_src_=prefs;jobbancheck=[i]'>BANNED</a><br>" dat += "<b>Be [capitalize(i)]:</b> <a href='?_src_=prefs;bancheck=[i]'>BANNED</a><br>"
else else
var/days_remaining = null 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 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 += "<tr bgcolor='[job.selection_color]'><td width='60%' align='right'>" HTML += "<tr bgcolor='[job.selection_color]'><td width='60%' align='right'>"
var/rank = job.title var/rank = job.title
lastJob = job lastJob = job
if(jobban_isbanned(user, rank)) if(is_banned_from(user.ckey, rank))
HTML += "<font color=red>[rank]</font></td><td><a href='?_src_=prefs;jobbancheck=[rank]'> BANNED</a></td></tr>" HTML += "<font color=red>[rank]</font></td><td><a href='?_src_=prefs;bancheck=[rank]'> BANNED</a></td></tr>"
continue continue
var/required_playtime_remaining = job.required_playtime_remaining(user.client) var/required_playtime_remaining = job.required_playtime_remaining(user.client)
if(required_playtime_remaining) if(required_playtime_remaining)
@@ -792,7 +792,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/available_in_days = job.available_in_days(user.client) var/available_in_days = job.available_in_days(user.client)
HTML += "<font color=red>[rank]</font></td><td><font color=red> \[IN [(available_in_days)] DAYS\]</font></td></tr>" HTML += "<font color=red>[rank]</font></td><td><font color=red> \[IN [(available_in_days)] DAYS\]</font></td></tr>"
continue continue
if((job_civilian_low & overflow.flag) && (rank != SSjob.overflow_role) && !jobban_isbanned(user, SSjob.overflow_role)) if((job_civilian_low & overflow.flag) && (rank != SSjob.overflow_role) && !is_banned_from(user.ckey, SSjob.overflow_role))
HTML += "<font color=orange>[rank]</font></td><td></td></tr>" HTML += "<font color=orange>[rank]</font></td><td></td></tr>"
continue continue
// yogs start - Donor features, quiet round // yogs start - Donor features, quiet round
@@ -1070,6 +1070,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
return bal return bal
/datum/preferences/proc/process_link(mob/user, list/href_list) /datum/preferences/proc/process_link(mob/user, list/href_list)
<<<<<<< HEAD
if(href_list["jobbancheck"]) if(href_list["jobbancheck"])
var/job = sanitizeSQL(href_list["jobbancheck"]) var/job = sanitizeSQL(href_list["jobbancheck"])
var/sql_ckey = sanitizeSQL(user.ckey) var/sql_ckey = sanitizeSQL(user.ckey)
@@ -1117,6 +1118,24 @@ GLOBAL_LIST_EMPTY(preferences_datums)
message_admins("EXPLOIT \[donor\]: [user] tried to access donor only functions (as a non-donor). Attempt made on \"[href_list["preference"]]\" -> \"[href_list["task"]]\".") message_admins("EXPLOIT \[donor\]: [user] tried to access donor only functions (as a non-donor). Attempt made on \"[href_list["preference"]]\" -> \"[href_list["task"]]\".")
// yogs end // yogs end
=======
if(href_list["bancheck"])
var/list/ban_details = is_banned_from_with_details(user.ckey, user.client.address, user.client.computer_id, href_list["bancheck"])
var/admin = FALSE
if(GLOB.admin_datums[user.ckey] || GLOB.deadmins[user.ckey])
admin = TRUE
for(var/i in ban_details)
if(admin && !text2num(i["applies_to_admins"]))
continue
ban_details = i
break //we only want to get the most recent ban's details
if(ban_details && ban_details.len)
var/expires = "This is a permanent ban."
if(ban_details["expiration_time"])
expires = " The ban is for [DisplayTimeText(text2num(ban_details["duration"]) MINUTES)] and expires on [ban_details["expiration_time"]] (server time)."
to_chat(user, "<span class='danger'>You, or another user of this computer or connection ([ban_details["key"]]) is banned from playing [href_list["bancheck"]].<br>The ban reason is: [ban_details["reason"]]<br>This ban (BanID #[ban_details["id"]]) was applied by [ban_details["admin_key"]] on [ban_details["bantime"]] during round ID [ban_details["round_id"]].<br>[expires]</span>")
return
>>>>>>> 8a66665e95... Ban system and interface update (#41176)
if(href_list["preference"] == "job") if(href_list["preference"] == "job")
switch(href_list["task"]) switch(href_list["task"])
if("close") if("close")
@@ -1128,7 +1147,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if("random") if("random")
switch(joblessrole) switch(joblessrole)
if(RETURNTOLOBBY) if(RETURNTOLOBBY)
if(jobban_isbanned(user, SSjob.overflow_role)) if(is_banned_from(user.ckey, SSjob.overflow_role))
joblessrole = BERANDOMJOB joblessrole = BERANDOMJOB
else else
joblessrole = BEOVERFLOW joblessrole = BEOVERFLOW

View File

@@ -19,7 +19,7 @@
if(prefs.muted & MUTE_OOC) if(prefs.muted & MUTE_OOC)
to_chat(src, "<span class='danger'>You cannot use OOC (muted).</span>") to_chat(src, "<span class='danger'>You cannot use OOC (muted).</span>")
return return
if(jobban_isbanned(src.mob, "OOC")) if(is_banned_from(ckey, "OOC"))
to_chat(src, "<span class='danger'>You have been banned from OOC.</span>") to_chat(src, "<span class='danger'>You have been banned from OOC.</span>")
return return
if(QDELETED(src)) if(QDELETED(src))

View File

@@ -308,7 +308,7 @@
return JOB_UNAVAILABLE_SLOTFULL return JOB_UNAVAILABLE_SLOTFULL
else else
return JOB_UNAVAILABLE_SLOTFULL return JOB_UNAVAILABLE_SLOTFULL
if(jobban_isbanned(src,rank)) if(is_banned_from(ckey, rank))
return JOB_UNAVAILABLE_BANNED return JOB_UNAVAILABLE_BANNED
if(QDELETED(src)) if(QDELETED(src))
return JOB_UNAVAILABLE_GENERIC return JOB_UNAVAILABLE_GENERIC
@@ -479,7 +479,7 @@
var/frn = CONFIG_GET(flag/force_random_names) var/frn = CONFIG_GET(flag/force_random_names)
if(!frn) if(!frn)
frn = jobban_isbanned(src, "appearance") frn = is_banned_from(ckey, "Appearance")
if(QDELETED(src)) if(QDELETED(src))
return return
if(frn) if(frn)

View File

@@ -85,7 +85,7 @@ GLOBAL_VAR(posibrain_notify_cooldown)
/obj/item/mmi/posibrain/proc/activate(mob/user) /obj/item/mmi/posibrain/proc/activate(mob/user)
if(QDELETED(brainmob)) if(QDELETED(brainmob))
return return
if(is_occupied() || jobban_isbanned(user,"posibrain") || QDELETED(brainmob) || QDELETED(src) || QDELETED(user)) if(is_occupied() || is_banned_from(user.ckey, ROLE_POSIBRAIN) || QDELETED(brainmob) || QDELETED(src) || QDELETED(user))
return return
if(user.suiciding) //if they suicided, they're out forever. if(user.suiciding) //if they suicided, they're out forever.
to_chat(user, "<span class='warning'>[src] fizzles slightly. Sadly it doesn't take those who suicided!</span>") to_chat(user, "<span class='warning'>[src] fizzles slightly. Sadly it doesn't take those who suicided!</span>")

View File

@@ -413,7 +413,7 @@
. = FALSE . = FALSE
/datum/emote/living/custom/run_emote(mob/user, params, type_override = null) /datum/emote/living/custom/run_emote(mob/user, params, type_override = null)
if(jobban_isbanned(user, "emote")) if(is_banned_from(user.ckey, "Emote"))
to_chat(user, "You cannot send custom emotes (banned).") to_chat(user, "You cannot send custom emotes (banned).")
return FALSE return FALSE
else if(QDELETED(user)) else if(QDELETED(user))

View File

@@ -41,7 +41,7 @@
//ATTACK GHOST IGNORING PARENT RETURN VALUE //ATTACK GHOST IGNORING PARENT RETURN VALUE
/obj/item/drone_shell/attack_ghost(mob/user) /obj/item/drone_shell/attack_ghost(mob/user)
if(jobban_isbanned(user,"drone") || QDELETED(src) || QDELETED(user)) if(is_banned_from(user.ckey, ROLE_DRONE) || QDELETED(src) || QDELETED(user))
return return
if(CONFIG_GET(flag/use_age_restriction_for_jobs)) if(CONFIG_GET(flag/use_age_restriction_for_jobs))
if(!isnum(user.client.player_age)) //apparently what happens when there's no DB connected. just don't let anybody be a drone without admin intervention if(!isnum(user.client.player_age)) //apparently what happens when there's no DB connected. just don't let anybody be a drone without admin intervention

View File

@@ -56,7 +56,7 @@
to_chat(usr, "<span class='danger'>Speech is currently admin-disabled.</span>") to_chat(usr, "<span class='danger'>Speech is currently admin-disabled.</span>")
return return
var/jb = jobban_isbanned(src, "OOC") var/jb = is_banned_from(ckey, "OOC")
if(QDELETED(src)) if(QDELETED(src))
return return

View File

@@ -726,7 +726,7 @@
if(SM.sentience_type != animal_type) if(SM.sentience_type != animal_type)
to_chat(user, "<span class='warning'>You cannot transfer your consciousness to [SM].</span>" ) to_chat(user, "<span class='warning'>You cannot transfer your consciousness to [SM].</span>" )
return ..() return ..()
var/jb = jobban_isbanned(user, ROLE_MIND_TRANSFER) var/jb = is_banned_from(user.ckey, ROLE_MIND_TRANSFER)
if(QDELETED(src) || QDELETED(M) || QDELETED(user)) if(QDELETED(src) || QDELETED(M) || QDELETED(user))
return return

View File

@@ -46,9 +46,6 @@ ADMIN_LEGACY_SYSTEM
##If enabled, each time admins are loaded ranks the database will be updated with the current ranks and their flags ##If enabled, each time admins are loaded ranks the database will be updated with the current ranks and their flags
#LOAD_LEGACY_RANKS_ONLY #LOAD_LEGACY_RANKS_ONLY
## Comment this out if you want to use the SQL based banning system. The legacy systems use the files in the data folder. You need to set up your database to use the SQL based system.
BAN_LEGACY_SYSTEM
## Comment this out to stop locally connected clients from being given the almost full access !localhost! admin rank ## Comment this out to stop locally connected clients from being given the almost full access !localhost! admin rank
ENABLE_LOCALHOST_RANK ENABLE_LOCALHOST_RANK

182
html/admin/banpanel.css Normal file
View File

@@ -0,0 +1,182 @@
.column {
float: left;
flex-wrap: wrap;
}
.left {
width: 280px;
}
.middle {
width: 80px;
}
.right {
width: 150px;
}
.row:after {
content: '';
display: table;
clear: both;
}
.reason {
resize: none;
min-height: 40px;
width: 340px;
}
.rolegroup {
padding: 3px;
width: 430px;
border: none;
text-align: center;
outline: none;
display: inline-block;
}
.long {
width: 860px;
}
.content {
text-align: center;
}
.command {
background-color: #948f02;
}
.security {
background-color: #a30000;
}
.engineering {
background-color: #fb5613;
}
.medical {
background-color: #337296;
}
.science {
background-color: #993399;
}
.supply {
background-color: #a8732b;
}
.silicon {
background-color: #ff00ff;
}
.civilian {
background-color: #6eaa2c;
}
.ghostandotherroles {
background-color: #5c00e6;
}
.antagonistpositions {
background-color: #6d3f40;
}
.inputlabel {
position: relative;
display: inline;
cursor: pointer;
padding-left: 20px;
}
.inputlabel input {
position: absolute;
z-index: -1;
opacity: 0;
}
.inputbox {
position: absolute;
top: 0px;
left: 4px;
width: 14px;
height: 14px;
background: #e6e6e6;
}
.radio .inputbox {
border-radius: 50%;
}
.inputlabel:hover input ~ .inputbox {
background: #b4b4b4;
}
.inputlabel input:checked ~ .inputbox {
background: #2196F3;
}
.inputlabel:hover input:not([disabled]):checked ~ .inputbox{
background: #0a6ebd;
}
.inputlabel input:disabled ~ .inputbox {
pointer-events: none;
background: #838383;
}
.banned {
background: #ff4e4e;
}
.inputlabel:hover input ~ .banned {
background: #ff0000;
}
.inputlabel input:checked ~ .banned {
background: #a80000;
}
.inputlabel:hover input:not([disabled]):checked ~ .banned{
background: #810000;
}
.inputbox:after {
position: absolute;
display: none;
content: '';
}
.inputlabel input:checked ~ .inputbox:after {
display: block;
}
.checkbox .inputbox:after {
top: 1px;
left: 5px;
width: 3px;
height: 9px;
transform: rotate(45deg);
border: solid #fff;
border-width: 0 2px 2px 0;
}
.radio .inputbox:after {
top: 4px;
left: 4px;
width: 6px;
height: 6px;
border-radius: 50%;
background: #fff;
}
.select {
position: relative;
display: inline-block;
}
.hidden {
display: none;
}

16
html/admin/banpanel.js Normal file
View File

@@ -0,0 +1,16 @@
function toggle_head(source, ext) {
document.getElementById(source.id.slice(0, -4) + ext).checked = source.checked;
}
function toggle_checkboxes(source, ext) {
var checkboxes = document.getElementsByClassName(source.name);
for (var i = 0, n = checkboxes.length; i < n; i++) {
checkboxes[i].checked = source.checked;
if (checkboxes[i].id) {
var idfound = document.getElementById(checkboxes[i].id.slice(0, -4) + ext);
if (idfound) {
idfound.checked = source.checked;
}
}
}
}

61
html/admin/unbanpanel.css Normal file
View File

@@ -0,0 +1,61 @@
body {
margin: 0;
}
.searchbar {
overflow: hidden;
background-color: #272727;
position: fixed;
top: 0;
width: 100%;
font-weight: bold;
text-align: center;
line-height: 30px;
z-index: 1;
}
.main {
padding: 16px;
margin-top: 20px;
text-align: center;
}
.banbox {
position: relative;
width: 90%;
display: table;
flex-direction: column;
border: 1px solid #161616;
margin-right: auto;
margin-left: auto;
margin-bottom: 10px;
border-radius: 3px;
}
.header {
width: 100%;
background-color:rgba(0,0,0,0.3);
}
.container {
display: table;
width: 100%;
}
.reason {
display: table-cell;
width: 90%;
}
.edit {
display: table-cell;
width: 10%;
}
.banned {
background-color:#ff5555;
}
.unbanned {
background-color:#00b75c;
}

View File

@@ -1077,7 +1077,6 @@
#include "code\modules\admin\admin_verbs.dm" #include "code\modules\admin\admin_verbs.dm"
#include "code\modules\admin\adminmenu.dm" #include "code\modules\admin\adminmenu.dm"
#include "code\modules\admin\antag_panel.dm" #include "code\modules\admin\antag_panel.dm"
#include "code\modules\admin\banjob.dm"
#include "code\modules\admin\chat_commands.dm" #include "code\modules\admin\chat_commands.dm"
#include "code\modules\admin\check_antagonists.dm" #include "code\modules\admin\check_antagonists.dm"
#include "code\modules\admin\create_mob.dm" #include "code\modules\admin\create_mob.dm"
@@ -1088,17 +1087,16 @@
#include "code\modules\admin\holder2.dm" #include "code\modules\admin\holder2.dm"
#include "code\modules\admin\ipintel.dm" #include "code\modules\admin\ipintel.dm"
#include "code\modules\admin\IsBanned.dm" #include "code\modules\admin\IsBanned.dm"
#include "code\modules\admin\NewBan.dm"
#include "code\modules\admin\permissionedit.dm" #include "code\modules\admin\permissionedit.dm"
#include "code\modules\admin\player_panel.dm" #include "code\modules\admin\player_panel.dm"
#include "code\modules\admin\secrets.dm" #include "code\modules\admin\secrets.dm"
#include "code\modules\admin\sound_emitter.dm" #include "code\modules\admin\sound_emitter.dm"
#include "code\modules\admin\sql_ban_system.dm"
#include "code\modules\admin\sql_message_system.dm" #include "code\modules\admin\sql_message_system.dm"
#include "code\modules\admin\stickyban.dm" #include "code\modules\admin\stickyban.dm"
#include "code\modules\admin\team_panel.dm" #include "code\modules\admin\team_panel.dm"
#include "code\modules\admin\topic.dm" #include "code\modules\admin\topic.dm"
#include "code\modules\admin\whitelist.dm" #include "code\modules\admin\whitelist.dm"
#include "code\modules\admin\DB_ban\functions.dm"
#include "code\modules\admin\verbs\adminhelp.dm" #include "code\modules\admin\verbs\adminhelp.dm"
#include "code\modules\admin\verbs\adminjump.dm" #include "code\modules\admin\verbs\adminjump.dm"
#include "code\modules\admin\verbs\adminpm.dm" #include "code\modules\admin\verbs\adminpm.dm"