<%INIT>
my $title = loc('System Configuration');
unless ($session{'CurrentUser'}->HasRight( Object=> $RT::System, Right => 'SuperUser')) {
 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;
$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;
my $stringify = sub {
    my $value = shift;
    return "" if !defined($value);

    local $Data::Dumper::Terse = 1;
    local $Data::Dumper::Indent = 2;
    local $Data::Dumper::Sortkeys = 1;
    my $output = Dumper $value;
    chomp $output;
    return $output;
};

if (delete $ARGS{Update}) {
    RT::Extension::ConfigInDatabase->BeginConfigChanges;
    $RT::Handle->BeginTransaction;
    my $has_error;

    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 ( $meta->{Immutable} || $meta->{Obfuscate} || ($key =~ /Password/i and $key !~ /MinimumPasswordLength|AllowLoginPasswordAutoComplete/ )) {
                push @results, loc("Cannot change [_1]: Permission Denied", $key);
                $has_error++;
                next;
            }

            if ($is_code) {
                if (!$has_execute_code) {
                    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 ($coderef) {
                    $val = eval { $coderef->() };
                    if ($@) {
                        my $error = $@;
                        push @results, loc("Couldn't execute [_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);
                }

                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) {
        push @results, loc("No changes made.");
        $RT::Handle->Rollback;
    }
    else {
        $RT::Handle->Commit;
    }
    RT::Extension::ConfigInDatabase->EndConfigChanges;
}

</%INIT>
<& /Admin/Elements/Header, Title => $title &>
<& /Elements/Tabs &>
<& /Elements/ListActions, actions => \@results &>

<form method="post" action="EditConfig.html">
<input type="hidden" name="Update" value=1></input>

<&|/Widgets/TitleBox, title => loc("RT Configuration") &>
<table border="0" cellspacing="0" cellpadding="5" width="100%" class="collection">
<tr class="collection-as-table">
<th class="collection-as-table"><&|/l&>Option</&></th>
<th class="collection-as-table"><&|/l&>Value</&></th>
</tr>
<%PERL>
my $index_conf;
foreach my $key ( RT->Config->Options( Overridable => undef, Sorted => 0 ) ) {
    my $meta = RT->Config->Meta( $key );

    next if $meta->{Invisible};

    my $raw_value = RT->Config->Get( $key );
    my $val = $stringify->($raw_value);

    $index_conf++;

    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 $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
    # 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,
            %$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>
<td class="collection-as-table">

% if ( $meta->{EditLink} ) {
% if ($widget eq '/Widgets/Form/MultilineString' || $widget eq '/Widgets/Form/Code') {
<textarea disabled class="<% $is_code ? 'code' : '' %>" rows="6" cols="80"><% $current_value %></textarea><br>
% } else {
<input type="text" disabled width="80" value="<% $current_value %>"></input><br>
% }
<&|/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>
% } 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 {
<input type="text" disabled width="80" value="<% $current_value %>"></input>
% }
<br><em><% loc('Must modify in config file' ) %></em>
% } else {
  <& $widget,
    Default      => 1,
    DefaultValue => '',
    DefaultLabel => '(no value)',

    %{ $m->comp('/Widgets/FinalizeWidgetArguments', WidgetArguments => $args ) },
    Name         => $key,
    CurrentValue => $current_value,
    Description  => '',
    Hints        => '',
  &>
<textarea class="hidden" name="<% $key %>-Current"><% $current_value %></textarea>
% }
</td>
</tr>
% }
</table>
</&>
<& /Elements/Submit, Label => loc('Save Changes') &>
</form>
