3 use vars qw(@ISA @EXPORT_OK);
4 use BSE::Util::SQL qw(sql_datetime now_sqldatetime);
8 @EXPORT_OK = qw(bse_cfg bse_make_product bse_make_catalog bse_encoding bse_add_image bse_add_step_child bse_add_owned_file bse_delete_owned_file bse_replace_owned_file);
9 use Carp qw(confess croak);
12 my %acticle_defaults =
19 release => sql_datetime(time - 86_400),
20 expire => '2999-12-31',
22 template => 'common/default.tmpl',
23 link => '', # needs to be set
24 admin => '', # needs to be set
27 generator => 'Generate::Article',
28 # level => undef, # needs to be set
30 #lastModified => undef, # needs to be set
33 # created => undef # needs to be set
37 inherit_siteuser_rights => 1,
38 metaDescription => '',
48 my %product_defaults =
50 template => 'shopitem.tmpl',
52 generator => 'Generate::Product',
57 subscription_id => -1,
58 subscription_period => 1,
59 subscription_usage => 3,
60 subscription_required => -1,
68 my %catalog_defaults =
70 template => 'catalog.tmpl',
72 generator => 'Generate::Catalog',
76 my ($cfg, $article) = @_;
78 if ($article->{parentid} == -1) {
79 $article->{level} = 1;
83 my $parent = Articles->getByPkey($article->{parentid})
84 or confess "Invalid parent $article->{parentid}\n";
85 $article->{level} = $parent->{level} + 1;
88 $article->{lastModified} = $article->{created} = now_sqldatetime();
91 sub _finalize_article {
92 my ($cfg, $article, $editor_class) = @_;
94 my $editor = $editor_class->new(cfg => $cfg, db => BSE::DB->single);
96 $article->update_dynamic($cfg);
97 $article->setAdmin("/cgi-bin/admin/admin.pl?id=$article->{id}");
98 $article->setLink($editor->make_link($article));
104 sub _next_display_order {
106 my ($row) = BSE::DB->query("bse_MaxArticleDisplayOrder");
107 $order = $row->{displayOrder} + 1;
115 my $cfg = BSE::Cfg->new;
116 $cfg->entry('site', 'url')
117 or confess "Could not load configuration";
122 sub bse_make_product {
125 my $cfg = delete $opts{cfg}
126 or confess "cfg option missing";
130 defined $opts{title} && length $opts{title}
131 or confess "Missing title option\n";
132 defined $opts{body} && length $opts{body}
133 or confess "Missing body option\n";
134 defined $opts{retailPrice} && $opts{retailPrice} =~ /^\d+$/
135 or confess "Missing or invalid retailPrice\n";
137 $opts{summary} ||= $opts{title};
138 $opts{description} ||= $opts{title};
139 unless ($opts{displayOrder}) {
140 $opts{displayOrder} = _next_display_order();
150 _set_dynamic($cfg, \%opts);
152 my @cols = Product->columns;
154 my $product = Products->add(@opts{@cols});
156 require BSE::Edit::Product;
157 _finalize_article($cfg, $product, 'BSE::Edit::Product');
162 sub bse_make_catalog {
165 my $cfg = delete $opts{cfg}
166 or confess "cfg option missing";
170 defined $opts{title} && length $opts{title}
171 or confess "Missing title option\n";
172 defined $opts{body} && length $opts{body}
173 or confess "Missing body option\n";
175 $opts{summary} ||= $opts{title};
176 unless ($opts{displayOrder}) {
177 $opts{displayOrder} = _next_display_order();
187 _set_dynamic($cfg, \%opts);
189 my @cols = Article->columns;
191 my $catalog = Articles->add(@opts{@cols});
193 require BSE::Edit::Catalog;
194 _finalize_article($cfg, $catalog, 'BSE::Edit::Catalog');
199 my %other_parent_defaults =
201 release => sql_datetime(time - 86_400),
202 expire => '2999-12-31',
205 sub bse_add_step_child {
208 my $cfg = delete $opts{cfg}
209 or confess "cfg option missing";
211 require OtherParents;
213 my $parent = delete $opts{parent}
214 or confess "parent option missing";
215 my $child = delete $opts{child}
216 or confess "child option missing";
219 %other_parent_defaults,
220 parentId => $parent->{id},
221 childId => $child->{id},
224 $opts{parentDisplayOrder} ||= _next_display_order();
225 $opts{childDisplayOrder} ||= _next_display_order();
227 my @cols = OtherParent->columns;
230 return OtherParents->add(@opts{@cols});
236 $cfg && $cfg->can('entry')
237 or confess "bse_encoding: Missing cfg parameter\n";
239 return $cfg->entry('html', 'charset', 'iso-8859-1');
243 my ($cfg, $article, %opts) = @_;
246 ($editor, $article) = _load_editor_class($article, $cfg);
249 my $file = delete $opts{file};
251 or croak "Missing image filename";
253 or croak "Failed opening image file $file: $!";
257 $editor->do_add_image
268 sub _load_editor_class {
269 my ($article, $cfg) = @_;
271 require BSE::Edit::Base;
272 return BSE::Edit::Base->article_class($article, 'Articles', $cfg);
275 # File::Copy doesn't like CGI.pm's fake fhs
276 sub _copy_file_from_fh {
277 my ($in_fh, $out_fh) = @_;
281 seek $in_fh, 0, SEEK_SET;
284 while (defined ($data = <$in_fh>)) {
291 sub bse_add_owned_file {
292 my ($cfg, $owner, %opts) = @_;
294 defined $opts{display_name} && $opts{display_name} =~ /\S/
295 or croak "bse_add_owned_file: display_name must be non-blank";
297 defined $opts{title} && $opts{title} =~ /\S/
298 or $opts{title} = $opts{display_name};
300 unless ($opts{content_type}) {
301 require BSE::Util::ContentType;
302 $opts{content_type} = BSE::Util::ContentType::content_type($cfg, $opts{display_name});
305 my $file = delete $opts{file}
306 or die "No source file provided\n";;
308 # copy the file to the right place
309 require DevHelp::FileUpload;
310 my $file_dir = $cfg->entryVar('paths', 'downloads');
312 my ($saved_name, $out_fh) = DevHelp::FileUpload->
313 make_img_filename($file_dir, $opts{display_name}, \$msg)
315 _copy_file_from_fh($file, $out_fh)
317 unless (close $out_fh) {
318 die "Error saving file: $!\n";
321 $opts{owner_type} = $owner->file_owner_type;
322 $opts{size_in_bytes} = -s "$file_dir/$saved_name";
323 $opts{owner_id} = $owner->id;
324 $opts{category} ||= '';
325 $opts{filename} = $saved_name;
327 require BSE::TB::OwnedFiles;
328 my $result = BSE::TB::OwnedFiles->make(%opts);
330 if ($cfg->entry('notify_files', 'active', 0)) {
331 BSE::DB->run(bseAddOwnedFileNotification => $result->id, $owner->file_owner_type, $owner->id);
337 sub bse_delete_owned_file {
338 my ($cfg, $owned_file) = @_;
340 my $file_dir = $cfg->entryVar('paths', 'downloads');
341 unlink "$file_dir/$owned_file->{filename}";
345 sub bse_replace_owned_file {
346 my ($cfg, $owned_file, %opts) = @_;
348 my $file_dir = $cfg->entryVar('paths', 'downloads');
352 require DevHelp::FileUpload;
353 my ($saved_name, $out_fh) = DevHelp::FileUpload->
354 make_img_filename($file_dir, $opts{display_name}, \$msg)
356 _copy_file_from_fh($opts{file}, $out_fh)
358 unless (close $out_fh) {
359 die "Error saving file: $!\n";
361 $old_name = $owned_file->{filename};
362 $owned_file->{filename} = $saved_name;
363 $owned_file->{size_in_bytes} = -s "$file_dir/$saved_name";
366 for my $field (qw/category display_name content_type download title body modwhen size_in_bytes/) {
367 defined $opts{$field}
368 and $owned_file->{$field} = $opts{$field};
372 and unlink "$file_dir/$old_name";