View | Details | Raw Unified | Return to bug 22785
Collapse All | Expand All

(-)a/Koha/REST/V1/ImportRecordMatches.pm (+106 lines)
Line 0 Link Here
1
package Koha::REST::V1::ImportRecordMatches;
2
3
# This file is part of Koha.
4
#
5
# Koha is free software; you can redistribute it and/or modify it
6
# under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 3 of the License, or
8
# (at your option) any later version.
9
#
10
# Koha is distributed in the hope that it will be useful, but
11
# WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18
use Modern::Perl;
19
20
use Mojo::Base 'Mojolicious::Controller';
21
22
use Koha::Import::Record::Matches;
23
24
use Try::Tiny;
25
26
=head1 API
27
28
=head2 Methods
29
30
=cut
31
32
=head3 unset_chosen
33
34
Method that handles unselecting all chosen matches for an import record
35
36
DELETE /api/v1/import/{import_batch_id}/records/{import_record_id}/matches/chosen
37
38
=cut
39
40
sub unset_chosen {
41
    my $c = shift->openapi->valid_input or return;
42
43
    my $import_record_id = $c->validation->param('import_record_id');
44
    my $matches = Koha::Import::Record::Matches->search({
45
        import_record_id => $import_record_id,
46
    });
47
    unless ($matches) {
48
        return $c->render(
49
            status  => 404,
50
            openapi => { error => "No matches not found" }
51
        );
52
    }
53
    return try {
54
        $matches->unset_chosen;
55
        return $c->render( status => 204, openapi => $matches );
56
    }
57
    catch {
58
        $c->unhandled_exception($_);
59
    };
60
}
61
62
=head3 set_chosen
63
64
Method that handles modifying if a Koha::Import::Record::Match object has been chosen for overlay
65
66
PUT /api/v1/import/{import_batch_id}/records/{import_record_id}/matches/chosen
67
68
Body should contain the condidate_match_id to chose
69
70
=cut
71
72
sub set_chosen {
73
    my $c = shift->openapi->valid_input or return;
74
75
    my $import_record_id = $c->validation->param('import_record_id');
76
    my $body    = $c->validation->param('body');
77
    my $candidate_match_id = $body->{'candidate_match_id'};
78
79
    my $match = Koha::Import::Record::Matches->find({
80
        import_record_id => $import_record_id,
81
        candidate_match_id => $candidate_match_id
82
    });
83
84
    unless ($match) {
85
        return $c->render(
86
            status  => 404,
87
            openapi => { error => "Match not found" }
88
        );
89
    }
90
91
    return try {
92
        my $matches = Koha::Import::Record::Matches->search({
93
            import_record_id => $import_record_id,
94
            chosen => 1
95
        });
96
        $matches->unset_chosen if $matches;
97
        $match->set_from_api({ chosen => JSON::true });
98
        $match->store;
99
        return $c->render( status => 200, openapi => $match );
100
    }
101
    catch {
102
        $c->unhandled_exception($_);
103
    };
104
}
105
106
1;
(-)a/api/v1/swagger/definitions/import_record_match.json (+21 lines)
Line 0 Link Here
1
{
2
  "type": "object",
3
  "properties": {
4
    "import_record_id": {
5
      "type": "integer",
6
      "description": "Internal import record identifier"
7
    },
8
    "candidate_match_id": {
9
      "type": "integer",
10
      "description": "Internal import record match candidate identifier"
11
    },
12
    "chosen": {
13
      "type": "boolean",
14
      "description": "Whether match has been chosen for overlay"
15
    },
16
    "score": {
17
      "type": "integer",
18
      "description": "Ranking value for this match calculated by the matching rules"
19
    }
20
  }
21
}
(-)a/api/v1/swagger/parameters/import_record_match.json (+16 lines)
Line 0 Link Here
1
{
2
  "import_record_id_pp": {
3
    "name": "import_record_id",
4
    "in": "path",
5
    "description": "Internal import_record identifier",
6
    "required": true,
7
    "type": "integer"
8
  },
9
  "candidate_match_id_pp": {
10
    "name": "candidate_match_id",
11
    "in": "path",
12
    "description": "Internal import_record_match_candidate identifier",
13
    "required": true,
14
    "type": "integer"
15
  }
16
}
(-)a/api/v1/swagger/paths/import_record_matches.json (+144 lines)
Line 0 Link Here
1
{
2
  "/import/{import_batch_id}/records/{import_record_id}/matches/chosen": {
3
    "put": {
4
      "x-mojo-to": "ImportRecordMatches#set_chosen",
5
      "operationId": "setChosen",
6
      "tags": ["import_record_matches"],
7
      "parameters": [{
8
          "name": "import_batch_id",
9
          "in": "path",
10
          "required": true,
11
          "description": "An import_batch ID",
12
          "type": "integer"
13
      }, {
14
          "name": "import_record_id",
15
          "in": "path",
16
          "required": true,
17
          "description": "An import_record ID",
18
          "type": "integer"
19
      }, {
20
          "name": "body",
21
          "in": "body",
22
          "description": "A JSON object containing fields to modify",
23
          "required": true,
24
          "schema": {
25
            "type": "object",
26
            "properties": {
27
              "candidate_match_id": {
28
                "description": "Candudate match to choose",
29
                "type": "integer"
30
              }
31
            }
32
          }
33
        }
34
      ],
35
      "consumes": ["application/json"],
36
      "produces": ["application/json"],
37
      "responses": {
38
        "200": {
39
          "description": "Match updated"
40
        },
41
        "400": {
42
          "description": "Missing or wrong parameters",
43
          "schema": {
44
            "$ref": "../definitions.json#/error"
45
          }
46
        },
47
        "401": {
48
          "description": "Authentication required",
49
          "schema": {
50
            "$ref": "../definitions.json#/error"
51
          }
52
        },
53
        "403": {
54
          "description": "Match management not allowed",
55
          "schema": {
56
            "$ref": "../definitions.json#/error"
57
          }
58
        },
59
        "404": {
60
          "description": "Import record match not found",
61
          "schema": {
62
            "$ref": "../definitions.json#/error"
63
          }
64
        },
65
        "500": {
66
          "description": "Internal server error",
67
          "schema": {
68
            "$ref": "../definitions.json#/error"
69
          }
70
        },
71
        "503": {
72
          "description": "Under maintenance",
73
          "schema": {
74
            "$ref": "../definitions.json#/error"
75
          }
76
        }
77
      },
78
      "x-koha-authorization": {
79
        "permissions": {
80
          "tools": "manage_staged_marc"
81
        }
82
      }
83
    },
84
    "delete": {
85
      "x-mojo-to": "ImportRecordMatches#unset_chosen",
86
      "operationId": "unsetChosen",
87
      "tags": ["import_record_matches"],
88
      "parameters": [{
89
          "name": "import_batch_id",
90
          "in": "path",
91
          "required": true,
92
          "description": "An import_batch ID",
93
          "type": "integer"
94
      }, {
95
          "name": "import_record_id",
96
          "in": "path",
97
          "required": true,
98
          "description": "An import_record ID",
99
          "type": "integer"
100
      }],
101
      "produces": ["application/json"],
102
      "responses": {
103
        "204": {
104
          "description": "Matches unchosen"
105
        },
106
        "401": {
107
          "description": "Authentication required",
108
          "schema": {
109
            "$ref": "../definitions.json#/error"
110
          }
111
        },
112
        "403": {
113
          "description": "Match management not allowed",
114
          "schema": {
115
            "$ref": "../definitions.json#/error"
116
          }
117
        },
118
        "404": {
119
          "description": "Import record matches not found",
120
          "schema": {
121
            "$ref": "../definitions.json#/error"
122
          }
123
        },
124
        "500": {
125
          "description": "Internal server error",
126
          "schema": {
127
            "$ref": "../definitions.json#/error"
128
          }
129
        },
130
        "503": {
131
          "description": "Under maintenance",
132
          "schema": {
133
            "$ref": "../definitions.json#/error"
134
          }
135
        }
136
      },
137
      "x-koha-authorization": {
138
        "permissions": {
139
          "tools": "manage_staged_marc"
140
        }
141
      }
142
    }
143
  }
144
}
(-)a/t/db_dependent/api/v1/import_record_matches.t (-1 / +167 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/env perl
2
3
# This file is part of Koha.
4
#
5
# Koha is free software; you can redistribute it and/or modify it
6
# under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 3 of the License, or
8
# (at your option) any later version.
9
#
10
# Koha is distributed in the hope that it will be useful, but
11
# WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18
use Modern::Perl;
19
20
use Test::More tests => 1;
21
use Test::Mojo;
22
use Test::Warn;
23
24
use t::lib::TestBuilder;
25
use t::lib::Mocks;
26
27
use C4::Auth;
28
use Koha::Import::Record::Matches;
29
30
my $schema  = Koha::Database->new->schema;
31
my $builder = t::lib::TestBuilder->new;
32
33
# FIXME: sessionStorage defaults to mysql, but it seems to break transaction handling
34
# this affects the other REST api tests
35
t::lib::Mocks::mock_preference( 'SessionStorage', 'tmp' );
36
37
my $remote_address = '127.0.0.1';
38
my $t              = Test::Mojo->new('Koha::REST::V1');
39
40
subtest 'import record matches tests' => sub {
41
42
    plan tests => 13;
43
44
    $schema->storage->txn_begin;
45
46
    my ( $unauthorized_borrowernumber, $unauthorized_session_id ) =
47
      create_user_and_session( { authorized => 0 } );
48
    my ( $authorized_borrowernumber, $authorized_session_id ) =
49
      create_user_and_session( { authorized => 1 } );
50
51
    my $match_1 = $builder->build_object({
52
        class => 'Koha::Import::Record::Matches',
53
        value => {
54
            chosen => 0,
55
        }
56
    });
57
    my $match_2 = $builder->build_object({
58
        class => 'Koha::Import::Record::Matches',
59
        value => {
60
            import_record_id => $match_1->import_record_id,
61
            chosen => 1,
62
        }
63
    });
64
    my $del_match = $builder->build_object({ class => 'Koha::Import::Record::Matches' });
65
    my $del_import_batch_id = $del_match->import_record->import_batch_id;
66
    my $del_match_id = $del_match->import_record_id;
67
68
    # Unauthorized attempt to update
69
    my $tx = $t->ua->build_tx(
70
      PUT => "/api/v1/import/".$match_1->import_record->import_batch_id."/records/".$match_1->import_record_id."/matches/chosen"=>
71
      json => {
72
          candidate_match_id => $match_1->candidate_match_id
73
      }
74
    );
75
    $tx->req->cookies(
76
        { name => 'CGISESSID', value => $unauthorized_session_id } );
77
    $tx->req->env( { REMOTE_ADDR => $remote_address } );
78
    $t->request_ok($tx)->status_is(403);
79
80
    # Invalid attempt to allow match on a non-existent record
81
    $tx = $t->ua->build_tx(
82
      PUT => "/api/v1/import/".$del_import_batch_id."/records/".$del_match_id."/matches/chosen" =>
83
      json => {
84
          candidate_match_id => $match_1->candidate_match_id
85
      }
86
    );
87
88
    $tx->req->cookies(
89
        { name => 'CGISESSID', value => $authorized_session_id } );
90
    $tx->req->env( { REMOTE_ADDR => $remote_address } );
91
    $del_match->delete();
92
    $t->request_ok($tx)->status_is(404)
93
      ->json_is( '/error' => "Match not found" );
94
95
    # Valid, authorised update
96
    $tx = $t->ua->build_tx(
97
      PUT => "/api/v1/import/".$match_1->import_record->import_batch_id."/records/".$match_1->import_record_id."/matches/chosen" =>
98
      json => {
99
          candidate_match_id => $match_1->candidate_match_id
100
      }
101
    );
102
    $tx->req->cookies(
103
        { name => 'CGISESSID', value => $authorized_session_id } );
104
    $tx->req->env( { REMOTE_ADDR => $remote_address } );
105
    $t->request_ok($tx)->status_is(200);
106
107
    $match_1->discard_changes;
108
    $match_2->discard_changes;
109
    ok( $match_1->chosen,"Match 1 is correctly set to chosen");
110
    ok( !$match_2->chosen,"Match 2 correctly unset when match 1 is set");
111
112
    # Valid unsetting
113
    $tx = $t->ua->build_tx(
114
      DELETE => "/api/v1/import/".$match_1->import_record->import_batch_id."/records/".$match_1->import_record_id."/matches/chosen" =>
115
      json => {
116
      }
117
    );
118
    $tx->req->cookies(
119
        { name => 'CGISESSID', value => $authorized_session_id } );
120
    $tx->req->env( { REMOTE_ADDR => $remote_address } );
121
    $t->request_ok($tx)->status_is(204);
122
123
    $match_1->discard_changes;
124
    $match_2->discard_changes;
125
    ok( !$match_1->chosen,"Match 1 is correctly unset to chosen");
126
    ok( !$match_2->chosen,"Match 2 is correctly unset to chosen");
127
128
    $schema->storage->txn_rollback;
129
};
130
131
sub create_user_and_session {
132
133
    my $args  = shift;
134
    my $dbh   = C4::Context->dbh;
135
136
    my $user = $builder->build(
137
        {
138
            source => 'Borrower',
139
            value  => {
140
                flags => 0
141
            }
142
        }
143
    );
144
145
    # Create a session for the authorized user
146
    my $session = C4::Auth::get_session('');
147
    $session->param( 'number',   $user->{borrowernumber} );
148
    $session->param( 'id',       $user->{userid} );
149
    $session->param( 'ip',       '127.0.0.1' );
150
    $session->param( 'lasttime', time() );
151
    $session->flush;
152
153
    if ( $args->{authorized} ) {
154
        $builder->build({
155
            source => 'UserPermission',
156
            value  => {
157
                borrowernumber => $user->{borrowernumber},
158
                module_bit     => 13,
159
                code           => 'manage_staged_marc',
160
            }
161
        });
162
    }
163
164
    return ( $user->{borrowernumber}, $session->id );
165
}
166
167
1;

Return to bug 22785