Bug 70998
git-svn-id: svn://svn.office.custis.ru/3rdparty/bugzilla.org/trunk@1006 6955db30-a419-402b-8a0d-67ecbb4d7f56master
parent
0bd5aa03f0
commit
66c12629de
|
@ -19,8 +19,6 @@ my $cgi = Bugzilla->cgi;
|
|||
my $params = $cgi->Vars;
|
||||
my $vars = {};
|
||||
|
||||
my @REAL_UPDATE_COLUMNS = qw(is_freeze is_fatal message);
|
||||
|
||||
$user->in_group('bz_editcheckers')
|
||||
|| ThrowUserError('auth_failure', {group => 'bz_editcheckers',
|
||||
action => 'modify',
|
||||
|
@ -33,42 +31,52 @@ if ($params->{save})
|
|||
if ($params->{edit})
|
||||
{
|
||||
check_token_data($params->{token}, 'editcheckers');
|
||||
# Заполняем поля-исключения
|
||||
my $except = {};
|
||||
for (keys %$params)
|
||||
{
|
||||
if (/^except_field_(\d+)$/so)
|
||||
{
|
||||
$except->{$params->{$_}} =
|
||||
$params->{"except_field_$1_value"} || undef;
|
||||
}
|
||||
}
|
||||
$except = undef if !%$except;
|
||||
if (!$params->{deny_all} && !$except)
|
||||
{
|
||||
$params->{deny_all} = 1;
|
||||
}
|
||||
my $flags =
|
||||
($params->{is_freeze} ? 1 : 0) * CF_FREEZE |
|
||||
($params->{is_fatal} ? 1 : 0) * CF_FATAL |
|
||||
($params->{on_update} ? 1 : 0) * CF_UPDATE |
|
||||
($params->{on_create} ? 1 : 0) * CF_CREATE |
|
||||
($params->{deny_all} ? 1 : 0) * CF_DENY;
|
||||
# Ошибка, если CF_CREATE & (есть except_fields).
|
||||
if (($flags & CF_CREATE) && $except)
|
||||
{
|
||||
ThrowUserError('chk_create_except');
|
||||
}
|
||||
# Создаём/обновляем
|
||||
my $ch;
|
||||
if ($params->{create})
|
||||
{
|
||||
$ch = Bugzilla::Checker->create({
|
||||
(map { ($_ => $params->{$_}) } 'query_id', @REAL_UPDATE_COLUMNS),
|
||||
query_id => $params->{query_id},
|
||||
user_id => $user->id,
|
||||
message => $params->{query_id},
|
||||
flags => $flags,
|
||||
except_fields => $except,
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
$ch = Bugzilla::Checker->check({ id => $id });
|
||||
my $f;
|
||||
for (@REAL_UPDATE_COLUMNS)
|
||||
{
|
||||
$f = "set_$_";
|
||||
$ch->$f($params->{$_});
|
||||
}
|
||||
}
|
||||
# поля-исключения: если deny_all=1, то разрешить только их,
|
||||
# если deny_all=0, то запретить только их,
|
||||
# если deny_all=0 и их нет, то deny_all=1
|
||||
my $except = { deny_all => $params->{deny_all}, except_fields => {} };
|
||||
for (keys %$params)
|
||||
{
|
||||
if (/^except_field_(\d+)$/so)
|
||||
{
|
||||
$except->{except_fields}->{$params->{$_}} =
|
||||
$params->{"except_field_$1_value"} || undef;
|
||||
}
|
||||
}
|
||||
if (!%{$except->{except_fields}})
|
||||
{
|
||||
$except = undef;
|
||||
}
|
||||
$ch->set_message($params->{message});
|
||||
$ch->set_flags($flags);
|
||||
$ch->set_except_fields($except);
|
||||
$ch->update;
|
||||
}
|
||||
delete_token($params->{token});
|
||||
}
|
||||
elsif ($params->{delete})
|
||||
|
@ -103,7 +111,7 @@ else
|
|||
}
|
||||
else
|
||||
{
|
||||
$vars->{checker} = { deny_all => 1 };
|
||||
$vars->{checker} = { is_fatal => 1, deny_all => 1, on_update => 1 };
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,27 +3,37 @@
|
|||
package Bugzilla::Checker;
|
||||
|
||||
use strict;
|
||||
use base 'Bugzilla::Object';
|
||||
use base qw(Bugzilla::Object Exporter);
|
||||
|
||||
use JSON;
|
||||
use Bugzilla::Search::Saved;
|
||||
|
||||
use constant DB_TABLE => 'checkers';
|
||||
|
||||
use constant {
|
||||
CF_FREEZE => 0x01, # да => заморозка, нет => проверка значений
|
||||
CF_FATAL => 0x02, # да => ошибка, нет => предупреждение
|
||||
CF_CREATE => 0x04, # да => проверять при создании бага, нет => не проверять
|
||||
CF_UPDATE => 0x08, # да => проверять при обновлении бага, нет => не проверять
|
||||
CF_DENY => 0x10, # да => запрещать изменения всех полей, кроме..., нет => разрешать изменения всех полей, кроме...
|
||||
};
|
||||
|
||||
our @EXPORT = qw(CF_FREEZE CF_FATAL CF_CREATE CF_UPDATE CF_DENY);
|
||||
|
||||
use constant DB_COLUMNS => (
|
||||
# <Это состояние> задаётся соответствием запросу поиска.
|
||||
'query_id',
|
||||
# Кто создал
|
||||
'user_id',
|
||||
# Два типа:
|
||||
# Check = запрещается переход багов в это состояние из любого другого
|
||||
# ("проверка корректности изменений")
|
||||
# Freeze = запрещается переход багов из этого состояния в любое другое
|
||||
# ("заморозка бага")
|
||||
'is_freeze',
|
||||
'is_fatal',
|
||||
# Флаги
|
||||
'flags',
|
||||
# Сообщение об ошибке в случае некорректности
|
||||
'message',
|
||||
# SQL-код генерировать при каждом изменении бага долго, поэтому кэшируем
|
||||
'sql_code',
|
||||
# Поля-исключения: если CF_DENY, то разрешить только их,
|
||||
# если !(flags & CF_DENY), то запретить только их,
|
||||
# если !(flags & CF_DENY) и их нет, то flags |= CF_DENY
|
||||
'except_fields',
|
||||
);
|
||||
use constant NAME_FIELD => 'message';
|
||||
|
@ -33,14 +43,12 @@ use constant LIST_ORDER => NAME_FIELD;
|
|||
use constant REQUIRED_CREATE_FIELDS => qw(query_id message);
|
||||
|
||||
use constant VALIDATORS => {
|
||||
query_id => \&check_query_id,
|
||||
is_fatal => \&Bugzilla::Object::check_boolean,
|
||||
is_freeze => \&Bugzilla::Object::check_boolean,
|
||||
query_id => \&_check_query_id,
|
||||
flags => \&_check_flags,
|
||||
};
|
||||
|
||||
use constant UPDATE_COLUMNS => (
|
||||
'is_freeze',
|
||||
'is_fatal',
|
||||
'flags',
|
||||
'message',
|
||||
'sql_code',
|
||||
'except_fields',
|
||||
|
@ -77,7 +85,11 @@ sub refresh_sql
|
|||
sub create
|
||||
{
|
||||
my ($class, $params) = @_;
|
||||
Bugzilla::Object::create(@_);
|
||||
if ($params->{except_fields})
|
||||
{
|
||||
$params->{except_fields} = encode_json($params->{except_fields});
|
||||
}
|
||||
Bugzilla::Object::create($class, $params);
|
||||
my $self = $class->new($params->{query_id});
|
||||
$self->update if $self;
|
||||
return $self;
|
||||
|
@ -92,7 +104,7 @@ sub update
|
|||
}
|
||||
|
||||
# Проверяем, что такой поиск существует и доступен пользователю
|
||||
sub check_query_id
|
||||
sub _check_query_id
|
||||
{
|
||||
my ($invocant, $value, $field) = @_;
|
||||
my $q = Bugzilla::Search::Saved->check({ id => $value });
|
||||
|
@ -112,14 +124,37 @@ sub check_query_id
|
|||
return $q->id;
|
||||
}
|
||||
|
||||
# FIXME проверка должна быть здесь, но Bugzilla::Object не позволяет это реализовать:
|
||||
# Ошибка, если CF_CREATE & (есть except_fields).
|
||||
sub _check_flags
|
||||
{
|
||||
my ($invocant, $value, $field) = @_;
|
||||
$value = int($value);
|
||||
if ($value & (CF_FREEZE|CF_CREATE))
|
||||
{
|
||||
ThrowUserError('chk_freeze_create');
|
||||
}
|
||||
elsif (($value & CF_CREATE) && !($value & CF_DENY))
|
||||
{
|
||||
ThrowUserError('chk_create_allow');
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
sub query_id { $_[0]->{query_id} }
|
||||
sub user_id { $_[0]->{user_id} }
|
||||
sub is_freeze { $_[0]->{is_freeze} }
|
||||
sub is_fatal { $_[0]->{is_fatal} }
|
||||
sub message { $_[0]->{message} }
|
||||
sub sql_code { $_[0]->{sql_code} }
|
||||
sub flags { $_[0]->{flags} }
|
||||
|
||||
# { deny_all => 1|0, except_fields => { field_name => value } }
|
||||
# Отдельные флаги
|
||||
sub is_freeze { $_[0]->{flags} & CF_FREEZE }
|
||||
sub is_fatal { $_[0]->{flags} & CF_FATAL }
|
||||
sub on_create { $_[0]->{flags} & CF_CREATE }
|
||||
sub on_update { $_[0]->{flags} & CF_UPDATE }
|
||||
sub deny_all { $_[0]->{flags} & CF_DENY }
|
||||
|
||||
# { field_name => value }
|
||||
# when value is undef, then the change of field with name=field_name to any value is an exception
|
||||
# when value is not undef, then only the change to value=value is an exception
|
||||
sub except_fields
|
||||
|
@ -132,12 +167,6 @@ sub except_fields
|
|||
return $self->{except_fields_obj};
|
||||
}
|
||||
|
||||
sub deny_all
|
||||
{
|
||||
my $self = shift;
|
||||
return $self->except_fields ? $self->except_fields->{deny_all} : 1;
|
||||
}
|
||||
|
||||
sub name
|
||||
{
|
||||
my $self = shift;
|
||||
|
@ -166,8 +195,7 @@ sub user
|
|||
|
||||
sub set_query_id { $_[0]->set('query_id', Bugzilla::Search::Saved->check({ id => $_[1] })->id) }
|
||||
sub set_user_id { $_[0]->set('user_id', Bugzilla::User->check({ userid => $_[1] })->id) }
|
||||
sub set_is_freeze { $_[0]->set('is_freeze', $_[1]) }
|
||||
sub set_is_fatal { $_[0]->set('is_fatal', $_[1]) }
|
||||
sub set_flags { $_[0]->set('flags', $_[1]) }
|
||||
sub set_message { $_[0]->set('message', $_[1]) }
|
||||
sub set_sql_code { $_[0]->set('sql_code', $_[1]) }
|
||||
|
||||
|
|
|
@ -33,9 +33,16 @@ sub all
|
|||
return $c->{checkers};
|
||||
}
|
||||
|
||||
# Запустить набор проверок по одному багу
|
||||
# $mask - маска из флагов, которые нужно проверять для фильтрации проверок
|
||||
# $flags - требуемые значения этих флагов
|
||||
# Т.е. check(..., CF_UPDATE, CF_FREEZE | CF_UPDATE) выберет проверки
|
||||
# с флагом CF_UPDATE, но без флага CF_FREEZE
|
||||
sub check
|
||||
{
|
||||
my ($bug_id, $is_freeze) = @_;
|
||||
my ($bug_id, $flags, $mask) = @_;
|
||||
$mask ||= 0;
|
||||
$flags ||= 0;
|
||||
$bug_id = $bug_id->bug_id if ref $bug_id;
|
||||
$bug_id = int($bug_id) || return;
|
||||
my $all = all();
|
||||
|
@ -43,7 +50,7 @@ sub check
|
|||
my ($s, $i);
|
||||
for (values %$all)
|
||||
{
|
||||
if (!($is_freeze xor $_->is_freeze))
|
||||
if (($_->flags & $mask) == $flags)
|
||||
{
|
||||
$s = $_->sql_code;
|
||||
$i = $_->id;
|
||||
|
@ -100,7 +107,7 @@ sub filter_failed_checkers
|
|||
my @rc;
|
||||
for (@$checkers)
|
||||
{
|
||||
my $e = $_->except_fields->{except_fields};
|
||||
my $e = $_->except_fields;
|
||||
my $ok = 1;
|
||||
if ($_->deny_all)
|
||||
{
|
||||
|
@ -140,7 +147,7 @@ sub bug_pre_update
|
|||
my ($args) = @_;
|
||||
my $bug = $args->{bug};
|
||||
# запускаем проверки, работающие ДО внесения изменений (заморозка багов)
|
||||
$bug->{failed_checkers} = check($bug->bug_id, 'freeze');
|
||||
$bug->{failed_checkers} = check($bug->bug_id, CF_FREEZE | CF_UPDATE, CF_FREEZE | CF_UPDATE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -154,7 +161,7 @@ sub bug_end_of_update
|
|||
? [ '', scalar @{$args->{bug}->{added_comments}} ] : undef;
|
||||
|
||||
# запускаем проверки, работающие ПОСЛЕ внесения изменений
|
||||
push @{$bug->{failed_checkers}}, @{ check($bug->bug_id) };
|
||||
push @{$bug->{failed_checkers}}, @{ check($bug->bug_id, CF_UPDATE, CF_FREEZE | CF_UPDATE) };
|
||||
|
||||
if (@{$bug->{failed_checkers}})
|
||||
{
|
||||
|
@ -175,18 +182,8 @@ sub post_bug_post_create
|
|||
{
|
||||
my ($args) = @_;
|
||||
my $bug = $args->{bug};
|
||||
$bug->{failed_checkers} = check($bug->bug_id);
|
||||
if (@{$bug->{failed_checkers}})
|
||||
{
|
||||
# при создании бага не хочется дёргать всякие
|
||||
# процедуры получения значений полей, поэтому
|
||||
# работаем по упрощённому варианту
|
||||
my $changes = {
|
||||
map { $_->name => [ '', $bug->{$_->name} ] }
|
||||
grep { $bug->{$_->name} }
|
||||
Bugzilla->get_fields };
|
||||
filter_failed_checkers($bug->{failed_checkers}, $changes);
|
||||
}
|
||||
# При создании бага сия радость по изменениям не фильтруеццо!
|
||||
$bug->{failed_checkers} = check($bug->bug_id, CF_CREATE, CF_CREATE);
|
||||
if (@{$bug->{failed_checkers}})
|
||||
{
|
||||
alert($bug);
|
||||
|
|
|
@ -311,6 +311,28 @@ sub install_update_db
|
|||
$dbh->bz_add_column('fielddefs', clone_bug => {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 1});
|
||||
}
|
||||
|
||||
# Временное, можно удалить
|
||||
if ($dbh->bz_column_info('checkers', 'is_freeze'))
|
||||
{
|
||||
use Bugzilla::Checker;
|
||||
use JSON;
|
||||
$dbh->bz_add_column('checkers', flags => {TYPE => 'INT2', NOTNULL => 1, DEFAULT => 1});
|
||||
my $rows = $dbh->selectall_arrayref('SELECT * FROM checkers', {Slice=>{}});
|
||||
for (@$rows)
|
||||
{
|
||||
$_->{except_fields} = $_->{except_fields} ? decode_json($_->{except_fields}) : {};
|
||||
$dbh->do('UPDATE checkers SET flags=?, except_fields=? WHERE query_id=?', undef,
|
||||
($_->{is_freeze} ? 1 : 0) * CF_FREEZE |
|
||||
($_->{is_fatal} ? 1 : 0) * CF_FATAL |
|
||||
($_->{except_fields}->{deny_all} ? 1 : 0) * CF_DENY |
|
||||
CF_CREATE | CF_UPDATE,
|
||||
$_->{except_fields}->{except_fields} ? encode_json($_->{except_fields}->{except_fields}) : undef,
|
||||
$_->{query_id});
|
||||
}
|
||||
$dbh->bz_drop_column('checkers', 'is_freeze');
|
||||
$dbh->bz_drop_column('checkers', 'is_fatal');
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -53,8 +53,12 @@
|
|||
<tr>
|
||||
<th>Параметры:</th>
|
||||
<td>
|
||||
<input type="checkbox" name="on_create" id="on_create" [% " checked='checked'" IF checker.on_create %] onclick="this.blur()" onblur="showhide_allowdeny()" />
|
||||
<label for="on_create">Проверять создание новых багов</label><br />
|
||||
<input type="checkbox" name="on_update" id="on_update" [% " checked='checked'" IF checker.on_update %] onclick="this.blur()" onblur="showhide_allowdeny()" />
|
||||
<label for="on_update">Проверять обновления багов</label><br />
|
||||
<input type="checkbox" name="is_freeze" id="is_freeze" [% " checked='checked'" IF checker.is_freeze %] />
|
||||
<label for="is_freeze">Режим заморозки багов (если нет, то режим проверки новых состояний)</label><br />
|
||||
<label for="is_freeze" id="label_for_is_freeze">Предварительная проверка (заморозка багов, только для режима обновления)</label><br />
|
||||
<input type="checkbox" name="is_fatal" id="is_fatal" [% " checked='checked'" IF checker.is_fatal %] />
|
||||
<label for="is_fatal">Запрещать изменения? (если нет, только даётся предупреждение)</label><br />
|
||||
</td>
|
||||
|
@ -62,8 +66,8 @@
|
|||
<tr>
|
||||
<th style="background: #FFE0E0">Запрещать:</th>
|
||||
<td style="background: #FFE0E0">
|
||||
<input type="checkbox" name="deny_all" id="deny_all" onclick="this.blur(); return true;" onblur="showhide_allowdeny(this.checked)" [% " checked='checked'" IF checker.deny_all %] />
|
||||
<label for="deny_all">Запрещать изменения всех полей</label>
|
||||
<input type="checkbox" name="deny_all" id="deny_all" onclick="this.blur(); return true;" onblur="showhide_allowdeny()" [% " checked='checked'" IF checker.deny_all %] />
|
||||
<label for="deny_all">Запрещать изменения всех полей</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="except_fields_tr" style="background: #FFE0E0">
|
||||
|
@ -87,10 +91,16 @@
|
|||
<script language="JavaScript">
|
||||
var fieldids = { '':'' [% FOR f = my_fielddefs %],"[% f.name | js %]": [% loop.count %][% END %] };
|
||||
var except_field_index = 0;
|
||||
function showhide_allowdeny(chk)
|
||||
function showhide_allowdeny()
|
||||
{
|
||||
var chk = document.getElementById('deny_all').checked;
|
||||
document.getElementById('except_fields_title').innerHTML = chk ? 'Но разрешать:' : '';
|
||||
document.getElementById('except_fields_tr').style.backgroundColor = chk ? '#E0FFE0' : '#FFE0E0';
|
||||
chk = document.getElementById('on_update').checked && !document.getElementById('on_create').checked;
|
||||
if (!chk)
|
||||
document.getElementById('is_freeze').checked = false;
|
||||
document.getElementById('label_for_is_freeze').style.color = chk ? '' : 'gray';
|
||||
document.getElementById('is_freeze').disabled = !chk;
|
||||
}
|
||||
function add_field(fld, val)
|
||||
{
|
||||
|
@ -106,10 +116,10 @@ function add_field(fld, val)
|
|||
except_field_index++;
|
||||
}
|
||||
[%# Загружаем текущее состояние дел %]
|
||||
showhide_allowdeny(document.getElementById('deny_all').checked);
|
||||
[% IF checker.except_fields.except_fields %]
|
||||
[% FOR f = checker.except_fields.except_fields.keys %]
|
||||
add_field("[% f | js %]", "[% checker.except_fields.except_fields.$f | js %]");
|
||||
showhide_allowdeny();
|
||||
[% IF checker.except_fields %]
|
||||
[% FOR f = checker.except_fields.keys %]
|
||||
add_field("[% f | js %]", "[% checker.except_fields.$f | js %]");
|
||||
[% END %]
|
||||
[% ELSE %]
|
||||
add_field();
|
||||
|
|
|
@ -142,7 +142,6 @@ sub reload
|
|||
if ($@)
|
||||
{
|
||||
warn $@;
|
||||
$INC{$key} ||= $file;
|
||||
}
|
||||
$STATS->{$file} = $mtime;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue