| 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; |