root/branches/release-41/lib/MT/CMS/Dashboard.pm @ 2812

Revision 2812, 16.6 kB (checked in by breese, 17 months ago)

fixed bug 80518 - finalized the upgrade widget copy

  • Property svn:keywords set to Id Revision
Line 
1package MT::CMS::Dashboard;
2
3use strict;
4use MT::Util qw( epoch2ts );
5
6sub dashboard {
7    my $app = shift;
8    my (%param) = @_;
9
10    if ( $app->request('fresh_login') ) {
11        if ( !$app->param('blog_id') ) {
12
13            # return to the last blog they visted, if any
14            my $fav_blogs = $app->user->favorite_blogs || [];
15            my $blog_id = $fav_blogs->[0] if @$fav_blogs;
16            $app->param( 'blog_id', $blog_id ) if $blog_id;
17            $app->delete_param('blog_id') unless $app->is_authorized;
18        }
19    }
20
21    my $param = \%param;
22
23    $param->{redirect}   ||= $app->param('redirect');
24    $param->{permission} ||= $app->param('permission');
25    $param->{saved}      ||= $app->param('saved');
26
27    $param->{system_overview_nav} = $app->param('blog_id') ? 0 : defined($app->param('blog_id')) ? 1 : 0;
28    $param->{quick_search}        = 0;
29    $param->{no_breadcrumbs}      = 1;
30    $param->{screen_class}        = "dashboard";
31    $param->{screen_id}           = "dashboard";
32
33    my $default_widgets = {
34        'blog_stats' =>
35          { param => { tab => 'entry' }, order => 1, set => 'main' },
36        'this_is_you-1' => { order => 1, set => 'sidebar' },
37        'mt_shortcuts'  => { order => 2, set => 'sidebar' },
38        'mt_news'       => { order => 3, set => 'sidebar' },
39    };
40
41    require MT::FileMgr;
42    my $fmgr = MT::FileMgr->new('Local');
43    foreach my $subdir (qw( uploads userpics )) {
44        $param->{support_path} =
45            File::Spec->catdir( $app->static_file_path, 'support', $subdir );
46        if ( !$fmgr->exists( $param->{support_path} ) ) {
47            $fmgr->mkpath( $param->{support_path} );
48        }
49        if ( $fmgr->exists( $param->{support_path} )
50             && $fmgr->can_write( $param->{support_path} ) )
51        {
52            $param->{has_uploads_path} = 1;
53        } else {
54            $param->{has_uploads_path} = 0;
55            last;
56        }
57    }
58    unless ( exists $param->{has_uploads_path} ) {
59        unless ( $fmgr->exists( $param->{support_path} ) ) {
60            # the path didn't exist - change the warning a little
61            $param->{support_path} =
62                File::Spec->catdir( $app->static_file_path, 'support' );
63        }
64    }
65
66    # We require that the determination of the 'single blog mode'
67    # state be done PRIOR to the generation of the widgets
68    $app->build_blog_selector($param);
69    $app->load_widget_list( 'dashboard', $param, $default_widgets );
70    $param = $app->load_widgets( 'dashboard', $param, $default_widgets );
71    return $app->load_tmpl( "dashboard.tmpl", $param );
72}
73
74sub new_version_widget {
75    my $app = shift;
76    my ( $tmpl, $param ) = @_;
77
78    push @{ $param->{feature_loop} ||= [] },
79      {
80        feature_label => MT->translate('Better, Stronger, Faster'),
81        feature_url  => $app->help_url('mt42/performance.html'),
82        feature_description => MT->translate('Movable Type has undergone a significant overhaul in all aspects of performance. Memory utilization has been reduced, publishing times have been increased significantly and search is now 100x faster!'),
83      },
84      {
85        feature_label => MT->translate('Module Caching'),
86        feature_url  => $app->help_url('mt42/module-caching.html'),
87        feature_description => MT->translate('Template module and widget content can now be cached in the database to dramatically speed up publishing.'),
88      },
89      {
90        feature_label => MT->translate('Improved Template and Design Management'),
91        feature_url  => $app->help_url('mt42/design-enhancements.html'),
92        feature_description => MT->translate('The template editing interface has been enhanced to make designers more efficient at updating their site\'s design. The default templates have also been dramatically simplified to make it easier for you to edit and create the site you want.'),
93      },
94      {
95        feature_label => MT->translate('Threaded Comments'),
96        feature_url  => $app->help_url('mt42/threading.html'),
97        feature_description => MT->translate('Allow commenters on your blog to reply to each other increasing user engagement and creating more dynamic conversations.'),
98      };
99}
100
101sub this_is_you_widget {
102    my $app = shift;
103    my ( $tmpl, $param ) = @_;
104
105    my $user = $app->user;
106
107    # User profile data
108    # Number of posts by this user
109    require MT::Entry;
110    $param->{publish_count} = MT::Entry->count( { author_id => $user->id, } );
111    $param->{draft_count} = MT::Entry->count(
112        {
113            author_id => $user->id,
114            status    => MT::Entry::HOLD(),
115        }
116    );
117    if ( $param->{publish_count} ) {
118        my $iter = MT::Entry->sum_group_by({
119            author_id => $user->id,
120        }, { sum => 'comment_count', group => ['author_id'] });
121        my ($count, $author_id) = $iter->();
122        $param->{comment_count} = $count;
123    }
124
125    my $last_post = MT::Entry->load(
126        {
127            author_id => $user->id,
128            status    => MT::Entry::RELEASE(),
129        },
130        {
131            sort      => 'authored_on',
132            direction => 'descend',
133            limit     => 1,
134        }
135    );
136    if ($last_post) {
137        $param->{last_post_id}      = $last_post->id;
138        $param->{last_post_blog_id} = $last_post->blog_id;
139        $param->{last_post_blog_name} = $last_post->blog->name;
140        $param->{last_post_ts}      = $last_post->authored_on;
141    }
142
143    if (my ($url) = $user->userpic_url()) {
144        $param->{author_userpic_url}    = $url;
145    }
146    $param->{author_userpic_width}  = 50;
147    $param->{author_userpic_height} = 50;
148}
149
150sub mt_news_widget {
151    my $app = shift;
152    my ( $tmpl, $param ) = @_;
153
154    $param->{news_html} = get_newsbox_content($app) || '';
155    $param->{learning_mt_news_html} = get_lmt_content($app) || '';
156}
157
158sub get_newsbox_content {
159    my $app = shift;
160    my $newsbox_url = $app->config('NewsboxURL');
161    if ( $newsbox_url && $newsbox_url ne 'disable' ) {
162        return MT::Util::get_newsbox_html($newsbox_url, 'NW');
163    }
164    return q();
165}
166
167sub get_lmt_content {
168    my $app = shift;
169    my $newsbox_url = $app->config('LearningNewsURL');
170    if ( $newsbox_url && $newsbox_url ne 'disable' ) {
171        return MT::Util::get_newsbox_html($newsbox_url, 'LW');
172    }
173    return q();
174}
175
176sub mt_blog_stats_widget {
177    my $app = shift;
178    my ( $tmpl, $param ) = @_;
179
180    # For stats shown on this page
181    generate_dashboard_stats($app, $param) or return;
182
183    my $tabs = $app->registry('blog_stats_tabs') or return;
184    $tabs = $app->filter_conditional_list($tabs, 'dashboard', ($param->{widget_scope} || ''));
185
186    $param->{tab_html_head} = '';
187    {
188        local $param->{main};
189        local $param->{html_head};
190
191        my %cfgs;
192        my $stat_url = delete $param->{stat_url};
193        while (my ($tab_id, $url) = each %$stat_url) {
194            $param->{has_stat_urls} = 1;
195            $cfgs{$tab_id} = { param => { stat_url => $url } };
196        }
197        $app->build_widgets(
198            set            => 'blog_stats',
199            param          => $param,
200            widgets        => $tabs,
201            widget_cfgs    => \%cfgs,
202            passthru_param => [qw( html_head js_include tabs active_stats_panel_updates )],
203        ) or return;
204
205        $param->{blog_stats} = $param->{main};
206        $param->{tab_html_head} .= $param->{html_head};
207    }
208}
209
210sub mt_blog_stats_widget_entry_tab {
211    my ($app, $tmpl, $param) = @_;
212
213    my $user    = $app->user;
214    my $blog    = $app->blog;
215    my $blog_id = $blog->id if $blog;
216
217    $param->{editable} = $user->is_superuser;
218    if ( $blog && !$param->{editable} ) {
219        $param->{editable} = $user->permissions($blog_id)->can_edit_all_posts;
220    }
221
222    my $entries = sub {
223        my $args = {
224            limit     => 10,
225            sort      => 'authored_on',
226            direction => 'descend',
227        };
228        if ( !$user->is_superuser && !$blog_id ) {
229            $args->{join} = MT::Permission->join_on(
230                undef,
231                {
232                    blog_id   => \'= entry_blog_id',
233                    author_id => $user->id
234                },
235            );
236        }
237        my @e =
238          MT::Entry->load( { ( $blog_id ? ( blog_id => $blog_id ) : () ), },
239            $args );
240        \@e;
241    };
242
243    require MT::Promise;
244    my $ctx = $tmpl->context;
245    $ctx->stash( 'entries',  MT::Promise::delay($entries) );
246}
247
248sub generate_dashboard_stats {
249    my $app = shift;
250    my ($param) = @_;
251
252    my $cache_time = 60 * 15;    # cache for 15 minutes
253
254    my $blog_id = $app->blog ? $app->blog->id : 0;
255    my $user    = $app->user;
256    my $user_id = $user->id;
257
258    my $static_path      = $app->static_path;
259    my $static_file_path = $app->static_file_path;
260
261    if ( -f File::Spec->catfile( $static_file_path, "mt.js" ) ) {
262        $param->{static_file_path} = $static_file_path;
263    }
264    else {
265        return;
266    }
267
268    my $low_dir = sprintf("%03d", $user_id % 1000);
269    my $sub_dir = sprintf("%03d", $blog_id % 1000);
270    my $top_dir = $blog_id > $sub_dir ? $blog_id - $sub_dir : 0;
271    $param->{support_path} =
272      File::Spec->catdir( $static_file_path, 'support', 'dashboard', 'stats',
273        $top_dir, $sub_dir, $low_dir); 
274
275    require MT::FileMgr;
276    my $fmgr = MT::FileMgr->new('Local');
277    unless ( $fmgr->exists( $param->{support_path} ) ) {
278        $fmgr->mkpath( $param->{support_path} );
279        unless ( $fmgr->exists( $param->{support_path} ) ) {
280            # the path didn't exist - change the warning a little
281            $param->{support_path} =
282                File::Spec->catdir( $app->static_file_path, 'support' );
283            return;
284        }
285    }
286
287    my $stats_static_path = $static_path . 'support/dashboard/stats/' .
288        $top_dir . '/' . $sub_dir . '/' . $low_dir;
289
290    my $tabs = $app->registry('blog_stats_tabs') or return;
291    while (my ($tab_id, $tab) = each %$tabs) {
292        my $file = "${tab_id}.xml";
293        $param->{stat_url}->{$tab_id} = $stats_static_path . '/' . $file;
294        my $path = File::Spec->catfile( $param->{support_path}, $file );
295
296        my $time = ( stat($path) )[9] if -f $path;
297
298        if ( !$time || ( time - $time > $cache_time ) ) {
299            my $gen_stats = $tab->{stats};
300            next if !$gen_stats;
301            $gen_stats = $app->handler_to_coderef($gen_stats);
302
303            my %counts = $gen_stats->($app, $tab);
304
305            unless ( create_dashboard_stats_file( $app, $path, \%counts ) ) {
306                delete $param->{stat_url}->{$tab_id};
307            }
308        }
309    }
310
311    1;
312}
313
314sub create_dashboard_stats_file {
315    my $app = shift;
316    my ( $file, $data ) = @_;
317
318    my $support_dir = File::Spec->catdir( $app->static_file_path, "support" );
319    if ( !-d $support_dir ) {
320        mkdir( $support_dir, 0777 );
321        if ($!) {
322            $app->log("Failed to create 'support' directory.");
323            return;
324        }
325    }
326
327    local *FOUT;
328    if ( !open( FOUT, ">$file" ) ) {
329        return;
330    }
331
332    print FOUT <<EOT;
333<?xml version="1.0"?>
334<rsp status_code="0" status_message="Success">
335  <daily_counts>
336EOT
337    my $now = time;
338    for ( my $i = 120 ; $i >= 1 ; $i-- ) {
339        my $ds =
340          substr( epoch2ts( $app->blog, $now - ( ( $i - 1 ) * 60 * 60 * 24 ) ),
341            0, 8 )
342          . 'T00:00:00';
343        my $count = $data->{$ds} || 0;
344        print FOUT qq{    <count date="$ds">$count</count>\n};
345    }
346    print FOUT <<EOT;
347  </daily_counts>
348</rsp>
349EOT
350    close FOUT;
351}
352
353sub generate_dashboard_stats_entry_tab {
354    my $app = shift;
355    my ($tab) = @_;
356   
357    my $blog_id = $app->blog ? $app->blog->id : 0;
358    my $user    = $app->user;
359    my $user_id = $user->id;
360
361    my $entry_class = $app->model('entry');
362    my $terms       = { status => MT::Entry::RELEASE() };
363    my $args        = {
364        group => [
365            "extract(year from authored_on)",
366            "extract(month from authored_on)",
367            "extract(day from authored_on)"
368        ],
369    };
370
371    require MT::Util;
372    my @ts = MT::Util::offset_time_list(time - (121 * 24 * 60 * 60), $blog_id);
373    my $earliest = sprintf('%04d%02d%02d%02d%02d%02d',
374        $ts[5]+1900, $ts[4]+1, @ts[3,2,1,0]);
375    $terms->{authored_on} = [ $earliest, undef ];
376    $args->{range_incl}{authored_on} = 1;
377
378    $terms->{blog_id} = $blog_id if $blog_id;
379    if ( !$user->is_superuser && !$blog_id ) {
380        $args->{join} = MT::Permission->join_on(
381            undef,
382            {
383                blog_id   => \'= entry_blog_id',
384                author_id => $user_id
385            },
386        );
387    }
388
389    my $entry_iter = $entry_class->count_group_by( $terms, $args );
390    my %counts;
391    while ( my ( $count, $y, $m, $d ) = $entry_iter->() ) {
392        my $date = sprintf( "%04d%02d%02dT00:00:00", $y, $m, $d );
393        $counts{$date} = $count;
394    }
395
396    %counts;
397}
398
399sub mt_blog_stats_tag_cloud_tab {
400    my ($app, $tmpl, $param) = @_;
401
402    my $blog = $app->blog;
403    my $blog_id = $blog->id if $blog;
404
405    my $terms = {};
406    $terms->{blog_id} = $blog_id if $blog_id;
407    $terms->{object_datasource} = 'entry';
408    my $args = {};
409    $args->{group} = [ 'tag_id' ];
410    $args->{sort} = '1'; # sort by count(*)
411    $args->{direction} = 'descend';
412    $args->{limit} = 100;
413
414    my $iter = $app->model('objecttag')->count_group_by($terms, $args);
415    my @tag_loop;
416    my $ntags = 0;
417    my $min = undef;
418    my $max = undef;
419    while (my ($count, $tag_id) = $iter->()) {
420        my $tag = MT::Tag->load($tag_id) or next;
421        next if $tag->is_private; # weed these from the dashboard
422        $ntags += $count;
423        $min = defined $min ? ($count < $min ? $count : $min) : $count;
424        $max = defined $max ? ($count > $max ? $count : $max) : $count;
425        push @tag_loop, { name => $tag->name, count => $count };
426    }
427
428    $min ||= 0;
429    $max ||= 0;
430    my $factor;
431    if ($max - $min == 0) {
432        $min -= 6;
433        $factor = 1;
434    } else {
435        $factor = 5 / log($max - $min + 1);
436    }
437    $factor *= ($ntags / 6) if $ntags < 6;
438
439    foreach my $tag (@tag_loop) {
440        # now calc rank
441        my $rank;
442        my $count = $tag->{count};
443        if ($count - $min + 1 == 0) {
444            $rank = 0;
445        } else {
446            $rank = 6 - int(log($count - $min + 1) * $factor);
447        }
448        $tag->{rank} = $rank;
449    }
450
451    @tag_loop = sort { $a->{name} cmp $b->{name} } @tag_loop;
452    $param->{tag_loop} = \@tag_loop;
453}
454
455sub mt_blog_stats_widget_comment_tab {
456    my ($app, $tmpl, $param) = @_;
457
458    my $user    = $app->user;
459    my $blog    = $app->blog;
460    my $blog_id = $blog->id if $blog;
461
462    $param->{editable} = $user->is_superuser;
463    if ( $blog && !$param->{editable} ) {
464        $param->{editable} = $user->permissions($blog_id)->can_edit_all_posts;
465        $param->{comment_editable} = $user->permissions($blog_id)->can_manage_feedback;
466    }
467
468    my $comments = sub {
469        my $args = {
470            limit     => 10,
471            sort      => 'created_on',
472            direction => 'descend',
473        };
474        if ( !$user->is_superuser && !$blog_id ) {
475            $args->{join} = MT::Permission->join_on(
476                undef,
477                {
478                    blog_id   => \'= comment_blog_id',
479                    author_id => $user->id
480                },
481            );
482        }
483        my @c = MT::Comment->load(
484            {
485                ( $blog_id ? ( blog_id => $blog_id ) : () ),
486                junk_status => 1,
487            },
488            $args
489        );
490        \@c;
491    };
492
493    require MT::Promise;
494    my $ctx = $tmpl->context;
495    $ctx->stash( 'comments',  MT::Promise::delay($comments) );
496}
497
498sub generate_dashboard_stats_comment_tab {
499    my $app = shift;
500    my ($tab) = @_;
501   
502    my $blog_id = $app->blog ? $app->blog->id : 0;
503    my $user    = $app->user;
504    my $user_id = $user->id;
505
506    my $cmt_class = $app->model('comment');
507    my $terms = { visible => 1 };
508    $terms->{blog_id} = $blog_id if $blog_id;
509    my $args = {
510        group => [
511            "extract(year from created_on)",
512            "extract(month from created_on)",
513            "extract(day from created_on)"
514        ],
515    };
516
517    require MT::Util;
518    my @ts = MT::Util::offset_time_list(time - (121 * 24 * 60 * 60), $blog_id);
519    my $earliest = sprintf('%04d%02d%02d%02d%02d%02d',
520        $ts[5]+1900, $ts[4]+1, @ts[3,2,1,0]);
521    $terms->{created_on} = [ $earliest, undef ];
522    $args->{range_incl}{created_on} = 1;
523
524    if ( !$user->is_superuser && !$blog_id ) {
525        $args->{join} = MT::Permission->join_on(
526            undef,
527            {
528                blog_id   => \'= comment_blog_id',
529                author_id => $user_id
530            },
531        );
532    }
533    my $cmt_iter = $cmt_class->count_group_by( $terms, $args );
534
535    my %counts;
536    while ( my ( $count, $y, $m, $d ) = $cmt_iter->() ) {
537        my $date = sprintf( "%04d%02d%02dT00:00:00", $y, $m, $d );
538        $counts{$date} = $count;
539    }
540
541    %counts;
542}
543
5441;
Note: See TracBrowser for help on using the browser.