[Bps-public-commit] rt-extension-configindatabase branch, master, updated. 9be38f8918bde78970031804ce11fc475be7ec49
Shawn Moore
shawn at bestpractical.com
Tue Aug 15 14:15:20 EDT 2017
The branch, master has been updated
via 9be38f8918bde78970031804ce11fc475be7ec49 (commit)
via e83711e8463addeba72a735c4b50cbcf7739af04 (commit)
via 5497c1cdea5e36c393207d24a66658568343da03 (commit)
via 82a56476d9475b1af9ef74cbe6c670bf7ebcc9d9 (commit)
via 6f5895be1aafcc2c90a1429aee4391d53d6978ff (commit)
via f0eaaaf1b75b138445fe78cedb4cade78181dfdc (commit)
via fa58307632d0d71ea941a5370fd42a1ab1bd25fb (commit)
via 25af4e4c9d400294ffdaefdb55f7dbc05caa3097 (commit)
via 42e43cb6b96e1cff3c8fca7c6ff3a192077598e6 (commit)
via 55517aec32338028f8c275c641c6626c3f48d288 (commit)
via 90437d486a27f47c0459c8caa9a8de25f3218c9a (commit)
via a18af773bb37ecf65a2ce5a1ef177dbbae6279cd (commit)
via bdbf85e7121260f7d3bbdc33253794a4b2144e1b (commit)
via 9d2b78cddebf1f6c7ea827870bf76ba81a5da0ab (commit)
via 838528bf9d6c4c187cd5f1eecf5a8bccfa1218e3 (commit)
via f64166fdffa559b00f862a1fdf17ef58ed8a7aff (commit)
via ca93ea85b527663535d92212f15b6addaa60f0b8 (commit)
via 998139ad88b29e3d2a733c679e848b74c93c8f36 (commit)
via c43afee73951b658895c5183ab129cb3093d8a90 (commit)
via 63ddb4281564fc6faf7229518b49ef8c8040b35d (commit)
from 7cf16a8eaf7d8832a2eef8af5e6794f0422fc775 (commit)
Summary of changes:
html/Admin/Tools/EditConfig.html | 177 ++++++++++++++++++++++-------------
lib/RT/DatabaseSetting.pm | 58 ++++++++----
lib/RT/Extension/ConfigInDatabase.pm | 120 +++++++++++++++++++++---
static/css/config-in-database.css | 6 +-
4 files changed, 267 insertions(+), 94 deletions(-)
- Log -----------------------------------------------------------------
commit 63ddb4281564fc6faf7229518b49ef8c8040b35d
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Tue Aug 15 15:43:02 2017 +0000
Reorganize template for better flow
diff --git a/html/Admin/Tools/EditConfig.html b/html/Admin/Tools/EditConfig.html
index 6cfe68c..1f1120d 100644
--- a/html/Admin/Tools/EditConfig.html
+++ b/html/Admin/Tools/EditConfig.html
@@ -134,24 +134,33 @@ foreach my $key ( RT->Config->Options( Overridable => undef, Sorted => 0 ) ) {
my $doc_url = "https://docs.bestpractical.com/rt/$doc_version/RT_Config.html#$key";
+ my $widget = $meta->{'Widget'} || '/Widgets/Form/Code';
+ my $is_code = $widget eq '/Widgets/Form/Code';
+ my $is_password = ($key =~ /Password/i and $key !~ /MinimumPasswordLength|AllowLoginPasswordAutoComplete/ );
+ my $current_value = $is_code ? $val : $raw_value;
+ my $is_immutable = $meta->{Immutable}
+ || $meta->{Obfuscate}
+ || ($is_code && !$session{CurrentUser}->HasRight(Right => 'ExecuteCode', Object => RT->System));
+
+ my $args = $meta->{'WidgetArguments'} || {};
</%PERL>
<tr class="<% $index_conf%2 ? 'oddline' : 'evenline'%>">
<td class="collection-as-table"><a href="<% $doc_url %>" target="_blank"><% $key %></a></td>
<td class="collection-as-table">
+
% if ( $meta->{EditLink} ) {
<&|/l_unsafe, "<a href=\"$meta->{EditLink}\">", loc($meta->{EditLinkLabel}), "</a>" &>Visit [_1][_2][_3] to manage this setting</&>
-% } elsif ( $meta->{Immutable} || $meta->{Obfuscate} || ($key =~ /Password/i and $key !~ /MinimumPasswordLength|AllowLoginPasswordAutoComplete/ )) {
-% unless ($key =~ /Password/i and $key !~ /MinimumPasswordLength|AllowLoginPasswordAutoComplete/ ) {
-<input type="text" disabled width="80" value="<% $val %>"></input><br>
% }
+</ul>
+<br><em><% loc('Must modify in config file' ) %></em>
+% } elsif ( $is_password ) {
<em><% loc('Must modify in config file' ) %></em>
+% } elsif ( $is_immutable ) {
+% if ($widget eq '/Widgets/Form/MultilineString' || $widget eq '/Widgets/Form/Code') {
+<textarea disabled class="<% $is_code ? 'code' : '' %>" rows="6" cols="80"><% $current_value %></textarea>
% } else {
-% my $widget = $meta->{'Widget'} || '/Widgets/Form/Code';
-% my $args = $meta->{'WidgetArguments'} || {};
-% my $current_value = $widget eq '/Widgets/Form/Code' ? $val : $raw_value;
-
-% if ($widget eq '/Widgets/Form/Code' && !$session{CurrentUser}->HasRight(Right => 'ExecuteCode', Object => RT->System)) {
-<textarea disabled rows="6" cols="80"><% $val %></textarea>
+<input type="text" disabled width="80" value="<% $current_value %>"></input>
+% }
<br><em><% loc('Must modify in config file' ) %></em>
% } else {
<& $widget,
@@ -167,7 +176,6 @@ foreach my $key ( RT->Config->Options( Overridable => undef, Sorted => 0 ) ) {
&>
<textarea class="hidden" name="<% $key %>-Current"><% $current_value %></textarea>
% }
-% }
</td>
</tr>
% }
diff --git a/static/css/config-in-database.css b/static/css/config-in-database.css
index 623cac5..1af6435 100644
--- a/static/css/config-in-database.css
+++ b/static/css/config-in-database.css
@@ -9,7 +9,8 @@ body#comp-Admin-Tools-EditConfig input:disabled {
background-color: #EEE;
}
-body#comp-Admin-Tools-EditConfig .widget.code textarea {
+body#comp-Admin-Tools-EditConfig .widget.code textarea,
+body#comp-Admin-Tools-EditConfig textarea.code {
font-family: Consolas, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace;
}
commit c43afee73951b658895c5183ab129cb3093d8a90
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Tue Aug 15 15:43:19 2017 +0000
Flag even immutable options as integer, string, etc
diff --git a/lib/RT/Extension/ConfigInDatabase.pm b/lib/RT/Extension/ConfigInDatabase.pm
index 1cdaa5c..afc9eea 100644
--- a/lib/RT/Extension/ConfigInDatabase.pm
+++ b/lib/RT/Extension/ConfigInDatabase.pm
@@ -57,7 +57,10 @@ for (qw/AllowUserAutocompleteForUnprivileged AlwaysDownloadAttachments
HideOneTimeSuggestions LinkArticlesOnInclude
MessageBoxUseSystemContextMenu
- SelfServiceCorrespondenceOnly ShowSearchResultCount/) {
+ SelfServiceCorrespondenceOnly ShowSearchResultCount
+
+ DevelMode DisallowExecuteCode ExternalAuth
+ /) {
next if !$RT::Config::META{$_};
$RT::Config::META{$_}{Widget} = '/Widgets/Form/Boolean';
@@ -68,6 +71,7 @@ for (qw/AttachmentListCount AutoLogoff BcryptCost DefaultSummaryRows
ExternalStorageCutoffSize LogoImageHeight LogoImageWidth LogoutRefresh
MaxAttachmentSize MaxFulltextAttachmentSize MessageBoxRichTextHeight
MinimumPasswordLength MoreAboutRequestorGroupsLimit TicketsItemMapSize
+ DatabasePort
/) {
next if !$RT::Config::META{$_};
@@ -82,7 +86,10 @@ for (qw/CommentAddress CorrespondAddress DashboardAddress DashboardSubject
LogoLinkURL LogoURL MailCommand OwnerEmail
RedistributeAutoGeneratedMessages SendmailArguments
SendmailBounceArguments SendmailPath SetOutgoingMailFrom Timezone
- WebImagesURL
+ WebImagesURL DatabaseAdmin DatabaseHost DatabaseName
+ DatabaseRTHost DatabaseType DatabaseUser Organization RecordBaseClass
+ WebBaseURL WebDomain WebPath WebPort WebSessionClass WebURL
+ rtname
/) {
next if !$RT::Config::META{$_};
commit 998139ad88b29e3d2a733c679e848b74c93c8f36
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Tue Aug 15 15:57:35 2017 +0000
Add config name as a css class
diff --git a/html/Admin/Tools/EditConfig.html b/html/Admin/Tools/EditConfig.html
index 1f1120d..2970156 100644
--- a/html/Admin/Tools/EditConfig.html
+++ b/html/Admin/Tools/EditConfig.html
@@ -144,7 +144,7 @@ foreach my $key ( RT->Config->Options( Overridable => undef, Sorted => 0 ) ) {
my $args = $meta->{'WidgetArguments'} || {};
</%PERL>
-<tr class="<% $index_conf%2 ? 'oddline' : 'evenline'%>">
+<tr class="<% $key %> <% $index_conf%2 ? 'oddline' : 'evenline'%>">
<td class="collection-as-table"><a href="<% $doc_url %>" target="_blank"><% $key %></a></td>
<td class="collection-as-table">
commit ca93ea85b527663535d92212f15b6addaa60f0b8
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Tue Aug 15 15:57:46 2017 +0000
Display /Plugins/ options as lists linking to metacpan
diff --git a/html/Admin/Tools/EditConfig.html b/html/Admin/Tools/EditConfig.html
index 2970156..b1bf150 100644
--- a/html/Admin/Tools/EditConfig.html
+++ b/html/Admin/Tools/EditConfig.html
@@ -150,6 +150,10 @@ foreach my $key ( RT->Config->Options( Overridable => undef, Sorted => 0 ) ) {
% if ( $meta->{EditLink} ) {
<&|/l_unsafe, "<a href=\"$meta->{EditLink}\">", loc($meta->{EditLinkLabel}), "</a>" &>Visit [_1][_2][_3] to manage this setting</&>
+% } elsif ( $key =~ /Plugins/) {
+<ul class="plugins">
+% for my $plugin (RT->Config->Get($key)) {
+<li><a href="https://metacpan.org/search?q=<% $plugin |u %>" target="_blank"><% $plugin %></a></li>
% }
</ul>
<br><em><% loc('Must modify in config file' ) %></em>
diff --git a/static/css/config-in-database.css b/static/css/config-in-database.css
index 1af6435..1415ddb 100644
--- a/static/css/config-in-database.css
+++ b/static/css/config-in-database.css
@@ -14,3 +14,6 @@ body#comp-Admin-Tools-EditConfig textarea.code {
font-family: Consolas, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace;
}
+body#comp-Admin-Tools-EditConfig ul.plugins {
+ margin: 0;
+}:
commit f64166fdffa559b00f862a1fdf17ef58ed8a7aff
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Tue Aug 15 16:19:26 2017 +0000
Improve handling for booleans
diff --git a/html/Admin/Tools/EditConfig.html b/html/Admin/Tools/EditConfig.html
index b1bf150..ef56985 100644
--- a/html/Admin/Tools/EditConfig.html
+++ b/html/Admin/Tools/EditConfig.html
@@ -38,6 +38,11 @@ if (delete $ARGS{Update}) {
my $prev = $ARGS{$key . '-Current'};
next if $val eq $prev;
+ # for bools, check for truthiness since 0, '', and undef are equivalent
+ if ($widget eq '/Widgets/Form/Boolean') {
+ next if !!$val eq !!$prev;
+ }
+
if ( $meta->{Immutable} || $meta->{Obfuscate} || ($key =~ /Password/i and $key !~ /MinimumPasswordLength|AllowLoginPasswordAutoComplete/ )) {
push @results, loc("Cannot change [_1]: Permission Denied", $key);
$has_error++;
@@ -143,6 +148,14 @@ foreach my $key ( RT->Config->Options( Overridable => undef, Sorted => 0 ) ) {
|| ($is_code && !$session{CurrentUser}->HasRight(Right => 'ExecuteCode', Object => RT->System));
my $args = $meta->{'WidgetArguments'} || {};
+
+ if ($widget eq '/Widgets/Form/Boolean') {
+ %$args = (
+ Default => 0,
+ RadioStyle => 1,
+ %$args,
+ );
+ }
</%PERL>
<tr class="<% $key %> <% $index_conf%2 ? 'oddline' : 'evenline'%>">
<td class="collection-as-table"><a href="<% $doc_url %>" target="_blank"><% $key %></a></td>
commit 838528bf9d6c4c187cd5f1eecf5a8bccfa1218e3
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Tue Aug 15 16:19:33 2017 +0000
Improve input field for strings and integers
diff --git a/html/Admin/Tools/EditConfig.html b/html/Admin/Tools/EditConfig.html
index ef56985..1280fab 100644
--- a/html/Admin/Tools/EditConfig.html
+++ b/html/Admin/Tools/EditConfig.html
@@ -156,6 +156,13 @@ foreach my $key ( RT->Config->Options( Overridable => undef, Sorted => 0 ) ) {
%$args,
);
}
+ elsif ($widget eq '/Widgets/Form/String' || $widget eq '/Widgets/Form/Integer') {
+ %$args = (
+ Size => 60,
+ %$args,
+ );
+ }
+
</%PERL>
<tr class="<% $key %> <% $index_conf%2 ? 'oddline' : 'evenline'%>">
<td class="collection-as-table"><a href="<% $doc_url %>" target="_blank"><% $key %></a></td>
commit 9d2b78cddebf1f6c7ea827870bf76ba81a5da0ab
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Tue Aug 15 16:19:48 2017 +0000
Avoid undef issues with config that isn't fully spec'd
diff --git a/lib/RT/Extension/ConfigInDatabase.pm b/lib/RT/Extension/ConfigInDatabase.pm
index afc9eea..3ac8588 100644
--- a/lib/RT/Extension/ConfigInDatabase.pm
+++ b/lib/RT/Extension/ConfigInDatabase.pm
@@ -146,20 +146,24 @@ sub LoadConfigFromDatabase {
# are we inadvertantly overriding RT_SiteConfig.pm?
my $meta = RT->Config->Meta($name);
- my %source = %{ $meta->{'Source'} };
- if ($source{'SiteConfig'} && $source{'File'} ne 'database') {
- RT->Logger->warning("Change of config option '$name' at $source{File} line $source{Line} has been overridden by the config setting from the database. Please remove it from $source{File} or from the database to avoid confusion.");
+ if ($meta->{'Source'}) {
+ my %source = %{ $meta->{'Source'} };
+ if ($source{'SiteConfig'} && $source{'File'} ne 'database') {
+ RT->Logger->warning("Change of config option '$name' at $source{File} line $source{Line} has been overridden by the config setting from the database. Please remove it from $source{File} or from the database to avoid confusion.");
+ }
}
+ my $type = $meta->{Type} || 'SCALAR';
+
# hashes combine, but we don't want that behavior because the previous
# config settings will shadow any change that the database config makes
- if ($meta->{Type} eq 'HASH') {
+ if ($type eq 'HASH') {
RT->Config->Set($name, ());
}
- my $val = $meta->{Type} eq 'ARRAY' ? $value
- : $meta->{Type} eq 'HASH' ? [ %$value ]
- : [ $value ];
+ my $val = $type eq 'ARRAY' ? $value
+ : $type eq 'HASH' ? [ %$value ]
+ : [ $value ];
RT->Config->SetFromConfig(
Option => \$name,
commit bdbf85e7121260f7d3bbdc33253794a4b2144e1b
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Tue Aug 15 16:22:12 2017 +0000
Only specify Default => 0 on 4.4.3+ which adds RadioStyle
diff --git a/html/Admin/Tools/EditConfig.html b/html/Admin/Tools/EditConfig.html
index 1280fab..bf8803f 100644
--- a/html/Admin/Tools/EditConfig.html
+++ b/html/Admin/Tools/EditConfig.html
@@ -149,7 +149,9 @@ foreach my $key ( RT->Config->Options( Overridable => undef, Sorted => 0 ) ) {
my $args = $meta->{'WidgetArguments'} || {};
- if ($widget eq '/Widgets/Form/Boolean') {
+ # RadioStyle was added to 4.4.3, and so if we are on an older version we
+ # can't specify Default => 0, since then we revert to just a checkbox
+ if ($widget eq '/Widgets/Form/Boolean' && RT::Handle::cmp_version($RT::VERSION,'4.4.3') >= 0 ) {
%$args = (
Default => 0,
RadioStyle => 1,
commit a18af773bb37ecf65a2ce5a1ef177dbbae6279cd
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Tue Aug 15 16:27:33 2017 +0000
Sort hash keys for consistency across processes
diff --git a/html/Admin/Tools/EditConfig.html b/html/Admin/Tools/EditConfig.html
index bf8803f..1cf7e82 100644
--- a/html/Admin/Tools/EditConfig.html
+++ b/html/Admin/Tools/EditConfig.html
@@ -17,6 +17,7 @@ sub stringify {
local $Data::Dumper::Terse = 1;
local $Data::Dumper::Indent = 2;
+ local $Data::Dumper::Sortkeys = 1;
my $output = Dumper $value;
chomp $output;
return $output;
commit 90437d486a27f47c0459c8caa9a8de25f3218c9a
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Tue Aug 15 16:42:36 2017 +0000
Implement syncing config changes across servers
diff --git a/lib/RT/Extension/ConfigInDatabase.pm b/lib/RT/Extension/ConfigInDatabase.pm
index 3ac8588..7e52faf 100644
--- a/lib/RT/Extension/ConfigInDatabase.pm
+++ b/lib/RT/Extension/ConfigInDatabase.pm
@@ -128,11 +128,16 @@ for (qw/DefaultSearchResultOrder/) {
# special case due to being only for PostLoadCheck
$RT::Config::META{RestrictReferrerLogin}{Invisible} = 1;
+my $config_cache_time;
+
__PACKAGE__->LoadConfigFromDatabase();
sub LoadConfigFromDatabase {
my $class = shift;
+ $config_cache_time = time;
+ RT->Logger->info("Loading config from database");
+
my $settings = RT::DatabaseSettings->new(RT->SystemUser);
$settings->UnLimit;
@@ -176,6 +181,18 @@ sub LoadConfigFromDatabase {
}
}
+sub ConfigCacheNeedsUpdate {
+ my $self = shift;
+ my $time = shift;
+
+ if ($time) {
+ return RT->System->SetAttribute(Name => 'ConfigCacheNeedsUpdate', Content => $time);
+ } else {
+ my $cache = RT->System->FirstAttribute('ConfigCacheNeedsUpdate');
+ return (defined $cache ? $cache->Content : 0 );
+ }
+}
+
sub ApplyConfigChangeToAllServerProcesses {
my $class = shift;
@@ -183,9 +200,24 @@ sub ApplyConfigChangeToAllServerProcesses {
$class->LoadConfigFromDatabase();
# then notify other servers
- # XXX
+ $class->ConfigCacheNeedsUpdate($config_cache_time);
}
+do {
+ require RT::Interface::Web;
+ no warnings 'redefine';
+
+ my $orig_HandleRequest = RT::Interface::Web->can('HandleRequest');
+ *RT::Interface::Web::HandleRequest = sub {
+ my $needs_update = __PACKAGE__->ConfigCacheNeedsUpdate;
+ if ($needs_update > $config_cache_time) {
+ __PACKAGE__->LoadConfigFromDatabase();
+ $config_cache_time = $needs_update;
+ }
+ $orig_HandleRequest->(@_);
+ };
+};
+
=head1 NAME
RT-Extension-ConfigInDatabase - update RT config via admin UI
commit 55517aec32338028f8c275c641c6626c3f48d288
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Tue Aug 15 16:44:07 2017 +0000
Apply all config changes once in a batch
If you change a dozen config settings at once, no need to reload the
config a dozen times. But one-off changes that don't opt into
BeginConfigChanges/EndConfigChanges should still immediately propagate
changes
diff --git a/html/Admin/Tools/EditConfig.html b/html/Admin/Tools/EditConfig.html
index 1cf7e82..0b41e84 100644
--- a/html/Admin/Tools/EditConfig.html
+++ b/html/Admin/Tools/EditConfig.html
@@ -24,6 +24,7 @@ sub stringify {
}
if (delete $ARGS{Update}) {
+ RT::Extension::ConfigInDatabase->BeginConfigChanges;
$RT::Handle->BeginTransaction;
my $has_error;
@@ -110,6 +111,7 @@ if (delete $ARGS{Update}) {
else {
$RT::Handle->Commit;
}
+ RT::Extension::ConfigInDatabase->EndConfigChanges;
}
</%INIT>
diff --git a/lib/RT/Extension/ConfigInDatabase.pm b/lib/RT/Extension/ConfigInDatabase.pm
index 7e52faf..568ee1e 100644
--- a/lib/RT/Extension/ConfigInDatabase.pm
+++ b/lib/RT/Extension/ConfigInDatabase.pm
@@ -193,9 +193,23 @@ sub ConfigCacheNeedsUpdate {
}
}
+my $in_config_change_txn = 0;
+sub BeginConfigChanges {
+ $in_config_change_txn = $in_config_change_txn + 1;
+}
+
+sub EndConfigChanges {
+ $in_config_change_txn = $in_config_change_txn - 1;
+ if (!$in_config_change_txn) {
+ shift->ApplyConfigChangeToAllServerProcesses();
+ }
+}
+
sub ApplyConfigChangeToAllServerProcesses {
my $class = shift;
+ return if $in_config_change_txn;
+
# first apply locally
$class->LoadConfigFromDatabase();
commit 42e43cb6b96e1cff3c8fca7c6ff3a192077598e6
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Tue Aug 15 16:48:18 2017 +0000
Make sure we don't accidentally end up in a BeginConfigChanges txn
diff --git a/html/Admin/Tools/EditConfig.html b/html/Admin/Tools/EditConfig.html
index 0b41e84..5e63c0d 100644
--- a/html/Admin/Tools/EditConfig.html
+++ b/html/Admin/Tools/EditConfig.html
@@ -28,80 +28,87 @@ if (delete $ARGS{Update}) {
$RT::Handle->BeginTransaction;
my $has_error;
- for my $key (keys %ARGS) {
- next if $key =~ /-Current$/;
-
- my $meta = RT->Config->Meta( $key );
- my $widget = $meta->{Widget} || '/Widgets/Form/Code';
- my $is_code = $widget eq '/Widgets/Form/Code';
-
- my $val = $ARGS{$key};
- $val = '' if $val eq '__empty_value__';
- my $prev = $ARGS{$key . '-Current'};
- next if $val eq $prev;
-
- # for bools, check for truthiness since 0, '', and undef are equivalent
- if ($widget eq '/Widgets/Form/Boolean') {
- next if !!$val eq !!$prev;
- }
-
- if ( $meta->{Immutable} || $meta->{Obfuscate} || ($key =~ /Password/i and $key !~ /MinimumPasswordLength|AllowLoginPasswordAutoComplete/ )) {
- push @results, loc("Cannot change [_1]: Permission Denied", $key);
- $has_error++;
- next;
- }
+ eval {
+ for my $key (keys %ARGS) {
+ next if $key =~ /-Current$/;
+
+ my $meta = RT->Config->Meta( $key );
+ my $widget = $meta->{Widget} || '/Widgets/Form/Code';
+ my $is_code = $widget eq '/Widgets/Form/Code';
+
+ my $val = $ARGS{$key};
+ $val = '' if $val eq '__empty_value__';
+ my $prev = $ARGS{$key . '-Current'};
+ next if $val eq $prev;
+
+ # for bools, check for truthiness since 0, '', and undef are equivalent
+ if ($widget eq '/Widgets/Form/Boolean') {
+ next if !!$val eq !!$prev;
+ }
- if ($is_code) {
- if (!$session{CurrentUser}->HasRight(Right => 'ExecuteCode', Object => RT->System)) {
+ if ( $meta->{Immutable} || $meta->{Obfuscate} || ($key =~ /Password/i and $key !~ /MinimumPasswordLength|AllowLoginPasswordAutoComplete/ )) {
push @results, loc("Cannot change [_1]: Permission Denied", $key);
$has_error++;
next;
}
- my $code = $val;
- my $coderef;
- # similar to RT::Scrip::CompileCheck
- do {
- no strict 'vars';
- $coderef = eval "sub { $code \n }";
- };
- if ($@) {
- my $error = $@;
- push @results, loc("Couldn't compile [_1] codeblock '[_2]': [_3]", $key, $code, $error);
- $has_error++;
- next;
- }
+ if ($is_code) {
+ if (!$session{CurrentUser}->HasRight(Right => 'ExecuteCode', Object => RT->System)) {
+ push @results, loc("Cannot change [_1]: Permission Denied", $key);
+ $has_error++;
+ next;
+ }
- if ($coderef) {
- $val = eval { $coderef->() };
+ my $code = $val;
+ my $coderef;
+ # similar to RT::Scrip::CompileCheck
+ do {
+ no strict 'vars';
+ $coderef = eval "sub { $code \n }";
+ };
if ($@) {
my $error = $@;
- push @results, loc("Couldn't execute [_1] codeblock '[_2]': [_3]", $key, $code, $error);
+ push @results, loc("Couldn't compile [_1] codeblock '[_2]': [_3]", $key, $code, $error);
$has_error++;
next;
}
- }
- }
- my $setting = RT::DatabaseSetting->new($session{CurrentUser});
- $setting->Load($key);
- if ($setting->Id) {
- if ($setting->Disabled) {
- $setting->SetDisabled(0);
+ if ($coderef) {
+ $val = eval { $coderef->() };
+ if ($@) {
+ my $error = $@;
+ push @results, loc("Couldn't execute [_1] codeblock '[_2]': [_3]", $key, $code, $error);
+ $has_error++;
+ next;
+ }
+ }
}
- my ($ok, $msg) = $setting->SetContent($val);
- push @results, $msg;
- $has_error++ if !$ok;
- }
- else {
- my ($ok, $msg) = $setting->Create(
- Name => $key,
- Content => $val,
- );
- push @results, $msg;
- $has_error++ if !$ok;
+ my $setting = RT::DatabaseSetting->new($session{CurrentUser});
+ $setting->Load($key);
+ if ($setting->Id) {
+ if ($setting->Disabled) {
+ $setting->SetDisabled(0);
+ }
+
+ my ($ok, $msg) = $setting->SetContent($val);
+ push @results, $msg;
+ $has_error++ if !$ok;
+ }
+ else {
+ my ($ok, $msg) = $setting->Create(
+ Name => $key,
+ Content => $val,
+ );
+ push @results, $msg;
+ $has_error++ if !$ok;
+ }
}
+ };
+
+ if ($@) {
+ push @results, $@;
+ $has_error++;
}
if ($has_error) {
diff --git a/lib/RT/Extension/ConfigInDatabase.pm b/lib/RT/Extension/ConfigInDatabase.pm
index 568ee1e..efc5394 100644
--- a/lib/RT/Extension/ConfigInDatabase.pm
+++ b/lib/RT/Extension/ConfigInDatabase.pm
@@ -223,6 +223,11 @@ do {
my $orig_HandleRequest = RT::Interface::Web->can('HandleRequest');
*RT::Interface::Web::HandleRequest = sub {
+ if ($in_config_change_txn) {
+ RT->Logger->error("It appears that there were unbalanced calls to BeginConfigChanges with EndConfigChanges; this indicates a software fault");
+ $in_config_change_txn = 0;
+ }
+
my $needs_update = __PACKAGE__->ConfigCacheNeedsUpdate;
if ($needs_update > $config_cache_time) {
__PACKAGE__->LoadConfigFromDatabase();
commit 25af4e4c9d400294ffdaefdb55f7dbc05caa3097
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Tue Aug 15 17:03:02 2017 +0000
When a database setting is disabled, restore what was in config files
That includes the metadata about where the config option was set (Meta)
diff --git a/lib/RT/Extension/ConfigInDatabase.pm b/lib/RT/Extension/ConfigInDatabase.pm
index efc5394..817fead 100644
--- a/lib/RT/Extension/ConfigInDatabase.pm
+++ b/lib/RT/Extension/ConfigInDatabase.pm
@@ -3,6 +3,7 @@ use strict;
use warnings;
use RT::DatabaseSetting;
use RT::DatabaseSettings;
+use Storable;
our $VERSION = '0.01';
@@ -129,6 +130,7 @@ for (qw/DefaultSearchResultOrder/) {
$RT::Config::META{RestrictReferrerLogin}{Invisible} = 1;
my $config_cache_time;
+my %original_setting_from_files;
__PACKAGE__->LoadConfigFromDatabase();
@@ -141,6 +143,8 @@ sub LoadConfigFromDatabase {
my $settings = RT::DatabaseSettings->new(RT->SystemUser);
$settings->UnLimit;
+ my %seen;
+
while (my $setting = $settings->Next) {
my $name = $setting->Name;
my $value = $setting->Content;
@@ -149,6 +153,15 @@ sub LoadConfigFromDatabase {
local $Data::Dumper::Terse = 1;
RT->Logger->debug("from database: Set('$name', ".Dumper($value).");");
+ if (!exists $original_setting_from_files{$name}) {
+ $original_setting_from_files{$name} = [
+ scalar(RT->Config->Get($name)),
+ Storable::dclone(scalar(RT->Config->Meta($name))),
+ ];
+ }
+
+ $seen{$name}++;
+
# are we inadvertantly overriding RT_SiteConfig.pm?
my $meta = RT->Config->Meta($name);
if ($meta->{'Source'}) {
@@ -179,6 +192,28 @@ sub LoadConfigFromDatabase {
SiteConfig => 1,
);
}
+
+ # anything that wasn't loaded from the database but has been set in
+ # %original_setting_from_files must have been disabled from the database,
+ # so we want to restore the original setting
+ for my $name (keys %original_setting_from_files) {
+ next if $seen{$name};
+
+ my ($value, $meta) = @{ $original_setting_from_files{$name} };
+ my $type = $meta->{Type} || 'SCALAR';
+
+ if ($type eq 'ARRAY') {
+ RT->Config->Set($name, @$value);
+ }
+ elsif ($type eq 'HASH') {
+ RT->Config->Set($name, %$value);
+ }
+ else {
+ RT->Config->Set($name, $value);
+ }
+
+ %{ RT->Config->Meta($name) } = %$meta;
+ }
}
sub ConfigCacheNeedsUpdate {
commit fa58307632d0d71ea941a5370fd42a1ab1bd25fb
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Tue Aug 15 17:30:00 2017 +0000
Don't get current user's preference, get config value
diff --git a/html/Admin/Tools/EditConfig.html b/html/Admin/Tools/EditConfig.html
index 5e63c0d..b35c915 100644
--- a/html/Admin/Tools/EditConfig.html
+++ b/html/Admin/Tools/EditConfig.html
@@ -142,7 +142,7 @@ foreach my $key ( RT->Config->Options( Overridable => undef, Sorted => 0 ) ) {
next if $meta->{Invisible};
- my $raw_value = RT->Config->Get( $key, $session{'CurrentUser'} );
+ my $raw_value = RT->Config->Get( $key );
my $val = stringify($raw_value);
$index_conf++;
commit f0eaaaf1b75b138445fe78cedb4cade78181dfdc
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Tue Aug 15 17:31:10 2017 +0000
Factor out $has_execute_code
diff --git a/html/Admin/Tools/EditConfig.html b/html/Admin/Tools/EditConfig.html
index b35c915..2f6fd38 100644
--- a/html/Admin/Tools/EditConfig.html
+++ b/html/Admin/Tools/EditConfig.html
@@ -4,6 +4,8 @@ unless ($session{'CurrentUser'}->HasRight( Object=> $RT::System, Right => 'Super
Abort(loc('This feature is only available to system administrators'));
}
+my $has_execute_code = $session{CurrentUser}->HasRight(Right => 'ExecuteCode', Object => RT->System);
+
my @results;
my $doc_version = $RT::VERSION;
@@ -53,7 +55,7 @@ if (delete $ARGS{Update}) {
}
if ($is_code) {
- if (!$session{CurrentUser}->HasRight(Right => 'ExecuteCode', Object => RT->System)) {
+ if (!$has_execute_code) {
push @results, loc("Cannot change [_1]: Permission Denied", $key);
$has_error++;
next;
@@ -155,7 +157,7 @@ foreach my $key ( RT->Config->Options( Overridable => undef, Sorted => 0 ) ) {
my $current_value = $is_code ? $val : $raw_value;
my $is_immutable = $meta->{Immutable}
|| $meta->{Obfuscate}
- || ($is_code && !$session{CurrentUser}->HasRight(Right => 'ExecuteCode', Object => RT->System));
+ || ($is_code && !$has_execute_code);
my $args = $meta->{'WidgetArguments'} || {};
commit 6f5895be1aafcc2c90a1429aee4391d53d6978ff
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Tue Aug 15 17:35:45 2017 +0000
Improve logging and permission checks for RT::DatabaseSetting
diff --git a/lib/RT/DatabaseSetting.pm b/lib/RT/DatabaseSetting.pm
index e603f56..de306dc 100644
--- a/lib/RT/DatabaseSetting.pm
+++ b/lib/RT/DatabaseSetting.pm
@@ -97,9 +97,11 @@ sub Create {
}
if (!ref($content) && !ref($old_value)) {
+ RT->Logger->info($self->CurrentUser->Name . " changed " . $self->Name . " from " . $old_value . " to " . $content);
return ($id, $self->loc("[_1] changed from [_2] to [_3]", $self->Name, $old_value, $content));
}
else {
+ RT->Logger->info($self->CurrentUser->Name . " changed " . $self->Name);
return ($id, $self->loc("[_1] changed", $self->Name));
}
}
@@ -183,6 +185,7 @@ sub Delete {
my ($ok, $msg) = $self->SUPER::Delete(@_);
return ($ok, $msg) if !$ok;
RT::Extension::ConfigInDatabase->ApplyConfigChangeToAllServerProcesses;
+ RT->Logger->info($self->CurrentUser->Name . " removed database setting for " . $self->Name);
return ($ok, $self->loc("Database setting removed."));
}
@@ -219,6 +222,8 @@ sub SetContent {
my $value = shift;
my $content_type = shift || '';
+ return (0, $self->loc("Permission Denied")) unless $self->CurrentUserCanSee;
+
my $old_value = $self->Content;
unless (defined($old_value) && length($old_value)) {
$old_value = $self->loc('(no value)');
@@ -256,8 +261,10 @@ sub SetContent {
}
if (!ref($value) && !ref($old_value)) {
+ RT->Logger->info($self->CurrentUser->Name . " changed " . $self->Name . " from " . $old_value . " to " . $value);
return ($ok, $self->loc("[_1] changed from [_2] to [_3]", $self->Name, $old_value, $value));
} else {
+ RT->Logger->info($self->CurrentUser->Name . " changed " . $self->Name);
return ($ok, $self->loc("[_1] changed", $self->Name));
}
}
commit 82a56476d9475b1af9ef74cbe6c670bf7ebcc9d9
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Tue Aug 15 17:40:34 2017 +0000
Use a lexical subroutine for stringify
Otherwise the core /Admin/Tools/Configuration.html page, which also has
a package-level stringify subroutine, competes with the one in this
template, as both use package HTML::Mason::Commands. Since the two
stringify()s do different things, you would get different results
depending on which order you load the two pages.
diff --git a/html/Admin/Tools/EditConfig.html b/html/Admin/Tools/EditConfig.html
index 2f6fd38..06e6e8b 100644
--- a/html/Admin/Tools/EditConfig.html
+++ b/html/Admin/Tools/EditConfig.html
@@ -13,7 +13,7 @@ $doc_version =~ s/rc\d+//; # 4.4.2rc1 -> 4.4.2
$doc_version =~ s/\.\d+-\d+-g\w+$//; # 4.4.3-1-g123 -> 4.4
use Data::Dumper;
-sub stringify {
+my $stringify = sub {
my $value = shift;
return "" if !defined($value);
@@ -23,7 +23,7 @@ sub stringify {
my $output = Dumper $value;
chomp $output;
return $output;
-}
+};
if (delete $ARGS{Update}) {
RT::Extension::ConfigInDatabase->BeginConfigChanges;
@@ -145,7 +145,7 @@ foreach my $key ( RT->Config->Options( Overridable => undef, Sorted => 0 ) ) {
next if $meta->{Invisible};
my $raw_value = RT->Config->Get( $key );
- my $val = stringify($raw_value);
+ my $val = $stringify->($raw_value);
$index_conf++;
commit 5497c1cdea5e36c393207d24a66658568343da03
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Tue Aug 15 17:47:57 2017 +0000
Avoid missing config name on error
When creating a new config setting, $self->Name isn't set yet, so
if serialization fails there was no way of knowing which setting caused
it
diff --git a/lib/RT/DatabaseSetting.pm b/lib/RT/DatabaseSetting.pm
index de306dc..b3ea007 100644
--- a/lib/RT/DatabaseSetting.pm
+++ b/lib/RT/DatabaseSetting.pm
@@ -69,7 +69,7 @@ sub Create {
}
if (ref ($args{'Content'}) ) {
- $args{'Content'} = $self->_SerializeContent($args{'Content'});
+ $args{'Content'} = $self->_SerializeContent($args{'Content'}, $args{'Name'});
if (!$args{'Content'}) {
return (0, $@);
}
@@ -312,9 +312,10 @@ sub _Value {
sub _SerializeContent {
my $self = shift;
my $content = shift;
+ my $name = shift || $self->Name;
my $frozen = eval { encode_base64(Storable::nfreeze($content)) };
if ($@) {
- $RT::Logger->error("Serialization of database setting ". $self->Name . " failed: $@");
+ $RT::Logger->error("Serialization of database setting $name failed: $@");
}
return $frozen;
commit e83711e8463addeba72a735c4b50cbcf7739af04
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Tue Aug 15 17:56:52 2017 +0000
Capture and propagate errors more consistently
diff --git a/lib/RT/DatabaseSetting.pm b/lib/RT/DatabaseSetting.pm
index b3ea007..59bb1e0 100644
--- a/lib/RT/DatabaseSetting.pm
+++ b/lib/RT/DatabaseSetting.pm
@@ -69,9 +69,9 @@ sub Create {
}
if (ref ($args{'Content'}) ) {
- $args{'Content'} = $self->_SerializeContent($args{'Content'}, $args{'Name'});
- if (!$args{'Content'}) {
- return (0, $@);
+ ($args{'Content'}, my $error) = $self->_SerializeContent($args{'Content'}, $args{'Name'});
+ if ($error) {
+ return (0, $error);
}
$args{'ContentType'} = 'storable';
}
@@ -91,7 +91,7 @@ sub Create {
RT::Extension::ConfigInDatabase->ApplyConfigChangeToAllServerProcesses;
- my $content = $self->Content;
+ my ($content, $error) = $self->Content;
unless (defined($content) && length($content)) {
$content = $self->loc('(no value)');
}
@@ -189,13 +189,13 @@ sub Delete {
return ($ok, $self->loc("Database setting removed."));
}
-=head2 Content
+=head2 DecodedContent
-Returns this setting's content.
+Returns a pair of this setting's content and any error.
=cut
-sub Content {
+sub DecodedContent {
my $self = shift;
# Here we call _Value to run the ACL check.
@@ -207,10 +207,10 @@ sub Content {
return $self->_DeserializeContent($content);
}
elsif ($type eq 'application/json') {
- return JSON::from_json($content);
+ return $self->_DeJSONContent($content);
}
- return $content;
+ return ($content, "");
}
=head2 SetContent
@@ -224,15 +224,15 @@ sub SetContent {
return (0, $self->loc("Permission Denied")) unless $self->CurrentUserCanSee;
- my $old_value = $self->Content;
+ my ($old_value, $error) = $self->Content;
unless (defined($old_value) && length($old_value)) {
$old_value = $self->loc('(no value)');
}
if (ref $value) {
- $value = $self->_SerializeContent($value);
- if (!$value) {
- return (0, $@);
+ ($value, my $error) = $self->_SerializeContent($value);
+ if ($error) {
+ return (0, $error);
}
$content_type = 'storable';
}
@@ -314,8 +314,10 @@ sub _SerializeContent {
my $content = shift;
my $name = shift || $self->Name;
my $frozen = eval { encode_base64(Storable::nfreeze($content)) };
- if ($@) {
- $RT::Logger->error("Serialization of database setting $name failed: $@");
+
+ if (my $error = $@) {
+ $RT::Logger->error("Storable serialization of database setting $name failed: $error");
+ return (undef, $self->loc("Storable serialization of database setting [_1] failed: [_2]", $name, $error));
}
return $frozen;
@@ -326,8 +328,22 @@ sub _DeserializeContent {
my $content = shift;
my $thawed = eval { Storable::thaw(decode_base64($content)) };
- if ($@) {
- $RT::Logger->error("Deserialization of database setting " . $self->Name . " failed: $@");
+ if (my $error = $@) {
+ $RT::Logger->error("Storable deserialization of database setting " . $self->Name . " failed: $error");
+ return (undef, $self->loc("Storable deserialization of database setting [_1] failed: [_2]", $self->Name, $error));
+ }
+
+ return $thawed;
+}
+
+sub _DeJSONContent {
+ my $self = shift;
+ my $content = shift;
+
+ my $thawed = eval { JSON::from_json($content) };
+ if (my $error = $@) {
+ $RT::Logger->error("JSON deserialization of database setting " . $self->Name . " failed: $error");
+ return (undef, $self->loc("JSON deserialization of database setting [_1] failed: [_2]", $self->Name, $error));
}
return $thawed;
diff --git a/lib/RT/Extension/ConfigInDatabase.pm b/lib/RT/Extension/ConfigInDatabase.pm
index 817fead..e7da405 100644
--- a/lib/RT/Extension/ConfigInDatabase.pm
+++ b/lib/RT/Extension/ConfigInDatabase.pm
@@ -147,7 +147,8 @@ sub LoadConfigFromDatabase {
while (my $setting = $settings->Next) {
my $name = $setting->Name;
- my $value = $setting->Content;
+ my ($value, $error) = $setting->DecodedContent;
+ next if $error;
use Data::Dumper;
local $Data::Dumper::Terse = 1;
commit 9be38f8918bde78970031804ce11fc475be7ec49
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Tue Aug 15 18:13:33 2017 +0000
Any coderefs means the config setting is effectively immutable
Must edit it in the config file because B::Deparse etc is not 100% accurate
diff --git a/html/Admin/Tools/EditConfig.html b/html/Admin/Tools/EditConfig.html
index 06e6e8b..8e4d171 100644
--- a/html/Admin/Tools/EditConfig.html
+++ b/html/Admin/Tools/EditConfig.html
@@ -154,11 +154,12 @@ foreach my $key ( RT->Config->Options( Overridable => undef, Sorted => 0 ) ) {
my $widget = $meta->{'Widget'} || '/Widgets/Form/Code';
my $is_code = $widget eq '/Widgets/Form/Code';
my $is_password = ($key =~ /Password/i and $key !~ /MinimumPasswordLength|AllowLoginPasswordAutoComplete/ );
- my $current_value = $is_code ? $val : $raw_value;
my $is_immutable = $meta->{Immutable}
|| $meta->{Obfuscate}
+ || ($is_code && $val =~ s/sub { "DUMMY" }/sub { ... }/g)
|| ($is_code && !$has_execute_code);
+ my $current_value = $is_code ? $val : $raw_value;
my $args = $meta->{'WidgetArguments'} || {};
# RadioStyle was added to 4.4.3, and so if we are on an older version we
-----------------------------------------------------------------------
More information about the Bps-public-commit
mailing list