File Coverage

blib/lib/Labyrinth/Plugin/Survey/Act/API.pm
Criterion Covered Total %
statement 15 15 100.0
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 20 20 100.0


line stmt bran cond sub pod time code
1             package Labyrinth::Plugin::Survey::Act::API;
2              
3 2     2   10398 use warnings;
  2         5  
  2         77  
4 2     2   10 use strict;
  2         4  
  2         104  
5 2     2   2132 use utf8;
  2         24  
  2         11  
6              
7 2     2   77 use vars qw($VERSION);
  2         3  
  2         134  
8             $VERSION = '0.06';
9              
10             =head1 NAME
11              
12             Labyrinth::Plugin::Survey::Act::API - YAPC Surveys' Act API plugin for Labyrinth framework
13              
14             =head1 DESCRIPTION
15              
16             Provides all the interfaces to an Act software instance for YAPC Surveys.
17              
18             =cut
19              
20             # -------------------------------------
21             # Library Modules
22              
23 2     2   11 use base qw(Labyrinth::Plugin::Base);
  2         5  
  2         1448  
24              
25             use Labyrinth::Audit;
26             use Labyrinth::DBUtils;
27             use Labyrinth::DTUtils;
28             use Labyrinth::MLUtils;
29             use Labyrinth::Support;
30             use Labyrinth::Users;
31             use Labyrinth::Variables;
32              
33             use Crypt::Lite;
34             use Digest::SHA1 qw(sha1_hex);
35             use HTML::Entities;
36             use JSON;
37             use Time::Local;
38             use WWW::Mechanize;
39              
40             #----------------------------------------------------------
41             # Variables
42              
43             my $crypt = Crypt::Lite->new( debug => 0, encoding => 'hex8' );
44             my $mech = WWW::Mechanize->new();
45             $mech->agent_alias( 'Linux Mozilla' );
46              
47             my %rooms;
48              
49             # -------------------------------------
50             # The Subs
51              
52             =head1 PUBLIC INTERFACE METHODS
53              
54             =over 4
55              
56             =item LoadUsers
57              
58             Builds the API call to retrieve the users, and stores the returned JSON into
59             the database, referencing all the users within Act, who have been recorded as
60             a speaker and/or registered for the conference event.
61              
62             =item LoadTalks
63              
64             Builds he API call to retrieve the talks for the conference event. Parses the
65             returned JSON, filtering the talks based on day, room and type into specific
66             categories and stores within the database.
67              
68             Note that LoadUsers should be called before LoadTalks in order to properly
69             attribute the tutor/speaker for a course or talk to the correct user within
70             the system.
71              
72             =back
73              
74             =cut
75              
76             sub LoadUsers {
77             my (@saved,%names,%users);
78             my $key = $settings{yapc_name};
79             $tvars{counts}{$_} = 0 for(qw(found saved users));
80              
81             # get data
82             my $url = sprintf $settings{actapi_users}, $settings{icode}, $settings{actapi_pass};
83             $mech->get($url);
84             unless($mech->success) {
85             $tvars{errmess} = 'Unable to access Act instance';
86             return;
87             }
88              
89             my $data = from_json($mech->content());
90              
91             for(@{ $settings{othernames} }) {
92             my ($k,$v) = split(':');
93             $names{$k} = $v;
94             }
95              
96             for my $user (@$data) {
97             $user->{full_name} = $names{$user->{full_name}} if($names{$user->{full_name}});
98             my $name = encode_entities($user->{full_name});
99             my $nick = encode_entities($user->{nick_name});
100             $users{$user->{email}} = 1;
101              
102             my @rows;
103             @rows = $dbi->GetQuery('hash','FindUserByAct',$user->{user_id}) if($user->{user_id});
104             @rows = $dbi->GetQuery('hash','FindUser',$user->{email}) unless(@rows);
105              
106             if(@rows) {
107             if(!$rows[0]->{actuserid} || $rows[0]->{actuserid} == 0) {
108             $dbi->DoQuery('UpdateActUser',$user->{user_id},$rows[0]->{userid});
109             }
110              
111             if($rows[0]->{userid} > 2) {
112             my @keys = $dbi->GetQuery('hash','GetUserCode',$rows[0]->{userid});
113             $dbi->DoQuery('ConfirmUser',1,$rows[0]->{userid});
114             #print "FOUND: $name <$user->{email}> => $keys[0]->{code}/$rows[0]->{userid}/$user->{userid}\n";
115             $tvars{counts}{found}++;
116             }
117             next;
118             }
119              
120             my $str = $$ . $user->{email} . time();
121             my $code = sha1_hex($crypt->encrypt($str, $key));
122              
123             $user->{user_id} ||= 0;
124             my $userid = $dbi->IDQuery('NewUser',$user->{email},$nick,$name,$user->{email},$user->{user_id});
125             $dbi->DoQuery('ConfirmUser',1,$userid);
126             $dbi->DoQuery('SaveUserCode',$code,$userid);
127              
128             push @saved, "$name <$user->{email}> => $code/$userid/$user->{user_id}";
129             $tvars{counts}{saved}++
130             }
131              
132             $tvars{data}{saved} = \@saved;
133              
134             my @users = $dbi->GetQuery('hash','AllUsers');
135             $tvars{counts}{users} = scalar(@users);
136             }
137              
138             sub LoadTalks {
139             my (@ignore,@insert,@update);
140             my $yapc = $settings{icode};
141             $tvars{counts}{$_} = 0 for(qw(insert update ignore found totals));
142              
143             for(@{ $settings{act_rooms} }) {
144             my ($k,$v) = split(':');
145             $rooms{$k} = $v;
146             }
147              
148             my ($y,$m,$d) = $settings{talks_start} =~ /^(\d+)\D(\d+)\D(\d+)\D/;
149             $tvars{yapc}{talks_start} = timegm(0,0,0,$d,$m-1,$y);
150             ($y,$m,$d) = $settings{survey_start} =~ /^(\d+)\D(\d+)\D(\d+)\D/;
151             $tvars{yapc}{talks_end} = timegm(23,59,59,$d,$m-1,$y);
152              
153             # get data
154             my $url = sprintf $settings{actapi_talks}, $settings{icode}, $settings{actapi_pass};
155             $mech->get($url);
156             unless($mech->success) {
157             $tvars{errmess} = 'Unable to access Act instance';
158             return;
159             }
160              
161             #my $data = from_json($mech->content(), {utf8 => 1});
162             my $data = from_json($mech->content());
163              
164             #print STDERR "data=".Dumper($data);
165              
166             for my $talk (@$data) {
167             my $title = encode_entities($talk->{title});
168             my $tutor = encode_entities($talk->{speaker});
169             $talk->{room} ||= '';
170             $talk->{datetime} ||= '';
171             my $type = _check_room($talk->{room}, $talk->{datetime});
172              
173             my @rows;
174             @rows = $dbi->GetQuery('hash','FindCourseByAct',$talk->{talk_id}) if($talk->{talk_id});
175             @rows = $dbi->GetQuery('hash','FindCourse',$title,$tutor) unless(@rows);
176              
177             if(@rows) {
178             if(!$rows[0]->{acttalkid} || $rows[0]->{acttalkid} == 0) {
179             $dbi->DoQuery('UpdateActCourse',$talk->{talk_id},$talk->{user_id},$rows[0]->{courseid});
180             }
181              
182             if($rows[0]->{talk} == -1) { # ignore this talk
183             push @ignore, "$rows[0]->{courseid},$title,$tutor,$talk->{room},$talk->{datetime} = $type";
184             $tvars{counts}{ignore}++;
185             next;
186             }
187              
188             if($rows[0]->{talk} == 2) { # preset LT
189             $type = $rows[0]->{talk};
190             $talk->{datetime} = $rows[0]->{datetime};
191             }
192              
193             my $diff = 0;
194             $diff = 1 if(_different($title,$rows[0]->{course}));
195             $diff = 1 if(_different($tutor,$rows[0]->{tutor}));
196             $diff = 1 if(_different($talk->{room},$rows[0]->{room}));
197             $diff = 1 if(_different($talk->{datetime},$rows[0]->{datetime}));
198             $diff = 1 if(_differant($type,$rows[0]->{talk}));
199              
200             if($diff) {
201             $dbi->DoQuery('SaveCourse',$title,$tutor,$talk->{room},$talk->{datetime},$type,$rows[0]->{courseid});
202             push @update, "$rows[0]->{courseid},$title,$tutor,$talk->{room},$talk->{datetime} = $type";
203             push @update, "WAS=$rows[0]->{courseid},$rows[0]->{course},$rows[0]->{tutor},$rows[0]->{room},$rows[0]->{datetime} = $rows[0]->{talk}";
204             push @update, "NOW=$rows[0]->{courseid},$title,$tutor,$talk->{room},$talk->{datetime} = $type";
205             $tvars{counts}{update}++;
206             } else {
207             $tvars{counts}{found}++;
208             }
209             } else {
210             my $id = $dbi->IDQuery('AddCourse',$title,$tutor,$talk->{room},$talk->{datetime},$type);
211             push @insert, "$id,$title,$tutor,$talk->{room},$talk->{datetime} = $type";
212             $tvars{counts}{insert}++;
213             }
214             }
215              
216             $tvars{counts}{totals} += $tvars{counts}{$_} for(qw(insert update ignore found));
217             }
218              
219             #----------------------------------------------------------
220             # Private functions
221              
222             sub _check_room {
223             my $room = shift or return 0;
224             my $time = shift or return 0;
225             my $type = $rooms{$room} ? 1 : 0;
226              
227             push @{$tvars{errors}}, "Undefined room: $room" if(!defined $rooms{$room});
228              
229             my $day = $tvars{yapc}{talks_start};
230             while($day < $tvars{yapc}{talks_end}) {
231             my $start = $day + (60*60*8);
232             my $end = $day + (60*60*18);
233             return 0 if($time < $start);
234             return $type if($time < $end);
235             $day += (60*60*24);
236             }
237              
238             return 0;
239             }
240              
241             sub _different {
242             my ($val1,$val2) = @_;
243              
244             return 1 if( $val1 && !$val2);
245             return 1 if(!$val1 && $val2);
246             return 0 if(!$val1 && !$val2);
247             return 1 if( $val1 ne $val2);
248             return 0;
249             }
250              
251             sub _differant {
252             my ($val1,$val2) = @_;
253              
254             return 1 if( $val1 && !$val2);
255             return 1 if(!$val1 && $val2);
256             return 0 if(!$val1 && !$val2);
257             return 1 if( $val1 != $val2);
258             return 0;
259             }
260              
261             1;
262              
263             __END__