diff --git a/editcheckers.cgi b/editcheckers.cgi index b255f7019..bb41f611f 100755 --- a/editcheckers.cgi +++ b/editcheckers.cgi @@ -52,6 +52,15 @@ if ($params->{save}) ($params->{on_update} ? 1 : 0) * CF_UPDATE | ($params->{on_create} ? 1 : 0) * CF_CREATE | ($params->{deny_all} ? 1 : 0) * CF_DENY; + # Триггеры + my $triggers; + for (keys %$params) + { + if ($params->{$_} !~ /^\s*$/so && /^triggers_(.*)$/so) + { + $triggers->{$1} = $params->{$_}; + } + } # Создаём/обновляем my $ch; if ($params->{create}) @@ -62,6 +71,7 @@ if ($params->{save}) message => $params->{message}, flags => $flags, except_fields => $except, + triggers => $triggers, }); } else @@ -71,6 +81,7 @@ if ($params->{save}) $ch->set_message($params->{message}); $ch->set_flags($flags); $ch->set_except_fields($except); + $ch->set_triggers($triggers); $ch->update; } delete_token($params->{token}); diff --git a/extensions/custis/lib/Bugzilla/Checker.pm b/extensions/custis/lib/Bugzilla/Checker.pm index dabe7539e..f72aa9d15 100644 --- a/extensions/custis/lib/Bugzilla/Checker.pm +++ b/extensions/custis/lib/Bugzilla/Checker.pm @@ -13,11 +13,18 @@ use Bugzilla::Error; use constant DB_TABLE => 'checkers'; use constant { - CF_FREEZE => 0x01, # да => заморозка, нет => проверка значений - CF_FATAL => 0x02, # да => ошибка, нет => предупреждение - CF_CREATE => 0x04, # да => проверять при создании бага, нет => не проверять - CF_UPDATE => 0x08, # да => проверять при обновлении бага, нет => не проверять - CF_DENY => 0x10, # да => запрещать изменения всех полей, кроме..., нет => разрешать изменения всех полей, кроме... + # Да => проверка старого состояния бага ("заморозка") + # Нет => проверка нового состояния бага ("проверка новых значений") + CF_FREEZE => 0x01, + # Да => ошибка, нет => предупреждение + CF_FATAL => 0x02, + # Да => проверять при создании бага, нет => не проверять + CF_CREATE => 0x04, + # Да => проверять при обновлении бага, нет => не проверять + CF_UPDATE => 0x08, + # Да => запрещать изменения всех полей, кроме except_fields + # Нет => разрешать изменения всех полей, кроме except_fields + CF_DENY => 0x10, }; our @EXPORT = qw(CF_FREEZE CF_FATAL CF_CREATE CF_UPDATE CF_DENY); @@ -38,6 +45,8 @@ use constant DB_COLUMNS => ( # если !(flags & CF_DENY), то запретить только их, # если !(flags & CF_DENY) и их нет, то flags |= CF_DENY 'except_fields', + # Триггеры - действия над полями багов (требует CF_FREEZE и !CF_FATAL) + 'triggers', ); use constant NAME_FIELD => 'message'; use constant ID_FIELD => 'id'; @@ -56,6 +65,7 @@ use constant UPDATE_COLUMNS => ( 'message', 'sql_code', 'except_fields', + 'triggers', ); # Перепостроение и перекэширование SQL-запроса в базу @@ -95,6 +105,10 @@ sub create { $params->{except_fields} = encode_json($params->{except_fields}); } + if ($params->{triggers}) + { + $params->{triggers} = encode_json($params->{triggers}); + } my $self = Bugzilla::Object::create($class, $params); $self->update; $self->query->set_shared_with_group(Bugzilla::Group->check({ name => 'bz_editcheckers' })); @@ -107,6 +121,10 @@ sub update my $self = shift; $self->refresh_sql; $self->query->set_shared_with_group(Bugzilla::Group->check({ name => 'bz_editcheckers' })); + if ($self->triggers) + { + $self->{flags} |= CF_FREEZE; + } $self->SUPER::update(@_); } @@ -147,14 +165,14 @@ sub flags { $_[0]->{flags} } # Отдельные флаги sub is_freeze { $_[0]->{flags} & CF_FREEZE } -sub is_fatal { $_[0]->{flags} & CF_FATAL } +sub is_fatal { ($_[0]->{flags} & CF_FATAL) && !$_[0]->triggers } 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 +# Исключать изменения поля field_name на значение value, +# либо на любое значение, если value = undef sub except_fields { my $self = shift; @@ -165,6 +183,21 @@ sub except_fields return $self->{except_fields_obj}; } +# { field_name => value } +# Изменить значение поля field_name на value. Для полей с множествами значений +# field_name также может быть add_ или remove_, что означает +# добавить значение или удалить значение соответственно. +# FIXME Пока поддерживается только add_cc. +sub triggers +{ + my $self = shift; + if (!exists $self->{triggers_obj}) + { + $self->{triggers_obj} = $self->{triggers} ? decode_json($self->{triggers}) : undef; + } + return $self->{triggers_obj}; +} + sub name { my $self = shift; @@ -204,5 +237,12 @@ sub set_except_fields delete $self->{except_fields_obj}; } +sub set_triggers +{ + my ($self, $value) = @_; + $self->set('triggers', $value ? encode_json($value) : undef); + delete $self->{triggers_obj}; +} + 1; __END__ diff --git a/extensions/custis/lib/Checkers.pm b/extensions/custis/lib/Checkers.pm index c15e27570..417f76563 100644 --- a/extensions/custis/lib/Checkers.pm +++ b/extensions/custis/lib/Checkers.pm @@ -75,7 +75,21 @@ sub alert { my ($bug, $is_new) = @_; my (@fatal, @warn); - map { $_->is_fatal ? push(@fatal, $_) : push(@warn, $_) } @{$bug->{failed_checkers} || []}; + for (@{$bug->{failed_checkers} || []}) + { + if ($_->triggers) + { + # Триггеры нас вообще не расстраивают + } + elsif ($_->is_fatal) + { + push(@fatal, $_); + } + else + { + push(@warn, $_); + } + } my $force = 1 && Bugzilla->cgi->param('force_checkers'); if (!@fatal && (!@warn || $force)) { @@ -110,15 +124,15 @@ sub show_checker_errors { my ($bugs) = @_; $bugs ||= Bugzilla->request_cache->{failed_checkers}; - return if !$bugs || !grep { @{$_->{failed_checkers} || []} } @$bugs; + return if !$bugs || !grep { grep { !$_->triggers } @{$_->{failed_checkers} || []} } @$bugs; if (Bugzilla->error_mode != ERROR_MODE_WEBPAGE) { my $info = [ map { { bug_id => $_->bug_id, - errors => [ map { $_->message } @{$_->{failed_checkers}} ] + errors => [ map { $_->message } grep { !$_->triggers } @{$_->{failed_checkers}} ] } } - grep { $_->{failed_checkers} } @$bugs + grep { @{$_->{failed_checkers} || []} } @$bugs ]; ThrowUserError('checks_failed', { bugs => $info }); } @@ -138,7 +152,7 @@ sub freeze_failed_checkers $failedbugs && @$failedbugs || return undef; return [ map { [ $_->bug_id, [ map { $_->id } @{$_->{failed_checkers}} ] ] } - grep { $_->{failed_checkers} } @$failedbugs + grep { @{$_->{failed_checkers} || []} } @$failedbugs ]; } @@ -160,10 +174,16 @@ sub unfreeze_failed_checkers sub filter_failed_checkers { my ($checkers, $changes, $bug) = @_; - # фильтруем подошедшие проверки по изменённым полям + # Фильтруем подошедшие проверки по изменённым полям my @rc; for (@$checkers) { + if ($_->triggers) + { + # Не трогаем триггеры + push @rc, $_; + next; + } my $e = $_->except_fields; my $ok = 1; if ($_->deny_all) @@ -220,14 +240,41 @@ sub filter_failed_checkers @$checkers = @rc; } +# Запустить триггеры для бага $bug из $bug->{failed_checkers} +sub run_triggers +{ + my ($bug) = @_; + my $modified = 0; + for (my $i = $#{$bug->{failed_checkers}}; $i >= 0; $i--) + { + my $checker = $bug->{failed_checkers}->[$i]; + if ($checker->triggers) + { + if ($checker->triggers->{add_cc}) + { + # FIXME Пока поддерживается только добавление CC, но несложно докрутить произвольные изменения + for (split /[\s,]+/, $checker->triggers->{add_cc}) + { + $bug->add_cc($_); + $modified = 1; + } + } + } + # FIXME Нужно показывать информацию о применённом триггере (сейчас оно работает втихаря) + splice @{$bug->{failed_checkers}}, $i, 1; + } + return $modified; +} + # hooks: sub bug_pre_update { my ($args) = @_; my $bug = $args->{bug}; - # запускаем проверки, работающие ДО внесения изменений (заморозка багов) + # запускаем проверки, работающие ДО внесения изменений - заморозку багов и триггеры $bug->{failed_checkers} = check($bug->bug_id, CF_FREEZE | CF_UPDATE, CF_FREEZE | CF_UPDATE); + run_triggers($bug); return 1; } @@ -274,6 +321,11 @@ sub bug_end_of_create { alert($bug, 1); } + # А ещё при создании бага триггеры срабатывают отдельным запросом + if (run_triggers($bug)) + { + $bug->update; + } return 1; } diff --git a/extensions/custis/lib/CustisDBHooks.pm b/extensions/custis/lib/CustisDBHooks.pm index cf88b20a6..450fbf8e0 100644 --- a/extensions/custis/lib/CustisDBHooks.pm +++ b/extensions/custis/lib/CustisDBHooks.pm @@ -122,6 +122,7 @@ sub db_schema_abstract_schema push @{$schema->{fielddefs}->{FIELDS}}, add_to_deps => {TYPE => 'INT2', NOTNULL => 1, DEFAULT => 0}; # Bug 68921 - Предикаты корректности из запросов поиска + # Bug 108088 - Триггеры (пока поддерживается только 1 триггер: добавление CC) $schema->{checkers} = { FIELDS => [ id => {TYPE => 'MEDIUMSERIAL', NOTNULL => 1, PRIMARYKEY => 1}, @@ -131,6 +132,7 @@ sub db_schema_abstract_schema message => {TYPE => 'LONGTEXT', NOTNULL => 1}, sql_code => {TYPE => 'LONGTEXT'}, except_fields => {TYPE => 'LONGBLOB'}, + triggers => {TYPE => 'LONGBLOB'}, ], INDEXES => [ checkers_query_id_idx => { FIELDS => ['query_id'] }, @@ -406,6 +408,9 @@ sub install_update_fielddefs $dbh->bz_alter_column('checkers', message => {TYPE => 'LONGTEXT', NOTNULL => 1}); } + # Bug 108088 - Триггеры (пока поддерживается только 1 триггер: добавление CC) + $dbh->bz_add_column('checkers', triggers => {TYPE => 'LONGBLOB'}); + # Устанавливаем значение buglist в правильное my @yes = map { $_->{name} } grep { $_->{buglist} } Bugzilla::Field::DEFAULT_FIELDS; my @no = map { $_->{name} } grep { !$_->{buglist} } Bugzilla::Field::DEFAULT_FIELDS; diff --git a/extensions/custis/template/en/default/edit-checkers.html.tmpl b/extensions/custis/template/en/default/edit-checkers.html.tmpl index 76fe520dd..52b905c0f 100644 --- a/extensions/custis/template/en/default/edit-checkers.html.tmpl +++ b/extensions/custis/template/en/default/edit-checkers.html.tmpl @@ -24,11 +24,22 @@ [% FOR c = checkers %] [% c.name | html %] - - [% c.is_fatal ? "Жёсткий" : "Мягкий" %] + [% IF c.triggers %] + + Триггер + [% ELSIF c.is_fatal %] + + Жёсткий + + [% ELSE %] + + Мягкий + + [% END %] @@ -56,14 +67,15 @@ [% ELSE %]

Редактирование предиката [% checker.name | html %]

[% END %] -
+ + [% IF create %] + + [% ELSE %] + + [% END %] - [% IF create %] - - [% ELSE %] - - [% END %] + - + + + + - + + + + + + + + + + + + + + + +
Сохранённый запрос:
Сообщение об ошибке: + + + + +
Описание проверки:
Параметры:Момент проверки:
-
+ +