[dw-free] Convert /admin/index to TT
[commit: http://hg.dwscoalition.org/dw-free/rev/61913b5952d1]
http://bugs.dwscoalition.org/show_bug.cgi?id=3164
Use controllers/TT for the admin page. Admin pages written in the new style
can register themselves rather than having to have us manually list them.
Patch by
exor674.
Files modified:
http://bugs.dwscoalition.org/show_bug.cgi?id=3164
Use controllers/TT for the admin page. Admin pages written in the new style
can register themselves rather than having to have us manually list them.
Patch by
![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
Files modified:
- cgi-bin/DW/Controller/Admin.pm
- cgi-bin/DW/Controller/Rename.pm
- cgi-bin/DW/Controller/SiteStats.pm
- cgi-bin/DW/Routing.pm
- cgi-bin/DW/Template/Plugin.pm
- cgi-bin/DW/Template/VMethods.pm
- htdocs/admin/index.bml
- htdocs/admin/index.bml.text
- t/routing.t
- views/admin/index.tt
- views/admin/index.tt.text
- views/admin/rename.tt
- views/admin/rename.tt.text
- views/admin/stats.tt.text
-------------------------------------------------------------------------------- diff -r f4fcc06b2940 -r 61913b5952d1 cgi-bin/DW/Controller/Admin.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cgi-bin/DW/Controller/Admin.pm Thu Oct 28 11:06:03 2010 +0800 @@ -0,0 +1,319 @@ +#!/usr/bin/perl +# +# DW::Controller::Admin +# +# Controller for admin action list index pages. +# +# Authors: +# Andrea Nall <anall@andreanall.com> +# Denise Paolucci <denise@dreamwidth.org> +# Sophie Hamilton <dw-bugzilla@theblob.org> +# +# Copyright (c) 2009-2010 by Dreamwidth Studios, LLC. +# +# This program is free software; you may redistribute it and/or modify it under +# the same terms as Perl itself. For a copy of the license, please reference +# 'perldoc perlartistic' or 'perldoc perlgpl'. +# + +package DW::Controller::Admin; + +=head1 NAME + +DW::Controller::Admin - Controller for admin action list index pages. + +This is for pages like /admin/index which list other pages, displaying only what the current user can do + +=head1 API + +=cut + +use strict; +use warnings; +use DW::Controller; +use DW::Routing; +use DW::Template; + +my $admin_pages = {}; + +DW::Controller::Admin->register_admin_scope( '/', title_ml => '.admin.title' ); + +# DO NOT add anything to here +DW::Controller::Admin->_register_admin_pages_legacy( '/', + [ 'capedit', '.admin.capability.link', '.admin.capability.text', [ 'admin:*', sub { + return ( $LJ::IS_DEV_SERVER, LJ::Lang::ml( "/admin/index.tt.devserver" ) ); + } ] ], + [ 'clusterstatus', + '.admin.cluster.link', '.admin.cluster.text', [ 'supporthelp' ] ], + [ 'console/', + '.admin.console.link', '.admin.console.text' ], + [ 'schema/', + '.admin.dbschema.link', '.admin.dbschema.text', [ 'schemadoc' ] ], + [ 'dupkiller', + '.admin.dupkiller.link', '.admin.dupkiller.text', [ 'supporthelp' ] ], + [ 'entryprops', + '.admin.entryprops.link', '.admin.entryprops.text', [ 'canview:entryprops', 'canview:*', sub { + return ( $LJ::IS_DEV_SERVER, LJ::Lang::ml( "/admin/index.tt.devserver" ) ); + } ] ], + [ 'faq/', + '.admin.faq.link', '.admin.faq.text', [ 'faqadd', 'faqedit', 'faqcat' ] ], + [ 'fileedit/', + '.admin.file_edit.link', '.admin.file_edit.text', [ 'fileedit' ] ], + [ 'invites/', '.admin.invites.link', '.admin.invites.text', [ 'finduser:codetrace', 'finduser:*', 'payments' ] ], + [ 'logout_user', + '.admin.logout_user.link', '.admin.logout_user.text', [ 'suspend' ] ], + [ 'memcache', + '.admin.memcache.link', '.admin.memcache.text', [ 'siteadmin:memcacheview', 'siteadmin:*' ] ], + [ 'memcache_view', + '.admin.memcache_view.link', '.admin.memcache_view.text', [ 'siteadmin:memcacheview', 'siteadmin:*', sub { + return ( $LJ::IS_DEV_SERVER, LJ::Lang::ml( "/admin/index.tt.devserver" ) ); + } ] ], + [ 'mysql_status', + '.admin.mysql.link', '.admin.mysql.text', [ 'siteadmin:mysqlstatus', 'siteadmin:*' ] ], + [ 'navtag', + '.admin.navtag.link', '.admin.navtag.text', [ 'siteadmin:navtag', 'siteadmin:*' ] ], + [ 'pay/', + '.admin.pay.link', '.admin.pay.text', [ 'payments' ] ], + [ 'priv/', + '.admin.priv.link', '.admin.priv.text' ], + [ 'propedit', + '.admin.propedit.link', '.admin.propedit.text', [ 'canview:userprops', 'canview:*' ] ], + [ 'recent_comments', + '.admin.recent_comments.link', '.admin.recent_comments.text', [ 'siteadmin:commentview', 'siteadmin:*' ] ], + [ 'sitemessages/add', + '.admin.sitemessages_add.link', '.admin.sitemessages_add.text', [ 'siteadmin:sitemessages', 'siteadmin:*', sub { + return ( $LJ::IS_DEV_SERVER, LJ::Lang::ml( "/admin/index.tt.devserver" ) ); + } ] ], + [ 'sitemessages/manage', + '.admin.sitemessages_manage.link', '.admin.sitemessages_manage.text', [ 'siteadmin:sitemessages', 'siteadmin:*', sub { + return ( $LJ::IS_DEV_SERVER, LJ::Lang::ml( "/admin/index.tt.devserver" ) ); + } ] ], + [ 'spamreports', + '.admin.spamreports.link', '.admin.spamreports.text', [ 'siteadmin:spamreports', 'siteadmin:*' ] ], + [ 'statushistory', + '.admin.statushistory.link', '.admin.statushistory.text', [ 'historyview', sub { + return ( $LJ::IS_DEV_SERVER, LJ::Lang::ml( "/admin/index.tt.devserver" ) ); + } ] ], + [ 'styleinfo', + '.admin.styleinfo.link', '.admin.styleinfo.text', [ sub { + return ( LJ::Support::has_any_support_priv($_[0]->{remote}), + LJ::Lang::ml( "/admin/index.tt.anysupportpriv" ) ); + }, sub { + return ( $LJ::IS_DEV_SERVER, LJ::Lang::ml( "/admin/index.tt.devserver" ) ); + } ] ], + [ 'sysban', + '.admin.sysban.link', '.admin.sysban.text', [ 'sysban' ] ], + [ 'theschwartz', + '.admin.theschwartz.link', '.admin.theschwartz.text', [ 'siteadmin:theschwartz' ] ], + [ 'translate/', + '.admin.translate.link', '.admin.translate.text' ], + [ 'userlog', + '.admin.userlog.link', '.admin.userlog.text', [ 'canview:userlog', 'canview:*' ] ], +); + + +sub admin_handler { + my $opts = shift @_; + my $r = DW::Request->get; + + my ( $ok, $rv ) = controller(); + return $rv unless $ok; + + my $remote = $rv->{remote}; + + my $args = $opts->args || {}; + my $scope = $args->{scope} || "/"; + + my $data = $admin_pages->{$scope}; + + my $vars = $rv; + + $vars->{$_} = $data->{$_} foreach qw( title_ml description_ml ml_scope ); + + my @pages; + my $adminstar = $remote && $remote->has_priv( 'admin', '*' ); + foreach my $page ( @{ $data->{pages} } ) { + my ( $path, $link_ml, $description_ml, $privs ) = @{$page}; + my $showpage = 0; + my ( @needsprivs, @gotprivs ); + my $haspriv = 0; + foreach my $priv ( @{$privs} ) { + my $code_result; + $code_result = [ + $priv->( { remote => $remote } ) + ] if ref( $priv ) eq "CODE"; + + my $result = ( $code_result ? + $code_result->[0] : + $remote && $remote->has_priv( split( /:/, $priv ) ) ); + my $displayedpriv = ( $code_result ? + $code_result->[1] : + $priv ); + push( @gotprivs, $displayedpriv ) if $result; + push( @needsprivs, $displayedpriv ) if !$result; + $haspriv = 1 if $result; + $showpage = 1 if $adminstar || $result; + } + if ( @$privs == 0 ) { + $showpage = 1; + $haspriv = 1; + } + $path = "/admin$scope$path" unless $path =~ m!^((https?://)|/)!; + if ( $showpage ) { + push @pages, { + path => $path, + link_ml => $link_ml, + description_ml => $description_ml, + haspriv => $haspriv, + gotprivs => \@gotprivs, + needsprivs => \@needsprivs, + }; + } + } + $vars->{pages} = \@pages; + + return DW::Template->render_template( 'admin/index.tt', $vars ); +} + +=head2 C<< $class->register_regex( $scope, %opts ) >> + +Register an admin scope. + +Arguments: + +=over 4 + +=item scope + +The name of the scope + +=back + +Additional options: + +=over 4 + +=item ml_scope + +The ML scope for the ml strings. + +=item title_ml + +ML string for title + +=item description_ml + +ML string for description + +=back + +=cut + +sub register_admin_scope { + my ( $class, $scope, %opts ) = @_; + + $admin_pages->{$scope} = \%opts; + + my $url = "/admin" . ( $scope eq '/' ? '' : $scope ) . '/index'; + + DW::Routing->register_string( $url, \&admin_handler, args => { scope => $scope } ); +} + +=head2 C<< $class->register_admin_page( $scope, %opts ) >> + +Register an admin scope. + +Arguments: + +=over 4 + +=item scope + +The name of the scope + +=back + +Additional options: + +=over 4 + +=item ml_scope + +The ML scope for the ml strings. + +=item link_ml + +ML string for link text ( defaults to ".admin.link" ) + +=item description_ml + +ML string for description ( defaults to ".admin.text" ) + +=item path + +Path, either relative to the scope ( no leading slash ), relative to the domain ( leading slash ), or a full URI + +=item privs + +An arrayref of priv names or subroutine refs + +The subref needs to return [ $has_priv, $string ] + +=back + +=cut + +sub register_admin_page { + my ( $class, $scope, %args ) = @_; + + my ( $path, $link_ml, $desc_ml, $privs ); + + $path = $args{path}; + $privs = $args{privs}; + + $link_ml = $args{link_ml} || ".admin.link"; + $desc_ml = $args{description_ml} || ".admin.text"; + + if ( $args{ml_scope} ) { + $link_ml = $args{ml_scope} . $link_ml; + $desc_ml = $args{ml_scope} . $desc_ml; + } + + $scope ||= "/"; + push @{$admin_pages->{$scope}->{pages}}, [ $path, $link_ml, $desc_ml, $privs ]; +} + +# DO NOT USE OUTSIDE THIS FILE! +# FIXME: Remove once the big scary array up above is gone! +sub _register_admin_pages_legacy { + my ( $class, $scope, @pages ) = @_; + + $scope ||= "/"; + foreach my $part ( @pages ) { + push @{$admin_pages->{$scope}->{pages}}, $part; + } +} + +=head1 AUTHOR + +=over + +=item Andrea Nall <anall@andreanall.com> + +=item Denise Paolucci <denise@dreamwidth.org> + +=item Sophie Hamilton <dw-bugzilla@theblob.org> + +=back + +=head1 COPYRIGHT AND LICENSE + +Copyright (c) 2009-2010 by Dreamwidth Studios, LLC. + +This program is free software; you may redistribute it and/or modify it under +the same terms as Perl itself. For a copy of the license, please reference +'perldoc perlartistic' or 'perldoc perlgpl'. + +=cut + +1; diff -r f4fcc06b2940 -r 61913b5952d1 cgi-bin/DW/Controller/Rename.pm --- a/cgi-bin/DW/Controller/Rename.pm Thu Oct 28 10:15:22 2010 +0800 +++ b/cgi-bin/DW/Controller/Rename.pm Thu Oct 28 11:06:03 2010 +0800 @@ -21,6 +21,7 @@ use DW::Controller; use DW::Controller; use DW::Routing; use DW::Template; +use DW::Controller::Admin; use DW::RenameToken; use DW::Shop; @@ -30,10 +31,16 @@ use DW::Shop; # ideally, should be: /rename, or /rename/(20 character token) DW::Routing->register_regex( qr!^/rename(?:/([A-Z0-9]*))?$!i, \&rename_handler, app => 1 ); -DW::Routing->register_string( "/admin/rename", \&rename_admin_handler, app => 1 ); +DW::Routing->register_string( "/admin/rename/index", \&rename_admin_handler, app => 1 ); DW::Routing->register_string( "/admin/rename/edit", \&rename_admin_edit_handler, app => 1 ); DW::Routing->register_string( "/admin/rename/new", \&siteadmin_rename_handler, app => 1 ); + +DW::Controller::Admin->register_admin_page( '/', + path => '/admin/rename/', + ml_scope => '/admin/rename.tt', + privs => [ 'siteadmin:rename' ] +); sub rename_handler { my $r = DW::Request->get; diff -r f4fcc06b2940 -r 61913b5952d1 cgi-bin/DW/Controller/SiteStats.pm --- a/cgi-bin/DW/Controller/SiteStats.pm Thu Oct 28 10:15:22 2010 +0800 +++ b/cgi-bin/DW/Controller/SiteStats.pm Thu Oct 28 11:06:03 2010 +0800 @@ -34,6 +34,7 @@ use DW::Template; use DW::Template; use DW::StatStore; use DW::StatData; +use DW::Controller::Admin; LJ::ModuleLoader::autouse_subclasses( 'DW::StatData' ); @@ -43,7 +44,11 @@ DW::Routing->register_string( '/admin/st DW::Routing->register_string( '/admin/stats', \&stats_page, app => 1, args => [ 'admin/stats.tt', \&admin_data, 0, 'payments' ] ); - +DW::Controller::Admin->register_admin_page( '/', + path => '/admin/stats', + ml_scope => '/admin/stats.tt', + privs => [ 'payments' ] +); =head1 Internals =head2 C<< DW::Controller::SiteStats::stats_page( $opts ) >> diff -r f4fcc06b2940 -r 61913b5952d1 cgi-bin/DW/Routing.pm --- a/cgi-bin/DW/Routing.pm Thu Oct 28 10:15:22 2010 +0800 +++ b/cgi-bin/DW/Routing.pm Thu Oct 28 11:06:03 2010 +0800 @@ -107,13 +107,16 @@ sub get_call_opts { # us accessors. my $call_opts = DW::Routing::CallInfo->new( \%opts ); + my $hash; + my $role = $call_opts->role; + # try the string options first as they're fast - my $hash = $string_choices{$call_opts->role . $uri}; + $hash = $string_choices{$role . $uri}; if ( defined $hash ) { $call_opts->init_call_opts( $hash ); return $call_opts; } - + # try the regex choices next # FIXME: this should be a dynamically sorting array so the most used items float to the top # for now it doesn't matter so much but eventually when everything is in the routing table @@ -135,7 +138,6 @@ Calls the raw hash. Calls the raw hash. =cut - sub call_hash { my ( $class, $opts ) = @_; my $r = DW::Request->get; @@ -147,12 +149,8 @@ sub call_hash { return $r->call_response_handler( \&_call_hash ); } -=head2 C<< $class->_call_hash() >> - -Perl Response Handler for call_hash - -=cut - +# INTERNAL METHOD: no POD +# Perl Response Handler for call_hash sub _call_hash { my $r = DW::Request->get; my $opts = $r->pnote('routing_opts'); @@ -190,7 +188,6 @@ sub _call_hash { $r->status( 500 ); $r->print(objToJson( { error => $text } )); return $r->OK; - # default error rendering } else { $msg = $err->as_html; @@ -207,14 +204,23 @@ sub _call_hash { } } +# INTERNAL METHOD: no POD +# controller sub for register_static sub _static_helper { my $r = DW::Request->get; - return DW::Template->render_template( $_[0]->args ); + return DW::Template->render_template( $_[0]->arg ); +} + +# INTERNAL METHOD: no POD +# controller sub for register_redirect +sub _redirect_helper { + my $r = DW::Request->get; + return $r->redirect( $_[0]->args ); } =head1 Registration API -=head2 C<< $class->register_static($string, $filename, $opts) >> +=head2 C<< $class->register_static( $string, $filename, %opts ) >> Static page helper. @@ -237,7 +243,7 @@ sub register_static { $class->register_string( $string, \&_static_helper, %opts ); } -=head2 C<< $class->register_string($string, $sub, $opts) >> +=head2 C<< $class->register_string( $string, $sub, %opts ) >> =over @@ -276,9 +282,47 @@ sub register_string { $string_choices{'app' . $string} = $hash if $hash->{app}; $string_choices{'ssl' . $string} = $hash if $hash->{ssl}; $string_choices{'user' . $string} = $hash if $hash->{user}; + + if ( $string =~ m!(^(.+)/)index$! && ! exists $opts{no_redirects} ) { + my %opts = ( + app => $hash->{app}, + ssl => $hash->{ssl}, + user => $hash->{user}, + formats => $hash->{formats}, + format => $hash->{format}, + no_redirects => 1, + ); + $class->register_redirect( $2, $1, %opts ); + $string_choices{'app' . $1} = $hash if $hash->{app}; + $string_choices{'ssl' . $1} = $hash if $hash->{ssl}; + $string_choices{'user' . $1} = $hash if $hash->{user}; + } } -=head2 C<< $class->register_regex($regex, $sub, $opts) >> +=head2 C<< $class->register_redirect( $string, $dest, %opts ) >> + +Redirect helper. + +=over + +=item string - path + +=item dest - destination + +=item Opts ( see register_string ) + +=back + +=cut + +sub register_redirect { + my ( $class, $string, $dest, %opts ) = @_; + + $opts{args} = $dest; + $class->register_string( $string, \&_redirect_helper, %opts ); +} + +=head2 C<< $class->register_regex( $regex, $sub, %opts ) >> =over @@ -306,7 +350,6 @@ sub register_regex { # internal method, intentionally no POD # applies default for opts and hash - sub _apply_defaults { my ( $opts, $hash ) = @_; diff -r f4fcc06b2940 -r 61913b5952d1 cgi-bin/DW/Template/Plugin.pm --- a/cgi-bin/DW/Template/Plugin.pm Thu Oct 28 10:15:22 2010 +0800 +++ b/cgi-bin/DW/Template/Plugin.pm Thu Oct 28 11:06:03 2010 +0800 @@ -18,6 +18,7 @@ use strict; use strict; use DW::Template::Filters; +use DW::Template::VMethods; =head1 NAME @@ -104,6 +105,26 @@ sub form_auth { return LJ::form_auth(); } +=head2 sort_by_key + +Sorts an array of hashrefs by given key + +=cut + +sub sort_by_key { + my $k = $_[2]; + my $md = $_[3] || 'alpha'; + + my @r; + if ( $md eq 'alpha' ) { + @r = sort { $a->{$k} cmp $b->{$k} } @{$_[1]}; + } else { + @r = sort { $a->{$k} <=> $b->{$k} } @{$_[1]}; + } + + return \@r; +} + =head1 AUTHOR =over diff -r f4fcc06b2940 -r 61913b5952d1 cgi-bin/DW/Template/VMethods.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cgi-bin/DW/Template/VMethods.pm Thu Oct 28 11:06:03 2010 +0800 @@ -0,0 +1,35 @@ +#!/usr/bin/perl +# +# DW::Template::VMethods +# +# VMethods for the Dreamwidth Template Toolkit plugin +# +# Authors: +# Andrea Nall <anall@andreanall.com> +# +# Copyright (c) 2010 by Dreamwidth Studios, LLC. +# +# This program is free software; you may redistribute it and/or modify it under +# the same terms as Perl itself. For a copy of the license, please reference +# 'perldoc perlartistic' or 'perldoc perlgpl'. +# + +package DW::Template::VMethods; +use strict; +use Template::Stash; + +$Template::Stash::LIST_OPS->{ sort_by_key } = sub { + my ( $lst, $k, $type ) = @_; + + my @r = (); + $type ||= 'alpha'; + if ( $type eq 'alpha' ) { + @r = sort { $a->{$k} cmp $b->{$k} } @$lst; + } elsif ( $type eq 'numeric' ) { + @r = sort { $a->{$k} <=> $b->{$k} } @$lst; + } + + return \@r; +}; + +1; diff -r f4fcc06b2940 -r 61913b5952d1 htdocs/admin/index.bml --- a/htdocs/admin/index.bml Thu Oct 28 10:15:22 2010 +0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,160 +0,0 @@ -<?_c -# -# admin/index.bml -# -# Because blank index files annoy me. Lists all pages $remote has privs -# to view; does not show the link if you can't use it. -# -# Authors: -# Denise Paolucci <denise@dreamwidth.org> -# Sophie Hamilton <dw-bugzilla@theblob.org> -# -# Copyright (c) 2009 by Dreamwidth Studios, LLC. -# -# This program is free software; you may redistribute it and/or modify it under -# the same terms as Perl itself. For a copy of the license, please reference -# 'perldoc perlartistic' or 'perldoc perlgpl'. -# -_c?><?page -body<= -<?_code -{ - use strict; - use vars qw/ %GET %POST $title $windowtitle @errors @warnings /; - - # translated/custom page title can go here - $title = "<?_ml .admin.title _ml?>"; - $windowtitle = "<?_ml .admin.title _ml?>"; - - # for pages that require authentication - my $remote = LJ::get_remote(); - return "<?needlogin?>" unless $remote; - - my $ret; - - my @adminpages = ( - [ 'capedit', - '<?_ml .admin.capability.link _ml?>', '<?_ml .admin.capability.text _ml?>', [ 'admin:*', sub { - return ( $LJ::IS_DEV_SERVER, "<?_ml .devserver _ml?>" ); - } ] ], - [ 'clusterstatus', - '<?_ml .admin.cluster.link _ml?>', '<?_ml .admin.cluster.text _ml?>', [ 'supporthelp' ] ], - [ 'console/', - '<?_ml .admin.console.link _ml?>', '<?_ml .admin.console.text _ml?>' ], - [ 'schema/', - '<?_ml .admin.dbschema.link _ml?>', '<?_ml .admin.dbschema.text _ml?>', [ 'schemadoc' ] ], - [ 'dupkiller', - '<?_ml .admin.dupkiller.link _ml?>', '<?_ml .admin.dupkiller.text _ml?>', [ 'supporthelp' ] ], - [ 'entryprops', - '<?_ml .admin.entryprops.link _ml?>', '<?_ml .admin.entryprops.text _ml?>', [ 'canview:entryprops', 'canview:*', sub { - return ( $LJ::IS_DEV_SERVER, "<?_ml .devserver _ml?>" ); - } ] ], - [ 'faq/', - '<?_ml .admin.faq.link _ml?>', '<?_ml .admin.faq.text _ml?>', [ 'faqadd', 'faqedit', 'faqcat' ] ], - [ 'fileedit/', - '<?_ml .admin.file_edit.link _ml?>', 'Allows you to edit various include files.', [ 'fileedit' ] ], - [ 'invites/', '<?_ml .admin.invites.link _ml?>', '<?_ml .admin.invites.text _ml?>', [ 'finduser:codetrace', 'finduser:*', 'payments' ] ], - [ 'logout_user', - '<?_ml .admin.logout_user.link _ml?>', '<?_ml .admin.logout_user.text _ml?>', [ 'suspend' ] ], - [ 'memcache', - '<?_ml .admin.memcache.link _ml?>', '<?_ml .admin.memcache.text _ml?>', [ 'siteadmin:memcacheview', 'siteadmin:*' ] ], - [ 'memcache_view', - '<?_ml .admin.memcache_view.link _ml?>', '<?_ml .admin.memcache_view.text _ml?>', [ 'siteadmin:memcacheview', 'siteadmin:*', sub { - return ( $LJ::IS_DEV_SERVER, "<?_ml .devserver _ml?>" ); - } ] ], - [ 'mysql_status', - '<?_ml .admin.mysql.link _ml?>', '<?_ml .admin.mysql.text _ml?>', [ 'siteadmin:mysqlstatus', 'siteadmin:*' ] ], - [ 'navtag', - '<?_ml .admin.navtag.link _ml?>', '<?_ml .admin.navtag.text _ml?>', [ 'siteadmin:navtag', 'siteadmin:*' ] ], - [ 'pay/', - '<?_ml .admin.pay.link _ml?>', '<?_ml .admin.pay.text _ml?>', [ 'payments' ] ], - [ 'priv/', - '<?_ml .admin.priv.link _ml?>', '<?_ml .admin.priv.text _ml?>' ], - [ 'propedit', - '<?_ml .admin.propedit.link _ml?>', '<?_ml .admin.propedit.text _ml?>', [ 'canview:userprops', 'canview:*' ] ], - [ 'recent_comments', - '<?_ml .admin.recent_comments.link _ml?>', '<?_ml .admin.recent_comments.text _ml?>', [ 'siteadmin:commentview', 'siteadmin:*' ] ], - [ 'sitemessages/add', - '<?_ml .admin.sitemessages_add.link _ml?>', '<?_ml .admin.sitemessages_add.text _ml?>', [ 'siteadmin:sitemessages', 'siteadmin:*', sub { - return ( $LJ::IS_DEV_SERVER, "<?_ml .devserver _ml?>" ); - } ] ], - [ 'sitemessages/manage', - '<?_ml .admin.sitemessages_manage.link _ml?>', '<?_ml .admin.sitemessages_manage.text _ml?>', [ 'siteadmin:sitemessages', 'siteadmin:*', sub { - return ( $LJ::IS_DEV_SERVER, "<?_ml .devserver _ml?>" ); - } ] ], - [ 'spamreports', - '<?_ml .admin.spamreports.link _ml?>', '<?_ml .admin.spamreports.text _ml?>', [ 'siteadmin:spamreports', 'siteadmin:*' ] ], - [ 'stats', - '<?_ml .admin.stats.link _ml?>', '<?_ml .admin.stats.text _ml?>', [ 'payments' ] ], - [ 'statushistory', - '<?_ml .admin.statushistory.link _ml?>', '<?_ml .admin.statushistory.text _ml?>', [ 'historyview', sub { - return ( $LJ::IS_DEV_SERVER, "<?_ml .devserver _ml?>" ); - } ] ], - [ 'styleinfo', - '<?_ml .admin.styleinfo.link _ml?>', '<?_ml .admin.styleinfo.text _ml?>', [ sub { - return ( LJ::Support::has_any_support_priv($remote), "<?_ml .anysupportpriv _ml?>" ); - }, sub { - return ( $LJ::IS_DEV_SERVER, "<?_ml .devserver _ml?>" ); - } ] ], - [ 'sysban', - '<?_ml .admin.sysban.link _ml?>', '<?_ml .admin.sysban.text _ml?>', [ 'sysban' ] ], - [ 'theschwartz', - '<?_ml .admin.theschwartz.link _ml?>', '<?_ml .admin.theschwartz.text _ml?>', [ 'siteadmin:theschwartz' ] ], - [ 'translate/', - '<?_ml .admin.translate.link _ml?>', '<?_ml .admin.translate.text _ml?>' ], - [ 'userlog', - '<?_ml .admin.userlog.link _ml?>', '<?_ml .admin.userlog.text _ml?>', [ 'canview:userlog', 'canview:*' ] ], - ); - - $ret .= "<ul>\n"; - - my $adminstar = $remote && $remote->has_priv( 'admin', '*' ); - foreach my $page ( @adminpages ) { - my ( $path, $name, $description, $privs ) = @{$page}; - my $showpage = 0; - my ( @needsprivs, @gotprivs ); - my $haspriv = 0; - foreach my $priv ( @{$privs} ) { - my $result = ( ref( $priv ) eq "CODE" ? - ( $priv->() )[0] : - $remote && $remote->has_priv( split( /:/, $priv ) ) ); - my $displayedpriv = ( ref( $priv ) eq "CODE" ? ( $priv->() )[1] : $priv ); - push( @gotprivs, $displayedpriv ) if $result; - push( @needsprivs, $displayedpriv ) if !$result; - $haspriv = 1 if $result; - $showpage = 1 if $adminstar || $result; - } - if ( @{$privs} == 0 ) { - $showpage = 1; - $haspriv = 1; - } - if ( $showpage ) { - my $needspriv = ( $haspriv ? "" : " needspriv" ); - my $privreason = ""; - if ( @gotprivs || @needsprivs ) { - my $needpriv = ( @needsprivs > 1 ? "<?_ml .needs_one_of _ml?>" : "<?_ml .needspriv _ml?>" ); - $privreason = ( $haspriv ? "(<b>" . join( "</b>, <b>", @gotprivs ) . "</b>)" - : "($needpriv: <b>" . join( "</b>, <b>", @needsprivs ) . "</b>)" ); - } - $ret .= "<li class='item$needspriv'><div class='itemhead'><a href='$path'>$name</a> <span class='itemprivs'>$privreason</span></div><div class='itemdef'>$description</div></li>\n"; - } - } - - $ret .= "</ul>"; - - return $ret; -} -_code?> -<=body -title=><?_code return $title; _code?> -windowtitle=><?_code return $windowtitle; _code?> -head<= -<style type="text/css"> -.item {margin-bottom: 15px;} -.item.needspriv div, .item.needspriv a {color: #A0A0A0;} -.itemhead {font-size: bigger; font-weight: bold;} -.itemdef {margin-left: 2em;} -.itemprivs {font-size: smaller; font-weight: normal; color: #707070;} -</style> -<=head -page?> diff -r f4fcc06b2940 -r 61913b5952d1 htdocs/admin/index.bml.text --- a/htdocs/admin/index.bml.text Thu Oct 28 10:15:22 2010 +0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,100 +0,0 @@ -;; -*- coding: utf-8 -*- - -.admin.title=Admin Tools - -.admin.capability.link=Capability Edit -.admin.capability.text=For editing user capabilities. - -.admin.cluster.link=Cluster Status -.admin.cluster.text=Get information on cluster availability. - -.admin.console.link=Console -.admin.console.text=For general input; usable by all users to an extent. - -.admin.dbschema.link=Database Schema -.admin.dbschema.text=Shows the database schema. - -.admin.dupkiller.link=Duplicate Entry Killer -.admin.dupkiller.text=Checks for (and kills) duplicate entries. - -.admin.entryprops.link=Entry Properties -.admin.entryprops.text=View the properties set on a particular entry. - -.admin.faq.link=FAQ Tools -.admin.faq.text=Allows you to manipulate the FAQ. - -.admin.file_edit.link=File Edit -.admin.file_edit.text=Allows you to edit various include files. - -.admin.invites.link=Invite Code Management -.admin.invites.text=View and manage invite codes. - -.admin.logout_user.link=Logout User -.admin.logout_user.text=Logs a user out of the site. - -.admin.memcache.link=Memcache Overview -.admin.memcache.text=Shows current memcache conditions. - -.admin.memcache_view.link=Memcache View -.admin.memcache_view.text=Shows current memcache details. - -.admin.mysql.link=MySQL Status -.admin.mysql.text=Shows current MySQL status. - -.admin.navtag.link=Navtag Edit -.admin.navtag.text=Allows you to tag pages for navigation. - -.admin.pay.link=Payment Managements -.admin.pay.text=Review payment details. - -.admin.priv.link=Privilege Management -.admin.priv.text=View privs by priv or by user. Some priv lists are private. - -.admin.propedit.link=User Property Edit -.admin.propedit.text=Allows you to view and edit userprops. - -.admin.recent_comments.link=Recent Comments -.admin.recent_comments.text=Allows you to view a user's recent comments. - -.admin.sitemessages_add.link=Site Messages - Add -.admin.sitemessages_add.text=Add new site-wide messages. - -.admin.sitemessages_manage.link=Site Messages - Manage -.admin.sitemessages_manage.text=View and manipulate site-wide messages. - -.admin.spamreports.link=Spam Reports -.admin.spamreports.text=View and handle reports of spam. - -.admin.stats.link=Business Statistics -.admin.stats.text=Detailed breakdown of business statistics - -.admin.statushistory.link=Statushistory -.admin.statushistory.text=Shows you a user's statushistory. - -.admin.styleinfo.link=Style Info -.admin.styleinfo.text=Shows you a user's style information. - -.admin.sysban.link=Sysban Management -.admin.sysban.text=Set and manage sysbans. - -.admin.theschwartz.link=TheSchwartz Queue/Error Viewer -.admin.theschwartz.text=View the status of jobs in the TheSchwartz queue. - -.admin.translate.link=Translation & Site Copy -.admin.translate.text=View and edit the site copy and translations. - -.admin.userlog.link=Userlog Viewer -.admin.userlog.text=Shows you a user's logged actions. - -.anysupportpriv=any support priv -.devserver=dev server - -.needspriv=needs -.needs_one_of=needs one of - - - - - - - diff -r f4fcc06b2940 -r 61913b5952d1 t/routing.t --- a/t/routing.t Thu Oct 28 10:15:22 2010 +0800 +++ b/t/routing.t Thu Oct 28 11:06:03 2010 +0800 @@ -1,6 +1,6 @@ # -*-perl-*- use strict; -use Test::More tests => 186; +use Test::More tests => 194; use lib "$ENV{LJHOME}/cgi-bin"; # don't let DW::Routing load DW::Controller subclasses @@ -217,7 +217,37 @@ handle_request( "/test app implied_forma handle_request( "/test app implied_format (app)" , "/test/app/all_format.json", 1, "it_worked_app_af" ); # 3 test # 186 -use Data::Dumper; +DW::Routing->register_string( "/xx3/index", \&handler, app => 1, args => "it_worked_redir" ); + +$expected_format = 'html'; +handle_request( "/xx3" , "/xx3/", 1, "it_worked_redir" ); # 3 tests +# 189 + +handle_request( "/xx3" , "/xx3/index", 1, "it_worked_redir" ); # 3 tests +# 192 + +handle_redirect( '/xx3', '/xx3/' ); +# 194 + +sub handle_redirect { + my ( $uri, $expected ) = @_; + + $DW::Request::determined = 0; + $DW::Request::cur_req = undef; + + my $req = HTTP::Request->new(GET=>"$uri"); + + my $opts = DW::Routing->get_call_opts( uri => $uri ); + + return fail( "Opts is undef" ) unless $opts; + + my $hash = $opts->call_opts; + return fail( "No call opts" ) unless $hash && $hash->{sub}; + + is( $hash->{sub}, \&DW::Routing::_redirect_helper ); + is( $hash->{args}, $expected ); +} + sub handle_request { my ( $name, $uri, $valid, $expected, %opts ) = @_; diff -r f4fcc06b2940 -r 61913b5952d1 views/admin/index.tt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/views/admin/index.tt Thu Oct 28 11:06:03 2010 +0800 @@ -0,0 +1,37 @@ +[%# admin/index.tt + +Admin action list index pages + +Authors: + Andrea Nall <anall@andreanall.com> + Denise Paolucci <denise@dreamwidth.org> + Sophie Hamilton <dw-bugzilla@theblob.org> + +This program is free software; you may redistribute it and/or modify it under +the same terms as Perl itself. For a copy of the license, please reference +'perldoc perlartistic' or 'perldoc perlgpl'. + +%][%- sections.title = title_ml | ml -%] +[%- sections.head = BLOCK %] +<style type="text/css"> +.item {margin-bottom: 15px;} +.item.needspriv div, .item.needspriv a {color: #A0A0A0;} +.itemhead {font-size: bigger; font-weight: bold;} +.itemdef {margin-left: 2em;} +.itemprivs {font-size: smaller; font-weight: normal; color: #707070;} +</style> +[%- END -%] + +[%- IF ml_scope -%][%- CALL dw.ml_scope( ml_scope ) -%][%- END -%] +[%- IF description_ml -%]<p>[%- description_ml | ml -%][%- END -%] + +[%- FOREACH p IN pages -%][%- p.link = p.link_ml | ml -%][%- END -%] +<ul>[% FOREACH p IN pages.sort_by_key( 'link' ) %] +<li class='item[%- p.haspriv ? "" : " needspriv" -%]'><div class='itemhead'><a href='[%- p.path -%]'>[%- p.link -%]</a> [%- IF p.gotprivs.size OR p.needsprivs.size -%]<span class='itemprivs'> +([%- IF p.haspriv -%] +<b>[%- p.gotprivs.join("</b>, <b>") -%]</b> +[%- ELSE -%] +<b>[%- ( p.needsprivs.size > 1 ? '.needs_one_of' : '.needspriv' ) | ml -%]: [%- p.needsprivs.join("</b>, <b>") -%]</b> +[%- END -%]) +</span>[%- END -%]</div><div class='itemdef'>[%- p.description_ml | ml -%]</div></li> +[% END %]</ul> diff -r f4fcc06b2940 -r 61913b5952d1 views/admin/index.tt.text --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/views/admin/index.tt.text Thu Oct 28 11:06:03 2010 +0800 @@ -0,0 +1,97 @@ +;; -*- coding: utf-8 -*- + +.admin.title=Admin Tools + +.admin.capability.link=Capability Edit +.admin.capability.text=For editing user capabilities. + +.admin.cluster.link=Cluster Status +.admin.cluster.text=Get information on cluster availability. + +.admin.console.link=Console +.admin.console.text=For general input; usable by all users to an extent. + +.admin.dbschema.link=Database Schema +.admin.dbschema.text=Shows the database schema. + +.admin.dupkiller.link=Duplicate Entry Killer +.admin.dupkiller.text=Checks for (and kills) duplicate entries. + +.admin.entryprops.link=Entry Properties +.admin.entryprops.text=View the properties set on a particular entry. + +.admin.faq.link=FAQ Tools +.admin.faq.text=Allows you to manipulate the FAQ. + +.admin.file_edit.link=File Edit +.admin.file_edit.text=Allows you to edit various include files. + +.admin.invites.link=Invite Code Management +.admin.invites.text=View and manage invite codes. + +.admin.logout_user.link=Logout User +.admin.logout_user.text=Logs a user out of the site. + +.admin.memcache.link=Memcache Overview +.admin.memcache.text=Shows current memcache conditions. + +.admin.memcache_view.link=Memcache View +.admin.memcache_view.text=Shows current memcache details. + +.admin.mysql.link=MySQL Status +.admin.mysql.text=Shows current MySQL status. + +.admin.navtag.link=Navtag Edit +.admin.navtag.text=Allows you to tag pages for navigation. + +.admin.pay.link=Payment Managements +.admin.pay.text=Review payment details. + +.admin.priv.link=Privilege Management +.admin.priv.text=View privs by priv or by user. Some priv lists are private. + +.admin.propedit.link=User Property Edit +.admin.propedit.text=Allows you to view and edit userprops. + +.admin.recent_comments.link=Recent Comments +.admin.recent_comments.text=Allows you to view a user's recent comments. + +.admin.sitemessages_add.link=Site Messages - Add +.admin.sitemessages_add.text=Add new site-wide messages. + +.admin.sitemessages_manage.link=Site Messages - Manage +.admin.sitemessages_manage.text=View and manipulate site-wide messages. + +.admin.spamreports.link=Spam Reports +.admin.spamreports.text=View and handle reports of spam. + +.admin.statushistory.link=Statushistory +.admin.statushistory.text=Shows you a user's statushistory. + +.admin.styleinfo.link=Style Info +.admin.styleinfo.text=Shows you a user's style information. + +.admin.sysban.link=Sysban Management +.admin.sysban.text=Set and manage sysbans. + +.admin.theschwartz.link=TheSchwartz Queue/Error Viewer +.admin.theschwartz.text=View the status of jobs in the TheSchwartz queue. + +.admin.translate.link=Translation & Site Copy +.admin.translate.text=View and edit the site copy and translations. + +.admin.userlog.link=Userlog Viewer +.admin.userlog.text=Shows you a user's logged actions. + +.anysupportpriv=any support priv +.devserver=dev server + +.needspriv=needs +.needs_one_of=needs one of + + + + + + + diff -r f4fcc06b2940 -r 61913b5952d1 views/admin/rename.tt --- a/views/admin/rename.tt Thu Oct 28 10:15:22 2010 +0800 +++ b/views/admin/rename.tt Thu Oct 28 11:06:03 2010 +0800 @@ -9,8 +9,9 @@ the same terms as Perl itself. For a co the same terms as Perl itself. For a copy of the license, please reference 'perldoc perlartistic' or 'perldoc perlgpl'. %] +[%- sections.title = '.title' | ml -%] -[% sections.title = '.title' | ml %] +<a href="[%site.root%]/admin/rename/new">[% '.new.link' | ml %]</a> [% IF renames %] [% IF renames.size == 0 %] @@ -35,7 +36,7 @@ the same terms as Perl itself. For a co [% IF user %] <p> -<a href="[%site.root%]/admin/rename">Return to renames lookup</a> +<a href="[%site.root%]/admin/rename/">Return to renames lookup</a> </p> [% ELSE %] <form method="GET"> diff -r f4fcc06b2940 -r 61913b5952d1 views/admin/rename.tt.text --- a/views/admin/rename.tt.text Thu Oct 28 10:15:22 2010 +0800 +++ b/views/admin/rename.tt.text Thu Oct 28 11:06:03 2010 +0800 @@ -1,4 +1,9 @@ ;; -*- coding: utf-8 -*- + +.admin.link=Renames +.admin.text=Manage renames + +.new.link=Create Rename .renames.list.empty=No renames involving "[[user]]". diff -r f4fcc06b2940 -r 61913b5952d1 views/admin/stats.tt.text --- a/views/admin/stats.tt.text Thu Oct 28 10:15:22 2010 +0800 +++ b/views/admin/stats.tt.text Thu Oct 28 11:06:03 2010 +0800 @@ -1,3 +1,7 @@ ;; -*- coding: utf-8 -*- +.admin.link=Business Statistics +.admin.text=Detailed breakdown of business statistics + .title=Business Statistics + --------------------------------------------------------------------------------