# This code was forked from the LiveJournal project owned and operated # by Live Journal, Inc. The code has been modified and expanded by # Dreamwidth Studios, LLC. These files were originally licensed under # the terms of the license supplied by Live Journal, Inc, which can # currently be found at: # # http://code.livejournal.org/trac/livejournal/browser/trunk/LICENSE-LiveJournal.txt # # In accordance with the original license, this code and all its # modifications are provided under the GNU General Public License. # A copy of that license can be found in the LICENSE file included as # part of this distribution. # Event that is fired when there is a new post in a journal. # sarg1 = optional tag id to filter on # sarg2 = optional poster id to filter on (in a community) package LJ::Event::JournalNewEntry; use strict; use Scalar::Util qw(blessed); use LJ::Entry; use Carp qw(croak); use base 'LJ::Event'; sub new { my ( $class, $entry ) = @_; croak 'Not an LJ::Entry' unless blessed $entry && $entry->isa("LJ::Entry"); return $class->SUPER::new( $entry->journal, $entry->ditemid ); } sub arg_list { return ("Entry ditemid"); } sub is_common { 1 } sub entry { my $self = shift; return LJ::Entry->new( $self->u, ditemid => $self->arg1 ); } sub matches_filter { my ( $self, $subscr ) = @_; return 0 unless $subscr->available_for_user; my $ditemid = $self->arg1; my $evtju = $self->event_journal; return 0 unless $evtju && $ditemid; # TODO: throw error? my $entry = LJ::Entry->new( $evtju, ditemid => $ditemid ); return 0 unless $entry && $entry->valid; # TODO: throw error? return 0 unless $entry->visible_to( $subscr->owner ); # filter by tag? my $stagid = $subscr->arg1; if ($stagid) { my $usertaginfo = LJ::Tags::get_usertags( $entry->journal, { remote => $subscr->owner } ); if ($usertaginfo) { my %tagmap = (); # tagname => tagid while ( my ( $tagid, $taginfo ) = each %$usertaginfo ) { $tagmap{ $taginfo->{name} } = $tagid; } return 0 unless grep { $tagmap{$_} == $stagid } $entry->tags; } } # filter by user? my $suserid = $subscr->arg2; my $su = LJ::load_userid($suserid); if ($su) { return 0 unless $subscr->journalid && $entry->poster->equals($su); } # all posts by friends return 1 if !$subscr->journalid && $subscr->owner->watches( $self->event_journal ); # a post on a specific journal return $evtju->equals( $subscr->journal ); } sub _can_view_content { my ( $self, $entry, $target ) = @_; return undef unless $entry && $entry->valid; return undef unless $entry->visible_to($target); return 1; } sub content { my ( $self, $target ) = @_; my $entry = $self->entry; return undef unless $self->_can_view_content( $entry, $target ); my $entry_body = $entry->event_html( { # double negatives, ouch! ljcut_disable => !$target->cut_inbox, cuturl => $entry->url, sandbox => 1, preformatted => $entry->prop("opt_preformatted"), } ) . $self->as_html_tags($target); $entry_body = "
" . $self->as_html_actions . "
" . $entry_body if LJ::has_too_many( $entry_body, linebreaks => 10, chars => 2000 ); $entry_body .= $self->as_html_actions; my $admin_post = ""; if ( $entry->admin_post ) { $admin_post = '
' . LJ::Lang::get_default_text( "esn.journal_new_entry.admin_post", { img => LJ::img('admin-post') } ) . '
'; } return $admin_post . $entry_body; } sub as_html_tags { my ( $self, $u ) = @_; my $tags = ''; my $url = $self->entry->journal->journal_base; # this is retrieving the values of a hash - needs sorting my @taglist = sort { $a cmp $b } $self->entry->tags; # add tag info for entries that have tags if (@taglist) { my @htmltags = (); push @htmltags, qq{$_} foreach @taglist; $tags = "
" . LJ::Lang::get_default_text( 'esn.tags.short', { tags => join( ', ', @htmltags ) } ) . "
"; } return $tags; } sub content_summary { my ( $self, $target ) = @_; my $entry = $self->entry; return undef unless $self->_can_view_content( $entry, $target ); my $truncated; my $event_summary = $entry->event_html_summary( 300, { cuturl => $entry->url }, \$truncated ); my $ret = $event_summary; $ret .= "..." if $truncated; $ret .= $self->as_html_actions; return $ret; } sub as_string { my $self = shift; my $entry = $self->entry; my $about = $entry->subject_text ? ' titled "' . $entry->subject_text . '"' : ''; my $poster = $entry->poster->user; my $journal = $entry->journal->user; return "$poster has posted a new entry$about at " . $entry->url if $entry->journal->is_person; return "$poster has posted a new entry$about in $journal at " . $entry->url; } sub as_html { my ( $self, $target ) = @_; croak "No target passed to as_html" unless LJ::isu($target); my $journal = $self->u; my $entry = $self->entry; return sprintf( "(Deleted entry in %s)", $journal->ljuser_display ) unless $entry && $entry->valid; return "(You are not authorized to view this entry)" unless $self->entry->visible_to($target); my $ju = LJ::ljuser($journal); my $pu = LJ::ljuser( $entry->poster ); my $url = $entry->url; my $about = $entry->subject_text ? ' titled "' . $entry->subject_text . '"' : ''; my $where = $journal->equals( $entry->poster ) ? "$pu" : "$pu in $ju"; return "New entry$about by $where."; } sub as_html_actions { my ($self) = @_; my $entry = $self->entry; my $url = $entry->url; my $reply_url = $entry->url( mode => 'reply' ); my $ret .= "
"; $ret .= " Reply |"; $ret .= " Link"; $ret .= "
"; return $ret; } my @_ml_strings_en = ( 'esn.journal_new_entry.posted_new_entry', # '[[who]] posted a new entry in [[journal]]!', 'esn.journal_new_entry.updated_their_journal', # '[[who]] updated their journal!', 'esn.hi', # 'Hi [[username]],', 'esn.journal_new_entry.about', # ' titled "[[title]]"', 'esn.tags', # 'The entry is tagged "[[tags]]"', 'esn.tags.short', 'esn.journal_new_entry.head_comm2' , # 'There is a new entry by [[poster]][[about]][[postsecurity]] in [[journal]]![[tags]]', 'esn.journal_new_entry.head_user2' , # '[[poster]] has posted a new entry[[about]][[postsecurity]].[[tags]]', 'esn.you_can', # 'You can:', 'esn.view_entry.nosubject', # '[[openlink]]View entry [[ditemid]][[closelink]]' 'esn.view_entry.subject', # '[[openlink]]View entry titled [[subject]][[closelink]]', 'esn.reply_to_entry', # '[[openlink]]Leave a reply to this entry[[closelink]]', 'esn.read_recent_entries', # '[[openlink]]Read the recent entries in [[journal]][[closelink]]', 'esn.join_community' , # '[[openlink]]Join [[journal]] to read Members-only entries[[closelink]]', 'esn.read_user_entries', # '[[openlink]]Read [[poster]]\'s recent entries[[closelink]]', 'esn.add_watch' # '[[openlink]]Subscribe to [[journal]][[closelink]]', ); sub as_email_subject { my ( $self, $u ) = @_; # Precache text lines LJ::Lang::get_default_text_multi( \@_ml_strings_en ); if ( $self->entry->journal->is_comm ) { return LJ::Lang::get_default_text( 'esn.journal_new_entry.posted_new_entry', { who => $self->entry->poster->display_username, journal => $self->entry->journal->display_username, } ); } else { return LJ::Lang::get_default_text( 'esn.journal_new_entry.updated_their_journal', { who => $self->entry->journal->display_username, } ); } } sub _as_email { my ( $self, $u, $is_html ) = @_; my $username = $is_html ? $u->ljuser_display : $u->display_username; my $poster_text = $self->entry->poster->display_username; my $poster = $is_html ? $self->entry->poster->ljuser_display : $poster_text; # $journal - html or plaintext version depends of $is_html # $journal_text - text version # $journal_user - text version, local journal user (ext_* if OpenId). my $journal_text = $self->entry->journal->display_username; my $journal = $is_html ? $self->entry->journal->ljuser_display : $journal_text; my $journal_user = $self->entry->journal->user; my $entry_url = $self->entry->url; my $journal_url = $self->entry->journal->journal_base; my $subject_text = $self->entry->subject_text; # Precache text lines, using DEFAULT_LANG for $u my $lang = $LJ::DEFAULT_LANG; LJ::Lang::get_text_multi( $lang, undef, \@_ml_strings_en ); my $email = LJ::Lang::get_text( $lang, 'esn.hi', undef, { username => $username } ) . "\n\n"; my $about = $subject_text ? ( LJ::Lang::get_text( $lang, 'esn.journal_new_entry.about', undef, { title => $self->entry->subject_text } ) ) : ''; my $tags = ''; # add tag info for entries that have tags if ( my @taglist = sort { $a cmp $b } $self->entry->tags ) { $tags = ' ' . LJ::Lang::get_text( $lang, 'esn.tags', undef, { tags => join( ', ', @taglist ) } ); } # indicate post security if it is locked or filtered my $postsecurity = ''; if ( $self->entry->security eq 'usemask' ) { $postsecurity = ' [locked]'; } my $head_ml = 'esn.journal_new_entry.head_user2'; my $entry = $self->entry; if ( $entry->journal->is_comm ) { $head_ml = 'esn.journal_new_entry.head_comm2'; $head_ml .= '.admin_post' if $entry->admin_post; } $email .= LJ::Lang::get_text( $lang, $head_ml, undef, { poster => $poster, about => $about, journal => $journal, tags => $tags, } ) . "\n\n"; # make hyperlinks for options # tags 'poster' and 'journal' cannot contain html tags # when it used between [[openlink]] and [[closelink]] tags. my $vars = { poster => $poster_text, journal => $journal_text, ditemid => $self->entry->ditemid, subject => $subject_text, }; my $has_subject = $subject_text ? "subject" : "nosubject"; $email .= LJ::Lang::get_text( $lang, 'esn.you_can', undef ) . $self->format_options( $is_html, $lang, $vars, { "esn.view_entry.$has_subject" => [ 1, $entry_url ], 'esn.reply_to_entry' => [ 2, "$entry_url?mode=reply" ], 'esn.read_recent_entries' => [ $self->entry->journal->is_comm ? 3 : 0, $journal_url ], 'esn.join_community' => [ ( $self->entry->journal->is_comm && !$u->member_of( $self->entry->journal ) ) ? 4 : 0, "$LJ::SITEROOT/circle/$journal_user/edit" ], 'esn.read_user_entries' => [ ( $self->entry->journal->is_comm ) ? 0 : 5, $journal_url ], 'esn.add_watch' => [ $u->watches( $self->entry->journal ) ? 0 : 6, "$LJ::SITEROOT/circle/$journal_user/edit?action=subscribe" ], } ); return $email; } sub as_email_string { my ( $self, $u ) = @_; return unless $self->entry && $self->entry->valid; return _as_email( $self, $u, 0 ); } sub as_email_html { my ( $self, $u ) = @_; return unless $self->entry && $self->entry->valid; return _as_email( $self, $u, 1 ); } sub subscription_applicable { my ( $class, $subscr ) = @_; return 1 unless $subscr->arg1; # subscription is for entries with tags. # not applicable if user has no tags my $journal = $subscr->journal; return 1 unless $journal; # ? my $usertags = LJ::Tags::get_usertags($journal); if ( $usertags && ( scalar keys %$usertags ) ) { my @unsub = $class->unsubscribed_tags($subscr); return ( scalar @unsub ) ? 1 : 0; } return 0; } # returns list of (hashref of (tagid => name)) sub unsubscribed_tags { my ( $class, $subscr ) = @_; my $journal = $subscr->journal; return () unless $journal; my $usertags = LJ::Tags::get_usertags( $journal, { remote => $subscr->owner } ); return () unless $usertags; my @tagids = sort { $usertags->{$a}->{name} cmp $usertags->{$b}->{name} } keys %$usertags; return grep { $_ } map { $subscr->owner->has_subscription( etypeid => $class->etypeid, arg1 => $_, journal => $journal ) ? undef : { $_ => $usertags->{$_}->{name} }; } @tagids; } sub subscription_as_html { my ( $class, $subscr ) = @_; my $journal = $subscr->journal; # are we filtering on a tag? my $arg1 = $subscr->arg1; my $usertags; if ( $arg1 eq '?' ) { my @unsub_tags = $class->unsubscribed_tags($subscr); my %entry_tags = $subscr->entry ? map { $_ => 1 } $subscr->entry->tags : (); my @entrytagdropdown; my @fulltagdropdown; foreach my $unsub_tag (@unsub_tags) { while ( my ( $tagid, $name ) = each %$unsub_tag ) { if ( $entry_tags{$name} ) { push @entrytagdropdown, { value => $tagid, text => $name }; } else { push @fulltagdropdown, { value => $tagid, text => $name }; } } } my @tagdropdown; if (@entrytagdropdown) { @tagdropdown = ( { optgroup => LJ::Lang::ml('event.journal_new_entry.taglist.entry'), items => \@entrytagdropdown }, { optgroup => LJ::Lang::ml('event.journal_new_entry.taglist.full'), items => \@fulltagdropdown }, ); } else { @tagdropdown = @fulltagdropdown; } $usertags = LJ::html_select( { name => $subscr->freeze('arg1'), }, @tagdropdown ); } elsif ($arg1) { $usertags = LJ::Tags::get_usertags( $journal, { remote => $subscr->owner } )->{$arg1}->{'name'}; } if ($arg1) { return BML::ml( 'event.journal_new_entry.tag.' . ( $journal->is_comm ? 'community' : 'user' ), { user => $journal->ljuser_display, tags => $usertags, } ); } # are we filtering on a poster? my $arg2 = $subscr->arg2; if ($arg2) { my $postu = LJ::load_userid($arg2); if ($postu) { return BML::ml( 'event.journal_new_entry.poster', { user => $journal->ljuser_display, poster => $postu->ljuser_display, } ); } } return BML::ml('event.journal_new_entry.friendlist') unless $journal; return BML::ml( 'event.journal_new_entry.' . ( $journal->is_comm ? 'community' : 'user' ), { user => $journal->ljuser_display, } ); } # when was this entry made? sub eventtime_unix { my $self = shift; my $entry = $self->entry; return $entry ? $entry->logtime_unix : $self->SUPER::eventtime_unix; } sub zero_journalid_subs_means { undef } 1;