diff --git a/lib/Pear/LocalLoop.pm b/lib/Pear/LocalLoop.pm index 966df36..8db6ac4 100644 --- a/lib/Pear/LocalLoop.pm +++ b/lib/Pear/LocalLoop.pm @@ -150,18 +150,6 @@ sub startup { $self->res->headers->header('Access-Control-Allow-Origin' => '*') if $self->app->mode eq 'development'; }); - #This assumes the user has no current session on that device. - $self->helper(generate_session => sub { - my ($self, $user) = @_; - - my $sessionToken = Data::UUID->new->create_str(); - - my $insertStatement = $self->db->prepare('INSERT INTO SessionTokens (SessionTokenName, UserIdAssignedTo_FK, ExpireDateTime) VALUES (?, ?, ?)'); - my $rowsAdded = $insertStatement->execute($sessionToken, $user, DateTime->now()->add( years => 1 )); - - return $sessionToken; - }); - $self->helper(get_age_foreign_key => sub { my ( $c, $age_string ) = @_; my $age_range = $c->schema->resultset('AgeRange')->find({ agerangestring => $age_string }); diff --git a/lib/Pear/LocalLoop/Controller/Api/Admin.pm b/lib/Pear/LocalLoop/Controller/Api/Admin.pm index 221f5a3..df1440e 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Admin.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Admin.pm @@ -105,15 +105,15 @@ sub post_admin_merge { sub copy_transactions_and_delete { my ( $c, $from_org, $to_org ) = @_; - my $from_org_transaction_rs = $from_org->pending_transactions; + my $from_org_transaction_rs = $from_org->transactions; while ( my $from_org_transaction = $from_org_transaction_rs->next ) { $to_org->create_related( 'transactions', { - buyeruserid_fk => $from_org_transaction->buyeruserid_fk, - valuemicrocurrency => $from_org_transaction->valuemicrocurrency, - proof_image => $from_org_transaction->proof_image, - timedatesubmitted => $from_org_transaction->timedatesubmitted, + buyer_id => $from_org_transaction->buyer_id, + value => $from_org_transaction->value, + proof_image => $from_org_transaction->proof_image, + submitted_at => $from_org_transaction->submitted_at, } ); } diff --git a/lib/Pear/LocalLoop/Controller/Api/Auth.pm b/lib/Pear/LocalLoop/Controller/Api/Auth.pm index f628087..4642bba 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Auth.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Auth.pm @@ -42,7 +42,7 @@ sub auth { my $session_key = $c->stash->{api_json}->{session_key}; if ( defined $session_key ) { - my $session_result = $c->schema->resultset('SessionToken')->find({ sessiontokenname => $session_key }); + my $session_result = $c->schema->resultset('SessionToken')->find({ token => $session_key }); if ( defined $session_result ) { $c->stash( api_user => $session_result->user ); @@ -78,7 +78,7 @@ sub post_login { if ( defined $user_result ) { if ( $user_result->check_password($password) ) { - my $session_key = $c->generate_session( $user_result->id ); + my $session_key = $user_result->generate_session; return $c->render( json => { success => Mojo::JSON->true, @@ -101,7 +101,7 @@ sub post_logout { my $session_key = $c->req->json( '/session_key' ); - my $session_result = $c->schema->resultset('SessionToken')->find({ sessiontokenname => $session_key }); + my $session_result = $c->schema->resultset('SessionToken')->find({ token => $session_key }); if ( defined $session_result ) { $session_result->delete; diff --git a/lib/Pear/LocalLoop/Controller/Api/Register.pm b/lib/Pear/LocalLoop/Controller/Api/Register.pm index 2fb4aad..ae8a129 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Register.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Register.pm @@ -30,6 +30,7 @@ has error_messages => sub { }, age => { required => { message => 'No age sent.', status => 400 }, + number => { message => 'Age range is invalid', status => 400 }, in_resultset => { message => 'Age range is invalid.', status => 400 }, }, street_name => { @@ -79,7 +80,7 @@ sub post_register{ if ( $usertype eq 'customer' ) { my $age_rs = $c->schema->resultset('AgeRange'); - $validation->required('age')->in_resultset('id', $age_rs); + $validation->required('age')->number->in_resultset('id', $age_rs); } elsif ( $usertype eq 'organisation' ) { diff --git a/lib/Pear/LocalLoop/Controller/Api/Upload.pm b/lib/Pear/LocalLoop/Controller/Api/Upload.pm index ecc4674..c376129 100644 --- a/lib/Pear/LocalLoop/Controller/Api/Upload.pm +++ b/lib/Pear/LocalLoop/Controller/Api/Upload.pm @@ -75,7 +75,6 @@ has error_messages => sub { sub post_upload { my $c = shift; - my $self = $c; my $user = $c->stash->{api_user}; @@ -94,75 +93,62 @@ sub post_upload { my $type = $validation->param('transaction_type'); + my $organisation; + if ( $type == 1 ) { # Validated Organisation my $valid_org_rs = $c->schema->resultset('Organisation'); $validation->required('organisation_id')->number->in_resultset( 'id', $valid_org_rs ); + + return $c->api_validation_error if $validation->has_error; + + $organisation = $valid_org_rs->find( $validation->param('organisation_id') ); + } elsif ( $type == 2 ) { # Unvalidated Organisation my $valid_org_rs = $c->schema->resultset('PendingOrganisation')->search({ submitted_by_id => $user->id }); $validation->required('organisation_id')->number->in_resultset( 'id', $valid_org_rs ); + + return $c->api_validation_error if $validation->has_error; + + $organisation = $valid_org_rs->find( $validation->param('organisation_id') ); + } elsif ( $type == 3 ) { # Unknown Organisation $validation->required('organisation_name'); $validation->optional('street_name'); $validation->optional('town'); $validation->optional('postcode')->postcode; - } + + return $c->api_validation_error if $validation->has_error; - return $c->api_validation_error if $validation->has_error; + $organisation = $c->schema->resultset('PendingOrganisation')->create({ + submitted_by => $user, + submitted_at => DateTime->now, + name => $validation->param('organisation_name'), + street_name => $validation->param('street_name'), + town => $validation->param('town'), + postcode => $validation->param('postcode'), + }); + } my $transaction_value = $validation->param('transaction_value'); my $upload = $validation->param('file'); - my $file = $c->store_file_from_upload( $upload ); - if ( $type == 1 ) { - # Validated organisation - $c->schema->resultset('Transaction')->create({ - buyeruserid_fk => $user->id, - sellerorganisationid_fk => $validation->param('organisation_id'), - valuemicrocurrency => $transaction_value, + $organisation->create_related( + 'transactions', + { + buyer => $user, + value => $transaction_value, proof_image => $file, - timedatesubmitted => DateTime->now, - }); - } elsif ( $type == 2 ) { - # Unvalidated Organisation - $c->schema->resultset('PendingTransaction')->create({ - buyeruserid_fk => $user->id, - pendingsellerorganisationid_fk => $validation->param('organisation_id'), - valuemicrocurrency => $transaction_value, - proof_image => $file, - timedatesubmitted => DateTime->now, - }); - } elsif ( $type == 3 ) { - my $organisation_name = $validation->param('organisation_name'); - my $street_name = $validation->param('street_name'); - my $town = $validation->param('town'); - my $postcode = $validation->param('postcode'); + } + ); - my $pending_org = $c->schema->resultset('PendingOrganisation')->create({ - submitted_by => $user, - submitted_at => DateTime->now, - name => $organisation_name, - street_name => $street_name, - town => $town, - postcode => $postcode, - }); - - $c->schema->resultset('PendingTransaction')->create({ - buyeruserid_fk => $user->id, - pendingsellerorganisationid_fk => $pending_org->id, - valuemicrocurrency => $transaction_value, - proof_image => $file, - timedatesubmitted => DateTime->now, - }); - } - return $self->render( json => { + return $c->render( json => { success => Mojo::JSON->true, message => 'Upload Successful', }); - } diff --git a/lib/Pear/LocalLoop/Schema/Result/AccountToken.pm b/lib/Pear/LocalLoop/Schema/Result/AccountToken.pm index fcd6a93..51e2f1f 100644 --- a/lib/Pear/LocalLoop/Schema/Result/AccountToken.pm +++ b/lib/Pear/LocalLoop/Schema/Result/AccountToken.pm @@ -1,4 +1,3 @@ -use utf8; package Pear::LocalLoop::Schema::Result::AccountToken; use strict; diff --git a/lib/Pear/LocalLoop/Schema/Result/AgeRange.pm b/lib/Pear/LocalLoop/Schema/Result/AgeRange.pm index 3120873..b963f5c 100644 --- a/lib/Pear/LocalLoop/Schema/Result/AgeRange.pm +++ b/lib/Pear/LocalLoop/Schema/Result/AgeRange.pm @@ -1,4 +1,3 @@ -use utf8; package Pear::LocalLoop::Schema::Result::AgeRange; use strict; diff --git a/lib/Pear/LocalLoop/Schema/Result/Customer.pm b/lib/Pear/LocalLoop/Schema/Result/Customer.pm index 04c4c14..a1deee4 100644 --- a/lib/Pear/LocalLoop/Schema/Result/Customer.pm +++ b/lib/Pear/LocalLoop/Schema/Result/Customer.pm @@ -1,4 +1,3 @@ -use utf8; package Pear::LocalLoop::Schema::Result::Customer; use strict; diff --git a/lib/Pear/LocalLoop/Schema/Result/Organisation.pm b/lib/Pear/LocalLoop/Schema/Result/Organisation.pm index d4a1b2d..e5a30a3 100644 --- a/lib/Pear/LocalLoop/Schema/Result/Organisation.pm +++ b/lib/Pear/LocalLoop/Schema/Result/Organisation.pm @@ -41,7 +41,7 @@ __PACKAGE__->set_primary_key('id'); __PACKAGE__->has_many( "transactions", "Pear::LocalLoop::Schema::Result::Transaction", - { "foreign.sellerorganisationid_fk" => 'self.id' }, + { "foreign.seller_id" => 'self.id' }, { cascade_copy => 0, cascade_delete => 0 }, ); diff --git a/lib/Pear/LocalLoop/Schema/Result/PendingOrganisation.pm b/lib/Pear/LocalLoop/Schema/Result/PendingOrganisation.pm index fd6ca5b..5cf1f51 100644 --- a/lib/Pear/LocalLoop/Schema/Result/PendingOrganisation.pm +++ b/lib/Pear/LocalLoop/Schema/Result/PendingOrganisation.pm @@ -5,7 +5,10 @@ use warnings; use base 'DBIx::Class::Core'; -__PACKAGE__->load_components("InflateColumn::DateTime"); +__PACKAGE__->load_components( qw/ + InflateColumn::DateTime + TimeStamp +/); __PACKAGE__->table("pending_organisations"); @@ -42,16 +45,17 @@ __PACKAGE__->add_columns( submitted_at => { data_type => "datetime", is_nullable => 0, + set_on_create => 1, }, ); __PACKAGE__->set_primary_key('id'); __PACKAGE__->has_many( - "pending_transactions", + "transactions", "Pear::LocalLoop::Schema::Result::PendingTransaction", { - "foreign.pendingsellerorganisationid_fk" => "self.id", + "foreign.seller_id" => "self.id", }, { cascade_copy => 0, cascade_delete => 1 }, ); diff --git a/lib/Pear/LocalLoop/Schema/Result/PendingTransaction.pm b/lib/Pear/LocalLoop/Schema/Result/PendingTransaction.pm index 9854929..f737725 100644 --- a/lib/Pear/LocalLoop/Schema/Result/PendingTransaction.pm +++ b/lib/Pear/LocalLoop/Schema/Result/PendingTransaction.pm @@ -1,4 +1,3 @@ -use utf8; package Pear::LocalLoop::Schema::Result::PendingTransaction; use strict; @@ -8,43 +7,56 @@ use base 'DBIx::Class::Core'; __PACKAGE__->load_components( qw/ InflateColumn::DateTime - InflateColumn::FS + TimeStamp /); -__PACKAGE__->table("PendingTransactions"); +__PACKAGE__->table("pending_transactions"); __PACKAGE__->add_columns( - "pendingtransactionid", - { data_type => "integer", is_auto_increment => 1, is_nullable => 0 }, - "buyeruserid_fk", - { data_type => "integer", is_foreign_key => 1, is_nullable => 0 }, - "pendingsellerorganisationid_fk", - { data_type => "integer", is_foreign_key => 1, is_nullable => 0 }, - "valuemicrocurrency", - { data_type => "integer", is_nullable => 0 }, - "proof_image", - { + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "buyer_id" => { + data_type => "integer", + is_foreign_key => 1, + is_nullable => 0, + }, + "seller_id" => { + data_type => "integer", + is_foreign_key => 1, + is_nullable => 0, + }, + "value" => { + data_type => "decimal", + size => [ 16, 2 ], + is_nullable => 0, + }, + "proof_image" => { data_type => "text", is_nullable => 0, }, - "timedatesubmitted", - { data_type => "datetime", is_nullable => 0 }, + "submitted_at" => { + data_type => "datetime", + is_nullable => 0, + set_on_create => 1, + }, ); - -__PACKAGE__->set_primary_key("pendingtransactionid"); +__PACKAGE__->set_primary_key("id"); __PACKAGE__->belongs_to( - "buyeruserid_fk", + "buyer", "Pear::LocalLoop::Schema::Result::User", - { id => "buyeruserid_fk" }, + { id => "buyer_id" }, { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, ); __PACKAGE__->belongs_to( - "pendingsellerorganisationid_fk", + "seller", "Pear::LocalLoop::Schema::Result::PendingOrganisation", - { id => "pendingsellerorganisationid_fk" }, + { id => "seller_id" }, { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, ); diff --git a/lib/Pear/LocalLoop/Schema/Result/SessionToken.pm b/lib/Pear/LocalLoop/Schema/Result/SessionToken.pm index d30aca5..17eb162 100644 --- a/lib/Pear/LocalLoop/Schema/Result/SessionToken.pm +++ b/lib/Pear/LocalLoop/Schema/Result/SessionToken.pm @@ -1,122 +1,39 @@ -use utf8; package Pear::LocalLoop::Schema::Result::SessionToken; -# Created by DBIx::Class::Schema::Loader -# DO NOT MODIFY THE FIRST PART OF THIS FILE - -=head1 NAME - -Pear::LocalLoop::Schema::Result::SessionToken - -=cut - use strict; use warnings; use base 'DBIx::Class::Core'; -=head1 COMPONENTS LOADED - -=over 4 - -=item * L - -=back - -=cut - -__PACKAGE__->load_components("InflateColumn::DateTime"); - -=head1 TABLE: C - -=cut - -__PACKAGE__->table("SessionTokens"); - -=head1 ACCESSORS - -=head2 sessiontokenid - - data_type: 'integer' - is_auto_increment: 1 - is_nullable: 0 - -=head2 sessiontokenname - - data_type: 'text' - is_nullable: 0 - -=head2 useridassignedto_fk - - data_type: 'integer' - is_foreign_key: 1 - is_nullable: 0 - -=head2 expiredatetime - - data_type: 'integer' - is_nullable: 0 - -=cut +__PACKAGE__->table("session_tokens"); __PACKAGE__->add_columns( - "sessiontokenid", - { data_type => "integer", is_auto_increment => 1, is_nullable => 0 }, - "sessiontokenname", - { data_type => "text", is_nullable => 0 }, - "useridassignedto_fk", - { data_type => "integer", is_foreign_key => 1, is_nullable => 0 }, - "expiredatetime", - { data_type => "datetime", is_nullable => 0 }, + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "token" => { + data_type => "varchar", + size => 255, + is_nullable => 0, + }, + "user_id" => { + data_type => "integer", + is_foreign_key => 1, + is_nullable => 0, + }, ); -=head1 PRIMARY KEY +__PACKAGE__->set_primary_key("id"); -=over 4 - -=item * L - -=back - -=cut - -__PACKAGE__->set_primary_key("sessiontokenid"); - -=head1 UNIQUE CONSTRAINTS - -=head2 C - -=over 4 - -=item * L - -=back - -=cut - -__PACKAGE__->add_unique_constraint("sessiontokenname_unique", ["sessiontokenname"]); - -=head1 RELATIONS - -=head2 useridassignedto_fk - -Type: belongs_to - -Related object: L - -=cut +__PACKAGE__->add_unique_constraint(["token"]); __PACKAGE__->belongs_to( "user", "Pear::LocalLoop::Schema::Result::User", - { id => "useridassignedto_fk" }, + { id => "user_id" }, { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, ); - -# Created by DBIx::Class::Schema::Loader v0.07046 @ 2017-02-24 17:32:21 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:/mNAPeSmfsDSIpey+eUucg - - -# You can replace this text with custom code or comments, and it will be preserved on regeneration 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/Transaction.pm b/lib/Pear/LocalLoop/Schema/Result/Transaction.pm index 7381bef..198c9ee 100644 --- a/lib/Pear/LocalLoop/Schema/Result/Transaction.pm +++ b/lib/Pear/LocalLoop/Schema/Result/Transaction.pm @@ -1,144 +1,63 @@ -use utf8; package Pear::LocalLoop::Schema::Result::Transaction; -# Created by DBIx::Class::Schema::Loader -# DO NOT MODIFY THE FIRST PART OF THIS FILE - -=head1 NAME - -Pear::LocalLoop::Schema::Result::Transaction - -=cut - use strict; use warnings; use base 'DBIx::Class::Core'; -=head1 COMPONENTS LOADED - -=over 4 - -=item * L - -=back - -=cut - __PACKAGE__->load_components(qw/ InflateColumn::DateTime - InflateColumn::FS + TimeStamp /); -=head1 TABLE: C - -=cut - -__PACKAGE__->table("Transactions"); - -=head1 ACCESSORS - -=head2 transactionid - - data_type: 'integer' - is_auto_increment: 1 - is_nullable: 0 - -=head2 buyeruserid_fk - - data_type: 'integer' - is_foreign_key: 1 - is_nullable: 0 - -=head2 sellerorganisationid_fk - - data_type: 'integer' - is_foreign_key: 1 - is_nullable: 0 - -=head2 valuemicrocurrency - - data_type: 'integer' - is_nullable: 0 - -=head2 proofimage - - data_type: 'text' - is_nullable: 0 - -=head2 timedatesubmitted - - data_type: 'integer' - is_nullable: 0 - -=cut +__PACKAGE__->table("transactions"); __PACKAGE__->add_columns( - "transactionid", - { data_type => "integer", is_auto_increment => 1, is_nullable => 0 }, - "buyeruserid_fk", - { data_type => "integer", is_foreign_key => 1, is_nullable => 0 }, - "sellerorganisationid_fk", - { data_type => "integer", is_foreign_key => 1, is_nullable => 0 }, - "valuemicrocurrency", - { data_type => "integer", is_nullable => 0 }, - "proof_image", - { + "id" => { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + }, + "buyer_id" => { + data_type => "integer", + is_foreign_key => 1, + is_nullable => 0, + }, + "seller_id" => { + data_type => "integer", + is_foreign_key => 1, + is_nullable => 0, + }, + "value" => { + data_type => "decimal", + size => [ 16, 2 ], + is_nullable => 0, + }, + "proof_image" => { data_type => "text", is_nullable => 0, }, - "timedatesubmitted", - { data_type => "datetime", is_nullable => 0 }, + "submitted_at" => { + data_type => "datetime", + is_nullable => 0, + set_on_create => 1, + }, ); -=head1 PRIMARY KEY - -=over 4 - -=item * L - -=back - -=cut - -__PACKAGE__->set_primary_key("transactionid"); - -=head1 RELATIONS - -=head2 buyeruserid_fk - -Type: belongs_to - -Related object: L - -=cut +__PACKAGE__->set_primary_key("id"); __PACKAGE__->belongs_to( - "buyeruserid_fk", + "buyer", "Pear::LocalLoop::Schema::Result::User", - { id => "buyeruserid_fk" }, + { id => "buyer_id" }, { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, ); -=head2 sellerorganisationid_fk - -Type: belongs_to - -Related object: L - -=cut - __PACKAGE__->belongs_to( - "sellerorganisationid_fk", + "seller", "Pear::LocalLoop::Schema::Result::Organisation", - { id => "sellerorganisationid_fk" }, + { id => "seller_id" }, { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" }, ); - -# Created by DBIx::Class::Schema::Loader v0.07046 @ 2017-02-24 17:32:21 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:CfPoE2egoSD1tKo7fYjZdg - - -# You can replace this text with custom code or comments, and it will be preserved on regeneration 1; diff --git a/lib/Pear/LocalLoop/Schema/Result/User.pm b/lib/Pear/LocalLoop/Schema/Result/User.pm index 4294d9b..cf82e40 100644 --- a/lib/Pear/LocalLoop/Schema/Result/User.pm +++ b/lib/Pear/LocalLoop/Schema/Result/User.pm @@ -1,4 +1,3 @@ -use utf8; package Pear::LocalLoop::Schema::Result::User; use strict; @@ -6,6 +5,8 @@ use warnings; use base 'DBIx::Class::Core'; +use Data::UUID; + __PACKAGE__->load_components( qw/ InflateColumn::DateTime PassphraseColumn @@ -70,7 +71,7 @@ __PACKAGE__->might_have( __PACKAGE__->belongs_to( "customer", "Pear::LocalLoop::Schema::Result::Customer", - { id => "customer_id" }, + { "foreign.id" => "self.customer_id" }, { is_deferrable => 0, join_type => "LEFT", @@ -82,7 +83,7 @@ __PACKAGE__->belongs_to( __PACKAGE__->belongs_to( "organisation", "Pear::LocalLoop::Schema::Result::Organisation", - { id => "organisation_id" }, + { "foreign.id" => "self.organisation_id" }, { is_deferrable => 0, join_type => "LEFT", @@ -101,22 +102,36 @@ __PACKAGE__->has_many( __PACKAGE__->has_many( "pending_transactions", "Pear::LocalLoop::Schema::Result::PendingTransaction", - { "foreign.buyeruserid_fk" => "self.id" }, + { "foreign.buyer_id" => "self.id" }, { cascade_copy => 0, cascade_delete => 0 }, ); __PACKAGE__->has_many( "session_tokens", "Pear::LocalLoop::Schema::Result::SessionToken", - { "foreign.useridassignedto_fk" => "self.id" }, + { "foreign.user_id" => "self.id" }, { cascade_copy => 0, cascade_delete => 0 }, ); __PACKAGE__->has_many( "transactions", "Pear::LocalLoop::Schema::Result::Transaction", - { "foreign.buyeruserid_fk" => "self.id" }, + { "foreign.buyer_id" => "self.id" }, { cascade_copy => 0, cascade_delete => 0 }, ); +sub generate_session { + my $self = shift; + + my $token = Data::UUID->new->create_str(); + $self->create_related( + 'session_tokens', + { + token => $token, + }, + ); + + return $token; +} + 1; diff --git a/t/admin-approve.t b/t/admin-approve.t index d6fc09b..3bac901 100644 --- a/t/admin-approve.t +++ b/t/admin-approve.t @@ -84,7 +84,7 @@ $testJson = { 'password' => $passwordReno, }; $t->post_ok('/api/login' => json => $testJson) - ->status_is(200) + ->status_is(200)->or($dump_error) ->json_is('/success', Mojo::JSON->true); my $session_key = $t->tx->res->json('/session_key'); @@ -129,7 +129,7 @@ $t->post_ok('/api/admin-approve' => json => $json) print "test 8 - Logout Reno\n"; $t->post_ok('/api/logout', json => { session_key => $session_key } ) - ->status_is(200) + ->status_is(200)->or($dump_error) ->json_is('/success', Mojo::JSON->true); #End of non-admin Reno