1 package OpenILS::Application::Cat::Authority;
2 use strict; use warnings;
3 use base qw/OpenILS::Application/;
4 use OpenILS::Utils::CStoreEditor q/:funcs/;
5 use OpenILS::Application::Cat::AuthCommon;
6 use OpenSRF::Utils::Logger qw($logger);
7 use OpenILS::Application::AppUtils;
8 use OpenILS::Utils::Fieldmapper;
9 use OpenILS::Const qw/:const/;
11 my $U = 'OpenILS::Application::AppUtils';
12 my $MARC_NAMESPACE = 'http://www.loc.gov/MARC21/slim';
15 # generate a MARC XML document from a MARC XML string
18 my $marc_doc = XML::LibXML->new->parse_string($xml);
19 $marc_doc->documentElement->setNamespace($MARC_NAMESPACE, 'marc', 1);
20 $marc_doc->documentElement->setNamespace($MARC_NAMESPACE);
25 __PACKAGE__->register_method(
26 method => 'import_authority_record',
27 api_name => 'open-ils.cat.authority.record.import',
30 sub import_authority_record {
31 my($self, $conn, $auth, $marc_xml, $source) = @_;
32 my $e = new_editor(authtoken=>$auth, xact=>1);
33 return $e->die_event unless $e->checkauth;
34 return $e->die_event unless $e->allowed('CREATE_AUTHORITY_RECORD');
35 my $rec = OpenILS::Application::Cat::AuthCommon->
36 import_authority_record($e, $marc_xml, $source);
37 $e->commit unless $U->event_code($rec);
41 __PACKAGE__->register_method(
42 method => 'create_authority_record_from_bib_field',
43 api_name => 'open-ils.cat.authority.record.create_from_bib',
45 desc => q/Create an authority record entry from a field in a bibliographic record/,
47 @param field A hash representing the field to control, consisting of: { tag: string, ind1: string, ind2: string, subfields: [ [code, value] ... ] }
48 @param identifier A MARC control number identifier
49 @param authtoken A valid authentication token
50 @returns The new record object
54 __PACKAGE__->register_method(
55 method => 'create_authority_record_from_bib_field',
56 api_name => 'open-ils.cat.authority.record.create_from_bib.readonly',
58 desc => q/Creates MARCXML for an authority record entry from a field in a bibliographic record/,
60 @param field A hash representing the field to control, consisting of: { tag: string, ind1: string, ind2: string, subfields: [ [code, value] ... ] }
61 @param identifier A MARC control number identifier
62 @returns The MARCXML for the authority record
66 sub create_authority_record_from_bib_field {
67 my($self, $conn, $field, $cni, $auth) = @_;
69 # Control number identifier should have been passed in
74 # Change the first character of the incoming bib field tag to a '1'
75 # for use in our authority record; close enough for now?
76 my $tag = $field->{'tag'};
79 my $ind1 = $field->{ind1} || ' ';
80 my $ind2 = $field->{ind2} || ' ';
82 my $control = qq{<datafield tag="$tag" ind1="$ind1" ind2="$ind2">};
83 foreach my $sf (@{$field->{subfields}}) {
85 my $val = $U->entityize($sf->[1]);
86 $control .= qq{<subfield code="$code">$val</subfield>};
88 $control .= '</datafield>';
90 # ARN, or "authority record number", used to need to be unique across the database.
91 # Of course, we have no idea what's in the database, and if the
92 # cat.maintain_control_numbers flag is set to "TRUE" then the 001 will
93 # be reset to the record ID anyway.
94 my $arn = 'AUTOGEN-' . time();
96 # Placeholder MARCXML;
97 # 001/003 can be be properly filled in via database triggers
98 # 005 will be filled in automatically at creation time
99 # 008 needs to be set by a cataloguer (could be some OU settings, I suppose)
100 # 040 should come from OU settings / OU shortname
102 my $marc_xml = <<MARCXML;
103 <record xmlns:marc="http://www.loc.gov/MARC21/slim" xmlns="http://www.loc.gov/MARC21/slim"><leader> nz a22 o 4500</leader>
104 <controlfield tag="001">$arn</controlfield>
105 <controlfield tag="008"> ||||||||||||||||||||||||||||||||||</controlfield>
106 <datafield tag="040" ind1=" " ind2=" "><subfield code="a">$cni</subfield><subfield code="c">$cni</subfield></datafield>
111 if ($self->api_name =~ m/readonly$/) {
114 my $e = new_editor(authtoken=>$auth, xact=>1);
115 return $e->die_event unless $e->checkauth;
116 return $e->die_event unless $e->allowed('CREATE_AUTHORITY_RECORD');
117 my $rec = OpenILS::Application::Cat::AuthCommon->import_authority_record($e, $marc_xml);
118 $e->commit unless $U->event_code($rec);
123 __PACKAGE__->register_method(
124 method => 'overlay_authority_record',
125 api_name => 'open-ils.cat.authority.record.overlay',
128 sub overlay_authority_record {
129 my($self, $conn, $auth, $rec_id, $marc_xml, $source) = @_;
130 my $e = new_editor(authtoken=>$auth, xact=>1);
131 return $e->die_event unless $e->checkauth;
132 return $e->die_event unless $e->allowed('UPDATE_AUTHORITY_RECORD');
133 my $rec = OpenILS::Application::Cat::AuthCommon->
134 overlay_authority_record($e, $rec_id, $marc_xml, $source);
135 $e->commit unless $U->event_code($rec);
139 __PACKAGE__->register_method(
140 method => 'retrieve_authority_record',
141 api_name => 'open-ils.cat.authority.record.retrieve',
143 desc => q/Retrieve an authority record entry/,
145 {desc => q/hash of options. Options include "clear_marc" which clears
146 the MARC xml from the record before it is returned/}
150 sub retrieve_authority_record {
151 my($self, $conn, $auth, $rec_id, $options) = @_;
152 my $e = new_editor(authtoken=>$auth);
153 return $e->die_event unless $e->checkauth;
154 my $rec = $e->retrieve_authority_record_entry($rec_id) or return $e->event;
155 $rec->clear_marc if $$options{clear_marc};
159 __PACKAGE__->register_method(
160 method => 'batch_retrieve_authority_record',
161 api_name => 'open-ils.cat.authority.record.batch.retrieve',
164 desc => q/Retrieve a set of authority record entry objects/,
166 {desc => q/hash of options. Options include "clear_marc" which clears
167 the MARC xml from the record before it is returned/}
171 sub batch_retrieve_authority_record {
172 my($self, $conn, $auth, $rec_id_list, $options) = @_;
173 my $e = new_editor(authtoken=>$auth);
174 return $e->die_event unless $e->checkauth;
175 for my $rec_id (@$rec_id_list) {
176 my $rec = $e->retrieve_authority_record_entry($rec_id) or return $e->event;
177 $rec->clear_marc if $$options{clear_marc};
178 $conn->respond($rec);
183 __PACKAGE__->register_method(
184 method => 'count_linked_bibs',
185 api_name => 'open-ils.cat.authority.records.count_linked_bibs',
187 Counts the number of bib records linked to each authority record in the input list
188 @param records Array of authority records to return counts
189 @return A list of hashes containing the authority record ID ("id") and linked bib count ("bibs")
193 sub count_linked_bibs {
194 my( $self, $conn, $records ) = @_;
196 my $editor = new_editor();
200 for my $auth ( @$records ) {
201 # Protection against SQL injection? Might be overkill.
202 my $intauth = int($auth);
204 push(@clean_records, $intauth);
207 return $link_count if !@clean_records;
209 $link_count = $editor->json_query({
213 "column" => "authority"
217 "transform" => "count",
224 "where" => { "authority" => \@clean_records }
230 __PACKAGE__->register_method(
231 "method" => "retrieve_acs",
232 "api_name" => "open-ils.cat.authority.control_set.retrieve",
237 "desc" => q/Retrieve authority.control_set objects with fleshed
238 thesauri and authority fields/,
240 {"name" => "limit", "desc" => "limit (optional; default 15)", "type" => "number"},
241 {"name" => "offset", "desc" => "offset doptional; default 0)", "type" => "number"},
242 {"name" => "focus", "desc" => "optionally make sure the acs object with ID matching this value comes at the top of the result set (only works with offset 0)", "type" => "number"}
247 # XXX I don't think this really needs to be protected by perms, or does it?
252 my ($limit, $offset, $focus) = map int, @_;
260 {"class" => "acs", "field" => "name"}
263 # Here is the magic that let's us say that a given acsaf
264 # will be our first result.
265 unshift @$order_by, {
266 "class" => "acs", "field" => "id",
267 "transform" => "numeric_eq", "params" => [$focus],
268 "direction" => "desc"
271 my $sets = $e->search_authority_control_set([
272 {"id" => {"!=" => undef}}, {
274 "flesh_fields" => {"acs" => [qw/thesauri authority_fields/]},
275 "order_by" => $order_by,
279 ]) or return $e->die_event;
283 $client->respond($_) foreach @$sets;
287 __PACKAGE__->register_method(
288 "method" => "retrieve_acsaf",
289 "api_name" => "open-ils.cat.authority.control_set_authority_field.retrieve",
294 "desc" => q/Retrieve authority.control_set_authority_field objects with
295 fleshed bib_fields and axes/,
297 {"name" => "limit", "desc" => "limit (optional; default 15)", "type" => "number"},
298 {"name" => "offset", "desc" => "offset (optional; default 0)", "type" => "number"},
299 {"name" => "control_set", "desc" => "optionally constrain by value of acsaf.control_set field", "type" => "number"},
300 {"name" => "focus", "desc" => "optionally make sure the acsaf object with ID matching this value comes at the top of the result set (only works with offset 0)"}
309 my ($limit, $offset, $control_set, $focus) = map int, @_;
313 $control_set ||= undef;
318 "control_set" => ($control_set ? $control_set : {"!=" => undef})
321 {"class" => "acsaf", "field" => "main_entry", "direction" => "desc"},
322 {"class" => "acsaf", "field" => "id"}
325 unshift @$order_by, {
326 "class" => "acsaf", "field" => "id",
327 "transform" => "numeric_eq", "params" => [$focus],
328 "direction" => "desc"
331 my $fields = $e->search_authority_control_set_authority_field([
335 "acsaf" => ["bib_fields", "axis_maps"],
338 "order_by" => $order_by,
342 ]) or return $e->die_event;
346 $client->respond($_) foreach @$fields;