LJSUP-17669: Login.bml form refactoring
[livejournal.git] / cgi-bin / LJ / NotificationInbox.pm
blobc3e347fcfbd49bda346555f9b84893775f908e58
1 package LJ::NotificationInbox;
3 use strict;
4 use warnings;
6 # External modules
7 use Carp 'croak';
8 use Class::Autouse qw{
9 LJ::Event::JournalNewComment
10 LJ::Event::InboxUserMessageRecvd
11 LJ::Event LJ::NotificationArchive
14 # Internal modules
15 use LJ::MemCacheProxy;
16 use LJ::NotificationItem;
18 my ($comment_typeid, $rmessage_typeid, $smessage_typeid);
20 # constructor takes a $u
21 sub new {
22 my ($class, $user) = @_;
24 croak 'Invalid args to construct LJ::NotificationInbox' unless $class and $user;
25 croak 'Invalid user' unless LJ::isu($user);
27 # return singleton from $u if it already exists
28 return $LJ::REQ_CACHE_INBOX{'inbox'} if $LJ::REQ_CACHE_INBOX{'inbox'};
30 my $self = {
31 userid => $user->id,
32 user => $user,
35 $comment_typeid ||= LJ::Event::JournalNewComment->etypeid;
36 $rmessage_typeid ||= LJ::Event::UserMessageRecvd->etypeid;
37 $smessage_typeid ||= LJ::Event::UserMessageSent->etypeid;
39 return $LJ::REQ_CACHE_INBOX{'inbox'} = bless $self;
42 # returns the user object associated with this queue
43 *u = \&owner;
44 sub owner { $_[0]->{'user'} }
46 # Returns a list of LJ::NotificationItems in this queue.
47 sub items {
48 return @{ $_[0]->{'items'} }
49 if $_[0]->{'items'};
51 my $user = &owner;
53 $_[0]->{'items'} = [map {
54 LJ::NotificationItem->new($user, $_);
55 } &_load];
57 # optimization:
58 # now items are defined ... if any are comment
59 # objects we'll instantiate those ahead of time
60 # so that if one has its data loaded they will
61 # all benefit from a coalesced load
62 &instantiate_singletons;
64 return @{ $_[0]->{'items'} };
67 # returns a list of all notification items except for sent user messages
68 sub all_items {
69 grep { $_->{state} ne 'S' } grep { $_->event->class ne "LJ::Event::UserMessageSent" } grep {$_->event} $_[0]->items;
72 # returns a list of friend-related notificationitems
73 sub friend_items {
74 my @friend_events = friend_event_list();
76 my %friend_events = map { "LJ::Event::" . $_ => 1 } @friend_events;
78 grep { $friend_events{$_->event->class} } grep {$_->event} $_[0]->items;
81 # returns a list of friend-related notificationitems
82 sub friendplus_items {
83 my @friend_events = friendplus_event_list();
85 my %friend_events = map { "LJ::Event::" . $_ => 1 } @friend_events;
87 grep { $friend_events{$_->event->class} } grep {$_->event} $_[0]->items;
90 # returns a list of non user-messaging notificationitems
91 sub non_usermsg_items {
92 my @usermsg_events = qw(
93 UserMessageRecvd
94 UserMessageSent
97 @usermsg_events = (@usermsg_events, (LJ::run_hook('usermsg_notification_types') || ()));
99 my %usermsg_events = map { "LJ::Event::" . $_ => 1 } @usermsg_events;
101 grep { !$usermsg_events{$_->event->class} } grep {$_->event} $_[0]->items;
104 # returns a list of non user-message recvd notificationitems
105 sub usermsg_recvd_items {
106 my @events = ( 'UserMessageRecvd' );
107 my @items = $_[0]->subset_items(@events);
109 @items = grep { $_->{state} ne 'S' } @items if LJ::is_enabled('spam_inbox');
111 return @items;
114 # returns a list of non user-message recvd notificationitems
115 sub usermsg_sent_items {
116 $_[0]->subset_items('UserMessageSent');
119 # returns a list of spam notificationitems
120 sub spam_items {
121 grep { $_->{'state'} eq 'S' } $_[0]->subset_items('UserMessageRecvd');
124 sub birthday_items {
125 $_[0]->subset_items('Birthday');
128 sub befriended_items {
129 $_[0]->subset_items('Befriended');
132 sub entrycomment_items {
133 $_[0]->subset_items(entrycomment_event_list());
136 # return a subset of notificationitems
137 sub subset_items {
138 my ($self, @subset) = @_;
140 my %subset_events = map { "LJ::Event::" . $_ => 1 } @subset;
141 return grep { $subset_events{$_->event->class} } $self->items;
144 # return flagged notifications
145 sub bookmark_items {
146 grep { $_[0]->is_bookmark($_->qid) } $_[0]->items;
149 # return archived notifications
150 sub archived_items {
151 &owner->notification_archive->items;
154 sub count {
155 my $count = LJ::MemCacheProxy::get(&_count_memkey);
157 return $count
158 if defined $count;
160 &_load;
162 $count = @{ $LJ::REQ_CACHE_INBOX{'events'} };
164 LJ::MemCacheProxy::set(&_count_memkey, $count, 86400);
166 return $count;
167 } # count
169 # returns number of unread items in inbox
170 sub unread_count {
171 my $self = $_[0];
173 my $unread = LJ::MemCacheProxy::get(&_unread_memkey);
175 return $unread
176 if defined $unread;
178 &_load;
180 $unread = grep {
181 'N' eq uc $_->{'state'}
182 } @{ $LJ::REQ_CACHE_INBOX{'events'} };
184 LJ::MemCacheProxy::set(&_unread_memkey, $unread, 86400);
186 return $unread;
187 } # unread_count
189 # unread message count
190 sub unread_message_count {
192 my $unread = LJ::MemCacheProxy::get(&_unread_msg_memkey);
194 return $unread
195 if defined $unread;
197 &_load;
199 $unread = grep {
200 'N' eq uc $_->{'state'}
201 } grep {
202 $_->{'etypeid'} == $rmessage_typeid
203 } @{ $LJ::REQ_CACHE_INBOX{'events'} };
205 LJ::MemCacheProxy::set(&_unread_msg_memkey, $unread, 86400);
207 return $unread;
208 } # unread_message_count
210 # unread message count
211 sub unread_event_count {
212 &_load;
214 return scalar grep {
215 'N' eq uc $_->{'state'}
216 } grep {
217 $_->{'etypeid'} != $rmessage_typeid and
218 $_->{'etypeid'} != $smessage_typeid
219 } @{ $LJ::REQ_CACHE_INBOX{'events'} };
220 } # unread_msg_count
222 sub spam_event_count {
223 &_load;
225 return scalar grep {
226 'S' eq $_->{'state'}
227 } @{ $LJ::REQ_CACHE_INBOX{'events'} };
228 } # spam_event_count
230 # load the items in this queue
231 # returns internal items hashref
232 sub _load {
233 &LJ::NotificationItem::_load;
235 return
236 unless defined wantarray;
238 return map $_->{'qid'}, @{ $LJ::REQ_CACHE_INBOX{'events'} };
241 sub instantiate_singletons {
242 return 1 unless $LJ::DISABLED{'inbox_controller'};
244 foreach (&items) {
245 my $event = $_->event() or next;
246 my $etypeid = $event->etypeid();
248 # instantiate all the comment singletons so that they will all be
249 # loaded efficiently later as soon as preload_rows is called on
250 # the first comment object
251 LJ::Comment->new(
252 $event->event_journal,
253 jtalkid => $event->{'args'}[0],
254 ) if $etypeid == $comment_typeid;
256 # instantiate all the message singletons so that they will all be
257 # loaded efficiently later as soon as preload_rows is called on
258 # the first message object
259 LJ::Message->new({
260 msgid => $event->{'args'}[0],
261 otherid => $event->{'args'}[1],
262 journalid => $event->{'userid'},
263 }) if $etypeid == $rmessage_typeid or $etypeid == $smessage_typeid;
266 return 1;
269 sub _memkey {
270 my $userid = $_[0]->{'userid'};
271 return [$userid, "inbox:$userid"];
274 sub _count_memkey {
275 my $userid = $_[0]->{'userid'};
276 return [$userid, "inbox:cnt:$userid"];
279 sub _unread_memkey {
280 my $userid = $_[0]->{'userid'};
281 return [$userid, "inbox:newct:$userid"];
284 sub _unread_msg_memkey {
285 my $userid = $_[0]->{'userid'};
286 return [$userid, "inbox:newct:msg:$userid"];
289 sub _bookmark_memkey {
290 my $userid = $_[0]->{'userid'};
291 return [$userid, "inbox:bookmarks:$userid"];
294 *_events_memkey = \&LJ::NotificationItem::_events_memkey;
296 # deletes an Event that is queued for this user
297 # args: Queue ID to remove from queue
298 sub delete_from_queue {
299 my ($self, $item) = @_;
301 my $qid = $item->qid();
303 croak 'no queueid for queue item passed to delete_from_queue'
304 unless int $qid;
306 my $user = &owner
307 or die 'No user object';
309 # Try to remove bookmark first
310 $self->remove_bookmark($qid);
312 $user->do('DELETE FROM notifyqueue WHERE userid=? AND qid=?', undef, $self->{'userid'}, $qid);
314 die $user->errstr
315 if $user->err;
317 # invalidate caches
318 &expire_cache;
320 return 1;
323 sub expire_cache {
324 my $self = $_[0];
326 delete $self->{'items'};
328 $self->{'_loaded'} = 0;
330 delete $LJ::REQ_CACHE_INBOX{'events'};
332 LJ::MemCacheProxy::delete(&_memkey);
333 LJ::MemCacheProxy::delete(&_count_memkey);
334 LJ::MemCacheProxy::delete(&_unread_memkey);
335 LJ::MemCacheProxy::delete(&_unread_msg_memkey);
336 LJ::MemCacheProxy::delete(&_events_memkey);
337 LJ::MemCacheProxy::delete(&_bookmark_memkey);
340 # This will enqueue an event object
341 # Returns the enqueued item
342 sub enqueue {
343 my ($self, %opts) = @_;
344 my $evt = delete $opts{event};
345 my $archive = delete $opts{archive} || 1;
347 croak "No event" unless $evt;
348 croak "Extra args passed to enqueue" if %opts;
350 my $u = &owner or die "No user";
352 # if over the max, delete the oldest notification
353 my $max = $u->get_cap('inbox_max');
354 my $skip = $max - 1; # number to skip to get to max
356 if ($max && $self->count >= $max) {
358 # Get list of bookmarks and ignore them when checking inbox limits
359 my $bmarks = join ',', $self->get_bookmarks_ids;
360 my $bookmark_sql = ($bmarks) ? "AND qid NOT IN ($bmarks) " : '';
362 my $too_old_qid = $u->selectrow_array
363 ("SELECT qid FROM notifyqueue ".
364 "WHERE userid=? $bookmark_sql".
365 "ORDER BY qid DESC LIMIT $skip,1",
366 undef, $u->id);
368 if ($too_old_qid) {
369 $u->do("DELETE FROM notifyqueue WHERE userid=? AND qid <= ? $bookmark_sql",
370 undef, $u->id, $too_old_qid);
371 $self->expire_cache;
375 # get a qid
376 my $qid = LJ::alloc_user_counter($u, 'Q');
377 my $spam = 0;
379 unless ($qid) {
380 die "Could not alloc new queue ID";
383 # Check spam
384 if ($evt->etypeid == LJ::Event::UserMessageRecvd->etypeid) {
385 if (my $msg = $evt->load_message()) {
386 if ($msg->is_spam) {
387 $spam = 1;
392 my %item = (qid => $qid,
393 userid => $u->{userid},
394 journalid => $evt->userid,
395 etypeid => $evt->etypeid,
396 arg1 => $evt->arg1,
397 arg2 => $evt->arg2,
398 state => $spam ? 'S' : $evt->mark_read ? 'R' : 'N',
399 createtime => $evt->eventtime_unix || time());
401 # insert this event into the notifyqueue table
402 $u->do("INSERT INTO notifyqueue (" . join(",", keys %item) . ") VALUES (" .
403 join(",", map { '?' } values %item) . ")", undef, values %item)
404 or die $u->errstr;
406 if ($archive) {
407 # insert into the notifyarchive table with State defaulted to space
408 $item{state} = ' ';
409 $u->do("INSERT INTO notifyarchive (" . join(",", keys %item) . ") VALUES (" .
410 join(",", map { '?' } values %item) . ")", undef, values %item)
411 or die $u->errstr;
414 # send notification
415 if ( LJ::Event::UserMessageRecvd->etypeid == $evt->etypeid ) {
416 $self->__send_notify({
417 'u' => $u,
418 'journal_u' => LJ::want_user($evt->arg2),
419 'msgid' => $evt->arg1,
420 'etypeid' => $evt->etypeid,
424 # invalidate memcache
425 $self->expire_cache;
427 return LJ::NotificationItem->new($u, $qid);
430 sub __send_notify {
431 my ($self, $data) = @_;
432 my $msgid = $data->{'msgid'};
433 my $u = $data->{'u'};
434 my $journal_u = $data->{'journal_u'};
436 LJ::Event::InboxUserMessageRecvd->new($u, $msgid, $journal_u)->fire;
439 # return true if item is bookmarked
440 sub is_bookmark {
441 my ($self, $qid) = @_;
443 # load bookmarks if they don't already exist
444 &load_bookmarks
445 unless $self->{'bookmarks'};
447 return $self->{'bookmarks'}{$qid}? 1 : 0;
450 sub is_contact {
451 my ($class, $u, $target) = @_;
452 die 'Expected parameter $u in is_contact' unless $u;
453 die 'Expected parameter $target in is_contact' unless $target;
455 my $uid = $u->id;
456 my $tid = $target->id;
458 return unless $uid;
459 return unless $tid;
461 my $key = [$uid, "inbox:contacts:$uid"];
462 my $val = LJ::MemCacheProxy::get($key);
464 if ($val) {
465 my %uids = unpack '(VC)*', $val;
467 if (exists $uids{$uid}) {
468 return $uids{$uid};
472 my $dbh = LJ::get_cluster_master($u);
474 return unless $dbh;
476 my $res = $dbh->selectcol_arrayref(qq[
477 SELECT
479 FROM
480 usermsg
481 WHERE
482 type = 'out'
484 journalid = ?
486 otherid = ?
487 LIMIT
490 undef,
491 $uid,
492 $tid
495 if ($dbh->err) {
496 return;
499 if ($res->[0]) {
500 $res = 1;
501 } else {
502 $res = 0;
505 $val ||= '';
506 $val .= pack 'VC', $uid, $res;
508 if ($val) {
509 LJ::MemCacheProxy::set($key, $val, 86400);
512 return $res;
515 # populate the bookmark hash
516 sub load_bookmarks {
517 my ($self) = @_;
518 my $format = 'N*';
520 return scalar keys %{ $self->{'bookmarks'} }
521 if $self->{'bookmarks'};
523 my $u = &owner;
524 my $row = LJ::MemCacheProxy::get(&_bookmark_memkey);
526 if ($row) {
527 $self->{'bookmarks'}{$_} = 1
528 foreach unpack $format, $row;
530 &_load;
532 my %items = map { $_->{'qid'} => 1 } @{ $LJ::REQ_CACHE_INBOX{'events'} };
534 my @obsolete = grep {
535 not exists $items{$_}
536 } keys %{ $self->{'bookmarks'} };
538 return scalar keys %{ $self->{'bookmarks'} }
539 unless @obsolete;
541 $self->{'bookmarks'} = {};
543 $u->do(join(join(',', map '?', @obsolete), 'DELETE FROM notifybookmarks WHERE userid=? AND qid IN (', ')'), undef, $self->{'userid'}, @obsolete);
546 my $qids = $u->selectcol_arrayref('SELECT qid FROM notifybookmarks WHERE userid=?', undef, $self->{'userid'});
548 die sprintf "Failed to load bookmarks: %s\n", $u->errstr
549 if $u->err;
551 $self->{'bookmarks'}{$_} = 1
552 foreach @$qids;
554 $row = pack $format, @$qids;
556 LJ::MemCacheProxy::set(&_bookmark_memkey, $row, 86400);
558 return scalar keys %{ $self->{'bookmarks'} };
559 } # load_bookmarks
561 ## returns array of qid of 'bookmarked' messages
562 sub get_bookmarks_ids {
563 my $self = $_[0];
565 &load_bookmarks
566 unless $self->{'bookmarks'};
568 return keys %{ $self->{'bookmarks'} };
571 # add a bookmark
572 sub add_bookmark {
573 my ($self, $qid) = @_;
575 my $user = &owner;
577 return 0
578 unless &can_add_bookmark;
580 return 1
581 if &is_bookmark;
583 $user->do('INSERT IGNORE INTO notifybookmarks (userid, qid) VALUES (?, ?)', undef, $self->{'userid'}, $qid);
585 die $user->errstr
586 if $user->err;
588 # try to load message by qid
589 $rmessage_typeid ||= LJ::Event::UserMessageRecvd->etypeid;
590 $smessage_typeid ||= LJ::Event::UserMessageSent->etypeid;
592 if (my ($msgid) = $user->selectrow_array("
593 SELECT arg1
594 FROM notifyqueue
595 WHERE userid=? AND qid=? AND etypeid IN (?, ?)",
596 undef, $self->{'userid'}, $qid, $rmessage_typeid, $smessage_typeid)) {
598 $user->do('INSERT IGNORE INTO usermsgbookmarks (journalid, msgid) VALUES (?, ?)', undef, $self->{'userid'}, $msgid);
600 die $user->errstr
601 if $user->err;
604 # Make sure notice is in inbox
605 $self->ensure_queued($qid);
607 $self->{'bookmarks'}{$qid} = 1;
609 LJ::MemCacheProxy::delete(&_bookmark_memkey);
611 return 1;
614 # remove bookmark
615 sub remove_bookmark {
616 my ($self, $qid) = @_;
618 my $user = &owner;
620 return 0
621 unless &is_bookmark;
623 $user->do('DELETE FROM notifybookmarks WHERE userid=? AND qid=?', undef, $self->{'userid'}, $qid);
625 die $user->errstr
626 if $user->err;
628 # try to load message by qid
629 $rmessage_typeid ||= LJ::Event::UserMessageRecvd->etypeid;
630 $smessage_typeid ||= LJ::Event::UserMessageSent->etypeid;
632 if (my ($msgid) = $user->selectrow_array("
633 SELECT arg1
634 FROM notifyqueue
635 WHERE userid=? AND qid=? AND etypeid IN (?, ?)",
636 undef, $self->{'userid'}, $qid, $rmessage_typeid, $smessage_typeid)) {
638 $user->do('DELETE FROM usermsgbookmarks WHERE journalid=? AND msgid=?', undef, $self->{'userid'}, $msgid);
640 die $user->errstr
641 if $user->err;
644 delete $self->{'bookmarks'}{$qid};
646 LJ::MemCacheProxy::delete(&_bookmark_memkey);
648 return 1;
651 # add or remove bookmark based on whether it is already bookmarked
652 sub toggle_bookmark { &is_bookmark? &remove_bookmark : &add_bookmark }
654 # return true if can add a bookmark
655 sub can_add_bookmark {
656 my $max = &owner->get_cap('inbox_max');
658 return 0 if $max <= &load_bookmarks + 1;
659 return 1;
662 sub delete_all {
663 my ( $self, $view, %opts ) = @_;
664 my @items;
666 # Unless in folder 'Bookmarks', don't fetch any bookmarks
667 if ( $view eq 'all' ) {
668 @items = $self->all_items;
669 push @items, $self->usermsg_sent_items;
670 } elsif ( $view eq 'usermsg_recvd' ) {
671 @items = $self->usermsg_recvd_items;
672 } elsif ( $view eq 'friendplus' ) {
673 @items = $self->friendplus_items;
674 push @items, $self->birthday_items;
675 push @items, $self->befriended_items;
676 } elsif ( $view eq 'birthday' ) {
677 @items = $self->birthday_items;
678 } elsif ( $view eq 'befriended' ) {
679 @items = $self->befriended_items;
680 } elsif ( $view eq 'entrycomment' ) {
681 @items = $self->entrycomment_items;
682 } elsif ( $view eq 'bookmark' ) {
683 @items = $self->bookmark_items;
684 } elsif ( $view eq 'usermsg_sent' ) {
685 @items = $self->usermsg_sent_items;
686 } elsif ( $view eq 'spam' ) {
687 @items = $self->spam_items;
690 @items = grep { !$self->is_bookmark($_->qid) } @items
691 unless $view eq 'bookmark';
693 my @ret;
694 foreach my $item (@items) {
695 push @ret, {qid => $item->qid};
698 my $u = &owner;
699 my $interface = $opts{'interface'};
701 LJ::User::UserlogRecord::InboxMassDelete->create( $u,
702 'remote' => $u,
703 'items' => scalar @items,
704 'method' => 'delete_all',
705 'view' => $view,
706 'via' => $interface,
709 # Delete items
710 foreach my $item (@items) {
711 if ($opts{spam}) {
712 my $msg = $item->event->load_message();
713 $msg->mark_as_spam();
715 $item->delete;
718 return @ret;
721 sub delete_all_from_sender {
722 my ( $self, $senderid ) = @_;
723 my @items;
725 @items = grep { $_->event->class ne "LJ::Event::UserMessageSent" } grep {$_->event} $self->items;
727 @items = grep { !$self->is_bookmark($_->qid) } @items;
729 my @ret;
730 # Delete items
731 foreach my $item (@items) {
732 next unless $item->event->arg2 == $senderid;
733 push @ret, {qid => $item->qid};
734 $item->delete;
737 return @ret;
740 sub mark_all_read {
741 my ( $self, $view ) = @_;
742 my @items;
744 # Only get items in currently viewed folder and subfolders
745 if ( $view eq 'all' ) {
746 @items = $self->all_items;
747 push @items, $self->usermsg_sent_items;
748 } elsif ( $view eq 'usermsg_recvd' ) {
749 @items = $self->usermsg_recvd_items;
750 } elsif ( $view eq 'friendplus' ) {
751 @items = $self->friendplus_items;
752 push @items, $self->birthday_items;
753 push @items, $self->befriended_items;
754 } elsif ( $view eq 'birthday' ) {
755 @items = $self->birthday_items;
756 } elsif ( $view eq 'befriended' ) {
757 @items = $self->befriended_items;
758 } elsif ( $view eq 'entrycomment' ) {
759 @items = $self->entrycomment_items;
760 } elsif ( $view eq 'bookmark' ) {
761 @items = $self->bookmark_items;
762 } elsif ( $view eq 'usermsg_sent' ) {
763 @items = $self->usermsg_sent_items;
766 # Mark read
767 $_->mark_read foreach @items;
768 return @items;
771 # Copy archive notice to inbox
772 # Needed when bookmarking a notice that only lives in archive
773 sub ensure_queued {
774 my ($self, $qid) = @_;
776 my $u = &owner
777 or die "No user object";
779 my $sth = $u->prepare
780 ("SELECT userid, qid, journalid, etypeid, arg1, arg2, state, createtime " .
781 "FROM notifyarchive WHERE userid=? AND qid=?");
782 $sth->execute($u->{userid}, $qid);
783 die $sth->errstr if $sth->err;
785 my $row = $sth->fetchrow_hashref;
786 if ($row) {
787 my %item = (qid => $row->{qid},
788 userid => $row->{userid},
789 journalid => $row->{journalid},
790 etypeid => $row->{etypeid},
791 arg1 => $row->{arg1},
792 arg2 => $row->{arg2},
793 state => 'R',
794 createtime => $row->{createtime});
796 # insert this event into the notifyqueue table
797 $u->do("INSERT IGNORE INTO notifyqueue (" . join(",", keys %item) . ") VALUES (" .
798 join(",", map { '?' } values %item) . ")", undef, values %item)
799 or die $u->errstr;
801 # invalidate memcache
802 $self->expire_cache;
805 return;
808 # return a count of a subset of notificationitems
809 sub subset_unread_count {
810 my ($self, @subset) = @_;
812 my %subset_events = map { "LJ::Event::" . $_ => 1 } @subset;
813 my @events = grep { $subset_events{$_->event->class} && $_->unread } grep {$_->event} $self->items;
814 return scalar @events;
817 sub all_event_count {
818 scalar grep { $_->event->class ne 'LJ::Event::UserMessageSent' && $_->unread } grep { $_->event } $_[0]->items;
821 sub friend_event_count {
822 $_[0]->subset_unread_count(friend_event_list());
825 sub friendplus_event_count {
826 $_[0]->subset_unread_count(friendplus_event_list());
829 sub entrycomment_event_count {
830 $_[0]->subset_unread_count(entrycomment_event_list());
833 sub usermsg_recvd_event_count {
834 $_[0]->subset_unread_count('UserMessageRecvd');
837 sub usermsg_sent_event_count {
838 $_[0]->subset_unread_count('UserMessageSent');
842 # Methods that return Arrays of Event categories
843 sub friend_event_list {
844 my @events = qw(
845 Befriended
846 InvitedFriendJoins
847 CommunityInvite
848 NewUserpic
850 @events = (@events, (LJ::run_hook('friend_notification_types') || ()));
851 return @events;
854 sub friendplus_event_list {
855 my @events = qw(
856 Befriended
857 InvitedFriendJoins
858 CommunityInvite
859 NewUserpic
860 NewVGift
861 Birthday
863 @events = (@events, (LJ::run_hook('friend_notification_types') || ()));
864 return @events;
867 sub entrycomment_event_list {
868 my @events = qw(
869 JournalNewEntry
870 JournalNewRepost
871 JournalNewComment
873 return @events;