OSDN Git Service

Model::Stories: fix 'create' method to add tags
[newslash/newslash.git] / src / newslash_web / lib / Newslash / Model / Stories.pm
1 package Newslash::Model::Stories;
2 use Newslash::Model::Base -base;
3
4 use Newslash::Model::SlashDB;
5
6 use Data::Dumper;
7
8 #========================================================================
9
10 =head2 latest(\%options)
11
12 get latest stories.
13
14 =over 4
15
16 =item Parameters
17
18 =over 4
19
20 =item \%options
21
22 options for query.
23
24 $options->{show_future}: when 1, return feature stories. default is 0.
25 $options->{limit}: number of stories. default is 10.
26
27 =back
28
29 =item Return value
30
31 ARRAY of story contents
32
33 =back
34
35 =cut
36
37 sub latest {
38   my ($self, $options) = @_;
39   $options ||= {};
40
41   my $show_future = $options->{show_future} || 0;
42   my $limit = $options->{limit} || 10;
43
44   my $dbh = $self->connect_db;
45
46   # get stories
47   my $where_clause = 'WHERE stories.time <= NOW()';;
48   if ($show_future) {
49     $where_clause = '';
50   }
51
52   my $sql = <<"EOSQL";
53 SELECT latest.*, story_text.*, users.nickname as author
54   FROM (SELECT * from stories $where_clause ORDER BY time DESC LIMIT ?) AS latest
55     LEFT JOIN story_text ON latest.stoid = story_text.stoid
56     LEFT JOIN users ON latest.uid = users.uid
57 EOSQL
58
59   my $sth = $dbh->prepare($sql);
60
61   $sth->execute($limit);
62   my $rs = $sth->fetchall_arrayref(+{});
63   $sth->finish;
64
65   if (@$rs == 0) {
66     $dbh->disconnect();
67     return [];
68   }
69
70   # get tags
71   $sql = <<"EOSQL";
72 SELECT story_topics_rendered.*, story_topics_chosen.weight, topics.*
73   FROM (SELECT stoid FROM stories $where_clause ORDER BY time DESC LIMIT ?) AS latest
74     INNER JOIN story_topics_rendered ON latest.stoid = story_topics_rendered.stoid
75     LEFT JOIN story_topics_chosen ON story_topics_rendered.stoid = story_topics_chosen.stoid
76       AND story_topics_rendered.tid = story_topics_chosen.tid
77     LEFT JOIN topics ON story_topics_rendered.tid = topics.tid
78 EOSQL
79
80   $sth = $dbh->prepare($sql);
81
82   $sth->execute($limit);
83   my $topics_table = $sth->fetchall_arrayref(+{});
84   $sth->finish;
85   $dbh->disconnect();
86
87   my $topics = {};
88   for my $topic (@$topics_table) {
89     if (!$topic->{stoid}) {
90       $topics->{$topic->{stoid}} = [];
91     }
92     push @{$topics->{$topic->{stoid}}}, $topic;
93   }
94
95   for my $story (@$rs) {
96       my $stoid = $story->{stoid};
97       $story->{topics} = $topics->{$stoid};
98       $self->_generalize($story);
99   }
100
101   return $rs;
102 }
103
104
105 #========================================================================
106
107 =head2 select($query_type, $value)
108
109 get a story.
110
111 =over 4
112
113 =item Parameters
114
115 =over 4
116
117 =item $query_type
118
119 query key, "sid" or "stoid"
120
121 =item $value
122
123 value for query
124
125 =back
126
127 =item Return value
128
129 HASH of story contents
130
131 =back
132
133 =cut
134
135 sub select {
136   my ($self, $query_type, $value) = @_;
137
138   if ($query_type !~ m/\A(sid|stoid)\z/) {
139     return undef;
140   }
141
142   my $dbh = $self->connect_db;
143   my $sql = <<"EOSQL";
144 SELECT stories.*, story_text.*, users.nickname as author
145   FROM stories
146     LEFT JOIN story_text ON stories.stoid = story_text.stoid
147     LEFT JOIN users ON stories.uid = users.uid
148   WHERE stories.$query_type = ?
149 EOSQL
150
151   my $sth = $dbh->prepare($sql);
152
153   $sth->execute($value);
154   my $story = $sth->fetchrow_hashref;
155   $sth->finish;
156
157   if (!$story) {
158     $dbh->disconnect();
159     return undef;
160   }
161
162   my $stoid = $story->{stoid};
163   if (!$stoid) {
164     $dbh->disconnect();
165     return undef;
166   }
167
168
169   # get tags
170   $sql = <<"EOSQL";
171 SELECT story_topics_rendered.*, story_topics_chosen.weight, topics.*
172   FROM story_topics_rendered
173     LEFT JOIN story_topics_chosen ON story_topics_rendered.stoid = story_topics_chosen.stoid
174       AND story_topics_rendered.tid = story_topics_chosen.tid
175     LEFT JOIN topics ON story_topics_rendered.tid = topics.tid
176   WHERE story_topics_rendered.stoid = ?
177 EOSQL
178
179   $sth = $dbh->prepare($sql);
180
181   $sth->execute($stoid);
182   my $topics = $sth->fetchall_arrayref(+{});
183   $sth->finish;
184   $dbh->disconnect();
185
186   $story->{topics} = $topics;
187   $self->_generalize($story);
188
189   return $story;
190 }
191
192 =head2 create(\%params, $uid)
193
194 create a story.
195
196 =over 4
197
198 =item Parameters
199
200 =over 4
201
202 =item \%params
203
204 parameters
205
206 $params->{fhid}
207 $params->{subid}
208
209 =item $uid
210
211 author's uid
212
213 =back
214
215 =item Return value
216
217 stoid
218
219 =back
220
221 =cut
222
223 sub create {
224     my ($self, $params, $user, $extra_params, $opts) = @_;
225
226     # check parameters
227     my $msg = "";
228     $msg = "no title" if !$params->{title};
229     $msg = "no title" if !$params->{title};
230     $msg = "no uid" if !$params->{uid};
231     $msg = "no topics" if !defined $params->{topics_chosen};
232
233     if (length($params->{title}) > $self->{options}->{Story}->{title_max_byte}) {
234         $msg = "title too long. max: $self->{options}->{Story}->{title_max_byte} bytes";
235     }
236
237     $params->{commentstatus} ||= "enabled";
238     if (!grep /\A$params->{commentstatus}\z/, qw(disabled enabled friends_only friends_fof_only no_foe no_foe_eof logged_in)) {
239         $msg = "invalid commentstatus";
240     }
241
242     # check timestamp. use ISO8601 style timestamp like: 2006-08-14T02:34:56-0600
243     my $rex_timestamp = qr/
244                          ^(\d+)-(\d+)-(\d+)\D+(\d+):(\d+):(\d+(?:\.\d+)?)   # datetime
245                          (?:Z|([+-])(\d+):(\d+))?$                          # tz
246                           /xi;
247     if ($params->{time} =~ $rex_timestamp) {
248         $params->{time} = "$1-$2-$3 $4:$5:$6";
249     }
250
251     # check parameters finish
252     if (length($msg) > 0) {
253         $self->set_error($msg, -1);
254         return;
255     }
256
257     $params->{neverdisplay} ||= 0;
258
259     # createStory deletes topics_chosen, so save before.
260     my $topics_chosen = $params->{topics_chosen};
261
262     my $slash_db = Newslash::Model::SlashDB->new($self->{options});
263     my $sid = $slash_db->createStory($params);
264
265     my $globjs = $self->new_instance_of("Newslash::Model::Globjs");
266     my $globj_id = $globjs->getGlobjidFromTargetIfExists("stories", $params->{stoid});
267     if ($globj_id) {
268         # set tags
269         use Newslash::Model::Tags;
270         my $tags = $self->new_instance_of("Newslash::Model::Tags");
271         for my $tid (keys %$topics_chosen) {
272             my $ret = $tags->set_tag(uid => $user->{uid},
273                                      tagname_id => $tid,
274                                      globj_id => $globj_id,
275                                      private => 0,
276                                     );
277             warn "set_tag fault..." if !$ret
278         }
279     }
280     return $sid;
281 }
282
283 sub createSid {
284     my ($self, $bogus_sid) = @_;
285     # yes, this format is correct, don't change it :-)
286     my $sidformat = '%02d/%02d/%02d/%02d%0d2%02d';
287     # Create a sid based on the current time.
288     my @lt;
289     my $start_time = time;
290     if ($bogus_sid) {
291         # If we were called being told that there's at
292         # least one sid that is invalid (already taken),
293         # then look backwards in time until we find it,
294         # then go one second further.
295         my $loops = 1000;
296         while (--$loops) {
297             $start_time--;
298             @lt = localtime($start_time);
299             $lt[5] %= 100; $lt[4]++; # year and month
300             last if $bogus_sid eq sprintf($sidformat, @lt[reverse 0..5]);
301         }
302         if ($loops) {
303             # Found the bogus sid by looking
304             # backwards.  Go one second further.
305             $start_time--;
306         } else {
307             # Something's wrong.  Skip ahead in
308             # time instead of back (not sure what
309             # else to do).
310             $start_time = time + 1;
311         }
312     }
313     @lt = localtime($start_time);
314     $lt[5] %= 100; $lt[4]++; # year and month
315     return sprintf($sidformat, @lt[reverse 0..5]);
316 }
317
318 =pod
319
320 sub grantStorySubmissionKarma {
321     my($self, $story) = @_;
322     #my $constants = getCurrentStatic();
323     my $db = $self->new_instance_of('LegacyDB');
324     #if ($constants->{plugin}{FireHose}) {
325     {
326         my $fhid;
327         #my $firehose = getObject("Slash::FireHose");
328         if ($story->{fhid}) {
329             $fhid = $story->{fhid};
330         } elsif ($story->{subid}) {
331             #my $subid_q = $self->sqlQuote($story->{subid});
332             #($fhid) = $self->sqlSelect('id', 'firehose', "type='submission' and srcid=$subid_q");
333             my $subid_q = $db->sqlQuote($story->{subid});
334             ($fhid) = $db->sqlSelect('id', 'firehose', "type='submission' and srcid=$subid_q");
335         }
336         #$firehose->setFireHose($fhid, { accepted => "yes" }) if $fhid;
337         $self->setFireHose($fhid, { accepted => "yes" }) if $fhid;
338     }
339     return 0 unless $story->{subid};
340     #my($submitter_uid) = $self->sqlSelect(
341     my($submitter_uid) = $db->sqlSelect(
342                                         'uid', 'submissions',
343                                         # 'subid=' . $self->sqlQuote($story->{subid})
344                                         'subid=' . $db->sqlQuote($story->{subid})
345                                        );
346
347     if (!isAnon($submitter_uid)) {
348         #my $constants = getCurrentStatic();
349         my $maxkarma = 50;
350         #$self->sqlUpdate('users_info',
351         $db->sqlUpdate('users_info',
352                        { -karma => "LEAST(karma + $constants->{submission_bonus}, $maxkarma)" },
353                        "uid=$submitter_uid");
354
355         #$self->clearRookie($submitter_uid);
356         my $users = $self->new_instance_of('Users');
357         $users->clearRookie($submitter_uid);
358
359         #$self->validateSubmitter($submitter_uid);
360         $users->update(target => 'class',
361                        field => 'validated_submitter',
362                        now => 1);
363         #$self->setUser_delete_memcached($submitter_uid);
364     }
365
366     #my $submission_info = { del => 2 };
367     #$submission_info->{stoid} = $story->{stoid} if $story->{stoid};
368     #$submission_info->{sid}   = $story->{sid}   if $story->{sid};
369     #$self->setSubmission($story->{subid}, $submission_info);
370     my $submissions = $self->new_instance_of('Submissions');
371     $submissions->update(subid => $story->{subid},
372                          field => 'del',
373                          value => 2);
374     $submissions->upsert_param(params => {
375                                           stoid => $story->{stoid},
376                                           sid => $story->{sid},
377                                          },
378                                subid => $story->{subid});
379 }
380
381
382 =cut
383
384 ########################################################
385
386 =pod
387
388 sub createStory {
389     my($self, $story) = @_;
390
391     #my $constants = getCurrentStatic();
392     my $db = $self->new_instance_of('LegacyDB');
393     #$self->sqlDo("SET AUTOCOMMIT=0");
394     $db->sqlDo("SET AUTOCOMMIT=0");
395
396     my $error = "";
397
398     $story->{submitter} = $story->{submitter} ?  $story->{submitter} : $story->{uid};
399     $story->{is_dirty} = 1;
400
401     if (!defined($story->{title})) {
402         $error = "createStory needs a defined title";
403     } else {
404         # Rather than call truncateStringForCharColumn() here,
405         # we prefer to throw an error.  Unlike createComment,
406         # we would prefer that overlong subjects not be silently
407         # chopped off.  Consider the consequences of saving a
408         # story with the headline "Chris Nandor is a Freakishly
409         # Ugly Twisted Criminal, Claims National Enquirer" and
410         # later realizing it had been truncated after 50 chars.
411         #my $title_len = $self->sqlGetCharColumnLength('story_text', 'title');
412         my $title_len = $db->sqlGetCharColumnLength('story_text', 'title');
413         if ($title_len && length($story->{title}) > $title_len) {
414             $error = "createStory title too long: " . length($story->{title}) . " > $title_len";
415         }
416     }
417
418     my $stoid;
419     if (!$error) {
420         #$story->{sid} = createSid();
421         $story->{sid} = $self->createSid;
422         my $sid_ok = 0;
423         while ($sid_ok == 0) {
424             # we rely on logic in setStory() later to properly
425             # set up the data for a story, so we can't someday
426             # just change this to do an insert of all the story
427             # data, we do need to continue pass it through
428             # setStory()
429             #$sid_ok = $self->sqlInsert('stories',
430             $sid_ok = $db->sqlInsert('stories',
431                                      { sid => $story->{sid} },
432                                      { ignore => 1 } ); # don't need error messages
433             if ($sid_ok == 0) { # returns 0E0 on collision, which == 0
434                 # Keep looking...
435                 $story->{sid} = $self->createSid($story->{sid});
436             }
437         }
438         # If this came from a submission, update submission and grant
439         # karma to the user
440         $stoid = $self->getLastInsertId({ table => 'stories', prime => 'stoid' });
441         $story->{stoid} = $stoid;
442         $self->grantStorySubmissionKarma($story);
443     }
444
445     if (!$error) {
446         #if (! $self->sqlInsert('story_text', { stoid => $stoid })) {
447         if (! $db->sqlInsert('story_text', { stoid => $stoid })) {
448             $error = "sqlInsert failed for story_text: " . $self->sqlError();
449         }
450     }
451
452     # Write the chosen topics into story_topics_chosen.  We do this
453     # here because it returns the primaryskid and we will write that
454     # into the stories table with setStory in just a moment.
455         my($primaryskid, $tids);
456         if (!$error) {
457                 my $success = $self->setStoryTopicsChosen($stoid, $story->{topics_chosen});
458                 $error = "Failed to set chosen topics for story '$stoid'\n" if !$success;
459         }
460         if (!$error) {
461                 my $info_hr = { };
462                 $info_hr->{neverdisplay} = 1 if $story->{neverdisplay};
463                 ($primaryskid, $tids) = $self->setStoryRenderedFromChosen($stoid,
464                         $story->{topics_chosen}, $info_hr);
465                 $error = "Failed to set rendered topics for story '$stoid'\n" if !defined($primaryskid);
466         }
467         delete $story->{topics_chosen};
468         my $commentstatus = delete $story->{commentstatus};
469
470         if (!$error) {
471                 if ($story->{fhid} && $constants->{plugin}{FireHose}) {
472                         my $firehose = getObject("Slash::FireHose");
473                         my $item = $firehose->getFireHose($story->{fhid});
474                         $firehose->setFireHose($story->{fhid}, { stoid => $stoid });
475                         if ($item && $item->{type} eq "journal") {
476                                 $story->{discussion} = $item->{discussion};
477                                 $story->{journal_id} = $item->{srcid};
478
479                                 if ($story->{journal_id}) {
480                                         if (!$self->sqlCount("journal_transfer", "id = ".$self->sqlQuote($story->{journal_id}))) {
481                                                 $self->sqlInsert("journal_transfer", {
482                                                         id => $story->{journal_id}
483                                                 });
484                                         }
485                                 }
486                         }
487
488                 } elsif ($story->{subid}) {
489                         if ($self->sqlSelect('id', 'journal_transfer',
490                                 'subid=' . $self->sqlQuote($story->{subid})
491                         )) {
492                                 my $sub = $self->getSubmission($story->{subid});
493                                 if ($sub) {
494                                         for (qw(discussion journal_id by by_url)) {
495                                                 $story->{$_} = $sub->{$_};
496                                         }
497                                 }
498                         }
499                 }
500
501                 $story->{body_length} = defined($story->{bodytext}) ? length($story->{bodytext}) : 0;
502                 $story->{word_count} = countWords($story->{introtext}) + countWords($story->{bodytext});
503                 $story->{primaryskid} = $primaryskid;
504                 $story->{tid} = $tids->[0];
505
506                 if (! $self->setStory($stoid, $story)) {
507                         $error = "setStory failed after creation: " . $self->sqlError();
508                 }
509         }
510         if (!$error) {
511                 my $rootdir;
512                 if ($story->{primaryskid}) {
513                     
514                         my $storyskin = $self->getSkin($story->{primaryskid});
515                         $rootdir = $storyskin->{rootdir};
516                 } else {
517                         # The story is set never-display so its discussion's rootdir
518                         # probably doesn't matter.  Just go with the default.
519                         my $storyskin = $self->getSkin($constants->{mainpage_skid});
520                         $rootdir = $storyskin->{rootdir};
521                 }
522                 my $comment_codes = $self->getDescriptions('commentcodes_extended');
523
524                 my $discussion = {
525                         kind            => 'story',
526                         uid             => $story->{uid},
527                         title           => $story->{title},
528                         primaryskid     => $primaryskid,
529                         topic           => $tids->[0],
530                         url             => $self->getUrlFromSid(
531                                                 $story->{sid},
532                                                 $story->{primaryskid},
533                                                 $tids->[0],
534                                                 $story->{title}
535                                            ),
536                         stoid           => $stoid,
537                         sid             => $story->{sid},
538                         commentstatus   => $comment_codes->{$commentstatus}
539                                            ? $commentstatus
540                                            : $constants->{defaultcommentstatus},
541                         ts              => $story->{'time'}
542                 };
543
544                 my $id;
545                 if ($story->{discussion} && $story->{journal_id}) {
546                         # updating now for journals tips off users that this will
547                         # be a story soon, esp. ts, url, title, kind ... i don't
548                         # care personally, does it matter?  if so we can task some
549                         # of these changes, if we need to make them -- pudge
550
551                         # update later in task
552                         delete @{$discussion}{qw(title url ts)};
553                         delete $discussion->{uid}; # leave it "owned" by poster
554
555                         $id = $story->{discussion};
556                         $discussion->{kind} = 'journal-story';
557                         $discussion->{type} = 'open'; # should be already
558                         $discussion->{archivable} = 'yes'; # for good measure
559
560                         if (!$self->setDiscussion($id, $discussion)) {
561                                 $error = "Failed to set discussion data for story\n";
562
563                         } elsif ($story->{journal_id}) {
564                                 $self->sqlUpdate('journal_transfer', {
565                                         stoid   => $stoid,
566                                         updated => 0,
567                                 }, 'id=' . $self->sqlQuote($story->{journal_id}));
568                         }
569
570                 } else {
571                         $id = $self->createDiscussion($discussion);
572                         if (!$id) {
573                                 $error = "Failed to create discussion for story";
574                         }
575                 }
576                 if (!$error && !$self->setStory($stoid, { discussion => $id })) {
577                         $error = "Failed to set discussion '$id' for story '$stoid'\n";
578                 }
579         }
580
581         if ($error) {
582                 # Rollback doesn't even work in 4.0.x, since some tables
583                 # are non-transactional...
584                 $self->sqlDo("ROLLBACK");
585                 $self->sqlDo("SET AUTOCOMMIT=1");
586                 chomp $error;
587                 print STDERR scalar(localtime) . " createStory error: $error\n";
588                 return "";
589         }
590
591         $self->sqlDo("COMMIT");
592         $self->sqlDo("SET AUTOCOMMIT=1");
593
594         if ($constants->{plugin}{FireHose}) {
595                 my $firehose = getObject("Slash::FireHose");
596                 $firehose->createItemFromStory($stoid);
597         }
598
599         return $story->{sid};
600 }
601
602 sub editCreateStory {
603     my($self, $preview, $fhitem) = @_;
604     my $constants = getCurrentStatic();
605     my $user = getCurrentUser();
606     my $form = getCurrentForm();
607     my $data;
608
609     my $tagsdb = getObject("Slash::Tags");
610     my $admindb = getObject("Slash::Admin");
611
612     my @topics;
613     push @topics, $fhitem->{tid} if $fhitem->{tid};
614
615     my $chosen_hr = $tagsdb->extractChosenFromTags($fhitem->{globjid}, 'admin');
616
617     my $save_extras = $self->getExtrasToSaveForChosen($chosen_hr, $preview);
618
619     my $is_sectiononly = $tagsdb->isAdminTagged($fhitem->{globjid}, 'sectiononly');
620     $save_extras->{offmainpage} = 1 if $is_sectiononly;
621
622     $data = {
623              uid             => $fhitem->{uid},
624              #sid
625              title           => $preview->{title},
626              #section
627              submitter       => $preview->{submitter},
628              topics_chosen   => $chosen_hr,
629              dept            => $fhitem->{dept},
630              'time'          => $admindb->findTheTime($fhitem->{createtime}, $preview->{fastforward}),
631              bodytext        => $preview->{bodytext},
632              introtext       => $preview->{introtext},
633              #relatedtext
634              media           => $fhitem->{media},
635              commentstatus   => $preview->{commentstatus},
636              thumb           => $fhitem->{thumb},
637              -rendered       => 'NULL',
638              neverdisplay    => $preview->{neverdisplay},
639              sponsor         => $preview->{sponsor},
640              stuck           => $preview->{stuck},
641              stuckpos        => $preview->{stuckpos},
642              stuckendtime    => $preview->{stuckendtime},
643             };
644
645     foreach my $key (keys %$save_extras) {
646         $data->{$key} = $save_extras->{$key};
647     }
648
649     $data->{subid} = $preview->{subid} if $preview->{subid};
650     $data->{fhid} = $preview->{fhid} if $preview->{fhid};
651
652     for (qw(dept bodytext relatedtext)) {
653         $data->{$_} = '' unless defined $data->{$_};  # allow to blank out
654     }
655
656     for my $field (qw( introtext bodytext media )) {
657         local $Slash::Utility::Data::approveTag::admin = 2;
658
659         # XXXEdit check this
660         $data->{$field} = $self->autoUrl($form->{section}, $data->{$field});
661         $data->{$field} = cleanSlashTags($data->{$field});
662         $data->{$field} = strip_html($data->{$field});
663         $data->{$field} = slashizeLinks($data->{$field});
664         $data->{$field} = parseSlashizedLinks($data->{$field});
665         $data->{$field} = balanceTags($data->{$field});
666         $data->{$field} = adjustStoryTags($data->{$field});
667     }
668
669     for (qw(dept bodytext relatedtext)) {
670         $data->{$_} = '' unless defined $data->{$_};  # allow to blank out
671     }
672
673     my $sid = $self->createStory($data);
674
675     if ($sid) {
676         my $st = $self->getStory($sid);
677         $self->setRelated($sid);
678         slashHook('admin_save_story_success', { story => $data });
679         my $stoid = $st->{stoid};
680         my $story_globjid = $self->getGlobjidCreate('stories', $stoid);
681
682         # XXXEdit Do we have to worry about user editing vs author uid on transfer
683         $tagsdb->transferTags($fhitem->{globjid}, $story_globjid);
684
685         #Don't automatically signoff with new editor, this makes it automatically disapper for an admin on first refresh
686         $self->createSignoff($st->{stoid}, $user->{uid}, "created", { no_filter => 1});
687
688         #XXXEdit Tags Auto save?
689         my $admindb = getObject("Slash::Admin");
690         if ($admindb) {
691             $admindb->grantStoryPostingAchievements($data->{uid}, $data->{submitter});
692             $admindb->addSpriteForSid($sid);
693         }
694
695         #XXX Move this to Slash::DB
696         my $sfids = $self->sqlSelect('value', 'preview_param', "name = 'sfid' and preview_id = " . $preview->{preview_id});
697         if ($sfids && $stoid) {
698             $self->sqlUpdate('static_files', { stoid => $stoid, fhid => 0 }, 'fhid = ' . $preview->{preview_fhid});
699         }
700     }
701
702     return $sid;
703 }
704
705
706
707
708 =cut
709
710
711
712
713
714 =head2 related_link($stoid)
715
716 get related links.
717
718 =over 4
719
720 =item Parameters
721
722 =over 4
723
724 =item $stoid
725
726 story id
727
728 =back
729
730 =item Return value
731
732 ARRAY of related links
733
734 =back
735
736 =cut
737
738 sub related {
739     my ($self, $stoid) = @_;
740
741     my $dbh = $self->connect_db;
742
743     my $sql = <<"EOSQL";
744 SELECT related.*, story_text.title as title2, firehose.srcid
745   FROM (
746     SELECT * FROM related_stories
747       WHERE stoid = ?
748       ORDER BY ordernum ASC
749     ) AS related
750   LEFT JOIN story_text ON related.rel_stoid = story_text.stoid
751   LEFT JOIN firehose ON firehose.id = related.fhid
752 EOSQL
753
754     my $sth = $dbh->prepare($sql);
755     $sth->execute($stoid);
756     my $related = $sth->fetchall_arrayref({});
757     $sth->finish;
758     $dbh->disconnect();
759
760     for my $r (@$related) {
761         $r->{title} = $r->{title2} unless $r->{title};
762         if ($r->{rel_sid}) {
763             $r->{type} = "story";
764             $r->{key_id} = $r->{rel_sid};
765         } else {
766             $r->{type} = "submission";
767             $r->{key_id} = $r->{srcid};
768         }
769     }
770
771     return $related;
772 }
773
774 =head2 parameters($stoid)
775
776 get story parameters.
777
778 =over 4
779
780 =item Parameters
781
782 =over 4
783
784 =item $stoid
785
786 story id
787
788 =back
789
790 =item Return value
791
792 HASH of parameters
793
794 =back
795
796 =cut
797
798 sub parameters {
799     my ($self, $stoid) = @_;
800
801     my $dbh = $self->connect_db;
802
803     my $sql = <<"EOSQL";
804 SELECT * FROM story_param WHERE stoid = ?
805 EOSQL
806
807     my $sth = $dbh->prepare($sql);
808     $sth->execute($stoid);
809     my $params = $sth->fetchall_hashref('name');
810     $sth->finish;
811
812     # get next/prev story info
813     if ($params->{next_stoid} || $params->{prev_stoid}) {
814         $sql = <<"EOSQL";
815 SELECT stories.*, story_text.* FROM stories JOIN story_text ON stories.stoid = story_text.stoid WHERE stories.stoid = ? OR stories.stoid = ?
816 EOSQL
817         $sth = $dbh->prepare($sql);
818         my $next = $params->{next_stoid}->{value} || 0;
819         my $prev = $params->{prev_stoid}->{value} || 0;
820         $sth->execute($next, $prev);
821         my $sids = $sth->fetchall_hashref('stoid');
822         $params->{next_stoid}->{story} = $sids->{$next} if $sids->{$next};
823         $params->{prev_stoid}->{story} = $sids->{$prev} if $sids->{$prev};
824         $sth->finish;
825     }
826
827     $dbh->disconnect();
828     return $params;
829 }
830
831 #========================================================================
832
833 =head2 set_dirty($key, $id)
834
835 set writestatus dirty for the story.
836
837 =over 4
838
839 =item Parameters
840
841 =over 4
842
843 =item $key
844
845 'stoid'
846
847 =item $id
848
849 id of the story
850
851 =back
852
853 =item Return value
854
855 1/0
856
857 =back
858
859 =cut
860
861 sub set_dirty {
862     my ($self, $key, $id) = @_;
863
864     my $stoid;
865     if ($key eq 'stoid') {
866         $stoid = $id;
867     }
868     else {
869         return;
870     }
871
872     my $dbh = $self->connect_db;
873     my $sql = <<"EOSQL";
874 INSERT INTO story_dirty (stoid) VALUES (?)
875 EOSQL
876
877     my $rs = $dbh->do($sql, undef, $stoid);
878     if (!$rs) {
879         return;
880     }
881     return 1;
882 }
883
884 sub _generalize {
885     my ($self, $story) = @_;
886
887     $story->{content_type} = "story";
888
889     #my $max_weight = 0;
890     for my $t (@{$story->{topics}}) {
891         if ($t->{tid} == $story->{tid}) {
892             $story->{primary_topic} = $t;
893         }
894         #if ($t->{weight} && $t->{weight} > $max_weight) {
895         #    $max_weight = $t->{weight};
896         #}
897     }
898 }
899
900 1;