Filename | /var/www/foswikidev/core/lib/Foswiki/Contrib/MailerContrib/Subscriber.pm |
Statements | Executed 311 statements in 1.50ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
56 | 1 | 1 | 212µs | 212µs | new | Foswiki::Contrib::MailerContrib::Subscriber::
62 | 1 | 1 | 157µs | 157µs | subscribe | Foswiki::Contrib::MailerContrib::Subscriber::
1 | 1 | 1 | 16µs | 28µs | BEGIN@17 | Foswiki::Contrib::MailerContrib::Subscriber::
1 | 1 | 1 | 12µs | 16µs | BEGIN@18 | Foswiki::Contrib::MailerContrib::Subscriber::
2 | 1 | 1 | 10µs | 10µs | isSubscribedTo | Foswiki::Contrib::MailerContrib::Subscriber::
1 | 1 | 1 | 10µs | 34µs | BEGIN@19 | Foswiki::Contrib::MailerContrib::Subscriber::
1 | 1 | 1 | 4µs | 4µs | BEGIN@21 | Foswiki::Contrib::MailerContrib::Subscriber::
1 | 1 | 1 | 3µs | 3µs | BEGIN@23 | Foswiki::Contrib::MailerContrib::Subscriber::
1 | 1 | 1 | 3µs | 3µs | BEGIN@22 | Foswiki::Contrib::MailerContrib::Subscriber::
0 | 0 | 0 | 0s | 0s | _subtract | Foswiki::Contrib::MailerContrib::Subscriber::
0 | 0 | 0 | 0s | 0s | getEmailAddresses | Foswiki::Contrib::MailerContrib::Subscriber::
0 | 0 | 0 | 0s | 0s | getEmailAddressesForUser | Foswiki::Contrib::MailerContrib::Subscriber::
0 | 0 | 0 | 0s | 0s | isUnsubscribedFrom | Foswiki::Contrib::MailerContrib::Subscriber::
0 | 0 | 0 | 0s | 0s | optimise | Foswiki::Contrib::MailerContrib::Subscriber::
0 | 0 | 0 | 0s | 0s | stringify | Foswiki::Contrib::MailerContrib::Subscriber::
0 | 0 | 0 | 0s | 0s | unsubscribe | Foswiki::Contrib::MailerContrib::Subscriber::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | # See bottom of file for license and copyright information | ||||
2 | |||||
3 | =begin TML | ||||
4 | |||||
5 | ---+ package Foswiki::Contrib::MailerContrib::Subscriber | ||||
6 | Object that represents a subscriber to notification. A subscriber is | ||||
7 | a name (which may be a wikiName or an email address) and a list of | ||||
8 | subscriptions which describe the topis subscribed to, and | ||||
9 | unsubscriptions representing topics they are specifically not | ||||
10 | interested in. The subscriber | ||||
11 | name may also be a group, so it may expand to many email addresses. | ||||
12 | |||||
13 | =cut | ||||
14 | |||||
15 | package Foswiki::Contrib::MailerContrib::Subscriber; | ||||
16 | |||||
17 | 2 | 27µs | 2 | 40µs | # spent 28µs (16+12) within Foswiki::Contrib::MailerContrib::Subscriber::BEGIN@17 which was called:
# once (16µs+12µs) by Foswiki::Contrib::MailerContrib::WebNotify::BEGIN@22 at line 17 # spent 28µs making 1 call to Foswiki::Contrib::MailerContrib::Subscriber::BEGIN@17
# spent 12µs making 1 call to strict::import |
18 | 2 | 25µs | 2 | 20µs | # spent 16µs (12+4) within Foswiki::Contrib::MailerContrib::Subscriber::BEGIN@18 which was called:
# once (12µs+4µs) by Foswiki::Contrib::MailerContrib::WebNotify::BEGIN@22 at line 18 # spent 16µs making 1 call to Foswiki::Contrib::MailerContrib::Subscriber::BEGIN@18
# spent 4µs making 1 call to warnings::import |
19 | 2 | 25µs | 2 | 59µs | # spent 34µs (10+25) within Foswiki::Contrib::MailerContrib::Subscriber::BEGIN@19 which was called:
# once (10µs+25µs) by Foswiki::Contrib::MailerContrib::WebNotify::BEGIN@22 at line 19 # spent 34µs making 1 call to Foswiki::Contrib::MailerContrib::Subscriber::BEGIN@19
# spent 24µs making 1 call to Exporter::import |
20 | |||||
21 | 2 | 19µs | 1 | 4µs | # spent 4µs within Foswiki::Contrib::MailerContrib::Subscriber::BEGIN@21 which was called:
# once (4µs+0s) by Foswiki::Contrib::MailerContrib::WebNotify::BEGIN@22 at line 21 # spent 4µs making 1 call to Foswiki::Contrib::MailerContrib::Subscriber::BEGIN@21 |
22 | 2 | 19µs | 1 | 3µs | # spent 3µs within Foswiki::Contrib::MailerContrib::Subscriber::BEGIN@22 which was called:
# once (3µs+0s) by Foswiki::Contrib::MailerContrib::WebNotify::BEGIN@22 at line 22 # spent 3µs making 1 call to Foswiki::Contrib::MailerContrib::Subscriber::BEGIN@22 |
23 | 2 | 854µs | 1 | 3µs | # spent 3µs within Foswiki::Contrib::MailerContrib::Subscriber::BEGIN@23 which was called:
# once (3µs+0s) by Foswiki::Contrib::MailerContrib::WebNotify::BEGIN@22 at line 23 # spent 3µs making 1 call to Foswiki::Contrib::MailerContrib::Subscriber::BEGIN@23 |
24 | |||||
25 | =begin TML | ||||
26 | |||||
27 | ---++ ClassMethod new($name) | ||||
28 | * =$name= - Wikiname, with no web, or email address, of user targeted for notification | ||||
29 | Create a new user. | ||||
30 | |||||
31 | =cut | ||||
32 | |||||
33 | # spent 212µs within Foswiki::Contrib::MailerContrib::Subscriber::new which was called 56 times, avg 4µs/call:
# 56 times (212µs+0s) by Foswiki::Contrib::MailerContrib::WebNotify::getSubscriber at line 101 of /var/www/foswikidev/core/lib/Foswiki/Contrib/MailerContrib/WebNotify.pm, avg 4µs/call | ||||
34 | 56 | 29µs | my ( $class, $name ) = @_; | ||
35 | 56 | 123µs | my $this = bless( | ||
36 | { | ||||
37 | name => $name, | ||||
38 | |||||
39 | # emails => [], | ||||
40 | # subscriptions => [], | ||||
41 | # unsubscriptions => [], | ||||
42 | }, | ||||
43 | $class | ||||
44 | ); | ||||
45 | 56 | 141µs | return $this; | ||
46 | } | ||||
47 | |||||
48 | =begin TML | ||||
49 | |||||
50 | ---++ ObjectMethod getEmailAddresses() -> \@list | ||||
51 | Get a list of email addresses for the user(s) represented by this | ||||
52 | subscription | ||||
53 | |||||
54 | =cut | ||||
55 | |||||
56 | sub getEmailAddresses { | ||||
57 | my $this = shift; | ||||
58 | |||||
59 | unless ( defined( $this->{emails} ) ) { | ||||
60 | $this->{emails} = getEmailAddressesForUser( $this->{name} ); | ||||
61 | } | ||||
62 | return $this->{emails}; | ||||
63 | } | ||||
64 | |||||
65 | =begin TML | ||||
66 | |||||
67 | ---++ STATIC getEmailAddressesForUser() -> \@list | ||||
68 | Get a list of email addresses for the user(s) represented by this | ||||
69 | subscription. Static method provided for use by other modules. | ||||
70 | |||||
71 | =cut | ||||
72 | |||||
73 | sub getEmailAddressesForUser { | ||||
74 | my $name = shift; | ||||
75 | my $emails = []; | ||||
76 | |||||
77 | return $emails unless $name; | ||||
78 | |||||
79 | if ( $name =~ /^$Foswiki::cfg{MailerContrib}{EmailFilterIn}$/ ) { | ||||
80 | push( @{$emails}, $name ); | ||||
81 | } | ||||
82 | else { | ||||
83 | my $users = $Foswiki::Plugins::SESSION->{users}; | ||||
84 | if ( $users->can('findUserByWikiName') ) { | ||||
85 | |||||
86 | # User is represented by a wikiname. Map to a canonical | ||||
87 | # userid. | ||||
88 | my $list = $users->findUserByWikiName($name); | ||||
89 | foreach my $user (@$list) { | ||||
90 | |||||
91 | # Automatically expands groups | ||||
92 | push( @{$emails}, $users->getEmails($user) ); | ||||
93 | } | ||||
94 | } | ||||
95 | else { | ||||
96 | |||||
97 | # Old code; use the user object | ||||
98 | my $user = $users->findUser( $name, undef, 1 ); | ||||
99 | if ($user) { | ||||
100 | push( @{$emails}, $user->emails() ); | ||||
101 | } | ||||
102 | else { | ||||
103 | $user = $users->findUser( $name, $name, 1 ); | ||||
104 | if ($user) { | ||||
105 | push( @{$emails}, $user->emails() ); | ||||
106 | } | ||||
107 | else { | ||||
108 | |||||
109 | # unknown - can't find an email | ||||
110 | $emails = []; | ||||
111 | } | ||||
112 | } | ||||
113 | } | ||||
114 | } | ||||
115 | return $emails; | ||||
116 | } | ||||
117 | |||||
118 | =begin TML | ||||
119 | |||||
120 | ---++ ObjectMethod optimise() | ||||
121 | Optimise the lists of subscriptions and unsubscriptions by finding | ||||
122 | overlaps and eliminating them. Intended to be used before writing | ||||
123 | a new WebNotify. | ||||
124 | |||||
125 | =cut | ||||
126 | |||||
127 | # O(N^2) | ||||
128 | # Call before writing. | ||||
129 | sub optimise { | ||||
130 | my $this = shift; | ||||
131 | |||||
132 | foreach my $set ( 'subscriptions', 'unsubscriptions' ) { | ||||
133 | my @new_set = (); | ||||
134 | |||||
135 | NEW: | ||||
136 | foreach my $new ( @{ $this->{$set} } ) { | ||||
137 | |||||
138 | # Don't add already covered duplicates | ||||
139 | my $i = 0; | ||||
140 | my @remove; | ||||
141 | foreach my $known (@new_set) { | ||||
142 | next NEW if $known->covers($new); | ||||
143 | if ( $new->covers($known) ) { | ||||
144 | |||||
145 | # remove anything covered by the new subscription | ||||
146 | unshift( @remove, $i ); | ||||
147 | } | ||||
148 | $i++; | ||||
149 | } | ||||
150 | foreach $i (@remove) { | ||||
151 | splice( @new_set, $i, 1 ); | ||||
152 | } | ||||
153 | push( @new_set, $new ); | ||||
154 | } | ||||
155 | |||||
156 | # TODO: should look at removing redundant exclusions e.g. | ||||
157 | # -SubScribe (2) when there is no positive subscription | ||||
158 | # if there are no subscriptions, there is no point lugging | ||||
159 | # around the unsubs | ||||
160 | $this->{$set} = \@new_set; | ||||
161 | } | ||||
162 | } | ||||
163 | |||||
164 | # Subtract a subscription from an internal list. If the removal expression | ||||
165 | # removes one or more existing expressions by exact matching, then return | ||||
166 | # true otherwise return false. Thus: | ||||
167 | # * removing 'This*' from 'This* ThisThat' will remove 'This*' and | ||||
168 | # 'ThisThat' and return true. | ||||
169 | # * removing '*That' will remove 'ThisThat' and return false. | ||||
170 | # * removing 'T*' will remove 'This*' and 'ThisThat' and return false. | ||||
171 | sub _subtract { | ||||
172 | my ( $this, $set, $dead ) = @_; | ||||
173 | |||||
174 | my $i = 0; | ||||
175 | my @remove; | ||||
176 | my $removed; | ||||
177 | |||||
178 | #print "Subtract ".$dead->stringify()." from ".$this->stringify()."\n"; | ||||
179 | foreach my $known ( @{ $this->{$set} } ) { | ||||
180 | $removed = $known->filterExact( $dead->{topics} ); | ||||
181 | if ( $dead->covers($known) ) { | ||||
182 | |||||
183 | #print "DEAD ".$dead->stringify()." COVERS ".$known->stringify()."\n"; | ||||
184 | # remove anything covered by the dead subscription | ||||
185 | unshift( @remove, $i ); | ||||
186 | } | ||||
187 | $i++; | ||||
188 | } | ||||
189 | foreach $i (@remove) { | ||||
190 | splice( @{ $this->{$set} }, $i, 1 ); | ||||
191 | } | ||||
192 | return $removed; | ||||
193 | } | ||||
194 | |||||
195 | =begin TML | ||||
196 | |||||
197 | ---++ ObjectMethod subscribe($subs) | ||||
198 | * =$subs= - Subscription object | ||||
199 | Add a new subscription to this subscriber object. no optimisation is performed; if | ||||
200 | the subscription is already there, or is covered by another subscription, then it | ||||
201 | will still be added. | ||||
202 | |||||
203 | =cut | ||||
204 | |||||
205 | # spent 157µs within Foswiki::Contrib::MailerContrib::Subscriber::subscribe which was called 62 times, avg 3µs/call:
# 62 times (157µs+0s) by Foswiki::Contrib::MailerContrib::WebNotify::subscribe at line 161 of /var/www/foswikidev/core/lib/Foswiki/Contrib/MailerContrib/WebNotify.pm, avg 3µs/call | ||||
206 | 62 | 34µs | my ( $this, $subs ) = @_; | ||
207 | |||||
208 | 62 | 185µs | push( @{ $this->{subscriptions} }, $subs ); | ||
209 | |||||
210 | #$this->_subtract( 'unsubscriptions', $subs ); disabled for performance reasons | ||||
211 | } | ||||
212 | |||||
213 | =begin TML | ||||
214 | |||||
215 | ---++ ObjectMethod unsubscribe($subs) | ||||
216 | * =$subs= - Subscription object | ||||
217 | Add a new unsubscription to this subscriber object. | ||||
218 | The unsubscription will always be added, even if there is | ||||
219 | a wildcard overlap with an existing subscription or unsubscription. | ||||
220 | |||||
221 | An unsubscription is a statement of the subscribers desire _not_ | ||||
222 | to be notified of changes to this topic. | ||||
223 | |||||
224 | =cut | ||||
225 | |||||
226 | sub unsubscribe { | ||||
227 | my ( $this, $subs ) = @_; | ||||
228 | |||||
229 | # If there was no exact match in the removal, then push a - | ||||
230 | if ( | ||||
231 | !$this->_subtract( 'subscriptions', $subs ) | ||||
232 | |||||
233 | # - * causes evaluation problems. | ||||
234 | && !$subs->matches('*') | ||||
235 | ) | ||||
236 | { | ||||
237 | push( @{ $this->{unsubscriptions} }, $subs ); | ||||
238 | } | ||||
239 | } | ||||
240 | |||||
241 | =begin TML | ||||
242 | |||||
243 | ---++ isSubscribedTo($topic, $db) -> $subscription | ||||
244 | * =$topic= - Topic object we are checking | ||||
245 | * =$db= - Foswiki::Contrib::MailerContrib::UpData database of parents | ||||
246 | Check if we have a subscription to the given topic. Return the subscription | ||||
247 | that matches if we do, undef otherwise. | ||||
248 | |||||
249 | =cut | ||||
250 | |||||
251 | # spent 10µs within Foswiki::Contrib::MailerContrib::Subscriber::isSubscribedTo which was called 2 times, avg 5µs/call:
# 2 times (10µs+0s) by Foswiki::Contrib::MailerContrib::_isSubscribedToTopic at line 168 of /var/www/foswikidev/core/lib/Foswiki/Contrib/MailerContrib.pm, avg 5µs/call | ||||
252 | 2 | 3µs | my ( $this, $topic, $db ) = @_; | ||
253 | |||||
254 | 2 | 4µs | foreach my $subscription ( @{ $this->{subscriptions} } ) { | ||
255 | if ( $subscription->matches( $topic, $db ) ) { | ||||
256 | return $subscription; | ||||
257 | } | ||||
258 | } | ||||
259 | |||||
260 | 2 | 7µs | return; | ||
261 | } | ||||
262 | |||||
263 | =begin TML | ||||
264 | |||||
265 | ---++ ObjectMethod isUnsubscribedFrom($topic) -> $subscription | ||||
266 | * =$topic= - Topic object we are checking | ||||
267 | * =$db= - Foswiki::Contrib::MailerContrib::UpData database of parents | ||||
268 | Check if we have an unsubscription from the given topic. Return the subscription that matches if we do, undef otherwise. | ||||
269 | |||||
270 | =cut | ||||
271 | |||||
272 | sub isUnsubscribedFrom { | ||||
273 | my ( $this, $topic, $db ) = @_; | ||||
274 | |||||
275 | foreach my $subscription ( @{ $this->{unsubscriptions} } ) { | ||||
276 | if ( $subscription->matches( $topic, $db ) ) { | ||||
277 | return $subscription; | ||||
278 | } | ||||
279 | } | ||||
280 | |||||
281 | return; | ||||
282 | } | ||||
283 | |||||
284 | =begin TML | ||||
285 | |||||
286 | ---++ ObjectMethod stringify() -> string | ||||
287 | Return a string representation of this object, in Web<nop>Notify format. | ||||
288 | |||||
289 | =cut | ||||
290 | |||||
291 | sub stringify { | ||||
292 | my $this = shift; | ||||
293 | my $subs = | ||||
294 | join( ' ', map { $_->stringify(); } @{ $this->{subscriptions} } ); | ||||
295 | my $unsubs = | ||||
296 | join( " - ", map { $_->stringify(); } @{ $this->{unsubscriptions} } ); | ||||
297 | $unsubs = " - $unsubs" if $unsubs; | ||||
298 | |||||
299 | my $name = $this->{name}; | ||||
300 | if ( $name =~ /^$Foswiki::regex{wikiWordRegex}$/ ) { | ||||
301 | $name = '%USERSWEB%.' . $name; | ||||
302 | } | ||||
303 | elsif ( $name !~ /^$Foswiki::cfg{MailerContrib}{EmailFilterIn}$/ ) { | ||||
304 | $name = $name =~ /'/ ? '"' . $name . '"' : "'$name'"; | ||||
305 | } | ||||
306 | return " * " . $name . ": " . $subs . $unsubs; | ||||
307 | } | ||||
308 | |||||
309 | 1 | 2µs | 1; | ||
310 | __END__ |