summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Bugzilla/Field.pm48
-rwxr-xr-xcustomfield.pl89
-rw-r--r--editfields.cgi120
-rw-r--r--template/en/default/admin/custom_fields/create.html.tmpl111
-rw-r--r--template/en/default/admin/custom_fields/edit.html.tmpl99
-rw-r--r--template/en/default/admin/custom_fields/list.html.tmpl63
-rw-r--r--template/en/default/global/user-error.html.tmpl30
7 files changed, 462 insertions, 98 deletions
diff --git a/Bugzilla/Field.pm b/Bugzilla/Field.pm
index c6c889957..cd510471d 100644
--- a/Bugzilla/Field.pm
+++ b/Bugzilla/Field.pm
@@ -93,6 +93,8 @@ use constant DB_COLUMNS => (
'description',
'type',
'custom',
+ 'mailhead',
+ 'sortkey',
'obsolete',
'enter_bug',
);
@@ -216,6 +218,31 @@ sub custom { return $_[0]->{custom} }
=over
+=item C<in_new_bugmail>
+
+a boolean specifying whether or not the field is displayed in bugmail
+for newly-created bugs;
+
+=back
+
+=cut
+
+sub in_new_bugmail { return $_[0]->{mailhead} }
+
+=over
+
+=item C<sortkey>
+
+an integer specifying the sortkey of the field.
+
+=back
+
+=cut
+
+sub sortkey { return $_[0]->{sortkey} }
+
+=over
+
=item C<obsolete>
a boolean specifying whether or not the field is obsolete;
@@ -256,8 +283,14 @@ Params: This function takes named parameters in a hashref:
C<desc> - string - The field label to display in the UI.
C<in_new_bugmail> - boolean - Whether this field appears at the
top of the bugmail for a newly-filed bug.
+
+ The following parameters are only available on field creation:
C<custom> - boolean - True if this is a Custom Field. The field
will be added to the C<bugs> table if it does not exist.
+ C<sortkey> - integer - The sortkey of the field.
+ C<editable_on_enter_bug> - boolean - Whether this field is
+ editable on the bug creation form.
+ C<is_obsolete> - boolean - Whether this field is obsolete.
Returns: a C<Bugzilla::Field> object.
@@ -267,12 +300,16 @@ Returns: a C<Bugzilla::Field> object.
sub create_or_update {
my ($params) = @_;
-
+
my $custom = $params->{custom} ? 1 : 0;
my $name = $params->{name};
my $in_new_bugmail = $params->{in_new_bugmail} ? 1 : 0;
+ my $sortkey = $params->{sortkey} || 0;
+ my $enter_bug = $params->{editable_on_enter_bug} ? 1 : 0;
+ my $is_obsolete = $params->{is_obsolete} ? 1 : 0;
# Some day we'll allow invocants to specify the field type.
+ # We don't care about $params->{type} yet.
my $type = $custom ? FIELD_TYPE_FREETEXT : FIELD_TYPE_UNKNOWN;
my $field = new Bugzilla::Field({name => $name});
@@ -285,16 +322,15 @@ sub create_or_update {
undef, $params->{desc}, $in_new_bugmail, $field->id);
}
else {
- # Some day we'll allow invocants to specify the sort key.
- my ($sortkey) = $dbh->selectrow_array(
+ $sortkey ||= $dbh->selectrow_array(
"SELECT MAX(sortkey) + 100 FROM fielddefs") || 100;
# Add the field to the list of fields at this Bugzilla installation.
$dbh->do("INSERT INTO fielddefs (name, description, sortkey, type,
- custom, mailhead)
- VALUES (?, ?, ?, ?, ?, ?)", undef,
+ custom, mailhead, obsolete, enter_bug)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)", undef,
$name, $params->{desc}, $sortkey, $type, $custom,
- $in_new_bugmail);
+ $in_new_bugmail, $is_obsolete, $enter_bug);
}
if (!$dbh->bz_column_info('bugs', $name) && $custom) {
diff --git a/customfield.pl b/customfield.pl
deleted file mode 100755
index b5b9fd07b..000000000
--- a/customfield.pl
+++ /dev/null
@@ -1,89 +0,0 @@
-#!/usr/bin/perl -wT
-# -*- Mode: perl; indent-tabs-mode: nil -*-
-#
-# The contents of this file are subject to the Mozilla Public
-# License Version 1.1 (the "License"); you may not use this file
-# except in compliance with the License. You may obtain a copy of
-# the License at http://www.mozilla.org/MPL/
-#
-# Software distributed under the License is distributed on an "AS
-# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-# implied. See the License for the specific language governing
-# rights and limitations under the License.
-#
-# The Original Code is the Bugzilla Bug Tracking System.
-#
-# The Initial Developer of the Original Code is Netscape Communications
-# Corporation. Portions created by Netscape are
-# Copyright (C) 1998 Netscape Communications Corporation. All
-# Rights Reserved.
-#
-# Contributor(s): Myk Melez <myk@mozilla.org>
-
-################################################################################
-# Script Initialization
-################################################################################
-
-use strict;
-
-use lib ".";
-
-use Bugzilla;
-use Bugzilla::Field;
-use Getopt::Long;
-
-my ($name, $desc);
-my $result = GetOptions("name=s" => \$name,
- "description|desc=s" => \$desc);
-
-if (!$name or !$desc) {
- my $command =
- $^O =~ /MSWin32/i ? "perl -T customfield.pl" : "./customfield.pl";
- print <<END;
-Usage:
-
- Use this script to add a custom field to your Bugzilla installation
- by invoking it with the --name and --desc command-line options:
-
- $command --name=<field_name> --desc="<field description>"
-
- <field_name> is the name of the custom field in the database.
- The string "cf_" will be prepended to this name to distinguish
- the field from standard fields. This name must conform to the
- naming rules for the database server you use.
-
- <field description> is a short string describing the field. It will
- be displayed to Bugzilla users in several parts of Bugzilla's UI,
- for example as the label for the field on the "show bug" page.
-
-Warning:
-
- Custom fields can make Bugzilla less usable. See this URL
- for alternatives to custom fields:
-
- http://www.gerv.net/hacking/custom-fields.html
-
- You should try to implement applicable alternatives before using
- this script to add a custom field.
-END
-
- exit;
-}
-
-# Prepend cf_ to the custom field name to distinguish it from standard fields.
-$name =~ /^cf_/
- or $name = "cf_" . $name;
-
-# Exit gracefully if there is already a field with the given name.
-if ( new Bugzilla::Field({name => $name}) ) {
- print "There is already a field named $name. Please choose " .
- "a different name.\n";
- exit;
-}
-
-
-# Create the field.
-print "Creating custom field $name ...\n";
-Bugzilla::Field::create_or_update(
- {name => $name, desc => $desc, custom => 1});
-print "Custom field $name created.\n";
diff --git a/editfields.cgi b/editfields.cgi
new file mode 100644
index 000000000..17db14092
--- /dev/null
+++ b/editfields.cgi
@@ -0,0 +1,120 @@
+#!/usr/bin/perl -wT
+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS
+# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# Contributor(s): Frédéric Buclin <LpSolit@gmail.com>
+
+use strict;
+use lib ".";
+
+use Bugzilla;
+use Bugzilla::Constants;
+use Bugzilla::Error;
+use Bugzilla::Util;
+use Bugzilla::Field;
+
+my $cgi = Bugzilla->cgi;
+my $template = Bugzilla->template;
+my $vars = {};
+
+# Make sure the user is logged in and is an administrator.
+my $user = Bugzilla->login(LOGIN_REQUIRED);
+$user->in_group('admin')
+ || ThrowUserError('auth_failure', {group => 'admin',
+ action => 'edit',
+ object => 'custom_fields'});
+
+my $action = trim($cgi->param('action') || '');
+
+print $cgi->header();
+
+# List all existing custom fields if no action is given.
+if (!$action) {
+ $vars->{'custom_fields'} = [Bugzilla->get_fields({'custom' => 1})];
+
+ $template->process('admin/custom_fields/list.html.tmpl', $vars)
+ || ThrowTemplateError($template->error());
+}
+# Interface to add a new custom field.
+elsif ($action eq 'add') {
+ $template->process('admin/custom_fields/create.html.tmpl')
+ || ThrowTemplateError($template->error());
+}
+elsif ($action eq 'new') {
+ my $name = clean_text($cgi->param('name') || '');
+ my $desc = clean_text($cgi->param('desc') || '');
+ # For now, there is only one type available for custom fields.
+ # In the future, we will have to look at $cgi->param('type').
+ my $type = FIELD_TYPE_FREETEXT;
+ my $sortkey = $cgi->param('sortkey') || 0;
+
+ # Validate these fields.
+ $name || ThrowUserError('customfield_missing_name');
+ # Prepend cf_ to the custom field name to distinguish it from standard fields.
+ if ($name !~ /^cf_/) {
+ $name = 'cf_' . $name;
+ }
+ my $field = new Bugzilla::Field({'name' => $name});
+ ThrowUserError('customfield_already_exists', {'field' => $field }) if $field;
+
+ $desc || ThrowUserError('customfield_missing_description', {'name' => $name});
+
+ my $skey = $sortkey;
+ detaint_natural($sortkey)
+ || ThrowUserError('customfield_invalid_sortkey', {'name' => $name,
+ 'sortkey' => $skey});
+
+ # All fields have been validated. We can create this new custom field.
+ trick_taint($name);
+ trick_taint($desc);
+
+ $vars->{'name'} = $name;
+ $vars->{'desc'} = $desc;
+ $vars->{'sortkey'} = $sortkey;
+ $vars->{'type'} = $type;
+ $vars->{'custom'} = 1;
+ $vars->{'in_new_bugmail'} = $cgi->param('new_bugmail') ? 1 : 0;
+ $vars->{'editable_on_enter_bug'} = $cgi->param('enter_bug') ? 1 : 0;
+ $vars->{'is_obsolete'} = $cgi->param('obsolete') ? 1 : 0;
+
+ Bugzilla::Field::create_or_update($vars);
+
+ $vars->{'custom_fields'} = [Bugzilla->get_fields({'custom' => 1})];
+
+ $template->process('admin/custom_fields/list.html.tmpl', $vars)
+ || ThrowTemplateError($template->error());
+}
+elsif ($action eq 'edit') {
+ my $name = $cgi->param('name') || ThrowUserError('customfield_missing_name');
+ trick_taint($name);
+ my @field = Bugzilla->get_fields({'name' => $name, 'custom' => 1});
+ scalar(@field) || ThrowUserError('customfield_nonexistent', {'name' => $name});
+
+ $vars->{'field'} = $field[0];
+
+ $template->process('admin/custom_fields/edit.html.tmpl', $vars)
+ || ThrowTemplateError($template->error());
+}
+elsif ($action eq 'update') {
+ die "not yet implemented...\n";
+}
+elsif ($action eq 'del') {
+ die "not yet implemented...\n";
+}
+elsif ($action eq 'delete') {
+ die "not yet implemented...\n";
+}
+else {
+ ThrowUserError('no_valid_action', {'field' => 'custom_field'});
+}
diff --git a/template/en/default/admin/custom_fields/create.html.tmpl b/template/en/default/admin/custom_fields/create.html.tmpl
new file mode 100644
index 000000000..b366371bd
--- /dev/null
+++ b/template/en/default/admin/custom_fields/create.html.tmpl
@@ -0,0 +1,111 @@
+[%# 1.0@bugzilla.org %]
+[%# The contents of this file are subject to the Mozilla Public
+ # License Version 1.1 (the "License"); you may not use this file
+ # except in compliance with the License. You may obtain a copy of
+ # the License at http://www.mozilla.org/MPL/
+ #
+ # Software distributed under the License is distributed on an "AS
+ # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ # implied. See the License for the specific language governing
+ # rights and limitations under the License.
+ #
+ # The Original Code is the Bugzilla Bug Tracking System.
+ #
+ # Contributor(s): Frédéric Buclin <LpSolit@gmail.com>
+ #%]
+
+[%# INTERFACE:
+ # none
+ #%]
+
+[% PROCESS "global/field-descs.none.tmpl" %]
+
+[% PROCESS global/header.html.tmpl
+ title = "Add a new Custom Field"
+ onload = "document.getElementById('new_bugmail').disabled = true;" %]
+
+<script type="text/javascript">
+ <!--
+ // Disable a checkbox based on the state of another one.
+ function toggleCheckbox(this_checkbox, other_checkbox_id) {
+ var other_checkbox = document.getElementById(other_checkbox_id);
+ other_checkbox.disabled = !this_checkbox.checked;
+ }
+ //-->
+</script>
+
+<p>
+ Adding custom fields can make the interface of [% terms.Bugzilla %] very
+ complicated. Many admins who are new to [% terms.Bugzilla %] start off
+ adding many custom fields, and then their users complain that the interface
+ is "too complex". Please think carefully before adding any custom fields.
+ It may be the case that [% terms.Bugzilla %] already does what you need,
+ and you just haven't enabled the correct feature yet.
+
+ <ul>
+ <li>Custom field names must begin with "cf_" to distinguish them from standard
+ fields. If you omit "cf_" from the name, it will automatically be appended.</li>
+ <li>Descriptions are a very short string describing the field and will be used
+ as the label for this field in the user interface.</li>
+ </ul>
+ <br>
+</p>
+
+<form id="add_field" action="editfields.cgi" method="GET">
+ <table border="0" cellspacing="0" cellpadding="5">
+ <tr>
+ <th align="right"><label for="name">Name:</label></th>
+ <td>
+ <input type="text" id="name" name="name" value="cf_" size="40" maxlength="64">
+ </td>
+
+ <th align="right">
+ <label for="enter_bug">Can be set on [% terms.bug %] creation:</label>
+ </th>
+ <td>
+ <input type="checkbox" id="enter_bug" name="enter_bug" value="1"
+ onchange="toggleCheckbox(this, 'new_bugmail');">
+ </td>
+ </tr>
+ <tr>
+ <th align="right"><label for="desc">Description:</label></th>
+ <td><input type="text" id="desc" name="desc" value="" size="40"></td>
+
+ <th align="right">
+ <label for="new_bugmail">Displayed in bugmail for new [% terms.bugs %]:</label>
+ </th>
+ <td><input type="checkbox" id="new_bugmail" name="new_bugmail" value="1"></td>
+ </tr>
+ <tr>
+ <th align="right"><label for="type">Type:</label></th>
+ <td>
+ [%# Only one field type is valid right now. But let's prepare the UI
+ # for future new types. %]
+ <select id="type" name="type">
+ <option value="FIELD_TYPE_FREETEXT">Free Text</option>
+ </select>
+ </td>
+
+ <th align="right"><label for="obsolete">Is obsolete:</label></th>
+ <td><input type="checkbox" id="obsolete" name="obsolete" value="1"></td>
+ </tr>
+ <tr>
+ <th align="right"><label for="sortkey">Sortkey:</label></th>
+ <td>
+ <input type="text" id="sortkey" name="sortkey" value="0" size="6" maxlength="6">
+ </td>
+
+ <th>&nbsp;</th>
+ <td>&nbsp;</td>
+ </tr>
+ </table>
+ <br>
+ <input type="hidden" name="action" value="new">
+ <input type="submit" id="create" value="Create">
+</form>
+
+<p>
+ <a href="editfields.cgi">Back to the list of existing custom fields</a>
+</p>
+
+[% PROCESS global/footer.html.tmpl %]
diff --git a/template/en/default/admin/custom_fields/edit.html.tmpl b/template/en/default/admin/custom_fields/edit.html.tmpl
new file mode 100644
index 000000000..cb7b56a0a
--- /dev/null
+++ b/template/en/default/admin/custom_fields/edit.html.tmpl
@@ -0,0 +1,99 @@
+[%# 1.0@bugzilla.org %]
+[%# The contents of this file are subject to the Mozilla Public
+ # License Version 1.1 (the "License"); you may not use this file
+ # except in compliance with the License. You may obtain a copy of
+ # the License at http://www.mozilla.org/MPL/
+ #
+ # Software distributed under the License is distributed on an "AS
+ # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ # implied. See the License for the specific language governing
+ # rights and limitations under the License.
+ #
+ # The Original Code is the Bugzilla Bug Tracking System.
+ #
+ # Contributor(s): Frédéric Buclin <LpSolit@gmail.com>
+ #%]
+
+[%# INTERFACE:
+ # none
+ #%]
+
+[% PROCESS "global/field-descs.none.tmpl" %]
+
+[% title = BLOCK %]
+ Edit the Custom Field '[% field.name FILTER html %]' ([% field.description FILTER html %])
+[% END %]
+
+[% PROCESS global/header.html.tmpl
+ title = title
+ onload = "toggleCheckbox(document.getElementById('enter_bug'), 'new_bugmail');" %]
+
+<script type="text/javascript">
+ <!--
+ // Disable a checkbox based on the state of another one.
+ function toggleCheckbox(this_checkbox, other_checkbox_id) {
+ var other_checkbox = document.getElementById(other_checkbox_id);
+ other_checkbox.disabled = !this_checkbox.checked;
+ }
+ //-->
+</script>
+
+<p>
+ Descriptions are a very short string describing the field and will be used as
+ the label for this field in the user interface.
+</p>
+
+<form id="edit_field" action="editfields.cgi" method="GET">
+ <table border="0" cellspacing="0" cellpadding="5">
+ <tr>
+ <th align="right">Name:</th>
+ <td>[% field.name FILTER html %]</td>
+
+ <th align="right">
+ <label for="enter_bug">Can be set on [% terms.bug %] creation:</label>
+ </th>
+ <td><input type="checkbox" id="enter_bug" name="enter_bug" value="1"
+ [%- " checked" IF field.enter_bug %]
+ onchange="toggleCheckbox(this, 'new_bugmail');"></td>
+ </tr>
+ <tr>
+ <th align="right"><label for="desc">Description:</label></th>
+ <td><input type="text" id="desc" name="desc" size="40"
+ value="[% field.description FILTER html %]"></td>
+
+ <th align="right">
+ <label for="new_bugmail">Displayed in bugmail for new [% terms.bugs %]:</label>
+ </th>
+ <td><input type="checkbox" id="new_bugmail" name="new_bugmail" value="1"
+ [%- " checked" IF field.mailhead %]></td>
+ </tr>
+ <tr>
+ <th align="right">Type:</th>
+ <td>Free Text</td>
+
+ <th align="right"><label for="obsolete">Is obsolete:</label></th>
+ <td><input type="checkbox" id="obsolete" name="obsolete" value="1"
+ [%- " checked" IF field.obsolete %]></td>
+ </tr>
+ <tr>
+ <th align="right"><label for="sortkey">Sortkey:</label></th>
+ <td>
+ <input type="text" id="sortkey" name="sortkey" size="6" maxlength="6"
+ value="[% field.sortkey FILTER html %]">
+ </td>
+
+ <th>&nbsp;</th>
+ <td>&nbsp;</td>
+ </tr>
+ </table>
+ <br>
+ <input type="hidden" name="action" value="update">
+ <input type="hidden" name="name" value="[% field.name FILTER html %]">
+ <input type="submit" id="edit" value="Submit" disabled="disabled">
+</form>
+
+<p>
+ <a href="editfields.cgi">Back to the list of existing custom fields</a>
+</p>
+
+[% PROCESS global/footer.html.tmpl %]
diff --git a/template/en/default/admin/custom_fields/list.html.tmpl b/template/en/default/admin/custom_fields/list.html.tmpl
new file mode 100644
index 000000000..e02609dd3
--- /dev/null
+++ b/template/en/default/admin/custom_fields/list.html.tmpl
@@ -0,0 +1,63 @@
+[%# 1.0@bugzilla.org %]
+[%# The contents of this file are subject to the Mozilla Public
+ # License Version 1.1 (the "License"); you may not use this file
+ # except in compliance with the License. You may obtain a copy of
+ # the License at http://www.mozilla.org/MPL/
+ #
+ # Software distributed under the License is distributed on an "AS
+ # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ # implied. See the License for the specific language governing
+ # rights and limitations under the License.
+ #
+ # The Original Code is the Bugzilla Bug Tracking System.
+ #
+ # Contributor(s): Frédéric Buclin <LpSolit@gmail.com>
+ #%]
+
+[%# INTERFACE:
+ # custom_fields: a list of Bugzilla::Field objects, representing custom fields.
+ #%]
+
+[% PROCESS "global/field-descs.none.tmpl" %]
+
+[% PROCESS global/header.html.tmpl title = "Custom Fields" %]
+
+[% columns = [
+ {
+ name => "name"
+ heading => "Edit custom field..."
+ contentlink => "editfields.cgi?action=edit&amp;name=%%name%%"
+ },
+ {
+ name => "description"
+ heading => "Description"
+ },
+ {
+ name => "sortkey"
+ heading => "Sortkey"
+ },
+ {
+ name => "enter_bug"
+ heading => "Editable on Bug Creation"
+ },
+ {
+ name => "mailhead"
+ heading => "In Bugmail on Bug Creation"
+ },
+ {
+ name => "obsolete"
+ heading => "Is Obsolete"
+ }
+ ]
+%]
+
+[% PROCESS admin/table.html.tmpl
+ columns = columns
+ data = custom_fields
+%]
+
+<p>
+ <a href="editfields.cgi?action=add">Add a new custom field</a>
+</p>
+
+[% PROCESS global/footer.html.tmpl %]
diff --git a/template/en/default/global/user-error.html.tmpl b/template/en/default/global/user-error.html.tmpl
index e67c1a81c..e07be8846 100644
--- a/template/en/default/global/user-error.html.tmpl
+++ b/template/en/default/global/user-error.html.tmpl
@@ -158,6 +158,8 @@
classifications
[% ELSIF object == "components" %]
components
+ [% ELSIF object == "custom_fields" %]
+ custom fields
[% ELSIF object == "flagtypes" %]
flag types
[% ELSIF object == "group_access" %]
@@ -307,9 +309,27 @@
Product [% product FILTER html %] does not have a component
named [% name FILTER html %].
- [% ELSIF error == "product_doesnt_exist" %]
- [% title = "Specified Product Does Not Exist" %]
- The product '[% product FILTER html %]' does not exist.
+ [% ELSIF error == "customfield_already_exists" %]
+ [% title = "Field Already Exists" %]
+ The field '[% field.name FILTER html %]' ([% field.description FILTER html %])
+ already exists. Please choose another name.
+
+ [% ELSIF error == "customfield_nonexistent" %]
+ [% title = "Unknown Custom Field" %]
+ There is no custom field with the name '[% name FILTER html %]'.
+
+ [% ELSIF error == "customfield_invalid_sortkey" %]
+ [% title = "Invalid Sortkey for Field" %]
+ The sortkey [% sortkey FILTER html %] that you have provided for
+ the '[% name FILTER html %]' field is not a valid positive integer.
+
+ [% ELSIF error == "customfield_missing_description" %]
+ [% title = "Missing Description for Field" %]
+ You must enter a description for the '[% name FILTER html %]' field.
+
+ [% ELSIF error == "customfield_missing_name" %]
+ [% title = "Missing Name for Field" %]
+ You must enter a name for this field.
[% ELSIF error == "dependency_loop_multi" %]
[% title = "Dependency Loop Detected" %]
@@ -1086,6 +1106,10 @@
Patches cannot be more than [% Param('maxpatchsize') %] KB in size.
Try breaking your patch into several pieces.
+ [% ELSIF error == "product_doesnt_exist" %]
+ [% title = "Specified Product Does Not Exist" %]
+ The product '[% product FILTER html %]' does not exist.
+
[% ELSIF error == "product_votes_per_bug_must_be_nonnegative" %]
[% title = "Maximum Votes Must Be Non-negative" %]
[% admindocslinks = {'voting.html' => 'Setting up the voting feature'} %]