File Coverage

blib/lib/Elive/Entity/User.pm
Criterion Covered Total %
statement 25 49 51.0
branch 2 14 14.2
condition 2 21 9.5
subroutine 7 13 53.8
pod 5 5 100.0
total 41 102 40.2


line stmt bran cond sub pod time code
1             package Elive::Entity::User;
2 8     8   24694 use warnings; use strict;
  8     8   8  
  8         229  
  8         46  
  8         12  
  8         200  
3              
4 8     8   471 use Mouse;
  8         25815  
  8         99  
5 8     8   2334 use Mouse::Util::TypeConstraints;
  8         12  
  8         42  
6              
7             extends 'Elive::Entity';
8              
9 8     8   2719 use Elive::Entity::Role;
  8         15  
  8         228  
10 8     8   41 use Elive::Util;
  8         9  
  8         4481  
11              
12             __PACKAGE__->entity_name('User');
13             __PACKAGE__->collection_name('Users');
14              
15             has 'userId' => (is => 'rw', isa => 'Str', required => 1,
16             documentation => 'user identifier (numeric, unless LDAP configured)');
17             __PACKAGE__->primary_key('userId');
18             __PACKAGE__->params(userName => 'Str');
19              
20             has 'deleted' => (is => 'rw', isa => 'Bool');
21              
22             has 'loginPassword' => (is => 'rw', isa => 'Str');
23              
24             has 'loginName' => (is => 'rw', isa => 'Str',
25             documentation => 'login name - must be unique');
26            
27             has 'email' => (is => 'rw', isa => 'Str',
28             documentation => 'users email address');
29              
30             has 'role' => (is => 'rw', isa => 'Elive::Entity::Role',
31             documentation => 'default user role',
32             coerce => 1);
33              
34             has 'firstName' => (is => 'rw', isa => 'Str',
35             documentation => 'users given name');
36              
37             has 'lastName' => (is => 'rw', isa => 'Str',
38             documentation => 'users surname');
39              
40             #
41             # 'groups' and 'domain' propreties made a brief appearence in Elm 9.5.0
42             # but haven't survived past 9.5.2. Will cull these shortly.
43             #
44              
45             has 'groups' => (is => 'rw', isa => 'Any',
46             documentation => 'groups that this user belongs to?');
47              
48             has 'domain' => (is => 'rw', isa => 'Any',
49             documentation => 'groups that this user belongs to?');
50              
51             sub BUILDARGS {
52 106     106 1 274 my $class = shift;
53 106         90 my $spec = shift;
54              
55 106         85 my %args;
56 106 100 66     400 if (defined $spec && ! ref $spec) {
57 21         42 %args = (userId => $spec);
58             }
59             else {
60 85         278 %args = %$spec;
61             }
62              
63 106         1010 return \%args;
64             }
65              
66             coerce 'Elive::Entity::User' => from 'HashRef|Str'
67             => via {Elive::Entity::User->new($_)};
68              
69             =head1 NAME
70              
71             Elive::Entity::User - Elluminate Users entity class
72              
73             =cut
74              
75             =head1 DESCRIPTION
76              
77             This class is used to query and maintain information on registered Elluminate I users.
78              
79             =cut
80              
81             =head1 METHODS
82              
83             =cut
84              
85             sub _readback_check {
86 0     0     my ($class, $update_ref, $rows, @args) = @_;
87              
88 0           my %updates = %$update_ref;
89              
90             #
91             # password not included in readback record - skip it
92             #
93              
94 0           delete $updates{loginPassword};
95              
96             #
97             # retrieve can accept either a userId or loginName
98             #
99 0 0 0       delete $updates{userId}
      0        
      0        
100             if ($updates{userId} && @$rows
101             && exists $rows->[0]{loginName}
102             && $updates{userId} eq $rows->[0]{loginName});
103              
104 0           return $class->SUPER::_readback_check(\%updates, $rows, @args, case_insensitive => 1);
105             }
106              
107             =head2 get_by_loginName
108              
109             my $user = Elive::Entity::User->get_by_loginName('joebloggs');
110              
111             Retrieve on loginName, which is a co-key for the users table.
112              
113             Please note that the Elluminate Web Services raise an error if the user
114             was not found. So, if you're not sure if the user exists:
115              
116             use Try::Tiny;
117             my $user = try {Elive::Entity::User->get_by_loginName('joebloggs')};
118              
119             =cut
120              
121             sub get_by_loginName {
122 0     0 1   my ($class, $loginName, @args) = @_;
123             #
124             # The entity name is loginName, but the fetch key is userName.
125             #
126 0           my $results = $class->_fetch({userName => $loginName},
127             @args,
128             );
129              
130 0   0       return @$results && $results->[0];
131             }
132              
133             =head2 insert
134              
135             my $new _user = Elive::Entity::User->insert({
136             loginName => ...,
137             loginPassword => ...,
138             firstName => ...,
139             lastName => ...,
140             email => ...,
141             role => ${Elive::Entity::Role::PARTICIPANT},
142             )};
143              
144             Insert a new user
145              
146             =cut
147              
148             sub _safety_check {
149 0     0     my ($self, %opt) = @_;
150              
151 0 0         unless ($opt{force}) {
152              
153 0 0 0       my $connection = $opt{connection} || $self->connection
154             or die "Not connected";
155              
156 0 0         die "Cowardly refusing to update login user"
157             if $self->userId eq $connection->login->userId;
158              
159 0 0         die "Cowardly refusing to update system admin account for ".$self->loginName.": (pass force => 1 to override)"
160             if ($self->_db_data->role->stringify <= ${Elive::Entity::Role::SYSTEM_ADMIN});
161             }
162             }
163              
164             =head2 update
165              
166             my $user_obj = Elive::Entity::user->retrieve($user_id);
167              
168             $user_obj->update(role => ${Elive::Entity::Role::SYSTEM_ADMIN}); # upgrade to an app admin
169             $user_obj->lastName('Smith');
170             $user_obj->update(undef, force => 1);
171              
172             Update an Elluminate user. Everything can be changed, other than userId.
173             This includes the loginName. However loginNames must all remain unique.
174              
175             As a safeguard, you'll need to pass C 1> to update:
176             (a) users with a Role Id of 0, i.e. system administrator accounts, or
177             (b) the login user
178              
179             =cut
180              
181             sub update {
182 0     0 1   my ($self, $data_href, %opt) = @_;
183              
184 0           $self->_safety_check(%opt);
185 0           return $self->SUPER::update( $data_href, %opt);
186             }
187              
188             =head2 change_password
189              
190             Implements the C SDK method.
191              
192             my $user = Elive::Entity::User->retrieve($user_id);
193             $user->change_password($new_password);
194              
195             This is equivalent to:
196              
197             my $user = Elive::Entity::User->retrieve($user_id);
198             $user->update({loginPassword => $new_password});
199              
200             =cut
201              
202             sub change_password {
203 0     0 1   my ($self, $new_password, %opt) = @_;
204              
205 0 0 0       if (defined $new_password && $new_password ne '') {
206 0           $self->_safety_check(%opt);
207 0           $self->SUPER::update({loginPassword => $new_password},
208             command => 'changePassword',
209             %opt,
210             )
211             }
212              
213 0           return $self;
214             }
215              
216             =head2 delete
217              
218             $user_obj->delete();
219             $admin_user_obj->delete(force => 1);
220              
221             Delete user objects. As a safeguard, you need to pass C 1> to delete
222             system administrator accounts, or the login user.
223              
224             Note that a deleted user, will have its deleted property immediately set,
225             but may remain accessible for a short period of time until garbage collected.
226              
227             So to check for a deleted user:
228              
229             my $user = Elive::Entity::User->retrieve( $user_id );
230             my $user_is_deleted = !$user || $user->deleted;
231              
232             =cut
233              
234             sub delete {
235 0     0 1   my ($self, %opt) = @_;
236              
237 0           $self->_safety_check(%opt);
238              
239 0           return $self->SUPER::delete( %opt );
240             }
241              
242             =head1 RESTRICTIONS
243              
244             Elluminate I can be configured to use LDAP for user management and
245             authentication.
246              
247             If LDAP is in use, the fetch and retrieve methods will continue to operate
248             via the Elluminate SOAP command layer. User access becomes read-only.
249             The affected methods are: C, C, C and C.
250              
251             =cut
252              
253             1;