summaryrefslogtreecommitdiff
path: root/rt/share/html/Admin/Tools
diff options
context:
space:
mode:
Diffstat (limited to 'rt/share/html/Admin/Tools')
-rw-r--r--rt/share/html/Admin/Tools/Configuration.html95
-rw-r--r--rt/share/html/Admin/Tools/Queries.html2
-rw-r--r--rt/share/html/Admin/Tools/Shredder/Elements/ObjectCheckBox4
-rw-r--r--rt/share/html/Admin/Tools/Shredder/Elements/PluginHelp4
-rw-r--r--rt/share/html/Admin/Tools/Shredder/autohandler4
-rw-r--r--rt/share/html/Admin/Tools/Theme.html219
-rw-r--r--rt/share/html/Admin/Tools/index.html2
7 files changed, 240 insertions, 90 deletions
diff --git a/rt/share/html/Admin/Tools/Configuration.html b/rt/share/html/Admin/Tools/Configuration.html
index f60cdba6f..fea3a5fcc 100644
--- a/rt/share/html/Admin/Tools/Configuration.html
+++ b/rt/share/html/Admin/Tools/Configuration.html
@@ -87,7 +87,7 @@ foreach my $key ( RT->Config->Options( Overridable => undef, Sorted => 0 ) ) {
<tr class="<% $index_conf%2 ? 'oddline' : 'evenline'%>">
<td class="collection-as-table"><% $key %></td>
<td class="collection-as-table">
-% if ( $key =~ /Password(?!Length)/i ) {
+% if ( $key =~ /Password/i and $key !~ /MinimumPasswordLength|AllowLoginPasswordAutoComplete/ ) {
<em><% loc('Password not printed' ) %></em>\
% } else {
<% stringify($val) |n %>\
@@ -150,6 +150,7 @@ for my $type (qw/Tickets Queues Transactions Groups PrivilegedUsers Unprivileged
$class =~ s/Privileged|Unprivileged//;
my $collection = $class->new(RT->SystemUser);
$collection->UnLimit;
+ $collection->FindAllRows; # find disabled
if ($type =~ /PrivilegedUsers/) {
$user_count = $collection->CountAll;
$collection->LimitToPrivileged;
@@ -179,6 +180,15 @@ for my $type (qw/Tickets Queues Transactions Groups PrivilegedUsers Unprivileged
</ol>
</&>
+<&|/Widgets/TitleBox, title => loc("Static file search order") &>
+<ol>
+% foreach my $path ( (map {$_->{root}} RT->Config->Get('StaticRoots')),
+% RT::Interface::Web->StaticRoots ) {
+<li><% $path %></li>
+% }
+</ol>
+</&>
+
<&|/Widgets/TitleBox, title => loc("Perl library search order") &>
<ol>
% foreach my $inc (@INC) {
@@ -187,6 +197,22 @@ for my $type (qw/Tickets Queues Transactions Groups PrivilegedUsers Unprivileged
</ol>
</&>
+<&|/Widgets/TitleBox, title=> loc("Loaded config files") &>
+<ol>
+% foreach my $config (RT->Config->LoadedConfigs) {
+% if ($config->{site}) {
+<li><strong><% $config->{filename} %></strong></li>
+% } else {
+<li><% $config->{filename} %></li>
+% }
+% }
+</ol>
+</&>
+
+<&|/Widgets/TitleBox, title=> loc("Logging summary") &>
+ <& /Admin/Elements/LoggingSummary &>
+</&>
+
</td>
</table>
@@ -199,6 +225,7 @@ for my $type (qw/Tickets Queues Transactions Groups PrivilegedUsers Unprivileged
% my $attrs = $RT::System->Attributes;
% my $index_size = 0;
% while ( my $attr = $attrs->Next ) {
+% next if $attr->Name eq 'UpgradeHistory';
<tr class="<% $index_size%2 ? 'oddline' : 'evenline'%>">
% if ($attr->Name eq 'UserLogo') {
% my $content = $attr->Content;
@@ -249,6 +276,10 @@ if ($item =~ /^\s*(.*?)\s*v(\S+);/) {
</table>
</&>
+<&|/Widgets/TitleBox, title => loc("RT upgrade history")&>
+<& /Admin/Elements/UpgradeHistory &>
+</&>
+
<&|/Widgets/TitleBox, title => loc("Perl configuration") &>
% require Config;
<pre>
@@ -256,6 +287,66 @@ if ($item =~ /^\s*(.*?)\s*v(\S+);/) {
</pre>
</&>
+<&|/Widgets/TitleBox, title=> loc("Environment variables") &>
+<table border="0" cellspacing="0" cellpadding="5" width="100%" class="collection">
+<tr class="collection-as-table">
+<th class="collection-as-table"><&|/l&>Variable</&></th>
+<th class="collection-as-table"><&|/l&>Value</&></th>
+</tr>
+% my $row = 0;
+% for my $key (sort keys %ENV) {
+<tr class="collection-as-table <% $row++ %2 ? 'oddline' : 'evenline'%>">
+<td class="collection-as-table"><% $key %></td>
+<td class="collection-as-table"><% $ENV{$key} %></td>
+</tr>
+% }
+</table>
+</&>
+
+<&|/Widgets/TitleBox, title => loc("Operating System") &>
+<table border="0" cellspacing="0" cellpadding="5" width="100%" class="collection">
+<tr class="collection-as-table evenline">
+<td class="collection-as-table">Deployment type</td>
+<td class="collection-as-table"><%
+ $INC{'mod_perl.pm'} ? "mod_perl" :
+ $INC{'FCGI.pm'} ? "fastcgi" :
+ "standalone" %>
+</td>
+</tr>
+<%perl>
+my @os = (
+ "Distribution" => 'lsb_release --all',
+ "uname -a" => 'uname -a',
+ "SELinux status" => 'getenforce',
+ "Apache" => [map { "$_ -V" } qw(apache2ctl apachectl httpdctl)],
+ "nginx" => 'nginx -V 2>&1',
+ "lighttpd" => 'lighttpd -V',
+);
+my @os_info;
+
+while (my ($name, $cmd) = splice @os, 0, 2) {
+ $cmd = [$cmd] unless ref $cmd eq 'ARRAY';
+ for my $run (@$cmd) {
+ $run .= " </dev/null";
+ $run .= " 2>/dev/null" unless $run =~ /2>/;
+ my $result = `$run`;
+ if (defined $result and $result =~ /\S/) {
+ push @os_info, $name => $result;
+ last;
+ }
+ }
+}
+my $row = 1;
+</%perl>
+% while (my ($name, $output) = splice @os_info, 0, 2) {
+<tr class="collection-as-table <% $row++ % 2 ? "oddline" : "evenline" %>">
+<td class="collection-as-table"><% $name %></td>
+<td class="collection-as-table" style="white-space: pre-wrap; font-family: monospace"><% $output %></td>
+</tr>
+% }
+</table>
+</&>
+
<%INIT>
use Data::Dumper;
local $Data::Dumper::Terse = 1;
@@ -264,7 +355,7 @@ local $Data::Dumper::Indent = 2;
sub stringify {
my $value = shift;
my $output = Dumper $value;
- RT::Interface::Web::EscapeUTF8(\$output);
+ RT::Interface::Web::EscapeHTML(\$output);
$output =~ s/ /&nbsp;/g;
$output =~ s!\n!<br />!g;
return $output;
diff --git a/rt/share/html/Admin/Tools/Queries.html b/rt/share/html/Admin/Tools/Queries.html
index 23025ec4b..66427dedf 100644
--- a/rt/share/html/Admin/Tools/Queries.html
+++ b/rt/share/html/Admin/Tools/Queries.html
@@ -53,7 +53,7 @@ unless ($session{'CurrentUser'}->HasRight( Object=> $RT::System, Right => 'Super
</%init>
<& /Admin/Elements/Header, Title => $title &>
<& /Elements/Tabs &>
-<script type="text/javascript" src="<%RT->Config->Get('WebPath')%>/NoAuth/js/jquery.tablesorter.min.js"></script>
+<script type="text/javascript" src="<%RT->Config->Get('WebPath')%>/static/js/jquery.tablesorter.min.js"></script>
<&|/Widgets/TitleBox, title => loc('SQL Queries') &>
% my $history = $RT::Handle->QueryHistory;
diff --git a/rt/share/html/Admin/Tools/Shredder/Elements/ObjectCheckBox b/rt/share/html/Admin/Tools/Shredder/Elements/ObjectCheckBox
index 757e10658..e333d0779 100644
--- a/rt/share/html/Admin/Tools/Shredder/Elements/ObjectCheckBox
+++ b/rt/share/html/Admin/Tools/Shredder/Elements/ObjectCheckBox
@@ -48,12 +48,12 @@
<%ARGS>
$Object => undef
</%ARGS>
-<input type="checkbox" name="WipeoutObject" value="<% $Object->_AsString %>" />
+<input type="checkbox" name="WipeoutObject" value="<% $Object->UID %>" />
<span>
% if( $m->comp_exists( $path ) ) {
% $m->comp( $path, Object => $Object );
% } else {
-<% $Object->_AsString %>
+<% $Object->UID %>
% }
</span><br />
<%ONCE>
diff --git a/rt/share/html/Admin/Tools/Shredder/Elements/PluginHelp b/rt/share/html/Admin/Tools/Shredder/Elements/PluginHelp
index bf37a890a..cc082767a 100644
--- a/rt/share/html/Admin/Tools/Shredder/Elements/PluginHelp
+++ b/rt/share/html/Admin/Tools/Shredder/Elements/PluginHelp
@@ -59,8 +59,8 @@ my %plugins = $plugin_obj->List;
<%INIT>
my $file = $plugins{ $Plugin };
unless( $file ) {
- $RT::Logger->error( "Couldn't find plugin '$Plugin'" );
- return;
+ $RT::Logger->error( "Couldn't find plugin '$Plugin'" );
+ return;
}
use RT::Shredder::POD qw();
diff --git a/rt/share/html/Admin/Tools/Shredder/autohandler b/rt/share/html/Admin/Tools/Shredder/autohandler
index 62909b0c3..9a5ecd106 100644
--- a/rt/share/html/Admin/Tools/Shredder/autohandler
+++ b/rt/share/html/Admin/Tools/Shredder/autohandler
@@ -47,13 +47,13 @@
%# END BPS TAGGED BLOCK }}}
<%INIT>
unless( $session{'CurrentUser'}->HasRight( Right => 'SuperUser', Object => $RT::System ) ) {
- return $m->comp( 'Elements/Error/NoRights' );
+ return $m->comp( 'Elements/Error/NoRights' );
}
use RT::Shredder ();
my $path = RT::Shredder->StoragePath;
unless( -d $path && -w _ ) {
- return $m->comp( 'Elements/Error/NoStorage', Path => $path );
+ return $m->comp( 'Elements/Error/NoStorage', Path => $path );
}
$m->call_next(%ARGS);
diff --git a/rt/share/html/Admin/Tools/Theme.html b/rt/share/html/Admin/Tools/Theme.html
index 83f88a98b..3a0c71b35 100644
--- a/rt/share/html/Admin/Tools/Theme.html
+++ b/rt/share/html/Admin/Tools/Theme.html
@@ -51,7 +51,7 @@
<& /Elements/Tabs &>
<& /Elements/ListActions, actions => \@results &>
-<script type="text/javascript" src="<%RT->Config->Get('WebPath')%>/NoAuth/js/farbtastic.js"></script>
+<script type="text/javascript" src="<%RT->Config->Get('WebPath')%>/static/js/farbtastic.js"></script>
<div id="simple-customize">
<div id="upload-logo">
@@ -61,26 +61,31 @@
<label for="logo-upload"><&|/l&>Upload a new logo</&>:</label>
<input type="file" name="logo-upload" id="logo-upload" /><br />
<div class="gd-support">
-% if (%gd_can) {
+% if ($valid_image_types) {
<&|/l, $valid_image_types &>Your system supports automatic color suggestions for: [_1]</&>
% } else {
<&|/l&>GD is disabled or not installed. You can upload an image, but you won't get automatic color suggestions.</&>
% }
</div>
- <input name="reset_logo" value="Reset to default RT Logo" type="submit" />
- <input type="submit" value="Upload" />
+ <input name="reset_logo" value="<&|/l&>Reset to default RT Logo</&>" type="submit" />
+ <input type="submit" value="<&|/l&>Upload</&>" />
</form>
</div>
<div id="customize-theme">
- <h2>Customize the RT theme</h2>
+ <h2><&|/l&>Customize the RT theme</&></h2>
<ol>
<li>
<label for="section"><&|/l&>Select a section</&>:</label>
<select id="section"></select>
</li>
<li>
- <div class="description"><&|/l&>Select a color for the section</&>:</div>
+ <div class="description">
+ <&|/l&>Select a color for the section</&>:
+ <div id="logo-picker-hint" style="display: none;">
+ <&|/l&>You can also click on the logo above to get colors!</&>
+ </div>
+ </div>
% if ($colors) {
<div class="primary-colors">
% for (@$colors) {
@@ -93,27 +98,29 @@
</div>
% }
<div id="color-picker"></div>
+ <canvas id="logo-color-picker" title="<&|/l&>Click to choose a color</&>"></canvas>
</li>
</ol>
</div>
</div>
<div id="custom-css">
- <h2>Custom CSS (Advanced)</h2>
-
+ <h2><&|/l&>Custom CSS (Advanced)</&></h2>
+
<form method="POST">
<textarea rows=20 id="user_css" name="user_css" wrap="off"><% $user_css %></textarea><br />
- <input id="try" type="button" class="button" value="Try" />
- <input id="reset" type="reset" value="Reset" type="submit" />
- <input name="reset_css" value="Reset to default RT Theme" type="submit" />
- <input value="Save" type="submit" />
+ <input id="try" type="button" class="button" value="<&|/l&>Try</&>" />
+ <input id="reset" type="reset" value="<&|/l&>Reset</&>" type="submit" />
+ <input name="reset_css" value="<&|/l&>Reset to default RT Theme</&>" type="submit" />
+ <input value="<&|/l&>Save</&>" type="submit" />
</form>
</div>
<%ONCE>
my @sections = (
- ['Page' => ['body']],
- ['Header' => ['div#quickbar', 'body.aileron #main-navigation #app-nav > li, body.aileron #main-navigation #app-nav > li > a, #prefs-menu > li, #prefs-menu > li > a, #logo .rtname']],
+ ['Page' => ['body', 'div#body']],
+ ['Menu bar' => ['div#quickbar', '#main-navigation #app-nav.sf-shadow > li, #main-navigation #app-nav.sf-shadow > li > a, #prefs-menu > li, #prefs-menu > li > a, #logo .rtname']],
+ ['Title bar' => ['div#header']],
['Page title' => ['div#header h1']],
['Page content' => ['div#body']],
['Buttons' => ['input[type="reset"], input[type="submit"], input[class="button"]']],
@@ -173,7 +180,7 @@ jQuery(function($) {
newcss += "; border: none;"
/* Page title's text color is the selected color */
- if (applying[name].match(/#header/))
+ if (applying[name].match(/h1/))
newcss = "color: " + bg;
/* Nav doesn't need a background, but it wants text color */
@@ -193,7 +200,35 @@ jQuery(function($) {
change_color($(this).css('background-color'), $(this).css('color'));
});
-
+ // Setup the canvas color picker
+ $("#logo-theme-editor img").load(function() {
+ var logo = $(this);
+ var canvas = $("#logo-color-picker");
+ var el_canvas = canvas.get(0);
+
+ if (!el_canvas.getContext) return;
+
+ var context = el_canvas.getContext("2d");
+ el_canvas.width = logo.width();
+ el_canvas.height = logo.height();
+ context.drawImage(logo.get(0), 0, 0);
+
+ logo.hide().after(canvas);
+ canvas.show().click(function(ev) {
+ ev.preventDefault();
+ var R = 0,
+ G = 1,
+ B = 2,
+ A = 3;
+ var pixel = this.getContext("2d").getImageData(ev.offsetX, ev.offsetY, 1, 1).data;
+ // Farbtastic expects values in the range of 0..1
+ var rgba = $.makeArray(pixel).map(function(v,i) { return v / 255 });
+ var wheel = $.farbtastic("#color-picker");
+ wheel.setHSL( wheel.RGBToHSL( rgba.slice(R,A) ) );
+ // XXX TODO factor in the alpha channel too
+ });
+ $('#logo-picker-hint').show();
+ });
});
</script>
<%INIT>
@@ -207,14 +242,82 @@ my $text_threshold = 0.6;
my @results;
my $imgdata;
+my $colors;
+my $valid_image_types;
+if (not RT->Config->Get('DisableGD') and Convert::Color->require) {
+ require GD;
+
+ # Always find out what GD can read...
+ my %gd_can;
+ for my $type (qw(Png Jpeg Gif)) {
+ $gd_can{$type}++ if GD::Image->can("newFrom${type}Data");
+ }
+ $valid_image_types = join(", ", map { uc } sort { lc $a cmp lc $b } keys %gd_can);
+}
+
+my $analyze_img = sub {
+ return undef unless $valid_image_types;
+
+ my $imgdata = shift;
+ return undef unless $imgdata;
+
+ # ...but only analyze the image if we have data
+ my $img = GD::Image->new($imgdata);
+ unless ($img) {
+ # This has to be one damn long line because the loc() needs to be
+ # source parsed correctly.
+ push @results, loc("Automatically suggested theme colors aren't available for your image. This might be because you uploaded an image type that your installed version of GD doesn't support. Supported types are: [_1]. You can recompile libgd and GD.pm to include support for other image types.", $valid_image_types);
+ return undef;
+ }
+
+ my %colors;
+
+ my @wsamples;
+ my @hsamples;
+ if ($img->width > 200) {
+ @wsamples = map { int($img->width*($_/200)) } (0..199);
+ } else {
+ @wsamples = ( 0 .. $img->width - 1 );
+ }
+ if ($img->height > 200) {
+ @hsamples = map { int($img->height*($_/200)) } (0..199);
+ } else {
+ @hsamples = ( 0 .. $img->height - 1 );
+ }
+ for my $i (@wsamples) {
+ for my $j (@hsamples) {
+ my @color = $img->rgb( $img->getPixel($i,$j) );
+ my $hsl = Convert::Color->new('rgb:'.join(',',map { $_ / 255 } @color))->convert_to('hsl');
+ my $c = join(',',@color);
+ next if $hsl->lightness < 0.1;
+ $colors{$c} ||= { h => $hsl->hue, s => $hsl->saturation, l => $hsl->lightness, cnt => 0, c => $c};
+ $colors{$c}->{cnt}++;
+ }
+ }
+
+ for (values %colors) {
+ $_->{rank} = $_->{s} * $_->{cnt};
+ }
+ my @top5 = grep { defined and $_->{'l'} and $_->{'c'} }
+ (sort { $b->{rank} <=> $a->{rank} } values %colors)[0..5];
+ return \@top5;
+};
+
if (my $file_hash = _UploadedFile( 'logo-upload' )) {
- my ($id, $msg) = RT->System->SetAttribute( Name => "UserLogo",
- Description => "User-provided logo",
- Content => {
- type => $file_hash->{ContentType},
- data => $file_hash->{LargeContent},
- hash => md5_hex($file_hash->{LargeContent}),
- } );
+ $colors = $analyze_img->($file_hash->{LargeContent});
+
+ my $my_system = RT::System->new( $session{CurrentUser} );
+ my ( $id, $msg ) = $my_system->SetAttribute(
+ Name => "UserLogo",
+ Description => "User-provided logo",
+ Content => {
+ type => $file_hash->{ContentType},
+ data => $file_hash->{LargeContent},
+ hash => md5_hex($file_hash->{LargeContent}),
+ colors => $colors,
+ },
+ );
+
push @results, loc("Unable to set UserLogo: [_1]", $msg) unless $id;
$imgdata = $file_hash->{LargeContent};
@@ -227,6 +330,19 @@ else {
my $content = $attr->Content;
if (ref($content) eq 'HASH') {
$imgdata = $content->{data};
+ $colors = $content->{colors};
+ unless ($colors) {
+ # No colors cached; attempt to generate them
+ $colors = $content->{colors} = $analyze_img->($content->{data});
+ if ($content->{colors}) {
+ # Found colors; update the attribute
+ RT->System->SetAttribute(
+ Name => "UserLogo",
+ Description => "User-provided logo",
+ Content => $content,
+ );
+ }
+ }
}
else {
RT->System->DeleteAttribute('UserLogo');
@@ -256,63 +372,6 @@ if (!$user_css) {
} @sections
);
}
-
-# XXX: move this to some other modules
-
-use List::MoreUtils qw(uniq);
-
-my $has_color_analyzer = eval { require Convert::Color; 1 };
-my $colors;
-my %gd_can;
-my $valid_image_types;
-
-if (not RT->Config->Get('DisableGD') and $has_color_analyzer) {
- require GD;
-
- # Always find out what GD can read...
- for my $type (qw(Png Jpeg Gif)) {
- $gd_can{$type}++ if GD::Image->can("newFrom${type}Data");
- }
- $valid_image_types = join(", ", map { uc } sort { lc $a cmp lc $b } keys %gd_can);
-
- # ...but only analyze the image if we have data
- if ($imgdata) {
- if ( my $img = GD::Image->new($imgdata) ) {
- $colors = analyze_img($img);
- }
- else {
- # This has to be one damn long line because the loc() needs to be
- # source parsed correctly.
- push @results, loc("Automatically suggested theme colors aren't available for your image. This might be because you uploaded an image type that your installed version of GD doesn't support. Supported types are: [_1]. You can recompile libgd and GD.pm to include support for other image types.", $valid_image_types);
- }
- }
-}
-
-sub analyze_img {
- my $img = shift;
- my $color;
-
- for my $i (0..$img->width-1) {
- for my $j (0..$img->height-1) {
- my @color = $img->rgb( $img->getPixel($i,$j) );
- my $hsl = Convert::Color->new('rgb:'.join(',',map { $_ / 255 } @color))->convert_to('hsl');
- my $c = join(',',@color);
- next if $hsl->lightness < 0.1;
- $color->{$c} ||= { h => $hsl->hue, s => $hsl->saturation, l => $hsl->lightness, cnt => 0, c => $c};
- $color->{$c}->{cnt}++;
- }
- }
-
- for (values %$color) {
- $_->{rank} = $_->{s} * $_->{cnt};
- }
- my @top5 = grep { defined and $_->{'l'} and $_->{'c'} }
- (sort { $b->{rank} <=> $a->{rank} } values %$color)[0..5];
- if ((scalar uniq map {$_->{rank}} @top5) == 1) {
- $RT::Logger->info("Only one color found in logo image");
- }
- return \@top5;
-}
</%INIT>
<%ARGS>
$user_css => ''
diff --git a/rt/share/html/Admin/Tools/index.html b/rt/share/html/Admin/Tools/index.html
index 891fe000a..b80ed0a32 100644
--- a/rt/share/html/Admin/Tools/index.html
+++ b/rt/share/html/Admin/Tools/index.html
@@ -47,4 +47,4 @@
%# END BPS TAGGED BLOCK }}}
<& /Admin/Elements/Header, Title => loc('System Tools') &>
<& /Elements/Tabs &>
-<& /Elements/ListMenu, menu => Menu()->child('tools')->child('config')->child('tools') &>
+<& /Elements/ListMenu, menu => Menu()->child('admin')->child('tools') &>