File Coverage

blib/lib/Labyrinth/Plugin/Articles.pm
Criterion Covered Total %
statement 9 9 100.0
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 12 12 100.0


line stmt bran cond sub pod time code
1             package Labyrinth::Plugin::Articles;
2              
3 2     2   22138 use warnings;
  2         4  
  2         65  
4 2     2   7 use strict;
  2         2  
  2         104  
5              
6             our $VERSION = '5.19';
7              
8             =head1 NAME
9              
10             Labyrinth::Plugin::Articles - Plugin Articles handler for Labyrinth
11              
12             =head1 DESCRIPTION
13              
14             Contains all the default article handling functionality for the Labyrinth
15             framework.
16              
17             =cut
18              
19             # -------------------------------------
20             # Library Modules
21              
22 2     2   8 use base qw(Labyrinth::Plugin::Base);
  2         5  
  2         979  
23              
24             use Clone qw(clone);
25             use Data::Pageset;
26              
27             use Labyrinth::Audit;
28             use Labyrinth::DBUtils;
29             use Labyrinth::DTUtils;
30             use Labyrinth::Media;
31             use Labyrinth::Metadata;
32             use Labyrinth::MLUtils;
33             use Labyrinth::Session;
34             use Labyrinth::Support;
35             use Labyrinth::Users;
36             use Labyrinth::Variables;
37              
38             # -------------------------------------
39             # Constants
40              
41             use constant MaxArticleWidth => 400;
42             use constant MaxArticleHeight => 400;
43              
44             use constant IMAGE => 1;
45             use constant PARA => 2;
46             use constant LINK => 3;
47             use constant MFILE => 4; # Media File
48             use constant DFILE => 5; # Download File
49             use constant VIDEO => 6;
50              
51             use constant MAINPAGE => 5;
52             use constant LIMIT_LATEST => 20;
53              
54             # -------------------------------------
55             # Variables
56              
57             # type: 0 = optional, 1 = mandatory
58             # html: 0 = none, 1 = text, 2 = textarea
59              
60             my %fields = (
61             articleid => { type => 0, html => 0 },
62             postdate => { type => 0, html => 1 },
63             quickname => { type => 1, html => 1 },
64             title => { type => 1, html => 1 },
65             publish => { type => 1, html => 1 },
66             folderid => { type => 0, html => 0 },
67             userid => { type => 0, html => 0 },
68             snippet => { type => 0, html => 2 },
69             front => { type => 0, html => 1 },
70             latest => { type => 0, html => 1 },
71             sectionid => { type => 0, html => 0 },
72             width => { type => 0, html => 1 },
73             height => { type => 0, html => 1 },
74             body => { type => 0, html => 2 },
75             metadata => { type => 0, html => 1 },
76             );
77              
78             my (@mandatory,@allfields);
79             for(keys %fields) {
80             push @mandatory, $_ if($fields{$_}->{type});
81             push @allfields, $_;
82             }
83              
84             our $INDEXKEY = 'articleid';
85             our $ALLSQL = 'AllArticles';
86             our $SAVESQL = 'SaveArticle';
87             our $ADDSQL = 'AddArticle';
88             our $GETSQL = 'GetArticleByID';
89             our $DELETESQL = 'DeleteRecords';
90             our $PROMOTESQL = 'PromoteArticle';
91             our $LEVEL = EDITOR;
92             our $LEVEL2 = PUBLISHER;
93              
94             # sectionid is used to reference different types of articles,
95             # however, the default is also a standard article.
96             my $SECTIONID = 1;
97              
98             =head1 CONFIGURATION
99              
100             The Articles package is meant to be used as a base package providing default
101             configuration and functionality for article based content. It is expected that
102             that a plugin will use this package as a base, and override configuration and
103             methods as required.
104              
105             =head2 Section IDs
106              
107             It is recommended that the following be used to differentiate the types of
108             sections, for which articles are used to provide the underlying structure.
109             If you wish to add your own plugins, it is recommended that you use a Section
110             ID that is greater than 99 to avoid clashing with any potential standard
111             plugins.
112              
113             1 = page article, traditional articles
114             2 = section entries, for sites that require intro text for each section
115             (see Articles::Section)
116             3 = site content, such as 'About' or 'Home' fixed layout content
117             (see Articles::Site)
118             4 = products (see Articles::Products)
119             5 = profiles (see Articles::Profiles)
120             6 = diary (see Articles::Diary)
121             7 = lyrics (see Articles::Lyrics)
122             8 = liner notes (see Release)
123              
124             Note that some plugins mentioned above may not be currently available, however
125             all are planned for release.
126              
127             =head2 SQL Phrases
128              
129             Several keys used to access SQL phrases can be overriden. These default keys
130             are used in the event that only basic configuration overrides are needed, such
131             as the Section ID.
132              
133             Key variables available are:
134              
135             our $INDEXKEY = 'articleid';
136             our $ALLSQL = 'AllArticles';
137             our $SAVESQL = 'SaveArticle';
138             our $ADDSQL = 'AddArticle';
139             our $GETSQL = 'GetArticleByID';
140             our $DELETESQL = 'DeleteRecords';
141             our $PROMOTESQL = 'PromoteArticle';
142             our $LEVEL = EDITOR; # for normal admin actions
143             our $LEVEL2 = PUBLISHER; # for delete actions
144              
145             =cut
146              
147             # -------------------------------------
148             # The Subs
149              
150             =head1 PUBLIC INTERFACE METHODS
151              
152             =over 4
153              
154             =item LatestArticles
155              
156             Retrieves a list of the latest article titles
157              
158             =item Archive
159              
160             Retrieves a list of the volumes available.
161              
162             =item Page
163              
164             Retrieves an set of articles, for a given page. Default to first page.
165              
166             =item List
167              
168             Retrieves an initial list of articles. Primarily used to prepare a front page.
169              
170             =item Meta
171              
172             Retrieves a list of articles based on given meta tags.
173              
174             =item Search
175              
176             Retrieves a list of articles based on a given search string.
177              
178             =item Cloud
179              
180             Provides the current tag cloud.
181              
182             =item Tags
183              
184             Retrieves the current list of meta tags
185              
186             =item Item
187              
188             Provides a single article.
189              
190             =back
191              
192             =cut
193              
194             sub LatestArticles {
195             # latest Articles list
196             my $limit = $settings{article_latest} || LIMIT_LATEST;
197             my @rows = $dbi->GetQuery('hash','GetArticlesLatest',{limit => $limit});
198             LogDebug("Latest:rows=".scalar(@rows));
199             for my $row (@rows) {
200             $row->{postdate} = formatDate(19,$row->{createdate});
201             $row->{name} = UserName($row->{userid});
202             }
203             $tvars{latest}->{articles} = \@rows if(@rows);
204             }
205              
206             sub Archive {
207             $cgiparams{sectionid} ||= $SECTIONID;
208             $cgiparams{section} ||= 'articles';
209              
210             my @rows = $dbi->GetQuery('hash','GetVolumes',$cgiparams{sectionid});
211             $tvars{archive}{$cgiparams{section}} = \@rows if(@rows);
212             }
213              
214             sub Page {
215             my @mainarts;
216             $cgiparams{name} = undef;
217             my $page = $cgiparams{page} || 1;
218            
219             my $limit = $settings{data}{article_pageset} || $settings{article_pageset} || MAINPAGE;
220             my $sectionid = $cgiparams{sectionid} || $SECTIONID;
221             my @where = ("sectionid=$sectionid","publish=3");
222             my $where = 'WHERE ' . join(' AND ',@where);
223             my $order = 'ORDER BY ' . ($settings{data}{order} || 'createdate DESC');
224             my @rows = $dbi->GetQuery('hash',$ALLSQL,{where=>$where,order=>$order});
225              
226             my $page_info = Data::Pageset->new({
227             'total_entries' => scalar(@rows),
228             'entries_per_page' => $limit,
229             # Optional, will use defaults otherwise.
230             'current_page' => $page,
231             #'pages_per_set' => $pages_per_set,
232             #'mode' => 'fixed', # default, or 'slide'
233             });
234              
235             $tvars{pages}{first} = $page_info->first_page;
236             $tvars{pages}{last} = $page_info->last_page;
237             $tvars{pages}{next} = $page_info->next_page;
238             $tvars{pages}{previous} = $page_info->previous_page;
239              
240             my @arts = splice(@rows, ($page - 1) * $limit, $limit);
241             for my $row (@arts) {
242             $cgiparams{articleid} = $row->{articleid};
243             Item();
244             push @mainarts, $tvars{articles}->{$tvars{primary}};
245             }
246             $tvars{mainarts} = \@mainarts if(@mainarts);
247             $cgiparams{sectionid} = undef;
248             }
249              
250             sub List {
251             my (@mainarts,@inbrief,@archive);
252             $cgiparams{name} = undef;
253              
254             my $limit = $settings{data}{article_limit} || $settings{article_limit};
255             my $step = "LIMIT $limit" if($limit);
256             my $stop = $settings{data}{article_stop} || MAINPAGE;
257              
258             my $sectionid = $cgiparams{sectionid} || $SECTIONID;
259              
260             my @where = ("sectionid=$sectionid","publish=3");
261             push @where, $settings{where} if($settings{where});
262             my $where = 'WHERE ' . join(' AND ',@where);
263             my $order = 'ORDER BY ' . ($settings{data}{order} || 'createdate DESC');
264              
265             my @rows = $dbi->GetQuery('hash',$ALLSQL,{where=>$where,limit=>$step,order=>$order});
266             for my $row (@rows) {
267             if($stop) {
268             $cgiparams{articleid} = $row->{articleid};
269             Item();
270             push @mainarts, $tvars{articles}->{$tvars{primary}};
271             $stop--;
272             next;
273             }
274             push @inbrief, {name => $row->{quickname}, title => $row->{title}, snippet => _snippet($row,82)};
275             }
276             # archived articles
277             @where = ("sectionid=$sectionid","publish=4");
278             $where = 'WHERE ' . join(' AND ',@where);
279             @rows = $dbi->GetQuery('hash',$ALLSQL,{where=>$where,limit=>$limit,order=>$order});
280             for my $row (@rows) {
281             push @archive, {name => $row->{quickname}, title => $row->{title}, snippet => _snippet($row,82)};
282             }
283             $tvars{mainarts} = \@mainarts if(@mainarts);
284             $tvars{inbrief} = \@inbrief if(@inbrief);
285             $tvars{archive} = \@archive if(@archive);
286             $cgiparams{sectionid} = undef;
287             }
288              
289             sub Meta {
290             my $page = $cgiparams{page} || 1;
291             my $limit = $settings{data}{article_pageset} || $settings{article_pageset} || MAINPAGE;
292             my $sectionid = $cgiparams{sectionid} || $SECTIONID;
293              
294             my @data = split(qr/[ ,]+/,$cgiparams{data});
295             my @rows = MetaSearch( 'keys' => ['Art'],
296             'meta' => \@data,
297             'where' => "sectionid=$sectionid AND publish=3",
298             'limit' => '',
299             'order' => 'createdate',
300             'sort' => 'desc');
301              
302             my $page_info = Data::Pageset->new({
303             'total_entries' => scalar(@rows),
304             'entries_per_page' => $limit,
305             'current_page' => $page,
306             });
307              
308             my @arts = splice(@rows, ($page - 1) * $limit, $limit);
309             for my $row (@arts) {
310             $cgiparams{articleid} = $row->{articleid};
311             Item();
312             push @{$tvars{mainarts}}, $tvars{articles}{$tvars{primary}};
313             }
314              
315             $tvars{pages}{first} = $page_info->first_page;
316             $tvars{pages}{last} = $page_info->last_page;
317             $tvars{pages}{next} = $page_info->next_page;
318             $tvars{pages}{previous} = $page_info->previous_page;
319             $tvars{pages}{data} = $cgiparams{data};
320             }
321              
322             sub Cloud {
323             my $sectionid = $cgiparams{sectionid} || $SECTIONID;
324             my $actcode = $cgiparams{actcode} || 'arts-meta';
325             $tvars{cloud} = MetaCloud(key => 'Art', sectionid => $sectionid, actcode => $actcode);
326             }
327              
328             sub Tags {
329             my $sectionid = $cgiparams{sectionid} || $SECTIONID;
330             my @tags = MetaTags(key => 'Art', sectionid => $sectionid);
331             $tvars{metatags} = \@tags if(@tags);
332             }
333              
334             sub Search {
335             my $page = $cgiparams{page} || 1;
336             my $limit = $settings{data}{article_pageset} || $settings{article_pageset} || MAINPAGE;
337             my $sectionid = $cgiparams{sectionid} || $SECTIONID;
338              
339             my @data = split(qr/[ ,]+/,$cgiparams{data});
340             my @rows = MetaSearch( 'keys' => ['Art'],
341             'meta' => \@data,
342             'full' => 1,
343             'where' => "sectionid=$sectionid AND publish=3",
344             'limit' => '',
345             'order' => 'createdate',
346             'sort' => 'desc');
347              
348             my $page_info = Data::Pageset->new({
349             'total_entries' => scalar(@rows),
350             'entries_per_page' => $limit,
351             'current_page' => $page,
352             });
353              
354             my @arts = splice(@rows, ($page - 1) * $limit, $limit);
355             for my $row (@arts) {
356             $cgiparams{articleid} = $row->{articleid};
357             Item();
358             push @{$tvars{mainarts}}, $tvars{articles}{$tvars{primary}};
359             }
360              
361             $tvars{pages}{first} = $page_info->first_page;
362             $tvars{pages}{last} = $page_info->last_page;
363             $tvars{pages}{next} = $page_info->next_page;
364             $tvars{pages}{previous} = $page_info->previous_page;
365             $tvars{pages}{data} = $cgiparams{data};
366             }
367              
368             sub Item {
369             my $name = $cgiparams{'name'} || undef;
370             my $naid = $cgiparams{articleid} || $cgiparams{id} || undef;
371              
372             my $maximagewidth = $settings{maximagewidth} || MaxArticleWidth;
373             my $maximageheight = $settings{maximageheight} || MaxArticleHeight;
374              
375             unless($name || $naid) {
376             $tvars{errcode} = 'ERROR';
377             return;
378             }
379              
380             # main article data
381             my ($key,$search) = $name ? ('GetArticleByName',$name) :
382             ('GetArticleByID',$naid);
383             my @data = $dbi->GetQuery('hash',$key,$search);
384             return unless(@data);
385              
386             $data[0]->{postdate} = formatDate(19,$data[0]->{createdate});
387             $data[0]->{name} = UserName($data[0]->{userid});
388             $tvars{article} = $data[0];
389             if($data[0]->{imageid}) {
390             my ($tag,$link,undef,$x) = GetImage($data[0]->{imageid});
391             $data[0]->{tag} = $tag;
392             $data[0]->{link} = $link;
393             $data[0]->{resize} = 1 if($x && $x > 100)
394             }
395              
396             # article content
397             my @body = $dbi->GetQuery('hash','GetContent',$data[0]->{$INDEXKEY});
398             foreach my $body (@body) {
399             if($body->{type} == IMAGE) {
400             my @rows = $dbi->GetQuery('hash','GetImageByID',$body->{imageid});
401             $body->{link} = $rows[0]->{link};
402             $body->{alignclass} = AlignClass($body->{align});
403             ($body->{tag},$body->{width},$body->{height}) = split(qr/\|/,$body->{body})
404             if($body->{body});
405              
406             ($body->{width},$body->{height}) = GetImageSize($body->{link},$rows[0]->{dimensions},$body->{width},$body->{height},$maximagewidth,$maximageheight);
407              
408             #LogDebug(sprintf "%d/%s [%d x %d]", ($body->{imageid}||0),($body->{link}||'-'),($body->{width}||0),($body->{height}||0));
409             } elsif($body->{type} == PARA) {
410             $body->{body} = LinkTitles($body->{body});
411             }
412             }
413              
414             $tvars{primary} = $data[0]->{quickname} || 'draft' . $data[0]->{articleid};
415             $tvars{articles}->{$tvars{primary}} = {
416             data => $data[0],
417             body => \@body,
418             };
419              
420             $tvars{article} = $tvars{articles}->{$tvars{primary}};
421             $cgiparams{sectionid} = undef;
422             my @meta = MetaGet($data[0]->{articleid},'Art');
423             $tvars{articles}->{$tvars{primary}}->{meta} = \@meta if(scalar(@meta));
424             $tvars{article} = $tvars{articles}->{$tvars{primary}};
425             }
426              
427             =head1 ADMIN INTERFACE METHODS
428              
429             =over 4
430              
431             =item Admin
432              
433             Lists the current set of articles for the given section.
434              
435             Also provides the delete, copy and promote functionality from the main
436             administration page for the given section.
437              
438             =item Add
439              
440             Add an article to the current section.
441              
442             =item Edit
443              
444             Edit an article within the current section.
445              
446             =item AddParagraph
447              
448             Add a text block to the current article.
449              
450             =item AddImage
451              
452             Add an image block to the current article.
453              
454             =item AddLink
455              
456             Add a link block to the current article.
457              
458             =item AddVideo
459              
460             Add a embedded video block to the current article.
461              
462             =item DeleteItem
463              
464             Delete an article.
465              
466             =item Relocate
467              
468             Relocate an article in a list, where an order is in use.
469              
470             =item LoadContent
471              
472             Load complete article from form fields, save all image and media files.
473              
474             =item EditAmendments
475              
476             Additional drop downs and fields prepared for edit form.
477              
478             =item Save
479              
480             Save an article within the current section.
481              
482             =item Promote
483              
484             Promote the given article within the current section.
485              
486             =item Copy
487              
488             Copy an article, to create a new article, within the current section.
489              
490             =item Delete
491              
492             Delete a given article within the current section.
493              
494             =back
495              
496             =cut
497              
498             sub Admin {
499             return unless AccessUser($LEVEL);
500              
501             if($cgiparams{doaction}) {
502             if($cgiparams{doaction} eq 'Delete') { Delete() }
503             elsif($cgiparams{doaction} eq 'Copy') { Copy() }
504             elsif($cgiparams{doaction} eq 'Promote') { Promote() }
505             }
506              
507             my @front = CGIArray('FRONT');
508             if(@front) {
509             my @check = $dbi->GetQuery('hash','CheckFrontPageArticles');
510             my %check = map {$_->{articleid} => 1} @check;
511             for my $id (@front) {
512             if($check{$id}) {
513             $check{$id} = 0;
514             } else {
515             $dbi->DoQuery('SetFrontPageArticle',$id);
516             }
517             }
518             for my $id (keys %check) {
519             next unless($check{$id});
520             $dbi->DoQuery('ClearFrontPageArticle',$id);
521             }
522             }
523              
524             my $sectionid = $cgiparams{sectionid} || $SECTIONID;
525             my @where = ("sectionid=$sectionid");
526             push @where, "publish<4" unless($cgiparams{publish});
527             push @where, "publish=$cgiparams{publish}" if($cgiparams{publish});
528             push @where, "userid=$tvars{'loginid'}" unless(Authorised(EDITOR));
529             push @where, "quickname LIKE '%$cgiparams{'searchname'}%'" if($cgiparams{'searchname'});
530             my $where = @where ? 'WHERE '.join(' AND ',@where) : '';
531              
532             my @rows = sort {int($b->{createdate}||0) <=> int($a->{createdate}||0)}
533             $dbi->GetQuery('hash',$ALLSQL,{where=>$where});
534             # LogDebug("Admin: rows=".scalar(@rows));
535             foreach my $row (@rows) {
536             $row->{publishstate} = PublishState($row->{publish});
537             $row->{name} = UserName($row->{userid});
538             $row->{postdate} = formatDate(3,$row->{createdate});
539             }
540             $tvars{data} = \@rows if(@rows);
541             $tvars{ddpublish} = PublishSelect($cgiparams{publish},1);
542             $tvars{sectionid} = $sectionid;
543             }
544              
545             sub Add {
546             return unless AccessUser($LEVEL);
547              
548             my %data = (
549             articleid => 0,
550             folderid => $tvars{user}->{folder},
551             userid => $tvars{loginid},
552             name => $tvars{user}->{name},
553             postdate => formatDate(3),
554             ddpublish => PublishSelect(1),
555             sectionid => $cgiparams{sectionid} || $SECTIONID, # default 1=article
556             );
557              
558             $tvars{primary} = 'draft' . $data{articleid};
559             my @fields = ( $data{folderid},
560             'DRAFT',
561             $data{userid},
562             $data{sectionid},
563             $tvars{primary},
564             1,
565             formatDate(0));
566             $data{articleid} = $dbi->IDQuery('AddArticle',@fields);
567             $data{quickname} = 'ID'.$data{articleid};
568              
569             @fields = ( $data{articleid},
570             1, # orderno
571             2, # type - paragraph
572             0, # imageid
573             '', # link
574             '', # body
575             '' # align
576             );
577             my $paraid = $dbi->IDQuery('AddContent',@fields);
578              
579             my @body = (
580             { paraid=>$paraid,orderno=>1,type=>PARA},
581             );
582              
583             $tvars{articles}->{$tvars{primary}} = {
584             blocks => '1', # '1,2'
585             data => \%data,
586             body => \@body,
587             htmltags => LegalTags(),
588             };
589              
590             $tvars{authors} = UserSelect($tvars{loginid},1);
591             $tvars{article} = $tvars{articles}{$tvars{primary}};
592             $tvars{preview} = $tvars{articles}{$tvars{primary}};
593             }
594              
595             sub Edit {
596             return unless AccessUser($LEVEL);
597             return unless AuthorCheck($GETSQL,$INDEXKEY,$LEVEL);
598             $tvars{primary} = $tvars{data}->{quickname} || 'draft' . ($tvars{data}->{articleid}||0);
599              
600             my $maximagewidth = $settings{maximagewidth} || MaxArticleWidth;
601             my $maximageheight = $settings{maximageheight} || MaxArticleHeight;
602              
603             # article content
604             my @blocks;
605             my $orderno = 1;
606             my @body = $dbi->GetQuery('hash','GetContent',$cgiparams{$INDEXKEY});
607             foreach my $body (@body) {
608             push @blocks, $orderno;
609             if($body->{type} == IMAGE
610             || $body->{type} == MFILE
611             || $body->{type} == DFILE) {
612             my @rows = $dbi->GetQuery('hash','GetImageByID',$body->{imageid});
613             $rows[0]->{body} ||= '';
614             ($body->{tag},$body->{width},$body->{height}) = split(qr/\|/,$body->{body});
615             $body->{link} = $rows[0]->{link};
616             $body->{ddalign} = AlignSelect($body->{align},$orderno);
617             $body->{alignclass} = AlignClass($body->{align});
618              
619             ($body->{width},$body->{height}) = GetImageSize($body->{link},$rows[0]->{dimensions},$body->{width},$body->{height},$maximagewidth,$maximageheight);
620              
621             LogDebug("$body->{imageid}/$body->{link} [$body->{width} x $body->{height}]");
622             }
623              
624             $body->{orderno} = $orderno++;
625             }
626             $tvars{articles}->{$tvars{primary}} = {
627             data => $tvars{data},
628             blocks => join(",",@blocks),
629             body => \@body,
630             };
631             EditAmendments();
632              
633             $tvars{dimensions}->{width} = $settings{maximagewidth} || MaxArticleWidth;
634             $tvars{dimensions}->{height} = $settings{maximageheight} || MaxArticleHeight;
635             }
636              
637             sub AddParagraph {
638             my ($blocks,$data) = LoadContent();
639             my $item = @$blocks ? (@$blocks)[-1] + 1 : 1;
640             $dbi->DoQuery('AddContent',$data->{articleid},$item,PARA,0,'','',0);
641             }
642              
643             sub AddImage {
644             my ($blocks,$data) = LoadContent();
645             my $item = @$blocks ? (@$blocks)[-1] + 1 : 1;
646             $dbi->IDQuery('AddContent',$data->{articleid},$item,IMAGE,0,'','',1);
647             }
648              
649             sub AddLink {
650             my ($blocks,$data,$body) = LoadContent();
651             my $item = @$blocks ? (@$blocks)[-1] + 1 : 1;
652             $dbi->IDQuery('AddContent',$data->{articleid},$item,LINK,0,'','',0);
653             }
654              
655             sub AddVideo {
656             my ($blocks,$data,$body) = LoadContent();
657             my $item = @$blocks ? (@$blocks)[-1] + 1 : 1;
658             $dbi->IDQuery('AddContent',$data->{articleid},$item,VIDEO,0,'','',0);
659             }
660              
661             sub DeleteItem {
662             return unless AccessUser($LEVEL2);
663             return unless $cgiparams{'recordid'};
664             $dbi->DoQuery('DeleteContent',$cgiparams{'recordid'});
665             }
666              
667             sub Relocate {
668             return unless AccessUser($LEVEL);
669             return unless $cgiparams{'recordid'};
670             my $move = shift;
671              
672             my ($blocks,$data,$body) = LoadContent();
673             my $para = $cgiparams{'recordid'};
674              
675             my ($this,$that);
676             for my $block (@$blocks) {
677             if($body->[$block]->{paraid} == $para) {
678             $this = $block;
679             } else {
680             $that = $block if( $move && !$this); # before
681             $that = $block if(!$move && $this && !$that); # after
682             }
683             }
684              
685             if($this && $that) {
686             $dbi->DoQuery('Relocate',$that,$body->[$this]->{paraid});
687             $dbi->DoQuery('Relocate',$this,$body->[$that]->{paraid});
688             }
689             }
690              
691             # list=1,2,3,4
692             # BLOCK2="1,2" - IMAGE,orderno
693             # IMAGETAG2=""
694             # IMAGEHREF2=""
695             # IMAGEUPLOAD2=""
696             # BLOCK1="2,1" - PARAGRAPH,orderno
697             # TEXT1="" - paragraphs are textblocks
698             # BLOCK1="3,3" - LINK,orderno
699             # LINK3="" - links are textblocks
700              
701             sub LoadContent {
702             my (@body,@ordernos);
703             my @blocks = $cgiparams{'list'} ? split(",", $cgiparams{'list'}) : ();
704              
705             my $maximagewidth = $settings{maximagewidth} || MaxArticleWidth;
706             my $maximageheight = $settings{maximageheight} || MaxArticleHeight;
707              
708             for my $block (@blocks) {
709             my ($type,$paraid) = split(",", $cgiparams{"BLOCK$block"});
710             push @ordernos, $block;
711              
712             $body[$block]->{type} = $type;
713             $body[$block]->{orderno} = $block;
714              
715             # images
716             if($type == IMAGE) {
717             $body[$block]->{paraid} = $paraid;
718             $body[$block]->{imagelink} = $cgiparams{"IMAGELINK$block"};
719             $body[$block]->{href} = $cgiparams{"IMAGEHREF$block"};
720             $body[$block]->{align} = $cgiparams{"ALIGN$block"};
721             my $tag = CleanTags($cgiparams{"IMAGETAG$block"});
722             my $width = $cgiparams{"width$block"} || $maximagewidth;
723             my $height = $cgiparams{"height$block"} || $maximageheight;
724              
725             # uploaded own image
726             if(defined $cgiparams{"IMAGEUPLOAD$block"} && $cgiparams{"IMAGEUPLOAD$block"}) {
727             my ($imageid,$imagelink) = SaveImageFile(
728             param => "IMAGEUPLOAD$block",
729             stock => 'Special',
730             width => $width,
731             height => $height);
732             $body[$block]->{imageid} = $imageid;
733             $body[$block]->{imagelink} = $imagelink;
734              
735             # using an existing image
736             } elsif(defined $cgiparams{"display$block"}) {
737             $body[$block]->{imageid} = $cgiparams{"display$block"};
738             (undef,$body[$block]->{imagelink}) = GetImage($body[$block]->{imageid});
739              
740             # already uploaded photo
741             } elsif(defined $cgiparams{"gallery$block"}) {
742             $body[$block]->{imageid} = $cgiparams{"gallery$block"};
743             (undef,$body[$block]->{imagelink}) = GetImage($body[$block]->{imageid});
744             }
745              
746             $body[$block]->{href} ||= $body[$block]->{imagelink};
747              
748             $tag ||= '';
749             $width = $cgiparams{"width$block"} ? ($cgiparams{"width$block"} > $maximagewidth ? $maximagewidth : $cgiparams{"width$block"}) : '';
750             $height = $cgiparams{"height$block"} ? ($cgiparams{"height$block"} > $maximageheight ? $maximageheight : $cgiparams{"height$block"}) : '';
751             $body[$block]->{body} = "$tag|$width|$height";
752             $body[$block]->{tag} = $tag;
753             $body[$block]->{width} = $width;
754             $body[$block]->{height} = $height;
755              
756             # paragraphs
757             } elsif($type == PARA) {
758             $body[$block]->{paraid} = $paraid;
759             $body[$block]->{body} = CleanTags($cgiparams{"TEXT$block"});
760             $body[$block]->{link} = '';
761             $body[$block]->{imageid} = 0;
762              
763             # links
764             } elsif($type == LINK) {
765             $body[$block]->{paraid} = $paraid;
766             $body[$block]->{body} = $cgiparams{"LINK$block"};
767             $body[$block]->{href} = CleanTags($cgiparams{"LINK$block"});
768             $body[$block]->{imageid} = 0;
769              
770             # video
771             } elsif($type == VIDEO) {
772             $body[$block]->{paraid} = $paraid;
773              
774             my $body = $cgiparams{"VIDEO$block"};
775             $body =~ s!.*?
776            
777             my $videoid = 0;
778             my ($type,$code) = $body =~ m!(.*)/(\w+)$!;
779             if($type =~ /youtu\.?be/) { $videoid = 1 }
780             elsif($type =~ /vimeo/) { $videoid = 2 }
781              
782             $body[$block]->{body} = $body;
783             $body[$block]->{href} = $code;
784             $body[$block]->{imageid} = $videoid;
785              
786             # media files
787             } elsif($type == MFILE) {
788             $body[$block]->{paraid} = $paraid;
789              
790             # uploaded own image
791             if(defined $cgiparams{"MEDIA$block"} && $cgiparams{"MEDIA$block"}) {
792             my ($fileid) = SaveMediaFile(
793             param => "MEDIA$block",
794             stock => 'Media');
795             $body[$block]->{imageid} = $fileid;
796              
797             # already uploaded
798             } elsif(defined $cgiparams{"media$block"}) {
799             $body[$block]->{imageid} = $cgiparams{"media$block"};
800             }
801              
802             # download files
803             } elsif($type == DFILE) {
804             $body[$block]->{paraid} = $paraid;
805              
806             LogDebug("LoadContent:DFILE");
807             LogDebug(qq!LoadContent:param=[MEDIA$block][$cgiparams{"MEDIA$block"}]!);
808              
809             # uploaded own image
810             if(defined $cgiparams{"MEDIA$block"} && $cgiparams{"MEDIA$block"}) {
811             my ($fileid) = SaveMediaFile(
812             param => "MEDIA$block",
813             stock => 'Talks');
814             $body[$block]->{imageid} = $fileid;
815              
816             # already uploaded
817             } elsif(defined $cgiparams{"media$block"}) {
818             $body[$block]->{imageid} = $cgiparams{"media$block"};
819             }
820             }
821             }
822              
823             $cgiparams{quickname} ||= $cgiparams{title};
824             $cgiparams{quickname} =~ tr/ /_/;
825             $cgiparams{quickname} = lc $cgiparams{quickname};
826              
827             my %data = map {$_ => ($cgiparams{$_} || $tvars{data}->{$_})}
828             qw(articleid createdate folderid userid title quickname publish snippet front latest sectionid);
829             $data{front} = ($data{'front'} ? 1 : 0);
830             $data{latest} = ($data{'latest'} ? 1 : 0);
831             $data{imageid} = $cgiparams{'display0'};
832             $data{postdate} = formatDate(6,$data{createdate});
833              
834             return(\@blocks,\%data,\@body);
835             }
836              
837             sub EditAmendments {
838             $tvars{articles}->{$tvars{primary}}{data}{metadata} = MetaGet( $tvars{articles}->{$tvars{primary}}{data}{'articleid'},'Art');
839             $tvars{articles}->{$tvars{primary}}{data}{name} = UserName( $tvars{articles}->{$tvars{primary}}{data}{userid});
840             $tvars{articles}->{$tvars{primary}}{data}{postdate} = formatDate(3,$tvars{articles}->{$tvars{primary}}{data}{createdate});
841             $tvars{articles}->{$tvars{primary}}{data}{publish} ||= 1;
842              
843             my $resize = 0;
844             if($tvars{articles}->{$tvars{primary}}{data}{imageid}) {
845             my ($tag,$link,undef,$x) = GetImage($tvars{articles}->{$tvars{primary}}{data}{imageid});
846             $tvars{articles}->{$tvars{primary}}{data}{tag} = $tag;
847             $tvars{articles}->{$tvars{primary}}{data}{link} = $link;
848             $resize = 1 if($x && $x > 100)
849             }
850              
851             if(Authorised(ADMIN)) {
852             LogDebug("EditAmendments: publish=[$tvars{articles}->{$tvars{primary}}{data}{publish}]");
853             $tvars{articles}->{$tvars{primary}}{data}{ddpublish} = PublishSelect($tvars{articles}->{$tvars{primary}}{data}{publish});
854             } else {
855             my $promote = 0;
856             $promote = 1 if($tvars{articles}->{$tvars{primary}}{data}{publish} == 1);
857             $promote = 1 if($tvars{articles}->{$tvars{primary}}{data}{publish} == 2 && AccessUser(PUBLISHER));
858             $promote = 1 if($tvars{articles}->{$tvars{primary}}{data}{publish} == 3 && AccessUser(PUBLISHER));
859             LogDebug("EditAmendments: publish=[$tvars{$tvars{primary}}{data}{publish}], promote=[$promote]");
860             $tvars{articles}->{$tvars{primary}}{data}{ddpublish} = PublishAction($tvars{articles}->{$tvars{primary}}{data}{publish},$promote);
861             }
862              
863             $tvars{htmltags} = LegalTags();
864             $tvars{preview}->{body} = clone($tvars{articles}->{$tvars{primary}}->{body});
865             $tvars{preview}->{data} = clone($tvars{articles}->{$tvars{primary}}->{data});
866             $tvars{preview}{data}{resize} = $resize;
867             $tvars{preview}{data}{postdate} = formatDate(6,$tvars{articles}->{$tvars{primary}}{data}{createdate});
868              
869             my @meta = MetaGet($tvars{articles}->{$tvars{primary}}{data}{'articleid'},'Art');
870             $tvars{preview}->{meta} = \@meta if(@meta);
871              
872             for(keys %fields) {
873             if($fields{$_}->{html} == 1) { $tvars{preview}{data}{$_} = CleanHTML($tvars{preview}{data}{$_});
874             $tvars{articles}->{$tvars{primary}}{data}{$_} = CleanHTML($tvars{articles}->{$tvars{primary}}{data}{$_}); }
875             elsif($fields{$_}->{html} == 2) { $tvars{articles}->{$tvars{primary}}{data}{$_} = SafeHTML($tvars{articles}->{$tvars{primary}}{data}{$_}); }
876             elsif($fields{$_}->{html} == 3) { $tvars{articles}->{$tvars{primary}}{data}{$_} = SafeHTML($tvars{articles}->{$tvars{primary}}{data}{$_}); }
877             }
878              
879             for my $item (@{$tvars{articles}->{$tvars{primary}}->{body}}) {
880             $item->{body} = SafeHTML($item->{body}) if($item->{type} == PARA);
881             }
882              
883             $tvars{article} = $tvars{articles}->{$tvars{primary}};
884             $tvars{authors} = UserSelect($tvars{article}{data}{userid},1);
885             }
886              
887             sub Save {
888             return unless AccessUser($LEVEL);
889             return unless AuthorCheck($GETSQL,$INDEXKEY,$LEVEL);
890             $tvars{primary} = $tvars{data}->{quickname} || 'draft' . ($tvars{data}->{articleid}||0);
891             my $publish = $tvars{data}->{publish} || 0;
892             my $sectionid = $cgiparams{sectionid} || $SECTIONID;
893              
894             for(keys %fields) {
895             if($fields{$_}->{html} == 1) { $cgiparams{$_} = CleanHTML($cgiparams{$_}) }
896             elsif($fields{$_}->{html} == 2) { $cgiparams{$_} = CleanTags($cgiparams{$_}) }
897             elsif($fields{$_}->{html} == 3) { $cgiparams{$_} = CleanLink($cgiparams{$_}) }
898             }
899              
900             # read the encoded form
901             my ($blocks,$data,$body) = LoadContent();
902             $tvars{$tvars{primary}}->{blocks} = join(",",@$blocks);
903             $tvars{$tvars{primary}}->{data} = $data;
904             $tvars{$tvars{primary}}->{body} = $body;
905              
906             my @manfields = @mandatory;
907             push @manfields, qw(snippet) if($cgiparams{front});
908             FieldCheck(\@allfields,\@manfields);
909              
910             for my $key (keys %{$tvars{data}}) {
911             next unless($key =~ /^(?:TEXT|LINK|IMAGELINK|IMAGEHREF|IMAGETAG)(\d+)_err/);
912             $tvars{body}->[$1]->{error} = ErrorSymbol;
913             $tvars{errcode} = 'ERROR';
914             }
915              
916             # check title is unique
917             my @data = $dbi->GetQuery('hash','FindTitle',$cgiparams{title});
918             for(@data) {
919             next if($_->{articleid} == $tvars{data}->{articleid});
920             $tvars{article}{data}{title_err} = ErrorSymbol;
921             $tvars{errmess} = 2;
922             last;
923             }
924              
925             return if($tvars{errcode});
926              
927             $data->{front} = $data->{front} ? 1 : 0;
928             $data->{latest} = $data->{latest} ? 1 : 0;
929             $data->{createdate} = formatDate(0) if($data->{publish} == 3 && $publish < 3);
930             $data->{createdate} = unformatDate(3,$cgiparams{postdate}) if($cgiparams{postdate});
931             $data->{userid} ||= $tvars{loginid};
932             $data->{sectionid} ||= 1; # default 1 = article
933              
934             if($sectionid == 6) {
935             if($data->{publish} == 3 && $publish < 3) {
936             my $archdate = formatDate(2, $data->{createdate});
937             my $volumeid = substr(formatDate(13,$data->{createdate}),0,6);
938             my @vols = $dbi->GetQuery('hash','GetVolume',$volumeid,$sectionid);
939             if(@vols) {
940             $dbi->DoQuery('UpdateVolume',$vols[0]->{counter}+1,$volumeid,$sectionid);
941             } else {
942             $dbi->DoQuery('InsertVolume',$volumeid,$sectionid,$archdate,1);
943             }
944             }
945             }
946              
947             # save master image, if one supplied
948             $data->{imageid} ||= 0;
949             if(defined $cgiparams{"IMAGEUPLOAD0"}) {
950             my $maximagewidth = $settings{maximagewidth} || MaxArticleWidth;
951             my $maximageheight = $settings{maximageheight} || MaxArticleHeight;
952             ($data->{imageid}) =
953             SaveImageFile(
954             param => "IMAGEUPLOAD0",
955             stock => 'Special',
956             width => $maximagewidth,
957             height => $maximageheight
958             );
959             }
960              
961             # save article metadata
962             $dbi->DoQuery($SAVESQL,
963             $data->{folderid},
964             $data->{title},
965             $data->{userid},
966             $data->{sectionid},
967             $data->{quickname},
968             $data->{snippet},
969             $data->{imageid},
970             $data->{front},
971             $data->{latest},
972             $data->{publish},
973             $data->{createdate},
974             $data->{articleid}
975             );
976              
977             # save each content item as appropriate
978             foreach my $block (@$blocks) {
979             # MUST have a paraid
980             next unless($body->[$block]->{paraid});
981              
982             # save article paragraph
983             $dbi->DoQuery('SaveContent',
984             $data->{articleid},
985             $block,
986             $body->[$block]->{type},
987             $body->[$block]->{imageid},
988             $body->[$block]->{href},
989             $body->[$block]->{body},
990             $body->[$block]->{align},
991             $body->[$block]->{paraid});
992             }
993              
994             if($cgiparams{doaction}) {
995             if($cgiparams{doaction} eq 'AddImage') { AddImage(); }
996             elsif($cgiparams{doaction} eq 'AddPara') { AddParagraph(); }
997             elsif($cgiparams{doaction} eq 'AddLink') { AddLink(); }
998             elsif($cgiparams{doaction} eq 'AddMedia') { AddMedia(); }
999             elsif($cgiparams{doaction} eq 'AddFile') { AddFile(); }
1000             elsif($cgiparams{doaction} eq 'AddVideo') { AddVideo(); }
1001             elsif($cgiparams{doaction} eq 'Delete') { DeleteItem(); }
1002             elsif($cgiparams{doaction} eq 'MoveUp') { Relocate(1); }
1003             elsif($cgiparams{doaction} eq 'MoveDn') { Relocate(0); }
1004             }
1005              
1006             # save metadata
1007             my @metadata = $cgiparams{metadata} ? split(qr/[, ]+/,$cgiparams{metadata}) : ();
1008             MetaSave($cgiparams{articleid},['Art'],@metadata);
1009              
1010             $tvars{thanks} = 1;
1011             }
1012              
1013             sub Promote {
1014             return unless AccessUser(PUBLISHER);
1015             my @ids = CGIArray('LISTED');
1016             return unless @ids;
1017             for my $id (@ids) {
1018             $cgiparams{'articleid'} = $id;
1019             next unless AuthorCheck('GetArticleByID','articleid');
1020             my $publish = $tvars{data}->{publish} + 1;
1021             next unless($publish < 5);
1022             $dbi->DoQuery('PromoteArticle',$publish,$cgiparams{'articleid'});
1023             }
1024             }
1025              
1026             sub Copy {
1027             return unless AccessUser($LEVEL);
1028             $cgiparams{$INDEXKEY} = $cgiparams{'LISTED'};
1029             return unless AuthorCheck($GETSQL,$INDEXKEY,$LEVEL);
1030              
1031             my @fields = ( $tvars{data}->{folderid},
1032             $tvars{data}->{title} . ' - COPY',
1033             $tvars{loginid},
1034             formatDate(0),
1035             $tvars{data}->{sectionid},
1036             $tvars{data}->{name} . '-copy',
1037             1);
1038             my $articleid = $dbi->IDQuery($ADDSQL,@fields);
1039              
1040             my $order = 1;
1041             my @body = $dbi->GetQuery('hash','GetContent',$cgiparams{$INDEXKEY});
1042             for my $item (@body) {
1043             $dbi->DoQuery('AddContent',$articleid,$order,$item->{type},$item->{imageid},$item->{link},$item->{body});
1044             $order++;
1045             }
1046              
1047             $cgiparams{$INDEXKEY} = $articleid;
1048             SetCommand('arts-edit');
1049             }
1050              
1051             sub Delete {
1052             return unless AccessUser($LEVEL2);
1053             # return unless AuthorCheck('GetArticleByID','articleid',$LEVEL);
1054              
1055             my @delete = CGIArray('LISTED');
1056             if(@delete) {
1057             $dbi->DoQuery('DeleteArticleContent',{ids=>join(",",@delete)});
1058             $dbi->DoQuery('DeleteArticle', {ids=>join(",",@delete)});
1059             }
1060             }
1061              
1062             sub _snippet {
1063             my ($row,$chars) = @_;
1064             my $text = $row->{snippet} || $row->{body};
1065             return substr(CleanHTML($text),0,($chars-length($row->{title})));
1066             }
1067              
1068             1;
1069              
1070             __END__