1 package Gruta
::Template
::Artemus
;
7 use base
'Gruta::Template::BASE';
16 my $a = bless( {}, $class );
18 $a->{_artemus
} = undef;
19 $a->{path
} = $args{path
};
20 $a->{lang
} = $args{lang
} || 'en';
23 # no path? set the default one
25 '/usr/share/gruta/templates/artemus/ALL',
26 '/usr/share/gruta/templates/artemus/' . $a->{lang
}
30 if (!ref($a->{path
})) {
31 $a->{path
} = [ split(':', $a->{path
}) ];
41 if (not $self->{_artemus
}) {
42 my $data = $self->data();
50 return $data->url($t, @_);
56 my $ret = $data->url($t, @_);
58 if ($ret !~ /^http:/) {
59 $ret = "http://{-cfg_host_name}/$ret";
67 my $d = shift || Gruta
::Data
::today
();
69 return Gruta
::Data
::format_date
($d, $fmt);
72 foreach my $p (Gruta
::Data
::Topic
->new->afields()) {
73 $f{'topic_' . $p} = sub {
78 if (my $topic = $data->source->topic($topic)) {
79 $ret = $topic->get($p) || '';
87 foreach my $p (Gruta
::Data
::Story
->new->afields()) {
88 $f{'story_' . $p} = sub {
96 if ($story = $data->source->story($topic_id, $id)) {
97 $ret = $story->get($p);
101 return $self->{_artemus
}->armor($ret);
105 $f{story_abstract
} = sub {
106 my $story = $data->source->story($_[0], $_[1]);
107 my $ret = $data->special_uris($story->get('abstract'));
109 return $self->{_artemus
}->armor($ret);
112 $f{story_body
} = sub {
113 my $topic_id = shift;
117 if (my $topic = $data->source->topic($topic_id)) {
118 if (my $story = $data->source->story($topic_id, $id)) {
119 my $date2 = $story->get('date2');
121 # if no user and story is not freed, bounce
122 if (!$data->auth() && $date2 && $date2 gt Gruta
::Data
::today
()) {
123 # return directly to avoid armoring
124 return '{-restricted_access}';
127 # touch the story if user is not
128 # (potentially) involved on it
129 if (! $topic->is_editor($data->auth())) {
133 $ret = $data->special_uris($story->get('body'));
138 if (!defined($ret)) {
139 $data->cgi->redirect('404');
143 return $self->{_artemus
}->armor($ret);
146 $f{story_date
} = sub {
148 my $topic_id = shift;
155 if ($story = $data->source->story($topic_id, $id)) {
156 $ret = $story->date($format);
160 return $self->{_artemus
}->armor($ret);
163 $f{story_date2
} = sub {
165 my $topic_id = shift;
172 if ($story = $data->source->story($topic_id, $id)) {
173 $ret = $story->date2($format);
177 return $self->{_artemus
}->armor($ret);
180 foreach my $p (Gruta
::Data
::User
->new->afields()) {
181 $f{'user_' . $p} = sub {
186 $ret = $data->source->user($id)->get($p);
189 return $self->{_artemus
}->armor($ret);
193 $f{user_xdate
} = sub {
199 $ret = $data->source->user($id)->xdate($format);
210 # try to find it in the source first
211 if (my $t = $data->source->template($id)) {
212 $ret = $t->get('content');
215 # not in source; search the stock ones
216 $ret = $data->template->template($id) || '';
219 $ret = $self->{_artemus
}->armor($ret);
225 $f{save_template
} = sub {
230 $content = $self->{_artemus
}->unarmor($content);
233 my $template = $data->source->template($id);
236 $template = Gruta
::Data
::Template
->new(
241 $template->set('content', $content);
243 if ($template->source()) {
244 $template = $template->save();
247 $template = $data->source->insert_template($template);
253 $f{is_logged_in
} = sub {
254 return $data->auth() ?
1 : 0;
258 return $data->auth() && $data->auth->get('is_admin') ?
1 : 0;
261 $f{is_topic_editor
} = sub {
262 if (my $topic = $data->source->topic($_[0])) {
263 return $topic->is_editor($data->auth()) ?
1 : 0;
271 my $password = shift;
272 my $error_msg = shift;
274 if ($user_id eq '') {
275 $error_msg = '{-block_login}';
277 elsif (my $sid = $data->login($user_id, $password)) {
278 $data->cgi->cookie("sid=$sid");
279 $data->cgi->redirect('INDEX');
283 return $error_msg || 'Login incorrect.';
288 $data->cgi->redirect('INDEX');
294 my $redir = shift || 'ADMIN';
297 $data->cgi->redirect($redir);
305 return $data->auth() && $data->auth->get('username') || '';
309 return $data->auth() && $data->auth->get('id') || '';
312 $f{search_stories
} = sub {
313 my $topic_id = shift;
316 my $template = shift || 'link_to_story_with_edit';
317 my $sep = shift || '';
320 my @l = $data->source->search_stories($topic_id, $query, $future);
323 $ret = "<p><b>{-topic_name|$topic_id}</b><br>\n";
326 $ret .= join($sep, map { "<li>{-$template|$topic_id|$_}</li>" } @l);
329 $self->{search_count
} += scalar(@l);
335 $f{is_visible_story
} = sub {
336 if (my $story = $data->source->story($_[0], $_[1])) {
337 return $story->is_visible($data->auth()) ?
1 : 0;
343 $f{redir_if_archived
} = sub {
344 my $template = shift;
345 my $topic_id = shift;
348 if ($topic_id =~ /-arch$/) {
352 my $story = $data->source->story($topic_id, $id);
354 if ($story && $story->get('topic_id') =~ /-arch$/) {
355 $data->cgi->redirect(
357 'topic' => $story->get('topic_id'),
366 $f{topic_has_archive
} = sub {
367 return $data->source->topic($_[0] . '-arch') ?
1 : 0;
370 $f{save_topic
} = sub {
371 my $topic_id = shift || return 'Error 1';
375 if (not $topic = $data->source->topic($topic_id)) {
376 $topic = Gruta
::Data
::Topic
->new (
380 $topic->set('name', shift);
381 $topic->set('editors', shift);
382 $topic->set('internal', shift eq 'on' ?
1 : 0);
383 $topic->set('max_stories', shift);
384 $topic->set('description', shift);
387 if ($topic->source()) {
388 $topic = $topic->save();
391 $topic = $data->source->insert_topic($topic);
394 return $topic ?
'OK' : 'Error 2';
397 $f{save_story
} = sub {
398 my $topic_id = shift || return 'Error 1';
403 # if there is an id, try to load the story
405 # this may crash if id is not valid
406 $story = $data->source->story($topic_id, $id);
410 $story = Gruta
::Data
::Story
->new (
411 topic_id
=> $topic_id,
417 $content = $self->{_artemus
}->unarmor($content);
420 $story->set('content', $content);
422 # pick date and drop time
427 my $date = Gruta
::Data
::today
();
429 if ($y && $m && $d) {
430 $date = sprintf("%04d%02d%02d000000", $y, $m, $d);
433 $story->set('date', $date);
434 $story->set('format', shift || 'grutatxt');
444 if ($y && $m && $d) {
445 $date = sprintf("%04d%02d%02d000000", $y, $m, $d);
451 $story->set('date2', $date);
453 $story->set('description', shift);
455 # if there is no userid, add one
456 if (!$story->get('userid')) {
457 $story->set('userid', $data->auth->get('id'));
461 $data->render($story);
463 if ($story->source()) {
464 $story = $story->save();
467 $story = $data->source->insert_story($story);
470 $story->tags(split(/\s*,\s*/, $tags));
472 return $story ?
$story->get('id') : 'Error 2';
475 $f{save_user
} = sub {
476 my $id = shift || return 'Error 1';
477 my $username = shift;
479 my $is_admin = shift;
480 my $can_upload = shift;
487 if ($data->auth->get('username') ne $username &&
488 ! $data->auth->get('is_admin')) {
489 $data->cgi->redirect('LOGIN');
496 if (not $user = $data->source->user($id)) {
497 $user = Gruta
::Data
::User
->new (
505 $user->set('username', $username);
506 $user->set('email', $email);
508 # these params can only be set by an admin
509 if ($data->auth->get('is_admin')) {
511 $user->set('is_admin', $is_admin eq 'on' ?
1 : 0);
512 $user->set('can_upload', $can_upload eq 'on' ?
1 : 0);
514 if ($xy and $xm and $xd) {
516 sprintf('%04d%02d%02d000000',
520 $user->set('xdate', '');
524 if ($pass1 and $pass2) {
525 if ($pass1 ne $pass2) {
526 croak
"Passwords are different";
529 $user->password($pass1);
532 if ($user->source()) {
533 $user = $user->save();
536 $user = $data->source->insert_user($user);
539 return $user ?
'OK' : 'Error 2';
544 $data->cgi->upload($_[0], $_[1]);
548 $f{delete_story
} = sub {
549 my $topic_id = shift || return 'Error 1';
552 $data->source->story($topic_id, $id)->delete();
557 $f{search_count
} = sub { $self->{search_count
}; };
559 $f{content_type
} = sub {
560 $data->cgi->http_headers('Content-Type' => $_[0]);
564 $f{topics
} = sub { join(':', $data->source->topics()); };
565 $f{users
} = sub { join(':', $data->source->users()); };
567 $f{templates
} = sub { join(':',
568 $data->template->templates($data->source->templates()));
571 $f{renderers
} = sub { join(':', sort(keys(%{$data->{renderers_h
}}))); };
572 $f{upload_dirs
} = sub { join(':', $data->cgi->upload_dirs()); };
573 $f{tags
} = sub { join(':',
574 map { $_->[0] . ',' . $_->[1] } $data->source->tags()); };
577 my $ret = $self->{cgi_vars
}->{$_[0]} || $_[1] || '';
579 return $self->{_artemus
}->armor($ret);
582 $f{story_tags
} = sub {
583 my $topic_id = shift;
588 if (my $story = $data->source->story($topic_id, $id)) {
589 $ret = join(':', $story->tags());
596 $f{stories_by_date
} = sub {
600 my $from_date = shift;
604 my @ret = map { join(',', @
{$_}) }
605 $data->source->stories_by_date(
607 [ map { (split(',', $_))[0] }
617 # $self->{search_count} += scalar(@ret);
619 return join(':', @ret);
622 $f{stories_by_tag
} = sub {
627 my @ret = $data->source->stories_by_tag(
629 [ map { (split(',', $_))[0] }
634 $self->{search_count
} += scalar(@ret);
636 return join(':', map { join(',', @
{$_}) } @ret);
639 $f{stories_top_ten
} = sub {
642 return join(':', map { join(',', @
{$_}) }
643 $data->source->stories_top_ten($num)
648 return 'Gruta ' . $data->version();
652 $self->{unresolved
} = [];
653 $self->{search_count
} = 0;
655 $self->{_artemus
} = Artemus
->new(
656 'include-path' => $self->{path
},
659 'unresolved' => $self->{unresolved
},
660 'abort' => \
$self->{abort
},
661 'loader_func' => sub {
664 if (my $t = $data->source->template($_[0])) {
665 $ret = $t->get('content');
673 return $self->{_artemus
};
681 if (defined($data)) {
682 $self->{data
} = $data;
683 $self->{_artemus
} = undef;
686 return $self->{data
};
694 $self->{cgi_vars
} = shift;
695 $self->{_artemus
} = undef;
698 return $self->{cgi_vars
};
706 my $ret = $self->_artemus->process('{-' . $st . '}');
708 # process special HTML variables
711 if ($t = $self->{_artemus
}->{vars
}->{html_title
}) {
712 $ret =~ s!</head>!<title>$t</title></head>!i;
715 if ($t = $self->{_artemus
}->{vars
}->{html_description
}) {
716 $ret =~ s!</head>!<meta name="description" content="$t"></head>!i;
719 if ($t = $self->{_artemus
}->{vars
}->{html_keywords
}) {
720 $ret =~ s!</head>!<meta name="keywords" content="$t"></head>!i;