]> git.imager.perl.org - bse.git/blame - site/cgi-bin/modules/Article.pm
admin links are now synthesized links to admin.pl
[bse.git] / site / cgi-bin / modules / Article.pm
CommitLineData
41b9d8ec 1package Article;
9d29b58f 2use strict;
41b9d8ec
TC
3# represents an article from the database
4use Squirrel::Row;
7646d96e 5use BSE::TB::SiteCommon;
76c6b28e 6use BSE::TB::TagOwner;
41b9d8ec 7use vars qw/@ISA/;
76c6b28e 8@ISA = qw/Squirrel::Row BSE::TB::SiteCommon BSE::TB::TagOwner/;
efcc5a30 9use Carp 'confess';
41b9d8ec 10
ec5a2133 11our $VERSION = "1.011";
cb7fd78d 12
41b9d8ec
TC
13sub columns {
14 return qw/id parentid displayOrder title titleImage body
15 thumbImage thumbWidth thumbHeight imagePos
16 release expire keyword template link admin threshold
331fd099 17 summaryLength generator level listed lastModified flags
9063386f 18 customDate1 customDate2 customStr1 customStr2
9604a90c 19 customInt1 customInt2 customInt3 customInt4
efcc5a30 20 lastModifiedBy created createdBy author pageTitle
12bcb7ac 21 force_dynamic cached_dynamic inherit_siteuser_rights
dbfbfb12
TC
22 metaDescription metaKeywords summary menu titleAlias linkAlias
23 category/;
41b9d8ec
TC
24}
25
58baa27b
TC
26sub table {
27 'article';
28}
29
41f10371
TC
30sub numeric {
31 qw(id listed parentid threshold summaryLength level
0a66f55c 32 customInt1 customInt2 customInt3 customInt4 menu);
41f10371
TC
33}
34
ff9130e4
TC
35sub section {
36 my ($self) = @_;
37
38 my $section = $self;
39 while ($section->{parentid} > 0
40 and my $parent = Articles->getByPkey($section->{parentid})) {
41 $section = $parent;
42 }
43
44 return $section;
45}
46
08123550
TC
47sub parent {
48 my ($self) = @_;
49 $self->{parentid} == -1 and return;
50 return Articles->getByPkey($self->{parentid});
51}
52
efcc5a30
TC
53sub update_dynamic {
54 my ($self, $cfg) = @_;
55
56 $cfg && $cfg->can('entry')
57 or confess 'update_dynamic called without $cfg';
58
59 # conditional in case something strange is in the config file
60 my $dynamic = $cfg->entry('basic', 'all_dynamic', 0) ? 1 : 0;
61
dfd483db
TC
62 if (!$dynamic && $self->generator =~ /\bCatalog\b/) {
63 require Products;
64 my @tiers = Products->pricing_tiers;
65 @tiers and $dynamic = 1;
66 }
67
efcc5a30
TC
68 $dynamic or $dynamic = $self->{force_dynamic};
69
63e99d77 70 $dynamic or $dynamic = $self->is_access_controlled;
c2096d67 71
63e99d77 72 $dynamic or $dynamic = $self->force_dynamic_inherited;
efcc5a30
TC
73
74 $self->{cached_dynamic} = $dynamic;
75}
76
77sub is_dynamic {
78 $_[0]{cached_dynamic};
79}
80
c2096d67
TC
81sub is_accessible_to {
82 my ($self, $group) = @_;
83
84 my $groupid = ref $group ? $group->{id} : $group;
85
86 my @rows = BSE::DB->query(articleAccessibleToGroup => $self->{id}, $groupid);
87
88 scalar @rows;
89}
90
91sub group_ids {
92 my ($self) = @_;
93
94 map $_->{id}, BSE::DB->query(siteuserGroupsForArticle => $self->{id});
95}
96
97sub add_group_id {
98 my ($self, $id) = @_;
99
100 eval {
101 BSE::DB->single->run(articleAddSiteUserGroup => $self->{id}, $id);
102 };
103}
104
105sub remove_group_id {
106 my ($self, $id) = @_;
107
108 BSE::DB->single->run(articleDeleteSiteUserGroup => $self->{id}, $id);
109}
110
b873a8fa
TC
111sub is_access_controlled {
112 my ($self) = @_;
113
114 my @group_ids = $self->group_ids;
115 return 1 if @group_ids;
116
117 return 0
118 unless $self->{inherit_siteuser_rights};
119
120 my $parent = $self->parent
121 or return 0;
122
123 return $parent->is_access_controlled;
124}
125
63e99d77
TC
126sub force_dynamic_inherited {
127 my ($self) = @_;
128
129 my $parent = $self->parent
130 or return 0;
131
132 $parent->{force_dynamic} && $parent->{flags} =~ /F/
133 and return 1;
134
135 return $parent->force_dynamic_inherited;
136}
137
138sub link_to_filename {
139 my ($self, $cfg, $link) = @_;
140
a739c25d 141 $cfg ||= BSE::Cfg->single;
16901a2a 142
63e99d77
TC
143 defined $link or $link = $self->{link};
144
8f84f3f1
TC
145 length $link or return;
146
63e99d77 147 my $filename = $link;
981d07ba
TC
148
149 # remove any appended title,
150 $filename =~ s!(.)/\w+$!$1!;
63e99d77 151 $filename =~ s{^\w+://[\w.-]+(?::\d+)?}{};
5abe2da5 152 $filename = $cfg->content_base_path() . $filename;
981d07ba
TC
153 if ($filename =~ m(/$)) {
154 $filename .= $cfg->entry("basic", "index_file", "index.html");
155 }
63e99d77
TC
156 $filename =~ s!//+!/!;
157
158 return $filename;
159}
160
16901a2a
TC
161sub cached_filename {
162 my ($self, $cfg) = @_;
163
a739c25d 164 $cfg ||= BSE::Cfg->single;
16901a2a
TC
165
166 my $dynamic_path = $cfg->entryVar('paths', 'dynamic_cache');
167 return $dynamic_path . "/" . $self->{id} . ".html";
168}
169
a739c25d
TC
170sub html_filename {
171 my ($self, $cfg) = @_;
172
173 $cfg ||= BSE::Cfg->single;
174
175 return $self->is_dynamic
176 ? $self->cached_filename($cfg)
177 : $self->link_to_filename($cfg);
178}
179
180sub remove_html {
181 my ($self, $cfg) = @_;
182
183 my $filename = $self->html_filename($cfg)
184 or return 1;
185
186 unlink $filename
187 or return;
188
189 return 1;
190}
191
bf87e97c
TC
192sub remove {
193 my ($self, $cfg) = @_;
194
195 $cfg or confess "No \$cfg supplied to ", ref $self, "->remove";
196
76c6b28e
TC
197 $self->remove_tags;
198
bf87e97c 199 $self->remove_images($cfg);
16901a2a
TC
200
201 for my $file ($self->files) {
202 $file->remove($cfg);
203 }
204
205 # remove any step(child|parent) links
206 require OtherParents;
207 my @steprels = OtherParents->anylinks($self->{id});
208 for my $link (@steprels) {
209 $link->remove();
210 }
211
212 # remove the static page
a739c25d 213 $self->remove_html($cfg);
16901a2a
TC
214
215 $self->SUPER::remove();
216}
217
201e926c
TC
218sub all_parents {
219 my ($self) = @_;
220
221 my @result = $self->step_parents;
222 if ($self->{parentid} > 0 && !grep $_->{id} eq $self->{parentid}, @result) {
223 push @result, $self->parent;
224 }
225
226 return @result;
227}
228
229sub is_step_ancestor {
230 my ($self, $other, $max) = @_;
231
232 my $other_id = ref $other ? $other->{id} : $other;
233 my %seen;
234
235 $max ||= 10;
236
237 # early exit if possible
238 return 1 if $self->{parentid} == $other_id;
239
240 my @all_parents = $self->all_parents;
241 return 1 if grep $_->{id} == $other_id, @all_parents;
242 my @work = map [ 0, $_], grep !$seen{$_}++, @all_parents;
243 while (@work) {
244 my $entry = shift @work;
245 my ($level, $workart) = @$entry;
246
247 $level++;
248 if ($level < $max) {
249 @all_parents = $workart->all_parents;
250 return 1 if grep $_->{id} == $other_id, @all_parents;
251 push @work, map [ $level, $_ ], grep !$seen{$_}++, @all_parents;
252 }
253 }
254
255 return 0;
256}
257
147e99e8
TC
258sub possible_stepparents {
259 my $self = shift;
260
261 return BSE::DB->query(articlePossibleStepparents => $self->{id}, $self->{id});
262}
263
264sub possible_stepchildren {
265 my $self = shift;
266
267 return BSE::DB->query(articlePossibleStepchildren => $self->{id}, $self->{id});
268}
269
c76e86ea
TC
270sub link {
271 my ($self, $cfg) = @_;
272
538b7aee
TC
273 if ($self->flags =~ /P/) {
274 my $parent = $self->parent;
275 $parent and return $parent->link($cfg);
276 }
277
a739c25d
TC
278 $self->is_linked
279 or return "";
280
538b7aee 281 $cfg ||= BSE::Cfg->single;
089bef32 282
cddcd8c0
TC
283 unless ($self->{linkAlias} && $cfg->entry('basic', 'use_alias', 1)) {
284 return $self->{link};
285 }
286
287 my $prefix = $cfg->entry('basic', 'alias_prefix', '');
288 my $link;
289 if ($cfg->entry('basic', 'alias_recursive')) {
290 my @steps = $self->{linkAlias};
291 my $article = $self;
292 while ($article = $article->parent) {
293 if ($article->{linkAlias}) {
294 unshift @steps, $article->{linkAlias};
295 }
73e6b73a 296 }
cddcd8c0 297 $link = join('/', $prefix, @steps);
c76e86ea
TC
298 }
299 else {
cddcd8c0
TC
300 $link = $prefix . '/' . $self->{linkAlias};
301 }
302 if ($cfg->entry('basic', 'alias_suffix', 1)) {
303 my $title = $self->{title};
304 $title =~ tr/a-zA-Z0-9/_/cs;
305 $link .= '/' . $title;
c76e86ea 306 }
cddcd8c0 307 return $link;
c76e86ea
TC
308}
309
ec5a2133
TC
310sub admin {
311 my ($self) = @_;
312
313 return BSE::Cfg->single->admin_url("admin", { id => $self->id });
314}
315
a739c25d
TC
316sub is_linked {
317 my ($self) = @_;
318
70c6e1e1 319 return $self->flags !~ /D/;
a739c25d
TC
320}
321
76c6b28e
TC
322sub tag_owner_type {
323 return "BA";
324}
325
8eaf4ceb
TC
326# the time used for expiry/release comparisons
327sub _expire_release_datetime {
328 my ($year, $month, $day) = (localtime)[5,4,3];
329 my $today = sprintf("%04d-%02d-%02d 00:00:00ZZZ", $year+1900, $month+1, $day);
330}
331
332=item is_expired
333
334Returns true if the article expiry date has passed.
335
336=cut
337
338sub is_expired {
339 my $self = shift;
340
341 return $self->expire lt _expire_release_datetime();
342}
343
344=item is_released
345
346Returns true if the article release date has passed (ie. the article
347has been released.)
348
349=cut
350
351sub is_released {
352 my $self = shift;
353
354 return $self->release le _expire_release_datetime();
355}
356
86dc77f9
TC
357sub restricted_methods {
358 my ($self, $name) = @_;
359
360 return $self->SUPER::restricted_methods($name)
361 || $name =~ /^(?:update_|remove_|add_)/;
362}
363
41b9d8ec 3641;