# Copyright 2002-2008 Josh Clark and Global Moxie, LLC. This code cannot be
# redistributed without permission from globalmoxie.com.  For more
# information, consult your Big Medium license.
#
# $Id: CP.pm 3233 2008-08-21 12:47:26Z josh $

package BigMed::App::Web::CP;
use strict;
use warnings;
use utf8;
use Carp;
$Carp::Verbose = 1;
use base qw(BigMed::App::Web::Login);
use BigMed::Plugin::CP;
use BigMed::DiskUtil qw(bm_file_path);
use BigMed::MD5 qw(md5_hex);

my $NAV_SECTION;
my @BREADCRUMBS;

my %NAVIGATION = (

    #NEWPAGE and subsections
    'NewPage' => {
        priority => 100,
        url => { script => 'bm-editor.cgi', rm => 'edit', args => ['page'] },
        min_level => 2,
    },
    'NewArticle' => {
        belongs_to => 'NewPage',
        priority   => 99,
        url        => {
            script => 'bm-editor.cgi',
            rm     => 'edit',
            args   => ['page.article']
        },
        min_level => 2,
    },
    'NewDownload' => {
        belongs_to => 'NewPage',
        priority   => 98,
        url        => {
            script => 'bm-editor.cgi',
            rm     => 'edit',
            args   => ['page.download']
        },
        min_level => 2,
    },
    'NewLink' => {
        belongs_to => 'NewPage',
        priority   => 96,
        url        =>
          { script => 'bm-editor.cgi', rm => 'edit', args => ['page.link'] },
        min_level => 2,
    },
    'NewPodcast' => {
        belongs_to => 'NewPage',
        priority   => 94,
        url        => {
            script => 'bm-editor.cgi',
            rm     => 'edit',
            args   => ['page.podcast']
        },
        min_level => 2,
    },
    'NewAnnc' => {
        belongs_to => 'NewPage',
        priority   => 70,
        url        => {
            script => 'bm-editor.cgi',
            rm     => 'edit',
            args   => ['announcement']
        },
        min_level => 2,
    },
    'NewTip' => {
        belongs_to => 'NewPage',
        priority   => 70,
        url => { script => 'bm-editor.cgi', rm => 'edit', args => ['tip'] },
        min_level => 2,
    },

    #EDITPAGE and subsections
    'Edit' => {
        priority => 90,
        url => { script => 'bm-editor.cgi', rm => 'menu', args => ['page'] },
        min_level => 2,
    },
    'EditPages' => {
        belongs_to => 'Edit',
        priority   => 100,
        url => { script => 'bm-editor.cgi', rm => 'menu', args => ['page'] },
        min_level => 2,
    },
    'EditArticles' => {
        belongs_to => 'Edit',
        priority   => 98,
        url        => {
            script => 'bm-editor.cgi',
            rm     => 'menu',
            args   => ['page.article']
        },
        min_level => 2,
    },
    'EditDownloads' => {
        belongs_to => 'Edit',
        priority   => 96,
        url        => {
            script => 'bm-editor.cgi',
            rm     => 'menu',
            args   => ['page.download']
        },
        min_level => 2,
    },
    'EditLinks' => {
        belongs_to => 'Edit',
        priority   => 94,
        url        => {
            script => 'bm-editor.cgi',
            rm     => 'menu',
            args   => ['page.link']
        },
        min_level => 2,
    },
    'EditPodcasts' => {
        belongs_to => 'Edit',
        priority   => 92,
        url        => {
            script => 'bm-editor.cgi',
            rm     => 'menu',
            args   => ['page.podcast']
        },
        min_level => 2,
    },
    'EditSections' => {
        belongs_to => 'Edit',
        priority   => 90,
        url        => {
            script => 'bm-editor.cgi',
            rm     => 'menu',
            args   => ['page.section']
        },
        min_level => 2,
    },
    'EditComm' => {
        belongs_to => 'Edit',
        priority   => 86,
        url        => { script => 'bm-mod.cgi', rm => 'public' },
        min_level  => 4,
    },
    'ModComm' => {
        belongs_to => 'Edit',
        priority   => 84,
        url        => { script => 'bm-mod.cgi', rm => 'mod' },
        min_level  => 4,
    },
    'SpamComm' => {
        belongs_to => 'Edit',
        priority   => 82,
        url        => { script => 'bm-mod.cgi', rm => 'spam' },
        min_level  => 4,
    },
    'EditTips' => {
        belongs_to => 'Edit',
        priority   => 70,
        url => { script => 'bm-editor.cgi', rm => 'menu', args => ['tip'] },
        min_level => 2,
    },
    'EditAnnc' => {
        belongs_to => 'Edit',
        priority   => 70,
        url        => {
            script => 'bm-editor.cgi',
            rm     => 'menu',
            args   => ['announcement']
        },
        min_level => 2,
    },

    #LIBRARY and subsections
    'Library' => {
        priority  => 90,
        url       => { script => 'bm-library.cgi', rm => 'menu' },
        min_level => 2,
    },
    'LibraryImage' => {
        belongs_to => 'Library',
        priority   => 98,
        url        =>
          { script => 'bm-library.cgi', rm => 'menu', args => ['image'] },
        min_level => 2,
    },
    'LibraryAV' => {
        belongs_to => 'Library',
        priority   => 96,
        url => { script => 'bm-library.cgi', rm => 'menu', args => ['av'] },
        min_level => 2,
    },
    'LibraryDoc' => {
        belongs_to => 'Library',
        priority   => 94,
        url        =>
          { script => 'bm-library.cgi', rm => 'menu', args => ['document'] },
        min_level => 2,
    },
    'LibraryPerson' => {
        belongs_to => 'Library',
        priority   => 92,
        url        =>
          { script => 'bm-library.cgi', rm => 'menu', args => ['person'] },
        min_level => 2,
    },

    #TEMPLATES and subsections --------
    'Layout' => {
        priority  => 80,
        url       => { script => 'bm-templates.cgi', rm => 'main-menu' },
        min_level => 5,
    },
    'RebuildPagesNow' => {
        belongs_to => 'Layout',
        priority   => 102,
        url        => { script => 'bm-build.cgi', rm => 'build-all' },
        min_level  => 5,
    },
    'RebuildPages' => {
        belongs_to => 'Layout',
        priority   => 101,
        url        => { script => 'bm-build.cgi', rm => 'menu' },
        min_level  => 5,
    },
    'SectionStructure' => {
        belongs_to => 'Layout',
        priority   => 95,
        url        => { script => 'bm-sections.cgi', rm => 'outline' },
        min_level  => 5,
    },
    'EditTemplates' => {
        belongs_to => 'Layout',
        priority   => 94,
        url        => { script => 'bm-templates.cgi', rm => 'menu' },
        min_level  => 5,
    },
    'EditThemeCSS' => {
        belongs_to => 'Layout',
        priority   => 92,
        url        => { script => 'bm-themes.cgi', rm => 'edit' },
        min_level  => 5,
    },
    'NewTheme' => {
        belongs_to => 'Layout',
        priority   => 87,
        url        => { script => 'bm-themes.cgi', rm => 'menu' },
        min_level  => 5,
    },
    'SaveTheme' => {
        belongs_to => 'Layout',
        priority   => 84,
        url        => { script => 'bm-themes.cgi', rm => 'save-site' },
        min_level  => 6,
    },
    'RemoveTheme' => {
        belongs_to => 'Layout',
        priority   => 82,
        url        => { script => 'bm-themes.cgi', rm => 'remove' },
        min_level  => 5,
    },

    # STYLES and subsections ----------
    'Styles' => {
        priority  => 70,
        url       => { script => 'bm-css.cgi', rm => 'edit' },
        min_level => 5,
    },

    # ACCOUNTS and subsections ----------
    'Accounts' => {
        priority  => 60,
        url       => { script => 'bm-account.cgi', rm => 'find-route' },
        min_level => 2,
        no_site   => 1,
    },
    'MyAccount' => {
        belongs_to => 'Accounts',
        priority   => 95,
        url        => { script => 'bm-account.cgi', rm => 'edit' },
        min_level => 5,    #other levels accounted for with top menu item
    },
    'NewAccount' => {
        belongs_to => 'Accounts',
        priority   => 87,
        url        => { script => 'bm-account.cgi', rm => 'new' },
        min_level  => 5,
    },
    'SearchAccounts' => {
        belongs_to => 'Accounts',
        priority   => 85,
        url        => { script => 'bm-account.cgi', rm => 'menu' },
        min_level  => 5,
    },
    'AllAccounts' => {
        belongs_to => 'Accounts',
        priority   => 83,
        url        =>
          { script => 'bm-account.cgi', rm => 'search', args => ['all'] },
        min_level => 5,
    },

    # SETTINGS and subsections ----------
    'Settings' => {
        priority  => 50,
        url       => { script => 'bm-prefs.cgi', rm => 'main-menu' },
        min_level => 5,
        no_site   => 1,
    },
    'HTMLPrefs' => {
        belongs_to => 'Settings',
        priority   => 87,
        url => { script => 'bm-prefs.cgi', rm => 'menu', args => 'HTML' },
        min_level => 5,
    },
    'RSSPrefs' => {
        belongs_to => 'Settings',
        priority   => 85,
        url        => {
            script => 'bm-prefs.cgi',
            rm     => 'edit',
            args   => ['RSS', 'rss_feeds']
        },
        min_level => 5,
    },
    'JSPrefs' => {
        belongs_to => 'Settings',
        priority   => 83,
        url        => {
            script => 'bm-prefs.cgi',
            rm     => 'edit',
            args   => ['JS', 'js_feeds']
        },
        min_level => 5,
    },
    'SectionProperties' => {
        belongs_to => 'Settings',
        priority   => 75,
        url        => {
            script => 'bm-prefs.cgi',
            rm     => 'section-menu',
        },
        min_level => 5,
    },
    'SiteProperties' => {
        belongs_to => 'Settings',
        priority   => 68,
        url        => { script => 'bm-siteconfig.cgi', rm => 'properties' },
        min_level  => 5,
    },
    'SiteImageFormats' => {
        belongs_to => 'Settings',
        priority   => 67,
        url        => { script => 'bm-siteconfig.cgi', rm => 'images' },
        min_level  => 5,
    },
    'SiteDir' => {
        belongs_to => 'Settings',
        priority   => 65,
        url        => { script => 'bm-config.cgi', rm => 'edit-site' },
        min_level  => 6,
    },
    'NewSite' => {
        belongs_to => 'Settings',
        priority   => 58,
        url        => { script => 'bm-config.cgi', rm => 'new-site' },
        min_level  => 6,
    },
    'CloneSite' => {
        belongs_to => 'Settings',
        priority   => 55,
        url        => { script => 'bm-config.cgi', rm => 'clone-site' },
        min_level  => 6,
    },
    'ReviewSites' => {
        belongs_to => 'Settings',
        priority   => 53,
        url        => { script => 'bm-review.cgi', rm => 'review' },
        min_level  => 6,
    },
    'ImportV1' => {
        belongs_to => 'Settings',
        priority   => 52,
        url        => { script => 'bm-import.cgi', rm => 'v1loc' },
        min_level  => 6,
    },
    'FileUploads' => {
        belongs_to => 'Settings',
        priority   => 17,
        url        => { script => 'bm-config.cgi', rm => 'filetypes' },
        min_level  => 6,
    },
    'Server' => {
        belongs_to => 'Settings',
        priority   => 15,
        url        => { script => 'bm-config.cgi', rm => 'server' },
        min_level  => 6,
    },
    'About' => {
        belongs_to => 'Settings',
        priority   => 12,
        url        => { script => 'bm-config.cgi', rm => 'about-you' },
        min_level  => 6,
    },
    'Register' => {
        belongs_to => 'Settings',
        priority   => 9,
        url        => { script => 'bm-config.cgi', rm => 'register' },
        min_level  => 6,
    },
    'Update' => {
        belongs_to => 'Settings',
        priority   => 6,
        url        => {
          url => 'http://globalmoxie.com/cgi-bin/license/update.cgi?v=' . BigMed->VERSION,
        },
        min_level  => 6,
    },

    #    'Plugins' => {
    #        priority  => 40,
    #        url       => { script => 'bm-plugins.cgi', rm => 'menu' },
    #        min_level => 2,
    #        no_site   => 1,
    #    },
    #    'Help' => {
    #        priority  => 30,
    #        url       => { script => 'bm-help.cgi', rm => 'menu' },
    #        min_level => 2,
    #        no_site   => 1,
    #    },
);

sub cgiapp_init {
    my $app = shift;
    $app->SUPER::cgiapp_init;

    #initialize navigation
    undef $NAV_SECTION;
    undef @BREADCRUMBS;

    return;
}

sub init_plugins {
    BigMed::Plugin::CP->init_plugins();
    return;
}

sub require_privilege_level {
    my $app   = shift;
    my $level = shift or return;
    my $user  = $app->current_user or return;
    my $site;
    if ( $level > 5 ) {    #admin, no need to load site
        return if $user->level >= $level;
        $app->prerun_mode('not-permitted');
    }
    elsif ( $site = $app->current_site ) {
        $app->prerun_mode('not-permitted')
          if $user->privilege_level($site) < $level;
    }
    else {
        $app->prerun_mode('login-site');
    }
    return;
}

sub html_general_params {
    my $app   = shift;
    my @param = @_;
    return if !$app->env('MOXIEDATA');    #not configured yet
    my $site       = $app->current_site;
    my $site_id    = $site ? $site->id : q{};
    my $user       = $app->current_user;
    my $priv_level = $user ? ( $user->privilege_level($site) || 0 ) : 0;

    #collect main nav and assign subsections to the appropriate parent
    my %nav = ( %NAVIGATION, BigMed::Plugin::CP->nav_items() );
    my @main_nav;
    my %subnav;
    foreach my $name ( keys %nav ) {
        next if !$site && !$nav{$name}->{no_site};
        next
          if $nav{$name}->{min_level}
          && $nav{$name}->{min_level} > $priv_level;

        my $parent = $nav{$name}->{belongs_to};
        if ( $parent && exists $nav{$parent} ) {    #subsection
            my $ritem = { %{ $nav{$name} }, name => $name };
            push @{ $subnav{$parent} }, $ritem;
        }
        else {                                      #main section
            push @main_nav, $name;
        }
    }
    @main_nav =
      sort { $b->{priority} <=> $a->{priority} || $a->{name} cmp $b->{name} }
      map {
        { %{ $nav{$_} }, name => $_ }
      } @main_nav;

    #build the navigation parameters, sorting subnav as we go.
    my @navigation;
    foreach my $nav (@main_nav) {
        $nav->{subnav} = $subnav{ $nav->{name} } || [];
        push @navigation,
          $app->_build_nav_silo( $nav, $priv_level, $site_id );
    }

    $app->js_add_script(
        [$app->env('BMADMINURL') . '/js/bm-iemenu.js', 'if lt IE 7'] );
    $app->js_add_onload('BM.Menu.init("bmcpNavigation");');

    #breadcrumb array
    my @bcrumbs = @BREADCRUMBS;
    foreach my $rbc (@bcrumbs) {
        my %bc = %{$rbc};
        $bc{bc_label} = $app->language( $bc{bc_label} );
        $rbc = \%bc;
    }

    #one-click editing
    my $oneclick = $site ? $site->html_url . '/bm.assets/edit.shtml' : undef;

    my %tmpl_param = $app->SUPER::html_general_params(@param);
    $tmpl_param{bmcp_nav}         = \@navigation;
    $tmpl_param{bmcp_breadcrumbs} = \@bcrumbs;
    $tmpl_param{bmcp_oneclick}    = $oneclick;
    return %tmpl_param;
}

sub cp_selected_nav {
    return $NAV_SECTION;
}

sub set_cp_selected_nav {
    return $NAV_SECTION = $_[1];
}

sub cp_breadcrumbs {
    return @BREADCRUMBS;
}

sub set_cp_breadcrumbs {
    my $app = shift;
    @BREADCRUMBS = @_;
    return @BREADCRUMBS;
}

sub set_session_message {
    my ( $app, $message, $is_error ) = @_;

    #TO DO: Handle multiple session messages
    $app->session->param( 'BMCP_message', $message );
    $app->session->param( 'BMCP_is_error', 1 ) if $is_error;
    $app->session->flush();
    return;
}

sub title_and_message {
    my $app     = shift;
    my %options = @_;
    my $session = $app->session;
    my $smsg    = $session->param('BMCP_message');
    if ( defined $smsg ) {
        $options{message} = $smsg;
        $app->js_make_error_box('bm_MainMessage')
          if $session->param('BMCP_is_error');
        $session->clear( ['BMCP_message', 'BMCP_is_error'] );
    }
    return $app->SUPER::title_and_message(%options);
}

sub _build_nav_silo {
    my ( $app, $nav, $priv_level, $site_id ) = @_;
    my %nav_item = %{$nav};    #de-reference for persistent environments
    $nav_item{nav_selected} = $NAV_SECTION && $NAV_SECTION eq $nav_item{name};
    $nav_item{label} ||= "BM_CP_NAVLABEL_$nav_item{name}";
    $nav_item{label} = $app->language( $nav_item{label} );
    $nav_item{label} = $app->language('BM_CP_NAVLABEL_MyAccount')
      if $nav_item{label} eq 'Accounts' && $priv_level < 5;
    $nav_item{url} = $app->build_url( %{ $nav_item{url} }, site => $site_id );
    my @subnav = $nav_item{subnav} ? @{ $nav_item{subnav} } : ();
    @subnav =
      sort { $b->{priority} <=> $a->{priority} || $a->{name} cmp $b->{name} }
      @subnav;
    my @subparam;
    my $level;

    foreach my $item (@subnav) {    #handle subnav, insert dividers
        if ( $level && int( $level / 10 ) > int( $item->{priority} / 10 ) ) {
            $item->{divider} = 1;
            $level = $item->{priority};
        }
        else {
            delete $item->{divider};
            $level = $item->{priority};
        }
        push @subparam, $app->_build_nav_silo( $item, $priv_level, $site_id );
    }
    $nav_item{all_subnav} = \@subparam;
    return \%nav_item;
}

sub _check_maint_updates {
    my $app = shift;
    return 1 if $app->current_user->level < 6;    #not admin

    my $janitor_log = bm_file_path( BigMed::Log->logdir, 'janitor_log.txt' );
    if ( !-e $janitor_log ) {
        $app->set_session_message( 'BM_CP_Maintenance routine never run',
            'is_error' );
    }
    elsif ( -M $janitor_log > 2 ) {
        my $days = int( -M $janitor_log );
        $app->set_session_message(
            ['BM_CP_Maintenance routine not run recently', $days],
            'is_error' );
    }
    return 1;
}

my $aft_fir_lg = pack( 'U0C*',
    97,  102, 116, 101, 114, 95,  102, 105,
    114, 115, 116, 95,  108, 111, 103 )
  . 'in';
BigMed::App::Web::CP->add_trigger( $aft_fir_lg, \&_ck_exp );
BigMed::App::Web::CP->add_trigger( $aft_fir_lg, \&_check_maint_updates );
my $CALLNAME = q{Ahab's fish};

sub _ck_exp {
    my $app       = shift;
    my $rm_act    = pack 'U0C*', ( 97, 99, 116, 105, 118, 97, 116, 101 );
    my $rm_rg     = pack 'U0C*', ( 114, 101, 103, 105, 115, 116, 101, 114 );
    my $rnum      = pack 'U0C*', ( 82, 69, 71, 78, 85, 77 );
    my $lang_pref = pack( 'U0C*',
        67, 79, 78, 70, 73, 71, 95, 82, 69, 71, 73, 83, 84, 69, 82 );
    if ( $app->isa('BigMed::App::Web::Config') ) {
        my $rm = $app->get_current_runmode();
        return if $rm eq $rm_act || $rm eq $rm_rg; #ret false: no more trigs
    }
    my $lev  = $app->current_user->level;
    my $ln   = $app->env($rnum);
    my $script = pack ('U0C*', 98,109,45,99,111,110,102,105,103,46,99,103,105);
    my $rurl = $app->build_url(
        script => $script,
        rm     => $rm_rg,
    );
    return $app->_ck_age( $lev, $rurl ) if !$ln;

    my $upd_rg =
      pack( 'U0C*', 117, 112, 100, 97, 116, 101, 95, 114, 101, 103 );
    if ( $ln =~ m{\ABM-\d+-\S{4}[1-9Zz]{6}\z}msi ) {
        my $expl = $lev >= 6 ? "admin_$upd_rg" : $upd_rg;
        my $url  = $lev >= 6 ? $rurl           : $app->env('ADMINEMAIL');
        return $app->basic_message(
            'head' => $app->language("${lang_pref}_HEAD_$expl"),
            'text' => $app->language( ["${lang_pref}_$expl", $url] ),
            'exit' => 1,
        );
    }

    my $v      = 0;
    my %ck_map =
      map { $_ => $v++ }
      qw(A B C D E F G H J K L M N P Q R T U V W Y 3 4 6 7 8 9);
    my $NDIG  = 19;
    my @chars = reverse( split //, uc $ln );
    my $digit = shift @chars;
    @chars = grep { exists $ck_map{$_} } @chars;
    my $ok;
    if ( @chars == $NDIG ) {
        my $totalVal = 0;
        my $flip     = 1;
        foreach my $c (@chars) {
            my $posVal = $ck_map{$c};
            $posVal *= 2 unless $flip = !$flip;
            while ($posVal) {
                $totalVal += $posVal % 10;
                $posVal = int( $posVal / 10 );
            }
        }
        $ok = ( $digit == ( ( 10 - $totalVal % 10 ) % 10 ) );
    }
    if ( !$ok ) {
        my $bm = $app->bigmed;
        $bm->set_env( $rnum, undef );
        $bm->save_config();
        return $app->_ck_age( $lev, $rurl );
    }

    my $act = $app->build_url(
        script => $script,
        site   => 'x',
        rm     => $rm_act,
    );
    my $code = md5_hex("$ln$act$CALLNAME");
    if ( !$app->env('RCONF') || $app->env('RCONF') ne $code ) {
        my $expl = $lev >= 6 ? 'ADMIN_' : q{};
        my $url  = $lev >= 6 ? $rurl    : $app->env('ADMINEMAIL');
        return $app->basic_message(
            'head' => $app->language("${lang_pref}_Please $rm_act"),
            'text' => $app->language("${lang_pref}_TEXT_please_$rm_act")
              . '<br /><br />'
              . $app->language(
                ["CONFIG_REGISTER_${expl}post_$rm_act", $url] ),
            'exit' => 1,
        );
    }
    return 1;
}

sub _ck_age {
    my ( $app, $lev, $rurl ) = @_;
    my $bad = ( -M $app->bigmed->{_config} > 30 );
    if ( !$bad ) {
        my $tobj = $app->bigmed->time_obj;
        $tobj->shift_time('-30d');
        my $cut = $tobj->bigmed_time;
        require BigMed::Site;
        $bad = BigMed::Site->fetch( { mod_time => { to => $cut } } );
        if ( !$bad ) {
            my $all_site = BigMed::Site->select() or return;
            while ( my $site = $all_site->next ) {
                $bad = ( $site->create_time lt $cut );
                last if $bad;
            }
        }
    }
    return 1 if !$bad;

    my $reg = pack 'U0C*', ( 114, 101, 103, 105, 115, 116, 101, 114 );
    my $expl = $lev >= 6 ? "please_$reg" : "must_$reg";
    my $url  = $lev >= 6 ? $rurl         : $app->env('ADMINEMAIL');
    my $lang_pref = pack( 'U0C*',
        67, 79, 78, 70, 73, 71, 95, 82, 69, 71, 73, 83, 84, 69, 82 );
    my $dem_per_exp = pack( 'U0C*',
        100, 101, 109, 111, 32,  112, 101, 114,
        105, 111, 100, 32,  101, 120, 112 )
      . 'ired';
    return $app->basic_message(
        'head' => $app->language("${lang_pref}_HEAD_$dem_per_exp"),
        'text' => $app->language("${lang_pref}_$dem_per_exp")
          . '<br /><br />'
          . $app->language( ["${lang_pref}_admin_$expl", $url] ),
        'exit' => 1,
    );
}

1;
__END__

=head1 NAME

BigMed::App::Web::CP - Big Medium application class for authenticated
control panel run modes

=head1 DESCRIPTION

BigMed::App::Web::CP is a subclass of BigMed::App::Login for run modes
requiring authentication, limitation to certain account types,
and control panel views. CP helps you by automatically adding the
appropriate HTML::Template parameters when the C<html_template_screen>
method is called to display a run mode screen. The navigation options
are tailored to the specific user privileges of the current user.

=head2 METHODS

=head3 C<< $app->require_privilege_level( $min_level ) >>

Checks to make sure that the current user has the minimum required privilege
level at the current site to use the run modes in your application module.
Accepts one argument, the numeric value of the minimum required privilege
level.  These levels are the same established by the BigMed::Priv
class:

=over 4

=item * 1 = guest

=item * 2 = writer

=item * 3 = editor

=item * 4 = publisher

=item * 5 = webmaster

=item * 6 = administrator

=back

This method should be called in your subclass module's cgiapp_prerun
method, after calling the SUPER::cgiapp_prerun method:

    sub cgiapp_prerun {
        my $app = shift;
        $app->SUPER::cgiapp_prerun;
        $app->require_privilege_level(5);
    }

=head3 C<< $app->html_general_params >>

Overrides the BigMed::App::Web::Login method to supplement the template
parameters with these additional params:

=over 4

=item * bmcp_nav

A reference to an array of hash references, intended to be processed
as a TMPL_LOOP by the shell_cp_top.tmpl HTML template. Each hash reference
represents a section of the control panel and consists of these key/value
pairs:

=over 4

=item * nav_name

The internal name of the section (the nav_label parameter is the
display name).

=item * nav_selected

Boolean value indicating whether this is the active section, as indicated
by the C<cp_selected_nav> method.

=item * nav_label

The localized name of the section.

=item * nav_url

The URL of the control panel section.

=back

=item * bmcp_breadcrumbs

A reference to an array of hash references, intended to be processed
as a TMPL_LOOP by the shell_cp_top.tmpl HTML template. Each hash reference
represents a page in the breadcrumb trail. Items are ordered in drill-down
order from the control panel main page to the current local page. Each
hash reference consists of these key/value pairs:

=over 4

=item * bc_label

The localized name of the breadcrumb page.

=item * bc_url

The URL of the breadcrumb page.

=back

=back

=head3  C<< $app->set_cp_selected_nav($section_name) >>

Sets the name of the selected navigation section for the current page,
which corresponds to the C<nav_name> parameter of the C<bmcp_nav> loop.

=head3  C<< $app->cp_selected_nav >>

Returns the name of the selected navigation section, which corresponds to
the C<nav_name> parameter of the C<bmcp_nav> loop.

=head3  C<< $app->set_cp_breadcrumbs(@breadcrumbs) >>

Sets the breadcrumb array. The array should be an array of hash references
with the C<bc_label> and C<bc_url> parameters described for the
C<bmcp_breadcrumbs> loop.

=head3  C<< $app->cp_breadcrumbs >>

Returns the breadcrumb array of hash references.

=head3 C<< $app->set_session_message($message[, $is_error]) >>

    #set a normal message
    $app->set_session_message('Message text');
    
    #set an error message
    $app->set_session_message('Error text', 'is_error';

Sets a message to display on the next control panel page viewed by the 
user. Useful, for example, if you redirect to a new URL after completing
an action and want to display a message at that next page display.

The first argument is an unlocalized language lexicon key to be sent to the
C<language> method.

If true, the optional second optional argument may be used to indicate that
the message should be displayed as an error.

Currently handles just one message; subsequent calls to set_session_message
overwrite previous messages.

=head1 AUTHOR & COPYRIGHTS

This module and all Big Medium modules are copyright Josh Clark
and Global Moxie. All rights reserved.

Use of this module and the Big Medium content
management system are governed by Global Moxie's software licenses
and may not be used outside of the terms and conditions outlined
there.

For more information, visit the Global Moxie website at
L<http://globalmoxie.com/>.

Big Medium and Global Moxie are service marks of Global Moxie
and Josh Clark. All rights reserved.

=cut

