File Coverage

blib/lib/Elive/Entity/Participant.pm
Criterion Covered Total %
statement 73 105 69.5
branch 16 54 29.6
condition 5 33 15.1
subroutine 18 20 90.0
pod 4 4 100.0
total 116 216 53.7


line stmt bran cond sub pod time code
1             package Elive::Entity::Participant;
2 5     5   19 use warnings; use strict;
  5     5   6  
  5         195  
  5         24  
  5         21  
  5         129  
3              
4 5     5   41 use Mouse;
  5         5  
  5         23  
5 5     5   1324 use Mouse::Util::TypeConstraints;
  5         5  
  5         26  
6              
7             extends 'Elive::Entity';
8              
9 5     5   408 use Scalar::Util;
  5         7  
  5         231  
10              
11 5     5   979 use Elive;
  5         7  
  5         102  
12 5     5   24 use Elive::Util;
  5         6  
  5         73  
13 5     5   1468 use Elive::Entity::User;
  5         10  
  5         159  
14 5     5   1961 use Elive::Entity::Group;
  5         14  
  5         174  
15 5     5   2020 use Elive::Entity::InvitedGuest;
  5         8  
  5         156  
16 5     5   26 use Elive::Entity::Role;
  5         8  
  5         81  
17 5     5   18 use Try::Tiny;
  5         8  
  5         867  
18              
19             =head1 NAME
20              
21             Elive::Entity::Participant - A Single Meeting Participant
22              
23             =head1 DESCRIPTION
24              
25             This is a component of L. It contains details
26             on a participating user, including their type and participation role.
27              
28             =head1 METHODS
29              
30             =cut
31              
32             __PACKAGE__->entity_name('Participant');
33              
34             has 'user' => (is => 'rw', isa => 'Elive::Entity::User',
35             documentation => 'User (type=0)',
36             coerce => 1,
37             );
38              
39             has 'group' => (is => 'rw', isa => 'Elive::Entity::Group',
40             documentation => 'Group of attendees (type=1)',
41             coerce => 1,
42             );
43             # for the benefit of createSession and updateSession commands
44             __PACKAGE__->_alias(participant => 'user' );
45              
46             has 'guest' => (is => 'rw', isa => 'Elive::Entity::InvitedGuest',
47             documentation => 'Guest (type=2)',
48             coerce => 1,
49             );
50             __PACKAGE__->_alias( invitedGuestId => 'guest' );
51              
52             has 'role' => (is => 'rw', isa => 'Elive::Entity::Role',
53             documentation => 'Role level of the meeting participant',
54             coerce => 1,
55             );
56              
57             has 'type' => (is => 'rw', isa => 'Int',
58             documentation => 'type of participant; 0:user, 1:group, 2:guest'
59             );
60              
61             our ( $TYPE_USER, $TYPE_GROUP, $TYPE_GUEST );
62             BEGIN {
63 5     5   10 $TYPE_USER = 0;
64 5         6 $TYPE_GROUP = 1;
65 5         5101 $TYPE_GUEST = 2;
66             }
67              
68             sub BUILDARGS {
69 212     212 1 348 my $class = shift;
70 212         302 local ($_) = shift;
71              
72 212 100       537 if (Scalar::Util::blessed($_)) {
73              
74 106 50   106   372 if (try {$_->isa('Elive::Entity::User')}) {
  106         2838  
75             #
76             # coerce participant as regular user
77             #
78             return {
79 0         0 user => $_,
80             role => {roleId => ${Elive::Entity::Role::PARTICIPANT}},
81             type => $TYPE_USER,
82             }
83             }
84              
85 106 50   106   1293 if (try {$_->isa('Elive::Entity::Group')}) {
  106         2578  
86             #
87             # coerce to group of participants
88             #
89             return {
90 0         0 group => $_,
91             role => {roleId => ${Elive::Entity::Role::PARTICIPANT}},
92             type => $TYPE_GROUP,
93             }
94             }
95              
96 106 50   106   1119 if (try {$_->isa('Elive::Entity::InvitedGuest')}) {
  106         2423  
97             #
98             # coerce to an invited guest
99             #
100             return {
101 0         0 guest => $_,
102             role => {roleId => ${Elive::Entity::Role::PARTICIPANT}},
103             type => $TYPE_GUEST,
104             }
105             }
106             }
107              
108 212         1300 my $reftype = Elive::Util::_reftype($_);
109 212 100       432 if ($reftype eq 'HASH') {
110             # already structured as a participant
111 153         557 my %spec = %$_;
112              
113 153         144 my $type;
114 153 50       266 if ($spec{user}) {
    0          
    0          
115 153   33     494 $spec{type} ||= $TYPE_USER;
116             }
117             elsif ($spec{group}) {
118 0   0     0 $spec{type} ||= $TYPE_GROUP;
119             }
120             elsif ($spec{guest}) {
121 0   0     0 $spec{type} ||= $TYPE_GUEST;
122             }
123              
124 153 50       591 return \%spec if defined $spec{type};
125             }
126              
127 59 50       106 if ($reftype) {
128 0 0       0 warn YAML::Syck::Dump({unbuildable_participant => $_})
129             if Elive->debug;
130 0         0 die "unable to build participant from $reftype reference";
131             }
132              
133             #
134             # Simple users:
135             # 'bob=3' => user:bob, role:3, type: 0 (user)
136             # 'alice' => user:bob, role:3 (defaulted), type: 0 (user)
137             # A leading '*' indicates a group:
138             # '*mygroup=2' => group:mygroup, role:2 type:1 (group)
139             # Invited guests are of the form: displayName(loginName)
140             # 'Robert(bob)' => guest:{loginName:bob, displayName:Robert}
141             #
142 59         81 my %parse;
143              
144 59 50       438 if (m{^ \s*
    50          
145             ([^;]*?) # display name
146             \s*
147             \( ([^;\)]+) \) # (login name)
148             \s*
149             (= (\d) \s*)? # possible '=role' (ignored)
150             $}x) {
151              
152 0         0 $parse{guest} = {displayName => $1, loginName => $2};
153 0         0 $parse{type} = $TYPE_GUEST;
154              
155 0         0 return \%parse;
156             }
157             elsif (m{^ \s*
158             (\*?) # optional group indicator '*'
159             \s*
160             ([^,]*?) # user/group id
161             \s*
162             (= (\d) \s*)? # optional '=role'
163             $}x) {
164              
165 59         106 my $is_group = $1;
166 59         77 my $id = $2;
167 59         73 my $roleId = $4;
168              
169 59 100 66     145 $roleId = ${Elive::Entity::Role::PARTICIPANT}
170             unless defined $roleId && $roleId ne '';
171              
172 59 50       92 if ( $is_group ) {
173 0         0 $parse{group} = {groupId => $id};
174 0         0 $parse{type} = $TYPE_GROUP;
175             }
176             else {
177 59         197 $parse{user} = {userId => $id};
178 59         97 $parse{type} = $TYPE_USER;
179             }
180              
181 59         99 $parse{role}{roleId} = $roleId;
182              
183 59         354 return \%parse;
184             }
185              
186             #
187             # slightly convoluted die on return to keep Perl::Critic happy
188             #
189 0         0 return die "participant '$_' not in format: userId=[0-3] or *groupId=[0-3] or guestName(guestLogin)";
190             }
191              
192             coerce 'Elive::Entity::Participant' => from 'Str'
193             => via { __PACKAGE__->new( $_) };
194              
195             =head2 participant
196              
197             Returns a participant. This can either be of type L (type
198             0), L (type 1) or L (type 2).
199              
200             =cut
201              
202             sub participant {
203 0     0 1 0 my ($self) = @_;
204            
205 0         0 return (!defined $self->type || $self->type == $TYPE_USER) ? $self->user
206             : ($self->type == $TYPE_GROUP) ? $self->group
207             : ($self->type == $TYPE_GUEST) ? $self->guest
208 0 0 0     0 : do {warn "unknown participant type: ".$self->type;
    0          
    0          
209 0 0 0     0 $self->user || $self->group || $self->guest};
210             }
211              
212             =head2 is_moderator
213              
214             Utility method to examine or set a meeting participant's moderator privileges.
215              
216             # does Bob have moderator privileges?
217             my $is_moderator = $bob->is_moderator;
218              
219             # grant moderator privileges to Alice
220             $alice->is_moderator(1);
221              
222             =cut
223              
224             sub is_moderator {
225 0     0 1 0 my $self = shift;
226              
227 0         0 my $role_id;
228              
229 0 0 0     0 if (defined $self->type && $self->type == $TYPE_GUEST) {
230             #
231             # invited guests cannot be moderators
232 0         0 return;
233             }
234              
235 0 0       0 if (@_) {
236 0         0 my $is_moderator = shift;
237 0 0       0 $role_id = $is_moderator
238             ? ${Elive::Entity::Role::MODERATOR}
239             : ${Elive::Entity::Role::PARTICIPANT};
240              
241 0 0       0 $self->role( $role_id )
242             unless $role_id == $self->role->stringify;
243             }
244             else {
245 0         0 $role_id = $self->role->stringify;
246             }
247              
248 0   0     0 return defined $role_id && $role_id != ${Elive::Entity::Role::PARTICIPANT};
249             }
250              
251             =head2 stringify
252              
253             Returns a string of the form 'userId=role' (users) '*groupId=role (groups),
254             or displayName(loginName) (guests). This value is used for comparisons,
255             display, etc...
256              
257             =cut
258              
259             sub stringify {
260 106     106 1 987 my $self = shift;
261 106   33     206 my $data = shift || $self;
262              
263 106         189 $data = $self->BUILDARGS($data);
264 106         332 my $role_id = Elive::Entity::Role->stringify( $data->{role} );
265              
266 106 50 33     504 if (!defined $data->{type} || $data->{type} == $TYPE_USER) {
    0          
    0          
267             # user => 'userId'
268 106         324 return Elive::Entity::User->stringify($data->{user}).'='.$role_id;
269             }
270             elsif ($data->{type} == $TYPE_GUEST) {
271             # guest => 'displayName(loginName)'
272 0           my $guest_str = Elive::Entity::InvitedGuest->stringify($data->{guest});
273              
274 0 0 0       Carp::carp ("ignoring moderator role for invited guest: $guest_str")
275             if defined $role_id && $role_id != ${Elive::Entity::Role::PARTICIPANT};
276              
277 0           return $guest_str;
278             }
279             elsif ($data->{type} == $TYPE_GROUP) {
280             # group => '*groupId'
281 0           return Elive::Entity::Group->stringify($data->{group}).'='.$role_id;
282             }
283             else {
284             # unknown
285 0           die "unrecognised participant type: $data->{type}";
286             }
287             }
288              
289             =head1 SEE ALSO
290              
291             L
292             L
293             L
294             L
295             L;
296             L
297              
298             =cut
299              
300             1;