Tomas Cohen Arazi
7a4cf3569d
The original development started before the changes we introduced in the guidelines in late 2019, and the major code changes that took place in January 2020. - Attribute mapping logic is now on the Koha::Object-level (the patches implement that, but are not using it) - Related to the above, some helper methods like to_api and to_model are kept, the same for the mappings in the controller, they should all go away - Related to the above, set_from_api and new_from_api should be used instead of using helper to_api and to_model methods in the controller - $c->objects->search doesn't use the to_model and to_api params - Response status codes need to be changed, at least for DELETE operations Those are fixed by this patch. To test: 1. Apply this patch 2. Run: $ kshell k$ prove t/db_dependent/api/v1/advanced_editor_macros.t => SUCCESS: Tests pass! 3. Sign off :-D Signed-off-by: Victor Grousset/tuxayo <victor@tuxayo.net> Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
476 lines
18 KiB
Perl
476 lines
18 KiB
Perl
#!/usr/bin/env perl
|
|
|
|
# This file is part of Koha.
|
|
#
|
|
# Koha is free software; you can redistribute it and/or modify it under the
|
|
# terms of the GNU General Public License as published by the Free Software
|
|
# Foundation; either version 3 of the License, or (at your option) any later
|
|
# version.
|
|
#
|
|
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with Koha; if not, see <http://www.gnu.org/licenses>.
|
|
|
|
use Modern::Perl;
|
|
|
|
use Test::More tests => 5;
|
|
use Test::Mojo;
|
|
use Test::Warn;
|
|
|
|
use t::lib::TestBuilder;
|
|
use t::lib::Mocks;
|
|
|
|
use Koha::AdvancedEditorMacros;
|
|
use Koha::Database;
|
|
|
|
my $schema = Koha::Database->new->schema;
|
|
my $builder = t::lib::TestBuilder->new;
|
|
|
|
t::lib::Mocks::mock_preference( 'RESTBasicAuth', 1 );
|
|
|
|
my $t = Test::Mojo->new('Koha::REST::V1');
|
|
|
|
$schema->storage->txn_begin;
|
|
|
|
subtest 'list() tests' => sub {
|
|
plan tests => 8;
|
|
|
|
|
|
my $patron_1 = $builder->build_object({
|
|
class => 'Koha::Patrons',
|
|
value => { flags => 9 }
|
|
});
|
|
my $patron_2 = $builder->build_object({
|
|
class => 'Koha::Patrons',
|
|
});
|
|
my $password = 'thePassword123';
|
|
$patron_1->set_password({ password => $password, skip_validation => 1 });
|
|
my $userid = $patron_1->userid;
|
|
|
|
# Create test context
|
|
my $macro_1 = $builder->build_object({ class => 'Koha::AdvancedEditorMacros', value =>
|
|
{
|
|
name => 'Test1',
|
|
macro => 'delete 100',
|
|
borrowernumber => $patron_1->borrowernumber,
|
|
shared => 0,
|
|
}
|
|
});
|
|
my $macro_2 = $builder->build_object({ class => 'Koha::AdvancedEditorMacros', value =>
|
|
{
|
|
name => 'Test2',
|
|
macro => 'delete 100',
|
|
borrowernumber => $patron_1->borrowernumber,
|
|
shared => 1,
|
|
}
|
|
});
|
|
my $macro_3 = $builder->build_object({ class => 'Koha::AdvancedEditorMacros', value =>
|
|
{
|
|
name => 'Test3',
|
|
macro => 'delete 100',
|
|
borrowernumber => $patron_2->borrowernumber,
|
|
shared => 0,
|
|
}
|
|
});
|
|
my $macro_4 = $builder->build_object({ class => 'Koha::AdvancedEditorMacros', value =>
|
|
{
|
|
name => 'Test4',
|
|
macro => 'delete 100',
|
|
borrowernumber => $patron_2->borrowernumber,
|
|
shared => 1,
|
|
}
|
|
});
|
|
|
|
my $macros_index = Koha::AdvancedEditorMacros->search({ -or => { shared => 1, borrowernumber => $patron_1->borrowernumber } })->count-1;
|
|
## Authorized user tests
|
|
# Make sure we are returned with the correct amount of macros
|
|
$t->get_ok( "//$userid:$password@/api/v1/advanced_editor/macros" )
|
|
->status_is( 200, 'SWAGGER3.2.2' )
|
|
->json_has('/' . $macros_index . '/macro_id')
|
|
->json_hasnt('/' . ($macros_index + 1) . '/macro_id');
|
|
|
|
subtest 'query parameters' => sub {
|
|
|
|
plan tests => 15;
|
|
$t->get_ok("//$userid:$password@/api/v1/advanced_editor/macros?name=" . $macro_2->name)
|
|
->status_is(200)
|
|
->json_is( [ $macro_2->to_api ] );
|
|
$t->get_ok("//$userid:$password@/api/v1/advanced_editor/macros?name=" . $macro_3->name)
|
|
->status_is(200)
|
|
->json_is( [ ] );
|
|
$t->get_ok("//$userid:$password@/api/v1/advanced_editor/macros?macro_text=delete%20100")
|
|
->status_is(200)
|
|
->json_is( [ $macro_1->to_api, $macro_2->to_api, $macro_4->to_api ] );
|
|
$t->get_ok("//$userid:$password@/api/v1/advanced_editor/macros?patron_id=" . $patron_1->borrowernumber)
|
|
->status_is(200)
|
|
->json_is( [ $macro_1->to_api, $macro_2->to_api ] );
|
|
$t->get_ok("//$userid:$password@/api/v1/advanced_editor/macros?shared=1")
|
|
->status_is(200)
|
|
->json_is( [ $macro_2->to_api, $macro_4->to_api ] );
|
|
};
|
|
|
|
# Warn on unsupported query parameter
|
|
$t->get_ok( "//$userid:$password@/api/v1/advanced_editor/macros?macro_blah=blah" )
|
|
->status_is(400)
|
|
->json_is( [{ path => '/query/macro_blah', message => 'Malformed query string'}] );
|
|
|
|
};
|
|
|
|
subtest 'get() tests' => sub {
|
|
|
|
plan tests => 15;
|
|
|
|
my $patron = $builder->build_object({
|
|
class => 'Koha::Patrons',
|
|
value => { flags => 1 }
|
|
});
|
|
my $password = 'thePassword123';
|
|
$patron->set_password({ password => $password, skip_validation => 1 });
|
|
my $userid = $patron->userid;
|
|
|
|
my $macro_1 = $builder->build_object( { class => 'Koha::AdvancedEditorMacros', value => {
|
|
shared => 1,
|
|
}
|
|
});
|
|
my $macro_2 = $builder->build_object( { class => 'Koha::AdvancedEditorMacros', value => {
|
|
shared => 0,
|
|
}
|
|
});
|
|
my $macro_3 = $builder->build_object( { class => 'Koha::AdvancedEditorMacros', value => {
|
|
borrowernumber => $patron->borrowernumber,
|
|
shared => 0,
|
|
}
|
|
});
|
|
|
|
$t->get_ok( "//$userid:$password@/api/v1/advanced_editor/macros/" . $macro_1->id )
|
|
->status_is( 403, 'Cannot get a shared macro via regular endpoint' )
|
|
->json_is( '/error' => 'This macro is shared, you must access it via advanced_editor/macros/shared' );
|
|
|
|
$t->get_ok( "//$userid:$password@/api/v1/advanced_editor/macros/shared/" . $macro_1->id )
|
|
->status_is( 200, 'Can get a shared macro via shared endpoint' )
|
|
->json_is( $macro_1->to_api );
|
|
|
|
$t->get_ok( "//$userid:$password@/api/v1/advanced_editor/macros/" . $macro_2->id )
|
|
->status_is( 403, 'Cannot access another users macro' )
|
|
->json_is( '/error' => 'You do not have permission to access this macro' );
|
|
|
|
$t->get_ok( "//$userid:$password@/api/v1/advanced_editor/macros/" . $macro_3->id )
|
|
->status_is( 200, 'Can get your own private macro' )
|
|
->json_is( $macro_3->to_api );
|
|
|
|
my $non_existent_code = $macro_1->id;
|
|
$macro_1->delete;
|
|
|
|
$t->get_ok( "//$userid:$password@/api/v1/advanced_editor/macros/" . $non_existent_code )
|
|
->status_is(404)
|
|
->json_is( '/error' => 'Macro not found' );
|
|
|
|
};
|
|
|
|
subtest 'add() tests' => sub {
|
|
|
|
plan tests => 24;
|
|
|
|
my $authorized_patron = $builder->build_object({
|
|
class => 'Koha::Patrons',
|
|
value => { flags => 0 }
|
|
});
|
|
$builder->build({
|
|
source => 'UserPermission',
|
|
value => {
|
|
borrowernumber => $authorized_patron->borrowernumber,
|
|
module_bit => 9,
|
|
code => 'advanced_editor',
|
|
},
|
|
});
|
|
|
|
my $password = 'thePassword123';
|
|
$authorized_patron->set_password({ password => $password, skip_validation => 1 });
|
|
my $auth_userid = $authorized_patron->userid;
|
|
|
|
my $unauthorized_patron = $builder->build_object({
|
|
class => 'Koha::Patrons',
|
|
value => { flags => 0 }
|
|
});
|
|
$unauthorized_patron->set_password({ password => $password, skip_validation => 1 });
|
|
my $unauth_userid = $unauthorized_patron->userid;
|
|
|
|
my $macro = $builder->build_object({
|
|
class => 'Koha::AdvancedEditorMacros',
|
|
value => { shared => 0 }
|
|
});
|
|
my $macro_values = $macro->to_api;
|
|
delete $macro_values->{macro_id};
|
|
$macro->delete;
|
|
|
|
# Unauthorized attempt to write
|
|
$t->post_ok( "//$unauth_userid:$password@/api/v1/advanced_editor/macros" => json => $macro_values )
|
|
->status_is(403);
|
|
|
|
# Authorized attempt to write invalid data
|
|
my $macro_with_invalid_field = { %$macro_values };
|
|
$macro_with_invalid_field->{'big_mac_ro'} = 'Mac attack';
|
|
|
|
$t->post_ok( "//$auth_userid:$password@/api/v1/advanced_editor/macros" => json => $macro_with_invalid_field )
|
|
->status_is(400)
|
|
->json_is(
|
|
"/errors" => [
|
|
{
|
|
message => "Properties not allowed: big_mac_ro.",
|
|
path => "/body"
|
|
}
|
|
]
|
|
);
|
|
|
|
# Authorized attempt to write
|
|
$t->post_ok( "//$auth_userid:$password@/api/v1/advanced_editor/macros" => json => $macro_values )
|
|
->status_is( 201, 'SWAGGER3.2.1' )
|
|
->json_has( '/macro_id', 'We generated a new id' )
|
|
->json_is( '/name' => $macro_values->{name}, 'The name matches what we supplied' )
|
|
->json_is( '/macro_text' => $macro_values->{macro_text}, 'The text matches what we supplied' )
|
|
->json_is( '/patron_id' => $macro_values->{patron_id}, 'The borrower matches the borrower who submitted' )
|
|
->json_is( '/shared' => Mojo::JSON->false, 'The macro is not shared' )
|
|
->header_like( Location => qr|^\/api\/v1\/advanced_editor/macros\/d*|, 'Correct location' );
|
|
|
|
# save the library_id
|
|
my $macro_id = 999;
|
|
|
|
# Authorized attempt to create with existing id
|
|
$macro_values->{macro_id} = $macro_id;
|
|
|
|
$t->post_ok( "//$auth_userid:$password@/api/v1/advanced_editor/macros" => json => $macro_values )
|
|
->status_is(400)
|
|
->json_is( '/errors' => [
|
|
{
|
|
message => "Read-only.",
|
|
path => "/body/macro_id"
|
|
}
|
|
]
|
|
);
|
|
|
|
$macro_values->{shared} = Mojo::JSON->true;
|
|
delete $macro_values->{macro_id};
|
|
|
|
# Unauthorized attempt to write a shared macro on private endpoint
|
|
$t->post_ok( "//$auth_userid:$password@/api/v1/advanced_editor/macros" => json => $macro_values )
|
|
->status_is(403);
|
|
# Unauthorized attempt to write a private macro on shared endpoint
|
|
$t->post_ok( "//$auth_userid:$password@/api/v1/advanced_editor/macros/shared" => json => $macro_values )
|
|
->status_is(403);
|
|
|
|
$builder->build({
|
|
source => 'UserPermission',
|
|
value => {
|
|
borrowernumber => $authorized_patron->borrowernumber,
|
|
module_bit => 9,
|
|
code => 'create_shared_macros',
|
|
},
|
|
});
|
|
|
|
# Authorized attempt to write a shared macro on private endpoint
|
|
$t->post_ok( "//$auth_userid:$password@/api/v1/advanced_editor/macros" => json => $macro_values )
|
|
->status_is(403);
|
|
|
|
# Authorized attempt to write a shared macro on shared endpoint
|
|
$t->post_ok( "//$auth_userid:$password@/api/v1/advanced_editor/macros/shared" => json => $macro_values )
|
|
->status_is(201);
|
|
|
|
};
|
|
|
|
subtest 'update() tests' => sub {
|
|
plan tests => 32;
|
|
|
|
my $authorized_patron = $builder->build_object({
|
|
class => 'Koha::Patrons',
|
|
value => { flags => 0 }
|
|
});
|
|
$builder->build({
|
|
source => 'UserPermission',
|
|
value => {
|
|
borrowernumber => $authorized_patron->borrowernumber,
|
|
module_bit => 9,
|
|
code => 'advanced_editor',
|
|
},
|
|
});
|
|
|
|
my $password = 'thePassword123';
|
|
$authorized_patron->set_password({ password => $password, skip_validation => 1 });
|
|
my $auth_userid = $authorized_patron->userid;
|
|
|
|
my $unauthorized_patron = $builder->build_object({
|
|
class => 'Koha::Patrons',
|
|
value => { flags => 0 }
|
|
});
|
|
$unauthorized_patron->set_password({ password => $password, skip_validation => 1 });
|
|
my $unauth_userid = $unauthorized_patron->userid;
|
|
|
|
my $macro = $builder->build_object({
|
|
class => 'Koha::AdvancedEditorMacros',
|
|
value => { borrowernumber => $authorized_patron->borrowernumber, shared => 0 }
|
|
});
|
|
my $macro_2 = $builder->build_object({
|
|
class => 'Koha::AdvancedEditorMacros',
|
|
value => { borrowernumber => $unauthorized_patron->borrowernumber, shared => 0 }
|
|
});
|
|
my $macro_id = $macro->id;
|
|
my $macro_2_id = $macro_2->id;
|
|
my $macro_values = $macro->to_api;
|
|
delete $macro_values->{macro_id};
|
|
|
|
# Unauthorized attempt to update
|
|
$t->put_ok( "//$unauth_userid:$password@/api/v1/advanced_editor/macros/$macro_id"
|
|
=> json => { name => 'New unauthorized name change' } )
|
|
->status_is(403);
|
|
|
|
# Attempt partial update on a PUT
|
|
my $macro_with_missing_field = {
|
|
name => "Call it macro-roni",
|
|
};
|
|
|
|
$t->put_ok( "//$auth_userid:$password@/api/v1/advanced_editor/macros/$macro_id" => json => $macro_with_missing_field )
|
|
->status_is(400)
|
|
->json_has( "/errors" =>
|
|
[ { message => "Missing property.", path => "/body/macro_text" } ]
|
|
);
|
|
|
|
my $macro_update = {
|
|
name => "Macro-update",
|
|
macro_text => "delete 100",
|
|
patron_id => $authorized_patron->borrowernumber,
|
|
shared => Mojo::JSON->false,
|
|
};
|
|
|
|
my $test = $t->put_ok( "//$auth_userid:$password@/api/v1/advanced_editor/macros/$macro_id" => json => $macro_update )
|
|
->status_is(200, 'Authorized user can update a macro')
|
|
->json_is( '/macro_id' => $macro_id, 'We get the id back' )
|
|
->json_is( '/name' => $macro_update->{name}, 'We get the name back' )
|
|
->json_is( '/macro_text' => $macro_update->{macro_text}, 'We get the text back' )
|
|
->json_is( '/patron_id' => $macro_update->{patron_id}, 'We get the patron_id back' )
|
|
->json_is( '/shared' => $macro_update->{shared}, 'It should still not be shared' );
|
|
|
|
# Now try to make the macro shared
|
|
$macro_update->{shared} = Mojo::JSON->true;
|
|
|
|
$t->put_ok( "//$auth_userid:$password@/api/v1/advanced_editor/macros/shared/$macro_id" => json => $macro_update )
|
|
->status_is(403, 'Cannot make your macro shared on private endpoint');
|
|
$t->put_ok( "//$auth_userid:$password@/api/v1/advanced_editor/macros/shared/$macro_id" => json => $macro_update )
|
|
->status_is(403, 'Cannot make your macro shared without permission');
|
|
|
|
$builder->build({
|
|
source => 'UserPermission',
|
|
value => {
|
|
borrowernumber => $authorized_patron->borrowernumber,
|
|
module_bit => 9,
|
|
code => 'create_shared_macros',
|
|
},
|
|
});
|
|
|
|
$t->put_ok( "//$auth_userid:$password@/api/v1/advanced_editor/macros/$macro_id" => json => $macro_update )
|
|
->status_is(403, 'Cannot make your macro shared on the private endpoint');
|
|
|
|
$t->put_ok( "//$auth_userid:$password@/api/v1/advanced_editor/macros/shared/$macro_id" => json => $macro_update )
|
|
->status_is(200, 'Can update macro to shared with permission')
|
|
->json_is( '/macro_id' => $macro_id, 'We get back the id' )
|
|
->json_is( '/name' => $macro_update->{name}, 'We get back the name' )
|
|
->json_is( '/macro_text' => $macro_update->{macro_text}, 'We get back the text' )
|
|
->json_is( '/patron_id' => $macro_update->{patron_id}, 'We get back our patron id' )
|
|
->json_is( '/shared' => Mojo::JSON->true, 'It is shared' );
|
|
|
|
# Authorized attempt to write invalid data
|
|
my $macro_with_invalid_field = { %$macro_update };
|
|
$macro_with_invalid_field->{'big_mac_ro'} = 'Mac attack';
|
|
|
|
$t->put_ok( "//$auth_userid:$password@/api/v1/advanced_editor/macros/$macro_id" => json => $macro_with_invalid_field )
|
|
->status_is(400)
|
|
->json_is(
|
|
"/errors" => [
|
|
{
|
|
message => "Properties not allowed: big_mac_ro.",
|
|
path => "/body"
|
|
}
|
|
]
|
|
);
|
|
|
|
my $non_existent_macro = $builder->build_object({class => 'Koha::AdvancedEditorMacros'});
|
|
my $non_existent_code = $non_existent_macro->id;
|
|
$non_existent_macro->delete;
|
|
|
|
$t->put_ok("//$auth_userid:$password@/api/v1/advanced_editor/macros/$non_existent_code" => json => $macro_update)
|
|
->status_is(404);
|
|
|
|
$t->put_ok("//$auth_userid:$password@/api/v1/advanced_editor/macros/$macro_2_id" => json => $macro_update)
|
|
->status_is(403, "Cannot update other borrowers private macro");
|
|
};
|
|
|
|
subtest 'delete() tests' => sub {
|
|
plan tests => 12;
|
|
|
|
my $authorized_patron = $builder->build_object({
|
|
class => 'Koha::Patrons',
|
|
value => { flags => 0 }
|
|
});
|
|
$builder->build({
|
|
source => 'UserPermission',
|
|
value => {
|
|
borrowernumber => $authorized_patron->borrowernumber,
|
|
module_bit => 9,
|
|
code => 'advanced_editor',
|
|
},
|
|
});
|
|
|
|
my $password = 'thePassword123';
|
|
$authorized_patron->set_password({ password => $password, skip_validation => 1 });
|
|
my $auth_userid = $authorized_patron->userid;
|
|
|
|
my $unauthorized_patron = $builder->build_object({
|
|
class => 'Koha::Patrons',
|
|
value => { flags => 0 }
|
|
});
|
|
$unauthorized_patron->set_password({ password => $password, skip_validation => 1 });
|
|
my $unauth_userid = $unauthorized_patron->userid;
|
|
|
|
my $macro = $builder->build_object({
|
|
class => 'Koha::AdvancedEditorMacros',
|
|
value => { borrowernumber => $authorized_patron->borrowernumber, shared => 0 }
|
|
});
|
|
my $macro_2 = $builder->build_object({
|
|
class => 'Koha::AdvancedEditorMacros',
|
|
value => { borrowernumber => $unauthorized_patron->borrowernumber, shared => 0 }
|
|
});
|
|
my $macro_id = $macro->id;
|
|
my $macro_2_id = $macro_2->id;
|
|
|
|
# Unauthorized attempt to delete
|
|
$t->delete_ok( "//$unauth_userid:$password@/api/v1/advanced_editor/macros/$macro_2_id")
|
|
->status_is(403, "Cannot delete macro without permission");
|
|
|
|
$t->delete_ok( "//$auth_userid:$password@/api/v1/advanced_editor/macros/$macro_id")
|
|
->status_is( 204, 'Can delete macro with permission');
|
|
|
|
$t->delete_ok( "//$auth_userid:$password@/api/v1/advanced_editor/macros/$macro_2_id")
|
|
->status_is(403, 'Cannot delete other users macro with permission');
|
|
|
|
$macro_2->shared(1)->store();
|
|
|
|
$t->delete_ok( "//$auth_userid:$password@/api/v1/advanced_editor/macros/shared/$macro_2_id")
|
|
->status_is(403, 'Cannot delete other users shared macro without permission');
|
|
|
|
$builder->build({
|
|
source => 'UserPermission',
|
|
value => {
|
|
borrowernumber => $authorized_patron->borrowernumber,
|
|
module_bit => 9,
|
|
code => 'delete_shared_macros',
|
|
},
|
|
});
|
|
$t->delete_ok( "//$auth_userid:$password@/api/v1/advanced_editor/macros/$macro_2_id")
|
|
->status_is(403, 'Cannot delete other users shared macro with permission on private endpoint');
|
|
$t->delete_ok( "//$auth_userid:$password@/api/v1/advanced_editor/macros/shared/$macro_2_id")
|
|
->status_is(204, 'Can delete other users shared macro with permission');
|
|
|
|
};
|
|
|
|
$schema->storage->txn_rollback;
|