diff --git a/TimeTracking/TimeTracking.php b/TimeTracking/TimeTracking.php
index 9d1df69..f38feb0 100644
--- a/TimeTracking/TimeTracking.php
+++ b/TimeTracking/TimeTracking.php
@@ -20,239 +20,268 @@
*/
class TimeTrackingPlugin extends MantisPlugin {
- function register() {
- plugin_require_api( 'core/constants.php' );
-
- $this->name = plugin_lang_get( 'plugin_title' );
- $this->description = plugin_lang_get( 'plugin_description' );
- $this->page = 'config_page';
-
- $this->version = '3.0-dev';
- $this->requires = array(
- 'MantisCore' => '2.0.0'
- );
-
- $this->author = 'Elmar Schumacher, Michael Baker, Erwann Penet';
- $this->contact = '';
- $this->url = 'https://github.com/mantisbt-plugins/timetracking';
- }
-
- function hooks() {
- return array(
- 'EVENT_LAYOUT_RESOURCES' => 'resources',
- 'EVENT_VIEW_BUG_EXTRA' => 'ev_view_bug',
- 'EVENT_MENU_ISSUE' => 'timerecord_menu',
- 'EVENT_MENU_MAIN' => 'showreport_menu',
- 'EVENT_VIEW_BUGNOTE' => 'ev_view_bugnote',
- 'EVENT_BUGNOTE_ADD_FORM' => 'ev_bugnote_add_form',
- 'EVENT_BUGNOTE_DATA' => 'ev_bugnote_add_validate',
- 'EVENT_BUGNOTE_ADD' => 'ev_bugnote_added',
- 'EVENT_VIEW_BUG_DETAILS' => 'ev_view_bug_details',
- 'EVENT_LAYOUT_CONTENT_BEGIN' => 'ev_layout_content_begin',
- 'EVENT_FILTER_COLUMNS' => 'ev_register_columns',
- );
- }
-
- function config() {
- return array(
- # old thresholds
- /*
- 'admin_own_threshold' => DEVELOPER,
- 'view_others_threshold' => MANAGER,
- 'admin_threshold' => ADMINISTRATOR,
- */
- # new thresholds
- 'view_threshold' => DEVELOPER,
- 'edit_threshold' => DEVELOPER,
- 'reporting_threshold' => MANAGER,
-
- 'stopwatch_enabled' => ON,
-
- 'categories' => ''
- );
- }
-
- function init() {
- plugin_require_api( 'core/timetracking_api.php' );
- plugin_require_api( 'core/stopwatch_api.php' );
- plugin_require_api( 'core/columns.php' );
- plugin_require_api( 'core/reports.php' );
- }
-
- function errors() {
- return array(
- TimeTracking\ERROR_INVALID_TIME_FORMAT => plugin_lang_get( 'ERROR_INVALID_TIME_FORMAT' ),
- TimeTracking\ERROR_ID_NOT_EXISTS => plugin_lang_get( 'ERROR_ID_NOT_EXISTS' ),
- );
- }
-
- function resources() {
- $res = '';
- $res .= '';
- $res .= '';
- if( \TimeTracking\stopwatch_enabled() ) {
- $res .= '';
- }
- return $res;
- }
-
- function ev_register_columns( $p_event ) {
- return array(
- new TimeTracking\ColumnTotalTime(),
- new TimeTracking\ColumnMyTime(),
- );
- }
-
- /**
- * Show time tracking info within the bugnote activity area
- */
- function ev_view_bugnote( $p_event, $p_bug_id, $p_note_id, $p_is_private ) {
- $t_record = TimeTracking\get_record_for_bugnote( $p_note_id );
- if( !$t_record ) {
- return;
- }
- if( TimeTracking\user_can_view_record_id( $t_record['id'] ) ) {
- TimeTracking\print_bugnote_label_row( $t_record, $p_is_private );
- }
- }
-
- /**
- * Prints the time tracking inputs within the bugnote-add form
- * @param type $p_event
- * @param type $p_bug_id
- */
- function ev_bugnote_add_form( $p_event, $p_bug_id ) {
- if( TimeTracking\user_can_edit_bug_id( $p_bug_id ) ) {
- TimeTracking\print_bugnote_add_form( $p_bug_id );
- }
- }
-
- /**
- * Validates time tracking submitted data when adding bugnotes
- */
- function ev_bugnote_add_validate( $p_event, $p_bugnote_text, $p_bug_id ) {
- $t_time_imput = gpc_get_string( 'plugin_timetracking_time_input', '' );
- if( !is_blank( $t_time_imput ) ) {
- if( TimeTracking\user_can_edit_bug_id( $p_bug_id ) ) {
- $t_parsed = TimeTracking\parse_gpc_time_record();
- }
- }
- return $p_bugnote_text;
- }
-
- /**
- * Creates a time tracking record from submitted data when adding bugnotes
- */
- function ev_bugnote_added( $p_event, $p_bug_id, $p_bugnote_id ) {
- $t_time_imput = gpc_get_string( 'plugin_timetracking_time_input', '' );
- if( !is_blank( $t_time_imput ) ) {
- if( TimeTracking\user_can_edit_bug_id( $p_bug_id ) ) {
- $t_record = TimeTracking\parse_gpc_time_record();
- $t_record['bugnote_id'] = $p_bugnote_id;
- $t_record['bug_id'] = $p_bug_id;
- TimeTracking\create_record( $t_record );
- }
- }
- }
-
- function ev_view_bug_details( $p_event, $p_bug_id ) {
- if( TimeTracking\user_can_view_bug_id( $p_bug_id ) ) {
- $t_records = TimeTracking\get_records_for_bug( $p_bug_id );
- if( $t_records ) {
- TimeTracking\print_bug_details_row( $p_bug_id );
- }
- }
- }
-
- function ev_layout_content_begin( $p_event ) {
- if( TimeTracking\stopwatch_enabled() && TimeTracking\stopwatch_exists() ) {
- TimeTracking\print_stopwatch_header_control();
- }
- }
-
- function ev_view_bug( $p_event, $p_bug_id ) {
- if( TimeTracking\user_can_view_bug_id( $p_bug_id ) ) {
- TimeTracking\print_bug_timetracking_section( $p_bug_id );
- }
- }
-
- function schema() {
- $schema[0] =
- array( 'CreateTableSQL', array( plugin_table( 'data' ), "
- id I NOTNULL UNSIGNED AUTOINCREMENT PRIMARY,
- bug_id I DEFAULT NULL UNSIGNED,
- user I DEFAULT NULL UNSIGNED,
- expenditure_date T DEFAULT NULL,
- hours F(15,3) DEFAULT NULL,
- timestamp T DEFAULT NULL,
- category C(255) DEFAULT NULL,
- info C(255) DEFAULT NULL
- " )
- );
-
- $schema[1] =
- array(
- 'AddColumnSQL',
- array( plugin_table( 'data' ),
- " user_id I UNSIGNED,
- date_created I UNSIGNED NOTNULL DEFAULT '1',
- time_count I UNSIGNED NOTNULL DEFAULT '0',
- time_exp_date I UNSIGNED NOTNULL DEFAULT '1',
- bugnote_id I UNSIGNED"
- )
- );
-
- $schema[2] = array( 'UpdateFunction', 'date_migrate', array( plugin_table( 'data' ), 'id', 'expenditure_date', 'time_exp_date' ) );
- $schema[3] = array( 'UpdateFunction', 'date_migrate', array( plugin_table( 'data' ), 'id', 'timestamp', 'date_created' ) );
- $schema[4] = array( 'UpdateFunction', 'timetracking_update_hours', array() );
- $schema[5] = array( 'UpdateFunction', 'timetracking_update_user_id', array() );
-
- $schema[6] = array( 'DropColumnSQL', array( plugin_table( 'data' ), 'user' ) );
- $schema[7] = array( 'DropColumnSQL', array( plugin_table( 'data' ), 'expenditure_date' ) );
- $schema[8] = array( 'DropColumnSQL', array( plugin_table( 'data' ), 'timestamp' ) );
- $schema[9] = array( 'DropColumnSQL', array( plugin_table( 'data' ), 'hours' ) );
-
- return $schema;
- }
-
- function timerecord_menu( $p_event, $p_bug_id ) {
- if( TimeTracking\user_can_view_bug_id( $p_bug_id ) ) {
- $t_href = '#timerecord';
- return array( plugin_lang_get( 'timerecord_menu' ) => $t_href );
- }
- else {
- return array ();
- }
- }
-
- function showreport_menu() {
- return array(
- array(
- 'title' => plugin_lang_get( 'title' ),
- 'access_level' => plugin_config_get( 'reporting_threshold' ),
- 'url' => plugin_page( 'report_page' ),
- 'icon' => 'fa-random'
- )
- );
- }
+ function register() {
+ plugin_require_api( 'core/constants.php' );
+
+ $this->name = plugin_lang_get( 'plugin_title' );
+ $this->description = plugin_lang_get( 'plugin_description' );
+ $this->page = 'config_page';
+
+ $this->version = '3.0-dev-03-2018';
+ $this->requires = array(
+ 'MantisCore' => '2.0.0'
+ );
+
+ $this->author = 'Elmar Schumacher, Michael Baker, Erwann Penet';
+ $this->contact = '';
+ $this->url = 'https://github.com/mantisbt-plugins/timetracking';
+ }
+
+ function hooks() {
+ return array(
+ 'EVENT_LAYOUT_RESOURCES' => 'resources',
+ 'EVENT_VIEW_BUG_EXTRA' => 'ev_view_bug',
+ 'EVENT_MENU_ISSUE' => 'timerecord_menu',
+ 'EVENT_MENU_MAIN' => 'showreport_menu',
+ 'EVENT_VIEW_BUGNOTE' => 'ev_view_bugnote',
+ 'EVENT_BUGNOTE_ADD_FORM' => 'ev_bugnote_add_form',
+ 'EVENT_BUGNOTE_DATA' => 'ev_bugnote_add_validate',
+ 'EVENT_BUGNOTE_ADD' => 'ev_bugnote_added',
+ 'EVENT_VIEW_BUG_DETAILS' => 'ev_view_bug_details',
+ 'EVENT_LAYOUT_CONTENT_BEGIN' => 'ev_layout_content_begin',
+ 'EVENT_FILTER_COLUMNS' => 'ev_register_columns',
+ );
+ }
+
+ /**
+ *
+ */
+ function config() {
+ return self::getConfig();
+ }
+
+ /**
+ *
+ */
+ function init() {
+ plugin_require_api( 'core/timetracking_api.php' );
+ plugin_require_api( 'core/stopwatch_api.php' );
+ plugin_require_api( 'core/columns.php' );
+ plugin_require_api( 'core/reports.php' );
+ }
+
+ /**
+ *
+ */
+ function errors() {
+ return array(
+ TimeTracking\ERROR_INVALID_TIME_FORMAT => plugin_lang_get( 'ERROR_INVALID_TIME_FORMAT' ),
+ TimeTracking\ERROR_ID_NOT_EXISTS => plugin_lang_get( 'ERROR_ID_NOT_EXISTS' ),
+ );
+ }
+
+ /**
+ *
+ */
+ function resources() {
+ $res = '';
+ $res .= '';
+ $res .= '';
+ if( \TimeTracking\stopwatch_enabled() ) {
+ $res .= '';
+ }
+ return $res;
+ }
+
+ /**
+ *
+ */
+ function ev_register_columns( $p_event ) {
+ return array(
+ new TimeTracking\ColumnTotalTime(),
+ new TimeTracking\ColumnMyTime(),
+ );
+ }
+
+ /**
+ * Show time tracking info within the bugnote activity area
+ */
+ function ev_view_bugnote( $p_event, $p_bug_id, $p_note_id, $p_is_private ) {
+ $t_record = TimeTracking\get_record_for_bugnote( $p_note_id );
+ if( !$t_record ) {
+ return;
+ }
+ if( TimeTracking\user_can_view_record_id( $t_record['id'] ) ) {
+ TimeTracking\print_bugnote_label_row( $t_record, $p_is_private );
+ }
+ }
+
+ /**
+ * Prints the time tracking inputs within the bugnote-add form
+ * @param type $p_event
+ * @param type $p_bug_id
+ */
+ function ev_bugnote_add_form( $p_event, $p_bug_id ) {
+
+ $t_project_id = bug_get_field( $p_bug_id, 'project_id' );
+ $t_enabled_on_bugnote_add_form = plugin_config_get('enabled_on_bugnote_add_form',false,false,null,$t_project_id);
+ if( $t_enabled_on_bugnote_add_form ) {
+ if( TimeTracking\user_can_edit_bug_id( $p_bug_id ) ) {
+ TimeTracking\print_bugnote_add_form( $p_bug_id );
+ }
+ }
+ }
+
+ /**
+ * Validates time tracking submitted data when adding bugnotes
+ */
+ function ev_bugnote_add_validate( $p_event, $p_bugnote_text, $p_bug_id ) {
+ $t_time_imput = gpc_get_string( 'plugin_timetracking_time_input', '' );
+ if( !is_blank( $t_time_imput ) ) {
+ if( TimeTracking\user_can_edit_bug_id( $p_bug_id ) ) {
+ $t_parsed = TimeTracking\parse_gpc_time_record();
+ }
+ }
+ return $p_bugnote_text;
+ }
+
+ /**
+ * Creates a time tracking record from submitted data when adding bugnotes
+ */
+ function ev_bugnote_added( $p_event, $p_bug_id, $p_bugnote_id ) {
+ $t_time_imput = gpc_get_string( 'plugin_timetracking_time_input', '' );
+ if( !is_blank( $t_time_imput ) ) {
+ if( TimeTracking\user_can_edit_bug_id( $p_bug_id ) ) {
+ $t_record = TimeTracking\parse_gpc_time_record();
+ $t_record['bugnote_id'] = $p_bugnote_id;
+ $t_record['bug_id'] = $p_bug_id;
+ TimeTracking\create_record( $t_record );
+ }
+ }
+ }
+
+ function ev_view_bug_details( $p_event, $p_bug_id ) {
+ if( TimeTracking\user_can_view_bug_id( $p_bug_id ) ) {
+ $t_records = TimeTracking\get_records_for_bug( $p_bug_id );
+ if( $t_records ) {
+ TimeTracking\print_bug_details_row( $p_bug_id );
+ }
+ }
+ }
+
+ function ev_layout_content_begin( $p_event ) {
+ if( TimeTracking\stopwatch_enabled() && TimeTracking\stopwatch_exists() ) {
+ TimeTracking\print_stopwatch_header_control();
+ }
+ }
+
+ function ev_view_bug( $p_event, $p_bug_id ) {
+ if( TimeTracking\user_can_view_bug_id( $p_bug_id ) ) {
+ TimeTracking\print_bug_timetracking_section( $p_bug_id );
+ }
+ }
+
+ /**
+ *
+ */
+ static function getConfig() {
+ return array(
+ # old thresholds
+ /*
+ 'admin_own_threshold' => DEVELOPER,
+ 'view_others_threshold' => MANAGER,
+ 'admin_threshold' => ADMINISTRATOR,
+ */
+ # new thresholds
+ 'view_threshold' => DEVELOPER,
+ 'edit_threshold' => DEVELOPER,
+ 'reporting_threshold' => MANAGER,
+
+ 'stopwatch_enabled' => ON,
+
+ 'categories' => '',
+ 'on_bugnote_enabled' => ON
+ );
+
+ }
+
+ function schema() {
+ $schema[0] =
+ array( 'CreateTableSQL', array( plugin_table( 'data' ), "
+ id I NOTNULL UNSIGNED AUTOINCREMENT PRIMARY,
+ bug_id I DEFAULT NULL UNSIGNED,
+ user I DEFAULT NULL UNSIGNED,
+ expenditure_date T DEFAULT NULL,
+ hours F(15,3) DEFAULT NULL,
+ timestamp T DEFAULT NULL,
+ category C(255) DEFAULT NULL,
+ info C(255) DEFAULT NULL
+ " )
+ );
+
+ $schema[1] =
+ array(
+ 'AddColumnSQL',
+ array( plugin_table( 'data' ),
+ " user_id I UNSIGNED,
+ date_created I UNSIGNED NOTNULL DEFAULT '1',
+ time_count I UNSIGNED NOTNULL DEFAULT '0',
+ time_exp_date I UNSIGNED NOTNULL DEFAULT '1',
+ bugnote_id I UNSIGNED"
+ )
+ );
+
+ $schema[2] = array( 'UpdateFunction', 'date_migrate', array( plugin_table( 'data' ), 'id', 'expenditure_date', 'time_exp_date' ) );
+ $schema[3] = array( 'UpdateFunction', 'date_migrate', array( plugin_table( 'data' ), 'id', 'timestamp', 'date_created' ) );
+ $schema[4] = array( 'UpdateFunction', 'timetracking_update_hours', array() );
+ $schema[5] = array( 'UpdateFunction', 'timetracking_update_user_id', array() );
+
+ $schema[6] = array( 'DropColumnSQL', array( plugin_table( 'data' ), 'user' ) );
+ $schema[7] = array( 'DropColumnSQL', array( plugin_table( 'data' ), 'expenditure_date' ) );
+ $schema[8] = array( 'DropColumnSQL', array( plugin_table( 'data' ), 'timestamp' ) );
+ $schema[9] = array( 'DropColumnSQL', array( plugin_table( 'data' ), 'hours' ) );
+
+ return $schema;
+ }
+
+ function timerecord_menu( $p_event, $p_bug_id ) {
+ if( TimeTracking\user_can_view_bug_id( $p_bug_id ) ) {
+ $t_href = '#timerecord';
+ return array( plugin_lang_get( 'timerecord_menu' ) => $t_href );
+ }
+ else {
+ return array ();
+ }
+ }
+
+ function showreport_menu() {
+ return array(
+ array(
+ 'title' => plugin_lang_get( 'title' ),
+ 'access_level' => plugin_config_get( 'reporting_threshold' ),
+ 'url' => plugin_page( 'report_page' ),
+ 'icon' => 'fa-random'
+ )
+ );
+ }
} # class end
function install_timetracking_update_hours() {
- $t_query = 'UPDATE ' . plugin_table( 'data' ) . ' SET time_count = hours*3600'
- . ' WHERE time_count = 0';
- db_query( $t_query );
+ $t_query = 'UPDATE ' . plugin_table( 'data' ) . ' SET time_count = hours*3600'
+ . ' WHERE time_count = 0';
+ db_query( $t_query );
- # Return 2 because that's what ADOdb/DataDict does when things happen properly
- return 2;
+ # Return 2 because that's what ADOdb/DataDict does when things happen properly
+ return 2;
}
function install_timetracking_update_user_id() {
- $t_query = 'UPDATE ' . plugin_table( 'data' ) . ' SET user_id = user'
- . ' WHERE user_id IS NULL';
- db_query( $t_query );
+ $t_query = 'UPDATE ' . plugin_table( 'data' ) . ' SET user_id = user'
+ . ' WHERE user_id IS NULL';
+ db_query( $t_query );
- # Return 2 because that's what ADOdb/DataDict does when things happen properly
- return 2;
+ # Return 2 because that's what ADOdb/DataDict does when things happen properly
+ return 2;
}
diff --git a/TimeTracking/core/reports.php b/TimeTracking/core/reports.php
index 14910d7..de8b942 100644
--- a/TimeTracking/core/reports.php
+++ b/TimeTracking/core/reports.php
@@ -5,647 +5,752 @@
* Class that encapsulates logic and presentation for report generation
*/
class Report {
- # these static fields are global definitions for this object and inherited
-
- /**
- * Array of possible column keys
- * @var array
- */
- static $column_keys = array(
- 'user', 'issue', 'project', 'time_category',
- );
-
- /**
- * Default keys to use
- * @var array
- */
- static $default_keys = array(
- 'user', 'time_category',
- );
-
- /**
- * db fields to use in sql query, for each key
- * using alias:
- * 'TT' as plugin data table
- * @var array
- */
- static $column_db_fileds = array(
- 'user' => '{user}.id',
- 'issue' => 'TT.bug_id',
- 'project' => '{project}.id',
- 'time_category' => 'TT.category',
- 'exp_date' => 'TT.time_exp_date',
- 'date_created' => 'TT.date_created',
- );
-
- /**
- * db fields to sort on, for each key
- * @var array
- */
- static $column_db_sort_fileds = array(
- 'user' => '{user}.username',
- 'issue' => 'TT.bug_id',
- 'project' => '{project}.name',
- 'time_category' => 'TT.category',
- 'exp_date' => 'TT.time_exp_date',
- 'date_created' => 'TT.date_created',
- );
-
- /**
- * Current selection of keys for this object
- * @var array
- */
- public $selected_keys = array();
-
- /**
- * pagination: rows per page
- * @var integer
- */
- public $rows_per_page = 100;
-
- /**
- * pagination, current page
- * @var integer
- */
- public $page = 1; /* starts at 1 */
-
- /**
- * Filter array, to filter current bug selection
- * @var array
- */
- public $bug_filter = null;
-
- # current values for timetracking filtering
- # if any is null, it won't be applied
- public $time_filter_from, $time_filter_to; # as integer timestamps
- public $time_filter_user_id = null;
- public $time_filter_category = null;
-
- /**
- * After the query is executed, total number of rows will be sotred here
- * Note: for consistency, use get_rows_count()
- * @var integer
- */
- protected $all_rows_count;
-
- /**
- * After the query is executed, the raw result will be stored here
- * Note: for consistency, use get_result()
- * @var iterator
- */
- protected $result;
-
- /**
- * Constructor. Initialize defaults
- */
- public function __construct() {
- $this->selected_keys = static::$default_keys;
- }
-
- /**
- * Build a sql select based on the configured filter.
- * This query is suitable to be used as IN clause
- * Note: this mthod will call db_param_push()
- * @param array $p_params db_params array (output)
- * @return string SQL query for subselect
- */
- protected function build_filter_subselect( array &$p_params ) {
- # prepare filter subselect
- if( !$this->bug_filter ) {
- $t_filter = array();
- $t_filter[FILTER_PROPERTY_HIDE_STATUS] = array( META_FILTER_NONE );
- $t_filter = filter_ensure_valid_filter( $t_filter );
- $this->bug_filter = $t_filter;
- }
- # Note: filter_get_bug_rows_query_clauses() calls db_param_push();
- $t_query_clauses = filter_get_bug_rows_query_clauses( $this->bug_filter, null, null, null );
- # if the query can't be formed, there are no results
- if( empty( $t_query_clauses ) ) {
- # reset the db_param stack that was initialized by "filter_get_bug_rows_query_clauses()"
- db_param_pop();
- return db_empty_result();
- }
- $t_select_string = 'SELECT {bug}.id ';
- $t_from_string = ' FROM ' . implode( ', ', $t_query_clauses['from'] );
- $t_join_string = count( $t_query_clauses['join'] ) > 0 ? implode( ' ', $t_query_clauses['join'] ) : ' ';
- $t_where_string = ' WHERE '. implode( ' AND ', $t_query_clauses['project_where'] );
- if( count( $t_query_clauses['where'] ) > 0 ) {
- $t_where_string .= ' AND ( ';
- $t_where_string .= implode( $t_query_clauses['operator'], $t_query_clauses['where'] );
- $t_where_string .= ' ) ';
- }
- $t_query = $t_select_string . $t_from_string . $t_join_string . $t_where_string;
- $p_params = $t_query_clauses['where_values'];
- return $t_query;
- }
-
- /**
- * Get the row count of the report result.
- * If the query has not been executed yet, calls to build an execute it-
- * @return type
- */
- public function get_rows_count() {
- if( !$this->result ) {
- $this->fetch_result();
- }
- return $this->all_rows_count;
- }
-
- /**
- * Get the query result
- * If the query has not been executed yet, calls to build an execute it-
- * @return iterator
- */
- public function get_result() {
- if( !$this->result ) {
- $this->fetch_result();
- }
- return $this->result;
- }
-
- /**
- * Builds the query, execute it and stores the result
- */
- protected function fetch_result() {
- $t_select_columns = array();
- $t_group_columns = array();
- $t_order_columns = array();
- foreach( $this->selected_keys as $key ) {
- $t_select_columns[] = static::$column_db_fileds[$key] . ' AS ' . $key;
- $t_group_columns[] = static::$column_db_fileds[$key];
- $t_order_columns[] = static::$column_db_sort_fileds[$key];
- }
-
- $t_where= array();
- $t_params = array();
-
- # bug filter
- $t_where[] = 'TT.bug_id IN ( ' . $this->build_filter_subselect( $t_params ) . ' )';
-
- # timetracking date
- if( $this->time_filter_from ) {
- $t_where[] = 'TT.time_exp_date >= ' . db_param();
- $t_params[] = (int)$this->time_filter_from;
- }
- if( $this->time_filter_to ) {
- $t_where[] = 'TT.time_exp_date < ' . db_param();
- $t_params[] = (int)$this->time_filter_to;
- }
-
- # timetracking user
- if( $this->time_filter_user_id ) {
- $t_where[] = 'TT.user_id = ' . db_param();
- $t_params[] = (int)$this->time_filter_user_id;
- }
-
- # timetracking category
- if( $this->time_filter_category ) {
- $t_where[] = 'TT.category = ' . db_param();
- $t_params[] = $this->time_filter_category;
- }
-
- # main query
- $t_cols_select = implode( ', ', $t_select_columns );
- if( !empty( $t_select_columns ) ) {
- $t_cols_select .= ', ';
- }
- $t_cols_group = implode( ', ', $t_group_columns );
- $t_cols_order = implode( ', ', $t_order_columns );
- $t_query = 'SELECT ' . $t_cols_select . 'SUM( TT.time_count ) AS time_count'
- . ' FROM {bug} JOIN ' . plugin_table( 'data' ) . ' TT ON {bug}.id = TT.bug_id'
- . ' JOIN {user} ON TT.user_id = {user}.id'
- . ' JOIN {project} ON {bug}.project_id = {project}.id'
- . ' WHERE ' . implode( ' AND ', $t_where );
- if( !empty( $t_select_columns ) ) {
- $t_query .= ' GROUP BY ' . $t_cols_group . ' ORDER BY ' . $t_cols_order;
- }
-
- $t_query_count = 'SELECT count(*) FROM ( ' . $t_query . ' ) C';
-
- # keeps db_params in the stack, for the next db_query
- $this->all_rows_count = db_result( db_query( $t_query_count, $t_params, -1, -1, false ) );
-
- # update current page if it is outside range
- $t_max_page = 1 + (int)floor( $this->all_rows_count / $this->rows_per_page );
- if( $this->page > $t_max_page ) {
- $this->page = $t_max_page;
- }
-
- $this->result = db_query( $t_query, $t_params, $this->rows_per_page, $this->rows_per_page * ( $this->page - 1 ) );
- }
-
- /**
- * Process a result array and cache relevant data in core apis
- * @param array $p_result_array The query result in array form
- */
- protected function cache_resut_array( array $p_result_array ) {
- foreach( $this->selected_keys as $t_key ) {
- switch( $t_key ) {
- case 'user':
- user_cache_array_rows( array_column( $p_result_array, $t_key ) );
- break;
- case 'project':
- project_cache_array_rows( array_column( $p_result_array, $t_key ) );
- break;
- case 'issue':
- bug_cache_array_rows( array_column( $p_result_array, $t_key ) );
- }
- }
- }
-
- /**
- * Formats each column key for proper presentation
- * @param string $p_key Column key
- * @param mixed $p_value Value to format
- * @return mixed Formatted value
- */
- public static function format_value( $p_key, $p_value ) {
- switch( $p_key ) {
- case 'user':
- $t_value = string_display_line( user_get_name( $p_value ) );
- break;
- case 'project':
- $t_value = string_display_line( project_get_name( $p_value ) );
- break;
- case 'issue':
- $t_value = string_get_bug_view_link( $p_value ) . ':' . lang_get( 'word_separator' ) . string_shorten( bug_get_field( $p_value, 'summary' ), 80 );
- break;
- case 'exp_date':
- $t_value = string_display_line( date( config_get( 'short_date_format' ), $p_value ) );
- break;
- case 'date_created':
- $t_value = string_display_line( date( config_get( 'normal_date_format' ), $p_value ) );
- break;
- default;
- $t_value = string_display_line( $p_value );
- }
- return $t_value;
- }
-
- /**
- * Outputs the query result into an htm table
- */
- public function print_table() {
- $t_result = $this->get_result();
- $t_result_array = array();
- while( $t_row = db_fetch_array( $t_result ) ) {
- $t_result_array[] = $t_row;
- }
- $this->cache_resut_array( $t_result_array );
-
- echo '
';
- echo '';
- echo '';
- foreach( $this->selected_keys as $t_col_name ) {
- echo '| ', plugin_lang_get( $t_col_name ) , ' | ';
- }
- echo '', plugin_lang_get( 'time_count' ) , ' | ';
- echo '
';
- echo '';
- echo '';
- foreach( $t_result_array as $t_row ) {
- echo '';
- foreach( $t_row as $t_key => $t_value ) {
- echo '| ';
- if( 'time_count' == $t_key ) {
- echo seconds_to_hours( $t_value );
- echo ' | ';
- echo '';
- echo seconds_to_hms( $t_value );
- } else {
- echo static::format_value( $t_key, $t_value );
- }
- echo ' | ';
- }
- echo '
';
- }
- echo '';
- echo '
';
- }
-
- /**
- * Prints the pagination controls for current report
- * @return string Html for pagination div
- */
- public function print_report_pagination() {
- $t_count = $this->get_rows_count();
- $t_pages = 1 + (int)floor( $t_count / $this->rows_per_page );
- if( $t_pages == 1 ) {
- return;
- }
-
- $t_url_page = url_self();
- $t_url_params = $this->get_current_params() + $_GET;
-
- $t_lang_first = lang_get( 'first' );
- $t_lang_last = lang_get( 'last' );
- $t_lang_prev = lang_get( 'prev' );
- $t_lang_next = lang_get( 'next' );
- $t_show_pages = 10;
- $t_show_from = max( 1, floor( $this->page - $t_show_pages / 2 ) );
- $t_show_to = min( $t_pages, 1+ floor( $this->page + $t_show_pages / 2 ) );
- echo '';
- echo '';
- echo '
';
- }
-
- /**
- * Reads GET and POST parameters to update the status of current filter and properties
- */
- public function read_gpc_params() {
- $f_page = gpc_get_int( 'ttreport_page', 1 );
- $this->page = $f_page;
-
- $f_groupby = gpc_get_string_array( 'ttreport_groupby', array() );
- # if empty, no value were submitted, then use defaults
- if( empty( $f_groupby ) ) {
- $this->selected_keys = static::$default_keys;
- } else {
- $c_groupby = array();
- foreach( $f_groupby as $t_key ) {
- if( in_array( $t_key, static::$column_keys ) ) {
- $c_groupby[] = $t_key;
- }
- }
- # here the group fields may be empty, but this was submitted intentionally
- $this->selected_keys = $c_groupby;
- }
-
- # Read filter parameters
- $f_reset = gpc_isset( 'reset_filter_button' );
- if( $f_reset ) {
- $this->time_filter_from = null;
- $this->time_filter_to = null;
- $this->time_filter_category = null;
- $this->time_filter_user_id = null;
- } else {
- # dates as d/m/Y
- $f_date_from_d = gpc_get_int( 'ttreport_date_from_d', 0 );
- $f_date_from_m = gpc_get_int( 'ttreport_date_from_m', 0 );
- $f_date_from_y = gpc_get_int( 'ttreport_date_from_y', 0 );
- $f_date_to_d = gpc_get_int( 'ttreport_date_to_d', 0 );
- $f_date_to_m = gpc_get_int( 'ttreport_date_to_m', 0 );
- $f_date_to_y = gpc_get_int( 'ttreport_date_to_y', 0 );
- if( $f_date_from_d && $f_date_from_m && $f_date_from_y ) {
- $this->time_filter_from = parse_date_parts( $f_date_from_y, $f_date_from_m, $f_date_from_d );
- }
- if( $f_date_to_d && $f_date_to_m && $f_date_to_y ) {
- $this->time_filter_to = parse_date_parts( $f_date_to_y, $f_date_to_m, $f_date_to_d );
- }
-
- # dates as timestamp
- $f_timestamp_from = gpc_get_int( 'ttreport_date_from', 0 );
- if( $f_timestamp_from > 0 ) {
- $this->time_filter_from = $f_timestamp_from;
- }
- $f_timestamp_to = gpc_get_int( 'ttreport_date_to', 0 );
- if( $f_timestamp_to > 0 ) {
- $this->time_filter_to = $f_timestamp_to;
- }
-
- # timetracking category
- $f_category = gpc_get_string( 'ttreport_category', '' );
- if( !empty( $f_category ) ) {
- $this->time_filter_category = string_html_entities( $f_category );
- }
-
- #timetracking user
- $f_user_id = gpc_get_int( 'ttreport_user_id', 0 );
- if( $f_user_id > 0 ) {
- $this->time_filter_user_id = $f_user_id;
- }
- }
- }
-
- /**
- * Returns an array of key/value pairs representign the state of current filter and properties,
- * suitable to build a query url
- * @return type
- */
- public function get_current_params() {
- $t_params = array();
- $t_params['ttreport_page'] = $this->page;
- $t_params['ttreport_groupby'] = $this->selected_keys;
- if( $this->time_filter_user_id ) {
- $t_params['ttreport_user_id'] = $this->time_filter_user_id;
- }
- if( $this->time_filter_category ) {
- $t_params['ttreport_category'] = $this->time_filter_category;
- }
- if( $this->time_filter_from ) {
- $t_params['ttreport_date_from'] = $this->time_filter_from;
- }
- if( $this->time_filter_to ) {
- $t_params['ttreport_date_to'] = $this->time_filter_to;
- }
- return $t_params;
- }
-
- /**
- * Prints html for current filter properties.
- * It will print the inputs and supporting html, but not the main form tags
- */
- function print_inputs_time_filter() {
- if( $this->time_filter_from ) {
- $t_date_enabled = true;
- $t_date_from = new \DateTime();
- $t_date_from->settimestamp( $this->time_filter_from );
- } else {
- $t_date_enabled = false;
- $t_date_from = new \DateTime( 'yesterday' );
- }
- if( $this->time_filter_to ) {
- $t_date_to = new \DateTime();
- $t_date_to->settimestamp( $this->time_filter_to );
- } else {
- $t_date_to = new \DateTime( 'today' );
- }
- $t_category_enabled = isset( $this->time_filter_category );
- $t_user_enabled = isset( $this->time_filter_user_id );
- ?>
-
- ';
- echo '' . plugin_lang_get( 'group_by' ) . ':';
- echo '';
- # set a dummy group field to allow for empty group, and avoid applying deafults.
- echo '';
- $t_elements = array();
- $t_par_index = 1;
- foreach( $this->selected_keys as $t_key ) {
- $t_el = '';
- $t_el .= '';
- $t_el .= '';
- $t_el .= plugin_lang_get( $t_key );
- $t_el .= '';
- $t_el .= '';
- $t_el .= '';
- $t_elements[] = $t_el;
- }
- $t_unused_keys = array_diff( static::$column_keys, $this->selected_keys );
- if( !empty( $t_unused_keys ) ) {
- $t_input = '';
- $t_input .= '';
- $t_input .= '';
- $t_elements[] = $t_input;
- }
- echo implode ( '', $t_elements );
- echo '';
- echo '';
- }
+ # these static fields are global definitions for this object and inherited
+
+ /**
+ * Array of possible column keys
+ * @var array
+ */
+ static $column_keys = array(
+ 'user', 'issue', 'project', 'time_category', 'time_exp_date',
+ );
+
+ /**
+ * Default keys to use
+ * @var array
+ */
+ static $default_keys = array(
+ 'user', 'time_category', 'time_exp_date',
+ );
+
+ /**
+ * db fields to use in sql query, for each key
+ * using alias:
+ * 'TT' as plugin data table
+ * @var array
+ */
+ static $column_db_fields = array(
+ 'user' => '{user}.id',
+ 'issue' => 'TT.bug_id',
+ 'project' => '{project}.id',
+ 'time_category' => 'TT.category',
+ 'exp_date' => 'TT.time_exp_date',
+ 'date_created' => 'TT.date_created',
+ 'time_exp_date' => " FROM_UNIXTIME(TT.time_exp_date,'%d-%m-%Y') ",
+ 'user_resource' => ''
+ );
+
+ /**
+ * db fields to sort on, for each key
+ * @var array
+ */
+ static $column_db_sort_fields = array(
+ 'user' => '{user}.username',
+ 'issue' => 'TT.bug_id',
+ 'project' => '{project}.name',
+ 'time_category' => 'TT.category',
+ 'exp_date' => 'TT.time_exp_date',
+ 'date_created' => 'TT.date_created',
+ 'time_exp_date' => 'TT.time_exp_date',
+ );
+
+ /**
+ * Current selection of keys for this object
+ * @var array
+ */
+ public $selected_keys = array();
+
+ /**
+ * pagination: rows per page
+ * @var integer
+ */
+ public $rows_per_page = 100;
+
+ /**
+ * pagination, current page
+ * @var integer
+ */
+ public $page = 1; /* starts at 1 */
+
+ /**
+ * Filter array, to filter current bug selection
+ * @var array
+ */
+ public $bug_filter = null;
+
+ # current values for timetracking filtering
+ # if any is null, it won't be applied
+ public $time_filter_from, $time_filter_to; # as integer timestamps
+ public $time_filter_user_id = null;
+ public $time_filter_category = null;
+
+ /**
+ * After the query is executed, total number of rows will be sotred here
+ * Note: for consistency, use get_rows_count()
+ * @var integer
+ */
+ protected $all_rows_count;
+
+ /**
+ * After the query is executed, the raw result will be stored here
+ * Note: for consistency, use get_result()
+ * @var iterator
+ */
+ protected $result;
+
+ var $userRoleViewExists;
+ var $userRoleView;
+
+ /**
+ * Constructor. Initialize defaults
+ */
+ public function __construct() {
+ global $g_db;
+ $this->selected_keys = static::$default_keys;
+ $t_views = $g_db->MetaTables( 'VIEW' );
+
+ $this->userRoleViewExists = false;
+ $this->userRoleView = 'v_AccountCustomFields_UserRole';
+ if( is_array( $t_views ) ) {
+ # Can't use in_array() since it is case sensitive
+ $t_table_view = utf8_strtolower( $this->userRoleView );
+ foreach( $t_views as $t_current_view ) {
+ if( utf8_strtolower( $t_current_view ) == $t_table_view ) {
+ $this->userRoleViewExists = true;
+ }
+ }
+ }
+ }
+
+ /**
+ * Build a sql select based on the configured filter.
+ * This query is suitable to be used as IN clause
+ * Note: this mthod will call db_param_push()
+ * @param array $p_params db_params array (output)
+ * @return string SQL query for subselect
+ */
+ protected function build_filter_subselect( array &$p_params ) {
+ # prepare filter subselect
+ if( !$this->bug_filter ) {
+ $t_filter = array();
+ $t_filter[FILTER_PROPERTY_HIDE_STATUS] = array( META_FILTER_NONE );
+ $t_filter = filter_ensure_valid_filter( $t_filter );
+ $this->bug_filter = $t_filter;
+ }
+ # Note: filter_get_bug_rows_query_clauses() calls db_param_push();
+ $t_query_clauses = filter_get_bug_rows_query_clauses( $this->bug_filter, null, null, null );
+ # if the query can't be formed, there are no results
+ if( empty( $t_query_clauses ) ) {
+ # reset the db_param stack that was initialized by "filter_get_bug_rows_query_clauses()"
+ db_param_pop();
+ return db_empty_result();
+ }
+ $t_select_string = 'SELECT {bug}.id ';
+ $t_from_string = ' FROM ' . implode( ', ', $t_query_clauses['from'] );
+ $t_join_string = count( $t_query_clauses['join'] ) > 0 ? implode( ' ', $t_query_clauses['join'] ) : ' ';
+ $t_where_string = ' WHERE '. implode( ' AND ', $t_query_clauses['project_where'] );
+ if( count( $t_query_clauses['where'] ) > 0 ) {
+ $t_where_string .= ' AND ( ';
+ $t_where_string .= implode( $t_query_clauses['operator'], $t_query_clauses['where'] );
+ $t_where_string .= ' ) ';
+ }
+ $t_query = $t_select_string . $t_from_string . $t_join_string . $t_where_string;
+ $p_params = $t_query_clauses['where_values'];
+ return $t_query;
+ }
+
+ /**
+ * Get the row count of the report result.
+ * If the query has not been executed yet, calls to build an execute it-
+ * @return type
+ */
+ public function get_rows_count() {
+ if( !$this->result ) {
+ $this->fetch_result();
+ }
+ return $this->all_rows_count;
+ }
+
+ /**
+ * Get the query result
+ * If the query has not been executed yet, calls to build an execute it-
+ * @return iterator
+ */
+ public function get_result() {
+ if( !$this->result ) {
+ $this->fetch_result();
+ }
+ return $this->result;
+ }
+
+ /**
+ * Builds the query, execute it and stores the result
+ */
+ protected function fetch_result() {
+ $t_select_columns = array();
+ $t_group_columns = array();
+ $t_order_columns = array();
+ foreach( $this->selected_keys as $key ) {
+ $t_select_columns[] = static::$column_db_fields[$key] . ' AS ' . $key;
+ $t_group_columns[] = static::$column_db_fields[$key];
+ $t_order_columns[] = static::$column_db_sort_fields[$key];
+ }
+
+ $t_where= array();
+ $t_params = array();
+
+ # bug filter
+ $t_where[] = 'TT.bug_id IN ( ' . $this->build_filter_subselect( $t_params ) . ' )';
+
+ # timetracking date
+ if( $this->time_filter_from ) {
+ $t_where[] = 'TT.time_exp_date >= ' . db_param();
+ $t_params[] = (int)$this->time_filter_from;
+ }
+ if( $this->time_filter_to ) {
+ $t_where[] = 'TT.time_exp_date < ' . db_param();
+ $t_params[] = (int)$this->time_filter_to;
+ }
+
+ # timetracking user
+ if( $this->time_filter_user_id ) {
+ $t_where[] = 'TT.user_id = ' . db_param();
+ $t_params[] = (int)$this->time_filter_user_id;
+ }
+
+ # timetracking category
+ if( $this->time_filter_category ) {
+ $t_where[] = 'TT.category = ' . db_param();
+ $t_params[] = $this->time_filter_category;
+ }
+
+ # main query
+ $t_cols_select = implode( ', ', $t_select_columns );
+ if( !empty( $t_select_columns ) ) {
+ $t_cols_select .= ', ';
+ }
+ $t_cols_group = implode( ', ', $t_group_columns );
+ $t_cols_order = implode( ', ', $t_order_columns );
+ $t_query = 'SELECT ' . $t_cols_select . 'SUM( TT.time_count ) AS time_count'
+ . ' FROM {bug} JOIN ' . plugin_table( 'data' ) . ' TT ON {bug}.id = TT.bug_id'
+ . ' JOIN {user} ON TT.user_id = {user}.id'
+ . ' JOIN {project} ON {bug}.project_id = {project}.id';
+
+ if( $this->userRoleViewExists ) {
+ $t_query .= ' JOIN ' . $this->userRoleView . ' AS VUR ' .
+ ' ON VUR.user_id = TT.user_id ';
+ }
+
+ $t_query .= ' WHERE ' . implode( ' AND ', $t_where );
+ if( !empty( $t_select_columns ) ) {
+ $t_query .= ' GROUP BY ' . $t_cols_group . ' ORDER BY ' . $t_cols_order;
+ }
+
+ $t_query_count = 'SELECT count(*) FROM ( ' . $t_query . ' ) C';
+
+ # keeps db_params in the stack, for the next db_query
+ $this->all_rows_count = db_result( db_query( $t_query_count, $t_params, -1, -1, false ) );
+
+ # update current page if it is outside range
+ $t_max_page = 1 + (int)floor( $this->all_rows_count / $this->rows_per_page );
+ if( $this->page > $t_max_page ) {
+ $this->page = $t_max_page;
+ }
+
+ $this->result = db_query( $t_query, $t_params, $this->rows_per_page, $this->rows_per_page * ( $this->page - 1 ) );
+ }
+
+ /**
+ * Process a result array and cache relevant data in core apis
+ * @param array $p_result_array The query result in array form
+ */
+ protected function cache_resut_array( array $p_result_array ) {
+ foreach( $this->selected_keys as $t_key ) {
+ switch( $t_key ) {
+ case 'user':
+ user_cache_array_rows( array_column( $p_result_array, $t_key ) );
+ break;
+ case 'project':
+ project_cache_array_rows( array_column( $p_result_array, $t_key ) );
+ break;
+ case 'issue':
+ bug_cache_array_rows( array_column( $p_result_array, $t_key ) );
+ }
+ }
+ }
+
+ /**
+ * Formats each column key for proper presentation
+ * @param string $p_key Column key
+ * @param mixed $p_value Value to format
+ * @return mixed Formatted value
+ */
+ public static function format_value( $p_key, $p_value ) {
+ switch( $p_key ) {
+ case 'user':
+ $t_value = string_display_line( user_get_name( $p_value ) );
+ break;
+ case 'project':
+ $t_value = string_display_line( project_get_name( $p_value ) );
+ break;
+ case 'issue':
+ $t_value = string_get_bug_view_link( $p_value ) . ':' . lang_get( 'word_separator' ) . string_shorten( bug_get_field( $p_value, 'summary' ), 80 );
+ break;
+ case 'exp_date':
+ $t_value = string_display_line( date( config_get( 'short_date_format' ), $p_value ) );
+ break;
+ case 'date_created':
+ $t_value = string_display_line( date( config_get( 'normal_date_format' ), $p_value ) );
+ break;
+ default;
+ $t_value = string_display_line( $p_value );
+ }
+ return $t_value;
+ }
+
+ /**
+ * Outputs the query result into an htm table
+ */
+ public function print_table() {
+ $t_result = $this->get_result();
+ $t_result_array = array();
+ while( $t_row = db_fetch_array( $t_result ) ) {
+ $t_result_array[] = $t_row;
+ }
+ $this->cache_resut_array( $t_result_array );
+
+ echo '';
+ echo '';
+ echo '';
+ foreach( $this->selected_keys as $t_col_name ) {
+ echo '| ', plugin_lang_get( $t_col_name ) , ' | ';
+ }
+ echo '', plugin_lang_get( 'time_count' ) , ' | ';
+ echo '
';
+ echo '';
+ echo '';
+ foreach( $t_result_array as $t_row ) {
+ echo '';
+ foreach( $t_row as $t_key => $t_value ) {
+ echo '| ';
+ if( 'time_count' == $t_key ) {
+ echo seconds_to_hours( $t_value );
+ echo ' | ';
+ echo '';
+ echo seconds_to_hms( $t_value );
+ } else {
+ echo static::format_value( $t_key, $t_value );
+ }
+ echo ' | ';
+ }
+ echo '
';
+ }
+ echo '';
+ echo '
';
+ }
+
+ /**
+ * Prints the pagination controls for current report
+ * @return string Html for pagination div
+ */
+ public function print_report_pagination() {
+ $t_count = $this->get_rows_count();
+ $t_pages = 1 + (int)floor( $t_count / $this->rows_per_page );
+ if( $t_pages == 1 ) {
+ return;
+ }
+
+ $t_url_page = url_self();
+ $t_url_params = $this->get_current_params() + $_GET;
+
+ $t_lang_first = lang_get( 'first' );
+ $t_lang_last = lang_get( 'last' );
+ $t_lang_prev = lang_get( 'prev' );
+ $t_lang_next = lang_get( 'next' );
+ $t_show_pages = 10;
+ $t_show_from = max( 1, floor( $this->page - $t_show_pages / 2 ) );
+ $t_show_to = min( $t_pages, 1+ floor( $this->page + $t_show_pages / 2 ) );
+ echo '';
+ echo '';
+ echo '
';
+ }
+
+ /**
+ * Reads GET and POST parameters to update the status of current filter and properties
+ */
+ public function read_gpc_params() {
+ $f_page = gpc_get_int( 'ttreport_page', 1 );
+ $this->page = $f_page;
+
+ $f_groupby = gpc_get_string_array( 'ttreport_groupby', array() );
+ # if empty, no value were submitted, then use defaults
+ if( empty( $f_groupby ) ) {
+ $this->selected_keys = static::$default_keys;
+ } else {
+ $c_groupby = array();
+ foreach( $f_groupby as $t_key ) {
+ if( in_array( $t_key, static::$column_keys ) ) {
+ $c_groupby[] = $t_key;
+ }
+ }
+ # here the group fields may be empty, but this was submitted intentionally
+ $this->selected_keys = $c_groupby;
+ }
+
+ # Read filter parameters
+ $f_reset = gpc_isset( 'reset_filter_button' );
+ if( $f_reset ) {
+ $this->time_filter_from = null;
+ $this->time_filter_to = null;
+ $this->time_filter_category = null;
+ $this->time_filter_user_id = null;
+ } else {
+ # dates as d/m/Y
+ $f_date_from_d = gpc_get_int( 'ttreport_date_from_d', 0 );
+ $f_date_from_m = gpc_get_int( 'ttreport_date_from_m', 0 );
+ $f_date_from_y = gpc_get_int( 'ttreport_date_from_y', 0 );
+ $f_date_to_d = gpc_get_int( 'ttreport_date_to_d', 0 );
+ $f_date_to_m = gpc_get_int( 'ttreport_date_to_m', 0 );
+ $f_date_to_y = gpc_get_int( 'ttreport_date_to_y', 0 );
+ if( $f_date_from_d && $f_date_from_m && $f_date_from_y ) {
+ $this->time_filter_from = parse_date_parts( $f_date_from_y, $f_date_from_m, $f_date_from_d );
+ }
+ if( $f_date_to_d && $f_date_to_m && $f_date_to_y ) {
+ $this->time_filter_to = parse_date_parts( $f_date_to_y, $f_date_to_m, $f_date_to_d );
+ }
+
+ # dates as timestamp
+ $f_timestamp_from = gpc_get_int( 'ttreport_date_from', 0 );
+ if( $f_timestamp_from > 0 ) {
+ $this->time_filter_from = $f_timestamp_from;
+ }
+ $f_timestamp_to = gpc_get_int( 'ttreport_date_to', 0 );
+ if( $f_timestamp_to > 0 ) {
+ $this->time_filter_to = $f_timestamp_to;
+ }
+
+ # timetracking category
+ $f_category = gpc_get_string( 'ttreport_category', '' );
+ if( !empty( $f_category ) ) {
+ $this->time_filter_category = string_html_entities( $f_category );
+ }
+
+ #timetracking user
+ $f_user_id = gpc_get_int( 'ttreport_user_id', 0 );
+ if( $f_user_id > 0 ) {
+ $this->time_filter_user_id = $f_user_id;
+ }
+ }
+ }
+
+ /**
+ * Returns an array of key/value pairs representign the state of current filter and properties,
+ * suitable to build a query url
+ * @return type
+ */
+ public function get_current_params() {
+ $t_params = array();
+ $t_params['ttreport_page'] = $this->page;
+ $t_params['ttreport_groupby'] = $this->selected_keys;
+ if( $this->time_filter_user_id ) {
+ $t_params['ttreport_user_id'] = $this->time_filter_user_id;
+ }
+ if( $this->time_filter_category ) {
+ $t_params['ttreport_category'] = $this->time_filter_category;
+ }
+ if( $this->time_filter_from ) {
+ $t_params['ttreport_date_from'] = $this->time_filter_from;
+ }
+ if( $this->time_filter_to ) {
+ $t_params['ttreport_date_to'] = $this->time_filter_to;
+ }
+ return $t_params;
+ }
+
+ /**
+ * Prints html for current filter properties.
+ * It will print the inputs and supporting html, but not the main form tags
+ */
+ function print_inputs_time_filter() {
+ if( $this->time_filter_from ) {
+ $t_date_enabled = true;
+ $t_date_from = new \DateTime();
+ $t_date_from->settimestamp( $this->time_filter_from );
+ } else {
+ $t_date_enabled = false;
+ $t_date_from = new \DateTime( 'yesterday' );
+ }
+ if( $this->time_filter_to ) {
+ $t_date_to = new \DateTime();
+ $t_date_to->settimestamp( $this->time_filter_to );
+ } else {
+ $t_date_to = new \DateTime( 'today' );
+ }
+ $t_category_enabled = isset( $this->time_filter_category );
+ $t_user_enabled = isset( $this->time_filter_user_id );
+ ?>
+
+ ';
+ echo '' . plugin_lang_get( 'group_by' ) . ':';
+ echo '';
+ # set a dummy group field to allow for empty group, and avoid applying deafults.
+ echo '';
+ $t_elements = array();
+ $t_par_index = 1;
+ foreach( $this->selected_keys as $t_key ) {
+ $t_el = '';
+ $t_el .= '';
+ $t_el .= '';
+ $t_el .= plugin_lang_get( $t_key );
+ $t_el .= '';
+ $t_el .= '';
+ $t_el .= '';
+ $t_elements[] = $t_el;
+ }
+ $t_unused_keys = array_diff( static::$column_keys, $this->selected_keys );
+ if( !empty( $t_unused_keys ) ) {
+ $t_input = '';
+ $t_input .= '';
+ $t_input .= '';
+ $t_elements[] = $t_input;
+ }
+ echo implode ( '', $t_elements );
+ echo '';
+ echo '';
+ }
}
/**
* Class for a report suitable for a single issue
*/
class ReportForBug extends Report {
- # override parent definiiton for keys, only to those that make sens for a singe issue
- static $column_keys = array(
- 'user', 'time_category',
- );
- static $default_keys = array(
- 'user', 'time_category',
- );
-
- protected $bug_id;
-
- /**
- * constructor, must be initialized with a bug id
- * @param integer $p_bug_id Bug id
- */
- public function __construct( $p_bug_id ) {
- parent::__construct();
- $this->bug_id = $p_bug_id;
- }
-
- /**
- * Overrides parent filter-based selection, to show only specified bug id
- * @param array $p_params db_params (output)
- * @return string sql string
- */
- protected function build_filter_subselect( array &$p_params ) {
- db_param_push();
- # use only the bug id, as it will be placed inside a IN () clause
- $t_query = db_param();
- $p_params[] = (int)$this->bug_id;
- return $t_query;
- }
+ # override parent definiiton for keys, only to those that make sens for a singe issue
+ static $column_keys = array(
+ 'user', 'time_category', 'time_exp_date'
+ );
+ static $default_keys = array(
+ 'user', 'time_category', 'time_exp_date'
+ );
+
+ protected $bug_id;
+
+ /**
+ * constructor, must be initialized with a bug id
+ * @param integer $p_bug_id Bug id
+ */
+ public function __construct( $p_bug_id ) {
+ parent::__construct();
+ $this->bug_id = $p_bug_id;
+ }
+
+ /**
+ * Overrides parent filter-based selection, to show only specified bug id
+ * @param array $p_params db_params (output)
+ * @return string sql string
+ */
+ protected function build_filter_subselect( array &$p_params ) {
+ db_param_push();
+ # use only the bug id, as it will be placed inside a IN () clause
+ $t_query = db_param();
+ $p_params[] = (int)$this->bug_id;
+ return $t_query;
+ }
+
+ /**
+ * Will be used ONLY IF Custom Fields AT USER LEVEL
+ * are enabled.
+ *
+ */
+ protected function fetchResultWithResourceType() {
+ $t_select_columns = array();
+ $t_group_columns = array();
+ $t_order_columns = array();
+
+ foreach( $this->selected_keys as $key ) {
+ $t_select_columns[] = static::$column_db_fields[$key] . ' AS ' . $key;
+ $t_group_columns[] = static::$column_db_fields[$key];
+ $t_order_columns[] = static::$column_db_sort_fields[$key];
+ }
+
+ $t_where= array();
+ $t_params = array();
+
+ # bug filter
+ $t_where[] = 'TT.bug_id IN ( ' . $this->build_filter_subselect( $t_params ) . ' )';
+
+ # timetracking date
+ if( $this->time_filter_from ) {
+ $t_where[] = 'TT.time_exp_date >= ' . db_param();
+ $t_params[] = (int)$this->time_filter_from;
+ }
+ if( $this->time_filter_to ) {
+ $t_where[] = 'TT.time_exp_date < ' . db_param();
+ $t_params[] = (int)$this->time_filter_to;
+ }
+
+ # timetracking user
+ if( $this->time_filter_user_id ) {
+ $t_where[] = 'TT.user_id = ' . db_param();
+ $t_params[] = (int)$this->time_filter_user_id;
+ }
+
+ # timetracking category
+ if( $this->time_filter_category ) {
+ $t_where[] = 'TT.category = ' . db_param();
+ $t_params[] = $this->time_filter_category;
+ }
+
+ # main query
+ $t_cols_select = implode( ', ', $t_select_columns );
+ if( !empty( $t_select_columns ) ) {
+ $t_cols_select .= ', ';
+ }
+ $t_cols_group = implode( ', ', $t_group_columns );
+ $t_cols_order = implode( ', ', $t_order_columns );
+ $t_query = 'SELECT ' . $t_cols_select .
+ 'SUM( TT.time_count ) AS time_count' .
+ ' FROM {bug} JOIN ' . plugin_table( 'data' ) .
+ ' TT ON {bug}.id = TT.bug_id' .
+ ' JOIN {user} ON TT.user_id = {user}.id' .
+ ' JOIN {project} ON {bug}.project_id = {project}.id' .
+ ' WHERE ' . implode( ' AND ', $t_where );
+ if( !empty( $t_select_columns ) ) {
+ $t_query .= ' GROUP BY ' . $t_cols_group . ' ORDER BY ' . $t_cols_order;
+ }
+
+ $t_query_count = 'SELECT count(*) FROM ( ' . $t_query . ' ) C';
+
+ # keeps db_params in the stack, for the next db_query
+ $this->all_rows_count = db_result( db_query( $t_query_count, $t_params, -1, -1, false ) );
+
+ # update current page if it is outside range
+ $t_max_page = 1 + (int)floor( $this->all_rows_count / $this->rows_per_page );
+ if( $this->page > $t_max_page ) {
+ $this->page = $t_max_page;
+ }
+
+ $this->result = db_query( $t_query, $t_params, $this->rows_per_page, $this->rows_per_page * ( $this->page - 1 ) );
+ }
+
+
+
}
\ No newline at end of file
diff --git a/TimeTracking/core/timetracking_api.php b/TimeTracking/core/timetracking_api.php
index f5f36c1..e91adc6 100644
--- a/TimeTracking/core/timetracking_api.php
+++ b/TimeTracking/core/timetracking_api.php
@@ -100,7 +100,7 @@ function cache_records_bug_ids( array $p_bug_id ) {
for( $i = 0; $i < $t_count; $i++ ) {
$t_ids_dbparams[] = db_param();
}
- $t_query = 'SELECT T.* FROM {bug} B JOIN ' . plugin_table( 'data' ) . ' T'
+ $t_query = 'SELECT T.* FROM {bug} B JOIN ' . plugin_table( 'data', __NAMESPACE__ ) . ' T'
. ' ON B.id = T.bug_id WHERE T.bug_id IN (' . implode( ',', $t_ids_dbparams ) . ')';
$t_result = db_query( $t_query, array_values( $t_bug_ids_to_search) );
diff --git a/TimeTracking/lang/strings_english.txt b/TimeTracking/lang/strings_english.txt
old mode 100755
new mode 100644
index e9ccfd3..363b32d
--- a/TimeTracking/lang/strings_english.txt
+++ b/TimeTracking/lang/strings_english.txt
@@ -1,10 +1,12 @@
$default ) {
+
+ if( is_int($default) ) {
+ $fn = 'gpc_get_int';
+ if( strpos($opt, 'enabled') !== FALSE ) {
+ // is a bool like 1/0
+ $default = OFF;
+ }
+ }
-form_security_purge( 'plugin_TimeTracking_config_update' );
+ if( is_string($default) ) {
+ $fn = 'gpc_get_string';
+ }
+ plugin_config_set( $opt, $fn( $opt, $default ) );
+}
+form_security_purge( $fid );
print_successful_redirect( plugin_page( 'config_page', true ) );