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.