Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 41e8ff9e

Von Werner Hahn vor mehr als 8 Jahren hinzugefügt

  • ID 41e8ff9e2f47080b5935ee760a325517e2036b31
  • Vorgänger 8081e39b
  • Nachfolger 6abedbe4

Fileuploader: cherry-pick2

Unterschiede anzeigen:

SL/Controller/FileUploader.pm
27 27
  $self->render('common/file_upload', {header => 0});
28 28
}
29 29

  
30
<<<<<<< HEAD
30 31
sub action_show_files {
31 32
  my ($self) = @_;
32 33

  
33 34

  
34 35
}
35 36

  
37
=======
38
>>>>>>> 85669d3... Fileuploader: Textpage für Parts und Shopparts ohne callback, Bilder werden mit thumbnails in der Datenbank gespeichert
36 39
sub action_ajax_add_file{
37 40
  my ($self) = @_;
38 41
  $self->file(SL::DB::File->new);
SL/DB/File.pm
1
# This file has been auto-generated only because it didn't exist.
2
# Feel free to modify it at will; it will not be overwritten automatically.
3

  
4
package SL::DB::File;
5

  
6
use strict;
7

  
8
use SL::DB::MetaSetup::File;
9
use SL::DB::Manager::File;
10
use SL::DB::Helper::ActsAsList;
11
use SL::DB::Helper::ThumbnailCreator;
12
use SL::Locale::String;
13

  
14
__PACKAGE__->meta->initialize;
15

  
16
__PACKAGE__->configure_acts_as_list(group_by => [qw(trans_id modul)]);
17

  
18
__PACKAGE__->before_save(\&file_update_thumbnail);
19

  
20
sub validate {
21
  my ( $self ) = @_;
22

  
23
  my @errors;
24
  push @errors, t8('The file name is missing') if !$self->filename;
25

  
26
  if (!length($self->file_content // '')) {
27
    push @errors, t8('No file has been uploaded');
28
  } else {
29
    push @errors, $self->file_update_type_and_dimensions;
30
  }
31
  return @errors;
32
}
33

  
34
1;
35
__END__
36

  
37
=pod
38

  
39
=encoding utf8
40

  
41
=head1 NAME
42

  
43
SL::DB::File - Databaseclass for Fileuploader
44

  
45
=head1 SYNOPSIS
46

  
47
  use SL::DB::File;
48

  
49
  # synopsis...
50

  
51
=head1 DESCRIPTION
52

  
53
# longer description.
54

  
55

  
56
=head1 INTERFACE
57

  
58

  
59
=head1 DEPENDENCIES
60

  
61

  
62
=head1 SEE ALSO
63

  
64
=head1 AUTHOR
65

  
66
Werner Hahn E<lt>wh@futureworldsearch.netE<gt>
67

  
68
=cut
SL/DB/Helper/ThumbnailCreator.pm
1
package SL::DB::Helper::ThumbnailCreator;
2

  
3
use strict;
4

  
5
use Carp;
6
use GD;
7
use Image::Info;
8
use File::MimeInfo::Magic;
9
use List::MoreUtils qw(apply);
10
use List::Util qw(max);
11
use Rose::DB::Object::Util;
12

  
13
require Exporter;
14
our @ISA      = qw(Exporter);
15
our @EXPORT   = qw(file_create_thumbnail file_update_thumbnail file_probe_type file_update_type_and_dimensions);
16

  
17
# TODO PDFs and others like odt,txt,...
18
our %supported_mime_types = (
19
  'image/gif'  => { extension => 'gif', convert_to_png => 1, },
20
  'image/png'  => { extension => 'png' },
21
  'image/jpeg' => { extension => 'jpg' },
22
  'image/tiff' => { extension => 'tif'},
23
);
24

  
25
sub file_create_thumbnail {
26
  my ($self) = @_;
27
  croak "No picture set yet" if !$self->file_content;
28

  
29
  my $image            = GD::Image->new($self->file_content);
30
  my ($width, $height) = $image->getBounds;
31
  my $max_dim          = 64;
32
  my $curr_max         = max $width, $height, 1;
33
  my $factor           = $curr_max <= $max_dim ? 1 : $curr_max / $max_dim;
34
  my $new_width        = int($width  / $factor + 0.5);
35
  my $new_height       = int($height / $factor + 0.5);
36
  my $thumbnail        = GD::Image->new($new_width, $new_height);
37

  
38
  $thumbnail->copyResized($image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
39

  
40
  $self->thumbnail_img_content($thumbnail->png);
41
  $self->thumbnail_img_content_type('image/png');
42
  $self->thumbnail_img_width($new_width);
43
  $self->thumbnail_img_height($new_height);
44
  return 1;
45

  
46
}
47

  
48
sub file_update_thumbnail {
49
  my ($self) = @_;
50

  
51
  return 1 if !$self->file_content || !$self->file_content_type || !Rose::DB::Object::Util::get_column_value_modified($self, 'file_content');
52
  $self->file_create_thumbnail;
53
  return 1;
54
}
55

  
56
sub file_probe_type {
57
  my ($self) = @_;
58

  
59
  return (t8("No file uploaded yet")) if !$self->file_content;
60
  my $mime_type = File::MimeInfo::Magic::magic($self->file_content);
61

  
62
  my $info = Image::Info::image_info(\$self->{file_content});
63
  if (!$info || $info->{error} || !$info->{file_media_type} || !$supported_mime_types{ $info->{file_media_type} }) {
64
    $::lxdebug->warn("Image::Info error: " . $info->{error}) if $info && $info->{error};
65
    return (t8('Unsupported image type (supported types: #1)', join(' ', sort keys %supported_mime_types)));
66
  }
67

  
68
  $self->file_content_type($info->{file_media_type});
69
  $self->files_img_width($info->{width});
70
  $self->files_img_height($info->{height});
71
  $self->files_mtime(DateTime->now_local);
72

  
73
  $self->file_create_thumbnail;
74

  
75
  return ();
76
}
77

  
78
sub file_update_type_and_dimensions {
79
  my ($self) = @_;
80

  
81
  return () if !$self->file_content;
82
  return () if $self->file_content_type && $self->file_img_width && $self->file_img_height && !Rose::DB::Object::Util::get_column_value_modified($self, 'file_content');
83

  
84
  my @errors = $self->file_probe_type;
85
  return @errors if @errors;
86

  
87
  my $info = $supported_mime_types{ $self->file_content_type };
88
  if ($info->{convert_to_png}) {
89
    $self->file_content(GD::Image->new($self->file_content)->png);
90
    $self->file_content_type('image/png');
91
    $self->filename(apply { s/\.[^\.]+$//;  $_ .= '.png'; } $self->filename);
92
  }
93
  return ();
94
}
95

  
96
1;
97
__END__
98

  
99
=pod
100

  
101
=encoding utf8
102

  
103
=head1 NAME
104

  
105
SL::DB::Helper::ThumbnailCreator - DatabaseClass Helper for Fileuploads
106

  
107
=head1 SYNOPSIS
108

  
109
  use SL::DB::Helper::ThumbnailCreator;
110

  
111
  # synopsis...
112

  
113
=head1 DESCRIPTION
114

  
115
# longer description..
116
=head1 AUTHOR
117

  
118
Werner Hahn E<lt>wh@futureworldsearch.netE<gt>
119

  
120
=cut
121

  
122

  
123
=head1 INTERFACE
124

  
125

  
126
=head1 DEPENDENCIES
127

  
128

  
129
=head1 SEE ALSO
130

  
131

  
SL/DB/Manager/File.pm
1
# This file has been auto-generated only because it didn't exist.
2
# Feel free to modify it at will; it will not be overwritten automatically.
3

  
4
package SL::DB::Manager::File;
5

  
6
use strict;
7

  
8
use parent qw(SL::DB::Helper::Manager);
9

  
10
sub object_class { 'SL::DB::File' }
11

  
12
__PACKAGE__->make_manager_methods;
13

  
14
1;
SL/DB/MetaSetup/File.pm
1
# This file has been auto-generated. Do not modify it; it will be overwritten
2
# by rose_auto_create_model.pl automatically.
3
package SL::DB::File;
4

  
5
use strict;
6

  
7
use parent qw(SL::DB::Object);
8

  
9
__PACKAGE__->meta->table('files');
10

  
11
__PACKAGE__->meta->columns(
12
  description                => { type => 'text' },
13
  file_content               => { type => 'bytea' },
14
  file_content_type          => { type => 'text' },
15
  filename                   => { type => 'text', not_null => 1 },
16
  files_img_height           => { type => 'integer' },
17
  files_img_width            => { type => 'integer' },
18
  files_mtime                => { type => 'timestamp', default => 'now()' },
19
  id                         => { type => 'serial', not_null => 1 },
20
  itime                      => { type => 'timestamp', default => 'now()' },
21
  location                   => { type => 'text' },
22
  modul                      => { type => 'text', not_null => 1 },
23
  mtime                      => { type => 'timestamp' },
24
  position                   => { type => 'integer' },
25
  thumbnail_img_content      => { type => 'bytea' },
26
  thumbnail_img_content_type => { type => 'text' },
27
  thumbnail_img_height       => { type => 'integer' },
28
  thumbnail_img_width        => { type => 'integer' },
29
  title                      => { type => 'varchar', length => 45 },
30
  trans_id                   => { type => 'integer', not_null => 1 },
31
);
32

  
33
__PACKAGE__->meta->primary_key_columns([ 'id' ]);
34

  
35
__PACKAGE__->meta->allow_inline_column_values(1);
36

  
37
1;
38
;
sql/Pg-upgrade2/files.sql
1
-- @tag: files
2
-- @description: Tabelle für Files
3
-- @charset: UTF-8
4
-- @depends: release_3_3_0
5
-- @ignore: 0
6

  
7
CREATE TABLE files(
8
  id                          SERIAL PRIMARY KEY,
9
  modul                       TEXT NOT NULL, -- Tabellenname des Moduls z.B. customer, parts ... Fremdschlüssel Zusammen mit trans_id
10
  trans_id                    INTEGER NOT NULL, -- Fremschlüssel auf die id der Tabelle aus Spalte modul
11
  filename                    TEXT NOT NULL, -- Dateiname
12
  location                    TEXT, -- Dateipfad
13
  description                 TEXT, -- Zusätzliche Beschreibung z.B. Alternative Bildbeschreibung für Shopbilder
14
  position                    INTEGER , -- Sortierreihenfolge der Bilder UNIQUE zusammen mit trans_id
15
  itime                       TIMESTAMP DEFAULT now(),
16
  mtime                       TIMESTAMP,
17
  file_content                bytea,
18
  files_img_width             integer,
19
  files_img_height            integer,
20
  thumbnail_img_content       bytea,
21
  thumbnail_img_width         integer,
22
  thumbnail_img_height        integer,
23
  title                       varchar(45),
24
  file_content_type           TEXT,
25
  files_mtime                 TIMESTAMP DEFAULT now(),
26
  thumbnail_img_content_type  TEXT
27
);
28

  
29
CREATE TRIGGER mtime_files BEFORE UPDATE ON files
30
    FOR EACH ROW EXECUTE PROCEDURE set_mtime();
templates/webpages/common/file_upload.html
1
[%- USE LxERP -%][%- USE L -%][%- USE HTML -%][%- USE JavaScript -%][% USE Base64 %]
2
[% SET style="width: 500px" %]
3
[% SET id_base = "fileupload" %]
4
[% L.dump(DATA) %]
5
<form method="post" id="fileupload_form" method="POST" enctype="multipart/form-data">
6
 [% L.hidden_tag('form_prefix',                    id_base,         id=id_base _ '_form_prefix') %]
7
 [% L.hidden_tag('id',                             DATA.id, no_id=1) %]
8
 [% L.hidden_tag('modul',                          DATA.modul) %]
9

  
10
 <h2>
11
  [%- IF SELF.file.id %]
12
   [%- LxERP.t8("Edit file properties ", SELF.file.number) %]
13
  [%- ELSE %]
14
   [%- LxERP.t8("Add file to webdav") %]
15
  [%- END %]
16
 </h2>
17

  
18
 <table>
19
[% IF SELF.file.number %]
20
  <tr>
21
   <th align="right">[%- LxERP.t8("Number") %]:</th>
22
   <td>[% HTML.escape(SELF.file.number) %]</td>
23
  </tr>
24
[% END %]
25

  
26
  <tr>
27
   <th align="right">[%- LxERP.t8("Description") %]:</th>
28
   <td>[% L.input_tag(id_base _ '.description', SELF.file.description, style=style) %]</td>
29
  </tr>
30

  
31
  <tr>
32
   <th align="right">[%- LxERP.t8("Title") %]:</th>
33
   <td>[% L.input_tag(id_base _ '.title', SELF.file.title, style=style) %]</td>
34
  </tr>
35

  
36
[% IF SELF.file.file_content %]
37
  <tr>
38
   <th align="right">[%- LxERP.t8("File name") %]:</th>
39
   <td>[% HTML.escape(SELF.file.file_file_name) %]</td>
40
  </tr>
41

  
42
  <tr>
43
   <th align="right">[%- LxERP.t8("MIME type") %]:</th>
44
   <td>[% HTML.escape(SELF.file.file_content_type) %]</td>
45
  </tr>
46

  
47
  <tr>
48
   <th align="right">[%- LxERP.t8("Dimensions") %]:</th>
49
   <td>[% HTML.escape(SELF.file.file_width) %]x[% HTML.escape(SELF.file.file_height) %]</td>
50
  </tr>
51

  
52
  <tr>
53
   <th align="right">[%- LxERP.t8("Uploaded at") %]:</th>
54
   <td>[% HTML.escape(SELF.file.file_mtime.to_kivitendo(precision='second')) %]</td>
55
  </tr>
56
[% END %]
57

  
58
  <tr>
59
   <th align="right">[%- LxERP.t8("Select file to upload") %]:</th>
60
   <td>[% L.input_tag(id_base _ '.file_content', '', type='file') %]</td>
61
  </tr>
62
 </table>
63

  
64
 <p>
65
  [%- L.ajax_submit_tag('controller.pl?action=FileUploader/ajax_upload_file', '#fileupload_form', LxERP.t8('Save'), no_id=1) %]
66
  <a href="#" onclick="$('#jqueryui_popup_dialog').dialog('close');">[%- LxERP.t8("Cancel") %]</a>
67
 </p>
68

  
69
</form>
70

  
71
[% IF SELF.file.id %]
72
<h2>[% LxERP.t8("Current file") %]</h2>
73

  
74
<div>
75
 <img src="data:[% HTML.escape(SELF.file.file_content_type) %];base64,[% SELF.file.file_content.encode_base64 %]">
76
</div>
77
[% END %]
templates/webpages/fileuploader/test_page.html
1
[% USE L %]
2

  
3
<h1>Fileupload Testpage</h1>
4
<form method="post" id="fileupload" method="POST" enctype="multipart/form-data">
5
  <div id="testfunctions" style="width:50%; float:left; border:thin solid green">
6
    <div id="part_1" height="75px">
7
      Part: Select Part Where to store the file<br>
8
      [% L.part_picker('part_id1','',fat_set_item=1) %]<br>
9
      Part: <span id="change1"> </span> -- <span id="change2"></span><br>
10
      <div id="fileupload_button" style="display:none;">
11
        [% L.hidden_tag("id") %]
12
        [% L.hidden_tag("modul","part") %]
13
        [% L.button_tag("add_file(this.form.id.value,this.form.modul.value)", 'Fileupload') %]
14
      </div>
15
    </div>
16
    <div id="shoppart" height="75px">
17
      ShopPart: Select Part Where to store the file<br>
18
      [% L.part_picker('shoppart','',fat_set_item=1) %]<br>
19
      ShopPart: <span id="shoppartchange1"> </span> -- <span id="shoppartchange2"></span><br>
20
      <div id="shop_img_upload_button" style="display:none;">
21
        [% L.hidden_tag("shop_part_id") %]
22
        [% L.hidden_tag("shop_part_modul","shop_part") %]
23
        [% L.button_tag("add_file(this.form.shop_part_id.value,this.form.shop_part_modul.value)", 'Fileupload') %]
24
      </div>
25
    </div>
26
  </div>
27
</form>
28

  
29
<div id="testviews" style="width:50%; float:left; border:thin solid green">
30
  <div id="viewpart" height="75px">
31
  </div>
32
  <div id="viewshoppart" height="75px">
33
  </div>
34
</div>
35
<script type='text/javascript'>
36
<!--
37
 $('#part_id1').change(function() { $('#change1').html($('#part_id1').val()) });
38
 $('#part_id1').on('set_item:PartPicker', function(e,o) { $('#id').val(o.id);
39
                                                          $('#change2').html(o.id);
40
                                                          $('#fileupload_button').show();
41
                                                                  });
42
 $('#shoppart').change(function() { $('#shoppartchange1').html($('#shoppart').val()) });
43
 $('#shoppart').on('set_item:PartPicker', function(e,o) { $('#shop_part_id').val(o.id);
44
                                                          $('#shoppartchange2').html(o.id);
45
                                                          $('#shop_img_upload_button').show();
46
                                                                  });
47
function add_file(id,modul) {
48
  //var id = this.$('#part').val();
49
  kivi.popup_dialog({
50
        url :           'controller.pl?action=FileUploader/ajax_add_file',
51
        data:           'id=' + id + '&modul=' + modul,
52
        dialog:         { title: kivi.t8('File upload') }
53
  } );
54
  return true;
55
}
56
-->
57
</script>

Auch abrufbar als: Unified diff