summaryrefslogtreecommitdiffstats
path: root/Bugzilla/BugUrl.pm
diff options
context:
space:
mode:
authorTiago Mello <timello@gmail.com>2010-12-20 23:49:10 +0100
committerTiago Mello <timello@gmail.com>2010-12-20 23:49:10 +0100
commited3e015a1c21061ed9f30cfc3fe3c3e83c0d2fb1 (patch)
tree16a3b61e4fd8f04479bcbe02c8ed4d367b97e9f4 /Bugzilla/BugUrl.pm
parentc9c81ee7156fc47d834317644baa25cec7cf16e4 (diff)
downloadbugzilla-ed3e015a1c21061ed9f30cfc3fe3c3e83c0d2fb1.tar.gz
bugzilla-ed3e015a1c21061ed9f30cfc3fe3c3e83c0d2fb1.tar.xz
Bug 593539: Refactor See Also to use separate modules for each type of URL
r/a=mkanat
Diffstat (limited to 'Bugzilla/BugUrl.pm')
-rw-r--r--Bugzilla/BugUrl.pm173
1 files changed, 173 insertions, 0 deletions
diff --git a/Bugzilla/BugUrl.pm b/Bugzilla/BugUrl.pm
new file mode 100644
index 000000000..521ee8193
--- /dev/null
+++ b/Bugzilla/BugUrl.pm
@@ -0,0 +1,173 @@
+# -*- 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 Tiago Mello
+# Portions created by Tiago Mello are Copyright (C) 2010
+# Tiago Mello. All Rights Reserved.
+#
+# Contributor(s): Tiago Mello <timello@linux.vnet.ibm.com>
+
+package Bugzilla::BugUrl;
+use strict;
+use base qw(Bugzilla::Object);
+
+use Bugzilla::Util;
+use Bugzilla::Error;
+use Bugzilla::Constants;
+
+use URI::QueryParam;
+
+###############################
+#### Initialization ####
+###############################
+
+use constant DB_TABLE => 'bug_see_also';
+use constant NAME_FIELD => 'value';
+use constant LIST_ORDER => 'id';
+
+use constant DB_COLUMNS => qw(
+ id
+ bug_id
+ value
+);
+
+# This must be strings with the names of the validations,
+# instead of coderefs, because subclasses override these
+# validators with their own.
+use constant VALIDATORS => {
+ value => '_check_value',
+ bug_id => '_check_bug_id',
+};
+
+# This is the order we go through all of subclasses and
+# pick the first one that should handle the url. New
+# subclasses should be added at the end of the list.
+use constant SUB_CLASSES => qw(
+ Bugzilla::BugUrl::Bugzilla::Local
+ Bugzilla::BugUrl::Bugzilla
+ Bugzilla::BugUrl::Launchpad
+ Bugzilla::BugUrl::Google
+ Bugzilla::BugUrl::Debian
+);
+
+###############################
+#### Methods ####
+###############################
+
+sub new {
+ my $class = shift;
+ my $param = shift;
+
+ if (ref $param) {
+ my $bug_id = $param->{bug_id};
+ my $name = $param->{name} || $param->{value};
+ if (!defined $bug_id) {
+ ThrowCodeError('bad_arg',
+ { argument => 'bug_id',
+ function => "${class}::new" });
+ }
+ if (!defined $name) {
+ ThrowCodeError('bad_arg',
+ { argument => 'name',
+ function => "${class}::new" });
+ }
+
+ my $condition = 'bug_id = ? AND value = ?';
+ my @values = ($bug_id, $name);
+ $param = { condition => $condition, values => \@values };
+ }
+
+ unshift @_, $param;
+ return $class->SUPER::new(@_);
+}
+
+# This is an abstract method. It must be overridden
+# in every subclass.
+sub should_handle {
+ my ($class, $input) = @_;
+ ThrowCodeError('unknown_method',
+ { method => "${class}::should_handle" });
+}
+
+sub class_for {
+ my ($class, $value) = @_;
+
+ my $uri = URI->new($value);
+ foreach my $subclass ($class->SUB_CLASSES) {
+ eval "use $subclass";
+ die $@ if $@;
+ return wantarray ? ($subclass, $uri) : $subclass
+ if $subclass->should_handle($uri);
+ }
+
+ ThrowUserError('bug_url_invalid', { url => $value,
+ reason => 'show_bug' });
+}
+
+sub _check_bug_id {
+ my ($class, $bug_id) = @_;
+
+ my $bug;
+ if (blessed $bug_id) {
+ # We got a bug object passed in, use it
+ $bug = $bug_id;
+ $bug->check_is_visible;
+ }
+ else {
+ # We got a bug id passed in, check it and get the bug object
+ $bug = Bugzilla::Bug->check({ id => $bug_id });
+ }
+
+ return $bug->id;
+}
+
+sub _check_value {
+ my ($class, $uri) = @_;
+
+ my $value = $uri->as_string;
+
+ if (!$value) {
+ ThrowCodeError('param_required',
+ { function => 'add_see_also', param => '$value' });
+ }
+
+ # We assume that the URL is an HTTP URL if there is no (something)://
+ # in front.
+ if (!$uri->scheme) {
+ # This works better than setting $uri->scheme('http'), because
+ # that creates URLs like "http:domain.com" and doesn't properly
+ # differentiate the path from the domain.
+ $uri = new URI("http://$value");
+ }
+ elsif ($uri->scheme ne 'http' && $uri->scheme ne 'https') {
+ ThrowUserError('bug_url_invalid', { url => $value, reason => 'http' });
+ }
+
+ # This stops the following edge cases from being accepted:
+ # * show_bug.cgi?id=1
+ # * /show_bug.cgi?id=1
+ # * http:///show_bug.cgi?id=1
+ if (!$uri->authority or $uri->path !~ m{/}) {
+ ThrowUserError('bug_url_invalid',
+ { url => $value, reason => 'path_only' });
+ }
+
+ if (length($uri->path) > MAX_BUG_URL_LENGTH) {
+ ThrowUserError('bug_url_too_long', { url => $uri->path });
+ }
+
+ return $uri;
+}
+
+1;