From ca1412bcefae88b69e3a6420186bcdb6461736b2 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Mon, 20 Feb 2017 22:45:00 -0600 Subject: [PATCH] Progress: continuing development, more documentation and database work Begin working on the database for the reservation program. Write some documentation. I am just starting to get work done on adding error messages (multi-lingual friendly at that). Many other changes. --- common/base/classes/base_access.php | 10 +- common/base/classes/base_charset.php | 6 +- common/base/classes/base_cookie.php | 48 +-- common/base/classes/base_error.php | 305 +++++++++------- .../base/classes/base_error_messages_english.php | 61 ++++ common/base/classes/base_markup.php | 7 +- common/base/classes/base_return.php | 52 +-- common/base/classes/base_session.php | 4 +- database/sql/reservation/base-associations.sql | 95 +++++ database/sql/reservation/base-cache.sql | 14 - database/sql/reservation/base-content.sql | 14 - database/sql/reservation/base-content_type.sql | 14 - database/sql/reservation/base-fields.sql | 88 +++++ database/sql/reservation/base-first.sql | 6 +- database/sql/reservation/base-groups.sql | 136 ++++++++ database/sql/reservation/base-log_groups.sql | 107 ++++++ database/sql/reservation/base-log_problems.sql | 87 +++++ .../{base-logs.sql => base-log_types.sql} | 388 +++------------------ database/sql/reservation/base-log_users.sql | 247 +++++++++++++ database/sql/reservation/base-main.sql | 105 +++++- database/sql/reservation/base-requests.sql | 153 ++++++++ database/sql/reservation/base-statistics.sql | 8 +- database/sql/reservation/base-structure.sql | 14 - database/sql/reservation/base-users.sql | 84 ++++- documentation/access_roles.txt | 87 +++++ documentation/database.txt | 48 +++ program/reservation/reservation_database.php | 2 +- 27 files changed, 1586 insertions(+), 604 deletions(-) create mode 100644 common/base/classes/base_error_messages_english.php create mode 100644 database/sql/reservation/base-associations.sql delete mode 100644 database/sql/reservation/base-cache.sql delete mode 100644 database/sql/reservation/base-content.sql delete mode 100644 database/sql/reservation/base-content_type.sql create mode 100644 database/sql/reservation/base-fields.sql create mode 100644 database/sql/reservation/base-groups.sql create mode 100644 database/sql/reservation/base-log_groups.sql create mode 100644 database/sql/reservation/base-log_problems.sql rename database/sql/reservation/{base-logs.sql => base-log_types.sql} (51%) create mode 100644 database/sql/reservation/base-log_users.sql create mode 100644 database/sql/reservation/base-requests.sql delete mode 100644 database/sql/reservation/base-structure.sql create mode 100644 documentation/access_roles.txt create mode 100644 documentation/database.txt diff --git a/common/base/classes/base_access.php b/common/base/classes/base_access.php index ee7bfea..93e3f17 100644 --- a/common/base/classes/base_access.php +++ b/common/base/classes/base_access.php @@ -104,8 +104,12 @@ class c_base_roles { * FALSE with error bit set is returned on error. */ public function set_role($role, $value) { - if (!is_int($role) || !is_bool($value)) { - return c_base_return_error::s_false(); + if (!is_int($role)) { + return c_base_return_error::s_false(c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'role')), i_base_error_messages::INVALID_ARGUMENT); + } + + if (!is_bool($value)) { + return c_base_return_error::s_false(c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'value')), i_base_error_messages::INVALID_ARGUMENT); } if ($role === self::NONE) { @@ -174,7 +178,7 @@ class c_base_roles { */ public function get_role($role) { if (!is_int($role)) { - return c_base_return_error::s_false(); + return c_base_return_error::s_false(c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'role')), i_base_error_messages::INVALID_ARGUMENT); } if ($role === self::NONE) { diff --git a/common/base/classes/base_charset.php b/common/base/classes/base_charset.php index e1e8383..0e978d1 100644 --- a/common/base/classes/base_charset.php +++ b/common/base/classes/base_charset.php @@ -42,7 +42,7 @@ class c_base_charset { */ public static function s_is_valid($charset) { if (!is_int($charset)) { - return c_base_return_error::s_false(); + return c_base_return_error::s_false(c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'charset')), i_base_error_messages::INVALID_ARGUMENT)); } if ($charset < self::ASCII || $charset > self::ISO_8859_16) { @@ -64,7 +64,7 @@ class c_base_charset { */ public static function s_to_string($charset) { if (!is_int($charset)) { - return c_base_return_error::s_false(); + return c_base_return_error::s_false(c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'charset')), i_base_error_messages::INVALID_ARGUMENT)); } switch ($charset) { @@ -110,6 +110,6 @@ class c_base_charset { return c_base_return_string::s_new('ISO-8859-16'); } - return c_base_return_error::s_false(); + return c_base_return_error::s_false(c_base_error::s_log(NULL, array('arguments' => array(':operation_name' => __CLASS__ . '::' . __FUNCTION__)), i_base_error_messages::OPERATION_FAILURE)); } } diff --git a/common/base/classes/base_cookie.php b/common/base/classes/base_cookie.php index f1d0e20..89d7daf 100644 --- a/common/base/classes/base_cookie.php +++ b/common/base/classes/base_cookie.php @@ -103,11 +103,11 @@ class c_base_cookie extends c_base_return_array { */ public function set_name($name) { if (!is_string($name) || empty($name)) { - return c_base_return_error::s_false(); + return c_base_return_error::s_false(c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'name')), i_base_error_messages::INVALID_ARGUMENT)); } if (mb_strlen($name) == 0 || preg_match('/^(\w|-)+$/iu', $name) != 1) { - return c_base_return_error::s_false(); + return c_base_return_error::s_false(c_base_error::s_log(NULL, array('arguments' => array(':format_name' => 'name')), i_base_error_messages::INVALID_FORMAT)); } $this->name = preg_replace('/(^\s+)|(\s+$)/us', '', rawurlencode($name)); @@ -138,7 +138,7 @@ class c_base_cookie extends c_base_return_array { */ public function set_secure($secure) { if (!is_bool($secure)) { - return c_base_return_error::s_false(); + return c_base_return_error::s_false(c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'secure')), i_base_error_messages::INVALID_ARGUMENT)); } $this->secure = $secure; @@ -180,15 +180,15 @@ class c_base_cookie extends c_base_return_array { */ public function set_expires($expires) { if (!is_null($expires) && (!is_int($expires) || $this->expires < 0)) { - if (is_string($max_age) && is_numeric($expires)) { + if (is_string($this->max_age) && is_numeric($expires)) { $expires = (int) $expires; if ($expires < 0) { - return c_base_return_error::s_false(); + return c_base_return_error::s_false(c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'expires')), i_base_error_messages::INVALID_ARGUMENT)); } } else { - return c_base_return_error::s_false(); + return c_base_return_error::s_false(c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'expires')), i_base_error_messages::INVALID_ARGUMENT)); } } @@ -238,11 +238,11 @@ class c_base_cookie extends c_base_return_array { $max_age = (int) $max_age; if ($max_age < 0) { - return c_base_return_error::s_false(); + return c_base_return_error::s_false(c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'max_age')), i_base_error_messages::INVALID_ARGUMENT)); } } else { - return c_base_return_error::s_false(); + return c_base_return_error::s_false(c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'max_age')), i_base_error_messages::INVALID_ARGUMENT)); } } @@ -279,14 +279,14 @@ class c_base_cookie extends c_base_return_array { */ public function set_path($path) { if (!is_string($path) || empty($path)) { - return c_base_return_error::s_false(); + return c_base_return_error::s_false(c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'path')), i_base_error_messages::INVALID_ARGUMENT)); } // sanitize the path string, only allowing the path portion of the url. $parsed = parse_url($path, PHP_URL_PATH); if ($parsed === FALSE) { unset($parsed); - return c_base_return_error::s_false(); + return c_base_return_error::s_false(c_base_error::s_log(NULL, array('arguments' => array(':operation_name' => 'parse_url(path)')), i_base_error_messages::OPERATION_FAILURE)); } $this->path = preg_replace('/(^\s+)|(\s+$)/us', '', $parsed); @@ -321,14 +321,14 @@ class c_base_cookie extends c_base_return_array { */ public function set_domain($domain) { if (!is_string($domain) || empty($domain)) { - return c_base_return_error::s_false(); + return c_base_return_error::s_false(c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'domain')), i_base_error_messages::INVALID_ARGUMENT); } // sanitize the domain string, only allowing the host portion of the url. $parsed = parse_url('stub://' . $domain, PHP_URL_HOST); if ($parsed === FALSE) { unset($parsed); - return c_base_return_error::s_false(); + return c_base_return_error::s_false(c_base_error::s_log(NULL, array('arguments' => array(':operation_name' => 'parse_url(stub://domain, PHP_URL_HOST)')), i_base_error_messages::OPERATION_FAILURE); } $this->domain = preg_replace('/(^\s+)|(\s+$)/us', '', $parsed); @@ -361,7 +361,7 @@ class c_base_cookie extends c_base_return_array { */ public function set_http_only($http_only) { if (!is_bool($http_only)) { - return c_base_return_error::s_false(); + return c_base_return_error::s_false(c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'http_only')), i_base_error_messages::INVALID_ARGUMENT); } $this->http_only = $http_only; @@ -397,7 +397,7 @@ class c_base_cookie extends c_base_return_array { */ public function set_first_only($first_only) { if (!is_bool($first_only)) { - return c_base_return_error::s_false(); + return c_base_return_error::s_false(c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'first_only')), i_base_error_messages::INVALID_ARGUMENT); } $this->first_only = $first_only; @@ -435,7 +435,7 @@ class c_base_cookie extends c_base_return_array { */ public function set_data($data) { if (!is_array($data)) { - return c_base_return_error::s_false(); + return c_base_return_error::s_false(c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'data')), i_base_error_messages::INVALID_ARGUMENT); } $this->data = $data; @@ -482,8 +482,12 @@ class c_base_cookie extends c_base_return_array { * @see: header() */ public function do_push($checksum = TRUE) { - if (is_null($this->name) || is_null($this->data)) { - return c_base_return_error::s_false(); + if (is_null($this->name)) { + return c_base_return_error::s_false(c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'name')), i_base_error_messages::INVALID_ARGUMENT); + } + + if (is_null($this->data)) { + return c_base_return_error::s_false(c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'data')), i_base_error_messages::INVALID_ARGUMENT); } if ($checksum) { @@ -492,7 +496,7 @@ class c_base_cookie extends c_base_return_array { if (is_null($this->data['checksum'])) { unset($this->data['checksum']); - return c_base_return_error::s_false(); + return c_base_return_error::s_false(c_base_error::s_log(NULL, array('arguments' => array(':operation_name' => 'this->p_build_checksum()')), i_base_error_messages::OPERATION_FAILURE); } } @@ -500,7 +504,7 @@ class c_base_cookie extends c_base_return_array { $json = json_encode($this->data); if ($json === FALSE) { unset($json); - return c_base_return_error::s_false(); + return c_base_return_error::s_false(c_base_error::s_log(NULL, array('arguments' => array(':operation_name' => 'json_encode(this->data)')), i_base_error_messages::OPERATION_FAILURE); } $data = rawurlencode(preg_replace('/(^\s+)|(\s+$)/us', '', $json)); @@ -599,7 +603,7 @@ class c_base_cookie extends c_base_return_array { unset($json); if ($data === FALSE) { - return c_base_return_error::s_false(); + return c_base_return_error::s_false(c_base_error::s_log(NULL, array('arguments' => array(':operation_name' => 'json_decode(json, TRUE)')), i_base_error_messages::OPERATION_FAILURE); } $this->data = $data; @@ -636,7 +640,7 @@ class c_base_cookie extends c_base_return_array { */ public function validate() { if (!is_array($this->data)) { - return c_base_return_error::s_false(); + return c_base_return_error::s_false(c_base_error::s_log(NULL, array('arguments' => array(':variable_name' => 'this->data')), i_base_error_messages::INVALID_VARIABLE); } if (!array_key_exists('checksum', $this->data)) { @@ -671,7 +675,7 @@ class c_base_cookie extends c_base_return_array { } unset($checksum); - return c_base_return_error::s_false(); + return c_base_return_error::s_false(c_base_error::s_log(NULL, array('arguments' => array(':operation_name' => 'this->p_build_checksum()')), i_base_error_messages::OPERATION_FAILURE); } /** diff --git a/common/base/classes/base_error.php b/common/base/classes/base_error.php index 829e500..cd1e5e4 100644 --- a/common/base/classes/base_error.php +++ b/common/base/classes/base_error.php @@ -4,90 +4,87 @@ * Provides a class for managing return values. */ -/* - const KERNEL = 0; - const USER = 1; - const MAIL = 2; - const DAEMON = 3; - const SECURITY = 4; - const MESSAGES = 5; - const PRINTER = 6; - const NETWORK = 7; - const UUCP = 8; - const CLOCK = 9; - const AUTHORIZATION = 10; - const FTP = 11; - const NTP = 12; - const AUDIT = 13; - const ALERT = 14; - const CRON = 15; - const LOCAL_0 = 16; - const LOCAL_1 = 17; - const LOCAL_2 = 18; - const LOCAL_3 = 19; - const LOCAL_4 = 20; - const LOCAL_5 = 21; - const LOCAL_6 = 22; - const LOCAL_7 = 23; -*/ - /** * A generic class for managing errors. * * This class is a dependency of classes provided by base_return.php. - * Therefore, it is an exception case to the use of base_return classes as a return value. + * Therefore, it is an exception case to the use of base_return classes as a return value and must instead return raw/native PHP values. * - * @todo: write this based on my cf_error code. + * This provides a custom facility for syslog/openlog calls so that a 'none' facility can be supported. */ class c_base_error { - const EMERGENCY = 0; - const ALERT = 1; - const CRITICAL = 2; - const ERROR = 3; - const WARNING = 4; - const NOTICE = 5; - const INFORMATIONAL = 6; - const DEBUG = 7; - const UNKNOWN = 8; + const SEVERITY_NONE = 0; + const SEVERITY_EMERGENCY = 1; + const SEVERITY_ALERT = 2; + const SEVERITY_CRITICAL = 3; + const SEVERITY_ERROR = 4; + const SEVERITY_WARNING = 5; + const SEVERITY_NOTICE = 6; + const SEVERITY_INFORMATIONAL = 7; + const SEVERITY_DEBUG = 8; + const SEVERITY_UNKNOWN = 9; + + const FACILITY_NONE = 0; + const FACILITY_KERNEL = 1; + const FACILITY_USER = 2; + const FACILITY_MAIL = 3; + const FACILITY_DAEMON = 4; + const FACILITY_SECURITY = 5; + const FACILITY_MESSAGES = 6; + const FACILITY_PRINTER = 7; + const FACILITY_NETWORK = 8; + const FACILITY_UUCP = 9; + const FACILITY_CLOCK = 10; + const FACILITY_AUTHORIZATION = 11; + const FACILITY_FTP = 12; + const FACILITY_NTP = 13; + const FACILITY_AUDIT = 14; + const FACILITY_ALERT = 15; + const FACILITY_CRON = 16; + const FACILITY_LOCAL_0 = 17; + const FACILITY_LOCAL_1 = 18; + const FACILITY_LOCAL_2 = 19; + const FACILITY_LOCAL_3 = 20; + const FACILITY_LOCAL_4 = 21; + const FACILITY_LOCAL_5 = 22; + const FACILITY_LOCAL_6 = 23; + const FACILITY_LOCAL_7 = 24; const DEFAULT_BACKTRACE_LIMIT = 4; - private $name; private $message; private $details; private $severity; private $limit; private $backtrace; private $code; - private $reported; + private $ignore_arguments; /** * Class constructor. */ public function __construct() { - $this->name = NULL; $this->message = NULL; $this->details = NULL; $this->severity = NULL; - $this->limit = NULL; - $this->backtrace = NULL; + $this->limit = self::DEFAULT_BACKTRACE_LIMIT; + $this->backtrace = array(); $this->code = NULL; - $this->reported = NULL; + $this->ignore_arguments = TRUE; } /** * Class destructor. */ public function __destruct() { - unset($this->name); unset($this->message); unset($this->details); unset($this->severity); unset($this->limit); unset($this->backtrace); unset($this->code); - unset($this->reported); + unset($this->ignore_arguments); } /** @@ -96,11 +93,6 @@ class c_base_error { * This will silently ignore invalid arguments, with the exception of the reporting controls. * For reporting information, use self::get_reporting(). * - * @todo: this is incomplete. - * - * @param string|null $name - * (optional) The name of something associated with a problem. - * This is often a variable name or a function name. * @param string|null $message * (optional) A message string describing the problem, in some manner. * @param array|null $details @@ -109,33 +101,20 @@ class c_base_error { * (optional) An integer identifying the message in some manner. * @param int|null $severity * (optional) A number representing the severity level. - * The c_base_error constants, such as EMERGENCY or ERROR should be use here. - * This defaults to: self::ERROR. + * The c_base_error constants, such as SEVERITY_SEVERITY_EMERGENCY or SEVERITY_SEVERITY_ERROR should be use here. * @param int|bool|null $limit * (optional) A number representing the backtrace limit. * If set to FALSE, then no backtrace is generated. - * @param bool $report - * (optional) If TRUE, then report the error using the appropriate methods. - * @fixme: it would probably be best to make this an object that knows how to report so that the object can do what it needs to do. * * @return c_base_error * Always returns a newly created c_base_error object. * No error status is ever returned. - * - * @see: self::get_reporting() */ - public static function s_log($name = NULL, $message = NULL, $details = NULL, $code = NULL, $severity = NULL, $limit = NULL, $report = TRUE) { + public static function s_log($message = NULL, $details = NULL, $code = NULL, $severity = NULL, $limit = NULL) { $class = __CLASS__; $entry = new $class(); unset($class); - if (is_string($name)) { - $entry->set_name($name); - } - elseif (is_null($this->name)) { - $entry->set_name(''); - } - if (is_string($message)) { $entry->set_message($message); } @@ -157,63 +136,24 @@ class c_base_error { $entry->set_code(0); } - if (is_int($severity) && $severity >= self::EMERGENCY && $severity < self::UNKNOWN) { + if (is_int($severity) && $severity >= self::SEVERITY_EMERGENCY && $severity < self::SEVERITY_UNKNOWN) { $entry->set_severity($severity); } elseif (is_null($this->message)) { - $entry->set_severity(self::ERROR); + $entry->set_severity(self::SEVERITY_ERROR); } - if ($limit === FALSE || (is_int($limit) && $limit >= 0)) { + if (is_int($limit) && $limit >= 0) { $entry->set_limit($limit); } - elseif (is_null($this->limit)) { - $entry->set_limit(self::DEFAULT_BACKTRACE_LIMIT); - } - // @todo: call self::p_backtrace() accordingly. - - if (is_bool($report) && $report) { - // @todo: use the report object to report the problem. - // @fixme: this is setup as a bool, but I know I need to create and use a report object (which has yet to be created). - $this->reported = NULL; - } - else { - $this->reported = NULL; - } + // build the backtrace, but ignore this function call when generating. + $this->set_backtrace(1); return $entry; } /** - * Assign an error name string. - * - * @param string $name - * An error name string - * - * @return bool - * TRUE on success, FALSE otherwise. - */ - public function set_name($name) { - if (!is_string($name)) { - return FALSE; - } - - $this->name = $name; - } - - /** - * Returns the assigned name. - * - * @return string|null - * A name to associate with the error, such as a variable or function name. - * NULL is returned if not defined. - */ - public function get_name() { - return $this->name; - } - - /** * Assign an error message string. * * @param string $message @@ -243,6 +183,8 @@ class c_base_error { /** * Assigns the details array. * + * The details array is defined by the caller and may have any structure, so long as it is an array. + * * @param array $details * An array of details. * @@ -275,7 +217,7 @@ class c_base_error { * * @param int $severity * A severity integer, representing the severity level. - * Such as self::ERROR. + * Such as self::SEVERITY_ERROR. */ public function set_severity($severity) { if (!is_int($severity) || $severity < 0 || $severity > 7) { @@ -291,11 +233,11 @@ class c_base_error { * * @return int * The currently assigned severity level. - * This defaults to self::ERROR when undefined. + * This defaults to self::SEVERITY_ERROR when undefined. */ public function get_severity() { if (is_null($this->severity)) { - $this->severity = self::ERROR; + $this->severity = self::SEVERITY_ERROR; } return $this->severity; @@ -312,7 +254,7 @@ class c_base_error { * @see: c_base_error::set_backtrace() */ public function set_limit($limit) { - if ($limit !== FALSE || !is_int($limit) || $limit < 0) { + if ($limit !== FALSE && (!is_int($limit) || $limit < 0)) { return FALSE; } @@ -324,13 +266,14 @@ class c_base_error { * Returns the currently assigned limit. * * @return int|bool - * The currently assigned limit. + * The currently assigned limit integer. + * FALSE is returned if backtracing is disabled. * This defaults to self::DEFAULT_BACKTRACE_LIMIT. * * @see: c_base_error::set_backtrace() */ public function get_limit() { - if ($limit !== FALSE || !is_int($limit) || $limit < 0) { + if ($limit !== FALSE && (!is_int($limit) || $limit < 0)) { $this->limit = self::DEFAULT_BACKTRACE_LIMIT; } @@ -343,13 +286,30 @@ class c_base_error { * This is auto-performed by the class. * All settings should be assigned prior to utilizing this. * + * @param int|false|null $count + * (optional) assign a backtrace ignore account. + * This is useful for when you have other debugging functions being called prior to this that should not appear in the backtrace. + * This function auto-adds 1 to account for this function call to this value. + * If set to FALSE, the backtrace will be reset to an empty array. + * * @return bool * TRUE on success, FALSE otherwise. * * @see: c_base_error::set_limit() */ - public function set_backtrace() { - $this->p_backtrace(1); + public function set_backtrace($count = NULL) { + if (is_null($count)) { + $this->p_backtrace(1); + } + elseif (is_int($count)) { + $this->p_backtrace($count + 1); + } + elseif ($count === FALSE) { + $this->backtrace = array(); + } + else { + return FALSE; + } return TRUE; } @@ -357,8 +317,8 @@ class c_base_error { /** * Returns the backtrace object. * - * @return object|null - * A populate backtrace object or NULL if no backtrace is defined. + * @return array|null + * A populate backtrace array of objects or NULL if no backtrace is defined. * * @see: c_base_error::set_limit() */ @@ -432,6 +392,34 @@ class c_base_error { } /** + * Assign an error ignore arguments boolean. + * + * @param bool $ignore_arguments + * The ignore arguments boolean. + * + * @return bool + * TRUE on success, FALSE otherwise. + */ + public function set_ignore_arguments($ignore_arguments) { + if (!is_bool($ignore_arguments)) { + return FALSE; + } + + $this->ignore_arguments = $ignore_arguments; + } + + /** + * Returns the assigned ignore arguments boolean. + * + * @return bool|null + * A boolean representing whether or not to get the arguments when building the backtrace. + * NULL is returned if not defined. + */ + public function get_ignore_arguments() { + return $this->ignore_arguments; + } + + /** * Build the debug backtrace. * * This will not include this function in the backtrace. @@ -446,30 +434,79 @@ class c_base_error { * @see: debug_backtrace() */ private function p_backtrace($count = 0) { + $this->backtrace = array(); + + // when limit is set to FALSE, backtrace is disabled. if ($this->limit === FALSE) { - $this->backtrace = NULL; return; } + if (is_null($this->limit)) { + $this->limit = self::DEFAULT_BACKTRACE_LIMIT; + } + // Make sure unnecessary backtrace logs are not part of the count. $limit = $this->limit; - if ($this->limit > 0) { - $limit = $this->limit + 1; - - if (is_int($count) && $count > 0) { - $limit += $count; - } + if ($limit > 0) { + $limit += $count; } - $this->backtrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, $limit); + if ($this->ignore_arguments) { + $backtrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT | DEBUG_BACKTRACE_IGNORE_ARGS, $limit); + } + else { + $backtrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, $limit); + } unset($limit); - // Remove unecessary backtrace logs. - $count = $count + 1; - $i = 0; - for (; $i < $count; $i++) { - array_shift($this->backtrace); + if (is_array($backtrace)) { + // Remove the call to the debug_backtrace() from the backtrace log and this function call. + $total = $count + 2; + $i = 0; + for (; $i < $total; $i++) { + array_shift($backtrace); + } + unset($i); + unset($total); + + $this->backtrace = $backtrace; } - unset($i); + unset($backtrace); } } + +/** + * A generic interface for providing basic error messages. + * + * This is for generating common error messages. + * + * @warning: this will be constantly updated and reogranized as the project is being developed. + * it is expected that the number of codes will get very large. + * expect major changes. + * + * @see: http://www.loc.gov/standards/iso639-2/php/code_list.php + */ +interface i_base_error_messages { + const NONE = 0; + const ARGUMENT_INVALID = 1; + const OPERATION_FAILURE = 2; + const INVALID_FORMAT = 3; + const INVALID_VARIABLE = 4; + + + /** + * Returns a standard error message associated with the given code. + * + * @param int $code + * The error message code. + * @param bool $arguments + * (optional) When TRUE, argument placeholders are added. + * When FALSE, no placeholders are provided. + * All placeholders should begin with a single colon ':'. + * + * @return string + * An error message associated with the error code. + * An empty sting is returned for unsupported or unknown codes. + */ + static function s_get_message($code); +} diff --git a/common/base/classes/base_error_messages_english.php b/common/base/classes/base_error_messages_english.php new file mode 100644 index 0000000..f163772 --- /dev/null +++ b/common/base/classes/base_error_messages_english.php @@ -0,0 +1,61 @@ +attribute[$attribute]); + return new c_base_return_true(); + } + switch ($attribute) { case c_base_markup_attributes::ATTRIBUTE_NONE: - unset($this->attribute[$attribute]); return new c_base_return_true(); case c_base_markup_attributes::ATTRIBUTE_ABBR: diff --git a/common/base/classes/base_return.php b/common/base/classes/base_return.php index 8a197d8..5c4e6b2 100644 --- a/common/base/classes/base_return.php +++ b/common/base/classes/base_return.php @@ -1313,22 +1313,22 @@ class c_base_return_error { /** * Creates a return boolean TRUE with the error value populated. * - * @todo: this is incomplete because the base_error class is not yet written. - * - * @param todo|null $error - * (optional) a custom error setting. + * @param c_base_error|null $error + * (optional) a custom error. * * @return c_base_return_true * A c_base_return_true object with the error value populated. */ public static function s_true($error = NULL) { - $object_error = new c_base_error(); - $object_return = new c_base_return_true(); - $object_return->set_error($object_error); - if (!is_null($error)) { - // @todo: do something with the code. + if (is_null($error)) { + $object_error = new c_base_error(); + $object_return->set_error($object_error); + unset($object_error); + } + else { + $object_return->set_error($error); } return $object_return; @@ -1337,22 +1337,22 @@ class c_base_return_error { /** * Creates a return boolean TRUE with the error value populated. * - * @todo: this is incomplete because the base_error class is not yet written. - * - * @param todo|null $error + * @param c_base_error|null $error * (optional) a custom error setting. * * @return c_base_return_false * A c_base_return_true object with the error value populated. */ public static function s_false($error = NULL) { - $object_error = new c_base_error(); - $object_return = new c_base_return_false(); - $object_return->set_error($object_error); - if (!is_null($error)) { - // @todo: do something with the code. + if (is_null($error)) { + $object_error = new c_base_error(); + $object_return->set_error($object_error); + unset($object_error); + } + else { + $object_return->set_error($error); } return $object_return; @@ -1361,13 +1361,11 @@ class c_base_return_error { /** * Creates a return boolean TRUE with the error value populated. * - * @todo: this is incomplete because the base_error class is not yet written. - * * @param $value * A value to provide * @param $class * A custom class name. - * @param todo|null $error + * @param c_base_error|null $error * (optional) a custom error setting. * * @return c_base_return_false|c_base_return_value @@ -1379,16 +1377,18 @@ class c_base_return_error { return self::s_false($error); } - $object_error = new c_base_error(); - $object_return = new $class(); - $object_return->set_error($object_error); - $object_return->set_value($value); - if (!is_null($error)) { - // @todo: do something with the code. + if (is_null($error)) { + $object_error = new c_base_error(); + $object_return->set_error($object_error); + unset($object_error); + } + else { + $object_return->set_error($error); } + $object_return->set_value($value); return $object_return; } } diff --git a/common/base/classes/base_session.php b/common/base/classes/base_session.php index c1ed720..d3d71fa 100644 --- a/common/base/classes/base_session.php +++ b/common/base/classes/base_session.php @@ -18,7 +18,7 @@ require_once('common/base/classes/base_return.php'); */ class c_base_session { const PACKET_MAX_LENGTH = 8192; - const SOCKET_PATH_PREFIX = '/var/www/sockets/sessionize_accounts/'; + const SOCKET_PATH_PREFIX = '/programs/sockets/sessionize_accounts/'; const SOCKET_PATH_SUFFIX = '/sessions.socket'; const PASSWORD_CLEAR_TEXT_LENGTH = 2048; @@ -551,7 +551,7 @@ class c_base_session { return c_base_return_error::s_false(); } - $connected = socket_connect($this->socket, $this->socket_path, 0); + $connected = @socket_connect($this->socket, $this->socket_path, 0); if ($connected === FALSE) { unset($connected); diff --git a/database/sql/reservation/base-associations.sql b/database/sql/reservation/base-associations.sql new file mode 100644 index 0000000..170fe3e --- /dev/null +++ b/database/sql/reservation/base-associations.sql @@ -0,0 +1,95 @@ +/** Standardized SQL Structure - Content **/ +/** This depends on: base-fields.sql **/ +start transaction; + + + +/** Custom database specific settings (do this on every connection made) **/ +set bytea_output to hex; +set search_path to system,administers,managers,auditors,publishers,insurers,financers,reviewers,drafters,users,public; +set datestyle to us; + + + +/*** Associations ***/ +create table managers.t_associations ( + id bigint not null, + id_owner bigint not null, + id_group bigint, + id_coordinator bigint not null, + + name_machine varchar(128) not null, + name_machine_owner varchar(128) not null, + name_machine_coordinator varchar(128) not null, + name_human varchar(256) not null, + + is_deleted boolean default false not null, + + date_created timestamp default localtimestamp not null, + date_changed timestamp default localtimestamp not null, + date_deleted timestamp, + + field_affiliation bigint not null, + field_classification bigint not null, + + constraint cu_associations_id unique (id), + constraint cu_associations_name_machine unique (name_machine), + + constraint cc_associations_id check (id > 0), + + constraint cf_associations_id_owner foreign key (id_owner, name_machine_owner) references administers.t_users (id, name_machine) on delete restrict on update cascade, + constraint cf_associations_id_coordinator foreign key (id_coordinator, name_machine_coordinator) references administers.t_users (id, name_machine) on delete restrict on update cascade, + constraint cf_associations_group foreign key (id_group) references managers.t_groups (id) on delete restrict on update cascade, + constraint cf_associations_field_affiliation foreign key (field_affiliation) references managers.t_field_affiliations (id) on delete restrict on update cascade, + constraint cf_associations_field_classification foreign key (field_classification) references managers.t_field_classifications (id) on delete restrict on update cascade +); + +create sequence managers.s_associations_id owned by managers.t_associations.id; +alter table managers.t_associations alter column id set default nextval('managers.s_associations_id'::regclass); + +grant select,insert,update on managers.t_associations to reservation_users_administer; +grant select,insert,update on managers.t_associations to reservation_users_manager; +grant select on managers.t_associations to reservation_users_auditor; +grant select,usage on managers.s_associations_id to reservation_users_administer; +grant select,usage on managers.s_associations_id to reservation_users_manager; +grant usage on managers.s_associations_id to reservation_users; + + +/*** provide current user access to their own information ***/ +create view users.v_associations_self with (security_barrier=true) as + with allowed_groups as (select id from users.v_groups_self) + select id, id_owner, id_group, id_coordinator, name_machine, name_machine_owner, name_machine_cooordinator, name_human, date_created, date_changed, field_affiliation, field_classification from managers.t_associations + where is_deleted is not true and ((group_id is null and (name_machine_owner)::text = (current_user)::text) or group_id in (select * from allowed_groups)); + +grant select on users.v_associations_self to reservation_users; + + +/*** provide current user access to associations who they are assigned as the coordinator of ***/ +create view users.v_associations_coordinator_self with (security_barrier=true) as + with allowed_groups as (select id from users.v_groups_self) + select id, id_owner, id_group, id_coordinator, name_machine, name_machine_owner, name_machine_cooordinator, name_human, date_created, date_changed, field_affiliation, field_classification from managers.t_associations + where is_deleted is not true and (name_machine_coordinator)::text = (current_user)::text); + +grant select on users.v_associations_coordinator_self to reservation_users; + + +/** provide current user access to insert their own associations **/ +create view users.v_associations_self_insert with (security_barrier=true) as + with allowed_groups as (select id from users.v_groups_self) + select id, id_owner, id_group, id_coordinator, name_machine, name_machine_owner, name_machine_cooordinator, name_human, field_affiliation, field_classification from managers.t_associations + where is_deleted is not true and (group_id is null or group_id in (select * from allowed_groups)) and (name_machine_owner)::text = (current_user)::text + with check option; + +grant insert on users.v_associations_self_insert to reservation_users; + + +/** provide current user access to update their own associations **/ +create view public.v_associations_self_update with (security_barrier=true) as + with allowed_groups as (select id from users.v_groups_self) + select id, id_group, id_coordinator, name_machine, name_machine_cooordinator, name_human, date_changed, field_affiliation, field_classification from managers.t_associations + where is_deleted is not true and (group_id is null or group_id in (select * from allowed_groups)) and date_changed = localtimestamp and (name_machine_owner)::text = (current_user)::text + with check option; + +grant insert on users.v_associations_self_update to reservation_users; + +commit transaction; diff --git a/database/sql/reservation/base-cache.sql b/database/sql/reservation/base-cache.sql deleted file mode 100644 index 6947a80..0000000 --- a/database/sql/reservation/base-cache.sql +++ /dev/null @@ -1,14 +0,0 @@ -/** Standardized SQL Structure - Cache **/ -/** This depends on: base-main.sql **/ -start transaction; - - - -/** Custom database specific settings (do this on every connection made) **/ -set bytea_output to hex; -set search_path to system,administers,managers,publishers,insurers,financers,reviewers,drafters,users,public; -set datestyle to us; - - - -commit transaction; diff --git a/database/sql/reservation/base-content.sql b/database/sql/reservation/base-content.sql deleted file mode 100644 index f45d3db..0000000 --- a/database/sql/reservation/base-content.sql +++ /dev/null @@ -1,14 +0,0 @@ -/** Standardized SQL Structure - Content **/ -/** This depends on: base-structure.sql **/ -start transaction; - - - -/** Custom database specific settings (do this on every connection made) **/ -set bytea_output to hex; -set search_path to system,administers,managers,publishers,insurers,financers,reviewers,drafters,users,public; -set datestyle to us; - - - -commit transaction; diff --git a/database/sql/reservation/base-content_type.sql b/database/sql/reservation/base-content_type.sql deleted file mode 100644 index 2a4e993..0000000 --- a/database/sql/reservation/base-content_type.sql +++ /dev/null @@ -1,14 +0,0 @@ -/** Standardized SQL Structure - Content **/ -/** This depends on: base-users.sql **/ -start transaction; - - - -/** Custom database specific settings (do this on every connection made) **/ -set bytea_output to hex; -set search_path to system,administers,managers,publishers,insurers,financers,reviewers,drafters,users,public; -set datestyle to us; - - - -commit transaction; diff --git a/database/sql/reservation/base-fields.sql b/database/sql/reservation/base-fields.sql new file mode 100644 index 0000000..acce227 --- /dev/null +++ b/database/sql/reservation/base-fields.sql @@ -0,0 +1,88 @@ +/** Standardized SQL Structure - Content **/ +/** This depends on: base-users.sql **/ +start transaction; + + + +/** Custom database specific settings (do this on every connection made) **/ +set bytea_output to hex; +set search_path to system,administers,managers,auditors,publishers,insurers,financers,reviewers,drafters,users,public; +set datestyle to us; + + + +/*** Field: Affiliations ***/ +create table managers.t_field_affiliations ( + id bigint not null, + id_external bigint, + + name_machine varchar(128) not null, + name_human varchar(256) not null, + + is_deleted boolean default false not null, + + date_created timestamp default localtimestamp not null, + date_changed timestamp default localtimestamp not null, + date_deleted timestamp, + + constraint cu_field_affiliations_id unique (id), + constraint cu_field_affiliations_name_machine unique (name_machine), + + constraint cc_field_affiliations_id check (id > 0) +); + +create sequence managers.s_field_affiliations_id owned by managers.t_field_affiliations.id; +alter table managers.t_field_affiliations alter column id set default nextval('managers.s_field_affiliations_id'::regclass); + +grant select,insert,update on managers.t_field_affiliations to reservation_users_administer; +grant select,insert,update on managers.t_field_affiliations to reservation_users_manager; +grant select on managers.t_field_affiliations to reservation_users_auditor; +grant select,usage on managers.s_field_affiliations_id to reservation_users_administer; +grant select,usage on managers.s_field_affiliations_id to reservation_users_manager; + +create view users.v_field_affiliations with (security_barrier=true) as + select id, id_external, name_machine, name_human from managers.t_field_affiliations + where is_deleted is false; + +grant select on users.v_field_affiliations to reservation_users; + + + +/*** Field: Classifications ***/ +create table managers.t_field_classifications ( + id bigint not null, + id_external bigint, + + name_machine varchar(128) not null, + name_human varchar(256) not null, + + is_deleted boolean default false not null, + + date_created timestamp default localtimestamp not null, + date_changed timestamp default localtimestamp not null, + date_deleted timestamp, + + constraint cu_field_classifications_id unique (id), + constraint cu_field_classifications_name_machine unique (name_machine), + + constraint cc_field_classifications_id check (id > 0) +); + +create sequence managers.s_field_classifications_id owned by managers.t_field_classifications.id; +alter table managers.t_field_classifications alter column id set default nextval('managers.s_field_classifications_id'::regclass); + +grant select,insert,update on managers.t_field_classifications to reservation_users_administer; +grant select,insert,update on managers.t_field_classifications to reservation_users_manager; +grant select on managers.t_field_classifications to reservation_users_auditor; +grant select,usage on managers.s_field_classifications_id to reservation_users_administer; +grant select,usage on managers.s_field_classifications_id to reservation_users_manager; + +create view users.v_field_classifications with (security_barrier=true) as + select id, id_external, name_machine, name_human from managers.t_field_classifications + where is_deleted is false; + +grant select on users.v_field_classifications to reservation_users; + +/** @todo: create all field types needed for f_requests fields **/ + +commit transaction; diff --git a/database/sql/reservation/base-first.sql b/database/sql/reservation/base-first.sql index 386a0fe..2bf5e64 100644 --- a/database/sql/reservation/base-first.sql +++ b/database/sql/reservation/base-first.sql @@ -9,6 +9,7 @@ create role reservation_users inherit nologin; create role reservation_users_administer inherit nologin; create role reservation_users_manager inherit nologin; +create role reservation_users_auditor inherit nologin; create role reservation_users_publisher inherit nologin; create role reservation_users_insurer inherit nologin; create role reservation_users_financer inherit nologin; @@ -17,6 +18,7 @@ create role reservation_users_drafter inherit nologin; grant reservation_users to reservation_users_administer with admin option; grant reservation_users to reservation_users_manager with admin option; +grant reservation_users to reservation_users_auditor; grant reservation_users to reservation_users_publisher; grant reservation_users to reservation_users_insurer; grant reservation_users to reservation_users_financer; @@ -25,6 +27,9 @@ grant reservation_users to reservation_users_drafter; grant reservation_users_manager to reservation_users_administer with admin option; +grant reservation_users_auditor to reservation_users_administer with admin option; +grant reservation_users_auditor to reservation_users_manager with admin option; + grant reservation_users_publisher to reservation_users_administer with admin option; grant reservation_users_publisher to reservation_users_manager with admin option; @@ -41,7 +46,6 @@ grant reservation_users_drafter to reservation_users_administer with admin optio grant reservation_users_drafter to reservation_users_manager with admin option; /** This is the role the database should use to connect to to perform system activity **/ -/** All users auto-created by the ldap helper should be creating users with this role. **/ create role reservation_user; grant reservation_users to reservation_user; diff --git a/database/sql/reservation/base-groups.sql b/database/sql/reservation/base-groups.sql new file mode 100644 index 0000000..72f317b --- /dev/null +++ b/database/sql/reservation/base-groups.sql @@ -0,0 +1,136 @@ +/** Standardized SQL Structure - Groups */ +/** This depends on: base-users.sql **/ +start transaction; + + + +/** Custom database specific settings (do this on every connection made) **/ +set bytea_output to hex; +set search_path to system,administers,managers,auditors,publishers,insurers,financers,reviewers,drafters,users,public; +set datestyle to us; + + + +/** Groups **/ +create table managers.t_groups ( + id bigint not null, + id_sort smallint not null default 0, + id_external bigint, + id_creator bigint not null, + id_manager bigint, + + name_machine varchar(128) not null, + name_machine_creator varchar(128) not null, + name_machine_manager varchar(128) not null, + name_human varchar(256) not null, + + date_created timestamp default localtimestamp not null, + date_changed timestamp default localtimestamp not null, + date_synced timestamp default localtimestamp not null, + date_deleted timestamp, + + is_deleted boolean default false not null, + is_locked boolean default false not null, + + settings json, + + constraint cp_groups_id primary key (id), + + constraint cc_groups_id check (id > 0), + constraint cc_groups_id_external check (id_external > 0), + + constraint cu_groups_id_external unique (id_external), + constraint cu_groups_name_machine unique (name_machine), + constraint cu_groups_user unique (id, name_machine), + + constraint cf_t_groups_creator foreign key (id_creator, name_machine_creator) references administers.t_users (id, name_machine) on delete restrict on update cascade, + constraint cf_t_groups_manager foreign key (id_manager, name_machine_manager) references administers.t_users (id, name_machine) on delete restrict on update cascade +); + +create sequence managers.s_groups_id owned by managers.t_groups.id; +alter table managers.t_groups alter column id set default nextval('managers.s_groups_id'::regclass); + +grant select,insert,update on managers.t_groups to reservation_users_administer; +grant select,insert,update on managers.t_groups to reservation_users_manager; +grant select on managers.t_groups to reservation_users_auditor; +grant select,usage on managers.s_groups_id to reservation_users_administer; +grant select,usage on managers.s_groups_id to reservation_users_manager; +grant usage on managers.s_groups_id to reservation_users; + +create index ci_groups_id_sort_a on managers.t_groups (id_sort) with (fillfactor = 100) where id_sort = 97; +create index ci_groups_id_sort_b on managers.t_groups (id_sort) with (fillfactor = 100) where id_sort = 98; +create index ci_groups_id_sort_c on managers.t_groups (id_sort) with (fillfactor = 100) where id_sort = 99; +create index ci_groups_id_sort_d on managers.t_groups (id_sort) with (fillfactor = 100) where id_sort = 100; +create index ci_groups_id_sort_e on managers.t_groups (id_sort) with (fillfactor = 100) where id_sort = 101; +create index ci_groups_id_sort_f on managers.t_groups (id_sort) with (fillfactor = 100) where id_sort = 102; +create index ci_groups_id_sort_g on managers.t_groups (id_sort) with (fillfactor = 100) where id_sort = 103; +create index ci_groups_id_sort_h on managers.t_groups (id_sort) with (fillfactor = 100) where id_sort = 104; +create index ci_groups_id_sort_i on managers.t_groups (id_sort) with (fillfactor = 100) where id_sort = 105; +create index ci_groups_id_sort_j on managers.t_groups (id_sort) with (fillfactor = 100) where id_sort = 106; +create index ci_groups_id_sort_k on managers.t_groups (id_sort) with (fillfactor = 100) where id_sort = 107; +create index ci_groups_id_sort_l on managers.t_groups (id_sort) with (fillfactor = 100) where id_sort = 108; +create index ci_groups_id_sort_m on managers.t_groups (id_sort) with (fillfactor = 100) where id_sort = 109; +create index ci_groups_id_sort_n on managers.t_groups (id_sort) with (fillfactor = 100) where id_sort = 110; +create index ci_groups_id_sort_o on managers.t_groups (id_sort) with (fillfactor = 100) where id_sort = 111; +create index ci_groups_id_sort_p on managers.t_groups (id_sort) with (fillfactor = 100) where id_sort = 112; +create index ci_groups_id_sort_q on managers.t_groups (id_sort) with (fillfactor = 100) where id_sort = 113; +create index ci_groups_id_sort_r on managers.t_groups (id_sort) with (fillfactor = 100) where id_sort = 114; +create index ci_groups_id_sort_s on managers.t_groups (id_sort) with (fillfactor = 100) where id_sort = 115; +create index ci_groups_id_sort_t on managers.t_groups (id_sort) with (fillfactor = 100) where id_sort = 116; +create index ci_groups_id_sort_u on managers.t_groups (id_sort) with (fillfactor = 100) where id_sort = 117; +create index ci_groups_id_sort_v on managers.t_groups (id_sort) with (fillfactor = 100) where id_sort = 118; +create index ci_groups_id_sort_w on managers.t_groups (id_sort) with (fillfactor = 100) where id_sort = 119; +create index ci_groups_id_sort_x on managers.t_groups (id_sort) with (fillfactor = 100) where id_sort = 120; +create index ci_groups_id_sort_y on managers.t_groups (id_sort) with (fillfactor = 100) where id_sort = 121; +create index ci_groups_id_sort_z on managers.t_groups (id_sort) with (fillfactor = 100) where id_sort = 122; + + + + +/** Groups to Users Association **/ +create table managers.t_groups_users ( + id_user bigint not null, + id_group bigint not null, + + name_machine_user varchar(128) not null, + + constraint cu_groups_id unique (id_user, id_group), + + constraint cf_t_groups_users_user foreign key (id_user, name_machine_user) references administers.t_users (id, name_machine) on delete cascade on update cascade, + constraint cf_t_groups_users_group foreign key (id_group) references managers.t_groups (id) on delete cascade on update cascade +); + +grant select,insert,update on managers.t_groups to reservation_users_administer; +grant select,insert,update on managers.t_groups to reservation_users_manager; +grant select on managers.t_groups to reservation_users_auditor; + + +/*** provide current user access to their own information ***/ +create view users.v_groups_self with (security_barrier=true) as + select g.id, g.id_sort, g.id_external, g.id_creator, g.id_manager, g.name_machine, g.name_human, g.is_locked, g.date_created, g.date_changed, g.date_synced, g.settings from managers.t_groups g + inner join managers.t_groups_users gu on g.id = gu.id_group + where g.is_deleted is not true and (gu.name_machine_user)::text = (current_user)::text; + +grant select on users.v_groups_self to reservation_users; + + +/*** provide group manages access to manage users assigned to their groups ***/ +create view users.v_groups_users_manage with (security_barrier=true) as + select gu.id_user, gu.id_group from managers.t_groups_users gu + inner join managers.t_groups g on g.id = gu.id_group + where g.is_deleted is not true and (gu.name_machine_manager)::text = (current_user)::text; + +grant select, insert, update, delete on users.v_groups_self to reservation_users; + + +/*** provide group manages access to manage users their groups ***/ +create view users.v_groups_manage with (security_barrier=true) as + select g.id, g.id_sort, g.id_external, g.name_machine, g.name_human, g.is_locked, g.date_changed, g.date_synced, g.settings from managers.t_groups g + inner join managers.t_groups_users gu on g.id = gu.id_group + where g.is_deleted is not true and date_changed = localtimestamp and (date_synced is null or date_synced = localtimestamp) and (gu.name_machine_user)::text = (current_user)::text; + +grant select, insert, update on users.v_groups_manage to reservation_users; + + + +commit transaction; diff --git a/database/sql/reservation/base-log_groups.sql b/database/sql/reservation/base-log_groups.sql new file mode 100644 index 0000000..5e91e4a --- /dev/null +++ b/database/sql/reservation/base-log_groups.sql @@ -0,0 +1,107 @@ +/** Standardized SQL Structure - Logs - Groups */ +/** This depends on: base-users.sql **/ +start transaction; + + + +/** Custom database specific settings (do this on every connection made) **/ +set bytea_output to hex; +set search_path to system,administers,managers,auditors,publishers,insurers,financers,reviewers,drafters,users,public; +set datestyle to us; + + + +/*** provide group activity logging ***/ +create table managers.t_log_groups ( + id bigint not null, + id_user bigint default 1 not null, + id_group bigint not null, + + name_machine_user varchar(128) not null, + + log_type bigint not null, + log_details json, + log_date timestamp default localtimestamp not null, + + constraint cp_log_groups_id primary key (id), + + constraint cc_log_groups_id check (id > 0), + + constraint cf_log_groups_id_user foreign key (id_user, name_machine_user) references administers.t_users (id, name_machine) on delete restrict on update cascade, + constraint cf_log_groups_id_group foreign key (id_group) references managers.t_groups (id) on delete restrict on update cascade, + constraint cf_log_groups_log_type foreign key (log_type) references managers.t_log_types (id) on delete restrict on update cascade, +); + +create sequence managers.s_log_groups_id owned by managers.t_log_groups.id; +alter table managers.t_log_groups alter column id set default nextval('managers.s_log_groups_id'::regclass); + +grant select on managers.t_log_groups to reservation_users_administer; +grant select on managers.t_log_groups to reservation_users_manager; +grant select on managers.t_log_groups to reservation_users_auditor; +grant select,usage on managers.s_log_groups_id to reservation_users_administer; +grant usage on managers.s_log_groups_id to reservation_users; + + +/** only allow select and insert for users when user id is current user **/ +create view users.v_log_groups_self with (security_barrier=true) as + gselect id, id_user, id_group, log_type, log_details, log_date from managers.t_log_groups + where (name_machine_user)::text = (current_user)::text; + +grant select on users.v_log_groups_self to reservation_users; + +create view users.v_log_groups_self_insert with (security_barrier=true) as + select id_user, id_group, name_machine_user, log_type, log_details from managers.t_log_groups + where (name_machine_user)::text = (current_user)::text + with check option; + +grant insert on users.v_log_groups_self_insert to reservation_users; + + + +/*** provide group user activity logging ***/ +create table managers.t_log_groups_users ( + id bigint not null, + id_user bigint default 1 not null, + id_group bigint not null, + + name_machine_user varchar(128) not null, + + log_type bigint not null, + log_date timestamp default localtimestamp not null, + + constraint cp_log_groups_id primary key (id), + + constraint cc_log_groups_id check (id > 0), + + constraint cf_log_groups_id_user foreign key (id_user, name_machine_user) references administers.t_users (id, name_machine) on delete restrict on update cascade, + constraint cf_log_groups_id_group foreign key (id_group) references managers.t_groups (id) on delete restrict on update cascade, + constraint cf_log_groups_log_type foreign key (log_type) references managers.t_log_types (id) on delete restrict on update cascade, +); + +create sequence managers.s_log_groups_users_id owned by managers.t_log_groups_users.id; +alter table managers.t_log_groups_users alter column id set default nextval('managers.s_log_groups_users_id'::regclass); + +grant select on managers.t_log_groups_users to reservation_users_administer; +grant select on managers.t_log_groups_users to reservation_users_manager; +grant select on managers.t_log_groups_users to reservation_users_auditor; +grant select,usage on managers.s_log_groups_users_id to reservation_users_administer; +grant usage on managers.s_log_groups_users_id to reservation_users; + + +/** only allow select and insert for users when user id is current user **/ +create view users.v_log_groups_users_self with (security_barrier=true) as + select id, id_user, id_group, log_type, log_date from managers.t_log_groups_users + where (name_machine_user)::text = (current_user)::text; + +grant select on users.v_log_groups_users_self to reservation_users; + +create view users.v_log_groups_users_self_insert with (security_barrier=true) as + select id_user, id_group, name_machine_user, log_type from managers.t_log_groups_users + where (name_machine_user)::text = (current_user)::text + with check option; + +grant insert on users.v_log_groups_users_self_insert to reservation_users; + + + +commit transaction; diff --git a/database/sql/reservation/base-log_problems.sql b/database/sql/reservation/base-log_problems.sql new file mode 100644 index 0000000..19ded9b --- /dev/null +++ b/database/sql/reservation/base-log_problems.sql @@ -0,0 +1,87 @@ +/** Standardized SQL Structure - Logs - Problems */ +/** This depends on: base-users.sql **/ +start transaction; + + + +/** Custom database specific settings (do this on every connection made) **/ +set bytea_output to hex; +set search_path to system,administers,managers,auditors,publishers,insurers,financers,reviewers,drafters,users,public; +set datestyle to us; + + + +/** Provide a log of problems, which are defined by the software. **/ +create table managers.t_log_problems ( + id bigint not null, + + name_machine varchar(128) not null, + name_human varchar(256) not null, + + date_created timestamp default localtimestamp not null, + date_changed timestamp default localtimestamp not null, + date_deleted timestamp, + + constraint cp_log_problems_id primary key (id), + + constraint cc_log_problems_id check (id > 0), + + constraint cu_log_problems_name_machine unique (name_machine) +); + +grant select on managers.t_log_activity to reservation_users_administer; +grant select on managers.t_log_activity to reservation_users_manager; +grant select on managers.t_log_activity to reservation_users_auditor; + + + +/** Provide a log of problems, associated with a given user. **/ +create table managers.t_log_problems_users ( + id_problem bigint not null, + id_user bigint not null, + + name_machine_user varchar(128) not null, + + date_created timestamp default localtimestamp not null, + date_changed timestamp default localtimestamp not null, + date_deleted timestamp, + + log_details json, + + constraint cp_log_problems_users_id primary key (id_problem, id_user), + + constraint cu_log_problems_users_name_machine unique (name_machine_user), + + constraint cf_log_problems_users_id_problem foreign key (id_problem) references managers.t_log_problems (id) on delete restrict on update cascade, + constraint cf_log_problems_users_id_user foreign key (id_user, name_machine_user) references administers.t_users (id, name_machine) on delete restrict on update cascade +); + +grant select,delete on managers.t_log_problems_users to reservation_users_administer; +grant select,delete on managers.t_log_problems_users to reservation_users_manager; +grant select on managers.t_log_problems_users to reservation_users_auditor; + + +/** only allow select, insert, and delete for users when user id is current user **/ +create view users.v_log_problems_users_self with (security_barrier=true) as + select id_problem, id_user, date_created, log_details from managers.t_log_problems_users + where (name_machine_user)::text = (current_user)::text; + +grant select on users.v_log_activity_self to reservation_users; + +create view users.v_log_problems_users_self_insert with (security_barrier=true) as + select id_problem, id_user, name_machine_user, log_details from managers.t_log_problems_users + where (name_machine_user)::text = (current_user)::text + with check option; + +grant insert on users.v_log_problems_users_self_insert to reservation_users; + +create view users.v_log_problems_users_self_delete with (security_barrier=true) as + select id_problem, id_user from managers.t_log_problems_users + where (name_machine_user)::text = (current_user)::text + with check option; + +grant delete on users.v_log_problems_users_self_delete to reservation_users; + + + +commit transaction; diff --git a/database/sql/reservation/base-logs.sql b/database/sql/reservation/base-log_types.sql similarity index 51% rename from database/sql/reservation/base-logs.sql rename to database/sql/reservation/base-log_types.sql index 8b682a1..dd43b4b 100644 --- a/database/sql/reservation/base-logs.sql +++ b/database/sql/reservation/base-log_types.sql @@ -1,13 +1,12 @@ -/** Standardized SQL Structure - Logs */ +/** Standardized SQL Structure - Logs - Types */ /** This depends on: base-users.sql **/ -/** Logs will contain a uuid type so that different logs may be associated with each other as to being related. Each request will have a new uuid. Requests maintained by ajax will likely have new uuids on each request. PHP should generate the uuid. */ start transaction; /** Custom database specific settings (do this on every connection made) **/ set bytea_output to hex; -set search_path to system,administers,managers,publishers,insurers,financers,reviewers,drafters,users,public; +set search_path to system,administers,managers,auditors,publishers,insurers,financers,reviewers,drafters,users,public; set datestyle to us; @@ -15,10 +14,15 @@ set datestyle to us; /*** provide log type id and names ***/ create table managers.t_log_types ( id bigint not null, + name_machine varchar(128) not null, name_human varchar(256) not null, + is_deleted boolean default false not null, + date_created timestamp default localtimestamp not null, + date_changed timestamp default localtimestamp not null, + date_deleted timestamp, constraint cp_log_types_id primary key (id), @@ -32,6 +36,7 @@ alter table managers.t_log_types alter column id set default nextval('managers.s grant select,insert,update on managers.t_log_types to reservation_users_administer; grant select on managers.t_log_types to reservation_users_manager; +grant select on managers.t_log_types to reservation_users_auditor; grant select,usage on managers.s_log_types_id to reservation_users_administer; create view public.v_log_types with (security_barrier=true) as @@ -60,44 +65,51 @@ insert into managers.t_log_types (id, name_machine, name_human) values (10, 'loa insert into managers.t_log_types (id, name_machine, name_human) values (11, 'save', 'Save'); insert into managers.t_log_types (id, name_machine, name_human) values (12, 'render', 'Render'); insert into managers.t_log_types (id, name_machine, name_human) values (13, 'client', 'Client'); -insert into managers.t_log_types (id, name_machine, name_human) values (14, 'update', 'Update'); -insert into managers.t_log_types (id, name_machine, name_human) values (15, 'delete', 'Delete'); -insert into managers.t_log_types (id, name_machine, name_human) values (16, 'redirect', 'Redirect'); -insert into managers.t_log_types (id, name_machine, name_human) values (17, 'login', 'Login'); -insert into managers.t_log_types (id, name_machine, name_human) values (18, 'logout', 'Logout'); -insert into managers.t_log_types (id, name_machine, name_human) values (19, 'session', 'Session'); -insert into managers.t_log_types (id, name_machine, name_human) values (20, 'database', 'Database'); -insert into managers.t_log_types (id, name_machine, name_human) values (21, 'not_found', 'Not Found'); -insert into managers.t_log_types (id, name_machine, name_human) values (22, 'access_denied', 'Access Denied'); -insert into managers.t_log_types (id, name_machine, name_human) values (23, 'removed', 'Removed'); -insert into managers.t_log_types (id, name_machine, name_human) values (24, 'locked', 'Locked'); -insert into managers.t_log_types (id, name_machine, name_human) values (25, 'timeout', 'Timeout'); -insert into managers.t_log_types (id, name_machine, name_human) values (26, 'expire', 'Expiration'); -insert into managers.t_log_types (id, name_machine, name_human) values (27, 'user', 'User'); -insert into managers.t_log_types (id, name_machine, name_human) values (28, 'error', 'Error'); -insert into managers.t_log_types (id, name_machine, name_human) values (29, 'content', 'Content'); -insert into managers.t_log_types (id, name_machine, name_human) values (30, 'workflow', 'Workflow'); -insert into managers.t_log_types (id, name_machine, name_human) values (31, 'draft', 'Draft'); -insert into managers.t_log_types (id, name_machine, name_human) values (32, 'clone', 'Clone'); -insert into managers.t_log_types (id, name_machine, name_human) values (33, 'publish', 'Publish'); -insert into managers.t_log_types (id, name_machine, name_human) values (34, 'revert', 'Revert'); -insert into managers.t_log_types (id, name_machine, name_human) values (35, 'validate', 'Validate'); -insert into managers.t_log_types (id, name_machine, name_human) values (36, 'approve', 'Approve'); -insert into managers.t_log_types (id, name_machine, name_human) values (37, 'password', 'Password'); -insert into managers.t_log_types (id, name_machine, name_human) values (38, 'revision', 'Revision'); -insert into managers.t_log_types (id, name_machine, name_human) values (39, 'search', 'Search'); -insert into managers.t_log_types (id, name_machine, name_human) values (40, 'access', 'Access'); -insert into managers.t_log_types (id, name_machine, name_human) values (41, 'unknown', 'Unknown'); +insert into managers.t_log_types (id, name_machine, name_human) values (14, 'add', 'Add'); +insert into managers.t_log_types (id, name_machine, name_human) values (15, 'create', 'Create'); +insert into managers.t_log_types (id, name_machine, name_human) values (16, 'change', 'Change'); +insert into managers.t_log_types (id, name_machine, name_human) values (17, 'delete', 'Delete'); +insert into managers.t_log_types (id, name_machine, name_human) values (18, 'redirect', 'Redirect'); +insert into managers.t_log_types (id, name_machine, name_human) values (19, 'login', 'Login'); +insert into managers.t_log_types (id, name_machine, name_human) values (20, 'logout', 'Logout'); +insert into managers.t_log_types (id, name_machine, name_human) values (21, 'session', 'Session'); +insert into managers.t_log_types (id, name_machine, name_human) values (22, 'database', 'Database'); +insert into managers.t_log_types (id, name_machine, name_human) values (23, 'not_found', 'Not Found'); +insert into managers.t_log_types (id, name_machine, name_human) values (24, 'access_denied', 'Access Denied'); +insert into managers.t_log_types (id, name_machine, name_human) values (25, 'removed', 'Removed'); +insert into managers.t_log_types (id, name_machine, name_human) values (26, 'locked', 'Locked'); +insert into managers.t_log_types (id, name_machine, name_human) values (27, 'timeout', 'Timeout'); +insert into managers.t_log_types (id, name_machine, name_human) values (28, 'expire', 'Expiration'); +insert into managers.t_log_types (id, name_machine, name_human) values (29, 'user', 'User'); +insert into managers.t_log_types (id, name_machine, name_human) values (30, 'error', 'Error'); +insert into managers.t_log_types (id, name_machine, name_human) values (31, 'content', 'Content'); +insert into managers.t_log_types (id, name_machine, name_human) values (32, 'workflow', 'Workflow'); +insert into managers.t_log_types (id, name_machine, name_human) values (33, 'draft', 'Draft'); +insert into managers.t_log_types (id, name_machine, name_human) values (34, 'clone', 'Clone'); +insert into managers.t_log_types (id, name_machine, name_human) values (35, 'publish', 'Publish'); +insert into managers.t_log_types (id, name_machine, name_human) values (36, 'revert', 'Revert'); +insert into managers.t_log_types (id, name_machine, name_human) values (37, 'validate', 'Validate'); +insert into managers.t_log_types (id, name_machine, name_human) values (38, 'approve', 'Approve'); +insert into managers.t_log_types (id, name_machine, name_human) values (39, 'password', 'Password'); +insert into managers.t_log_types (id, name_machine, name_human) values (40, 'revision', 'Revision'); +insert into managers.t_log_types (id, name_machine, name_human) values (41, 'search', 'Search'); +insert into managers.t_log_types (id, name_machine, name_human) values (42, 'access', 'Access'); +insert into managers.t_log_types (id, name_machine, name_human) values (43, 'unknown', 'Unknown'); /*** provide HTTP status codes ***/ create table managers.t_log_http_status_codes ( id smallint not null, + name_machine varchar(128) not null, name_human varchar(256) not null, + is_deleted boolean default false not null, + date_created timestamp default localtimestamp not null, + date_changed timestamp default localtimestamp not null, + date_deleted timestamp, constraint cp_log_http_status_codes_id primary key (id), @@ -111,6 +123,7 @@ alter table managers.t_log_http_status_codes alter column id set default nextval grant select,insert,update on managers.t_log_http_status_codes to reservation_users_administer; grant select on managers.t_log_http_status_codes to reservation_users_manager; +grant select on managers.t_log_http_status_codes to reservation_users_auditor; grant select,usage on managers.s_log_http_status_codes_id to reservation_users_administer; create view public.v_log_http_status_codes with (security_barrier=true) as @@ -197,7 +210,11 @@ create table managers.t_log_severity_levels ( name_machine varchar(128) not null, name_human varchar(256) not null, + is_deleted boolean default false not null, + date_created timestamp default localtimestamp not null, + date_changed timestamp default localtimestamp not null, + date_deleted timestamp, constraint cp_log_severity_levels_id primary key (id), @@ -211,13 +228,15 @@ alter table managers.t_log_severity_levels alter column id set default nextval(' grant select,insert,update on managers.t_log_severity_levels to reservation_users_administer; grant select on managers.t_log_severity_levels to reservation_users_manager; +grant select on managers.t_log_severity_levels to reservation_users_auditor; grant select,usage on managers.s_log_severity_levels_id to reservation_users_administer; -create view public.v_log_severity_levels with (security_barrier=true) as - select id, name_machine, name_human from managers.t_log_severity_levels; +create view users.v_log_severity_levels with (security_barrier=true) as + select id, name_machine, name_human from managers.t_log_severity_levels + where is_deleted is false; -grant select on public.v_log_severity_levels to reservation_users; -grant select on public.v_log_severity_levels to public_users; +grant select on users.v_log_severity_levels to reservation_users; +grant select on users.v_log_severity_levels to public_users; /*** start the sequence count at 1000 to allow for < 1000 to be reserved for special uses ***/ @@ -237,303 +256,4 @@ insert into managers.t_log_severity_levels (id, name_machine, name_human) values -/*** provide user activity logging ***/ -create table managers.t_log_users ( - id bigint not null, - id_user bigint default 1 not null, - id_uuid uuid not null, - name_machine varchar(128) not null, - log_title varchar(512) not null, - log_type bigint not null, - log_severity bigint not null, - log_details json, - log_date timestamp default localtimestamp not null, - request_client public.ct_client not null, - response_code smallint not null default 0, - - constraint cp_log_users_id primary key (id), - - constraint cc_log_users_id check (id > 0), - constraint cc_log_users_log_severity check (log_severity > 0), - - constraint cf_log_users_id_user foreign key (id_user, name_machine) references administers.t_users (id, name_machine) on delete set null on update cascade, - constraint cf_log_users_log_type foreign key (log_type) references managers.t_log_types (id) on delete restrict on update cascade, - constraint cf_log_users_log_severity foreign key (log_severity) references managers.t_log_severity_levels (id) on delete restrict on update cascade, - constraint cf_log_users_response_code foreign key (response_code) references managers.t_log_http_status_codes (id) on delete restrict on update cascade -); - -create sequence managers.s_log_users_id owned by managers.t_log_users.id; -alter table managers.t_log_users alter column id set default nextval('managers.s_log_users_id'::regclass); - -grant select on managers.t_log_users to reservation_users_administer; -grant select on managers.t_log_users to reservation_users_manager; -grant select,usage on managers.s_log_users_id to reservation_users_administer; -grant usage on managers.s_log_users_id to reservation_users; -grant usage on managers.s_log_users_id to public_users; - -create index ci_log_users_type_php on managers.t_log_users (id) - where log_type = 1; - -create index ci_log_users_type_theme on managers.t_log_users (id) - where log_type = 2; - -create index ci_log_users_type_cache on managers.t_log_users (id) - where log_type = 3; - -create index ci_log_users_type_javascript on managers.t_log_users (id) - where log_type = 4; - -create index ci_log_users_type_ajax on managers.t_log_users (id) - where log_type = 5; - -create index ci_log_users_type_sql on managers.t_log_users (id) - where log_type = 6; - -create index ci_log_users_type_redirect on managers.t_log_users (id) - where log_type = 16; - -create index ci_log_users_type_login on managers.t_log_users (id) - where log_type = 17; - -create index ci_log_users_type_logout on managers.t_log_users (id) - where log_type = 18; - -create index ci_log_users_type_user on managers.t_log_users (id) - where log_type = 27; - -create index ci_log_users_type_error on managers.t_log_users (id) - where log_type = 28; - -create index ci_log_users_type_content on managers.t_log_users (id) - where log_type = 29; - -create index ci_log_users_type_workflow on managers.t_log_users (id) - where log_type = 30; - -create index ci_log_users_type_search on managers.t_log_users (id) - where log_type = 39; - -create index ci_log_users_response_code_200 on managers.t_log_users (id) - where response_code = 200; - -create index ci_log_users_response_code_403 on managers.t_log_users (id) - where response_code = 403; - -create index ci_log_users_response_code_404 on managers.t_log_users (id) - where response_code = 404; - -create index ci_log_users_response_code_410 on managers.t_log_users (id) - where response_code = 410; - -create index ci_log_users_response_code_500 on managers.t_log_users (id) - where response_code = 500; - -create index ci_log_users_response_code_503 on managers.t_log_users (id) - where response_code = 503; - -create index ci_log_users_response_code_normal on managers.t_log_users (id) - where response_code in (200, 201, 202, 304); - -create index ci_log_users_response_code_redirects on managers.t_log_users (id) - where response_code in (301, 302, 303, 307, 308); - -create index ci_log_users_response_code_notable on managers.t_log_users (id) - where response_code in (400, 403, 404, 410, 500, 503); - -/** when using current_user reserved function/word the index gets ignored. To prevent this, create a manual/custom index and alter the behavior of the views to be more explicit. **/ -create unique index ci_log_users_current_user on managers.t_log_users (name_machine) with (fillfactor = 100); - - -/** only allow select and insert for users when user id is current user **/ -create view users.v_log_users_self with (security_barrier=true) as - select id, id_user, id_uuid, log_title, log_type, log_severity, log_details, log_date, request_client from managers.t_log_users - where (name_machine)::text = (current_user)::text; - -grant select on users.v_log_users_self to reservation_users; - -create view users.v_log_users_self_insert with (security_barrier=true) as - select id_user, id_uuid, name_machine, log_title, log_type, log_severity, log_details, request_client from managers.t_log_users - where (name_machine)::text = (current_user)::text - with check option; - -grant insert on users.v_log_users_self_insert to reservation_users; - - -/** only allow insert for the public user **/ -create view public.v_log_users_self_insert with (security_barrier=true) as - select id_user, id_uuid, name_machine, log_title, log_type, log_severity, log_details, request_client from managers.t_log_users - where id_user = 1 and name_machine = 'unknown' - with check option; - -grant insert on public.v_log_users_self_insert to public_users; - - -/** only allow insert for the system user **/ -create view system.v_log_users_self_insert with (security_barrier=true) as - select id_user, id_uuid, name_machine, log_title, log_type, log_severity, log_details, request_client from managers.t_log_users - where id_user = 2 and name_machine = 'system' - with check option; - -grant insert on system.v_log_users_self_insert to reservation_user; - - - -/*** provide access activity logging ***/ -create table managers.t_log_activity ( - id bigint not null, - id_user bigint default 1 not null, - id_uuid uuid not null, - name_machine varchar(128) not null, - request_path varchar(512) not null, - request_arguments varchar(512) not null, - request_date timestamp default localtimestamp not null, - request_client public.ct_client not null, - request_headers json, - response_headers json, - response_code smallint not null default 0, - - constraint cp_log_activity_id primary key (id), - - constraint cc_log_activity_id check (id > 0), - - constraint cf_log_activity_id_user foreign key (id_user, name_machine) references administers.t_users (id, name_machine) on delete set null on update cascade, - constraint cf_log_activity_response_code foreign key (response_code) references managers.t_log_http_status_codes (id) on delete restrict on update cascade -); - -create sequence managers.s_log_activity_id owned by managers.t_log_activity.id; -alter table managers.t_log_activity alter column id set default nextval('managers.s_log_activity_id'::regclass); - -grant select on managers.t_log_activity to reservation_users_administer; -grant select on managers.t_log_activity to reservation_users_manager; -grant select,usage on managers.s_log_activity_id to reservation_users_administer; -grant usage on managers.s_log_activity_id to reservation_users; -grant usage on managers.s_log_activity_id to public_users; - -create index ci_log_activity_response_code_4xx on managers.t_log_activity (id) - where response_code >= 400 and response_code < 500; - -create index ci_log_activity_response_code_403 on managers.t_log_activity (id) - where response_code = 403; - -create index ci_log_activity_response_code_404 on managers.t_log_activity (id) - where response_code = 404; - -create index ci_log_activity_response_code_410 on managers.t_log_activity (id) - where response_code = 410; - -create index ci_log_activity_response_code_5xx on managers.t_log_activity (id) - where response_code >= 500 and response_code < 600; - -create index ci_log_activity_response_code_500 on managers.t_log_activity (id) - where response_code = 500; - -create index ci_log_activity_response_code_503 on managers.t_log_activity (id) - where response_code = 503; - -create index ci_log_activity_response_code_notable on managers.t_log_activity (id) - where response_code in (403, 404, 410, 500, 503); - -/** when using current_user reserved function/word the index gets ignored. To prevent this, create a manual/custom index and alter the behavior of the views to be more explicit. **/ -create unique index ci_log_activity_current_user on managers.t_log_activity (name_machine) with (fillfactor = 100); - - -/** only allow select and insert for users when user id is current user **/ -create view users.v_log_activity_self with (security_barrier=true) as - select id, id_user, id_uuid, request_path, request_arguments, request_date, request_client, request_headers, response_headers, response_code from managers.t_log_activity - where (name_machine)::text = (current_user)::text; - -grant select on users.v_log_activity_self to reservation_users; - -create view users.v_log_activity_self_insert with (security_barrier=true) as - select id_user, id_uuid, name_machine, request_path, request_arguments, request_client, request_headers, response_headers, response_code from managers.t_log_activity - where (name_machine)::text = (current_user)::text - with check option; - -grant insert on users.v_log_activity_self_insert to reservation_users; - - -/** only allow insert for the public user **/ -create view public.v_log_activity_self_insert with (security_barrier=true) as - select id_user, id_uuid, name_machine, request_path, request_arguments, request_client, request_headers, response_headers, response_code from managers.t_log_activity - where id_user = 1 and name_machine = 'unknown' - with check option; - -grant insert on public.v_log_activity_self_insert to public_users; - - -/** only allow insert for the system user **/ -create view system.v_log_activity_self_insert with (security_barrier=true) as - select id_user, id_uuid, name_machine, request_path, request_arguments, request_client, request_headers, response_headers, response_code from managers.t_log_activity - where id_user = 2 and name_machine = 'system' - with check option; - -grant insert on system.v_log_activity_self_insert to reservation_user; - - - -/** Provide a log of problems, which are defined by the software. **/ -create table managers.t_log_problems ( - id bigint not null, - name_machine varchar(128) not null, - name_human varchar(256) not null, - - date_created timestamp default localtimestamp not null, - - constraint cp_log_problems_id primary key (id), - - constraint cc_log_problems_id check (id > 0), - - constraint cu_log_problems_name_machine unique (name_machine) -); - -grant select on managers.t_log_activity to reservation_users_administer; -grant select on managers.t_log_activity to reservation_users_manager; - - - -/** Provide a log of problems, associated with a given user. **/ -create table managers.t_log_problems_users ( - id_problem bigint not null, - id_user bigint not null, - - name_machine varchar(128) not null, - - date_created timestamp default localtimestamp not null, - - information_additional json, - - constraint cp_log_problems_users_id primary key (id_problem, id_user), - - constraint cu_log_problems_users_name_machine unique (name_machine), - - constraint cf_log_problems_users_id_problem foreign key (id_problem) references managers.t_log_problems (id) on delete restrict on update cascade, - constraint cf_log_problems_users_id_user foreign key (id_user, name_machine) references administers.t_users (id, name_machine) on delete restrict on update cascade -); - -grant select,delete on managers.t_log_problems_users to reservation_users_administer; -grant select,delete on managers.t_log_problems_users to reservation_users_manager; - - -/** only allow select, insert, and delete for users when user id is current user **/ -create view users.v_log_problems_users_self with (security_barrier=true) as - select id_problem, id_user, date_created, information_additional from managers.t_log_problems_users - where (name_machine)::text = (current_user)::text; - -grant select on users.v_log_activity_self to reservation_users; - -create view users.v_log_problems_users_self_insert with (security_barrier=true) as - select id_problem, id_user, name_machine, information_additional from managers.t_log_problems_users - where (name_machine)::text = (current_user)::text - with check option; - -grant insert on users.v_log_problems_users_self_insert to reservation_users; - -create view users.v_log_problems_users_self_delete with (security_barrier=true) as - select id_problem, id_user from managers.t_log_problems_users - where (name_machine)::text = (current_user)::text - with check option; - -grant delete on users.v_log_problems_users_self_delete to reservation_users; - - commit transaction; diff --git a/database/sql/reservation/base-log_users.sql b/database/sql/reservation/base-log_users.sql new file mode 100644 index 0000000..d938c73 --- /dev/null +++ b/database/sql/reservation/base-log_users.sql @@ -0,0 +1,247 @@ +/** Standardized SQL Structure - Logs */ +/** This depends on: base-users.sql **/ +start transaction; + + + +/*** provide user activity logging ***/ +create table managers.t_log_users ( + id bigint not null, + id_user bigint default 1 not null, + + name_machine_user varchar(128) not null, + + log_title varchar(512) not null, + log_type bigint not null, + log_severity bigint not null, + log_details json, + log_date timestamp default localtimestamp not null, + + request_client public.ct_client not null, + response_code smallint not null default 0, + + constraint cp_log_users_id primary key (id), + + constraint cc_log_users_id check (id > 0), + constraint cc_log_users_log_severity check (log_severity > 0), + + constraint cf_log_users_id_user foreign key (id_user, name_machine_user) references administers.t_users (id, name_machine) on delete restrict on update cascade, + constraint cf_log_users_log_type foreign key (log_type) references managers.t_log_types (id) on delete restrict on update cascade, + constraint cf_log_users_log_severity foreign key (log_severity) references managers.t_log_severity_levels (id) on delete restrict on update cascade, + constraint cf_log_users_response_code foreign key (response_code) references managers.t_log_http_status_codes (id) on delete restrict on update cascade +); + +create sequence managers.s_log_users_id owned by managers.t_log_users.id; +alter table managers.t_log_users alter column id set default nextval('managers.s_log_users_id'::regclass); + +grant select on managers.t_log_users to reservation_users_administer; +grant select on managers.t_log_users to reservation_users_manager; +grant select on managers.t_log_users to reservation_users_auditor; +grant select,usage on managers.s_log_users_id to reservation_users_administer; +grant usage on managers.s_log_users_id to reservation_users; +grant usage on managers.s_log_users_id to public_users; + +create index ci_log_users_type_php on managers.t_log_users (id) + where log_type = 1; + +create index ci_log_users_type_theme on managers.t_log_users (id) + where log_type = 2; + +create index ci_log_users_type_cache on managers.t_log_users (id) + where log_type = 3; + +create index ci_log_users_type_javascript on managers.t_log_users (id) + where log_type = 4; + +create index ci_log_users_type_ajax on managers.t_log_users (id) + where log_type = 5; + +create index ci_log_users_type_sql on managers.t_log_users (id) + where log_type = 6; + +create index ci_log_users_type_redirect on managers.t_log_users (id) + where log_type = 16; + +create index ci_log_users_type_login on managers.t_log_users (id) + where log_type = 17; + +create index ci_log_users_type_logout on managers.t_log_users (id) + where log_type = 18; + +create index ci_log_users_type_user on managers.t_log_users (id) + where log_type = 27; + +create index ci_log_users_type_error on managers.t_log_users (id) + where log_type = 28; + +create index ci_log_users_type_content on managers.t_log_users (id) + where log_type = 29; + +create index ci_log_users_type_workflow on managers.t_log_users (id) + where log_type = 30; + +create index ci_log_users_type_search on managers.t_log_users (id) + where log_type = 39; + +create index ci_log_users_response_code_200 on managers.t_log_users (id) + where response_code = 200; + +create index ci_log_users_response_code_403 on managers.t_log_users (id) + where response_code = 403; + +create index ci_log_users_response_code_404 on managers.t_log_users (id) + where response_code = 404; + +create index ci_log_users_response_code_410 on managers.t_log_users (id) + where response_code = 410; + +create index ci_log_users_response_code_500 on managers.t_log_users (id) + where response_code = 500; + +create index ci_log_users_response_code_503 on managers.t_log_users (id) + where response_code = 503; + +create index ci_log_users_response_code_normal on managers.t_log_users (id) + where response_code in (200, 201, 202, 304); + +create index ci_log_users_response_code_redirects on managers.t_log_users (id) + where response_code in (301, 302, 303, 307, 308); + +create index ci_log_users_response_code_notable on managers.t_log_users (id) + where response_code in (400, 403, 404, 410, 500, 503); + +/** when using current_user reserved function/word the index gets ignored. To prevent this, create a manual/custom index and alter the behavior of the views to be more explicit. **/ +create unique index ci_log_users_current_user on managers.t_log_users (name_machine_user) with (fillfactor = 100); + + +/** only allow select and insert for users when user id is current user **/ +create view users.v_log_users_self with (security_barrier=true) as + select id, id_user, log_title, log_type, log_severity, log_details, log_date, request_client from managers.t_log_users + where (name_machine_user)::text = (current_user)::text; + +grant select on users.v_log_users_self to reservation_users; + +create view users.v_log_users_self_insert with (security_barrier=true) as + select id_user, name_machine_user, log_title, log_type, log_severity, log_details, request_client from managers.t_log_users + where (name_machine_user)::text = (current_user)::text + with check option; + +grant insert on users.v_log_users_self_insert to reservation_users; + + +/** only allow insert for the public user **/ +create view public.v_log_users_self_insert with (security_barrier=true) as + select id_user, name_machine_user, log_title, log_type, log_severity, log_details, request_client from managers.t_log_users + where id_user = 1 and name_machine_user = 'unknown' + with check option; + +grant insert on public.v_log_users_self_insert to public_users; + + +/** only allow insert for the system user **/ +create view system.v_log_users_self_insert with (security_barrier=true) as + select id_user, name_machine_user, log_title, log_type, log_severity, log_details, request_client from managers.t_log_users + where id_user = 2 and name_machine_user = 'system' + with check option; + +grant insert on system.v_log_users_self_insert to reservation_users; + + + +/*** provide access activity logging ***/ +create table managers.t_log_activity ( + id bigint not null, + id_user bigint default 1 not null, + + name_machine_user varchar(128) not null, + + request_path varchar(512) not null, + request_arguments varchar(512) not null, + request_date timestamp default localtimestamp not null, + request_client public.ct_client not null, + request_headers json, + + response_headers json, + response_code smallint not null default 0, + + constraint cp_log_activity_id primary key (id), + + constraint cc_log_activity_id check (id > 0), + + constraint cf_log_activity_id_user foreign key (id_user, name_machine_user) references administers.t_users (id, name_machine) on delete restrict on update cascade, + constraint cf_log_activity_response_code foreign key (response_code) references managers.t_log_http_status_codes (id) on delete restrict on update cascade +); + +create sequence managers.s_log_activity_id owned by managers.t_log_activity.id; +alter table managers.t_log_activity alter column id set default nextval('managers.s_log_activity_id'::regclass); + +grant select on managers.t_log_activity to reservation_users_administer; +grant select on managers.t_log_activity to reservation_users_manager; +grant select on managers.t_log_activity to reservation_users_auditor; +grant select,usage on managers.s_log_activity_id to reservation_users_administer; +grant usage on managers.s_log_activity_id to reservation_users; +grant usage on managers.s_log_activity_id to public_users; + +create index ci_log_activity_response_code_4xx on managers.t_log_activity (id) + where response_code >= 400 and response_code < 500; + +create index ci_log_activity_response_code_403 on managers.t_log_activity (id) + where response_code = 403; + +create index ci_log_activity_response_code_404 on managers.t_log_activity (id) + where response_code = 404; + +create index ci_log_activity_response_code_410 on managers.t_log_activity (id) + where response_code = 410; + +create index ci_log_activity_response_code_5xx on managers.t_log_activity (id) + where response_code >= 500 and response_code < 600; + +create index ci_log_activity_response_code_500 on managers.t_log_activity (id) + where response_code = 500; + +create index ci_log_activity_response_code_503 on managers.t_log_activity (id) + where response_code = 503; + +create index ci_log_activity_response_code_notable on managers.t_log_activity (id) + where response_code in (403, 404, 410, 500, 503); + +/** when using current_user reserved function/word the index gets ignored. To prevent this, create a manual/custom index and alter the behavior of the views to be more explicit. **/ +create unique index ci_log_activity_current_user on managers.t_log_activity (name_machine_user) with (fillfactor = 100); + + +/** only allow select and insert for users when user id is current user **/ +create view users.v_log_activity_self with (security_barrier=true) as + select id, id_user, request_path, request_arguments, request_date, request_client, request_headers, response_headers, response_code from managers.t_log_activity + where (name_machine_user)::text = (current_user)::text; + +grant select on users.v_log_activity_self to reservation_users; + +create view users.v_log_activity_self_insert with (security_barrier=true) as + select id_user, name_machine_user, request_path, request_arguments, request_client, request_headers, response_headers, response_code from managers.t_log_activity + where (name_machine_user)::text = (current_user)::text + with check option; + +grant insert on users.v_log_activity_self_insert to reservation_users; + + +/** only allow insert for the public user **/ +create view public.v_log_activity_self_insert with (security_barrier=true) as + select id_user, name_machine_user, request_path, request_arguments, request_client, request_headers, response_headers, response_code from managers.t_log_activity + where id_user = 1 and name_machine_user = 'unknown' + with check option; + +grant insert on public.v_log_activity_self_insert to public_users; + + +/** only allow insert for the system user **/ +create view system.v_log_activity_self_insert with (security_barrier=true) as + select id_user, name_machine_user, request_path, request_arguments, request_client, request_headers, response_headers, response_code from managers.t_log_activity + where id_user = 2 and name_machine_user = 'system' + with check option; + +grant insert on system.v_log_activity_self_insert to reservation_users; + + + +commit transaction; diff --git a/database/sql/reservation/base-main.sql b/database/sql/reservation/base-main.sql index 906e8af..33b2ee2 100644 --- a/database/sql/reservation/base-main.sql +++ b/database/sql/reservation/base-main.sql @@ -15,7 +15,7 @@ start transaction; /** Custom database specific settings (do this on every connection made) **/ set bytea_output to hex; -set search_path to system,administers,managers,publishers,insurers,financers,reviewers,drafters,users,public; +set search_path to system,administers,managers,auditors,publishers,insurers,financers,reviewers,drafters,users,public; set datestyle to us; @@ -24,6 +24,7 @@ set datestyle to us; create schema system authorization reservation_user; create schema administers authorization reservation_users_administer; create schema managers authorization reservation_users_manager; +create schema auditors authorization reservation_users_auditor; create schema publishers authorization reservation_users_publisher; create schema insurer authorization reservation_users_insurer; create schema financer authorization reservation_users_financer; @@ -33,6 +34,7 @@ create schema users authorization reservation_users; revoke create on schema system from reservation_user; revoke create on schema administers from reservation_users_administer; +revoke create on schema auditors from reservation_users_auditor; revoke create on schema managers from reservation_users_manager; revoke create on schema publishers from reservation_users_publisher; revoke create on schema insurer from reservation_users_insurer; @@ -44,6 +46,7 @@ revoke create on schema users from reservation_users; grant usage on schema system to reservation_user; grant usage on schema administers to reservation_users_administer; grant usage on schema managers to reservation_users_manager; +grant usage on schema auditors to reservation_users_auditor; grant usage on schema publishers to reservation_users_publisher; grant usage on schema insurer to reservation_users_insurer; grant usage on schema financer to reservation_users_financer; @@ -54,6 +57,7 @@ grant usage on schema users to reservation_users; grant create,usage on schema system to postgres; grant create,usage on schema administers to postgres; grant create,usage on schema managers to postgres; +grant create,usage on schema auditors to postgres; grant create,usage on schema publishers to postgres; grant create,usage on schema insurer to postgres; grant create,usage on schema financer to postgres; @@ -89,6 +93,105 @@ create type public.ct_text as ( context bigint ); +create type public.ct_location as ( + building bigint, + room bigint[] +); + +create type public.ct_date as ( + date timestamp, + time_start timestamp, + time_stop timestamp +); + +create type public.ct_date_context as ( + date timestamp, + time_start timestamp, + time_stop timestamp, + context bigint +); + +create type public.ct_phone_number as ( + country smallint, + area smallint, + number smallint, + extension smallint +); + +create type public.ct_phone_number_context as ( + country smallint, + area smallint, + number smallint, + extension smallint, + context bigint +); + +create type public.ct_money_context as ( + money money, + context bigint +); + +create type public.ct_field_fees as ( + needed bool, + quantity bigint, + days bigint, + hours bigint, + amount money +); + +create type public.ct_field_used_with_contact as ( + used bool, + email text, + name text, + phone public.ct_phone_number +); + +create type public.ct_field_needed_with_total as ( + needed bool, + total bigint +); + +create type public.ct_field_needed_with_details as ( + needed bool, + details text +); + +create type public.ct_field_used_with_details as ( + used bool, + details text +); + +create type public.ct_field_used_with_designer as ( + used bool, + designer text +); + +create type public.ct_field_served_with_caterer as ( + served bool, + caterer text +); + +create type public.ct_field_generated_with_types as ( + generated bool, + types bigint[] +); + +create type public.ct_field_needed_with_types as ( + needed bool, + types bigint[] +); + +create type public.ct_field_needed_with_types_and_microphone as ( + needed bool, + types bigint[], + microphone bigint +); + +create type public.ct_field_insurance as ( + needed bool, + provided bool +); + commit transaction; diff --git a/database/sql/reservation/base-requests.sql b/database/sql/reservation/base-requests.sql new file mode 100644 index 0000000..24f3129 --- /dev/null +++ b/database/sql/reservation/base-requests.sql @@ -0,0 +1,153 @@ +/** Standardized SQL Structure - Content **/ +/** This depends on: base-fields.sql **/ +start transaction; + + + +/** Custom database specific settings (do this on every connection made) **/ +set bytea_output to hex; +set search_path to system,administers,managers,auditors,publishers,insurers,financers,reviewers,drafters,users,public; +set datestyle to us; + + + +/*** Request: Type ***/ +create table managers.t_request_types ( + id bigint not null, + id_external bigint, + + name_machine varchar(128) not null, + name_human varchar(256) not null, + + is_deleted boolean default false not null, + + date_created timestamp default localtimestamp not null, + date_changed timestamp default localtimestamp not null, + date_deleted timestamp, + + constraint cu_request_types_id unique (id), + constraint cu_request_types_name_machine unique (name_machine), + + constraint cc_request_types_id check (id > 0) +); + +create sequence managers.s_request_types_id owned by managers.t_request_types.id; +alter table managers.t_request_types alter column id set default nextval('managers.s_request_types_id'::regclass); + +grant select,insert,update on managers.t_request_types to reservation_users_administer; +grant select,insert,update on managers.t_request_types to reservation_users_manager; +grant select on managers.t_request_types to reservation_users_auditor; +grant select,usage on managers.s_request_types_id to reservation_users_administer; +grant select,usage on managers.s_request_types_id to reservation_users_manager; + +create view users.v_request_types with (security_barrier=true) as + select id, id_external, name_machine, name_human from managers.t_request_types + where is_deleted is false; + +grant select on users.v_request_types to reservation_users; + +/** @todo: consider creating default request types **/ + + + +/*** Requests ***/ +create table managers.t_requests ( + id bigint not null, + id_owner bigint not null, + id_revision bigint not null, + id_type bigint not null, + + name_machine varchar(128) not null, + name_machine_owner varchar(128) not null, + name_human varchar(256) not null, + + is_approved boolean default false not null, + is_cancelled boolean default false not null, + is_deleted boolean default false not null, + is_denied boolean default false not null, + is_troubled boolean default false not null, + + date_created timestamp default localtimestamp not null, + date_changed timestamp default localtimestamp not null, + date_synced timestamp default localtimestamp not null, + date_deleted timestamp, + + field_additional text not null, + field_dates public.ct_date_context[] not null, + field_fees_custodial public.ct_field_fees[] not null, + field_fees_equipment public.ct_field_fees[] not null, + field_fees_facilities public.ct_field_fees[] not null, + field_fees_grounds public.ct_field_fees[] not null, + field_fees_maintenance public.ct_field_fees[] not null, + field_fees_other public.ct_field_fees[] not null, + field_fees_security public.ct_field_fees[] not null, + field_fees_university public.ct_field_fees[] not null, + field_location public.ct_location[] not null, + field_information_attendance bigint not null, + field_information_organization bigint not null, + field_information_adviser_approval bool not null, + field_insurance_affiliated public.ct_field_insurance not null, + field_insurance_contractor public.ct_field_insurance not null, + field_insurance_unaffiliated public.ct_field_insurance not null, + field_plans_activities text not null, + field_plans_audience bigint not null, + field_plans_description text not null, + field_presentation_designing_material public.ct_field_used_with_contact not null, + field_presentation_external_audio_person public.ct_field_used_with_contact not null, + field_presentation_production public.ct_field_used_with_contact not null, + field_presentation_printed_material public.ct_field_used_with_details not null, + field_presentation_publicity public.ct_field_needed_with_types not null, + field_presentation_technical_equipment public.ct_field_needed_with_types_and_microphone not null, + field_presentation_university_logo public.ct_field_used_with_designer not null, + field_registration_revenue public.ct_field_generated_with_types not null, + field_registration_phone public.ct_phone_number not null, + field_registration_required bool not null, + field_registration_ticket_dates public.ct_date_context[] not null, + field_registration_ticket_phone public.ct_phone_number_context not null, + field_registration_ticket_price public.ct_money_context[] not null, + field_registration_ticket_website text not null, + field_registration_website text not null, + field_setup_other_tables public.ct_field_needed_with_details not null, + field_setup_parking_assistance public.ct_field_needed_with_details not null, + field_setup_podium public.ct_field_needed_with_details not null, + field_setup_portable_stage public.ct_field_needed_with_details not null, + field_setup_rectangular_tables_8ft public.ct_field_needed_with_total not null, + field_setup_road_closures public.ct_field_needed_with_details not null, + field_setup_round_tables_8ft public.ct_field_needed_with_total not null, + field_setup_security public.ct_field_needed_with_details not null, + field_setup_special_requests public.ct_field_needed_with_details not null, + field_setup_standard_blue_chairs public.ct_field_needed_with_total not null; + field_services_alcohol_served public.ct_field_served_with_caterer not null, + field_services_food public.ct_field_served_with_caterer not null, + field_services_open_flames public.ct_field_used_with_details not null, + field_title text not null, + + in_state bigint not null, + in_step bigint not null, + + constraint cu_requests_id unique (id), + constraint cu_requests_name_machine unique (name_machine), + + constraint cc_requests_id check (id > 0), + + constraint cf_requests_id_owner foreign key (id_owner, name_machine_owner) references administers.t_users (id, name_machine) on delete restrict on update cascade, + constraint cf_requests_request_type foreign key (id_type) references managers.t_request_types (id) on delete restrict on update cascade +); + +create sequence managers.s_requests_id owned by managers.t_requests.id; +alter table managers.t_requests alter column id set default nextval('managers.s_requests_id'::regclass); + +grant select,insert,update on managers.t_requests to reservation_users_administer; +grant select,insert,update on managers.t_requests to reservation_users_manager; +grant select on managers.t_requests to reservation_users_auditor; +grant select,usage on managers.s_requests_id to reservation_users_administer; +grant select,usage on managers.s_requests_id to reservation_users_manager; +grant usage on managers.s_requests_id to reservation_users; + + +/** @todo: create all appropriate views, including individual views for is_cancelled, is_deleted, is_published, is_unpublished, is_denied, and is_troubled **/ + + +/** @todo: create "managers.t_requests_revision" that is identical to "managers.t_requests" with all the columns allowed to be null. + +commit transaction; diff --git a/database/sql/reservation/base-statistics.sql b/database/sql/reservation/base-statistics.sql index cffbea9..6b06ffb 100644 --- a/database/sql/reservation/base-statistics.sql +++ b/database/sql/reservation/base-statistics.sql @@ -6,7 +6,7 @@ start transaction; /** Custom database specific settings (do this on every connection made) **/ set bytea_output to hex; -set search_path to system,administers,managers,publishers,insurers,financers,reviewers,drafters,users,public; +set search_path to system,administers,managers,auditors,publishers,insurers,financers,reviewers,drafters,users,public; set datestyle to us; @@ -17,6 +17,8 @@ create table managers.t_statistics_http_status_codes ( count bigint not null default 0, date_created timestamp default localtimestamp not null, + date_changed timestamp default localtimestamp not null, + date_deleted timestamp, constraint cp_statistics_http_status_codes_code primary key (code), @@ -27,6 +29,7 @@ create table managers.t_statistics_http_status_codes ( grant select,insert,update on managers.t_statistics_http_status_codes to reservation_users_administer; grant select,insert,update on managers.t_statistics_http_status_codes to reservation_users_manager; +grant select on managers.t_statistics_http_status_codes to reservation_users_auditor; /** create an auto-update trigger. set the role to reservation_users_manager so that the function runs as that role when using "SECURITY DEFINER". The reservation_users_manager must also have the appropriate create privileges. **/ @@ -133,6 +136,8 @@ create table managers.t_statistics_request_path ( count bigint not null default 0, date_created timestamp default localtimestamp not null, + date_changed timestamp default localtimestamp not null, + date_deleted timestamp, constraint cp_statistics_request_path_code primary key (path), @@ -141,6 +146,7 @@ create table managers.t_statistics_request_path ( grant select on managers.t_statistics_request_path to reservation_users_administer; grant select on managers.t_statistics_request_path to reservation_users_manager; +grant select on managers.t_statistics_request_path to reservation_users_auditor; /** permissions prevent this from working as desired, so for now open up these stats to the following users (via a view) **/ create view users.v_statistics_request_path with (security_barrier=true) as diff --git a/database/sql/reservation/base-structure.sql b/database/sql/reservation/base-structure.sql deleted file mode 100644 index 7bd32fd..0000000 --- a/database/sql/reservation/base-structure.sql +++ /dev/null @@ -1,14 +0,0 @@ -/** Standardized SQL Structure - Structure **/ -/** This depends on: base-content_type.sql **/ -start transaction; - - - -/** Custom database specific settings (do this on every connection made) **/ -set bytea_output to hex; -set search_path to system,administers,managers,publishers,insurers,financers,reviewers,drafters,users,public; -set datestyle to us; - - - -commit transaction; diff --git a/database/sql/reservation/base-users.sql b/database/sql/reservation/base-users.sql index 3ecade6..b68bb46 100644 --- a/database/sql/reservation/base-users.sql +++ b/database/sql/reservation/base-users.sql @@ -6,7 +6,7 @@ start transaction; /** Custom database specific settings (do this on every connection made) **/ set bytea_output to hex; -set search_path to system,administers,managers,publishers,insurers,financers,reviewers,drafters,users,public; +set search_path to system,administers,managers,auditors,publishers,insurers,financers,reviewers,drafters,users,public; set datestyle to us; @@ -17,16 +17,22 @@ create table administers.t_users ( id bigint not null, id_sort smallint not null default 0, id_external bigint, + name_machine varchar(128) not null, name_human public.ct_name_person default (null, null, null, null, null, null) not null, + address_email public.ct_email default (null, null, true) not null, - is_private boolean default true not null, - is_locked boolean default false not null, + + is_coordinator boolean default false not null, is_deleted boolean default false not null, + is_locked boolean default false not null, + is_private boolean default true not null, + date_created timestamp default localtimestamp not null, date_changed timestamp default localtimestamp not null, date_synced timestamp default localtimestamp not null, date_deleted timestamp, + settings json, constraint cp_users_id primary key (id), @@ -36,14 +42,14 @@ create table administers.t_users ( constraint cu_users_id_external unique (id_external), constraint cu_users_name_machine unique (name_machine), - constraint cu_users_user unique (id, name_machine), - constraint cu_external_id unique (id_external) + constraint cu_users_user unique (id, name_machine) ); create sequence administers.s_users_id owned by administers.t_users.id; alter table administers.t_users alter column id set default nextval('administers.s_users_id'::regclass); grant select,insert,update on administers.t_users to reservation_users_administer; +grant select on administers.t_users to reservation_users_auditor; grant select,usage on administers.s_users_id to reservation_users_administer; grant usage on administers.s_users_id to reservation_users; @@ -59,7 +65,32 @@ create index ci_users_private_email_not on administers.t_users (id) /** when using current_user reserved function/word the index gets ignored. To prevent this, create a manual/custom index and alter the behavior of the views to be more explicit. **/ create unique index ci_users_current_user on administers.t_users (name_machine) with (fillfactor = 100); +create index ci_users_id_sort_a on administers.t_users (id_sort) with (fillfactor = 100) where id_sort = 97; +create index ci_users_id_sort_b on administers.t_users (id_sort) with (fillfactor = 100) where id_sort = 98; +create index ci_users_id_sort_c on administers.t_users (id_sort) with (fillfactor = 100) where id_sort = 99; +create index ci_users_id_sort_d on administers.t_users (id_sort) with (fillfactor = 100) where id_sort = 100; +create index ci_users_id_sort_e on administers.t_users (id_sort) with (fillfactor = 100) where id_sort = 101; +create index ci_users_id_sort_f on administers.t_users (id_sort) with (fillfactor = 100) where id_sort = 102; +create index ci_users_id_sort_g on administers.t_users (id_sort) with (fillfactor = 100) where id_sort = 103; +create index ci_users_id_sort_h on administers.t_users (id_sort) with (fillfactor = 100) where id_sort = 104; +create index ci_users_id_sort_i on administers.t_users (id_sort) with (fillfactor = 100) where id_sort = 105; +create index ci_users_id_sort_j on administers.t_users (id_sort) with (fillfactor = 100) where id_sort = 106; create index ci_users_id_sort_k on administers.t_users (id_sort) with (fillfactor = 100) where id_sort = 107; +create index ci_users_id_sort_l on administers.t_users (id_sort) with (fillfactor = 100) where id_sort = 108; +create index ci_users_id_sort_m on administers.t_users (id_sort) with (fillfactor = 100) where id_sort = 109; +create index ci_users_id_sort_n on administers.t_users (id_sort) with (fillfactor = 100) where id_sort = 110; +create index ci_users_id_sort_o on administers.t_users (id_sort) with (fillfactor = 100) where id_sort = 111; +create index ci_users_id_sort_p on administers.t_users (id_sort) with (fillfactor = 100) where id_sort = 112; +create index ci_users_id_sort_q on administers.t_users (id_sort) with (fillfactor = 100) where id_sort = 113; +create index ci_users_id_sort_r on administers.t_users (id_sort) with (fillfactor = 100) where id_sort = 114; +create index ci_users_id_sort_s on administers.t_users (id_sort) with (fillfactor = 100) where id_sort = 115; +create index ci_users_id_sort_t on administers.t_users (id_sort) with (fillfactor = 100) where id_sort = 116; +create index ci_users_id_sort_u on administers.t_users (id_sort) with (fillfactor = 100) where id_sort = 117; +create index ci_users_id_sort_v on administers.t_users (id_sort) with (fillfactor = 100) where id_sort = 118; +create index ci_users_id_sort_w on administers.t_users (id_sort) with (fillfactor = 100) where id_sort = 119; +create index ci_users_id_sort_x on administers.t_users (id_sort) with (fillfactor = 100) where id_sort = 120; +create index ci_users_id_sort_y on administers.t_users (id_sort) with (fillfactor = 100) where id_sort = 121; +create index ci_users_id_sort_z on administers.t_users (id_sort) with (fillfactor = 100) where id_sort = 122; /*** start the sequence count at 1000 to allow for < 1000 to be reserved for special uses ***/ @@ -76,8 +107,8 @@ insert into administers.t_users (id, name_machine, name_human, is_private) value /*** provide current user access to their own information ***/ create view users.v_users_self with (security_barrier=true) as - select id, id_sort, id_external, name_machine, name_human, address_email, is_private, is_locked, date_created, date_changed, date_synced, settings from administers.t_users - where (name_machine)::text = (current_user)::text and is_deleted is not true; + select id, id_sort, id_external, name_machine, name_human, address_email, is_private, is_locked, is_coordinator, date_created, date_changed, date_synced, settings from administers.t_users + where is_deleted is not true and (name_machine)::text = (current_user)::text; grant select on users.v_users_self to reservation_users; @@ -90,7 +121,7 @@ grant insert on users.v_users_self_insert to reservation_users; create view users.v_users_self_update with (security_barrier=true) as select address_email, is_private, date_changed, date_synced, settings from administers.t_users - where (name_machine)::text = (current_user)::text and is_deleted is not true and (date_changed is null or date_changed = localtimestamp) + where is_deleted is not true and date_changed = localtimestamp and (date_synced is null or date_synced = localtimestamp) and (name_machine)::text = (current_user)::text with check option; grant update on users.v_users_self_update to reservation_users; @@ -98,7 +129,7 @@ grant update on users.v_users_self_update to reservation_users; /**** anonymous user has uid = 1 ****/ create view public.v_users_self with (security_barrier=true) as - select id, id_sort, id_external, name_machine, name_human, address_email, is_private, is_locked, date_created, date_changed, date_synced, settings from administers.t_users + select id, id_sort, id_external, name_machine, name_human, address_email, is_private, is_locked, is_coordinator, date_created, date_changed, date_synced, settings from administers.t_users where id = 1 and is_deleted is not true and id_sort = 0; grant select on public.v_users_self to public_users; @@ -106,7 +137,7 @@ grant select on public.v_users_self to public_users; /**** system user has uid = 2 ****/ create view system.v_users_self with (security_barrier=true) as - select id, id_sort, id_external, name_machine, name_human, address_email, is_private, is_locked, date_created, date_changed, date_synced, settings from administers.t_users + select id, id_sort, id_external, name_machine, name_human, address_email, is_private, is_locked, is_coordinator, date_created, date_changed, date_synced, settings from administers.t_users where id = 2 and is_deleted is not true and id_sort = 0; grant select on system.v_users_self to reservation_user; @@ -115,7 +146,7 @@ grant select on system.v_users_self to reservation_user; /*** provide public user information ***/ create view public.v_users with (security_barrier=true) as select id, id_sort, name_machine, name_human from administers.t_users - where (is_deleted is not true and is_private is not true) or ((name_machine)::text = (current_user)::text and is_deleted is not true); + where (is_deleted is not true and is_private is not true) or (is_deleted is not true and (name_machine)::text = (current_user)::text); grant select on public.v_users to reservation_users; grant select on public.v_users to public_users; @@ -124,7 +155,7 @@ grant select on public.v_users to public_users; /*** provide e-mail address as public information only if it is explicitly allowed ***/ create view public.v_users_email with (security_barrier=true) as select id, id_sort, name_machine, name_human, address_email from administers.t_users - where (is_deleted is not true and is_private is not true and (address_email).private is not true) or ((name_machine)::text = (current_user)::text and is_deleted is not true); + where (is_deleted is not true and is_private is not true and (address_email).private is not true) or (is_deleted is not true and (name_machine)::text = (current_user)::text); grant select on public.v_users_email to reservation_users; grant select on public.v_users_email to public_users; @@ -132,20 +163,20 @@ grant select on public.v_users_email to public_users; /*** provide managers with the ability to modify accounts ***/ create view managers.v_users with (security_barrier=true) as - select id, id_sort, id_external, name_machine, name_human, address_email, is_private, is_locked, date_created, date_changed, date_synced from administers.t_users + select id, id_sort, id_external, name_machine, name_human, address_email, is_private, is_locked, is_coordinator, date_created, date_changed, date_synced from administers.t_users where is_deleted is not true; grant select on managers.v_users to reservation_users_manager; create view managers.v_users_insert with (security_barrier=true) as - select id, id_sort, id_external, name_machine, name_human, address_email, is_private, is_locked, date_created, date_changed, date_synced from administers.t_users - where is_deleted is not true and date_created = localtimestamp and date_changed = localtimestamp and (date_synced is null or date_synced = localtimestamp) + select id, id_sort, id_external, name_machine, name_human, address_email, is_private, is_locked, is_coordinator from administers.t_users + where is_deleted is not true with check option; grant insert on managers.v_users_insert to reservation_users_manager; create view managers.v_users_update with (security_barrier=true) as - select id, id_sort, id_external, name_machine, name_human, address_email, is_private, is_locked, date_changed, date_synced from administers.t_users + select id, id_sort, id_external, name_machine, name_human, address_email, is_private, is_locked, is_coordinator, date_changed, date_synced from administers.t_users where is_deleted is not true and date_changed = localtimestamp and (date_synced is null or date_synced = localtimestamp) with check option; @@ -163,6 +194,11 @@ create materialized view administers.vm_users_date_changed_previous_day as selec create materialized view administers.vm_users_date_changed_previous_month as select * from administers.t_users where date_trunc('month', date_changed) = date_trunc('month', current_timestamp) - interval '1 month'; create materialized view administers.vm_users_date_changed_previous_year as select * from administers.t_users where date_trunc('year', date_changed) = date_trunc('year', current_timestamp) - interval '1 year'; +create materialized view administers.vm_users_date_synced_this_day as select * from administers.t_users where date_trunc('day', date_synced) = date_trunc('day', current_timestamp); +create materialized view administers.vm_users_date_synced_previous_day as select * from administers.t_users where date_trunc('day', date_synced) = date_trunc('day', current_timestamp) - interval '1 day'; +create materialized view administers.vm_users_date_synced_previous_month as select * from administers.t_users where date_trunc('month', date_synced) = date_trunc('month', current_timestamp) - interval '1 month'; +create materialized view administers.vm_users_date_synced_previous_year as select * from administers.t_users where date_trunc('year', date_synced) = date_trunc('year', current_timestamp) - interval '1 year'; + grant select on administers.vm_users_date_created_this_day to reservation_users_administer; grant select on administers.vm_users_date_created_this_day to reservation_users_manager; grant select on administers.vm_users_date_created_previous_day to reservation_users_administer; @@ -181,6 +217,15 @@ grant select on administers.vm_users_date_changed_previous_month to reservation_ grant select on administers.vm_users_date_changed_previous_year to reservation_users_administer; grant select on administers.vm_users_date_changed_previous_year to reservation_users_manager; +grant select on administers.vm_users_date_synced_this_day to reservation_users_administer; +grant select on administers.vm_users_date_synced_this_day to reservation_users_manager; +grant select on administers.vm_users_date_synced_previous_day to reservation_users_administer; +grant select on administers.vm_users_date_synced_previous_day to reservation_users_manager; +grant select on administers.vm_users_date_synced_previous_month to reservation_users_administer; +grant select on administers.vm_users_date_synced_previous_month to reservation_users_manager; +grant select on administers.vm_users_date_synced_previous_year to reservation_users_administer; +grant select on administers.vm_users_date_synced_previous_year to reservation_users_manager; + /*** provide sequence id preservation table ***/ create table administers.t_users_sequences ( @@ -199,23 +244,24 @@ create table administers.t_users_sequences ( ); grant select,insert,update,delete on administers.t_users_sequences to reservation_users_administer; +grant select on administers.t_users_sequences to reservation_users_auditor; /** when using current_user reserved function/word the index gets ignored. To prevent this, create a manual/custom index and alter the behavior of the views to be more explicit. **/ create unique index ci_users_sequences_current_user on administers.t_users_sequences (name_machine) with (fillfactor = 40); create view public.v_users_sequences_locked with (security_barrier=true) as select id, id_user, name_machine, is_locked, date_expire from administers.t_users_sequences - where (name_machine)::text = (current_user)::text and is_locked is true and date_expire >= current_timestamp + where is_locked is true and date_expire >= current_timestamp and (name_machine)::text = (current_user)::text with check option; grant select,insert,update,delete on v_users_sequences_locked to reservation_users; create view public.v_users_sequences_unlocked with (security_barrier=true) as select id, id_user, name_machine, is_locked, date_expire from administers.t_users_sequences - where (name_machine)::text = (current_user)::text and (is_locked is not true or date_expire < current_timestamp) + where (is_locked is not true or date_expire < current_timestamp) and (name_machine)::text = (current_user)::text with check option; -grant select,update,delete on v_users_sequences_unlocked to reservation_users;; +grant select,update,delete on v_users_sequences_unlocked to reservation_users; diff --git a/documentation/access_roles.txt b/documentation/access_roles.txt new file mode 100644 index 0000000..4f487a8 --- /dev/null +++ b/documentation/access_roles.txt @@ -0,0 +1,87 @@ +This focuses on database access roles that are being considered standard. + +This is a minimal set of roles to be used for access to the database and its underlining functionality. +This minimal set naming scheme is then to be used by many of the example projects provided within this repository. +Systems may also impose a sub-set of access roles used within the database via tables, those such roles do not gain the security advantages but are more flexible. + + +The roles: +- administer: + - This is essentially the root account as is intended to have (almost) full access to everything. + - There is a small set of actions that are restricted, generally for integrity reasons, see the appropriate database sql files of a given project for details. + +- manager: + - This is essentially a non-technical administer account. + - This grants the user almost full control to the system except for highly technical areas. + - For the most part, when administer is given access to some table, view, etc.. so is manager. + - Should never be allowed to create administer users, but should be able to create other accounts. + +- auditor: + - Thus role is intended for users who may need to view and review the system for auding/legal reasons. + - Generally, this should have read (select) access to everything, especially logs, but should never be able to write to anything. + +- publisher: + - This role is intended for users who should have access to make information public. + - A publisher does not make changes other than acting as a final approver. + +- insurer: + - This role is intended for users who need to be involved in insurance related information. + +- financer: + - This role is intended for users involve in finance or financially related information. + +- reviewer: + - This role is intended for users who need to approve, deny, or otherwise be involved in some sort of workflow process. + - It should be very common for projects to have a sub-set of reviewer access roles via tables. + +- drafter: + - This role is intended for users who create content but are not allowed to publish that content. + - This is primarily used for workflow. + +- (system)_users: + - Replace (system) with the appropriate name for the system, generally the database name (for example, the reservation system, this would be reservation_users). + - Provides basic access to the database, such as ldap integration. + - All other roles should be a sub-set of this role. + - Do not confuse this with "(system)_user" (described below), which is considered a special-case user account. + - All users should be part of this role. + +- public_users: + - Provides access to the database but only for information that should be made available to the world. + - This role has the least amount of access. + - Should not be assigned to any user with the (system)_users role or any such subset. + + +These roles can be further grouped based on major type of access control purposes. +There are five groups: +- Management Group: + - administer, manager. + - These are the administrative accounts and generally have full if not almost full access to the entire database. + +- Legal Group: + - auditor + - These are for special accounts that (often for legal reasons) need full read access to the entire database. + +- Special Group: + - publisher, insurer, financer, reviewer, drafter + - These are for accounts that are non-administrative but have additional access to the database beyond basic user access. + +- Basic Group: + - (system)_users + - These are for accounts that need login access and are granted access that every user on the system should have access to. + +- Public Group: + - public_users + - These are for anonymous accounts and other public access entities. + - Everything this should be able to access is generally considered public information. + + +There are also special user accounts: +- public_user: + - This account should not require a password to login and essentially represent a public web user. + - Some systems are designed to be private and require login, these systems generally provided almost no access for public_user. + - Because there is no password and all data is considered public, ssl is not needed and access to/from the database should have higher performance than other user accounts. + +- (system)_user: + - Replace (system) with the appropriate name for the system, generally the database name (for example, the reservation system, this would be reservation_user). + - This is the account the system uses for general cron jobs and other automated tasks. + - The access provided here is dependent to the particular system and therefore this may also have or not have a password. diff --git a/documentation/database.txt b/documentation/database.txt new file mode 100644 index 0000000..ac8b43f --- /dev/null +++ b/documentation/database.txt @@ -0,0 +1,48 @@ +The database follows the naming structure explained in the naming.txt documentation. + +Much of my database design strategy is built around sacrificing storage space for performance and efficiency reasons. + +This system extensively uses postgresql's access control functionality to get as much of the access control out of PHP (or something else for that matter) and into the database. +There are some limitations and there is a notable cost in performance. + +The database access control design strategy is based around ldap account names. +Using postgresql's ldap functionality, accounts can be auto-used without restarting or reloading the database. +There is a specific weakness (arguably) in postgresql's design that prevents ldap accounts from being auto-created. +An experimental helper service called autocreate_ldap_accounts_in_postgresql is provided under the programs directory to help facilitate auto-creation of ldap accounts. +Using this helper can also provide a way to auto-assign additional postgresql roles for users based on ldap information. +By basing access control around postgresql ldap, passwords no longer need to be stored in the database and therefore significantly more secure. + +One of the problems with the current design is that the access control uses the current user name. +This is all well in good, except that the access control tests need to be performed on what is essentially a string. +String comparisons are expensive and should be avoided in favor of integers (which happens to be part of the development strategy of this project). +To use the username while have integers would require performing appropriate inner joins on every view access check to get the username. +To avoid using joins, a varchar(128), generally called name_machine or name_machine_user, is provided in many of the tables that include the user id. +The idea here is that the cost of disk space is cheaper than the cost of time. + +Postgresql schemas are used as a form of organization, access control, and order of operations. +As for organization, tables, views, and other database objects are assigned to their appropriate group (preferably, the highest necessary schema based on access control concepts and the purpose and intention of the table/view/etc..). +For access control, most things in their appropriate schema a granted full access while limited access is required to reach a higher schema. +For example, managers are not supposed to create administrator accounts and therefore the t_users table is placed in the administrators schema. +However, the t_groups table has no such restrictions and can be safely placed in the managers schema. +As for order of operations, postgresql provides a database environment variable called search_path. +This search_path provides an order in which schemas may be searched. +Because of a users access control, some schemas may not be available. +This has the convenient effect of allowing multiple identically named tables to be used, but provide different content based on access restrictions. +For example, there are at least two views filtering the user account infomration: managers.v_users and public.v_users. +Users without access to the managers will at least see the public.v_users view. +The view public.v_users provides a limited subset of user rows based on criteria such as if the account is not marked private and then only a limited set of columns are made visible. +The view managers.v_users provides access to far more accounts and many more columns. +This then allows the client software, such as PHP, to not need to understand the access control situation and to only need to select v_users to access user data. + +Postgresql materialized views are experimentally being used to provide a sort of live cache of information. +With my previous database designs, I required multiple write operations for saving certain information that is cached. +Materialized views seem to provide a way to have static (aka: materialized) data instead of using views (which requires building of the data on each request). +This, once again, uses more disk space but improves performance. +The materialized views can then be updated after commit operations or designed cron jobs via the refresh materialized view postgresql command. + +The t_users table (and a few others) are providing a column called 'id_sort'. +Because user account (and similar) data can become massive, performing selects on an arbitrarily large users table can become slow. +This can then slow down site response time, directly affecting the user experience. +This id_sort column is used, in conjunction with custom indexing, to provide a sub-set of the arbitrarily large users table. +The id_sort is simply an ordinal integer (as returned by PHPs ord() function) for the first (lower-cased) letter of the username. +This is obviously not an optimal solution, in part because some alphabets will have more names than others, but I believe it is a good enough solution. diff --git a/program/reservation/reservation_database.php b/program/reservation/reservation_database.php index 401ec34..6a062a9 100644 --- a/program/reservation/reservation_database.php +++ b/program/reservation/reservation_database.php @@ -67,7 +67,7 @@ // configure default settings. $database->do_query('set bytea_output to hex;'); - $database->do_query('set search_path to system,administers,managers,publishers,insurers,financers,reviewers,drafters,users,public;'); + $database->do_query('set search_path to system,administers,managers,auditors,publishers,insurers,financers,reviewers,drafters,users,public;'); $database->do_query('set datestyle to us;'); return new c_base_return_true(); -- 1.8.3.1