From c3b5ad3a65dc4a77b76270c5037606c674bf8f53 Mon Sep 17 00:00:00 2001 From: Agustin Moyano Date: Thu, 2 Feb 2023 21:07:55 -0300 Subject: [PATCH] Bug 32607: Add CRUD for import sources This patch adds vue components to create, read, update and delete import sources To test: 1. apply patches 2. updatedatabase 3. yarn build_js 4. go to Administration -> Import sources 5. play around with the ui and create, update, remove and search import sources 6. Sign off ;) --- Koha/ImportSource.pm | 56 +++ Koha/ImportSources.pm | 51 +++ Koha/REST/V1/ImportSources.pm | 141 ++++++ Koha/Schema/Result/ImportSource.pm | 8 + admin/import-sources.pl | 38 ++ api/v1/swagger/definitions/import_source.yaml | 13 + api/v1/swagger/paths/import_sources.yaml | 237 ++++++++++ api/v1/swagger/swagger.yaml | 15 + .../prog/en/modules/admin/admin-home.tt | 2 + .../prog/en/modules/admin/import-sources.tt | 37 ++ .../prog/js/vue/components/Dialog.vue | 20 +- .../vue/components/import-sources/ISEdit.vue | 99 ++++ .../vue/components/import-sources/ISList.vue | 82 ++++ .../vue/components/import-sources/ISMain.vue | 28 ++ .../js/vue/components/shared/Breadcrumbs.vue | 41 ++ .../prog/js/vue/components/shared/Dialog.vue | 53 +++ .../prog/js/vue/components/shared/Form.vue | 140 ++++++ .../js/vue/components/shared/KohaTable.vue | 433 ++++++++++++++++++ .../prog/js/vue/components/shared/Menu.vue | 57 +++ .../js/vue/components/shared/MenuItem.vue | 41 ++ .../prog/js/vue/components/shared/Page.vue | 48 ++ .../intranet-tmpl/prog/js/vue/i18n/index.js | 9 + .../prog/js/vue/import-source/main.ts | 77 ++++ .../prog/js/vue/import-source/model.js | 83 ++++ .../prog/js/vue/import-source/router.js | 12 + .../prog/js/vue/import-source/tree.js | 31 ++ .../prog/js/vue/inputs/autocomplete.js | 199 ++++++++ .../intranet-tmpl/prog/js/vue/inputs/index.js | 5 + .../intranet-tmpl/prog/js/vue/stores/main.js | 60 ++- .../intranet-tmpl/prog/js/vue/stores/menu.js | 100 ++++ .../intranet-tmpl/prog/js/vue/stores/model.js | 51 +++ .../intranet-tmpl/prog/js/vue/stores/table.js | 96 ++++ package.json | 14 +- t/db_dependent/Koha/ImportSources.t | 44 ++ t/db_dependent/api/v1/import_sources.t | 318 +++++++++++++ webpack.config.js | 1 + 36 files changed, 2710 insertions(+), 30 deletions(-) create mode 100644 Koha/ImportSource.pm create mode 100644 Koha/ImportSources.pm create mode 100644 Koha/REST/V1/ImportSources.pm create mode 100644 admin/import-sources.pl create mode 100644 api/v1/swagger/definitions/import_source.yaml create mode 100644 api/v1/swagger/paths/import_sources.yaml create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/admin/import-sources.tt create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/import-sources/ISEdit.vue create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/import-sources/ISList.vue create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/import-sources/ISMain.vue create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/shared/Breadcrumbs.vue create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/shared/Dialog.vue create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/shared/Form.vue create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/shared/KohaTable.vue create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/shared/Menu.vue create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/shared/MenuItem.vue create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/components/shared/Page.vue create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/i18n/index.js create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/import-source/main.ts create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/import-source/model.js create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/import-source/router.js create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/import-source/tree.js create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/inputs/autocomplete.js create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/inputs/index.js create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/stores/menu.js create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/stores/model.js create mode 100644 koha-tmpl/intranet-tmpl/prog/js/vue/stores/table.js create mode 100644 t/db_dependent/Koha/ImportSources.t create mode 100644 t/db_dependent/api/v1/import_sources.t diff --git a/Koha/ImportSource.pm b/Koha/ImportSource.pm new file mode 100644 index 0000000000..b23fc95422 --- /dev/null +++ b/Koha/ImportSource.pm @@ -0,0 +1,56 @@ +package Koha::ImportSource; + +# This file is part of Koha. +# +# Copyright 2020 Koha Development Team +# +# 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 +# + +use Modern::Perl; + +use base qw(Koha::Object); + +=head1 NAME + +Koha::ImportSource - Koha ImportSource Object class + +=head1 API + +=head2 Class Methods + +=head3 patron + +my $patron = $import_source->patron + +Return the patron for this import source + +=cut + +sub patron { + my ($self) = @_; + + my $patron_rs = $self->_result->patron; + return Koha::Patron->_new_from_dbic($patron_rs); +} + +=head3 _type + +=cut + +sub _type { + return 'ImportSource'; +} + +1; \ No newline at end of file diff --git a/Koha/ImportSources.pm b/Koha/ImportSources.pm new file mode 100644 index 0000000000..1cdca37b1b --- /dev/null +++ b/Koha/ImportSources.pm @@ -0,0 +1,51 @@ +package Koha::ImportSources; + +# This file is part of Koha. +# +# Copyright 2020 Koha Development Team +# +# 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 +# + +use Modern::Perl; + +use base qw(Koha::Objects); + +use Koha::ImportSource; + +=head1 NAME + +Koha::ImportSources - Koha ImportSources Object class + +=head1 API + +=head2 Class Methods + +=head3 _type + +=cut + +sub _type { + return 'ImportSource'; +} + +=head3 object_class + +=cut + +sub object_class { + return 'Koha::ImportSource'; +} + +1; \ No newline at end of file diff --git a/Koha/REST/V1/ImportSources.pm b/Koha/REST/V1/ImportSources.pm new file mode 100644 index 0000000000..b77e2cadca --- /dev/null +++ b/Koha/REST/V1/ImportSources.pm @@ -0,0 +1,141 @@ +package Koha::REST::V1::ImportSources; + +# Copyright 2023 Theke Solutions +# +# 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 . + +use Modern::Perl; + +use Mojo::Base 'Mojolicious::Controller'; + +use Koha::ImportSources; + +use Try::Tiny qw( catch try ); + +=head1 API + +=head2 Methods + +=head3 list + +=cut + +sub list { + my $c = shift->openapi->valid_input or return; + + return try { + my $import_sources_set = Koha::ImportSources->new; + my $import_sources = $c->objects->search( $import_sources_set ); + return $c->render( status => 200, openapi => $import_sources ); + } + catch { + $c->unhandled_exception($_); + }; +} + +=head3 get + +=cut + +sub get { + my $c = shift->openapi->valid_input or return; + + return try { + my $import_sources_set = Koha::ImportSources->new; + my $import_source = $c->objects->find( $import_sources_set, $c->validation->param('import_source_id') ); + unless ($import_source) { + return $c->render( status => 404, + openapi => { error => "Import source not found" } ); + } + + return $c->render( status => 200, openapi => $import_source ); + } + catch { + $c->unhandled_exception($_); + }; +} + +=head3 add + +=cut + +sub add { + my $c = shift->openapi->valid_input or return; + + return try { + my $import_source = Koha::ImportSource->new_from_api( $c->validation->param('body') ); + $import_source->store; + $c->res->headers->location( $c->req->url->to_string . '/' . $import_source->import_source_id ); + return $c->render( + status => 201, + openapi => $import_source->to_api + ); + } + catch { + $c->unhandled_exception($_); + }; +} + +=head3 update + +=cut + +sub update { + my $c = shift->openapi->valid_input or return; + + my $import_source = Koha::ImportSources->find( $c->validation->param('import_source_id') ); + + if ( not defined $import_source ) { + return $c->render( status => 404, + openapi => { error => "Object not found" } ); + } + + return try { + $import_source->set_from_api( $c->validation->param('body') ); + $import_source->store(); + return $c->render( status => 200, openapi => $import_source->to_api ); + } + catch { + $c->unhandled_exception($_); + }; +} + +=head3 delete + +=cut + +sub delete { + my $c = shift->openapi->valid_input or return; + + my $import_source = Koha::ImportSources->find( $c->validation->param('import_source_id') ); + if ( not defined $import_source ) { + return $c->render( status => 404, + openapi => { error => "Object not found" } ); + } + + return try { + $import_source->delete; + return $c->render( + status => 204, + openapi => q{} + ); + } + catch { + $c->unhandled_exception($_); + }; +} + +1; diff --git a/Koha/Schema/Result/ImportSource.pm b/Koha/Schema/Result/ImportSource.pm index a902cb0892..83be473817 100644 --- a/Koha/Schema/Result/ImportSource.pm +++ b/Koha/Schema/Result/ImportSource.pm @@ -86,4 +86,12 @@ __PACKAGE__->belongs_to( # You can replace this text with custom code or comments, and it will be preserved on regeneration + +sub koha_object_class { + 'Koha::ImportSource'; +} +sub koha_objects_class { + 'Koha::ImportSources'; +} + 1; diff --git a/admin/import-sources.pl b/admin/import-sources.pl new file mode 100644 index 0000000000..c23c53270a --- /dev/null +++ b/admin/import-sources.pl @@ -0,0 +1,38 @@ +#!/usr/bin/perl + +# Copyright 2023 Theke Solutions +# +# 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 . + +use Modern::Perl; + +use CGI qw ( -utf8 ); +use C4::Auth qw( get_template_and_user ); +use C4::Output qw( output_html_with_http_headers ); +use Koha::Plugins; + +my $query = CGI->new; + +my ( $template, $loggedinuser, $cookie ) = get_template_and_user( + { + template_name => "admin/import-sources.tt", + query => $query, + type => "intranet", + flagsrequired => { parameters => 'manage_import_sources' }, + } +); + +output_html_with_http_headers $query, $cookie, $template->output; diff --git a/api/v1/swagger/definitions/import_source.yaml b/api/v1/swagger/definitions/import_source.yaml new file mode 100644 index 0000000000..b7d3555d1d --- /dev/null +++ b/api/v1/swagger/definitions/import_source.yaml @@ -0,0 +1,13 @@ +--- +type: object +properties: + import_source_id: + type: integer + description: internally assigned import source identifier + readOnly: true + name: + description: import source name + type: string + patron_id: + description: linked patron identifier + type: integer diff --git a/api/v1/swagger/paths/import_sources.yaml b/api/v1/swagger/paths/import_sources.yaml new file mode 100644 index 0000000000..fc18fd4db3 --- /dev/null +++ b/api/v1/swagger/paths/import_sources.yaml @@ -0,0 +1,237 @@ +/import_sources: + get: + x-mojo-to: ImportSources#list + operationId: listImportSources + summary: List import sources + tags: + - import_sources + parameters: + - $ref: "../swagger.yaml#/parameters/match" + - $ref: "../swagger.yaml#/parameters/order_by" + - $ref: "../swagger.yaml#/parameters/page" + - $ref: "../swagger.yaml#/parameters/per_page" + - $ref: "../swagger.yaml#/parameters/q_param" + - $ref: "../swagger.yaml#/parameters/q_body" + - $ref: "../swagger.yaml#/parameters/q_header" + - $ref: "../swagger.yaml#/parameters/request_id_header" + consumes: + - application/json + produces: + - application/json + responses: + "200": + description: A list of import sources + "400": + description: Missing or wrong parameters + schema: + $ref: "../swagger.yaml#/definitions/error" + "401": + description: Authentication required + schema: + $ref: "../swagger.yaml#/definitions/error" + "403": + description: Not allowed + schema: + $ref: "../swagger.yaml#/definitions/error" + "500": + description: | + Internal server error. Possible `error_code` attribute values: + + * `internal_server_error` + schema: + $ref: "../swagger.yaml#/definitions/error" + "503": + description: Under maintenance + schema: + $ref: "../swagger.yaml#/definitions/error" + x-koha-authorization: + permissions: + parameters: manage_import_sources + post: + x-mojo-to: ImportSources#add + operationId: addImportSources + summary: Add an import source + tags: + - import_sources + parameters: + - name: body + in: body + description: A JSON object containing informations about the new import source + required: true + schema: + $ref: "../swagger.yaml#/definitions/import_source" + consumes: + - application/json + produces: + - application/json + responses: + "201": + description: An import source + "400": + description: Missing or wrong parameters + schema: + $ref: "../swagger.yaml#/definitions/error" + "401": + description: Authentication required + schema: + $ref: "../swagger.yaml#/definitions/error" + "403": + description: Not allowed + schema: + $ref: "../swagger.yaml#/definitions/error" + "500": + description: | + Internal server error. Possible `error_code` attribute values: + + * `internal_server_error` + schema: + $ref: "../swagger.yaml#/definitions/error" + "503": + description: Under maintenance + schema: + $ref: "../swagger.yaml#/definitions/error" + x-koha-authorization: + permissions: + parameters: manage_import_sources +"/import_sources/{import_source_id}": + get: + x-mojo-to: ImportSources#get + operationId: getImportSources + summary: Get an import source + tags: + - import_sources + parameters: + - $ref: "../swagger.yaml#/parameters/import_source_id_pp" + consumes: + - application/json + produces: + - application/json + responses: + "200": + description: An import source + "400": + description: Missing or wrong parameters + schema: + $ref: "../swagger.yaml#/definitions/error" + "401": + description: Authentication required + schema: + $ref: "../swagger.yaml#/definitions/error" + "403": + description: Not allowed + schema: + $ref: "../swagger.yaml#/definitions/error" + "404": + description: Not found + schema: + $ref: "../swagger.yaml#/definitions/error" + "500": + description: | + Internal server error. Possible `error_code` attribute values: + + * `internal_server_error` + schema: + $ref: "../swagger.yaml#/definitions/error" + "503": + description: Under maintenance + schema: + $ref: "../swagger.yaml#/definitions/error" + x-koha-authorization: + permissions: + parameters: manage_import_sources + put: + x-mojo-to: ImportSources#update + operationId: updateImportSources + summary: Update an import source + tags: + - import_sources + parameters: + - $ref: "../swagger.yaml#/parameters/import_source_id_pp" + - name: body + in: body + description: A JSON object containing informations about the new import source + required: true + schema: + $ref: "../swagger.yaml#/definitions/import_source" + consumes: + - application/json + produces: + - application/json + responses: + "200": + description: An import source + "400": + description: Missing or wrong parameters + schema: + $ref: "../swagger.yaml#/definitions/error" + "401": + description: Authentication required + schema: + $ref: "../swagger.yaml#/definitions/error" + "403": + description: Not allowed + schema: + $ref: "../swagger.yaml#/definitions/error" + "404": + description: Not found + schema: + $ref: "../swagger.yaml#/definitions/error" + "500": + description: | + Internal server error. Possible `error_code` attribute values: + + * `internal_server_error` + schema: + $ref: "../swagger.yaml#/definitions/error" + "503": + description: Under maintenance + schema: + $ref: "../swagger.yaml#/definitions/error" + x-koha-authorization: + permissions: + parameters: manage_import_sources + delete: + x-mojo-to: ImportSources#delete + operationId: deleteImportSources + summary: Delete an import source + tags: + - import_sources + parameters: + - $ref: "../swagger.yaml#/parameters/import_source_id_pp" + consumes: + - application/json + produces: + - application/json + responses: + "204": + description: Deleted + "400": + description: Missing or wrong parameters + schema: + $ref: "../swagger.yaml#/definitions/error" + "401": + description: Authentication required + schema: + $ref: "../swagger.yaml#/definitions/error" + "403": + description: Not allowed + schema: + $ref: "../swagger.yaml#/definitions/error" + "404": + description: Not found + schema: + $ref: "../swagger.yaml#/definitions/error" + "500": + description: | + Internal server error. Possible `error_code` attribute values: + + * `internal_server_error` + schema: + $ref: "../swagger.yaml#/definitions/error" + "503": + description: Under maintenance + schema: + $ref: "../swagger.yaml#/definitions/error" + x-koha-authorization: + permissions: + parameters: manage_import_sources \ No newline at end of file diff --git a/api/v1/swagger/swagger.yaml b/api/v1/swagger/swagger.yaml index 479c4d710b..327e244f52 100644 --- a/api/v1/swagger/swagger.yaml +++ b/api/v1/swagger/swagger.yaml @@ -54,6 +54,8 @@ definitions: $ref: ./definitions/import_batch_profiles.yaml import_record_match: $ref: ./definitions/import_record_match.yaml + import_source: + $ref: ./definitions/import_source.yaml invoice: $ref: ./definitions/invoice.yaml item: @@ -235,6 +237,10 @@ paths: $ref: ./paths/import_batch_profiles.yaml#/~1import_batch_profiles "/import_batch_profiles/{import_batch_profile_id}": $ref: "./paths/import_batch_profiles.yaml#/~1import_batch_profiles~1{import_batch_profile_id}" + /import_sources: + $ref: ./paths/import_sources.yaml#/~1import_sources + "/import_sources/{import_source_id}": + $ref: ./paths/import_sources.yaml#/~1import_sources~1{import_source_id} /items: $ref: ./paths/items.yaml#/~1items "/items/{item_id}": @@ -434,6 +440,12 @@ parameters: name: import_record_id required: true type: integer + import_source_id_pp: + description: Internal import source identifier + in: path + name: import_source_id + required: true + type: integer item_id_pp: description: Internal item identifier in: path @@ -724,6 +736,9 @@ tags: - description: "Manage item groups\n" name: item_groups x-displayName: Item groups + - description: "Manage import sources\n" + name: import_sources + x-displayName: Import source - description: "Manage items\n" name: items x-displayName: Items diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt index 0e83b36721..71c9f89f23 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt @@ -211,6 +211,8 @@
Search engine configuration (Elasticsearch)
Manage indexes, facets, and their mappings to MARC fields and subfields
[% END %] +
Import sources
+
Define sources to import from
[% END %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/import-sources.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/import-sources.tt new file mode 100644 index 0000000000..63fd41f541 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/import-sources.tt @@ -0,0 +1,37 @@ +[% USE raw %] +[% USE To %] +[% USE Asset %] +[% USE KohaDates %] +[% USE TablesSettings %] +[% USE AuthorisedValues %] +[% SET footerjs = 1 %] +[% PROCESS 'i18n.inc' %] +[% INCLUDE 'doc-head-open.inc' %] + + Import sources › Koha + +[% INCLUDE 'doc-head-close.inc' %] + + + +[% WRAPPER 'header.inc' %] + [% INCLUDE 'erm-search.inc' %] +[% END %] + +
+ +[% MACRO jsinclude BLOCK %] + [% INCLUDE 'calendar.inc' %] + [% INCLUDE 'datatables.inc' %] + [% INCLUDE 'columns_settings.inc' %] + [% INCLUDE 'js-patron-format.inc' %] + [% INCLUDE 'js-date-format.inc' %] + + + + [% Asset.js("js/vue/dist/import-source.js") | $raw %] + +[% END %] +[% INCLUDE 'intranet-bottom.inc' %] diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Dialog.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Dialog.vue index ae336ce1dd..1561779789 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Dialog.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Dialog.vue @@ -1,8 +1,16 @@