root/branches/release-41/plugins/MultiBlog/lib/MultiBlog.pm @ 2727

Revision 2727, 11.7 kB (checked in by bchoate, 17 months ago)

Updated MultiBlog to issue triggered publishing for scheduled posts. BugId:80355

  • Property svn:keywords set to Id
Line 
1# Movable Type (r) Open Source (C) 2006-2008 Six Apart, Ltd.
2# This program is distributed under the terms of the
3# GNU General Public License, version 2.
4#
5# $Id$
6
7# Original Copyright (c) 2004-2006 David Raynes
8
9package MultiBlog;
10
11use strict;
12use warnings;
13
14# Blog-level Access override statuses
15sub DENIED  () { 1 }
16sub ALLOWED () { 2 }
17
18sub preprocess_native_tags {
19    my ( $ctx, $args, $cond ) = @_;
20    my $plugin = MT::Plugin::MultiBlog->instance;
21
22    my $tag = lc $ctx->stash('tag');
23
24    # If we're running under MT-Search, set the context based on the search
25    # parameters available.
26    unless ($args->{blog_id} || $args->{include_blogs} || $args->{exclude_blogs}) {
27        my $app = MT->instance;
28        if ($app->isa('MT::App::Search')) {
29            if (my $excl = $app->{searchparam}{ExcludeBlogs}) {
30                $args->{exclude_blogs} ||= join ',', keys %$excl;
31            } elsif (my $incl = $app->{searchparam}{IncludeBlogs}) {
32                $args->{include_blogs} = join ',', keys %$incl;
33            } 
34            if (($args->{include_blogs} || $args->{exclude_blogs}) && $args->{blog_id}) {
35                delete $args->{blog_id};
36            }
37        }
38    }
39
40   # Filter through MultiBlog's access controls.  If no blogs
41   # are accessible given the specified attributes, we return
42   # NULL or an error if one occured.
43    if ( ! filter_blogs_from_args($plugin, $ctx, $args) ) {
44        return $ctx->errstr ? $ctx->error($ctx->errstr) : '';
45    }
46    # Explicity set blog_id for MTInclude if not specified
47    # so that it never gets a multiblog context from MTMultiBlog
48    elsif ($tag eq 'include' and ! exists $args->{blog_id}) {
49        my $local_blog_id = $ctx->stash('local_blog_id');
50        if (defined $local_blog_id) {
51            $args->{blog_id} = $ctx->stash('local_blog_id');
52        }
53    }
54    # If no include_blogs/exclude_blogs specified look for a
55    # previously set MTMultiBlog context
56    elsif ( my $mode = $ctx->stash('multiblog_context') ) {
57        $args->{$mode} = $ctx->stash('multiblog_blog_ids');       
58    }
59
60    # Save local blog ID for all tags other than
61    # MTMultiBlog since that tag handles it itself.
62    local $ctx->{__stash}{local_blog_id} = $ctx->stash('blog_id') 
63        unless $ctx->stash('multiblog_context');
64    # Remove local blog ID from MTTags since it is cross-blog
65    # and hence MTMultiBlogIfLocalBlog doesn't make sense there.   
66    local $ctx->{__stash}{local_blog_id} = 0 if $tag eq 'tags';
67
68    # Call original tag handler with new args
69    defined(my $result = $ctx->super_handler( $args, $cond ))
70        or return $ctx->error($ctx->errstr);
71    return $result;
72}
73
74
75sub post_feedback_save {
76    my $plugin = shift;
77    my ( $trigger, $eh, $feedback ) = @_;
78    if ( $feedback->visible ) {
79        my $blog_id = $feedback->blog_id;
80        my $app = MT->instance;
81        foreach my $scope ("blog:$blog_id", "system") {
82            my $d = $plugin->get_config_value( $scope eq 'system' ? 'all_triggers' : 'other_triggers', $scope );
83            while ( my ( $id, $a ) = each( %{ $d->{$trigger} } ) ) {
84                next if $id == $blog_id;
85                perform_mb_action( $app, $id, $_ ) foreach keys %$a;
86            }
87        }
88    }
89}
90
91sub post_entry_save {
92    my $plugin = shift;
93    my ( $eh, $app, $entry ) = @_;
94    my $blog_id = $entry->blog_id;
95
96    foreach my $scope ("blog:$blog_id", "system") {
97        my $d = $plugin->get_config_value( $scope eq 'system' ? 'all_triggers' : 'other_triggers', $scope );
98        while ( my ( $id, $a ) = each( %{ $d->{'entry_save'} } ) ) {
99            next if $id == $blog_id;
100            perform_mb_action( $app, $id, $_ ) foreach keys %$a;
101        }
102
103        require MT::Entry;
104        if ( ( $entry->status || 0 ) == MT::Entry::RELEASE() ) {
105            while ( my ( $id, $a ) = each( %{ $d->{'entry_pub'} } ) ) {
106                next if $id == $blog_id;
107                perform_mb_action( $app, $id, $_ ) foreach keys %$a;
108            }
109        }
110    }
111}
112
113sub post_entry_pub {
114    my $plugin = shift;
115    my ( $eh, $app, $entry ) = @_;
116    my $blog_id = $entry->blog_id;
117
118    foreach my $scope ("blog:$blog_id", "system") {
119        my $d = $plugin->get_config_value( $scope eq 'system' ? 'all_triggers' : 'other_triggers', $scope );
120        require MT::Entry;
121        if ( ( $entry->status || 0 ) == MT::Entry::RELEASE() ) {
122            while ( my ( $id, $a ) = each( %{ $d->{'entry_pub'} } ) ) {
123                next if $id == $blog_id;
124                perform_mb_action( $app, $id, $_ ) foreach keys %$a;
125            }
126        }
127    }
128}
129
130sub perform_mb_action {
131    my ( $app, $blog_id, $action ) = @_;
132
133    # Don't rebuild the same thing twice in a request
134    require MT::Request;
135    my $r = MT::Request->instance;
136    my $rebuilt = $r->stash('multiblog_rebuilt') || {};
137    return if exists $rebuilt->{"$blog_id,$action"};
138    $rebuilt->{"$blog_id,$action"} = 1;
139    $r->stash('multiblog_rebuilt', $rebuilt);
140
141    # If the action we are performing starts with ri
142    # we rebuild indexes for the given blog_id
143    if ( $action =~ /^ri/ ) {
144        $app->rebuild_indexes( BlogID => $blog_id );
145
146        # And if the action contains a p
147        # we send out pings for the given blog_id too
148        if ( $action =~ /p/ ) {
149            $app->ping( BlogID => $blog_id );
150        }
151    }
152}
153
154sub filter_blogs_from_args { 
155    my ($plugin, $ctx, $args) = @_;
156
157    # SANITY CHECK ON ARGUMENTS
158    my $err;
159    # Set and clean up working variables
160    my $incl = $args->{include_blogs} || $args->{blog_id} || $args->{blog_ids};
161    my $excl = $args->{exclude_blogs};
162    for ($incl,$excl) {
163        next unless $_;
164        s{\s+}{}g ; # Remove spaces
165    }
166   
167    # If there are no multiblog arguments to filter, we don't need to be here
168    return 1 unless $incl or $excl;
169
170    # Only one multiblog argument can be used
171    my $arg_count = scalar grep { $_ and $_ ne '' } $args->{include_blogs}, 
172                                                    $args->{blog_id}, 
173                                                    $args->{blog_ids}, 
174                                                    $args->{exclude_blogs};
175    if ($arg_count > 1) {
176        $err = $plugin->translate('The include_blogs, exclude_blogs, blog_ids and blog_id attributes cannot be used together.');
177    }
178    # exclude_blogs="all" is not allowed
179    elsif ($excl and $excl =~ /all/i) {
180        $err = $plugin->translate('The attribute exclude_blogs cannot take "all" for a value.');
181    }
182    # blog_id only accepts a single blog ID
183    elsif ($args->{blog_id} and $args->{blog_id} !~ /^\d+$/) {
184        $err = $plugin->translate('The value of the blog_id attribute must be a single blog ID.');
185    }
186    # Make sure include_blogs/exclude_blogs is valid
187    elsif (($incl || $excl) ne 'all' 
188        and ($incl || $excl) !~ /^\d+([,-]\d+)*$/) {
189        $err =  $plugin->translate('The value for the include_blogs/exclude_blogs attributes must be one or more blog IDs, separated by commas.');
190    }
191    return $ctx->error($err) if $err;
192
193    # Prepare for filter_blogs
194    my ($attr, $val, @blogs);
195    if ($incl) {
196        ($attr, $val) = ('include_blogs', $incl);
197    } else {
198        ($attr, $val) = ('exclude_blogs', $excl);
199    }
200
201    if ($val =~ m/-/) {
202        my @list = split /\s*,\s*/, $val;
203        foreach my $id (@list) {
204            if ($id =~ m/^(\d+)-(\d+)$/) {
205                push @blogs, $_ for $1..$2;
206            } else {
207                push @blogs, $id;
208            }
209        }
210    }
211    else {
212        @blogs = split(/\s*,\s*/, $val);
213    }
214
215    # Filter the blogs using the MultiBlog access controls
216    ($attr, @blogs) = filter_blogs($plugin, $ctx, $attr, @blogs);
217    return unless $attr && @blogs;
218   
219    # Rewrite the args to the modifed value
220    delete $args->{blog_ids} if exists $args->{blog_ids};  # Deprecated
221    if ($args->{blog_id}) {
222        $args->{'blog_id'} = $blogs[0];
223    } else {
224        delete $args->{include_blogs};
225        delete $args->{exclude_blogs};
226        $args->{$attr} = join(',', @blogs);
227    }
228    1;
229}
230
231## Get a mode (include/exclude) and list of blogs
232## Process list using system default access setting and
233## any blog-level overrides.
234## Returns empty list if no blogs can be used
235sub filter_blogs {
236    my $plugin = shift;
237    my ( $ctx, $is_include, @blogs ) = @_;
238
239    # Set flag to indicate whether @blogs are to be included or excluded
240    $is_include = $is_include eq 'include_blogs' ? 1 : 0;
241
242    # Set local blog
243    my $this_blog = $ctx->stash('blog_id') || 0;
244
245    # Get the MultiBlog system config for default access and overrides
246    my $default_access_allowed = 
247        $plugin->get_config_value( 'default_access_allowed', 'system' );
248    my $access_overrides = 
249        $plugin->get_config_value( 'access_overrides', 'system' ) || {};
250
251    # System setting allows access by default
252    if ($default_access_allowed) {
253
254        # include_blogs="all"
255        if ($is_include and $blogs[0] eq "all") {
256            # Check for any deny overrides.
257            # If found, switch to exclude_blogs="..."
258            my @deny = grep {     $_ != $this_blog 
259                              and exists $access_overrides->{$_} 
260                              and $access_overrides->{$_} == DENIED
261                            } keys %$access_overrides;
262            return @deny ? ('exclude_blogs', @deny)
263                         : ('include_blogs', 'all');
264         }
265         # include_blogs="1,2,3,4"
266         elsif ($is_include and @blogs) {
267            # Remove any included blogs that are specifically deny override
268            # Return undef is all specified blogs are deny override
269            my @allow = grep {    $_ == $this_blog 
270                               or ! exists $access_overrides->{$_} 
271                               or $access_overrides->{$_} == ALLOWED
272                             } @blogs;
273            return @allow ? ('include_blogs', @allow) : undef;
274         }
275         # exclude_blogs="1,2,3,4"
276         else {
277             # Add any deny overrides blogs to the list and de-dupe
278             push(@blogs, grep { $_ != $this_blog
279                                 and $access_overrides->{$_} == DENIED
280                               } keys %$access_overrides);
281            my %seen;
282            @seen{@blogs} = ();
283            @blogs = keys %seen;
284            return ('exclude_blogs', @blogs);
285         }
286    }
287    # System setting does not allow access by default
288    else {
289        # include_blogs="all"
290        if ($is_include and $blogs[0] eq "all") {
291            # Enumerate blogs from allow override
292            # Hopefully this is significantly smaller than @all_blogs
293            my @allow = grep { $_ == $this_blog 
294                               or $access_overrides->{$_} == ALLOWED
295                             } ($this_blog, keys %$access_overrides);
296            return @allow ? ('include_blogs', @allow) : undef;
297        }
298        # include_blogs="1,2,3,4"
299        elsif ($is_include and @blogs) {
300            # Filter @blogs returning only those with allow override
301            my @allow = grep {    $_ == $this_blog
302                               or ( exists $access_overrides->{$_} 
303                                    and $access_overrides->{$_} == ALLOWED)
304                             } @blogs;
305            return @allow ? ('include_blogs', @allow) : undef;
306        }
307        # exclude_blogs="1,2,3,4"
308        else {
309            # Get allow override blogs and then omit
310            # the specified excluded blogs.
311            my @allow = grep { $_ == $this_blog
312                               or $access_overrides->{$_} == ALLOWED
313                             } ($this_blog, keys %$access_overrides);
314            my %seen;
315            @seen{@blogs} = ();
316            @blogs = grep { ! $seen{$_} } @allow;
317            return @blogs ? ('include_blogs', @blogs) : undef;
318        }
319    }
320}
321
322
3231;
Note: See TracBrowser for help on using the browser.