View Issue Details

IDProjectCategoryView StatusLast Update
0013180mantisbtcustom fieldspublic2020-08-25 04:48
Reporterrombert Assigned To 
PrioritynormalSeverityfeatureReproducibilityN/A
Status confirmedResolutionopen 
Summary0013180: Url template custom field
Description

We should provide a custom field of type url template. It would take a parameter of type template with a placeholder for substitution, e.g.

http://www.example.com/view/%s?page=put

This can be useful for integration with other systems, e.g Github's pull requests in our case.

When rendered the field would be clickable and navigate to the linked page, with the substitution applied.

TagsNo tags attached.
Attached Files
0001-Added-custom-field-Template.patch (13,128 bytes)   
From c4507fdbe00b0a7a496fa12d21ca3708a8a865e2 Mon Sep 17 00:00:00 2001
From: Vincent Sels <vincent_sels@hotmail.com>
Date: Sun, 5 Feb 2012 18:52:19 +0100
Subject: [PATCH] Added custom field 'Template'

When choosing custom field type 'Template', you can define a template value with
a placeholder ({0}) in the 'Default value' field. Upon entering a
value for this custom field, it will be inserted in the template's
placeholder. Links will be interpreted.
---
 config_defaults_inc.php        |    2 +-
 core/cfdefs/cfdef_standard.php |   44 ++++++++++++++++++++++++++++++++++++++++
 core/constant_inc.php          |    1 +
 core/custom_field_api.php      |   32 +++++++++++++---------------
 core/email_api.php             |    2 +-
 core/gpc_api.php               |    1 +
 lang/strings_dutch.txt         |    2 +-
 lang/strings_english.txt       |    2 +-
 8 files changed, 65 insertions(+), 21 deletions(-)

diff --git a/config_defaults_inc.php b/config_defaults_inc.php
index 7087dab..cd59cb1 100644
--- a/config_defaults_inc.php
+++ b/config_defaults_inc.php
@@ -3019,7 +3019,7 @@
 	 *
 	 * @global string $g_custom_field_type_enum_string
 	 */
-	$g_custom_field_type_enum_string    = '0:string,1:numeric,2:float,3:enum,4:email,5:checkbox,6:list,7:multiselection list,8:date,9:radio';
+	$g_custom_field_type_enum_string    = '0:string,1:numeric,2:float,3:enum,4:email,5:checkbox,6:list,7:multiselection list,8:date,9:radio,10:template';
 
 	/*********************************
 	 * MantisBT Javascript Variables *
diff --git a/core/cfdefs/cfdef_standard.php b/core/cfdefs/cfdef_standard.php
index f358d3b..c1ea092 100644
--- a/core/cfdefs/cfdef_standard.php
+++ b/core/cfdefs/cfdef_standard.php
@@ -158,6 +158,20 @@ $g_custom_field_type_definition[ CUSTOM_FIELD_TYPE_DATE ] = array (
 	'#function_string_value_for_email' => 'cfdef_prepare_date_value_for_email',
 );
 
+$g_custom_field_type_definition[ CUSTOM_FIELD_TYPE_TEMPLATE ] = array (
+	'#display_possible_values' => FALSE,
+	'#display_valid_regexp' => TRUE,
+	'#display_length_min' => TRUE,
+	'#display_length_max' => TRUE,
+	'#display_default_value' => TRUE,
+	'#function_return_distinct_values' => null,
+	'#function_value_to_database' => null,
+	'#function_database_to_value' => null,
+	'#function_print_input' => 'cfdef_input_textbox',
+	'#function_string_value' => 'cfdef_prepare_template_value',
+	'#function_string_value_for_email' => 'cfdef_prepare_template_value_for_email',
+);
+
 function cfdef_prepare_list_database_to_value($p_value) {
 	return rtrim( ltrim( $p_value, '|' ), '|' );
 }
@@ -224,6 +238,36 @@ function cfdef_prepare_date_value($p_value) {
 	}
 }
 
+/**
+ * Replaces the wildcard '{0}' from the field's 'default value' with the specified $p_value.
+ * Also converts the resulting string to a link if applicable.
+ * @param $p_value The value to be inserted in the template
+ * @return string replaces the wildcard '{0}' from the 'default value' with the specified $p_value
+ */
+function cfdef_prepare_template_value($p_value, $p_field_def) {
+	$t_template = $p_field_def['default_value'];
+
+	if ( empty( $p_value ) ) {
+		return '';
+	}
+
+	return string_display_line_links(str_replace('{0}', $p_value, $t_template));
+}
+
+/**
+ * Replaces the wildcard '{0}' from the field's 'default value' with the specified $p_value
+ * @param $p_value The value to be inserted in the template
+ * @return string replaces the wildcard '{0}' from the 'default value' with the specified $p_value
+ */
+function cfdef_prepare_template_value_for_email($p_value, $p_field_def) {
+	$t_template = $p_field_def['default_value'];
+
+	if ( empty( $p_value ) ) {
+		return '';
+	}
+
+	return str_replace('{0}', $p_value, $t_template);
+}
 
 #print_custom_field_input
 
diff --git a/core/constant_inc.php b/core/constant_inc.php
index a10a54b..149ec5e 100644
--- a/core/constant_inc.php
+++ b/core/constant_inc.php
@@ -416,6 +416,7 @@ define( 'CUSTOM_FIELD_TYPE_LIST', 6 );
 define( 'CUSTOM_FIELD_TYPE_MULTILIST', 7 );
 define( 'CUSTOM_FIELD_TYPE_DATE', 8 );
 define( 'CUSTOM_FIELD_TYPE_RADIO', 9 );
+define( 'CUSTOM_FIELD_TYPE_TEMPLATE', 10 );
 
 # Meta filter values
 define( 'META_FILTER_MYSELF', -1 );
diff --git a/core/custom_field_api.php b/core/custom_field_api.php
index a6faa8a..4e6d8c4 100644
--- a/core/custom_field_api.php
+++ b/core/custom_field_api.php
@@ -53,6 +53,7 @@ $g_custom_field_types[CUSTOM_FIELD_TYPE_CHECKBOX] = 'standard';
 $g_custom_field_types[CUSTOM_FIELD_TYPE_LIST] = 'standard';
 $g_custom_field_types[CUSTOM_FIELD_TYPE_MULTILIST] = 'standard';
 $g_custom_field_types[CUSTOM_FIELD_TYPE_DATE] = 'standard';
+$g_custom_field_types[CUSTOM_FIELD_TYPE_TEMPLATE] = 'standard';
 
 foreach( $g_custom_field_types as $type ) {
 	require_once( 'cfdefs' . DIRECTORY_SEPARATOR . 'cfdef_' . $type . '.php' );
@@ -380,9 +381,9 @@ function custom_field_has_write_access( $p_field_id, $p_bug_id, $p_user_id = nul
 }
 
 /**
- * create a new custom field with the name $p_name
- * the definition are the default values and can be changes later
- * return the ID of the new definition
+ * create a new custom field with the name $p_name.
+ * the definition are the default values and can be changed later.
+ * return the ID of the new definition.
  * @param string $p_name custom field name
  * @return int custom field id
  * @access public
@@ -413,7 +414,7 @@ function custom_field_create( $p_name ) {
 }
 
 /**
- * Update the field definition
+ * Update the field definition.
  * return true on success, false on failure
  * @param int $p_field_id custom field id
  * @param array custom field definition
@@ -984,9 +985,6 @@ function custom_field_get_value( $p_field_id, $p_bug_id ) {
 
 	$row = custom_field_cache_row( $p_field_id );
 
-	$t_access_level_r = $row['access_level_r'];
-	$t_default_value = $row['default_value'];
-
 	if( !custom_field_has_read_access( $p_field_id, $p_bug_id, auth_get_current_user_id() ) ) {
 		return false;
 	}
@@ -1148,6 +1146,7 @@ function custom_field_validate( $p_field_id, $p_value ) {
 	$t_length = utf8_strlen( $p_value );
 	switch ($t_type) {
 		case CUSTOM_FIELD_TYPE_STRING:
+		case CUSTOM_FIELD_TYPE_TEMPLATE:
 			# Regular expression string validation
 			if( !is_blank( $t_valid_regexp ) && !is_blank( $p_value ) ) {
 				$t_valid &= preg_match( "/$t_valid_regexp/", $p_value );
@@ -1243,7 +1242,6 @@ function custom_field_prepare_possible_values( $p_possible_values ) {
 function custom_field_distinct_values( $p_field_def, $p_project_id = ALL_PROJECTS ) {
 	global $g_custom_field_type_definition;
 	$c_field_id = $p_field_def['id'];
-	$c_project_id = db_prepare_int( $p_project_id );
 	$t_custom_field_string_table = db_get_table( 'mantis_custom_field_string_table' );
 	$t_mantis_bug_table = db_get_table( 'mantis_bug_table' );
 	$t_return_arr = array();
@@ -1414,10 +1412,10 @@ function custom_field_set_sequence( $p_field_id, $p_project_id, $p_sequence ) {
 
 /**
  * Print an input field
- * $p_field_def contains the definition of the custom field (including it's field id
+ * $p_field_def contains the definition of the custom field (including its field id)
  * $p_bug_id    contains the bug where this field belongs to. If it's left
- * away, it'll default to 0 and thus belongs to a new (i.e. non-existant) bug
- * NOTE: This probably belongs in the print_api.php
+ * away, it'll default to 0 and thus belong to a new (i.e. non-existant) bug
+ * @todo This probably belongs in the print_api.php
  * @param array $p_field_def custom field definition
  * @param int $p_bug_id bug id
  * @access public
@@ -1461,14 +1459,14 @@ function string_custom_field_value( $p_def, $p_field_id, $p_bug_id ) {
 	}
 	global $g_custom_field_type_definition;
 	if( isset( $g_custom_field_type_definition[$p_def['type']]['#function_string_value'] ) ) {
-		return call_user_func( $g_custom_field_type_definition[$p_def['type']]['#function_string_value'], $t_custom_field_value );
+		return call_user_func( $g_custom_field_type_definition[$p_def['type']]['#function_string_value'], $t_custom_field_value , $p_def );
 	}
 	return string_display_links( $t_custom_field_value );
 }
 
 /**
  * Print a custom field value for display
- * NOTE: This probably belongs in the print_api.php
+ * @todo This probably belongs in the print_api.php
  * @param array  $p_def contains the definition of the custom field
  * @param int $p_field_id contains the id of the field
  * @param int $p_bug_id contains the bug id to display the custom field value for
@@ -1481,16 +1479,16 @@ function print_custom_field_value( $p_def, $p_field_id, $p_bug_id ) {
 
 /**
  * Prepare a string containing a custom field value for email
- * NOTE: This probably belongs in the string_api.php
+ * @todo This probably belongs in the string_api.php
  * @param string $p_value value of custom field
  * @param int $p_type	type of custom field
  * @return string value ready for sending via email
  * @access public
  */
-function string_custom_field_value_for_email( $p_value, $p_type ) {
+function string_custom_field_value_for_email( $p_value, $p_def ) {
 	global $g_custom_field_type_definition;
-	if( isset( $g_custom_field_type_definition[$p_type]['#function_string_value_for_email'] ) ) {
-		return call_user_func( $g_custom_field_type_definition[$p_type]['#function_string_value_for_email'], $p_value );
+	if( isset( $g_custom_field_type_definition[$p_def['type']]['#function_string_value_for_email'] ) ) {
+		return call_user_func( $g_custom_field_type_definition[$p_def['type']]['#function_string_value_for_email'], $p_value, $p_def );
 	}
 	return $p_value;
 }
diff --git a/core/email_api.php b/core/email_api.php
index 59bb51c..a947560 100644
--- a/core/email_api.php
+++ b/core/email_api.php
@@ -1240,7 +1240,7 @@ function email_format_bug_message( $p_visible_bug_data ) {
 	# custom fields formatting
 	foreach( $p_visible_bug_data['custom_fields'] as $t_custom_field_name => $t_custom_field_data ) {
 		$t_message .= utf8_str_pad( lang_get_defaulted( $t_custom_field_name, null ) . ': ', $t_email_padding_length, ' ', STR_PAD_RIGHT );
-		$t_message .= string_custom_field_value_for_email( $t_custom_field_data['value'], $t_custom_field_data['type'] );
+		$t_message .= string_custom_field_value_for_email( $t_custom_field_data['value'], $t_custom_field_data );
 		$t_message .= " \n";
 	}
 
diff --git a/core/gpc_api.php b/core/gpc_api.php
index a08205a..7ae01bc 100644
--- a/core/gpc_api.php
+++ b/core/gpc_api.php
@@ -182,6 +182,7 @@ function gpc_isset_custom_field( $p_var_name, $p_custom_field_type ) {
 		case CUSTOM_FIELD_TYPE_FLOAT:
 		case CUSTOM_FIELD_TYPE_ENUM:
 		case CUSTOM_FIELD_TYPE_EMAIL:
+		case CUSTOM_FIELD_TYPE_TEMPLATE:
 			return gpc_isset( $t_field_name ) && !is_blank( gpc_get_string( $t_field_name ) );
 		default:
 			return gpc_isset( $t_field_name );
diff --git a/lang/strings_dutch.txt b/lang/strings_dutch.txt
index 438a89e..5d5b221 100644
--- a/lang/strings_dutch.txt
+++ b/lang/strings_dutch.txt
@@ -1006,7 +1006,7 @@ $s_link_custom_field_to_project_title = 'Gebruikersveld aan project koppelen';
 $s_link_custom_field_to_project_button = 'Gebruikersveld koppelen';
 $s_linked_projects = 'Gekoppelde projecten';
 $s_custom_field_sequence = 'Volgorde';
-$s_custom_field_type_enum_string = '0:String,1:Numeriek,2:Drijvende komma,3:Enumeratie,4:E-mail,5:Checkbox,6:Lijst,7:Multiselectie lijst,8:Datum,9:Keuzerondje';
+$s_custom_field_type_enum_string = '0:String,1:Numeriek,2:Drijvende komma,3:Enumeratie,4:E-mail,5:Checkbox,6:Lijst,7:Multiselectie lijst,8:Datum,9:Keuzerondje,10:Template';
 $s_confirm_used_custom_field_deletion = 'Op dit moment is dit veld verbonden met tenminste één project.  Als u doorgaat, worden alle waarden voor dit veld permanent verwijderd. Deze handeling kan niet ongedaan gemaakt worden. Als u dit veld niet wilt verwijderen, klik dan op de knop "Vorige" in uw browser. Klik op onderstaande knop om door te gaan.';
 $s_confirm_custom_field_deletion = 'Weet u zeker dat u dit gebruikersveld en alle bijbehorende waarden wilt verwijderen?';
 $s_field_delete_button = 'Gebruikersveld verwijderen';
diff --git a/lang/strings_english.txt b/lang/strings_english.txt
index bf638cb..f166eaa 100644
--- a/lang/strings_english.txt
+++ b/lang/strings_english.txt
@@ -1304,7 +1304,7 @@ $s_link_custom_field_to_project_button = 'Link Custom Field';
 $s_linked_projects = 'Linked Projects';
 
 $s_custom_field_sequence = 'Sequence';
-$s_custom_field_type_enum_string = '0:String,1:Numeric,2:Float,3:Enumeration,4:E-mail,5:Checkbox,6:List,7:Multiselection list,8:Date,9:Radio';
+$s_custom_field_type_enum_string = '0:String,1:Numeric,2:Float,3:Enumeration,4:E-mail,5:Checkbox,6:List,7:Multiselection list,8:Date,9:Radio,10:Template';
 
 $s_confirm_used_custom_field_deletion = 'This field is currently linked to at least one project. If you continue all values for this field will be permanently deleted. This action cannot be undone. If you do not want to delete this field, hit the Back button in your browser. To proceed, click the button below';
 $s_confirm_custom_field_deletion = 'Are you sure you want to delete this custom field and all associated values?';
-- 
1.7.6.msysgit.0

Relationships

has duplicate 0007020 closedatrol Custom field can become a parameter in an HTML link 

Activities

vincent_sels

vincent_sels

2011-12-07 10:46

reporter   ~0030493

Also very interested in this. We would use this for integration with a document sharing tool like sharepoint.

marcin

marcin

2011-12-20 08:26

reporter   ~0030667

+1
I would gladly sponsor this, as long as it's a bit more generic. I think '%s' approach works good enough, but I'd be also interested in more generic regular expression, so one can create multiple links for multiple entered elements.

I raised it also in the forums
http://www.mantisbt.org/forums/viewtopic.php?f=2&amp;t=19986

Few simple ideas:

  • this concept gives you even more power - e.g. making some fields visible in a different way, e.g. in bold
  • might be nice to have a different rewrite for view in the issue details (e.g. to make it large and bold) and in the issue list (keep it normal)
marcin

marcin

2012-01-25 08:54

reporter   ~0031024

No reactions? Would boosting sponsorship work? :)

rombert

rombert

2012-01-25 10:20

reporter   ~0031025

Thanks for the offer, but we don't typically work through sponsorships ( I guess this should be disabled ... ) . It's just a matter of time, which is not easy to find.

marcin

marcin

2012-01-25 10:28

reporter   ~0031026

OK, thanks for the clarification.

I'd love to contribute with working on it myself, but, as you wrote, time is not easy to find :(

vincent_sels

vincent_sels

2012-01-27 07:51

reporter   ~0031058

marcin, I'd gladly add it for you, I can still occasionally find some spare time :) Feel free to contact me by email, vincent_sels@hotmail.com

marcin

marcin

2012-02-05 09:19

reporter   ~0031132

Last edited: 2012-02-05 10:28

Vincent, thanks for the offer.

I implemented a trivial fix for my needs:

<pre>
*** core/custom_field_api.php.org 2012-02-05 15:11:22.000000000 +0100
--- core/custom_field_api.php 2012-02-05 15:15:03.000000000 +0100


* 1272,1277 **
--- 1272,1286 ----

NOTE: This probably belongs in the string_api.php

function string_custom_field_value( $p_def, $p_field_id, $p_bug_id ) {
    $t_custom_field_value = custom_field_get_value( $p_field_id, $p_bug_id );
  • if ($p_def['name'] == 'MY_FIELD') {
  • $val = preg_replace(
  • '/\b(\d+)\b/',
  • '<span style="font-size:130%"><a href="https://MY_URL?ID=1&quot;><b>$1</b></a></span>', $t_custom_field_value);
  • return $val;
  • }
  • switch( $p_def['type'] ) {
        case CUSTOM_FIELD_TYPE_EMAIL:
            return &quot;&lt;a href=\&quot;mailto:$t_custom_field_value\&quot;>$t_custom_field_value&lt;/a>&quot;;

    </pre>

(ARGH, pasting code in doesn't work ideally, see the attached patch)

This allows me converting all numeric ids contained in this field into links, additionally in bold as it's important.

So, I'm content for now, and I can hack it any way I want.

But I still think it would be nice to have as an official plugin/feature. But that's way more work, esp. configuration. If it's done by someone, my sponsorship still holds :)

vincent_sels

vincent_sels

2012-02-05 13:01

reporter   ~0031140

Last edited: 2012-02-05 13:04

Created pull request https://github.com/mantisbt/mantisbt/pull/41 that adds this.
Or check out the branch: https://github.com/vincentsels/mantisbt/tree/add-13180-template-custom-field
Also added the modifications as a patch (to the 1.2.x branch)

Screenshots:

Field definition: http://grab.by/bPp0
Edit field: http://grab.by/bPp2
Display: http://grab.by/bPp6
History: http://grab.by/bPp8

Feel free to test it and if you encounter any issues, I'll immediately take a look at them.

vboctor

vboctor

2012-02-13 02:37

manager   ~0031223

I've deleted trivial.patch based on Marcin's request.

marcin

marcin

2012-02-23 08:36

reporter   ~0031301

Btw, we discussed it with Vincent offline. His change is nice, but another idea popped up.

We could add two attributes to all custom fields:

  • "Template pattern" - specifying what in the stored value should be replaced. Default: ".*" (anything)
  • "Template replacement" - specifying what should be the replacement value. Default: empty
    If both are empty - no action would be taken.

This way, we keep it generic and allow more stuff. For example, in our system we have a custom "Fixed in branch" field which is now a multi-choice. If it was extended with the template mechanism, the choices (branch names) could be converted into links automatically on display.

But perhaps it's an overkill :)

dhx

dhx

2012-06-02 05:57

reporter   ~0031977

Changed the target version to 1.3.x. This is a feature and should therefore land in a feature branch -- not the 1.2.x maintenance branch.

rombert

rombert

2013-01-12 15:13

reporter   ~0034786

New PR at https://github.com/mantisbt/mantisbt/pull/71

rombert

rombert

2013-04-25 11:12

reporter   ~0036669

Confirmed, makes sense to have this.

vboctor

vboctor

2015-01-22 00:58

manager   ~0042230

This seems like a useful feature that should probably make it into master now to make it into the 1.3.x release train which is currently in beta.

Will this template model support showing a hyperlinked text or image? This would provide a clean look for long URLs (e.g. value 1234 becomes "1234" hyperlinked). Such values are cleaner looking and can fit nicely in View Issues page.

cproensa

cproensa

2015-09-26 10:47

developer   ~0051538

This functionality could be done with a plugin

attached is an example plugin:
"template_column_test.php"

It creates a new column, that outputs an url using another custom field as source for some of its parameters.
Being a proof of concept, source field is hardcoded, you should change it to your existing custom field name. Also could source from standrad fields, as you have the BugData objetc available in the display method.

One possible problem. This can define only one column for each class defined in source. Not valid for runtime configuration of new templated columns?

template_column_test.php (1,660 bytes)   
<?php


class CustomColumn extends MantisColumn {
	public $title = 'column_test';
	public $column = 'column_test';
	
	public $source_field = 'source_custom_field_name';
	
	function display( BugData $p_bug, $p_columns_target ){
		$t_field_id = custom_field_get_id_from_name( $this->source_field );
		$t_value= custom_field_get_value( $t_field_id, $p_bug->id );
		echo '<a href="http://example.com?val=' . $t_value . '">' . $t_value . '</a>';
	}
}


class template_column_testPlugin extends MantisPlugin {
/* 
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

        function register() {
                $this->name = 'template_column_test';    # Proper name of plugin
                $this->description = 'template_column_test';    # Short description of the plugin
                
                $this->version = '1.0';     # Plugin version string
                $this->requires = array(    # Plugin dependencies, array of basename => version pairs
                    'MantisCore' => '1.3.0',  #   Should always depend on an appropriate version of MantisBT
                    );
                
                $this->author = 'carlos proensa';         # Author/team name
                $this->contact = '';        # Author/team e-mail address
                $this->url = '';            # Support webpage
        }
		
	function hooks( )
	{
		$hooks = array(
			'EVENT_FILTER_COLUMNS' => 'register_column',
		);

		return $hooks;
	}
	
	function register_column( $p_event ) {
		return array ( 'CustomColumn' );
	}
		
}
template_column_test.php (1,660 bytes)   
cproensa

cproensa

2015-09-26 18:19

developer   ~0051540

opened 0020140 for a fix
if accepted, a proper plugin could be implemented