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

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

Always pass a defined value even 0 to end/start computation

  • Property svn:keywords set to Id Rev
File size: 52.4 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') || 0);
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            _startEmployment => {
318                formtype => 'DATETIME',
319                managed => 1,
320                ro => 1,
321                hide => 1,
322                get => sub {
323                    my ($attr) = @_;
324                    my $self = $attr->object;
325                    $self->_computeStartEmployment($self->base->config('employment_delay') || 0);
326                },
327                label => l('Start of employment'),
328            },
329            startEmployment => {
330                formtype => 'DATETIME',
331                ro => 1,
332                label => l('Start of employment'),
333            },
334            _startStrictEmployment => {
335                formtype => 'DATETIME',
336                managed => 1,
337                ro => 1,
338                hide => 1,
339                get => sub {
340                    my ($attr) = @_;
341                    my $self = $attr->object;
342                    $self->_computeStartEmployment();
343                },
344            },
345            startStrictEmployment => {
346                formtype => 'DATETIME',
347                ro => 1,
348            },
349            _startCurrentEmployment => {
350                formtype => 'DATETIME',
351                managed => 1,
352                ro => 1,
353                hide => 1,
354                get => sub {
355                    my ($attr) = @_;
356                    my $self = $attr->object;
357
358                    my $list_empl = $self->base->db->prepare_cached(q{
359                        SELECT * FROM employment WHERE "user" = ? and
360                            firstday <= now() and
361                            (lastday is null or lastday >= now() - '1 days'::interval)
362                            order by firstday asc
363                    });
364                    $list_empl->execute($self->id);
365                    my $start;
366                    while (my $res = $list_empl->fetchrow_hashref) {
367                        $start = DateTime->from_epoch(epoch => str2time($res->{firstday}));
368                        $start->set_time_zone( DateTime::TimeZone->new( name => 'local' ) );
369                        last;
370                    }
371                    $list_empl->finish;
372
373                    return $start ? $start->iso8601 : undef
374                },
375            },
376            startCurrentEmployment => {
377                formtype => 'DATETIME',
378                ro => 1,
379            },
380            _startFirstEmployment => {
381                formtype => 'DATETIME',
382                managed => 1,
383                ro => 1,
384                hide => 1,
385                get => sub {
386                    my ($attr) = @_;
387                    my $self = $attr->object;
388
389                    my $list_empl = $self->base->db->prepare_cached(q{
390                        SELECT * FROM employment WHERE "user" = ?
391                        order by firstday asc
392                    });
393                    $list_empl->execute($self->id);
394                    my $res = $list_empl->fetchrow_hashref;
395                    $list_empl->finish;
396                    my $start;
397                    if ($res && $res->{firstday}) {
398                        $start = DateTime->from_epoch(epoch => str2time($res->{firstday}));
399                        $start->set_time_zone( DateTime::TimeZone->new( name => 'local' ) );
400                    }
401                    return $start ? $start->iso8601 : undef
402                },
403                label => l('Start of any employment'),
404            },
405            startFirstEmployment => {
406                formtype => 'DATETIME',
407                ro => 1,
408                label => l('Start of any employment'),
409            },
410            cn        => {
411                inline => 1, ro => 1,
412                get => sub {
413                    my ($self) = @_;
414                    return join(' ', grep { $_ } 
415                        (
416                            $self->object->_get_c_field('givenName'),
417                            $self->object->_get_c_field('sn')
418                        )
419                    )
420                    || $self->object->_get_c_field('description')
421                    || $self->object->id;
422                },
423            },
424            memberOf  => {
425                reference => 'group',
426                multiple => 1, delayed => 1,
427                get => sub {
428                    my ($self) = @_;
429                    my $obj = $self->object;
430                    my $sth = $obj->db->prepare_cached(
431                        q{
432                        select name from "group" join
433                        group_attributes on group_attributes.okey = "group".ikey
434                        where value = ? and attr = ?
435                        } . ($self->base->{wexported} ? '' : ' and "group".exported = true')
436                    );
437                    $sth->execute($obj->id, 'memberUID');
438                    my @res;
439                    while (my $res = $sth->fetchrow_hashref) {
440                        push(@res, $res->{name});
441                    }
442                    return \@res;
443                },
444                set => sub {
445                    my ($self, $values) = @_;
446                    my %old = map { $_ => 'o' } @{ $self->get };
447                    foreach my $group (grep { $_ } ref $values ? @{ $values } : $values) {
448                        if ($old{$group}) {
449                            $old{$group} = undef; # no change
450                        } else {
451                            $old{$group} = 'n';
452                        }
453                    }
454
455                    my $res = 0;
456                    foreach my $group (keys %old) {
457                        $old{$group} or next; # no change
458
459                        my $ogroup = $self->base->get_object('group', $group) or next;
460                        ($ogroup->_get_c_field('sutype') || '') =~ /^(jobtype|contrattype)$/ and next;
461
462                        if ($old{$group} eq 'n') {
463                            $res += $ogroup->_addAttributeValue('memberUID', $self->object->id);
464                        } else {
465                            if (($self->object->_get_c_field('department') || '') eq $ogroup->id) {
466                                $self->base->log(LA_WARN,
467                                    "Don't removing user %s from group %s: is its department",
468                                    $self->object->id, $ogroup->id);
469                                next;
470                            }
471                            $res += $ogroup->_delAttributeValue('memberUID', $self->object->id);
472                        }
473                    }
474                    return $res;
475                },
476                label => l('Member of'),
477            },
478            forward => {
479                managed => 1,
480                get => sub {
481                    my ($self) = @_;
482                    my $sth = $self->base->db->prepare(q{
483                        select forward from aliases where name = ?
484                        } . ($self->base->{wexported} ? '' : ' and exported = true'));
485                    $sth->execute($self->object->id);
486                    my $res = $sth->fetchrow_hashref;
487                    $sth->finish;
488                    return $res->{forward}
489                },
490                set => sub {
491                    my ($self, $data) = @_;
492                    if ($data) {
493                        if (my $f = $self->base->get_object('aliases', $self->object->id)) {
494                            return $f->_set_c_fields(forward => $data);
495                        } else {
496                            if ($self->base->_create_c_object(
497                                    'aliases', $self->object->id,
498                                    forward => $data,
499                                    description => 'automatically created for ' . $self->object->id,
500                                )) {
501                                return 1;
502                            } else {
503                                $self->base->log(LA_ERR, "Cannot add forward for %s",
504                                    $self->object->id);
505                            }
506                        }
507                    } else {
508                        if (my $res = $self->base->_delete_object('aliases', $self->object->id)) {
509                            return $res;
510                        } else {
511                            $self->base->log(LA_ERR, "Cannot remove forward for %s",
512                                $self->object->id);
513                        }
514                    }
515                    return;
516                },
517                label => l('Forward'),
518            },
519            aliases   => {
520                #reference => 'aliases',
521                delayed => 1,
522                formtype => 'TEXT',
523                multiple => 1,
524                get => sub {
525                    my ($self) = @_;
526                    my $sth = $self->base->db->prepare(q{
527                        select name from aliases where lower($1) =
528                        lower(array_to_string("forward", ','))
529                        } . ($self->base->{wexported} ? '' : 'and exported = true'));
530                    $sth->execute($self->object->id);
531                    my @values;
532                    while (my $res = $sth->fetchrow_hashref) {
533                        push(@values, $res->{name});
534                    }
535                    return \@values;
536                },
537                set => sub {
538                    my ($self, $data) = @_;
539
540                    my $res = 0;
541                    my %aliases = map { $_ => 1 } grep { $_ } (ref $data ? @{$data} : $data);
542                    foreach ($self->object->_get_attributes('aliases')) {
543                        $aliases{$_} ||= 0;
544                        $aliases{$_} +=2;
545                    }
546                    foreach (keys %aliases) {
547                        if ($aliases{$_} == 2) {
548                            if ($self->base->_delete_object('aliases', $_)) {
549                                $res++
550                            } else {
551                                $self->base->log(LA_ERR,
552                                    "Cannot remove aliases %s from user %s", $_,
553                                    $self->object->id);
554                            }
555                        } elsif ($aliases{$_} == 1) {
556                            if ($self->base->_create_c_object(
557                                    'aliases', $_,
558                                    forward => [ $self->object->id ],
559                                    description => 'automatically created for ' . $self->object->id,
560                                )) {
561                                $res++
562                            } else {
563                                $self->base->log(LA_ERR, 'Cannot set forward %s to user %s',
564                                    $_, $self->object->id);
565                                return;
566                            }
567                        } # 3 no change
568                    }
569                    $res
570                },
571                label => l('Aliases'),
572            },
573            revaliases => {
574                formtype => 'TEXT',
575                get => sub {
576                    my ($self) = @_;
577
578                    if (my $obj = $self->base->
579                        get_object('revaliases', $self->object->id)) {
580                        return $obj->get_attributes('as');
581                    } else {
582                        return;
583                    }
584                },
585                set => sub {
586                    my ($self, $data) = @_;
587               
588                    my $res = 0;
589                    if ($data) {
590                        if (my $obj = $self->base->
591                            get_object('revaliases', $self->object->id)) {
592                            my $ares = $obj->set_c_fields(
593                                'as' => $data,
594                                'exported' => ($self->object->get_attributes('exported') || 0),
595                            );
596                            if (defined($ares)) {
597                                $res+=$ares;
598                            } else {
599                                $self->base->log(LA_ERR, 'Cannot set revaliases for user %s',
600                                    $self->object->id);
601                            }
602                        } else {
603                            if ($self->base->_create_c_object(
604                                    'revaliases',
605                                    $self->object->id, as => $data,
606                                    'exported' => ($self->object->get_attributes('exported') || 0),
607                                    description => 'automatically created for ' . $self->object->id,
608                                )) {
609                                $res++;
610                            } else {
611                                $self->base->log(LA_ERR, 'Cannot set revaliases for user %s',
612                                    $self->object->id);
613                            }
614                        }
615                    } else {
616                        $self->base->_delete_object('revaliases', $self->object->id);
617                        $res++;
618                    }
619
620                    $res
621                },
622            },
623            manager => {
624                reference => 'user',
625                ro => 1,
626                get => sub {
627                    my ($self) = @_;
628                    if (my $manager = $self->object->_get_c_field('managerContact')) {
629                        return $manager;
630                    } elsif (my $department = $self->object->_get_c_field('department')) {
631                        my $obj = $self->base->get_object('group', $department);
632                        return $obj->_get_c_field('managedBy');
633                    } else {
634                        return;
635                    }
636                },
637                label => l('Responsible'),
638            },
639            department => {
640                reference => 'group',
641                can_values => sub {
642                    $base->search_objects('group', 'sutype=dpmt')
643                },
644                monitored => 1,
645                label => l('Department'),
646            },
647            contratType => {
648                reference => 'group',
649                can_values => sub {
650                    $base->search_objects('group', 'sutype=contrattype')
651                },
652                monitored => 1,
653                label => l('Type of contract'),
654            },
655            site => {
656                reference => 'site',
657                can_values => sub {
658                    $base->search_objects('site')
659                },
660                get => sub {
661                    my ($self) = @_;
662                    if (my $fmainaddress = $self->object->_get_c_field('mainaddress')) {
663                        $self->base->get_object('address', $fmainaddress)
664                            ->_get_c_field($self->name);
665                    } else {
666                        return;
667                    }
668                },
669                set => $subsetaddress,
670                label => l('Site'),
671            },
672            co => {
673                get => sub {
674                    my ($self) = @_;
675                    if (my $fmainaddress = $self->object->_get_c_field('mainaddress')) {
676                        $self->base->get_object('address', $fmainaddress)
677                            ->_get_c_field($self->name);
678                    } else {
679                        return;
680                    }
681                },
682                set => $subsetaddress,
683            },
684            l => {
685                get => sub {
686                    my ($self) = @_;
687                    if (my $fmainaddress = $self->object->_get_c_field('mainaddress')) {
688                        $self->base->get_object('address', $fmainaddress)
689                            ->_get_c_field($self->name);
690                    } else {
691                        return;
692                    }
693                },
694                set => $subsetaddress,
695                label => l('City'),
696            },
697            postalCode => {
698                get => sub {
699                    my ($self) = @_;
700                    if (my $fmainaddress = $self->object->_get_c_field('mainaddress')) {
701                        $self->base->get_object('address', $fmainaddress)
702                            ->_get_c_field($self->name);
703                    } else {
704                        return;
705                    }
706                },
707                set => $subsetaddress,
708                label => l('Postal code'),
709            },
710            streetAddress => {
711                formtype => 'TEXTAREA',
712                get => sub {
713                    my ($self) = @_;
714                    if (my $fmainaddress = $self->object->_get_c_field('mainaddress')) {
715                        $self->base->get_object('address', $fmainaddress)
716                            ->_get_c_field($self->name);
717                    } else {
718                        return;
719                    }
720                },
721                set => $subsetaddress,
722                label => l('Street'),
723            },
724            postOfficeBox => {
725                get => sub {
726                    my ($self) = @_;
727                    if (my $fmainaddress = $self->object->_get_c_field('mainaddress')) {
728                        $self->base->get_object('address', $fmainaddress)
729                            ->_get_c_field($self->name);
730                    } else {
731                        return;
732                    }
733                },
734                set => $subsetaddress,
735                label => l('Post office box'),
736            },
737            st => {
738                get => sub {
739                    my ($self) = @_;
740                    if (my $fmainaddress = $self->object->_get_c_field('mainaddress')) {
741                        $self->base->get_object('address', $fmainaddress)
742                            ->_get_c_field($self->name);
743                    } else {
744                        return;
745                    }
746                },
747                set => $subsetaddress,
748            },
749            facsimileTelephoneNumber => {
750                get => sub {
751                    my ($self) = @_;
752                    if (my $fmainaddress = $self->object->_get_c_field('mainaddress')) {
753                        $self->base->get_object('address', $fmainaddress)
754                            ->_get_c_field($self->name);
755                    } else {
756                        return;
757                    }
758                },
759                set => $subsetaddress,
760                label => l('Fax number'),
761            },
762            o => {
763                ro => 1,
764                iname => 'company',
765                label => l('Company'),
766            },
767            ou => {
768                iname => 'department',
769                ro => 1,
770                label => l('Department'),
771            },
772            telephoneNumber => {
773                get => sub {
774                    my ($self) = @_;
775                    if (my $fmainaddress = $self->object->_get_c_field('mainaddress')) {
776                        $self->base->get_object('address', $fmainaddress)
777                            ->_get_c_field($self->name);
778                    } else {
779                        return;
780                    }
781                },
782                set => $subsetaddress,
783                label => l('Phone number'),
784            },
785            physicalDeliveryOfficeName => {
786                get => sub {
787                    my ($self) = @_;
788                    if (my $fmainaddress = $self->object->_get_c_field('mainaddress')) {
789                        $self->base->get_object('address', $fmainaddress)
790                            ->_get_c_field($self->name);
791                    } else {
792                        return;
793                    }
794                },
795                set => $subsetaddress,
796                label => l('Office'),
797            },
798            uid => {
799                iname => 'name',
800                ro => 1,
801                label => l('Login'),
802            },
803            cn =>  { iname => 'name', ro => 1 },
804            gecos => {
805                managed => 1,
806                ro => 1,
807                get => sub {
808                    my ($self) = @_;
809                    my $obj = $self->object;
810                    my $gecos = sprintf("%s,%s,%s,%s",
811                        join(' ', grep { $_ }
812                                ($obj->_get_c_field('givenName'),
813                                ($obj->_get_c_field('sn'))))
814                            || $obj->_get_c_field('description') || '',
815                        join(' - ', grep { $_ } (($obj->_get_c_field('site') ||
816                                    $obj->_get_c_field('l')),
817                            $obj->_get_c_field('physicalDeliveryOfficeName'))) || '',
818                        $obj->_get_c_field('telephoneNumber') || '',
819                        $obj->_get_c_field('expireText') || '',
820                    );
821                    $gecos =~ s/:/ /g;
822                    return to_ascii($gecos);
823                },
824                label => l('GECOS'),
825            },
826            displayName  => {
827                ro => 1, managed => 1,
828                get => sub {
829                    my ($self) = @_;
830                    return join(' ', grep { $_ } 
831                        (
832                            $self->object->_get_c_field('givenName'),
833                            $self->object->_get_c_field('sn')
834                        )
835                    )
836                    || $self->object->_get_c_field('description')
837                    || $self->object->id;
838                },
839                label => l('Name'),
840            },
841            sAMAccountName  => {
842                ro => 1,
843                managed => 1,
844                iname => 'name',
845            },
846            accountExpires => {
847                ro => 1,
848                managed => 1,
849                get => sub {
850                    my ($self) = @_;
851                    my $obj = $self->object;
852                    my $sth = $obj->db->prepare_cached(
853                        sprintf(
854                            q{select extract(epoch from COALESCE(endcircuit,  expire)) + 11644474161 as expire
855                            from %s where %s = ?},
856                            $obj->db->quote_identifier($obj->_object_table),
857                            $obj->db->quote_identifier($obj->_key_field),
858                        )
859                    );
860                    $sth->execute($obj->id);
861                    my $res = $sth->fetchrow_hashref;
862                    $sth->finish;
863                    return $res->{expire} ? sprintf("%.f", $res->{expire} * 1E7) : '9223372036854775807';
864                }
865            },
866            shadowExpire => {
867                ro => 1,
868                managed => 1,
869                get => sub {
870                    my ($self) = @_;
871                    my $obj = $self->object;
872                    my $sth = $obj->db->prepare_cached(
873                        sprintf(
874                            q{select justify_hours(COALESCE(endcircuit,  expire) - '1/1/1970'::timestamp) as expire
875                            from %s where %s = ?},
876                            $obj->db->quote_identifier($obj->_object_table),
877                            $obj->db->quote_identifier($obj->_key_field),
878                        )
879                    );
880                    $sth->execute($obj->id);
881                    my $res = $sth->fetchrow_hashref;
882                    $sth->finish;
883                    return -1 unless($res->{expire});
884                    $res->{expire} =~ /(\d+) days\s*(\w)?/;
885                    return $1 + ($2 ? 1 : 0);
886                }
887            },
888            directReports => {
889                reference => 'user',
890                ro => 1,
891                delayed => 1,
892                get => sub {
893                    my ($self) = @_;
894                    my $obj = $self->object;
895                    my $sth = $obj->db->prepare_cached(
896                        q{
897                        SELECT
898                        "user".name FROM
899                        public."user",
900                        public.user_attributes_groups,
901                        public.group_attributes_users,
902                        public.group_attributes_base gb,
903                        public."group"
904                        WHERE
905                        "user".ikey = user_attributes_groups.okey AND
906                        user_attributes_groups.value = "group".name AND
907                        group_attributes_users.okey = gb.okey AND
908                        "group".ikey = group_attributes_users.okey AND
909                        gb.attr = 'sutype' AND
910                        gb.value = 'dpmt' AND
911                        group_attributes_users.attr = 'managedBy' AND
912                        group_attributes_users.value = ?
913                        } . ($self->base->{wexported} ? '' : ' and "user".exported = true') . q{
914                            and "user".ikey not in
915                        (select okey from user_attributes_users
916                        where attr = 'manager' and value != ? )
917                        union
918                        select "user".name FROM public."user",
919                        user_attributes_users where
920                        user_attributes_users.attr = 'manager' and user_attributes_users.value = ?
921                            and "user".ikey = user_attributes_users.okey
922                        } . ($self->base->{wexported} ? '' : ' and "user".exported = true')
923                    );
924                    $sth->execute($obj->id, $obj->id, $obj->id);
925                    my @res;
926                    while (my $res = $sth->fetchrow_hashref) {
927                        push(@res, $res->{name});
928                    }
929                    return \@res;
930                },
931            },
932            managedObjects => { ro => 1, reference => 'group', },
933            otheraddress => {
934                ro => 1,
935                reference => 'address',
936                get => sub {
937                    my ($self) = @_;
938                    my $sth = $self->base->db->prepare_cached(q{
939                        select name from address left join address_attributes
940                        on address.ikey = address_attributes.okey and
941                        address_attributes.attr = 'isMainAddress'
942                        where "user" = ?
943                        order by address_attributes.attr
944                        });
945                    $sth->execute($self->object->id);
946                    my @values;
947                    while (my $res = $sth->fetchrow_hashref) {
948                        push(@values, $res->{name});
949                    }
950                    return \@values;
951                },
952            },
953            mainaddress => {
954                ro => 1,
955                reference => 'address',
956                get => sub {
957                    my ($self) = @_;
958                    my $sth = $self->base->db->prepare_cached(q{
959                        select name from address join address_attributes on ikey = okey
960                        where "user" = ? and attr = 'isMainAddress'
961                        });
962                    $sth->execute($self->object->id);
963                    my $res = $sth->fetchrow_hashref;
964                    $sth->finish;
965                    return $res->{name};
966                },
967            },
968            postalAddress => {
969                ro => 1,
970                get => sub {
971                    my ($self) = @_;
972                    if (my $fmainaddress = $self->object->_get_c_field('mainaddress')) {
973                        $self->base->get_object('address', $fmainaddress)
974                            ->_get_c_field($self->name);
975                    } else {
976                        return;
977                    }
978                },
979                label => l('Postal Address'),
980            },
981            facsimileTelephoneNumber => {
982                ro => 1,
983                label => l('Fax number'),
984            },
985            allsite   => {
986                ro => 1,
987                reference => 'site',
988            },
989            managerContact => {
990                delayed => 1,
991                can_values => sub {
992                    my %uniq = map { $_ => 1 } grep { $_ }
993                    ($_[1] ? $_[1]->get_attributes('managerContact') : ()),
994                    $base->search_objects('user', 'active=*');
995                    sort keys %uniq;
996                },
997                reference => 'user',
998                monitored => 1,
999                iname => 'manager',
1000                label => l('Manager'),
1001            },
1002            expireText => {
1003                ro => 1,
1004                get => sub {
1005                    my ($self) = @_;
1006                    my $obj = $self->object;
1007                    my $sth = $obj->db->prepare_cached(
1008                        sprintf(
1009                            q{select to_char(COALESCE(endcircuit,  expire), 'YYYY/MM/DD') as expire
1010                            from %s where %s = ?},
1011                            $obj->db->quote_identifier($obj->_object_table),
1012                            $obj->db->quote_identifier($obj->_key_field),
1013                        )
1014                    );
1015                    $sth->execute($obj->id) or $obj->db->rollback;
1016                    my $res = $sth->fetchrow_hashref;
1017                    $sth->finish;
1018                    return $res->{expire}
1019                },
1020            },
1021            krb5ValidEnd => {
1022                ro => 1,
1023                managed => 1,
1024                get => sub {
1025                    my ($self) = @_;
1026                    my $sth = $self->object->db->prepare_cached(
1027                        sprintf(
1028                            q{select date_part('epoch', COALESCE(endcircuit,  expire))::int as expire
1029                            from %s where %s = ?},
1030                            $self->object->db->quote_identifier($self->object->_object_table),
1031                            $self->object->db->quote_identifier($self->object->_key_field),
1032                        )
1033                    );
1034                    $sth->execute($self->object->id) or $self->object->db->rollback;
1035                    my $res = $sth->fetchrow_hashref;
1036                    $sth->finish;
1037                    return $res->{expire}
1038                },
1039            },
1040            cells  => {
1041                ro => 1,
1042                reference => 'group',
1043            },
1044            departments => {
1045                reference => 'group',
1046                delayed => 1,
1047                ro => 1,
1048                label => l('Departments'),
1049            },
1050            arrivalDate => { },
1051            expired => {
1052                ro => 1,
1053                label => l('Expired'),
1054            },
1055            active => {
1056                ro => 1,
1057                label => l('Active'),
1058            },
1059            pwdAccountLockedTime => {
1060                managed => 1,
1061                ro => 1,
1062                get => sub {
1063                    my ($self) = @_;
1064                    my $obj = $self->object;
1065                    if ($obj->_get_c_field('locked')) {
1066                        return '000001010000Z';
1067                    } else {
1068                        my $sth = $obj->db->prepare_cached(
1069                            sprintf(
1070                                q{select to_char(COALESCE(endcircuit,  expire) AT TIME ZONE 'Z', 'YYYYMMDDHH24MISSZ') as expire
1071                                from %s where %s = ? and expire < now()},
1072                                $obj->db->quote_identifier($obj->_object_table),
1073                                $obj->db->quote_identifier($obj->_key_field),
1074                            )
1075                        );
1076                        $sth->execute($obj->id);
1077                        my $res = $sth->fetchrow_hashref;
1078                        $sth->finish;
1079                        return $res->{expire}
1080                    }
1081                },
1082            },
1083            userPassword => { readable => 0, },
1084            wWWHomePage => {
1085                label => l('Web Page'),
1086            },
1087            title => { },
1088            snNative => {
1089                label => l('Native name'),
1090            },
1091            givenNameNative => {
1092                label => l('Native first name'),
1093            },
1094            sn => {
1095                label => l('Name'),
1096            },
1097            shadowWarning => { },
1098            shadowMin => { },
1099            shadowMax => { },
1100            shadowLastChange => { },
1101            shadowInactive => { },
1102            shadowFlag => { },
1103            otherTelephone => { },
1104            nickname => {
1105                label => l('Nickname'),
1106            },
1107            mobile => { },
1108            mail => {
1109                label => l('Email'),
1110            },
1111            labeledURI => { },
1112            jobType => { },
1113            ipPhone => { },
1114            initials => {
1115                label => l('Initials'),
1116            },
1117            homePhone => { },
1118            homeDirectory => {
1119                label => l('Home directory'),
1120            },
1121            halReference => {
1122                label => l('HAL id'),
1123            },
1124            grade => { },
1125            givenName => {
1126                label => l('First name'),
1127            },
1128            encryptedPassword => { },
1129            description => {
1130                label => l('Description'),
1131            },
1132            company => {
1133                label => l('Company'),
1134            },
1135            comment => {
1136                label => l('Comment'),
1137            },
1138            college => { },
1139            passwordLastSet => {
1140                ro => 1,
1141                label => l('Password set'),
1142            },
1143            currentEmployment => {
1144                managed => 1,
1145                ro => 1,
1146                reference => 'employment',
1147                get => sub {
1148                    my ($attr) = @_;
1149                    my $self = $attr->object;
1150
1151                    my $sth = $self->base->db->prepare_cached(
1152                        q{
1153                        select name from employment where firstday <= now() and
1154                        (lastday is null or lastday >= now() - '1 days'::interval) and "user" = ?
1155                        limit 1
1156                        }
1157                    );
1158                    $sth->execute($self->id);
1159                    my $res = $sth->fetchrow_hashref;
1160                    $sth->finish;
1161                    if ($res) {
1162                        return $res->{name}
1163                    } else {
1164                        return;
1165                    }
1166                },
1167            },
1168            nextEmployment => {
1169                managed => 1,
1170                ro => 1,
1171                reference => 'employment',
1172                get => sub {
1173                    my ($attr) = @_;
1174                    my $self = $attr->object;
1175
1176                    my $sth = $self->base->db->prepare_cached(
1177                        q{
1178                        select name from employment where firstday > now() and
1179                        (lastday is null or lastday >= now() - '1 days'::interval) and "user" = ?
1180                        limit 1
1181                        }
1182                    );
1183                    $sth->execute($self->id);
1184                    my $res = $sth->fetchrow_hashref;
1185                    $sth->finish;
1186                    if ($res) {
1187                        return $res->{name}
1188                    } else {
1189                        return;
1190                    }
1191                }
1192            },
1193            appliedEmployement => {
1194                hide => 1,
1195                reference => 'employment',
1196            },
1197            hosted => {
1198                formtype => 'CHECKBOX',
1199                label => l('Hosted'),
1200            },
1201
1202    };
1203
1204    my $employmentro = sub {
1205        my $setting = $base->config('employment_lock_user') || 'any';
1206
1207        for ($setting) {
1208            /^always$/ and return 1;
1209            /^never$/ and return 0;
1210
1211            !$_[0] and return 1;
1212
1213            /^any$/i and return $_[0]->listEmployment ? 1 : 0;
1214            /^active/i and do {
1215                return $_[0]->_get_c_field('currentEmployment')
1216                ? 1
1217                : $_[0]->_get_c_field('nextEmployment') ? 1 : 0;
1218            };
1219            /(\S+)=(\S+)/ and do {
1220                my $attr = $_[0]->_get_c_field($1);
1221                if (defined($attr)) {
1222                    if ($2 eq '*') {
1223                        return 1;
1224                    } elsif($2 eq $attr) {
1225                        return 1;
1226                    } else {
1227                        return 0;
1228                    }
1229                } else {
1230                    return 0;
1231                }
1232            };
1233        }
1234        return $_[0]->listEmployment ? 1 : 0; # default is any!
1235    };
1236
1237    foreach (qw(contratType managerContact company endcircuit department hosted)) {
1238        $attrs->{$_}{ro} = $employmentro;
1239    }
1240
1241    $attrs->{expire}{ro} = sub {
1242        my $expireOn = $base->config('expireOn') || '';
1243        if ($expireOn eq 'never') {
1244            return 0;
1245        }
1246
1247        $employmentro->($_[0]);
1248    };
1249
1250    $class->SUPER::_get_attr_schema($base, $attrs)
1251}
1252
1253sub _get_state {
1254    my ($self, $state) = @_;
1255    for ($state) {
1256        /^expired$/ and do {
1257            my $attribute = $self->attribute('expire');
1258            $attribute->check_acl('r') or return;
1259            my $sth = $self->db->prepare_cached(
1260                q{ select coalesce(expire < now(), false) as exp from "user"
1261                where "user".name = ?}
1262            );
1263            $sth->execute($self->id);
1264            my $res = $sth->fetchrow_hashref;
1265            $sth->finish;
1266            return $res->{exp} ? 1 : 0;
1267        };
1268    }
1269}
1270
1271=head2 listEmployment
1272
1273Return the ordered list of contract
1274
1275=cut
1276
1277sub listEmployment {
1278    my ($self) = @_;
1279
1280    my $sth = $self->base->db->prepare_cached(
1281        q{
1282        select name from employment where "user" = ?
1283        order by lastday desc NULLS first
1284        }
1285    );
1286    $sth->execute($self->id);
1287    my @list = ();
1288    while (my $res = $sth->fetchrow_hashref) {
1289        push(@list, $res->{name});
1290    }
1291
1292    @list
1293}
1294
1295
1296sub _computeStartEmployment {
1297    my ($self, $delay) = @_;
1298
1299    my $list_empl = $self->base->db->prepare_cached(q{
1300        SELECT *, (lastday is null or lastday >= now()) as "current" FROM employment WHERE "user" = ?
1301        order by firstday desc
1302        });
1303    $list_empl->execute($self->id);
1304    my $start;
1305    while (my $res = $list_empl->fetchrow_hashref) {
1306        if ($start) {
1307            my $prevend = DateTime->from_epoch(epoch => str2time($res->{lastday}));
1308            my $tstart = $start->clone;
1309            if ($delay) {
1310                $tstart->subtract(days => $delay);
1311            }
1312            if ($tstart->ymd gt $prevend->ymd) {
1313                last;
1314            }
1315        } else {
1316            if (!$res->{current}) {
1317                last;
1318            }
1319        }
1320        $start = DateTime->from_epoch(epoch => str2time($res->{firstday}));
1321        $start->set_time_zone( DateTime::TimeZone->new( name => 'local' ) );
1322    }
1323    $list_empl->finish;
1324
1325    if (!$start) {
1326        my $listold = $self->base->db->prepare_cached(q{
1327            SELECT min(firstday) as firstday FROM employment WHERE "user" = ? and
1328            lastday IS NOT NULL and lastday <= now() - '1 days'::interval
1329            });
1330        $listold->execute($self->id);
1331        my $res = $listold->fetchrow_hashref;
1332        if ($res && $res->{firstday}) {
1333            $start = DateTime->from_epoch(epoch => str2time($res->{firstday}));
1334            $start->set_time_zone( DateTime::TimeZone->new( name => 'local' ) );
1335        }
1336        $listold->finish;
1337    }
1338    return $start ? $start->iso8601 : undef
1339}
1340
1341sub _computeEndEmployment {
1342    my ($self, $delay) = @_;
1343
1344    my $list_empl = $self->base->db->prepare_cached(q{
1345        SELECT *, firstday <= now() as "current" FROM employment WHERE "user" = ? and
1346        (lastday is null or lastday >= now() - '1 days'::interval)
1347        order by firstday asc
1348        });
1349    $list_empl->execute($self->id);
1350    my $end;
1351    while (my $res = $list_empl->fetchrow_hashref) {
1352        if (!$res->{lastday}) {
1353            # Ultimate employment.
1354            $list_empl->finish;
1355            return undef;
1356        }
1357        if ($end) {
1358            my $nextstart = DateTime->from_epoch(epoch => str2time($res->{firstday}));
1359            my $tend = $end->clone;
1360            if ($delay) {
1361                $tend->add(days => $delay);
1362            }
1363            if ($tend->ymd lt $nextstart->ymd) {
1364                last;
1365            }
1366        } else {
1367            if (!$res->{current}) {
1368                last;
1369            }
1370        }
1371        $end = DateTime->from_epoch(epoch => str2time($res->{lastday}));
1372        $end->set_time_zone( DateTime::TimeZone->new( name => 'local' ) );
1373        $end->add(hours => 23, minutes => 59, seconds => 59);
1374    }
1375    $list_empl->finish;
1376
1377    if (!$end) {
1378        my $listold = $self->base->db->prepare_cached(q{
1379            SELECT max(lastday) as lastday FROM employment WHERE "user" = ? and
1380            lastday IS NOT NULL and lastday <= now() - '1 days'::interval
1381            });
1382        $listold->execute($self->id);
1383        my $res = $listold->fetchrow_hashref;
1384        if ($res && $res->{lastday}) {
1385            $end = DateTime->from_epoch(epoch => str2time($res->{lastday}));
1386            $end->set_time_zone( DateTime::TimeZone->new( name => 'local' ) );
1387            $end->add(hours => 23, minutes => 59, seconds => 59);
1388        } else {
1389            if (my $default = $self->base->config('unemployed_expire')) {
1390                $end = DateTime->from_epoch(epoch => str2time($default));
1391            }
1392        }
1393        $listold->finish;
1394    }
1395    return $end ? $end->iso8601 : undef
1396}
1397
13981;
1399
1400__END__
1401
1402=head1 SEE ALSO
1403
1404=head1 AUTHOR
1405
1406Olivier Thauvin, E<lt>olivier.thauvin@latmos.ipsl.frE<gt>
1407
1408=head1 COPYRIGHT AND LICENSE
1409
1410Copyright (C) 2008, 2009 CNRS SA/CETP/LATMOS
1411
1412This library is free software; you can redistribute it and/or modify
1413it under the same terms as Perl itself, either Perl version 5.10.0 or,
1414at your option, any later version of Perl 5 you may have available.
1415
1416=cut
Note: See TracBrowser for help on using the repository browser.