root/branches/release-31/plugins/MultiBlog/lib/MultiBlog.pm @ 1522

Revision 1522, 11.1 kB (checked in by bchoate, 21 months ago)

More constant declaration changes.

  • 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 perform_mb_action {
114    my ( $app, $blog_id, $action ) = @_;
115
116    # Don't rebuild the same thing twice in a request
117    require MT::Request;
118    my $r = MT::Request->instance;
119    my $rebuilt = $r->stash('multiblog_rebuilt') || {};
120    return if exists $rebuilt->{"$blog_id,$action"};
121    $rebuilt->{"$blog_id,$action"} = 1;
122    $r->stash('multiblog_rebuilt', $rebuilt);
123
124    # If the action we are performing starts with ri
125    # we rebuild indexes for the given blog_id
126    if ( $action =~ /^ri/ ) {
127        $app->rebuild_indexes( BlogID => $blog_id );
128
129        # And if the action contains a p
130        # we send out pings for the given blog_id too
131        if ( $action =~ /p/ ) {
132            $app->ping( BlogID => $blog_id );
133        }
134    }
135}
136
137sub filter_blogs_from_args { 
138    my ($plugin, $ctx, $args) = @_;
139
140    # SANITY CHECK ON ARGUMENTS
141    my $err;
142    # Set and clean up working variables
143    my $incl = $args->{include_blogs} || $args->{blog_id} || $args->{blog_ids};
144    my $excl = $args->{exclude_blogs};
145    for ($incl,$excl) {
146        next unless $_;
147        s{\s+}{}g ; # Remove spaces
148    }
149   
150    # If there are no multiblog arguments to filter, we don't need to be here
151    return 1 unless $incl or $excl;
152
153    # Only one multiblog argument can be used
154    my $arg_count = scalar grep { $_ and $_ ne '' } $args->{include_blogs}, 
155                                                    $args->{blog_id}, 
156                                                    $args->{blog_ids}, 
157                                                    $args->{exclude_blogs};
158    if ($arg_count > 1) {
159        $err = $plugin->translate('The include_blogs, exclude_blogs, blog_ids and blog_id attributes cannot be used together.');
160    }
161    # exclude_blogs="all" is not allowed
162    elsif ($excl and $excl =~ /all/i) {
163        $err = $plugin->translate('The attribute exclude_blogs cannot take "all" for a value.');
164    }
165    # blog_id only accepts a single blog ID
166    elsif ($args->{blog_id} and $args->{blog_id} !~ /^\d+$/) {
167        $err = $plugin->translate('The value of the blog_id attribute must be a single blog ID.');
168    }
169    # Make sure include_blogs/exclude_blogs is valid
170    elsif (($incl || $excl) ne 'all' 
171        and ($incl || $excl) !~ /^\d+([,-]\d+)*$/) {
172        $err =  $plugin->translate('The value for the include_blogs/exclude_blogs attributes must be one or more blog IDs, separated by commas.');
173    }
174    return $ctx->error($err) if $err;
175
176    # Prepare for filter_blogs
177    my ($attr, $val, @blogs);
178    if ($incl) {
179        ($attr, $val) = ('include_blogs', $incl);
180    } else {
181        ($attr, $val) = ('exclude_blogs', $excl);
182    }
183
184    if ($val =~ m/-/) {
185        my @list = split /\s*,\s*/, $val;
186        foreach my $id (@list) {
187            if ($id =~ m/^(\d+)-(\d+)$/) {
188                push @blogs, $_ for $1..$2;
189            } else {
190                push @blogs, $id;
191            }
192        }
193    }
194    else {
195        @blogs = split(/\s*,\s*/, $val);
196    }
197
198    # Filter the blogs using the MultiBlog access controls
199    ($attr, @blogs) = filter_blogs($plugin, $ctx, $attr, @blogs);
200    return unless $attr && @blogs;
201   
202    # Rewrite the args to the modifed value
203    delete $args->{blog_ids} if exists $args->{blog_ids};  # Deprecated
204    if ($args->{blog_id}) {
205        $args->{'blog_id'} = $blogs[0];
206    } else {
207        delete $args->{include_blogs};
208        delete $args->{exclude_blogs};
209        $args->{$attr} = join(',', @blogs);
210    }
211    1;
212}
213
214## Get a mode (include/exclude) and list of blogs
215## Process list using system default access setting and
216## any blog-level overrides.
217## Returns empty list if no blogs can be used
218sub filter_blogs {
219    my $plugin = shift;
220    my ( $ctx, $is_include, @blogs ) = @_;
221
222    # Set flag to indicate whether @blogs are to be included or excluded
223    $is_include = $is_include eq 'include_blogs' ? 1 : 0;
224
225    # Set local blog
226    my $this_blog = $ctx->stash('blog_id') || 0;
227
228    # Get the MultiBlog system config for default access and overrides
229    my $default_access_allowed = 
230        $plugin->get_config_value( 'default_access_allowed', 'system' );
231    my $access_overrides = 
232        $plugin->get_config_value( 'access_overrides', 'system' ) || {};
233
234    # System setting allows access by default
235    if ($default_access_allowed) {
236
237        # include_blogs="all"
238        if ($is_include and $blogs[0] eq "all") {
239            # Check for any deny overrides.
240            # If found, switch to exclude_blogs="..."
241            my @deny = grep {     $_ != $this_blog 
242                              and exists $access_overrides->{$_} 
243                              and $access_overrides->{$_} == DENIED
244                            } keys %$access_overrides;
245            return @deny ? ('exclude_blogs', @deny)
246                         : ('include_blogs', 'all');
247         }
248         # include_blogs="1,2,3,4"
249         elsif ($is_include and @blogs) {
250            # Remove any included blogs that are specifically deny override
251            # Return undef is all specified blogs are deny override
252            my @allow = grep {    $_ == $this_blog 
253                               or ! exists $access_overrides->{$_} 
254                               or $access_overrides->{$_} == ALLOWED
255                             } @blogs;
256            return @allow ? ('include_blogs', @allow) : undef;
257         }
258         # exclude_blogs="1,2,3,4"
259         else {
260             # Add any deny overrides blogs to the list and de-dupe
261             push(@blogs, grep { $_ != $this_blog
262                                 and $access_overrides->{$_} == DENIED
263                               } keys %$access_overrides);
264            my %seen;
265            @seen{@blogs} = ();
266            @blogs = keys %seen;
267            return ('exclude_blogs', @blogs);
268         }
269    }
270    # System setting does not allow access by default
271    else {
272        # include_blogs="all"
273        if ($is_include and $blogs[0] eq "all") {
274            # Enumerate blogs from allow override
275            # Hopefully this is significantly smaller than @all_blogs
276            my @allow = grep { $_ == $this_blog 
277                               or $access_overrides->{$_} == ALLOWED
278                             } ($this_blog, keys %$access_overrides);
279            return @allow ? ('include_blogs', @allow) : undef;
280        }
281        # include_blogs="1,2,3,4"
282        elsif ($is_include and @blogs) {
283            # Filter @blogs returning only those with allow override
284            my @allow = grep {    $_ == $this_blog
285                               or ( exists $access_overrides->{$_} 
286                                    and $access_overrides->{$_} == ALLOWED)
287                             } @blogs;
288            return @allow ? ('include_blogs', @allow) : undef;
289        }
290        # exclude_blogs="1,2,3,4"
291        else {
292            # Get allow override blogs and then omit
293            # the specified excluded blogs.
294            my @allow = grep { $_ == $this_blog
295                               or $access_overrides->{$_} == ALLOWED
296                             } ($this_blog, keys %$access_overrides);
297            my %seen;
298            @seen{@blogs} = ();
299            @blogs = grep { ! $seen{$_} } @allow;
300            return @blogs ? ('include_blogs', @blogs) : undef;
301        }
302    }
303}
304
305
3061;
Note: See TracBrowser for help on using the browser.