File Coverage

blib/lib/Ado/Model/Users.pm
Criterion Covered Total %
statement 46 79 58.2
branch 4 16 25.0
condition 9 15 60.0
subroutine 17 21 80.9
pod 13 13 100.0
total 89 144 61.8


line stmt bran cond sub pod time code
1             package Ado::Model::Users; #A table/row class
2 23     23   8326 use 5.010001;
  23         67  
3 23     23   101 use strict;
  23         72  
  23         386  
4 23     23   134 use warnings;
  23         38  
  23         467  
5 23     23   90 use utf8;
  23         193  
  23         114  
6 23     23   547 use parent qw(Ado::Model);
  23         42  
  23         117  
7 23     23   1178 use Carp;
  23         37  
  23         1348  
8 23     23   6397 use Email::Address;
  23         117020  
  23         25816  
9 84     84 1 36846 sub is_base_class { return 0 }
10             my $CLASS = __PACKAGE__;
11             my $TABLE_NAME = 'users';
12              
13 49     49 1 295 sub TABLE { return $TABLE_NAME }
14 0     0 1 0 sub PRIMARY_KEY { return 'id' }
15             my $COLUMNS = [
16             'id', 'group_id', 'login_name', 'login_password',
17             'first_name', 'last_name', 'email', 'description',
18             'created_by', 'changed_by', 'tstamp', 'reg_date',
19             'disabled', 'start_date', 'stop_date'
20             ];
21              
22 26     26 1 653 sub COLUMNS { return $COLUMNS }
23             my $ALIASES = {};
24              
25 195     195 1 3324 sub ALIASES { return $ALIASES }
26             my $CHECKS = {
27             'changed_by' => {'allow' => qr/(?^x:^\d{1,}$)/},
28             'disabled' => {
29             'required' => 1,
30             'defined' => 1,
31             'allow' => qr/(?^x:^\d{1,1}$)/,
32             'default' => '1'
33             },
34             'tstamp' => {
35             'required' => 1,
36             'defined' => 1,
37             'allow' => qr/(?^x:^\d{1,10}$)/
38             },
39             'login_password' => {
40             'required' => 1,
41             'defined' => 1,
42              
43             #result of Mojo::Util::sha1_hex($login_name.$login_password)
44             'allow' => qr/^[A-Fa-f0-9]{40}$/x
45             },
46             'stop_date' => {'allow' => qr/(?^x:^-?\d{1,}$)/},
47             'description' => {
48             'allow' => qr/(?^x:^.{0,255}$)/,
49             'default' => ''
50             },
51             'last_name' => {'allow' => qr/(?^x:^.{1,100}$)/},
52             'email' => {
53             'required' => 1,
54             'defined' => 1,
55             'allow' => $Email::Address::addr_spec
56             },
57             'group_id' => {'allow' => qr/(?^x:^-?\d{1,}$)/},
58             'reg_date' => {
59             'required' => 1,
60             'defined' => 1,
61             'allow' => qr/(?^x:^-?\d{1,}$)/
62             },
63             'start_date' => {
64             'required' => 1,
65             'defined' => 1,
66             'allow' => qr/(?^x:^-?\d{1,}$)/
67             },
68             'id' => {'allow' => qr/(?^x:\d{1,}$)/},
69             'login_name' => {
70             'required' => 1,
71             'defined' => 1,
72             'allow' => qr/(?^x:^.{1,100}$)/
73             },
74             'created_by' => {'allow' => qr/(?^x:^-?\d{1,}$)/},
75             'first_name' => {'allow' => qr/(?^x:^.{1,100}$)/}
76             };
77              
78 7     7 1 30 sub CHECKS { return $CHECKS }
79              
80             __PACKAGE__->QUOTE_IDENTIFIERS(0);
81              
82             #__PACKAGE__->BUILD;#build accessors during load
83              
84             #find and instantiate a user object by email
85             sub by_email {
86 0     0 1 0 state $sql = $_[0]->SQL('SELECT') . ' WHERE email=?';
87 0         0 return $_[0]->query($sql, $_[1]);
88             }
89              
90             #find and instantiate a user object by login_name
91             sub by_login_name {
92 69     69 1 1157 state $sql = $_[0]->SQL('SELECT') . ' WHERE login_name=?';
93 69         527 return $_[0]->query($sql, $_[1]);
94             }
95              
96             sub name {
97 48 50   48 1 204 ref($_[0]) || Carp::croak("The method $_[0]::name must be called only on instances!");
98 48   66     194 return $_[0]->{name} ||= do {
99             Mojo::Util::trim(
100             ($_[0]->{data}{first_name} || '') . ' ' . ($_[0]->{data}{last_name} || ''))
101 47 50 50     482 || $_[0]->{data}{login_name};
      100        
102             };
103             }
104              
105             sub add {
106 0     0 1 0 my $class = shift;
107 0         0 my $args = $class->_get_obj_args(@_);
108 0         0 state $dbix = $class->dbix;
109              
110 0         0 state $GR = 'Ado::Model::Groups'; #shorten class name
111 0         0 my ($group, $user);
112 0         0 my $try = eval {
113 0         0 $dbix->begin_work;
114              
115             #First we need a primary group for the user.
116             $group = $GR->create(
117             name => $args->{login_name},
118             disabled => 0,
119             description => 'Primary group for user ' . $args->{login_name},
120 0   0     0 created_by => $args->{created_by} || 1,
121             );
122              
123             #Let us create the user now...
124             $user = $class->create(
125             first_name => $args->{first_name},
126             last_name => $args->{last_name},
127             login_name => $args->{login_name},
128             login_password => $args->{login_password},
129             email => $args->{email},
130             disabled => $args->{disabled},
131             tstamp => time,
132             reg_date => time,
133             created_by => $args->{created_by},
134             changed_by => $args->{changed_by},
135             stop_date => $args->{stop_date},
136             start_date => $args->{start_date},
137             description => $args->{description},
138 0         0 group_id => $group->id,
139             );
140              
141             #And link them additionally
142 0         0 Ado::Model::UserGroup->create(
143             user_id => $user->id,
144             group_id => $group->id
145             );
146 0         0 $dbix->commit;
147             };
148 0 0       0 unless ($try) {
149 0 0       0 $dbix->rollback or croak($dbix->error);
150 0         0 carp("ERROR adding user(rolling back):[$@]");
151             }
152 0         0 return $user;
153             }
154              
155             #Add an existing user to a potentially not existing group(create the group)
156             sub add_to_group {
157 0     0 1 0 my $self = shift;
158 0         0 my $args = $self->_get_obj_args(@_);
159 0         0 state $dbix = $self->dbix;
160 0         0 state $GR = 'Ado::Model::Groups'; #shorten class name
161 0         0 my $ingroup;
162 0         0 my $try = eval {
163 0         0 $dbix->begin_work;
164              
165             #Create the group if it does not exist yet
166 0 0       0 if (!(($ingroup = $GR->by_name($args->{ingroup}))->id)) {
167             $ingroup = $GR->create(
168             name => $args->{ingroup},
169             disabled => 0,
170             description => 'Additional group initially created for user ' . $self->login_name,
171 0   0     0 created_by => $args->{created_by} || 1,
172             );
173             }
174              
175             #Link them
176             Ado::Model::UserGroup->create(
177 0         0 user_id => $self->id,
178             group_id => $ingroup->id
179             );
180 0         0 $dbix->commit;
181             };
182 0 0       0 unless ($try) {
183 0 0       0 $dbix->rollback or croak($dbix->error);
184 0         0 carp("ERROR adding user to group (rolling back):[$@]");
185             }
186 0         0 return $ingroup;
187             }
188              
189             __PACKAGE__->SQL(SELECT_group_names => <<"SQL");
190             SELECT name FROM groups
191             WHERE id IN (SELECT group_id FROM user_group WHERE user_id=?)
192             SQL
193              
194             sub ingroup {
195 4     4 1 15 my ($self, $group) = @_;
196 4         17 state $sql = __PACKAGE__->SQL('SELECT_group_names');
197 4         52 my @groups = $self->dbix->query($sql, $self->id)->flat;
198 4 100       792 if ($group) {
199 3     3   226 return List::Util::first { $_ eq $group } @groups;
  3         20  
200             }
201 1         79 return @groups;
202             }
203              
204             $CLASS->SQL('user_id_by_group_name' => <<"UG");
205             SELECT user_id FROM user_group WHERE group_id =
206             (SELECT id FROM groups WHERE name = ?)
207             UG
208              
209             $CLASS->SQL('by_group_name' => <<"SQL");
210             SELECT id, login_name, first_name, last_name, email
211             FROM ${\ $CLASS->TABLE }
212             WHERE id IN(${\ $CLASS->SQL('user_id_by_group_name') })
213             AND (disabled=0 AND (stop_date>? OR stop_date=0) AND start_date
214             ORDER BY first_name, last_name ASC
215              
216             SQL
217              
218             #Selects users belonging to a group only.
219             #returns a list of hashes
220             sub by_group_name {
221 2     2 1 238 my ($class, $group, $limit, $offset) = @_;
222              
223 2         9 state $SQL = $class->SQL('by_group_name') . $CLASS->SQL_LIMIT('?', '?');
224 2   100     43 $limit //= 500;
225 2   100     9 $offset //= 0;
226 2         4 my $time = time;
227 2         9 my @a = $class->query($SQL, $group, $time, $time, $limit, $offset);
228 2         632 return map { +{%{$_->data}, name => $_->name} } @a;
  1         73  
  1         4  
229             }
230              
231             1;
232              
233             =pod
234              
235             =encoding utf8
236              
237             =head1 NAME
238              
239             A class for TABLE users in schema main
240              
241             =head1 SYNOPSIS
242              
243              
244             #In a controller use the helper.
245             #Find a user by login_name and change the current user
246             my $user = Ado::Model::Users->by_login_name($login_name);
247             $c->user($user);
248              
249             #in a template
250            

Hello, <%=user->name%>!

251              
252             #Create a new user.
253             my $user = Ado::Model::Users->add(login_name=>'petko'...);
254             #Add the user to a group
255             $user->add_to_group('cool');
256              
257             =head1 DESCRIPTION
258              
259             This class maps to rows in table C.
260              
261             =head1 ATTRIBUTES
262              
263             Ado::Model::Users inherits all attributes from Ado::Model
264             and provides the following.
265              
266             =head2 name
267              
268             Readonly. Returns concatenated L and L of the user
269             or the username (in case the first two are not available).
270              
271             # Hello, Guest
272            

Hello, <%=user->name%>!

273              
274             =head1 COLUMNS
275              
276             Each column from table C has an accessor method in this class.
277              
278             =head2 id
279              
280             =head2 group_id
281              
282             =head2 login_name
283              
284             =head2 login_password
285              
286             =head2 first_name
287              
288             =head2 last_name
289              
290             =head2 email
291              
292             =head2 description
293              
294             =head2 created_by
295              
296             =head2 changed_by
297              
298             =head2 tstamp
299              
300             =head2 reg_date
301              
302             =head2 disabled
303              
304             =head2 start_date
305              
306             =head2 stop_date
307              
308             =head1 ALIASES
309              
310             none
311              
312             =head1 METHODS
313              
314             Ado::Model::Users inherits all methods from Ado::Model and provides the
315             following additional methods:
316              
317             =head2 add
318              
319             Given enough parameters creates a new user object and inserts it into the
320             table C. Creates a primary group for the user with the same group
321             C. Throws an exception if any of the above fails. Returns (the
322             eventually newly created) user object.
323              
324             my $user = Ado::Model::Users->add(
325             login_name => $login_name,
326             login_password => Mojo::Util::sha1_hex($login_name.$login_password)
327             );
328              
329             =head2 add_to_group
330              
331             Adds a user with C to a group.
332             Creates the group if it does not already exists.
333             Returns the group.
334              
335             $ingroup = $user->add_to_group(ingroup=>'admin');
336              
337             =head2 by_email
338              
339             Selects a user by email column.
340              
341             my $user = Ado::Model::Users->by_email('user@example.com');
342             say $user->email if $user->id;
343              
344             =head2 by_group_name
345              
346             Selects active users (C$now OR stop_date=0)
347             AND start_date<$now )>) belonging to a given group only and within a given
348             range, ordered by C alphabetically. C<$limit> defaults
349             to 500 and C<$offset> to 0. Only the following fields are retrieved: C
350             login_name, first_name, last_name, email>.
351              
352             Returns an array of hashes. The L method is executed for each row in
353             the resultset and the evaluation is available via key 'name'.
354              
355             #get contacts of the user 'berov'
356             my @users = Ado::Model::Users->by_group_name('vest_contacts_for_berov', $limit, $offset);
357              
358             =head2 by_login_name
359              
360             Selects a user by login_name column.
361              
362             my $user = Ado::Model::Users->by_login_name('guest');
363             say $user->login_name if $user->id;
364              
365             =head2 ingroup
366              
367             Given a group name returns true if a user is member of the group.
368             Returns false otherwise.
369             Returns a list of all group names a user belongs to if no group name passed.
370              
371             say $user->name . ' is admin!' if $user->ingroup('admin');
372             say $user->name .' is member of the following groups:'
373             . join(', ', $user->ingroup);
374              
375             =head1 GENERATOR
376              
377             L
378              
379             This class contains also custom code.
380              
381             =head1 SEE ALSO
382              
383             L, L,
384             L, L, L
385              
386             =cut