source: main/trunk/greenstone2/perllib/cgiactions/modmetadataaction.pm@ 37207

Last change on this file since 37207 was 37207, checked in by davidb, 15 months ago

Support added in for optional cgi param 'dv' specifying the file-level document-version history (_fldv_history) folder to use

File size: 105.8 KB
Line 
1##########################################################################
2#
3# modmetadataaction.pm --
4# A component of the Greenstone digital library software
5# from the New Zealand Digital Library Project at the
6# University of Waikato, New Zealand.
7#
8# Copyright (C) 2009 New Zealand Digital Library Project
9#
10# This program is free software; you can redistribute it and/or modify
11# it under the terms of the GNU General Public License as published by
12# the Free Software Foundation; either version 2 of the License, or
13# (at your option) any later version.
14#
15# This program is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18# GNU General Public License for more details.
19#
20# You should have received a copy of the GNU General Public License
21# along with this program; if not, write to the Free Software
22# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23#
24###########################################################################
25
26# This is a submodule of metadataaction.pm. It is loaded conditionally
27# upon having the permissions to modify (not just get) metadata.
28# With sufficient permissions, these additional subroutines should be made
29# available to metadataaction.pm
30
31# See http://www.perlmonks.org/?node_id=881761 for splitting module into multiple files
32# and how variables declared with 'our' are used there.
33
34package metadataaction;
35
36use strict;
37
38use cgiactions::baseaction;
39use cgiactions::metadataactioncommon;
40
41use dbutil;
42use ghtml;
43
44use JSON;
45
46# convenient to have shorter version around
47my $FLDV_HISTORY_DIR = $metadataactioncommon::FLDV_HISTORY_DIR;
48
49$metadataaction::modmeta_action_table = #OR: our $modmeta_action_table =
50{
51 #SET METHODS
52 "set-live-metadata" => {
53 'compulsory-args' => [ "d", "metaname", "metavalue" ],
54 'optional-args' => [ ] },
55
56 "set-metadata" => { # generic set-meta function. The 'where' param can be set to any combination of index|archives|import|live. docid d is still compulsory for setting index, archives and live meta
57 'compulsory-args' => [ "metaname", "metavalue" ],
58 'optional-args' => [ "where", "metapos", "metamode", "prevmetavalue", "d", "dv", "f" ] },
59
60 "set-index-metadata" => {
61 'compulsory-args' => [ "d", "metaname", "metavalue" ],
62 'optional-args' => [ "metapos", "metamode" ] },
63
64 "set-archives-metadata" => {
65 'compulsory-args' => [ "d", "metaname", "metavalue" ],
66 'optional-args' => [ "dv", "metapos", "metamode", "prevmetavalue" ] }, # metamode can be "accumulate", "override",
67
68 ###### !!!!!
69 # Should there not be a "set-archives-text" also ???!!!!??
70 ###### !!!!!
71
72 "set-import-metadata" => {
73 'compulsory-args' => [ "metaname", "metavalue" ],
74 'optional-args' => [ "d", "f", "metamode", "metapos", "prevmetavalue" ] }, # metamode can be "accumulate", "override", or "unique-id". Also need to add the ability to specify a previous metadata value to overwrite (because we can't use metapos). Metapos now supported, but assumes you are working with a Simple (instead of Complex) collection
75
76 #SET METHODS (ARRAY)
77 "set-metadata-array" => {
78 'compulsory-args' => [ "where", "json" ],
79 'optional-args' => [ ],
80 'help-string' => [
81 'A simple example: metadata-server.pl?a=set-metadata-array&where=archives|index|import&c=demo&json=[{"docid":"HASHc5bce2d6d3e5b04e470ec9","metaname":"Title","metavalue":"Tralalala","metamode":"accumulate"},{"docid":"HASHbe483fa4df4e096335d1c8","metaname":"Title","metavalue":"Lala was here","metapos":0, "metamode":"override"}]',
82
83 'A more complex example: metadata-server.pl?a=set-metadata-array&where=archives|index&c=demo&json=[{"docid":"HASHc5bce2d6d3e5b04e470ec9.1","metatable":[{"metaname":"Title","metavals":["Transformers","Robots in disguise","Autobots"]}],"metamode":"override"},{"docid":"HASHbe483fa4df4e096335d1c8.2","metaname":"Title","metavalue":"Pinky was here","metamode":"accumulate"}]' ] },
84
85# The same examples rewritten for when running the metadata-server.pl script from the commandline:
86
87# the simple example: metadata-server.pl a="set-metadata-array" where="archives|index|import" c="demo" json="[{\"docid\":\"HASHc5bce2d6d3e5b04e470ec9\",\"metaname\":\"Title\",\"metavalue\":\"Tralalala\",\"metamode\":\"accumulate\"},{\"docid\":\"HASHbe483fa4df4e096335d1c8\",\"metaname\":\"Title\",\"metavalue\":\"Lala was here\",\"metapos\":0, \"metamode\":\"override\"}]",
88
89# the more complex example: metadata-server.pl a="set-metadata-array" where="archives|index" c="demo" json="[{\"docid\":\"HASHc5bce2d6d3e5b04e470ec9.1\",\"metatable\":[{\"metaname\":\"Title\",\"metavals\":[\"Transformers\",\"Robots in disguise\",\"Autobots\"]}],\"metamode\":\"override\"},{\"docid\":\"HASHbe483fa4df4e096335d1c8.2\",\"metaname\":\"Title\",\"metavalue\":\"Pinky was here\",\"metamode\":\"accumulate\"}]"
90
91 "set-archives-metadata-array" => {
92 'compulsory-args' => [ "json" ],
93 'optional-args' => [ ] },
94
95 "set-import-metadata-array" => {
96 'compulsory-args' => [ "json" ],
97 'optional-args' => [ ] },
98
99 "set-index-metadata-array" => {
100 'compulsory-args' => [ "json" ],
101 'optional-args' => [ ] },
102
103 "set-live-metadata-array" => {
104 'compulsory-args' => [ "json" ],
105 'optional-args' => [ ] },
106
107 #REMOVE METHODS
108 "remove-import-metadata" => {
109 'compulsory-args' => [ "d", "metaname" ], #TODO: add f argument
110 'optional-args' => [ "metapos", "metavalue", "metamode" ] }, # only provide metapos arg for SIMPLE collections.
111# Metavalue is now an optional arg for remove_import_metadata() based on what the implementation did, which allowed metavalue to be undefined, and if so, used metapos.
112
113 "remove-archives-metadata" => {
114 'compulsory-args' => [ "d", "metaname" ], #TODO: add f argument
115 'optional-args' => [ "dv", "metapos", "metavalue", "metamode" ] },
116
117 "remove-live-metadata" => {
118 'compulsory-args' => [ "d", "metaname" ],
119 'optional-args' => [ ] },
120
121 "remove-index-metadata" => {
122 'compulsory-args' => [ "d", "metaname" ],
123 'optional-args' => [ "metapos", "metavalue" ] },
124
125 "remove-metadata" => { # generic remove-meta function. The 'where' param can be set to any combination of index|archives|import|live. docid d is still compulsory for setting index, archives and live meta
126 'compulsory-args' => [ "d", "metaname" ],
127 'optional-args' => [ "where", "dv", "metapos", "metavalue", "metamode" ] }, # metamode is optional since remove-metadata can call any of remove_import_meta and remove_archives_meta, remove_index_meta, of which the first two accept metamode as an optional param
128
129
130 #REMOVE MULTIPLE (REMOVE ALL MATCHING METANAME AT DOCID)
131 "erase-import-metadata" => {
132 'compulsory-args' => [ "d", "metaname" ] },
133
134 "erase-archives-metadata" => {
135 'compulsory-args' => [ "d", "metaname" ],
136 'optional-args' => [ "dv" ] },
137
138 "erase-index-metadata" => {
139 'compulsory-args' => [ "d", "metaname" ] },
140
141 "erase-live-metadata" => {
142 'compulsory-args' => [ "d", "metaname" ] },
143
144 "erase-metadata" => { # generic erase-meta function. The 'where' param can be set to any combination of index|archives|import|live. docid d is still compulsory for setting index, archives and live meta
145 'compulsory-args' => [ "d", "metaname" ],
146 'optional-args' => [ "where" ] },
147
148
149 #INSERT METHODS
150 "insert-metadata" => {
151 'compulsory-args' => [ "d", "metaname", "metavalue" ],
152 'optional-args' => [ ] }
153};
154
155sub _set_live_metadata
156{
157 my $self = shift @_;
158
159 my $collect = $self->{'collect'};
160 my $gsdl_cgi = $self->{'gsdl_cgi'};
161 my $infodbtype = $self->{'infodbtype'};
162
163 # Obtain the collect dir
164 my $site = $self->{'site'};
165 my $collect_dir = $gsdl_cgi->get_collection_dir($site);
166
167
168 # look up additional args
169 my $docid = $self->{'d'};
170 if ((!defined $docid) || ($docid =~ m/^\s*$/)) {
171 $gsdl_cgi->generate_error("No docid (d=...) specified."); # generates error and dies
172 }
173 my $metavalue = $self->{'metavalue'};
174
175 # Generate the dbkey
176 my $metaname = $self->{'metaname'};
177 my $dbkey = "$docid.$metaname";
178
179 # To people who know $collect_tail please add some comments
180 # Obtain path to the database
181 my $collect_tail = $collect;
182 $collect_tail =~ s/^.*[\/|\\]//;
183 my $index_text_directory = &util::filename_cat($collect_dir,$collect,"index","text");
184 my $infodb_file_path = &dbutil::get_infodb_file_path($infodbtype, "live-$collect_tail", $index_text_directory);
185
186 # Set the new value
187 my $cmd = "gdbmset \"$infodb_file_path\" \"$dbkey\" \"$metavalue\"";
188 my $status = system($cmd);
189 if ($status != 0) {
190 # Catch error if gdbmget failed
191 my $mess = "Failed to set metadata key: $dbkey\n";
192
193 $mess .= "PATH: $ENV{'PATH'}\n";
194 $mess .= "cmd = $cmd\n";
195 $mess .= "Exit status: $status\n";
196 $mess .= "System Error Message: $!\n";
197
198 $gsdl_cgi->generate_error($mess);
199 }
200 else {
201 $gsdl_cgi->generate_ok_message("set-live-metadata successful: Key[$metaname]=$metavalue");
202 }
203
204 #return $status; # in case calling functions have any further use for this
205}
206
207sub set_live_metadata
208{
209 my $self = shift @_;
210
211 my $username = $self->{'username'};
212 my $collect = $self->{'collect'};
213 my $gsdl_cgi = $self->{'gsdl_cgi'};
214
215 if ($baseaction::authentication_enabled) {
216 # Ensure the user is allowed to edit this collection
217 $self->authenticate_user($username, $collect); #&authenticate_user($gsdl_cgi, $username, $collect);
218 }
219
220 # Make sure the collection isn't locked by someone else
221 $self->lock_collection($username, $collect);
222
223 $self->_set_live_metadata(@_);
224
225 # Release the lock once it is done
226 $self->unlock_collection($username, $collect);
227}
228
229sub set_index_metadata_entry
230{
231 my $self = shift @_;
232 my ($collect_dir,$collect,$infodbtype,$docid,$metaname,$metapos,$metavalue,$metamode,$prevmetavalue) = @_;
233
234 # To people who know $collect_tail please add some comments
235 # Obtain path to the database
236 my $collect_tail = $collect;
237 $collect_tail =~ s/^.*[\/|\\]//;
238 my $index_text_directory = &util::filename_cat($collect_dir,$collect,"index","text");
239 my $infodb_file_path = &dbutil::get_infodb_file_path($infodbtype, $collect_tail, $index_text_directory);
240
241# print STDERR "**** infodb file path = $infodb_file_path\n";
242# print STDERR "***** infodb type = $infodbtype\n";
243
244 # Read the docid entry
245 my $doc_rec = &dbutil::read_infodb_entry($infodbtype, $infodb_file_path, $docid);
246
247 # Set the metadata value
248 if (defined $metapos) {
249 # if metamode=accumulate AND metapos, warn user and then use metapos
250 if (defined $metamode && $metamode eq "accumulate") {
251 print STDERR "**** Warning: metamode is set to accumulate yet metapos is also provided for $docid\n";
252 print STDERR "**** Proceeding by using metapos\n";
253 }
254 $doc_rec->{$metaname}->[$metapos] = $metavalue;
255 }
256 elsif (defined $prevmetavalue) {
257 my $array = $doc_rec->{$metaname};
258 my $length = @$array;
259
260 my $found = 0;
261 for (my $i = 0; $i < $length; $i++){
262 if(defined $doc_rec->{$metaname}->[$i] && $doc_rec->{$metaname}->[$i] eq $prevmetavalue){
263 $doc_rec->{$metaname}->[$i] = $metavalue;
264 $found = 1;
265 last;
266 }
267 }
268
269 if($found == 0){
270 $doc_rec->{$metaname} = [ $metavalue ];
271 }
272 }
273 elsif (defined $metamode && $metamode eq "override") {
274 $doc_rec->{$metaname} = [ $metavalue ];
275 }
276 else { # default for index was to override, but because accumulate is less destructive,
277 # and because accumulate is the default for archives and import, that's the new default for index too
278 if(defined $doc_rec->{$metaname}) {
279 push(@{$doc_rec->{$metaname}}, $metavalue); # accumulate the value for that metaname
280 } else {
281 $doc_rec->{$metaname} = [ $metavalue ];
282 }
283 }
284
285 my $status = &dbutil::set_infodb_entry($infodbtype, $infodb_file_path,$docid,$doc_rec);
286
287 return $status;
288
289}
290
291sub _set_import_metadata
292{
293 my $self = shift @_;
294
295 my $collect = $self->{'collect'};
296 my $gsdl_cgi = $self->{'gsdl_cgi'};
297 my $infodbtype = $self->{'infodbtype'};
298
299 # Obtain the collect and archive dir
300 my $site = $self->{'site'};
301 my $collect_dir = $gsdl_cgi->get_collection_dir($site);
302 my $archive_dir = &util::filename_cat($collect_dir,$collect,"archives");
303
304 # look up additional args
305 # want either d= or f=
306 my $docid = $self->{'d'};
307 my ($docid_root,$docid_secnum);
308 if(defined $docid) {
309 ($docid_root,$docid_secnum) = ($docid =~ m/^(.*?)(\..*)?$/);
310 # as yet no support for setting subsection metadata in metadata.xml
311 if ((defined $docid_secnum) && ($docid_secnum !~ m/^\s*$/)) {
312 $gsdl_cgi->generate_message("*** No support yet for setting import metadata at subsections level.\n");
313 return;
314 }
315 }
316
317 my $import_file = $self->{'f'};
318 if ((!defined $docid || $docid =~ m/^\s*$/) && (!defined $import_file || $import_file =~ m/^\s*$/)) {
319 $gsdl_cgi->generate_error("No docid (d=...) or import file (f=) specified."); # at least d or f must be specified
320 }
321
322 # Get the parameters and set default mode to "accumulate"
323 my $metaname = $self->{'metaname'};
324 my $metavalue = $self->{'metavalue'};
325## $metavalue =~ s/&amp;lt;(.*?)&amp;gt;/<$1>/g;
326 $metavalue =~ s/&lt;(.*?)&gt;/<$1>/g;
327
328 my $metamode = $self->{'metamode'};
329 if ((!defined $metamode) || ($metamode =~ m/^\s*$/)) {
330 # make "accumulate" the default (less destructive, as it won't actually
331 # delete any existing values)
332 $metamode = "accumulate";
333 }
334
335 # adding metapos and prevmetavalue support to import_metadata subroutines
336 my $metapos = $self->{'metapos'}; # don't force undef to 0. Undef has meaning when metamode=override
337 my $prevmetavalue = $self->{'prevmetavalue'};
338 $metapos = undef if(defined $metapos && ($metapos =~ m/^\s*$/));
339 $prevmetavalue = undef if(defined $prevmetavalue && ($prevmetavalue =~ m/^\s*$/));
340
341 my $arcinfo_doc_filename = &dbutil::get_infodb_file_path($infodbtype, "archiveinf-doc", $archive_dir);
342 my $metadata_xml_filename = $self->set_import_metadata_entry($gsdl_cgi, $arcinfo_doc_filename, $infodbtype, $docid_root, $metaname, $metapos,$metavalue, $metamode,$prevmetavalue, $collect, $collect_dir); # at this point, docid_root = docid
343
344 my $mess = "set-import-metadata successful: Key[$docid] -> $metadata_xml_filename\n";
345 $mess .= " $metaname";
346 $mess .= " = $metavalue";
347 $mess .= " ($metamode)\n";
348
349 $gsdl_cgi->generate_ok_message($mess);
350
351 #return $status; # in case calling functions have any further use for this
352}
353
354# the version of set_archives_meta that doesn't do authentication
355sub _set_archives_metadata
356{
357 my $self = shift @_;
358
359 my $collect = $self->{'collect'};
360 my $gsdl_cgi = $self->{'gsdl_cgi'};
361 my $infodbtype = $self->{'infodbtype'};
362
363 # Obtain the collect and archive dir
364 my $site = $self->{'site'};
365 my $collect_dir = $gsdl_cgi->get_collection_dir($site);
366 my $archive_dir = &util::filename_cat($collect_dir,$collect,"archives");
367
368 # look up additional args
369 my $docid = $self->{'d'};
370 my $dv = $self->{'dv'};
371
372 my $metaname = $self->{'metaname'};
373 my $metavalue = $self->{'metavalue'};
374 my $prevmetavalue = $self->{'prevmetavalue'};
375
376 my $metapos = $self->{'metapos'}; # don't force undef to 0. Undef has meaning when metamode=override
377 # Don't append "|| undef", since if metapos=0 it will then be set to undef
378
379 $metapos = undef if(defined $metapos && ($metapos =~ m/^\s*$/));
380 $prevmetavalue = undef if(defined $prevmetavalue && ($prevmetavalue =~ m/^\s*$/));
381
382 my $metamode = $self->{'metamode'};
383 if ((!defined $metamode) || ($metamode =~ m/^\s*$/)) {
384 # make "accumulate" the default (less destructive, as it won't actually
385 # delete any existing values)
386 $metamode = "accumulate";
387 }
388
389 my $status = $self->set_archives_metadata_entry($gsdl_cgi,$archive_dir, $collect_dir,$collect, $infodbtype,
390 $docid,$dv, $metaname,$metapos,$metavalue,$metamode,$prevmetavalue);
391
392 if ($status == 0) {
393 my $mess = "set-archives-metadata successful: Key[$docid]\n";
394 $mess .= " $metaname";
395 $mess .= "->[$metapos]" if (defined $metapos);
396 $mess .= " = $metavalue";
397 $mess .= " ($metamode)\n";
398
399 $gsdl_cgi->generate_ok_message($mess);
400 }
401 else {
402 my $mess .= "Failed to set archives metadata key: $docid\n";
403 $mess .= "Exit status: $status\n";
404 if(defined $self->{'error_msg'}) {
405 $mess .= "Error Message: $self->{'error_msg'}\n";
406 } else {
407 $mess .= "System Error Message: $!\n";
408 }
409 $mess .= "-" x 20 . "\n";
410
411 $gsdl_cgi->generate_error($mess);
412 }
413
414 #return $status; # in case calling functions have any further use for this
415}
416
417
418# the version of set_index_meta that doesn't do authentication
419sub _set_index_metadata
420{
421 print STDERR "START SET INDEX METADATA\n";
422 my $self = shift @_;
423
424 my $collect = $self->{'collect'};
425 my $gsdl_cgi = $self->{'gsdl_cgi'};
426
427 # Obtain the collect dir
428 my $site = $self->{'site'};
429 my $collect_dir = $gsdl_cgi->get_collection_dir($site);
430
431 # look up additional args
432 my $docid = $self->{'d'};
433 my $metaname = $self->{'metaname'};
434 my $metapos = $self->{'metapos'}; # undef has meaning
435 my $metavalue = $self->{'metavalue'};
436 my $infodbtype = $self->{'infodbtype'};
437 my $metamode = $self->{'metamode'};
438 my $prevmetavalue = $self->{'prevmetavalue'};
439
440 $metapos = undef if(defined $metapos && ($metapos =~ m/^\s*$/));
441 $prevmetavalue = undef if(defined $prevmetavalue && ($prevmetavalue =~ m/^\s*$/));
442
443 print STDERR "SETTING INDEX METADATA ENTRY\n";
444 my $status = $self->set_index_metadata_entry($collect_dir,$collect,$infodbtype,$docid,$metaname,$metapos,$metavalue,$metamode,$prevmetavalue);
445 print STDERR "DONE SETTING INDEX METADATA ENTRY\n";
446 if ($status != 0) {
447 # Catch error if set infodb entry failed
448 my $mess = "Failed to set metadata key: $docid\n";
449
450 $mess .= "PATH: $ENV{'PATH'}\n";
451 $mess .= "Exit status: $status\n";
452 $mess .= "System Error Message: $!\n";
453
454 $gsdl_cgi->generate_error($mess);
455 }
456 else {
457 my $mess = "set-index-metadata successful: Key[$docid]\n";
458 $mess .= " $metaname";
459 $mess .= "->[$metapos]" if (defined $metapos);
460 $mess .= " = $metavalue\n";
461
462 $gsdl_cgi->generate_ok_message($mess);
463 }
464
465 print STDERR "END SET INDEX METADATA\n";
466 #return $status; # in case calling functions have any further use for this
467}
468
469sub set_index_metadata
470{
471 my $self = shift @_;
472
473 my $username = $self->{'username'};
474 my $collect = $self->{'collect'};
475 my $gsdl_cgi = $self->{'gsdl_cgi'};
476
477 if ($baseaction::authentication_enabled) {
478 # Ensure the user is allowed to edit this collection
479 $self->authenticate_user($username, $collect); #&authenticate_user($gsdl_cgi, $username, $collect);
480 }
481
482 # Obtain the collect dir
483 my $site = $self->{'site'};
484 my $collect_dir = $gsdl_cgi->get_collection_dir($site);
485
486 $gsdl_cgi->checked_chdir($collect_dir);
487
488 # Make sure the collection isn't locked by someone else
489 $self->lock_collection($username, $collect);
490
491 $self->_set_index_metadata(@_);
492
493 # Release the lock once it is done
494 $self->unlock_collection($username, $collect);
495}
496
497# call this to set the metadata for a combination of dirs archives, import or index, or live
498# if none specified, defaults to index which was the original behaviour of set_metadata.
499sub set_metadata
500{
501 my $self = shift @_;
502
503 # Testing that not defining a variable, setting it to "" or to " " all return false
504 # >perl -e 'my $whichdirs=""; if($whichdirs) {print "$whichdirs\n"};'
505
506 my $where = $self->{'where'};
507 if(!$where || ($where =~ m/^\s*$/)) {
508 $self->set_index_metadata(@_); # call the full version of set_index_meta for the default behaviour
509 return;
510 }
511
512 # authenticate and lock collection once, even if processing multiple dirs
513 my $username = $self->{'username'};
514 my $collect = $self->{'collect'};
515 my $gsdl_cgi = $self->{'gsdl_cgi'};
516
517 if ($baseaction::authentication_enabled) {
518 # Ensure the user is allowed to edit this collection
519 $self->authenticate_user($username, $collect); #&authenticate_user($gsdl_cgi, $username, $collect);
520 }
521
522 if($where =~ m/index/) {
523 my $site = $self->{'site'};
524 my $collect_dir = $gsdl_cgi->get_collection_dir($site);
525 $gsdl_cgi->checked_chdir($collect_dir);
526 }
527
528 # Make sure the collection isn't locked by someone else
529 $self->lock_collection($username, $collect);
530
531
532 # now at last can set the metadata. $where can specify multiple
533 # $where is of the form: import|archives|index, or a subset thereof
534
535 #my @whichdirs = split('\|', $where);
536
537 # just check whether $where contains import/archives/index/live in turn, and
538 # for each case, process it accordingly
539 if($where =~ m/import/) {
540 $self->_set_import_metadata(@_);
541 }
542
543 if($where =~ m/archives/) {
544
545 # look up docID arg which is optional to set_metadata because it's optional
546 # to set_import, but which is compulsory to set_archives_metadata
547 my $docid = $self->{'d'};
548 if ((!defined $docid) || ($docid =~ m/^\s*$/)) {
549 $gsdl_cgi->generate_error("No docid (d=...) specified."); # generates error and dies
550 }
551 # we have a docid, so can set archives meta
552 $self->_set_archives_metadata(@_);
553 }
554
555 if($where =~ m/index/) {
556
557 # look up docID arg which is optional to set_metadata because it's optional
558 # to set_import, but which is compulsory to set_archives_metadata
559 my $docid = $self->{'d'};
560 if ((!defined $docid) || ($docid =~ m/^\s*$/)) {
561 $gsdl_cgi->generate_error("No docid (d=...) specified.");
562 }
563 # we have a docid, so can set index meta
564 $self->_set_index_metadata(@_);
565 }
566
567 if($where =~ m/live/) {
568 $self->_set_live_metadata(@_); # docid param, d, is compulsory, but is checked for in subroutine
569 }
570
571 # Release the lock once it is done
572 $self->unlock_collection($username, $collect);
573}
574
575sub set_metadata_array
576{
577 my $self = shift @_;
578
579 my $where = $self->{'where'};
580 if(!$where || ($where =~ m/^\s*$/)) {
581 $self->set_index_metadata_array(@_); # default behaviour is the full version of set_index_meta_array
582 return;
583 }
584
585 my $username = $self->{'username'};
586 my $collect = $self->{'collect'};
587 my $gsdl_cgi = $self->{'gsdl_cgi'};
588
589 if ($baseaction::authentication_enabled) {
590 # Ensure the user is allowed to edit this collection
591 $self->authenticate_user($username, $collect); #&authenticate_user($gsdl_cgi, $username, $collect);
592 }
593
594 # Not sure if the checked_chdir is necessary, since lock_collection also does a chdir
595 # But including the stmt during this code reorganisation to preserve as-is what used to happen
596 my $site = $self->{'site'};
597 my $collect_dir = $gsdl_cgi->get_collection_dir($site);
598 $gsdl_cgi->checked_chdir($collect_dir);
599
600 # Make sure the collection isn't locked by someone else
601 $self->lock_collection($username, $collect);
602
603 if($where =~ m/import/) {
604 $self->_set_import_metadata_array(@_);
605 }
606 if($where =~ m/archives/) {
607 $self->_set_archives_metadata_array(@_);
608 }
609 if($where =~ m/index/) {
610 $self->_set_index_metadata_array(@_);
611 }
612 if($where =~ m/live/) {
613 $self->_set_live_metadata_array(@_);
614 }
615
616 # Release the lock once it is done
617 $self->unlock_collection($username, $collect);
618}
619
620sub _set_index_metadata_array
621{
622 my $self = shift @_;
623
624 my $collect = $self->{'collect'};
625 my $gsdl_cgi = $self->{'gsdl_cgi'};
626
627 # Obtain the collect dir
628 my $site = $self->{'site'};
629 my $collect_dir = $gsdl_cgi->get_collection_dir($site);
630
631 # look up additional args
632
633 my $infodbtype = $self->{'infodbtype'};
634
635 my $json_str = $self->{'json'};
636 my $doc_array = decode_json $json_str;
637
638
639 my $global_status = 0;
640 my $global_mess = "";
641
642 my @all_docids = ();
643
644 foreach my $doc_array_rec ( @$doc_array ) {
645
646 my $status = -1;
647 my $docid = $doc_array_rec->{'docid'};
648
649 push(@all_docids,$docid);
650
651 my $metaname = $doc_array_rec->{'metaname'};
652 if(defined $metaname) {
653 my $metapos = $doc_array_rec->{'metapos'}; # can legitimately be undef
654 my $metavalue = $doc_array_rec->{'metavalue'};
655 my $metamode = $doc_array_rec->{'metamode'} || $self->{'metamode'};
656
657 $status = $self->set_index_metadata_entry($collect_dir,$collect,$infodbtype,$docid,$metaname,$metapos,$metavalue,$metamode);
658 } elsif (defined $doc_array_rec->{'metatable'}) { # if no metaname, we expect a metatable
659 my $metatable = $doc_array_rec->{'metatable'}; # a subarray, or need to generate an error saying JSON structure is wrong
660
661 foreach my $metatable_rec ( @$metatable ) { # the subarray metatable is an array of hashmaps
662 $metaname = $metatable_rec->{'metaname'};
663 my $metamode = $metatable_rec->{'metamode'} || $doc_array_rec->{'metamode'} || $self->{'metamode'};
664 my $metapos = undef;
665 my $metavals = $metatable_rec->{'metavals'}; # a sub-subarray
666
667 foreach my $metavalue ( @$metavals ) { # metavals is an array
668 $status = $self->set_index_metadata_entry($collect_dir,$collect,$infodbtype,$docid,$metaname,$metapos,$metavalue,$metamode); # how do we use metamode in set_meta_entry?
669 if($metamode eq "override") { # now, having overridden the metavalue for the first,
670 # need to accumulate subsequent metavals for this metaname, else the just-assigned
671 # metavalue for this metaname will be lost
672 $metamode = "accumulate";
673 }
674 }
675 }
676 }
677
678 if ($status != 0) {
679 # Catch error if set infodb entry failed
680 $global_status = $status;
681 $global_mess .= "Failed to set metadata key: $docid\n";
682 $global_mess .= "Exit status: $status\n";
683 $global_mess .= "System Error Message: $!\n";
684 $global_mess .= "-" x 20;
685 }
686 }
687
688 if ($global_status != 0) {
689 $global_mess .= "PATH: $ENV{'PATH'}\n";
690 $gsdl_cgi->generate_error($global_mess);
691 }
692 else {
693 my $mess = "set-metadata-array successful: Keys[ ".join(", ",@all_docids)."]\n";
694 $gsdl_cgi->generate_ok_message($mess);
695 }
696}
697
698sub set_index_metadata_array
699{
700 my $self = shift @_;
701
702 my $username = $self->{'username'};
703 my $collect = $self->{'collect'};
704 my $gsdl_cgi = $self->{'gsdl_cgi'};
705
706 if ($baseaction::authentication_enabled) {
707 # Ensure the user is allowed to edit this collection
708 $self->authenticate_user($username, $collect); #&authenticate_user($gsdl_cgi, $username, $collect);
709 }
710
711 # Obtain the collect dir
712 my $site = $self->{'site'};
713 my $collect_dir = $gsdl_cgi->get_collection_dir($site);
714
715 $gsdl_cgi->checked_chdir($collect_dir);
716
717
718 # Make sure the collection isn't locked by someone else
719 $self->lock_collection($username, $collect);
720
721 $self->_set_index_metadata_array(@_);
722
723 # Release the lock once it is done
724 $self->unlock_collection($username, $collect);
725}
726
727# experimental, newly added in and untested
728sub _set_live_metadata_array
729{
730 my $self = shift @_;
731
732 my $collect = $self->{'collect'};
733 my $gsdl_cgi = $self->{'gsdl_cgi'};
734
735 # Obtain the collect dir
736 my $site = $self->{'site'};
737 my $collect_dir = $gsdl_cgi->get_collection_dir($site);
738
739 # look up additional args
740 my $infodbtype = $self->{'infodbtype'};
741 # To people who know $collect_tail please add some comments
742 # Obtain path to the database
743 my $collect_tail = $collect;
744 $collect_tail =~ s/^.*[\/|\\]//;
745 my $index_text_directory = &util::filename_cat($collect_dir,$collect,"index","text");
746 my $infodb_file_path = &dbutil::get_infodb_file_path($infodbtype, "live-$collect_tail", $index_text_directory);
747
748
749 my $json_str = $self->{'json'};
750 my $doc_array = decode_json $json_str;
751
752
753 my $global_status = 0;
754 my $global_mess = "";
755
756 my @all_docids = ();
757
758
759 foreach my $doc_array_rec ( @$doc_array ) {
760
761 my $status = -1;
762 my $docid = $doc_array_rec->{'docid'};
763
764 push(@all_docids,$docid);
765
766 my $metaname = $doc_array_rec->{'metaname'};
767 if(defined $metaname) {
768 my $dbkey = "$docid.$metaname";
769 my $metavalue = $doc_array_rec->{'metavalue'};
770
771 # Set the new value
772 my $cmd = "gdbmset \"$infodb_file_path\" \"$dbkey\" \"$metavalue\"";
773 $status = system($cmd);
774
775 } elsif (defined $doc_array_rec->{'metatable'}) { # if no metaname, we expect a metatable
776 my $metatable = $doc_array_rec->{'metatable'}; # a subarray, or need to generate an error saying JSON structure is wrong
777 foreach my $metatable_rec ( @$metatable ) {
778 $metaname = $metatable_rec->{'metaname'};
779 my $dbkey = "$docid.$metaname";
780
781 my $metavals = $metatable_rec->{'metavals'}; # a sub-subarray
782 foreach my $metavalue ( @$metavals ) {
783 my $cmd = "gdbmset \"$infodb_file_path\" \"$dbkey\" \"$metavalue\"";
784 $status = system($cmd);
785 }
786 }
787
788 }
789
790 if ($status != 0) {
791 # Catch error if gdbmget failed
792 $global_status = $status;
793 $global_mess .= "Failed to set metadata key: $docid\n"; # $dbkey
794 $global_mess .= "Exit status: $status\n";
795 $global_mess .= "System Error Message: $!\n";
796 $global_mess .= "-" x 20;
797 }
798 }
799
800 if ($global_status != 0) {
801 $global_mess .= "PATH: $ENV{'PATH'}\n";
802 $gsdl_cgi->generate_error($global_mess);
803 }
804 else {
805 my $mess = "set-live-metadata-array successful: Keys[ ".join(", ",@all_docids)."]\n";
806 $gsdl_cgi->generate_ok_message($mess);
807 }
808}
809
810sub set_live_metadata_array
811{
812 my $self = shift @_;
813
814 my $username = $self->{'username'};
815 my $collect = $self->{'collect'};
816 my $gsdl_cgi = $self->{'gsdl_cgi'};
817
818 if ($baseaction::authentication_enabled) {
819 # Ensure the user is allowed to edit this collection
820 $self->authenticate_user($username, $collect); #&authenticate_user($gsdl_cgi, $username, $collect);
821 }
822
823 # Obtain the collect dir
824 my $site = $self->{'site'};
825 my $collect_dir = $gsdl_cgi->get_collection_dir($site);
826
827 $gsdl_cgi->checked_chdir($collect_dir);
828
829 # Make sure the collection isn't locked by someone else
830 $self->lock_collection($username, $collect);
831
832 $self->_set_live_metadata_array(@_);
833
834 # Release the lock once it is done
835 $self->unlock_collection($username, $collect);
836}
837
838
839sub dxml_metadata
840{
841 my ($tagname, $attrHash, $contextArray, $parentDataArray, $parser) = @_;
842 my $metaname = $parser->{'parameters'}->{'metaname'};
843 my $metamode = $parser->{'parameters'}->{'metamode'};
844
845###!!! print STDERR "**** Processing closing </Metadata> tag\n";
846
847 my $opt_doc_secnum = $parser->{'parameters'}->{'secnum'};
848
849 # Find the right metadata tag and checks if we are going to
850 # override it
851 #
852 # Note: This over writes the first metadata block it
853 # encountered. If there are multiple Sections in the doc.xml, it
854 # might not behave as you would expect
855
856 my $curr_secnum = $parser->{'parameters'}->{'curr_section_num'};
857## print STDERR "**** checking $opt_doc_secnum <=> $curr_secnum\n" if (defined $opt_doc_secnum);
858## print STDERR "**** metamode = $metamode\n";
859
860 if ((!defined $opt_doc_secnum) || ($opt_doc_secnum eq $curr_secnum))
861 {
862 my $name_attr = $attrHash->{'name'};
863 # print STDOUT "*** testing: $name_attr eq $metaname ? and $metamode eq override ?\n";
864 if (($name_attr eq $metaname) && ($metamode eq "override"))
865 {
866 if (!defined $parser->{'parameters'}->{'poscount'})
867 {
868 $parser->{'parameters'}->{'poscount'} = 0;
869 }
870 else
871 {
872 $parser->{'parameters'}->{'poscount'}++;
873 }
874
875 if (defined $parser->{'parameters'}->{'metapos'}) { # if pos defined, ignore any prevmeta if also defined, and just wait for pos match
876
877 if ($parser->{'parameters'}->{'poscount'} == $parser->{'parameters'}->{'metapos'}) {
878 ###print STDERR "#### got pos match!!\n";
879 # Get the value and override the current value
880 my $metavalue = $parser->{'parameters'}->{'metavalue'};
881 $attrHash->{'_content'} = $metavalue;
882
883 # until we have clearly determined the role of metamode in doc.xml files (we know what it means in import/metadata.xml files)
884 # we're not setting metamode to override here.
885
886 # Don't want it to wipe out any other pieces of metadata
887 $parser->{'parameters'}->{'metamode'} = "done";
888 }
889 }
890 elsif (defined $parser->{'parameters'}->{'prevmetavalue'}) { # if no pos defined but prevmeta defined, then wait for prevmeta match
891 if ($parser->{'parameters'}->{'prevmetavalue'} eq $attrHash->{'_content'}) {
892 ###print STDERR "### prev meta value matches\n";
893 my $metavalue = $parser->{'parameters'}->{'metavalue'};
894 $attrHash->{'_content'} = $metavalue;
895
896 # until we have clearly determined the role of metamode in doc.xml files (we know what it means in import/metadata.xml files)
897 # we're not setting metamode to override here.
898
899 $parser->{'parameters'}->{'metamode'} = "done";
900
901 }
902 }
903 # Note that before commit rev 32076, if neither metapos nor prevmeta defined, then code tried to set pos 0 for that metaname to the new value
904 # However that is not how the code works now (and couldn't get it to work that way yet after rev 32076).
905 # What it does now, and what Dr Bainbridge approved of is that:
906 # If no pos or prevmeta defined, then on override, the metavalue set for the specificed metaname becomes the ONLY instance of that metaname
907 # So any earlier instances of that metaname is removed and replaced by the single new instance.
908 }
909 }
910
911 # RAW is [$tagname => $attrHash] not $tagname => $attrHash!!
912 return [$tagname => $attrHash];
913}
914
915# This method exists purely for catching invalid section numbers that the client
916# requested to edit. Once the parser has reached the end (the final </Archive> tag),
917# we've seen all the Sections in the doc.xml, and none of their section nums matched
918# if the metamode has not been set to 'done' by then.
919sub dxml_archive
920{
921 my ($tagname, $attrHash, $contextArray, $parentDataArray, $parser) = @_;
922 my $metamode = $parser->{'parameters'}->{'metamode'};
923
924 my $curr_secnum = $parser->{'parameters'}->{'curr_section_num'};
925 my $opt_doc_secnum = $parser->{'parameters'}->{'secnum'};
926
927 # print STDERR "@@@ $tagname Processing a closing </Archive> tag [$curr_secnum|$opt_doc_secnum]\n";
928
929 if ($metamode ne "done" && $curr_secnum ne $opt_doc_secnum) {
930 #print STDERR "@@@ $tagname Finished processing FINAL Section.\n";
931
932 my $metaname = $parser->{'parameters'}->{'metaname'};
933 my $metavalue = $parser->{'parameters'}->{'metavalue'};
934
935 print STDERR "@@@ Requested section number $opt_doc_secnum not found.\n";
936 print STDERR "\t(last seen section number in document was $curr_secnum)\n";
937 print STDERR "\tDiscarded metadata value '$metavalue' for meta '$metaname'\n";
938 print STDERR "\tin section $opt_doc_secnum.\n";
939 $parser->{'custom_err_msg'} = "Requested section number $opt_doc_secnum not found.";
940 }
941
942 # RAW is [$tagname => $attrHash] not $tagname => $attrHash!!
943 return [$tagname => $attrHash];
944}
945
946sub dxml_description
947{
948 my ($tagname, $attrHash, $contextArray, $parentDataArray, $parser) = @_;
949 my $metamode = $parser->{'parameters'}->{'metamode'};
950
951 my $curr_secnum = $parser->{'parameters'}->{'curr_section_num'};
952 my $opt_doc_secnum = $parser->{'parameters'}->{'secnum'} || "";
953
954###!!! print STDERR "**** Processing a closing </Description> tag \n";
955 # print STDERR "@@@ $tagname Processing a closing </Description> tag [$curr_secnum|$opt_doc_secnum]\n";
956
957 # Accumulate the metadata
958
959 # We'll be accumulating metadata at this point if we haven't found and therefore
960 # haven't processed the metadata yet.
961 # For subsections, this means that if we're at a matching subsection, but haven't
962 # found the correct metaname to override in that subsection, we accumulate it as new
963 # meta in the subsection by adding it to the current description.
964 # If there's no subsection info for the metadata, it will accumulate at the top level
965 # section description if we hadn't found a matching metaname to override at this point.
966
967 # Both curr_secnum and opt_doc_secnum can be "". In the former case, it means we're now
968 # at the toplevel section. In the latter case, it means we want to process meta in the
969 # toplevel section. So the eq check between the values below will work in all cases.
970
971 # The only time this won't work is if an opt_doc_secnum beyond the section numbers of
972 # this document has been provided. In that case, the metadata for that opt_doc_secnum
973 # won't get attached/accumulated to any part of the doc, not even its top-level section.
974
975 if ($curr_secnum eq $opt_doc_secnum
976 && ($metamode eq "accumulate" || $metamode eq "override")) {
977 # note, metamode would have been set to done if a metadata operation had already succeeded.
978 # If we get here, we still have the metadata to append.
979 if ($metamode eq "override") {
980 print "Got to end of <Description> block. No metadata value to override. Switching 'metamode' to accumulate\n";
981 }
982
983 # If we get to here and metamode is override, this means there
984 # was no existing value to overide => treat as an append operation
985
986 # Tack a new metadata tag on to the end of the <Metadata>+ block
987 my $metaname = $parser->{'parameters'}->{'metaname'};
988 my $metavalue = $parser->{'parameters'}->{'metavalue'};
989
990 my $metadata_attr = {
991 '_content' => $metavalue,
992 'name' => $metaname,
993 'mode' => "accumulate"
994 };
995
996 my $append_metadata = [ "Metadata" => $metadata_attr ];
997 my $description_content = $attrHash->{'_content'};
998 print "Appending metadata to doc.xml\n";
999
1000 if (ref($description_content)) {
1001 # got some existing interesting nested content
1002 push(@$description_content, " ", $append_metadata, "\n ");
1003 }
1004 else {
1005 #description_content is most likely a string such as "\n"
1006 $attrHash->{'_content'} = [$description_content, " ", $append_metadata ,"\n" ];
1007 }
1008
1009 $parser->{'parameters'}->{'metamode'} = "done";
1010 }
1011 else {
1012 # metamode most likely "done" signifying that it has already found a position to add the metadata to.
1013## print STDERR "**** NOT ACCUMULATE?!? \n";
1014 }
1015 # RAW is [$tagname => $attrHash] not $tagname => $attrHash!!
1016 return [$tagname => $attrHash];
1017}
1018
1019sub edit_xml_file
1020{
1021 my $self = shift @_;
1022 my ($gsdl_cgi, $filename, $start_rules, $rules, $options) = @_;
1023
1024 # use XML::Rules to add it in (read in and out again)
1025 my $parser = XML::Rules->new(start_rules => $start_rules,
1026 rules => $rules,
1027 style => 'filter',
1028 output_encoding => 'utf8' );
1029
1030 my $xml_in = "";
1031 if (!open(MIN,"<$filename")) {
1032 $gsdl_cgi->generate_error("Unable to read in $filename: $!");
1033 }
1034 else {
1035 # Read all the text in
1036 my $line;
1037 while (defined ($line=<MIN>)) {
1038 $xml_in .= $line if($line !~ m/^\s*$/); # preserve all but empty lines
1039 }
1040 close(MIN);
1041
1042 my $MOUT;
1043 if (!open($MOUT,">$filename")) {
1044 $gsdl_cgi->generate_error("Unable to write out to $filename: $!");
1045 }
1046 else {
1047 # Matched lines will get handled by the call backs
1048## my $xml_out = "";
1049
1050 binmode($MOUT,":utf8");
1051 $parser->filter($xml_in,$MOUT, $options);
1052
1053# binmode(MOUT,":utf8");
1054# print MOUT $xml_out;
1055 close($MOUT);
1056 }
1057 }
1058
1059 # copy across any custom error information that was stored during parsing
1060 $self->{'error_msg'} = $parser->{'custom_err_msg'} if(defined $parser->{'custom_err_msg'});
1061}
1062
1063sub edit_doc_xml
1064{
1065 my $self = shift @_;
1066 my ($gsdl_cgi, $doc_xml_filename, $metaname, $metavalue, $metapos, $metamode, $opt_secnum, $prevmetavalue) = @_;
1067
1068 my $info_mess = <<RAWEND;
1069****************************
1070 edit_doc_xml()
1071****************************
1072RAWEND
1073
1074 $info_mess .= " doc_xml_filename = $doc_xml_filename\n" if defined($doc_xml_filename);
1075 $info_mess .= " metaname = $metaname\n" if defined($metaname);
1076 $info_mess .= " metapos = $metapos\n" if defined($metapos);
1077 $info_mess .= " metavalue = $metavalue\n" if defined($metavalue);
1078 $info_mess .= " metamode = $metamode\n" if defined($metamode);
1079 $info_mess .= " opt_secnum = $opt_secnum\n" if defined($opt_secnum);
1080 $info_mess .= " prevmetaval = $prevmetavalue\n" if defined($prevmetavalue);
1081
1082 $info_mess .= "****************************\n";
1083
1084 $gsdl_cgi->generate_message($info_mess);
1085
1086 # To monitor which section/subsection number we are in
1087 my @start_rules =
1088 ( 'Section' => \&dxml_start_section );
1089
1090 # use XML::Rules to add it in (read in and out again)
1091 # Set the call back functions
1092 my @rules =
1093 ( _default => 'raw',
1094 'Metadata' => \&dxml_metadata,
1095 'Description' => \&dxml_description,
1096 'Archive' => \&dxml_archive); # just for catching errors at end
1097
1098 # Sets the parameters
1099 my $options = { 'metaname' => $metaname,
1100 'metapos' => $metapos,
1101 'metavalue' => $metavalue,
1102 'metamode' => $metamode,
1103 'prevmetavalue' => $prevmetavalue };
1104
1105 if (defined $opt_secnum) {
1106 $options->{'secnum'} = $opt_secnum;
1107 }
1108
1109 $self->edit_xml_file($gsdl_cgi,$doc_xml_filename,\@start_rules,\@rules,$options);
1110}
1111
1112sub set_archives_metadata_entry
1113{
1114 my $self = shift @_;
1115 my ($gsdl_cgi, $archive_dir, $collect_dir, $collect, $infodbtype, $docid, $dv, $metaname, $metapos, $metavalue, $metamode, $prevmetavalue) = @_;
1116
1117 my $info_mess = <<RAWEND;
1118****************************
1119 set_archives_metadata_entry()
1120****************************
1121RAWEND
1122
1123 $info_mess .= " archive_dir = $archive_dir\n" if defined($archive_dir);
1124 $info_mess .= " collect_dir = $collect_dir\n" if defined($collect_dir);
1125 $info_mess .= " collect = $collect\n" if defined($collect);
1126 $info_mess .= " infodbtype = $infodbtype\n" if defined($infodbtype);
1127 $info_mess .= " docid = $docid\n" if defined($docid);
1128 $info_mess .= " metaname = $metaname\n" if defined($metaname);
1129 $info_mess .= " metapos = $metapos\n" if defined($metapos);
1130 $info_mess .= " metavalue = $metavalue\n" if defined($metavalue);
1131 $info_mess .= " metamode = $metamode\n" if defined($metamode);
1132 $info_mess .= " prevmetaval = $prevmetavalue\n" if defined($prevmetavalue);
1133
1134 $info_mess .= "****************************\n";
1135
1136 $gsdl_cgi->generate_message($info_mess);
1137
1138 # Obtain the doc.xml path for the specified docID
1139 my ($docid_root,$docid_secnum) = ($docid =~ m/^(.*?)(\..*)?$/);
1140
1141 my $arcinfo_doc_filename = &dbutil::get_infodb_file_path($infodbtype, "archiveinf-doc", $archive_dir);
1142 my $doc_rec = &dbutil::read_infodb_entry($infodbtype, $arcinfo_doc_filename, $docid_root);
1143 my $doc_xml_file = $doc_rec->{'doc-file'}->[0];
1144
1145 # check if request if for file-level doc-version history 'nminus-<n>' version
1146 if (defined $dv && ($dv ne "")) {
1147 # Need to insert '_fldv_history/nminus-<n>' into doc_filename
1148
1149 my ($doc_xml_tailname, $doc_xml_dirname) = File::Basename::fileparse($doc_xml_file);
1150 $doc_xml_file = &util::filename_cat($doc_xml_dirname,$FLDV_HISTORY_DIR,$dv,$doc_xml_tailname);
1151 }
1152
1153 # The $doc_xml_file is relative to the archives, and now let's get the full path
1154 my $archives_dir = &util::filename_cat($collect_dir,$collect,"archives");
1155
1156 my $doc_xml_filename = &util::filename_cat($archives_dir,$doc_xml_file);
1157
1158 # If we're overriding everything, then $metamode=override combined with $metapos=undefined and $prevmetavalue=undefined
1159 # in which case, we need to remove all metavalues for the metaname at the given (sub)section
1160 # Thereafter, we will finally be setting the overriding metavalue for this metaname
1161 if (!defined $prevmetavalue && !defined $metapos && $metamode eq "override") {
1162 print "override mode with no pos or prev value set. Removing all existing values for $metaname, and setting mode to accumulate for the new value.\n";
1163 # remove all values of $metaname metadata
1164 $self->remove_from_doc_xml($gsdl_cgi, &util::filename_cat($archive_dir, $doc_xml_file), $metaname, undef, undef, $docid_secnum, $metamode);
1165 $metamode = "accumulate";
1166 }
1167 # Edit the doc.xml file with the specified metadata name, value and position.
1168 # TODO: there is a potential problem here as this edit_doc_xml function
1169 # is assuming the simple doc.xml situation where there is only one Section and no SubSections.
1170 # Running import.pl -groupsize will cause this to have multiple sections in one doc.xml
1171
1172 # dxml_metadata method ignores metapos if metamode anything other than override
1173 $self->edit_doc_xml($gsdl_cgi,$doc_xml_filename,
1174 $metaname,$metavalue,$metapos,$metamode,$docid_secnum,$prevmetavalue);
1175
1176 # return 0; # return 0 for now to indicate no error
1177 return (defined $self->{'error_msg'}) ? 1 : 0;
1178}
1179
1180
1181sub set_archives_metadata
1182{
1183 my $self = shift @_;
1184
1185 my $username = $self->{'username'};
1186 my $collect = $self->{'collect'};
1187 my $gsdl_cgi = $self->{'gsdl_cgi'};
1188
1189 if ($baseaction::authentication_enabled) {
1190 # Ensure the user is allowed to edit this collection
1191 $self->authenticate_user($username, $collect);
1192 }
1193
1194 # Make sure the collection isn't locked by someone else
1195 $self->lock_collection($username, $collect);
1196
1197 $self->_set_archives_metadata(@_);
1198
1199 # Release the lock once it is done
1200 $self->unlock_collection($username, $collect);
1201}
1202
1203sub _set_archives_metadata_array
1204{
1205 my $self = shift @_;
1206
1207 my $collect = $self->{'collect'};
1208 my $gsdl_cgi = $self->{'gsdl_cgi'};
1209
1210 # Obtain the collect dir
1211 my $site = $self->{'site'};
1212 my $collect_dir = $gsdl_cgi->get_collection_dir($site);
1213
1214 # look up additional args
1215
1216 my $infodbtype = $self->{'infodbtype'};
1217
1218 my $archive_dir = &util::filename_cat($collect_dir,$collect,"archives");
1219
1220 my $json_str = $self->{'json'};
1221 my $doc_array = decode_json $json_str;
1222
1223
1224 my $global_status = 0;
1225 my $global_mess = "";
1226
1227 my @all_docids = ();
1228
1229 foreach my $doc_array_rec ( @$doc_array ) {
1230 my $status = -1;
1231 my $docid = $doc_array_rec->{'docid'};
1232 my $dv = $doc_array_rec->{'dv'};
1233
1234 push(@all_docids,$docid);
1235
1236 my $metaname = $doc_array_rec->{'metaname'};
1237 if(defined $metaname) {
1238
1239 my $metapos = $doc_array_rec->{'metapos'}; # don't force undef to 0. Undef has meaning when metamode=override
1240
1241 my $metamode = $doc_array_rec->{'metamode'} || $self->{'metamode'};
1242 my $metavalue = $doc_array_rec->{'metavalue'};
1243 my $prevmetavalue = $self->{'prevmetavalue'}; # to make this sub behave as _set_archives_metadata
1244
1245
1246 if ((!defined $metamode) || ($metamode =~ m/^\s*$/)) {
1247 # make "accumulate" the default (less destructive, as it won't actually
1248 # delete any existing values)
1249 $metamode = "accumulate";
1250 }
1251
1252 $status = $self->set_archives_metadata_entry($gsdl_cgi,$archive_dir, $collect_dir,$collect, $infodbtype,
1253 $docid,$dv, $metaname,$metapos,$metavalue,$metamode,$prevmetavalue);
1254 } elsif (defined $doc_array_rec->{'metatable'}) { # if no metaname, we expect a metatable
1255 my $metatable = $doc_array_rec->{'metatable'}; # a subarray, or need to generate an error saying JSON structure is wrong
1256
1257 foreach my $metatable_rec ( @$metatable ) {
1258 $metaname = $metatable_rec->{'metaname'};
1259 my $metamode = $metatable_rec->{'metamode'} || $doc_array_rec->{'metamode'} || $self->{'metamode'};
1260 my $metapos = undef;
1261 my $prevmetavalue = undef;
1262 my $metavals = $metatable_rec->{'metavals'}; # a sub-subarray
1263
1264 foreach my $metavalue ( @$metavals ) {
1265 $status = $self->set_archives_metadata_entry($gsdl_cgi,$archive_dir, $collect_dir,$collect,$infodbtype,
1266 $docid,$dv, $metaname,$metapos,$metavalue,$metamode,$prevmetavalue);
1267
1268 if($metamode eq "override") { # now, having overridden the metavalue for the first,
1269 # need to accumulate subsequent metavals for this metaname, else the just-assigned
1270 # metavalue for this metaname will be lost
1271 $metamode = "accumulate";
1272 }
1273 }
1274 }
1275 }
1276
1277 if ($status != 0) {
1278 # Catch error if set infodb entry failed
1279 $global_status = $status;
1280 $global_mess .= "Failed to set metadata key: $docid\n";
1281 $global_mess .= "Exit status: $status\n";
1282 $global_mess .= "System Error Message: $!\n";
1283 $global_mess .= "-" x 20 . "\n";
1284 }
1285 }
1286
1287 if ($global_status != 0) {
1288 $global_mess .= "PATH: $ENV{'PATH'}\n";
1289 $gsdl_cgi->generate_error($global_mess);
1290 }
1291 else {
1292 my $mess = "set-archives-metadata-array successful: Keys[ ".join(", ",@all_docids)."]\n";
1293 $gsdl_cgi->generate_ok_message($mess);
1294 }
1295}
1296
1297sub set_archives_metadata_array
1298{
1299 my $self = shift @_;
1300
1301 my $username = $self->{'username'};
1302 my $collect = $self->{'collect'};
1303 my $gsdl_cgi = $self->{'gsdl_cgi'};
1304
1305 if ($baseaction::authentication_enabled) {
1306 # Ensure the user is allowed to edit this collection
1307 $self->authenticate_user($username, $collect); #&authenticate_user($gsdl_cgi, $username, $collect);
1308 }
1309
1310 # Obtain the collect dir
1311 my $site = $self->{'site'};
1312 my $collect_dir = $gsdl_cgi->get_collection_dir($site);
1313
1314 $gsdl_cgi->checked_chdir($collect_dir);
1315
1316 # Make sure the collection isn't locked by someone else
1317 $self->lock_collection($username, $collect);
1318
1319 $self->_set_archives_metadata_array(@_);
1320
1321 # Release the lock once it is done
1322 $self->unlock_collection($username, $collect);
1323}
1324
1325sub _remove_archives_metadata
1326{
1327 my $self = shift @_;
1328
1329 my $collect = $self->{'collect'};
1330 my $gsdl_cgi = $self->{'gsdl_cgi'};
1331 my $infodbtype = $self->{'infodbtype'};
1332
1333
1334 # Obtain the collect and archive dir
1335 my $site = $self->{'site'};
1336 my $collect_dir = $gsdl_cgi->get_collection_dir($site);
1337
1338 my $archive_dir = &util::filename_cat($collect_dir,$collect,"archives");
1339
1340 # look up additional args
1341 my ($docid, $docid_secnum) = ($self->{'d'} =~ m/^(.*?)(\..*)?$/);
1342
1343 my $metaname = $self->{'metaname'};
1344 my $metapos = $self->{'metapos'};
1345 my $metavalue = $self->{'metavalue'};
1346
1347 $metapos = undef if(defined $metapos && ($metapos =~ m/^\s*$/));
1348 $metavalue = undef if(defined $metavalue && ($metavalue =~ m/^\s*$/)); # necessary to force fallback to undef here
1349
1350 # if the user hasn't told us what to delete, not having given a metavalue or metapos,
1351 # default to deleting the first metavalue for the given metaname
1352 # Beware that if both metapos AND metavalue are defined, both matches (if any)
1353 # seem to get deleted in one single remove_archives_meta action invocation.
1354 # Similarly, if 2 identical metavalues for a metaname exist and that metavalue is being
1355 # deleted, both get deleted.
1356 if(!defined $metapos && !defined $metavalue) {
1357 $metapos = 0;
1358 }
1359
1360 my $metamode = $self->{'metamode'};
1361 $metamode = undef if(defined $metamode && ($metamode =~ m/^\s*$/));
1362
1363 my $arcinfo_doc_filename = &dbutil::get_infodb_file_path($infodbtype, "archiveinf-doc", $archive_dir);
1364 my $doc_rec = &dbutil::read_infodb_entry($infodbtype, $arcinfo_doc_filename, $docid);
1365
1366 # This now stores the full pathname
1367 my $doc_file = $doc_rec->{'doc-file'}->[0];
1368
1369 # check if request if for file-level doc-version history 'nminus-<n>' version
1370 my $dv = $self->{'dv'};
1371 if (defined $dv && ($dv ne "")) {
1372 # Need to insert '_fldv_history/nminus-<n>' into doc_filename
1373
1374 my ($doc_tailname, $doc_dirname) = File::Basename::fileparse($doc_file);
1375 $doc_file = &util::filename_cat($doc_dirname,$FLDV_HISTORY_DIR,$dv,$doc_tailname);
1376 }
1377
1378 my $doc_filename = &util::filename_cat($archive_dir, $doc_file);
1379
1380 my $status = $self->remove_from_doc_xml($gsdl_cgi, $doc_filename, $metaname, $metapos, $metavalue, $docid_secnum, $metamode);
1381# my $status = $self->remove_from_doc_xml($gsdl_cgi, $doc_filename, $metaname, $metapos, undef, $docid_secnum);
1382
1383 if ($status == 0)
1384 {
1385 my $mess = "\nremove-archives-metadata successful: \nKey[$docid]\n";
1386 $mess .= " $metaname";
1387 $mess .= "->[$metapos]" if (defined $metapos);
1388 $mess .= " ($metavalue)" if (defined $metavalue);
1389 $gsdl_cgi->generate_ok_message($mess);
1390 }
1391 else
1392 {
1393 my $mess .= "Failed to remove archives metadata key: $docid\n";
1394 $mess .= "Exit status: $status\n";
1395 $mess .= "System Error Message: $!\n";
1396 $mess .= "-" x 20 . "\n";
1397
1398 $gsdl_cgi->generate_error($mess);
1399 }
1400
1401 #return $status; # in case calling functions have a use for this
1402}
1403
1404sub remove_archives_metadata
1405{
1406 my $self = shift @_;
1407
1408 my $username = $self->{'username'};
1409 my $collect = $self->{'collect'};
1410 my $gsdl_cgi = $self->{'gsdl_cgi'};
1411
1412 if ($baseaction::authentication_enabled)
1413 {
1414 # Ensure the user is allowed to edit this collection
1415 $self->authenticate_user($username, $collect); #&authenticate_user($gsdl_cgi, $username, $collect);
1416 }
1417
1418 # Make sure the collection isn't locked by someone else
1419 $self->lock_collection($username, $collect);
1420
1421 $self->_remove_archives_metadata(@_);
1422
1423 # Release the lock once it is done
1424 $self->unlock_collection($username, $collect);
1425}
1426
1427sub remove_from_doc_xml
1428{
1429 my $self = shift @_;
1430 my ($gsdl_cgi, $doc_xml_filename, $metaname, $metapos, $metavalue, $secid, $metamode) = @_;
1431
1432 my @start_rules = ('Section' => \&dxml_start_section);
1433
1434 # Set the call-back functions for the metadata tags
1435 my @rules =
1436 (
1437 _default => 'raw',
1438 'Metadata' => \&rfdxml_metadata
1439 );
1440
1441 my $parser = XML::Rules->new
1442 (
1443 start_rules => \@start_rules,
1444 rules => \@rules,
1445 style => 'filter',
1446 output_encoding => 'utf8',
1447# normalisespaces => 1, # http://search.cpan.org/~jenda/XML-Rules-1.16/lib/XML/Rules.pm
1448 stripspaces => 2|0|0 # ineffectual
1449 );
1450
1451 my $status = 0;
1452 my $xml_in = "";
1453 if (!open(MIN,"<$doc_xml_filename"))
1454 {
1455 $gsdl_cgi->generate_error("Unable to read in $doc_xml_filename: $!");
1456 $status = 1;
1457 }
1458 else
1459 {
1460 # Read them in
1461 my $line;
1462 while (defined ($line=<MIN>)) {
1463 $xml_in .= $line if($line !~ m/^\s*$/); # preserve all but empty lines
1464 }
1465 close(MIN);
1466
1467 # Filter with the call-back functions
1468 my $xml_out = "";
1469
1470 my $MOUT;
1471 if (!open($MOUT,">$doc_xml_filename")) {
1472 $gsdl_cgi->generate_error("Unable to write out to $doc_xml_filename: $!");
1473 $status = 1;
1474 }
1475 else {
1476 binmode($MOUT,":utf8");
1477 $parser->filter($xml_in, $MOUT, {metaname => $metaname, metapos => $metapos, metavalue => $metavalue, secid => $secid, metamode => $metamode});
1478 close($MOUT);
1479 }
1480 }
1481 return $status;
1482}
1483
1484sub rfdxml_metadata
1485{
1486 my ($tagname, $attrHash, $contextArray, $parentDataArray, $parser) = @_;
1487
1488 # For comparisons, toplevel section is indicated by ""
1489 my $curr_sec_num = $parser->{'parameters'}->{'curr_section_num'} || "";
1490 my $secid = $parser->{'parameters'}->{'secid'} || "";
1491
1492 if (!($secid eq $curr_sec_num))
1493 {
1494 # RAW is [$tagname => $attrHash] not $tagname => $attrHash!!
1495 return [$tagname => $attrHash];
1496 }
1497
1498 if ($parser->{'parameters'}->{'metaname'} eq $attrHash->{'name'})
1499 {
1500 if (!defined $parser->{'parameters'}->{'poscount'})
1501 {
1502 $parser->{'parameters'}->{'poscount'} = 0;
1503 }
1504 else
1505 {
1506 $parser->{'parameters'}->{'poscount'}++;
1507 }
1508
1509 # if overriding (for set-meta) but no metapos, then clear all the meta for this metaname
1510 if ((defined $parser->{'parameters'}->{'metamode'}) && ($parser->{'parameters'}->{'metamode'} eq "override") && (!defined $parser->{'parameters'}->{'metapos'}) &&(!defined $parser->{'parameters'}->{'metavalue'})) {
1511 return [];
1512 }
1513
1514 if ((defined $parser->{'parameters'}->{'metapos'}) && ($parser->{'parameters'}->{'poscount'} == $parser->{'parameters'}->{'metapos'}))
1515 {
1516 return [];
1517 }
1518
1519 if ((defined $parser->{'parameters'}->{'metavalue'}) && ($parser->{'parameters'}->{'metavalue'} eq $attrHash->{'_content'}))
1520 {
1521 return [];
1522 }
1523 }
1524
1525 # RAW is [$tagname => $attrHash] not $tagname => $attrHash!!
1526 return [$tagname => $attrHash];
1527}
1528
1529sub mxml_metadata
1530{
1531 my ($tagname, $attrHash, $contextArray, $parentDataArray, $parser) = @_;
1532 my $metaname = $parser->{'parameters'}->{'metaname'};
1533 my $metamode = $parser->{'parameters'}->{'metamode'};
1534
1535 # Report error if we don't see FileName tag before this
1536 die "Fatal Error: Unexpected metadata.xml structure. Undefined current_file, possibly encountered Description before FileName" if (!defined($parser->{'parameters'}->{'current_file'}));
1537
1538 # Don't do anything if we are not in the right FileSet
1539 my $file_regexp = $parser->{'parameters'}->{'current_file'};
1540 if ($file_regexp =~ /\.\*/) {
1541 # Only interested in a file_regexp if it specifies precisely one
1542 # file.
1543 # So, skip anything with a .* in it as it is too general
1544## print STDERR "@@@@ Skipping entry in metadata.xml where FileName=.* as it is too general\n";
1545 return [$tagname => $attrHash];
1546 }
1547 my $src_file = $parser->{'parameters'}->{'src_file'};
1548 if (!($src_file =~ /$file_regexp/)) {
1549 return [$tagname => $attrHash];
1550 }
1551## print STDERR "*** mxl metamode = $metamode\n";
1552
1553 # Find the right metadata tag and checks if we are going to override it
1554 my $name_attr = $attrHash->{'name'};
1555 if (($name_attr eq $metaname) && ($metamode eq "override")) {
1556
1557 # now metadata.xml functions need to keep track of metapos
1558 if (!defined $parser->{'parameters'}->{'poscount'})
1559 {
1560 $parser->{'parameters'}->{'poscount'} = 0;
1561 }
1562 else
1563 {
1564 $parser->{'parameters'}->{'poscount'}++;
1565 }
1566
1567 # If either the metapos or prevmetavalue is set,
1568 # get the value and override the current value
1569 my $metavalue = $parser->{'parameters'}->{'metavalue'};
1570
1571 if(defined $parser->{'parameters'}->{'prevmetavalue'} && $parser->{'parameters'}->{'prevmetavalue'} eq $attrHash->{'_content'})
1572 {
1573 $attrHash->{'_content'} = $metavalue;
1574
1575 ## print STDERR "**** overriding metadata.xml\n";
1576
1577 # Don't want it to wipe out any other pieces of metadata
1578 $parser->{'parameters'}->{'metamode'} = "done";
1579 }
1580 elsif(defined $parser->{'parameters'}->{'metapos'} && $parser->{'parameters'}->{'poscount'} == $parser->{'parameters'}->{'metapos'})
1581 {
1582 $attrHash->{'_content'} = $metavalue;
1583 $parser->{'parameters'}->{'metamode'} = "done";
1584 }
1585 }
1586
1587 # mxml_description will process the metadata if metadata is accumulate,
1588 # or if we haven't found the metadata to override
1589
1590 # RAW is [$tagname => $attrHash] not $tagname => $attrHash!!
1591 return [$tagname => $attrHash];
1592}
1593
1594
1595sub mxml_description
1596{
1597 my ($tagname, $attrHash, $contextArray, $parentDataArray, $parser) = @_;
1598 my $metamode = $parser->{'parameters'}->{'metamode'};
1599
1600 # Failed... Report error if we don't see FileName tag before this
1601 die "Fatal Error: Unexpected metadata.xml structure. Undefind current_file, possiblely encountered Description before FileName" if (!defined($parser->{'parameters'}->{'current_file'}));
1602
1603 # Don't do anything if we are not in the right FileSet
1604 my $file_regexp = $parser->{'parameters'}->{'current_file'};
1605 if ($file_regexp =~ m/\.\*/) {
1606 # Only interested in a file_regexp if it specifies precisely one
1607 # file.
1608 # So, skip anything with a .* in it as it is too general
1609 return [$tagname => $attrHash];
1610 }
1611 my $src_file = $parser->{'parameters'}->{'src_file'};
1612
1613 if (!($src_file =~ m/$file_regexp/)) {
1614 return [$tagname => $attrHash];
1615 }
1616
1617 # Accumulate the metadata block to the end of the description block
1618 # Note: This adds metadata block to all description blocks, so if there are
1619 # multiple FileSets, it will add to all of them
1620 if (($metamode eq "accumulate") || ($metamode eq "override")) {
1621
1622 # if metamode was "override" but get to here then it failed to
1623 # find an item to override, in which case it should append its
1624 # value to the end, just like the "accumulate" mode
1625
1626 if ($metamode eq "override") {
1627 print "No metadata value to override. Switching 'metamode' to accumulate\n";
1628 }
1629
1630 # tack a new metadata tag on to the end of the <Metadata>+ block
1631 my $metaname = $parser->{'parameters'}->{'metaname'};
1632 my $metavalue = $parser->{'parameters'}->{'metavalue'};
1633
1634 my $metadata_attr = { '_content' => $metavalue,
1635 'name' => $metaname,
1636 'mode' => "accumulate" };
1637
1638 my $append_metadata = [ "Metadata" => $metadata_attr ];
1639 my $description_content = $attrHash->{'_content'};
1640
1641## print STDERR "*** appending to metadata.xml\n";
1642
1643 # append the new metadata element to the end of the current
1644 # content contained inside this tag
1645 if (ref($description_content) eq "") {
1646 # => string or numeric literal
1647 # this is caused by a <Description> block has no <Metadata> child elements
1648 # => set up an empty array in '_content'
1649 $attrHash->{'_content'} = [ "\n" ];
1650 $description_content = $attrHash->{'_content'};
1651 }
1652
1653 push(@$description_content, " ", $append_metadata, "\n ");
1654 $parser->{'parameters'}->{'metamode'} = "done";
1655 }
1656
1657 # RAW is [$tagname => $attrHash] not $tagname => $attrHash!!
1658 return [$tagname => $attrHash];
1659}
1660
1661
1662sub mxml_fileset
1663{
1664 my ($tagname, $attrHash, $contextArray, $parentDataArray, $parser) = @_;
1665
1666 # Initilise the current_file
1667 # Note: According to http://greenstone.org/dtd/DirectoryMetadata/1.0/DirectoryMetadata.dtd
1668 # FileName tag must come before Description tag
1669 $parser->{'parameters'}->{'current_file'} = "";
1670
1671 # RAW is [$tagname => $attrHash] not $tagname => $attrHash!!
1672 return [$tagname => $attrHash];
1673}
1674
1675sub mxml_directorymetadata
1676{
1677 my ($tagname, $attrHash, $contextArray, $parentDataArray, $parser) = @_;
1678
1679 # if we haven't processed the metadata when we reach the end of metadata.xml
1680 # it's because there's no particular FileSet element whose FileName matched
1681 # In which case, add a new FileSet for this FileName
1682 my $metamode = $parser->{'parameters'}->{'metamode'};
1683 if($metamode ne "done") {
1684
1685 if ($metamode eq "override") {
1686 print "No metadata value to override. Switching 'metamode' to accumulate\n";
1687 }
1688
1689 # If we get to here and metamode is override, this means there
1690 # was no existing value to overide => treat as an append operation
1691
1692 # Create a new FileSet element and append to DirectoryMetadata
1693 # <FileSet>
1694 # <FileName>src_file</FileName>
1695 # <Description>
1696 # <Metadata mode="" name="">metavalue</Metadata>
1697 # </Description>
1698 # </FileSet>
1699 my $src_file = $parser->{'parameters'}->{'src_file'};
1700 my $metaname = $parser->{'parameters'}->{'metaname'};
1701 my $metavalue = $parser->{'parameters'}->{'metavalue'};
1702 my $metadata_attr = {
1703 '_content' => $metavalue,
1704 'name' => $metaname,
1705 'mode' => "accumulate"
1706 };
1707 my $append_metadata = [ "Metadata" => $metadata_attr ];
1708 my $description_attr = { '_content' => [ "\n\t\t ", $append_metadata, "\n\t\t"] };
1709 my $description_element = [ "Description" => $description_attr ];
1710
1711 #_content is not an attribute, it's special and holds the children of this element
1712 # including the textnode value embedded in this element if any.
1713 my $filename_attr = {'_content' => $src_file};
1714 my $filename_element = [ "FileName" => $filename_attr ];
1715
1716 my $fileset_attr = {};
1717 $fileset_attr->{'_content'} = [ "\n\t\t", $filename_element,"\n\t\t",$description_element ,"\n\t" ];
1718 my $fileset = [ "FileSet" => $fileset_attr ]; #my $fileset = [ "FileSet" => {} ];
1719
1720
1721 # get children of dirmeta, and push the new FileSet element onto it
1722 print "Appending metadata to metadata.xml\n";
1723 my $dirmeta_content = $attrHash->{'_content'};
1724 if (ref($dirmeta_content)) {
1725 # got some existing interesting nested content
1726 #push(@$dirmeta_content, " ", $fileset ,"\n ");
1727 push(@$dirmeta_content, "\t", $fileset ,"\n");
1728 }
1729 else {
1730 #description_content is most likely a string such as "\n"
1731 #$attrHash->{'_content'} = [$dirmeta_content, " ", $fileset ,"\n" ];
1732 $attrHash->{'_content'} = [$dirmeta_content, "\t", $fileset ,"\n" ];
1733 }
1734
1735 $parser->{'parameters'}->{'metamode'} = "done";
1736 }
1737 # RAW is [$tagname => $attrHash] not $tagname => $attrHash!!
1738 return [$tagname => $attrHash];
1739}
1740
1741
1742sub edit_metadata_xml
1743{
1744 my $self = shift @_;
1745 my ($gsdl_cgi, $metadata_xml_filename, $metaname, $metapos, $metavalue, $metamode, $src_file, $prevmetavalue) = @_;
1746
1747 # Set the call-back functions for the metadata tags
1748 my @rules =
1749 ( _default => 'raw',
1750 'FileName' => \&mxml_filename,
1751 'Metadata' => \&mxml_metadata,
1752 'Description' => \&mxml_description,
1753 'FileSet' => \&mxml_fileset,
1754 'DirectoryMetadata' => \&mxml_directorymetadata);
1755
1756 # use XML::Rules to add it in (read in and out again)
1757 my $parser = XML::Rules->new(rules => \@rules,
1758 style => 'filter',
1759 output_encoding => 'utf8',
1760 stripspaces => 2|0|0); # http://search.cpan.org/~jenda/XML-Rules-1.16/lib/XML/Rules.pm
1761
1762 if (!-e $metadata_xml_filename) {
1763
1764 if (open(MOUT,">$metadata_xml_filename")) {
1765
1766 my $src_file_re = &util::filename_to_regex($src_file);
1767 # shouldn't the following also be in the above utility routine??
1768 # $src_file_re =~ s/\./\\./g;
1769
1770 print MOUT "<?xml version=\"1.0\"?>\n";
1771 print MOUT "<DirectoryMetadata>\n";
1772 print MOUT " <FileSet>\n";
1773 print MOUT " <FileName>$src_file_re</FileName>\n";
1774 print MOUT " <Description>\n";
1775 print MOUT " </Description>\n";
1776 print MOUT " </FileSet>\n";
1777 print MOUT "</DirectoryMetadata>\n";
1778
1779 close(MOUT);
1780 }
1781 else {
1782 $gsdl_cgi->generate_error("Unable to create $metadata_xml_filename: $!");
1783 }
1784 }
1785
1786
1787 my $xml_in = "";
1788 if (!open(MIN,"<$metadata_xml_filename")) {
1789 $gsdl_cgi->generate_error("Unable to read in $metadata_xml_filename: $!");
1790 }
1791 else {
1792 # Read them in
1793 my $line;
1794 while (defined ($line=<MIN>)) {
1795 $xml_in .= $line if($line !~ m/^\s*$/); # preserve all but empty lines
1796 }
1797 close(MIN);
1798
1799 # Filter with the call-back functions
1800 my $xml_out = "";
1801
1802 my $MOUT;
1803 if (!open($MOUT,">$metadata_xml_filename")) {
1804 $gsdl_cgi->generate_error("Unable to write out to $metadata_xml_filename: $!");
1805 }
1806 else {
1807 binmode($MOUT,":utf8");
1808
1809 # Some wise person please find out how to keep the DTD and encode lines in after it gets filtered by this XML::Rules
1810 # At the moment, I will just hack it!
1811 #my $header_with_utf8_dtd = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
1812 #$header_with_utf8_dtd .= "<!DOCTYPE DirectoryMetadata SYSTEM \"http://greenstone.org/dtd/DirectoryMetadata/1.0/DirectoryMetadata.dtd\">";
1813 #$xml_out =~ s/\<\?xml\sversion\=\"1.0\"\?\>/$header_with_utf8_dtd/;
1814 #print MOUT $xml_out;
1815
1816 $parser->filter($xml_in, $MOUT, { metaname => $metaname,
1817 metapos => $metapos,
1818 metavalue => $metavalue,
1819 metamode => $metamode,
1820 src_file => $src_file,
1821 prevmetavalue => $prevmetavalue,
1822 current_file => undef} );
1823 close($MOUT);
1824 }
1825 }
1826}
1827
1828
1829sub set_import_metadata
1830{
1831 my $self = shift @_;
1832
1833 my $username = $self->{'username'};
1834 my $collect = $self->{'collect'};
1835 my $gsdl_cgi = $self->{'gsdl_cgi'};
1836
1837 if ($baseaction::authentication_enabled) {
1838 # Ensure the user is allowed to edit this collection
1839 $self->authenticate_user($username, $collect);
1840 }
1841
1842 # Make sure the collection isn't locked by someone else
1843 $self->lock_collection($username, $collect);
1844
1845 $self->_set_import_metadata(@_);
1846
1847 # Release the lock once it is done
1848 $self->unlock_collection($username, $collect);
1849
1850}
1851
1852sub set_import_metadata_array
1853{
1854 my $self = shift @_;
1855
1856 my $username = $self->{'username'};
1857 my $collect = $self->{'collect'};
1858 my $gsdl_cgi = $self->{'gsdl_cgi'};
1859
1860 if ($baseaction::authentication_enabled) {
1861 # Ensure the user is allowed to edit this collection
1862 $self->authenticate_user($username, $collect); #&authenticate_user($gsdl_cgi, $username, $collect);
1863 }
1864
1865 # Obtain the collect dir
1866 my $site = $self->{'site'};
1867 my $collect_dir = $gsdl_cgi->get_collection_dir($site);
1868
1869 $gsdl_cgi->checked_chdir($collect_dir);
1870
1871 # Make sure the collection isn't locked by someone else
1872 $self->lock_collection($username, $collect);
1873
1874 $self->_set_import_metadata_array(@_);
1875
1876 # Release the lock once it is done
1877 $self->unlock_collection($username, $collect);
1878
1879}
1880
1881
1882sub _set_import_metadata_array
1883{
1884 my $self = shift @_;
1885
1886 my $collect = $self->{'collect'};
1887 my $gsdl_cgi = $self->{'gsdl_cgi'};
1888
1889 # Obtain the collect dir
1890 my $site = $self->{'site'};
1891 my $collect_dir = $gsdl_cgi->get_collection_dir($site);
1892
1893 # look up additional args
1894
1895 my $infodbtype = $self->{'infodbtype'};
1896
1897 my $archive_dir = &util::filename_cat($collect_dir,$collect,"archives");
1898 my $arcinfo_doc_filename = &dbutil::get_infodb_file_path($infodbtype, "archiveinf-doc", $archive_dir);
1899
1900 my $json_str = $self->{'json'};
1901 my $doc_array = decode_json $json_str;
1902
1903 my $global_status = 0;
1904 my $global_mess = "";
1905
1906 my @all_docids = ();
1907
1908 foreach my $doc_array_rec ( @$doc_array )
1909 {
1910 my $status = -1;
1911 my $docid = $doc_array_rec->{'docid'};
1912
1913 my ($docid_root,$docid_secnum);
1914 if(defined $docid) {
1915 ($docid_root,$docid_secnum) = ($docid =~ m/^(.*?)(\..*)?$/);
1916 # as yet no support for setting subsection metadata in metadata.xml
1917 if ((defined $docid_secnum) && ($docid_secnum !~ m/^\s*$/)) {
1918 $gsdl_cgi->generate_message("*** docid: $docid. No support yet for setting import metadata at subsections level.\n");
1919 next; # skip this docid in for loop
1920 }
1921 }
1922
1923 push(@all_docids,$docid); # docid_root rather
1924
1925 my $metaname = $doc_array_rec->{'metaname'};
1926 if (defined $metaname) {
1927 my $metamode = $doc_array_rec->{'metamode'} || $self->{'metamode'};
1928 my $metavalue = $doc_array_rec->{'metavalue'};
1929 $metavalue =~ s/&lt;(.*?)&gt;/<$1>/g;
1930
1931 if ((!defined $metamode) || ($metamode =~ m/^\s*$/)) {
1932 # make "accumulate" the default (less destructive, as it won't actually
1933 # delete any existing values)
1934 $metamode = "accumulate";
1935 }
1936
1937 # adding metapos and prevmetavalue support to import_metadata subroutines
1938 my $metapos = $doc_array_rec->{'metapos'}; # don't force undef to 0. Undef has meaning when metamode=override
1939 my $prevmetavalue = $self->{'prevmetavalue'};
1940
1941 $self->set_import_metadata_entry($gsdl_cgi, $arcinfo_doc_filename, $infodbtype, $docid_root, $metaname, $metapos, $metavalue, $metamode, $prevmetavalue, $collect, $collect_dir); # at this point, docid_root = docid
1942
1943 } elsif (defined $doc_array_rec->{'metatable'}) { # if no metaname, we expect a metatable
1944 my $metatable = $doc_array_rec->{'metatable'}; # a subarray, or need to generate an error saying JSON structure is wrong
1945
1946 foreach my $metatable_rec ( @$metatable ) {
1947 $metaname = $metatable_rec->{'metaname'};
1948 my $metamode = $metatable_rec->{'metamode'} || $doc_array_rec->{'metamode'} || $self->{'metamode'};
1949 if ((!defined $metamode) || ($metamode =~ m/^\s*$/)) {
1950 # make "accumulate" the default (less destructive, as it won't actually
1951 # delete any existing values)
1952 $metamode = "accumulate";
1953 }
1954
1955 # No support for metapos and prevmetavalue in the JSON metatable substructure
1956 my $metapos = undef;
1957 my $prevmetavalue = undef;
1958 my $metavals = $metatable_rec->{'metavals'}; # a sub-subarray
1959
1960 foreach my $metavalue ( @$metavals ) {
1961 $metavalue =~ s/&lt;(.*?)&gt;/<$1>/g;
1962
1963 $self->set_import_metadata_entry($gsdl_cgi, $arcinfo_doc_filename, $infodbtype, $docid_root, $metaname, $metapos, $metavalue, $metamode, $prevmetavalue, $collect, $collect_dir); # at this point, docid_root = docid
1964 if($metamode eq "override") { # now, having overridden the first metavalue of the metaname,
1965 # need to accumulate subsequent metavals for this metaname, else the just-assigned
1966 # metavalue for this metaname will be lost
1967 $metamode = "accumulate";
1968 }
1969 }
1970 }
1971 }
1972 }
1973
1974 # always a success message
1975 my $mess = "set-archives-metadata-array successful: Keys[ ".join(", ",@all_docids)."]\n";
1976 $gsdl_cgi->generate_ok_message($mess);
1977}
1978
1979# always returns true (1)
1980sub set_import_metadata_entry
1981{
1982 my $self = shift @_;
1983 my ($gsdl_cgi, $arcinfo_doc_filename, $infodbtype, $docid, $metaname, $metapos, $metavalue, $metamode, $prevmetavalue, $collect, $collect_dir) = @_;
1984
1985 my $info_mess = <<RAWEND;
1986****************************
1987 set_import_metadata_entry()
1988****************************
1989RAWEND
1990
1991 $info_mess .= " collect_dir = $collect_dir\n" if defined($collect_dir);
1992 $info_mess .= " collect = $collect\n" if defined($collect);
1993 $info_mess .= " infodbtype = $infodbtype\n" if defined($infodbtype);
1994 $info_mess .= " arcinfo_doc_filename = $arcinfo_doc_filename\n" if defined($arcinfo_doc_filename);
1995 $info_mess .= " docid = $docid\n" if defined($docid);
1996 $info_mess .= " metaname = $metaname\n" if defined($metaname);
1997 $info_mess .= " metapos = $metapos\n" if defined($metapos);
1998 $info_mess .= " metavalue = $metavalue\n" if defined($metavalue);
1999 $info_mess .= " metamode = $metamode\n" if defined($metamode);
2000 $info_mess .= " prevmetaval = $prevmetavalue\n" if defined($prevmetavalue);
2001
2002 $info_mess .= "****************************\n";
2003
2004 $gsdl_cgi->generate_message($info_mess);
2005
2006 # import works with metadata.xml which can have inherited metadata
2007 # so setting or removing at a metapos can have unintended effects for a COMPLEX collection
2008 # (a collection that has or can have inherited metadata). Metapos has expected behaviour for
2009 # a SIMPLE collection, which is one that doesn't have inherited metadata. Assume caller knows
2010 # what they're doing if they provide a metapos.
2011 if(defined $metapos) {
2012 print STDERR "@@@@ WARNING: metapos defined.\n";
2013 print STDERR "@@@@ Assuming SIMPLE collection and proceeding to modify the import meta at $metapos.\n";
2014 }
2015
2016 # Obtain where the metadata.xml is from the archiveinfo-doc.gdb file
2017 # If the doc oid is not specified, we assume the metadata.xml is next to the specified "f"
2018 my $metadata_xml_file;
2019 my $import_filename = undef;
2020
2021 if (defined $docid) {
2022 # my $arcinfo_doc_filename = &dbutil::get_infodb_file_path($infodbtype, "archiveinf-doc", $archive_dir);
2023 my $doc_rec = &dbutil::read_infodb_entry($infodbtype, $arcinfo_doc_filename, $docid);
2024
2025 # This now stores the full pathname
2026 $import_filename = $doc_rec->{'src-file'}->[0];
2027 $import_filename = &util::placeholders_to_abspath($import_filename);
2028
2029 } else { # only for set_import_meta, not the case when calling method is set_import_metadata_array
2030 # as the array version of the method doesn't support the -f parameter yet
2031 my $import_file = $self->{'f'};
2032 $import_filename = &util::filename_cat($collect_dir,$collect,$import_file);
2033 }
2034
2035 # figure out correct metadata.xml file [?]
2036 # Assuming the metadata.xml file is next to the source file
2037 # Note: This will not work if it is using the inherited metadata from the parent folder
2038 my ($import_tailname, $import_dirname) = File::Basename::fileparse($import_filename);
2039 my $metadata_xml_filename = &util::filename_cat($import_dirname,"metadata.xml");
2040
2041 # If we're overriding everything, then $prevmetavalue=undefined and
2042 # $metamode=override combined with $metapos=undefined
2043 # in which case we need to remove all metavalues for the metaname at the given (sub)section
2044 # Thereafter, we will finally be able to set the overriding metavalue for this metaname
2045 if(!defined $prevmetavalue && !defined $metapos && $metamode eq "override") {
2046## print STDERR "@@@ REMOVING all import metadata for $metaname\n";
2047 $self->remove_from_metadata_xml($gsdl_cgi, $metadata_xml_filename, $metaname, $metapos, undef, $import_tailname, $metamode); # we're removing all values, so metavalue=undef
2048
2049 }
2050
2051 # Edit the metadata.xml
2052 # Modified by Jeffrey from DL Consulting
2053 # Handle the case where there is one metadata.xml file for multiple FileSets
2054 # The XML filter needs to know whether it is in the right FileSet
2055 # TODO: This doesn't fix the problem where the metadata.xml is not next to the src file.
2056 # TODO: This doesn't handle the common metadata (where FileName doesn't point to a single file)
2057 $self->edit_metadata_xml($gsdl_cgi, $metadata_xml_filename, $metaname,
2058 $metapos, $metavalue, $metamode, $import_tailname, $prevmetavalue);
2059 #return 0;
2060 return $metadata_xml_filename;
2061}
2062
2063sub _remove_import_metadata
2064{
2065 my $self = shift @_;
2066
2067 my $collect = $self->{'collect'};
2068 my $gsdl_cgi = $self->{'gsdl_cgi'};
2069 my $infodbtype = $self->{'infodbtype'};
2070
2071 # Obtain the collect and archive dir
2072 my $site = $self->{'site'};
2073 my $collect_dir = $gsdl_cgi->get_collection_dir($site);
2074
2075 my $archive_dir = &util::filename_cat($collect_dir,$collect,"archives");
2076
2077 # look up additional args
2078 my $docid = $self->{'d'};
2079 if ((!defined $docid) || ($docid =~ m/^\s*$/))
2080 {
2081 $gsdl_cgi->generate_error("No docid (d=...) specified.\n");
2082 }
2083
2084 my $metaname = $self->{'metaname'};
2085 my $metapos = $self->{'metapos'};
2086 my $metavalue = $self->{'metavalue'};
2087
2088 $metapos = undef if(defined $metapos && ($metapos =~ m/^\s*$/));
2089 $metavalue = undef if(defined $metavalue && ($metavalue =~ m/^\s*$/));
2090
2091 if(defined $metavalue) { # metavalue is now a compulsory arg for remove_import_metadata()
2092 $metavalue =~ s/&lt;(.*?)&gt;/<$1>/g;
2093 } elsif (!defined $metapos) { # if given no metavalue or metapos to delete, default to deleting the 1st
2094 $metapos = 0;
2095 }
2096 my $metamode = $self->{'metamode'};
2097 $metamode = undef if(defined $metamode && ($metamode =~ m/^\s*$/));
2098
2099 # import works with metadata.xml which can have inherited metadata
2100 # so setting or removing at a metapos can have unintended effects for a COMPLEX collection
2101 # (a collection that has or can have inherited metadata). Metapos has expected behaviour for
2102 # a SIMPLE collection, which is one that doesn't have inherited metadata. Assume caller knows
2103 # what they're doing if they provide a metapos.
2104 if(defined $metapos) {
2105 print STDERR "@@@@ WARNING: metapos defined.\n";
2106 print STDERR "@@@@ Assuming SIMPLE collection and proceeding to modify the import meta at $metapos.\n";
2107 }
2108
2109 # Obtain where the metadata.xml is from the archiveinfo-doc.gdb file
2110 # If the doc oid is not specified, we assume the metadata.xml is next to the specified "f"
2111 my $metadata_xml_file;
2112 my $import_filename = undef;
2113 if (defined $docid)
2114 {
2115 my $arcinfo_doc_filename = &dbutil::get_infodb_file_path($infodbtype, "archiveinf-doc", $archive_dir);
2116 my $doc_rec = &dbutil::read_infodb_entry($infodbtype, $arcinfo_doc_filename, $docid);
2117
2118 # This now stores the full pathname
2119 $import_filename = $doc_rec->{'src-file'}->[0];
2120 $import_filename = &util::placeholders_to_abspath($import_filename);
2121 }
2122
2123 if((!defined $import_filename) || ($import_filename =~ m/^\s*$/))
2124 {
2125 $gsdl_cgi->generate_error("There is no metadata\n");
2126 }
2127
2128 # figure out correct metadata.xml file [?]
2129 # Assuming the metadata.xml file is next to the source file
2130 # Note: This will not work if it is using the inherited metadata from the parent folder
2131 my ($import_tailname, $import_dirname) = File::Basename::fileparse($import_filename);
2132 my $metadata_xml_filename = &util::filename_cat($import_dirname,"metadata.xml");
2133
2134 $self->remove_from_metadata_xml($gsdl_cgi, $metadata_xml_filename, $metaname, $metapos, $metavalue, $import_tailname, $metamode); # metamode has no meaning for removing meta, but is used by set_meta when overriding All
2135
2136 my $mess = "remove-import-metadata successful: Key[$docid] -> $metadata_xml_filename\n";
2137 $mess .= " $metaname";
2138 $mess .= " = $metavalue\n";
2139
2140 $gsdl_cgi->generate_ok_message($mess);
2141
2142 #return $status; # in case calling functions have a use for this
2143}
2144
2145sub remove_import_metadata
2146{
2147 my $self = shift @_;
2148
2149 my $username = $self->{'username'};
2150 my $collect = $self->{'collect'};
2151 my $gsdl_cgi = $self->{'gsdl_cgi'};
2152
2153 if ($baseaction::authentication_enabled) {
2154 # Ensure the user is allowed to edit this collection
2155 $self->authenticate_user($username, $collect); #&authenticate_user($gsdl_cgi, $username, $collect);
2156 }
2157
2158 # Make sure the collection isn't locked by someone else
2159 $self->lock_collection($username, $collect);
2160
2161 $self->_remove_import_metadata(@_);
2162
2163 # Release the lock once it is done
2164 $self->unlock_collection($username, $collect);
2165
2166}
2167
2168sub remove_from_metadata_xml
2169{
2170 my $self = shift @_;
2171 my ($gsdl_cgi, $metadata_xml_filename, $metaname, $metapos, $metavalue, $src_file, $metamode) = @_;
2172 # metamode generally has no meaning for removing meta, but is used by set_meta
2173 # when overriding all metavals for a metaname, in which case remove_meta is called with metamode
2174
2175 # Set the call-back functions for the metadata tags
2176 my @rules =
2177 (
2178 _default => 'raw',
2179 'Metadata' => \&rfmxml_metadata,
2180 'FileName' => \&mxml_filename
2181 );
2182
2183 my $parser = XML::Rules->new
2184 (
2185 rules => \@rules,
2186 style => 'filter',
2187 output_encoding => 'utf8',
2188 #normalisespaces => 1,
2189 stripspaces => 2|0|0 # ineffectual
2190 );
2191
2192 my $xml_in = "";
2193 if (!open(MIN,"<$metadata_xml_filename"))
2194 {
2195 $gsdl_cgi->generate_error("Unable to read in $metadata_xml_filename: $!");
2196 }
2197 else
2198 {
2199 # Read them in
2200 my $line;
2201 while (defined ($line=<MIN>)) {
2202 $xml_in .= $line if($line !~ m/^\s*$/); # preserve all but empty lines
2203 }
2204 close(MIN);
2205
2206 # Filter with the call-back functions
2207 my $xml_out = "";
2208
2209 my $MOUT;
2210 if (!open($MOUT,">$metadata_xml_filename")) {
2211 $gsdl_cgi->generate_error("Unable to write out to $metadata_xml_filename: $!");
2212 }
2213 else {
2214 binmode($MOUT,":utf8");
2215 $parser->filter($xml_in, $MOUT, {metaname => $metaname, metapos => $metapos, metavalue => $metavalue, src_file => $src_file, metamode => $metamode, current_file => undef});
2216 close($MOUT);
2217 }
2218 }
2219}
2220
2221sub rfmxml_metadata
2222{
2223 my ($tagname, $attrHash, $contextArray, $parentDataArray, $parser) = @_;
2224
2225 # metadata.xml does not handle subsections
2226
2227 # since metadata.xml now has to deal with metapos, we keep track of the metadata position
2228 if (($parser->{'parameters'}->{'src_file'} eq $parser->{'parameters'}->{'current_file'})
2229 && $parser->{'parameters'}->{'metaname'} eq $attrHash->{'name'})
2230 {
2231 if (!defined $parser->{'parameters'}->{'poscount'})
2232 {
2233 $parser->{'parameters'}->{'poscount'} = 0;
2234 }
2235 else
2236 {
2237 $parser->{'parameters'}->{'poscount'}++;
2238 }
2239
2240 # if overriding but no metapos, then clear all the meta for this metaname
2241 if ((defined $parser->{'parameters'}->{'metamode'}) && ($parser->{'parameters'}->{'metamode'} eq "override") && (!defined $parser->{'parameters'}->{'metapos'}) && (!defined $parser->{'parameters'}->{'metavalue'})) {
2242 return [];
2243 }
2244
2245 if ((defined $parser->{'parameters'}->{'metapos'}) && ($parser->{'parameters'}->{'poscount'} == $parser->{'parameters'}->{'metapos'}))
2246 {
2247 return [];
2248 }
2249 if ((defined $parser->{'parameters'}->{'metavalue'}) && ($attrHash->{'_content'} eq $parser->{'parameters'}->{'metavalue'}))
2250 {
2251 return [];
2252 }
2253 }
2254
2255 # RAW is [$tagname => $attrHash] not $tagname => $attrHash!!
2256 return [$tagname => $attrHash];
2257}
2258
2259sub _remove_live_metadata
2260{
2261 my $self = shift @_;
2262
2263 my $collect = $self->{'collect'};
2264 my $gsdl_cgi = $self->{'gsdl_cgi'};
2265 my $infodbtype = $self->{'infodbtype'};
2266
2267 # Obtain the collect dir
2268 my $site = $self->{'site'};
2269 my $collect_dir = $gsdl_cgi->get_collection_dir($site);
2270
2271 # look up additional args
2272 my $docid = $self->{'d'};
2273 if ((!defined $docid) || ($docid =~ m/^\s*$/)) {
2274 $gsdl_cgi->generate_error("No docid (d=...) specified.");
2275 }
2276
2277 # Generate the dbkey
2278 my $metaname = $self->{'metaname'};
2279 my $dbkey = "$docid.$metaname";
2280
2281 # To people who know $collect_tail please add some comments
2282 # Obtain the live gdbm_db path
2283 my $collect_tail = $collect;
2284 $collect_tail =~ s/^.*[\/|\\]//;
2285 my $index_text_directory = &util::filename_cat($collect_dir,$collect,"index","text");
2286 my $infodb_file_path = &dbutil::get_infodb_file_path($infodbtype, "live-$collect_tail", $index_text_directory);
2287
2288 # Remove the key
2289 my $cmd = "gdbmdel \"$infodb_file_path\" \"$dbkey\"";
2290 my $status = system($cmd);
2291 if ($status != 0) {
2292 # Catch error if gdbmdel failed
2293 my $mess = "Failed to delete metadata key: $dbkey\n";
2294
2295 $mess .= "PATH: $ENV{'PATH'}\n";
2296 $mess .= "cmd = $cmd\n";
2297 $mess .= "Exit status: $status\n";
2298 $mess .= "System Error Message: $!\n";
2299
2300 $gsdl_cgi->generate_error($mess);
2301 }
2302 else {
2303 $gsdl_cgi->generate_ok_message("DB remove successful: Key[$metaname]");
2304 }
2305
2306}
2307
2308sub remove_live_metadata
2309{
2310 my $self = shift @_;
2311
2312 my $username = $self->{'username'};
2313 my $collect = $self->{'collect'};
2314 my $gsdl_cgi = $self->{'gsdl_cgi'};
2315
2316 if ($baseaction::authentication_enabled) {
2317 # Ensure the user is allowed to edit this collection
2318 $self->authenticate_user($username, $collect); #&authenticate_user($gsdl_cgi, $username, $collect);
2319 }
2320
2321 # Make sure the collection isn't locked by someone else
2322 $self->lock_collection($username, $collect);
2323
2324 $self->_remove_live_metadata(@_);
2325
2326 $self->unlock_collection($username, $collect);
2327}
2328
2329sub remove_metadata
2330{
2331 my $self = shift @_;
2332
2333 my $where = $self->{'where'};
2334 if(!$where || ($where =~ m/^\s*$/)) {
2335 $self->remove_index_metadata(@_); # call the full version of set_index_meta for the default behaviour
2336 return;
2337 }
2338
2339 my $username = $self->{'username'};
2340 my $collect = $self->{'collect'};
2341 my $gsdl_cgi = $self->{'gsdl_cgi'};
2342
2343 if ($baseaction::authentication_enabled) {
2344 # Ensure the user is allowed to edit this collection
2345 $self->authenticate_user($username, $collect); #&authenticate_user($gsdl_cgi, $username, $collect);
2346 }
2347
2348 # Make sure the collection isn't locked by someone else
2349 $self->lock_collection($username, $collect);
2350
2351 # check which directories need to be processed, specified in $where as
2352 # any combination of import|archives|index|live
2353 if($where =~ m/import/) {
2354 $self->_remove_import_metadata(@_);
2355 }
2356 if($where =~ m/archives/) {
2357 $self->_remove_archives_metadata(@_);
2358 }
2359 if($where =~ m/index/) {
2360 $self->_remove_index_metadata(@_);
2361 }
2362
2363 # Release the lock once it is done
2364 $self->unlock_collection($username, $collect);
2365}
2366
2367# the internal version, without authentication
2368sub _remove_index_metadata
2369{
2370 my $self = shift @_;
2371
2372 my $collect = $self->{'collect'};
2373 my $gsdl_cgi = $self->{'gsdl_cgi'};
2374 my $infodbtype = $self->{'infodbtype'};
2375
2376 # Obtain the collect dir
2377 my $site = $self->{'site'};
2378 my $collect_dir = $gsdl_cgi->get_collection_dir($site);
2379
2380 # look up additional args
2381 my $docid = $self->{'d'};
2382 if ((!defined $docid) || ($docid =~ m/^\s*$/)) {
2383 $gsdl_cgi->generate_error("No docid (d=...) specified.");
2384 }
2385 my $metaname = $self->{'metaname'};
2386 my $metapos = $self->{'metapos'};
2387 my $metavalue = $self->{'metavalue'};
2388
2389 $metapos = undef if(defined $metapos && ($metapos =~ m/^\s*$/));
2390 $metavalue = undef if(defined $metavalue && ($metavalue =~ m/^\s*$/)); # necessary to force fallback to undef here
2391
2392 # To people who know $collect_tail please add some comments
2393 # -> In collection groups, I think collect_tailname is the subcollection name,
2394 # e.g. colgroup-name/col-tail-name
2395 # Obtain the path to the database
2396 my $collect_tail = $collect;
2397 $collect_tail =~ s/^.*[\/|\\]//;
2398 my $index_text_directory = &util::filename_cat($collect_dir,$collect,"index","text");
2399 my $infodb_file_path = &dbutil::get_infodb_file_path($infodbtype, $collect_tail, $index_text_directory);
2400
2401 # Read the docid entry
2402 my $doc_rec = &dbutil::read_infodb_entry($infodbtype, $infodb_file_path, $docid);
2403
2404 # Check to make sure the key does exist
2405 if (!defined ($doc_rec->{$metaname})) {
2406 $gsdl_cgi->generate_error("No metadata field \"" . $metaname . "\" in the specified document: [" . $docid . "]");
2407 }
2408
2409 # Obtain the specified metadata pos
2410 # if no metavalue or metapos to delete, default to deleting the 1st value for the metaname
2411 if(!defined $metapos && !defined $metavalue) {
2412 $metapos = 0;
2413 }
2414
2415
2416 # consider check key is defined before deleting?
2417 # Loop through the metadata array and ignore the specified position
2418 my $filtered_metadata = [];
2419 my $num_metadata_vals = scalar(@{$doc_rec->{$metaname}});
2420 for (my $i=0; $i<$num_metadata_vals; $i++) {
2421 my $metaval = shift(@{$doc_rec->{$metaname}});
2422
2423 if (!defined $metavalue && $i != $metapos) {
2424 push(@$filtered_metadata,$metaval);
2425 }
2426
2427 if(defined $metavalue && !($metavalue eq $metaval))
2428 {
2429 push(@$filtered_metadata,$metaval);
2430 }
2431 }
2432 $doc_rec->{$metaname} = $filtered_metadata;
2433
2434 ## Use the dbutil set_entry method instead of assuming the database is gdbm
2435 my $status = &dbutil::set_infodb_entry($infodbtype, $infodb_file_path, $docid, $doc_rec);
2436
2437 if ($status != 0) {
2438 my $mess = "Failed to set metadata key: $docid\n";
2439
2440 $mess .= "PATH: $ENV{'PATH'}\n";
2441 $mess .= "Exit status: $status\n";
2442 $mess .= "System Error Message: $!\n";
2443
2444 $gsdl_cgi->generate_error($mess);
2445 }
2446 else {
2447 my $mess = "DB set (with item deleted) successful: Key[$docid]\n";
2448 $mess .= " $metaname";
2449 $mess .= "->[$metapos]" if (defined $metapos);
2450 $mess .= " ($metavalue)" if (defined $metavalue);
2451
2452 $gsdl_cgi->generate_ok_message($mess);
2453 }
2454
2455 #return $status; # in case calling functions have a use for this
2456}
2457
2458sub remove_index_metadata
2459{
2460 my $self = shift @_;
2461
2462 my $username = $self->{'username'};
2463 my $collect = $self->{'collect'};
2464 my $gsdl_cgi = $self->{'gsdl_cgi'};
2465
2466 if ($baseaction::authentication_enabled) {
2467 # Ensure the user is allowed to edit this collection
2468 $self->authenticate_user($username, $collect); #&authenticate_user($gsdl_cgi, $username, $collect);
2469 }
2470
2471 # Obtain the collect dir
2472 my $site = $self->{'site'};
2473 my $collect_dir = $gsdl_cgi->get_collection_dir($site);
2474
2475 # Make sure the collection isn't locked by someone else
2476 $self->lock_collection($username, $collect);
2477
2478 $self->_remove_index_metadata(@_);
2479
2480 # Release the lock once it is done
2481 $self->unlock_collection($username, $collect);
2482}
2483
2484#################################################################################
2485# ERASE META METHODS: ERASE ALL VALUES FOR MATCHING METANAME AT SPECIFIED DOCID #
2486#################################################################################
2487
2488sub erase_metadata
2489{
2490 my $self = shift @_;
2491
2492 my $where = $self->{'where'};
2493 # when $where is unspecified, following behaviour of sub remove_metadata by defaulting to erasing metadata from index
2494 if(!$where || ($where =~ m/^\s*$/)) {
2495 $self->erase_index_metadata(@_); # call the full version of set_index_meta for the default behaviour
2496 return;
2497 }
2498
2499 my $username = $self->{'username'};
2500 my $collect = $self->{'collect'};
2501 my $gsdl_cgi = $self->{'gsdl_cgi'};
2502
2503 if ($baseaction::authentication_enabled) {
2504 # Ensure the user is allowed to edit this collection
2505 $self->authenticate_user($username, $collect); #&authenticate_user($gsdl_cgi, $username, $collect);
2506 }
2507
2508 # Make sure the collection isn't locked by someone else
2509 $self->lock_collection($username, $collect);
2510
2511 # check which directories need to be processed, specified in $where as
2512 # any combination of import|archives|index|live
2513 if($where =~ m/import/) {
2514 $self->_erase_import_metadata(@_);
2515 }
2516 if($where =~ m/archives/) {
2517 $self->_erase_archives_metadata(@_);
2518 }
2519 if($where =~ m/index/) {
2520 $self->_erase_index_metadata(@_);
2521 }
2522
2523 # Release the lock once it is done
2524 $self->unlock_collection($username, $collect);
2525}
2526
2527# the internal version, without authentication
2528sub _erase_index_metadata
2529{
2530 my $self = shift @_;
2531
2532 my $collect = $self->{'collect'};
2533 my $gsdl_cgi = $self->{'gsdl_cgi'};
2534 my $infodbtype = $self->{'infodbtype'};
2535
2536 # Obtain the collect dir
2537 my $site = $self->{'site'};
2538 my $collect_dir = $gsdl_cgi->get_collection_dir($site);
2539
2540 # look up additional args
2541 my $docid = $self->{'d'};
2542 if ((!defined $docid) || ($docid =~ m/^\s*$/)) {
2543 $gsdl_cgi->generate_error("No docid (d=...) specified.");
2544 }
2545 my $metaname = $self->{'metaname'};
2546 my $metapos = undef;
2547 my $metavalue = undef;
2548
2549 # To people who know $collect_tail please add some comments
2550 # -> In collection groups, I think collect_tailname is the subcollection name,
2551 # e.g. colgroup-name/col-tail-name
2552 # Obtain the path to the database
2553 my $collect_tail = $collect;
2554 $collect_tail =~ s/^.*[\/|\\]//;
2555 my $index_text_directory = &util::filename_cat($collect_dir,$collect,"index","text");
2556 my $infodb_file_path = &dbutil::get_infodb_file_path($infodbtype, $collect_tail, $index_text_directory);
2557
2558 # Read the docid entry
2559 my $doc_rec = &dbutil::read_infodb_entry($infodbtype, $infodb_file_path, $docid);
2560
2561 # Check to make sure the key does exist
2562 if (defined ($doc_rec->{$metaname})) {
2563
2564 $doc_rec->{$metaname} = [];
2565
2566 ## Use the dbutil set_entry method instead of assuming the database is gdbm
2567 my $status = &dbutil::set_infodb_entry($infodbtype, $infodb_file_path, $docid, $doc_rec);
2568
2569 if ($status != 0) {
2570 my $mess = "Failed to erase metadata key: $docid\n";
2571
2572 $mess .= "PATH: $ENV{'PATH'}\n";
2573 $mess .= "Exit status: $status\n";
2574 $mess .= "System Error Message: $!\n";
2575
2576 $gsdl_cgi->generate_error($mess);
2577 }
2578 else {
2579 my $mess = "DB set (with item deleted) successful: Key[$docid]\n";
2580 $mess .= " $metaname";
2581 $mess .= "->[$metapos]" if (defined $metapos);
2582 $mess .= " ($metavalue)" if (defined $metavalue);
2583
2584 $gsdl_cgi->generate_ok_message($mess);
2585 }
2586 }
2587 else { # no such metaname. Is it really an error?
2588 $gsdl_cgi->generate_ok_message("Can't erase. No metadata field \"" . $metaname . "\" in the specified document: [" . $docid . "]");
2589 }
2590 #return $status; # in case calling functions have a use for this
2591}
2592
2593sub erase_index_metadata
2594{
2595 my $self = shift @_;
2596
2597 my $username = $self->{'username'};
2598 my $collect = $self->{'collect'};
2599 my $gsdl_cgi = $self->{'gsdl_cgi'};
2600
2601 if ($baseaction::authentication_enabled) {
2602 # Ensure the user is allowed to edit this collection
2603 $self->authenticate_user($username, $collect); #&authenticate_user($gsdl_cgi, $username, $collect);
2604 }
2605
2606 # Obtain the collect dir
2607 my $site = $self->{'site'};
2608 my $collect_dir = $gsdl_cgi->get_collection_dir($site);
2609
2610 # Make sure the collection isn't locked by someone else
2611 $self->lock_collection($username, $collect);
2612
2613 $self->_erase_index_metadata(@_);
2614
2615 # Release the lock once it is done
2616 $self->unlock_collection($username, $collect);
2617}
2618
2619
2620# Given a metaname, removes ALL metadata with that metaname at the provided docid
2621sub _erase_archives_metadata
2622{
2623 my $self = shift @_;
2624
2625 my $collect = $self->{'collect'};
2626 my $gsdl_cgi = $self->{'gsdl_cgi'};
2627 my $infodbtype = $self->{'infodbtype'};
2628
2629 # Obtain the collect and archive dir
2630 my $site = $self->{'site'};
2631 my $collect_dir = $gsdl_cgi->get_collection_dir($site);
2632
2633 my $archive_dir = &util::filename_cat($collect_dir,$collect,"archives");
2634
2635 # look up additional args
2636 my ($docid, $docid_secnum) = ($self->{'d'} =~ m/^(.*?)(\..*)?$/);
2637
2638 my $metaname = $self->{'metaname'};
2639
2640 # metapos, metavalue and metamode are never provided and therefore all undefined for erase_archives_metadata
2641 my $metapos = undef;
2642 my $metavalue = undef;
2643 my $metamode = "override"; # when override and no metapos or metaval, all values for metaname will be affected
2644
2645 my $arcinfo_doc_filename = &dbutil::get_infodb_file_path($infodbtype, "archiveinf-doc", $archive_dir);
2646 my $doc_rec = &dbutil::read_infodb_entry($infodbtype, $arcinfo_doc_filename, $docid);
2647
2648 # This now stores the full pathname
2649 my $doc_file = $doc_rec->{'doc-file'}->[0];
2650
2651 # check if request if for file-level doc-version history 'nminus-<n>' version
2652 my $dv = $self->{'dv'};
2653 if (defined $dv && ($dv ne "")) {
2654 # Need to insert '_fldv_history/nminus-<n>' into doc_filename
2655
2656 my ($doc_tailname, $doc_dirname) = File::Basename::fileparse($doc_file);
2657 $doc_file = &util::filename_cat($doc_dirname,$FLDV_HISTORY_DIR,$dv,$doc_tailname);
2658 }
2659
2660 my $doc_filename = &util::filename_cat($archive_dir, $doc_file);
2661
2662 my $status = $self->remove_from_doc_xml($gsdl_cgi, $doc_filename, $metaname, $metapos, $metavalue, $docid_secnum, $metamode);
2663
2664 if ($status == 0)
2665 {
2666 my $mess = "\nerase-archives-metadata successful: \nKey[$docid]\n";
2667 $mess .= " $metaname";
2668 $gsdl_cgi->generate_ok_message($mess);
2669 }
2670 else
2671 {
2672 my $mess .= "Failed to erase archives metadata key: $docid\n";
2673 $mess .= "Exit status: $status\n";
2674 $mess .= "System Error Message: $!\n";
2675 $mess .= "-" x 20 . "\n";
2676
2677 $gsdl_cgi->generate_error($mess);
2678 }
2679
2680 #return $status; # in case calling functions have a use for this
2681}
2682
2683# practically identical to remove_archives_metadata
2684sub erase_archives_metadata
2685{
2686 my $self = shift @_;
2687
2688 my $username = $self->{'username'};
2689 my $collect = $self->{'collect'};
2690 my $gsdl_cgi = $self->{'gsdl_cgi'};
2691
2692 if ($baseaction::authentication_enabled)
2693 {
2694 # Ensure the user is allowed to edit this collection
2695 $self->authenticate_user($username, $collect); #&authenticate_user($gsdl_cgi, $username, $collect);
2696 }
2697
2698 # Make sure the collection isn't locked by someone else
2699 $self->lock_collection($username, $collect);
2700
2701 $self->_erase_archives_metadata(@_);
2702
2703 # Release the lock once it is done
2704 $self->unlock_collection($username, $collect);
2705}
2706
2707sub _erase_import_metadata
2708{
2709 my $self = shift @_;
2710
2711 my $collect = $self->{'collect'};
2712 my $gsdl_cgi = $self->{'gsdl_cgi'};
2713 my $infodbtype = $self->{'infodbtype'};
2714
2715 # Obtain the collect dir
2716 my $site = $self->{'site'};
2717 my $collect_dir = $gsdl_cgi->get_collection_dir($site);
2718
2719 my $archive_dir = &util::filename_cat($collect_dir,$collect,"archives");
2720
2721 # look up additional args
2722 my $docid = $self->{'d'};
2723 if ((!defined $docid) || ($docid =~ m/^\s*$/))
2724 {
2725 $gsdl_cgi->generate_error("No docid (d=...) specified.\n");
2726 }
2727
2728 my $metaname = $self->{'metaname'};
2729 my $metapos = undef;
2730 my $metavalue = undef;
2731 my $metamode = "override";
2732
2733 # Obtain where the metadata.xml is from the archiveinfo-doc.gdb file
2734 # If the doc oid is not specified, we assume the metadata.xml is next to the specified "f"
2735 my $metadata_xml_file;
2736 my $import_filename = undef;
2737 if (defined $docid)
2738 {
2739 my $arcinfo_doc_filename = &dbutil::get_infodb_file_path($infodbtype, "archiveinf-doc", $archive_dir);
2740 my $doc_rec = &dbutil::read_infodb_entry($infodbtype, $arcinfo_doc_filename, $docid);
2741
2742 # This now stores the full pathname
2743 $import_filename = $doc_rec->{'src-file'}->[0];
2744 $import_filename = &util::placeholders_to_abspath($import_filename);
2745 }
2746
2747 if((!defined $import_filename) || ($import_filename =~ m/^\s*$/))
2748 {
2749 $gsdl_cgi->generate_error("There is no metadata\n");
2750 }
2751
2752 # figure out correct metadata.xml file [?]
2753 # Assuming the metadata.xml file is next to the source file
2754 # Note: This will not work if it is using the inherited metadata from the parent folder
2755 my ($import_tailname, $import_dirname) = File::Basename::fileparse($import_filename);
2756 my $metadata_xml_filename = &util::filename_cat($import_dirname,"metadata.xml");
2757
2758 $self->remove_from_metadata_xml($gsdl_cgi, $metadata_xml_filename, $metaname, $metapos, $metavalue, $import_tailname, $metamode); # metamode=override, means all values of metaname are affected
2759
2760 my $mess = "erase-import-metadata successful: Key[$docid] -> $metadata_xml_filename\n";
2761 $mess .= " $metaname";
2762 $mess .= " = $metavalue\n";
2763
2764 $gsdl_cgi->generate_ok_message($mess);
2765
2766 #return $status; # in case calling functions have a use for this
2767}
2768
2769sub erase_import_metadata
2770{
2771 my $self = shift @_;
2772
2773 my $username = $self->{'username'};
2774 my $collect = $self->{'collect'};
2775 my $gsdl_cgi = $self->{'gsdl_cgi'};
2776
2777 if ($baseaction::authentication_enabled) {
2778 # Ensure the user is allowed to edit this collection
2779 $self->authenticate_user($username, $collect); #&authenticate_user($gsdl_cgi, $username, $collect);
2780 }
2781
2782 # Make sure the collection isn't locked by someone else
2783 $self->lock_collection($username, $collect);
2784
2785 $self->_erase_import_metadata(@_);
2786
2787 # Release the lock once it is done
2788 $self->unlock_collection($username, $collect);
2789
2790}
2791
2792# removes all meta with matching metaname for the specified docid from the live metadata index
2793sub _erase_live_metadata
2794{
2795 my $self = shift @_;
2796 # At present, _remove_live_metadata doesn't take metaval or metapos either and therefore has the desired effect
2797 $self->_remove_live_metadata(@_);
2798
2799}
2800
2801sub erase_live_metadata
2802{
2803 my $self = shift @_;
2804
2805 my $username = $self->{'username'};
2806 my $collect = $self->{'collect'};
2807 my $gsdl_cgi = $self->{'gsdl_cgi'};
2808
2809 if ($baseaction::authentication_enabled) {
2810 # Ensure the user is allowed to edit this collection
2811 $self->authenticate_user($username, $collect); #&authenticate_user($gsdl_cgi, $username, $collect);
2812 }
2813
2814 # Make sure the collection isn't locked by someone else
2815 $self->lock_collection($username, $collect);
2816
2817 $self->_erase_live_metadata(@_);
2818
2819 $self->unlock_collection($username, $collect);
2820}
2821
2822
2823# Was trying to reused the codes, but the functions need to be broken
2824# down more before they can be reused, otherwise there will be too
2825# much overhead and duplicate process...
2826sub insert_metadata
2827{
2828 my $self = shift @_;
2829
2830 my $username = $self->{'username'};
2831 my $collect = $self->{'collect'};
2832 my $gsdl_cgi = $self->{'gsdl_cgi'};
2833 my $infodbtype = $self->{'infodbtype'};
2834
2835 # If the import metadata and gdbm database have been updated, we
2836 # need to insert some notification to warn user that the the text
2837 # they see at the moment is not indexed and require a rebuild.
2838 my $rebuild_pending_macro = "_rebuildpendingmessage_";
2839
2840 if ($baseaction::authentication_enabled) {
2841 # Ensure the user is allowed to edit this collection
2842 $self->authenticate_user($username, $collect);
2843 }
2844
2845 # Obtain the collect and archive dir
2846 my $site = $self->{'site'};
2847 my $collect_dir = $gsdl_cgi->get_collection_dir($site);
2848 my $archive_dir = &util::filename_cat($collect_dir,$collect,"archives");
2849
2850 # Make sure the collection isn't locked by someone else
2851 $self->lock_collection($username, $collect);
2852
2853 # Check additional args
2854 my $docid = $self->{'d'};
2855 if (!defined($docid) || ($docid =~ m/^\s*$/)) {
2856 $gsdl_cgi->generate_error("No document id is specified: d=...");
2857 }
2858 my $metaname = $self->{'metaname'};
2859 if (!defined($metaname) || ($metaname =~ m/^\s*$/)) {
2860 $gsdl_cgi->generate_error("No metaname is specified: metadataname=...");
2861 }
2862 my $metavalue = $self->{'metavalue'};
2863 if (!defined($metavalue) || ($metavalue =~ m/^\s*$/)) {
2864 $gsdl_cgi->generate_error("No metavalue or empty metavalue is specified: metadataname=...");
2865 }
2866 # make "accumulate" the default (less destructive, as it won't actually
2867 # delete any existing values)
2868 my $metamode = "accumulate";
2869
2870 # metapos/prevmetavalue were never before used in this subroutine, so set them to undefined
2871 my $metapos = undef;
2872 my $prevmetavalue = undef;
2873
2874 #=======================================================================#
2875 # set_import_metadata [START]
2876 #=======================================================================#
2877 # Obtain where the metadata.xml is from the archiveinfo-doc.gdb file
2878 # If the doc oid is not specified, we assume the metadata.xml is next to the specified "f"
2879 my $metadata_xml_file;
2880 my $arcinfo_doc_filename = &dbutil::get_infodb_file_path($infodbtype, "archiveinf-doc", $archive_dir);
2881 my $archive_doc_rec = &dbutil::read_infodb_entry($infodbtype, $arcinfo_doc_filename, $docid);
2882
2883 # This now stores the full pathname
2884 my $import_filename = $archive_doc_rec->{'src-file'}->[0];
2885 $import_filename = &util::placeholders_to_abspath($import_filename);
2886
2887 # figure out correct metadata.xml file [?]
2888 # Assuming the metadata.xml file is next to the source file
2889 # Note: This will not work if it is using the inherited metadata from the parent folder
2890 my ($import_tailname, $import_dirname)
2891 = File::Basename::fileparse($import_filename);
2892 my $metadata_xml_filename = &util::filename_cat($import_dirname,"metadata.xml");
2893
2894 # Shane's escape characters
2895 $metavalue = pack "U0C*", unpack "C*", $metavalue;
2896 $metavalue =~ s/\,/&#44;/g;
2897 $metavalue =~ s/\:/&#58;/g;
2898 $metavalue =~ s/\|/&#124;/g;
2899 $metavalue =~ s/\(/&#40;/g;
2900 $metavalue =~ s/\)/&#41;/g;
2901 $metavalue =~ s/\[/&#91;/g;
2902 $metavalue =~ s/\\/&#92;/g;
2903 $metavalue =~ s/\]/&#93;/g;
2904 $metavalue =~ s/\{/&#123;/g;
2905 $metavalue =~ s/\}/&#125;/g;
2906 $metavalue =~ s/\"/&#34;/g;
2907 $metavalue =~ s/\`/&#96;/g;
2908 $metavalue =~ s/\n/_newline_/g;
2909
2910 # Edit the metadata.xml
2911 # Modified by Jeffrey from DL Consulting
2912 # Handle the case where there is one metadata.xml file for multiple FileSets
2913 # The XML filter needs to know whether it is in the right FileSet
2914 # TODO: This doesn't fix the problem where the metadata.xml is not next to the src file.
2915 # TODO: This doesn't handle the common metadata (where FileName doesn't point to a single file)
2916 $self->edit_metadata_xml($gsdl_cgi, $metadata_xml_filename, $metaname,
2917 $metapos, $metavalue, $metamode, $import_tailname, $prevmetavalue);
2918 #=======================================================================#
2919 # set_import_metadata [END]
2920 #=======================================================================#
2921
2922
2923 #=======================================================================#
2924 # set_metadata (accumulate version) [START]
2925 #=======================================================================#
2926 # To people who know $collect_tail please add some comments
2927 # Obtain path to the database
2928 my $collect_tail = $collect;
2929 $collect_tail =~ s/^.*[\/|\\]//;
2930 my $index_text_directory = &util::filename_cat($collect_dir,$collect,"index","text");
2931 my $infodb_file_path = &dbutil::get_infodb_file_path($infodbtype, $collect_tail, $index_text_directory);
2932
2933 # Read the docid entry
2934 my $doc_rec = &dbutil::read_infodb_entry($infodbtype, $infodb_file_path, $docid);
2935
2936 # Protect the quotes
2937 $metavalue =~ s/\"/\\\"/g;
2938
2939 # Adds the pending macro
2940 my $macro_metavalue = $rebuild_pending_macro . $metavalue;
2941
2942 # If the metadata doesn't exist, create a new one
2943 if (!defined($doc_rec->{$metaname})){
2944 $doc_rec->{$metaname} = [ $macro_metavalue ];
2945 }
2946 # Else, let's acculumate the values
2947 else {
2948 push(@{$doc_rec->{$metaname}},$macro_metavalue);
2949 }
2950
2951 ## Use the dbutil set_entry method instead of assuming the database is gdbm
2952 my $status = &dbutil::set_infodb_entry($infodbtype, $infodb_file_path, $docid, $doc_rec);
2953
2954 if ($status != 0) {
2955 # Catch error if gdbmget failed
2956 my $mess = "Failed to set metadata key: $docid\n";
2957
2958 $mess .= "PATH: $ENV{'PATH'}\n";
2959 $mess .= "Exit status: $status\n";
2960 $mess .= "System Error Message: $!\n";
2961
2962 $gsdl_cgi->generate_error($mess);
2963 }
2964 else {
2965 my $mess = "insert-metadata successful: Key[$docid]\n";
2966 $mess .= " [In metadata.xml] $metaname";
2967 $mess .= " = $metavalue\n";
2968 $mess .= " [In database] $metaname";
2969 $mess .= " = $macro_metavalue\n";
2970 $mess .= " The new text has not been indexed, rebuilding collection is required\n";
2971 $gsdl_cgi->generate_ok_message($mess);
2972 }
2973 #=======================================================================#
2974 # set_metadata (accumulate version) [END]
2975 #=======================================================================#
2976
2977 # Release the lock once it is done
2978 $self->unlock_collection($username, $collect);
2979}
2980
2981# not returning 1; here since this file is conditionally included by metadataction.pm
2982# and not otherwise meant to be used on its own
2983
Note: See TracBrowser for help on using the repository browser.