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