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

(-)a/Koha/REST/V1/ExtendedAttributeTypes.pm (-12 / +47 lines)
Lines 35-48 use Try::Tiny qw( catch try ); Link Here
35
35
36
=head2 Methods
36
=head2 Methods
37
37
38
=head3 list
38
=head3 _list
39
39
40
=cut
40
=cut
41
41
42
sub list {
42
sub _list {
43
    my $c = shift->openapi->valid_input or return;
43
    my ( $self, @resource_types ) = @_;
44
45
    my $resource_type = $c->param('resource_type');
46
44
47
    # FIXME: Maybe not the best place for this mapping
45
    # FIXME: Maybe not the best place for this mapping
48
    my $resource_to_table = {
46
    my $resource_to_table = {
Lines 56-72 sub list { Link Here
56
        order     => 'aqorders',
54
        order     => 'aqorders',
57
    };
55
    };
58
56
59
    return try {
57
    my @tables;
60
        my $additional_fields_set = Koha::AdditionalFields->new;
58
    for my $resource_type (@resource_types) {
61
        if ( $resource_type && $resource_to_table->{$resource_type} ) {
59
        if ( $resource_type && $resource_to_table->{$resource_type} ) {
62
            $additional_fields_set =
60
            push @tables, $resource_to_table->{$resource_type};
63
                $additional_fields_set->search( { tablename => $resource_to_table->{$resource_type} } );
64
        } elsif ($resource_type) {
61
        } elsif ($resource_type) {
65
            $additional_fields_set = $additional_fields_set->search( { tablename => $resource_type } );
62
            push @tables, $resource_type;
66
        } else {
67
            $additional_fields_set = $additional_fields_set->search();
68
        }
63
        }
64
    }
65
    return Koha::AdditionalFields->new->search( ( @tables ? { tablename => \@tables } : () ) );
66
}
67
68
=head3 list
69
70
List all additional fields, can be filtered using the resource_type parameter.
71
72
=cut
73
74
sub list {
75
    my ($self) = @_;
76
77
    my $c = $self->openapi->valid_input or return;
78
79
    my $resource_type = $c->param('resource_type');
69
80
81
    return try {
82
        my $additional_fields_set = $self->_list($resource_type);
83
        return $c->render(
84
            status  => 200,
85
            openapi => $c->objects->search($additional_fields_set)
86
        );
87
    } catch {
88
        $c->unhandled_exception($_);
89
    };
90
}
91
92
=head3 list_erm
93
94
List the ERM-related additional fields, can be filtered using the resource_type parameter.
95
96
=cut
97
98
sub list_erm {
99
    my ($self)         = @_;
100
    my $c              = shift->openapi->valid_input or return;
101
    my @resource_types = qw(erm_licenses erm_agreements erm_packages);
102
103
    return try {
104
        my $additional_fields_set = $self->_list(@resource_types);
70
        return $c->render(
105
        return $c->render(
71
            status  => 200,
106
            status  => 200,
72
            openapi => $c->objects->search($additional_fields_set)
107
            openapi => $c->objects->search($additional_fields_set)
(-)a/api/v1/swagger/paths/erm_extended_attribute_types.yaml (+57 lines)
Line 0 Link Here
1
---
2
/erm/extended_attribute_types:
3
  get:
4
    x-mojo-to: ExtendedAttributeTypes#list_erm
5
    operationId: listErmAdditionalFields
6
    tags:
7
      - additional_fields
8
    summary: List ERM extended attribute types
9
    produces:
10
      - application/json
11
    parameters:
12
      - description: filter by resource type
13
        in: query
14
        name: resource_type
15
        type: string
16
        enum:
17
          - license
18
          - agreement
19
          - package
20
      - $ref: "../swagger.yaml#/parameters/match"
21
      - $ref: "../swagger.yaml#/parameters/order_by"
22
      - $ref: "../swagger.yaml#/parameters/page"
23
      - $ref: "../swagger.yaml#/parameters/per_page"
24
      - $ref: "../swagger.yaml#/parameters/q_param"
25
      - $ref: "../swagger.yaml#/parameters/q_body"
26
    responses:
27
      200:
28
        description: A list of extended attribute types for ERM
29
        schema:
30
          items:
31
            $ref: "../swagger.yaml#/definitions/extended_attribute_type"
32
          type: array
33
      "400":
34
        description: |
35
          Bad request. Possible `error_code` attribute values:
36
37
            * `invalid_query`
38
        schema:
39
          $ref: "../swagger.yaml#/definitions/error"
40
      403:
41
        description: Access forbidden
42
        schema:
43
          $ref: "../swagger.yaml#/definitions/error"
44
      500:
45
        description: |-
46
          Internal server error. Possible `error_code` attribute values:
47
          * `internal_server_error`
48
        schema:
49
          $ref: "../swagger.yaml#/definitions/error"
50
      503:
51
        description: Under maintenance
52
        schema:
53
          $ref: "../swagger.yaml#/definitions/error"
54
    x-koha-authorization:
55
      permissions:
56
        - parameters: manage_additional_fields
57
        - erm: 1
(-)a/api/v1/swagger/swagger.yaml (+2 lines)
Lines 383-388 paths: Link Here
383
    $ref: "./paths/erm_custom_reports.yaml#/~1erm~1eUsage~1metric_types_report~1{data_type}"
383
    $ref: "./paths/erm_custom_reports.yaml#/~1erm~1eUsage~1metric_types_report~1{data_type}"
384
  "/erm/eUsage/provider_rollup_report/{data_type}":
384
  "/erm/eUsage/provider_rollup_report/{data_type}":
385
    $ref: "./paths/erm_custom_reports.yaml#/~1erm~1eUsage~1provider_rollup_report~1{data_type}"
385
    $ref: "./paths/erm_custom_reports.yaml#/~1erm~1eUsage~1provider_rollup_report~1{data_type}"
386
  /erm/extended_attribute_types:
387
    $ref: ./paths/erm_extended_attribute_types.yaml#/~1erm~1extended_attribute_types
386
  /erm/licenses:
388
  /erm/licenses:
387
    $ref: ./paths/erm_licenses.yaml#/~1erm~1licenses
389
    $ref: ./paths/erm_licenses.yaml#/~1erm~1licenses
388
  "/erm/licenses/{license_id}":
390
  "/erm/licenses/{license_id}":
(-)a/koha-tmpl/intranet-tmpl/prog/js/fetch/additional-fields-api-client.js (-1 / +35 lines)
Lines 1-3 Link Here
1
import ERMAPIClient from "@fetch/erm-api-client";
2
1
export class AdditionalFieldsAPIClient {
3
export class AdditionalFieldsAPIClient {
2
    constructor(HttpClient) {
4
    constructor(HttpClient) {
3
        this.httpClient = new HttpClient({
5
        this.httpClient = new HttpClient({
Lines 16-19 export class AdditionalFieldsAPIClient { Link Here
16
    }
18
    }
17
}
19
}
18
20
19
export default AdditionalFieldsAPIClient;
21
export class AdditionalFieldsAPIClientWrapper {
22
    constructor(HttpClient) {
23
        this.clients = {
24
            admin: new AdditionalFieldsAPIClient(HttpClient),
25
            erm: new ERMAPIClient(HttpClient),
26
        };
27
    }
28
29
    get additional_fields() {
30
        return {
31
            getAll: resource_type => {
32
                let moduleName = this.getModuleName(resource_type);
33
                return this.clients[moduleName].additional_fields.getAll(
34
                    resource_type
35
                );
36
            },
37
        };
38
    }
39
40
    getModuleName(resource_type) {
41
        const moduleMappings = {
42
            erm: ["agreement", "license", "package"],
43
        };
44
45
        for (const [module, resourceTypes] of Object.entries(moduleMappings)) {
46
            if (resourceTypes.includes(resource_type)) return module;
47
        }
48
49
        return "admin";
50
    }
51
}
52
53
export default AdditionalFieldsAPIClientWrapper;
(-)a/koha-tmpl/intranet-tmpl/prog/js/fetch/erm-api-client.js (+10 lines)
Lines 447-452 export class ERMAPIClient { Link Here
447
                }),
447
                }),
448
        };
448
        };
449
    }
449
    }
450
451
    get additional_fields() {
452
        return {
453
            getAll: resource_type =>
454
                this.httpClient.getAll({
455
                    endpoint: "extended_attribute_types",
456
                    params: { resource_type },
457
                }),
458
        };
459
    }
450
}
460
}
451
461
452
export default ERMAPIClient;
462
export default ERMAPIClient;
(-)a/t/cypress/integration/AdditionalFields_spec.ts (-18 / +18 lines)
Lines 489-495 describe("Additional Fields operations", () => { Link Here
489
        let license_additional_fields = get_licenses_additional_fields();
489
        let license_additional_fields = get_licenses_additional_fields();
490
        let av_cats = get_av_cats();
490
        let av_cats = get_av_cats();
491
491
492
        cy.intercept("GET", "/api/v1/extended_attribute_types*", {
492
        cy.intercept("GET", "/api/v1/erm/extended_attribute_types*", {
493
            body: license_additional_fields,
493
            body: license_additional_fields,
494
            statusCode: 200,
494
            statusCode: 200,
495
        });
495
        });
Lines 551-557 describe("Additional Fields operations", () => { Link Here
551
            statusCode: 200,
551
            statusCode: 200,
552
            body: vendors,
552
            body: vendors,
553
        });
553
        });
554
        cy.intercept("GET", "/api/v1/extended_attribute_types*", {
554
        cy.intercept("GET", "/api/v1/erm/extended_attribute_types*", {
555
            body: [],
555
            body: [],
556
            statusCode: 200,
556
            statusCode: 200,
557
        }).as("empty-additional-fields");
557
        }).as("empty-additional-fields");
Lines 562-568 describe("Additional Fields operations", () => { Link Here
562
        cy.wait("@get-empty-license");
562
        cy.wait("@get-empty-license");
563
        cy.get("#licenses_show #additional_fields").should("not.exist");
563
        cy.get("#licenses_show #additional_fields").should("not.exist");
564
564
565
        cy.intercept("GET", "/api/v1/extended_attribute_types*", {
565
        cy.intercept("GET", "/api/v1/erm/extended_attribute_types*", {
566
            body: license_additional_fields,
566
            body: license_additional_fields,
567
            statusCode: 200,
567
            statusCode: 200,
568
        }).as("existing-additional-fields");
568
        }).as("existing-additional-fields");
Lines 657-663 describe("Additional Fields operations", () => { Link Here
657
            statusCode: 200,
657
            statusCode: 200,
658
            body: vendors,
658
            body: vendors,
659
        });
659
        });
660
        cy.intercept("GET", "/api/v1/extended_attribute_types*", {
660
        cy.intercept("GET", "/api/v1/erm/extended_attribute_types*", {
661
            body: [],
661
            body: [],
662
            statusCode: 200,
662
            statusCode: 200,
663
        }).as("empty-additional-fields");
663
        }).as("empty-additional-fields");
Lines 666-672 describe("Additional Fields operations", () => { Link Here
666
        cy.visit("/cgi-bin/koha/erm/licenses/add");
666
        cy.visit("/cgi-bin/koha/erm/licenses/add");
667
        cy.get("#licenses_add form #additional_fields").should("not.exist");
667
        cy.get("#licenses_add form #additional_fields").should("not.exist");
668
668
669
        cy.intercept("GET", "/api/v1/extended_attribute_types*", {
669
        cy.intercept("GET", "/api/v1/erm/extended_attribute_types*", {
670
            body: license_additional_fields,
670
            body: license_additional_fields,
671
            statusCode: 200,
671
            statusCode: 200,
672
        }).as("existing-additional-fields");
672
        }).as("existing-additional-fields");
Lines 791-797 describe("Additional Fields operations", () => { Link Here
791
            body: vendors,
791
            body: vendors,
792
        });
792
        });
793
793
794
        cy.intercept("GET", "/api/v1/extended_attribute_types*", {
794
        cy.intercept("GET", "/api/v1/erm/extended_attribute_types*", {
795
            body: license_additional_fields,
795
            body: license_additional_fields,
796
            statusCode: 200,
796
            statusCode: 200,
797
        }).as("existing-additional-fields");
797
        }).as("existing-additional-fields");
Lines 888-894 describe("Additional Fields operations", () => { Link Here
888
        let agreement_additional_fields = get_agreements_additional_fields();
888
        let agreement_additional_fields = get_agreements_additional_fields();
889
        let av_cats = get_av_cats();
889
        let av_cats = get_av_cats();
890
890
891
        cy.intercept("GET", "/api/v1/extended_attribute_types*", {
891
        cy.intercept("GET", "/api/v1/erm/extended_attribute_types*", {
892
            body: agreement_additional_fields,
892
            body: agreement_additional_fields,
893
            statusCode: 200,
893
            statusCode: 200,
894
        });
894
        });
Lines 950-956 describe("Additional Fields operations", () => { Link Here
950
            statusCode: 200,
950
            statusCode: 200,
951
            body: vendors,
951
            body: vendors,
952
        });
952
        });
953
        cy.intercept("GET", "/api/v1/extended_attribute_types*", {
953
        cy.intercept("GET", "/api/v1/erm/extended_attribute_types*", {
954
            body: [],
954
            body: [],
955
            statusCode: 200,
955
            statusCode: 200,
956
        }).as("empty-additional-fields");
956
        }).as("empty-additional-fields");
Lines 961-967 describe("Additional Fields operations", () => { Link Here
961
        cy.wait("@get-empty-agreement");
961
        cy.wait("@get-empty-agreement");
962
        cy.get("#agreements_show #additional_fields").should("not.exist");
962
        cy.get("#agreements_show #additional_fields").should("not.exist");
963
963
964
        cy.intercept("GET", "/api/v1/extended_attribute_types*", {
964
        cy.intercept("GET", "/api/v1/erm/extended_attribute_types*", {
965
            body: agreement_additional_fields,
965
            body: agreement_additional_fields,
966
            statusCode: 200,
966
            statusCode: 200,
967
        }).as("existing-additional-fields");
967
        }).as("existing-additional-fields");
Lines 1056-1062 describe("Additional Fields operations", () => { Link Here
1056
            statusCode: 200,
1056
            statusCode: 200,
1057
            body: vendors,
1057
            body: vendors,
1058
        });
1058
        });
1059
        cy.intercept("GET", "/api/v1/extended_attribute_types*", {
1059
        cy.intercept("GET", "/api/v1/erm/extended_attribute_types*", {
1060
            body: [],
1060
            body: [],
1061
            statusCode: 200,
1061
            statusCode: 200,
1062
        }).as("empty-additional-fields");
1062
        }).as("empty-additional-fields");
Lines 1065-1071 describe("Additional Fields operations", () => { Link Here
1065
        cy.visit("/cgi-bin/koha/erm/agreements/add");
1065
        cy.visit("/cgi-bin/koha/erm/agreements/add");
1066
        cy.get("#agreements_add form #additional_fields").should("not.exist");
1066
        cy.get("#agreements_add form #additional_fields").should("not.exist");
1067
1067
1068
        cy.intercept("GET", "/api/v1/extended_attribute_types*", {
1068
        cy.intercept("GET", "/api/v1/erm/extended_attribute_types*", {
1069
            body: agreement_additional_fields,
1069
            body: agreement_additional_fields,
1070
            statusCode: 200,
1070
            statusCode: 200,
1071
        }).as("existing-additional-fields");
1071
        }).as("existing-additional-fields");
Lines 1190-1196 describe("Additional Fields operations", () => { Link Here
1190
            body: vendors,
1190
            body: vendors,
1191
        });
1191
        });
1192
1192
1193
        cy.intercept("GET", "/api/v1/extended_attribute_types*", {
1193
        cy.intercept("GET", "/api/v1/erm/extended_attribute_types*", {
1194
            body: agreement_additional_fields,
1194
            body: agreement_additional_fields,
1195
            statusCode: 200,
1195
            statusCode: 200,
1196
        }).as("existing-additional-fields");
1196
        }).as("existing-additional-fields");
Lines 1290-1296 describe("Additional Fields operations", () => { Link Here
1290
            get_packages_additional_fields();
1290
            get_packages_additional_fields();
1291
        let av_cats = get_av_cats();
1291
        let av_cats = get_av_cats();
1292
1292
1293
        cy.intercept("GET", "/api/v1/extended_attribute_types*", {
1293
        cy.intercept("GET", "/api/v1/erm/extended_attribute_types*", {
1294
            body: eholdings_package_additional_fields,
1294
            body: eholdings_package_additional_fields,
1295
            statusCode: 200,
1295
            statusCode: 200,
1296
        });
1296
        });
Lines 1359-1365 describe("Additional Fields operations", () => { Link Here
1359
            statusCode: 200,
1359
            statusCode: 200,
1360
            body: vendors,
1360
            body: vendors,
1361
        });
1361
        });
1362
        cy.intercept("GET", "/api/v1/extended_attribute_types*", {
1362
        cy.intercept("GET", "/api/v1/erm/extended_attribute_types*", {
1363
            body: [],
1363
            body: [],
1364
            statusCode: 200,
1364
            statusCode: 200,
1365
        }).as("empty-additional-fields");
1365
        }).as("empty-additional-fields");
Lines 1370-1376 describe("Additional Fields operations", () => { Link Here
1370
        cy.wait("@get-empty-eholdings-package");
1370
        cy.wait("@get-empty-eholdings-package");
1371
        cy.get("#packages_list #additional_fields").should("not.exist");
1371
        cy.get("#packages_list #additional_fields").should("not.exist");
1372
1372
1373
        cy.intercept("GET", "/api/v1/extended_attribute_types*", {
1373
        cy.intercept("GET", "/api/v1/erm/extended_attribute_types*", {
1374
            body: eholdings_package_additional_fields,
1374
            body: eholdings_package_additional_fields,
1375
            statusCode: 200,
1375
            statusCode: 200,
1376
        }).as("existing-additional-fields");
1376
        }).as("existing-additional-fields");
Lines 1468-1474 describe("Additional Fields operations", () => { Link Here
1468
            statusCode: 200,
1468
            statusCode: 200,
1469
            body: vendors,
1469
            body: vendors,
1470
        });
1470
        });
1471
        cy.intercept("GET", "/api/v1/extended_attribute_types*", {
1471
        cy.intercept("GET", "/api/v1/erm/extended_attribute_types*", {
1472
            body: [],
1472
            body: [],
1473
            statusCode: 200,
1473
            statusCode: 200,
1474
        }).as("empty-additional-fields");
1474
        }).as("empty-additional-fields");
Lines 1477-1483 describe("Additional Fields operations", () => { Link Here
1477
        cy.visit("/cgi-bin/koha/erm/eholdings/local/packages/add");
1477
        cy.visit("/cgi-bin/koha/erm/eholdings/local/packages/add");
1478
        cy.get("#packages_add form #additional_fields").should("not.exist");
1478
        cy.get("#packages_add form #additional_fields").should("not.exist");
1479
1479
1480
        cy.intercept("GET", "/api/v1/extended_attribute_types*", {
1480
        cy.intercept("GET", "/api/v1/erm/extended_attribute_types*", {
1481
            body: eholdings_package_additional_fields,
1481
            body: eholdings_package_additional_fields,
1482
            statusCode: 200,
1482
            statusCode: 200,
1483
        }).as("existing-additional-fields");
1483
        }).as("existing-additional-fields");
Lines 1605-1611 describe("Additional Fields operations", () => { Link Here
1605
            body: vendors,
1605
            body: vendors,
1606
        });
1606
        });
1607
1607
1608
        cy.intercept("GET", "/api/v1/extended_attribute_types*", {
1608
        cy.intercept("GET", "/api/v1/erm/extended_attribute_types*", {
1609
            body: eholdings_package_additional_fields,
1609
            body: eholdings_package_additional_fields,
1610
            statusCode: 200,
1610
            statusCode: 200,
1611
        }).as("existing-additional-fields");
1611
        }).as("existing-additional-fields");
(-)a/t/db_dependent/api/v1/extended_attribute_types.t (-2 / +101 lines)
Lines 18-24 Link Here
18
use Modern::Perl;
18
use Modern::Perl;
19
19
20
use Test::NoWarnings;
20
use Test::NoWarnings;
21
use Test::More tests => 2;
21
use Test::More tests => 3;
22
use Test::Mojo;
22
use Test::Mojo;
23
23
24
use t::lib::TestBuilder;
24
use t::lib::TestBuilder;
Lines 133-135 subtest 'list() tests' => sub { Link Here
133
133
134
    $schema->storage->txn_rollback;
134
    $schema->storage->txn_rollback;
135
};
135
};
136
- 
136
137
subtest 'list_erm() tests' => sub {
138
139
    plan tests => 23;
140
141
    $schema->storage->txn_begin;
142
143
    Koha::AdditionalFields->search->delete;
144
145
    my $librarian = $builder->build_object(
146
        {
147
            class => 'Koha::Patrons',
148
            value => { flags => 2**3 }    # parameters
149
        }
150
    );
151
    my $password = 'thePassword123';
152
    $librarian->set_password( { password => $password, skip_validation => 1 } );
153
    my $userid = $librarian->userid;
154
155
    my $patron = $builder->build_object(
156
        {
157
            class => 'Koha::Patrons',
158
            value => { flags => 0 }
159
        }
160
    );
161
162
    $patron->set_password( { password => $password, skip_validation => 1 } );
163
    my $unauth_userid = $patron->userid;
164
165
    my $erm_patron = $builder->build_object(
166
        {
167
            class => 'Koha::Patrons',
168
            value => { flags => 28 }    # erm => 1
169
        }
170
    );
171
172
    $patron->set_password( { password => $password, skip_validation => 1 } );
173
    my $erm_userid = $patron->userid;
174
175
    ## Authorized user tests
176
    # No additional fields, so empty array should be returned
177
    $t->get_ok("//$userid:$password@/api/v1/erm/extended_attribute_types")->status_is(200)->json_is( [] );
178
179
    my $additional_field = $builder->build_object(
180
        {
181
            class => 'Koha::AdditionalFields',
182
            value => { tablename => 'aqinvoices', name => 'af_name' },
183
        }
184
    );
185
186
    # One aqinvoices additional_field created, none for 'erm' should get returned
187
    $t->get_ok("//$userid:$password@/api/v1/erm/extended_attribute_types")->status_is(200)->json_is( [] );
188
189
    my $erm_agreement_additional_field = $builder->build_object(
190
        {
191
            class => 'Koha::AdditionalFields',
192
            value => { tablename => 'erm_agreements', name => 'agreement_name' },
193
        }
194
    );
195
196
    my $erm_license_additional_field = $builder->build_object(
197
        {
198
            class => 'Koha::AdditionalFields',
199
            value => { tablename => 'erm_licenses', name => 'license_name' },
200
        }
201
    );
202
203
    $t->get_ok("//$userid:$password@/api/v1/erm/extended_attribute_types")->status_is(200)->json_is(
204
        [
205
            $erm_agreement_additional_field->to_api,
206
            $erm_license_additional_field->to_api,
207
        ]
208
    );
209
210
    # Filtering works, two existing additional fields returned for the queried table name
211
    $t->get_ok("//$userid:$password@/api/v1/erm/extended_attribute_types?resource_type=license")->status_is(200)
212
        ->json_is( [ $erm_license_additional_field->to_api ] );
213
214
    # Cannot retrieve attributes from other tables
215
    $t->get_ok("//$userid:$password@/api/v1/erm/extended_attribute_types?resource_type=order")->status_is(400)
216
        ->json_is(
217
        "/errors" => [ { message => "Not in enum list: license, agreement, package.", path => "/resource_type" } ] );
218
219
    # Warn on unsupported query parameter
220
    $t->get_ok("//$userid:$password@/api/v1/erm/extended_attribute_types?blah=blah")->status_is(400)
221
        ->json_is( [ { path => '/query/blah', message => 'Malformed query string' } ] );
222
223
    # erm only user
224
    $t->get_ok("//$userid:$password@/api/v1/erm/extended_attribute_types")->status_is(200)->json_is(
225
        [
226
            $erm_agreement_additional_field->to_api,
227
            $erm_license_additional_field->to_api,
228
        ]
229
    );
230
231
    # Unauthorized access
232
    $t->get_ok("//$unauth_userid:$password@/api/v1/extended_attribute_types")->status_is(403);
233
234
    $schema->storage->txn_rollback;
235
};

Return to bug 38446