3 LJ
::Event module
: the
"event" part of the Event
-Subscription
-Notification
(ESN
)
4 subsystem
. See comments
in LJ
::ESN
for information about how ESN works
.
6 ESN Event is a
"value object" in the sense that it never gets stored
in the DB
7 (it may be passed to workers
, however
). Event object is essentially a structure
8 with the following fields
:
10 * event type
(etypeid
), which can be translated to a subclass of LJ
::Event
;
11 LJ
::Typemap is used to maintain this translation
.
12 * journal
in which the event happened
(userid
).
13 * two arguments
, arg1
and arg2
; meaning of these arguments is determined by
14 the logic of specific LJ
::Event subclass
.
16 Note that Event is
not a Subscription
, so it doesn
't have information about
17 which user is supposed to receive a Notification about it. Functions that
18 are supposed to return information about various Event-User relationships
19 (e.g. "can this user subscribe to this event?") receive an LJ::User object
20 as one of their parameters.
22 LJ::Event is an abstract class, only implementing functionality common to all
23 event types. There is a number of LJ::Event::* subclasses which implement
24 event-specific functionality.
27 * JournalNewEntry -- a journal has a new entry in it
28 * JoutnalNewEntry -- a journal has a new repost in it
29 * JournalNewComment -- a journal has a new comment in it
30 * CommunityEntryReply -- a user's community entry has received a comment
31 * CommentReply
-- someone replied to a user
's comment
32 * Befriended -- one user added another as a friend
33 * Defriended -- one user removed another from their friends list
34 * CommunityInvite -- one user invited another to a community
35 * InvitedFriendJoins -- a person invited to LiveJournal by a user has created a journal
36 * NewUserpic -- a user uploaded a userpic
37 * UserExpunged -- a user has been purged from the servers
38 * Birthday -- a user has upcoming birthday
39 * PollVote -- a user voted in a poll
40 * UserMessageRecvd -- a user has received a message from another
41 * UserMessageSent -- a user has sent a message to another
43 In this module, "ExampleEvent" will be used for documentation purposes only.
44 (And we assume that $example_etypeid is its etypeid.) It is not an actually
47 Please note that there are two possible uses for LJ::Event object:
49 * "Fire event" -- send Schwartz a notification that the event has occured.
50 * As a value object -- to store information about an event or a group of events.
51 These objects do not necessarily represent valid events; for example, they
52 may not have the "journal" field set.
58 no warnings 'uninitialized
';
71 ### COMMON FUNCTIONS ###
73 # create a new event structure based on its type, journal and arguments
75 # my $event = LJ::Event::ExampleEvent->new($u, $arg1, $arg2);
77 my ($class, $u, @args) = @_;
78 confess
("too many args") if @args > 4;
80 my $userid = LJ
::want_userid
($u);
89 # create a new event structure based on its type, journal and arguments
90 # difference from "new" is that all arguments are integers: etypeid for
91 # determining type, and userid for journalid for determining journal.
94 # LJ::Event->new_from_raw_params($example_etypeid, $u->id, $arg1, $arg2, $arg3, $arg4);
95 sub new_from_raw_params
{
96 my (undef, $etypeid, $journalid, @args ) = @_;
98 my $class = LJ
::Event
->class($etypeid) or confess
"Classname cannot be undefined/false";
99 my $journal = LJ
::load_userid
($journalid);
100 my $evt = LJ
::Event
->new($journal, @args);
102 # Store etypeid in instance to check it faster
103 $evt->{'etypeid'} = $etypeid;
105 # bless into correct class
111 # return an array or an arrayref of event fields: etypeid, journalid, args
113 # my ($etypeid, $journalid, $arg1, $arg2) = $event->raw_params;
115 # my $params = $event->raw_params;
116 # my ($etypeid, $journalid, $arg1, $arg2) = @$params;
120 my $ju = $self->event_journal;
121 Carp
::confess
("Event $self has no journal")
122 unless $ju || $self->allow_emails_to_unauthorised;
124 my $uid = $ju ?
$ju->id : 0 ;
126 my @params = map { $_ || 0 } (
131 return wantarray ?
@params : \
@params;
134 # "getter" methods; all of these are final.
136 # my $journal = $event->event_journal;
137 # my $journal = $event->u;
138 # my $arg1 = $event->arg1;
139 sub userid
{ $_[0]->{userid
}; }
141 sub u
{ return $_[0]->{'u'} ||= LJ
::load_userid
($_[0]->{'userid'}); }
143 *event_journal
= \
&u
;
145 sub arg1
{ $_[0]->{args
}[0] }
146 sub arg2
{ $_[0]->{args
}[1] }
148 # alias for LJ::ESN->process_fired_events
149 sub process_fired_events
{
151 confess
("Can't call in web context") if LJ
::is_web_context
();
152 LJ
::ESN
->process_fired_events;
155 # returns a scalar indicating what a journal=0 wildcard means in a subscription
158 # valid values are nothing ("" or undef), "all", or "friends"
160 # this is a virtual function; base class function returns "" for nothing.
162 # warn "not notifying"
163 # unless $sub->journal || $event->zero_journalid_subs_means;
164 sub zero_journalid_subs_means
{ "" }
166 # returns a boolean value indicating whether the inbox notification for this
167 # event should initially come already read.
169 # this is a virtual function; base class function returns 0 for "initially
172 # $inbox->mark_read($notification) if $event->mark_read;
178 # return the typemap for the Events classes
180 # my $tm = LJ::Event->typemap;
181 # my $class = $tm->typeid_to_class($etypeid);
183 return LJ
::Typemap
->new(
184 table
=> 'eventtypelist',
185 classfield
=> 'class',
186 idfield
=> 'etypeid',
190 my (%classes, %etypeids);
192 # return the class name, given an etypeid
194 # my $class = LJ::Event->class($etypeid);
196 my ($class, $typeid) = @_;
198 $typeid ||= $class->etypeid;
200 unless ($classes{$typeid}) {
201 my $tm = $class->typemap
204 $classes{$typeid} = $tm->typeid_to_class($typeid);
207 return $classes{$typeid};
210 # return etypeid for the class
212 # my $etypeid = LJ::Event::ExampleEvent->etypeid;
214 my $invocant = $_[0];
218 return $invocant->{'etypeid'}
219 if $invocant->{'etypeid'};
221 $class = ref $invocant;
226 unless ($etypeids{$class}) {
227 my $tm = $class->typemap
230 $etypeids{$class} = $tm->class_to_typeid($class);
233 return $etypeids{$class};
236 # return etypeid for the given class
238 # my $etypeid = LJ::Event->event_to_etypeid('ExampleEvent');
239 # my $etypeid = LJ::Event->event_to_etypeid('LJ::Event::ExampleEvent');
240 sub event_to_etypeid
{
241 my ($class, $evt_name) = @_;
243 $evt_name = "LJ::Event::$evt_name" unless $evt_name =~ /^LJ::Event::/;
246 unless $class->typemap->class_to_typeid($evt_name);
248 my $tm = $class->typemap
250 return $tm->class_to_typeid($evt_name);
253 # return an array listing all LJ::Event subclasses
255 # my @classes = LJ::Event->all_classes;
259 # return config'd classes if they exist, otherwise just return everything that has a mapping
260 return @LJ::EVENT_TYPES
if @LJ::EVENT_TYPES
;
262 confess
"all_classes is a class method" unless $class;
264 my $tm = $class->typemap
265 or confess
"Bad class $class";
267 return $tm->all_classes;
271 return BASE_PRIORITY
;
274 # return string containing nicely-represented list of links to go with
275 # the notification (the "now that you're receiving this notification, you
280 # 'aopts' => qq{ href="$LJ::SITEROOT"; },
283 # # key is an ML key (and $mlvars are used to expand it), value is an
286 # # the first element of that arrayref is a sort order number; passing 0
287 # # there prevents the element from showing.
289 # # the second element is where the link should point.
290 # 'esn.smile' => [ 1, $LJ::SITEROOT ],
291 # 'esn.facepalm' => [ 0, $LJ::SITEROOT ],
293 # my $extra = "additional blinky text";
294 # my $str = LJ::Event->format_options($is_html, $lang, $mlvars, $urls, $extra);
296 my ($self, $is_html, $lang, $vars, $urls, $extra) = @_;
298 my ($tag_p, $tag_np, $tag_li, $tag_nli, $tag_ul, $tag_nul, $tag_br) = ('','','','','','',"\n");
301 $tag_p = '<p>'; $tag_np = '</p>';
302 $tag_li = '<li>'; $tag_nli = '</li>';
303 $tag_ul = '<ul>'; $tag_nul = '</ul>';
306 my $options = $tag_br . $tag_br . $tag_ul;
309 $vars->{'closelink'} = '</a>';
314 $vars->{'openlink'} = '<a href="' . $urls->{$key}->[1] . '">';
315 $tag_li . LJ
::Lang
::get_text
($lang, $key, undef, $vars) . $tag_nli;
317 sort { $urls->{$a}->[0] <=> $urls->{$b}->[0] }
318 grep { $urls->{$_}->[0] }
321 $vars->{'openlink'} = '';
322 $vars->{'closelink'} = '';
327 ' - ' . LJ
::Lang
::get_text
($lang, $key, undef, $vars) . ":\n" .
328 ' ' . $urls->{$key}->[1] . "\n"
330 sort { $urls->{$a}->[0] <=> $urls->{$b}->[0] }
331 grep { $urls->{$_}->[0] }
336 $options .= $extra if $extra;
338 $options .= $tag_nul . $tag_br;
343 ### FIRED EVENT FUNCTIONS ###
345 # return a boolean value specifying whether we should notify the user
346 # regardless of their account state -- for example, if they are suspended.
348 # this is a virtual function; base class function returns "do not notify",
349 # meaning that only visible users with their emails validated are notified.
351 # return unless $u->is_visible || $event->is_significant;
352 sub is_significant
{ 0 }
354 # return HTML code representing the event.
356 # this is a purely virtual function; base class function returns an empty
359 # my $html = $event->content;
362 # return a hashref representing information returned by the getinbox protocol
363 # and XML-RPC method.
365 # this is a virtual function; base class function returns a hashref containing
366 # information about event class only.
368 # my $hashref = $event->raw_info;
369 # print $hashref->{'type'};
373 my $subclass = ref $self;
374 $subclass =~ s/LJ::Event:?:?//;
376 return { type
=> $subclass };
379 # return a string representing a notification sent to the passed user notifying
380 # them that this event has happened.
382 # this is a virtual function; base class function returns a dummy string
383 # listing information about the event class and its arguments. it does not
384 # do anything trying to parse arguments.
386 # print $event->as_string($u);
390 confess
"No target passed to Event->as_string" unless LJ
::isu
($u);
392 my ($classname) = (ref $self) =~ /Event::(.+?)$/;
393 return "Event $classname fired for user=$u->{user}, args=[@{$self->{args}}]";
396 # return HTML code representing a notification sent to the passed user notifying
397 # them that this event has happened.
399 # this is a virtual function; base class function returns whatever "as_string"
402 # print $event->as_html($u);
406 confess
"No target passed to Event->as_string" unless LJ
::isu
($u);
408 return $self->as_string;
411 sub tmpl_params
{return {}}
413 # return a string representing an IM (Jabber) notification sent to the passed
414 # user notifying them that this event has happened.
416 # this is a virtual function; base class function returns whatever "as_string"
419 # $ljtalk->send($u, $event->as_im($u));
422 return $self->as_string($u);
425 # return a string representing an "Alerts" (Windows Live Messenger)
426 # notification sent to the passed user notifying them that this event has
429 # this is a virtual function; base class function returns whatever "as_string"
432 # $wlm->send($u, $event->as_alert($u));
435 return $self->as_string($u);
438 # return a string representing an "Web Notification" body (or another popup
440 # notification sent to the passed user notifying them that this event has
443 # this is a virtual function; base class function returns whatever default
444 # structure method returns.
446 # $wlm->send($u, $event->as_web_body($u));
447 sub as_web_notification
{
449 return { title
=> $self->as_email_subject($u),
450 content
=> $self->as_string($u),
456 # return a string representing an email subject of an email notification sent
457 # to the passed user notifying them that this event has happened.
459 # this is a virtual function; base class function returns whatever "as_string"
462 # my $subject = $event->as_email_subject($u);
463 sub as_email_subject
{
465 return $self->as_string($u);
468 # return a string representing HTML content of an email notification sent
469 # to the passed user notifying them that this event has happened.
471 # this is a virtual function; base class function returns whatever
472 # "as_email_string" method returns.
474 # my $body_html = $event->as_email_html($u);
477 return $self->as_email_string($u);
480 # return a string representing plain text content of an email notification sent
481 # to the passed user notifying them that this event has happened.
483 # this is a virtual function; base class function returns whatever
484 # "as_string" method returns.
486 # my $body_text = $event->as_email_string($u);
487 sub as_email_string
{
489 return $self->as_string($u);
492 # return a string representing the "From:" header of an email notification sent
493 # to the passed user notifying them that this event has happened.
495 # this is a virtual function; base class function returns $LJ::SITENAMESHORT.
497 # my $from = $event->as_email_from_name($u);
498 sub as_email_from_name
{
500 return $LJ::SITENAMESHORT
;
503 # return a hashref representing additional headers of an email notification sent
504 # to the passed user notifying them that this event has happened.
506 # this is a virtual function; base class function returns undef, which means
507 # "no additional headers".
509 # my $headers = $event->as_email_headers($u);
510 # print $headers->{'Message-ID'};
511 sub as_email_headers
{
516 # return a boolean value indicating that email notifications of this event need
517 # a standard footer (ml(esn.email.html.footer)) appended to them.
519 # this is a virtual function; the base class function returns 1 for "yes".
521 # if ($evt->need_standard_footer) { $html .= BML::ml('esn.email.html.footer'); }
522 sub need_standard_footer
{ 1 }
524 # return a boolean value indicating that email notifications of this event need
525 # a promo appended to them.
527 # this is a virtual function; the base class function returns 1 for "yes".
530 # return a string representing an "SMS" (TxtLJ) notification sent to the passed
531 # user notifying them that this event has happened.
533 # this is a virtual function; base class function returns whatever "as_string"
534 # method returns, truncated to 160 chars with an EBCDIC ellipsis ('...') added.
536 # $txtlj->send($u, $event->as_sms($u));
538 my ($self, $u, $opt) = @_;
539 return LJ
::Text
->truncate_with_ellipsis(
540 'str' => $self->as_string($u, $opt),
546 sub as_push
{ warn "method 'as_push' has to be overriden in ".ref(shift)."!"; return '' }
548 sub as_push_payload
{ warn "method 'as_push_payload' has to be overriden in ".ref(shift)."!"; return ''}
552 # Returns a string representing a Schwartz role [queue] used to handle this event
553 # By default returns undef, which is ok for most cases.
556 my $class = ref $self || $self;
558 return $LJ::SCHWARTZ_ROLE_FOR_ESN_CLASS
{$class};
561 # insert a job for TheSchwartz to process this event.
566 return 0 if $LJ::DISABLED
{'esn'};
568 my $sclient = LJ
::theschwartz
( { role
=> $self->schwartz_role } );
569 return 0 unless $sclient;
571 my $job = $self->fire_job or
574 $job->priority($self->priority);
576 my $h = $sclient->insert($job);
580 # returns a Schwartz Job object to process this event
582 # my $job = $event->fire_job;
585 return if $LJ::DISABLED
{'esn'};
587 if (my $val = $LJ::DEBUG
{'firings'}) {
588 if (ref $val eq "CODE") {
591 warn $self->as_string( $self->event_journal ) . "\n";
595 return TheSchwartz
::Job
->new_from_array("LJ::Worker::FiredEvent", [ $self->raw_params ]);
598 # returns an array of subscriptions that MAY match this event; it is not
599 # necessary for all of them to match it -- it is needed to further filter
600 # them to remove ones that do not match.
602 # this is a virtual function; base class function only filters by etypeid,
603 # journal, and flags (must be active). it doesn't filter by
604 # arg1/arg2, whatever these might mean in a subclss.
606 # it may be senseful to override this in a subclass to allow for additional
607 # subscriptions to be triggered.
609 # my @subs = $event->subscriptions(
610 # 'cluster' => 1, # optional, search the subs table on the given cluster
611 # 'limit' => 5000, # optional, return no more than $limit subscriptions
614 my ($self, %args) = @_;
615 my $cid = delete $args{'cluster'};
616 my $limit = delete $args{'limit'};
617 confess
("Unknown options: " . join(', ', keys %args)) if %args;
618 confess
("Can't call in web context") if LJ
::is_web_context
();
624 my $zeromeans = $self->zero_journalid_subs_means;
628 if ($zeromeans eq 'friends') {
629 # find friendofs, add to @wildcards_from
630 @wildcards_from = $self->u->friendof_uids();
632 elsif ($zeromeans eq 'all') {
636 my $limit_remain = $limit;
638 # SQL to match only on active subs
639 my $and_enabled = "AND flags & " .
640 LJ
::Subscription
->INACTIVE . " = 0";
642 # TODO: gearman parallelize:
643 foreach my $cid ($cid ?
($cid) : @LJ::CLUSTERS
) {
645 last if $limit && $limit_remain <= 0;
647 ## hack: use inactive server of user cluster to find subscriptions
648 ## LJ::DBUtil wouldn't load in web-context
649 ## inactive DB may be unavailable due to backup, or on dev servers
650 ## TODO: check that LJ::get_cluster_master($cid) in other parts of code
651 ## will return handle to 'active' db, not cached 'inactive' db handle
654 if (not $LJ::DISABLED
{'try_to_load_subscriptions_from_slave'}){
656 require 'LJ/DBUtil.pm';
657 LJ
::DBUtil
->get_inactive_db($cid); # connect to slave
661 $udbh ||= LJ
::get_cluster_master
($cid); # default (master) connect
663 die "Can't connect to db" unless $udbh;
665 # first we find exact matches (or all matches)
666 my $journal_match = $allmatch ?
"" : "AND journalid=?";
668 my $limit_sql = ($limit && $limit_remain) ?
"LIMIT $limit_remain" : '';
669 my ($extra_condition, @extra_args) = $self->extra_params_for_finding_subscriptions();
670 my $sql = "SELECT userid, subid, is_dirty, journalid, etypeid, " .
671 "arg1, arg2, ntypeid, createtime, expiretime, flags " .
672 "FROM subs WHERE etypeid=? $journal_match $and_enabled $extra_condition " .
675 my $sth = $udbh->prepare($sql);
676 my @args = ($self->etypeid);
677 push @args, $self->u->id unless $allmatch;
678 push @args, @extra_args;
680 $sth->execute(@args);
683 warn "SQL: [$sql], args=[@args]\n";
687 while (my $row = $sth->fetchrow_hashref) {
688 my $sub = LJ
::Subscription
->new_from_row($row);
689 next unless $sub->owner->clusterid == $cid;
694 # then we find wildcard matches.
695 if (@wildcards_from) {
696 # FIXME: journals are only on one cluster! split jidlist based on cluster
697 my $jidlist = join(",", @wildcards_from);
699 ## Strictly specify USE INDEX(PRIMARY) hint.
700 ## Otherwise mysql query planner is acting out and query takes inexcusable amount of time.
701 my $sth = $udbh->prepare(qq{
703 userid
, subid
, is_dirty
, journalid
, etypeid
,
704 arg1
, arg2
, ntypeid
, createtime
, expiretime
, flags
707 WHERE etypeid
=? AND journalid
=0 $and_enabled
708 AND userid IN
($jidlist)
711 $sth->execute($self->etypeid);
712 die $sth->errstr if $sth->err;
714 while (my $row = $sth->fetchrow_hashref) {
715 my $sub = LJ
::Subscription
->new_from_row($row);
716 next unless $sub->owner->clusterid == $cid;
722 $limit_remain = $limit - @subs;
728 sub extra_params_for_finding_subscriptions
{
732 # returns a boolean value indicating whether the given subscription matches
735 # this is a virtual function; base class function returns 1 for "yes".
737 # my @subs = grep { $event->matches_filter($_) } @subs;
739 my ($self, $subsc) = @_;
743 # returns a scalar value representing the time event happened.
745 # this is a virtual function; base class function returns undef for "unknown"
747 # my $time = $event->eventtime_unix;
748 # print scalar(localtime($time)) if defined $time;
753 # Returns path to template file by event type for certain language, journal
754 # and e-mail section.
756 # @params: section = [subject | body_html | body_text]
757 # lang = [ en | ru | ... ]
759 # @returns: filename or undef if template could not be found.
761 sub template_file_for
{
765 return if LJ
::conf_test
($LJ::DISABLED
{template_files
});
767 my $section = $opts{section
};
768 my $lang = $opts{lang
} || 'default';
769 my ($event_type) = (ref $self) =~ /\:([^:]+)$/; #
770 my $journal_name = $self->event_journal->user;
772 # all ESN e-mail templates are located in:
773 # $LJHOME/templates/ESN/$event_type/$language/$journal_name
775 # go though file paths until found existing one
777 "$event_type/$lang/$journal_name/$section.tmpl",
778 "$event_type/$lang/default/$section.tmpl",
779 "$event_type/default/$journal_name/$section.tmpl",
780 "$event_type/default/default/$section.tmpl",
782 $file = "$ENV{LJHOME}/templates/ESN/$file"; # add common prefix
783 return $file if -e
$file;
788 ### VALUE OBJECT FUNCTIONS ###
790 # return a string with HTML code representing a subscription as shown to
791 # the user on a settings page.
793 # this is a virtual function; base class function returns a dummy string listing
794 # event class, journal, and arguments.
796 # my $html = LJ::Event::ExampleEvent->subscription_as_html(bless({
797 # 'journalid' => $journal->id,
800 # }, "LJ::Subscription"));
802 # my $html = LJ::Event::ExampleEvent->subscription_as_html(bless({
803 # 'journalid' => $journal->id,
806 # }, "LJ::Subscription::Group"));
807 sub subscription_as_html
{
808 my ($class, $subscr) = @_;
810 confess
"No subscription" unless $subscr;
812 my $arg1 = $subscr->arg1;
813 my $arg2 = $subscr->arg2;
814 my $journalid = $subscr->journalid;
816 my $user = $journalid ? LJ
::ljuser
(LJ
::load_userid
($journalid)) : "(wildcard)";
818 return $class . " arg1: $arg1 arg2: $arg2 user: $user";
821 # return a boolean indicating that event could be emailed to unauthorized users
822 # it is required for SupportRequest and SupportResponse events,
823 # since support requests could be created by non-users
824 sub allow_emails_to_unauthorised
{ 0 }
826 # return a boolean indicating relation of the event to Support
827 sub is_support_class
{ 0 }
829 # return a boolean value indicating whether a user is able to subscribe to
830 # this event and receive notifications.
832 # this is a virtual function; base class function returns true, which means
835 # @subs = grep { $_->available_for_user($u) } @subs;
836 sub available_for_user
{
842 # return a boolean indicating whether the subscription for this event is a
843 # "tracking" one, that is, it
845 # * counts towards user's quota of subscriptions
846 # * shows up on the bottom of the user's subscriptions list on the main
849 # this is a virtual function; base class function returns 1 for "yes"
851 # next unless $event->is_tracking;
852 sub is_tracking
{ 1 }
854 # return a boolean indicating whether the subscription for this event may
855 # be shown to the user. it may still not be shown if the calling page doesn't
856 # want it to be shown; returning true from here prevents the subscription
857 # from showing for good -- when this is done, LJ::Widget::SubscribeInterface
858 # will never show it, regardless of what is passed to it.
860 # this is a virtual function; base class function returns 1 for "yes"
862 # next unless $event->is_subscription_visible_to($u);
863 sub is_subscription_visible_to
{ 1 }
865 # return a string containing HTML code with information for the user about
866 # what they can do to have this subscription available (e.g. upgrade account).
868 # this is a virtual function; base class function calls a "disabled_esn_sub"
869 # hook for the user and returns whatever it returned or an empty string.
871 # print $event->get_disabled_pic;
872 sub get_disabled_pic
{
875 return LJ
::run_hook
("disabled_esn_sub", $u) || '';
878 # return a boolean indicating whether the checkbox corresponding to the
879 # given notification type may be shown to the user.
881 # this is a virtual function; base class function returns 1 for "yes".
883 # $checkbox = '' unless $event->is_subscription_ntype_visible_to($ntypeid, $u);
884 sub is_subscription_ntype_visible_to
{ 1 }
886 # return a boolean indicating whether the checkbox corresponding to the
887 # given notification type must be disabled.
889 # this is a virtual function; base class function checks whether the user
890 # is able to subscribe to this event, and whether the notification method
891 # is configured for them -- if one of these conditions not met, it returns
892 # 0 for "no"; otherwise, it returns 1 for "yes".
894 # overriding functions in subclasses are still expected to call the parent
895 # class function in order to avoid duplicating these checks.
897 # $disabled = $event->is_subscription_ntype_disabled_for($ntypeid, $u);
898 sub is_subscription_ntype_disabled_for
{
899 my ($self, $ntypeid, $u) = @_;
901 if ($self->class !~ /Support/) {
902 return 1 unless $self->available_for_user($u);
905 my $nclass = LJ
::NotificationMethod
->class($ntypeid);
906 return 1 unless $nclass->configured_for_user($u);
908 return 1 unless $nclass->is_subtype_enabled($self);
913 # assuming that the checkbox corresponding to the given notification type
914 # is disabled for the user, return a boolean value whether it is checked or not.
916 # this is a virtual function; base class function returns 0 for "no".
918 # $value = $disabled ?
919 # $event->get_subscription_ntype_force($ntype, $u) :
921 sub get_subscription_ntype_force
{ 0 }
923 # returns a hashref with the information returned from these functions:
925 # * is_subscription_visible_to (the 'visible' key)
926 # * !available_for_user (the 'disabled' key)
927 # * get_disabled_pic (the 'disabled_pic' key)
929 # note that this function forces the event to be invisible in case user is
930 # unable to subscribe to this event and is unable to upgrade to it [that is, is
933 # my $interface_info = $event->get_interface_status($u);
934 sub get_interface_status
{
937 my $available = $self->available_for_user($u);
939 my $visible = $self->is_subscription_visible_to($u);
940 $visible &&= ($available || !$u->is_identity);
943 'visible' => $visible,
944 'disabled' => !$available,
945 'disabled_pic' => $self->get_disabled_pic($u),
949 # returns a hashref with the information returned from these functions:
951 # * is_subscription_ntype_visible_to (the 'visible' key)
952 # * is_subscription_ntype_disabled_for (the 'disabled' key)
953 # * get_subscription_ntype_force (the 'force' key)
955 # my $interface_info = $event->get_ntype_interface_status($u);
956 sub get_ntype_interface_status
{
957 my ($self, $ntypeid, $u) = @_;
960 'visible' => $self->is_subscription_ntype_visible_to($ntypeid, $u),
961 'disabled' => $self->is_subscription_ntype_disabled_for($ntypeid, $u),
962 'force' => $self->get_subscription_ntype_force($ntypeid, $u),
966 # initialization code. do not touch this.
967 my @EVENTS = LJ
::ModuleLoader
->module_subclasses("LJ::Event");
968 foreach my $event (@EVENTS) {
970 confess
"Error loading event module '$event': $@" if $@
;
975 return $u->email_raw;
980 return $LJ::BOGUS_EMAIL
;
983 sub go_through_clusters
{1}
987 sub update_events_counter
{ 0 }