source: trunk/LATMOS-Accounts/lib/LATMOS/Accounts/Bases/Sql/User.pm @ 1570

Last change on this file since 1570 was 1570, checked in by nanardon, 8 years ago

Add Remote/ tree for distant quering

  • Property svn:keywords set to Id Rev
File size: 47.1 KB
Line 
1package LATMOS::Accounts::Bases::Sql::User;
2
3use 5.010000;
4use strict;
5use warnings;
6use overload '""' => 'stringify';
7
8use LATMOS::Accounts::Utils;
9use LATMOS::Accounts::Log;
10use POSIX qw(strftime);
11use Date::Parse qw(str2time);
12use DateTime;
13use DateTime::TimeZone;
14use base qw(LATMOS::Accounts::Bases::Sql::objects);
15use LATMOS::Accounts::I18N;
16
17our $VERSION = (q$Rev$ =~ /^Rev: (\d+) /)[0];
18
19=head1 NAME
20
21LATMOS::Ad - Perl extension for blah blah blah
22
23=head1 DESCRIPTION
24
25Account base access over standard unix file format.
26
27=head1 FUNCTIONS
28
29=cut
30
31=head2 new(%config)
32
33Create a new LATMOS::Ad object for windows AD $domain.
34
35domain / server: either the Ad domain or directly the server
36
37ldap_args is an optionnal list of arguments to pass to L<Net::LDAP>.
38
39=cut
40
41sub _object_table { 'user' }
42
43sub _key_field { 'name' }
44
45sub _has_extended_attributes { 1 }
46
47sub stringify {
48    my ($self) = @_;
49
50    return join(' ', grep { $_ }
51        (
52            $self->get_field('givenName'),
53            $self->get_field('sn')
54        )
55    )
56    || $self->get_field('description')
57    || $self->id;
58}
59
60sub _get_attr_schema {
61    my ($class, $base) = @_;
62
63    my $subsetaddress = sub {
64        my ($self, $data) = @_;
65        my $fmainaddress = $self->object->_get_c_field('mainaddress');
66
67        # set address attribute => create address object on the fly
68        # except if attr is empty !
69        if (!$fmainaddress && $data) {
70            $fmainaddress = $self->object->id . '-' . join('', map { ('a'..'z')[rand(26)] }
71                (0..4));
72            $self->base->_create_c_object(
73                'address', $fmainaddress,
74                user => $self->object->id,
75                isMainAddress => 1, ) or do {
76                $self->base->log(LA_ERR,
77                    "Cannot create main address for user %s", $self->object->id);
78                return;
79            };
80        }
81        if ($fmainaddress && 
82            (my $address = $self->base->get_object('address', $fmainaddress))) {
83            if ($address->attribute($self->name) &&
84                !$address->attribute($self->name)->ro) {
85                return $address->set_c_fields($self->name => $data) ||0;
86            }
87        }
88    };
89
90    my $attrs = {
91            exported => {
92                post => sub {
93                    my ($self, $value) = @_;
94                    my $attr = $self->name;
95
96                    if (my $obj = $self->base->
97                            get_object('revaliases', $self->object->id)) {
98                        my $ares = $obj->set_c_fields(
99                            ($attr eq 'exported' ? 'exported' : 'unexported') => $value
100                        );
101                        if (!defined($ares)) {
102                            $self->base->log(LA_ERR,
103                                'Cannot set revaliases exported attribute for user %s',
104                                $self->object->id);
105                        }
106                    }
107                    my $must_expire = $self->name eq 'exported'
108                        ? ($value ? 0 : 1 )
109                        : ($value ? 1 : 0 );
110
111                    foreach my $al (grep { $_ } $self->object->get_attributes('aliases'), $self->object->id) {
112                        my $obj = $self->base->get_object('aliases', $al) or next;
113                        $obj->_set_c_fields(
114                            exported => $value,
115                        );
116                    }
117                    foreach my $al ($self->object->get_attributes('otheraddress')) {
118                        my $obj = $self->base->get_object('address', $al) or next;
119                        $obj->_set_c_fields(
120                            exported => $value,
121                        );
122                    }
123                },
124            },
125            uidNumber => {
126                inline => 1,
127                iname => 'uidnumber',
128                uniq => 1,
129                mandatory => 1,
130                formopts => { length => 7 },
131                label => l('UID'),
132            },
133            uidnumber => { inline => 1, hide => 1, monitored => 1 },
134            gidNumber => {
135                inline => 1,
136                iname => 'gidnumber',
137                mandatory => 1,
138                can_values => sub {
139                    map { $_->id, $_->get_attributes('gidNumber') }
140                    map { $base->get_object('group', $_) }
141                    $base->list_objects('group')
142                },
143                can_values => sub {
144                    my $sth = $base->db->prepare_cached(
145                        q{
146                        select name, gidnumber from "group" where exported = true
147                        }
148                    );
149                    $sth->execute();
150                    my @res;
151                    while (my $res = $sth->fetchrow_hashref) {
152                        push(@res, $res->{name});
153                        push(@res, $res->{gidnumber});
154                    }
155                    return @res;
156                },
157                display => sub {
158                    my ($self, $val) = @_;
159                    my ($gr) = $self->base->search_objects('group', "gidNumber=$val")
160                        or return;
161                    return $gr;
162                },
163                input => sub {
164                    my ($val) = @_;
165                    $val =~ /^\d+$/ and return $val;
166                    my ($gr) = $base->search_objects('group', "name=$val") or return;
167                    return $base->get_object('group', $gr)->get_attributes('gidNumber');
168                },
169                reference => 'group',
170                label => l('GID'),
171            },
172            loginShell => {
173                mandatory => 1,
174                label => l('Shell'),
175            },
176            gidnumber => { inline => 1, hide => 1,
177                can_values => sub {
178                    map { $_->id, $_->get_attributes('gidNumber') }
179                    map { $base->get_object('group', $_) }
180                    $base->list_objects('group')
181                },
182                display => sub {
183                    my ($self, $val) = @_;
184                    my ($gr) = $self->base->search_objects('group', "gidNumber=$val")
185                        or return;
186                    return $gr;
187                },
188                input => sub {
189                    my ($val) = @_;
190                    $val =~ /^\d+$/ and return $val;
191                    my ($gr) = $base->search_objects('group', "name=$val") or return;
192                    return $base->get_object('group', $gr)->get_attributes('gidNumber');
193                },
194                mandatory => 1,
195                reference => 'group',
196                monitored => 1,
197            },
198            locked    => {
199                formtype => 'CHECKBOX',
200                formopts => { rawvalue => 1, },
201                monitored => 1,
202                label => l('Locked'),
203            },
204            expire        => {
205                inline => 1,
206                formtype => 'DATETIME',
207                monitored => 1,
208                label => l('Expire'),
209            },
210            endcircuit    => {
211                inline => 1,
212                formtype => 'DATE',
213                monitored => 1,
214                label => l('End of entrance'),
215            },
216            _endEmployment => {
217                formtype => 'DATETIME',
218                managed => 1,
219                ro => 1,
220                hide => 1,
221                get => sub {
222                    my ($attr) = @_;
223                    my $self = $attr->object;
224                    $self->_computeEndEmployment($self->base->config('employment_delay'));
225                },
226                label => l('End of employment'),
227            },
228            endEmployment => {
229                formtype => 'DATETIME',
230                ro => 1,
231                label => l('End of employment'),
232            },
233            _endStrictEmployment => {
234                formtype => 'DATETIME',
235                managed => 1,
236                ro => 1,
237                hide => 1,
238                get => sub {
239                    my ($attr) = @_;
240                    my $self = $attr->object;
241                    $self->_computeEndEmployment();
242                },
243            },
244            endStrictEmployment => {
245                formtype => 'DATETIME',
246                ro => 1,
247            },
248            _endCurrentEmployment => {
249                formtype => 'DATETIME',
250                managed => 1,
251                ro => 1,
252                hide => 1,
253                get => sub {
254                    my ($attr) = @_;
255                    my $self = $attr->object;
256
257                    my $list_empl = $self->base->db->prepare_cached(q{
258                        SELECT * FROM employment WHERE "user" = ? and
259                            firstday <= now() and
260                            (lastday is null or lastday >= now() - '1 days'::interval)
261                            order by firstday asc
262                    });
263                    $list_empl->execute($self->id);
264                    my $end;
265                    while (my $res = $list_empl->fetchrow_hashref) {
266                        if (!$res->{lastday}) {
267                            # Ultimate employment.
268                            $list_empl->finish;
269                            return undef;
270                        } else {
271                            $end = DateTime->from_epoch(epoch => str2time($res->{lastday}));
272                            $end->set_time_zone( DateTime::TimeZone->new( name => 'local' ) );
273                            $end->add(hours => 23, minutes => 59, seconds => 59);
274                        }
275                        last;
276                    }
277                    $list_empl->finish;
278
279                    return $end ? $end->iso8601 : undef
280                },
281            },
282            endCurrentEmployment => {
283                formtype => 'DATETIME',
284                ro => 1,
285            },
286            _endLastEmployment => {
287                formtype => 'DATETIME',
288                managed => 1,
289                ro => 1,
290                hide => 1,
291                get => sub {
292                    my ($attr) = @_;
293                    my $self = $attr->object;
294
295                    my $list_empl = $self->base->db->prepare_cached(q{
296                        SELECT * FROM employment WHERE "user" = ?
297                        order by lastday desc nulls first
298                    });
299                    $list_empl->execute($self->id);
300                    my $res = $list_empl->fetchrow_hashref;
301                    $list_empl->finish;
302                    my $end;
303                    if ($res && $res->{lastday}) {
304                        $end = DateTime->from_epoch(epoch => str2time($res->{lastday}));
305                        $end->set_time_zone( DateTime::TimeZone->new( name => 'local' ) );
306                        $end->add(hours => 23, minutes => 59, seconds => 59);
307                    }
308                    return $end ? $end->iso8601 : undef
309                },
310                label => l('End of any employment'),
311            },
312            endLastEmployment => {
313                formtype => 'DATETIME',
314                ro => 1,
315                label => l('End of any employment'),
316            },
317            cn        => {
318                inline => 1, ro => 1,
319                get => sub {
320                    my ($self) = @_;
321                    return join(' ', grep { $_ } 
322                        (
323                            $self->object->_get_c_field('givenName'),
324                            $self->object->_get_c_field('sn')
325                        )
326                    )
327                    || $self->object->_get_c_field('description')
328                    || $self->object->id;
329                },
330            },
331            memberOf  => {
332                reference => 'group',
333                multiple => 1, delayed => 1,
334                get => sub {
335                    my ($self) = @_;
336                    my $obj = $self->object;
337                    my $sth = $obj->db->prepare_cached(
338                        q{
339                        select name from "group" join
340                        group_attributes on group_attributes.okey = "group".ikey
341                        where value = ? and attr = ?
342                        } . ($self->base->{wexported} ? '' : ' and "group".exported = true')
343                    );
344                    $sth->execute($obj->id, 'memberUID');
345                    my @res;
346                    while (my $res = $sth->fetchrow_hashref) {
347                        push(@res, $res->{name});
348                    }
349                    return \@res;
350                },
351                set => sub {
352                    my ($self, $values) = @_;
353                    my %old = map { $_ => 'o' } @{ $self->get };
354                    foreach my $group (grep { $_ } ref $values ? @{ $values } : $values) {
355                        if ($old{$group}) {
356                            $old{$group} = undef; # no change
357                        } else {
358                            $old{$group} = 'n';
359                        }
360                    }
361
362                    my $res = 0;
363                    foreach my $group (keys %old) {
364                        $old{$group} or next; # no change
365
366                        my $ogroup = $self->base->get_object('group', $group) or next;
367                        ($ogroup->_get_c_field('sutype') || '') =~ /^(jobtype|contrattype)$/ and next;
368
369                        if ($old{$group} eq 'n') {
370                            $res += $ogroup->_addAttributeValue('memberUID', $self->object->id);
371                        } else {
372                            if (($self->object->_get_c_field('department') || '') eq $ogroup->id) {
373                                $self->base->log(LA_WARN,
374                                    "Don't removing user %s from group %s: is its department",
375                                    $self->object->id, $ogroup->id);
376                                next;
377                            }
378                            $res += $ogroup->_delAttributeValue('memberUID', $self->object->id);
379                        }
380                    }
381                    return $res;
382                },
383                label => l('Member of'),
384            },
385            forward => {
386                managed => 1,
387                get => sub {
388                    my ($self) = @_;
389                    my $sth = $self->base->db->prepare(q{
390                        select forward from aliases where name = ?
391                        } . ($self->base->{wexported} ? '' : ' and exported = true'));
392                    $sth->execute($self->object->id);
393                    my $res = $sth->fetchrow_hashref;
394                    $sth->finish;
395                    return $res->{forward}
396                },
397                set => sub {
398                    my ($self, $data) = @_;
399                    if ($data) {
400                        if (my $f = $self->base->get_object('aliases', $self->object->id)) {
401                            return $f->_set_c_fields(forward => $data);
402                        } else {
403                            if ($self->base->_create_c_object(
404                                    'aliases', $self->object->id,
405                                    forward => $data,
406                                    description => 'automatically created for ' . $self->object->id,
407                                )) {
408                                return 1;
409                            } else {
410                                $self->base->log(LA_ERR, "Cannot add forward for %s",
411                                    $self->object->id);
412                            }
413                        }
414                    } else {
415                        if (my $res = $self->base->_delete_object('aliases', $self->object->id)) {
416                            return $res;
417                        } else {
418                            $self->base->log(LA_ERR, "Cannot remove forward for %s",
419                                $self->object->id);
420                        }
421                    }
422                    return;
423                },
424                label => l('Forward'),
425            },
426            aliases   => {
427                #reference => 'aliases',
428                delayed => 1,
429                formtype => 'TEXT',
430                multiple => 1,
431                get => sub {
432                    my ($self) = @_;
433                    my $sth = $self->base->db->prepare(q{
434                        select name from aliases where lower($1) =
435                        lower(array_to_string("forward", ','))
436                        } . ($self->base->{wexported} ? '' : 'and exported = true'));
437                    $sth->execute($self->object->id);
438                    my @values;
439                    while (my $res = $sth->fetchrow_hashref) {
440                        push(@values, $res->{name});
441                    }
442                    return \@values;
443                },
444                set => sub {
445                    my ($self, $data) = @_;
446
447                    my $res = 0;
448                    my %aliases = map { $_ => 1 } grep { $_ } (ref $data ? @{$data} : $data);
449                    foreach ($self->object->_get_attributes('aliases')) {
450                        $aliases{$_} ||= 0;
451                        $aliases{$_} +=2;
452                    }
453                    foreach (keys %aliases) {
454                        if ($aliases{$_} == 2) {
455                            if ($self->base->_delete_object('aliases', $_)) {
456                                $res++
457                            } else {
458                                $self->base->log(LA_ERR,
459                                    "Cannot remove aliases %s from user %s", $_,
460                                    $self->object->id);
461                            }
462                        } elsif ($aliases{$_} == 1) {
463                            if ($self->base->_create_c_object(
464                                    'aliases', $_,
465                                    forward => [ $self->object->id ],
466                                    description => 'automatically created for ' . $self->object->id,
467                                )) {
468                                $res++
469                            } else {
470                                $self->base->log(LA_ERR, 'Cannot set forward %s to user %s',
471                                    $_, $self->object->id);
472                                return;
473                            }
474                        } # 3 no change
475                    }
476                    $res
477                },
478                label => l('Aliases'),
479            },
480            revaliases => {
481                formtype => 'TEXT',
482                get => sub {
483                    my ($self) = @_;
484
485                    if (my $obj = $self->base->
486                        get_object('revaliases', $self->object->id)) {
487                        return $obj->get_attributes('as');
488                    } else {
489                        return;
490                    }
491                },
492                set => sub {
493                    my ($self, $data) = @_;
494               
495                    my $res = 0;
496                    if ($data) {
497                        if (my $obj = $self->base->
498                            get_object('revaliases', $self->object->id)) {
499                            my $ares = $obj->set_c_fields(
500                                'as' => $data,
501                                'exported' => ($self->object->get_attributes('exported') || 0),
502                            );
503                            if (defined($ares)) {
504                                $res+=$ares;
505                            } else {
506                                $self->base->log(LA_ERR, 'Cannot set revaliases for user %s',
507                                    $self->object->id);
508                            }
509                        } else {
510                            if ($self->base->_create_c_object(
511                                    'revaliases',
512                                    $self->object->id, as => $data,
513                                    'exported' => ($self->object->get_attributes('exported') || 0),
514                                    description => 'automatically created for ' . $self->object->id,
515                                )) {
516                                $res++;
517                            } else {
518                                $self->base->log(LA_ERR, 'Cannot set revaliases for user %s',
519                                    $self->object->id);
520                            }
521                        }
522                    } else {
523                        $self->base->_delete_object('revaliases', $self->object->id);
524                        $res++;
525                    }
526
527                    $res
528                },
529            },
530            manager => {
531                reference => 'user',
532                ro => 1,
533                get => sub {
534                    my ($self) = @_;
535                    if (my $manager = $self->object->_get_c_field('managerContact')) {
536                        return $manager;
537                    } elsif (my $department = $self->object->_get_c_field('department')) {
538                        my $obj = $self->base->get_object('group', $department);
539                        return $obj->_get_c_field('managedBy');
540                    } else {
541                        return;
542                    }
543                },
544                label => l('Responsible'),
545            },
546            department => {
547                reference => 'group',
548                can_values => sub {
549                    $base->search_objects('group', 'sutype=dpmt')
550                },
551                monitored => 1,
552                label => l('Department'),
553            },
554            contratType => {
555                reference => 'group',
556                can_values => sub {
557                    $base->search_objects('group', 'sutype=contrattype')
558                },
559                monitored => 1,
560                label => l('Type of contract'),
561            },
562            site => {
563                reference => 'site',
564                can_values => sub {
565                    $base->search_objects('site')
566                },
567                get => sub {
568                    my ($self) = @_;
569                    if (my $fmainaddress = $self->object->_get_c_field('mainaddress')) {
570                        $self->base->get_object('address', $fmainaddress)
571                            ->_get_c_field($self->name);
572                    } else {
573                        return;
574                    }
575                },
576                set => $subsetaddress,
577                label => l('Site'),
578            },
579            co => {
580                get => sub {
581                    my ($self) = @_;
582                    if (my $fmainaddress = $self->object->_get_c_field('mainaddress')) {
583                        $self->base->get_object('address', $fmainaddress)
584                            ->_get_c_field($self->name);
585                    } else {
586                        return;
587                    }
588                },
589                set => $subsetaddress,
590            },
591            l => {
592                get => sub {
593                    my ($self) = @_;
594                    if (my $fmainaddress = $self->object->_get_c_field('mainaddress')) {
595                        $self->base->get_object('address', $fmainaddress)
596                            ->_get_c_field($self->name);
597                    } else {
598                        return;
599                    }
600                },
601                set => $subsetaddress,
602                label => l('City'),
603            },
604            postalCode => {
605                get => sub {
606                    my ($self) = @_;
607                    if (my $fmainaddress = $self->object->_get_c_field('mainaddress')) {
608                        $self->base->get_object('address', $fmainaddress)
609                            ->_get_c_field($self->name);
610                    } else {
611                        return;
612                    }
613                },
614                set => $subsetaddress,
615                label => l('Postal code'),
616            },
617            streetAddress => {
618                formtype => 'TEXTAREA',
619                get => sub {
620                    my ($self) = @_;
621                    if (my $fmainaddress = $self->object->_get_c_field('mainaddress')) {
622                        $self->base->get_object('address', $fmainaddress)
623                            ->_get_c_field($self->name);
624                    } else {
625                        return;
626                    }
627                },
628                set => $subsetaddress,
629                label => l('Street'),
630            },
631            postOfficeBox => {
632                get => sub {
633                    my ($self) = @_;
634                    if (my $fmainaddress = $self->object->_get_c_field('mainaddress')) {
635                        $self->base->get_object('address', $fmainaddress)
636                            ->_get_c_field($self->name);
637                    } else {
638                        return;
639                    }
640                },
641                set => $subsetaddress,
642                label => l('Post office box'),
643            },
644            st => {
645                get => sub {
646                    my ($self) = @_;
647                    if (my $fmainaddress = $self->object->_get_c_field('mainaddress')) {
648                        $self->base->get_object('address', $fmainaddress)
649                            ->_get_c_field($self->name);
650                    } else {
651                        return;
652                    }
653                },
654                set => $subsetaddress,
655            },
656            facsimileTelephoneNumber => {
657                get => sub {
658                    my ($self) = @_;
659                    if (my $fmainaddress = $self->object->_get_c_field('mainaddress')) {
660                        $self->base->get_object('address', $fmainaddress)
661                            ->_get_c_field($self->name);
662                    } else {
663                        return;
664                    }
665                },
666                set => $subsetaddress,
667                label => l('Fax number'),
668            },
669            o => {
670                ro => 1,
671                iname => 'company',
672                label => l('Company'),
673            },
674            ou => {
675                iname => 'department',
676                ro => 1,
677                label => l('Department'),
678            },
679            telephoneNumber => {
680                get => sub {
681                    my ($self) = @_;
682                    if (my $fmainaddress = $self->object->_get_c_field('mainaddress')) {
683                        $self->base->get_object('address', $fmainaddress)
684                            ->_get_c_field($self->name);
685                    } else {
686                        return;
687                    }
688                },
689                set => $subsetaddress,
690                label => l('Phone number'),
691            },
692            physicalDeliveryOfficeName => {
693                get => sub {
694                    my ($self) = @_;
695                    if (my $fmainaddress = $self->object->_get_c_field('mainaddress')) {
696                        $self->base->get_object('address', $fmainaddress)
697                            ->_get_c_field($self->name);
698                    } else {
699                        return;
700                    }
701                },
702                set => $subsetaddress,
703                label => l('Office'),
704            },
705            uid => {
706                iname => 'name',
707                ro => 1,
708                label => l('Login'),
709            },
710            cn =>  { iname => 'name', ro => 1 },
711            gecos => {
712                managed => 1,
713                ro => 1,
714                get => sub {
715                    my ($self) = @_;
716                    my $obj = $self->object;
717                    my $gecos = sprintf("%s,%s,%s,%s",
718                        join(' ', grep { $_ }
719                                ($obj->_get_c_field('givenName'),
720                                ($obj->_get_c_field('sn'))))
721                            || $obj->_get_c_field('description') || '',
722                        join(' - ', grep { $_ } (($obj->_get_c_field('site') ||
723                                    $obj->_get_c_field('l')),
724                            $obj->_get_c_field('physicalDeliveryOfficeName'))) || '',
725                        $obj->_get_c_field('telephoneNumber') || '',
726                        $obj->_get_c_field('expireText') || '',
727                    );
728                    $gecos =~ s/:/ /g;
729                    return to_ascii($gecos);
730                },
731                label => l('GECOS'),
732            },
733            displayName  => {
734                ro => 1, managed => 1,
735                get => sub {
736                    my ($self) = @_;
737                    return join(' ', grep { $_ } 
738                        (
739                            $self->object->_get_c_field('givenName'),
740                            $self->object->_get_c_field('sn')
741                        )
742                    )
743                    || $self->object->_get_c_field('description')
744                    || $self->object->id;
745                },
746                label => l('Name'),
747            },
748            sAMAccountName  => {
749                ro => 1,
750                managed => 1,
751                iname => 'name',
752            },
753            accountExpires => {
754                ro => 1,
755                managed => 1,
756                get => sub {
757                    my ($self) = @_;
758                    my $obj = $self->object;
759                    my $sth = $obj->db->prepare_cached(
760                        sprintf(
761                            q{select extract(epoch from COALESCE(endcircuit,  expire)) + 11644474161 as expire
762                            from %s where %s = ?},
763                            $obj->db->quote_identifier($obj->_object_table),
764                            $obj->db->quote_identifier($obj->_key_field),
765                        )
766                    );
767                    $sth->execute($obj->id);
768                    my $res = $sth->fetchrow_hashref;
769                    $sth->finish;
770                    return $res->{expire} ? sprintf("%.f", $res->{expire} * 1E7) : '9223372036854775807';
771                }
772            },
773            shadowExpire => {
774                ro => 1,
775                managed => 1,
776                get => sub {
777                    my ($self) = @_;
778                    my $obj = $self->object;
779                    my $sth = $obj->db->prepare_cached(
780                        sprintf(
781                            q{select justify_hours(COALESCE(endcircuit,  expire) - '1/1/1970'::timestamp) as expire
782                            from %s where %s = ?},
783                            $obj->db->quote_identifier($obj->_object_table),
784                            $obj->db->quote_identifier($obj->_key_field),
785                        )
786                    );
787                    $sth->execute($obj->id);
788                    my $res = $sth->fetchrow_hashref;
789                    $sth->finish;
790                    return -1 unless($res->{expire});
791                    $res->{expire} =~ /(\d+) days\s*(\w)?/;
792                    return $1 + ($2 ? 1 : 0);
793                }
794            },
795            directReports => {
796                reference => 'user',
797                ro => 1,
798                delayed => 1,
799                get => sub {
800                    my ($self) = @_;
801                    my $obj = $self->object;
802                    my $sth = $obj->db->prepare_cached(
803                        q{
804                        SELECT
805                        "user".name FROM
806                        public."user",
807                        public.user_attributes_groups,
808                        public.group_attributes_users,
809                        public.group_attributes_base gb,
810                        public."group"
811                        WHERE
812                        "user".ikey = user_attributes_groups.okey AND
813                        user_attributes_groups.value = "group".name AND
814                        group_attributes_users.okey = gb.okey AND
815                        "group".ikey = group_attributes_users.okey AND
816                        gb.attr = 'sutype' AND
817                        gb.value = 'dpmt' AND
818                        group_attributes_users.attr = 'managedBy' AND
819                        group_attributes_users.value = ?
820                        } . ($self->base->{wexported} ? '' : ' and "user".exported = true') . q{
821                            and "user".ikey not in
822                        (select okey from user_attributes_users
823                        where attr = 'manager' and value != ? )
824                        union
825                        select "user".name FROM public."user",
826                        user_attributes_users where
827                        user_attributes_users.attr = 'manager' and user_attributes_users.value = ?
828                            and "user".ikey = user_attributes_users.okey
829                        } . ($self->base->{wexported} ? '' : ' and "user".exported = true')
830                    );
831                    $sth->execute($obj->id, $obj->id, $obj->id);
832                    my @res;
833                    while (my $res = $sth->fetchrow_hashref) {
834                        push(@res, $res->{name});
835                    }
836                    return \@res;
837                },
838            },
839            managedObjects => { ro => 1, reference => 'group', },
840            otheraddress => {
841                ro => 1,
842                reference => 'address',
843                get => sub {
844                    my ($self) = @_;
845                    my $sth = $self->base->db->prepare_cached(q{
846                        select name from address left join address_attributes
847                        on address.ikey = address_attributes.okey and
848                        address_attributes.attr = 'isMainAddress'
849                        where "user" = ?
850                        order by address_attributes.attr
851                        });
852                    $sth->execute($self->object->id);
853                    my @values;
854                    while (my $res = $sth->fetchrow_hashref) {
855                        push(@values, $res->{name});
856                    }
857                    return \@values;
858                },
859            },
860            mainaddress => {
861                ro => 1,
862                reference => 'address',
863                get => sub {
864                    my ($self) = @_;
865                    my $sth = $self->base->db->prepare_cached(q{
866                        select name from address join address_attributes on ikey = okey
867                        where "user" = ? and attr = 'isMainAddress'
868                        });
869                    $sth->execute($self->object->id);
870                    my $res = $sth->fetchrow_hashref;
871                    $sth->finish;
872                    return $res->{name};
873                },
874            },
875            postalAddress => {
876                ro => 1,
877                get => sub {
878                    my ($self) = @_;
879                    if (my $fmainaddress = $self->object->_get_c_field('mainaddress')) {
880                        $self->base->get_object('address', $fmainaddress)
881                            ->_get_c_field($self->name);
882                    } else {
883                        return;
884                    }
885                },
886                label => l('Postal Address'),
887            },
888            facsimileTelephoneNumber => {
889                ro => 1,
890                label => l('Fax number'),
891            },
892            allsite   => {
893                ro => 1,
894                reference => 'site',
895            },
896            managerContact => {
897                delayed => 1,
898                can_values => sub {
899                    my %uniq = map { $_ => 1 } grep { $_ }
900                    ($_[1] ? $_[1]->get_attributes('managerContact') : ()),
901                    $base->search_objects('user', 'active=*');
902                    sort keys %uniq;
903                },
904                reference => 'user',
905                monitored => 1,
906                iname => 'manager',
907                label => l('Manager'),
908            },
909            expireText => {
910                ro => 1,
911                get => sub {
912                    my ($self) = @_;
913                    my $obj = $self->object;
914                    my $sth = $obj->db->prepare_cached(
915                        sprintf(
916                            q{select to_char(COALESCE(endcircuit,  expire), 'YYYY/MM/DD') as expire
917                            from %s where %s = ?},
918                            $obj->db->quote_identifier($obj->_object_table),
919                            $obj->db->quote_identifier($obj->_key_field),
920                        )
921                    );
922                    $sth->execute($obj->id) or $obj->db->rollback;
923                    my $res = $sth->fetchrow_hashref;
924                    $sth->finish;
925                    return $res->{expire}
926                },
927            },
928            krb5ValidEnd => {
929                ro => 1,
930                managed => 1,
931                get => sub {
932                    my ($self) = @_;
933                    my $sth = $self->object->db->prepare_cached(
934                        sprintf(
935                            q{select date_part('epoch', COALESCE(endcircuit,  expire))::int as expire
936                            from %s where %s = ?},
937                            $self->object->db->quote_identifier($self->object->_object_table),
938                            $self->object->db->quote_identifier($self->object->_key_field),
939                        )
940                    );
941                    $sth->execute($self->object->id) or $self->object->db->rollback;
942                    my $res = $sth->fetchrow_hashref;
943                    $sth->finish;
944                    return $res->{expire}
945                },
946            },
947            cells  => {
948                ro => 1,
949                reference => 'group',
950            },
951            departments => {
952                reference => 'group',
953                delayed => 1,
954                ro => 1,
955                label => l('Departments'),
956            },
957            arrivalDate => { },
958            expired => {
959                ro => 1,
960                label => l('Expired'),
961            },
962            active => {
963                ro => 1,
964                label => l('Active'),
965            },
966            pwdAccountLockedTime => {
967                managed => 1,
968                ro => 1,
969                get => sub {
970                    my ($self) = @_;
971                    my $obj = $self->object;
972                    if ($obj->_get_c_field('locked')) {
973                        return '000001010000Z';
974                    } else {
975                        my $sth = $obj->db->prepare_cached(
976                            sprintf(
977                                q{select to_char(COALESCE(endcircuit,  expire) AT TIME ZONE 'Z', 'YYYYMMDDHH24MISSZ') as expire
978                                from %s where %s = ? and expire < now()},
979                                $obj->db->quote_identifier($obj->_object_table),
980                                $obj->db->quote_identifier($obj->_key_field),
981                            )
982                        );
983                        $sth->execute($obj->id);
984                        my $res = $sth->fetchrow_hashref;
985                        $sth->finish;
986                        return $res->{expire}
987                    }
988                },
989            },
990            userPassword => { readable => 0, },
991            wWWHomePage => {
992                label => l('Web Page'),
993            },
994            title => { },
995            snNative => {
996                label => l('Native name'),
997            },
998            givenNameNative => {
999                label => l('Native first name'),
1000            },
1001            sn => {
1002                label => l('Name'),
1003            },
1004            shadowWarning => { },
1005            shadowMin => { },
1006            shadowMax => { },
1007            shadowLastChange => { },
1008            shadowInactive => { },
1009            shadowFlag => { },
1010            otherTelephone => { },
1011            nickname => {
1012                label => l('Nickname'),
1013            },
1014            mobile => { },
1015            mail => {
1016                label => l('Email'),
1017            },
1018            labeledURI => { },
1019            jobType => { },
1020            ipPhone => { },
1021            initials => {
1022                label => l('Initials'),
1023            },
1024            homePhone => { },
1025            homeDirectory => {
1026                label => l('Home directory'),
1027            },
1028            halReference => {
1029                label => l('HAL id'),
1030            },
1031            grade => { },
1032            givenName => {
1033                label => l('First name'),
1034            },
1035            encryptedPassword => { },
1036            description => {
1037                label => l('Description'),
1038            },
1039            company => {
1040                label => l('Company'),
1041            },
1042            comment => {
1043                label => l('Comment'),
1044            },
1045            college => { },
1046            passwordLastSet => {
1047                ro => 1,
1048                label => l('Password set'),
1049            },
1050            currentEmployment => {
1051                managed => 1,
1052                ro => 1,
1053                reference => 'employment',
1054                get => sub {
1055                    my ($attr) = @_;
1056                    my $self = $attr->object;
1057
1058                    my $sth = $self->base->db->prepare_cached(
1059                        q{
1060                        select name from employment where firstday <= now() and
1061                        (lastday is null or lastday >= now() - '1 days'::interval) and "user" = ?
1062                        limit 1
1063                        }
1064                    );
1065                    $sth->execute($self->id);
1066                    my $res = $sth->fetchrow_hashref;
1067                    $sth->finish;
1068                    if ($res) {
1069                        return $res->{name}
1070                    } else {
1071                        return;
1072                    }
1073                },
1074            },
1075            nextEmployment => {
1076                managed => 1,
1077                ro => 1,
1078                reference => 'employment',
1079                get => sub {
1080                    my ($attr) = @_;
1081                    my $self = $attr->object;
1082
1083                    my $sth = $self->base->db->prepare_cached(
1084                        q{
1085                        select name from employment where firstday > now() and
1086                        (lastday is null or lastday >= now() - '1 days'::interval) and "user" = ?
1087                        limit 1
1088                        }
1089                    );
1090                    $sth->execute($self->id);
1091                    my $res = $sth->fetchrow_hashref;
1092                    $sth->finish;
1093                    if ($res) {
1094                        return $res->{name}
1095                    } else {
1096                        return;
1097                    }
1098                }
1099            },
1100            appliedEmployement => {
1101                hide => 1,
1102                reference => 'employment',
1103            },
1104    };
1105
1106    foreach (qw(expire contratType managerContact company endcircuit department)) {
1107        $attrs->{$_}{ro} = sub {
1108
1109            my $setting = $base->config('employment_lock_user') || 'any';
1110
1111            for ($setting) {
1112                /^always$/ and return 1;
1113                /^never$/ and return 0;
1114
1115                !$_[0] and return 1;
1116
1117                /^any$/i and return $_[0]->listEmployment ? 1 : 0;
1118                /^active/i and do {
1119                    return $_[0]->_get_c_field('currentEmployment')
1120                        ? 1
1121                        : $_[0]->_get_c_field('nextEmployment') ? 1 : 0;
1122                };
1123                /(\S+)=(\S+)/ and do {
1124                    my $attr = $_[0]->_get_c_field($1);
1125                    if (defined($attr)) {
1126                        if ($2 eq '*') {
1127                            return 1;
1128                        } elsif($2 eq $attr) {
1129                            return 1;
1130                        } else {
1131                            return 0;
1132                        }
1133                    } else {
1134                        return 0;
1135                    }
1136                };
1137            }
1138            return $_[0]->listEmployment ? 1 : 0; # default is any!
1139        };
1140    }
1141
1142    $class->SUPER::_get_attr_schema($base, $attrs)
1143}
1144
1145sub _get_state {
1146    my ($self, $state) = @_;
1147    for ($state) {
1148        /^expired$/ and do {
1149            my $attribute = $self->attribute('expire');
1150            $attribute->check_acl('r') or return;
1151            my $sth = $self->db->prepare_cached(
1152                q{ select coalesce(expire < now(), false) as exp from "user"
1153                where "user".name = ?}
1154            );
1155            $sth->execute($self->id);
1156            my $res = $sth->fetchrow_hashref;
1157            $sth->finish;
1158            return $res->{exp} ? 1 : 0;
1159        };
1160    }
1161}
1162
1163=head2 listEmployment
1164
1165Return the ordered list of contract
1166
1167=cut
1168
1169sub listEmployment {
1170    my ($self) = @_;
1171
1172    my $sth = $self->base->db->prepare_cached(
1173        q{
1174        select name from employment where "user" = ?
1175        order by lastday desc NULLS first
1176        }
1177    );
1178    $sth->execute($self->id);
1179    my @list = ();
1180    while (my $res = $sth->fetchrow_hashref) {
1181        push(@list, $res->{name});
1182    }
1183
1184    @list
1185}
1186
1187
1188sub _computeEndEmployment {
1189    my ($self, $delay) = @_;
1190
1191    my $list_empl = $self->base->db->prepare_cached(q{
1192        SELECT *, firstday <= now() as "started" FROM employment WHERE "user" = ? and
1193        (lastday is null or lastday >= now() - '1 days'::interval)
1194        order by firstday asc
1195        });
1196    $list_empl->execute($self->id);
1197    my $end;
1198    while (my $res = $list_empl->fetchrow_hashref) {
1199        if (!$res->{lastday}) {
1200            # Ultimate employment.
1201            $list_empl->finish;
1202            return undef;
1203        }
1204        if ($end) {
1205            my $nextstart = DateTime->from_epoch(epoch => str2time($res->{firstday}));
1206            my $tend = $end->clone;
1207            if ($delay) {
1208                $tend->add(days => $delay);
1209            }
1210            if ($tend->ymd lt $nextstart->ymd) {
1211                last;
1212            }
1213        } else {
1214            if (!$res->{started}) {
1215                last;
1216            }
1217        }
1218        $end = DateTime->from_epoch(epoch => str2time($res->{lastday}));
1219        $end->set_time_zone( DateTime::TimeZone->new( name => 'local' ) );
1220        $end->add(hours => 23, minutes => 59, seconds => 59);
1221    }
1222    $list_empl->finish;
1223
1224    if (!$end) {
1225        my $listold = $self->base->db->prepare_cached(q{
1226            SELECT max(lastday) as lastday FROM employment WHERE "user" = ? and
1227            lastday IS NOT NULL and lastday <= now() - '1 days'::interval
1228            });
1229        $listold->execute($self->id);
1230        my $res = $listold->fetchrow_hashref;
1231        if ($res && $res->{lastday}) {
1232            $end = DateTime->from_epoch(epoch => str2time($res->{lastday}));
1233            $end->set_time_zone( DateTime::TimeZone->new( name => 'local' ) );
1234            $end->add(hours => 23, minutes => 59, seconds => 59);
1235        } else {
1236            if (my $default = $self->base->config('unemployed_expire')) {
1237                $end = DateTime->from_epoch(epoch => str2time($default));
1238            }
1239        }
1240        $listold->finish;
1241    }
1242    return $end ? $end->iso8601 : undef
1243}
1244
12451;
1246
1247__END__
1248
1249=head1 SEE ALSO
1250
1251=head1 AUTHOR
1252
1253Olivier Thauvin, E<lt>olivier.thauvin@latmos.ipsl.frE<gt>
1254
1255=head1 COPYRIGHT AND LICENSE
1256
1257Copyright (C) 2008, 2009 CNRS SA/CETP/LATMOS
1258
1259This library is free software; you can redistribute it and/or modify
1260it under the same terms as Perl itself, either Perl version 5.10.0 or,
1261at your option, any later version of Perl 5 you may have available.
1262
1263=cut
Note: See TracBrowser for help on using the repository browser.