diff --git a/.dockerignore b/.dockerignore index 8d25d3e84..6895048b1 100644 --- a/.dockerignore +++ b/.dockerignore @@ -17,6 +17,7 @@ docs/WebCalendar-UserManual.html includes/settings.php java Makefile +sqlite-data release-files tests TODO diff --git a/.gitignore b/.gitignore index b049111bf..f34d28451 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ pub/ __pycache__ *.save *.sha +sqlite-data tests/.phpunit.result.cache vendor/ -wc-icons/ \ No newline at end of file +wc-icons/ diff --git a/Makefile b/Makefile index aee4c241d..b6853e235 100644 --- a/Makefile +++ b/Makefile @@ -47,6 +47,7 @@ $(PHPMAILER_DIR)/SMTP.php: $(PHPMAILER_VENDOR_DIR)/SMTP.php _ICONS: \ $(BOOTSTRAP_ICON_DIR)/printer.svg \ $(BOOTSTRAP_ICON_DIR)/search.svg \ + $(BOOTSTRAP_ICON_DIR)/arrow-left.svg \ $(BOOTSTRAP_ICON_DIR)/arrow-right-circle.svg \ $(BOOTSTRAP_ICON_DIR)/arrow-left-circle.svg \ $(BOOTSTRAP_ICON_DIR)/arrow-up-short.svg \ @@ -61,7 +62,8 @@ _ICONS: \ $(BOOTSTRAP_ICON_DIR)/check-circle.svg \ $(BOOTSTRAP_ICON_DIR)/trash.svg \ $(BOOTSTRAP_ICON_DIR)/key-fill.svg \ - $(BOOTSTRAP_ICON_DIR)/info-circle-fill.svg + $(BOOTSTRAP_ICON_DIR)/info-circle-fill.svg \ + $(BOOTSTRAP_ICON_DIR)/circle.svg $(BOOTSTRAP_ICON_DIR)/printer.svg: $(BOOTSTRAP_ICON_VENDOR_DIR)/printer.svg cp $< $@ @@ -72,6 +74,9 @@ $(BOOTSTRAP_ICON_DIR)/search.svg: $(BOOTSTRAP_ICON_VENDOR_DIR)/search.svg $(BOOTSTRAP_ICON_DIR)/arrow-right-circle.svg: $(BOOTSTRAP_ICON_VENDOR_DIR)/arrow-right-circle.svg cp $< $@ +$(BOOTSTRAP_ICON_DIR)/arrow-left.svg: $(BOOTSTRAP_ICON_VENDOR_DIR)/arrow-left.svg + cp $< $@ + $(BOOTSTRAP_ICON_DIR)/arrow-left-circle.svg: $(BOOTSTRAP_ICON_VENDOR_DIR)/arrow-left-circle.svg cp $< $@ @@ -114,6 +119,9 @@ $(BOOTSTRAP_ICON_DIR)/key-fill.svg: $(BOOTSTRAP_ICON_VENDOR_DIR)/key-fill.svg $(BOOTSTRAP_ICON_DIR)/info-circle-fill.svg: $(BOOTSTRAP_ICON_VENDOR_DIR)/info-circle-fill.svg cp $< $@ +$(BOOTSTRAP_ICON_DIR)/circle.svg: $(BOOTSTRAP_ICON_VENDOR_DIR)/circle.svg + cp $< $@ + includes/load_assets.php: \ pub/bootstrap.min.css \ pub/bootstrap.min.css.sha \ diff --git a/UPGRADING.html b/UPGRADING.html index b928d5f29..a0914a9bb 100644 --- a/UPGRADING.html +++ b/UPGRADING.html @@ -15,7 +15,7 @@

WebCalendar Upgrading Notes

- +
WebCalendar Version:1.9.101.9.12

Important News: A major improvement beginning with Version 1.1 is the addition of an automated installation script. This script will guide you through the installation process and help identify any problem areas that might prevent successful installation or operation of WebCalendar. diff --git a/admin.php b/admin.php index 4419188c5..65d607294 100644 --- a/admin.php +++ b/admin.php @@ -678,9 +678,7 @@ function save_pref ( $prefs, $src ) { . print_radio ( 'CATEGORIES_ENABLED' ) . '

' - . print_radio ( 'ENABLE_ICON_UPLOADS' ) . '' . ( ! is_dir ( 'wc-icons/' ) - ? str_replace ( 'XXX', 'wc-icons', - translate ( '(Requires XXX folder to exist.)' ) ) : '' ) . '
+ . print_radio ( 'ENABLE_ICON_UPLOADS' ) . '
@@ -132,9 +102,6 @@ foreach ($categories as $K => $V) { if ($K < 1) continue; - $catIcon = $icon_path . 'cat-' . $K . '.gif'; - if (!file_exists($catIcon)) - $catIcon = $icon_path . 'cat-' . $K . '.png'; $catStr = '' . htmlentities($V['cat_name']) . ''; @@ -147,8 +114,11 @@ $global_found = true; } - echo (file_exists($catIcon) ? ''
-        . $catIconStr . '' : '') . ''; + if (!empty($V['cat_icon_mime'])) { + echo ''
+        . $catIconStr . ''; + } + echo ''; } echo ' '; diff --git a/category_handler.php b/category_handler.php index 4a6c42311..f5cea9fa6 100644 --- a/category_handler.php +++ b/category_handler.php @@ -4,19 +4,21 @@ $icon_max_size = '6000'; $icon_path = 'wc-icons/'; -/** - * Rename any icons associated with this cat_id. - */ -function renameIcon($id) -{ - global $icon_path; - $bakIcon = $catIcon = $icon_path . 'cat-'; - $bakIcon .= date('YmdHis') . '.gif'; - $catIcon .= $id . '.gif'; - if (!file_exists($catIcon)) - $catIcon = $icon_path . '/cat-' . $id . '.png'; - if (file_exists($catIcon)) - rename($catIcon, $bakIcon); + +function updateIconBlob($catId, $iconData, $iconMimeType) { + // Update the icon binary data in the database. + dbi_update_blob( + 'webcal_categories', + 'cat_icon_blob', + "cat_id = $catId", + $iconData + ); + + // Update the MIME type of the icon in the database. + dbi_execute( + 'UPDATE webcal_categories SET cat_icon_mime = ? WHERE cat_id = ?', + [$iconMimeType, $catId] + ); } // Does the category belong to the user? @@ -74,8 +76,6 @@ function renameIcon($id) )) { $error = db_error(); } - // Rename any icons associated with this cat_id. - renameIcon($id); } else if (empty($error) && empty($catname)) { $error = translate('Category name is required'); } else if (empty($error)) { @@ -87,9 +87,6 @@ function renameIcon($id) [$catname, $catcolor, $id] )) $error = db_error(); - - if (!empty($delIcon) && $delIcon == 'Y') - renameIcon($id); } else { // Add new category. // Get new id. @@ -109,42 +106,34 @@ function renameIcon($id) } else $error = db_error(); } - if (empty($delIcon) && is_dir($icon_path) && (!empty($ENABLE_ICON_UPLOADS) && $ENABLE_ICON_UPLOADS == 'Y' || - $is_admin)) { + if (empty($delIcon) && (!empty($ENABLE_ICON_UPLOADS) && $ENABLE_ICON_UPLOADS == 'Y' || $is_admin)) { // Save icon if uploaded. if (!empty($file['tmp_name'])) { - if (($file['type'] == 'image/gif' || $file['type'] == 'image/png') - && $file['size'] <= $icon_max_size - ) { - // $icon_props = getimagesize( $file['tmp_name'] ); - // print_r ($icon_props ); - $path_parts = pathinfo($_SERVER['SCRIPT_FILENAME']); - $fullIcon = $path_parts['dirname'] . '/' - . $icon_path . 'cat-' . $id; - if ($file['type'] == 'image/gif') - $fullIcon .= '.gif'; - else - $fullIcon .= '.png'; - renameIcon($id); - $file_result = move_uploaded_file($file['tmp_name'], $fullIcon); - // echo "Upload Result:" . $file_result; - } else if ($file['size'] > $icon_max_size) { - $error = translate('File size exceeds maximum.'); - } else if ( - $file['type'] != 'image/gif' && - $file['type'] != 'image/png' - ) { - $error = translate('File is not a GIF or PNG image') . ': ' - . $file['type']; - } + if (($file['type'] == 'image/gif' || $file['type'] == 'image/png') + && $file['size'] <= $icon_max_size) { + // Get binary data of the icon. + $iconData = file_get_contents($file['tmp_name']); + // Update the icon data and MIME type in the database. + updateIconBlob($id, $iconData, $file['type']); + } else if ($file['size'] > $icon_max_size) { + $error = translate('File size exceeds maximum.'); + } else if ( + $file['type'] != 'image/gif' && + $file['type'] != 'image/png' + ) { + $error = translate('File is not a GIF or PNG image') . ': ' + . $file['type']; + } } // Copy icon if local file specified. $urlname = getPostvalue('urlname'); if (!empty($urlname) && file_exists($icon_path . $urlname)) { - if (preg_match('/.(gif|GIF)$/', $urlname)) - copy($icon_path . $urlname, $icon_path . 'cat-' . $id . '.gif'); - else - copy($icon_path . $urlname, $icon_path . 'cat-' . $id . '.png'); + // Get binary data of the icon. + $iconData = file_get_contents($icon_path . $urlname); + // Determine the MIME type based on the file extension. + $iconMimeType = (preg_match('/.(gif|GIF)$/', $urlname)) ? 'image/gif' : 'image/png'; + // Update the icon data and MIME type in the database. + updateIconBlob($id, $iconData, $iconMimeType); } } } diff --git a/composer.json b/composer.json index bd0811f59..9125a46af 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "k5n/webcalendar", "type": "project", "description": "Multi-user web-based calendar app", - "version": "1.9.10", + "version": "1.9.12", "homepage": "https://www.k5n.us/webcalendar/", "authors": [ { diff --git a/composer.lock b/composer.lock index d7adbc7a6..91982ab86 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c1feaefa310526e57a89a1f696f398e3", + "content-hash": "f79c4018d6e61e62b0f7342654c1d79a", "packages": [ { "name": "ckeditor/ckeditor", diff --git a/getIcon.php b/getIcon.php new file mode 100644 index 000000000..680c47bbf --- /dev/null +++ b/getIcon.php @@ -0,0 +1,23 @@ + + + \ No newline at end of file diff --git a/images/bootstrap-icons/circle.svg b/images/bootstrap-icons/circle.svg new file mode 100644 index 000000000..dc57919b3 --- /dev/null +++ b/images/bootstrap-icons/circle.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/includes/config.php b/includes/config.php index cd8bc4b26..825ea5c33 100644 --- a/includes/config.php +++ b/includes/config.php @@ -20,6 +20,26 @@ // See composer.json for version. require_once 'load_assets.php'; +// Define possible app settings and their types +$config_possible_settings = [ + 'install_password' => 'string', + 'install_password_hint' => 'string', + 'db_cachedir' => 'string', + 'db_database' => 'string', + 'db_debug' => 'boolean', + 'db_host' => 'string', + 'db_login' => 'string', + 'db_password' => 'string', + 'db_persistent' => 'boolean', + 'db_type' => 'string', + 'readonly' => 'string', # "Y" or "N" + 'single_user' => 'string', # "Y" or "N" + 'use_http_auth' => 'boolean', + 'user_inc' => 'string', + 'config_inc' => 'string', + 'mode' => 'string' # "dev" or "prod" +]; + /** * Prints a fatal error message to the user along with a link to the * Troubleshooting section of the WebCalendar System Administrator's Guide. @@ -133,37 +153,21 @@ function get_full_include_path($filename) * @global string $TROUBLE_URL URL pointing to the Troubleshooting section. * @global string $user_inc Indicates the type of user authentication. */ - -function do_config() +function do_config($callingFromInstall=false) { - global $db_database, $db_host, $db_login, $db_password, $db_persistent, + global $db_database, $db_debug, $db_host, $db_login, $db_password, $db_persistent, $db_type, $ignore_user_case, $NONUSER_PREFIX, $phpdbiVerbose, $PROGRAM_DATE, $PROGRAM_NAME, $PROGRAM_URL, $PROGRAM_VERSION, $readonly, $run_mode, $settings, $single_user, $single_user_login, $TROUBLE_URL, $user_inc, $use_http_auth; + global $config_possible_settings; // Define possible app settings and their types - $possible_settings = [ - 'install_password' => 'string', - 'db_cachedir' => 'string', - 'db_database' => 'string', - 'db_debug' => 'boolean', - 'db_host' => 'string', - 'db_login' => 'string', - 'db_password' => 'string', - 'db_persistent' => 'boolean', - 'db_type' => 'string', - 'readonly' => 'string', # "Y" or "N" - 'single_user' => 'string', # "Y" or "N" - 'use_http_auth' => 'boolean', - 'user_inc' => 'string', - 'config_inc' => 'string', - 'mode' => 'string' # "dev" or "prod" - ]; + $possible_settings = $config_possible_settings; // When changing PROGRAM VERSION, also change it in install/default_config.php - $PROGRAM_VERSION = 'v1.9.10'; + $PROGRAM_VERSION = 'v1.9.12'; // Update PROGRAM_DATE with official release data - $PROGRAM_DATE = '02 Oct 2023'; + $PROGRAM_DATE = '03 Nov 2023'; $PROGRAM_NAME = 'WebCalendar ' . "$PROGRAM_VERSION ($PROGRAM_DATE)"; $PROGRAM_URL = 'http://k5n.us/wp/webcalendar/'; @@ -191,6 +195,9 @@ function do_config() // Load from settings.php file $settings_content = file_get_contents(__DIR__ . '/settings.php'); if (empty($settings_content)) { + if ($callingFromInstall) { + return; // not an error during install + } // There is no settings.php file. // Redirect user to install page if it exists. if (file_exists('install/index.php')) { @@ -206,6 +213,7 @@ function do_config() $value = trim($matches[1]); $settings[$key] = ($type === 'boolean') ? filter_var($value, FILTER_VALIDATE_BOOLEAN) : $value; } else { + // Setting not found if ($type === 'boolean') { $settings[$key] = false; } @@ -228,25 +236,34 @@ function do_config() $db_persistent = (preg_match( '/(1|yes|true|on)/i', $settings['db_persistent'] - ) ? '1' : '0'); + ) ? true : false ); + $db_debug = (preg_match( + '/(1|yes|true|on)/i', + $settings['db_debug'] + ) ? true : false); $db_type = $settings['db_type']; // If no db settings, then user has likely started install but not yet // completed. So, send them back to the install script. if (empty($db_type)) { + if ($callingFromInstall) { + return; // not an error during install + } if (file_exists('install/index.php')) { - header('Location: install/index.php?reason=no_dbtype'); + header('Location: install/index.php'); exit; } else die_miserable_death(translate('Incomplete settings.php file...')); } // Use 'db_cachedir' if found, otherwise look for 'cachedir'. - if (!empty($settings['db_cachedir'])) - dbi_init_cache($settings['db_cachedir']); - else - if (!empty($settings['cachedir'])) - dbi_init_cache($settings['cachedir']); + if (!$callingFromInstall) { + if (!empty($settings['db_cachedir'])) + dbi_init_cache($settings['db_cachedir']); + else + if (!empty($settings['cachedir'])) + dbi_init_cache($settings['cachedir']); + } if ( !empty($settings['db_debug']) @@ -254,13 +271,15 @@ function do_config() ) dbi_set_debug(true); - foreach ( ['db_type', 'db_host', 'db_login'] as $s) { - if (empty($settings[$s])) - die_miserable_death(str_replace( - 'XXX', - $s, - translate('Could not find XXX defined in...') - )); + if (!$callingFromInstall) { + foreach ( ['db_type', 'db_host', 'db_login'] as $s) { + if (empty($settings[$s])) + die_miserable_death(str_replace( + 'XXX', + $s, + translate('Could not find XXX defined in...') + )); + } } // Allow special settings of 'none' in some settings[] values. @@ -269,25 +288,26 @@ function do_config() $db_password = (empty($db_password) || $db_password == 'none' ? '' : $db_password); - if (empty($settings['readonly'])) - $settings['readonly'] = 'N'; - $readonly = preg_match( - '/(1|yes|true|on|y)/i', - $settings['readonly'] - ) ? 'Y' : 'N'; + $readonly = $settings['readonly'] = (!empty($settings['readonly']) + && preg_match('/(1|true|yes|enable|on)/i', $settings['readonly'])) ? 'Y' : 'N'; + if (empty($settings['mode'])) $settings['mode'] = 'prod'; $run_mode = (preg_match('/(dev)/i', $settings['mode']) ? 'dev' : 'prod'); $phpdbiVerbose = ($run_mode == 'dev'); + $single_user = $settings['single_user'] = (!empty($settings['single_user']) + && preg_match('/(1|true|yes|enable|on)/i', $settings['single_user'])) ? 'Y' : 'N'; if (isset($single_user) && $single_user == 'Y') { $single_user_login = $settings['single_user_login']; - if (empty($single_user_login)) - die_miserable_death(str_replace( - 'XXX', - 'single_user_login', - translate('You must define XXX in') - )); + if (!$callingFromInstall) { + if (empty($single_user_login)) + die_miserable_death(str_replace( + 'XXX', + 'single_user_login', + translate('You must define XXX in') + )); + } } else { $single_user = 'N'; $single_user_login = ''; @@ -302,8 +322,7 @@ function do_config() $db_database = get_full_include_path($db_database); } - // & does not work here...leave it as &. - $locateStr = 'Location: install/index.php?action=mismatch&version='; + $locateStr = 'Location: install/index.php'; // Check the current installation version. // Redirect user to install page if it is different from stored value. @@ -311,7 +330,7 @@ function do_config() // (typically through the web-based install pages). $c = @dbi_connect($db_host, $db_login, $db_password, $db_database, false); - if ($c) { + if ($c && !$callingFromInstall) { $rows = dbi_get_cached_rows('SELECT cal_value FROM webcal_config WHERE cal_setting = \'WEBCAL_PROGRAM_VERSION\''); @@ -339,9 +358,11 @@ function do_config() } dbi_close($c); } else { - // Must mean we don't have a settings.php file or env variables. - header($locateStr . 'UNKNOWN'); - exit; + if (!$callingFromInstall) { + // Must mean we don't have a settings.php file or env variables. + header($locateStr . 'UNKNOWN'); + exit; + } } // We can add extra "nonuser" calendars such as a holiday, corporate, @@ -355,3 +376,14 @@ function do_config() return $settings; } + + +function setSettingsInSession() { + global $config_possible_settings, $settings; + //echo "
settings:\n"; print_r($settings); echo "
"; + foreach ($config_possible_settings as $key => $type) { + if (isset($settings[$key])) { + $_SESSION[$key] = $settings[$key]; + } + } +} diff --git a/includes/dbi4php.php b/includes/dbi4php.php index 3716d9672..034fc1252 100644 --- a/includes/dbi4php.php +++ b/includes/dbi4php.php @@ -151,20 +151,25 @@ function dbi_connect( $host, $login, $password, $database, $lazy = true ) { return $c; } else return false; - } elseif( strcmp( $GLOBALS['db_type'], 'mysqli' ) == 0 ) { - #mysqli_report(MYSQLI_REPORT_ALL); - $c = new mysqli( $host, $login, $password, $database ); - - if( $c ) { - if( mysqli_connect_errno() && ! empty( $database ) ) + } elseif (strcmp($GLOBALS['db_type'], 'mysqli') == 0) { + // mysqli_report(MYSQLI_REPORT_ALL); + $c = null; + $errorString = ""; + try { + $c = new mysqli($host, $login, $password, $database); + if ($c->connect_error) { + $db_connection_info['last_error'] = $c->connect_error; return false; + } - $db_connection_info['connected'] = true; - $db_connection_info['connection'] = - $GLOBALS['db_connection'] = $c; + $db_connection_info['connected'] = true; + $db_connection_info['connection'] = $GLOBALS['db_connection'] = $c; + $db_connection_info['last_error'] = ''; return $c; - } else + } catch (Exception $e) { + $db_connection_info['last_error'] = $e->getMessage(); return false; + } } elseif( strcmp( $GLOBALS['db_type'], 'odbc' ) == 0 ) { $c = ( $GLOBALS['db_persistent'] ? odbc_pconnect( $database, $login, $password ) @@ -216,15 +221,16 @@ function dbi_connect( $host, $login, $password, $database, $lazy = true ) { $GLOBALS['sqlite_c'] = $c; return $c; } elseif( strcmp( $GLOBALS['db_type'], 'sqlite3' ) == 0 ) { - $c = new SQLite3 ( $database ); - - if( ! $c ) { - echo str_replace( 'XXX', $db_sqlite_error_str, - translate( 'Error connecting to database XXX' ) ) . "\n"; - exit; + try { + $c = new SQLite3($database); + $db_connection_info['connected'] = true; + $db_connection_info['connection'] = $GLOBALS['sqlite3_c'] = $c; + $db_connection_info['last_error'] = ''; + return $c; + } catch (Exception $e) { + $GLOBALS['db_sqlite_error_str'] = $db_connection_info['last_error'] = $e->getMessage(); + return false; } - $db_connection_info['connected'] = true; - $db_connection_info['connection'] = $GLOBALS['sqlite3_c'] = $c; return $c; } else dbi_fatal_error( 'dbi_connect(): ' @@ -409,11 +415,12 @@ function dbi_query( $sql, $fatalOnError = true, $showError = true ) { } if( $found_db_type ) { - if( ! $res ) + if( ! $res ) { + //echo "Db error: " . dbi_error() . "
\n"; dbi_fatal_error( translate( 'Error executing query.' ) . ( $phpdbiVerbose ? ( dbi_error() . "\n\n
\n" . $sql ) : '' ), $fatalOnError, $showError ); - + } return $res; } else dbi_fatal_error( 'dbi_query(): ' . translate( 'db_type not defined.' ) ); @@ -667,9 +674,13 @@ function dbi_error() { $ret = mssql_get_last_message(); elseif( strcmp( $GLOBALS['db_type'], 'mysql' ) == 0 ) $ret = mysql_error(); - elseif( strcmp( $GLOBALS['db_type'], 'mysqli' ) == 0 ) - $ret = $GLOBALS['db_connection']->error; - elseif( strcmp( $GLOBALS['db_type'], 'odbc' ) == 0 ) + elseif (strcmp($GLOBALS['db_type'], 'mysqli') == 0) { + if (!empty($GLOBALS['db_connection_info']['last_error'])) { + $ret = $GLOBALS['db_connection_info']['last_error']; + } else { + $ret = $GLOBALS['db_connection']->error; + } + } elseif( strcmp( $GLOBALS['db_type'], 'odbc' ) == 0 ) // No way to get error from ODBC API. $ret = translate( 'Unknown ODBC error.' ); elseif( strcmp( $GLOBALS['db_type'], 'oracle' ) == 0 ) { @@ -686,7 +697,16 @@ function dbi_error() { $GLOBALS['db_sqlite_error_str'] = ''; } } elseif ( strcmp ( $GLOBALS['db_type'], 'sqlite3' ) == 0 ) { - $ret = $GLOBALS['sqlite3_c']->lastErrorMsg (); + try { + if ( empty($$GLOBALS['sqlite3_c']) || !empty($GLOBALS['db_sqlite_error_str'])) { + $ret = $GLOBALS['db_sqlite_error_str']; + } else { + $ret = $GLOBALS['sqlite3_c']->lastErrorMsg (); + } + } catch ( Exception $e) { + $GLOBALS['db_sqlite_error_str'] = $e->getMessage(); + $ret = $e->getMessage(); + } } else $ret = 'dbi_error(): ' . translate( 'db_type not defined.' ); @@ -776,6 +796,7 @@ function dbi_escape_string( $string ) { function dbi_execute ( $sql, $params = [], $fatalOnError = true, $showError = true ) { + //echo "SQL: $sql
\n"; if( count( $params ) == 0 ) return dbi_query( $sql, $fatalOnError, $showError ); diff --git a/includes/functions.php b/includes/functions.php index 0fc933e94..a37afa831 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -3110,7 +3110,7 @@ function get_preferred_view ( $indate = '', $args = '' ) { $xdate = ( empty ( $indate ) ? $thisdate : $indate ); $url .= ( empty ( $xdate ) ? '' : ( strstr ( $url, '?' ) ? '&' : '?' ) - . 'date=' . $xdate ); + . 'date=' . ( $xdate instanceof DateTime ? $xdate->format('Ymd') : $xdate ) ); $url .= ( empty ( $args ) ? '' : ( strstr ( $url, '?' ) ? '&' : '?' ) . $args ); @@ -3602,9 +3602,7 @@ function html_for_event_day_at_a_glance ( $event, $date ) { $time_only = 'N'; $view_text = translate ( 'View this event' ); - $catIcon = 'wc-icons/cat-' . $getCat . '.gif'; - if ( ! file_exists ( $catIcon ) ) - $catIcon = 'wc-icons/cat-' . $getCat . '.png'; + $catIcon = get_category_icon_url($getCat); $key++; if( access_is_enabled() ) { @@ -3758,9 +3756,7 @@ function html_for_event_week_at_a_glance ( $event, $date, $time_only = 'N'; $title = ' 0 ) { - $catIcon = 'wc-icons/cat-' . $catNum . '.gif'; - if ( ! file_exists ( $catIcon ) ) - $catIcon = 'wc-icons/cat-' . $catNum . '.png'; - if ( ! file_exists ( $catIcon ) ) - $catIcon = ''; + $catIcon = get_category_icon_url($catNum); } if ( empty ( $catIcon ) ) diff --git a/includes/init.php b/includes/init.php index d5fc235ee..cc454e375 100644 --- a/includes/init.php +++ b/includes/init.php @@ -360,7 +360,7 @@ function print_trailer( $include_nav_links = true, $closeDb = true, $MENU_DATE_TOP, $MENU_ENABLED, $NONUSER_ENABLED, $PUBLIC_ACCESS, $PUBLIC_ACCESS_CAN_ADD, $PUBLIC_ACCESS_FULLNAME, $PUBLIC_ACCESS_OTHERS, $readonly, $REPORTS_ENABLED, $REQUIRE_APPROVALS, $single_user, $STARTVIEW, - $thisday, $thismonth, $thisyear, $use_http_auth, $user, $views, $WEEK_START; + $SQLLOG, $thisday, $thismonth, $thisyear, $use_http_auth, $user, $views, $WEEK_START; $ret = ''; @@ -393,6 +393,19 @@ function print_trailer( $include_nav_links = true, $closeDb = true, $GLOBALS['ALLOW_HTML_DESCRIPTION'] == 'Y' && in_array ( $GLOBALS['SCRIPT'], $pagesWithFullEditor ); + $debug = ''; + if (dbi_get_debug()) { + $debug = '
' + . 'Executed queries:' . dbi_num_queries() + . '   Cached queries:' . dbi_num_cached_queries() + . "
    \n"; + $log = $GLOBALS['SQLLOG']; + $logcnt = count ( $log ); + for ( $i = 0; $i < $logcnt; $i++ ) { + $debug .= '
  1. ' . $log[$i] . '
  2. '; + } + $debug .= "
\n
\n"; + } return $ret . '' . ( $includeCkeditor ? @@ -408,8 +421,8 @@ function print_trailer( $include_nav_links = true, $closeDb = true,

' . 'Valid XHTML 1.0!

' : '' )/* Close HTML page properly. */ . ' -
- + ' . $debug . + ' '; } diff --git a/includes/xcal.php b/includes/xcal.php index b805801f8..998d31590 100644 --- a/includes/xcal.php +++ b/includes/xcal.php @@ -2627,7 +2627,7 @@ function format_ical ( $event ) { } } - $fevent['UID'] = $event['uid']; + $fevent['UID'] = $event['uid'] ?? null; // Process VALARM stuff if ( ! empty ( $event['alarm_trigger'] ) ) { $fevent['AlarmSet'] = 1; diff --git a/install/default_config.php b/install/default_config.php index 07592af8a..e8b33e37d 100644 --- a/install/default_config.php +++ b/install/default_config.php @@ -153,7 +153,7 @@ 'USER_RSS_ENABLED' => 'N', 'USER_SEES_ONLY_HIS_GROUPS' => 'Y', 'USER_SORT_ORDER' => 'cal_lastname, cal_firstname', - 'WEBCAL_PROGRAM_VERSION' => 'v1.9.10', + 'WEBCAL_PROGRAM_VERSION' => 'v1.9.12', 'WEEK_START' => '0', 'WEEKEND_START' => '6', 'WEEKENDBG' => '#d0d0d0', diff --git a/install/headless.php b/install/headless.php index dfc8c9576..cdcab219e 100644 --- a/install/headless.php +++ b/install/headless.php @@ -95,7 +95,7 @@ default: $install_filename .= 'mysql.sql'; } - db_populate( $install_filename, $display_sql ); + executeSqlFromFile($install_filename); } // Convert passwords to secure hashes if needed. diff --git a/install/index.php b/install/index.php index 26de7cbfb..569ea71b2 100644 --- a/install/index.php +++ b/install/index.php @@ -1,12 +1,12 @@ '; - -$checked = ' checked'; -$selected= ' selected'; +$debugInstaller = false; // Set to true to get more details on the installer pages -$setting_correct_img = '!'; -$setting_wrong_img = '!'; +do_config(true); +ini_set('session.cookie_lifetime', 3600); // 3600 seconds = 1 hour +session_name('WebCalendar-Install-' . __DIR__); +session_start(); +if (empty($_SESSION['initialized'])) { + // New session. Load the current settings found in either env vars or includes/settings.php + // into $_SESSION. + setSettingsInSession(); + $_SESSION['initialized'] = 1; +} +$validUser = (isset($_SESSION['validUser']) && !empty($_SESSION['validUser'])) ? true : false; +$phpSettingsAcked = (isset($_SESSION['phpSettingsAcked']) && !empty($_SESSION['phpSettingsAcked'])) ? true : false; + +function tryDbConnect() +{ + global $settings, $db_database; + if (!isset($_SESSION['db_host']) || !isset($_SESSION['db_login']) || !isset($_SESSION['db_database'])) { + return false; + } + $c = @dbi_connect( + $_SESSION['db_host'], + $_SESSION['db_login'], + $_SESSION['db_password'], + $_SESSION['db_database'], + false + ); + return !empty($c); +} -// First pass at settings.php. -// We need to read it first in order to get the md5 password. -$fd = @fopen( $file, 'rb', true ); -$settings = []; -$password = ''; -$forcePassword = false; +function isEmptyDatabase() +{ + global $debugInstaller; + try { + // If we have 1 or more users in webcal_user, the db is not empty + $res = dbi_execute('SELECT COUNT(*) FROM webcal_config', [], false, false); + if ($res) { + $row = dbi_fetch_row($res); + dbi_free_result($res); + return $row[0] == 0; + } + } catch (Exception $e) { + if ($debugInstaller) { + echo "Error: " . $e->getMessage() . "
"; + } + // Error connecting to db + } + return true; +} -if( ! empty( $fd ) ) { - while( ! feof( $fd ) ) { - $buffer = trim( fgets( $fd, 4096 ) ); +function getDbVersion() +{ + $dbVersion = 'Unknown'; + $sql = 'SELECT cal_value FROM webcal_config WHERE cal_setting = ?'; + $res = dbi_execute( + $sql, + ['WEBCAL_PROGRAM_VERSION'], + false, + false + ); + if ($res) { + $row = dbi_fetch_row($res); + if ($row) { + $dbVersion = $row[0]; + } + } + return $dbVersion; +} - if( preg_match( '/^(\S+):\s*(.*)/', $buffer, $matches ) ) { - if( $matches[1] == 'install_password' ) - $password = $settings['install_password'] = $matches[2]; +function getAdminUserCount() +{ + $count = 0; + $sql = 'SELECT cal_value FROM webcal_config WHERE cal_setting = ?'; + $res = dbi_execute( + 'SELECT COUNT(*) FROM webcal_user WHERE cal_is_admin = ?', + ['Y'], + false, + false + ); + if ($res) { + $row = dbi_fetch_row($res); + if ($row) { + $count = $row[0]; + } } - } - fclose( $fd ); + return $count; +} - // File exists, but no password. Force them to create a password. - if( empty( $password ) ) - $forcePassword = true; +function getNextStepAction($action) +{ + global $steps; + for ($i = 0; $i < count($steps) - 1; $i++) { + if ($steps[$i]['step'] == $action) { + return $steps[$i + 1]['step']; + } + } + echo "NULL!"; + exit; + return null; } -session_start(); -$doLogin = false; +function getStepUrl($action) +{ + return basename($_SERVER['PHP_SELF']) . '?action=' . htmlentities($action); +} -// Set default Application Name. -if( ! isset( $_SESSION['application_name'] ) ) - $_SESSION['application_name'] = 'WebCalendar'; +function getNextStepUrl($action) +{ + return basename($_SERVER['PHP_SELF']) . '?action=' . getNextStepAction($action); +} -// Set Server URL. -if( ! isset( $_SESSION['server_url'] ) ) { - if( ! empty( $_SERVER['HTTP_HOST'] ) && ! empty( $_SERVER['REQUEST_URI'] ) ) { - $ptr = strpos( $_SERVER['REQUEST_URI'], '/install', 2 ); +function getStepName($action) +{ + global $steps; + for ($i = 0; $i < count($steps); $i++) { + if ($steps[$i]['step'] == $action) { + return $steps[$i]['name']; + } + } + return null; +} - if( $ptr > 0 ) - $_SESSION['server_url'] = $SERVER_URL = 'http://' . $_SERVER['HTTP_HOST'] - . ( ! empty( $_SERVER['SERVER_PORT'] ) && $_SERVER['SERVER_PORT'] != 80 - ? ':' . $_SERVER['SERVER_PORT'] : '' ) - . substr( $_SERVER['REQUEST_URI'], 0, $ptr + 1 ); - } +function printNextPageButton($action, $extraHtml = '') +{ + $nextStep = getNextStepAction($action); + $description = getStepName($nextStep); + echo '' . translate('Next') . ': ' . $description . ''; } -// Handle "Logout" button. -if( 'logout' == getGetValue( 'action' ) ) { - session_destroy(); - Header( 'Location: index.php' ); - exit; +function printSubmitButton($action, $extraHtml = '', $buttonLabel = '') +{ + if (empty($buttonLabel)) { + $buttonLabel = translate('Submit'); + } + $nextStep = getNextStepAction($action); + echo ''; } -$use_env = getenv('WEBCALENDAR_USE_ENV'); -$envpwd = ''; +function redirectToAction($action) +{ + $nextUrl = getStepUrl($action); + header("Location: $nextUrl"); + echo "Redirect"; + exit; +} -// If password already exists, check for valid session. -if ( - ((file_exists($file) && !empty($password)) || (!empty($use_env) && !empty($password))) && - (empty($_SESSION['validuser']) || $_SESSION['validuser'] != $password) -) - // Make user login. - $doLogin = true; +function redirectToNextAction() +{ + global $action; -if (!empty($use_env) && $use_env == 'true') { - $envpwd = getenv('WEBCALENDAR_INSTALL_PASSWORD'); + // Sub-pages should redirect to $nextUrl after a successful form submission + $nextUrl = getNextStepUrl($action); + header("Location: $nextUrl"); + echo "Redirect"; + exit; } -$pwd = getPostValue('password'); -if ((file_exists($file) || $use_env) && !empty($pwd)) { - $_SESSION['validuser'] = ''; - echo ' - - - '; +function redirectToFurthestAvailableAction() +{ + global $steps; - if (md5($pwd) == $password || md5($pwd) == $envpwd) { - $_SESSION['validuser'] = $password; - echo translate( 'Password Accepted' ) . ' - - - '; - } else { - echo ''; - // Invalid password. - echo '
' . translate( 'Password Incorrect' ) . '' . translate( 'Password Incorrect' ); - echo ''; + $lastStep = null; + foreach ($steps as $step) { + if ($step['complete']) { + $lastStep = $step['step']; + } + } + // Sub-pages should redirect to $nextUrl after a successful form submission + $nextUrl = getNextStepUrl($lastStep); + header("Location: $nextUrl"); + echo "Redirect"; exit; - } } -// [0]Display Text [1]ini_get name [2]required value [3]ini_get string search value -//DO NOT TRANSLATE OFF/ON in this section +// Below we analyze the current status to determine which steps are complete. +// If this is a start of a new session, we either read from includes/settings.php or +// get settings from env vars (which takes precedant). The values get stored in +// the session ($_SESSION). As the user makes changes to settings, those changes +// will only apply to $_SESSION values until the user presses the "Save Settings" button +// as part of the "Database Configuration" step. +// Note: That button is not available when using env vars since those settings must be +// changed outside of the WebCalendar file system. + +$usingEnv = getenv('WEBCALENDAR_USE_ENV') ? true : false; +$versionTooltip = str_replace('XXX', '8.0', 'Only PHP XXX or later is supported by WebCalendar'); $php_settings = [ - //[translate ( 'Display Errors' ), 'display_errors', 'ON', false], - [translate ( 'File Uploads' ), 'file_uploads', 'ON', false], - [translate ( 'Allow URL fopen' ), 'allow_url_fopen', 'ON', false], - [translate ( 'Safe Mode' ), 'safe_mode', 'OFF', false] -]; - -//Add 'Safe Mode Allowed Vars' if 'Safe Mode' is enabled -if( get_php_setting( 'safe_mode' ) == 'ON' ) - $php_settings[] = [ - translate('Safe Mode Allowed Vars'), - 'safe_mode_allowed_env_vars', 'TZ', 'TZ']; - -// Set up array to test for some constants -// (display name, constant name, preferred value ) -$php_constants = [ - // future expansion - // ['CRYPT_BLOWFISH',CRYPT_BLOWFISH, 1] - // ['CRYPT_MD5',CRYPT_MD5, 1] - // ['CRYPT_STD_DES',CRYPT_STD_DES, 1] -]; -$php_modules = [ - [translate ( 'GD' ), 'imagepng', 'ON'], + // Description, required setting/value, found value, is-correct, tooltip explanation + [ + translate('PHP Version'), '8.0+', phpversion(), version_compare(phpversion(), '8.0', '>='), + $versionTooltip + ], + [ + translate('GD Module'), 'Installed', function_exists('imagepng') ? translate('Installed') : translate('Not found'), + function_exists('gd_info'), + translate('GD module required for gradient background colors') + ], + [ + translate('Allow File Uploads'), 'ON', get_php_setting('file_uploads'), get_php_setting('file_uploads') == 'ON', + translate('File uploads are required to upload category icons') + ], + [ + translate('Allow URL fopen'), 'ON', get_php_setting('allow_url_fopen'), get_php_setting('allow_url_fopen') == 'ON', + translate('Remote URL fopen is required to load remote calendars') + ], + [ + translate('Safe Mode'), 'OFF', get_php_setting('safe_mode'), get_php_setting('safe_mode') == 'OFF', + translate('Safe Mode needs to be disabled to allow setting env variables to specify the timezone') + ] ]; - -$pwd1 = getPostValue( 'password1' ); -$pwd2 = getPostValue( 'password2' ); -if( file_exists( $file ) && $forcePassword && ! empty( $pwd1 ) ) { - if( $pwd1 != $pwd2 ) { - echo translate( 'Passwords do not match!' ) . "
\n"; - exit; - } - $fd = @fopen( $file, 'a+b', false ); - if( empty( $fd ) ) { - echo '' - . translate( 'Unable to write password to settings.php file' ) - . ''; - exit; - } - fwrite( $fd, '\r\n" ); - fclose( $fd ); - - echo ' - - - ' . translate( 'Password Updated' ) . ' - - ' . $jquery_install . ' - - - -'; - exit; +//echo "
"; print_r($php_settings); echo "
"; +// Has the user modified the App Settings so they are different than settings.php +if (empty($_SESSION['appSettingsModified'])) { + $appSettingsModified = false; +} else { + $appSettingsModified = true; + $_SESSION['appSettingsModified'] = 1; } - -$fd = @fopen( $file, 'rb', false ); -if( ! empty( $fd ) ) { - while( ! feof( $fd ) ) { - $buffer = trim( fgets( $fd, 4096 ) ); - - if( preg_match( '/^#|\/\*/', $buffer ) // comments - || preg_match( '/^<\?/', $buffer ) // start php code - || preg_match( '/^\?\>/', $buffer ) // end php code - ) { - continue; +// Can we connect? +$connectError = ''; +$canConnectDb = tryDbConnect(); +if (!$canConnectDb) + $connectError = dbi_error (); +$emptyDatabase = $canConnectDb ? isEmptyDatabase() : true; +$unsavedDbSettings = !empty($_SESSION['unsavedDbSettings']); // Keep track if Db settings were modified by not yet saved +$reportedDbVersion = 'Unknown'; +$adminUserCount = 0; +$databaseExists = false; +$databaseCurrent = false; +$settingsSaved = true; // True if a valid settings.php found unless user changes settings +if ($canConnectDb) { + $reportedDbVersion = getDbVersion(); + $detectedDbVersion = getDatabaseVersionFromSchema(); + if ($debugInstaller) { + //echo "Db Version: $dbV
"; + } + $adminUserCount = getAdminUserCount(); + if ($detectedDbVersion != $reportedDbVersion) { + // The version set in webcal_config is different than what we found when using + // SQL queries to examine the schema. Override the webcal_config setting + // with what we found. This is likely from a missed SQL update in a prior + // install update. + // Show we alert the user? + } + if ($detectedDbVersion != 'Unknown') { + $databaseExists = true; + $databaseCurrent = ($detectedDbVersion == $PROGRAM_VERSION); + } else if ($_SESSION['db_type'] == 'sqlite3') { + // This is good enough to consider the sqlite3 database created. There is no separate create database function. + $databaseExists = true; } - if( preg_match( '/(\S+):\s*(.*)/', $buffer, $matches ) ) - $settings[$matches[1]] = $matches[2]; - } - fclose( $fd ); - - if( isset( $settings['config_inc'] ) ) { - # Load 3rd party configs from external app - require_once get_full_include_path ( $settings['config_inc'] ); - $settings = do_external_configs( $settings ); - } } - -$action = getGetValue( 'action' ); -// We were sent here because of a mismatch of $PROGRAM_VERSION. -// A simple way to ensure that UPGRADING.html gets read and processed. -if( ! empty( $action ) && $action == 'mismatch' ) - $_SESSION['old_program_version'] = $version = getGetValue( 'version' ); - -// Go to the proper page. -if( ! empty( $action ) && $action == 'switch' ) { - $page = getGetValue( 'page' ); - switch( $page ) { - case 2: - if( ! empty( $_SESSION['validuser'] ) ) { - $_SESSION['step'] = $page; - $onload = 'db_type_handler();'; - } - break; - case 3: - if( ! empty( $_SESSION['validuser'] ) - && ! empty( $_SESSION['db_success'] ) ) - $_SESSION['step'] = $page; - break; - case 4: - if( ! empty( $_SESSION['validuser'] ) - && ! empty( $_SESSION['db_success'] ) - && empty( $_SESSION['db_create'] ) ) { - $_SESSION['step'] = $page; - $onload = 'auth_handler();'; - } - break; - default: - $_SESSION['step'] = 1; - } +// Check PHP settings, set to true only if ALL settings are correct +$phpSettingsCorrect = true; +if ($debugInstaller && $_SERVER['REQUEST_METHOD'] === 'GET') { + echo "

App Settings

\n"; } - -// Is this a call to phpinfo()? -if( ! empty( $action ) && $action == 'phpinfo' ) { - if( ! empty( $_SESSION['validuser'] ) ) - phpinfo(); - else - echo translate( 'You are not authorized.' ); - - exit; +$appSettingsCorrect = isset($_SESSION['readonly']) && isset($_SESSION['user_inc']) && isset($_SESSION['use_http_auth']) && isset($_SESSION['single_user']) + && isset($_SESSION['mode']); + +// If we found an existing db, then this is an update rather than an install. +$installType = ($detectedDbVersion == 'Unknown') ? 'Install' : 'Upgrade'; + +$steps = [ + ["step" => "welcome", "name" => "Welcome / Status", "complete" => true], + ["step" => "auth", "name" => "Authentication", "complete" => isset($_SESSION["validUser"])], + ["step" => "phpsettings", "name" => "PHP Settings", "complete" => $phpSettingsCorrect || !empty($phpSettingsAcked)], + ["step" => "appsettings", "name" => "Application Settings", "complete" => $appSettingsCorrect], + ["step" => "dbsettings", "name" => "Database Configuration", "complete" => $canConnectDb && !$unsavedDbSettings], + ["step" => "createdb", "name" => "Create Database", "complete" => $databaseExists && !$unsavedDbSettings], + ["step" => "dbtables", "name" => "Create/Update Tables", "complete" => $databaseCurrent && !$unsavedDbSettings], + ["step" => "dbload", "name" => "Load Defaults", "complete" => !$emptyDatabase], + ["step" => "adminuser", "name" => "Create Admin User", "complete" => $adminUserCount > 0 && !$unsavedDbSettings], + ["step" => "finish", "name" => "Completion", "complete" => false] +]; +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $action = $_POST['action'] ?? 'welcome'; + // Make sure we received the CSRF token + if (empty($_POST['csrf_form_key'])) { + $_SESSION['alert'] = translate('Your form post was either missing a required session token or timed out.'); + redirectToAction($action); + } +} else { + $action = $_GET['action'] ?? 'welcome'; } -// Session check counter. -if( isset( $_SESSION['check'] ) ) - $_SESSION['check']++; -else - $_SESSION['check'] = 0; - -$canWrite = false; -$exists = file_exists( $file ); - -if( $exists ) - $canWrite = is_writable( $file ); -else { - // Check to see if we can create the settings file. - $testFd = @fopen( $file, 'w+b', false ); - - if( file_exists( $file ) ) - $canWrite = $exists = $forcePassword = true; - - @fclose( $testFd ); +if ($action == 'logout') { // This is helpful when developing/debugging the installer + session_destroy(); + redirectToAction('welcome'); } - -// If we are handling a form POST, -// take that data and put it in settings array. -$x = getPostValue( 'form_db_type' ); - -if( empty( $x ) ) { - // No form was posted. Set defaults if none set yet. - if( ! file_exists( $file ) || count( $settings ) == 1 ) { - $settings['db_cachedir'] = '/tmp'; - $settings['db_database'] = 'intranet'; - $settings['db_host'] = 'localhost'; - $settings['db_login'] = 'webcalendar'; - $settings['db_password'] = 'webcal01'; - $settings['db_persistent'] = - $settings['readonly'] = - $settings['single_user'] = - $settings['use_http_auth'] = 'false'; - if ( function_exists ( 'mysqli_connect' ) ) - $settings['db_type'] = 'mysqli'; - else - $settings['db_type'] = 'mysql'; - $settings['install_password'] = - $settings['single_user_login'] = ''; - $settings['user_inc'] = 'user.php'; - } +// Use array_column to get all 'name' values from the $steps array +$validActions = array_column($steps, 'step'); +// Check if $action is one of the valid actions +if (in_array($action, $validActions)) { + // $action is valid } else { - $settings['db_cachedir'] = getPostValue( 'form_db_cachedir' ); - $settings['db_database'] = getPostValue( 'form_db_database' ); - $settings['db_host'] = getPostValue( 'form_db_host' ); - $settings['db_login'] = getPostValue( 'form_db_login' ); - $settings['db_password'] = getPostValue( 'form_db_password' ); - $settings['db_persistent'] = getPostValue( 'form_db_persistent' ); - $settings['db_type'] = getPostValue( 'form_db_type' ); - $settings['install_password'] = ( isset( $settings['install_password'] ) - ? $settings['install_password'] : '' ); - $settings['readonly'] = ( isset( $settings['readonly'] ) - ? $settings['readonly'] : 'false' ); - $settings['single_user'] = ( isset( $settings['single_user'] ) - ? $settings['single_user'] : 'false' ); - $settings['single_user_login'] = ( isset( $settings['single_user_login'] ) - ? $settings['single_user_login'] : '' ); - $settings['use_http_auth'] = ( isset( $settings['use_http_auth'] ) - ? $settings['use_http_auth'] : 'false' ); - $settings['user_inc'] = ( isset( $settings['user_inc'] ) - ? $settings['user_inc'] : 'user.php' ); + // $action is invalid or not provided + $action = 'welcome'; // switch back to first page } -$y = getPostValue( 'app_settings' ); -if (!empty($y)) { - $formUserStr = getPostValue('form_user_inc'); - $settings['mode'] = getPostValue('form_mode'); - $settings['readonly'] = getPostValue('form_readonly'); - $settings['single_user'] = $settings['use_http_auth'] = 'false'; - $settings['single_user_login'] = getPostValue('form_single_user_login'); - $settings['user_inc'] = 'user.php'; - - if ($formUserStr == 'http') - $settings['use_http_auth'] = 'true'; - elseif ($formUserStr == 'none') - $settings['single_user'] = 'true'; - else - $settings['user_inc'] = $formUserStr; - - // Save Application Name and Server URL. - $_SESSION['application_name'] = getPostValue('form_application_name'); - $_SESSION['server_url'] = getPostValue('form_server_url'); - $db_persistent = false; - $db_type = $settings['db_type']; - $db_database = ($db_type == 'sqlite' || $db_type == 'sqlite3' - ? get_full_include_path($settings['db_database']) - : $settings['db_database']); - - if (empty($settings['db_password'])) - $settings['db_password'] = ''; - - // Use ENV values, not what the user put in the form. - $use_env = getenv('WEBCALENDAR_USE_ENV'); - if ($use_env && strtolower($use_env) === "true") { - $settings['db_host'] = getenv('WEBCALENDAR_DB_HOST'); - $settings['db_login'] = getenv('WEBCALENDAR_DB_LOGIN'); - $settings['db_password'] = getenv('WEBCALENDAR_DB_PASSWORD'); - $db_database = $settings['db_database'] = getenv('WEBCALENDAR_DB_DATABASE'); - } - - $c = dbi_connect( - $settings['db_host'], - $settings['db_login'], - $settings['db_password'], - $db_database, - false - ); - - if ($c) { - if (isset($_SESSION['application_name'])) { - dbi_execute('DELETE FROM webcal_config - WHERE cal_setting = \'APPLICATION_NAME\''); - dbi_execute( - 'INSERT INTO webcal_config ( cal_setting, cal_value ) - VALUES ( \'APPLICATION_NAME\', ? )', - [$_SESSION['application_name']] - ); +// Make sure all prior steps are valid before allowing the user to access a later step. +// Example: don't let user access the appsettings page if they have not logged in on the auth page. +foreach ($steps as $astep) { + if ($astep['step'] == $action) { + // This is the step the user is requesting. + // No prior not-complete steps. Let them proceed. + break; } - if (isset($_SESSION['server_url'])) { - dbi_execute('DELETE FROM webcal_config - WHERE cal_setting = \'SERVER_URL\''); - dbi_execute('INSERT INTO webcal_config ( cal_setting, cal_value ) - VALUES ( "SERVER_URL", ? )', [$_SESSION['server_url']] ); + if (!$astep['complete']) { + // We found a not-completed step before the one the user is requesting. + // Redirect the user back to this step. + // This could happen if the user waits over an hour before proceeding and the session times out, + // causing them to no longer be logged in ('auth' action). + redirectToAction($astep['step']); } - } - $do_load_admin = getPostValue('load_admin'); - - if (!empty($do_load_admin)) { - // Add default admin user if not exists. - db_load_admin(); - // Check if an Admin account exists. - $_SESSION['admin_exists'] = db_check_admin(); - } - $setup_complete = true; } -// Save settings to file now. -if (!empty($x) || !empty($y)) { - if ($use_env) { - // do nothing here since we don't use settings.php when using env vars... - } else { - if ($doLogin) { - // Hack attempt :-) - echo "Bugger off.
"; - exit; - } - foreach ($settings as $k => $v) { - // Don't allow someone to put start/end PHP tags in settings.php - if (preg_match('/<\?(php)?|(\?>)/', $v)) { - echo "Bugger off.
"; - exit; - } - } - $fd = @fopen($file, 'w+b', false); - - if (empty($fd)) - $onload = 'alert( \'' . str_replace( - 'XXX', - $file, - translate('Error Unable to write to file XXX.', true) - ) . "\\n" - . (file_exists($file) - ? translate('Please change the file permissions of this file.', true) - : translate('Please change includes dir permission', true)) . '\' );'; - else { - if (function_exists("date_default_timezone_set")) - date_default_timezone_set("America/New_York"); - fwrite($fd, ' $v) { - if ($v != '
' && $v != '') - fwrite($fd, $k . ': ' . $v . "\r\n"); - } - fwrite($fd, "# end settings.php */\r\n?>\r\n"); - fclose($fd); - if ($post_action != $testSettingsStr && $post_action2 != $createNewStr) - $onload .= 'alert( \'' - . translate('Your settings have been saved.', true) . "\\n\\n' );"; - - // Change to read/write by us only (only applies if we created file) - // and read-only by all others. Would be nice to make it 600, - // but the "send_reminders.php" script is usually run under a different - // user than the web server. - @chmod($file, 0644); +// TODO: Handle form POST here... +$error = ''; +// If the form handler fails, the $error variable should be set. +// If it succeeds, it should do a redirect and exit. +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + // The request is a POST request + // Handle the POST data + $filename = basename('install_' . $action . '_handler.php'); + if (file_exists($filename)) { + include_once($filename); + } else { + $error = "Missing file: $filename"; } - } } -$noStr = translate( 'No' ); -$offStr = translate( 'OFF' ); -$onStr = translate( 'ON' ); -$yesStr = translate( 'Yes' ); - -echo ' +?> + - - ' . translate( 'WebCalendar Setup Wizard' ) . ' - ' - . "\n" . $jquery_install . ' - - - - - ' . - '
'; - -if( empty( $_SESSION['step'] ) || $_SESSION['step'] < 2 ) { - $class = ( version_compare( phpversion(), '7.4.0', '>=' ) ? '' : 'not' ) - . 'recommended'; - echo ' - - - - - - - - - - - - - - - - - '; - foreach( $php_settings as $setting ) { - $ini_get_result = get_php_setting( $setting[1], $setting[3] ); - $class = ( $ini_get_result == $setting[2] ? '' : 'not' ) . 'recommended'; - echo ' - - - - '; - } - foreach( $php_constants as $constant ) { - $class = ( $constant[1] == $constant[2] ? '' : 'not' ) . 'recommended'; - echo ' - - - - '; - } - foreach( $php_modules as $module ) { - $class = ( get_php_modules( $module[1] ) == $module[2] - ? '' : 'not' ) . 'recommended'; - echo ' - - - - '; - } - $settingsStatStr = translate( 'settings.php Status' ); - echo ' - - - - - - - - - - - - ' . $setting_wrong_img . ' ' - . translate( 'The file permissions of settings.php are set...' ) . ': - - '; - // or, if the settings file doesn't exist - // and we can't write to the includes directory... - else - if( ! $exists && ! $canWrite ) - echo ' colspan="2">' . $setting_wrong_img . ' ' - . translate( 'The file permissions of the includes directory are set...' ) - . ':
' . realpath( $fileDir ) . '
- '; - // If settings.php DOES exist & we CAN write to it... - else { - echo '>' - . translate( 'Your settings.php file appears to be valid.' ) . ' - - '; - - if( empty( $_SESSION['validuser'] ) ) { - echo ' - - - - - - -
' - . str_replace( 'XXX', translate( '1' ), $wizardStr ) . '
' - . translate( 'This installation wizard will guide you...' ) . ' - -
' - . translate( 'PHP Version Check' ) . '
' - . translate( 'Check to see if PHP 7.4.0 or greater is installed.' ) . '' . ( $class == 'recommended' - ? $setting_correct_img : $setting_wrong_img ) . ' ' - . translate( 'PHP version' ) . ' ' . phpversion() . '
' . translate( 'PHP Settings' ) - . ( empty( $_SESSION['validuser'] ) - ? '' : ' ' ) . '
' . $setting[0] . '' - . ( $class == 'recommended' ? $setting_correct_img : $setting_wrong_img ) - . ' ' . $ini_get_result . '
' . $constant[0] . '' - . ( $class == 'recommended' - ? $setting_correct_img . ' ' . $onStr - : $setting_wrong_img . ' ' . $offStr ) . '
' . $module[0] . '' - . ( $class == 'recommended' ? $setting_correct_img : $setting_wrong_img ) - . ' ' . get_php_modules( $module[1] ) . '
' - . translate( 'Session Check' ) . '
' - . translate( 'To test the proper operation of sessions...' ) . '' - . ( $_SESSION['check'] > 0 ? $setting_correct_img : $setting_wrong_img ) - . ' ' . translate( 'SESSION COUNTER' ) . ': ' - . $_SESSION['check'] . '
' . $settingsStatStr . ': ' . translate( 'Error' ) - // otherwise, echo a regular header. - : 'header">' . $settingsStatStr ) - . '
' . realpath( $file ) . '
' - . translate( 'Configuration Wizard Password' ) . '
'; +"; +} +?> - if( $doLogin ) - echo ' -
' . csrf_form_key() . ' - - - - - -
' . $passwordStr . ': - - -
-
'; - else - if( $forcePassword ) - echo ' -
' . csrf_form_key () . ' - - - - - - - - - - - - - - - -
' - . translate( 'Create Settings File Password' ) . '
' . $passwordStr . ':
' . translate( 'Password (again)' ) . '
-
'; + + + + WebCalendar Installer + tags for bootstrap and jquery + ?> + + + + + SESSION
";
+        print_r($_SESSION);
+        echo "
"; } - } - echo ' -
' . ( empty( $_SESSION['validuser'] ) ? '' : ' - - - - -
-
' . csrf_form_key() . ' - -
-
' ); - - // BEGIN STEP 2 -} elseif( $_SESSION['step'] == 2 ) { - echo ' - - - - - - - - - - - - - - - - - - - -
' - . str_replace( 'XXX', translate( '2' ), $wizardStr ) . '
' - . translate( 'db setup directions...' ) . '
' - . translate( 'Database Status' ) . '
-
    -'; - - if( ! empty( $_SESSION['db_success'] ) && $_SESSION['db_success'] ) { - echo ' - '; - if( ! empty( $response_msg ) && empty( $response_msg2 ) ) - echo ' - '; - elseif( empty( $response_msg2 ) && empty( $_SESSION['db_success'] ) ) - echo ' -
  • ' . $setting_wrong_img - . ' ' . translate( 'Please Test Settings' ) . '
  • '; - } else - echo ' -
  • ' - . ( empty( $response_msg ) ? '' : ' -
  • ' . $setting_wrong_img - . ' ' . $response_msg . '
  • ' ); - - echo ( empty( $response_msg2 ) ? '' : ' -
  • ' . $setting_wrong_img - . ' ' . $response_msg2 . '
  • ' ) . ' -
-
' - . translate( 'Database Settings' ) . '
-
' . csrf_form_key() . ' - - - - - - - - - - - - - - - - - - - - - - ' - /* This a workaround for postgresql. The db_type should be 'pgsql' - but 'postgresql' is used in a lot of places... - so this is easier for now :( */ - . ( substr( php_sapi_name(), 0, 3 ) <> 'cgi' && - ini_get( ( $sel_db == 'postgresql' - ? 'pgsql' : $sel_db ) . '.allow_persistent' ) ? ' - - - - ' :/* Need to set a default value. */ ' - ' ); - - if( function_exists( 'file_get_contents' ) ) { - if( empty( $sel_cachedir ) ) - $sel_cachedir= $settings['db_cachedir'] = ''; - - echo ' - - - - '; - } //end test for file_get_contents - - echo ( empty( $_SESSION['validuser'] ) ? '' : ' - - - -
 ' - . ' - -
-      - -
' . $cachedirStr . ':
- ' . ( ! empty( $_SESSION['db_noexist'] ) && - empty( $_SESSION['db_success'] ) ? ' - ' : '' ) . ' -
-
-
' ) . ' - - - - - - -
-
' . csrf_form_key() . ' - -
-
-
' . csrf_form_key() . ' - -
-
-
' . csrf_form_key() . ' - -
-
'; -} elseif( $_SESSION['step'] == 3 ) { - $_SESSION['db_updated'] = false; - if( $_SESSION['old_program_version'] == $PROGRAM_VERSION && - empty( $_SESSION['blank_database'] ) ) { - $response_msg = translate( 'All your database tables appear to be up...' ); - $_SESSION['db_updated'] = true; - // $response_msg .= '
Previous Version: ' . - // $_SESSION['old_program_version'] . '
- // New Version: ' . $PROGRAM_VERSION; - } else - $response_msg = ( $_SESSION['old_program_version'] == 'new_install' - ? translate( 'This appears to be a new installation...' ) - : ( empty( $_SESSION['blank_database'] ) - ? str_replace ( ['XXX', 'YYY'], - [$_SESSION['old_program_version'], $PROGRAM_VERSION], - translate( 'This appears to be an upgrade...' ) ) - : translate( 'The database requires some data input...' ) ) ); - - echo ' - - - - - - - - - - - - - - - - '; - else { - echo 'redheader">' - . translate( 'The following database actions are required' ) . ': - '; - - if( $settings['db_type'] == 'odbc' && empty( $_SESSION['db_updated'] ) ) { - if( empty( $_SESSION['odbc_db'] ) ) - $_SESSION['odbc_db'] = 'mysql'; - - echo ' - - - '; + ?> +
+
+ install icon +

WebCalendar

+
+ + =')) ? "Supported" : "Not supported"; + ?> + + +
+ + +
+ +

Steps

+
    + "; + if ($astep['complete']) { + echo ' X '; + } else { + echo ' - '; + } + if ($astep['step'] == $action) { + $step = $astep; + echo ''; + } else { + // Provide clickable link if all links up to this step have been completed, + // allowing user to go back. + if ($priorStepsTrue) { + echo ''; + } + } + echo htmlentities($astep['name']); + if ($priorStepsTrue) { + echo ''; + } + if ($astep['step'] == $action) { + echo '   <---'; + } + echo "\n"; + if (!$astep['complete']) { + $priorStepsTrue = false; + } + } + ?> +
+ +
+ + +
+

System Status

+ +

+ Settings storage:
+ Database connection:
+ Number of admin users:
+ WebCalendar version (installer):
+ WebCalendar version (database):
+ PHP version: ()
+

+
+ +
+ +
+

+
+ " . htmlentities($error) . "
"; + } + ?> + + "; + echo "Error: unsupported action '" . htmlentities($action) . "'"; + } + ?> + +
+ + + + + - echo ' - - - ' - . ( ! empty( $settings['db_type'] ) && $settings['db_type'] != 'sqlite' - && $settings['db_type'] != 'sqlite3' - && empty( $_SESSION['blank_database'] ) ? ' - - - ' : '' ); - } - - echo ' -
' - . str_replace( 'XXX', translate( '3' ), $wizardStr ) . '
' - . translate( 'In this section we will perform...' ) . '
' - . translate( 'Database Status' ) . '
' . $response_msg . '
' . translate( 'No database actions are required.' ) . '
-
' . csrf_form_key() . translate( 'ODBC Underlying Database' ) . ' - -
-
-
' . csrf_form_key() . ' - - -
' . ( empty( $str_parsed_sql ) ? '' : ' -
- ' ) . ' -
-
- - - - - - -
-
' . csrf_form_key() . ' - -
-
-
' . csrf_form_key() . ' - -
-
-
' . csrf_form_key() . ' - -
-
'; -} elseif( $_SESSION['step'] == 4 ) { - if( empty( $settings['mode'] ) ) - $settings['mode'] = 'prod'; - - $mode = ( preg_match( '/dev/', $settings['mode'] ) - ? 'dev' // development - : 'prod' ); // production - echo ' - - - - - ' - . ( ! empty( $_SESSION['tz_conversion'] ) && $_SESSION['tz_conversion'] != 'Y' ? ' - - - - ' : '' )/* end Timezone Conversion */ . ' - - - - - - - -
' - . str_replace( 'XXX', translate( '4' ), $wizardStr ) . '
' - . translate( 'This is the final step in setting up your WebCalendar Installation.' ) - . '
' - . translate( 'Timezone Conversion' ) . '
' . ( $_SESSION['tz_conversion'] != 'Success' ? ' -
' . csrf_form_key() . ' -
  • ' - . translate( 'It appears that you have NOT converted...' ) . '
-
-
' : ' -
  • ' . $tzSuccessStr . '
' ) . ' -
' - . translate( 'Application Settings' ) . '
-
  • ' . ( empty( $PHP_AUTH_USER ) - ? translate( 'HTTP-based authentication was not detected...' ) - : translate( 'HTTP-based authentication was detected...' ) ) - . '
-
- - - ' . csrf_form_key() . ' - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
' . translate( 'Create Default Admin Account' ) - . ': - ' . ( $_SESSION['admin_exists'] == 0 ? ' - ' - . translate( '(Admin Account Not Found)' ) . '' : '' ) . ' -
' . translate( 'Application Name' ) . ':
' . translate( 'Server URL' ) . ':
' - . translate( 'User Authentication' ) . ': - -
   ' . $singleUserStr . ' ' - . $loginStr . ':
' . translate( 'Read-Only' ) . ': - ' - . $yesStr . '     - ' . $noStr . ' -
' . translate( 'Environment' ) . ': - -
-
- - - - -
' - . ( ! empty( $_SESSION['db_success'] ) && $_SESSION['db_success'] && - empty( $dologin ) ? ' - ' - . ( ! empty( $_SESSION['old_program_version'] ) && - ( $_SESSION['old_program_version'] == $PROGRAM_VERSION ) && - !empty( $setup_complete )? ' - ' - : '' ) : '' ) . ( ! empty( $_SESSION['validuser'] ) ? ' - ' - : '' ) . ' - -
'; -} -?> -
+ - +
+ diff --git a/install/install_adminuser.php b/install/install_adminuser.php new file mode 100644 index 000000000..7adcb209b --- /dev/null +++ b/install/install_adminuser.php @@ -0,0 +1,24 @@ +

+ 0); + dbi_free_result($res); + } + echo $msg; + ?> +

+ + 0) { + printNextPageButton($action); + } +?> diff --git a/install/install_adminuser_handler.php b/install/install_adminuser_handler.php new file mode 100644 index 000000000..cfeca355b --- /dev/null +++ b/install/install_adminuser_handler.php @@ -0,0 +1,14 @@ +getMessage(); +} + +if (empty($error)) { + redirectToNextAction(); +} diff --git a/install/install_ajax.php b/install/install_ajax.php new file mode 100644 index 000000000..7926284f7 --- /dev/null +++ b/install/install_ajax.php @@ -0,0 +1,132 @@ +connect_errno == 0); + $error_msg = $c->connect_error . ", login=$login, password=$password, host=$host"; + $c->close(); + } elseif ($_POST['dbType'] == 'sqlite3') { + $c = new SQLite3($database, SQLITE3_OPEN_CREATE | SQLITE3_OPEN_READWRITE); + $ret = true; + $c->close(); + } elseif ($_POST['dbType'] == 'postgresql') { + $c = pg_connect("host=$host dbname=$database user=$login password=$password"); + $ret = ($c !== false); + $error_msg = pg_last_error($c); + pg_close($c); + } elseif ($_POST['dbType'] == 'ibase') { + $c = ibase_connect($database, $login, $password); + $ret = ($c !== false); + $error_msg = ibase_errmsg(); + ibase_close($c); + } elseif ($_POST['dbType'] == 'ibm_db2') { + $c = db2_connect($database, $login, $password); + $ret = ($c !== false); + $error_msg = db2_conn_errormsg($c); + db2_close($c); + } elseif ($_POST['dbType'] == 'odbc') { + $c = odbc_connect("Driver={ODBC Driver 17 for SQL Server};Server=$host;Database=$database;", $login, $password); + $ret = ($c !== false); + $error_msg = odbc_errormsg($c); + odbc_close($c); + } elseif ($_POST['dbType'] == 'oracle') { + $c = oci_connect($login, $password, $host); + $ret = ($c !== false); + $e = oci_error(); + $error_msg = $e['message']; + oci_close($c); + } else { + // Fallback to your original method + $c = @dbi_connect($host, $login, $password, $database, false); + $ret = !empty($c); + $error_msg = dbi_error(); + // might want to capture the error message for this as well, depending on the dbi_connect function. + } + } catch (Exception $e) { + $error_msg = $_POST['dbType'] . " exception: " . $e->getMessage(); + } + + return $ret; +} + + +$response = array(); +ini_set('session.cookie_lifetime', 3600); // 3600 seconds = 1 hour +session_name('WebCalendar-Install-' . __DIR__); +session_start(); + +$errorResponse = array(); +$errorResponse['status'] = "error"; +$errorResponse['error'] = translate('Invalid test connection request'); + +if (empty($_POST['csrf_form_key'])) { + $errorResponse['error'] = translate('Your form post was either missing a required session token or timed out.'); + echo json_encode($errorResponse); + exit; +} + +// Only allow post +if ($_SERVER['REQUEST_METHOD'] === 'GET') { + $errorResponse['error'] .= "\n" . 'GET not supported'; + echo json_encode($errorResponse); + exit; +} +// Must be a valid PHP session already established +if (empty($_SESSION['initialized'])) { + $errorResponse['error'] .= "\n" . 'Invalid session'; + echo json_encode($errorResponse); + exit; +} +$validUser = (isset($_SESSION['validUser']) && !empty($_SESSION['validUser'])) ? true : false; +if (!$validUser) { // User must be logged in to install pages + $errorResponse['error'] .= "\n" . 'Not logged in'; + echo json_encode($errorResponse); + exit; +} + +$requestType = $_POST['request']; + +if ($requestType == 'test-db-connection') { + // Get posted data + $db_type = $_POST['dbType']; + $server = $_POST['server']; + $login = $_POST['login']; + $password = $_POST['password']; + $dbName = $_POST['dbName']; + $dbCacheDir = $_POST['dbCacheDir']; + + $canConnect = testDbConnection($server, $login, $password, $dbName); + + if ($canConnect) { + $response['status'] = "ok"; + } else { + $response['status'] = "error"; + $response['error'] = $error_msg; + } +} else { + $response['status'] = "error"; + $response['error'] = "Unknown request type"; +} + +echo json_encode($response); diff --git a/install/install_appsettings.php b/install/install_appsettings.php new file mode 100644 index 000000000..780467787 --- /dev/null +++ b/install/install_appsettings.php @@ -0,0 +1,207 @@ +"; +?> + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+ > +
+ +
+ + + \ No newline at end of file diff --git a/install/install_appsettings_handler.php b/install/install_appsettings_handler.php new file mode 100644 index 000000000..fea01fc7c --- /dev/null +++ b/install/install_appsettings_handler.php @@ -0,0 +1,38 @@ +"; print_r($_SESSION); echo ""; exit; + // Did the user change anything + $foundChange = false; + foreach ($app_settings as $setting) { + if ($_SESSION[$setting] != $settings[$setting] ){ + $foundChange = true; + } + } + if ($foundChange) { + // Require user to save and overwrite settings.php in a future step. + $_SESSION['appSettingsModified'] = 1; + } + redirectToNextAction(); + } else { + $error = translate('Invalid Application Settings'); + } +} diff --git a/install/install_auth.php b/install/install_auth.php new file mode 100644 index 000000000..98b99b946 --- /dev/null +++ b/install/install_auth.php @@ -0,0 +1,62 @@ +

+ \n

"; + etranslate('Once the installation is complete, you will need not this passphrase again until you want to upgrade your installation. Please take note of your password because there is no way to recover it.'); + ?> +

+
+ + + + + + +
+

+ + + + + + + + + + + + +
+ + + +
+ + + +
+ + + diff --git a/install/install_auth_handler.php b/install/install_auth_handler.php new file mode 100644 index 000000000..642a09912 --- /dev/null +++ b/install/install_auth_handler.php @@ -0,0 +1,65 @@ +format('D, d M Y H:i:s O'); + $content = preg_replace('/updated via install\/index.php on .*/', 'updated via install/index.php on ' . $formattedDate, $content); + + // Write the updated content back to the file + return file_put_contents($file, $content); +} + +// Handle form submission on Auth page (both setting and checking password) +$passwordSet = !empty($_SESSION['install_password']); + +if (!$passwordSet) { + // No password set. New instsall. Set password now. + $password = $_POST['password']; + $password2 = $_POST['password2']; + if ($password != $password2) { + $error = translate('Your passwords must match.'); + } + $hint = $_POST['hint']; + $ret = update_password_in_settings(__DIR__ . '/../includes/settings.php', md5($password), $hint); + if (! $ret) { + $error = 'Error writing includes/settings.php file.'; + } else { + redirectToNextAction(); + } +} else { + // Upgrade: check the password + $password = $_POST['password']; + $hash = md5($password); + if ($hash == $settings['install_password']) { + // Success + $_SESSION["validUser"] = "1"; // Successful login session var + $_SESSION['alert'] = translate('Successful login'); + redirectToFurthestAvailableAction(); + } else { + $error = translate("Invalid passphrase."); + } +} +?> diff --git a/install/install_createdb.php b/install/install_createdb.php new file mode 100644 index 000000000..d42c9a77b --- /dev/null +++ b/install/install_createdb.php @@ -0,0 +1,24 @@ +

+ +

+ + diff --git a/install/install_createdb_handler.php b/install/install_createdb_handler.php new file mode 100644 index 000000000..9adfe11eb --- /dev/null +++ b/install/install_createdb_handler.php @@ -0,0 +1,147 @@ +connect_error) { + throw new Exception("Connection failed: " . $conn->connect_error); + } + + // Create database + $sql = "CREATE DATABASE " . $databaseName; + if ($conn->query($sql) === TRUE) { + $conn->close(); + return true; + } else { + throw new Exception("Error creating database: " . $conn->error); + } +} + +function createSqliteDatabase(string $filename): bool +{ + try { + $db = new SQLite3($filename, SQLITE3_OPEN_CREATE | SQLITE3_OPEN_READWRITE); + // Create a dummy table to force the file to be created + $db->exec("CREATE TABLE IF NOT EXISTS dummy (id INTEGER)"); + $db->exec("DROP TABLE dummy"); + $db->close(); + return true; + } catch (Exception $e) { + throw new Exception("Error creating SQLite3 database: " . $e->getMessage()); + } +} + +function createPostgresqlDatabase($hostname, $login, $password, $databaseName): bool +{ + $connString = "host={$hostname} user={$login} password={$password}"; + $db = pg_connect($connString); + if (!$db) { + throw new Exception("Connection failed: " . pg_last_error()); + } + + $result = pg_query($db, "CREATE DATABASE {$databaseName}"); + if (!$result) { + throw new Exception("Error creating database: " . pg_last_error($db)); + } + pg_close($db); + return true; +} + +function createIbaseDatabase($hostname, $login, $password, $databaseName): bool +{ + // Firebird/Interbase requires a full path for database creation + $fullPath = $databaseName; + $dir = basename($databaseName); + if (!file_exists($dir)) { + throw new Exception("Missing parent directory: $dir"); + } + // The db_create function creates a new database + if (!ibase_create_db("{$hostname}:{$databaseName}", $login, $password)) { + throw new Exception("Error creating database: " . ibase_errmsg()); + } + return true; +} + +function createOdbcDatabase($dsn, $login, $password, $databaseName): bool +{ + // Connect to the ODBC + $conn = odbc_connect($dsn, $login, $password); + if (!$conn) { + throw new Exception("Connection failed: " . odbc_errormsg()); + } + + // This SQL is generic and may not work for all ODBC sources. + // You might need to adjust this SQL based on your actual database. + $sql = "CREATE DATABASE " . $databaseName; + + if (!odbc_exec($conn, $sql)) { + throw new Exception("Error creating database: " . odbc_errormsg($conn)); + } + + odbc_close($conn); + return true; +} + +function createDB2Database($hostname, $login, $password, $databaseName): bool +{ + // Connect to the database + $conn = db2_connect($hostname, $login, $password); + if (!$conn) { + throw new Exception("IBM DB2 Connection failed: " . db2_conn_errormsg()); + } + + // SQL to create a new database + $sql = "CREATE DATABASE " . $databaseName; + + $stmt = db2_exec($conn, $sql); + if (!$stmt) { + db2_close($conn); + throw new Exception("Error creating database in IBM DB2: " . db2_stmt_errormsg()); + } + + db2_free_stmt($stmt); + db2_close($conn); + + return true; +} + + + +try { + switch ($_SESSION['db_type']) { + case 'mysqli': + createMysqlDatabase($_SESSION['db_host'], $_SESSION['db_login'], $_SESSION['db_password'], $_SESSION['db_database']); + break; + case 'sqlite3': + createSqliteDatabase($_SESSION['db_database']); + break; + case 'postgresql': + createPostgresqlDatabase($_SESSION['db_host'], $_SESSION['db_login'], $_SESSION['db_password'], $_SESSION['db_database']); + break; + case 'ibase': + createIbaseDatabase($_SESSION['db_host'], $_SESSION['db_login'], $_SESSION['db_password'], $_SESSION['db_database']); + break; + case 'odbc': + createOdbcDatabase($_SESSION['db_dsn'], $_SESSION['db_login'], $_SESSION['db_password'], $_SESSION['db_database']); + break; + case 'oracle': + $error = 'Creating databases is not currently supported in the installer. Please do this manually'; + break; + case 'ibm_db2': + createDB2Database($_SESSION['db_host'], $_SESSION['db_login'], $_SESSION['db_password'], $_SESSION['db_database']); + break; + default: + $error = 'Creating databases for ' . $_SESSION['db_type'] . ' is not yet supported.'; + break; + } +} catch (Exception $e) { + $error = $e->getMessage(); +} +if (empty($error)) { + redirectToNextAction(); +} diff --git a/install/install_dbload.php b/install/install_dbload.php new file mode 100644 index 000000000..9c21847cd --- /dev/null +++ b/install/install_dbload.php @@ -0,0 +1,24 @@ +

+ +

+ + diff --git a/install/install_dbload_handler.php b/install/install_dbload_handler.php new file mode 100644 index 000000000..9adfe11eb --- /dev/null +++ b/install/install_dbload_handler.php @@ -0,0 +1,147 @@ +connect_error) { + throw new Exception("Connection failed: " . $conn->connect_error); + } + + // Create database + $sql = "CREATE DATABASE " . $databaseName; + if ($conn->query($sql) === TRUE) { + $conn->close(); + return true; + } else { + throw new Exception("Error creating database: " . $conn->error); + } +} + +function createSqliteDatabase(string $filename): bool +{ + try { + $db = new SQLite3($filename, SQLITE3_OPEN_CREATE | SQLITE3_OPEN_READWRITE); + // Create a dummy table to force the file to be created + $db->exec("CREATE TABLE IF NOT EXISTS dummy (id INTEGER)"); + $db->exec("DROP TABLE dummy"); + $db->close(); + return true; + } catch (Exception $e) { + throw new Exception("Error creating SQLite3 database: " . $e->getMessage()); + } +} + +function createPostgresqlDatabase($hostname, $login, $password, $databaseName): bool +{ + $connString = "host={$hostname} user={$login} password={$password}"; + $db = pg_connect($connString); + if (!$db) { + throw new Exception("Connection failed: " . pg_last_error()); + } + + $result = pg_query($db, "CREATE DATABASE {$databaseName}"); + if (!$result) { + throw new Exception("Error creating database: " . pg_last_error($db)); + } + pg_close($db); + return true; +} + +function createIbaseDatabase($hostname, $login, $password, $databaseName): bool +{ + // Firebird/Interbase requires a full path for database creation + $fullPath = $databaseName; + $dir = basename($databaseName); + if (!file_exists($dir)) { + throw new Exception("Missing parent directory: $dir"); + } + // The db_create function creates a new database + if (!ibase_create_db("{$hostname}:{$databaseName}", $login, $password)) { + throw new Exception("Error creating database: " . ibase_errmsg()); + } + return true; +} + +function createOdbcDatabase($dsn, $login, $password, $databaseName): bool +{ + // Connect to the ODBC + $conn = odbc_connect($dsn, $login, $password); + if (!$conn) { + throw new Exception("Connection failed: " . odbc_errormsg()); + } + + // This SQL is generic and may not work for all ODBC sources. + // You might need to adjust this SQL based on your actual database. + $sql = "CREATE DATABASE " . $databaseName; + + if (!odbc_exec($conn, $sql)) { + throw new Exception("Error creating database: " . odbc_errormsg($conn)); + } + + odbc_close($conn); + return true; +} + +function createDB2Database($hostname, $login, $password, $databaseName): bool +{ + // Connect to the database + $conn = db2_connect($hostname, $login, $password); + if (!$conn) { + throw new Exception("IBM DB2 Connection failed: " . db2_conn_errormsg()); + } + + // SQL to create a new database + $sql = "CREATE DATABASE " . $databaseName; + + $stmt = db2_exec($conn, $sql); + if (!$stmt) { + db2_close($conn); + throw new Exception("Error creating database in IBM DB2: " . db2_stmt_errormsg()); + } + + db2_free_stmt($stmt); + db2_close($conn); + + return true; +} + + + +try { + switch ($_SESSION['db_type']) { + case 'mysqli': + createMysqlDatabase($_SESSION['db_host'], $_SESSION['db_login'], $_SESSION['db_password'], $_SESSION['db_database']); + break; + case 'sqlite3': + createSqliteDatabase($_SESSION['db_database']); + break; + case 'postgresql': + createPostgresqlDatabase($_SESSION['db_host'], $_SESSION['db_login'], $_SESSION['db_password'], $_SESSION['db_database']); + break; + case 'ibase': + createIbaseDatabase($_SESSION['db_host'], $_SESSION['db_login'], $_SESSION['db_password'], $_SESSION['db_database']); + break; + case 'odbc': + createOdbcDatabase($_SESSION['db_dsn'], $_SESSION['db_login'], $_SESSION['db_password'], $_SESSION['db_database']); + break; + case 'oracle': + $error = 'Creating databases is not currently supported in the installer. Please do this manually'; + break; + case 'ibm_db2': + createDB2Database($_SESSION['db_host'], $_SESSION['db_login'], $_SESSION['db_password'], $_SESSION['db_database']); + break; + default: + $error = 'Creating databases for ' . $_SESSION['db_type'] . ' is not yet supported.'; + break; + } +} catch (Exception $e) { + $error = $e->getMessage(); +} +if (empty($error)) { + redirectToNextAction(); +} diff --git a/install/install_dbsettings.php b/install/install_dbsettings.php new file mode 100644 index 000000000..e0ca704f5 --- /dev/null +++ b/install/install_dbsettings.php @@ -0,0 +1,219 @@ + 'function:ibase_connect', + 'ibm_db2' => 'function:db2_connect', + 'mysqli' => 'function:mysqli_connect', + 'odbc' => 'function:odbc_connect', + 'oracle' => 'function:oci_connect', + 'postgresql' => 'function:pg_connect', + 'sqlite3' => 'class:SQLite3' +]; +function printDbSetting($name) +{ + if (!empty($_SESSION[$name])) { + echo htmlentities($_SESSION[$name]); + } +} +$readonlyForm = ''; +$disabledForm = ''; +if ($usingEnv) { + $readonlyForm = 'readonly'; + $disabledForm = 'disabled'; +?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
value="">
value="">
value="">
value="">
value="">
+
+ + + + + + \ No newline at end of file diff --git a/install/install_dbsettings_handler.php b/install/install_dbsettings_handler.php new file mode 100644 index 000000000..ecc6cb0be --- /dev/null +++ b/install/install_dbsettings_handler.php @@ -0,0 +1,43 @@ +POST
"; print_r($_POST); echo "
"; +foreach ($config_possible_settings as $key => $type) { + $value = ''; + if (isset($_POST[$key])) { + $value = $_POST[$key]; + } else if (isset($_SESSION[$key])) { + $value = $_SESSION[$key]; + } + // Handle special types like boolean + switch ($type) { + case 'boolean': + $value = (!empty($value) && $value != 'N') ? 'true' : 'false'; + break; + case 'string': + // For readonly and single_user, convert "Y" or "N" to true or false respectively + if ($key == 'readonly' || $key == 'single_user') { + $value = ($value == "Y") ? 'true' : 'false'; + } + break; + } + if (!empty($value)) { + $fileContent .= "$key: $value\n"; + } +} + +$fileContent .= "# end settings.php */\n"; +$fileContent .= "?>"; + +// Write the content to the file +file_put_contents(__DIR__ . '/../includes/settings.php', $fileContent); + +// Now read it back in to update our session +setSettingsInSession(); + +// Handle the user's db setting changes. +redirectToNextAction(); diff --git a/install/install_dbtables.php b/install/install_dbtables.php new file mode 100644 index 000000000..421c91bd7 --- /dev/null +++ b/install/install_dbtables.php @@ -0,0 +1,107 @@ +

+ \n"; + } + } + echo $msg; + } + ?> +

+ + + + + + + + + \ No newline at end of file diff --git a/install/install_dbtables_handler.php b/install/install_dbtables_handler.php new file mode 100644 index 000000000..d440b676e --- /dev/null +++ b/install/install_dbtables_handler.php @@ -0,0 +1,87 @@ +"; +try { + $success = true; + if (empty($error)) { + if ($emptyDb) { + executeSqlFromFile($install_filename); + } else { + if (empty($detectedDbVersion) || $detectedDbVersion == 'Unknown') { + $error = translate('Unable to determine current database version.'); + } else { + // Get a list of SQL commands and possibly PHP function names. + // For any specific version, the function name should appear in this list after + // the SQL commands allowing the upgrade function to use any new db changes. + $sqlLines = getSqlUpdates($detectedDbVersion, $_SETTINGS['db_type'], true); + //echo '
'; print_r($sqlLines); echo "
\n"; exit; + //echo "\n"; + } + } + } +} catch (Exception $e) { + $error = $e->getMessage(); +} +if (empty($error)) { + $msg = translate('Database successfully migrated from XXX to YYY'); + $msg = str_replace('XXX', $detectedDbVersion, $msg); + $msg = str_replace('YYY', $PROGRAM_VERSION, $msg); + $_SESSION['alert'] = $msg; + redirectToNextAction(); +} diff --git a/install/install_finish.php b/install/install_finish.php new file mode 100644 index 000000000..b22e6e131 --- /dev/null +++ b/install/install_finish.php @@ -0,0 +1,8 @@ +

+ +

+ + \ No newline at end of file diff --git a/install/install_functions.php b/install/install_functions.php index 5201e5b86..1366fedfb 100644 --- a/install/install_functions.php +++ b/install/install_functions.php @@ -5,7 +5,7 @@ /** * Developer debug log ( */ -function do_debug ( $msg ) { +function X_do_debug ( $msg ) { // log to /tmp/webcal-debug.log // error_log ( date ( "Y-m-d H:i:s" ) . "> $msg\n", // 3, "d:\php\logs\debug.txt" ); @@ -201,17 +201,86 @@ function do_v11e_updates() { } } +/** + * Migrate category icons from the file system into the webcal_categories table as + * part of the updates for v1.9.11. Storing everything in the database will eventually + * allow multiple instances of WebCalendar to run against the same database and make + * database backups a complete site backup. + */ +function do_v1_9_11_updates() { + $icon_path = __DIR__ . "/../wc-icons/"; + // Get all icon files from the wc-icons directory + $iconFiles = glob($icon_path . 'cat-*.gif'); + $iconFilesPng = glob($icon_path . 'cat-*.png'); + $iconFiles = array_merge($iconFiles, $iconFilesPng); + foreach ($iconFiles as $iconFile) { + // Extract the category ID from the filename + preg_match('/cat-(\d+)\.(gif|png)/', $iconFile, $matches); + $catId = $matches[1]; + $fileType = $matches[2]; + $iconData = ''; + $fd = @fopen($iconFile, 'r'); + if (!$fd) + die_miserable_death("Error reading temp file: $iconFile"); + while (!feof($fd)) { + $iconData .= fgets($fd, 4096); + } + fclose($fd); + // Get MIME type of the icon + $iconMime = 'image/' . $fileType; + // Update the database + $res = dbi_execute( + 'UPDATE webcal_categories SET cat_icon_mime = ? WHERE cat_id = ?', + [$iconMime, $catId] + ); + if (!$res) { + echo "Failed to update icon for category ID $catId: " . dbi_error(); + continue; + } else { + if (!dbi_update_blob( + 'webcal_categories', + 'cat_icon_blob', + "cat_id = $catId", + $iconData + )) { + echo "Failed to update icon for category ID $catId: " . dbi_error(); + } else { + // Encode the binary data to Base64. + $base64Data = base64_encode($iconData); + // Create a data URL. + $dataUrl = 'data:image/png;base64,' . $base64Data; + echo 'Embedded Image
'; + echo "cat $catId done
\n"; + // Delete the files so we don't repeat this later + //if (!unlink($iconFile)) { + // echo "Failed to delete icon file $iconFile"; + //} + } + } + } +} + /* Functions moved from index.php script */ /** - * get_php_setting (needs description) + * Retrieves the value of a specified PHP configuration directive (from php.ini). + * + * This function will return either 'ON' or 'OFF' for boolean settings, + * or check if a specific string value exists within the directive's value. + * + * @param string $val The configuration directive (php.ini setting) to retrieve. + * @param string|bool $string Optional. If specified, checks if this value exists within the directive's value. + * If not specified or set to false, the function will return 'ON' or 'OFF' for the directive. + * + * @return string|bool Returns 'ON' or 'OFF' for boolean settings. If $string is specified, it returns the string + * if found within the directive's value, otherwise false. */ -function get_php_setting ( $val, $string = false ) { - $setting = ini_get ( $val ); - return ( $string == false - ? ( $setting == '1' || $setting == 'ON' ? 'ON' : 'OFF' ) +function get_php_setting($val, $string = false) { + $setting = ini_get($val); + return ($string == false + ? ($setting == '1' || $setting == 'ON' ? 'ON' : 'OFF') : // Test for $string in ini value. - ( in_array ( $string, explode ( ',', $setting ) ) ? $string : false ) ); + (in_array($string, explode(',', $setting)) ? $string : false)); } /** * get_php_modules (needs description) @@ -326,69 +395,76 @@ function convert_server_to_GMT ( $offset = 0, $cutoffdate = '' ) { return $error; } + /** - * get_installed_version (needs description) + * Examine the database to determine what version of WebCalendar the database was last used with. + * This involves trying various SQL to see what fails and what succeeds. */ -function get_installed_version ( $postinstall = false ) { +function getDatabaseVersionFromSchema($silent = true) +{ global $database_upgrade_matrix, $PROGRAM_VERSION, $settings, $show_all_errors; - - // Set this as the default value. - $_SESSION['application_name'] = 'Title'; - $_SESSION['blank_database'] = ''; - // We will append the db_type to come up te proper filename. - $_SESSION['install_file'] = 'tables'; - //echo "Set install_files in get_installed_version
"; - //echo "install_file = " . $_SESSION['install_file'] . "
"; - $_SESSION['old_program_version'] = ( $postinstall - ? $PROGRAM_VERSION : 'new_install' ); + $dbVersion = null; + $success = true; + //$silent = false; // Suppress errors based on $show_all_errors. - if ( ! $show_all_errors ) - show_errors ( false ); + if (!$show_all_errors) + show_errors(false); // This data is read from file upgrade_matrix.php. - for ( $i = 0, $dbCntStr = count ( $database_upgrade_matrix ); $i < $dbCntStr; $i++ ) { + for ($i = 0; $i < count($database_upgrade_matrix); $i++) { $sql = $database_upgrade_matrix[$i][0]; - //echo "SQL: $sql
\n"; + if (!$silent) { + echo "SQL: $sql
\n"; + } if (empty($sql)) { - // We reached the end of database_upgrade_matrix[] with no errors, which - // means the database is structurally up-to-date. - } else { - try{ - $res = dbi_execute ( $sql, [], false, $show_all_errors ); + if ($success) { + // We reached the end of database_upgrade_matrix[] with no errors, which + // means the database is structurally up-to-date. + $dbVersion = $PROGRAM_VERSION; } - catch (Exception $e){ + } else { + try { + $res = dbi_execute($sql, [], false, $show_all_errors); + } catch (Exception $e) { // Suppress any exceptions; this is only used for testing what version // we are on, so when it fails we know it's before the version that SQL // could have worked on. $res = false; + $success = false; } - if ( $res ) { - //echo "Success on " . $database_upgrade_matrix[$i][2] . "
"; - $_SESSION['old_program_version'] = $database_upgrade_matrix[$i + 1][2]; - $_SESSION['install_file'] = $database_upgrade_matrix[$i + 1][3]; - //echo "install_file = " . $_SESSION['install_file'] . "
"; - $res = ''; + if ($res) { + if (!$silent) { + echo "Success on " . $database_upgrade_matrix[$i][2] . "
"; + } + $dbVersion = $database_upgrade_matrix[$i][2]; + $res = null; + // Clean up our test $sql = $database_upgrade_matrix[$i][1]; - if ( $sql != '' ) - dbi_execute ( $sql, [], false, $show_all_errors ); + if ($sql != '') + dbi_execute($sql, [], false, $show_all_errors); } else { - //echo "Failure on " . $database_upgrade_matrix[$i][2] . "
"; + if (!$silent) { + echo "Failure on " . $database_upgrade_matrix[$i][2] . "
"; + echo "Error: " . dbi_error() . "
\n"; + } + $success = false; //echo "Failure SQL: $sql
"; } } } - $response_msg = ( $_SESSION['old_program_version'] == 'pre-v0.9.07' - ? translate ( 'Perl script required' ) - : translate ( 'previous version requires updating several tables' ) ); // We need to determine if this is a blank database. // This may be due to a manual table setup. - $res = dbi_execute ( 'SELECT COUNT( cal_value ) FROM webcal_config', - [], false, $show_all_errors ); - if ( $res ) { - $row = dbi_fetch_row ( $res ); - if ( isset ( $row[0] ) && $row[0] == 0 ) { + $res = dbi_execute( + 'SELECT COUNT( cal_value ) FROM webcal_config', + [], + false, + $show_all_errors + ); + if ($res) { + $row = dbi_fetch_row($res); + if (isset($row[0]) && $row[0] == 0) { $_SESSION['blank_database'] = true; } else { // Make sure all existing values in config and pref tables are UPPERCASE. @@ -396,71 +472,30 @@ function get_installed_version ( $postinstall = false ) { // Clear db_cache. This will prevent looping when launching WebCalendar // if upgrading and WEBCAL_PROGRAM_VERSION is cached. - if ( ! empty ( $settings['db_cachedir'] ) ) - dbi_init_cache ( $settings['db_cachedir'] ); + if (!empty($settings['db_cachedir'])) + dbi_init_cache($settings['db_cachedir']); else - if ( ! empty ( $settings['cachedir'] ) ) - dbi_init_cache ( $settings['cachedir'] ); + if (!empty($settings['cachedir'])) + dbi_init_cache($settings['cachedir']); // Delete existing WEBCAL_PROGRAM_VERSION number. - dbi_execute ( 'DELETE FROM webcal_config - WHERE cal_setting = \'WEBCAL_PROGRAM_VERSION\'' ); + dbi_execute('DELETE FROM webcal_config + WHERE cal_setting = \'WEBCAL_PROGRAM_VERSION\''); } - dbi_free_result ( $res ); + dbi_free_result($res); // Insert webcal_config values only if blank. db_load_config(); - // Check if an Admin account exists. - $_SESSION['admin_exists'] = db_check_admin(); - } - // Determine if old data has been converted to GMT. - // This seems lke a good place to put this. - $res = dbi_execute ( 'SELECT cal_value FROM webcal_config - WHERE cal_setting = \'WEBCAL_TZ_CONVERSION\'', - [], false, $show_all_errors ); - if ( $res ) { - $row = dbi_fetch_row ( $res ); - dbi_free_result ( $res ); - // If not 'Y', prompt user to do conversion from server time to GMT time. - if ( ! empty ( $row[0] ) ) { - $_SESSION['tz_conversion'] = $row[0]; - } else { // We'll test if any events even exist. - $res = dbi_execute ( 'SELECT COUNT( cal_id ) FROM webcal_entry ', - [], false, $show_all_errors ); - if ( $res ) { - $row = dbi_fetch_row ( $res ); - dbi_free_result ( $res ); - } - $_SESSION['tz_conversion'] = ( $row[0] > 0 ? 'NEEDED' : 'Y' ); - } - } - // Don't show TZ conversion if blank database. - if ( $_SESSION['blank_database'] == true ) - $_SESSION['tz_conversion'] = 'Y'; - // Get existing server URL. - // We could use the self-discvery value, but this may be a custom value. - $res = dbi_execute ( 'SELECT cal_value FROM webcal_config - WHERE cal_setting = "SERVER_URL"', [], false, $show_all_errors ); - if ( $res ) { - $row = dbi_fetch_row ( $res ); - if ( ! empty ( $row[0] ) && strlen ( $row[0] ) ) - $_SESSION['server_url'] = $row[0]; - - dbi_free_result ( $res ); } + // Note: We don't do TZ conversion anymore since that changes was 15+ years ago. // Get existing application name. - $res = dbi_execute ( 'SELECT cal_value FROM webcal_config - WHERE cal_setting = \'APPLICATION_NAME\'', - [], false, $show_all_errors ); - if ( $res ) { - $row = dbi_fetch_row ( $res ); - if ( ! empty ( $row[0] ) ) - $_SESSION['application_name'] = $row[0]; - - dbi_free_result ( $res ); - } // Enable warnings. - show_errors ( true ); -} // end get_installed_version + show_errors(true); + if (!$silent) { + echo "Db structure is version: " . $dbVersion . "
\n"; + } + return $dbVersion; +} + /** * parse_sql (needs description) */ @@ -480,61 +515,142 @@ function parse_sql ( $sql ) { return ( $ret ); } /** - * db_populate (needs description) + * Extracts SQL statements from a specified file. + * + * This function reads the content of the provided SQL file, strips out + * any comments (single line starting with # or --, and multiline enclosed + * in /* and *\/), and then returns each SQL statement as an array. + * + * @param string $filename The path to the SQL file. + * + * @throws Exception If the specified file is not found. + * + * @return array An array of SQL statements. */ -function db_populate ( $install_filename, $display_sql ) { - global $show_all_errors, $str_parsed_sql; +function extractSqlCommandsFromFile($filename) { + // Check if file exists + if (!file_exists($filename)) { + throw new Exception("File not found: $filename"); + } - if ( $install_filename == '' ) - return; + // Read the file contents + $content = file_get_contents($filename); - $current_pointer = false; - $full_sql = ''; + // Strip out all comments + $contentWithoutComments = preg_replace('/(--[^\r\n]*)|(\#[^\r\n]*)|\/\*.*?\*\//s', '', $content); - $fd = @fopen ( 'sql/' . $install_filename, 'r', true ); + // Split the content into individual SQL statements + return array_filter(array_map('trim', explode(";\n", $contentWithoutComments))); +} - // Discard everything up to the required point in the upgrade file. - while ( ! feof ( $fd ) && empty ( $current_pointer ) ) { - $data = trim ( fgets ( $fd, 4096 ), "\r\n " ); - if ( strpos ( strtoupper ( $data ), - strtoupper ( $_SESSION['install_file'] ) ) || - substr ( $_SESSION['install_file'], 0, 6 ) == 'tables' ) - $current_pointer = true; - } - // We already have a $data item from above. - if ( substr ( $data, 0, 2 ) == "/*" && - substr ( $_SESSION['install_file'], 0, 6 ) != 'tables' ) { - // Do nothing...We skip over comments in upgrade files. - } else - $full_sql .= $data; - - // We need to strip out the comments from upgrade files. - while ( ! feof ( $fd ) ) { - $data = trim ( fgets ( $fd, 4096 ), "\r\n " ); - if ( substr ( $data, 0, 2 ) == '/*' && - substr ( $_SESSION['install_file'], 0, 6 ) != 'tables' ) { - // Do nothing...We skip over comments in upgrade files. - } else - $full_sql .= $data; +/** +* Executes SQL statements from a specified file. +* +* This function reads the content of the provided SQL file using +* extractSqlCommandsFromFile() and then executes each SQL statement. +* +* @param string $filename The path to the SQL file. +* +* @throws Exception If there are issues executing the SQL or if the file is not found. +* +* @return void +*/ +function executeSqlFromFile($filename) { + $sqlStatements = extractSqlCommandsFromFile($filename); + + foreach ($sqlStatements as $statement) { + if (!empty($statement)) { + // Assuming dbi_execute() is a function that takes a SQL statement and executes it + dbi_execute($statement); + } } +} - fclose ( $fd ); - $parsed_sql = parse_sql ( $full_sql ); - - // String version of parsed_sql that is used if displaying SQL only. - $str_parsed_sql = ''; - for ( $i = 0, $sqlCntStr = count ( $parsed_sql ); $i < $sqlCntStr; $i++ ) { - if ( empty ( $display_sql ) ) { - if ( $show_all_errors == true ) - echo $parsed_sql[$i] . '
'; +function getSqlFile($dbType, $isUpgrade=false) { + $file_base = __DIR__ . '/sql/' . ($isUpgrade ? 'upgrade' : 'tables'); + $install_filename = $file_base . '-'; + switch ($dbType) { + case 'ibase': + case 'mssql': + case 'oracle': + $install_filename .= $dbType . '.sql'; + break; + case 'ibm_db2': + $install_filename .= 'db2.sql'; + break; + // Need to add more form fields to capture odbc db type... + case 'odbc': + // Not yet supported in installer :-( + $install_filename .= $_SESSION['odbc_db'] . '.sql'; + break; + case 'postgresql': + $install_filename .= 'postgres.sql'; + break; + case 'sqlite3': + require_once 'sql/tables-sqlite3.php'; + populate_sqlite_db($real_db, $c); + $install_filename = ''; + break; + default: + $install_filename .= 'mysql.sql'; + } + return $install_filename; +} - dbi_execute( $parsed_sql[$i], [], false, $show_all_errors ); - } else - $str_parsed_sql .= $parsed_sql[$i] . "\n\n"; +/** + * Extracts SQL commands for upgrading from the specified version to the latest version. + * + * @param string $filename The path to the SQL file containing upgrade commands. + * @param string $version The starting version for the upgrade. + * + * @throws Exception If the specified file is not found. + * + * @return array An array of SQL statements for the upgrade. + */ +function extractUpgradeSqlCommands($filename, $version) { + if (!file_exists($filename)) { + throw new Exception("File not found: $filename"); + } + $content = file_get_contents($filename); + // Split content into chunks based on the upgrade version comments + //preg_match_all('/\/\*upgrade_(v[\d\.]+)\*\/(.*?)(?=\/\*upgrade_|$)/sm', $content, $matches, PREG_SET_ORDER); + preg_match_all('/\/\*upgrade_(v[\d\.]+)\*\/(.*?)(?=\/\*upgrade_|$)/sm', $content, $matches, PREG_SET_ORDER); + + + $commands = []; + $record = false; + echo "
"; print_r($matches); echo "
"; + foreach ($matches as $match) { + echo "match: \"$match[1]\"
"; + if ($match[1] === $version) { + $record = true; // Start recording commands from the provided version + } + if ($record) { + echo "MATCH: " . $match[2] . "
"; + echo "NEXT: " . $match[3] . "
"; + $sqls = array_map('trim', explode(';', $match[2])); + foreach ($sqls as $sql) { + if (!empty($sql)) { + $commands[] = $sql; + } + } + } } - // Enable warnings. - show_errors ( true ); -} // end db_populate + return $commands; +} + +function removeWhitespaceOnlyLines($inputStr) { + // Split the string by newlines + $lines = explode("\n", $inputStr); + + // Filter out lines that only contain whitespace + $filteredLines = array_filter($lines, function($line) { + return trim($line) !== ''; + }); + + // Join the lines back together + return implode("\n", $filteredLines); +} ?> diff --git a/install/install_phpsettings.php b/install/install_phpsettings.php new file mode 100644 index 000000000..03c506ba6 --- /dev/null +++ b/install/install_phpsettings.php @@ -0,0 +1,39 @@ + + + + + + + + + + + "; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + } + ?> + +
" . htmlentities($description) . "" . htmlentities($requiredValue) . "" . htmlentities($foundValue) . "" . ($isCorrect ? translate("Correct") : translate("Incorrect")) . "
+ + \ No newline at end of file diff --git a/install/install_phpsettings_handler.php b/install/install_phpsettings_handler.php new file mode 100644 index 000000000..bcbe254e9 --- /dev/null +++ b/install/install_phpsettings_handler.php @@ -0,0 +1,6 @@ + diff --git a/install/install_welcome.php b/install/install_welcome.php new file mode 100644 index 000000000..9d6670843 --- /dev/null +++ b/install/install_welcome.php @@ -0,0 +1,21 @@ + +

+ +

+ \ No newline at end of file diff --git a/install/sql/tables-db2.sql b/install/sql/tables-db2.sql index 3cede427e..cbefb53ab 100644 --- a/install/sql/tables-db2.sql +++ b/install/sql/tables-db2.sql @@ -30,7 +30,7 @@ CREATE TABLE webcal_entry ( cal_access CHAR(1) DEFAULT 'P', cal_name VARCHAR(80) NOT NULL, cal_location VARCHAR(100), - cal_url VARCHAR(100), + cal_url VARCHAR(255), cal_completed INT, cal_description VARCHAR(1024), PRIMARY KEY ( cal_id ) @@ -153,7 +153,10 @@ CREATE TABLE webcal_categories ( cat_owner VARCHAR(25) NULL, cat_name VARCHAR(80) NOT NULL, cat_color VARCHAR(8), - PRIMARY KEY ( cat_id ) + cat_status CHAR DEFAULT 'A', + cat_icon_mime VARCHAR(32) DEFAULT NULL, + cat_icon_blob BLOB DEFAULT NULL, + PRIMARY KEY (cal_id, cat_id, cat_order, cat_owner) ); CREATE TABLE webcal_asst ( cal_boss VARCHAR(25) NOT NULL, diff --git a/install/sql/tables-ibase.sql b/install/sql/tables-ibase.sql index 478f0f49a..521662525 100644 --- a/install/sql/tables-ibase.sql +++ b/install/sql/tables-ibase.sql @@ -16,7 +16,7 @@ CREATE TABLE WEBCAL_ENTRY CAL_ACCESS CHAR(1) CHARACTER SET WIN1252 DEFAULT 'P', CAL_NAME VARCHAR(80) CHARACTER SET WIN1252 NOT NULL, CAL_LOCATION VARCHAR(100)CHARACTER SET WIN1252, - CAL_URL VARCHAR(100)CHARACTER SET WIN1252, + CAL_URL VARCHAR(255)CHARACTER SET WIN1252, CAL_COMPLETED INTEGER DEFAULT NULL, CAL_DESCRIPTION VARCHAR(1024) CHARACTER SET WIN1252 ); @@ -153,7 +153,10 @@ CREATE TABLE WEBCAL_CATEGORIES CAT_ID INTEGER DEFAULT 0 NOT NULL, CAT_OWNER VARCHAR(25) CHARACTER SET WIN1252 NULL, CAT_NAME VARCHAR(80) CHARACTER SET WIN1252 NOT NULL, - CAT_COLOR VARCHAR(8) CHARACTER SET WIN1252 DEFAULT NULL + CAT_COLOR VARCHAR(8) CHARACTER SET WIN1252 DEFAULT NULL, + CAT_STATUS CHAR DEFAULT 'A', + CAT_ICON_MIME VARCHAR(32) DEFAULT NULL, + CAT_ICON_BLOB BLOB DEFAULT NULL, ); CREATE TABLE WEBCAL_ASST ( @@ -273,7 +276,7 @@ CREATE INDEX IWEBCAL_VIEWNEWINDEX ON WEBCAL_VIEW(CAL_VIEW_ID); CREATE INDEX IWEBCAL_VIEWUSERNEWINDEX ON WEBCAL_VIEW_USER(CAL_VIEW_ID, CAL_LOGIN); CREATE INDEX IWEBCAL_CONFIGNEWINDEX ON WEBCAL_CONFIG(CAL_SETTING); CREATE INDEX IWEBCAL_ENTRYLOGINDEX ON WEBCAL_ENTRY_LOG(CAL_LOG_ID); -CREATE INDEX IWEBCAL_CATEGORIESINDEX ON WEBCAL_CATEGORIES(CAT_ID); +CREATE INDEX IWEBCAL_CATEGORIESINDEX ON WEBCAL_CATEGORIES(CAL_ID, CAT_ID, CAT_ORDER, CAT_OWNER); CREATE INDEX IWEBCAL_BOSSINDEX ON WEBCAL_ASST(CAL_BOSS, CAL_ASSISTANT); CREATE INDEX IWEBCAL_NONUSERCALSINDEX ON WEBCAL_NONUSER_CALS(CAL_LOGIN); CREATE INDEX IWEBCAL_IMPORT2INDEX ON WEBCAL_IMPORT(CAL_IMPORT_ID); diff --git a/install/sql/tables-mssql.sql b/install/sql/tables-mssql.sql deleted file mode 100644 index cf833f314..000000000 --- a/install/sql/tables-mssql.sql +++ /dev/null @@ -1,294 +0,0 @@ -CREATE TABLE webcal_user ( - cal_login VARCHAR(25) NOT NULL, - cal_passwd VARCHAR(255) NULL, - cal_lastname VARCHAR(25) NULL, - cal_firstname VARCHAR(25) NULL, - cal_is_admin CHAR(1) DEFAULT 'N', - cal_email VARCHAR(75) NULL, - cal_enabled CHAR(1) DEFAULT 'Y', - cal_telephone VARCHAR(50) NULL, - cal_address VARCHAR(75) NULL, - cal_title VARCHAR(75) NULL, - cal_birthday INT NULL, - cal_last_login INT NULL, - PRIMARY KEY ( cal_login ) -); -INSERT INTO webcal_user ( - cal_login, cal_passwd, cal_lastname, cal_firstname, cal_is_admin ) - VALUES ( 'admin', '21232f297a57a5a743894a0e4a801fc3', 'Administrator', 'Default', 'Y' ); -CREATE TABLE webcal_entry ( - cal_id INT NOT NULL, - cal_group_id INT NULL, - cal_ext_for_id INT NULL, - cal_create_by VARCHAR(25) NOT NULL, - cal_date INT NOT NULL, - cal_time INT NULL, - cal_mod_date INT NULL, - cal_mod_time INT NULL, - cal_duration INT NOT NULL, - cal_due_date INT NULL, - cal_due_time INT NULL, - cal_priority INT DEFAULT 5, - cal_type CHAR(1) DEFAULT 'E', - cal_access CHAR(1) DEFAULT 'P', - cal_name VARCHAR(80) NOT NULL, - cal_location VARCHAR(100) NULL, - cal_url VARCHAR(100) NULL, - cal_completed INT NULL, - cal_description TEXT NULL, - PRIMARY KEY ( cal_id ) -); -CREATE TABLE webcal_entry_repeats ( - cal_id INT DEFAULT '0' NOT NULL, - cal_type VARCHAR(20) NOT NULL, - cal_end INT NULL, - cal_frequency INT DEFAULT '1', - cal_days CHAR(7) NULL, - cal_endtime INT NULL, - cal_bymonth VARCHAR(50) NULL, - cal_bymonthday VARCHAR(100) NULL, - cal_byday VARCHAR(100) NULL, - cal_bysetpos VARCHAR(50) NULL, - cal_byweekno VARCHAR(50) NULL, - cal_byyearday VARCHAR(50) NULL, - cal_wkst char(2) DEFAULT 'MO', - cal_count INT NULL, - PRIMARY KEY (cal_id) -); -CREATE TABLE webcal_entry_repeats_not ( - cal_id INT NOT NULL, - cal_date INT NOT NULL, - cal_exdate INT DEFAULT '1' NOT NULL, - PRIMARY KEY ( cal_id, cal_date ) -); -CREATE TABLE webcal_entry_user ( - cal_id int DEFAULT '0' NOT NULL, - cal_login varchar(25) DEFAULT '' NOT NULL, - cal_status char(1) DEFAULT 'A' NOT NULL, - cal_category INT NULL, - cal_percent INT DEFAULT '0' NOT NULL, - PRIMARY KEY ( cal_id,cal_login ) -); -CREATE TABLE webcal_entry_ext_user ( - cal_id INT DEFAULT 0 NOT NULL, - cal_fullname VARCHAR(50) NOT NULL, - cal_email VARCHAR(75) NOT NULL, - PRIMARY KEY ( cal_id, cal_fullname ) -); -CREATE TABLE webcal_user_pref ( - cal_login varchar(25) NOT NULL, - cal_setting varchar(25) NOT NULL, - cal_value varchar(100) NULL, - PRIMARY KEY ( cal_login, cal_setting ) -); -CREATE TABLE webcal_user_layers ( - cal_layerid INT DEFAULT '0' NOT NULL, - cal_login varchar(25) NOT NULL, - cal_layeruser varchar(25) NOT NULL, - cal_color varchar(25) NULL, - cal_dups CHAR(1) DEFAULT 'N', - PRIMARY KEY ( cal_login, cal_layeruser ) -); -CREATE TABLE webcal_site_extras ( - cal_id INT DEFAULT '0' NOT NULL, - cal_name VARCHAR(25) NOT NULL, - cal_type INT NOT NULL, - cal_date INT DEFAULT '0', - cal_remind INT DEFAULT '0', - cal_data TEXT -); -CREATE TABLE webcal_reminders ( - cal_id INT NOT NULL DEFAULT '0', - cal_date INT NOT NULL DEFAULT '0', - cal_offset INT NOT NULL DEFAULT '0', - cal_related CHAR(1) NOT NULL DEFAULT 'S', - cal_before CHAR(1) NOT NULL DEFAULT 'Y', - cal_last_sent INT DEFAULT '0', - cal_repeats INT NOT NULL DEFAULT '0', - cal_duration INT NOT NULL DEFAULT '0', - cal_times_sent INT NOT NULL DEFAULT '0', - cal_action VARCHAR(12) NOT NULL DEFAULT 'EMAIL', - PRIMARY KEY ( cal_id ) -); -CREATE TABLE webcal_group ( - cal_group_id INT NOT NULL, - cal_owner VARCHAR(25) NOT NULL, - cal_name VARCHAR(50) NOT NULL, - cal_last_update INT NOT NULL, - PRIMARY KEY ( cal_group_id ) -); -CREATE TABLE webcal_group_user ( - cal_group_id INT NOT NULL, - cal_login VARCHAR(25) NOT NULL, - PRIMARY KEY ( cal_group_id, cal_login ) -); -CREATE TABLE webcal_view ( - cal_view_id INT NOT NULL, - cal_owner VARCHAR(25) NOT NULL, - cal_name VARCHAR(50) NOT NULL, - cal_view_type CHAR(1) NULL, - cal_is_global CHAR(1) DEFAULT 'N' NOT NULL, - PRIMARY KEY ( cal_view_id ) -); -CREATE TABLE webcal_view_user ( - cal_view_id INT NOT NULL, - cal_login VARCHAR(25) NOT NULL, - PRIMARY KEY ( cal_view_id, cal_login ) -); -CREATE TABLE webcal_config ( - cal_setting VARCHAR(50) NOT NULL, - cal_value VARCHAR(100) NULL, - PRIMARY KEY ( cal_setting ) -); -CREATE TABLE webcal_entry_log ( - cal_log_id INT NOT NULL, - cal_entry_id INT NOT NULL, - cal_login VARCHAR(25) NOT NULL, - cal_user_cal VARCHAR(25) NULL, - cal_type CHAR(1) NOT NULL, - cal_date INT NOT NULL, - cal_time INT NOT NULL, - cal_text TEXT NULL, - PRIMARY KEY ( cal_log_id ) -); -CREATE TABLE webcal_categories ( - cat_id INT NOT NULL, - cat_owner VARCHAR(25) NULL, - cat_name VARCHAR(80) NOT NULL, - cat_color VARCHAR(8) NULL, - PRIMARY KEY ( cat_id ) -); -CREATE TABLE webcal_asst ( - cal_boss VARCHAR(25) NOT NULL, - cal_assistant VARCHAR(25) NOT NULL, - PRIMARY KEY ( cal_boss, cal_assistant ) -); -CREATE TABLE webcal_nonuser_cals ( - cal_login VARCHAR(25) NOT NULL, - cal_lastname VARCHAR(25) NULL, - cal_firstname VARCHAR(25) NULL, - cal_admin VARCHAR(25) NOT NULL, - cal_is_public CHAR(1) NOT NULL DEFAULT 'N', - cal_url VARCHAR(255) DEFAULT NULL, - PRIMARY KEY ( cal_login ) -); -CREATE TABLE webcal_import ( - cal_import_id INT NOT NULL, - cal_name VARCHAR(50) NULL, - cal_date INT NOT NULL, - cal_check_date INT NULL, - cal_type VARCHAR(10) NOT NULL, - cal_login VARCHAR(25) NULL, - cal_md5 VARCHAR(32) NULL DEFAULT NULL, - PRIMARY KEY ( cal_import_id ) -); -CREATE INDEX webcal_import_data_type ON webcal_import_data(cal_import_type); -CREATE INDEX webcal_import_data_ext_id ON webcal_import_data(cal_external_id); -CREATE TABLE webcal_import_data ( - cal_import_id INT NOT NULL, - cal_id INT NOT NULL, - cal_login VARCHAR(25) NOT NULL, - cal_import_type VARCHAR(15) NOT NULL, - cal_external_id VARCHAR(200) NULL, - PRIMARY KEY ( cal_id, cal_login ) -); -CREATE TABLE webcal_report ( - cal_login VARCHAR(25) NOT NULL, - cal_report_id INT NOT NULL, - cal_is_global CHAR(1) DEFAULT 'N' NOT NULL, - cal_report_type VARCHAR(20) NOT NULL, - cal_include_header CHAR(1) DEFAULT 'Y' NOT NULL, - cal_report_name VARCHAR(50) NOT NULL, - cal_time_range INT NOT NULL, - cal_user VARCHAR(25) NULL, - cal_allow_nav CHAR(1) DEFAULT 'Y', - cal_cat_id INT NULL, - cal_include_empty CHAR(1) DEFAULT 'N', - cal_show_in_trailer CHAR(1) DEFAULT 'N', - cal_update_date INT NOT NULL, - PRIMARY KEY ( cal_report_id ) -); -CREATE TABLE webcal_report_template ( - cal_report_id INT NOT NULL, - cal_template_type CHAR(1) NOT NULL, - cal_template_text TEXT NULL, - PRIMARY KEY ( cal_report_id, cal_template_type ) -); -CREATE TABLE webcal_access_user ( - cal_login VARCHAR(25) NOT NULL, - cal_other_user VARCHAR(25) NOT NULL, - cal_can_view INT NOT NULL DEFAULT '0', - cal_can_edit INT NOT NULL DEFAULT '0', - cal_can_approve INT NOT NULL DEFAULT '0', - cal_can_invite CHAR(1) NOT NULL DEFAULT 'Y', - cal_can_email CHAR(1) NOT NULL DEFAULT 'Y', - cal_see_time_only CHAR(1) NOT NULL DEFAULT 'N', - PRIMARY KEY ( cal_login, cal_other_user ) -); -CREATE TABLE webcal_access_function ( - cal_login VARCHAR(25) NOT NULL, - cal_permissions VARCHAR(64) NOT NULL, - PRIMARY KEY ( cal_login ) -); -CREATE TABLE webcal_tz_zones ( - zone_name VARCHAR(50) NOT NULL DEFAULT '', - zone_gmtoff INT NOT NULL DEFAULT '0', - zone_rules VARCHAR(50) NOT NULL DEFAULT '', - zone_format VARCHAR(20) NOT NULL DEFAULT '', - zone_from BIGINT NOT NULL DEFAULT '0', - zone_until BIGINT NOT NULL DEFAULT '0', - zone_cc CHAR(2) NOT NULL DEFAULT '', - zone_coord VARCHAR(20) NOT NULL DEFAULT '', - zone_country VARCHAR(50) NOT NULL DEFAULT '' -); -CREATE TABLE webcal_tz_rules ( - rule_name VARCHAR(50) DEFAULT '' NOT NULL, - rule_from INT DEFAULT '0' NOT NULL, - rule_to INT DEFAULT '0' NOT NULL, - rule_type VARCHAR(20) DEFAULT '' NOT NULL, - rule_in INT DEFAULT '0' NOT NULL, - rule_on VARCHAR(20) DEFAULT '' NOT NULL, - rule_at INT DEFAULT '0' NOT NULL, - rule_at_suffix CHAR(1) DEFAULT '' NOT NULL, - rule_save INT default '0' NOT NULL, - rule_letter VARCHAR(5) DEFAULT '' NOT NULL -); -CREATE TABLE webcal_tz_list ( - tz_list_id INT default '0' NOT NULL, - tz_list_name VARCHAR(50) default '' NOT NULL, - tz_list_text VARCHAR(75) default '' NOT NULL -); -CREATE TABLE webcal_user_template ( - cal_login VARCHAR(25) NOT NULL, - cal_type CHAR(1) NOT NULL, - cal_template_text TEXT NULL, - PRIMARY KEY ( cal_login, cal_type ) -); -CREATE TABLE webcal_entry_categories ( - cal_id INT DEFAULT '0' NOT NULL, - cat_id INT DEFAULT '0' NOT NULL, - cat_order INT DEFAULT '0' NOT NULL, - cat_owner VARCHAR(25) DEFAULT '' NOT NULL, - PRIMARY KEY ( cal_id, cat_id, cat_order, cat_owner ) -); -CREATE TABLE webcal_blob ( - cal_blob_id INT NOT NULL, - cal_id INT NULL, - cal_login VARCHAR(25) NULL, - cal_name VARCHAR(30) NULL, - cal_description VARCHAR(128) NULL, - cal_size INT NULL, - cal_mime_type VARCHAR(50) NULL, - cal_type CHAR(1) NOT NULL, - cal_mod_date INT NOT NULL, - cal_mod_time INT NOT NULL, - cal_blob IMAGE NULL, - PRIMARY KEY ( cal_blob_id ) -); -CREATE TABLE webcal_timezones ( - tzid VARCHAR(100) NOT NULL DEFAULT '', - dtstart VARCHAR(25) DEFAULT NULL, - dtend VARCHAR(25) DEFAULT NULL, - vtimezone TEXT, - PRIMARY KEY ( tzid ) -); diff --git a/install/sql/tables-mysql.sql b/install/sql/tables-mysql.sql index 798f9b2c7..72ed8e7e3 100644 --- a/install/sql/tables-mysql.sql +++ b/install/sql/tables-mysql.sql @@ -106,7 +106,7 @@ CREATE TABLE webcal_entry ( /* location of event */ cal_location varchar(100) DEFAULT NULL, /* URL of event */ - cal_url varchar(100) DEFAULT NULL, + cal_url varchar(255) DEFAULT NULL, /* date task completed */ cal_completed INT DEFAULT NULL, /* full description of event */ @@ -426,7 +426,13 @@ CREATE TABLE webcal_categories ( cat_name VARCHAR(80) NOT NULL, /* RGB color for category */ cat_color VARCHAR(8) NULL, - PRIMARY KEY ( cat_id ) + /* Status of the category (A = Active, I = Inactive, D = Deleted) */ + cat_status CHAR DEFAULT 'A', + /* category icon mime type (e.g. "image/png") */ + cat_icon_mime VARCHAR(32) DEFAULT NULL, + /* category icon image blob */ + cat_icon_blob LONGBLOB DEFAULT NULL, + PRIMARY KEY ( cal_id, cat_id, cat_order, cat_owner ) ); /** diff --git a/install/sql/tables-oracle.sql b/install/sql/tables-oracle.sql index a2c72a6e0..4cc134af7 100644 --- a/install/sql/tables-oracle.sql +++ b/install/sql/tables-oracle.sql @@ -35,7 +35,7 @@ CREATE TABLE webcal_entry ( cal_priority INT DEFAULT 5, cal_time INT NULL, cal_type CHAR(1) DEFAULT 'E', - cal_url VARCHAR2(100) NULL, + cal_url VARCHAR2(255) NULL, PRIMARY KEY ( cal_id ) ); CREATE TABLE webcal_entry_repeats ( @@ -156,7 +156,10 @@ CREATE TABLE webcal_categories ( cat_color VARCHAR2(8) NULL, cat_name VARCHAR2(80) NOT NULL, cat_owner VARCHAR2(25), - PRIMARY KEY ( cat_id ) + cat_status CHAR DEFAULT 'A', + cat_icon_mime VARCHAR(32) DEFAULT NULL, + cat_icon_blob BLOB DEFAULT NULL, + PRIMARY KEY ( cal_id, cat_id, cat_order, cat_owner ) ); CREATE TABLE webcal_asst ( cal_boss VARCHAR2(25) NOT NULL, diff --git a/install/sql/tables-postgres.sql b/install/sql/tables-postgres.sql index 3e35eefe1..58412cff5 100644 --- a/install/sql/tables-postgres.sql +++ b/install/sql/tables-postgres.sql @@ -32,7 +32,7 @@ CREATE TABLE webcal_entry ( cal_access CHAR(1) DEFAULT 'P', cal_name VARCHAR(80) NOT NULL, cal_location VARCHAR(100) DEFAULT NULL, - cal_url VARCHAR(100) DEFAULT NULL, + cal_url VARCHAR(255) DEFAULT NULL, cal_completed INT DEFAULT NULL, cal_description TEXT, PRIMARY KEY ( cal_id ) @@ -155,7 +155,10 @@ CREATE TABLE webcal_categories ( cat_owner VARCHAR(25), cat_name VARCHAR(80) NOT NULL, cat_color VARCHAR(8) DEFAULT NULL, - PRIMARY KEY ( cat_id ) + cat_status CHAR DEFAULT 'A', + cat_icon_mime VARCHAR(32) DEFAULT NULL, + cat_icon_blob BYTEA DEFAULT NULL, + PRIMARY KEY ( cal_id, cat_id, cat_order, cat_owner ) ); CREATE TABLE webcal_asst ( cal_boss VARCHAR(25) NOT NULL, diff --git a/install/sql/upgrade-db2.sql b/install/sql/upgrade-db2.sql index da42dbfd8..a94b03727 100644 --- a/install/sql/upgrade-db2.sql +++ b/install/sql/upgrade-db2.sql @@ -299,6 +299,15 @@ CREATE INDEX webcal_import_data_ext_id ON webcal_import_data(cal_external_id); ALTER TABLE webcal_user MODIFY cal_passwd VARCHAR(255); /*upgrade_v1.9.5*/ update webcal_entry_categories SET cat_owner = '' WHERE cat_owner IS NULL; +ALTER TABLE webcal_entry_categories DROP PRIMARY KEY; ALTER TABLE webcal_entry_categories ADD PRIMARY KEY (cal_id, cat_id, cat_order, cat_owner); -/*upgrade_v1.9.7*/ +/*upgrade_v1.9.6*/ /*upgrade_v1.9.10*/ +ALTER TABLE webcal_categories ADD cat_status CHAR DEFAULT 'A'; +ALTER TABLE webcal_categories ADD cat_icon_mime VARCHAR(32) DEFAULT NULL; +ALTER TABLE webcal_categories ADD cat_icon_blob LONGBLOB DEFAULT NULL; +ALTER TABLE webcal_categories MODIFY cat_owner VARCHAR(25) DEFAULT '' NOT NULL; +/*upgrade_v1.9.11*/ +ALTER TABLE webcal_nonuser_cals MODIFY COLUMN cal_url varchar(255); +ALTER TABLE webcal_entry MODIFY COLUMN cal_url varchar(255); +/*upgrade_v1.9.12*/ diff --git a/install/sql/upgrade-ibase.sql b/install/sql/upgrade-ibase.sql index 69798dd5e..6620f24ab 100644 --- a/install/sql/upgrade-ibase.sql +++ b/install/sql/upgrade-ibase.sql @@ -314,6 +314,15 @@ CREATE INDEX IF NOT EXISTS ALTER TABLE webcal_user MODIFY cal_passwd VARCHAR(255); /*upgrade_v1.9.5*/ update webcal_entry_categories SET cat_owner = '' WHERE cat_owner IS NULL; +ALTER TABLE webcal_entry_categories DROP PRIMARY KEY; ALTER TABLE webcal_entry_categories ADD PRIMARY KEY (cal_id, cat_id, cat_order, cat_owner); -/*upgrade_v1.9.7*/ +/*upgrade_v1.9.6*/ /*upgrade_v1.9.10*/ +ALTER TABLE webcal_categories ADD cat_status CHAR DEFAULT 'A'; +ALTER TABLE webcal_categories ADD cat_icon_mime VARCHAR(32) DEFAULT NULL; +ALTER TABLE webcal_categories ADD cat_icon_blob LONGBLOB DEFAULT NULL; +ALTER TABLE webcal_categories MODIFY cat_owner VARCHAR(25) DEFAULT '' NOT NULL; +/*upgrade_v1.9.11*/ +ALTER TABLE webcal_nonuser_cals MODIFY COLUMN cal_url varchar(255); +ALTER TABLE webcal_entry MODIFY COLUMN cal_url varchar(255); +/*upgrade_v1.9.12*/ diff --git a/install/sql/upgrade-mssql.sql b/install/sql/upgrade-mssql.sql deleted file mode 100644 index c5a0d5e12..000000000 --- a/install/sql/upgrade-mssql.sql +++ /dev/null @@ -1,305 +0,0 @@ -/*upgrade_v0.9.14*/ -UPDATE webcal_entry SET cal_time = -1 WHERE cal_time is null; -CREATE TABLE webcal_entry_repeats ( - cal_id INT DEFAULT '0' NOT NULL, - cal_type VARCHAR(20) NULL, - cal_end INT NULL, - cal_frequency INT DEFAULT '1', - cal_days CHAR(7) NULL, - PRIMARY KEY (cal_id) -); - -/*upgrade_v0.9.22*/ -CREATE TABLE webcal_user_layers ( - cal_layerid INT DEFAULT '0' NOT NULL, - cal_login VARCHAR(25) NOT NULL, - cal_layeruser VARCHAR(25) NOT NULL, - cal_color VARCHAR(25) NULL, - cal_dups CHAR(1) DEFAULT 'N', - PRIMARY KEY ( cal_login, cal_layeruser ) -); - -/*upgrade_v0.9.27*/ -CREATE TABLE webcal_site_extras ( - cal_id INT DEFAULT '0' NOT NULL, - cal_name VARCHAR(25) NOT NULL, - cal_type INT NOT NULL, - cal_date INT DEFAULT '0', - cal_remind INT DEFAULT '0', - cal_data TEXT NULL, - PRIMARY KEY ( cal_id, cal_name, cal_type ) -); -/*upgrade_v0.9.35*/ -CREATE TABLE webcal_group ( - cal_group_id INT NOT NULL, - cal_owner VARCHAR(25) NULL, - cal_name VARCHAR(50) NOT NULL, - cal_last_update INT NOT NULL, - PRIMARY KEY ( cal_group_id ) -); -CREATE TABLE webcal_group_user ( - cal_group_id INT NOT NULL, - cal_login VARCHAR(25) NOT NULL, - PRIMARY KEY ( cal_group_id, cal_login ) -); -CREATE TABLE webcal_view ( - cal_view_id INT NOT NULL, - cal_owner VARCHAR(25) NOT NULL, - cal_name VARCHAR(50) NOT NULL, - cal_view_type CHAR(1) NULL, - PRIMARY KEY ( cal_view_id ) -); -CREATE TABLE webcal_view_user ( - cal_view_id INT NOT NULL, - cal_login VARCHAR(25) NOT NULL, - PRIMARY KEY ( cal_view_id, cal_login ) -); -CREATE TABLE webcal_config ( - cal_setting VARCHAR(50) NOT NULL, - cal_value VARCHAR(50) NULL, - PRIMARY KEY ( cal_setting ) -); -CREATE TABLE webcal_entry_log ( - cal_log_id INT NOT NULL, - cal_entry_id INT NOT NULL, - cal_login VARCHAR(25) NOT NULL, - cal_type CHAR(1) NOT NULL, - cal_date INT NOT NULL, - cal_time INT NULL, - cal_text TEXT NULL, - PRIMARY KEY ( cal_log_id ) -); - -/*upgrade_v0.9.37*/ -ALTER TABLE webcal_entry_log ADD cal_user_cal VARCHAR(25) NULL; -CREATE TABLE webcal_entry_repeats_not ( - cal_id INT NOT NULL, - cal_date INT NOT NULL, - PRIMARY KEY ( cal_id, cal_date ) -); - -/*upgrade_v0.9.38*/ -ALTER TABLE webcal_entry_user ADD cal_category INT NULL; -CREATE TABLE webcal_categories ( - cat_id INT NOT NULL, - cat_owner VARCHAR(25) NULL, - cat_name VARCHAR(80) NOT NULL, - PRIMARY KEY ( cat_id ) -); - -/*upgrade_v0.9.40*/ -DELETE FROM webcal_config WHERE cal_setting LIKE 'DATE_FORMAT%'; -DELETE FROM webcal_user_pref WHERE cal_setting LIKE 'DATE_FORMAT%'; - -CREATE TABLE webcal_asst ( - cal_boss VARCHAR(25) NOT NULL, - cal_assistant VARCHAR(25) NOT NULL, - PRIMARY KEY ( cal_boss, cal_assistant ) -); -CREATE TABLE webcal_entry_ext_user ( - cal_id INT DEFAULT 0 NOT NULL, - cal_fullname VARCHAR(50) NOT NULL, - cal_email VARCHAR(75) NULL, - PRIMARY KEY ( cal_id, cal_fullname ) -); -ALTER TABLE webcal_entry ADD cal_ext_for_id INT NULL; - -/*upgrade_v0.9.41*/ -CREATE TABLE webcal_nonuser_cals ( - cal_login VARCHAR(25) NOT NULL, - cal_lastname VARCHAR(25) NULL, - cal_firstname VARCHAR(25) NULL, - cal_admin VARCHAR(25) NOT NULL, - PRIMARY KEY ( cal_login ) -); - -/*upgrade_v0.9.42*/ -CREATE TABLE webcal_report ( - cal_login VARCHAR(25) NOT NULL, - cal_report_id INT NOT NULL, - cal_is_global CHAR(1) DEFAULT 'N' NOT NULL, - cal_report_type VARCHAR(20) NOT NULL, - cal_include_header CHAR(1) DEFAULT 'Y' NOT NULL, - cal_report_name VARCHAR(50) NOT NULL, - cal_time_range INT NOT NULL, - cal_user VARCHAR(25) NULL, - cal_allow_nav CHAR(1) DEFAULT 'Y', - cal_cat_id INT NULL, - cal_include_empty CHAR(1) DEFAULT 'N', - cal_show_in_trailer CHAR(1) DEFAULT 'N', - cal_update_date INT NOT NULL, - PRIMARY KEY ( cal_report_id ) -); -CREATE TABLE webcal_report_template ( - cal_report_id INT NOT NULL, - cal_template_type CHAR(1) NOT NULL, - cal_template_text TEXT NULL, - PRIMARY KEY ( cal_report_id, cal_template_type ) -); -CREATE TABLE webcal_import_data ( - cal_id int NOT NULL, - cal_login VARCHAR(25) NOT NULL, - cal_import_type VARCHAR(15) NOT NULL, - cal_external_id VARCHAR(200) NULL, - PRIMARY KEY ( cal_id, cal_login ) -); - -/*upgrade_v0.9.43*/ -ALTER TABLE webcal_user MODIFY cal_passwd VARCHAR(32) NULL; -DROP TABLE webcal_import_data; -CREATE TABLE webcal_import ( - cal_import_id INT NOT NULL, - cal_name VARCHAR(50) NULL, - cal_date INT NOT NULL, - cal_type VARCHAR(10) NOT NULL, - cal_login VARCHAR(25) NULL, - PRIMARY KEY ( cal_import_id ) -); -CREATE TABLE webcal_import_data ( - cal_import_id INT NOT NULL, - cal_id INT NOT NULL, - cal_login VARCHAR(25) NOT NULL, - cal_import_type VARCHAR(15) NOT NULL, - cal_external_id VARCHAR(200) NULL, - PRIMARY KEY ( cal_id, cal_login ) -); - -/*upgrade_v1.0RC3*/ -ALTER TABLE webcal_view ADD cal_is_global CHAR(1) DEFAULT 'N' NOT NULL; -UPDATE webcal_user_pref SET cal_value = 'day.php' - WHERE cal_value = 'day' AND cal_setting = 'STARTVIEW'; -UPDATE webcal_user_pref SET cal_value = 'week.php' - WHERE cal_value = 'week' AND cal_setting = 'STARTVIEW'; -UPDATE webcal_user_pref SET cal_value = 'month.php' - WHERE cal_value = 'month' AND cal_setting = 'STARTVIEW'; -UPDATE webcal_user_pref SET cal_value = 'year.php' - WHERE cal_value = 'year' AND cal_setting = 'STARTVIEW'; -UPDATE webcal_config SET cal_value = 'week.php' - WHERE cal_setting = 'STARTVIEW'; - -/*upgrade_v1.1.0-CVS*/ -CREATE TABLE webcal_access_function ( - cal_login VARCHAR(25) NOT NULL, - cal_permissions VARCHAR(64) NOT NULL, - PRIMARY KEY ( cal_login ) -); -CREATE TABLE webcal_access_user ( - cal_login VARCHAR(25) NOT NULL, - cal_other_user VARCHAR(25) NOT NULL, - PRIMARY KEY ( cal_login, cal_other_user ) -); -ALTER TABLE webcal_nonuser_cals ADD cal_is_public CHAR(1) DEFAULT 'N' NOT NULL; - -/*upgrade_v1.1.0a-CVS*/ -CREATE TABLE webcal_user_template ( - cal_login VARCHAR(25) NOT NULL, - cal_type CHAR(1) NOT NULL, - cal_template_text TEXT NULL, - PRIMARY KEY ( cal_login, cal_type ) -); -ALTER TABLE webcal_entry_repeats ADD cal_endtime INT NULL; -ALTER TABLE webcal_entry_repeats ADD cal_bymonth VARCHAR(50) NULL; -ALTER TABLE webcal_entry_repeats ADD cal_bymonthday VARCHAR(100) NULL; -ALTER TABLE webcal_entry_repeats ADD cal_byday VARCHAR(100) NULL; -ALTER TABLE webcal_entry_repeats ADD cal_bysetpos VARCHAR(50) NULL; -ALTER TABLE webcal_entry_repeats ADD cal_byweekno VARCHAR(50) NULL; -ALTER TABLE webcal_entry_repeats ADD cal_byyearday VARCHAR(50) NULL; -ALTER TABLE webcal_entry_repeats ADD cal_wkst char(2) default 'MO'; -ALTER TABLE webcal_entry_repeats ADD cal_count INT NULL; -ALTER TABLE webcal_entry_repeats_not ADD cal_exdate INT NOT NULL default '1'; -ALTER TABLE webcal_entry ADD cal_due_date INT NULL; -ALTER TABLE webcal_entry ADD cal_due_time INT NULL; -ALTER TABLE webcal_entry ADD cal_location VARCHAR(100) NULL; -ALTER TABLE webcal_entry ADD cal_url VARCHAR(100) NULL; -ALTER TABLE webcal_entry ADD cal_completed INT NULL; -ALTER TABLE webcal_entry_user ADD cal_percent INT NOT NULL default '0'; - -/*upgrade_v1.1.0b-CVS*/ -CREATE TABLE webcal_entry_categories ( - cal_id INT NOT NULL default '0', - cat_id INT NOT NULL default '0', - cat_order INT NOT NULL default '0', - cat_owner VARCHAR(25) NULL -); - -/*upgrade_v1.1.0c-CVS*/ -CREATE TABLE webcal_blob ( - cal_blob_id INT NOT NULL, - cal_id INT NULL, - cal_login VARCHAR(25) NULL, - cal_name VARCHAR(30) NULL, - cal_description VARCHAR(128) NULL, - cal_size INT NULL, - cal_mime_type VARCHAR(50) NULL, - cal_type CHAR(1) NOT NULL, - cal_mod_date INT NOT NULL, - cal_mod_time INT NOT NULL, - cal_blob IMAGE NULL, - PRIMARY KEY ( cal_blob_id ) -); - -/*upgrade_v1.1.0d-CVS*/ -DROP TABLE webcal_access_user; -CREATE TABLE webcal_access_user ( - cal_login VARCHAR(25) NOT NULL, - cal_other_user VARCHAR(25) NOT NULL, - cal_can_view INT NOT NULL DEFAULT '0', - cal_can_edit INT NOT NULL DEFAULT '0', - cal_can_approve INT NOT NULL DEFAULT '0', - cal_can_invite CHAR(1) NOT NULL DEFAULT 'Y', - cal_can_email CHAR(1) NOT NULL DEFAULT 'Y', - cal_see_time_only CHAR(1) NOT NULL DEFAULT 'N', - PRIMARY KEY ( cal_login, cal_other_user ) -); - -/*upgrade_v1.1.0e-CVS*/ -CREATE TABLE webcal_reminders ( - cal_id INT NOT NULL DEFAULT '0', - cal_date INT NOT NULL DEFAULT '0', - cal_offset INT NOT NULL DEFAULT '0', - cal_related CHAR(1) NOT NULL DEFAULT 'S', - cal_before CHAR(1) NOT NULL DEFAULT 'Y', - cal_last_sent INT NOT NULL DEFAULT '0', - cal_repeats INT NOT NULL DEFAULT '0', - cal_duration INT NOT NULL DEFAULT '0', - cal_times_sent INT NOT NULL DEFAULT '0', - cal_action VARCHAR(12) NOT NULL DEFAULT 'EMAIL', - PRIMARY KEY ( cal_id ) -); - -/*upgrade_v1.1.1*/ -ALTER TABLE webcal_nonuser_cals ADD cal_url VARCHAR(75) DEFAULT NULL; - -/*upgrade_v1.1.2*/ -ALTER TABLE webcal_categories ADD cat_color VARCHAR(8) DEFAULT NULL; -ALTER TABLE webcal_user ADD cal_enabled CHAR(1) DEFAULT 'Y'; -ALTER TABLE webcal_user ADD cal_telephone VARCHAR(50) NULL; -ALTER TABLE webcal_user ADD cal_address VARCHAR(75) NULL; -ALTER TABLE webcal_user ADD cal_title VARCHAR(75) NULL; -ALTER TABLE webcal_user ADD cal_birthday INT NULL; -ALTER TABLE webcal_user ADD cal_last_login INT NULL; - -/*upgrade_v1.1.3*/ -CREATE TABLE webcal_timezones ( - tzid VARCHAR(100) NOT NULL DEFAULT '', - dtstart VARCHAR(25) DEFAULT NULL, - dtend VARCHAR(25) DEFAULT NULL, - vtimezone TEXT, - PRIMARY KEY ( tzid ) -); -/*upgrade_v1.3.0*/ -CREATE INDEX - webcal_entry_categories ON webcal_entry_categories(cat_id); -/*upgrade_v1.9.0*/ -ALTER TABLE webcal_import ADD cal_check_date INT NULL; -ALTER TABLE webcal_import ADD cal_md5 VARCHAR(32) NULL DEFAULT NULL; -CREATE INDEX - webcal_import_data_type ON webcal_import_data(cal_import_type); -CREATE INDEX - webcal_import_data_ext_id ON webcal_import_data(cal_external_id); -ALTER TABLE webcal_user MODIFY cal_passwd VARCHAR(255); -/*upgrade_v1.9.5*/ -update webcal_entry_categories SET cat_owner = '' WHERE cat_owner IS NULL; -ALTER TABLE webcal_entry_categories ADD PRIMARY KEY (cal_id, cat_id, cat_order, cat_owner); -/*upgrade_v1.9.7*/ -/*upgrade_v1.9.10*/ diff --git a/install/sql/upgrade-mysql.sql b/install/sql/upgrade-mysql.sql index c55bb10a0..e217fcb56 100644 --- a/install/sql/upgrade-mysql.sql +++ b/install/sql/upgrade-mysql.sql @@ -269,6 +269,15 @@ ALTER TABLE webcal_user MODIFY cal_passwd VARCHAR(255); /*upgrade_v1.9.2*/ /*upgrade_v1.9.5*/ update webcal_entry_categories SET cat_owner = '' WHERE cat_owner IS NULL; +ALTER TABLE webcal_entry_categories DROP PRIMARY KEY; ALTER TABLE webcal_entry_categories ADD PRIMARY KEY (cal_id, cat_id, cat_order, cat_owner); /*upgrade_v1.9.6*/ /*upgrade_v1.9.10*/ +ALTER TABLE webcal_categories ADD cat_status CHAR DEFAULT 'A'; +ALTER TABLE webcal_categories ADD cat_icon_mime VARCHAR(32) DEFAULT NULL; +ALTER TABLE webcal_categories ADD cat_icon_blob LONGBLOB DEFAULT NULL; +ALTER TABLE webcal_categories MODIFY cat_owner VARCHAR(25) DEFAULT '' NOT NULL; +/*upgrade_v1.9.11*/ +ALTER TABLE webcal_nonuser_cals MODIFY COLUMN cal_url varchar(255); +ALTER TABLE webcal_entry MODIFY COLUMN cal_url varchar(255); +/*upgrade_v1.9.12*/ diff --git a/install/sql/upgrade-oracle.sql b/install/sql/upgrade-oracle.sql index f4128669e..58b93b430 100644 --- a/install/sql/upgrade-oracle.sql +++ b/install/sql/upgrade-oracle.sql @@ -297,6 +297,15 @@ CREATE INDEX webcal_import_data_ext_id ON webcal_import_data(cal_external_id); ALTER TABLE webcal_user MODIFY cal_passwd VARCHAR(255); /*upgrade_v1.9.5*/ update webcal_entry_categories SET cat_owner = '' WHERE cat_owner IS NULL; +ALTER TABLE webcal_entry_categories DROP PRIMARY KEY; ALTER TABLE webcal_entry_categories ADD PRIMARY KEY (cal_id, cat_id, cat_order, cat_owner); -/*upgrade_v1.9.7*/ +/*upgrade_v1.9.6*/ /*upgrade_v1.9.10*/ +ALTER TABLE webcal_categories ADD cat_status CHAR DEFAULT 'A'; +ALTER TABLE webcal_categories ADD cat_icon_mime VARCHAR(32) DEFAULT NULL; +ALTER TABLE webcal_categories ADD cat_icon_blob LONGBLOB DEFAULT NULL; +ALTER TABLE webcal_categories MODIFY cat_owner VARCHAR(25) DEFAULT '' NOT NULL; +/*upgrade_v1.9.11*/ +ALTER TABLE webcal_nonuser_cals MODIFY COLUMN cal_url varchar(255); +ALTER TABLE webcal_entry MODIFY COLUMN cal_url varchar(255); +/*upgrade_v1.9.12*/ diff --git a/install/sql/upgrade-postgres.sql b/install/sql/upgrade-postgres.sql index 4b8a5f5bb..9a8cbad20 100644 --- a/install/sql/upgrade-postgres.sql +++ b/install/sql/upgrade-postgres.sql @@ -315,6 +315,15 @@ CREATE INDEX webcal_import_data_ext_id ON webcal_import_data(cal_external_id); ALTER TABLE webcal_user MODIFY cal_passwd VARCHAR(255); /*upgrade_v1.9.5*/ update webcal_entry_categories SET cat_owner = '' WHERE cat_owner IS NULL; +ALTER TABLE webcal_entry_categories DROP PRIMARY KEY; ALTER TABLE webcal_entry_categories ADD PRIMARY KEY (cal_id, cat_id, cat_order, cat_owner); -/*upgrade_v1.9.7*/ +/*upgrade_v1.9.6*/ /*upgrade_v1.9.10*/ +ALTER TABLE webcal_categories ADD cat_status CHAR DEFAULT 'A'; +ALTER TABLE webcal_categories ADD cat_icon_mime VARCHAR(32) DEFAULT NULL; +ALTER TABLE webcal_categories ADD cat_icon_blob LONGBLOB DEFAULT NULL; +ALTER TABLE webcal_categories MODIFY cat_owner VARCHAR(25) DEFAULT '' NOT NULL; +/*upgrade_v1.9.11*/ +ALTER TABLE webcal_nonuser_cals MODIFY COLUMN cal_url varchar(255); +ALTER TABLE webcal_entry MODIFY COLUMN cal_url varchar(255); +/*upgrade_v1.9.12*/ diff --git a/install/sql/upgrade-sql.php b/install/sql/upgrade-sql.php new file mode 100644 index 000000000..057d53d53 --- /dev/null +++ b/install/sql/upgrade-sql.php @@ -0,0 +1,462 @@ + $update) { + $normalizedUpdateVersion = str_replace('v', '', strtolower($update['version'])); + if (version_compare($normalizedUpdateVersion, $normalizedCurrentVersion, '>=')) { + return $index; + } + } + + // If no update is found, return null + return null; +} + +function getSqlUpdates($currentVersion, $dbType = 'default', $includeFunctions = false) +{ + global $updates; + if ($dbType == 'mysqli') + $dbType = 'mysql'; // use the same SQL + $startIndex = findUpgradeStartIndex($currentVersion); + $sql = []; + if ($startIndex >= 0 && $startIndex != null) { + for ($i = $startIndex + 1; $i < count($updates); $i++) { + $key = 'default-sql'; + if (isset($updates[$i][$dbType . '-sql'])) { + $key = $dbType . '-sql'; + } + //echo "updates $i $key => '" . $updates[$i][$key] . "'\n"; + $s = explode(';', rtrim($updates[$i][$key], ';')); + for ($j = 0; $j < count($s); $j++) { + $s[$j] = trim($s[$j]); + //echo "$j => '" . $s[$j] . "'\n"; + } + $sql = array_merge($sql, $s); + // Add any upgrade function after the SQL changes + if (isset($updates[$i]['upgrade-function'])) { + $sql[] = 'function:' . $updates[$i]['upgrade-function']; + } + } + } + return $sql; +} + +$updates = [ + [ + 'version' => 'v0.9.22', + 'default-sql' => <<<'SQL' +UPDATE webcal_entry SET cal_time = -1 WHERE cal_time IS NULL; +ALTER TABLE webcal_entry MODIFY cal_time INT NOT NULL DEFAULT -1; +CREATE TABLE webcal_entry_repeats ( + cal_id INT NOT NULL, + cal_days CHAR(7), + cal_end INT, + cal_frequency INT DEFAULT 1, + cal_type VARCHAR(20), + PRIMARY KEY (cal_id) +); +SQL + ], + [ + 'version' => 'v0.9.27', + 'default-sql' => <<<'SQL' +CREATE TABLE webcal_user_layers ( + cal_login VARCHAR(25) NOT NULL, + cal_layeruser VARCHAR(25) NOT NULL, + cal_color VARCHAR(25), + cal_dups CHAR(1) NOT NULL DEFAULT 'N', + cal_layerid INT NOT NULL, + PRIMARY KEY (cal_login,cal_layeruser) +); +SQL + ], + [ + 'version' => 'v0.9.35', + 'default-sql' => <<<'SQL' +CREATE TABLE webcal_site_extras ( + cal_id INT NOT NULL, + cal_name VARCHAR(25) NOT NULL, + cal_type INT NOT NULL, + cal_date INT, + cal_remind INT, + cal_data TEXT, + PRIMARY KEY (cal_id,cal_name,cal_type) +); +SQL + ], + [ + 'version' => 'v0.9.37', + 'default-sql' => <<<'SQL' +CREATE TABLE webcal_config ( + cal_setting VARCHAR(50) NOT NULL, + cal_value VARCHAR(50), + PRIMARY KEY (cal_setting) +); +CREATE TABLE webcal_entry_log ( + cal_log_id INT NOT NULL, + cal_date INT NOT NULL, + cal_entry_id INT NOT NULL, + cal_login VARCHAR(25) NOT NULL, + cal_time INT, + cal_type CHAR(1) NOT NULL, + cal_text TEXT, + PRIMARY KEY (cal_log_id) +); +CREATE TABLE webcal_group ( + cal_group_id INT NOT NULL, + cal_last_update INT NOT NULL, + cal_name VARCHAR(50) NOT NULL, + cal_owner VARCHAR(25), + PRIMARY KEY (cal_group_id) +); +CREATE TABLE webcal_group_user ( + cal_group_id INT NOT NULL, + cal_login VARCHAR(25) NOT NULL, + PRIMARY KEY (cal_group_id,cal_login) +); +CREATE TABLE webcal_view ( + cal_view_id INT NOT NULL, + cal_name VARCHAR(50) NOT NULL, + cal_owner VARCHAR(25) NOT NULL, + cal_view_type CHAR(1), + PRIMARY KEY (cal_view_id) +); +CREATE TABLE webcal_view_user ( + cal_view_id INT NOT NULL, + cal_login VARCHAR(25) NOT NULL, + PRIMARY KEY (cal_view_id,cal_login) +); +SQL + ], + [ + 'version' => 'v0.9.38', + 'default-sql' => <<<'SQL' +ALTER TABLE webcal_entry_log ADD cal_user_cal VARCHAR(25); +CREATE TABLE webcal_entry_repeats_not ( + cal_id INT NOT NULL, + cal_date INT NOT NULL, + PRIMARY KEY (cal_id,cal_date) +); +SQL + ], + [ + 'version' => 'v0.9.40', + 'default-sql' => <<<'SQL' +ALTER TABLE webcal_entry_user ADD cal_category INT; +CREATE TABLE webcal_categories ( + cat_id INT NOT NULL, + cat_name VARCHAR(80) NOT NULL, + cat_owner VARCHAR(25), + PRIMARY KEY (cat_id) +); +SQL + ], + [ + 'version' => 'v0.9.41', + 'default-sql' => <<<'SQL' +DELETE FROM webcal_config WHERE cal_setting LIKE 'DATE_FORMAT%'; +DELETE FROM webcal_user_pref WHERE cal_setting LIKE 'DATE_FORMAT%'; +ALTER TABLE webcal_entry ADD cal_ext_for_id INT; +CREATE TABLE webcal_asst ( + cal_boss VARCHAR(25) NOT NULL, + cal_assistant VARCHAR(25) NOT NULL, + PRIMARY KEY (cal_boss,cal_assistant) +); +CREATE TABLE webcal_entry_ext_user ( + cal_id INT NOT NULL, + cal_fullname VARCHAR(50) NOT NULL, + cal_email VARCHAR(75), + PRIMARY KEY (cal_id,cal_fullname) +); +SQL + ], + [ + 'version' => 'v0.9.42', + 'default-sql' => <<<'SQL' +CREATE TABLE webcal_nonuser_cals ( + cal_login VARCHAR(25) NOT NULL, + cal_admin VARCHAR(25) NOT NULL, + cal_firstname VARCHAR(25), + cal_lastname VARCHAR(25), + PRIMARY KEY (cal_login) +); +SQL + ], + [ + 'version' => 'v0.9.43', + 'default-sql' => <<<'SQL' +CREATE TABLE webcal_report ( + cal_report_id INT NOT NULL, + cal_allow_nav CHAR(1) NOT NULL DEFAULT 'Y', + cal_cat_id INT, + cal_include_empty CHAR(1) NOT NULL DEFAULT 'N', + cal_include_header CHAR(1) NOT NULL DEFAULT 'Y', + cal_is_global CHAR(1) NOT NULL DEFAULT 'N', + cal_login VARCHAR(25) NOT NULL, + cal_report_name VARCHAR(50) NOT NULL, + cal_report_type VARCHAR(20) NOT NULL, + cal_show_in_trailer CHAR(1) NOT NULL DEFAULT 'N', + cal_time_range INT NOT NULL, + cal_update_date INT NOT NULL, + cal_user VARCHAR(25), + PRIMARY KEY (cal_report_id) +); +CREATE TABLE webcal_report_template ( + cal_report_id INT NOT NULL, + cal_template_type CHAR(1) NOT NULL, + cal_template_text TEXT, + PRIMARY KEY (cal_report_id,cal_template_type) +); +SQL + ], + [ + 'version' => 'v1.0RC3', + 'default-sql' => <<<'SQL' +ALTER TABLE webcal_user MODIFY cal_passwd VARCHAR(32); +DROP TABLE IF EXISTS webcal_import_data; +CREATE TABLE webcal_import ( + cal_import_id INT NOT NULL, + cal_date INT NOT NULL, + cal_login VARCHAR(25), + cal_name VARCHAR(50), + cal_type VARCHAR(10) NOT NULL, + PRIMARY KEY (cal_import_id) +); +CREATE TABLE webcal_import_data ( + cal_id INT NOT NULL, + cal_login VARCHAR(25) NOT NULL, + cal_external_id VARCHAR(200), + cal_import_id INT NOT NULL, + cal_import_type VARCHAR(15) NOT NULL, + PRIMARY KEY (cal_id,cal_login) +); +SQL + ], + [ + 'version' => 'v1.1.0-CVS', + 'default-sql' => <<<'SQL' +UPDATE webcal_config SET cal_value = 'week.php' WHERE cal_setting = 'STARTVIEW'; +UPDATE webcal_user_pref SET cal_value = 'day.php' WHERE cal_value = 'day' AND cal_setting = 'STARTVIEW'; +UPDATE webcal_user_pref SET cal_value = 'month.php' WHERE cal_value = 'month' AND cal_setting = 'STARTVIEW'; +UPDATE webcal_user_pref SET cal_value = 'week.php' WHERE cal_value = 'week' AND cal_setting = 'STARTVIEW'; +UPDATE webcal_user_pref SET cal_value = 'year.php' WHERE cal_value = 'year' AND cal_setting = 'STARTVIEW'; +UPDATE webcal_view SET cal_is_global = 'N'; +SQL + ], + [ + 'version' => 'v1.1.0a-CVS', + 'default-sql' => <<<'SQL' +CREATE TABLE webcal_access_function ( + cal_login VARCHAR(25) NOT NULL, + cal_permissions VARCHAR(64) NOT NULL, + PRIMARY KEY (cal_login) +); +ALTER TABLE webcal_nonuser_cals ADD cal_is_public CHAR(1) NOT NULL DEFAULT 'N'; +SQL + ], + [ + 'version' => 'v1.1.0b-CVS', + 'default-sql' => <<<'SQL' +CREATE TABLE webcal_user_template ( + cal_login VARCHAR(25) NOT NULL, + cal_type CHAR(1) NOT NULL, + cal_template_text TEXT, + PRIMARY KEY (cal_login,cal_type) +); +ALTER TABLE webcal_entry_repeats ADD cal_endtime INT(11) DEFAULT NULL; +ALTER TABLE webcal_entry_repeats ADD cal_bymonth VARCHAR(50) DEFAULT NULL; +ALTER TABLE webcal_entry_repeats ADD cal_bymonthday VARCHAR(100) DEFAULT NULL; +ALTER TABLE webcal_entry_repeats ADD cal_byday VARCHAR(100) DEFAULT NULL; +ALTER TABLE webcal_entry_repeats ADD cal_bysetpos VARCHAR(50) DEFAULT NULL; +ALTER TABLE webcal_entry_repeats ADD cal_byweekno VARCHAR(50) DEFAULT NULL; +ALTER TABLE webcal_entry_repeats ADD cal_byyearday VARCHAR(50) DEFAULT NULL; +ALTER TABLE webcal_entry_repeats ADD cal_wkst CHAR(2) DEFAULT 'MO'; +ALTER TABLE webcal_entry_repeats ADD cal_count INT(11) DEFAULT NULL; +ALTER TABLE webcal_entry_repeats_not ADD cal_exdate INT(1) NOT NULL DEFAULT '1'; +ALTER TABLE webcal_entry ADD cal_due_date INT(11) DEFAULT NULL; +ALTER TABLE webcal_entry ADD cal_due_time INT(11) DEFAULT NULL; +ALTER TABLE webcal_entry ADD cal_location VARCHAR(100) DEFAULT NULL; +ALTER TABLE webcal_entry ADD cal_url VARCHAR(100) DEFAULT NULL; +ALTER TABLE webcal_entry ADD cal_completed INT(11) DEFAULT NULL; +ALTER TABLE webcal_entry_user ADD cal_percent INT(11) NOT NULL DEFAULT '0'; +ALTER TABLE webcal_site_extras DROP PRIMARY KEY; +SQL + ], + [ + 'version' => 'v1.1.0c-CVS', + 'upgrade-function' => 'do_v11b_updates', + 'default-sql' => <<<'SQL' +CREATE TABLE webcal_entry_categories ( + cal_id int(11) NOT NULL DEFAULT '0', + cat_id int(11) NOT NULL DEFAULT '0', + cat_order int(11) NOT NULL DEFAULT '0', + cat_owner VARCHAR(25) DEFAULT NULL +); +SQL + ], + [ + 'version' => 'v1.1.0d-CVS', + 'default-sql' => <<<'SQL' +CREATE TABLE webcal_blob ( + cal_blob_id INT NOT NULL, + cal_id INT NULL, + cal_login VARCHAR(25) NULL, + cal_name VARCHAR(30) NULL, + cal_description VARCHAR(128) NULL, + cal_size INT NULL, + cal_mime_type VARCHAR(50) NULL, + cal_type CHAR(1) NOT NULL, + cal_mod_date INT NOT NULL, + cal_mod_time INT NOT NULL, + cal_blob BYTEA, + PRIMARY KEY ( cal_blob_id ) +); +SQL, + 'postgres-sql' => <<<'SQL' +CREATE TABLE webcal_blob ( + cal_blob_id INT NOT NULL, + cal_id INT NULL, + cal_login VARCHAR(25) NULL, + cal_name VARCHAR(30) NULL, + cal_description VARCHAR(128) NULL, + cal_size INT NULL, + cal_mime_type VARCHAR(50) NULL, + cal_type CHAR(1) NOT NULL, + cal_mod_date INT NOT NULL, + cal_mod_time INT NOT NULL, + cal_blob LONGBLOB, + PRIMARY KEY ( cal_blob_id ) +); +SQL + ], + [ + 'version' => 'v1.1.0e-CVS', + 'upgrade-function' => 'do_v11e_updates', + 'default-sql' => <<<'SQL' +DROP TABLE IF EXISTS webcal_access_user; +CREATE TABLE webcal_access_user ( + cal_login VARCHAR(25) NOT NULL, + cal_other_user VARCHAR(25) NOT NULL, + cal_can_view INT NOT NULL DEFAULT '0', + cal_can_edit INT NOT NULL DEFAULT '0', + cal_can_approve INT NOT NULL DEFAULT '0', + cal_can_invite CHAR(1) DEFAULT 'Y', + cal_can_email CHAR(1) DEFAULT 'Y', + cal_see_time_only CHAR(1) DEFAULT 'N', + PRIMARY KEY ( cal_login, cal_other_user ) +); +SQL + ], + [ + 'version' => 'v1.1.1', + 'default-sql' => <<<'SQL' +CREATE TABLE webcal_reminders ( + cal_id INT NOT NULL DEFAULT '0', + cal_date INT NOT NULL DEFAULT '0', + cal_offset INT NOT NULL DEFAULT '0', + cal_related CHAR(1) NOT NULL DEFAULT 'S', + cal_before CHAR(1) NOT NULL DEFAULT 'Y', + cal_last_sent INT NOT NULL DEFAULT '0', + cal_repeats INT NOT NULL DEFAULT '0', + cal_duration INT NOT NULL DEFAULT '0', + cal_times_sent INT NOT NULL DEFAULT '0', + cal_action VARCHAR(12) NOT NULL DEFAULT 'EMAIL', + PRIMARY KEY ( cal_id ) +); +SQL + ], + [ + 'version' => 'v1.1.2', + 'default-sql' => <<<'SQL' +ALTER TABLE webcal_nonuser_cals ADD cal_url VARCHAR(255) DEFAULT NULL; +SQL + ], + [ + 'version' => 'v1.1.3', + 'default-sql' => <<<'SQL' +ALTER TABLE webcal_categories ADD cat_color VARCHAR(8) DEFAULT NULL; +ALTER TABLE webcal_user ADD cal_enabled CHAR(1) DEFAULT 'Y'; +ALTER TABLE webcal_user ADD cal_telephone VARCHAR(50) DEFAULT NULL; +ALTER TABLE webcal_user ADD cal_address VARCHAR(75) DEFAULT NULL; +ALTER TABLE webcal_user ADD cal_title VARCHAR(75) DEFAULT NULL; +ALTER TABLE webcal_user ADD cal_birthday INT NULL; +ALTER TABLE webcal_user ADD cal_last_login INT NULL; +SQL + ], + [ + 'version' => 'v1.3.0', + 'default-sql' => <<<'SQL' +CREATE TABLE webcal_timezones ( + tzid VARCHAR(100) NOT NULL DEFAULT '', + dtstart VARCHAR(25) DEFAULT NULL, + dtend VARCHAR(25) DEFAULT NULL, + vtimezone TEXT, + PRIMARY KEY ( tzid ) +); +SQL + ], + [ + 'version' => 'v1.9.0', + 'default-sql' => <<<'SQL' +CREATE INDEX webcal_entry_categories ON webcal_entry_categories(cat_id); +SQL + ], + [ + 'version' => 'v1.9.1', + 'default-sql' => <<<'SQL' +ALTER TABLE webcal_import ADD cal_check_date INT NULL; +ALTER TABLE webcal_import ADD cal_md5 VARCHAR(32) NULL DEFAULT NULL; +CREATE INDEX webcal_import_data_type ON webcal_import_data(cal_import_type); +CREATE INDEX webcal_import_data_ext_id ON webcal_import_data(cal_external_id); +ALTER TABLE webcal_user MODIFY cal_passwd VARCHAR(255); +SQL + ], + [ + 'version' => 'v1.9.6', + 'default-sql' => <<<'SQL' +UPDATE webcal_entry_categories SET cat_owner = '' WHERE cat_owner IS NULL; +ALTER TABLE webcal_entry_categories ADD PRIMARY KEY (cal_id, cat_id, cat_order, cat_owner); +SQL + ], + [ + 'version' => 'v1.9.11', + 'upgrade-function' => 'do_v1_9_11_updates', + 'default-sql' => <<<'SQL' +ALTER TABLE webcal_categories ADD cat_status CHAR DEFAULT 'A'; +ALTER TABLE webcal_categories ADD cat_icon_mime VARCHAR(32) DEFAULT NULL; +ALTER TABLE webcal_categories ADD cat_icon_blob LONGBLOB DEFAULT NULL; +ALTER TABLE webcal_categories MODIFY cat_owner VARCHAR(25) DEFAULT '' NOT NULL; +SQL, + 'postgres-sql' => <<<'SQL' +ALTER TABLE webcal_categories ADD COLUMN cat_status CHAR DEFAULT 'A'; +ALTER TABLE webcal_categories ADD COLUMN cat_icon_mime VARCHAR(32) DEFAULT NULL; +ALTER TABLE webcal_categories ADD COLUMN cat_icon_blob BYTEA DEFAULT NULL; +ALTER TABLE webcal_categories MODIFY cat_owner VARCHAR(25) DEFAULT '' NOT NULL; +SQL + ], + [ + 'version' => 'v1.9.12', + 'default-sql' => <<<'SQL' +ALTER TABLE webcal_nonuser_cals MODIFY COLUMN cal_url VARCHAR(255); +ALTER TABLE webcal_entry MODIFY COLUMN cal_url VARCHAR(255); +SQL + ], +]; diff --git a/install/sql/upgrade.sql b/install/sql/upgrade.sql index 9e620564d..932242dc6 100644 --- a/install/sql/upgrade.sql +++ b/install/sql/upgrade.sql @@ -615,6 +615,15 @@ CREATE INDEX webcal_import_data_ext_id ON webcal_import_data(cal_external_id); ALTER TABLE webcal_user MODIFY cal_passwd VARCHAR(255); /*upgrade_v1.9.5*/ update webcal_entry_categories SET cat_owner = '' WHERE cat_owner IS NULL; +ALTER TABLE webcal_entry_categories DROP PRIMARY KEY; ALTER TABLE webcal_entry_categories ADD PRIMARY KEY (cal_id, cat_id, cat_order, cat_owner); -/*upgrade_v1.9.7*/ +/*upgrade_v1.9.6*/ /*upgrade_v1.9.10*/ +ALTER TABLE webcal_categories ADD cat_status CHAR DEFAULT 'A'; +ALTER TABLE webcal_categories ADD cat_icon_mime VARCHAR(32) DEFAULT NULL; +ALTER TABLE webcal_categories ADD cat_icon_blob LONGBLOB DEFAULT NULL; +ALTER TABLE webcal_categories MODIFY cat_owner VARCHAR(25) DEFAULT '' NOT NULL; +/*upgrade_v1.9.11*/ +ALTER TABLE webcal_nonuser_cals MODIFY COLUMN cal_url varchar(255); +ALTER TABLE webcal_entry MODIFY COLUMN cal_url varchar(255); +/*upgrade_v1.9.12*/ diff --git a/install/sql/upgrade_matrix.php b/install/sql/upgrade_matrix.php index 46fe8a509..dfa3403d8 100644 --- a/install/sql/upgrade_matrix.php +++ b/install/sql/upgrade_matrix.php @@ -1,63 +1,30 @@ 1.3.0 ['INSERT INTO webcal_timezones ( tzid ) VALUES ( "zzz" )', 'DELETE FROM webcal_timezones WHERE tzid = "zzz"', - 'v1.1.2', 'upgrade_v1.1.3'], - // This one is different because it is an index that was added. - // Upgrade from 1.1.3 -> 1.3.0 - ['DROP INDEX webcal_entry_categories ON webcal_entry_categories', - 'CREATE INDEX webcal_entry_categories ON webcal_entry_categories(cat_id)', - 'v1.1.3', 'upgrade_v1.3.0'], + 'v1.1.2', 'upgrade_v1.3.0'], // Upgrade from 1.3.0 -> 1.9.0 ['INSERT INTO webcal_import (cal_import_id, cal_md5, cal_date, cal_type) VALUES (999999, "XXX", 1, "X")', 'DELETE FROM webcal_import WHERE cal_import_id = 999999', @@ -87,10 +50,18 @@ // Upgrade from 1.9.0 -> 1.9.6 // Check to see if we can set cat_owner to NULL in webcal_entry_categories // Should get MySQL error: Column 'cat_owner' cannot be null - ['INSERT INTO webcal_entry_categories (cal_id, cat_id, cat_order, cat_owner) VALUES (999999, 1, -1, NULL)', + ['INSERT INTO webcal_entry_categories (cal_id, cat_id, cat_order, cat_owner) VALUES (999999, 1, -1, "")', 'DELETE FROM webcal_entry_categories WHERE cal_id = 999999 AND cat_order = -1', - 'v1.3.0', 'upgrade_v1.9.6'], -//don't change this array element + 'v1.9.0', 'upgrade_v1.9.6'], + // Upgrade from 1.9.10 -> 1.9.11 + ['INSERT INTO webcal_categories (cat_id, cat_name, cat_owner, cat_icon_mime) VALUES (999999, "nocat", "nobody", "image/gif")', + 'DELETE FROM webcal_categories WHERE cat_id = 999999 AND cat_owner = "nobody"', + 'v1.9.10', 'upgrade_v1.9.11'], + // Upgrade from 1.9.11 -> 1.9.12 + ["insert into webcal_entry (cal_id, cal_name, cal_create_by, cal_date, cal_duration, cal_url) values (-999, 'Test', 'nobody', 20201231, 0, '01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789')", + 'delete from webcal_entry where cal_id = -999', + 'v1.9.11', 'upgrade_v1.9.12'], + // don't change this array element ['','', $PROGRAM_VERSION, ''] ]; diff --git a/install/style.css b/install/style.css new file mode 100644 index 000000000..7369ad96b --- /dev/null +++ b/install/style.css @@ -0,0 +1,26 @@ +.titlecontainer { + display: flex; /* Use flexbox layout */ + align-items: center; /* Center items vertically */ +} + +.titlecontainer img { + display: block; /* Remove any default spacing below the image */ + margin-right: 20px; /* Space between image and text */ +} + +.heading { + margin: 0; /* Remove default margins from h1 */ + /* Additional styles for your h1 if needed */ +} + +li { + display: flex; /* Use flexbox layout */ + align-items: center; /* Center items vertically */ + margin-bottom: 0.3em; +} + +li img { + display: block; /* Remove any default spacing below the image */ + margin-right: 10px; /* Space between text and image */ +} + diff --git a/install/webcal_installer_sm.png b/install/webcal_installer_sm.png new file mode 100644 index 000000000..7fd1d0c67 Binary files /dev/null and b/install/webcal_installer_sm.png differ diff --git a/release-files b/release-files index 03e21a443..ca23e1438 100644 --- a/release-files +++ b/release-files @@ -36,6 +36,7 @@ export_handler.php export.php favicon.ico freebusy.php +getIcon.php GPL.html groups.php help_admin.php @@ -53,10 +54,12 @@ images/blank.gif images/bootstrap-icons/arrow-90deg-up.svg images/bootstrap-icons/arrow-down-short.svg images/bootstrap-icons/arrow-left-circle.svg +images/bootstrap-icons/arrow-left.svg images/bootstrap-icons/arrow-right-circle.svg images/bootstrap-icons/arrow-up-short.svg images/bootstrap-icons/check-circle.svg images/bootstrap-icons/circle-fill.svg +images/bootstrap-icons/circle.svg images/bootstrap-icons/dash-circle.svg images/bootstrap-icons/exclamation-triangle-fill.svg images/bootstrap-icons/info-circle-fill.svg @@ -172,12 +175,30 @@ index.php install/default_config.php install/headless.php install/index.php +install/install_adminuser_handler.php +install/install_adminuser.php +install/install_ajax.php +install/install_appsettings_handler.php +install/install_appsettings.php +install/install_auth_handler.php +install/install_auth.php +install/install_createdb_handler.php +install/install_createdb.php +install/install_dbload_handler.php +install/install_dbload.php +install/install_dbsettings_handler.php +install/install_dbsettings.php +install/install_dbtables_handler.php +install/install_dbtables.php +install/install_finish.php install/install_functions.php +install/install_phpsettings_handler.php +install/install_phpsettings.php +install/install_welcome.php install/not_recommended.jpg install/recommended.gif install/sql/tables-db2.sql install/sql/tables-ibase.sql -install/sql/tables-mssql.sql install/sql/tables-mysql.sql install/sql/tables-oracle.sql install/sql/tables-postgres.sql @@ -186,11 +207,13 @@ install/sql/tables-sqlite.php install/sql/upgrade-db2.sql install/sql/upgrade-ibase.sql install/sql/upgrade_matrix.php -install/sql/upgrade-mssql.sql install/sql/upgrade-mysql.sql install/sql/upgrade-oracle.sql install/sql/upgrade-postgres.sql install/sql/upgrade.sql +install/sql/upgrade-sql.php +install/style.css +install/webcal_installer_sm.png js_cacher.php layers_ajax.php layers.php diff --git a/tests/functionsTest.php b/tests/functionsTest.php index 0b5389f9e..a2625de8c 100644 --- a/tests/functionsTest.php +++ b/tests/functionsTest.php @@ -3,6 +3,7 @@ use PHPUnit\Framework\TestCase; require_once __DIR__ . "/../includes/functions.php"; +require_once __DIR__ . "/../install/sql/upgrade_matrix.php"; /** * Unit tests for includes/functions.php @@ -204,5 +205,4 @@ function test_upgrade_requires_db_changes() { $this->assertTrue(upgrade_requires_db_changes('mysql', 'v1.9.5', 'v1.9.6')); $this->assertFalse(upgrade_requires_db_changes('mysql', 'v1.9.7', 'v1.9.8')); } - } diff --git a/upcoming.php b/upcoming.php index bfa1e3065..dcaf170e7 100644 --- a/upcoming.php +++ b/upcoming.php @@ -149,7 +149,7 @@ * declared twice in case of this file being included twice or more within the same doc. */ function print_upcoming_event ( $e, $date ) { - global $charset, $display_link, $display_tzid, $eventinfo, + global $categories, $charset, $display_link, $display_tzid, $eventinfo, $hcalendar_output, $link_target, $login, $SERVER_URL, $showPopups, $showTime, $UPCOMING_DISPLAY_CAT_ICONS, $username; @@ -188,16 +188,11 @@ function print_upcoming_event ( $e, $date ) { $SERVER_URL . 'view_entry.php?id=' . $e->getID() . "&date=$date&user=" . $e->getLogin() . ( empty( $link_target ) ? '>' : "\" target=\"$link_target\">" ); - if ( empty ( $UPCOMING_DISPLAY_CAT_ICONS ) || - $UPCOMING_DISPLAY_CAT_ICONS != 'N' ) { - $catNum = abs (intval($e->getCategory())); - if ( $catNum > 0 ) { - $catIcon = 'wc-icons/cat-' . $catNum . '.gif'; - if ( ! file_exists ( $catIcon ) ) - $catIcon = 'wc-icons/cat-' . $catNum . '.png'; - if ( file_exists ( $catIcon ) ) - echo $link . - 'category icon'; + if (empty($UPCOMING_DISPLAY_CAT_ICONS) || $UPCOMING_DISPLAY_CAT_ICONS != 'N') { + $catNum = abs(intval($e->getCategory())); + if ($catNum > 0 && !empty($categories[$catNum]['cat_icon_mime'])) { + $catIcon = "getIcon.php?cat_id=" . $catNum; + $link .= 'category icon'; } } echo $link; @@ -398,14 +393,14 @@ function print_upcoming_event ( $e, $date ) { $x = getGetValue ( 'showTitle', true ); if ( strlen( $x ) > 0 ) { - $showTitle = $x; + $showTitle = $x; } if ( $load_layers ) { load_user_layers ( $username ); } - //load_user_categories(); + load_user_categories(); // required to determine if cat icon exists // Calculate date range $date = getValue ( 'date', '-?[0-9]+', true );