Filename | /var/www/foswiki11/lib/Foswiki/Plugins/ActionTrackerPlugin.pm |
Statements | Executed 54 statements in 3.08ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 678µs | 757µs | BEGIN@33 | Foswiki::Plugins::ActionTrackerPlugin::
13 | 1 | 1 | 214µs | 214µs | commonTagsHandler | Foswiki::Plugins::ActionTrackerPlugin::
1 | 1 | 1 | 53µs | 3.21ms | initPlugin | Foswiki::Plugins::ActionTrackerPlugin::
1 | 1 | 1 | 14µs | 27µs | BEGIN@4 | Foswiki::Plugins::ActionTrackerPlugin::
1 | 1 | 1 | 14µs | 217µs | BEGIN@6 | Foswiki::Plugins::ActionTrackerPlugin::
1 | 1 | 1 | 10µs | 24µs | BEGIN@5 | Foswiki::Plugins::ActionTrackerPlugin::
1 | 1 | 1 | 4µs | 4µs | BEGIN@8 | Foswiki::Plugins::ActionTrackerPlugin::
1 | 1 | 1 | 3µs | 3µs | BEGIN@9 | Foswiki::Plugins::ActionTrackerPlugin::
0 | 0 | 0 | 0s | 0s | __ANON__[:558] | Foswiki::Plugins::ActionTrackerPlugin::
0 | 0 | 0 | 0s | 0s | __ANON__[:563] | Foswiki::Plugins::ActionTrackerPlugin::
0 | 0 | 0 | 0s | 0s | __ANON__[:568] | Foswiki::Plugins::ActionTrackerPlugin::
0 | 0 | 0 | 0s | 0s | _addMissingAttributes | Foswiki::Plugins::ActionTrackerPlugin::
0 | 0 | 0 | 0s | 0s | _beforeActionEdit | Foswiki::Plugins::ActionTrackerPlugin::
0 | 0 | 0 | 0s | 0s | _beforeNormalEdit | Foswiki::Plugins::ActionTrackerPlugin::
0 | 0 | 0 | 0s | 0s | _handleActionNotify | Foswiki::Plugins::ActionTrackerPlugin::
0 | 0 | 0 | 0s | 0s | _handleActionSearch | Foswiki::Plugins::ActionTrackerPlugin::
0 | 0 | 0 | 0s | 0s | _hiddenMeta | Foswiki::Plugins::ActionTrackerPlugin::
0 | 0 | 0 | 0s | 0s | _updateRESTHandler | Foswiki::Plugins::ActionTrackerPlugin::
0 | 0 | 0 | 0s | 0s | _updateSingleAction | Foswiki::Plugins::ActionTrackerPlugin::
0 | 0 | 0 | 0s | 0s | afterEditHandler | Foswiki::Plugins::ActionTrackerPlugin::
0 | 0 | 0 | 0s | 0s | beforeEditHandler | Foswiki::Plugins::ActionTrackerPlugin::
0 | 0 | 0 | 0s | 0s | beforeSaveHandler | Foswiki::Plugins::ActionTrackerPlugin::
0 | 0 | 0 | 0s | 0s | lazyInit | Foswiki::Plugins::ActionTrackerPlugin::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | # See bottom of file for license and copyright information | ||||
2 | package Foswiki::Plugins::ActionTrackerPlugin; | ||||
3 | |||||
4 | 2 | 27µs | 2 | 40µs | # spent 27µs (14+13) within Foswiki::Plugins::ActionTrackerPlugin::BEGIN@4 which was called:
# once (14µs+13µs) by Foswiki::Plugin::BEGIN@2.3 at line 4 # spent 27µs making 1 call to Foswiki::Plugins::ActionTrackerPlugin::BEGIN@4
# spent 13µs making 1 call to strict::import |
5 | 2 | 33µs | 2 | 38µs | # spent 24µs (10+14) within Foswiki::Plugins::ActionTrackerPlugin::BEGIN@5 which was called:
# once (10µs+14µs) by Foswiki::Plugin::BEGIN@2.3 at line 5 # spent 24µs making 1 call to Foswiki::Plugins::ActionTrackerPlugin::BEGIN@5
# spent 14µs making 1 call to Assert::import |
6 | 2 | 36µs | 2 | 420µs | # spent 217µs (14+203) within Foswiki::Plugins::ActionTrackerPlugin::BEGIN@6 which was called:
# once (14µs+203µs) by Foswiki::Plugin::BEGIN@2.3 at line 6 # spent 217µs making 1 call to Foswiki::Plugins::ActionTrackerPlugin::BEGIN@6
# spent 203µs making 1 call to Error::import |
7 | |||||
8 | 2 | 19µs | 1 | 4µs | # spent 4µs within Foswiki::Plugins::ActionTrackerPlugin::BEGIN@8 which was called:
# once (4µs+0s) by Foswiki::Plugin::BEGIN@2.3 at line 8 # spent 4µs making 1 call to Foswiki::Plugins::ActionTrackerPlugin::BEGIN@8 |
9 | 2 | 116µs | 1 | 3µs | # spent 3µs within Foswiki::Plugins::ActionTrackerPlugin::BEGIN@9 which was called:
# once (3µs+0s) by Foswiki::Plugin::BEGIN@2.3 at line 9 # spent 3µs making 1 call to Foswiki::Plugins::ActionTrackerPlugin::BEGIN@9 |
10 | |||||
11 | 1 | 700ns | our $VERSION = '2.4.10'; | ||
12 | 1 | 200ns | our $RELEASE = '2013-02-27'; | ||
13 | 1 | 200ns | our $SHORTDESCRIPTION = | ||
14 | 'Adds support for action tags in topics, and automatic notification of action statuses'; | ||||
15 | 1 | 200ns | our $initialised = 0; | ||
16 | |||||
17 | 1 | 300ns | my $doneHeader = 0; | ||
18 | 1 | 100ns | my $actionNumber = 0; | ||
19 | 1 | 100ns | my $defaultFormat; | ||
20 | |||||
21 | # Map default options | ||||
22 | 1 | 100ns | our $options; | ||
23 | |||||
24 | # spent 3.21ms (53µs+3.16) within Foswiki::Plugins::ActionTrackerPlugin::initPlugin which was called:
# once (53µs+3.16ms) by Foswiki::Plugin::__ANON__[/var/www/foswiki11/lib/Foswiki/Plugin.pm:241] at line 234 of /var/www/foswiki11/lib/Foswiki/Plugin.pm | ||||
25 | |||||
26 | 1 | 700ns | $initialised = 0; | ||
27 | 1 | 400ns | $doneHeader = 0; | ||
28 | |||||
29 | 1 | 6µs | 1 | 2.80ms | Foswiki::Func::registerRESTHandler( 'update', \&_updateRESTHandler ); # spent 2.80ms making 1 call to Foswiki::Func::registerRESTHandler |
30 | |||||
31 | 1 | 6µs | 1 | 76µs | Foswiki::Func::registerTagHandler( 'ACTIONSEARCH', \&_handleActionSearch, # spent 76µs making 1 call to Foswiki::Func::registerTagHandler |
32 | 'context-free' ); | ||||
33 | 2 | 2.60ms | 1 | 757µs | # spent 757µs (678+79) within Foswiki::Plugins::ActionTrackerPlugin::BEGIN@33 which was called:
# once (678µs+79µs) by Foswiki::Plugin::BEGIN@2.3 at line 33 # spent 757µs making 1 call to Foswiki::Plugins::ActionTrackerPlugin::BEGIN@33 |
34 | 1 | 28µs | 1 | 12µs | if ( $@ || !$Foswiki::Contrib::JSCalendarContrib::VERSION ) { # spent 12µs making 1 call to version::(bool |
35 | Foswiki::Func::writeWarning( 'JSCalendarContrib not found ' . $@ ); | ||||
36 | } | ||||
37 | else { | ||||
38 | 1 | 7µs | 1 | 265µs | Foswiki::Contrib::JSCalendarContrib::addHEAD('foswiki'); # spent 265µs making 1 call to Foswiki::Contrib::JSCalendarContrib::addHEAD |
39 | } | ||||
40 | |||||
41 | 1 | 9µs | return 1; | ||
42 | } | ||||
43 | |||||
44 | # spent 214µs within Foswiki::Plugins::ActionTrackerPlugin::commonTagsHandler which was called 13 times, avg 16µs/call:
# 13 times (214µs+0s) by Foswiki::Plugin::invoke at line 294 of /var/www/foswiki11/lib/Foswiki/Plugin.pm, avg 16µs/call | ||||
45 | 13 | 65µs | my ( $otext, $topic, $web, $meta ) = @_; | ||
46 | |||||
47 | 13 | 127µs | return unless ( $_[0] =~ m/%ACTION.*{.*}%/o ); | ||
48 | |||||
49 | return unless lazyInit( $web, $topic ); | ||||
50 | |||||
51 | # Format actions in the topic. | ||||
52 | # Done this way so we get tables built up by | ||||
53 | # collapsing successive actions. | ||||
54 | my $as = | ||||
55 | Foswiki::Plugins::ActionTrackerPlugin::ActionSet::load( $web, $topic, | ||||
56 | $otext, 1 ); | ||||
57 | my $actionGroup; | ||||
58 | my $text = ''; | ||||
59 | |||||
60 | foreach my $entry ( @{ $as->{ACTIONS} } ) { | ||||
61 | if ( ref($entry) ) { | ||||
62 | if ( !$actionGroup ) { | ||||
63 | $actionGroup = | ||||
64 | new Foswiki::Plugins::ActionTrackerPlugin::ActionSet(); | ||||
65 | } | ||||
66 | $actionGroup->add($entry); | ||||
67 | } | ||||
68 | elsif ( $entry =~ /(\S|\n\s*\n)/s ) { | ||||
69 | if ($actionGroup) { | ||||
70 | $text .= $actionGroup->formatAsHTML( $defaultFormat, 'atpDef' ); | ||||
71 | $actionGroup = undef; | ||||
72 | } | ||||
73 | $text .= $entry; | ||||
74 | } | ||||
75 | } | ||||
76 | if ($actionGroup) { | ||||
77 | $text .= $actionGroup->formatAsHTML( $defaultFormat, 'atpDef' ); | ||||
78 | } | ||||
79 | |||||
80 | $_[0] = $text; | ||||
81 | |||||
82 | # COVERAGE OFF debug only | ||||
83 | if ( $options->{DEBUG} ) { | ||||
84 | $_[0] =~ | ||||
85 | s/%ACTIONNOTIFICATIONS{(.*?)}%/_handleActionNotify($web, $1)/geo; | ||||
86 | } | ||||
87 | |||||
88 | # COVERAGE ON | ||||
89 | |||||
90 | } | ||||
91 | |||||
92 | # This handler is called by the edit script just before presenting | ||||
93 | # the edit text in the edit box. | ||||
94 | # We use it to populate the actionform.tmpl template, which is then | ||||
95 | # inserted in the edit.action.tmpl as the %UNENCODED_TEXT%. | ||||
96 | # We process the %META fields from the raw text of the topic and | ||||
97 | # insert them as hidden fields in the form, so the topic is | ||||
98 | # fully populated. | ||||
99 | sub beforeEditHandler { | ||||
100 | |||||
101 | #my( $text, $topic, $web, $meta ) = @_; | ||||
102 | |||||
103 | if ( Foswiki::Func::getSkin() =~ /\baction\b/ ) { | ||||
104 | return _beforeActionEdit(@_); | ||||
105 | } | ||||
106 | else { | ||||
107 | return _beforeNormalEdit(@_); | ||||
108 | } | ||||
109 | } | ||||
110 | |||||
111 | sub _beforeNormalEdit { | ||||
112 | |||||
113 | #my( $text, $topic, $web, $meta ) = @_; | ||||
114 | # Coarse method of testing if modern action syntax is used | ||||
115 | my $oc = scalar( $_[0] =~ m/%ACTION{.*?}%/g ); | ||||
116 | my $cc = scalar( $_[0] =~ m/%ENDACTION%/g ); | ||||
117 | |||||
118 | if ( $cc < $oc ) { | ||||
119 | return unless lazyInit( $_[2], $_[1] ); | ||||
120 | |||||
121 | my $as = | ||||
122 | Foswiki::Plugins::ActionTrackerPlugin::ActionSet::load( $_[2], $_[1], | ||||
123 | $_[0], 1 ); | ||||
124 | $_[0] = $as->stringify(); | ||||
125 | } | ||||
126 | } | ||||
127 | |||||
128 | # Note: a simple return will effectively ignore the action tracker for | ||||
129 | # purposes of this edit. However the skin template will still be expanded, | ||||
130 | # so for clean error handling, make sure $_[0] is set to something. | ||||
131 | sub _beforeActionEdit { | ||||
132 | my ( $text, $topic, $web, $meta ) = @_; | ||||
133 | |||||
134 | return unless lazyInit( $web, $topic ); | ||||
135 | |||||
136 | my $query = Foswiki::Func::getCgiQuery(); | ||||
137 | |||||
138 | my $uid = $query->param('atp_action'); | ||||
139 | unless ( defined $uid ) { | ||||
140 | $_[0] = "Bad URL parameters; atp_action is not set"; | ||||
141 | return; | ||||
142 | } | ||||
143 | |||||
144 | # actionform.tmpl is a sub-template inserted into the parent template | ||||
145 | # as %TEXT%. This is done so we can use the standard template mechanism | ||||
146 | # without screwing up the content of the subtemplate. | ||||
147 | my $tmpl = | ||||
148 | Foswiki::Func::readTemplate( 'actionform', Foswiki::Func::getSkin() ); | ||||
149 | |||||
150 | # Here we want to show the current time in same time format as the user | ||||
151 | # sees elsewhere in his browser on Foswiki. | ||||
152 | my $date = | ||||
153 | Foswiki::Func::formatTime( time(), undef, | ||||
154 | $Foswiki::cfg{DisplayTimeValues} ); | ||||
155 | |||||
156 | die unless ($date); | ||||
157 | |||||
158 | $tmpl =~ s/%DATE%/$date/g; | ||||
159 | my $user = Foswiki::Func::getWikiUserName(); | ||||
160 | $tmpl =~ s/%WIKIUSERNAME%/$user/go; | ||||
161 | $tmpl = Foswiki::Func::expandCommonVariables( $tmpl, $topic, $web ); | ||||
162 | $tmpl = Foswiki::Func::renderText( $tmpl, $web ); | ||||
163 | |||||
164 | # The 'command' parameter is used to signal to the afterEditHandler and | ||||
165 | # the beforeSaveHandler that they have to handle the fields of the | ||||
166 | # edit differently | ||||
167 | my $fields = CGI::hidden( -name => 'closeactioneditor', -value => 1 ); | ||||
168 | $fields .= CGI::hidden( -name => 'cmd', -value => "" ); | ||||
169 | |||||
170 | # write in hidden fields | ||||
171 | if ($meta) { | ||||
172 | $meta->forEachSelectedValue( qr/FIELD/, undef, \&_hiddenMeta, | ||||
173 | { text => \$fields } ); | ||||
174 | } | ||||
175 | |||||
176 | # Find the action. | ||||
177 | my $as = | ||||
178 | Foswiki::Plugins::ActionTrackerPlugin::ActionSet::load( $web, $topic, | ||||
179 | $text, 1 ); | ||||
180 | |||||
181 | my ( $action, $pre, $post ) = $as->splitOnAction($uid); | ||||
182 | |||||
183 | # Make sure the action currently exists | ||||
184 | unless ($action) { | ||||
185 | $_[0] = "Action does not exist - cannot edit"; | ||||
186 | return; | ||||
187 | } | ||||
188 | |||||
189 | # Add revision info to support merging | ||||
190 | my $info = $meta->getRevisionInfo(); | ||||
191 | $fields .= CGI::hidden( | ||||
192 | -name => 'originalrev', | ||||
193 | -value => "$info->{version}_$info->{date}" | ||||
194 | ); | ||||
195 | |||||
196 | $tmpl =~ s/%UID%/$uid/go; | ||||
197 | |||||
198 | $fields .= CGI::hidden( | ||||
199 | -name => 'unlock', | ||||
200 | -value => 'on' | ||||
201 | ); | ||||
202 | |||||
203 | # If an origin - the name or URL of the topic the edit started in - is | ||||
204 | # supplied in the query, then use it to redirect to. | ||||
205 | $fields .= CGI::hidden( | ||||
206 | -name => 'redirectto', | ||||
207 | -value => $query->param('origin') | ||||
208 | ) if $query->param('origin'); | ||||
209 | |||||
210 | # Legacy support for old templates | ||||
211 | $tmpl =~ s/%SUBMITCMDNAME%/Save/g; | ||||
212 | $tmpl =~ s/%SUBMITCOMMAND%/save/g; | ||||
213 | $tmpl =~ s/%SUBMITCMDOPT%//g; | ||||
214 | |||||
215 | my $fmt = new Foswiki::Plugins::ActionTrackerPlugin::Format( | ||||
216 | $options->{EDITHEADER}, | ||||
217 | $options->{EDITFORMAT}, | ||||
218 | $options->{EDITORIENT}, | ||||
219 | "", "" | ||||
220 | ); | ||||
221 | my $editable = $action->formatForEdit($fmt); | ||||
222 | $tmpl =~ s/%EDITFIELDS%/$editable/o; | ||||
223 | |||||
224 | $tmpl =~ s/%EBH%/$options->{EDITBOXHEIGHT}/go; | ||||
225 | $tmpl =~ s/%EBW%/$options->{EDITBOXWIDTH}/go; | ||||
226 | |||||
227 | $text = $action->{text}; | ||||
228 | |||||
229 | # Process the text so it's nice to edit. This gets undone in Action.pm | ||||
230 | # when the action is saved. | ||||
231 | $text =~ s/^\t/ /gos; | ||||
232 | $text =~ s/<br( \/)?>/\n/gios; | ||||
233 | $text =~ s/<p( \/)?>/\n\n/gios; | ||||
234 | |||||
235 | $tmpl =~ s/%TEXT%/$text/go; | ||||
236 | $tmpl =~ s/%HIDDENFIELDS%/$fields/go; | ||||
237 | |||||
238 | $_[0] = $tmpl; | ||||
239 | } | ||||
240 | |||||
241 | sub _hiddenMeta { | ||||
242 | my ( $value, $options ) = @_; | ||||
243 | |||||
244 | my $name = $options->{_key}; | ||||
245 | ${ $options->{text} } .= CGI::hidden( -name => $name, -value => $value ); | ||||
246 | return $value; | ||||
247 | } | ||||
248 | |||||
249 | # This handler is called by the preview script just before | ||||
250 | # presenting the text. | ||||
251 | # The skin name is passed over from the original invocation of | ||||
252 | # edit so if the skin is "action" we know we have been editing | ||||
253 | # an action and have to recombine fields to create the | ||||
254 | # actual text. | ||||
255 | # Metadata is handled by the preview script itself. | ||||
256 | sub afterEditHandler { | ||||
257 | my ( $text, $topic, $web ) = @_; | ||||
258 | |||||
259 | my $query = Foswiki::Func::getCgiQuery(); | ||||
260 | return unless ( $query->param('closeactioneditor') ); | ||||
261 | |||||
262 | return unless lazyInit( $web, $topic ); | ||||
263 | |||||
264 | my ( $ancestorRev, $ancestorDate ) = ( 0, 0 ); | ||||
265 | my $origin = $query->param('originalrev'); | ||||
266 | ASSERT( defined($origin) ) if DEBUG; | ||||
267 | |||||
268 | if ( $origin =~ /^(\d+)_(\d+)$/ ) { | ||||
269 | ( $ancestorRev, $ancestorDate ) = ( $1, $2 ); | ||||
270 | } | ||||
271 | |||||
272 | # Get the most recently saved rev | ||||
273 | ( my $meta, $text ) = Foswiki::Func::readTopic( $web, $topic ); | ||||
274 | my $info = $meta->getRevisionInfo(); | ||||
275 | my $mustMerge = | ||||
276 | ( $ancestorRev ne $info->{version} | ||||
277 | || $ancestorDate && $info->{date} && $ancestorDate ne $info->{date} ); | ||||
278 | |||||
279 | my $latest_as = | ||||
280 | Foswiki::Plugins::ActionTrackerPlugin::ActionSet::load( $web, $topic, | ||||
281 | $text, 1 ); | ||||
282 | |||||
283 | my $uid = $query->param("uid"); | ||||
284 | ASSERT( defined($uid) ) if DEBUG; | ||||
285 | |||||
286 | my $latest_act = | ||||
287 | $latest_as->search( new Foswiki::Attrs( 'uid="' . $uid . '"' ) )->first; | ||||
288 | |||||
289 | my $new_act = | ||||
290 | Foswiki::Plugins::ActionTrackerPlugin::Action::createFromQuery( $_[2], | ||||
291 | $_[1], $latest_act->{ACTION_NUMBER}, $query ); | ||||
292 | |||||
293 | unless ( | ||||
294 | UNIVERSAL::isa( | ||||
295 | $latest_act, 'Foswiki::Plugins::ActionTrackerPlugin::Action' | ||||
296 | ) | ||||
297 | ) | ||||
298 | { | ||||
299 | |||||
300 | # If the edited action was not found in the latest rev, then force it in (it may | ||||
301 | # have been removed in another parallel edit) | ||||
302 | $latest_act = $new_act; | ||||
303 | $latest_as->add($new_act); | ||||
304 | } | ||||
305 | |||||
306 | # See if we can get a common ancestor for merging | ||||
307 | my $old_act; | ||||
308 | if ($mustMerge) { | ||||
309 | |||||
310 | # If we have to merge, we need the ancestor root of the action to | ||||
311 | # do a three-way merge. | ||||
312 | # If the previous revision was generated by a reprev, | ||||
313 | # then the original is lost and we can't 3-way merge | ||||
314 | unless ( $info->{reprev} | ||||
315 | && $info->{version} | ||||
316 | && $info->{reprev} == $info->{version} ) | ||||
317 | { | ||||
318 | |||||
319 | my ( $ances_meta, $ances_text ) = | ||||
320 | Foswiki::Func::readTopic( $web, $topic, $ancestorRev ); | ||||
321 | my $ances = | ||||
322 | Foswiki::Plugins::ActionTrackerPlugin::ActionSet::load( $web, | ||||
323 | $topic, $ances_text, $ancestorRev ); | ||||
324 | $old_act = | ||||
325 | $ances->search( new Foswiki::Attrs( 'uid="' . $uid . '"' ) ) | ||||
326 | ->first; | ||||
327 | } | ||||
328 | } | ||||
329 | |||||
330 | $latest_act->updateFromCopy( $new_act, $mustMerge, $info->{version}, | ||||
331 | $ancestorRev, $old_act ); | ||||
332 | $latest_act->populateMissingFields(); | ||||
333 | $text = $latest_as->stringify(); | ||||
334 | |||||
335 | # take the opportunity to fill in the missing fields in actions | ||||
336 | _addMissingAttributes( $text, $_[1], $_[2] ); | ||||
337 | |||||
338 | $_[0] = $text; | ||||
339 | } | ||||
340 | |||||
341 | # Process the actions and add UIDs and other missing attributes | ||||
342 | sub beforeSaveHandler { | ||||
343 | my ( $text, $topic, $web ) = @_; | ||||
344 | |||||
345 | return unless $text; | ||||
346 | |||||
347 | return unless lazyInit( $web, $topic ); | ||||
348 | |||||
349 | my $query = Foswiki::Func::getCgiQuery(); | ||||
350 | return unless ($query); | ||||
351 | |||||
352 | if ( $query->param('closeactioneditor') ) { | ||||
353 | |||||
354 | # this is a save from the action editor. Text will just be the text of the action - we | ||||
355 | # must recover the rest from the topic on disc. | ||||
356 | |||||
357 | # Strip pre and post metadata from the text | ||||
358 | my $premeta = ""; | ||||
359 | my $postmeta = ""; | ||||
360 | my $inpost = 0; | ||||
361 | my $text = ""; | ||||
362 | foreach my $line ( split( /\r?\n/, $_[0] ) ) { | ||||
363 | if ( $line =~ /^%META:[^{]+{[^}]*}%/ ) { | ||||
364 | if ($inpost) { | ||||
365 | $postmeta .= "$line\n"; | ||||
366 | } | ||||
367 | else { | ||||
368 | $premeta .= "$line\n"; | ||||
369 | } | ||||
370 | } | ||||
371 | else { | ||||
372 | $text .= "$line\n"; | ||||
373 | $inpost = 1; | ||||
374 | } | ||||
375 | } | ||||
376 | |||||
377 | # compose the text | ||||
378 | afterEditHandler( $text, $topic, $web ); | ||||
379 | |||||
380 | # reattach the metadata | ||||
381 | $text .= "\n" unless $text =~ /\n$/s; | ||||
382 | $postmeta = "\n$postmeta" if $postmeta; | ||||
383 | $_[0] = $premeta . $text . $postmeta; | ||||
384 | } | ||||
385 | else { | ||||
386 | |||||
387 | # take the opportunity to fill in the missing fields in actions | ||||
388 | _addMissingAttributes( $_[0], $topic, $web ); | ||||
389 | } | ||||
390 | } | ||||
391 | |||||
392 | # PRIVATE Add missing attributes to all actions that don't have them | ||||
393 | sub _addMissingAttributes { | ||||
394 | |||||
395 | #my ( $text, $topic, $web ) = @_; | ||||
396 | my $text = ""; | ||||
397 | my $descr; | ||||
398 | my $attrs; | ||||
399 | my $gathering; | ||||
400 | my $processAction = 0; | ||||
401 | my $an = 0; | ||||
402 | my %seenUID; | ||||
403 | |||||
404 | my $as = | ||||
405 | Foswiki::Plugins::ActionTrackerPlugin::ActionSet::load( $_[2], $_[1], | ||||
406 | $_[0], 1 ); | ||||
407 | |||||
408 | foreach my $action ( @{ $as->{ACTIONS} } ) { | ||||
409 | next unless ref($action); | ||||
410 | $action->populateMissingFields(); | ||||
411 | if ( $seenUID{ $action->{uid} } ) { | ||||
412 | |||||
413 | # This can happen if there has been a careless | ||||
414 | # cut and paste. In this case, the first instance | ||||
415 | # of the action gets the old UID. This may banjax | ||||
416 | # change notification, but it's better than the | ||||
417 | # alternative! | ||||
418 | $action->{uid} = $action->getNewUID(); | ||||
419 | } | ||||
420 | $seenUID{ $action->{uid} } = 1; | ||||
421 | } | ||||
422 | $_[0] = $as->stringify(); | ||||
423 | } | ||||
424 | |||||
425 | # ========================= | ||||
426 | # Perform filtered search for all actions | ||||
427 | sub _handleActionSearch { | ||||
428 | my ( $session, $attrs, $topic, $web ) = @_; | ||||
429 | |||||
430 | return unless lazyInit( $web, $topic ); | ||||
431 | |||||
432 | # use default format unless overridden | ||||
433 | my $fmt; | ||||
434 | my $fmts = $attrs->remove('format'); | ||||
435 | my $plain = Foswiki::Func::isTrue( $attrs->remove('nohtml') ); | ||||
436 | my $hdrs = $attrs->remove('header'); | ||||
437 | my $foot = $attrs->remove('footer'); | ||||
438 | my $sep = $attrs->remove('separator'); | ||||
439 | my $orient = $attrs->remove('orient'); | ||||
440 | my $sort = $attrs->remove('sort'); | ||||
441 | my $reverse = $attrs->remove('reverse'); | ||||
442 | |||||
443 | $fmts = $defaultFormat->getFields() unless ( defined($fmts) ); | ||||
444 | $hdrs = $defaultFormat->getHeaders() unless ( defined($hdrs) ); | ||||
445 | $orient = $defaultFormat->getOrientation() unless ( defined($orient) ); | ||||
446 | $fmt = | ||||
447 | new Foswiki::Plugins::ActionTrackerPlugin::Format( $hdrs, $fmts, $orient, | ||||
448 | $fmts, '', 1 ); | ||||
449 | |||||
450 | my $actions = | ||||
451 | Foswiki::Plugins::ActionTrackerPlugin::ActionSet::allActionsInWebs( $web, | ||||
452 | $attrs, 0 ); | ||||
453 | $actions->sort( $sort, $reverse ); | ||||
454 | my $result; | ||||
455 | if ($plain) { | ||||
456 | $result = $actions->formatAsString($fmt); | ||||
457 | } | ||||
458 | else { | ||||
459 | $result = $actions->formatAsHTML( $fmt, 'atpSearch' ); | ||||
460 | } | ||||
461 | return $result; | ||||
462 | } | ||||
463 | |||||
464 | # Lazy initialize of plugin 'cause of performance | ||||
465 | sub lazyInit { | ||||
466 | my ( $web, $topic ) = @_; | ||||
467 | |||||
468 | return 1 if $initialised; | ||||
469 | |||||
470 | Foswiki::Plugins::JQueryPlugin::registerPlugin( 'ActionTracker', | ||||
471 | 'Foswiki::Plugins::ActionTrackerPlugin::JQuery' ); | ||||
472 | unless ( | ||||
473 | Foswiki::Plugins::JQueryPlugin::createPlugin( | ||||
474 | 'ActionTracker', $Foswiki::Plugins::SESSION | ||||
475 | ) | ||||
476 | ) | ||||
477 | { | ||||
478 | die 'Failed to register JQuery plugin'; | ||||
479 | } | ||||
480 | |||||
481 | require Foswiki::Attrs; | ||||
482 | require Foswiki::Plugins::ActionTrackerPlugin::Options; | ||||
483 | require Foswiki::Plugins::ActionTrackerPlugin::Action; | ||||
484 | require Foswiki::Plugins::ActionTrackerPlugin::ActionSet; | ||||
485 | require Foswiki::Plugins::ActionTrackerPlugin::Format; | ||||
486 | |||||
487 | $options = Foswiki::Plugins::ActionTrackerPlugin::Options::load(); | ||||
488 | |||||
489 | # Add the ATP CSS (conditionally included from $options, which is why | ||||
490 | # it's not done in the JQuery plugin decl) | ||||
491 | Foswiki::Func::addToZone( "head", "JQUERYPLUGIN::ActionTracker::CSS", | ||||
492 | <<"HERE"); | ||||
493 | <link rel='stylesheet' href='$Foswiki::Plugins::ActionTrackerPlugin::options->{CSS}' type='text/css' media='all' /> | ||||
494 | HERE | ||||
495 | |||||
496 | $defaultFormat = new Foswiki::Plugins::ActionTrackerPlugin::Format( | ||||
497 | $options->{TABLEHEADER}, | ||||
498 | $options->{TABLEFORMAT}, | ||||
499 | $options->{TABLEORIENT}, | ||||
500 | $options->{TEXTFORMAT}, | ||||
501 | $options->{NOTIFYCHANGES}, 0 | ||||
502 | ); | ||||
503 | |||||
504 | if ( $options->{EXTRAS} ) { | ||||
505 | my $e = Foswiki::Plugins::ActionTrackerPlugin::Action::extendTypes( | ||||
506 | $options->{EXTRAS} ); | ||||
507 | |||||
508 | # COVERAGE OFF safety net | ||||
509 | if ( defined($e) ) { | ||||
510 | Foswiki::Func::writeWarning( | ||||
511 | "- Foswiki::Plugins::ActionTrackerPlugin ERROR $e"); | ||||
512 | } | ||||
513 | |||||
514 | # COVERAGE ON | ||||
515 | } | ||||
516 | |||||
517 | $initialised = 1; | ||||
518 | |||||
519 | return 1; | ||||
520 | } | ||||
521 | |||||
522 | # PRIVATE return formatted actions that have changed in all webs | ||||
523 | # Debugging only | ||||
524 | # COVERAGE OFF debug only | ||||
525 | sub _handleActionNotify { | ||||
526 | my ( $web, $expr ) = @_; | ||||
527 | |||||
528 | eval 'require Foswiki::Plugins::ActionTrackerPlugin::ActionNotify'; | ||||
529 | if ($@) { | ||||
530 | Foswiki::Func::writeWarning("ATP: $@"); | ||||
531 | return; | ||||
532 | } | ||||
533 | |||||
534 | my $text = | ||||
535 | Foswiki::Plugins::ActionTrackerPlugin::ActionNotify::doNotifications( | ||||
536 | $web, $expr, 1 ); | ||||
537 | |||||
538 | $text =~ s/<html>/<\/pre>/gios; | ||||
539 | $text =~ s/<\/html>/<pre>/gios; | ||||
540 | $text =~ s/<\/?body>//gios; | ||||
541 | return "<!-- from an --> <pre>$text</pre> <!-- end from an -->"; | ||||
542 | } | ||||
543 | |||||
544 | # COVERAGE ON | ||||
545 | |||||
546 | sub _updateRESTHandler { | ||||
547 | my $session = shift; | ||||
548 | my $query = Foswiki::Func::getCgiQuery(); | ||||
549 | try { | ||||
550 | my $topic = $query->param('topic'); | ||||
551 | my $web; | ||||
552 | ( $web, $topic ) = | ||||
553 | Foswiki::Func::normalizeWebTopicName( undef, $topic ); | ||||
554 | lazyInit( $web, $topic ); | ||||
555 | _updateSingleAction( $web, $topic, $query->param('uid'), | ||||
556 | $query->param('field') => $query->param('value') ); | ||||
557 | print CGI::header( 'text/plain', 200 ); # simple message | ||||
558 | } | ||||
559 | catch Error::Simple with { | ||||
560 | my $e = shift; | ||||
561 | print CGI::header( 'text/plain', 500 ); | ||||
562 | print $e->{-text}; | ||||
563 | } | ||||
564 | catch Foswiki::AccessControlException with { | ||||
565 | my $e = shift; | ||||
566 | print CGI::header( 'text/plain', 500 ); | ||||
567 | print $e->stringify(); | ||||
568 | }; | ||||
569 | return undef; | ||||
570 | } | ||||
571 | |||||
572 | sub _updateSingleAction { | ||||
573 | my ( $web, $topic, $uid, %changes ) = @_; | ||||
574 | |||||
575 | my ( $meta, $text ) = Foswiki::Func::readTopic( $web, $topic ); | ||||
576 | |||||
577 | my $descr; | ||||
578 | my $attrs; | ||||
579 | my $gathering; | ||||
580 | my $processAction = 0; | ||||
581 | my $an = 0; | ||||
582 | my %seenUID; | ||||
583 | |||||
584 | my $as = | ||||
585 | Foswiki::Plugins::ActionTrackerPlugin::ActionSet::load( $web, $topic, | ||||
586 | $text, 1 ); | ||||
587 | |||||
588 | foreach my $action ( @{ $as->{ACTIONS} } ) { | ||||
589 | if ( ref($action) ) { | ||||
590 | if ( $action->{uid} == $uid ) { | ||||
591 | foreach my $key ( keys %changes ) { | ||||
592 | $action->{$key} = $changes{$key}; | ||||
593 | } | ||||
594 | } | ||||
595 | } | ||||
596 | } | ||||
597 | Foswiki::Func::saveTopic( $web, $topic, $meta, $as->stringify(), | ||||
598 | { comment => 'atp save' } ); | ||||
599 | } | ||||
600 | |||||
601 | 1 | 4µs | 1; | ||
602 | __END__ |