diff --git a/application/core/FHC_Controller.php b/application/core/FHC_Controller.php index f6f138441..815c03da2 100644 --- a/application/core/FHC_Controller.php +++ b/application/core/FHC_Controller.php @@ -4,6 +4,10 @@ if (! defined('BASEPATH')) exit('No direct script access allowed'); class FHC_Controller extends CI_Controller { + const FHC_CONTROLLER_ID = 'fhc_controller_id'; // name of the parameter used to identify uniquely a call to a controller + + private $_controllerId; // contains the unique identifier of a call to a controller + /** * Standard construct for all the controllers, loads the authentication system */ @@ -11,6 +15,8 @@ class FHC_Controller extends CI_Controller { parent::__construct(); + $this->_controllerId = null; // set _controllerId as null by default + $this->load->helper('fhcauth'); } @@ -23,4 +29,34 @@ class FHC_Controller extends CI_Controller { $this->load->library('PhrasesLib', array($categories, $language), 'p'); } + + /** + * Sets the unique id for the called controller + * NOTE: it is only working with HTTP GET request, not neeaded with POST + * because the first call to the controller is via HTTP GET, + * therefore a fhc_controller_id is already generated + */ + protected function setControllerId() + { + if ($_SERVER['REQUEST_METHOD'] === 'GET') + { + $this->_controllerId = $this->input->get(self::FHC_CONTROLLER_ID); + + if (!isset($this->_controllerId) || empty($this->_controllerId)) + { + $this->_controllerId = uniqid(); // generate a unique id + // Redirect to the same URL, but giving FHC_CONTROLLER_ID as HTTP GET parameter + header(sprintf('Location: %s?%s=%s', $_SERVER['REQUEST_URI'], self::FHC_CONTROLLER_ID, $this->_controllerId)); + exit; // terminate immediately the execution of this controller + } + } + } + + /** + * Return the value of the property _controllerId + */ + protected function getControllerId() + { + return $this->_controllerId; + } } diff --git a/application/libraries/DocumentLib.php b/application/libraries/DocumentLib.php index 6def51ab5..ed87a9f38 100644 --- a/application/libraries/DocumentLib.php +++ b/application/libraries/DocumentLib.php @@ -57,6 +57,10 @@ class DocumentLib case 'application/vnd.ms-word': case 'application/vnd.oasis.opendocument.text': case 'text/plain': + // Unoconv Version 0.6 seems to fail on converting TXT Files + if ($this->unoconv_version == '0.6') + return error(); + $ret = $this->convert($filename, $outFile, 'pdf'); if(isSuccess($ret)) { @@ -64,7 +68,7 @@ class DocumentLib } else { - return $ret; + return error($ret->retval); } case 'application/pdf': return success($filename); diff --git a/application/models/organisation/Geschaeftsjahr_model.php b/application/models/organisation/Geschaeftsjahr_model.php index e806058ae..9c856f40e 100644 --- a/application/models/organisation/Geschaeftsjahr_model.php +++ b/application/models/organisation/Geschaeftsjahr_model.php @@ -21,7 +21,9 @@ class Geschaeftsjahr_model extends DB_Model $query = 'SELECT * FROM public.tbl_geschaeftsjahr WHERE start <= now() - AND ende >= now()'; + AND ende >= now() + ORDER BY start DESC + LIMIT 1'; return $this->execQuery($query); } diff --git a/application/views/templates/FHC-Header.php b/application/views/templates/FHC-Header.php index 52ed50dbd..853eb8de7 100755 --- a/application/views/templates/FHC-Header.php +++ b/application/views/templates/FHC-Header.php @@ -2,7 +2,7 @@ if (! defined('BASEPATH')) exit('No direct script access allowed'); -// Retrives the URL path of the called controller + controller method +// Retrives the URL path of the called controller + called controller method // NOTE: placed here because it doesn't work inside functions $calledPath = $this->router->directory.$this->router->class; $calledMethod = $this->router->method; @@ -15,6 +15,7 @@ $customJSs = isset($customJSs) ? $customJSs : null; // By default set the parameters to false $jquery = isset($jquery) ? $jquery : false; $jqueryui = isset($jqueryui) ? $jqueryui : false; +$ajaxlib = isset($ajaxlib) ? $ajaxlib : false; $bootstrap = isset($bootstrap) ? $bootstrap : false; $fontawesome = isset($fontawesome) ? $fontawesome : false; $tablesorter = isset($tablesorter) ? $tablesorter : false; @@ -141,12 +142,15 @@ function _generateAddonsJSsInclude($calledFrom) // jQuery UI CSS if ($jqueryui === true) _generateCSSsInclude('vendor/components/jqueryui/themes/base/jquery-ui.min.css'); - // bootstrap CSS + // Bootstrap CSS if ($bootstrap === true) _generateCSSsInclude('vendor/twbs/bootstrap/dist/css/bootstrap.min.css'); - // font awesome CSS + // Font Awesome CSS if ($fontawesome === true) _generateCSSsInclude('vendor/components/font-awesome/css/font-awesome.min.css'); + // AjaxLib CSS + if ($ajaxlib === true) _generateCSSsInclude('public/css/AjaxLib.css'); + // Table sorter CSS if ($tablesorter === true) { @@ -154,7 +158,7 @@ function _generateAddonsJSsInclude($calledFrom) _generateCSSsInclude('vendor/mottie/tablesorter/dist/css/jquery.tablesorter.pager.min.css'); } - // sb admin template CSS + // SB Admin 2 template CSS if ($sbadmintemplate === true) { _generateCSSsInclude('vendor/BlackrockDigital/startbootstrap-sb-admin-2/vendor/metisMenu/metisMenu.min.css'); @@ -164,10 +168,11 @@ function _generateAddonsJSsInclude($calledFrom) // Eventually required CSS _generateCSSsInclude($customCSSs); // Eventually required CSS + // -------------------------------------------------------------------------------------------------------- // Javascripts - // Generates the global object to pass useful parms to the other javascripts + // Generates the global object to pass useful parameters to other javascripts // NOTE: must be called before any other JS include _generateJSDataStorageObject($calledPath, $calledMethod); @@ -178,11 +183,13 @@ function _generateAddonsJSsInclude($calledFrom) if ($jqueryui === true) { _generateJSsInclude('vendor/components/jqueryui/jquery-ui.min.js'); - //datepicker german language file - _generateJSsInclude('vendor/components/jqueryui/ui/i18n/datepicker-de.js'); + _generateJSsInclude('vendor/components/jqueryui/ui/i18n/datepicker-de.js'); // datepicker german language file } - // bootstrap JS + // AjaxLib JS + if ($ajaxlib === true) _generateJSsInclude('public/js/AjaxLib.js'); + + // Bootstrap JS if ($bootstrap === true) _generateJSsInclude('vendor/twbs/bootstrap/dist/js/bootstrap.min.js'); // Table sorter JS @@ -193,10 +200,10 @@ function _generateAddonsJSsInclude($calledFrom) _generateJSsInclude('vendor/mottie/tablesorter/dist/js/extras/jquery.tablesorter.pager.min.js'); } - //tinymce JS + // Tinymce JS if($tinymce === true) _generateJSsInclude('vendor/tinymce/tinymce/tinymce.min.js') ; - // sb admin template JS + // SB Admin 2 template JS if ($sbadmintemplate === true) { _generateJSsInclude('vendor/BlackrockDigital/startbootstrap-sb-admin-2/vendor/metisMenu/metisMenu.min.js'); diff --git a/include/zeitaufzeichnung.class.php b/include/zeitaufzeichnung.class.php index 422cde18c..07c87cf50 100755 --- a/include/zeitaufzeichnung.class.php +++ b/include/zeitaufzeichnung.class.php @@ -634,24 +634,37 @@ or not exists FROM lehre.tbl_lehreinheitmitarbeiter m, lehre.tbl_lehreinheit l + JOIN + lehre.tbl_lehrveranstaltung lv using (lehrveranstaltung_id) + JOIN + public.tbl_studiengang s using (studiengang_kz) WHERE $where AND $where_sem AND l.lehreinheit_id = m.lehreinheit_id AND - m.stundensatz * m.semesterstunden > 0 + m.stundensatz * m.semesterstunden > 0 AND + s.typ not in ('l') AND + lv.studiengang_kz > 0 UNION SELECT sum(pb.stunden) AS semstunden FROM lehre.tbl_projektarbeit pa, lehre.tbl_projektbetreuer pb, - lehre.tbl_lehreinheit l, - public.tbl_benutzer b + public.tbl_benutzer b, + lehre.tbl_lehreinheit l + JOIN + lehre.tbl_lehrveranstaltung lv using (lehrveranstaltung_id) + JOIN + public.tbl_studiengang s using (studiengang_kz) + WHERE pa.lehreinheit_id = l.lehreinheit_id AND pb.projektarbeit_id = pa.projektarbeit_id AND pb.person_id = b.person_id AND b.uid = ".$this->db_add_param($user)." AND pb.stunden * pb.stundensatz > 0 AND + s.typ not in ('l') AND + lv.studiengang_kz > 0 AND $where_sem ) AS semstunden "; diff --git a/public/css/.placeholder b/public/css/.placeholder deleted file mode 100644 index e69de29bb..000000000 diff --git a/public/css/AjaxLib.css b/public/css/AjaxLib.css new file mode 100644 index 000000000..d80ab95a6 --- /dev/null +++ b/public/css/AjaxLib.css @@ -0,0 +1,14 @@ +.veil { + position: absolute; + top: 0; + left: 0; + height: 98%; + width: 99%; + background-color: white; + border-width: 1px; + border-style: solid; + border-color: black; + background-image: url("/public/imgages/loader.gif"); + background-repeat: no-repeat; + background-position: center; +} diff --git a/public/images/.placeholder b/public/images/.placeholder deleted file mode 100644 index e69de29bb..000000000 diff --git a/public/images/loader.gif b/public/images/loader.gif new file mode 100644 index 000000000..a718bd89b Binary files /dev/null and b/public/images/loader.gif differ diff --git a/public/js/AjaxLib.js b/public/js/AjaxLib.js new file mode 100644 index 000000000..2ee8d458e --- /dev/null +++ b/public/js/AjaxLib.js @@ -0,0 +1,449 @@ +/** + * FH-Complete + * + * @package + * @author + * @copyright Copyright (c) 2016 fhcomplete.org + * @license GPLv3 + * @link https://fhcomplete.org + * @since Version 1.0.0 + */ + +//-------------------------------------------------------------------------------------------------------------------- +// Configs + +// To see debug messages into the browser console set this parameter as true +const DEBUG = false; + +// Default veil timeout (milliseconds) +const VEIL_TIMEOUT = 1000; + +//-------------------------------------------------------------------------------------------------------------------- +// Constants + +// Success +const SUCCESS = 0; + +// Properties present in a response +const CODE = "error"; +const RESPONSE = "retval"; + +// HTTP method parameters +const HTTP_GET_METHOD = "GET"; +const HTTP_POST_METHOD = "POST"; + +const REMOTE_CONTROLLER = "remoteController"; + +const FHC_CONTROLLER_ID = "fhc_controller_id"; + +/** + * Definition and initialization of object FHC_Ajax_Client + */ +var FHC_Ajax_Client = { + //------------------------------------------------------------------------------------------------------------------ + // Properties + + _veilCallersCounter: 0, // count the number of callers that want to activate the veil + + //------------------------------------------------------------------------------------------------------------------ + // Public methods + + /** + * Performs a call using the HTTP GET method + * controllerParameters is an object + * ajaxCallParameters is an object + */ + ajaxCallGet: function(remoteController, controllerParameters, ajaxCallParameters) { + FHC_Ajax_Client._ajaxCall(remoteController, controllerParameters, HTTP_GET_METHOD, ajaxCallParameters); + }, + + /** + * Performs a call using the HTTP POST method + * controllerParameters is an object + * ajaxCallParameters is an object + */ + ajaxCallPost: function(remoteController, controllerParameters, ajaxCallParameters) { + FHC_Ajax_Client._ajaxCall(remoteController, controllerParameters, HTTP_POST_METHOD, ajaxCallParameters); + }, + + /** + * Checks if the response is a success + */ + isSuccess: function(response) { + var isSuccess = false; + + if (jQuery.type(response) == "object" && response.hasOwnProperty(CODE) && response.hasOwnProperty(RESPONSE)) + { + if (response.error == SUCCESS) + { + isSuccess = true; + } + } + + return isSuccess; + }, + + /** + * Checks if the response is an error + */ + isError: function(response) { + return !FHC_Ajax_Client.isSuccess(response); + }, + + /** + * Checks if the response has data + */ + hasData: function(response) { + var hasData = false; + + if (FHC_Ajax_Client.isSuccess(response)) + { + if ((jQuery.type(response.retval) == "object" && !jQuery.isEmptyObject(response.retval)) + || (jQuery.isArray(response.retval) && response.retval.length > 0) + || (jQuery.type(response.retval) == "string" && response.retval.trim() != "") + || jQuery.type(response.retval) == "number") + { + hasData = true; + } + } + + return hasData; + }, + + /** + * Retrives data from response object + */ + getData: function(response) { + var data = null; + + if (FHC_Ajax_Client.hasData(response)) + { + data = response.retval; + } + + return data; + }, + + /** + * Retrives code from response object + */ + getCode: function(response) { + var code = 1; // Generic error + + if (jQuery.type(response) == "object" && response.hasOwnProperty(CODE)) + { + if (response.error == SUCCESS) + { + isSuccess = true; + } + } + + return code; + }, + + /** + * Show a veil + */ + showVeil: function(veilTimeout) { + if (typeof veilTimeout == "number") + { + FHC_Ajax_Client._veilTimeout = veilTimeout; + } + else + { + FHC_Ajax_Client._veilTimeout = VEIL_TIMEOUT; + } + FHC_Ajax_Client._showVeil(); + }, + + /** + * Hide a veil that was shown before + */ + hideVeil: function() { + FHC_Ajax_Client._hideVeil(); + }, + + //------------------------------------------------------------------------------------------------------------------ + // Private methods + + /** + * Generate the router URI using the connection parameters + */ + _generateRouterURI: function(remoteController) { + var uri = null; + + // Checks if global JS object FHC_JS_DATA_STORAGE_OBJECT exists + if (typeof FHC_JS_DATA_STORAGE_OBJECT !== "undefined") + { + uri = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + "/" + remoteController; + } + + return uri; + }, + + /** + * Method to print debug info after a controller has been called + */ + _printDebug: function(parameters, response, errorThrown) { + + if (DEBUG === true) // If global const DEBUG is true, but really true! + { + // Print info about called controller + console.log("Called controller: " + parameters.remoteController); + console.log("Call parameters:"); // parameters given to this call + console.log(parameters); + + if (response != null) // if there is a response... + { + console.log("Controller Response:"); + console.log(response); // ...print it + } + if (errorThrown != null) // if there is a jQuery error... + { + console.log("jQuery error:"); + console.log(errorThrown); // ...print it + } + console.log("--------------------------------------------------------------------------------------------"); + } + }, + + /** + * Method to call if the ajax call has succeeded + */ + _onSuccess: function(response, textStatus, jqXHR) { + + FHC_Ajax_Client._printDebug(this._data, response); // debug time! + + // Call the success callback saved in _successCallback property + // NOTE: this is not referred to FHC_Ajax_Client but to the ajax object + this._successCallback(response); + }, + + /** + * Method to call if the ajax call has raised an error + */ + _onError: function(jqXHR, textStatus, errorThrown) { + + FHC_Ajax_Client._printDebug(this._data, null, errorThrown); // debug time! + + // Call the error callback saved in _errorCallback property + // NOTE: this is not referred to FHC_Ajax_Client but to the ajax object + this._errorCallback(jqXHR, textStatus, errorThrown); + }, + + /** + * Instantiate a new object and copy in it the properties from the parameter + */ + _cpObjProps: function(obj) { + var returnObj = {}; + + for (var prop in obj) + { + returnObj[prop] = obj[prop]; + } + + return returnObj; + }, + + /** + * Method to show the veil + */ + _showVeil: function() { + if (FHC_Ajax_Client._veilCallersCounter == 0) + { + $("
").appendTo('body'); + } + + FHC_Ajax_Client._veilCallersCounter++; + }, + + /** + * Method to hide the veil + */ + _hideVeil: function() { + window.setTimeout(function() { + if (FHC_Ajax_Client._veilCallersCounter >= 0) + { + if (FHC_Ajax_Client._veilCallersCounter > 0) + { + FHC_Ajax_Client._veilCallersCounter--; + } + + if (FHC_Ajax_Client._veilCallersCounter == 0) + { + $(".veil").remove(); + } + } + }, + this._veilTimeout); + }, + + /** + * Retrives parameters from URL query string (HTTP GET parameters) + */ + _getUrlParameter: function(sParam) { + var sPageURL = decodeURIComponent(window.location.search.substring(1)), + sURLVariables = sPageURL.split('&'), + sParameterName, + i; + + for (i = 0; i < sURLVariables.length; i++) + { + sParameterName = sURLVariables[i].split('='); + + if (sParameterName[0] === sParam) + { + return sParameterName[1]; + } + } + }, + + /** + * Checks call parameters, if they are present and are valid + * It generates and returns all the parameters needed to perform an ajax remote call + * NOTE: console.error is used here because those are not messages for the final user, + * but for the web interface developer + */ + _checkAndGenerateAjaxParams: function(remoteController, controllerParameters, type, ajaxCallParameters) { + + var valid = true; // by default they are ok (we want to trust you, please do not betray it) + + // Returned parameters + var ajaxParameters = { + cache: false, // data are never cached by the browser + dataType: "json", // always json! + type: type // set HTTP method, GET or POST + }; + + // remoteController must be a NON-empty string + if (typeof remoteController == "string" && remoteController.trim() != "") + { + // Is it possible to generate the URL + if ((url = FHC_Ajax_Client._generateRouterURI(remoteController)) != null) + { + ajaxParameters.url = url; + } + else // but it could fail + { + console.error("FHC_JS_DATA_STORAGE_OBJECT is not present"); + valid = false; + } + } + else // otherwise is NOT possible to generate the URL + { + console.error("Invalid remoteController parameter"); + valid = false; + } + + // controllerParameters must be an object + if (typeof controllerParameters == "object") + { + // Copy the properties of controllerParameters into a new object + var data = FHC_Ajax_Client._cpObjProps(controllerParameters); + // Remote controller + data[REMOTE_CONTROLLER] = remoteController; + // fhc_controller_id is given if present + data[FHC_CONTROLLER_ID] = FHC_Ajax_Client._getUrlParameter(FHC_CONTROLLER_ID); + + // Stores them into ajaxParameters + // NOTE: property data is not possible to get later, + // so the variable data is saved also in _data and it will be used later + ajaxParameters.data = data; + ajaxParameters._data = data; + } + else + { + console.error("Invalid controller parameters, must be an object"); + valid = false; + } + + + // Checks if ajaxCallParameters is an object + if (typeof ajaxCallParameters == "object") + { + // If present, errorCallback must be a function + if (ajaxCallParameters.hasOwnProperty("errorCallback")) + { + if (typeof ajaxCallParameters.errorCallback == "function") + { + ajaxParameters._errorCallback = ajaxCallParameters.errorCallback; // save as property the callback error + ajaxParameters.error = FHC_Ajax_Client._onError; // function to call if an error occurred + } + else + { + console.error("Invalid errorCallback, it must be a function"); + valid = false; + } + } + + // If present, successCallback must be a function + if (ajaxCallParameters.hasOwnProperty("successCallback")) + { + if (typeof ajaxCallParameters.successCallback == "function") + { + ajaxParameters._successCallback = ajaxCallParameters.successCallback; // save as property the callback success + ajaxParameters.success = FHC_Ajax_Client._onSuccess; // function to call if succeeded + } + else + { + console.error("Invalid successCallback, it must be a function"); + valid = false; + } + } + + // If present, veilTimeout must be a number and cannot be less then 0 or greater then 60000 + if (ajaxCallParameters.hasOwnProperty("veilTimeout") && typeof ajaxCallParameters.veilTimeout == "number") + { + if (ajaxCallParameters.veilTimeout > 0 && ajaxCallParameters.veilTimeout < 60000) + { + ajaxParameters._veilTimeout = ajaxCallParameters.veilTimeout; + ajaxParameters.beforeSend = FHC_Ajax_Client._showVeil; + ajaxParameters.complete = FHC_Ajax_Client._hideVeil; + } + else if(ajaxCallParameters.veilTimeout == 0) + { + // veil is disabled + } + else + { + console.error("Invalid veilTimeout parameter, must be a number >= 0 and <= 60000"); + valid = false; + } + } + else // is not present or the value is invalid + { + ajaxParameters._veilTimeout = VEIL_TIMEOUT; + ajaxParameters.beforeSend = FHC_Ajax_Client._showVeil; + ajaxParameters.complete = FHC_Ajax_Client._hideVeil; + } + } + + if (valid === false) + { + ajaxParameters = null; + } + + return ajaxParameters; + }, + + /** + * Performs a call to the server were the CI PHP layer is running + * - remoteController: alias of the core controller to call + * - controllerParameters: parameters to give to the called controller + * - type: POST or GET HTTP method + * - ajaxCallParameters is an object and could contains: + * - errorCallback: function to call after an error has been raised + * - successCallback: function to call after succeeded + * - veilTimeout: veil timeout + */ + _ajaxCall: function(remoteController, controllerParameters, type, ajaxCallParameters) { + // Retrives the parameters for the ajax call + var ajaxParameters = FHC_Ajax_Client._checkAndGenerateAjaxParams(remoteController, controllerParameters, type, ajaxCallParameters); + + // Checks the given parameters if they are present and are valid + if (ajaxParameters != null) + { + $.ajax(ajaxParameters); // ajax call + } + } +}; diff --git a/public/js/bootstrapper.js b/public/js/bootstrapper.js index 8697e17ad..290749c11 100644 --- a/public/js/bootstrapper.js +++ b/public/js/bootstrapper.js @@ -1,10 +1,8 @@ -/* -file for adding bootstrap classes, e.g. in case usage of non-bootstrap widgets in a bootstrap page -AVOID USING THIS IF POSSIBLE +/** + * To add bootstrap classes, e.g. in case usage of non-bootstrap widgets in a bootstrap page + * NOTE: avoid using this if possible */ -$(document).ready( - function() - { +$(document).ready(function() { $("input[type=text], select").addClass("form-control"); $("button, input[type=button]").addClass("btn btn-default"); $("table").addClass("table-condensed");