http://qs1969.pair.com?node_id=321064


in reply to Re: Re: Why CGI::Application?
in thread Why CGI::Application?

Sure. I'll post a condensation of what I'm working on right now. The plan is this - you have a main C::A, where you handle logging in, the home page, and logging out. You also have a C::A that handles how reporting works. Remember - some of your users might not have the authority to run reports, so it's easier to just disallow the whole C::A than it is to disallow certain run-modes.
package My::Application::Base; use CGI::Application; our @ISA = qw( CGI::Application ); sub setup { # Do basic stuff, including run_modes everyone has, like 'redirect +_login' } sub cgiapp_prerun { # Do $dbh and $user setup, including standard cookie handling } sub print { my $self = shift; my ($display_type, $template_name, @params) = @_; # This is my method. I have to potentially display in a number of +formats. # I use different templating modules to do that, like PDF::Templat +e or # Excel::Template, instead of just HTML::Template. This does that +for me. } -------- package My::Application::Main; use My::Application::Base; our @ISA = qw( My::Application::Base ); sub setup { my $self = shift; $self->run_modes([qw( login validate home logout )]; } sub login { my $self = shift; my ($error) = @_; my %params; $params{ERROR} = $error if defined $error; $self->print( 'html', 'login', %params, ); } sub validate { my $self = shift; if (BAD_LOGIN) { return $self->login($SOME_ERROR); } # Set the cookie up, and possibly a session. Hand this off # to other modules / functions / objects $self->home; } sub home { my $self = shift; $self->print( 'html', 'home', ); } sub logout { my $self = shift; # Destroy the session and the cookie $self->print( 'html', 'logout', ); }

Ok, so far so good. But, we don't have another C::A yet. I personally do my navigation through some header that I've TMPL_INCLUDE'd into all the relevant templates. (All of them, except login and logout.) The header basically has

HOME => main.cgi?mode=home REPORTS => reports.cgi LOGOUT => main.cgi?mode=logout

But, you wanted to see the other C::A. Here ya go:

package My::Application::Reports; use My::Application::Base; our @ISA = qw( My::Application::Base ); sub setup { my $self = shift; $self->runmodes([qw( choose display )]); } sub choose { # Display some method of choosing reports, probably with some auth +orization # checks in there } sub display { # Do the actual display of the report. }

That's it. No handling of cookies, no handling of nothing. In fact, there's absolutely no way the cookies are NOT going to be handled. You can't forget to add it to the top. You can't forget to do standard processing. It's quite ... nice to be able to forget that you have it cause it just works.

------
We are the carpenters and bricklayers of the Information Age.

Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

Replies are listed 'Best First'.
Re: Re: Re: Re: Why CGI::Application?
by t'mo (Pilgrim) on Jan 14, 2004 at 19:58 UTC

    I like the idea of composing subclasses of C::A into the larger application, but I didn't see how you implemented this bit of the 'technical specification':

    "...so it's easier to just disallow the whole C::A than it is to disallow certain run-modes."

    If REPORTS => reports.cgi is in the navigation template on every page, then how do you prevent the user from executing that particular C::A? And I don't think that

    # Display some method of choosing reports, probably with some author +ization # checks in there

    inside sub choose counts; it's still disallowing a certain run-mode named "choose". :-)

    p.s. I enjoyed and learned something from being sidetracked by http://www.mail-archive.com/cgiapp@lists.erlbaum.net/msg00849.html.

      It all depends on how your authentication method is set up. I'm still a little fuzzy on all the details, but you can do a few different things. Each has its own pros and cons, and some combination is probably best.
      1. Each C::A could authenticate itself against a master set of authorities. The C::A would implement a check against a set of authorities the user must have. The link would exist, but the user wouldn't get very far.
      2. If you're using TT or Mason, you could pass in a $user object and have it determine what links are available, based on the $user object. (Not C::A specific, I know, but not everything is implentable in C::A, nor should it be.)
      3. Instead of the $user knowing what links it can go to, you would have the C::A indicate what authorities are needed to get to it. Then, it would register with some master and the $user / TT / something would ask that master where it can go.

      And, I'm sure I'm missing other possible schemelets.

      ------
      We are the carpenters and bricklayers of the Information Age.

      Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

Late to the party, Re^4: Why CGI::Application?
by wfsp (Abbot) on Apr 27, 2007 at 10:23 UTC
    This is a tad on the late side. :-)

    The situation you discuss earlier is one that I'm also facing. I'd be interested in breaking a C::A into one or more C::As.

    I've tried to recreate the method you've used but I've hit a snag.

    You have

    package My::Application::Base; use CGI::Application; our @ISA = qw( CGI::Application ); sub setup{ # Do basic stuff, including run_modes everyone has, like 'redirect +_login' }
    Note the reference to run_modes. Later you have
    package My::Application::Reports; use My::Application::Base; our @ISA = qw( My::Application::Base ); sub setup{ my $self = shift; $self->runmodes([qw( choose display )]); }
    As far as I can tell the run_modes in Base are overwritten by the run_modes in Reports and I get a "No such run mode..." error when reffering to any run_mode in Base.

    Did you encounter this?

    Also, how would you implement such a scheme as this? Would each C::A have its own instance script?

    Update:

    fwi, I've post my attempt here

      You need to call $self->SUPER::setup() as the first line after my $self = shift;

      My criteria for good software:
      1. Does it work?
      2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?