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

(-)a/Koha/REST/V1/Biblios.pm (-1 / +62 lines)
Lines 22-28 use Mojo::Base 'Mojolicious::Controller'; Link Here
22
use Koha::Biblios;
22
use Koha::Biblios;
23
use Koha::Ratings;
23
use Koha::Ratings;
24
use Koha::RecordProcessor;
24
use Koha::RecordProcessor;
25
use C4::Biblio qw( DelBiblio );
25
use C4::Biblio qw( DelBiblio AddBiblio );
26
use C4::Search qw( FindDuplicate );
26
27
27
use List::MoreUtils qw( any );
28
use List::MoreUtils qw( any );
28
use MARC::Record::MiJ;
29
use MARC::Record::MiJ;
Lines 480-483 sub set_rating { Link Here
480
    };
481
    };
481
}
482
}
482
483
484
=head3 add
485
486
Controller function that handles creating a biblio object
487
488
=cut
489
490
sub add {
491
    my $c = shift->openapi->valid_input or return;
492
493
    try {
494
        my $body = $c->validation->param('Body');
495
496
        my $flavour = $c->validation->param('x-marc-schema');
497
        $flavour = C4::Context->preference('marcflavour') unless $flavour;
498
499
        my $record;
500
501
        my $frameworkcode = $c->validation->param('x-framework-id');
502
        if ( $c->req->headers->content_type =~ m/application\/marcxml\+xml/ ) {
503
            $record = MARC::Record->new_from_xml( $body, 'UTF-8', $flavour );
504
        } elsif ( $c->req->headers->content_type =~ m/application\/marc-in-json/ ) {
505
            $record = MARC::Record->new_from_mij_structure( $body );
506
        } elsif ( $c->req->headers->content_type =~ m/application\/marc/ ) {
507
            $record = MARC::Record->new_from_usmarc( $body );
508
        } else {
509
            return $c->render(
510
                status  => 406,
511
                openapi => [
512
                    "application/marcxml+xml",
513
                    "application/marc-in-json",
514
                    "application/marc"
515
                ]
516
            );
517
        }
518
519
        my ( $duplicatebiblionumber, $duplicatetitle );
520
            ( $duplicatebiblionumber, $duplicatetitle ) = FindDuplicate($record);
521
522
        my $confirm_not_duplicate = $c->validation->param('x-confirm-not-duplicate');
523
524
        return $c->render(
525
            status  => 400,
526
            openapi => {
527
                error => "Duplicate biblio $duplicatebiblionumber"
528
            }
529
        ) unless !$duplicatebiblionumber || $confirm_not_duplicate;
530
531
        my ( $biblionumber, $oldbibitemnum );
532
            ( $biblionumber, $oldbibitemnum ) = AddBiblio( $record, $frameworkcode );
533
534
        $c->render(
535
            status  => 200,
536
            openapi => { id => $biblionumber }
537
        );
538
    }
539
    catch {
540
        $c->unhandled_exception($_);
541
    };
542
}
543
483
1;
544
1;
(-)a/api/v1/swagger/paths/biblios.yaml (+57 lines)
Lines 1-4 Link Here
1
---
1
---
2
"/biblios":
3
  post:
4
    x-mojo-to: Biblios#add
5
    operationId: addBiblio
6
    tags:
7
      - biblios
8
    summary: Add biblio
9
    parameters:
10
      - name: Body
11
        in: body
12
        description: A JSON object or the Marc string describing a biblio
13
        required: true
14
        schema:
15
          type:
16
            - string
17
            - object
18
      - $ref: "../swagger.yaml#/parameters/framework_id_header"
19
      - $ref: "../swagger.yaml#/parameters/marc_schema_header"
20
      - $ref: "../swagger.yaml#/parameters/confirm_not_duplicate_header"
21
    produces:
22
      - application/json
23
    responses:
24
      "200":
25
        description: A biblio
26
      "400":
27
        description: Bad request
28
        schema:
29
          $ref: "../swagger.yaml#/definitions/error"
30
      "401":
31
        description: Authentication required
32
        schema:
33
          $ref: "../swagger.yaml#/definitions/error"
34
      "403":
35
        description: Access forbidden
36
        schema:
37
          $ref: "../swagger.yaml#/definitions/error"
38
      "406":
39
        description: Not acceptable
40
        schema:
41
          type: array
42
          description: Accepted content-types
43
          items:
44
            type: string
45
      "500":
46
        description: |
47
          Internal server error. Possible `error_code` attribute values:
48
49
          * `internal_server_error`
50
        schema:
51
          $ref: "../swagger.yaml#/definitions/error"
52
      "503":
53
        description: Under maintenance
54
        schema:
55
          $ref: "../swagger.yaml#/definitions/error"
56
    x-koha-authorization:
57
      permissions:
58
        editcatalogue: edit_catalogue
2
"/biblios/{biblio_id}":
59
"/biblios/{biblio_id}":
3
  get:
60
  get:
4
    x-mojo-to: Biblios#get
61
    x-mojo-to: Biblios#get
(-)a/api/v1/swagger/swagger.yaml (+24 lines)
Lines 137-142 paths: Link Here
137
    $ref: paths/auth.yaml#/~1auth~1identity_providers~1{identity_provider_id}~1domains
137
    $ref: paths/auth.yaml#/~1auth~1identity_providers~1{identity_provider_id}~1domains
138
  "/auth/identity_providers/{identity_provider_id}/domains/{identity_provider_domain_id}":
138
  "/auth/identity_providers/{identity_provider_id}/domains/{identity_provider_domain_id}":
139
    $ref: paths/auth.yaml#/~1auth~1identity_providers~1{identity_provider_id}~1domains~1{identity_provider_domain_id}
139
    $ref: paths/auth.yaml#/~1auth~1identity_providers~1{identity_provider_id}~1domains~1{identity_provider_domain_id}
140
  "/biblios":
141
    $ref: "./paths/biblios.yaml#/~1biblios"
140
  "/biblios/{biblio_id}":
142
  "/biblios/{biblio_id}":
141
    $ref: "./paths/biblios.yaml#/~1biblios~1{biblio_id}"
143
    $ref: "./paths/biblios.yaml#/~1biblios~1{biblio_id}"
142
  "/biblios/{biblio_id}/checkouts":
144
  "/biblios/{biblio_id}/checkouts":
Lines 336-341 parameters: Link Here
336
    name: agreement_period_id
338
    name: agreement_period_id
337
    required: true
339
    required: true
338
    type: integer
340
    type: integer
341
  framework_id_header:
342
    description: Framework id. Use when content type is not application/json
343
    name: x-framework-id
344
    in: header
345
    required: false
346
    type: string
347
  marc_schema_header:
348
    description: March schema. One of MARC21 or UNIMARC
349
    name: x-marc-schema
350
    in: header
351
    required: false
352
    type: string
353
    enum:
354
      - MARC21
355
      - UNIMARC
356
  confirm_not_duplicate_header:
357
    description: Confirm the posted element is not a duplicate
358
    name: x-confirm-not-duplicate
359
    in: header
360
    required: false
361
    type: integer
362
339
  identity_provider_id_pp:
363
  identity_provider_id_pp:
340
    description: Authentication provider internal identifier
364
    description: Authentication provider internal identifier
341
    in: path
365
    in: path
(-)a/t/db_dependent/api/v1/biblios.t (-2 / +430 lines)
Lines 20-26 use Modern::Perl; Link Here
20
use utf8;
20
use utf8;
21
use Encode;
21
use Encode;
22
22
23
use Test::More tests => 8;
23
use Test::More tests => 9;
24
use Test::MockModule;
24
use Test::MockModule;
25
use Test::Mojo;
25
use Test::Mojo;
26
use Test::Warn;
26
use Test::Warn;
Lines 713-715 subtest 'set_rating() tests' => sub { Link Here
713
    $schema->storage->txn_rollback;
713
    $schema->storage->txn_rollback;
714
714
715
};
715
};
716
- 
716
717
718
subtest 'post() tests' => sub {
719
720
    plan tests => 13;
721
722
    $schema->storage->txn_begin;
723
724
    my $patron = $builder->build_object(
725
        {
726
            class => 'Koha::Patrons',
727
            value => { flags => 0 } # no permissions
728
        }
729
    );
730
    my $password = 'thePassword123';
731
    $patron->set_password( { password => $password, skip_validation => 1 } );
732
    my $userid = $patron->userid;
733
734
    my $frameworkcode = 'BKS';
735
    my $marcxml = q|<?xml version="1.0" encoding="UTF-8"?>
736
<record
737
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
738
    xsi:schemaLocation="http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd"
739
    xmlns="http://www.loc.gov/MARC21/slim">
740
741
  <leader>01102pam a2200289 a 7500</leader>
742
  <controlfield tag="001">2504398</controlfield>
743
  <controlfield tag="005">20200421093816.0</controlfield>
744
  <controlfield tag="008">920610s1993    caub         s001 0 eng  </controlfield>
745
  <datafield tag="010" ind1=" " ind2=" ">
746
    <subfield code="a">   92021731 </subfield>
747
  </datafield>
748
  <datafield tag="020" ind1=" " ind2=" ">
749
    <subfield code="a">05200784381 (Test marcxml)</subfield>
750
  </datafield>
751
  <datafield tag="020" ind1=" " ind2=" ">
752
    <subfield code="a">05200784461 (Test marcxml)</subfield>
753
  </datafield>
754
  <datafield tag="040" ind1=" " ind2=" ">
755
    <subfield code="a">DLC</subfield>
756
    <subfield code="c">DLC</subfield>
757
    <subfield code="d">DLC</subfield>
758
  </datafield>
759
  <datafield tag="041" ind1="0" ind2=" ">
760
    <subfield code="a">enggrc</subfield>
761
  </datafield>
762
  <datafield tag="050" ind1="0" ind2="0">
763
    <subfield code="a">PA522</subfield>
764
    <subfield code="b">.M38 1993</subfield>
765
  </datafield>
766
  <datafield tag="082" ind1="0" ind2="0">
767
    <subfield code="a">480</subfield>
768
    <subfield code="2">20</subfield>
769
  </datafield>
770
  <datafield tag="100" ind1="1" ind2=" ">
771
    <subfield code="a">Mastronarde, Donald J.</subfield>
772
    <subfield code="9">389</subfield>
773
  </datafield>
774
  <datafield tag="245" ind1="1" ind2="0">
775
    <subfield code="a">Introduction to Attic Greek (Using marcxml) /</subfield>
776
    <subfield code="c">Donald J. Mastronarde.</subfield>
777
  </datafield>
778
  <datafield tag="260" ind1=" " ind2=" ">
779
    <subfield code="a">Berkeley :</subfield>
780
    <subfield code="b">University of California Press,</subfield>
781
    <subfield code="c">c1993.</subfield>
782
  </datafield>
783
  <datafield tag="300" ind1=" " ind2=" ">
784
    <subfield code="a">ix, 425 p. :</subfield>
785
    <subfield code="b">maps ;</subfield>
786
    <subfield code="c">26 cm.</subfield>
787
  </datafield>
788
  <datafield tag="500" ind1=" " ind2=" ">
789
    <subfield code="a">Includes index.</subfield>
790
  </datafield>
791
  <datafield tag="650" ind1=" " ind2="0">
792
    <subfield code="a">Attic Greek dialect</subfield>
793
    <subfield code="9">7</subfield>
794
  </datafield>
795
  <datafield tag="856" ind1="4" ind2="2">
796
    <subfield code="3">Contributor biographical information</subfield>
797
    <subfield code="u">http://www.loc.gov/catdir/bios/ucal051/92021731.html</subfield>
798
  </datafield>
799
  <datafield tag="856" ind1="4" ind2="2">
800
    <subfield code="3">Publisher description</subfield>
801
    <subfield code="u">http://www.loc.gov/catdir/description/ucal041/92021731.html</subfield>
802
  </datafield>
803
  <datafield tag="906" ind1=" " ind2=" ">
804
    <subfield code="a">7</subfield>
805
    <subfield code="b">cbc</subfield>
806
    <subfield code="c">orignew</subfield>
807
    <subfield code="d">1</subfield>
808
    <subfield code="e">ocip</subfield>
809
    <subfield code="f">19</subfield>
810
    <subfield code="g">y-gencatlg</subfield>
811
  </datafield>
812
  <datafield tag="942" ind1=" " ind2=" ">
813
    <subfield code="2">ddc</subfield>
814
    <subfield code="c">BK</subfield>
815
  </datafield>
816
  <datafield tag="955" ind1=" " ind2=" ">
817
    <subfield code="a">pc05 to ea00 06-11-92; ea04 to SCD 06-11-92; fd11 06-11-92 (PA522.M...); fr21 06-12-92; fs62 06-15-92; CIP ver. pv07 11-12-93</subfield>
818
  </datafield>
819
  <datafield tag="999" ind1=" " ind2=" ">
820
    <subfield code="c">3</subfield>
821
    <subfield code="d">3</subfield>
822
  </datafield>
823
</record>|;
824
825
    my $mij = q|{
826
  "fields": [
827
    {
828
      "001": "2504398"
829
    },
830
    {
831
      "005": "20200421093816.0"
832
    },
833
    {
834
      "008": "920610s1993    caub         s001 0 eng  "
835
    },
836
    {
837
      "010": {
838
        "ind1": " ",
839
        "subfields": [
840
          {
841
            "a": "   92021731 "
842
          }
843
        ],
844
        "ind2": " "
845
      }
846
    },
847
    {
848
      "020": {
849
        "subfields": [
850
          {
851
            "a": "05200784382 (Test mij)"
852
          }
853
        ],
854
        "ind2": " ",
855
        "ind1": " "
856
      }
857
    },
858
    {
859
      "020": {
860
        "subfields": [
861
          {
862
            "a": "05200784462 (Test mij)"
863
          }
864
        ],
865
        "ind1": " ",
866
        "ind2": " "
867
      }
868
    },
869
    {
870
      "040": {
871
        "subfields": [
872
          {
873
            "a": "DLC"
874
          },
875
          {
876
            "c": "DLC"
877
          },
878
          {
879
            "d": "DLC"
880
          }
881
        ],
882
        "ind2": " ",
883
        "ind1": " "
884
      }
885
    },
886
    {
887
      "041": {
888
        "ind2": " ",
889
        "subfields": [
890
          {
891
            "a": "enggrc"
892
          }
893
        ],
894
        "ind1": "0"
895
      }
896
    },
897
    {
898
      "050": {
899
        "subfields": [
900
          {
901
            "a": "PA522"
902
          },
903
          {
904
            "b": ".M38 1993"
905
          }
906
        ],
907
        "ind1": "0",
908
        "ind2": "0"
909
      }
910
    },
911
    {
912
      "082": {
913
        "subfields": [
914
          {
915
            "a": "480"
916
          },
917
          {
918
            "2": "20"
919
          }
920
        ],
921
        "ind2": "0",
922
        "ind1": "0"
923
      }
924
    },
925
    {
926
      "100": {
927
        "ind2": " ",
928
        "subfields": [
929
          {
930
            "a": "Mastronarde, Donald J."
931
          },
932
          {
933
            "9": "389"
934
          }
935
        ],
936
        "ind1": "1"
937
      }
938
    },
939
    {
940
      "245": {
941
        "ind1": "1",
942
        "subfields": [
943
          {
944
            "a": "Introduction to Attic Greek  (Using mij) /"
945
          },
946
          {
947
            "c": "Donald J. Mastronarde."
948
          }
949
        ],
950
        "ind2": "0"
951
      }
952
    },
953
    {
954
      "260": {
955
        "subfields": [
956
          {
957
            "a": "Berkeley :"
958
          },
959
          {
960
            "b": "University of California Press,"
961
          },
962
          {
963
            "c": "c1993."
964
          }
965
        ],
966
        "ind2": " ",
967
        "ind1": " "
968
      }
969
    },
970
    {
971
      "300": {
972
        "ind1": " ",
973
        "subfields": [
974
          {
975
            "a": "ix, 425 p. :"
976
          },
977
          {
978
            "b": "maps ;"
979
          },
980
          {
981
            "c": "26 cm."
982
          }
983
        ],
984
        "ind2": " "
985
      }
986
    },
987
    {
988
      "500": {
989
        "subfields": [
990
          {
991
            "a": "Includes index."
992
          }
993
        ],
994
        "ind1": " ",
995
        "ind2": " "
996
      }
997
    },
998
    {
999
      "650": {
1000
        "subfields": [
1001
          {
1002
            "a": "Attic Greek dialect"
1003
          },
1004
          {
1005
            "9": "7"
1006
          }
1007
        ],
1008
        "ind2": "0",
1009
        "ind1": " "
1010
      }
1011
    },
1012
    {
1013
      "856": {
1014
        "subfields": [
1015
          {
1016
            "3": "Contributor biographical information"
1017
          },
1018
          {
1019
            "u": "http://www.loc.gov/catdir/bios/ucal051/92021731.html"
1020
          }
1021
        ],
1022
        "ind2": "2",
1023
        "ind1": "4"
1024
      }
1025
    },
1026
    {
1027
      "856": {
1028
        "ind1": "4",
1029
        "subfields": [
1030
          {
1031
            "3": "Publisher description"
1032
          },
1033
          {
1034
            "u": "http://www.loc.gov/catdir/description/ucal041/92021731.html"
1035
          }
1036
        ],
1037
        "ind2": "2"
1038
      }
1039
    },
1040
    {
1041
      "906": {
1042
        "subfields": [
1043
          {
1044
            "a": "7"
1045
          },
1046
          {
1047
            "b": "cbc"
1048
          },
1049
          {
1050
            "c": "orignew"
1051
          },
1052
          {
1053
            "d": "1"
1054
          },
1055
          {
1056
            "e": "ocip"
1057
          },
1058
          {
1059
            "f": "19"
1060
          },
1061
          {
1062
            "g": "y-gencatlg"
1063
          }
1064
        ],
1065
        "ind1": " ",
1066
        "ind2": " "
1067
      }
1068
    },
1069
    {
1070
      "942": {
1071
        "subfields": [
1072
          {
1073
            "2": "ddc"
1074
          },
1075
          {
1076
            "c": "BK"
1077
          }
1078
        ],
1079
        "ind2": " ",
1080
        "ind1": " "
1081
      }
1082
    },
1083
    {
1084
      "955": {
1085
        "subfields": [
1086
          {
1087
            "a": "pc05 to ea00 06-11-92; ea04 to SCD 06-11-92; fd11 06-11-92 (PA522.M...); fr21 06-12-92; fs62 06-15-92; CIP ver. pv07 11-12-93"
1088
          }
1089
        ],
1090
        "ind2": " ",
1091
        "ind1": " "
1092
      }
1093
    },
1094
    {
1095
      "999": {
1096
        "subfields": [
1097
          {
1098
            "c": "3"
1099
          },
1100
          {
1101
            "d": "3"
1102
          }
1103
        ],
1104
        "ind1": " ",
1105
        "ind2": " "
1106
      }
1107
    }
1108
  ],
1109
  "leader": "01102pam a2200289 a 8500"
1110
}|;
1111
    my $marc = q|01102pam a2200289 a 9500001000800000005001700008008004100025010001700066020002800083020003500111040001800146041001100164050002100175082001200196100003200208245005800240260005600298300003300354500002000387650002700407856009500434856008700529906004500616942001200661955013000673999000900803250439820200421093816.0920610s1993    caub         s001 0 eng    a   92021731   a05200784383 (Test usmarc)  a05200784463 (Test usmarc)  aDLCcDLCdDLC0 aenggrc00aPA522b.M38 199300a4802201 aMastronarde, Donald J.938910aIntroduction to Attic Greek  (Using usmarc) /cDonald J. Mastronarde.  aBerkeley :bUniversity of California Press,cc1993.  aix, 425 p. :bmaps ;c26 cm.  aIncludes index. 0aAttic Greek dialect97423Contributor biographical informationuhttp://www.loc.gov/catdir/bios/ucal051/92021731.html423Publisher descriptionuhttp://www.loc.gov/catdir/description/ucal041/92021731.html  a7bcbccorignewd1eocipf19gy-gencatlg  2ddccBK  apc05 to ea00 06-11-92; ea04 to SCD 06-11-92; fd11 06-11-92 (PA522.M...); fr21 06-12-92; fs62 06-15-92; CIP ver. pv07 11-12-93  c3d3|;
1112
1113
    $t->post_ok("//$userid:$password@/api/v1/biblios")
1114
      ->status_is(403, 'Not enough permissions makes it return the right code');
1115
1116
    # Add permissions
1117
    $builder->build(
1118
        {
1119
            source => 'UserPermission',
1120
            value  => {
1121
                borrowernumber => $patron->borrowernumber,
1122
                module_bit     => 9,
1123
                code           => 'edit_catalogue'
1124
            }
1125
        }
1126
    );
1127
1128
    $t->post_ok("//$userid:$password@/api/v1/biblios" => {'Content-Type' => 'application/marcxml+xml', 'x-framework-id' => $frameworkcode, "x-march-schema" => 'INVALID'})
1129
      ->status_is(400, 'Invalid header x-marc-schema');
1130
1131
    $t->post_ok("//$userid:$password@/api/v1/biblios" => {'Content-Type' => 'application/marcxml+xml', 'x-framework-id' => $frameworkcode} => $marcxml)
1132
      ->status_is(200)
1133
      ->json_has('/id');
1134
1135
    $t->post_ok("//$userid:$password@/api/v1/biblios" => {'Content-Type' => 'application/marc-in-json', 'x-framework-id' => $frameworkcode, 'x-confirm-not-duplicate' => 1} => $mij)
1136
      ->status_is(200)
1137
      ->json_has('/id');
1138
1139
    $t->post_ok("//$userid:$password@/api/v1/biblios" => {'Content-Type' => 'application/marc', 'x-framework-id' => $frameworkcode} => $marc)
1140
      ->status_is(200)
1141
      ->json_has('/id');
1142
1143
    $schema->storage->txn_rollback;
1144
};

Return to bug 31800