1package App::Web;
2
3use strict;
4use vars qw($VERSION);
5use Log::Log4perl     qw( get_logger );
6use Workflow::Factory qw( FACTORY );
7use XML::Simple       qw( :strict );
8
9$VERSION = '0.01';
10
11my ( $log );
12
13my %ACTION_DATA = ();
14my %DISPATCH    = ();
15
16sub initialize_mappings {
17    my ( $class, $mapping_file ) = @_;
18    $log ||= get_logger();
19    my %options = (
20        ForceArray => [ 'url-mapping', 'action-display' ],
21        KeyAttr    => [],
22    );
23    my $config = XMLin( $mapping_file, %options );
24    no strict 'refs';
25    foreach my $url_map ( @{ $config->{'url-mapping'} } ) {
26        my $map_class  = $url_map->{class};
27        my $map_method = $url_map->{method};
28        eval "require $map_class";
29        if ( $@ ) {
30            die "Cannot include class '$map_class': $@\n";
31        }
32        my $method = \&{ $map_class . '::' . $map_method };
33        unless ( $method ) {
34            die "No method '$map_class->$map_method'\n";
35        }
36        $DISPATCH{ $url_map->{url} } = $method;
37    }
38
39    foreach my $action_template ( @{ $config->{'action-display'} } ) {
40        $ACTION_DATA{ $action_template->{name} } = $action_template->{template};
41    }
42
43    return $config;
44}
45
46
47########################################
48# DISPATCH MAPPINGS
49#
50# Each of these routines returns a template name, stuffing data used
51# by the template into \%params and any outbound cookies into
52# \%cookies_out.
53
54sub lookup_dispatch {
55    my ( $class, $action_name ) = @_;
56    return $DISPATCH{ $action_name };
57}
58
59sub create_workflow {
60    my ( $client, $request, $cookies_in, $cookies_out, $params ) = @_;
61    my $wf = FACTORY->create_workflow( 'Ticket' );
62    $params->{workflow} = $wf;
63    $cookies_out->{workflow_id} = $wf->id;
64    return 'workflow_created.tmpl';
65}
66
67sub fetch_workflow {
68    my ( $client, $request, $cookies_in, $cookies_out, $params ) = @_;
69    my $wf = _get_workflow( $params, $cookies_in );
70    $cookies_out->{workflow_id} = $wf->id;
71    return 'workflow_fetched.tmpl';
72}
73
74sub list_history {
75    my ( $client, $request, $cookies_in, $cookies_out, $params ) = @_;
76    my $wf = _get_workflow( $params, $cookies_in );
77    my @history = $wf->get_history();
78    $params->{history_list} = \@history;
79    return 'workflow_history.tmpl';
80}
81
82sub execute_action {
83    my ( $client, $request, $cookies_in, $cookies_out, $params ) = @_;
84    my $wf = _get_workflow( $params, $cookies_in );
85
86    my $action = $params->{action};
87    unless ( $action ) {
88        die "To execute an action you must specify an action name!\n";
89    }
90
91    # If they haven't entered data yet, add the fields (as a map) to
92    # the parameters and redirect to the form for entering it
93
94    unless ( $params->{_action_data_entered} || ! $ACTION_DATA{ $action } ) {
95        $params->{status_msg} =
96            "Action cannot be executed until you enter its data";
97        my @fields = $wf->get_action_fields( $action );
98        my %by_name = map { $_->name => $_ } @fields;
99        $params->{ACTION_FIELDS} = \%by_name;
100        return $ACTION_DATA{ $action };
101    }
102
103    # Otherwise, set the user data directly into the workflow context...
104    $wf->context->param( $params );
105
106    # ...and execute the action
107    eval { $wf->execute_action( $params->{action} ) };
108
109    # ...if we catch a condition/validation exception, display the
110    # error and go back to the data entry form
111
112    if ( $@ && ( $@->isa( 'Workflow::Exception::Condition' ) ||
113                 $@->isa( 'Workflow::Exception::Validation' ) ) ) {
114        $log->error( "One or more conditions not met to execute action: $@; ",
115                     "redirecting to form" );
116        $params->{error_msg} = "Failed to execute action: $@";
117        return $ACTION_DATA{ $action };
118    }
119    $params->{status_msg} = "Action '$action' executed ok";
120    return list_history( $client, $request, $cookies_in, $cookies_out, $params );
121}
122
123sub login {
124    my ( $client, $request, $cookies_in, $cookies_out, $params ) = @_;
125    if ( $params->{current_user} ) {
126        $cookies_out->{current_user} = $params->{current_user};
127    }
128    else {
129        $params->{error_msg} = "Please specify a login name I can use!";
130    }
131    return 'index.tmpl';
132}
133
134sub _get_workflow {
135    my ( $params, $cookies_in ) = @_;
136    return $params->{workflow} if ( $params->{workflow} );
137    my $log = get_logger();
138    my $wf_id = $params->{workflow_id} || $cookies_in->{workflow_id};
139    unless ( $wf_id ) {
140        die "No workflow ID given! Please fetch a workflow or create ",
141            "a new one.\n";
142    }
143    $log->debug( "Fetching workflow with ID '$wf_id'" );
144    my $wf = FACTORY->fetch_workflow( 'Ticket', $wf_id );
145    if ( $wf ) {
146        $log->debug( "Workflow found, current state is '", $wf->state, "'" );
147        $params->{workflow} = $wf;
148    }
149    else {
150        $log->warn( "No workflow found with ID '$wf_id'" );
151        die "No workflow found with ID '$wf_id'\n";
152    }
153    return $wf;
154}
155
1561;
157