File Coverage

blib/lib/Elive/Entity/Meeting.pm
Criterion Covered Total %
statement 16 18 88.8
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 22 24 91.6


line stmt bran cond sub pod time code
1             package Elive::Entity::Meeting;
2 7     7   2492 use warnings; use strict;
  7     7   14  
  7         276  
  7         216  
  7         15  
  7         218  
3              
4 7     7   37 use Mouse;
  7         14  
  7         59  
5 7     7   2458 use Mouse::Util::TypeConstraints;
  7         15  
  7         144  
6              
7             extends 'Elive::Entity';
8              
9 7     7   665 use Elive::Util;
  7         21  
  7         189  
10 7     7   5996 use Elive::Entity::Preload;
  0            
  0            
11             use Elive::Entity::Preloads;
12             use Elive::Entity::Recording;
13             use Elive::Entity::MeetingParameters;
14             use Elive::Entity::ServerParameters;
15             use Elive::Entity::ParticipantList;
16              
17             use YAML::Syck;
18              
19             =head1 NAME
20              
21             Elive::Entity::Meeting - Elluminate Meeting instance class
22              
23             =head1 DESCRIPTION
24              
25             This is the main entity class for meetings.
26              
27             =cut
28              
29             __PACKAGE__->entity_name('Meeting');
30             __PACKAGE__->collection_name('Meetings');
31             __PACKAGE__->params(
32             displayName => 'Str',
33             endDate => 'HiResDate',
34             preloadId => 'Int',
35             recurrenceCount => 'Int',
36             recurrenceDays => 'Int',
37             seats => 'Int',
38             startDate => 'HiResDate',
39             timeZone => 'Str',
40             sessionRole => 'Int',
41             version => 'Str',
42             userId => 'Str',
43             userName => 'Str',
44             );
45              
46             coerce 'Elive::Entity::Meeting' => from 'HashRef'
47             => via {Elive::Entity::Meeting->new($_) };
48              
49             # help out elive_query; expansion of 'select ** from meeting...'
50             __PACKAGE__->derivable(
51             recordings => 'list_recordings',
52             preloads => 'list_preloads',
53             url => 'web_url');
54              
55             has 'meetingId' => (is => 'rw', isa => 'Int', required => 1);
56             __PACKAGE__->primary_key('meetingId');
57              
58             has 'name' => (is => 'rw', isa => 'Str', required => 1,
59             documentation => 'meeting name',
60             );
61              
62             has 'start' => (is => 'rw', isa => 'HiResDate', required => 1,
63             documentation => 'meeting start date and time');
64              
65             has 'end' => (is => 'rw', isa => 'HiResDate', required => 1,
66             documentation => 'meeting end date and time');
67              
68             has 'password' => (is => 'rw', isa => 'Str',
69             documentation => 'meeting password');
70              
71             has 'deleted' => (is => 'rw', isa => 'Bool',
72             documentation => 'whether meeting has been deleted');
73              
74             has 'facilitatorId' => (is => 'rw', isa => 'Str',
75             documentation => 'userId of facilitator');
76             __PACKAGE__->_alias(facilitator => 'facilitatorId', freeze => 1);
77              
78             has 'privateMeeting' => (is => 'rw', isa => 'Bool',
79             documentation => "don't display meeting in public schedule");
80             __PACKAGE__->_alias(private => 'privateMeeting', freeze => 1);
81              
82             has 'allModerators' => (is => 'rw', isa => 'Bool',
83             documentation => "all participants can moderate");
84             __PACKAGE__->_alias(all_moderators => 'allModerators');
85              
86             has 'restrictedMeeting' => (is => 'rw', isa => 'Bool',
87             documentation => "all participants must login");
88             __PACKAGE__->_alias(restricted => 'restrictedMeeting');
89              
90             has 'adapter' => (is => 'rw', isa => 'Str',
91             documentation => 'adapter used to create the meeting/session. E.g.: "default", "standardv2"');
92              
93             =head1 METHODS
94              
95             =cut
96              
97             =head2 insert
98              
99             Note: the C and C methods are depreciated. For alternatives,
100             please see L.
101              
102             my $start = time() + 15 * 60; # starts in 15 minutes
103             my $end = $start + 30 * 60; # runs for half an hour
104              
105             my $meeting = Elive::Entity::Meeting->insert({
106             name => 'Test Meeting',
107             facilitatorId => Elive->login,
108             start => $start . '000',
109             end => $end . '000',
110             password => 'secret!',
111             privateMeeting => 1,
112             restrictedMeeting => 1,
113             seats => 42,
114             });
115              
116             #
117             # Set the meeting participants
118             #
119             my $participant_list = $meeting->participant_list;
120             $participant_list->participants([$smith->userId, $jones->userId]);
121             $participant_list->update;
122              
123             A series of meetings can be created using the C and
124             C parameters.
125              
126             #
127             # create three weekly meetings
128             #
129             my @meetings = Elive::Entity::Meeting->insert({
130             ...,
131             recurrenceCount => 3,
132             recurrenceDays => 7,
133             });
134             =cut
135              
136             =head2 update
137              
138             my $meeting = Elive::Entity::Meeting->update({
139             start => hires-date,
140             end => hires-date,
141             name => string,
142             password => string,
143             seats => int,
144             privateMeeting => 0|1,
145             restrictedMeeting => 0|1,
146             timeZone => string
147             });
148              
149             =cut
150              
151             =head2 delete
152              
153             my $meeting = Elive::Entity::Meeting->retrieve($meeting_id);
154             $meeting->delete
155              
156             Delete the meeting.
157              
158             Note:
159              
160             =over 4
161              
162             =item Meeting recordings are not deleted.
163              
164             If you also want to remove the associated recordings, you'll need to delete
165             them yourself, E.g.:
166              
167             my $recordings = $meeting->list_recordings;
168              
169             foreach my $recording (@$recordings) {
170             $recording->delete;
171             }
172              
173             $meeting->delete;
174              
175             =item Recently deleted meetings may remain retrievable, but with the I property to true.
176              
177             Meetings, Meeting Parameters, Server Parameters and recordings may remain
178             accessible via the SOAP interface for a short period of time until they
179             are garbage collected by ELM.
180              
181             You'll may need to check for deleted meetings:
182              
183             my $meeting = Elive::Entity::Meeting->retrieve($meeting_id);
184             if ($meeting && ! $meeting->deleted) {
185             # ...
186             }
187              
188             or filter them out when listing meetings:
189              
190             my $live_meetings = Elive::Entity::Meeting->list(filter => 'deleted = false');
191              
192             =back
193              
194             =cut
195              
196             sub delete {
197             my $self = shift;
198              
199             $self->SUPER::delete(@_);
200              
201             # update the object as well
202             if (my $db_data = $self->_db_data) {
203             $db_data->{deleted} = 1;
204             }
205              
206             return $self->deleted(1);
207             }
208              
209             =head2 list_user_meetings_by_date
210              
211             Lists all meetings for which this user is a participant, over a given
212             date range.
213              
214             For example, to list all meetings for a particular user over the next week:
215              
216             my $now = DateTime->now;
217             my $next_week = $now->clone->add(days => 7);
218              
219             my $meetings = Elive::Entity::Meeting->list_user_meetings_by_date(
220             {userId => $user_id,
221             startDate => $now->epoch.'000',
222             endDate => $next_week->epoch.'000'}
223             );
224              
225             =cut
226              
227             sub list_user_meetings_by_date {
228             my ($class, $params, %opt) = @_;
229              
230             my %fetch_params;
231             my $reftype = Elive::Util::_reftype($params);
232              
233             if ($reftype eq 'HASH') {
234             %fetch_params = %$params;
235             }
236             elsif ($reftype eq 'ARRAY'
237             && $params->[0] && @$params <= 3) {
238             # older usage
239             @fetch_params{qw{userId startDate endDate}} = @$params;
240             }
241             else {
242             die 'usage: $class->user_meetings_by_date({userId=>$user, startDate=>$start_date, endDate=>$end_date})'
243             }
244              
245             return $class->_fetch($class->_freeze(\%fetch_params),
246             command => 'listUserMeetingsByDate',
247             %opt,
248             );
249             }
250              
251             =head2 add_preload
252              
253             my $preload = Elive::Entity::Preload->upload( 'c:\tmp\intro.wbd');
254             my $meeting = Elive::Entity::Meeting->retrieve($meeting_id);
255             $meeting->add_preload($preload);
256              
257             Associates a preload with the given meeting-Id, or meeting object.
258              
259             =cut
260              
261             sub add_preload {
262             my ($self, $preload_id, %opt) = @_;
263              
264             die 'usage: $meeting_obj->add_preload($preload)'
265             unless $preload_id;
266              
267             my %params = %{ $opt{param} || {} };
268              
269             my $meeting_id = $opt{meeting_id} || $self->meetingId;
270             die "unable to determine meeting_id"
271             unless $meeting_id;
272              
273             $params{meetingId} ||= $meeting_id;
274             $params{preloadId} = $preload_id;
275              
276             my $connection = $self->connection
277             or die "not connected";
278              
279             my $som = $connection->call('addMeetingPreload',
280             %{ $self->_freeze( \%params ) });
281              
282             return $connection->_check_for_errors($som);
283             }
284              
285             =head2 check_preload
286              
287             my $ok = $meeting_obj->check_preload($preload);
288              
289             Checks that the preload is associated with this meeting.
290              
291             =cut
292              
293             sub check_preload {
294             my ($self, $preload_id, %opt) = @_;
295              
296             die 'usage: $meeting_obj->check_preload($preload || $preload_id)'
297             unless $preload_id;
298              
299             my $meeting_id = $opt{meeting_id} || $self->meetingId;
300              
301             die "unable to determine meeting_id"
302             unless $meeting_id;
303              
304             my $connection = $self->connection
305             or die "not connected";
306              
307             my $som = $connection
308             ->call('checkMeetingPreload',
309             %{ $self->_freeze({ preloadId => $preload_id,
310             meetingId => $meeting_id,
311             });
312             }
313             );
314              
315             $connection->_check_for_errors($som);
316              
317             my $results = $self->_unpack_as_list($som->result);
318              
319             return @$results && Elive::Util::_thaw($results->[0], 'Bool');
320             }
321              
322             =head2 is_participant
323              
324             my $ok = $meeting_obj->is_participant($user);
325              
326             Checks that the user is a meeting participant.
327              
328             =cut
329              
330             sub is_participant {
331             my ($self, $user, %opt) = @_;
332              
333             die 'usage: $meeting_obj->is_preload($user || $user_id)'
334             unless $user;
335              
336             my $meeting_id = $opt{meeting_id} || $self->meetingId;
337              
338             die "unable to determine meeting_id"
339             unless $meeting_id;
340              
341             my $connection = $self->connection
342             or die "not connected";
343              
344             my $command = $opt{command} || 'isParticipant';
345              
346             my $som = $connection
347             ->call($command,
348             %{ $self->_freeze({ userId => $user,
349             meetingId => $meeting_id,
350             })
351             }
352             );
353              
354             $connection->_check_for_errors($som);
355              
356             my $results = $self->_unpack_as_list($som->result);
357              
358             return @$results && Elive::Util::_thaw($results->[0], 'Bool');
359             }
360              
361             =head2 is_moderator
362              
363             my $ok = $meeting_obj->is_moderator($user);
364              
365             Checks that the user is a meeting moderator.
366              
367             =cut
368              
369             sub is_moderator {
370             my ($self, $user, %opt) = @_;
371              
372             return $self->is_participant($user, %opt, command => 'isModerator');
373             }
374              
375             sub _readback_check {
376             my ($class, $updates_ref, $rows, @args) = @_;
377             my %updates = %$updates_ref;
378              
379             #
380             # password not included in readback record - skip it
381             #
382             delete $updates{password};
383              
384             #
385             # A series of recurring meetings can potentially be returned.
386             # to do: check for correct sequence of start and end times.
387             # for now, we just check the first meeting.
388             #
389             $rows = [$rows->[0]] if @$rows > 1;
390              
391             return $class->SUPER::_readback_check(\%updates, $rows, @args);
392             }
393              
394             =head2 remove_preload
395              
396             $meeting_obj->remove_preload($preload_obj);
397             $preload_obj->delete; # if you don't want it to hang around
398              
399             Disassociate a preload from a meeting.
400              
401             =cut
402              
403             sub remove_preload {
404             my ($self, $preload_id, %opt) = @_;
405              
406             my $meeting_id = $opt{meeting_id} || $self->meetingId;
407              
408             die 'unable to get a meeting_id'
409             unless $meeting_id;
410              
411             die 'unable to get a preload'
412             unless $preload_id;
413              
414             my $connection = $self->connection
415             or die "not connected";
416              
417             my $som = $connection->call('deleteMeetingPreload',
418             %{ $self->_freeze({ meetingId => $meeting_id,
419             preloadId => $preload_id,
420             })
421             }
422             );
423              
424             return $connection->_check_for_errors($som);
425             }
426            
427             =head2 buildJNLP
428              
429             Builds a JNLP for the meeting.
430              
431             # ...
432             use Elive;
433             use Elive::Entity::Role;
434             use Elive::Entity::Meeting;
435              
436             use CGI;
437             my $cgi = CGI->new;
438              
439             #
440             # authentication, calls to Elive->connect, etc goes here...
441             #
442             my $meeting_id = $cgi->param('meeting_id');
443             my $meeting = Elive::Entity::Meeting->retrieve($meeting_id);
444              
445             my $login_name = $cgi->param('user');
446              
447             my $jnlp = $meeting->buildJNLP(
448             userName => $login_name,
449             sessionRole => ${Elive::Entity::Role::PARTICIPANT},
450             );
451             #
452             # join this user to the meeting
453             #
454              
455             print $cgi->header(-type => 'application/x-java-jnlp-file',
456             -attachment => 'my-meeting.jnlp');
457              
458             print $jnlp;
459              
460             Alternatively, you can pass a user object or user-id via C
461              
462             my $user = Elive::Entity::User->get_by_loginName($login_name);
463              
464             my $jnlp = $meeting->buildJNLP(userId => $user);
465              
466             Or you can just conjure up a display name and role. The user does
467             not have to exist as in the ELM database, or in the meeting's participant list:
468              
469             my $jnlp = $meeting->buildJNLP(
470             displayName => 'Joe Bloggs',
471             sessionRole => ${Elive::Entity::Role::PARTICIPANT}
472             );
473              
474             Guests will by default be given a C of participant (3).
475              
476             JNLP is the 'Java Network Launch Protocol', also commonly known as Java
477             WebStart. To launch the meeting you can, for example, render this as a web
478             page, or send email attachments with mime type C.
479              
480             Under Windows, and other desktops, files are usually saved with extension
481             C<.jnlp>.
482              
483             See also L.
484              
485             =cut
486              
487             sub buildJNLP {
488             my ($self, %opt) = @_;
489              
490             my $connection = $self->connection || $opt{connection}
491             or die "not connected";
492              
493             my $meeting_id = $opt{meeting_id} ||= $self->meetingId;
494              
495             die "unable to determine meeting_id"
496             unless $meeting_id;
497              
498             my %soap_params = (meetingId => $meeting_id);
499              
500             foreach my $param (qw(displayName sessionRole userName userId)) {
501             my $val = delete $opt{$param};
502             $soap_params{$param} = $val
503             if defined $val;
504             }
505              
506             my $user = delete $opt{user};
507              
508             if ($user) {
509             if (ref($user) || $user =~ m{^\d+$}x) {
510             $soap_params{userId} ||= $user;
511             }
512             else {
513             $soap_params{userName} ||= $user;
514             }
515             }
516              
517             $soap_params{userId} ||= $connection->login
518             unless $soap_params{userName} || $soap_params{displayName};
519              
520             my %params_frozen = %{$self->_freeze(\%soap_params)};
521             my $som = $connection->call('buildMeetingJNLP' => %params_frozen);
522              
523             my $results = $self->_get_results($som, $connection);
524              
525             return @$results && $results->[0];
526             }
527              
528             =head2 web_url
529              
530             Utility method to return various website links for the meeting. This is
531             available as both class level and object level methods.
532              
533             #
534             # Class level access.
535             #
536             my $url = Elive::Entity::Meeting->web_url(
537             meeting_id => $meeting_id,
538             action => 'join', # join|edit|...
539             connection => $my_connection); # optional
540              
541             #
542             # Object level.
543             #
544             my $meeting = Elive::Entity::Meeting->retrieve($meeting_id);
545             my $url = meeting->web_url(action => 'join');
546              
547             =cut
548              
549             sub web_url {
550             my ($self, %opt) = @_;
551              
552             my $meeting_id = $opt{meeting_id} || $self->meetingId;
553              
554             die "no meeting_id given"
555             unless $meeting_id;
556              
557             my $connection = $self->connection || $opt{connection}
558             or die "not connected";
559              
560             my $url = $connection->url;
561              
562             my %Actions = (
563             'join' => '%s/join_meeting.html?meetingId=%s',
564             'edit' => '%s/modify_meeting.event?meetingId=%s',
565             'delete' => '%s/delete_meeting?meetingId=%s',
566             );
567              
568             my $action = $opt{action} || 'join';
569              
570             die "unrecognised action: $action"
571             unless exists $Actions{$action};
572              
573             $meeting_id = Elive::Util::_freeze($meeting_id, 'Str');
574              
575             return sprintf($Actions{$action},
576             $url, $meeting_id);
577             }
578              
579             =head2 parameters
580              
581             my $meeting = Elive::Entity::Meeting->retrieve($meeting_id);
582             my $meeting_parameters = $meeting->parameters;
583              
584             Utility method to return the meeting parameters associated with a meeting.
585             See also L.
586              
587             =cut
588              
589             sub parameters {
590             my ($self, @args) = @_;
591              
592             return Elive::Entity::MeetingParameters
593             ->retrieve($self->meetingId,
594             reuse => 1,
595             connection => $self->connection,
596             @args,
597             );
598             }
599              
600             =head2 server_parameters
601              
602             my $meeting = Elive::Entity::Meeting->retrieve($meeting_id);
603             my $server_parameters = $meeting->server_parameters;
604              
605             Utility method to return the server parameters associated with a meeting.
606             See also L.
607              
608             =cut
609              
610             sub server_parameters {
611             my ($self, @args) = @_;
612              
613             return Elive::Entity::ServerParameters
614             ->retrieve($self->meetingId,
615             reuse => 1,
616             connection => $self->connection,
617             @args,
618             );
619             }
620              
621             =head2 participant_list
622              
623             my $meeting = Elive::Entity::Meeting->retrieve($meeting_id);
624             my $participant_list = $meeting->participant_list;
625             my $participants = $participant_list->participants;
626              
627             Utility method to return the participant_list associated with a meeting.
628             See also L.
629              
630             =cut
631              
632             sub participant_list {
633             my ($self, @args) = @_;
634              
635             return Elive::Entity::ParticipantList
636             ->retrieve($self->meetingId,
637             reuse => 1,
638             connection => $self->connection,
639             @args,
640             );
641             }
642              
643             =head2 list_preloads
644              
645             my $preloads = $meeting_obj->list_preloads;
646              
647             Lists all preloads associated with the meeting. See also L.
648              
649             =cut
650              
651             sub list_preloads {
652             my ($self, @args) = @_;
653              
654             return Elive::Entity::Preload
655             ->list_meeting_preloads($self->meetingId,
656             connection => $self->connection,
657             @args);
658             }
659              
660             =head2 list_recordings
661              
662             my $recordings = $meeting_obj->list_recordings;
663              
664             Lists all recordings associated with the meeting. See also
665             L.
666              
667             =cut
668              
669             sub list_recordings {
670             my ($self, @args) = shift;
671              
672             return Elive::Entity::Recording
673             ->list(filter => 'meetingId = '.$self->quote( $self->meetingId ),
674             connection => $self->connection,
675             @args);
676             }
677              
678             =head1 SEE ALSO
679              
680             L
681              
682             L
683              
684             L
685              
686             L
687              
688             L
689              
690             L
691              
692             =cut
693              
694             1;