Skip to content

Commit

Permalink
prize management admin interface
Browse files Browse the repository at this point in the history
  • Loading branch information
mjmusante committed Aug 17, 2023
1 parent b02bb10 commit e94c800
Show file tree
Hide file tree
Showing 9 changed files with 324 additions and 3 deletions.
2 changes: 1 addition & 1 deletion IFComp/lib/IFComp/Controller/Admin.pm
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ sub root : Chained('/') : PathPart( 'admin' ) : CaptureArgs(0) {
my ( $self, $c ) = @_;

unless ( $c->user
&& $c->check_any_user_role( 'votecounter', 'curator', 'cheez', ) )
&& $c->check_any_user_role( 'votecounter', 'curator', 'cheez', 'prizemanager', ) )
{
$c->detach('/error_403');
return;
Expand Down
125 changes: 125 additions & 0 deletions IFComp/lib/IFComp/Controller/Admin/Prizes.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package IFComp::Controller::Admin::Prizes;
use Moose;
use namespace::autoclean;

BEGIN { extends 'Catalyst::Controller'; }

use IFComp::Form::UpdatePrize;

has 'prize_form' => (
is => 'ro',
isa => 'IFComp::Form::UpdatePrize',
lazy_build => 1,
);

has 'prize' => (
is => 'rw',
isa => 'Maybe[IFComp::Schema::Result::Prize]',
);

sub root : Chained('/admin/root') : PathPart('prizes') : CaptureArgs(0) {
my ( $self, $c ) = @_;

unless ( $c->user && $c->check_any_user_role('prizemanager') ) {
$c->res->redirect('/');
return;
}

my $year = $c->req->param('year');
my $comp;
if ($year) {
$comp =
$c->model('IFCompDB::Comp')->search( { year => $year } )->single;
}
else {
$comp = $c->model('IFCompDB::Comp')->current_comp;
$year = $comp->year;
}

my $prize_list = $c->model('IFCompDB::Prize')->search(
{ comp => $comp->id, },
{ order_by => [ 'category' ] }
);

$c->stash(
prize_form => $self->prize_form,
prize_list => $prize_list,
current_comp => $comp,
template => 'admin/prizes/index.tt',
year => $year
);
}

sub index : Chained('root') : PathPart('list') : Args(0) {
}

sub create : Chained('root') : PathPart('create') : Args(0) {
my ( $self, $c ) = @_;

my %new_result_args = (
comp => $c->stash->{current_comp},
);

$c->stash( prize =>
$c->model('IFCompDB::Prize')->new_result( \%new_result_args ) );
if ( $self->_process_prize_form($c) ) {
# $c->res->redirect( $c->uri_for_action('/admin') );
}
}

sub _build_prize_form {
return IFComp::Form::UpdatePrize->new;
}

sub fetch_prize: Chained('root') : PathPart('') : CaptureArgs(1) {
my ( $self, $c, $id ) = @_;

my $prize = $c->model('IFCompDB::Prize')->find($id);
if ( $prize ) {
$c->stash->{prize} = $prize;
$self->prize($prize);
} else {
$c->res->redirect('/');
}
}

sub update : Chained('fetch_prize') : PathPart('update') : Args(0) {
my ( $self, $c ) = @_;

my $prize = $c->stash->{prize};
my $prize_id = $prize->id;

return $self->_process_prize_form($c);
}

sub _process_prize_form {
my ( $self, $c ) = @_;

$c->stash(
form => $self->prize_form,
template => 'admin/prizes/update.tt',
);

my $prize = $c->stash->{prize};

if ( $self->prize_form->process( item => $prize, params => $c->req->params, ) ) {
# prizedit.category | av
# prizedit.donor | Cindy Sinful
# prizedit.donor_email | cindy@example.com
# prizedit.location |
# prizedit.name | Pirated Copy of Infidel
# prizedit.notes |
# prizedit.ships_internationally | 1
# prizedit.submit | Update Prize
# prizedit.url |

$c->res->redirect( $c->uri_for_action('/admin/prizes/index') );
return 1;
}

$c->stash->{prize_form} = $self->prize_form;
}

__PACKAGE__->meta->make_immutable;

1;
104 changes: 104 additions & 0 deletions IFComp/lib/IFComp/Form/UpdatePrize.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package IFComp::Form::UpdatePrize;

use Regexp::Common qw( URI );
use Email::Valid;

use HTML::FormHandler::Moose;
extends 'HTML::FormHandler::Model::DBIC';

has '+name' => ( default => 'prizedit' );
has '+html_prefix' => ( default => 1 );

has '+widget_wrapper' => ( default => 'Bootstrap3', );

has_field 'donor' => (
required => 1,
type => 'Text',
maxlength => 64,
);

has_field 'donor_email' => (
required => 1,
type => 'Text',
maxlength => 64,
);

has_field 'name' => (
required => 1,
type => 'Text',
maxlength => 128,
);

has_field 'notes' => (
type => 'Text'
);

has_field 'url' => (
type => 'Text',
maxlength => 128,
);

has_field 'category' => (
type => 'Select',
id => 'category',
label => 'Prize Category',
options => [
{ value => 'money', label => "Money and gift certificates" },
{ value => 'expertise', label => "Expert services" },
{ value => 'food', label => "Food" },
{ value => 'apparel', label => "Apparel" },
{ value => 'games', label => "Games" },
{ value => 'hardware', label => "Computer hardware and other electronics" },
{ value => 'software', label => "Non-game software" },
{ value => 'books', label => "Books and magazines" },
{ value => 'av', label => "Music and movies" },
{ value => 'misc', label => "Other stuff" },
{ value => 'special', label => "Special prizes" },
],
);

has_field 'location' => (
type => 'Text',
maxlength => 64,
);

has_field 'ships_internationally' => (
default => 1,
label => "Will ship internationally",
type => 'Checkbox',
);

has_field 'submit' => (
type => 'Submit',
value => 'Submit',
element_attr => { class => 'btn btn-primary', },
);

sub validate_url {
my $self = shift;
my ($field) = @_;

if ( my $url = $field->value ) {
unless ( $url =~ /^$RE{URI}$/ ) {
$url = $field->value("http://$url");
}
unless ( $url =~ /^$RE{URI}$/ ) {
$field->add_error("This doesn't look like a valid URL.");
}
}

}

sub validate_donor_email {
my $self = shift;
my ($field) = @_;

if ( my $email = $field->value ) {
unless ( Email::Valid->address( $email ) ) {
$field->add_error("This doesn't look like a valid email address.");
}
}
}

__PACKAGE__->meta->make_immutable;
1;
5 changes: 4 additions & 1 deletion IFComp/root/src/admin/index.tt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<h1 style="text-align:center;">Administrative Functions</h1>
</div>

<p>The following functions are available for administrators</p>
<p>The following functions are available for administrators:</p>

<ul>
[% IF c.check_user_roles( 'votecounter' ) %]
Expand All @@ -17,6 +17,9 @@
[% IF c.check_user_roles( 'cheez' ) %]
<li><a href="[% c.uri_for('/admin/validation/') %]">User Validation</a></li>
[% END %]
[% IF c.check_user_roles( 'prizemanager' ) %]
<li><a href="[% c.uri_for('/admin/prizes/list') %]">Prize Management</a></li>
[% END %]
</ul>

</div>
40 changes: 40 additions & 0 deletions IFComp/root/src/admin/prizes/index.tt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@

<div class="container">

[% IF prize_list.count %]
<h1>Prizes for [% year %]</h1>
<a href="[% c.uri_for_action( '/admin/prizes/create' ) %]" class="btn btn-primary">Add New Prize</a>

<table class="table table-striped table-hover">
<thead>
<tr>
<th>Donor</th>
<th>Email</th>
<th>Name</th>
<th>URL</th>
<th>Location</th>
<th>Category</th>
<th>&nbsp;</th>
</tr>
</thead>
<tbody>

[% WHILE (prize = prize_list.next) %]
<tr>
<td>[% prize.donor %]</td>
<td>[% prize.donor_email %]</td>
<td>[% prize.name %]</td>
<td>[% prize.url %]</td>
<td>[% prize.location %]</td>
<td>[% prize.category %]</td>
<td><a href="[% c.uri_for_action( '/admin/prizes/update', [ prize.id ] ) %]"><span class="glyphicon glyphicon-pencil"></span></a></td>
</tr>
[% END %]
</tbody>
</table>
[% ELSE %]
<h1>No prizes have been entered for [% year %]</h1>
[% END %]


</div>
4 changes: 4 additions & 0 deletions IFComp/root/src/admin/prizes/update.tt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<div class="container">
<h1>[% IF prize.id %]Edit Prize[% ELSE %]Enter Prize[% END %]</h1>
[% prize_form.render %]
</div>
26 changes: 26 additions & 0 deletions IFComp/t/controller_Admin-Prizes.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use strict;
use warnings;
use Test::More;


unless ( eval q{use Test::WWW::Mechanize::Catalyst 0.55; 1} ) {
plan skip_all => 'Test::WWW::Mechanize::Catalyst >= 0.55 required';
exit 0;
}

use FindBin;
use lib ("$FindBin::Bin/lib");
use IFCompTest;
my $schema = IFCompTest->init_schema();

use Catalyst::Test 'IFComp';
use IFComp::Controller::Admin::Prizes;

ok( my $mech =
Test::WWW::Mechanize::Catalyst->new( catalyst_app => 'IFComp' ),
'Created mech object'
);

IFCompTest::log_in_as_prizemanager($mech);
ok( $mech->get_ok('/admin/prizes'), 'Request should succeed' );
done_testing();
5 changes: 5 additions & 0 deletions IFComp/t/lib/IFCompTest.pm
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ sub log_in_as_cheez {
_log_in_as( $mech, 'cheez@example.com', 'Cheddar Cheez' );
}

sub log_in_as_prizemanager {
my ($mech) = @_;
_log_in_as( $mech, 'prizes@example.com', 'Patricia Prizemanager' );
}

sub _log_in_as {
my ( $mech, $email, $name ) = @_;

Expand Down
16 changes: 15 additions & 1 deletion IFComp/t/lib/IFCompTestData.pm
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ sub add_test_data_to_schema {
'f4384fd7e541f4279d003cf89fc40c33',
$SALT, 'cheez@example.com', 1, undef, 1, undef,
],
[ 6,
'Patricia Prizemanager',
'f4384fd7e541f4279d003cf89fc40c33',
$SALT, 'prizes@example.com', 1, undef, 1, undef,
],
],
);

Expand All @@ -63,12 +68,13 @@ sub add_test_data_to_schema {
[ 1, 'votecounter' ],
[ 2, 'curator' ],
[ 3, 'cheez' ],
[ 4, 'prizemanager' ],
]
);

$schema->populate(
'UserRole',
[ [ 'id', 'user', 'role' ], [ 1, 3, 1 ], [ 2, 4, 2 ], [ 3, 5, 3 ], ],
[ [ 'id', 'user', 'role' ], [ 1, 3, 1 ], [ 2, 4, 2 ], [ 3, 5, 3 ], [ 4, 6, 4 ] ],
);

# There are two comps - last year and this year. The current comp is open
Expand Down Expand Up @@ -201,6 +207,14 @@ sub add_test_data_to_schema {
],
);

$schema->populate(
'Prize',
[ [ 'comp', 'donor', 'donor_email', 'name', 'category' ],
[ 2, 'Joe Donor', 'donor@example.com', 'Box of Fluff', 'apparel' ],
[ 2, 'Cindy Sinful', 'cindy@example.com', 'Pirated Copy of Infidel', 'games' ],
],
);

return;
}

Expand Down

0 comments on commit e94c800

Please sign in to comment.