# This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. # # This Source Code Form is "Incompatible With Secondary Licenses", as # defined by the Mozilla Public License, v. 2.0. package Bugzilla::Extension::ZPushNotify; use 5.10.1; use strict; use warnings; use base qw(Bugzilla::Extension); our $VERSION = '1'; use Bugzilla; # # insert into the notifications table # sub _notify { my ($bug_id, $delta_ts) = @_; # beacuse the push_notify table is hot, we defer updating it until the # request has completed. this ensures we are outside the scope of any # transaction blocks. my $stash = Bugzilla->request_cache->{ZPushNotify_stash} ||= []; push @$stash, { bug_id => $bug_id, delta_ts => $delta_ts }; } sub request_cleanup { my $stash = Bugzilla->request_cache->{ZPushNotify_stash} || return; my $dbh = Bugzilla->dbh; foreach my $rh (@$stash) { # using REPLACE INTO or INSERT .. ON DUPLICATE KEY UPDATE results in a # lock on the bugs table due to the FK. this way is more verbose but # only locks the push_notify table. $dbh->bz_start_transaction(); my ($id) = $dbh->selectrow_array( "SELECT id FROM push_notify WHERE bug_id=?", undef, $rh->{bug_id} ); if ($id) { $dbh->do( "UPDATE push_notify SET delta_ts=? WHERE id=?", undef, $rh->{delta_ts}, $id ); } else { $dbh->do( "INSERT INTO push_notify (bug_id, delta_ts) VALUES (?, ?)", undef, $rh->{bug_id}, $rh->{delta_ts} ); } $dbh->bz_commit_transaction(); } } # # object hooks # sub object_end_of_create { my ($self, $args) = @_; my $object = $args->{object}; return unless Bugzilla->params->{enable_simple_push}; return unless $object->isa('Bugzilla::Flag'); _notify($object->bug->id, $object->creation_date); } sub flag_updated { my ($self, $args) = @_; my $flag = $args->{flag}; my $timestamp = $args->{timestamp}; my $changes = $args->{changes}; return unless Bugzilla->params->{enable_simple_push}; return unless scalar(keys %$changes); _notify($flag->bug->id, $timestamp); } sub flag_deleted { my ($self, $args) = @_; my $flag = $args->{flag}; my $timestamp = $args->{timestamp}; return unless Bugzilla->params->{enable_simple_push}; _notify($flag->bug->id, $timestamp); } sub attachment_end_of_update { my ($self, $args) = @_; return unless Bugzilla->params->{enable_simple_push}; return unless scalar keys %{ $args->{changes} }; return unless my $object = $args->{object}; _notify($object->bug->id, $object->modification_time); } sub object_before_delete { my ($self, $args) = @_; return unless Bugzilla->params->{enable_simple_push}; return unless my $object = $args->{object}; if ($object->isa('Bugzilla::Attachment')) { my $timestamp = Bugzilla->dbh->selectrow_array('SELECT LOCALTIMESTAMP(0)'); _notify($object->bug->id, $timestamp); } } sub bug_end_of_update_delta_ts { my ($self, $args) = @_; return unless Bugzilla->params->{enable_simple_push}; _notify($args->{bug_id}, $args->{timestamp}); } sub bug_end_of_create { my ($self, $args) = @_; return unless Bugzilla->params->{enable_simple_push}; _notify($args->{bug}->id, $args->{timestamp}); } # # schema / param # sub db_schema_abstract_schema { my ($self, $args) = @_; $args->{'schema'}->{'push_notify'} = { FIELDS => [ id => { TYPE => 'INTSERIAL', NOTNULL => 1, PRIMARYKEY => 1, }, bug_id => { TYPE => 'INT3', NOTNULL => 1, REFERENCES => { TABLE => 'bugs', COLUMN => 'bug_id', DELETE => 'CASCADE' }, }, delta_ts => { TYPE => 'DATETIME', NOTNULL => 1, }, ], INDEXES => [ push_notify_idx => { FIELDS => [ 'bug_id' ], TYPE => 'UNIQUE', }, ], }; } sub config_modify_panels { my ($self, $args) = @_; push @{ $args->{panels}->{advanced}->{params} }, { name => 'enable_simple_push', type => 'b', default => 0, }; } __PACKAGE__->NAME;