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

(-)a/Koha/Upload.pm (-11 / +112 lines)
Lines 51-56 use constant BYTES_DIGEST => 2048; Link Here
51
use Modern::Perl;
51
use Modern::Perl;
52
use CGI; # no utf8 flag, since it may interfere with binary uploads
52
use CGI; # no utf8 flag, since it may interfere with binary uploads
53
use Digest::MD5;
53
use Digest::MD5;
54
use Encode;
54
use File::Spec;
55
use File::Spec;
55
use IO::File;
56
use IO::File;
56
use Time::HiRes;
57
use Time::HiRes;
Lines 58-63 use Time::HiRes; Link Here
58
use base qw(Class::Accessor);
59
use base qw(Class::Accessor);
59
60
60
use C4::Context;
61
use C4::Context;
62
use C4::Koha;
61
63
62
__PACKAGE__->mk_ro_accessors( qw||);
64
__PACKAGE__->mk_ro_accessors( qw||);
63
65
Lines 94-99 sub cgi { Link Here
94
    }
96
    }
95
}
97
}
96
98
99
=head2 count
100
101
    Returns number of uploaded files without errors
102
103
=cut
104
105
sub count {
106
    my ( $self ) = @_;
107
    return scalar grep { !exists $self->{files}->{$_}->{errcode} } keys $self->{files};
108
}
109
97
=head2 result
110
=head2 result
98
111
99
    Returns new object based on Class::Accessor.
112
    Returns new object based on Class::Accessor.
Lines 102-109 sub cgi { Link Here
102
115
103
sub result {
116
sub result {
104
    my ( $self ) = @_;
117
    my ( $self ) = @_;
105
    my @a = map { $self->{files}->{$_}->{id} } keys $self->{files};
118
    my @a = map { $self->{files}->{$_}->{id} }
106
    return join ',', @a;
119
        grep { !exists $self->{files}->{$_}->{errcode} }
120
        keys $self->{files};
121
    return @a? ( join ',', @a ): undef;
107
}
122
}
108
123
109
=head2 err
124
=head2 err
Lines 136-146 sub get { Link Here
136
    my ( @rv, $res);
151
    my ( @rv, $res);
137
    foreach my $r ( @$temp ) {
152
    foreach my $r ( @$temp ) {
138
        undef $res;
153
        undef $res;
154
        foreach( qw[id hashvalue filesize categorycode public] ) {
155
            $res->{$_} = $r->{$_};
156
        }
139
        $res->{name} = $r->{filename};
157
        $res->{name} = $r->{filename};
140
        $res->{path}= $self->_full_fname($r);
158
        $res->{path} = $self->_full_fname($r);
141
        if( $res->{path} && -r $res->{path} ) {
159
        if( $res->{path} && -r $res->{path} ) {
142
            $res->{fh} = IO::File->new( $res->{path}, "r" )
160
            if( $params->{filehandle} ) {
143
                if $params->{filehandle};
161
                my $fh = IO::File->new( $res->{path}, "r" );
162
                $fh->binmode if $fh;
163
                $res->{fh} = $fh;
164
            }
144
            push @rv, $res;
165
            push @rv, $res;
145
        } else {
166
        } else {
146
            $self->{files}->{ $r->{filename} }->{errcode}=5; #not readable
167
            $self->{files}->{ $r->{filename} }->{errcode}=5; #not readable
Lines 150-158 sub get { Link Here
150
    return wantarray? @rv: $res;
171
    return wantarray? @rv: $res;
151
}
172
}
152
173
174
=head2 delete
175
176
    Returns array of deleted filenames or undef.
177
    Since it now only accepts id as parameter, you should not expect more
178
    than one filename.
179
180
=cut
181
182
sub delete {
183
    my ( $self, $params ) = @_;
184
    return if !$params->{id};
185
    my @res;
186
    my $temp = $self->_lookup({ id => $params->{id} });
187
    foreach( @$temp ) {
188
        my $d = $self->_delete( $_ );
189
        push @res, $d if $d;
190
    }
191
    return if !@res;
192
    return @res;
193
}
194
153
sub DESTROY {
195
sub DESTROY {
154
}
196
}
155
197
198
# **************  HELPER ROUTINES / CLASS METHODS ******************************
199
200
=head2 getCategories
201
202
    getCategories returns a list of upload category codes and names
203
204
=cut
205
206
sub getCategories {
207
    my ( $class ) = @_;
208
    my $cats = C4::Koha::GetAuthorisedValues('UPLOAD');
209
    [ map {{ code => $_->{authorised_value}, name => $_->{lib} }} @$cats ];
210
}
211
212
=head2 httpheaders
213
214
    httpheaders returns http headers for a retrievable upload
215
    Will be extended by report 14282
216
217
=cut
218
219
sub httpheaders {
220
    my ( $class, $name ) = @_;
221
    return (
222
        '-type'       => 'application/octet-stream',
223
        '-attachment' => $name,
224
    );
225
}
226
156
# **************  INTERNAL ROUTINES ********************************************
227
# **************  INTERNAL ROUTINES ********************************************
157
228
158
sub _init {
229
sub _init {
Lines 192-198 sub _create_file { Link Here
192
    } else {
263
    } else {
193
        my $dir = $self->_dir;
264
        my $dir = $self->_dir;
194
        my $fn = $self->{files}->{$filename}->{hash}. '_'. $filename;
265
        my $fn = $self->{files}->{$filename}->{hash}. '_'. $filename;
195
        if( -e "$dir/$fn" ) {
266
        if( -e "$dir/$fn" && @{ $self->_lookup({
267
          hashvalue => $self->{files}->{$filename}->{hash} }) } ) {
268
        # if the file exists and it is registered, then set error
196
            $self->{files}->{$filename}->{errcode} = 1; #already exists
269
            $self->{files}->{$filename}->{errcode} = 1; #already exists
197
            return;
270
            return;
198
        }
271
        }
Lines 232-237 sub _full_fname { Link Here
232
305
233
sub _hook {
306
sub _hook {
234
    my ( $self, $filename, $buffer, $bytes_read, $data ) = @_;
307
    my ( $self, $filename, $buffer, $bytes_read, $data ) = @_;
308
    $filename= Encode::decode_utf8( $filename ); # UTF8 chars in filename
235
    $self->_compute( $filename, $buffer );
309
    $self->_compute( $filename, $buffer );
236
    my $fh = $self->_fh( $filename ) // $self->_create_file( $filename );
310
    my $fh = $self->_fh( $filename ) // $self->_create_file( $filename );
237
    print $fh $buffer if $fh;
311
    print $fh $buffer if $fh;
Lines 269-287 sub _register { Link Here
269
sub _lookup {
343
sub _lookup {
270
    my ( $self, $params ) = @_;
344
    my ( $self, $params ) = @_;
271
    my $dbh = C4::Context->dbh;
345
    my $dbh = C4::Context->dbh;
272
    my $sql = 'SELECT id,hashvalue,filename,dir,categorycode '.
346
    my $sql = 'SELECT id,hashvalue,filename,dir,filesize,categorycode,public '.
273
        'FROM uploaded_files ';
347
        'FROM uploaded_files ';
348
    my @pars;
274
    if( $params->{id} ) {
349
    if( $params->{id} ) {
275
        $sql.= "WHERE id=?";
350
        return [] if $params->{id} !~ /^\d+(,\d+)*$/;
276
    } else {
351
        $sql.= "WHERE id IN ($params->{id})";
352
        @pars = ();
353
    } elsif( $params->{hashvalue} ) {
277
        $sql.= "WHERE hashvalue=?";
354
        $sql.= "WHERE hashvalue=?";
355
        @pars = ( $params->{hashvalue} );
356
    } elsif( $params->{term} ) {
357
        $sql.= "WHERE (filename LIKE ? OR hashvalue LIKE ?)";
358
        @pars = ( '%'.$params->{term}.'%', '%'.$params->{term}.'%' );
359
    } else {
360
        return [];
278
    }
361
    }
279
    $sql.= $self->{public}? " AND public=1": '';
362
    $sql.= $self->{public}? " AND public=1": '';
280
    my $temp= $dbh->selectall_arrayref( $sql, { Slice => {} },
363
    $sql.= ' ORDER BY id';
281
        ( $params->{id} // $params->{hashvalue} // 0 ) );
364
    my $temp= $dbh->selectall_arrayref( $sql, { Slice => {} }, @pars );
282
    return $temp;
365
    return $temp;
283
}
366
}
284
367
368
sub _delete {
369
    my ( $self, $rec ) = @_;
370
    my $dbh = C4::Context->dbh;
371
    my $sql = 'DELETE FROM uploaded_files WHERE id=?';
372
    my $file = $self->_full_fname($rec);
373
    if( !-e $file ) { # we will just delete the record
374
        # TODO Should we add a trace here for the missing file?
375
        $dbh->do( $sql, undef, ( $rec->{id} ) );
376
        return $rec->{filename};
377
    } elsif( unlink($file) ) {
378
        $dbh->do( $sql, undef, ( $rec->{id} ) );
379
        return $rec->{filename};
380
    }
381
    $self->{files}->{ $rec->{filename} }->{errcode} = 7;
382
    #NOTE: errcode=6 is used to report successful delete (see template)
383
    return;
384
}
385
285
sub _compute {
386
sub _compute {
286
# Computes hash value when sub hook feeds the first block
387
# Computes hash value when sub hook feeds the first block
287
# For temporary files, the id is made unique with time
388
# For temporary files, the id is made unique with time
(-)a/cataloguing/value_builder/upload.pl (-132 / +21 lines)
Lines 4-9 Link Here
4
4
5
# This file is part of Koha.
5
# This file is part of Koha.
6
#
6
#
7
# Copyright (C) 2015 Rijksmuseum
7
# Copyright (C) 2011-2012 BibLibre
8
# Copyright (C) 2011-2012 BibLibre
8
#
9
#
9
# Koha is free software; you can redistribute it and/or modify it
10
# Koha is free software; you can redistribute it and/or modify it
Lines 20-164 Link Here
20
# along with Koha; if not, see <http://www.gnu.org/licenses>.
21
# along with Koha; if not, see <http://www.gnu.org/licenses>.
21
22
22
use Modern::Perl;
23
use Modern::Perl;
23
use CGI qw/-utf8/;
24
24
25
use C4::Auth;
25
# This plugin does not use the plugin launcher. It refers to tools/upload.pl.
26
use C4::Context;
26
# That script and template support using it as a plugin.
27
use C4::Output;
27
28
use C4::UploadedFiles;
28
# If the plugin is called with the pattern [id=some_hashvalue] in the
29
# corresponding field, it starts the upload script as a search, providing
30
# the possibility to delete the uploaded file. If the field is empty, you
31
# can upload a new file.
29
32
30
my $builder = sub {
33
my $builder = sub {
31
    my ( $params ) = @_;
34
    my ( $params ) = @_;
32
    my $function_name = $params->{id};
35
    return <<"SCRIPT";
33
    my $res           = "
36
<script type=\"text/javascript\">
34
    <script type=\"text/javascript\">
37
        function Click$params->{id}(event) {
35
        function Click$function_name(event) {
36
            var index = event.data.id;
38
            var index = event.data.id;
37
            var id = document.getElementById(index).value;
39
            var str = document.getElementById(index).value;
38
            var IsFileUploadUrl=0;
40
            var myurl, term;
39
            if (id.match(/opac-retrieve-file/)) {
41
            if( str && str.match(/id=([0-9a-f]+)/) ) {
40
                IsFileUploadUrl=1;
42
                term = RegExp.\$1;
41
            }
43
                myurl = '../tools/upload.pl?op=search&index='+index+'&term='+term+'&plugin=1';
42
            if(id.match(/id=([0-9a-f]+)/)){
43
                id = RegExp.\$1;
44
            }
45
            var newin=window.open(\"../cataloguing/plugin_launcher.pl?plugin_name=upload.pl&index=\"+index+\"&id=\"+id+\"&from_popup=0\"+\"&IsFileUploadUrl=\"+IsFileUploadUrl, 'upload', 'width=600,height=400,toolbar=false,scrollbars=no');
46
            newin.focus();
47
        }
48
    </script>
49
";
50
    return $res;
51
};
52
53
my $launcher = sub {
54
    my ( $params ) = @_;
55
    my $input = $params->{cgi};
56
    my $index = $input->param('index');
57
    my $id = $input->param('id');
58
    my $delete = $input->param('delete');
59
    my $uploaded_file = $input->param('uploaded_file');
60
    my $from_popup = $input->param('from_popup');
61
    my $isfileuploadurl = $input->param('IsFileUploadUrl');
62
    my $dangling = C4::UploadedFiles::DanglingEntry($id,$isfileuploadurl);
63
    my $template_name;
64
    if ($delete || ($id && ($dangling==0 || $dangling==1))) {
65
        $template_name = "upload_delete_file.tt";
66
    }
67
    else {
68
        $template_name = "upload.tt";
69
    }
70
71
    my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
72
        {   template_name   => "cataloguing/value_builder/$template_name",
73
            query           => $input,
74
            type            => "intranet",
75
            authnotrequired => 0,
76
            flagsrequired   => { editcatalogue => '*' },
77
            debug           => 1,
78
        }
79
    );
80
81
    if ($dangling==2) {
82
        $template->param( dangling => 1 );
83
    }
84
85
    # Dealing with the uploaded file
86
    my $dir = $input->param('uploadcategory');
87
    if ($uploaded_file and $dir) {
88
        my $fh = $input->upload('uploaded_file');
89
90
        $id = C4::UploadedFiles::UploadFile($uploaded_file, $dir, $fh->handle);
91
        my $OPACBaseURL = C4::Context->preference('OPACBaseURL') // '';
92
        $OPACBaseURL =~ s#/$##;
93
        if (!$OPACBaseURL) {
94
            $template->param(MissingURL => 1);
95
        }
96
        if($id && $OPACBaseURL) {
97
            my $return = "$OPACBaseURL/cgi-bin/koha/opac-retrieve-file.pl?id=$id";
98
            $template->param(
99
                success => 1,
100
                return => $return,
101
                uploaded_file => $uploaded_file,
102
            );
103
        } else {
104
            $template->param(error => 1);
105
        }
106
    } elsif ($delete || ($id && ($dangling==0 || $dangling==1))) {
107
        # If there's already a file uploaded for this field,
108
        # We handle its deletion
109
        if ($delete) {
110
            if(C4::UploadedFiles::DelUploadedFile($id)==0) {;
111
                $template->param(error => 1);
112
            } else {
44
            } else {
113
                $template->param(success => 1);
45
                myurl = '../tools/upload.pl?op=new&index='+index+'&plugin=1';
114
            }
46
            }
47
            window.open( myurl, 'tag_editor', 'width=800,height=400,toolbar=false,scrollbars=yes' );
115
        }
48
        }
116
    } else {
49
</script>
117
        my $upload_path = C4::Context->config('upload_path');
50
SCRIPT
118
        if ($upload_path) {
119
            my $filefield = CGI::filefield(
120
                -name => 'uploaded_file',
121
                -size => 50,
122
            );
123
            $template->param(
124
                filefield => $filefield,
125
                uploadcategories => C4::UploadedFiles::getCategories(),
126
            );
127
        } else {
128
            $template->param( error_upload_path_not_configured => 1 );
129
        }
130
131
        if (!$uploaded_file && !$dir && $from_popup) {
132
            $template->param(error_nothing_selected => 1);
133
        }
134
        elsif (!$uploaded_file && $dir) {
135
            $template->param(error_no_file_selected => 1);
136
        }
137
        if ($uploaded_file and not $dir) {
138
            $template->param(error_no_dir_selected => 1);
139
        }
140
141
    }
142
143
    $template->param(
144
        index => $index,
145
        id => $id,
146
    );
147
148
    output_html_with_http_headers $input, $cookie, $template->output;
149
};
51
};
150
52
151
return { builder => $builder, launcher => $launcher };
53
return { builder => $builder };
152
153
1;
154
155
__END__
156
157
=head1 upload.pl
158
159
This plugin allows to upload files on the server and reference it in a marc
160
field.
161
162
It uses config variable upload_path and pref OPACBaseURL.
163
164
=cut
(-)a/koha-tmpl/intranet-tmpl/prog/en/js/file-upload.js (-3 / +3 lines)
Lines 1-4 Link Here
1
function AjaxUpload ( input, progressbar, callback ) {
1
function AjaxUpload ( input, progressbar, xtra, callback ) {
2
    // input and progressbar are jQuery objects
2
    // input and progressbar are jQuery objects
3
    // callback is the callback function for completion
3
    // callback is the callback function for completion
4
    var formData= new FormData();
4
    var formData= new FormData();
Lines 6-12 function AjaxUpload ( input, progressbar, callback ) { Link Here
6
        formData.append( "uploadfile", file );
6
        formData.append( "uploadfile", file );
7
    });
7
    });
8
    var xhr= new XMLHttpRequest();
8
    var xhr= new XMLHttpRequest();
9
    var url= '/cgi-bin/koha/tools/upload-file.pl';
9
    var url= '/cgi-bin/koha/tools/upload-file.pl?' + xtra;
10
    progressbar.val( 0 );
10
    progressbar.val( 0 );
11
    progressbar.next('.fileuploadpercent').text( '0' );
11
    progressbar.next('.fileuploadpercent').text( '0' );
12
    xhr.open('POST', url, true);
12
    xhr.open('POST', url, true);
Lines 21-27 function AjaxUpload ( input, progressbar, callback ) { Link Here
21
            progressbar.val( 100 );
21
            progressbar.val( 100 );
22
            progressbar.next('.fileuploadpercent').text( '100' );
22
            progressbar.next('.fileuploadpercent').text( '100' );
23
        }
23
        }
24
        callback( data.status, data.fileid );
24
        callback( data.status, data.fileid, data.errors );
25
    }
25
    }
26
    xhr.onerror = function (e) {
26
    xhr.onerror = function (e) {
27
        // Probably only fires for network failure
27
        // Probably only fires for network failure
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/offline_circ/process_koc.tt (-1 / +1 lines)
Lines 20-26 function StartUpload() { Link Here
20
    $("#fileuploadstatus").show();
20
    $("#fileuploadstatus").show();
21
    $("form#processfile #uploadedfileid").val('');
21
    $("form#processfile #uploadedfileid").val('');
22
    $("form#enqueuefile #uploadedfileid").val('');
22
    $("form#enqueuefile #uploadedfileid").val('');
23
    xhr= AjaxUpload( $('#fileToUpload'), $('#fileuploadprogress'), cbUpload );
23
    xhr= AjaxUpload( $('#fileToUpload'), $('#fileuploadprogress'), '', cbUpload );
24
}
24
}
25
25
26
function cbUpload( status, fileid ) {
26
function cbUpload( status, fileid ) {
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/stage-marc-import.tt (-1 / +1 lines)
Lines 39-45 function StartUpload() { Link Here
39
    $("#processfile").hide();
39
    $("#processfile").hide();
40
    $("#fileuploadstatus").show();
40
    $("#fileuploadstatus").show();
41
    $("#uploadedfileid").val('');
41
    $("#uploadedfileid").val('');
42
    xhr= AjaxUpload( $('#fileToUpload'), $('#fileuploadprogress'), cbUpload );
42
    xhr= AjaxUpload( $('#fileToUpload'), $('#fileuploadprogress'), '', cbUpload );
43
    $("#fileuploadcancel").show();
43
    $("#fileuploadcancel").show();
44
}
44
}
45
function CancelUpload() {
45
function CancelUpload() {
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/upload-images.tt (-1 / +1 lines)
Lines 18-24 function StartUpload() { Link Here
18
    $('#uploadform button.submit').prop('disabled',true);
18
    $('#uploadform button.submit').prop('disabled',true);
19
    $("#fileuploadstatus").show();
19
    $("#fileuploadstatus").show();
20
    $("#uploadedfileid").val('');
20
    $("#uploadedfileid").val('');
21
    xhr= AjaxUpload( $('#fileToUpload'), $('#fileuploadprogress'), cbUpload );
21
    xhr= AjaxUpload( $('#fileToUpload'), $('#fileuploadprogress'), '', cbUpload );
22
}
22
}
23
function cbUpload( status, fileid ) {
23
function cbUpload( status, fileid ) {
24
    if( status=='done' ) {
24
    if( status=='done' ) {
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/upload.tt (+332 lines)
Line 0 Link Here
1
[% INCLUDE 'doc-head-open.inc' %]
2
[% USE Koha %]
3
[% IF plugin %]
4
    <title>Upload plugin</title>
5
[% ELSE %]
6
    <title>Koha &rsaquo; Tools &rsaquo; Upload</title>
7
[% END %]
8
[% INCLUDE 'doc-head-close.inc' %]
9
10
[% BLOCK plugin_pars %]
11
    [% IF plugin %]
12
        <input type="hidden" name="plugin" value="1" />
13
        <input type="hidden" name="index" value="[% index %]" />
14
    [% END %]
15
[% END %]
16
17
[% BLOCK breadcrumbs %]
18
    <div id="breadcrumbs">
19
        <a href="/cgi-bin/koha/mainpage.pl">Home</a>
20
        &rsaquo;
21
        <a href="/cgi-bin/koha/tools/tools-home.pl">Tools</a>
22
        &rsaquo;
23
        <a href="/cgi-bin/koha/tools/upload.pl">Upload</a>
24
        &rsaquo;
25
        <span id="lastbreadcrumb">
26
        [% IF mode=='new' || mode =='deleted'%]
27
            Add new upload or search
28
        [% ELSE %]
29
            Results
30
        [% END %]
31
        </span>
32
    </div>
33
[% END %]
34
35
[% BLOCK form_new %]
36
    <form method="post" action="[% SCRIPT_NAME %]" id="uploadfile" enctype="multipart/form-data">
37
        [% PROCESS plugin_pars %]
38
        <fieldset class="rows" id="uploadform">
39
        <legend>Upload new files</legend>
40
        <ol>
41
        <li>
42
        <div id="fileuploadform">
43
            <label for="fileToUpload">Select files: </label>
44
            <input type="file" id="fileToUpload" name="fileToUpload" multiple/>
45
        </div>
46
        </li>
47
        <li>
48
            <label for="uploadcategory">Category: </label>
49
                      <select id="uploadcategory" name="uploadcategory">
50
                      [% IF !plugin %]
51
                          <option value="" disabled hidden selected></option>
52
                      [% END %]
53
                      [% FOREACH cat IN uploadcategories %]
54
                          <option value="[% cat.code %]">[% cat.name %]</option>
55
                      [% END %]
56
                      </select>
57
        </li>
58
        [% IF !plugin %]
59
            <li>
60
                <div class="hint">Note: For temporary uploads do not select a category. The file will not be made available for public downloading.</div>
61
            </li>
62
        [% END %]
63
        <li>
64
            [% IF plugin %]
65
                <input type="hidden" id="public" name="public" value="1"/>
66
            [% ELSE %]
67
                <label>&nbsp;</label>
68
                <input type="checkbox" id="public" name="public">
69
                    Allow public downloads
70
                </input>
71
            [% END %]
72
        </li>
73
        </ol>
74
        <fieldset class="action">
75
            <button id="fileuploadbutton" onclick="StartUpload(); return false;">Upload</button>
76
            <button id="fileuploadcancel" onclick="CancelUpload(); return false;">Cancel</button>
77
        </fieldset>
78
        </fieldset>
79
        <div id="fileuploadpanel">
80
            <div id="fileuploadstatus">Upload progress:
81
            <progress id="fileuploadprogress" min="0" max="100" value="0">
82
            </progress>
83
            <span class="fileuploadpercent">0</span>%
84
            </div>
85
            <div id="fileuploadfailed"></div>
86
        </div>
87
    </form>
88
[% END %]
89
90
[% BLOCK form_search %]
91
    <form method="post" id="searchfile" action="[% SCRIPT_NAME %]" enctype="multipart/form-data">
92
        [% PROCESS plugin_pars %]
93
        <input type="hidden" name="op" value="search"/>
94
        <fieldset class="rows">
95
        <legend>Search uploads by name or hashvalue</legend>
96
        <ol>
97
        <li>
98
            <label for="searchupload">Search term: </label>
99
            <input type="text" id="term" name="term" value=""/>
100
        </li>
101
        <li>
102
            <fieldset class="action">
103
                <button id="searchbutton" onclick="return CheckSearch();" class="submit">Search</button>
104
            </fieldset>
105
        </li>
106
        </ol>
107
        </fieldset>
108
    </form>
109
[% END %]
110
111
[% BLOCK submitter %]
112
    <form id="submitter" style="display:none;" method="post">
113
        [% PROCESS plugin_pars %]
114
        <input type="hidden" name="op" id="op" value=""/>
115
        <input type="hidden" name="id" id="id" value="" />
116
        <input type="hidden" name="msg" id="msg" value="" />
117
    </form>
118
[% END %]
119
120
[% BLOCK closer %]
121
    [% IF plugin %]
122
        <form id="closer">
123
            <fieldset class="action">
124
                <button onclick="window.close();return false;">Close</button>
125
            </fieldset>
126
        </form>
127
    [% END %]
128
[% END %]
129
130
[% BLOCK newsearch %]
131
    <form id="newsearch">
132
        <fieldset class="action">
133
            <button onclick="SubmitMe('new'); return false;">New search</button>
134
            [% IF plugin %]
135
                <button onclick="window.close();return false;">Close</button>
136
            [% END %]
137
        </fieldset>
138
    </form>
139
[% END %]
140
141
[% BLOCK table_results %]
142
    <table>
143
    <thead>
144
    <tr>
145
        <th>Filename</td>
146
        <th>Size</td>
147
        <th>Hashvalue</td>
148
        <th>Category</td>
149
        [% IF !plugin %]<th>Public</td>[% END %]
150
        <th>Actions</td>
151
    </tr>
152
    </thead>
153
    <tbody>
154
    [% FOREACH record IN uploads %]
155
    <tr>
156
        <td>[% record.name %]</td>
157
        <td>[% record.filesize %]</td>
158
        <td>[% record.hashvalue %]</td>
159
        <td>[% record.categorycode %]</td>
160
        [% IF !plugin %]
161
            <td>[% IF record.public %]Yes[% ELSE %]No[% END %]</td>
162
        [% END %]
163
        <td>
164
            [% IF plugin %]
165
                <a href="" onclick="Choose('[% record.hashvalue %]'); return false;">Choose</a>&nbsp;
166
            [% END %]
167
            <a href="" onclick="SubmitMe( 'download', [% record.id %] ); return false;">Download</a>&nbsp;
168
            <a href="" onclick="ClearField(); SubmitMe( 'delete', [% record.id %] ); return false;">Delete</a>
169
        </td>
170
   </tr>
171
   [% END %]
172
   </tbody>
173
   </table>
174
[% END %]
175
176
<style type="text/css">
177
    #fileuploadstatus,#fileuploadfailed { display : none; }
178
    #fileuploadstatus { margin:.4em; }
179
    #fileuploadprogress { width:150px;height:10px;border:1px solid #666;background:url('[% interface %]/[% theme %]/img/progress.png') -300px 0px no-repeat; }
180
</style>
181
182
<script type="text/javascript">
183
//<![CDATA[
184
    var errMESSAGES = [
185
        "Error 0: Not in use",
186
        _("This file already exists (in this category)."),
187
        _("File could not be created. Check permissions."),
188
        _("Your koha-conf.xml does not contain a valid upload_path."),
189
        _("No temporary directory found."),
190
        _("File could not be read."),
191
        _("File has been deleted."),
192
        _("File could not be deleted."),
193
    ];
194
//]]>
195
</script>
196
<script type="text/javascript" src="[% themelang %]/js/file-upload.js"></script>
197
<script type="text/javascript">
198
//<![CDATA[
199
function StartUpload() {
200
    if( $('#fileToUpload').prop('files').length == 0 ) return;
201
    $('#fileToUpload').prop('disabled',true);
202
    $('#fileuploadbutton').hide();
203
    $("#fileuploadcancel").show();
204
    $("#fileuploadfailed").html('');
205
    $("#myalerts").hide('');
206
    $("#myalerts").html('');
207
    $("#fileuploadstatus").show();
208
    $("#uploadedfileid").val('');
209
    $("#searchfile").hide();
210
    $("#lastbreadcrumb").text( _("Add a new upload") );
211
212
    var xtra='';
213
    var catg = encodeURIComponent( $("#uploadcategory").val() );
214
    if( catg ) xtra= xtra + 'category=' + catg;
215
    [% IF plugin %]
216
        xtra = xtra + '&public=1';
217
    [% ELSE %]
218
        if( $('#public').prop('checked') ) xtra = xtra + '&public=1';
219
    [% END %]
220
    xhr= AjaxUpload( $('#fileToUpload'), $('#fileuploadprogress'), xtra, cbUpload );
221
}
222
function CancelUpload() {
223
    if( xhr ) xhr.abort();
224
    $("#fileuploadstatus").hide();
225
    $('#fileToUpload').prop('disabled', false);
226
    $('#fileuploadbutton').show();
227
    $("#fileuploadcancel").hide();
228
    $("#fileuploadfailed").show();
229
    $("#fileuploadfailed").text( _("Upload status: Cancelled ") );
230
}
231
function cbUpload( status, fileid, err ) {
232
    $('#fileToUpload').prop('disabled', false);
233
    if( status=='done' ) {
234
        var e = err? JSON.stringify(err): '';
235
        SubmitMe( 'search', fileid, e );
236
    } else {
237
        $('#fileuploadbutton').show();
238
        $("#fileuploadcancel").hide();
239
        $("#fileuploadstatus").hide();
240
        $("#fileuploadfailed").show();
241
        $("#fileuploadfailed").html( _("Upload status: ") +
242
            ( status=='failed'? _("Failed"):
243
            ( status=='denied'? _("Denied"): status ))
244
        );
245
        ShowAlerts( err );
246
    }
247
}
248
function ShowAlerts(err) {
249
    var str = '';
250
    for( var file in err ) {
251
        str= str + '<p>' + file + ': ' +
252
            errMESSAGES[ err[file] ] + '</p>';
253
    }
254
    if( str ) {
255
        $('#myalerts').html(str);
256
        $('#myalerts').show();
257
    }
258
}
259
function CheckSearch() {
260
    if( $("#term").val()=="" ) {
261
        alert( _("Please enter a search term.") );
262
        return false;
263
    }
264
    return true;
265
}
266
function SubmitMe(op, id, msg ) {
267
    $("#submitter #op").val( op );
268
    $("#submitter #id").val( id );
269
    $("#submitter #msg").val( msg );
270
    $("#submitter").submit();
271
}
272
function ClearField() {
273
    [% IF plugin %]
274
        $(window.opener.document).find('#[% index %]').val( '' );
275
    [% END %]
276
}
277
function Choose(hashval) {
278
    var res = '[% Koha.Preference('OPACBaseURL') %]';
279
    res = res.replace( /\/$/, '');
280
    res = res + '/cgi-bin/koha/opac-retrieve-file.pl?id=' + hashval;
281
    [% IF index %]
282
        $(window.opener.document).find('#[% index %]').val( res );
283
    [% END %]
284
    window.close();
285
}
286
$(document).ready(function() {
287
    [% IF msg %]
288
        ShowAlerts( [% msg %] );
289
    [% END %]
290
    $("#fileuploadcancel").hide();
291
});
292
//]]>
293
</script>
294
</head>
295
296
<body id="tools_upload" class="tools">
297
[% IF !plugin %]
298
    [% INCLUDE 'header.inc' %]
299
    [% INCLUDE 'cat-search.inc' %]
300
    [% PROCESS breadcrumbs %]
301
[% END %]
302
303
<div id="doc3" class="yui-t2">
304
   <div id="bd">
305
    <div id="yui-main">
306
    <div class="yui-b">
307
308
<h1>Upload</h1>
309
310
<div class="dialog alert" id="myalerts" style="display:none;"></div>
311
312
[% PROCESS submitter %]
313
[% IF mode == 'new' || mode == 'deleted' %]
314
    [% PROCESS form_new %]
315
    [% PROCESS form_search %]
316
    [% PROCESS closer %]
317
[% ELSIF mode == 'report' %]
318
    [% IF uploads %]
319
        <h3>Your request gave the following results:</h3>
320
        [% PROCESS table_results %]
321
        [% PROCESS closer %]
322
    [% ELSE %]
323
        <h4>Sorry, your request had no results.</h4>
324
        [% PROCESS newsearch %]
325
    [% END %]
326
[% END %]
327
328
</div>
329
</div>
330
</div>
331
332
[% INCLUDE 'intranet-bottom.inc' %]
(-)a/tools/upload-file.pl (-10 / +31 lines)
Lines 18-27 Link Here
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
19
20
use Modern::Perl;
20
use Modern::Perl;
21
use CGI::Cookie;
22
21
23
use CGI qw ( -utf8 );
22
use CGI qw ( -utf8 );
24
#use CGI::Session;
23
use CGI::Cookie;
24
use Encode;
25
use JSON;
26
use URI::Escape;
27
25
use C4::Context;
28
use C4::Context;
26
use C4::Auth qw/check_cookie_auth haspermission/;
29
use C4::Auth qw/check_cookie_auth haspermission/;
27
use Koha::Upload;
30
use Koha::Upload;
Lines 57-74 if ($auth_failure) { Link Here
57
    exit 0;
60
    exit 0;
58
}
61
}
59
62
60
my $upload = Koha::Upload->new({ });
63
my $upload = Koha::Upload->new( extr_pars($ENV{QUERY_STRING}) );
61
if( !$upload || !$upload->cgi || $upload->err ) {
64
if( !$upload || !$upload->cgi || !$upload->count ) {
62
    send_reply( 'failed' );
65
    # not one upload succeeded
66
    send_reply( 'failed', undef, $upload? $upload->err: undef );
63
} else {
67
} else {
64
    send_reply( 'done', $upload->result );
68
    # in case of multiple uploads, at least one got through
69
    send_reply( 'done', $upload->result, $upload->err );
65
}
70
}
66
exit 0;
71
exit 0;
67
72
68
sub send_reply {    # response will be sent back as JSON
73
sub send_reply {    # response will be sent back as JSON
69
    my ( $upload_status, $data ) = @_;
74
    my ( $upload_status, $data, $error ) = @_;
70
    my $reply = CGI->new("");
75
    my $reply = CGI->new("");
71
    print $reply->header(-type => 'text/html');
76
    print $reply->header( -type => 'text/html', -charset => 'UTF-8' );
72
    print '{"status":"' . $upload_status .
77
    print JSON::encode_json({
73
        ( $data? '","fileid":"' . $data: '' ) . '"}';
78
        status => $upload_status,
79
        fileid => $data,
80
        errors => $error,
81
   });
82
}
83
84
sub extr_pars {
85
    my ( $qstr ) = @_;
86
    $qstr = Encode::decode_utf8( uri_unescape( $qstr ) );
87
    # category could include a utf8 character
88
    my $rv = {};
89
    foreach my $p ( qw[public category] ) {
90
        if( $qstr =~ /(^|&)$p=(\w+)(&|$)/ ) {
91
            $rv->{$p} = $2;
92
        }
93
    }
94
    return $rv;
74
}
95
}
(-)a/tools/upload.pl (-1 / +98 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/perl
2
3
# This file is part of Koha.
4
#
5
# Copyright (C) 2015 Rijksmuseum
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
use CGI qw/-utf8/;
22
use JSON;
23
24
use C4::Auth;
25
use C4::Output;
26
use Koha::Upload;
27
28
my $input = CGI::->new;
29
my $op = $input->param('op') // 'new';
30
my $plugin = $input->param('plugin');
31
my $index = $input->param('index'); # MARC editor input field id
32
my $term = $input->param('term');
33
my $id = $input->param('id');
34
my $msg = $input->param('msg');
35
36
my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
37
    {   template_name   => "tools/upload.tt",
38
        query           => $input,
39
        type            => "intranet",
40
        authnotrequired => 0,
41
        flagsrequired   => { editcatalogue => '*' },
42
    }
43
);
44
45
$template->param(
46
    plugin => $plugin,
47
    index  => $index,
48
);
49
50
my $upar = $plugin? { public => 1 }: {};
51
if( $op eq 'new' ) {
52
    $template->param(
53
        mode => 'new',
54
        uploadcategories => Koha::Upload->getCategories,
55
    );
56
    output_html_with_http_headers $input, $cookie, $template->output;
57
} elsif( $op eq 'search' ) {
58
    my $h = $id? { id => $id }: { term => $term };
59
    my @uploads = Koha::Upload->new( $upar )->get( $h );
60
    $template->param(
61
        mode => 'report',
62
        msg => $msg,
63
        uploads => \@uploads,
64
    );
65
    output_html_with_http_headers $input, $cookie, $template->output;
66
} elsif( $op eq 'delete' ) {
67
    # delete only takes the id parameter
68
    my $upl = Koha::Upload->new( $upar );
69
    my ( $fn ) = $upl->delete({ id => $id });
70
    my $e = $upl->err;
71
    my $msg = $fn? JSON::to_json({ $fn => 6 }):
72
        $e? JSON::to_json( $e ): undef;
73
    $template->param(
74
        mode => 'deleted',
75
        msg => $msg,
76
        uploadcategories => $upl->getCategories,
77
    );
78
    output_html_with_http_headers $input, $cookie, $template->output;
79
} elsif( $op eq 'download' ) {
80
    my $upl = Koha::Upload->new( $upar );
81
    my $rec = $upl->get({ id => $id, filehandle => 1 });
82
    my $fh = $rec->{fh};
83
    if( !$rec || !$fh ) {
84
        $template->param(
85
            mode => 'new',
86
            msg => JSON::to_json({ $id => 5 }),
87
            uploadcategories => $upl->getCategories,
88
        );
89
        output_html_with_http_headers $input, $cookie, $template->output;
90
    } else {
91
        my @hdr = $upl->httpheaders( $rec->{name} );
92
        print $input->header( @hdr );
93
        while( <$fh> ) {
94
            print $_;
95
        }
96
        $fh->close;
97
    }
98
}

Return to bug 14321