File Coverage

blib/lib/Labyrinth/Plugin/CPAN/Preferences.pm
Criterion Covered Total %
statement 9 9 100.0
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 12 12 100.0


line stmt bran cond sub pod time code
1             package Labyrinth::Plugin::CPAN::Preferences;
2              
3 4     4   47843 use strict;
  4         8  
  4         173  
4 4     4   16 use warnings;
  4         5  
  4         157  
5              
6             our $VERSION = '0.19';
7              
8             =head1 NAME
9              
10             Labyrinth::Plugin::CPAN::Preferences - Handles preferences pages.
11              
12             =cut
13              
14             #----------------------------------------------------------------------------
15             # Libraries
16              
17 4     4   16 use base qw(Labyrinth::Plugin::Base);
  4         4  
  4         1834  
18              
19             use Labyrinth::Audit;
20             use Labyrinth::DTUtils;
21             use Labyrinth::MLUtils;
22             use Labyrinth::Mailer;
23             use Labyrinth::Session;
24             use Labyrinth::Support;
25             use Labyrinth::Variables;
26              
27             use Sort::Versions;
28             use Time::Local;
29              
30             #----------------------------------------------------------------------------
31             # Variables
32              
33             # The following distributions are considered exceptions from the norm and
34             # are to be added on a case by case basis.
35             my $EXCEPTIONS = 'Test.php|Net-ITE.pm|CGI.pm';
36              
37             my %date_fields = (
38             y => { type => 1, html => 1 },
39             m => { type => 1, html => 1 },
40             d => { type => 1, html => 1 },
41             );
42              
43             my (@date_man,@date_all);
44             for(keys %date_fields) {
45             push @date_man, $_ if($date_fields{$_}->{type});
46             push @date_all, $_;
47             }
48              
49             my %pref_fields = (
50             dist => { type => 1, html => 1 },
51             active => { type => 1, html => 0 },
52             ignored => { type => 0, html => 0 },
53             report => { type => 1, html => 0 },
54             grade => { type => 1, html => 0 },
55             tuple => { type => 1, html => 1 },
56             version => { type => 1, html => 0 },
57             versions => { type => 0, html => 0 },
58             patches => { type => 0, html => 0 },
59             perl => { type => 1, html => 0 },
60             perls => { type => 0, html => 0 },
61             platform => { type => 1, html => 0 },
62             platforms => { type => 0, html => 0 },
63             );
64              
65             my (@pref_man,@pref_all);
66             for(keys %pref_fields) {
67             push @pref_man, $_ if($pref_fields{$_}->{type});
68             push @pref_all, $_;
69             }
70              
71             my %months = (
72             1 => 'January',
73             2 => 'February',
74             3 => 'March',
75             4 => 'April',
76             5 => 'May',
77             6 => 'June',
78             7 => 'July',
79             8 => 'August',
80             9 => 'September',
81             10 => 'October',
82             11 => 'November',
83             12 => 'December',
84             );
85              
86             #----------------------------------------------------------------------------
87             # Public Interface Functions
88              
89             =head1 METHODS
90              
91             =head2 Public Interface Methods
92              
93             =over 4
94              
95             =item Login
96              
97             Author Login mechanism. Uses the PAUSE authentication system.
98              
99             =item Logged
100              
101             Ensure correct user is logged in.
102              
103             =item Default
104              
105             Default preferences page.
106              
107             =item Distros
108              
109             Author distributions list page.
110              
111             =item Distro
112              
113             Single distribution preferences page.
114              
115             =item XDropDownMultiList
116              
117             Provide a drop down multi-select list, base on a list of strings.
118              
119             =item XDropDownMultiRows
120              
121             Provide a drop down multi-select list, base on a list of rows.
122              
123             =item DefSave
124              
125             Save default preferences.
126              
127             =item DistSave
128              
129             Save distribution preferences.
130              
131             =item Delete
132              
133             Delete the preferences for a distribution, and use the default preferences.
134              
135             =back
136              
137             =cut
138              
139             sub Login {
140             # if a regular login or no login, use the core login mechanism
141             if(!$cgiparams{pause} || !$cgiparams{eject} || $cgiparams{pause} =~ /\@/) {
142             $cgiparams{cause} = $cgiparams{pause};
143             $cgiparams{effect} = $cgiparams{eject};
144              
145             LogDebug("pause=$cgiparams{pause}, eject=$cgiparams{eject}");
146             LogDebug("cause=$cgiparams{cause}, effect=$cgiparams{effect}");
147              
148             $tvars{errcode} = 'NEXT';
149             $tvars{command} = 'user-logged';
150             return;
151             }
152              
153             use MIME::Base64;
154             use Net::SSLeay qw(get_https make_headers);
155              
156             use LWP::UserAgent;
157             my $result = LWP::UserAgent->new->get("https://pause.perl.org/pause/authenquery",
158             Authorization =>
159             'Basic ' . MIME::Base64::encode("$cgiparams{pause}:$cgiparams{eject}",'')
160             );
161              
162             if($result->code == 200) {
163             my @rows = $dbi->GetQuery('hash','CheckUser','PAUSE','PAUSE');
164              
165             # add entry to session table
166             my $session;
167             ( $session,
168             $tvars{user}{name},
169             $tvars{'loginid'},
170             $tvars{realm},
171             $tvars{langcode}
172             ) = Labyrinth::Session::_save_session(uc $cgiparams{pause},$rows[0]->{userid},$rows[0]->{realm},$rows[0]->{langcode});
173              
174             # set template variables
175             $tvars{'loggedin'} = 1;
176             $tvars{user}{folder} = 1;
177             $tvars{user}{option} = 0;
178             $tvars{user}{userid} = $tvars{'loginid'};
179             $tvars{user}{access} = VerifyUser($tvars{'loginid'});
180             $tvars{realm} ||= 'public';
181              
182             # set login activity
183             $dbi->DoQuery('UpdateAuthorLogin',time(),$tvars{user}{name});
184              
185             } else {
186             $tvars{errmess} = 2;
187             $tvars{errcode} = 'ERROR';
188             }
189             }
190              
191             sub Logged {
192             return unless RealmCheck('author','admin');
193             }
194              
195             sub Default {
196             return unless RealmCheck('author','admin');
197             my $author = $tvars{user}{author} || $tvars{user}{name};
198             my @rows = $dbi->GetQuery('hash','GetAuthorDefault',$author);
199             $tvars{data} = $rows[0] if(@rows);
200              
201             my $cpan = Labyrinth::Plugin::CPAN->new();
202              
203             my @perls = sort {versioncmp($b->{perl},$a->{perl})} $dbi->GetQuery('hash','GetPerlVersions');
204              
205             $cpan->Configure();
206             my $archs = $cpan->osnames();
207             my @archs = map {{oscode => $_, osname => $archs->{$_}}} sort {lc $archs->{$a} cmp lc $archs->{$b}} keys %$archs;
208              
209             $tvars{data}{ddarch} = XDropDownMultiRows($tvars{data}{platform},'platforms','oscode','osname',5,@archs);
210             $tvars{data}{ddperl} = XDropDownMultiRows($tvars{data}{perl},'perls','perl','perl',5,@perls);
211             }
212              
213             sub Distros {
214             return unless RealmCheck('author','admin');
215              
216             my $author = $tvars{user}{author} || $tvars{user}{name};
217              
218             my $cpan = Labyrinth::Plugin::CPAN->new();
219             my @rows = $dbi->GetQuery('array','GetAuthorDists',$author);
220             my @dists = map {$_->[0]} @rows;
221              
222             my @distros = $dbi->GetQuery('hash','GetAuthorDistros',$author);
223             my %distros = map {$_->{distribution} => $_} @distros;
224             for(keys %distros) {
225             $distros{$_}->{name} = $_;
226              
227             $distros{$_}->{grade} =~ s/PASS/P/;
228             $distros{$_}->{grade} =~ s/FAIL/F/;
229             $distros{$_}->{grade} =~ s/UNKNOWN/U/;
230             $distros{$_}->{grade} =~ s/NA/N/;
231             $distros{$_}->{grade} =~ s/,//g;
232              
233             $distros{$_}->{tuple} =~ s/ALL/A/;
234             $distros{$_}->{tuple} =~ s/FIRST/F/;
235              
236             $distros{$_}->{version} =~ s/ALL/A/;
237             $distros{$_}->{version} =~ s/LATEST/L/;
238             $distros{$_}->{version} =~ s/(NOT|INC).*/C/;
239              
240             $distros{$_}->{perl} =~ s/ALL/A/;
241             $distros{$_}->{perl} =~ s/(NOT|INC).*/C/;
242             $distros{$_}->{perl} .= '+P' if($distros{$_}->{perl} eq 'A' && $distros{$_}->{patches});
243              
244             $distros{$_}->{platform} =~ s/ALL/A/;
245             $distros{$_}->{platform} =~ s/(NOT|INC).*/C/;
246             }
247              
248             # check whether any distributions have had their ignore status altered
249             if($cgiparams{enable}) {
250             my $updated = 0;
251             my @check = CGIArray('dists');
252             my %check = @check ? map {$_=>1} @check : ();
253             my @list;
254              
255             # ensure user checked are disabled in the DB
256             for(@check) {
257             next if($distros{$_} && $distros{$_}->{ignored} == 1);
258             $updated = 1;
259             if(defined $distros{$_}) {
260             push @list, "'$_'";
261             $distros{$_}->{ignored} = 2;
262             } else {
263             $dbi->DoQuery('InsertDistroPrefs',1,1,'FAIL','FIRST','LATEST',0,'ALL','ALL',$author,$_);
264             $distros{$_}->{ignored} = 1;
265             }
266             }
267             $dbi->DoQuery('SetAuthorIgnore',{dists => join(',',@list)},2,$author) if(@list);
268              
269             # ensure user unchecked are enabled in the DB
270             @list = ();
271             for(keys %distros) {
272             next if($check{$_});
273             $updated = 1;
274             my @rows = $dbi->GetQuery('hash','GetAuthorDistro',$author,$_);
275             if(@rows) {
276             if($rows[0]->{ignored} == 1 ) {
277             $dbi->DoQuery('DeleteDistroPrefs', $author, $_);
278             delete $distros{$_};
279             } else {
280             push @list, "'$_'";
281             $distros{$_}->{ignored} = 0;
282             }
283             }
284             }
285             $dbi->DoQuery('SetAuthorIgnore',{dists => join(',',@list)},0,$author) if(@list);
286              
287             $tvars{thanks} = 1 if($updated);
288             }
289              
290             @distros = ();
291             my %dists = map {$_ => 1} @dists;
292             for my $dist (sort keys %dists) {
293             next unless($dist =~ /^[A-Za-z0-9][A-Za-z0-9\-_]*$/
294             || $dist =~ /$EXCEPTIONS/);
295             if(defined $distros{$dist}) {
296             if($distros{$dist}->{ignored}) {
297             push @distros, {name => $dist, ignored => $distros{$dist}->{ignored}};
298             } else {
299             push @distros, $distros{$dist}
300             }
301             } else {
302             push @distros, {name => $dist, ignored => 0};
303             }
304             }
305              
306             $tvars{data}{dists} = \@distros;
307             #$tvars{hash}{dists} = \%dists;
308             }
309              
310             sub Distro {
311             return unless RealmCheck('author','admin');
312              
313             my $author = $tvars{user}{author} || $tvars{user}{name};
314             my $dist = $cgiparams{dist};
315             my $version = $cgiparams{version};
316              
317             my @rows = $dbi->GetQuery('hash','GetAuthorDistro',$author,$dist);
318             $tvars{data} = $rows[0] if(@rows);
319             $tvars{data}{dist} = $dist;
320              
321             my $cpan = Labyrinth::Plugin::CPAN->new();
322             my @vers = $dbi->GetQuery('array','GetAuthorDistVersions',$author,$dist);
323             my @versions = sort {versioncmp($b,$a)} map {$_->[0]} @vers;
324             $tvars{data}{ddversions} = XDropDownMultiList($version,'versions',5,@versions);
325              
326             my @perls = sort {versioncmp($b->{perl},$a->{perl})} $dbi->GetQuery('hash','GetPerlVersions');
327              
328             $cpan->Configure();
329             my $archs = $cpan->osnames();
330             my @archs = map {{oscode => $_, osname => $archs->{$_}}} sort {lc $archs->{$a} cmp lc $archs->{$b}} keys %$archs;
331              
332             $tvars{data}{ddarch} = XDropDownMultiRows($tvars{data}{platform},'platforms','oscode','osname',5,@archs);
333             $tvars{data}{ddperl} = XDropDownMultiRows($tvars{data}{perl},'perls','perl','perl',5,@perls);
334              
335             for(qw(version perl platform)) {
336             $tvars{data}{$_} =~ s/,/, /g;
337             $tvars{data}{$_} =~ s/(NOT|INC),/$1:/g;
338             }
339             }
340              
341             sub XDropDownMultiList {
342             my ($opts,$name,$count,@items) = @_;
343             my %opts;
344              
345             if(defined $opts) {
346             if(ref($opts) eq 'ARRAY') {
347             %opts = map {$_ => 1} @$opts;
348             } elsif($opts =~ /,/) {
349             %opts = map {$_ => 1} split(/,/,$opts);
350             } elsif($opts) {
351             %opts = ("$opts" => 1);
352             }
353             }
354              
355             my %hash = ( name => $name );
356             for(@items) {
357             push @{$hash{options}}, { index => $_,
358             value => $_,
359             selected => (defined $opts && $opts{$_} ? 1 : 0)};
360             }
361              
362             return \%hash;
363             }
364              
365             sub XDropDownMultiRows {
366             my ($opts,$name,$index,$value,$count,@items) = @_;
367             my %opts;
368              
369             if(defined $opts) {
370             if(ref($opts) eq 'ARRAY') {
371             %opts = map {$_ => 1} @$opts;
372             } elsif($opts =~ /,/) {
373             %opts = map {$_ => 1} split(/,/,$opts);
374             } elsif($opts) {
375             %opts = ("$opts" => 1);
376             }
377             }
378              
379             my %hash = ( name => $name );
380             for(@items) {
381             push @{$hash{options}}, { index => $_->{$index},
382             value => $_->{$value},
383             selected => (defined $opts && $opts{$_->{$index}} ? 1 : 0)};
384             }
385              
386             return \%hash;
387             }
388              
389              
390             sub DefSave {
391             return unless RealmCheck('author','admin');
392              
393             for(keys %pref_fields) {
394             if($pref_fields{$_}->{html} == 1) { $cgiparams{$_} = CleanHTML($cgiparams{$_}) }
395             elsif($pref_fields{$_}->{html} == 2) { $cgiparams{$_} = CleanTags($cgiparams{$_}) }
396             elsif($pref_fields{$_}->{html} == 3) { $cgiparams{$_} = CleanLink($cgiparams{$_}) }
397             }
398              
399             return if FieldCheck(\@pref_all,\@pref_man);
400              
401             my $author = $tvars{user}{author} || $tvars{user}{name};
402              
403             # change reporting activity
404             $dbi->DoQuery('UpdateAuthorActive',$tvars{data}{active},$author);
405              
406             _save_distprefs($author,'-');
407             }
408              
409             sub DistSave {
410             return unless RealmCheck('author','admin');
411              
412             for(keys %pref_fields) {
413             if($pref_fields{$_}->{html} == 1) { $cgiparams{$_} = CleanHTML($cgiparams{$_}) }
414             elsif($pref_fields{$_}->{html} == 2) { $cgiparams{$_} = CleanTags($cgiparams{$_}) }
415             elsif($pref_fields{$_}->{html} == 3) { $cgiparams{$_} = CleanLink($cgiparams{$_}) }
416             }
417              
418             return if FieldCheck(\@pref_all,\@pref_man);
419              
420             my $author = $tvars{user}{author} || $tvars{user}{name};
421              
422             _save_distprefs($author,$tvars{data}{dist});
423             }
424              
425             sub _save_distprefs {
426             my ($author,$dist) = @_;
427             my @fields;
428              
429             $tvars{data}{patches} = $tvars{data}{patches} ? 1 : 0;
430              
431             # save default settings
432             for(qw(grade versions perls platforms)) {
433             my @array = CGIArray($_);
434             #LogDebug("$_ => @array");
435             $tvars{data}{$_} = join(',',@array);
436             #LogDebug("tvars($_) => $tvars{data}{$_}");
437             }
438             for(qw(version perl platform)) {
439             next if($tvars{data}{$_} eq 'ALL');
440             next if($tvars{data}{$_} eq 'LATEST'); # only applicable to version
441             next unless($tvars{data}{$_ . 's'});
442             $tvars{data}{$_} .= ',' . $tvars{data}{$_ . 's'};
443             }
444             push @fields, $tvars{data}{$_} for(qw(ignored report grade tuple version patches perl platform));
445              
446             my @rows = $dbi->GetQuery('hash','GetAuthorDistro',$author,$dist);
447             if(@rows) { $dbi->DoQuery('UpdateDistroPrefs',@fields, $author, $dist) }
448             else { $dbi->DoQuery('InsertDistroPrefs',@fields, $author, $dist) }
449              
450             $tvars{thanks} = 1;
451             }
452              
453             sub Delete {
454             return unless RealmCheck('author','admin');
455              
456             my $author = $tvars{user}{author} || $tvars{user}{name};
457             my $dist = $cgiparams{dist};
458              
459             my @rows = $dbi->GetQuery('hash','GetAuthorDistro',$author,$dist);
460             $dbi->DoQuery('DeleteDistroPrefs', $author, $dist) if(@rows);
461             }
462              
463             =head2 Admin Interface Methods
464              
465             =over 4
466              
467             =item Admin
468              
469             Prepare Admin login as author.
470              
471             =item Imposter
472              
473             Allow Admin to login as named author.
474              
475             =item Clear
476              
477             Clear imposter status and return to Admin.
478              
479             =back
480              
481             =cut
482              
483             sub Admin {
484             return unless RealmCheck('admin');
485             $tvars{where} = "AND u.realm='author' AND u.userid > 3";
486             }
487              
488             sub Imposter {
489             return unless RealmCheck('admin');
490             UpdateSession('name' => 'imposter:' . $cgiparams{pause});
491             $tvars{user}{author} = $cgiparams{pause};
492             }
493              
494             sub Clear {
495             return unless RealmCheck('admin');
496             UpdateSession('name' => 'Admin');
497             $tvars{user}{name} = 'Admin';
498             delete $tvars{user}{author};
499             }
500              
501             1;
502              
503             __END__