OSDN Git Service

Model::Stories: add 'create' method
authorhylom <hylom@users.sourceforge.jp>
Fri, 21 Oct 2016 18:09:04 +0000 (03:09 +0900)
committerhylom <hylom@users.sourceforge.jp>
Fri, 21 Oct 2016 18:09:04 +0000 (03:09 +0900)
src/newslash_web/lib/Newslash/Model/Stories.pm

index f0fe75d..1dc4b5e 100644 (file)
@@ -187,6 +187,463 @@ EOSQL
   return $story;
 }
 
+=head2 create(\%params, $uid)
+
+create a story.
+
+=over 4
+
+=item Parameters
+
+=over 4
+
+=item \%params
+
+parameters
+
+=item $uid
+
+author's uid
+
+=back
+
+=item Return value
+
+stoid
+
+=back
+
+=cut
+
+sub create {
+    my ($self, $params, $uid) = @_;
+    #createStory
+
+}
+
+sub createSid {
+    my ($self, $bogus_sid) = @_;
+    # yes, this format is correct, don't change it :-)
+    my $sidformat = '%02d/%02d/%02d/%02d%0d2%02d';
+    # Create a sid based on the current time.
+    my @lt;
+    my $start_time = time;
+    if ($bogus_sid) {
+        # If we were called being told that there's at
+        # least one sid that is invalid (already taken),
+        # then look backwards in time until we find it,
+        # then go one second further.
+        my $loops = 1000;
+        while (--$loops) {
+            $start_time--;
+            @lt = localtime($start_time);
+            $lt[5] %= 100; $lt[4]++; # year and month
+            last if $bogus_sid eq sprintf($sidformat, @lt[reverse 0..5]);
+        }
+        if ($loops) {
+            # Found the bogus sid by looking
+            # backwards.  Go one second further.
+            $start_time--;
+        } else {
+            # Something's wrong.  Skip ahead in
+            # time instead of back (not sure what
+            # else to do).
+            $start_time = time + 1;
+        }
+    }
+    @lt = localtime($start_time);
+    $lt[5] %= 100; $lt[4]++; # year and month
+    return sprintf($sidformat, @lt[reverse 0..5]);
+}
+
+sub grantStorySubmissionKarma {
+    my($self, $story) = @_;
+    #my $constants = getCurrentStatic();
+    my $db = $self->new_instance_of('LegacyDB');
+    #if ($constants->{plugin}{FireHose}) {
+    {
+        my $fhid;
+        #my $firehose = getObject("Slash::FireHose");
+        if ($story->{fhid}) {
+            $fhid = $story->{fhid};
+        } elsif ($story->{subid}) {
+            #my $subid_q = $self->sqlQuote($story->{subid});
+            #($fhid) = $self->sqlSelect('id', 'firehose', "type='submission' and srcid=$subid_q");
+            my $subid_q = $db->sqlQuote($story->{subid});
+            ($fhid) = $db->sqlSelect('id', 'firehose', "type='submission' and srcid=$subid_q");
+        }
+        #$firehose->setFireHose($fhid, { accepted => "yes" }) if $fhid;
+        $self->setFireHose($fhid, { accepted => "yes" }) if $fhid;
+    }
+    return 0 unless $story->{subid};
+    #my($submitter_uid) = $self->sqlSelect(
+    my($submitter_uid) = $db->sqlSelect(
+                                        'uid', 'submissions',
+                                        # 'subid=' . $self->sqlQuote($story->{subid})
+                                        'subid=' . $db->sqlQuote($story->{subid})
+                                       );
+
+    if (!isAnon($submitter_uid)) {
+        #my $constants = getCurrentStatic();
+        my $maxkarma = 50;
+        #$self->sqlUpdate('users_info',
+        $db->sqlUpdate('users_info',
+                       { -karma => "LEAST(karma + $constants->{submission_bonus}, $maxkarma)" },
+                       "uid=$submitter_uid");
+
+        #$self->clearRookie($submitter_uid);
+        my $users = $self->new_instance_of('Users');
+        $users->clearRookie($submitter_uid);
+
+        #$self->validateSubmitter($submitter_uid);
+        $users->update(target => 'class',
+                       field => 'validated_submitter',
+                       now => 1);
+        #$self->setUser_delete_memcached($submitter_uid);
+    }
+
+    #my $submission_info = { del => 2 };
+    #$submission_info->{stoid} = $story->{stoid} if $story->{stoid};
+    #$submission_info->{sid}   = $story->{sid}   if $story->{sid};
+    #$self->setSubmission($story->{subid}, $submission_info);
+    my $submissions = $self->new_instance_of('Submissions');
+    $submissions->update(subid => $story->{subid},
+                         field => 'del',
+                         value => 2);
+    $submissions->upsert_param(params => {
+                                          stoid => $story->{stoid},
+                                          sid => $story->{sid},
+                                         },
+                               subid => $story->{subid});
+}
+
+########################################################
+sub createStory {
+    my($self, $story) = @_;
+
+    #my $constants = getCurrentStatic();
+    my $db = $self->new_instance_of('LegacyDB');
+    #$self->sqlDo("SET AUTOCOMMIT=0");
+    $db->sqlDo("SET AUTOCOMMIT=0");
+
+    my $error = "";
+
+    $story->{submitter} = $story->{submitter} ?  $story->{submitter} : $story->{uid};
+    $story->{is_dirty} = 1;
+
+    if (!defined($story->{title})) {
+        $error = "createStory needs a defined title";
+    } else {
+        # Rather than call truncateStringForCharColumn() here,
+        # we prefer to throw an error.  Unlike createComment,
+        # we would prefer that overlong subjects not be silently
+        # chopped off.  Consider the consequences of saving a
+        # story with the headline "Chris Nandor is a Freakishly
+        # Ugly Twisted Criminal, Claims National Enquirer" and
+        # later realizing it had been truncated after 50 chars.
+        #my $title_len = $self->sqlGetCharColumnLength('story_text', 'title');
+        my $title_len = $db->sqlGetCharColumnLength('story_text', 'title');
+        if ($title_len && length($story->{title}) > $title_len) {
+            $error = "createStory title too long: " . length($story->{title}) . " > $title_len";
+        }
+    }
+
+    my $stoid;
+    if (!$error) {
+        #$story->{sid} = createSid();
+        $story->{sid} = $self->createSid;
+        my $sid_ok = 0;
+        while ($sid_ok == 0) {
+            # we rely on logic in setStory() later to properly
+            # set up the data for a story, so we can't someday
+            # just change this to do an insert of all the story
+            # data, we do need to continue pass it through
+            # setStory()
+            #$sid_ok = $self->sqlInsert('stories',
+            $sid_ok = $db->sqlInsert('stories',
+                                     { sid => $story->{sid} },
+                                     { ignore => 1 } ); # don't need error messages
+            if ($sid_ok == 0) { # returns 0E0 on collision, which == 0
+                # Keep looking...
+                $story->{sid} = $self->createSid($story->{sid});
+            }
+        }
+        # If this came from a submission, update submission and grant
+        # karma to the user
+        $stoid = $self->getLastInsertId({ table => 'stories', prime => 'stoid' });
+        $story->{stoid} = $stoid;
+        $self->grantStorySubmissionKarma($story);
+    }
+
+       if (!$error) {
+               if (! $self->sqlInsert('story_text', { stoid => $stoid })) {
+                       $error = "sqlInsert failed for story_text: " . $self->sqlError();
+               }
+       }
+
+       # Write the chosen topics into story_topics_chosen.  We do this
+       # here because it returns the primaryskid and we will write that
+       # into the stories table with setStory in just a moment.
+       my($primaryskid, $tids);
+       if (!$error) {
+               my $success = $self->setStoryTopicsChosen($stoid, $story->{topics_chosen});
+               $error = "Failed to set chosen topics for story '$stoid'\n" if !$success;
+       }
+       if (!$error) {
+               my $info_hr = { };
+               $info_hr->{neverdisplay} = 1 if $story->{neverdisplay};
+               ($primaryskid, $tids) = $self->setStoryRenderedFromChosen($stoid,
+                       $story->{topics_chosen}, $info_hr);
+               $error = "Failed to set rendered topics for story '$stoid'\n" if !defined($primaryskid);
+       }
+       delete $story->{topics_chosen};
+       my $commentstatus = delete $story->{commentstatus};
+
+       if (!$error) {
+               if ($story->{fhid} && $constants->{plugin}{FireHose}) {
+                       my $firehose = getObject("Slash::FireHose");
+                       my $item = $firehose->getFireHose($story->{fhid});
+                       $firehose->setFireHose($story->{fhid}, { stoid => $stoid });
+                       if ($item && $item->{type} eq "journal") {
+                               $story->{discussion} = $item->{discussion};
+                               $story->{journal_id} = $item->{srcid};
+
+                               if ($story->{journal_id}) {
+                                       if (!$self->sqlCount("journal_transfer", "id = ".$self->sqlQuote($story->{journal_id}))) {
+                                               $self->sqlInsert("journal_transfer", {
+                                                       id => $story->{journal_id}
+                                               });
+                                       }
+                               }
+                       }
+
+               } elsif ($story->{subid}) {
+                       if ($self->sqlSelect('id', 'journal_transfer',
+                               'subid=' . $self->sqlQuote($story->{subid})
+                       )) {
+                               my $sub = $self->getSubmission($story->{subid});
+                               if ($sub) {
+                                       for (qw(discussion journal_id by by_url)) {
+                                               $story->{$_} = $sub->{$_};
+                                       }
+                               }
+                       }
+               }
+
+               $story->{body_length} = defined($story->{bodytext}) ? length($story->{bodytext}) : 0;
+               $story->{word_count} = countWords($story->{introtext}) + countWords($story->{bodytext});
+               $story->{primaryskid} = $primaryskid;
+               $story->{tid} = $tids->[0];
+
+               if (! $self->setStory($stoid, $story)) {
+                       $error = "setStory failed after creation: " . $self->sqlError();
+               }
+       }
+       if (!$error) {
+               my $rootdir;
+               if ($story->{primaryskid}) {
+                    
+                       my $storyskin = $self->getSkin($story->{primaryskid});
+                       $rootdir = $storyskin->{rootdir};
+               } else {
+                       # The story is set never-display so its discussion's rootdir
+                       # probably doesn't matter.  Just go with the default.
+                       my $storyskin = $self->getSkin($constants->{mainpage_skid});
+                       $rootdir = $storyskin->{rootdir};
+               }
+               my $comment_codes = $self->getDescriptions('commentcodes_extended');
+
+               my $discussion = {
+                       kind            => 'story',
+                       uid             => $story->{uid},
+                       title           => $story->{title},
+                       primaryskid     => $primaryskid,
+                       topic           => $tids->[0],
+                       url             => $self->getUrlFromSid(
+                                               $story->{sid},
+                                               $story->{primaryskid},
+                                               $tids->[0],
+                                               $story->{title}
+                                          ),
+                       stoid           => $stoid,
+                       sid             => $story->{sid},
+                       commentstatus   => $comment_codes->{$commentstatus}
+                                          ? $commentstatus
+                                          : $constants->{defaultcommentstatus},
+                       ts              => $story->{'time'}
+               };
+
+               my $id;
+               if ($story->{discussion} && $story->{journal_id}) {
+                       # updating now for journals tips off users that this will
+                       # be a story soon, esp. ts, url, title, kind ... i don't
+                       # care personally, does it matter?  if so we can task some
+                       # of these changes, if we need to make them -- pudge
+
+                       # update later in task
+                       delete @{$discussion}{qw(title url ts)};
+                       delete $discussion->{uid}; # leave it "owned" by poster
+
+                       $id = $story->{discussion};
+                       $discussion->{kind} = 'journal-story';
+                       $discussion->{type} = 'open'; # should be already
+                       $discussion->{archivable} = 'yes'; # for good measure
+
+                       if (!$self->setDiscussion($id, $discussion)) {
+                               $error = "Failed to set discussion data for story\n";
+
+                       } elsif ($story->{journal_id}) {
+                               $self->sqlUpdate('journal_transfer', {
+                                       stoid   => $stoid,
+                                       updated => 0,
+                               }, 'id=' . $self->sqlQuote($story->{journal_id}));
+                       }
+
+               } else {
+                       $id = $self->createDiscussion($discussion);
+                       if (!$id) {
+                               $error = "Failed to create discussion for story";
+                       }
+               }
+               if (!$error && !$self->setStory($stoid, { discussion => $id })) {
+                       $error = "Failed to set discussion '$id' for story '$stoid'\n";
+               }
+       }
+
+       if ($error) {
+               # Rollback doesn't even work in 4.0.x, since some tables
+               # are non-transactional...
+               $self->sqlDo("ROLLBACK");
+               $self->sqlDo("SET AUTOCOMMIT=1");
+               chomp $error;
+               print STDERR scalar(localtime) . " createStory error: $error\n";
+               return "";
+       }
+
+       $self->sqlDo("COMMIT");
+       $self->sqlDo("SET AUTOCOMMIT=1");
+
+       if ($constants->{plugin}{FireHose}) {
+               my $firehose = getObject("Slash::FireHose");
+               $firehose->createItemFromStory($stoid);
+       }
+
+       return $story->{sid};
+}
+
+
+sub editCreateStory {
+    my($self, $preview, $fhitem) = @_;
+    my $constants = getCurrentStatic();
+    my $user = getCurrentUser();
+    my $form = getCurrentForm();
+    my $data;
+
+    my $tagsdb = getObject("Slash::Tags");
+    my $admindb = getObject("Slash::Admin");
+
+    my @topics;
+    push @topics, $fhitem->{tid} if $fhitem->{tid};
+
+    my $chosen_hr = $tagsdb->extractChosenFromTags($fhitem->{globjid}, 'admin');
+
+    my $save_extras = $self->getExtrasToSaveForChosen($chosen_hr, $preview);
+
+    my $is_sectiononly = $tagsdb->isAdminTagged($fhitem->{globjid}, 'sectiononly');
+    $save_extras->{offmainpage} = 1 if $is_sectiononly;
+
+    $data = {
+             uid             => $fhitem->{uid},
+             #sid
+             title           => $preview->{title},
+             #section
+             submitter       => $preview->{submitter},
+             topics_chosen   => $chosen_hr,
+             dept            => $fhitem->{dept},
+             'time'          => $admindb->findTheTime($fhitem->{createtime}, $preview->{fastforward}),
+             bodytext        => $preview->{bodytext},
+             introtext       => $preview->{introtext},
+             #relatedtext
+             media           => $fhitem->{media},
+             commentstatus   => $preview->{commentstatus},
+             thumb           => $fhitem->{thumb},
+             -rendered       => 'NULL',
+             neverdisplay    => $preview->{neverdisplay},
+             sponsor         => $preview->{sponsor},
+             stuck           => $preview->{stuck},
+             stuckpos        => $preview->{stuckpos},
+             stuckendtime    => $preview->{stuckendtime},
+            };
+
+    foreach my $key (keys %$save_extras) {
+        $data->{$key} = $save_extras->{$key};
+    }
+
+    $data->{subid} = $preview->{subid} if $preview->{subid};
+    $data->{fhid} = $preview->{fhid} if $preview->{fhid};
+
+    for (qw(dept bodytext relatedtext)) {
+        $data->{$_} = '' unless defined $data->{$_};  # allow to blank out
+    }
+
+    for my $field (qw( introtext bodytext media )) {
+        local $Slash::Utility::Data::approveTag::admin = 2;
+
+        # XXXEdit check this
+        $data->{$field} = $self->autoUrl($form->{section}, $data->{$field});
+        $data->{$field} = cleanSlashTags($data->{$field});
+        $data->{$field} = strip_html($data->{$field});
+        $data->{$field} = slashizeLinks($data->{$field});
+        $data->{$field} = parseSlashizedLinks($data->{$field});
+        $data->{$field} = balanceTags($data->{$field});
+        $data->{$field} = adjustStoryTags($data->{$field});
+    }
+
+    for (qw(dept bodytext relatedtext)) {
+        $data->{$_} = '' unless defined $data->{$_};  # allow to blank out
+    }
+
+    my $sid = $self->createStory($data);
+
+    if ($sid) {
+        my $st = $self->getStory($sid);
+        $self->setRelated($sid);
+        slashHook('admin_save_story_success', { story => $data });
+        my $stoid = $st->{stoid};
+        my $story_globjid = $self->getGlobjidCreate('stories', $stoid);
+
+        # XXXEdit Do we have to worry about user editing vs author uid on transfer
+        $tagsdb->transferTags($fhitem->{globjid}, $story_globjid);
+
+        #Don't automatically signoff with new editor, this makes it automatically disapper for an admin on first refresh
+        $self->createSignoff($st->{stoid}, $user->{uid}, "created", { no_filter => 1});
+
+        #XXXEdit Tags Auto save?
+        my $admindb = getObject("Slash::Admin");
+        if ($admindb) {
+            $admindb->grantStoryPostingAchievements($data->{uid}, $data->{submitter});
+            $admindb->addSpriteForSid($sid);
+        }
+
+        #XXX Move this to Slash::DB
+        my $sfids = $self->sqlSelect('value', 'preview_param', "name = 'sfid' and preview_id = " . $preview->{preview_id});
+        if ($sfids && $stoid) {
+            $self->sqlUpdate('static_files', { stoid => $stoid, fhid => 0 }, 'fhid = ' . $preview->{preview_fhid});
+        }
+    }
+
+    return $sid;
+}
+
+
+
+
+
+
+
+
+
+
 =head2 related_link($stoid)
 
 get related links.