Changeset 861


Ignore:
Timestamp:
12/02/11 11:42:17 (12 years ago)
Author:
nanardon
Message:
  • reimport missing files from previous svn
Files:
108 added
104 edited

Legend:

Unmodified
Added
Removed
  • LATMOS-Accounts-Web/Changes

    r94 r861  
    11This file documents the revision history for Perl extension LATMOS::Accounts::Web. 
    22 
     32.0.0 
     4    - add support of nethost/netzone object 
     5 
     6    - add a "My" page in user page listing object they own 
     7 
     8    - add icons to quickly identify user's account status in list (temporary, 
     9      expired, unexported) 
     10 
     11    - add a department page in group page with a realistic view of the current 
     12      people in the department. The section appear only when group have 
     13      sutype=dpmt 
     14 
     15    - add link to objects when attributes have reference 
     16 
    3170.01  2009-05-12 03:23:51 
    4         - initial revision, generated by Catalyst 
     18    - initial revision, generated by Catalyst 
  • LATMOS-Accounts-Web/MANIFEST

    r757 r861  
    11Changes 
     2MANIFEST 
     3MANIFEST.skip 
    24Makefile.PL 
    35README 
    46etc/httpd/latmos-accounts-web.conf 
    57etc/init.d/latmos-accounts-web 
    6 inc/Module/AutoInstall.pm 
    7 inc/Module/Install/AutoInstall.pm 
    8 inc/Module/Install/Base.pm 
    9 inc/Module/Install/Can.pm 
    10 inc/Module/Install/Catalyst.pm 
    11 inc/Module/Install/Fetch.pm 
    12 inc/Module/Install/Include.pm 
    13 inc/Module/Install/Makefile.pm 
    14 inc/Module/Install/Metadata.pm 
    15 inc/Module/Install/Scripts.pm 
    16 inc/Module/Install/Win32.pm 
    17 inc/Module/Install/WriteAll.pm 
    18 inc/Module/Install.pm 
    198latmos-accounts-web.spec.in 
    209latmos_accounts_web.yml.in 
    2110lib/Catalyst/Authentication/Credential/La.pm 
     11lib/LATMOS/Accounts/Web/Controller/About.pm 
    2212lib/LATMOS/Accounts/Web/Controller/Ajax.pm 
    2313lib/LATMOS/Accounts/Web/Controller/Aliases.pm 
    2414lib/LATMOS/Accounts/Web/Controller/Create.pm 
    2515lib/LATMOS/Accounts/Web/Controller/Groups.pm 
    26 lib/LATMOS/Accounts/Web/Controller/MassEdit.pm 
     16lib/LATMOS/Accounts/Web/Controller/NetHosts.pm 
     17lib/LATMOS/Accounts/Web/Controller/NetZones.pm 
    2718lib/LATMOS/Accounts/Web/Controller/Root.pm 
    2819lib/LATMOS/Accounts/Web/Controller/Sites.pm 
     
    3627lib/LATMOS/Accounts/Web.pm 
    3728root/favicon.ico 
     29root/html/about/index.tt 
    3830root/html/ajax/attrvalues.tt 
    3931root/html/ajax/check_new_name.tt 
    4032root/html/ajax/check_ug_validity.tt 
    4133root/html/ajax/cracklib.tt 
     34root/html/ajax/displayattr.tt 
    4235root/html/ajax/objattrexist.tt 
    4336root/html/ajax/objexist.tt 
    4437root/html/ajax/rawattr.tt 
     38root/html/ajax/select_freeip_select.tt 
    4539root/html/aliases/index.tt 
    46 root/html/create/group.tt 
    47 root/html/create/user.tt 
     40root/html/create/default.tt 
    4841root/html/default.tt 
    4942root/html/departments/default.tt 
     
    5144root/html/departments/menu.tt 
    5245root/html/groups/default.tt 
     46root/html/groups/dpmt.tt 
    5347root/html/groups/index.tt 
    5448root/html/groups/menu.tt 
     
    6155root/html/login.tt 
    6256root/html/logout.tt 
    63 root/html/massedit/index.tt 
     57root/html/nethosts/default.tt 
     58root/html/nethosts/index.tt 
     59root/html/nethosts/menu.tt 
     60root/html/netzones/default.tt 
     61root/html/netzones/index.tt 
     62root/html/netzones/menu.tt 
    6463root/html/no_object.tt 
    6564root/html/sites/default.tt 
     
    7574root/html/users/mail.tt 
    7675root/html/users/menu.tt 
     76root/html/users/my.tt 
    7777root/html/users/passwd.tt 
     78root/static/icons/add.png 
     79root/static/icons/appointment-new.png 
     80root/static/icons/appointment-soon.png 
    7881root/static/icons/arrow-right.png 
     82root/static/icons/avatar-default.png 
     83root/static/icons/changes-prevent.png 
    7984root/static/icons/dialog-cancel.png 
     85root/static/icons/dialog-password.png 
     86root/static/icons/document-save-as.png 
     87root/static/icons/document-save.png 
     88root/static/icons/emblem-urgent.png 
     89root/static/icons/icon_edit.png 
     90root/static/icons/expired.png 
     91root/static/icons/gnome-session-logout.png 
     92root/static/icons/gnome-stock-mail-snd.png 
     93root/static/icons/gtk-about.png 
     94root/static/icons/gtk-cancel.png 
     95root/static/icons/gtk-close.png 
     96root/static/icons/gtk-delete.png 
     97root/static/icons/gtk-go-back-ltr.png 
     98root/static/icons/gtk-go-back-rtl.png 
     99root/static/icons/gtk-goto-first-ltr.png 
     100root/static/icons/gtk-goto-first-rtl.png 
     101root/static/icons/gtk-home.png 
     102root/static/icons/gtk-jump-to-rtl.png 
     103root/static/icons/locked.png 
     104root/static/icons/mail_forward.png 
     105root/static/icons/network-workgroup.png 
     106root/static/icons/preferences-desktop-wallpaper.png 
     107root/static/icons/stock_smiley-22.png 
     108root/static/icons/system-config-users.png 
     109root/static/icons/system-users.png 
    80110root/static/icons/user-group-delete.png 
    81111root/static/icons/user-group-new.png 
    82112root/static/icons/user-group-properties.png 
     113root/static/icons/user-info.png 
     114root/static/icons/user-invisible.png 
    83115root/static/icons/user-properties.png 
     116root/static/icons/video-display.png 
    84117root/static/icons/view-calendar-day.png 
     118root/static/icons/view-media-artist.png 
     119root/static/icons/xfce-internet.png 
    85120root/static/images/btn_120x50_built.png 
    86121root/static/images/btn_120x50_built_shadow.png 
     
    98133root/static/images/mail-mark-important.png 
    99134root/static/images/process-stop.png 
    100 root/static/images/view-media-artist.png 
    101135root/static/images/view-pim-contacts.png 
    102136root/static/js/CalendarPopup.js 
     
    114148t/02pod.t 
    115149t/03podcoverage.t 
     150t/controller_About.t 
    116151t/controller_Ajax.t 
    117152t/controller_Aliases.t 
     
    119154t/controller_Groups.t 
    120155t/controller_MassEdit.t 
     156t/controller_NetHost.t 
    121157t/controller_Sites.t 
    122158t/controller_Users.t 
  • LATMOS-Accounts-Web/Makefile.PL

    r552 r861  
    44all_from 'lib/LATMOS/Accounts/Web.pm'; 
    55 
    6 requires 'Catalyst' => '5.7015'; 
     6#requires 'Catalyst' => '5.7015'; 
    77requires 'Catalyst::Plugin::ConfigLoader'; 
    88requires 'Catalyst::Plugin::Static::Simple'; 
     
    2020 
    2121install_script glob('script/*.pl'); 
    22 auto_install; 
    23 WriteAll; 
     22#auto_install; 
     23WriteMakefile( 
     24    macro => {  
     25        DESTRPMDIR => '$(shell pwd)', 
     26    }, 
     27); 
    2428 
    2529package MY; 
     
    2731sub postamble { 
    2832    <<EOF; 
    29 .PHONY .= svnmanifest 
     33# .PHONY .= svnmanifest 
    3034 
    3135svnmanifest: 
     
    3943 
    4044rpm: \$(DISTVNAME).tar.gz latmos-accounts-web.spec 
    41 \tmkdir ./noarch || : 
     45\tmkdir \$(DESTRPMDIR)/noarch || : 
    4246\trpmbuild -ba --clean\\ 
    4347\t --define "_sourcedir `pwd`" \\ 
    4448\t --define "_specdir `pwd`" \\ 
    45 \t --define "_srcrpmdir `pwd`" \\ 
    46 \t --define "_rpmdir `pwd`" \\ 
     49\t --define "_srcrpmdir \$(DESTRPMDIR)" \\ 
     50\t --define "_rpmdir \$(DESTRPMDIR)" \\ 
     51\t latmos-accounts-web.spec 
     52 
     53svnrpm: \$(DISTVNAME).tar.gz latmos-accounts-web.spec 
     54\tmkdir \$(DESTRPMDIR)/noarch || : 
     55\trpmbuild -ba --clean\\ 
     56\t --define "_sourcedir `pwd`" \\ 
     57\t --define "_specdir `pwd`" \\ 
     58\t --define "_srcrpmdir \$(DESTRPMDIR)" \\ 
     59\t --define "_rpmdir \$(DESTRPMDIR)" \\ 
     60\t --define "svnrelease `LC_ALL=C svn info | grep '^Revision:' | sed 's/Revision: //'`" \\ 
    4761\t latmos-accounts-web.spec 
    4862 
  • LATMOS-Accounts-Web/latmos-accounts-web.spec.in

    r737 r861  
    22%define name       latmos-accounts-web 
    33%define version    @VERSION@ 
    4 %define release    %mkrel 1 
     4%define release    %mkrel %{?svnrelease:0.%{svnrelease}}%{?!svnrelease:1} 
    55 
    66Name:       %{name} 
     
    8181fi 
    8282 
     83%triggerpostun -- latmos-accounts 
     84/sbin/service %name restart 
     85 
    8386%files 
    8487%defattr(-,root,root) 
  • LATMOS-Accounts-Web/latmos_accounts_web.yml.in

    r97 r861  
    11--- 
    22name: LATMOS::Accounts::Web 
     3# config: /etc/latmos-accounts/latmos-accounts.ini 
     4# company: COMPANY NAME 
  • LATMOS-Accounts-Web/lib/LATMOS/Accounts/Web.pm

    r860 r861  
    2424    /; 
    2525 
    26 our $VERSION = '0.0.11'; 
     26our $VERSION = '2.0.0'; 
    2727 
    2828# Configure the application.  
    29 # 
    30 # Note that settings in LATMOS::Accounts::Web.yml (or other external 
    31 # configuration file that you set up manually) take precedence 
    32 # over this when using ConfigLoader. Thus configuration 
    33 # details given here can function as a default configuration, 
    34 # with a external configuration file acting as an override for 
    35 # local deployment. 
     29 
     30my $config_file = '/etc/latmos-accounts/latmos-accounts-web.yml'; 
     31if (-r $config_file ) { 
     32    __PACKAGE__->config( 'Plugin::ConfigLoader' => {  
     33            file => $config_file  
     34        }  
     35    ); 
     36} 
    3637 
    3738# http://stackoverflow.com/questions/1664816/is-there-a-way-to-force-c-urifor-in-catalyst-to-generate-a-uri-that-begins-wit 
  • LATMOS-Accounts-Web/lib/LATMOS/Accounts/Web/Controller.pm

    r718 r861  
    2525 
    2626    if (!$c->user_exists) { 
    27         if ($c->req->path ne 'login') { 
    28             $c->forward('/login'); 
     27        # No need to login for About section 
     28        if ($c->namespace ne 'about') { 
     29            if ($c->req->path ne 'login') { 
     30                $c->forward('/login'); 
     31            } 
     32            return; 
    2933        } 
    3034    } else { 
    31         $c->model('Accounts')->db->connect($c->user->{username}, 
     35        $c->model('Accounts')->db->connect( 
     36            $c->user->{username}, 
    3237            $c->user->{password}); 
    3338    } 
    34      
    35     my $menu = ''; 
    36     my @menus = ( 
    37         [ 'users' => 'Utilisateurs' ], 
    38         ($c->model('Accounts')->db->check_acl('user', '@CREATE', 'w') 
    39             ? [ 'create/user' => 'Nouvel Util.' ] 
    40             : ()), 
    41         [ 'groups' => 'Groupes' ], 
    42         ($c->model('Accounts')->db->check_acl('group', '@CREATE', 'w') 
    43             ? [ 'create/group' => 'Nouveau Groupe' ] 
    44             : ()), 
    45         [ 'sites' => 'Sites' ], 
    46         [ 'aliases' => 'Alias Mail' ], 
    47     ); 
    48     foreach(@menus) { 
    49         $menu .= sprintf( 
    50             q{<a href="%s"><span%s>%s</span></a>}, 
    51             $c->uri_for('/' . $_->[0]), 
    52             ($c->req->path =~ m:^$_->[0]: ? ' id="actif"' : ''), 
    53             $_->[1], 
    54         ); 
    55  
    56     } 
    57     $c->stash->{mainmenu} = $menu; 
    5839} 
    5940 
  • LATMOS-Accounts-Web/lib/LATMOS/Accounts/Web/Controller/Ajax.pm

    r755 r861  
    4545} 
    4646 
     47sub displayattr : Local { 
     48    my ($self, $c, $otype) = @_; 
     49    my $attribute = $c->model('Accounts')->db->attribute($otype, 
     50        $c->req->param('attr')) or return; 
     51    $c->stash->{value} = $attribute->display($c->req->param('id')); 
     52} 
     53 
    4754sub attrvalues : Local { 
    4855    my ($self, $c, $otype, $attr) = @_; 
     
    6370 
    6471    $c->stash->{'exists'} = join(', ', $obj->get_attributes($c->req->param('attr') || 
    65             'displayName')) if($obj); 
     72            'displayName') || $obj->id) if($obj); 
    6673} 
    6774 
     
    8895    my ($self, $c, $otype, $attr) = @_; 
    8996    my $base = $c->model('Accounts')->db; 
    90     my $val = $c->req->param('val'); 
     97    my $attribute = $base->attribute($otype, $attr) or return; 
     98    my $val = $attribute->input($c->req->param('val')); 
    9199    my @obj = $val ? $base->search_objects($otype, "$attr=$val") : (); 
    92100 
     
    125133} 
    126134 
     135sub select_freeip_select : Local { 
     136    my ($self, $c) = @_; 
     137 
     138} 
     139 
     140sub goto : Local { 
     141    my ($self, $c) = @_; 
     142 
     143    $c->res->redirect( 
     144        $c->uri_for('/' . $c->req->param('otype') . 's', $c->req->param('goto'), 
     145        $c->req->param('subform')) 
     146    ); 
     147    $c->stash->{template} = 'no_object.tt'; 
     148} 
     149 
     150 
    127151sub end : Private { 
    128152    my ( $self, $c ) = @_; 
  • LATMOS-Accounts-Web/lib/LATMOS/Accounts/Web/Controller/Aliases.pm

    r641 r861  
    2929    my @name = $c->req->param('name'); 
    3030    my @forward = $c->req->param('forward'); 
     31    $c->stash->{page}{title} = "Gestion des alias"; 
    3132    foreach my $idx (0 .. scalar(@name) - 1) { 
    3233 
  • LATMOS-Accounts-Web/lib/LATMOS/Accounts/Web/Controller/Create.pm

    r765 r861  
    55use base 'LATMOS::Accounts::Web::Controller'; 
    66use LATMOS::Accounts::Utils; 
     7use LATMOS::Accounts::Log; 
    78 
    89=head1 NAME 
     
    2930} 
    3031 
    31 sub user : Local { 
    32     my ( $self, $c ) = @_; 
    33  
     32sub default : LocalPath { 
     33    my ($self, $c, undef, $otype ) = @_; 
    3434    my $base = $c->model('Accounts')->db; 
    35     $c->stash->{form} = $c->model('AttrForms', undef, 'user', $base); 
    36     for ($c->req->param('step') || '') { 
    37         /^1$/ and do { 
    38             $c->stash->{step} = 2; 
    39             my $acc = $c->model('Accounts')->accounts; 
    40             foreach ($acc->Parameters('_defattr_')) { 
    41                 if (/^user\.(.*)/) { 
    42                     $c->req->params->{$1} ||= $acc->val('_defattr_', $_); 
    43                 } 
    44             } 
    45             $c->req->params->{exported} = 1; 
    46             if (! $c->req->params->{id}) { 
    47                 for (1) { 
    48                     my $login; 
    49                     if ($c->req->param('sn')) { 
    50                         $login = lc(to_ascii($c->req->param('sn'))); 
    51                         length($login) > 10 and $login = substr($login, 0, 8); 
    52                         $base->get_object('user', $login) or do { 
    53                             $c->req->params->{id} = $login; 
    54                             last; 
    55                         }; 
    56                         if ($c->req->param('givenName')) { 
    57                             length($login) > 8 and $login = substr($login, 0, 8); 
    58                             $login .= substr(lc(to_ascii($c->req->param('givenName'))), 0, 1); 
    59                             $base->get_object('user', $login) or do { 
    60                                 $c->req->params->{id} = $login; 
    61                                 last; 
    62                             }; 
    63                         } 
    64                     } 
    65                 } 
    66  
    67                 my $mailid = $c->req->params->{givenName} && $c->req->params->{sn} 
    68                 ? sprintf('%s.%s', 
    69                     to_ascii(lc($c->req->params->{givenName})), 
    70                     to_ascii(lc($c->req->params->{sn})),) 
    71                 : undef; 
    72  
    73                 if ($mailid && 
    74                     $base->is_supported_object('aliases') && 
    75                     ! $base->get_object('aliases', $mailid)) { 
    76                     if ($base->get_field_name('user', 'mail', 'write')) { 
    77                         if ($base->{defattr}{'user.maildomain'}) { 
    78                             $c->req->params->{mail} ||= sprintf('%s@%s', 
    79                                 $mailid, 
    80                                 $base->{defattr}{'user.maildomain'}); 
    81                         } 
    82                     } 
    83                     if ($base->get_field_name('user', 'aliases', 'write')) { 
    84                         $c->req->params->{aliases} ||= $mailid; 
    85                     } 
    86                     warn $base->get_field_name('user', 'revaliases', 'write'); 
    87                     if ($base->get_field_name('user', 'revaliases', 'write')) { 
    88                         $c->req->params->{revaliases} ||= $mailid; 
    89                     } 
    90                 } 
    91             } 
    92             last; 
    93         }; 
    94         /^2$/ and do { 
    95             $c->stash->{step} = 2; 
    96             $c->req->params->{id} or return; 
    97             $base->get_object('user', $c->req->params->{id}) and do { 
    98                 $c->stash->{idexists} = 1; 
    99                 return; 
    100             }; 
    101             $base->create_c_object('user', $c->req->params->{id}, 
    102                 %{ $c->req->params }, 
    103                 exported => $c->req->param('exported') ? 1 : 0, 
    104             ) or return; 
    105             $base->commit; 
    106             $c->res->redirect($c->uri_for('/users', $c->req->params->{id})); 
    107             last; 
    108         }; 
     35    my ($step) = $c->req->param('step'); 
     36    my $form = $c->model('AttrForms', undef, $otype, $base); 
     37    my ($status, $info); 
     38    $c->stash->{page}{title} = "Ajouter un objet / $otype"; 
     39    if ($step) { 
     40        $info = $c->session->{ochelper}; 
    10941    } 
     42    if ($info->{name}{ask}) { 
     43        $info->{name}{content} = $c->req->param('_name'); 
     44    } 
     45    foreach my $attr (@{$info->{ask} || []}) { 
     46        $info->{contents}{$attr} = $c->req->param($form->attr_field_name($attr)); 
     47    } 
     48    my $ochelper = $base->ochelper($otype); 
     49    ($status, $info) = $ochelper->step($info); 
     50     
     51    if ($status eq 'CREATED') { 
     52        $base->commit; 
     53        $c->res->redirect($c->uri_for('/' . $otype . 's', 
     54                $info->{name}{content})); 
     55    } elsif ($status eq 'ERROR') { 
     56        # On error, restart the process 
     57        $c->stash->{page}{error} = 
     58            'Erreur lors de la création de l\'objet: ' . 
     59            LATMOS::Accounts::Log::lastmessage(LA_ERR); 
     60        foreach my $attr (@{$info->{ask} || []}) { 
     61            $c->req->params->{$form->attr_field_name($attr)} = $info->{contents}{$attr}; 
     62        } 
     63        $info->{step} = 0; # reset 
     64        ($status, $info) = $ochelper->step($info); 
     65    } else { 
     66        foreach my $attr (@{$info->{ask} || []}) { 
     67            $c->req->params->{$form->attr_field_name($attr)} = $info->{contents}{$attr}; 
     68        } 
     69    } 
     70    $c->stash->{form} = $form; 
     71    $c->stash->{ochelper} = $info;  
     72    $c->session->{ochelper} = $info; 
    11073} 
    11174 
    112 sub group : Local { 
    113     my ( $self, $c ) = @_; 
    114  
    115     my $base = $c->model('Accounts')->db; 
    116     $c->stash->{form} = $c->model('AttrForms', undef, 'group', $base); 
    117     if (!exists($c->req->params->{id})) { 
    118         $c->req->params->{exported} = 1; 
    119     } 
    120  
    121     if ($c->req->params->{id}) { 
    122         $base->get_object('group', $c->req->params->{id}) and do { 
    123             $c->stash->{idexists} = 1; 
    124             return; 
    125         }; 
    126         $base->create_c_object('group', $c->req->params->{id}, 
    127             %{ $c->req->params }, 
    128             exported => $c->req->param('exported') ? 1 : 0, 
    129         ) or return; 
    130         $base->commit; 
    131         $c->res->redirect($c->uri_for('/groups', $c->req->params->{id})); 
    132     } 
    133 } 
    13475 
    13576=head1 AUTHOR 
  • LATMOS-Accounts-Web/lib/LATMOS/Accounts/Web/Controller/Groups.pm

    r718 r861  
    2727    $c->stash->{ofilter} = $c->model('AttrFilter', 'group'); 
    2828    $c->stash->{groupslist} = [  map { $_->id } @{ $c->stash->{objectslist} } ]; 
     29    $c->stash->{page}{title} = "Liste des groupes"; 
    2930 
    3031} 
     
    3536    my $base = $c->model('Accounts')->db; 
    3637 
     38    $c->stash->{page}{title} = "Groupe :: $groupname"; 
    3739    $c->stash->{groupname} = $groupname; 
    3840    $c->stash->{group} = $base->get_object('group', $groupname) or do { 
     
    6567            last; 
    6668        }; 
     69        /^dpmt$/ and do { 
     70            $c->stash->{template} = 'groups/dpmt.tt'; 
     71            my @filter = (); 
     72            push(@filter, 'active=*') if (!$c->req->param('inactive')); 
     73            push(@filter, 'mail=*') if ($c->req->param('mail')); 
     74            push(@filter, 'company=' . $c->req->param('company')) if 
     75                ($c->req->param('company')); 
     76            $c->stash->{dpmt} = $groupname; 
     77            $c->stash->{odpmt} = $c->stash->{group}; 
     78            $c->stash->{user} = [ $base->search_objects('user', 
     79                    'department=' . $c->stash->{dpmt}, 
     80                    @filter, 
     81                ) ]; 
     82            foreach my $u ($base->search_objects('user', 
     83                    'memberOf=' . $c->stash->{dpmt}, 
     84                    @filter, 
     85                )) { 
     86                push(@{$c->{stash}->{guser}}, $u) 
     87                unless(grep { $u eq $_ } @{$c->stash->{user}}); 
     88            } 
     89            last; 
     90        }; 
    6791 
    6892        $c->stash->{form} = $c->model('AttrForms', 'group' . $c->stash->{subform}, $c->stash->{group}); 
  • LATMOS-Accounts-Web/lib/LATMOS/Accounts/Web/Controller/Sites.pm

    r718 r861  
    2727    $c->stash->{ofilter} = $c->model('AttrFilter', 'site'); 
    2828    $c->stash->{siteslist} = [  map { $_->id } @{ $c->stash->{objectslist} } ]; 
     29    $c->stash->{page}{title} = "Liste des sites"; 
    2930} 
    3031 
     
    3435    my $base = $c->model('Accounts')->db; 
    3536 
     37    $c->stash->{page}{title} = "Site :: $sitename"; 
    3638    $c->stash->{sitename} = $sitename; 
    3739    $c->stash->{site} = $base->get_object('site', $sitename) or do { 
  • LATMOS-Accounts-Web/lib/LATMOS/Accounts/Web/Controller/Users.pm

    r759 r861  
    4343        $c->stash->{initials} = [ sort keys %initials ]; 
    4444    } 
     45    $c->stash->{page}{title} = 'Listes des utilisateurs (' . scalar(@{ 
     46                $c->stash->{objectslist} }) . ')'; 
    4547    $c->stash->{userslist} = \@userlist; 
    4648} 
     
    5153    my $base = $c->model('Accounts')->db; 
    5254 
     55    $c->stash->{page}{title} = "Utilisateur :: $username"; 
    5356    $c->stash->{username} = $username; 
    5457    $c->stash->{user} = $base->get_object('user', $username) or do { 
     
    5760    }; 
    5861    $c->stash->{subform} = $subform || ''; 
     62    $c->stash->{page}{title} = "Utilisateur :: $username"; 
    5963 
    6064    for ($subform || '') { 
     
    155159            last; 
    156160        }; 
     161        /^my$/ and do { 
     162            $c->stash->{db} = $base; 
     163            $c->stash->{template} = 'users/my.tt'; 
     164        }; 
    157165        /^dump$/ and do { 
    158166            $c->stash->{db} = $base; 
  • LATMOS-Accounts-Web/lib/LATMOS/Accounts/Web/Model/Accounts.pm

    r791 r861  
    5656} 
    5757 
     58sub object_navigate { 
     59    my ($self, $otype, $id, @filter) = @_; 
     60 
     61    my @list = $self->db->search_objects($otype, @filter); 
     62 
     63    my $i = 0; 
     64    for($i = 0; $i <= $#list; $i++) { 
     65        $list[$i] eq $id and last; 
     66    } 
     67 
     68    my %ptr = (); 
     69    $ptr{oprev} = $list[$i-1] if ($i > 0); 
     70    $ptr{'onext'} = $list[$i+1] if ($i < $#list); 
     71    $ptr{ofirst} = $list[0] if ($i > 1); 
     72    $ptr{'olast'} = $list[$#list] if ($i < $#list -1); 
     73    $ptr{list} = \@list; 
     74 
     75    return \%ptr; 
     76} 
     77 
    5878# Such function must not be here, but in LATMOS::Accounts 
    5979# But code does not allow this at time 
  • LATMOS-Accounts-Web/lib/LATMOS/Accounts/Web/Model/AttrFilter.pm

    r638 r861  
    1919    group => [ qw(cn description gidNumber sutype) ], 
    2020    site => [ qw(l) ], 
     21    nethost => [ qw(name cname otherName ip macaddr owner serialNumber) ], 
     22    netzone => [ qw(net group type site) ], 
    2123}; 
    2224 
  • LATMOS-Accounts-Web/lib/LATMOS/Accounts/Web/Model/AttrForms.pm

    r804 r861  
    44use warnings; 
    55use base 'Catalyst::Model'; 
     6use LATMOS::Accounts::Log; 
    67 
    78=head1 NAME 
     
    3940    sutype => [ 'Structure admin.', 'select-N:sutype' ], 
    4041    exported => [ 'Propagé', 'label' ], 
     42    unexported => [ 'Caché' ], 
    4143    locked => [ 'Vérouillé', 'checkbox:l' ], 
    4244    isMainAddress => [ 'Adresse principale', 'checkbox' ], 
     
    5456    contratType => [ 'Type de contrat', 'select-N:group/sutype=contrattype' ], 
    5557    managerContact => [ 'Contact' ], 
     58    owner => [ 'Propriétaire' ], 
     59    description => [ 'Description' ], 
     60    name => [ 'Nom' ], 
     61    net => [ "Réseau" ], 
     62    macaddr => [ "Adresse Ethernet" ], 
     63    noDynamic => [ "Pas d'adressage dyn." ], 
     64    cname => [ "Alias (CName)" ], 
     65    type => [ "Type" ], 
     66    netExclude => [ "Réseau exclus" ], 
     67    output => [ "Sortie" ], 
     68    template => [ "ModÚle" ], 
     69    outputD => [ "Sortie" ], 
     70    templateD => [ "ModÚle" ], 
     71    group => [ "Groupe" ], 
     72    allow_dyn => [ "DHCP dynamique" ], 
     73    ipCount => [ "Nb d'IP" ], 
     74    freeIPCount => [ "Nb d'IP libres" ], 
     75    dnsRevision => [ "Révision DNS" ], 
     76    lastUpdate => [ "DerniÚre mise à jour "], 
     77    otherName => [ "Autres noms (A)" ], 
     78    'reverse' => [ "Forcer le reverse à" ], 
     79    dynFrom => [ 'Sans Ip depuis' ], 
     80    siteNick => [ 'Acronyme' ], 
     81    serialNumber => [ 'N° de série' ], 
     82    snNative => [ 'Nom d\'origine' ], 
     83    givenNameNative => [ 'Prénom d\'origine' ], 
     84    wWWHomePage => [ 'Site Web' ], 
     85    halReference => [ 'Référence HAL' ], 
    5686}; 
    5787 
     
    6494            mail initials nickname 
    6595            locked 
    66             exported 
    6796            create 
    6897            date 
     
    76105        ) ], 
    77106    }, 
    78     userstatus => { 
    79         name => 'Status', 
     107    userstatut => { 
     108        name => 'Statut', 
    80109        attrs => [ qw( 
    81110            company 
     
    87116        ) ], 
    88117    }, 
     118    usermy => { 
     119        name => 'My', 
     120        attrs => [ qw( 
     121            snNative 
     122            givenNameNative 
     123            wWWHomePage 
     124            halReference 
     125        ) ], 
     126    }, 
    89127    site => { 
    90128        name => 'Site', 
    91129        attrs => [ qw( 
    92130            description 
     131            siteNick 
    93132            streetAddress 
    94133            postOfficeBox 
     
    115154            site 
    116155            co 
    117             exported 
     156            unexported 
    118157            description 
    119158        ) ], 
     
    124163            gidNumber description 
    125164            managedBy 
    126             sutype exported 
     165            sutype 
    127166            create 
    128167            date 
     168        ) ], 
     169    }, 
     170    nethost => { 
     171        name => 'Ordinateur', 
     172        attrs => [ qw( 
     173            name 
     174            description 
     175            serialNumber 
     176            owner 
     177            ip 
     178            macaddr 
     179            noDynamic 
     180            cname 
     181            otherName 
     182            reverse 
     183            create 
     184            date 
     185            unexported 
     186        ) ], 
     187    }, 
     188    netzone => { 
     189        name => 'Zone réseau', 
     190        attrs => [ qw( 
     191            name 
     192            description 
     193            type 
     194            net 
     195            netExclude 
     196            outputD 
     197            templateD 
     198            site 
     199            allow_dyn 
     200            dynFrom 
     201            domain 
     202            ipCount 
     203            freeIPCount 
     204            create 
     205            date 
     206            dnsRevision 
     207            lastUpdate 
     208            unexported 
    129209        ) ], 
    130210    }, 
     
    179259    my ($self, $for) = @_; 
    180260    grep { $_ } 
    181     grep { $self->base->check_acl($self->{object} || $self->otype, $_, 'r') } 
    182     grep { $self->base->get_field_name($self->otype, $_, $for || 'a') } 
     261    grep { $self->base->attribute($self->otype, $_) } 
    183262    @{ $forms->{$self->{form}}->{attrs} }; 
    184263} 
     
    196275    my ($self, $attr) = @_; 
    197276    return $self->{c}->req->param($attr) || 
    198         ($self->{object} ? $self->{object}->get_c_field($attr) : '') 
    199 } 
    200  
    201 sub attr_field { 
    202     my ($self, $attr, $type) = @_; 
    203     my $modallow = $self->base->check_acl($self->{object} 
    204         ? ($self->{object}, $attr, 'w') 
    205         : ($self->otype, '@CREATE', 'w')); 
    206     $type ||= $attrs->{$attr}[1] || ''; 
    207     if (!($self->base->get_field_name($self->otype, $attr, 'w') && $modallow)) { 
    208         $type = 'label'; 
    209     } 
    210     # exception: gidNumber is used also in group, but we don't want 
    211     # group list here, really the number ! 
    212     $type = $modallow ? 'text-U:6' : 'label' if ($self->{otype} eq 'group' && $attr eq 'gidNumber'); 
    213     $type ||= 'text'; 
    214      
    215     my $htmlname = $self->escape(($self->{object}  
     277        ($self->{object} ? $self->{object}->get_attributes($attr) : '') 
     278} 
     279 
     280sub attr_field_name { 
     281    my ($self, $attr) = @_; 
     282    return ($self->{object} 
    216283            ? $self->{object}->id . '_' 
    217284            : '' 
    218285        ) . $attr 
    219     ); 
    220     for ($type) { 
    221         /^textarea$/ and return sprintf( 
    222             '<textarea id="%s" name="%s" cols="40">%s</textarea>', 
    223             $self->escape($htmlname), 
    224             $self->escape($htmlname), 
    225             $self->escape($self->attr_raw_value($attr) || ''), 
    226         ); 
    227         /^label$/ and do { 
    228             my $field = $self->escape( 
    229                 $self->attr_raw_value($attr) 
    230             ); 
    231             $field =~ s/\n/<br>/g; 
    232             return $field . sprintf('<input type="hidden" name="%s" value="%s">', 
    233                 $self->escape($htmlname), ($self->attr_raw_value($attr) || '')); 
    234         }; 
    235         /^date$/ and do { 
    236             my ($date, $time) = split(/ /, $self->attr_raw_value($attr) || ''); 
    237             if ($date && $date =~ /^(\d+)-(\d+)-(\d+)$/) { 
    238                 $date = "$3/$2/$1"; 
    239             } 
    240             my $html = "\n" . q{<SCRIPT LANGUAGE="JavaScript" ID="js13"> 
    241             var cal13 = new CalendarPopup(); 
    242             </SCRIPT>} . "\n"; 
    243             $html .= sprintf( 
    244                 '<input type="text" id="%s" name="%s" value="%s" size="12">', 
    245                 $self->escape($htmlname), 
    246                 $self->escape($htmlname), 
    247                 $self->escape($date) 
    248             ); 
    249             $html .= q{<DIV ID="testdiv1" STYLE="position:absolute;visibility:hidden;background-color:white;layer-background-color:white;"></DIV>}; 
    250             $html .= qq| 
    251             <A HREF="#" 
    252                 onClick="cal13.select(document.forms[0].$htmlname,'${htmlname}_anc','dd/MM/yyyy');return false;" 
    253                 TITLE="cal13.select(document.forms[0].$htmlname,'${htmlname}_anc','dd/MM/yyyy');return false;" 
    254                 NAME="${htmlname}_anc" ID="${htmlname}_anc"> 
    255                 <img src="| . $self->{c}->uri_for(qw(/static icons view-calendar-day.png)) 
    256                 . qq{" style="ref"></A> 
    257                 } . "\n"; 
    258             return $html; 
    259         }; 
    260         /^checkbox(?::(\w+))?$/ and do { 
    261             my $options = $1 || ''; 
    262             my $text = sprintf('<input type="checkbox" name="%s"%s>', 
    263                 $self->escape($htmlname), 
    264                 $self->attr_raw_value($attr) ? '  checked="yes"' : '' 
    265             );  
    266             $text .= sprintf('<input type="hidden" name="%s">', 
    267                 $self->escape($htmlname)); 
    268             if ($options =~ /l/) { 
    269                 $text .= $self->attr_raw_value($attr) 
    270                     ? ' ' . $self->attr_raw_value($attr) 
    271                     : '';  
    272             } 
    273             return $text; 
    274         }; 
    275         /^select(-\w+)?:([^:\/]+)(?:\/([^:]+))?(?::(.*))?/ and do { 
    276             my $options = $1 || ''; 
    277             my $otype = $2; 
    278             my $filter = $3; 
    279             my $keyfield = $4; 
    280             my $observe_keyfield = $keyfield || 'displayName'; 
    281             my $select = sprintf('<select id="%s" name="%s">', 
    282                 $self->escape($htmlname), 
    283                 $self->escape($htmlname)) . "\n"; 
    284             $select .= '<option value="">--</option>' . "\n" if ($options =~ /N/); 
    285             my $value = $self->attr_raw_value($attr) || ''; 
    286             my $initial_observed = ''; 
    287             foreach my $id (sort $filter 
    288                 ? $self->base->search_objects($otype, $filter) 
    289                 : $self->base->list_objects($otype)) { 
    290                 my $val = $id; 
    291                 if ($keyfield) { 
    292                     my $obj = $self->base->get_object($otype, $id) or next; 
    293                     $val = $obj->get_c_field($keyfield); 
    294                 } 
    295                 $select .= sprintf( 
    296                     '    <option value="%s"%s>%s</option>', 
    297                     $self->escape($val || ''), 
    298                     $value eq $val ? ' selected="selected"' : '', 
    299                     $self->escape($id || ''), 
     286} 
     287 
     288sub attr_field { 
     289    my ($self, $attr, $type) = @_; 
     290 
     291    my $attribute = ($self->{object} 
     292        ? $self->{object}->attribute($attr) 
     293        : $self->base->attribute($self->otype, $attr)) or return; 
     294 
     295    my $htmlname = $self->escape($self->attr_field_name($attr)); 
     296 
     297    my @html_fields; 
     298    foreach my $attr_raw_value ( 
     299        $attribute->{multiple} 
     300            ? ((grep { $_ } $self->attr_raw_value($attr)), 
     301                $attribute->readonly 
     302                    ? () 
     303                    : ('') 
     304            ) 
     305            : ($self->attr_raw_value($attr))) { 
     306 
     307        my $html_id = $htmlname . 
     308            (scalar(@html_fields) ? scalar(@html_fields) : ''); 
     309 
     310        my $html_field = ''; 
     311        for ($attribute->form_type) { 
     312            /^textarea$/i and do { 
     313                $html_field = sprintf( 
     314                    '<textarea id="%s" name="%s" cols="40">%s</textarea>', 
     315                    $self->escape($html_id), 
     316                    $self->escape($htmlname), 
     317                    $self->escape($attr_raw_value || ''), 
    300318                ); 
    301                 $select .= "\n"; 
    302                 if($value eq $val) { 
    303                     if (my $obj = $self->base->get_object($otype, $id)) { 
    304                         $initial_observed = $obj->get_c_field($observe_keyfield) 
    305                         || ''; 
    306                     } 
    307                 } 
    308             } 
    309             $select .= "</select>\n"; 
    310             $select .= $self->{c}->prototype->observe_field( $htmlname, { 
    311                 update => "${htmlname}_span", 
    312                 url => $self->{c}->uri_for('/ajax', 'rawattr', $otype), 
    313                 frequency => 1, 
    314                 with   => "'attr=" . $observe_keyfield . 
    315                 "&id='+element.options[element.selectedIndex].text", 
    316             }) . 
    317             qq|<span id="${htmlname}_span">$initial_observed</span>|; 
    318             return $select; 
    319         }; 
    320         /^text(-\w+)?(?::(\d+))?/ and do { 
    321             my $flag = $1 || ''; 
    322             if (my @allowed = $self->base->obj_attr_allowed_values( 
    323                     $self->{otype}, $attr)) { 
    324                 my $cvalue = $self->attr_raw_value($attr); 
    325                 my $textf = sprintf('<select  id="%s" name="%s">', 
     319                last; 
     320            }; 
     321            /^label$/i and do { 
     322                $attr_raw_value or last; 
     323                $html_field = $self->escape($attr_raw_value); 
     324                $html_field =~ s/\n/<br>/g; 
     325                $html_field .= sprintf('<input type="hidden" name="%s" value="%s">', 
     326                    $self->escape($htmlname), ($attr_raw_value || '')); 
     327                last; 
     328            }; 
     329            /^date$/i and do { 
     330                my ($date, $time) = split(/ /, $self->attr_raw_value($attr) || ''); 
     331                if ($date && $date =~ /^(\d+)-(\d+)-(\d+)$/) { 
     332                    $date = "$3/$2/$1"; 
     333                } 
     334                my $html = "\n" . q{<SCRIPT LANGUAGE="JavaScript" ID="js13"> 
     335                var cal13 = new CalendarPopup(); 
     336                </SCRIPT>} . "\n"; 
     337                $html .= sprintf( 
     338                    '<input type="text" id="%s" name="%s" value="%s" size="12">', 
     339                    $self->escape($html_id), 
    326340                    $self->escape($htmlname), 
     341                    $self->escape($date) 
     342                ); 
     343                $html .= q{<DIV ID="testdiv1" STYLE="position:absolute;visibility:hidden;background-color:white;layer-background-color:white;"></DIV>}; 
     344                $html .= qq| 
     345                <A HREF="#" 
     346                    onClick="cal13.select(document.getElementById('$html_id'),'${html_id}_anc','dd/MM/yyyy');return false;" 
     347                    TITLE="Date" 
     348                    NAME="${html_id}_anc" ID="${html_id}_anc"> 
     349                    <img class="attr" src="| . $self->{c}->uri_for(qw(/static icons view-calendar-day.png)) 
     350                    . qq{" style="ref"></A> 
     351                    } . "\n"; 
     352                $html_field = $html; 
     353                last; 
     354            }; 
     355            /^checkbox(?::(\w+))?$/i and do { 
     356                my $options = $1 || ''; 
     357                $html_field = sprintf('<input type="checkbox" name="%s"%s>', 
     358                    $self->escape($htmlname), 
     359                    $attr_raw_value ? '  checked="yes"' : '' 
     360                );  
     361                $html_field .= sprintf('<input type="hidden" name="%s">', 
     362                    $self->escape($htmlname)); 
     363                if ($attribute->form_option('rawvalue')) { 
     364                    $html_field .= $attr_raw_value 
     365                        ? ' ' . $attr_raw_value 
     366                        : '';  
     367                } 
     368                last; 
     369            }; 
     370            /^LIST/ and do { 
     371                my $options = $1 || ''; 
     372                my $select = sprintf('<select id="%s" name="%s">', 
     373                    $self->escape($html_id), 
    327374                    $self->escape($htmlname)) . "\n"; 
    328                 $textf .= '<option value="">--</option>' . "\n"; 
    329                 foreach (sort @allowed) { 
    330                     $textf .= sprintf('<option value="%s"%s>%s</option>' . "\n", 
    331                         $self->escape($_), 
    332                         (($cvalue || '') eq $_ ? ' selected="selected"' : ''), 
    333                         $self->escape($_), 
     375                $select .= '<option value="">--</option>' . "\n" 
     376                    unless($attribute->mandatory); 
     377                my $value = $attr_raw_value || ''; 
     378                my $initial_observed = ''; 
     379                my @valslist; 
     380                foreach my $val (sort $attribute->can_values) { 
     381                    push(@valslist, { 
     382                        val => $val, 
     383                        disp => $attribute->display($val || ''), 
     384                    }); 
     385                } 
     386                foreach (sort { $a->{disp} cmp $b->{disp} } @valslist) { 
     387                    $select .= sprintf( 
     388                        '    <option value="%s"%s>%s</option>', 
     389                        $self->escape($_->{val} || ''), 
     390                        $value eq $_->{val} ? ' selected="selected"' : '', 
     391                        $self->escape($_->{disp} || ''), 
    334392                    ); 
    335                 } 
    336                 $textf .= "</select>\n"; 
    337                 return $textf; 
    338             } else { 
    339                 my $textf = sprintf( 
     393                    $select .= "\n"; 
     394                } 
     395                $select .= "</select>\n"; 
     396 
     397                $html_field = $select; 
     398                last; 
     399            }; 
     400            /^text(-\w+)?(?::(\d+))?/i and do { 
     401                my $flag = $1 || ''; 
     402                $html_field = sprintf( 
    340403                    '<input type="text" id="%s" name="%s" value="%s" size="%d">', 
     404                    $self->escape($html_id), 
    341405                    $self->escape($htmlname), 
    342                     $self->escape($htmlname), 
    343                     $self->escape($self->attr_raw_value($attr)), 
    344                     $2 || 30, 
     406                    $self->escape($attr_raw_value), 
     407                    $attribute->form_option('length') || 30, 
    345408                ); 
    346409                if ($flag =~ /A/) { 
    347                 $textf .= qq|<span id="${htmlname}_auto_complete"></span>|; 
    348                 $textf .= "\n"; 
    349                 $textf .= $self->{c}->prototype->auto_complete_field( 
    350                     $htmlname, 
    351                     { 
    352                     update => "${htmlname}_auto_complete", 
    353                     url => $self->{c}->uri_for('/ajax', 'attrvalues', $self->otype, $attr), 
    354                     indicator => "${htmlname}_stat", min_chars => 1, 
    355                     with => "'val='+document.getElementById('$htmlname').value", 
    356                     frequency => 2, 
    357                     } 
    358                 ); 
    359                 } 
    360                 if ($flag =~ /U/) { 
    361                 $textf .= qq|<span id="${htmlname}_observer_uniq"></span>|; 
    362                 $textf .= "\n"; 
    363                 $textf .= $self->{c}->prototype->observe_field( 
    364                     $htmlname, 
    365                     { 
    366                     update => "${htmlname}_observer_uniq", 
    367                     url => $self->{c}->uri_for('/ajax', 'objattrexist', 
    368                         $self->otype, $attr), 
    369                     frequency => 2, 
    370                     indicator => "${htmlname}_stat", min_chars => 1, 
    371                     with => "'val='+document.getElementById('$htmlname').value" . 
    372                         ($self->{object} ? "+'&exclude=" . $self->{object}->id . "'" : 
    373                             ''), 
    374                     } 
    375                 ); 
    376                 } 
    377                 $textf .= qq|<span style="display:none" id="${htmlname}_stat">Searching...</span>|; 
    378  
    379                 return $textf; 
     410                    $html_field .= qq|<span id="${html_id}_auto_complete"></span>|; 
     411                    $html_field .= "\n"; 
     412                    $html_field .= $self->{c}->prototype->auto_complete_field( 
     413                        $html_id, 
     414                        { 
     415                            update => "${html_id}_auto_complete", 
     416                            url => $self->{c}->uri_for('/ajax', 'attrvalues', $self->otype, $attr), 
     417                            indicator => "${html_id}_stat", min_chars => 1, 
     418                            with => "'val='+document.getElementById('$html_id').value", 
     419                            frequency => 2, 
     420                        } 
     421                    ); 
     422                } 
     423                if ($attribute->uniq) { 
     424                    $html_field .= qq|<span class="inputvalidate" id="${html_id}_observer_uniq"></span>|; 
     425                    $html_field .= "\n"; 
     426                    $html_field .= $self->{c}->prototype->observe_field( 
     427                        $html_id, 
     428                        { 
     429                            update => "${html_id}_observer_uniq", 
     430                            url => $self->{c}->uri_for('/ajax', 'objattrexist', 
     431                                $self->otype, $attr), 
     432                            frequency => 2, 
     433                            indicator => "${html_id}_stat", min_chars => 1, 
     434                            with => "'val='+document.getElementById('$html_id').value" . 
     435                            ($self->{object} ? "+'&exclude=" . $self->{object}->id . "'" : 
     436                                ''), 
     437                        } 
     438                    ); 
     439                    $html_field .= qq|<span style="display:none" id="${html_id}_stat">Searching...</span>|; 
     440                } 
     441                last; 
     442            }; 
     443        } 
     444        if (my $ref = $attribute->reference) { 
     445            my $uri_part= { 
     446                user => 'users', 
     447                group => 'groups', 
     448                nethost => 'nethosts', 
     449                netzone => 'netzones', 
     450                site => 'sites' 
     451            }->{$ref}; 
     452            my $text; 
     453            if ($self->base->attribute($ref, 'displayName')) { 
     454                if ($attr_raw_value && 
     455                    (my $obj = $self->base->get_object($ref, $attr_raw_value))) 
     456                { 
     457                    $text = $obj->get_attributes('displayName'); 
     458                } 
     459                 
     460                $html_field .= $self->{c}->prototype->observe_field( $html_id, { 
     461                        update => "${html_id}_span", 
     462                        url => $self->{c}->uri_for('/ajax', 'rawattr', $ref), 
     463                        frequency => 1, 
     464                        with   => "'attr=displayName" . 
     465                        "&id=' + element.options[element.selectedIndex].text", 
     466                    }) . "\n" if ($attribute->form_type =~ /list/i); 
     467            } elsif($attr_raw_value && $uri_part) { 
     468                $text = sprintf( 
     469                    '<img class="attr" src="%s" title="%s">', 
     470                    $self->{c}->uri_for('/static', 'icons', 'arrow-right.png'), 
     471                    $attr_raw_value, 
     472                ) 
    380473            } 
    381         }; 
     474            $html_field .= sprintf(qq{<span id="%s" style="margin-left: 1em">}, 
     475                "${html_id}_span"); 
     476 
     477            if (defined($text)) { 
     478                $html_field .= $uri_part 
     479                    ? sprintf('<a href="%s">%s</a>', 
     480                        $self->{c}->uri_for("/$uri_part", $attribute->display($attr_raw_value)), 
     481                        $text,) 
     482                    : $text; 
     483            } 
     484 
     485            $html_field .= "</span>\n"; 
     486        } 
     487        push(@html_fields, $html_field); 
    382488    } 
     489    return join("<br>\n", @html_fields); 
    383490} 
    384491 
     
    391498} 
    392499 
     500sub write_attributes { 
     501    my ($self) = @_; 
     502    my @attrs; 
     503    foreach ($self->attributes) { 
     504        my $attr = ($self->{object} 
     505            ? $self->{object}->attribute($_) 
     506            : $self->base->attribute($self->otype, $_)) or next; 
     507        $attr->readonly and next; 
     508        push(@attrs, $_); 
     509    } 
     510    @attrs; 
     511} 
     512 
    393513sub set_attrs { 
    394514    my ($self) = @_; 
     
    396516    my $prefix = $self->{object}->id . '_'; 
    397517    my %fields; 
    398     foreach ( 
    399         grep { $self->base->get_field_name($self->otype, $_, 'w') } 
    400         $self->attributes) { 
     518    foreach ($self->write_attributes) { 
     519        my $attr = ($self->{object} 
     520            ? $self->{object}->attribute($_) 
     521            : $self->base->attribute($self->otype, $_)) or next; 
    401522        if (($attrs->{$_}[1] || '') eq 'checkbox') { 
    402523            $fields{$_} = $self->{c}->req->param("$prefix$_") ? 1 : 0; 
     524        } elsif ($attr->{multiple}) { 
     525            $fields{$_} = [ grep { $_ } $self->{c}->req->param("$prefix$_") ]; 
    403526        } else { 
    404527            $fields{$_} = $self->{c}->req->param("$prefix$_"); 
    405528        } 
    406529    } 
    407     $self->{object}->set_c_fields(%fields) or return; 
     530    $self->{object}->set_c_fields(%fields) or do { 
     531        $self->{c}->stash->{page}{error} = 
     532            LATMOS::Accounts::Log::lastmessage(LA_ERR); 
     533        $self->{object}->base->rollback; 
     534        return; 
     535    }; 
    408536    $self->{object}->base->commit; 
    409537} 
  • LATMOS-Accounts-Web/root/html/ajax/objexist.tt

    r500 r861  
    11[% IF exists %] 
    2 <img src="[% c.uri_for('/static', 'images', 'dialog-cancel.png') %]"> 
     2<img class="attr" src="[% c.uri_for('/static', 'images', 'dialog-cancel.png') %]"> 
    33([% exists %]) 
    44[% ELSE %] 
    5 <img src="[% c.uri_for('/static', 'images', 'dialog-ok-apply.png') %]"> 
     5<img class="attr" src="[% c.uri_for('/static', 'images', 'dialog-ok-apply.png') %]"> 
    66[% END %] 
  • LATMOS-Accounts-Web/root/html/departments/default.tt

    r148 r861  
    1 <!-- $Id: default.tt 432 2009-05-17 13:19:38Z nanardon $ --> 
     1<!-- $Id: default.tt 2800 2010-08-01 12:02:51Z nanardon $ --> 
    22[% IF NOT department %] 
    33No department [% departmentname | html %] found. 
  • LATMOS-Accounts-Web/root/html/departments/menu.tt

    r148 r861  
    1 <!-- $Id: user_menu.tt 443 2009-05-18 03:52:21Z nanardon $ --> 
     1<!-- $Id: menu.tt 2800 2010-08-01 12:02:51Z nanardon $ --> 
    22<div> 
    33    <table border="0"> 
  • LATMOS-Accounts-Web/root/html/groups/index.tt

    r220 r861  
    1010<table border="0"> 
    1111<tr><td colspan="2">[% groupslist.size %] groupes</td></tr> 
    12 <tr><th>Nom</th><th>Description</th></tr> 
     12<tr><th>Nom</th><th>Description</th><th></th></tr> 
    1313[% FOREACH groupname = groupslist %] 
    1414[% group = db.get_object('group', groupname) %] 
    1515<tr> 
    16     <td>[% group.id | html %]</td> 
    17     <td>[% group.get_c_field('description') | truncate(30) | html %] 
    18     <a href="[% c.uri_for('/groups', groupname) %]"> 
    19         <img src="[% c.uri_for('/static', 'icons', 'arrow-right.png') %]" 
     16    <td><a href="[% c.uri_for('/groups', groupname) %]"> 
     17        <img src="[% c.uri_for('/static', 'icons', 'icon_edit.png') %]" 
    2018            height="16" width="16" 
    2119            alt="[% "edit " _ groupname | html %]"> 
    22     </a></td> 
     20    </a> [% group.id | html %]</td> 
     21    <td> 
     22    <span title="[% group.get_c_field('description') | html %]"> 
     23    [% group.get_c_field('description') | truncate(30) | html %] 
     24    </span> 
     25    </td> 
    2326</tr> 
    2427[% END %] 
  • LATMOS-Accounts-Web/root/html/groups/menu.tt

    r544 r861  
    11<!-- $Id$ --> 
    2 <div id="omenu"> 
     2<div id="oinfo"> 
    33    [% INCLUDE 'includes/obj_prev_next.tt' objtype='group' objname=groupname %] 
    4     <table border="0"> 
    5     <tr><td> 
     4 
     5    <div> 
    66    <img src="[% c.uri_for('/static', 'icons', 'user-group-properties.png') %]" 
    77    alt="[% "Groupe " _ groupname %]"> 
    8     </td> 
    9     <td>    
    10     [% groupname | html %]<br> 
     8    </div> 
     9 
     10    <div>    
     11    <p id="oname">[% groupname | html %]</p> 
    1112    [% group.get_c_field('description') | html %] 
    12     </table> 
    13     <div style="clear: both;"></div> 
     13    </div> 
     14 
     15</div> 
     16<div style="clear: both;"></div> 
     17<div id="omenu"> 
    1418        <a href="[% c.uri_for(groupname) %]"><span [% 'id="oactive"' IF subform == '' %]>SystÚme</span></a> 
    1519        <a href="[% c.uri_for(groupname, 'users') %]"><span [% 'id="oactive"' IF subform == 'users' %]>Utilisateurs</span></a> 
     20[% IF group.get_attributes('sutype') == 'dpmt' %] 
     21        <a href="[% c.uri_for(groupname, 'dpmt') %]"><span [% 'id="oactive"' IF subform == 'dpmt' %]>Département</span></a> 
     22[% END %] 
    1623</div> 
     24<div style="clear: both;"></div> 
  • LATMOS-Accounts-Web/root/html/groups/users.tt

    r756 r861  
    44[% ELSE %] 
    55     
    6 [% modallow = c.model('Accounts').db.check_acl(group, 'memberUID', 'w') %] 
     6[% modallow = c.model('Accounts').db.check_acl(group, 'memberUID', 'w') AND 
     7NOT group.attribute('memberUID').ro %] 
    78 
    89<div class="objectform" id="objectform"> 
     
    1920<b>Membres primaire:</b><br> 
    2021[% END %] 
    21 <a href="[% c.uri_for('/users', uid) %]">[% uid | html %]</a><br> 
     22<a href="[% c.uri_for('/users', uid) %]">[% uid | html %]</a> 
     23[% ouser = c.model('Accounts').db.get_object('user', uid) %] 
     24[% INCLUDE user_flag ouser=ouser %] 
     25<br> 
    2226[% END %] 
    2327 
    2428[% FOREACH uid = group.get_c_field('member').sort %] 
     29[% ouser = c.model('Accounts').db.get_object('user', uid) %] 
    2530[% IF loop.first %] 
    2631<b>Membres</b><br> 
    2732[% END %] 
    2833[% IF modallow %] 
    29 <form action="[% c.uri_for(groupname, subform) %]" method="POST"> 
     34[% IF ouser.get_attributes('department') == group.id OR 
     35      ouser.get_attributes('contratType') == group.id %] 
     36<img src="[% c.uri_for('/static', 'icons', 'changes-prevent.png') %]" 
     37    width="24" height="24" title="Ce groupe est géré via un autre attribut"> 
     38[% ELSE %] 
     39<form action="[% c.uri_for(groupname, subform) %]" method="POST" style="display: inline"> 
    3040<input type="hidden" name="deluser" value="[% uid | html %]"> 
    3141<input type="image" src="[% c.uri_for('/static', 'icons', 'user-group-delete.png') %]" width="24" height="24"> 
     42</form> 
    3243[% END %] 
    33 <a href="[% c.uri_for('/users', uid) %]">[% uid | html %] 
    34 ([% c.model('Accounts').db.get_object('user', uid).get_attributes('displayName') | html %])</a><br> 
     44[% END %] 
     45<a href="[% c.uri_for('/users', uid, 'statut') %]">[% uid | html %] 
     46([% ouser.get_attributes('displayName') | html %])</a> 
     47[% INCLUDE user_flag ouser=ouser %] 
     48<br> 
    3549[% IF modallow %] 
    36 </form> 
    3750[% END %] 
    3851[% IF loop.last %] 
  • LATMOS-Accounts-Web/root/html/includes/form.tt

    r507 r861  
    11<!-- $Id$ --> 
    2 <div id="oform"> 
     2<div id="oform" class="oform"> 
    33[% attributes = form.attributes() %] 
    44[% IF attributes.0 %] 
     
    1313<tr><th>[% form.attr_label(attr) %]</th><td>[% form.attr_field(attr) %]</td> 
    1414[% IF loop.last %] 
     15[% IF form.write_attributes %] 
    1516<tr><td colspan=2>[% form.submit %]</td></tr> 
     17[% END %] 
    1618</table> 
    1719</form> 
  • LATMOS-Accounts-Web/root/html/includes/header.tt

    r689 r861  
    22<html> 
    33<head> 
    4 <title>[% page.title %]</title> 
     4<title>LATMOS::Accounts / [% page.title %]</title> 
    55<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 
    66<link rel="stylesheet" href="[% c.uri_for('/static', 'style.css') %]?" type="text/css"> 
     
    1212<script type="text/javascript" language="JavaScript" src="[% c.uri_for('/static', 'js', 'dragdrop.js') %]"></script> 
    1313<script type="text/javascript" language="JavaScript" src="[% c.uri_for('/static', 'js', 'controls.js') %]"></script> 
     14<script type="text/javascript" language="JavaScript"> 
     15function resetmenu() { 
     16    document.getElementById('menui').innerHTML = '[% page.title | html %]'; 
     17} 
     18 
     19[% IF page.error %] 
     20window.onload = analert; 
     21 
     22function analert () { 
     23    alert('[% page.error | replace('\'', '\\\'') %]'); 
     24} 
     25[% END %] 
     26</script> 
    1427</head> 
    1528 
     
    2033[% END %] 
    2134 
     35[% BLOCK user_flag %] 
     36[% INCLUDE object_flag object = ouser %] 
     37[% END %] 
     38 
     39[% BLOCK object_flag %] 
     40[% IF object.type == 'user' %] 
     41    [% IF object.get_attributes('unexported') %] 
     42<img src="[% c.uri_for('/static', 'icons', 'gtk-delete.png') %]" 
     43class="notice" title="Ce compte est désactivé" alt="disable"> 
     44    [% ELSIF object.get_attributes('expired') %] 
     45<img src="[% c.uri_for('/static', 'icons', 'emblem-urgent.png') %]" 
     46class="notice" title="Ce compte est expiré ([% object.get_attributes('expired') %])" alt="expired"> 
     47    [% ELSIF object.get_attributes('expire') %] 
     48<img src="[% c.uri_for('/static', 'icons', 'appointment-new.png') %]" 
     49class="notice" title="Ce compte est temporaire ([% object.get_attributes('expire') %])" alt="temporary"> 
     50    [% END %] 
     51[% ELSE %] 
     52    [% IF object.get_attributes('unexported') %] 
     53<img src="[% c.uri_for('/static', 'icons', 'gtk-delete.png') %]" 
     54class="notice" title="Cette entrée est désactivés" alt="disable"> 
     55    [% END %] 
     56[% END %] 
     57[% END %] 
     58 
    2259<body> 
    2360<!-- $Id$ --> 
    24 <div id="head" class="pmenu"> 
    25     Gestion des Utilisateurs du LATMOS 
    26 [% IF c.user.username %] 
    27 <span style="float:right; font-size: 0.5em;"> 
    28 Vous êtes [% c.user.username | html %] 
    29 </span> 
    30 [% END %] 
     61<div id="head"> 
     62    <div class="pmenu"> 
     63        [% IF c.config.company %] 
     64        Gestion informatique - [% c.config.company | html %] 
     65        [% ELSE %] 
     66        Gestion informatique 
     67        [% END %] 
     68    [% IF c.user.username %] 
     69    <span style="float:right; font-size: 0.5em;"> 
     70    Vous êtes [% c.user.username | html %] 
     71    </span> 
     72    [% END %] 
     73    </div> 
     74 
     75    <div id="mainmenu" style="float: left"> 
     76        <span> 
     77            <a href="[% c.uri_for('/users') %]" 
     78            onMouseOver="document.getElementById('menui').innerHTML='Liste des utilisateurs';" 
     79            onMouseOut="resetmenu();" 
     80            > 
     81            <img title="Utilisateurs" src="[% c.uri_for('/static', 'icons', 'avatar-default.png') %]"></a> 
     82        [% IF c.model('Accounts').db.check_acl('user', '@CREATE', 'w') %] 
     83            <a href="[% c.uri_for('/create', 'user') %]" 
     84            onMouseOver="document.getElementById('menui').innerHTML='Créer un utilisateur';" 
     85            onMouseOut="resetmenu();" 
     86            > 
     87            <img title="Ajouter un utilisateurs" src="[% c.uri_for('/static', 'icons', 'add.png') %]"></a> 
     88        [% END %] 
     89        </span> 
     90        <span> 
     91            <a href="[% c.uri_for('/groups') %]" 
     92            onMouseOver="document.getElementById('menui').innerHTML='Liste des groupes';" 
     93            onMouseOut="resetmenu();" 
     94            > 
     95            <img title="Groupes" src="[% c.uri_for('/static', 'icons', 'system-users.png') %]"></a> 
     96        [% IF c.model('Accounts').db.check_acl('group', '@CREATE', 'w') %] 
     97            <a href="[% c.uri_for('/create', 'group') %]" 
     98            onMouseOver="document.getElementById('menui').innerHTML='Créer un groupe';" 
     99            onMouseOut="resetmenu();" 
     100            > 
     101            <img title="Ajouter un groupe" src="[% c.uri_for('/static', 'icons', 'add.png') %]"></a> 
     102        [% END %] 
     103        </span> 
     104        <span> 
     105            <a href="[% c.uri_for('/sites') %]" 
     106            onMouseOver="document.getElementById('menui').innerHTML='Liste des sites';" 
     107            onMouseOut="resetmenu();" 
     108            > 
     109            <img title="Sites" src="[% c.uri_for('/static', 'icons', 'xfce-internet.png') %]"></a> 
     110        </span> 
     111        [% # On cache volontairement les alias si l'utilisateur ne doit pas y 
     112        toucher %] 
     113        [% IF c.model('Accounts').db.check_acl('aliases', '@CREATE', 'w') %] 
     114        <span> 
     115            <a href="[% c.uri_for('/aliases') %]" 
     116            onMouseOver="document.getElementById('menui').innerHTML= 
     117                'Alias mail sans utilisateur';" 
     118            onMouseOut="resetmenu();" 
     119            > 
     120            <img title="Alias mail" src="[% c.uri_for('/static', 'icons', 'mail_forward.png') %]"></a> 
     121        </span> 
     122        [% END %] 
     123        <span> 
     124            <a href="[% c.uri_for('/nethosts') %]" 
     125            onMouseOver="document.getElementById('menui').innerHTML='Liste des hÃŽtes réseau';" 
     126            onMouseOut="resetmenu();" 
     127            > 
     128            <img title="HÃŽtes réseau" src="[% c.uri_for('/static', 'icons', 'video-display.png') %]"></a> 
     129        [% IF c.model('Accounts').db.check_acl('nethost', '@CREATE', 'w') %] 
     130            <a href="[% c.uri_for('/create', 'nethost') %]" 
     131            onMouseOver="document.getElementById('menui').innerHTML='Ajouter un hote réseau';" 
     132            onMouseOut="resetmenu();" 
     133            > 
     134            <img title="Ajouter un hÃŽte réseau" src="[% c.uri_for('/static', 'icons', 'add.png') %]"></a> 
     135        [% END %] 
     136        </span> 
     137        [% # On cache volontaire les zones si l'utilisateur ne doit pas y 
     138        toucher %] 
     139        [% IF c.model('Accounts').db.check_acl('netzone', '@CREATE', 'w') %] 
     140        <span> 
     141            <a href="[% c.uri_for('/netzones') %]" 
     142            onMouseOver="document.getElementById('menui').innerHTML='Liste des zones réseaux';" 
     143            onMouseOut="resetmenu();" 
     144            > 
     145            <img title="Gestion Réseau" src="[% c.uri_for('/static', 'icons', 'network-workgroup.png') %]"></a> 
     146            <a href="[% c.uri_for('/create', 'netzone') %]" 
     147            onMouseOver="document.getElementById('menui').innerHTML='Ajouter une zones réseau';" 
     148            onMouseOut="resetmenu();" 
     149            ><img title="Ajouter une zone" src="[% c.uri_for('/static', 'icons', 'add.png') %]"></a> 
     150        </span> 
     151        [% END %] 
     152        <span> 
     153            <a href="[% c.uri_for('/about') %]" 
     154            onMouseOver="document.getElementById('menui').innerHTML='A propos...';" 
     155            onMouseOut="resetmenu();" 
     156            > 
     157            <img title="A propos..." src="[% c.uri_for('/static', 'icons', 'gtk-about.png') %]"></a> 
     158        </span> 
     159    </div> 
     160 
     161    [% IF c.user.username %] 
     162    <div style="float: right"> 
     163        <span> 
     164            <a href="[% c.uri_for('/users', c.user.username) %]" 
     165            onMouseOver="document.getElementById('menui').innerHTML='Mon profile';" 
     166            onMouseOut="resetmenu();" 
     167            > 
     168            <img title="Mon profile" src="[% c.uri_for('/static', 'icons', 'gtk-home.png') %]"></a> 
     169        </span> 
     170        <span> 
     171            <a href="[% c.uri_for('/users', c.user.username, 'passwd') %]" 
     172            onMouseOver="document.getElementById('menui').innerHTML='Changer mon mot de passe';" 
     173            onMouseOut="resetmenu();" 
     174            > 
     175            <img title="Changer mon mot de passe" src="[% c.uri_for('/static', 
     176            'icons', 'dialog-password.png') %]"></a> 
     177        </span> 
     178        <span> 
     179            <a href="[% c.uri_for('/logout') %]" 
     180            onMouseOver="document.getElementById('menui').innerHTML='Se déconnecter';" 
     181            onMouseOut="resetmenu();" 
     182            > 
     183            <img title="Se déconnecter" src="[% c.uri_for('/static', 
     184                    'icons', 'gtk-close.png') %]"></a> 
     185        </span> 
     186    </div> 
     187    [% END %] 
     188     
     189    <div style="clear: both"></div> 
     190 
     191    <p>&gt; <span id="menui">[% page.title | html %]</span></p> 
    31192</div> 
    32 <div id="mainmenu" class="pmenu"> 
    33 <div style="float: left">[% mainmenu %]</div> 
    34 [% IF c.user.username %] 
    35 <div style="float: right"> 
    36     <a href="[% c.uri_for('/users', c.user.username) %]"><span>Mon profile</span></a> 
    37     <a href="[% c.uri_for('/users', c.user.username, 'passwd') %]"><span>Mon mot de passe</span></a> 
    38     <a href="[% c.uri_for('/logout') %]"><span>Se déconnecter</span></a> 
    39 </div> 
    40 [% END %] 
    41 <div style="clear: both"></div> 
    42 </div> 
  • LATMOS-Accounts-Web/root/html/includes/obj_prev_next.tt

    r544 r861  
    11<!-- $Id$ --> 
    22 
    3 <p style="float: right"> 
    4 [% prev_next = c.model('Accounts').object_prev_next(objtype, objname) %] 
    5 [% IF prev_next.0 %]                                                     
    6 <a href="[% c.uri_for(prev_next.0, subform) %]" title="[% prev_next.0 | html 
    7 %]">Prec.</a> 
    8 [% ELSE %]                                                                                 
    9 Prec.                                                                                      
    10 [% END %]                                                                                  
    11 [% IF prev_next.1 %]                                                                       
    12 <a href="[% c.uri_for(prev_next.1, subform) %]" title="[% prev_next.1 | html 
    13 %]">Suiv.</a> 
    14 [% ELSE %]                                                                                 
    15 Suiv.                                                                                      
    16 [% END %]                                                                                  
    17 </p>   
     3<div id="navigate" style="float: right"> 
     4<p> 
     5[% nav = c.model('Accounts').object_navigate(objtype, objname) %] 
     6 
     7[% IF nav.ofirst %] 
     8<a href="[% c.uri_for(nav.ofirst, subform) %]"> 
     9<img src="[% c.uri_for('/static', 'icons/gtk-goto-first-ltr.png') %]" title="[% 
     10nav.ofirst | html %]" alt="first"> 
     11</a> 
     12[% END %] 
     13 
     14[% IF nav.oprev %] 
     15<a href="[% c.uri_for(nav.oprev, subform) %]"> 
     16<img src="[% c.uri_for('/static', 'icons/gtk-go-back-ltr.png') %]" title="[% 
     17nav.oprev | html %]" alt="previous"> 
     18</a> 
     19[% END %] 
     20 
     21[% IF nav.onext %] 
     22<a href="[% c.uri_for(nav.onext, subform) %]"> 
     23<img src="[% c.uri_for('/static', 'icons/gtk-go-back-rtl.png') %]" title="[% 
     24nav.onext | html %]" alt="next"> 
     25</a> 
     26[% END %] 
     27 
     28[% IF nav.olast %] 
     29<a href="[% c.uri_for(nav.olast, subform) %]"> 
     30<img src="[% c.uri_for('/static', 'icons/gtk-goto-first-rtl.png') %]" title="[% 
     31nav.olast | html %]" alt="last"> 
     32</a> 
     33[% END %] 
     34</p> 
     35 
     36[% IF nav.list %] 
     37<form action="[% c.uri_for('/ajax/goto') %]"> 
     38<p> 
     39<input type="hidden" name="otype" value="[% objtype | html %]"> 
     40<input type="hidden" name="subform" value="[% subform | html %]"> 
     41<select name="goto"> 
     42[% FOREACH item = nav.list %] 
     43<option value="[% item | html %]" [% 'selected="selected"' IF item == objname 
     44%]>[% item | html %]</option> 
     45[% END %] 
     46</select> 
     47<input type="image" alt="Go To" title="Aller à" src="[% 
     48c.uri_for('/static', 'icons', 'gtk-jump-to-rtl.png') %]"> 
     49</p> 
     50</form> 
     51[% END %] 
     52 
     53</div>  
  • LATMOS-Accounts-Web/root/html/sites/default.tt

    r214 r861  
    1 <!-- $Id: default.tt 432 2009-05-17 13:19:38Z nanardon $ --> 
     1<!-- $Id: default.tt 2800 2010-08-01 12:02:51Z nanardon $ --> 
    22[% IF NOT site %] 
    33No site [% sitename | html %] found. 
  • LATMOS-Accounts-Web/root/html/sites/menu.tt

    r214 r861  
    1 <!-- $Id: user_menu.tt 443 2009-05-18 03:52:21Z nanardon $ --> 
    2 <div id="omenu"> 
    3     <table border="0"> 
    4     <tr><td> 
     1<!-- $Id: menu.tt 3103 2010-08-26 12:47:15Z nanardon $ --> 
     2<div id="oinfo"> 
     3 
     4    [% INCLUDE 'includes/obj_prev_next.tt' objtype='site' objname=sitename %] 
     5 
     6    <div> 
    57    <img src="[% c.uri_for('/static', 'icons', 'user-properties.png') %]" 
    68    alt="[% "User " _ sitename %]"> 
    7     </td> 
    8     <td>    
    9     [% sitename | html %]<br> 
     9    </div> 
     10    <div>    
     11    <p id="oname">[% sitename | html %]</p> 
    1012    [% user.get_c_field('l') | html %] 
    11     </td></tr> 
    12     </table> 
     13    </div> 
    1314</div> 
     15<div style="clear: both;"></div> 
  • LATMOS-Accounts-Web/root/html/users/address.tt

    r686 r861  
    2020</form> 
    2121 
     22[% IF address.base.check_acl(address, '@DELETE', 'w') %] 
    2223<table border=1><tr><td align="center"> 
    2324<form action="[% c.uri_for(username, subform) %]" method="POST"> 
     
    2829</form> 
    2930</td></tr></table> 
     31[% END %] 
    3032 
    3133</div> 
  • LATMOS-Accounts-Web/root/html/users/address_form.tt

    r760 r861  
    6363    <td>[% form.attr_field('co', fieldtype) %]</td> 
    6464</tr> 
     65[% IF form.write_attributes %] 
    6566<tr> 
    6667    <th></th> 
    67     <td>[% form.submit %]</td> 
     68    <td> 
     69    [% form.submit %] 
     70    </td> 
    6871</tr> 
     72[% END %] 
    6973</table> 
  • LATMOS-Accounts-Web/root/html/users/groups.tt

    r508 r861  
    2020[% FOREACH g = user.get_c_field('memberOf') %] 
    2121[% IF modallow %] 
    22 <form action="[% c.uri_for(username, subform) %]" method="POST"> 
     22[% IF user.get_attributes('department') == g OR  
     23      user.get_attributes('contratType') == g %] 
     24<img src="[% c.uri_for('/static', 'icons', 'changes-prevent.png') %]" 
     25    width="24" height="24" title="Ce groupe est géré via un autre attribut"> 
     26[% ELSE %] 
     27<form action="[% c.uri_for(username, subform) %]" method="POST" style="display: inline"> 
    2328<input type="hidden" name="delgroup" value="[% g | html %]"> 
    2429<input type="image" src="[% c.uri_for('/static', 'icons', 'user-group-delete.png') %]" width="24" height="24"> 
     30</form> 
     31[% END %] 
    2532[% END %] 
    2633<a href="[% c.uri_for('/groups', g) %]">[% g | html %]</a><br> 
    2734[% IF modallow %] 
    28 </form> 
    2935[% END %] 
    3036[% END %] 
  • LATMOS-Accounts-Web/root/html/users/index.tt

    r682 r861  
    99 
    1010<table border="0"> 
    11 <tr><td colspan="2">[% objectslist.size %] Utilisateurs<br> 
     11<tr><td colspan="5"> 
    1212[% IF initials %] 
    1313Pages:  
     
    2222[% END %] 
    2323</td></tr> 
    24 <tr><th>Login</th><th>Nom</th></tr> 
     24<tr><td></td><th>Login</th><th>Nom</th><th>Description</th><th>Mail</th></tr> 
    2525[% FOREACH username = userslist %] 
    2626[% user = db.get_object('user', username) %] 
    2727<tr> 
    28     <td>[% username | html %]</td> 
     28    <td> 
     29[% INCLUDE 'user_flag' ouser=user %] 
     30    </td> 
     31    <td><a href="[% c.uri_for('/users', username) %]"> 
     32        <img src="[% c.uri_for('/static', 'icons', 'icon_edit.png') %]" 
     33            height="16" width="16" 
     34            alt="[% "edit " _ username | html %]"> 
     35    </a>[% username | html %]</td> 
    2936    <td> 
    3037        [% user.get_c_field('sn') | html %] 
    3138        [% user.get_c_field('givenName') | html %] 
    32         [% user.get_c_field('description') | truncate(20) | html %] 
    33     <a href="[% c.uri_for('/users', username) %]"> 
    34         <img src="[% c.uri_for('/static', 'icons', 'arrow-right.png') %]" 
    35             height="16" width="16" 
    36             alt="[% "edit " _ username | html %]"> 
    37     </a></td> 
     39   </td> 
     40    <td> 
     41    <span title="[% user.get_c_field('description') | html %]">     
     42    [% user.get_c_field('description') | truncate(20) | html %] 
     43    </span> 
     44   </td> 
     45    <td><span title="[% user.get_c_field('mail') | html %]"> 
     46    [% user.get_c_field('mail') | truncate(20) | html %]</span> 
     47   </td> 
    3848</tr> 
    3949[% END %] 
  • LATMOS-Accounts-Web/root/html/users/menu.tt

    r730 r861  
    11<!-- $Id$ --> 
    2 <div id="omenu"> 
    3  
     2<div id="oinfo"> 
    43[% INCLUDE 'includes/obj_prev_next.tt' objtype='user' objname=username %] 
    54 
    6 <table border="0"> 
    7 <tr><td> 
    8 [% IF NOT user.get_c_field('exported') OR user.get_c_field('locked') %] 
    9 <img src="[% c.uri_for('/static', 'icons', 'view-media-artist.png') %]" 
    10 [% ELSE %] 
    11 <img src="[% c.uri_for('/static', 'icons', 'user-properties.png') %]" 
    12 [% END %] 
    13 alt="[% "User " _ username %]"> 
    14 </td> 
    15 <td>    
    16 [% username | html %]<br> 
    17 [% user.get_c_field('displayName') | html %] 
    18 </td> 
    19 </tr> 
    20 </table> 
     5    <div> 
     6    [% IF NOT user.get_c_field('exported') %] 
     7    <img src="[% c.uri_for('/static', 'icons', 'gtk-delete.png') %]" 
     8    alt="[% "User " _ username %]" title="le compte est désactivé"> 
     9    [% ELSE %] 
     10    <img src="[% c.uri_for('/static', 'icons', 'user-properties.png') %]" 
     11    alt="[% "User " _ username %]"> 
     12    [% END %] 
     13    </div> 
     14 
     15    <div> 
     16    [% IF user.get_c_field('locked') %] 
     17    <img src="[% c.uri_for('/static', 'icons', 'locked.png') %]"  
     18    alt="le compte est vérrouillé" title="le compte est vérrouillé"> 
     19    [% END %] 
     20    </div> 
     21 
     22    <div> 
     23    <p id="oname">[% username | html %] 
     24        [% INCLUDE user_flag ouser = user %]</span></p> 
     25    [% user.get_c_field('displayName') | html %] 
     26    </div> 
     27</div> 
    2128<div style="clear: both;"></div> 
     29<div id="omenu"> 
    2230        <a href="[% c.uri_for(username) %]"><span [% 'id="oactive"' IF subform == '' %]>SystÚme</span></a> 
    23         <a href="[% c.uri_for(username, 'status') %]"><span [% 'id="oactive"' IF subform == 'status' %]>Status</span></a> 
     31        <a href="[% c.uri_for(username, 'statut') %]"><span [% 'id="oactive"' IF subform == 'statut' %]>Statut</span></a> 
    2432        <a href="[% c.uri_for(username, 'groups') %]"><span [% 'id="oactive"' IF subform == 'groups' %]>Groupes</span></a> 
    2533        <a href="[% c.uri_for(username, 'address') %]"><span [% 'id="oactive"' IF subform == 'address' %]>Adresses</span></a> 
    2634        <a href="[% c.uri_for(username, 'mail') %]"><span [% 'id="oactive"' IF subform == 'mail' %]>eMail</span></a> 
     35        <a href="[% c.uri_for(username, 'my') %]"><span [% 'id="oactive"' IF subform == 'my' %]>My</span></a> 
    2736[% IF c.model('Accounts').db.check_acl(user, 'userPasswd', 'r') %] 
    2837        <a href="[% c.uri_for(username, 'passwd') %]"><span [% 'id="oactive"' IF subform == 'passwd' %]>Mot de passe</span></a> 
    2938[% END %] 
    3039</div> 
     40<div style="clear:both"></div> 
  • LATMOS-Accounts-Web/root/html/users/passwd.tt

    r667 r861  
    33[% INCLUDE 'users/menu.tt' %] 
    44 
     5<script type="text/javascript"> 
     6function check_passwd() { 
     7    new Ajax.Updater( 
     8        'perror', 
     9        '[% c.uri_for('/ajax', 'cracklib', username) %]', 
     10        { parameters: 'passwd=' + document.getElementById("passwd").value + 
     11            '&cpasswd=' + document.getElementById("cpasswd").value } 
     12    ) 
     13} 
     14</script> 
     15 
    516<div id="oform"> 
    617[% IF c.model('Accounts').db.check_acl(user, 'userPassword', 'w') %] 
    718<form id="fpasswd" action="[% c.uri_for(username, subform) %]" method="POST"> 
    8 [% c.prototype.observe_form('fpasswd', { 
    9     url => c.uri_for('/ajax', 'cracklib', username), 
    10     update => 'perror', 
    11     frequency => 1, 
    12 }) %] 
    1319<table border="1"> 
    1420<tr> 
    1521<th>Nouveau mot de passe:</th> 
    16 <td><input type="password" name="passwd"></td> 
     22<td><input type="password" name="passwd" id="passwd" onkeyup="check_passwd()"></td> 
    1723</tr> 
    1824<tr> 
    1925<th>Confirmation:</th> 
    20 <td><input type="password" name="cpasswd"></td> 
     26<td><input type="password" name="cpasswd" id="cpasswd" onkeyup="check_passwd()"></td> 
    2127</tr> 
    2228<tr><td colspan="2"><span id="perror">[% pmerror | html %]</span></td></tr> 
  • LATMOS-Accounts-Web/root/static/style.css

    r507 r861  
    22    border: none; 
    33    vertical-align: middle; 
     4    padding: 0em 
    45} 
    56 
    67.pmenu { 
     8    padding: 0.5em; 
     9    font-size: 2em; 
     10} 
     11 
     12.permdenied { 
     13    padding: 0.5em; 
     14} 
     15 
     16#head { 
    717    background-color: #7DB4D8; 
    8     padding: 0.5em; 
    9 } 
    10  
    11 .permdenied { 
    12     padding: 0.5em; 
    13 } 
    14  
    15 #head { 
    16     font-size: 2em; 
     18    padding-bottom: 0.2em; 
     19    padding-top: 0.2em; 
    1720} 
    1821 
    1922#mainmenu a { 
    20     font-size: 80%; 
     23    font-size: 50px; 
    2124    overflow: hidden; 
    2225    text-decoration: none; 
     
    2427 
    2528#mainmenu span { 
     29    padding-left: 1em; 
     30    padding-right: 1em; 
     31    text-decoration: none; 
     32} 
     33 
     34#mainmenu span#actif { 
    2635    border-style: outset; 
    2736    padding-left: 1em; 
    2837    padding-right: 1em; 
    2938    text-decoration: none; 
    30 } 
    31  
    32 #mainmenu span#actif { 
    33     border-style: inset; 
    34     border-size: 1px; 
    35     padding-left: 1em; 
    36     padding-right: 1em; 
    37     text-decoration: none; 
     39    height: 32px; 
    3840} 
    3941 
    4042#mainmenu a:hover { 
    41     border: solid; 
    42 } 
    43  
    44 div#objectform  { 
     43/*    border: solid;*/ 
     44    background-color: #7DB4D8; 
     45} 
     46 
     47#oinfo div { 
     48    float: left; 
     49    padding: 0.5em; 
     50} 
     51 
     52#oname { 
     53    font-size: 1.2em; 
     54    padding: 0em; 
     55    margin: 0em; 
     56} 
     57 
     58#omenu a { 
     59    text-decoration: none; 
     60    color: black; 
     61} 
     62 
     63#omenu div { 
     64    float: left; 
     65    padding-top: 0.5em; 
     66    padding-bottom: 0.5em; 
     67} 
     68 
     69 
     70#omenu span { 
     71    padding-left: 1em; 
     72    padding-right: 1em; 
     73    margin: 0; 
     74    border: groove thin; 
     75    text-decoration: none; 
     76    float: left; 
     77    background-color: #DDDDD9; 
     78    color: black; 
     79} 
     80 
     81#omenu span#oactive { 
     82    padding-left: 1em; 
     83    padding-right: 1em; 
     84    margin: 0; 
     85    border: groove thin; 
     86    text-decoration: none; 
     87    float: left; 
     88    background-color: #7DB4D8; 
     89    color: black; 
     90} 
     91 
     92#omenu a:hover { 
     93    /* border: inset; */ 
     94    text-color blue; 
     95} 
     96 
     97div.objectform  { 
    4598    border-style: outset; 
    4699    width: 60%; 
     
    49102} 
    50103 
    51 #objectform table { 
     104.objectform table { 
    52105    margin-left: auto; 
    53106    margin-right: auto; 
     
    56109} 
    57110 
    58 #omenu a { 
    59     text-decoration: none; 
    60 } 
    61  
    62 #omenu td { 
    63     padding-left: 0.5em; 
    64     padding-right: 0.5em; 
    65 } 
    66  
    67 #omenu table { 
     111div.objectformleft { 
     112    /* border-style: outset; */ 
     113    width: 60%; 
     114    margin-left: auto; 
     115    margin-right: auto; 
     116} 
     117 
     118.objectformleft table { 
     119    /* 
     120    margin-top: 1em; 
     121    margin-bottom: 1em; 
     122    */ 
     123} 
     124 
     125.objectformleft #oform { 
     126    /*border: inset;*/ 
     127    float: left; 
     128} 
     129 
     130.oform { 
     131    /* border: inset; */ 
    68132    margin: 0.5em; 
    69133} 
    70134 
    71  
    72 #omenu span { 
    73     padding-left: 1em; 
    74     padding-right: 1em; 
    75     margin: 0; 
    76     border: groove thin; 
    77     text-decoration: none; 
    78 } 
    79  
    80 #omenu span#oactive { 
    81     margin: 0; 
    82     padding-left: 1em; 
    83     padding-right: 1em; 
    84     border: outset; 
    85     border-bottom-style: none; 
    86     text-decoration: none; 
    87     font-weight:bold; 
    88 } 
    89  
    90 #omenu a:hover { 
    91     border: inset; 
    92 } 
    93  
    94 #oform { 
    95     border: inset; 
    96 } 
    97  
    98 table#oform { 
    99     margin-left: 20%; 
    100     margin-right: 20%; 
     135.oform table { 
     136    /* margin-left: 20%; 
     137    margin-right: 20%; */ 
     138} 
     139 
     140.oform td { 
     141    vertical-align: top; 
     142} 
     143 
     144.oform p { 
     145    margin: 0.5em; 
     146    font-weight: bold; 
     147} 
     148 
     149.oform ul { 
     150    padding: 0.5em; 
     151} 
     152 
     153.oform li { 
     154    list-style-type: none; 
     155    padding-left: 0.2em; 
     156} 
     157 
     158.inputvalidate img { 
     159    width: 1em; 
     160    height:1em; 
     161} 
     162 
     163#navigate { 
     164} 
     165 
     166#navigate p { 
     167    margin: 0em; 
     168    text-align: center; 
     169} 
     170 
     171#navigate input { 
     172    width: 3em; 
     173    height:3em; 
     174    vertical-align: middle; 
     175} 
     176 
     177#navigate img { 
     178    width: 2em; 
     179    height:2em; 
     180    vertical-align: middle; 
     181} 
     182 
     183img.notice { 
     184    width: 1em; 
     185    height:1em; 
     186    vertical-align: middle; 
     187} 
     188 
     189img.attr { 
     190    width: 1.5em; 
     191    height:1.5em; 
     192    vertical-align: middle; 
    101193} 
    102194 
  • LATMOS-Accounts/Changes

    r1 r861  
    11Revision history for Perl extension LATMOS::Accounts. 
     2 
     32.0.0 
     4    - attributes are now object with possible properties: 
     5        * hide: attributes is still availlable but not listed 
     6        * ro: attributes can only be read 
     7        * can_values: list of possible values, other are rejected  
     8        * mandatory: cannot be empty or not set 
     9        * reference: the attribute point to this object type 
     10 
     11    - add support of network management 
     12        * object nethost and netzone 
     13        * BuildNet objects 
     14        * associated tools 
     15 
     16    - la-sync-manager can now manage multiples task: each task is an object 
     17      and la-sync-manager.ini control task to run 
     18 
     19    - all configurations files are now located in /etc/latmos-accounts and all 
     20      files have a fixed name. --config is no longer the main configuration file 
     21      but the directory containing theses files 
     22 
     23    - configuration files are now more or less documented (man section 5) 
     24 
     25    - exported attributes is replace by unexported attributes (reverse meaning), 
     26      unlike exported which is true/false, unexported is set or not. 
     27 
     28    - some optimization, especially for SQL base 
     29 
     30    - add la-cli tools: interactive command line with completion 
    231 
    3320.01  Wed Feb 25 17:58:38 2009 
  • LATMOS-Accounts/MANIFEST

    r859 r861  
    77bin/la-acls 
    88bin/la-attributes 
     9bin/la-buildnet 
    910bin/la-cli 
    1011bin/la-config 
     
    1314bin/la-delete 
    1415bin/la-edit 
     16bin/la-exchange-ip 
     17bin/la-expired-reminder 
     18bin/la-find-expired 
     19bin/la-freeip 
    1520bin/la-graph.pl 
    1621bin/la-group 
     
    2126bin/la-query 
    2227bin/la-rename 
     28bin/la-rename-host 
    2329bin/la-rev 
    2430bin/la-search 
     31bin/la-sql-loadatt 
     32bin/la-sql-regatt 
    2533bin/la-sync 
    2634bin/la-sync-list 
     
    4048lib/LATMOS/Accounts/Bases/Dummy/User.pm 
    4149lib/LATMOS/Accounts/Bases/Dummy.pm 
     50lib/LATMOS/Accounts/Bases/Heimdal/User.pm 
     51lib/LATMOS/Accounts/Bases/Heimdal.pm 
    4252lib/LATMOS/Accounts/Bases/Ldap/Group.pm 
    4353lib/LATMOS/Accounts/Bases/Ldap/Onlyaddress.pm 
     
    4959lib/LATMOS/Accounts/Bases/Mail/objects.pm 
    5060lib/LATMOS/Accounts/Bases/Mail.pm 
     61lib/LATMOS/Accounts/Bases/OCHelper/User.pm 
     62lib/LATMOS/Accounts/Bases/OCHelper.pm 
    5163lib/LATMOS/Accounts/Bases/Objects.pm 
     64lib/LATMOS/Accounts/Bases/Sql/Accreq.pm 
    5265lib/LATMOS/Accounts/Bases/Sql/Address.pm 
    5366lib/LATMOS/Accounts/Bases/Sql/Aliases.pm 
    5467lib/LATMOS/Accounts/Bases/Sql/Group.pm 
     68lib/LATMOS/Accounts/Bases/Sql/Nethost.pm 
     69lib/LATMOS/Accounts/Bases/Sql/Netzone.pm 
     70lib/LATMOS/Accounts/Bases/Sql/OCHelper/Accreq.pm 
    5571lib/LATMOS/Accounts/Bases/Sql/Onlyaddress.pm 
    5672lib/LATMOS/Accounts/Bases/Sql/Revaliases.pm 
     
    6480lib/LATMOS/Accounts/Bases/Unix.pm 
    6581lib/LATMOS/Accounts/Bases.pm 
     82lib/LATMOS/Accounts/BuildNet.pm 
    6683lib/LATMOS/Accounts/Cli.pm 
    6784lib/LATMOS/Accounts/Log.pm 
    6885lib/LATMOS/Accounts/Maintenance.pm 
     86lib/LATMOS/Accounts/SyncManager.pm 
    6987lib/LATMOS/Accounts/SynchAccess/Objects.pm 
    7088lib/LATMOS/Accounts/SynchAccess/base.pm 
    7189lib/LATMOS/Accounts/SynchAccess.pm 
    7290lib/LATMOS/Accounts/Synchro.pm 
     91lib/LATMOS/Accounts/Task/Basessynchro.pm 
     92lib/LATMOS/Accounts/Task/Buildlistes.pm 
     93lib/LATMOS/Accounts/Task/Buildnet.pm 
     94lib/LATMOS/Accounts/Task/Dummy.pm 
     95lib/LATMOS/Accounts/Task/Refreshexpired.pm 
     96lib/LATMOS/Accounts/Task.pm 
    7397lib/LATMOS/Accounts/Utils.pm 
    7498lib/LATMOS/Accounts.pm 
     99man/la-allowed-values.ini.5.pod 
     100man/la-sync-list.ini.5.pod 
     101man/la-sync-manager.ini.5.pod 
     102man/latmos-accounts.ini.5.pod 
    75103patchset/no_useless_load.patch 
    76 sample/allowed_values.ini 
    77 sample/latmos-account.ini 
    78 sample/list.cfg 
     104sample/la-allowed-values.ini 
     105sample/la-sync-list.ini 
     106sample/la-sync-manager.ini 
     107sample/latmos-accounts.ini 
     108scripts/la-sw-net 
     109scripts/ochelper 
     110sqldata/attributes.csv 
     111sqldata/base.sql 
    79112t/05_utils.t 
    80113t/06_cli.t 
     
    88121t/21_acls.t 
    89122t/22_accounts_attributes.t 
     123t/23_ochelper.t 
    90124t/25_la_synchro.t 
    91125t/26_la_synchaccess.t 
     126t/30_la_task.t 
    92127t/LATMOS-Accounts.t 
    93128templates/mail/account_expire.mail 
     129templates/mail/account_expired_reminder.mail 
    94130testdata/acls1 
    95131testdata/acls2 
    96132testdata/aliases 
    97 testdata/config 
     133testdata/configdir/latmos-accounts.ini 
    98134testdata/group 
    99135testdata/gshadow 
  • LATMOS-Accounts/Makefile.PL

    r860 r861  
    55WriteMakefile( 
    66    NAME              => 'LATMOS::Accounts', 
    7     VERSION           => '0.0.25', # finds $VERSION 
     7    VERSION           => '2.0.5', # finds $VERSION 
    88    PREREQ_PM         => { 
    99        'Net::LDAP' => undef, 
     
    2121        'Unicode::String' => undef, 
    2222        'Crypt::Cracklib' => undef, 
     23        'Net::IP' => undef, 
    2324    }, # e.g., Module::Name => 1.1 
    2425    ($] >= 5.005 ?     ## Add these new keywords supported since 5.005 
     
    3536        bin/la-delete 
    3637        bin/la-edit 
     38        bin/la-find-expired 
    3739        bin/la-group 
    3840        bin/la-guser 
     
    4042        bin/la-query 
    4143        bin/la-rename 
     44        bin/la-rename-host 
     45        bin/la-exchange-ip 
    4246        bin/la-rev 
    4347        bin/la-search 
     
    4751        bin/la-warn-expire 
    4852        bin/la-web-directory 
     53        bin/la-freeip 
     54        bin/la-buildnet 
     55        bin/la-expired-reminder 
     56        bin/la-sql-regatt 
     57        bin/la-sql-loadatt 
    4958        ) ], 
     59        macro => { 
     60            INSTALLMAN5DIR      => '$(PERLPREFIX)/share/man/man5', 
     61            DESTINSTALLMAN5DIR  => '$(DESTDIR)$(INSTALLMAN5DIR)', 
     62            INST_MAN5DIR        => 'blib/man5', 
     63            DESTRPMDIR          => '$(shell pwd)' 
     64        }, 
     65        MAN1PODS        => { 
     66            map { 
     67                my $targ = $_; 
     68                $targ =~ s{^man/}{}; 
     69                $targ =~ s{^bin/}{}; 
     70                $targ =~ s/\.(\d)\.pod$//; 
     71                my $section = $1 || 1; 
     72                ( $_ => 
     73                    "\$(INST_MAN${section}DIR)/$targ.$section" ); 
     74            } <man/*.pod>, (grep { ! /~$/ } <bin/*>) 
     75        }, 
     76 
    5077); 
    5178 
     
    5481sub postamble { 
    5582    <<EOF; 
    56 .PHONY .= svnmanifest 
     83#.PHONY .= svnmanifest 
    5784 
    5885svnmanifest: 
     
    7097\t --define "_sourcedir `pwd`" \\ 
    7198\t --define "_specdir `pwd`" \\ 
    72 \t --define "_srcrpmdir `pwd`" \\ 
    73 \t --define "_rpmdir `pwd`" \\ 
     99\t --define "_srcrpmdir \$(DESTRPMDIR)" \\ 
     100\t --define "_rpmdir \$(DESTRPMDIR)" \\ 
     101\t latmos-accounts.spec 
     102 
     103svnrpm: \$(DISTVNAME).tar.gz latmos-accounts.spec 
     104\tmkdir \$(DESTRPMDIR)/noarch || : 
     105\trpmbuild -ba --clean\\ 
     106\t --define "_sourcedir `pwd`" \\ 
     107\t --define "_specdir `pwd`" \\ 
     108\t --define "_srcrpmdir \$(DESTRPMDIR)" \\ 
     109\t --define "_rpmdir \$(DESTRPMDIR)" \\ 
     110\t --define "svnrelease `LC_ALL=C svn info | grep '^Revision:' | sed 's/Revision: //'`" \\ 
    74111\t latmos-accounts.spec 
    75112 
    76113EOF 
     114} 
     115 
     116sub installbin { 
     117    my $self = shift; 
     118    my $inherited = $self->SUPER::installbin(@_); 
     119    my $s = join '|', map quotemeta, @sbin_scripts; 
     120    # how to create needed directories under blib 
     121    $inherited .= $self->dir_target("\$(INST_$_)") for qw(MAN5DIR); 
     122    $inherited; 
     123} 
     124 
     125sub top_targets { 
     126    my $inherited = shift->SUPER::top_targets(@_); 
     127    $inherited =~ s/^config ::/$& \$(INST_MAN5DIR)\$(DIRFILESEP).exists/m; 
     128    $inherited; 
    77129} 
    78130 
     
    82134 
    83135    $section =~ s/(^install ::.*)/$1 install_config install_templates/m; 
     136    $section =~ s/\$\(INST_BIN\) \$\(DESTINSTALL(\w*)BIN\)/$& \$(INST_MAN5DIR) \$(DESTINSTALLMAN5DIR)/g; 
    84137 
    85138    $section .= q[ 
    86139install_config :: 
    87140        install -d $(DESTDIR)/etc 
    88         install sample/latmos-account.ini $(DESTDIR)/etc/latmos-account.ini 
     141        install -d $(DESTDIR)/etc/latmos-accounts 
     142        install sample/latmos-accounts.ini $(DESTDIR)/etc/latmos-accounts/latmos-accounts.ini 
     143        install sample/la-sync-list.ini $(DESTDIR)/etc/latmos-accounts/la-sync-list.ini 
     144        install sample/la-allowed-values.ini $(DESTDIR)/etc/latmos-accounts/la-allowed-values.ini 
     145        install sample/la-sync-manager.ini $(DESTDIR)/etc/latmos-accounts/la-sync-manager.ini 
    89146 
    90147install_templates :: 
  • LATMOS-Accounts/TODO

    r282 r861  
    11$Id$ 
    22 
    3 Having a way to requires: 
    4     perl(IO::Socket::SSL) (need by LDAP for SSL) 
    5     perl(Unicode::Map8) (Need by AD module) 
    6  
     3- fix la-rename when one of base don't support the object type 
  • LATMOS-Accounts/bin/la-attributes

    r594 r861  
    2828=head1 OPTIONS 
    2929 
    30 =item -c|--config configfile 
     30=over 4 
    3131 
    32 Use this configuration file instead of thr default one. 
     32=item -c|--config configdir 
     33 
     34Use this configuration directory instead of thr default one. 
    3335 
    3436=item -b|--base basename 
    3537 
    3638Perform query on this base(s) (can be set multiple times). 
     39 
     40=back 
    3741 
    3842=cut 
     
    5559        }; 
    5660        foreach($labase->list_canonical_fields($otype, 'a')) { 
    57             $supported{$_}{$basename} = sprintf('%s%s', 
    58                 ($labase->get_field_name($otype, $_, 'r') ? 'r' : ' '), 
    59                 ($labase->get_field_name($otype, $_, 'w') ? 'w' : ' '), 
     61            my $attr = $labase->attribute($otype, $_); 
     62            $supported{$_}{$basename} = sprintf('%s', 
     63                $attr ? ($attr->ro ? 'r ' : 'rw') : '  ' 
    6064            ); 
    6165        } 
  • LATMOS-Accounts/bin/la-cli

    r849 r861  
    3030=over 4 
    3131 
    32 =item -c|--config configfile 
     32=item -c|--config configdir 
    3333 
    34 Use this configuration file instead of the default one. 
     34Use this configuration directory instead of the default one. 
    3535 
    3636=item -b|--base basename 
  • LATMOS-Accounts/bin/la-config

    r594 r861  
    2929=head1 OPTIONS 
    3030 
    31 =item -c|--config configfile 
     31=item -c|--config configdir 
    3232 
    33 Use this configuration file instead of the default one. 
     33Use this configuration directory instead of the default one. 
    3434 
    3535=item -b|--base basename 
     
    7878        $otype, 
    7979        $base ? $base : $LA->default_base_name; 
    80         printf( 
    81             "  %s (%s%s)\n", $_, 
    82             ($labase->get_field_name($otype, $_, 'r') ? 'r' : ' '), 
    83             ($labase->get_field_name($otype, $_, 'w') ? 'w' : ' '), 
    84         ) foreach($labase->list_canonical_fields($otype, 'a')); 
     80        foreach($labase->list_canonical_fields($otype, 'a')) { 
     81                my $attr = $labase->attribute($otype, $_); 
     82            printf( 
     83                "  %s (%s%s)\n", $_, 
     84                'r', 
     85                ($attr->readonly ? 'w' : ' '), 
     86            ) 
     87        } 
    8588    } else { 
    8689        my $labase = $base ? $LA->base($base) : $LA->default_base 
     
    8992        printf "Supported object type by base %s\n", 
    9093            $base ? $base : $LA->default_base_name; 
    91         print "  $_\n" foreach($labase->list_supported_objects); 
     94        print "  $_\n" foreach($labase->ordered_objects); 
    9295    } 
    9396} 
  • LATMOS-Accounts/bin/la-create

    r672 r861  
    3434=over 4 
    3535 
    36 =item -c|--config configfile 
     36=item -c|--config configdir 
    3737 
    38 Use this configuration file instead of the default one. 
     38Use this configuration directory instead of the default one. 
    3939 
    4040=item -b|--base basename 
  • LATMOS-Accounts/bin/la-crypt-passwd

    r664 r861  
    33use strict; 
    44use warnings; 
    5 use LATMOS::Accounts::Maintenance; 
     5use LATMOS::Accounts; 
    66use Getopt::Long; 
    77use Pod::Usage; 
     
    2525    'regen'      => \my $regen, 
    2626    'set=s'      => \my $set, 
     27    'base=s'     => \my $base, 
    2728) or pod2usage(); 
    2829 
     
    3132=over 4 
    3233 
    33 =item -c|--config configfile 
     34=item -c|--config configdir 
    3435 
    35 Use this configuration file instead of the default one. 
     36Use this configuration directory instead of the default one. 
    3637 
    3738=item --genkey 
     
    4647Stored password will be read and encrypted again using the new key. 
    4748 
     49=item --base base 
     50 
     51Work on this specific base instead default one 
     52 
    4853=item --set BASE 
    4954 
     
    5560=cut 
    5661 
    57 my $LA = LATMOS::Accounts::Maintenance->new($config); 
    58 $LA->wexported(1); 
     62my $LA = LATMOS::Accounts->new($config, noacl => 1); 
     63my $labase = $base ? $LA->base($base) : $LA->default_base; 
     64$labase && $labase->load or die "Cannot load base"; 
     65$labase->wexported(1); 
    5966 
    6067my $clear; 
     
    6269sub get_clear_password { 
    6370    $clear and return $clear; 
    64     my %encpasswd = $LA->get_rsa_password; 
     71    my %encpasswd = $labase->get_rsa_password; 
    6572    scalar(keys %encpasswd) or return {}; 
    6673    ReadMode('noecho'); 
     
    6976    ReadMode 0; 
    7077    print "\n"; 
    71     my $private_key = $LA->private_key($password) or 
     78    my $private_key = $labase->private_key($password) or 
    7279        die "Cannot get private key\n"; 
    7380    my $rsa = new Crypt::RSA ES => 'PKCS1v15'; 
     
    8996 
    9097if ($set) { 
    91     if (!$LA->_base->get_global_value('rsa_private_key')) { 
     98    if (!$labase->get_global_value('rsa_private_key')) { 
    9299        warn "No rsa key found in database\n"; 
    93100    } 
     
    104111    $destbase->commit; 
    105112} elsif ($regen || $genkey) { 
    106     if ($LA->_base->get_global_value('rsa_private_key') && !$regen) { 
     113    if ($labase->get_global_value('rsa_private_key') && !$regen) { 
    107114        die <<EOF; 
    108115A rsa key were found in database please use --regen to force a new key 
     
    118125    ReadMode 0; 
    119126    print "\n"; 
    120     my ($public, $private) = $LA->generate_rsa_key($password); 
     127    my ($public, $private) = $labase->generate_rsa_key($password); 
    121128 
    122     $LA->store_rsa_key($public, $private); 
    123     my $base = $LA->_base; 
    124     $base->wexported(1); 
     129    $labase->store_rsa_key($public, $private); 
    125130    foreach (keys %$clearpasswd) { 
    126         my $obj = $base->get_object('user', $_); 
     131        my $obj = $labase->get_object('user', $_); 
    127132        $obj->set_password($clearpasswd->{$_}); 
    128133    } 
    129     $base->commit; 
     134    $labase->commit; 
    130135} else { 
    131     if ($LA->_base->get_global_value('rsa_private_key')) { 
     136    if ($labase->get_global_value('rsa_private_key')) { 
    132137        my $clearpasswd = get_clear_password(); 
    133138        foreach (keys %$clearpasswd) { 
  • LATMOS-Accounts/bin/la-delete

    r685 r861  
    3131=over 4 
    3232 
    33 =item -c|--config configfile 
     33=item -c|--config configdir 
    3434 
    35 Use this configuration file instead of the default one. 
     35Use this configuration directory instead of the default one. 
    3636 
    3737=item -b|--base basename 
  • LATMOS-Accounts/bin/la-edit

    r664 r861  
    3333=over 4 
    3434 
    35 =item -c|--config configfile 
     35=item -c|--config configdir 
    3636 
    37 Use this configuration file instead of the default one. 
     37Use this configuration directory instead of the default one. 
    3838 
    3939=item -b|--base basename 
  • LATMOS-Accounts/bin/la-graph.pl

    r457 r861  
    3030=over 4 
    3131 
    32 =item -c|--config configfile 
     32=item -c|--config configdir 
    3333 
    34 Use this configuration file instead the default one 
     34Use this configuration directory instead the default one 
    3535 
    3636=item -b|--base basename 
     
    4747 
    4848my $g = GraphViz->new( 
    49     layout => 'neato', 
    50     concentrate => 1, 
    51     overlap => 'compress', 
    52     ratio => 'compress', 
     49    layout => 'dot', 
     50    overlap => 'false', 
     51    rankdir => 1, 
     52    width => 10, height => 8, 
    5353); 
    5454 
     
    6060 
    6161my %users; 
     62my %cluster; 
    6263 
     64sub add_user { 
     65    my ($user) = @_; 
     66    $users{$user} and return; 
     67    my $ou = $labase->get_object('user', $user) or return; 
     68    my $dpmt = $ou->get_attributes('department'); 
     69    if ($dpmt) { 
     70        $cluster{$dpmt} ||= { 
     71            name => $dpmt, 
     72        }; 
     73    } 
     74    $g->add_node($user, ($dpmt ? (cluster => $cluster{$dpmt}) : ())); 
     75    1; 
     76} 
     77 
     78$g->add_node('latmos'); 
    6379foreach my $gr ($labase->list_objects('group')) { 
    6480    my $o = $labase->get_object('group', $gr); 
    65     ($o->get_c_field('sutype') || '') =~ /^(dpmt|cell)$/ or next; 
    66     $g->add_node($gr,fillcolor => 'red', style => 'filled'); 
     81    my $sutype = $o->get_c_field('sutype'); 
     82    ($sutype || '') =~ /^(dpmt|cell)$/ or next; 
     83    $g->add_node($gr,fillcolor => ($sutype eq 'dpmt' ? 'red' : 'green'), style => 'filled'); 
     84    my $manager = $o->get_attributes('managedBy') || ''; 
     85    warn "MANAGER $manager"; 
     86    if ($manager) { 
     87        add_user($manager); 
     88        $g->add_edge('latmos', $gr); 
     89        $g->add_edge($manager => $gr, weight => 3); 
     90    } 
    6791    foreach ($o->get_attributes('member')) { 
    68         $users{$_} or do { 
    69             $users{$_} = 1; 
    70             $g->add_node($_); 
    71         }; 
     92        $_ eq $manager and next; 
     93        add_user($_); 
    7294        warn "$_ => $gr"; 
    73         $g->add_edge($_ => $gr); 
     95        $g->add_edge($gr => $_, weight => 1); 
    7496    } 
    7597} 
  • LATMOS-Accounts/bin/la-group

    r849 r861  
    4141=over 4 
    4242 
    43 =item -c|--config configfile 
     43=item -c|--config configdir 
    4444 
    45 Use this configuration file instead of the default one. 
     45Use this configuration directory instead of the default one. 
    4646 
    4747=item -b|--base basename 
  • LATMOS-Accounts/bin/la-guser

    r849 r861  
    4141=over 4 
    4242 
    43 =item -c|--config configfile 
     43=item -c|--config configdir 
    4444 
    45 Use this configuration file instead of the default one. 
     45Use this configuration directory instead of the default one. 
    4646 
    4747=item -b|--base basename 
  • LATMOS-Accounts/bin/la-log-test

    r594 r861  
    2020    'c|config=s' => \my $config, 
    2121    'l|level=s'  => \my $level, 
    22     'list'       => \my $list, 
     22    'mail=s'     => \my $mail, 
    2323    'help'       => sub { pod2usage(0) }, 
    2424) or pod2usage(); 
     
    2828=over 4 
    2929 
    30 =item -c|--config configfile 
     30=item -c|--config configdir 
    3131 
    32 Use this configuration file instead of the default one. 
     32Use this configuration directory instead of the default one. 
    3333 
    3434=item -l|--level level 
     
    3636Set the log level 
    3737 
     38=item --mail email 
     39 
     40Setup log error sent to email at end of execution 
     41 
    3842=cut 
    3943 
    4044$level ||= 'LA_INFO'; 
    4145 
     46if ($mail) { 
     47    la_set_log(mail => $mail); 
     48} 
     49 
    4250my $numlevel = eval "LATMOS::Accounts::Log::$level()"; 
    4351 
  • LATMOS-Accounts/bin/la-passwd

    r773 r861  
    2020=over 4 
    2121 
    22 =item -c|--config configfile 
     22=item -c|--config configdir 
    2323 
    24 Use this configuration file instead of the default one. 
     24Use this configuration directory instead of the default one. 
    2525 
    2626=item -b|--base basename 
  • LATMOS-Accounts/bin/la-qacls

    r849 r861  
    3636=head1 OPTIONS 
    3737 
    38 =item -c|--config configfile 
     38=item -c|--config configdir 
    3939 
    40 Use this configuration file instead of the default one. 
     40Use this configuration directory instead of the default one. 
    4141 
    4242=item -b|--base basename 
  • LATMOS-Accounts/bin/la-query

    r849 r861  
    4343=over 4 
    4444 
    45 =item -c|--config configfile 
     45=item -c|--config configdir 
    4646 
    47 Use this configuration file instead of the default one. 
     47Use this configuration directory instead of the default one. 
    4848 
    4949=item -b|--base basename 
  • LATMOS-Accounts/bin/la-rename

    r715 r861  
    2020=over 4 
    2121 
    22 =item -c|--config configfile 
     22=item -c|--config configdir 
    2323 
    24 Use this configuration file instead of the default one. 
     24Use this configuration directory instead of the default one. 
    2525 
    2626=item -b|--base basename 
  • LATMOS-Accounts/bin/la-rev

    r837 r861  
    2727=over 4 
    2828 
    29 =item -c|--config configfile 
     29=item -c|--config configdir 
    3030 
    31 Use this configuration file instead of the default one. 
     31Use this configuration directory instead of the default one. 
    3232 
    3333=item -b|--base basename 
  • LATMOS-Accounts/bin/la-search

    r849 r861  
    1919=over 4 
    2020 
    21 =item --config configfile 
     21=item --config configdir 
    2222 
    23 Use this configuration file instead default 
     23Use this configuration directory instead default 
    2424 
    2525=item --base basename 
     
    9191$otype ||= 'user'; 
    9292 
    93 my $LA = LATMOS::Accounts->new($config); 
     93my $LA = LATMOS::Accounts->new($config, noacl => 1); 
    9494my $labase = $base ? $LA->base($base) : $LA->default_base; 
    9595$labase && $labase->load or die "Cannot load base"; 
  • LATMOS-Accounts/bin/la-sync

    r777 r861  
    2626    'to=s'         => \my @to, 
    2727    'nocreate'     => \my $nocreate, 
     28    'nodelete'     => \my $nodelete, 
    2829    'test'         => \my $test, 
    2930    'o|object=s'   => \my $otype, 
    3031    's|syncname=s' => \my $syncname, 
    31     'b|batch'    => \my $batch, 
     32    'b|batch'      => \my $batch, 
     33    'unexp'        => \my $unexp, 
    3234) or pod2usage(); 
    3335 
    3436=head1 OPTIONS 
    3537 
    36 =item -c|--config configfile 
     38=item -c|--config configdir 
    3739 
    38 Use this configuration file instead of the default one. 
     40Use this configuration directory instead of the default one. 
    3941 
    4042=item --from basename 
     
    6870to perform immediate synchronisation.  
    6971 
     72=item --unexp 
     73 
     74Sync unexported objects in source base 
     75 
    7076=cut 
    7177 
     
    8086    from => $from, 
    8187    to => (@to ? [ @to ] : undef), 
    82     nocreate => $nocreate, 
    8388    test     => $test, 
     89    unexported => $unexp, 
    8490) or die "cannot create sync object\n"; 
    8591$sync->load_dest and return; 
     
    9399    } 
    94100} else { 
    95     $sync->process() or warn "Sync has failed\n"; 
     101    $sync->process( 
     102        test     => $test, 
     103        nodelete => $nodelete, 
     104        nocreate => $nocreate, 
     105    ) or warn "Sync has failed\n"; 
    96106} 
    97107 
  • LATMOS-Accounts/bin/la-sync-list

    r834 r861  
    33use strict; 
    44use warnings; 
    5 use LATMOS::Accounts; 
     5use LATMOS::Accounts::Task; 
    66use Getopt::Long; 
    77use Pod::Usage; 
    8 use Config::IniFiles; 
    98 
    109=head1 NAME 
     
    2019=over 4 
    2120 
    22 =item --config configfile 
     21=item --config configdir 
    2322 
    24 Use this configuration file instead default 
     23Use this configuration directory instead default 
    2524 
    2625=item --base basename 
     
    3029=item --lc cfg 
    3130 
    32 la-list-sync config file 
     31la-list-sync config file, defaults to la-sync-list.ini in config directory. 
    3332 
    3433=back 
     
    4342) or pod2usage(); 
    4443 
    45 my $listcfg = Config::IniFiles->new( 
    46     -file => $listconfig, 
    47     -default => '_default_', 
    48 ) or die "Cannot open list config file\n"; 
    4944 
    50 my $LA = LATMOS::Accounts->new($config); 
    51 my $labase = $base ? $LA->base($base) : $LA->default_base; 
    52 $labase && $labase->load or die "Cannot load base"; 
     45my $task = LATMOS::Accounts::Task->new( 
     46    'buildlistes', 
     47    listconfig => $listconfig, 
     48    base => $base, 
     49    config => $config, 
     50); 
    5351 
    54 my %cache; 
     52$task->init || die "Can't instanciate\n"; 
     53exit($task->run ? 0 : 1); 
    5554 
    56 foreach my $list ($listcfg->Sections) { 
    57     my %content = (); 
    58     $list eq '_default_' and next; 
    59     $listcfg->val($list, 'ignore') and next; 
    60     my $fmt = $listcfg->val($list, 'fmt', '%{mail}'); 
    61     my $otype = $listcfg->val($list, 'objects', 'user'); 
    62     foreach (grep { $_ } $listcfg->val($list, 'addtolist')) { 
    63         $content{$_} = 1; 
    64     } 
    65     my %ids; 
    66     foreach my $param ($listcfg->Parameters($list)) { 
    67         $param =~ /^filter/ or next; 
    68  
    69         foreach my $id (sort $labase->search_objects( 
    70                 $listcfg->val($list, 'objects', 'user'), 
    71                 $listcfg->val($list, $param),)) { 
    72             $ids{$id} = 1; 
    73         } 
    74     } 
    75     foreach my $id (sort keys %ids) { 
    76         if (!$cache{$otype}{$fmt}{$id}) { 
    77             my $obj = $labase->get_object( 
    78                 $otype, 
    79                 $id, 
    80             ); 
    81  
    82             $cache{$otype}{$fmt}{$id} = $obj->queryformat($fmt); 
    83         } 
    84         $content{ $cache{$otype}{$fmt}{$id} } = 1; 
    85     } 
    86     my $cmd = $listcfg->val($list, 'cmd', 'cat'); 
    87     $cmd =~ s/%%/$list/g; 
    88     if (open(my $handle, '|' . $cmd)) { 
    89         foreach (keys %content) { 
    90             print $handle $_ ."\n"; 
    91         } 
    92         close($handle); 
    93     } 
    94 } 
    95  
    96 exit(0); 
  • LATMOS-Accounts/bin/la-sync-manager

    r816 r861  
    55use Getopt::Long; 
    66use Pod::Usage; 
     7use Config::IniFiles; 
    78use LATMOS::Accounts; 
     9use LATMOS::Accounts::SyncManager; 
    810use LATMOS::Accounts::Log; 
     11use LATMOS::Accounts::Task; 
    912 
    1013GetOptions( 
     
    1316    'help'         => sub { pod2usage(0) }, 
    1417    'test'         => \my $test, 
    15     's|syncname=s' => \my $syncname, 
     18    'wait=i'       => \my $wait, 
     19    'r|run=s'      => \my $run, 
    1620) or pod2usage(); 
    1721 
    18 my $needsync = 0; 
     22my $needsync = 2; 
    1923my $pidfile = undef; 
     24$wait ||= 5; # default in minutes 
     25 
     26my $syncm = LATMOS::Accounts::SyncManager->new($config) or do { 
     27    la_log LA_ERR, "Cannot instanciate Sync Manager"; 
     28    exit(1); 
     29}; 
     30 
     31if ($run) { 
     32    my $res = $syncm->process_module($run); 
     33    exit($res ? 0 : 1); 
     34} 
    2035 
    2136la_set_log( 
     
    2439); 
    2540 
     41 
    2642{ 
    2743    my $LA = LATMOS::Accounts->new($config, noacl => 1); 
    2844    if ($LA->val('_default_', 'state_dir')) { 
    2945        $pidfile = $LA->val('_default_', 'state_dir') . '/sync-manager.pid'; 
     46    } 
     47    if (my $mail = $LA->val('_network_', 'maillog')) { 
     48            la_set_log(mail => $mail); 
    3049    } 
    3150} 
     
    4665} 
    4766 
    48 sub sync { 
    49  
    50     la_log LA_NOTICE, "Starting synchronisation"; 
    51     my $LA = LATMOS::Accounts->new($config, noacl => 1) or do { 
    52         la_log LA_ERR, "Cannot instantiate LA"; 
    53         return 1; 
    54     }; 
    55  
    56     my $sync = $LA->create_synchro( 
    57         $syncname || $LA->default_synchro_name, 
    58         test     => $test, 
    59     ) or do { 
    60        la_log LA_ERR, "cannot create sync object"; 
    61        return 2; 
    62     }; 
    63  
    64     $sync->load_dest and do { 
    65         la_log LA_ERR, "Cannot load destination"; 
    66         return 3; 
    67     }; 
    68  
    69     $sync->process() or do { 
    70         la_log LA_ERR, "Sync has failed\n"; 
    71         return 4; 
    72     }; 
    73     la_log LA_NOTICE, "Ending synchronisation"; 
    74  
    75     return 0; 
    76 } 
    77  
    7867$SIG{INT} = sub { 
    7968    unlink($pidfile) if ($pidfile); 
     
    8675}; 
    8776 
     77sub process { 
     78    my ($module, $baserev) = @_; 
     79    my $pid = fork; 
     80    if ($pid == 0) { 
     81        $SIG{INT} = 'DEFAULT'; 
     82        my $res = $syncm->process_module($module, $baserev); 
     83        exit($res ? 0 : 1); 
     84    } 
     85    my $retpid; 
     86    while(($retpid = waitpid(-1, 0)) <= 0) {} 
     87    local $SIG{HUP} = 'IGNORE'; 
     88    if ($retpid) { 
     89        my $res = $? << 8; 
     90        if ($res) { 
     91            la_log LA_ERR, "Sync process exit with $res"; 
     92            return; 
     93        } 
     94    } 
     95    return 1; 
     96} 
     97 
     98my $lasttout; 
     99my %revs; 
    88100while (1) { 
    89101    if ($needsync) { 
     102        my $levelsync = $needsync; 
    90103        $needsync = 0; 
    91         my $pid = fork; 
    92         if ($pid == 0) { 
    93             $SIG{INT} = undef; 
    94             exit sync(); 
     104        { 
     105            local $SIG{HUP} = 'IGNORE'; 
     106            $syncm->updrev; 
     107            # listing module to run in this loop 
     108            $lasttout = scalar(time) if ($levelsync == 2); 
    95109        } 
    96         my $retpid; 
    97         while(($retpid = waitpid(-1, 0)) <= 0) {} 
    98         if ($retpid) { 
    99             my $res = $? << 8; 
     110        foreach my $module ($syncm->list_modules()) { 
     111            next if ($syncm->ini->val($module, 'lazy') && $levelsync < 2); 
     112            my $res = process($module, $revs{$module} || 0); 
    100113            if ($res) { 
    101                 la_log LA_ERR, "Sync process exit with $res"; 
    102             }  
    103             next; 
     114                $revs{$module} = $syncm->dbrev; 
     115            } 
    104116        } 
    105117    } 
    106118 
    107119    # waiting, to perform next sync 
    108     sleep(60 * 15); 
    109     $needsync = 1; 
     120    sleep(15) unless($needsync); 
     121    # if it is not time yet: 
     122    next if($lasttout + ($wait * 60) > scalar(time)); 
     123    $needsync = 2; 
    110124} 
    111125 
  • LATMOS-Accounts/bin/la-warn-expire

    r778 r861  
    3333=over 4 
    3434 
    35 =item -c|--config configfile 
     35=item -c|--config configdir 
    3636 
    37 Use this configuration file instead of the default one. 
     37Use this configuration directory instead of the default one. 
    3838 
    3939=item -m|mail 
     
    6969=head1 CONFIGURATION 
    7070 
    71 Some variables are taken from configuration file: 
     71Some variables are taken from configuration directory: 
    7272 
    7373=over 4 
  • LATMOS-Accounts/bin/la-web-directory

    r849 r861  
    1010=head1 NAME 
    1111 
    12     la-query - Tools to query base in LATMOS::Accounts system 
     12    la-web-directory - Generate directory file for website 
    1313 
    1414=head1 SYNOPSIS 
    1515 
    16     la-query [options] [obj_id] 
    17  
    18 =item [obj_id] : If present, all set attributes (rw) will be displayed for that obj_id. 
    19         If none is given, all obj_ids will be printed. 
    20  
    21 For the default object_type (user), obj_id = login. 
    22  
    23 Example : la-query lambda 
     16    la-web-directory 
    2417 
    2518=cut 
     
    3932=over 4 
    4033 
    41 =item -c|--config configfile 
     34=item -c|--config configdir 
    4235 
    43 Use this configuration file instead of the default one. 
     36Use this configuration directory instead of the default one. 
    4437 
    4538=item -b|--base basename 
     
    7366foreach my $user (sort $labase->search_objects('user', 
    7467            @filters ? @filters : 'sn=*')) { 
    75     my $ouser = $labase->get_object('user', $user); 
     68    my $ouser = $labase->get_object('user', $user) or next; 
    7669    $ouser->get_attributes('sn') or next; 
    7770    if ($noexpire && (my $expdate = $ouser->get_attributes('expireText'))) { 
     
    8477 
    8578    my $company = $ouser->get_attributes('company'); 
    86     my $contrat = $ouser->get_attributes('contratType'); 
     79    my $contrat = $ouser->get_attributes('contratType') || ''; 
    8780    if ($company){ 
    8881        if (($company ne "LATMOS")&&($contrat ne "heberges")) { 
     
    10194 
    10295    if ($labase->is_supported_object('address')) { 
    103         @oaddress =  
     96        @oaddress = 
     97            sort { $a->get_attributes('isMainAddress') ? 0 : 1 } 
    10498            grep { $_ } ( 
    10599            map { $labase->get_object('address', $_) } 
     
    125119        $department = join(' ', @userdepts); 
    126120    } 
    127              
    128     my $line = join(';', map { $_ || '' } ( 
     121 
     122    my @fmtaddr; 
     123    foreach (0, 1) { 
     124        if ($oaddress[$_]) { 
     125 
     126            my $city; 
     127            if (my $site = $oaddress[$_]->get_attributes('site')) { 
     128                $city = $labase->get_object('site', 
     129                    $site)->get_attributes('siteNick'); 
     130            } 
     131            if (!$city) { 
     132                $city = $oaddress[$_]->get_attributes('l') || ''; 
     133                $city =~s/Paris */PAR/g; 
     134                $city =~s/Guyancourt */GUY/g; 
     135                $city =~s/Vélizy-Villacoublay */VEL/g; 
     136                $city =~s/VerriÚres le Buisson */VLB/g; 
     137                $city =~s/St Maur des Fossés */STM/g; 
     138            } 
     139            my $office = $oaddress[$_]->get_attributes('physicalDeliveryOfficeName'); 
     140            push(@fmtaddr, join('-', grep { defined($_) } ($city || '', $office))); 
     141        } 
     142    } 
     143 
     144    my $line = join('|', map { $_ || '' } ( 
    129145            $ouser->get_attributes('sn'), 
    130146            $ouser->get_attributes('givenName'), 
    131147            $department, 
    132             ($oaddress[0] ? join(' ', map { $_ || '' } 
    133                     $oaddress[0]->get_attributes('l'), grep { $_ } 
    134                     $oaddress[0]->get_attributes('physicalDeliveryOfficeName'), 
    135                 ) : ''), 
    136             ($oaddress[1] ? join(' ', map { $_ || '' } grep { $_ } 
    137                     $oaddress[1]->get_attributes('l'), 
    138                     $oaddress[1]->get_attributes('physicalDeliveryOfficeName'), 
    139                 ) : ''), 
    140             ($oaddress[0] ? $oaddress[0]->get_attributes('telephoneNumber') : ''), 
    141             ($oaddress[1] ? $oaddress[1]->get_attributes('telephoneNumber') : ''), 
     148            $fmtaddr[0] || '', 
     149            $fmtaddr[1] || '', 
     150            map { 
     151                my $l = $_ || ''; 
     152                $l =~s/ *([0-9])/$1/g; 
     153                $l =~s/\(//g; 
     154                $l =~s/\)//g; 
     155                $l =~s/\+33//g; 
     156                $l 
     157            } ( 
     158                ($oaddress[0] ? $oaddress[0]->get_attributes('telephoneNumber') : ''), 
     159                ($oaddress[1] ? $oaddress[1]->get_attributes('telephoneNumber') : ''), 
     160            ), 
    142161            $ouser->get_attributes('mail'), 
    143162            $ouser->get_attributes('nickname'), 
     163            $ouser->get_attributes('snNative') || '', 
     164            $ouser->get_attributes('givenNameNative') || '', 
     165            $ouser->get_attributes('wWWHomePage') || '', 
     166            $ouser->get_attributes('halReference') || '', 
    144167        )); 
    145         $line =~s/Paris */PAR-/g; 
    146         $line =~s/Guyancourt */GUY-/g; 
    147         $line =~s/Vélizy-Villacoublay */VEL-/g; 
    148         $line =~s/VerriÚres le Buisson */VLB-/g; 
    149         $line =~s/St Maur des Fossés */STM-/g; 
    150         $line =~s/\+ *33 *1 *//g; 
     168        $line =~s/:1/:01/g; 
    151169 
    152170    $users{$ouser->get_attributes('sn')}{$ouser->get_attributes('givenName')} = $line; 
  • LATMOS-Accounts/etc/init.d/la-sync-manager

    r603 r861  
    1111export LANG 
    1212 
    13 USER=apache 
     13USER=nobody 
    1414[ -f /etc/sysconfig/latmos-accounts ] && \ 
    1515    . /etc/sysconfig/latmos-accounts 
  • LATMOS-Accounts/latmos-accounts.spec.in

    r841 r861  
    11%define realname   LATMOS-Accounts 
    22%define version    @VERSION@ 
    3 %define release    %mkrel 1 
     3%define release    %mkrel %{?svnrelease:0.%{svnrelease}}%{?!svnrelease:1} 
    44 
    55Name:       latmos-accounts 
     
    2424BuildRequires: perl(Net::DNS) 
    2525BuildRequires: perl(Template) 
     26BuildRequires: perl(Net::IP) 
     27BuildRequires: perl(Text::CSV_XS) 
     28BuildRequires: perl(Heimdal::Kadm5) 
    2629 
    2730Requires: perl(Mail::Sendmail) 
     
    3033Requires: perl(DBD::Pg) 
    3134Requires: perl(IO::Socket::SSL) 
     35Requires: perl-Term-ReadLine-Gnu 
    3236 
    3337%description 
     
    7781%config(noreplace) %_sysconfdir/sysconfig/latmos-accounts 
    7882%config(noreplace) %_sysconfdir/cron.d/latmos-accounts 
    79 %attr(0600,root,root) %config(noreplace) %_sysconfdir/latmos-account.ini 
     83%attr(0600,nobody,nobody) %config(noreplace) %_sysconfdir/latmos-accounts/* 
    8084%_bindir/* 
     85%{_mandir}/man1/* 
    8186%{_mandir}/man3/* 
    82 %{_mandir}/man1/* 
     87%{_mandir}/man5/* 
    8388%perl_vendorlib/* 
    8489%_datadir/latmos-accounts 
  • LATMOS-Accounts/lib/LATMOS/Accounts.pm

    r684 r861  
    2121=cut 
    2222 
     23sub _configdir { 
     24   my ($self) = @_; 
     25   ($self || {})->{_configdir} || '/etc/latmos-accounts' 
     26} 
     27 
    2328=head1 FUNCTION 
    2429 
    25 =head2 new($configfile) 
     30=head2 new($configdir) 
    2631 
    2732Instanciate a new LATMOS::Accounts object. 
    2833 
    29 $configfile if defined is the Config::IniFiles formatted file to use, 
    30 default to F</etc/latmos-account.ini>. 
     34$configdir if defined is the directory containing files to use, 
     35default to F</etc/latmos-accounts/>. 
    3136 
    3237=cut 
     
    3540    my ($class, $config, %options) = @_; 
    3641 
    37     $config ||= '/etc/latmos-account.ini'; 
     42    $config ||= _configdir(); 
     43    my $oldconfig ||= '/etc/latmos-account.ini'; 
     44 
     45    # If config file not found, fallback to old one 
     46    my $configfile = -f join('/', $config, 'latmos-accounts.ini') 
     47        ? join('/', $config, 'latmos-accounts.ini') 
     48        : '/etc/latmos-account.ini'; 
    3849 
    3950    my $self = Config::IniFiles->new( 
    40         -file => $config, 
     51        -file => $configfile, 
    4152        '-default' => '_default_', 
    42     ); 
    43     if ((!$options{noacl}) && $self->val('_default_', 'acls')) { 
    44         my $acls = LATMOS::Accounts::Acls->new( 
    45             $self->val('_default_', 'acls') 
    46         ) or do { 
    47             return; 
    48         }; 
    49         $self->{_acls} = $acls; 
     53    ) or do { 
     54        la_log(LA_ERR, 'Can\'t open main config file %s', $configfile); 
     55        return; 
     56    }; 
     57 
     58    $self->{_configdir} = $config; 
     59    bless($self, $class); 
     60 
     61    if (!$options{noacl}) { 
     62        if ($self->val('_default_', 'acls')) { 
     63            $self->{_acls} = LATMOS::Accounts::Acls->new( 
     64                $self->val('_default_', 'acls') 
     65            ) or do { 
     66                la_log(LA_ERR, 
     67                    'Cannot load ACL file %s', $self->val('_default_', 'acls') 
     68                ); 
     69                return; 
     70            }; 
     71        } elsif (-f (my $aclf = join('/', $self->_configdir, 'la-acls.ini'))) { 
     72            $self->{_acls} = LATMOS::Accounts::Acls->new($aclf) or do { 
     73                la_log(LA_ERR, 'Cannot load ACL file %s', $aclf); 
     74                return; 
     75            }; 
     76        } 
    5077    } 
    5178 
     
    5380        $self->{_allowed_values} = Config::IniFiles->new( 
    5481            -file => $self->val('_default_', 'allowed_values'), 
    55             -allowempty => 1, 
    5682        ) or do { 
     83            la_log(LA_ERR, 'Cannot load ALLOWED VALUES %s', 
     84                $self->val('_default_', 'allowed_values')); 
    5785            return; 
    5886        }; 
    59     } 
    60  
    61     bless($self, $class) 
     87    } elsif (-f (my $allowf = join('/', $self->_configdir, 
     88                'la-allowed-values.ini'))) { 
     89        $self->{_allowed_values} = Config::IniFiles->new( 
     90            -file => $allowf, 
     91        ) or do { 
     92            la_log(LA_ERR, 'Cannot load ALLOWED VALUES %s', $allowf); 
     93            return; 
     94        }; 
     95    } 
     96 
     97    $self 
    6298} 
    6399 
     
    153189        acls => $self->{_acls}, 
    154190        allowed_values => $self->{_allowed_values}, 
     191        configdir => $self->_configdir, 
    155192    ) or do { 
    156193        la_log(LA_WARN, "Cannot instanciate base $section ($type)"); 
  • LATMOS-Accounts/lib/LATMOS/Accounts/Bases.pm

    r856 r861  
    6767} 
    6868 
     69=head2 log($level, $msg, $arg) 
     70 
     71Log a message prefixed by database information 
     72 
     73=cut 
     74 
    6975sub log { 
    7076    my ($self, $level, $msg, @args) = @_; 
     
    7379} 
    7480 
     81=head2 label 
     82 
     83Return the database label 
     84 
     85=cut 
     86 
    7587sub label { 
    7688    $_[0]->{_label} || 'NoLabel'; 
     
    8193} 
    8294 
    83 sub allowed_values { 
    84     $_[0]->{_allowed_values} 
    85 } 
    86  
    87 sub obj_attr_allowed_values { 
    88     my ($self, $otype, $attr) = @_; 
    89     if ($self->allowed_values) { 
    90         return $self->allowed_values->val("$otype.$attr", 'allowed'); 
    91     } 
    92     return(); 
    93 } 
    94  
    95 sub check_allowed_values { 
    96     my ($self, $otype, $attr, $attrvalues) = @_; 
    97     $self->allowed_values or return 1; 
    98     my @values = ref $attrvalues ? @{ $attrvalues } : $attrvalues; 
    99     foreach my $value (@values) { 
    100         $value or next; 
    101         if (my @allowed = $self->allowed_values->val("$otype.$attr", 'allowed')) { 
    102             grep { $value eq $_ } @allowed or do { 
    103                 $self->log(LA_ERR, 
    104                     "value `%s' is not allow for %s.%s per configuration (allowed_values)", 
    105                     $value, $otype, $attr 
    106                 ); 
    107                 return; 
    108             }; 
    109         } 
    110     } 
    111     return 1; 
    112 } 
    113  
    114 sub _load_obj_class { 
    115     my ($self, $otype) = @_; 
    116  
    117     # finding perl class: 
    118     my $pclass = ref $self; 
    119     $pclass .= '::' . ucfirst(lc($otype)); 
    120     eval "require $pclass;"; 
    121     if ($@) { 
    122         $self->log(LA_DEBUG, 'Cannot load perl class %s', $pclass); 
    123         return 
    124     } # error message ? 
    125     return $pclass; 
    126 } 
    127  
    128 =head2 list_canonical_fields($otype, $for) 
    129  
    130 Return the list of supported fields by the database for object type $otype. 
    131  
    132 Optionnal $for specify the goal for which the list is requested, only supported 
    133 fields will be returns 
    134  
    135 =cut 
    136  
    137 sub list_canonical_fields { 
    138     my ($self, $otype, $for) = @_; 
    139     $for ||= 'rw'; 
    140     my $pclass = $self->_load_obj_class($otype) or return; 
    141     sort $pclass->_canonical_fields($self, $for); 
    142 } 
    143  
    144 sub get_attr_schema { 
    145     my ($self, $otype, $attribute) = @_; 
    146     my $pclass = $self->_load_obj_class($otype) or return; 
    147     if ($pclass->can('_get_attr_schema')) { 
    148         my $info = $pclass->_get_attr_schema($self, $attribute); 
    149         return $info if ($info); 
    150     } 
    151     if ($self->can('_get_attr_schema')) { 
    152         my $info = $self->_get_attr_schema($otype, $attribute); 
    153         return $info if($info); 
    154     } 
    155     return {} 
    156 } 
    157  
    158 sub attribute { 
    159     my ($self, $otype, $attribute) = @_; 
    160     return LATMOS::Accounts::Bases::Attributes->new( 
    161         $attribute, 
    162         $self, 
    163         $otype, 
    164     ); 
    165 } 
    166  
    167 sub delayed_fields { 
    168     my ($self, $otype, $for) = @_; 
    169     $for ||= 'rw'; 
    170     my $pclass = $self->_load_obj_class($otype) or return; 
    171     $pclass->_delayed_fields($self, $for); 
    172 } 
    173  
    174 =head2 get_field_name($otype, $c_fields, $for) 
    175  
    176 Return the internal fields name for $otype object for 
    177 canonical fields $c_fields 
    178  
    179 =cut 
    180  
    181 sub get_field_name { 
    182     my ($self, $otype, $c_fields, $for) = @_; 
    183     $for ||= 'rw'; 
    184     my $pclass = $self->_load_obj_class($otype) or return; 
    185     $pclass->_get_field_name($c_fields, $self, $for); 
     95sub options { 
     96    my ($self, $opt) = @_; 
     97    return $self->{_options}{$opt}; 
    18698} 
    18799 
     
    212124} 
    213125 
     126sub ordered_objects { 
     127    my ($self) = @_; 
     128 
     129    my %deps; 
     130    my %maxdeps; 
     131    my @objs = sort { $b cmp $a } $self->list_supported_objects; 
     132    foreach my $obj (@objs) { 
     133        foreach my $at ($self->list_canonical_fields($obj)) { 
     134            my $attr = $self->attribute($obj, $at); 
     135            $attr->ro and next; 
     136            $attr->{delayed} and next; 
     137            if (my $res = $attr->reference) { 
     138                $deps{$obj}{$res} ||= 1; 
     139                if ($attr->mandatory) { 
     140                    $deps{$obj}{$res} = 2; 
     141                    $maxdeps{$res} = 1; 
     142                } 
     143            } 
     144        } 
     145    } 
     146 
     147    sort { 
     148        if (keys %{$deps{$a} || {}}) { 
     149            if (keys %{$deps{$b} || {}}) { 
     150                return ( 
     151                    ($deps{$a}{$b} || 0) > ($deps{$b}{$a} || 0) ?  1 : 
     152                    ($deps{$b}{$a} || 0) > ($deps{$a}{$b} || 0) ? -1 : 
     153                    ($maxdeps{$b} || 0) - ($maxdeps{$a} || 0) 
     154                ); 
     155            } else { 
     156                return 1; 
     157            } 
     158        } elsif (keys %{$deps{$b} || {}}) { 
     159            return -1; 
     160        } else { 
     161            return  ($maxdeps{$b} || 0) - ($maxdeps{$a} || 0) 
     162        } 
     163    } @objs; 
     164} 
     165 
     166sub _load_obj_class { 
     167    my ($self, $otype) = @_; 
     168 
     169    # finding perl class: 
     170    my $pclass = ref $self; 
     171    $pclass .= '::' . ucfirst(lc($otype)); 
     172    eval "require $pclass;"; 
     173    if ($@) { 
     174        $self->log(LA_DEBUG, 'Cannot load perl class %s', $pclass); 
     175        return 
     176    } # error message ? 
     177    return $pclass; 
     178} 
     179 
     180 
    214181=head2 is_supported_object($otype) 
    215182 
     
    259226sub create_object { 
    260227    my ($self, $otype, $id, %data) = @_; 
     228    "$id" or do { 
     229        $self->log(LA_ERR, "Cannot create %s object with empty id", 
     230            $otype); 
     231        return; 
     232    }; 
    261233    my $pclass = $self->_load_obj_class($otype); 
    262234    if ($pclass->_create($self, $id, %data)) { 
     
    289261        return; 
    290262    }; 
    291     if (my $chk = (lc($otype) eq 'user' || lc($otype) eq 'group') 
     263 
     264    $self->_create_c_object($otype, $id, %cdata); 
     265} 
     266 
     267sub _create_c_object { 
     268    my ($self, $otype, $id, %cdata) = @_; 
     269     
     270    if (my $chk = ( 
     271        lc($otype) eq 'user' || lc($otype) eq 'group') 
    292272        ? LATMOS::Accounts::Utils::check_ug_validity($id) 
    293273        : LATMOS::Accounts::Utils::check_oid_validity($id)) { 
     
    301281        }; 
    302282    } 
    303  
    304     $self->_create_c_object($otype, $id, %cdata); 
    305 } 
    306  
    307 sub _create_c_object { 
    308     my ($self, $otype, $id, %cdata) = @_; 
    309283 
    310284    # populating default value 
     
    324298                to_ascii(lc($cdata{sn})),) 
    325299            : undef; 
     300        $mailid =~ s/\s*//g if($mailid); 
    326301 
    327302        if ($mailid && 
    328303            $self->is_supported_object('aliases') && 
    329304            ! $self->get_object('aliases', $mailid)) { 
    330             if ($self->get_field_name($otype, 'mail', 'write')) { 
    331                 if ($self->{defattr}{'user.maildomain'}) { 
     305            if (my $attr = $self->attribute($otype, 'mail')) { 
     306                if ((!$attr->ro) && $self->{defattr}{'user.maildomain'}) { 
    332307                    $cdata{mail} ||= sprintf('%s@%s', 
    333308                    $mailid, 
     
    335310                } 
    336311            } 
    337             if ($self->get_field_name($otype, 'aliases', 'write')) { 
    338                 $cdata{aliases} ||= $mailid; 
     312            if (my $attr = $self->attribute($otype, 'aliases')) { 
     313                $cdata{aliases} ||= $mailid unless ($attr->ro); 
    339314            } 
    340             if ($self->get_field_name($otype, 'revaliases', 'write')) { 
    341                 $cdata{revaliases} ||= $mailid; 
     315            if (my $attr = $self->attribute($otype, 'revaliases')) { 
     316                $cdata{revaliases} ||= $mailid unless ($attr->ro); 
    342317            } 
    343318        } 
     
    348323    my %data; 
    349324    foreach my $cfield (keys %cdata) { 
    350         my $field = $self->get_field_name($otype, $cfield, 'write') or next; 
    351         $data{$field} = $cdata{$cfield}; 
    352     } 
    353     keys %data or return 0; # TODO: return an error ? 
     325        my $attribute = $self->attribute($otype, $cfield) or next; 
     326        $attribute->ro and next; 
     327        $data{$attribute->iname} = $cdata{$cfield}; 
     328    } 
     329    #keys %data or return 0; # TODO: return an error ? 
    354330    $self->create_object($otype, $id, %data); 
     331} 
     332 
     333 
     334sub _allowed_values { 
     335    $_[0]->{_allowed_values} 
     336} 
     337 
     338sub obj_attr_allowed_values { 
     339    my ($self, $otype, $attr) = @_; 
     340    if ($self->_allowed_values && 
     341        $self->_allowed_values->SectionExists("$otype.$attr")) { 
     342        return grep { defined($_) } $self->_allowed_values->val("$otype.$attr", 'allowed'); 
     343    } 
     344    return(); 
     345} 
     346 
     347sub check_allowed_values { 
     348    my ($self, $otype, $attr, $attrvalues) = @_; 
     349    $self->_allowed_values or return 1; 
     350    my @values = ref $attrvalues ? @{ $attrvalues } : $attrvalues; 
     351    foreach my $value (@values) { 
     352        $value or next; 
     353        if (my @allowed = $self->obj_attr_allowed_values($otype, $attr)) { 
     354            grep { $value eq $_ } @allowed or do { 
     355                $self->log(LA_ERR, 
     356                    "value `%s' is not allow for %s.%s per configuration (allowed_values)", 
     357                    $value, $otype, $attr 
     358                ); 
     359                return; 
     360            }; 
     361        } 
     362    } 
     363    return 1; 
     364} 
     365 
     366=head2 list_canonical_fields($otype, $for) 
     367 
     368Return the list of supported fields by the database for object type $otype. 
     369 
     370Optionnal $for specify the goal for which the list is requested, only supported 
     371fields will be returns 
     372 
     373=cut 
     374 
     375sub list_canonical_fields { 
     376    my ($self, $otype, $for) = @_; 
     377    $for ||= 'rw'; 
     378    my $pclass = $self->_load_obj_class($otype) or return; 
     379    sort $pclass->_canonical_fields($self, $for); 
     380} 
     381 
     382sub _get_attr_schema { 
     383    my ($self, $otype) = @_; 
     384    my $pclass = $self->_load_obj_class($otype) or return; 
     385    return $pclass->_get_attr_schema($self); 
     386} 
     387 
     388sub get_attr_schema { 
     389    my ($self, $otype, $attribute) = @_; 
     390    my $info = $self->_get_attr_schema($otype); 
     391    if ($info->{$attribute}) { 
     392        return $info->{$attribute}; 
     393    } else { 
     394        return; 
     395    } 
     396} 
     397 
     398sub attribute { 
     399    my ($self, $otype, $attribute) = @_; 
     400    return LATMOS::Accounts::Bases::Attributes->new( 
     401        $attribute, 
     402        $self, 
     403        $otype, 
     404    ); 
     405} 
     406 
     407sub delayed_fields { 
     408    my ($self, $otype, $for) = @_; 
     409    $self->log(LA_WARN, "calling DEPRECATED delayed_fields " . join(',', 
     410            caller)); 
     411    $for ||= 'rw'; 
     412    my @attrs; 
     413    foreach ($self->list_canonical_fields($otype, $for)) { 
     414        my $attr = $self->attribute($otype, $_) or next; 
     415        $for =~ /w/ && $attr->ro and next; 
     416        $attr->delayed or next; 
     417        push(@attrs, $_); 
     418    } 
     419    @attrs 
     420} 
     421 
     422sub ochelper { 
     423    my ($self, $otype) = @_; 
     424    my $pclass = ucfirst(lc($otype)); 
     425    foreach my $class ( 
     426        ref($self) . '::OCHelper::' . $pclass, 
     427        ref($self) . '::OCHelper', 
     428        "LATMOS::Accounts::Bases::OCHelper::$pclass", 
     429        'LATMOS::Accounts::Bases::OCHelper' ) { 
     430        eval "require $class;"; 
     431        if ($@) { next } # error message ? 
     432        my $ochelper = "$class"->new($self, $otype); 
     433        return $ochelper; 
     434    } 
     435    return; 
    355436} 
    356437 
     
    463544        } 
    464545    } 
     546 
     547    $self->postcommit(); 
     548 
    465549    return 1; 
     550} 
     551 
     552sub postcommit { 
     553    my ($self) = @_; 
     554 
     555    if ($self->{_options}{postcommit}) { 
     556        exec_command($self->{_options}{postcommit}, 
     557            { 
     558                BASE => $self->label, 
     559                BASETYPE => $self->type, 
     560                HOOK_TYPE => 'POST', 
     561                CONFIG => $self->{_options}{configdir},   
     562            } 
     563        ); 
     564    } else { 
     565        return 1; 
     566    } 
    466567} 
    467568 
     
    541642        : $self->list_canonical_fields($srcobj->type, 'w'); 
    542643    my %data; 
    543     my %delayed = map { $_ => 1 } $self->delayed_fields($srcobj->type); 
    544644    foreach (@fields) { 
    545         $srcobj->get_field_name($_, 'r') or next; 
     645        # check attribute exists in source: 
     646        my $attr = $srcobj->attribute($_) or next; 
    546647        if (! $options{onepass}) { 
    547648            if ($options{firstpass}) { 
    548                 $delayed{$_} and next; 
     649                $attr->delayed and next; 
    549650            } else { 
    550                 $delayed{$_} or next; 
     651                $attr->delayed or next; 
    551652            } 
    552653        } 
    553654        $data{$_} = $srcobj->_get_c_field($_); 
    554655    } 
    555     keys %data or return ''; 
    556656    if (my $dstobj = $self->get_object($srcobj->type, $srcobj->id)) { 
     657        keys %data or return 'SYNCED'; 
     658        foreach (keys %data) { 
     659            if (!$dstobj->attribute($_) || 
     660                $dstobj->attribute($_)->ro) { 
     661                delete($data{$_}); 
     662            } 
     663        } 
    557664        my $res = $dstobj->_set_c_fields(%data); 
    558665        if (defined $res) { 
     
    615722    }; 
    616723 
    617     if ($self->get_field_name('user', 'exported', 'r')) { 
     724    if ($self->attribute('user', 'exported')) { 
    618725        if (!$uobj->_get_c_field('exported')) { 
    619726            la_log(LA_ERR, "User $username found but currently unexported"); 
     
    622729    } 
    623730 
    624     if (my $expire = $uobj->_get_c_field('shadowExpire')) { 
    625         if ($expire > 0 && $expire < int(time / ( 3600 * 24 ))) { 
    626             la_log(LA_ERR, "Account $username has expired (%d / %d)", 
    627                 $expire, int(time / ( 3600 * 24 ))); 
    628             return; 
    629         } 
     731    if ($uobj->_get_c_field('expired')) { 
     732        la_log(LA_ERR, "Account $username has expired (%s)", 
     733            $uobj->_get_c_field('expired')); 
     734        return; 
    630735    } 
    631736 
  • LATMOS-Accounts/lib/LATMOS/Accounts/Bases/Ad/Group.pm

    r821 r861  
    4242sub _my_ldap_classes { qw(top group) } 
    4343 
    44 sub _delayed_fields { 
    45     my ($self)= @_; 
    46     return qw(memberUID member managedBy); 
    47 } 
    48  
    49 sub _canonical_fields { 
    50     my ($self, $base, $mode) = @_; 
    51     ( 
    52         qw(gidNumber description member memberUID sAMAccountName managedBy), 
    53         ($mode !~ /w/ 
    54             ? qw(cn dn objectClass) 
    55             : () 
    56         ) 
    57     ) 
     44sub _get_attr_schema { 
     45    my ($class, $base) = @_; 
     46    { 
     47        gidNumber  => { uniq => 1, }, 
     48        description => { }, 
     49        member => { 
     50            delayed => 1, 
     51            can_values => sub { $base->list_objects('user') }, 
     52        }, 
     53        memberUID => { delayed => 1, }, 
     54        sAMAccountName => { }, 
     55        managedBy => { 
     56            delayed => 1, 
     57            can_values => sub { $base->list_objects('user') }, 
     58        }, 
     59        cn => { ro => 1, }, 
     60        dn => { ro => 1, }, 
     61        objectClass => { ro => 1, }, 
     62        msSFU30NisDomain => { }, 
     63        msSFU30Name => { }, 
     64 
     65    } 
    5866} 
    5967 
  • LATMOS-Accounts/lib/LATMOS/Accounts/Bases/Ad/User.pm

    r810 r861  
    4343sub _my_ldap_classes { qw(top person organizationalPerson user) } 
    4444 
    45 sub _delayed_fields { 
    46     my ($self)= @_; 
    47     return qw(memberOf manager); 
    48 } 
    49  
    50 sub _canonical_fields { 
    51     my ($self, $base, $mode) = @_; 
    52     ( 
    53         qw( 
    54         sn name givenName 
    55         sAMAccountName uid gecos 
    56         homeDirectory loginShell 
    57         uidNumber gidNumber 
    58         shadowLastChange shadowMin shadowMax 
    59         shadowWarning shadowInactive shadowExpire 
    60         shadowFlag 
    61         description 
    62         mail 
    63         telephoneNumber 
    64         ipPhone otherTelephone department 
    65         title mobile homePhone 
    66         accountExpires 
    67         streetAddress postalCode postOfficeBox l 
    68         physicalDeliveryOfficeName 
    69         company st 
    70         displayName 
    71         initials 
    72         manager 
    73         userAccountControl 
    74         locked 
    75         memberOf 
    76         winhomeDirectory 
    77         facsimileTelephoneNumber 
    78         ), 
    79         ($mode !~ /w/ 
    80             ? qw(cn dn uSNCreated uSNChanged directReports objectClass) 
    81             : () 
    82         ) 
    83     ) 
     45sub _get_attr_schema { 
     46    my ($class, $base) = @_; 
     47    { 
     48        sn => { }, 
     49        name => { }, 
     50        givenName => { }, 
     51        sAMAccountName => { }, 
     52        uid => { uniq => 1, }, 
     53        gecos => { }, 
     54        homeDirectory => { }, 
     55        loginShell => { }, 
     56        uidNumber => { uniq => 1, }, 
     57        gidNumber => { 
     58            mandatory => 1, 
     59            can_values => sub { 
     60                map { $base->get_object('group', 
     61                        $_)->get_attributes('gidNumber') } 
     62                $base->list_objects('group') 
     63            }, 
     64            display => sub { 
     65                my ($self, $val) = @_; 
     66                my ($gr) = $self->base->search_objects('group', "gidNumber=$val") 
     67                    or return; 
     68                return $gr; 
     69            }, 
     70            reference => 'group', 
     71        }, 
     72        shadowLastChange => { }, 
     73        shadowMin => { }, 
     74        shadowMax => { }, 
     75        shadowWarning => { }, 
     76        shadowInactive => { }, 
     77        shadowExpire => { }, 
     78        shadowFlag => { }, 
     79        description => { }, 
     80        mail => { }, 
     81        telephoneNumber => { }, 
     82        ipPhone => { }, 
     83        otherTelephone => { }, 
     84        department => { }, 
     85        title => { }, 
     86        mobile => { }, 
     87        homePhone => { }, 
     88        accountExpires => { }, 
     89        streetAddress => { }, 
     90        postalCode => { }, 
     91        postOfficeBox => { }, 
     92        l => { }, 
     93        physicalDeliveryOfficeName => { }, 
     94        company => { }, 
     95        st => { }, 
     96        displayName => { }, 
     97        initials => { }, 
     98        manager => { 
     99            delayed => 1, 
     100            can_values => sub { $base->list_objects('user') }, 
     101        }, 
     102        userAccountControl => { }, 
     103        locked => { }, 
     104        memberOf => { delayed => 1, }, 
     105        winhomeDirectory => { }, 
     106        facsimileTelephoneNumber => { }, 
     107        cn => { ro => 1, }, 
     108        dn => { ro => 1, }, 
     109        uSNCreated => { ro => 1, }, 
     110        uSNChanged => { ro => 1, }, 
     111        directReports => { ro => 1, }, 
     112        objectClass => { ro => 1, }, 
     113        msSFU30NisDomain => { }, 
     114        msSFU30Name => { }, 
     115        labeledURI => {}, 
     116        wWWHomePage => {}, 
     117    } 
    84118} 
    85119 
     
    206240        }; 
    207241        /^manager$/ && $value and do { 
    208             my $user = $base->get_object('user', $value) or next; 
     242            my $user = $base->get_object('user', $value) or do { 
     243                $value = undef; 
     244                next; 
     245            }; 
    209246            $value = $user->get_field('dn'); 
    210247            next; 
    211248        }; 
    212249        /^locked$/ and do { 
    213             my $uac = $entry->get_value('userAccountControl'); 
     250            my $uac = $entry->get_value('userAccountControl') || 0; 
    214251            if ($value) { 
    215252                $uac |= 0x00000002; 
  • LATMOS-Accounts/lib/LATMOS/Accounts/Bases/Attributes.pm

    r857 r861  
    2525        : (undef, $base_or_object, $maybe_otype); 
    2626 
    27     my $attr_info = $base->get_attr_schema($otype, $attributes); 
     27    my $attr_info = $base->get_attr_schema($otype, $attributes) or return; 
    2828 
    2929    $attr_info->{_base} = $base; 
     
    3838sub name  { $_[0]->{_name}  } 
    3939sub otype { $_[0]->{_otype} } 
     40sub mandatory { $_[0]->{mandatory} || 0 } 
     41sub object { $_[0]->{_object} } 
     42 
     43=head2 reference 
     44 
     45A object type this attribute refer to 
     46 
     47=cut 
     48 
     49sub reference { 
     50    my ($self) = @_; 
     51    if ($self->{reference} && 
     52        $self->base->is_supported_object($self->{reference})) { 
     53        return $self->{reference}; 
     54    } else { 
     55        return; 
     56    } 
     57} 
    4058 
    4159=head2 
     
    4967sub label { $_[0]->{label} || $_[0]->{_name} } 
    5068 
     69sub has_values_list { 
     70    my ($self) = @_; 
     71    if ($self->base->obj_attr_allowed_values( 
     72        $self->otype, 
     73        $self->name) || 
     74        $self->{can_values} || 
     75        $self->reference) { 
     76        return 1; 
     77    } else { 
     78        return 0; 
     79    } 
     80} 
     81 
    5182sub can_values { 
    5283    my ($self) = @_; 
     
    5990            return @{$self->{can_values}}; 
    6091        } elsif (ref $self->{can_values} eq 'CODE') { 
    61             $self->{can_values}->($self); 
     92            $self->{can_values}->($self, $self->object); 
    6293        } else { 
    6394            return; 
    6495        } 
     96    } elsif (my $ref = $self->reference) { 
     97        return $self->base->list_objects($ref); 
    6598    } else { return } 
    6699} 
    67100 
    68 sub ro { $_[0]->{ro} || 0 } 
     101sub display { 
     102    my ($self, $value) = @_; 
     103    if ($self->{display}) { 
     104        return $self->{display}->($self, $value); 
     105    } else { 
     106        return $value; 
     107    } 
     108} 
     109 
     110sub input { 
     111    my ($self, $value) = @_; 
     112    if ($self->{input}) { 
     113        return $self->{input}->($value); 
     114    } else { 
     115        return $value; 
     116    } 
     117} 
     118 
     119sub ro { 
     120    my ($self) = @_; 
     121    if (ref $self->{ro} eq 'CODE') { 
     122        return $self->{ro}->($self->object) || 0; 
     123    } else { 
     124        return $_[0]->{ro} || 0  
     125    } 
     126} 
    69127 
    70128sub readonly {  
     
    72130    return 1 if ($self->ro); 
    73131     
    74     return ! $self->base->check_acl($self->object 
    75         ? ($self->object, $self->name, 'w') 
    76         : ($self->otype, '@CREATE', 'w')); 
     132    return ! $self->check_acl('w'); 
     133} 
     134 
     135sub check_acl { 
     136    my ($self, $mode) = @_; 
     137    return $self->base->check_acl($self->object 
     138        ? ($self->object, $self->name, $mode) 
     139        : ($self->otype, '@CREATE', $mode)); 
    77140} 
    78141 
    79142=head2 form_type 
    80143 
    81 Return the way the fields must be show in GUI: 
     144Return the way the fields must be show in GUI. 
     145For each type option maybe given by from_option 
     146 
     147=head3 LABEL 
    82148 
    83149=over 4 
    84150 
    85 =item LABEL 
     151=item length 
    86152 
    87 =item TEXT 
     153The length to use to show the attribute 
    88154 
    89 =item DATE 
     155=back 
    90156 
    91 =item LIST 
     157=head3 TEXT 
    92158 
    93 =item CHECKBOX 
     159=head3 TEXTAREA 
     160 
     161=head3 DATE 
     162 
     163=head3 LIST 
     164 
     165=head3 CHECKBOX 
     166 
     167=over 4 
     168 
     169=item rawvalue 
     170 
     171The real value of the attribute must be show 
    94172 
    95173=back 
     
    97175=cut 
    98176 
    99 sub form_type { $_[0]->ro ? 'LABEL' : ($_[0]->{formtype} || 'TEXT') } 
     177sub real_form_type { $_[0]->{formtype} || 'TEXT' } 
     178 
     179sub form_type { 
     180    $_[0]->readonly ? 'LABEL' : 
     181    $_[0]->{formtype} ? $_[0]->{formtype} : 
     182    $_[0]->has_values_list ? 'LIST' : 
     183    $_[0]->real_form_type 
     184} 
     185 
     186sub form_option { 
     187    my ($self, $option) = @_; 
     188    return $self->{formopts}{$option} 
     189} 
    100190 
    101191sub uniq { $_[0]->{uniq} || 0 } 
     
    103193sub multiple { $_[0]->{multiple} || 0 } 
    104194 
     195sub hidden { $_[0]->{hide} || 0 } 
     196 
     197sub delayed { $_[0]->{delayed} || 0 } 
     198 
    1051991; 
  • LATMOS-Accounts/lib/LATMOS/Accounts/Bases/Dummy/User.pm

    r679 r861  
    77our $VERSION = (q$Rev$ =~ /^Rev: (\d+) /)[0]; 
    88 
    9 my %fields_map = ( 
    10     username => 'username', 
    11     homeDirectory => 'home', 
    12 ); 
     9sub _get_attr_schema { 
     10    { 
     11        username => {}, 
     12        homeDirectory => { iname => 'home' }, 
     13    } 
     14} 
     15 
     16sub list { 
     17    return (); 
     18} 
    1319 
    1420sub new { 
     
    2228} 
    2329 
    24 sub _canonical_fields { 
    25     my ($self) = @_; 
    26     return keys %fields_map; 
    27 } 
    28  
    29 sub _get_field_name { 
    30     my ($self, $field) = @_; 
    31     return $fields_map{$field}; 
    32 } 
    33  
    34301; 
  • LATMOS-Accounts/lib/LATMOS/Accounts/Bases/Ldap/Group.pm

    r766 r861  
    4242sub _my_ldap_classes { qw(top posixGroup) } 
    4343 
    44 sub _delayed_fields { 
    45     my ($self)= @_; 
    46     return qw(memberUID); 
    47 } 
    48  
    49 sub _canonical_fields { 
    50     my ($self, $base, $mode) = @_; 
    51     ( 
    52         qw(gidNumber description memberUID), 
    53         ($mode !~ /w/ 
    54             ? qw(cn dn objectClass) 
    55             : () 
    56         ) 
    57     ) 
     44sub _get_attr_schema { 
     45    my ($class, $base) = @_; 
     46    $class->SUPER::_get_attr_schema($base, 
     47    { 
     48        gidNumber => { uniq => 1, }, 
     49        description => { }, 
     50        memberUID => { multiple => 1, delayed => 1, }, 
     51        cn => { ro => 1 }, 
     52        dn => { ro => 1 }, 
     53        objectClass => { ro => 1 }, 
     54    } 
     55    ); 
    5856} 
    5957 
     
    6967    $entry->replace(objectClass => [ $class->_my_ldap_classes ],); 
    7068    my %delayed; 
     69    $data{cn} = $id; 
    7170    foreach (keys %data) { 
    7271        /^(memberUID)$/ and do { 
  • LATMOS-Accounts/lib/LATMOS/Accounts/Bases/Ldap/Onlyaddress.pm

    r678 r861  
    4747) } 
    4848 
    49 sub _delayed_fields { 
    50     my ($self)= @_; 
    51     return qw(); 
    52 } 
    53  
    54 sub _canonical_fields { 
    55     my ($self, $base, $mode) = @_; 
    56     ( 
    57         qw(displayName givenName 
    58         initials mail sn 
    59         mobile o uid facsimileTelephoneNumber), # inetOrgPerson 
    60         qw(street postOfficeBox postalCode postalAddress streetAddress 
    61         physicalDeliveryOfficeName ou st l telephoneNumber), # organizationalPerson 
    62         ($mode 
    63             !~ /w/ 
    64               ? qw(cn dn objectClass) 
    65               : () 
    66         ) 
    67     ) 
     49sub _get_attr_schema { 
     50    my ($class, $base) = @_; 
     51    { 
     52        # inetOrgPerson 
     53        displayName => {}, 
     54        givenName => {}, 
     55        initials => {}, 
     56        mail => {}, 
     57        sn => {}, 
     58        mobile => {}, 
     59        o => {}, 
     60        uid => {}, 
     61        facsimileTelephoneNumber => {}, 
     62        # organizationalPerson 
     63        street => {}, 
     64        postOfficeBox => {}, 
     65        postalCode => {}, 
     66        postalAddress => {}, 
     67        streetAddress => {}, 
     68        physicalDeliveryOfficeName => {}, 
     69        ou => {}, 
     70        st => {}, 
     71        l => {}, 
     72        telephoneNumber => {}, 
     73        cn => { ro => 1 }, 
     74        dn => { ro => 1 }, 
     75        objectClass => { ro => 1 }, 
     76    } 
    6877} 
    6978 
     
    8089        [ $class->_my_ldap_classes ],); 
    8190    $data{sn} ||= $id; # sn is mandatory 
     91    $data{cn} = $id; 
    8292    foreach (keys %data) { 
    8393        $class->_populate_entry($entry, 
  • LATMOS-Accounts/lib/LATMOS/Accounts/Bases/Ldap/User.pm

    r767 r861  
    4949) } 
    5050 
    51 sub _delayed_fields { 
    52     my ($self)= @_; 
    53     return qw(memberOf manager); 
    54 } 
    55  
    56 sub _canonical_fields { 
    57     my ($self, $base, $mode) = @_; 
    58     ( 
    59         qw(displayName givenName homePhone homePostalAddress 
    60         initials mail sn 
    61         mobile o uid manager facsimileTelephoneNumber), # inetOrgPerson 
    62         qw(uidNumber gidNumber homeDirectory 
    63         userPassword loginShell 
    64         gecos description), # posixAccount 
    65         qw(shadowLastChange 
    66         shadowMin shadowMax 
    67         shadowWarning 
    68         shadowInactive 
    69         shadowExpire 
    70         shadowFlag), # shadowAccount 
    71         qw(street postOfficeBox postalCode postalAddress streetAddress 
    72         physicalDeliveryOfficeName ou st l telephoneNumber), # organizationalPerson 
    73         ('memberOf'), 
    74         ($mode 
    75             !~ /w/ 
    76               ? qw(cn dn objectClass) 
    77               : () 
    78         ) 
    79     ) 
     51sub _get_attr_schema { 
     52    my ($class, $base) = @_; 
     53    $class->SUPER::_get_attr_schema($base, 
     54    { 
     55        displayName => { }, 
     56        givenName => { }, 
     57        homePhone => { }, 
     58        homePostalAddress => { }, 
     59        initials => { }, 
     60        mail => { }, 
     61        sn => { }, 
     62        mobile => { }, 
     63        o => { }, 
     64        uid => { }, 
     65        manager => { 
     66            delayed => 1, 
     67            can_values => sub { $base->list_objects('user') }, 
     68        }, 
     69        facsimileTelephoneNumber => { }, 
     70        uidNumber => { uniq => 1, }, 
     71        gidNumber => { 
     72            reference => 'group', 
     73            mandatory => 1, 
     74            can_values => sub { 
     75                map { $base->get_object('group', 
     76                        $_)->get_attributes('gidNumber') } 
     77                $base->list_objects('group') 
     78            }, 
     79            display => sub { 
     80                my ($self, $val) = @_; 
     81                my ($gr) = $self->base->search_objects('group', "gidNumber=$val") 
     82                    or return; 
     83                return $gr; 
     84            }, 
     85 
     86        }, 
     87        homeDirectory => { }, 
     88        userPassword => { }, 
     89        loginShell => { }, 
     90        gecos => { }, 
     91        description => { }, 
     92        shadowLastChange => { }, 
     93        shadowMin => { }, 
     94        shadowMax => { }, 
     95        shadowWarning => { }, 
     96        shadowInactive => { }, 
     97        shadowExpire => { }, 
     98        shadowFlag => { }, 
     99        street => { }, 
     100        postOfficeBox => { }, 
     101        postalCode => { }, 
     102        postalAddress => { }, 
     103        streetAddress => { }, 
     104        physicalDeliveryOfficeName => { }, 
     105        ou => { }, 
     106        st => { }, 
     107        l => { }, 
     108        telephoneNumber => { }, 
     109        memberOf => { delayed => 1, }, 
     110 
     111        cn => { ro => 1, }, 
     112        dn => { ro => 1, }, 
     113        objectClass => { ro => 1, }, 
     114        pwdAccountLockedTime => {}, 
     115        pwdPolicySubentry => {}, 
     116        pwdChangedTime => { ro => 1 }, 
     117        labeledURI => {}, 
     118    } 
     119    ); 
    80120} 
    81121 
     
    91131    $entry->replace(objectClass => 
    92132        [ $class->_my_ldap_classes ],); 
     133    $data{cn} = $id; 
    93134    $data{sn} ||= $id; # sn is mandatory 
    94135    $data{homeDirectory} ||= '/dev/null'; # homeDirectory is mandatory 
     
    153194    $field eq 'manager' and do { 
    154195        my $dn = $self->SUPER::get_field($field) or return; 
    155         return $self->base->_get_object_from_dn($dn)->get_value('cn'); 
     196        my $manager = $self->base->_get_object_from_dn($dn) or return; 
     197        return $manager->get_value('cn'); 
    156198    }; 
    157199    $self->SUPER::get_field($field); 
     
    195237        }; 
    196238        /^manager$/ && $val and do { 
    197             my $user = $base->get_object('user', $val) or 
    198             next; 
     239            my $user = $base->get_object('user', $val) or do { 
     240                $val = undef; 
     241                next; 
     242            }; 
    199243            $val = $user->get_field('dn'); 
    200244            next; 
  • LATMOS-Accounts/lib/LATMOS/Accounts/Bases/Ldap/objects.pm

    r715 r861  
    3535 
    3636=cut 
     37 
     38sub _get_attr_schema { 
     39    my ($class, $base, $info) = @_; 
     40    $info ||= {}; 
     41 
     42    foreach (qw( 
     43            createTimestamp 
     44            creatorsName 
     45            entryUUID 
     46            modifiersName 
     47            modifyTimestamp 
     48            entryCSN 
     49            )) { 
     50        $info->{$_} = { ro => 1 }; 
     51    } 
     52 
     53    return $info; 
     54}     
    3755 
    3856sub list { 
     
    5977} 
    6078 
    61 sub _get_field_name { 
    62     my ($self, $field, $base, $for) = @_; 
    63  
    64     my %fields = map { $_ => 1 } $self->_canonical_fields($base, $for); 
    65  
    66     return $fields{$field} ? $field : undef; 
    67 } 
    68  
    6979sub new { 
    7080    my ($class, $base, $uid) = @_; 
     
    7888        ), 
    7989        base => $base->object_base_dn($class->type), 
     90        attrs => [ $class->_canonical_fields($base, 'r') ], 
    8091    ); 
    8192 
     
    135146sub _populate_entry { 
    136147    my ($self, $entry, $field, $value, $base) = @_; 
    137     my $val = $entry->get_value($field); 
     148    my $val = ref $self ? $self->get_field($field) : undef; 
    138149    my $tr =  join(', ', map { $_ || '' } ($field, $val, $value)); 
    139150    if ($value) { 
     
    159170    } 
    160171    foreach (keys %fields) { 
    161         $self->get_field_name($_, 'w') or next; 
     172        my $attr = $self->attribute($_) or do { 
     173            $self->base->log(LA_ERR, "Unknow attribute %s (%s)", 
     174                $_, $self->type); 
     175            return; 
     176        }; 
     177        $attr->ro and next; 
    162178        $self->_populate_entry($self->{entry}, $_, $fields{$_}); 
    163179    } 
  • LATMOS-Accounts/lib/LATMOS/Accounts/Bases/Mail.pm

    r817 r861  
    1515 
    1616    my $base = { 
    17         file => { 
    18             aliases => $options{aliases} || '/etc/aliases', 
    19             revaliases => $options{revaliases} || '/etc/revaliases', 
    20         }, 
     17        file => {}, 
    2118        aliases => {}, 
    2219        revaliases => {}, 
    2320    }; 
     21 
     22    foreach (qw(aliases revaliases)) { 
     23        if ($options{$_}) { 
     24            $base->{file}{$_} = $options{$_}; 
     25        } elsif ($options{directory}) { 
     26            $base->{file}{$_} = $options{directory} . '/' . $_; 
     27        } else { 
     28            $base->{file}{$_} = "/etc/$_"; 
     29        } 
     30    } 
     31 
    2432 
    2533    bless($base, $class); 
  • LATMOS-Accounts/lib/LATMOS/Accounts/Bases/Mail/Aliases.pm

    r812 r861  
    1616} 
    1717 
    18 sub _canonical_fields { 
    19     my ($self, $for) = @_; 
    20     return (qw(forward)); 
    21 } 
    22  
    23 sub _get_field_name { 
    24     my ($self, $c_field, $base, $for) = @_; 
    25     for ($c_field) { 
    26         /^forward$/ and last; 
    27         return; 
     18sub _get_attr_schema { 
     19    my ($class, $base) = @_; 
     20    { 
     21        forward => {}, 
    2822    } 
    29     return $c_field; 
    3023} 
    3124 
  • LATMOS-Accounts/lib/LATMOS/Accounts/Bases/Mail/Revaliases.pm

    r351 r861  
    1616} 
    1717 
    18 sub _canonical_fields { 
    19     my ($self, $for) = @_; 
    20     return (qw(as)); 
    21 } 
    22  
    23 sub _get_field_name { 
    24     my ($self, $c_field, $base, $for) = @_; 
    25     for ($c_field) { 
    26         /^as$/ and last; 
    27         return; 
     18sub _get_attr_schema { 
     19    my ($class, $base) = @_; 
     20    { 
     21        as => {}, 
    2822    } 
    29     return $c_field; 
    3023} 
    3124 
  • LATMOS-Accounts/lib/LATMOS/Accounts/Bases/Mail/objects.pm

    r305 r861  
    99our $VERSION = (q$Rev: 641 $ =~ /^Rev: (\d+) /)[0]; 
    1010 
    11 #sub list_canonical_fields { 
    12 #    my ($self, $for) = @_; 
    13 #} 
  • LATMOS-Accounts/lib/LATMOS/Accounts/Bases/Objects.pm

    r852 r861  
    126126sub list_canonical_fields { 
    127127    my ($self, $for) = @_; 
    128     $self->base->list_canonical_fields($self->type, $for); 
     128    $for ||= 'rw'; 
     129    $self->_canonical_fields($for); 
    129130} 
    130131 
     
    137138}    
    138139 
    139 =head2 get_field_name($field, $for) 
    140  
    141 Object shortcut to get the field name supported by the object. 
    142  
    143 =cut 
    144  
    145 sub get_field_name { 
    146     my ($self, $field, $for) = @_; 
    147     $self->base->get_field_name($self->type, $field, $for); 
    148 } 
    149  
    150 =head2 _canonical_fields 
    151  
    152 Must return the list of field supported by the object. 
    153  
    154 Notice this query will always come from the upstream data base, 
    155 this function is just a facility to store data in the module, but the 
    156 underling database can reply themself. 
    157  
    158 Is call if underling base doesn't override list_canonical_fields() 
    159  
    160 See list_canonical_fields(). 
    161  
    162     sub _canonical_fields {  
    163         my ($self) = @_; 
    164     } 
    165  
    166 =cut 
    167  
    168 sub _delayed_fields { 
    169     my ($self)= @_; 
    170     return (); 
    171 } 
    172  
    173 =head2 _get_fields_name($field, $for) 
    174  
    175 Return the fields name for canonical field $field. 
    176 $for, if set, is a string containing 'r' for read, 'w' for write, 
    177 depending usage context. 
    178  
    179     sub _get_field_name { 
    180         my ($self, $field, $for) = @_; 
    181     } 
    182  
    183 =cut 
     140sub _canonical_fields { 
     141    my ($class, $base, $for) = @_; 
     142    $for ||= 'rw'; 
     143    my $info = $base->_get_attr_schema($class->type); 
     144    my @attrs = map { $base->attribute($class->type, $_) } keys %{$info || {}}; 
     145    @attrs = grep { ! $_->ro } @attrs if($for =~ /w/); 
     146    map { $_->name } grep { !$_->hidden }  @attrs; 
     147} 
    184148 
    185149=head2 get_field($field) 
     
    197161Return the value for canonical field $cfield. 
    198162 
    199 Call driver specific get_field_name() and get_field() 
     163Call driver specific get_field() 
    200164 
    201165=cut 
     
    231195} 
    232196 
     197sub get_state { 
     198    my ($self, $state) = @_; 
     199    # hum... 
     200    if (defined(my $res = $self->_get_state($state))) { 
     201        return $res; 
     202    } 
     203    for ($state) { 
     204    } 
     205    return; 
     206} 
     207 
     208sub _get_state { 
     209    my ($self, $state) = @_; 
     210    return; 
     211} 
     212 
    233213sub _get_c_field { 
    234214    my ($self, $cfield) = @_; 
    235215    my $return; 
    236     my $field = $self->base->get_field_name($self->type, $cfield, 'r') or do { 
     216    my $attribute = $self->attribute($cfield) or do { 
    237217        $self->base->log(LA_WARN, "Unknow attribute $cfield"); 
    238218        return; 
    239219    }; 
    240     $return = $self->get_field($field); 
     220    $return = $self->get_field($attribute->iname); 
    241221} 
    242222 
     
    307287    my %data; 
    308288    foreach my $cfield (keys %cdata) { 
    309         my $field = $self->base->get_field_name($self->type, $cfield, 'w') or do { 
     289        my $attribute = $self->attribute($cfield) or do { 
    310290            $self->base->log(LA_ERR, 
    311291                "Cannot set unsupported attribute %s to %s (%s)", 
     
    314294            return; 
    315295        }; 
    316         $data{$field} = $cdata{$cfield}; 
     296        $attribute->ro and do { 
     297            $self->base->log(LA_ERR, 
     298                "Cannot set read-only attribute %s to %s (%s)", 
     299                $cfield, $self->id, $self->type 
     300            ); 
     301            return; 
     302        }; 
     303        $attribute->mandatory && 
     304            (!(defined($cdata{$cfield})) || $cdata{$cfield} eq '') and do { 
     305            $self->base->log(LA_ERR, 
     306                "%s attribute cannot be empty, ignoring for object %s/%s", 
     307                $cfield, 
     308                $self->type, 
     309                $self->id, 
     310            ); 
     311            return 0; 
     312        }; 
     313        if (ref $cdata{$cfield}) { 
     314            $data{$attribute->iname} = []; # ensure hash entry exists 
     315            foreach (@{$cdata{$cfield}}) { 
     316                push(@{$data{$attribute->iname}}, defined($_) 
     317                    ? $attribute->input($_) 
     318                    : undef 
     319                ); 
     320            } 
     321        } else { 
     322            $data{$attribute->iname} = defined($cdata{$cfield}) 
     323                ? $attribute->input($cdata{$cfield}) 
     324                : undef; 
     325        } 
    317326    } 
    318327    keys %data or return 0; # TODO: return an error ? 
     
    346355sub _set_password { 
    347356    my ($self, $clear_pass) = @_; 
    348     if (my $field = $self->base->get_field_name($self->type, 'userPassword')) { 
     357    if (my $attribute = $self->base->attribute($self->type, 'userPassword')) { 
    349358        my @salt_char = (('a' .. 'z'), ('A' .. 'Z'), (0 .. 9), '/', '.'); 
    350359        my $salt = join('', map { $salt_char[rand(scalar(@salt_char))] } (1 .. 8)); 
    351         my $res = $self->set_fields($field, crypt($clear_pass, '$1$' . $salt)); 
    352         $self->base->log(LA_NOTICE, 'Mot de passe changé pour %s', $self->id); 
     360        my $res = $self->set_fields($attribute->iname, crypt($clear_pass, '$1$' . $salt)); 
     361        $self->base->log(LA_NOTICE, 'Mot de passe changé pour %s', $self->id) 
     362            if($res); 
    353363        return $res; 
    354364    } else { 
     
    390400        my $match = 1; 
    391401        foreach my $field (keys %parsed_filter) { 
    392             $base->get_field_name($class->type, $field, 'r') or die 
    393             "Unsupported attribute $field\n"; 
     402            $base->attribute($class->type, $field) or 
     403                la_log LA_WARN "Unsupported attribute $field"; 
    394404            my $tmatch = 0; 
    395405            foreach (@{$parsed_filter{$field}}) { 
     
    447457sub find_next_numeric_id { 
    448458    my ($class, $base, $field, $min, $max) = @_; 
    449     $base->get_field_name($class->type, $field) or return; 
     459    $base->attribute($class->type, $field) or return; 
    450460    $min ||=  
    451461        $field eq 'uidNumber' ? 500 : 
     
    492502    foreach my $attr (sort { $a cmp $b } $base->list_canonical_fields($otype, 
    493503        $options->{only_rw} ? 'rw' : 'r')) { 
    494         my $wok = $base->get_field_name($otype, $attr, 'w'); 
     504        my $oattr = $base->attribute($otype, $attr); 
    495505        if (ref $self) { 
    496506            my $val = $self->get_c_field($attr); 
    497507            if ($val || $options->{empty_attr}) { 
    498508                if (my @allowed = $base->obj_attr_allowed_values($otype, $attr)) { 
    499                     $dump .= sprintf("# %s must be empty or either: %s\n", 
     509                    $dump .= sprintf("# %s must be%s: %s\n", 
    500510                        $attr, 
     511                        ($oattr->mandatory ? '' : ' empty or either'), 
    501512                        join(', ', @allowed) 
    502513                    ); 
     
    507518                    s/\r?\n/\\n/g; 
    508519                    $dump .= sprintf("%s%s:%s\n",  
    509                         $wok ? '' : '# (ro) ', 
     520                        $oattr->ro ? '# (ro) ' : '', 
    510521                        $attr, $_ ? " $_" : ''); 
    511522                } 
     
    519530            } 
    520531            $dump .= sprintf("%s%s: %s\n",  
    521                 $wok ? '' : '# (ro) ', 
     532                $oattr->ro ? '# (ro) ' : '', 
    522533                $attr, ''); 
    523534        } 
  • LATMOS-Accounts/lib/LATMOS/Accounts/Bases/Sql.pm

    r850 r861  
    88use LATMOS::Accounts::Log; 
    99use DBI; 
     10use Crypt::RSA; 
     11use Crypt::RSA::Key::Public::SSH; 
     12use Crypt::RSA::Key::Private::SSH; 
     13use MIME::Base64; 
    1014 
    1115our $VERSION = (q$Rev$ =~ /^Rev: (\d+) /)[0]; 
     
    6468            undef, undef, 
    6569            { 
    66                 RaiseError => 1, 
     70                RaiseError => 0, 
    6771                AutoCommit => 0, 
    6872                PrintWarn => 1, 
     
    7074            } 
    7175        ) or do { 
    72             $self->log(LA_ERR, "Cannot connect to database");    
     76            $self->log(LA_ERR, "Cannot connect to database: %s", $DBI::errstr);    
    7377            return; 
    7478        }; 
     
    9296} 
    9397 
    94 sub commit { 
     98sub _commit { 
    9599    my ($self) = @_; 
    96100    if ($ENV{LA_NO_COMMIT}) { 
     
    104108} 
    105109 
    106 sub rollback { 
     110sub _rollback { 
    107111    my ($self) = @_; 
    108112    if ($ENV{LA_NO_COMMIT}) { 
     
    131135    return ($res->{max}); 
    132136}  
     137 
     138 
     139# Extra non standard functions 
    133140 
    134141sub get_global_value { 
     
    156163    }; 
    157164} 
     165 
     166sub generate_rsa_key { 
     167    my ($self, $password) = @_; 
     168 
     169    my $rsa = new Crypt::RSA ES => 'PKCS1v15'; 
     170    my ($public, $private) = $rsa->keygen ( 
     171        Identity  => 'LATMOS-Accounts', 
     172        Size      => 768, 
     173        Password  => $password, 
     174        Verbosity => 0, 
     175        KF=>'SSH', 
     176    ) or die $rsa->errstr(); # TODO avoid die 
     177    return ($public, $private); 
     178} 
     179 
     180sub private_key { 
     181    my ($self, $password) = @_; 
     182    my $base = $self; 
     183    my $serialize = $base->get_global_value('rsa_private_key') or return; 
     184    my $privkey = Crypt::RSA::Key::Private::SSH->new; 
     185    $privkey->deserialize(String => [ decode_base64($serialize) ], 
     186        Passphrase => $password); 
     187    $privkey 
     188} 
     189 
     190sub get_rsa_password { 
     191    my ($self) = @_; 
     192    my $base = $self; 
     193    my $sth = $base->db->prepare(q{ 
     194        select "name", value from "user" join user_attributes_base 
     195        on "user".ikey = user_attributes_base.okey 
     196        where user_attributes_base.attr = 'encryptedPassword' 
     197    }); 
     198    $sth->execute; 
     199    my %users; 
     200    while (my $res = $sth->fetchrow_hashref) { 
     201        $users{$res->{name}} = $res->{value}; 
     202    } 
     203    %users 
     204} 
     205 
     206sub store_rsa_key { 
     207    my ($self, $public, $private) = @_; 
     208    my $base = $self; 
     209    $base->set_global_value('rsa_private_key', 
     210        encode_base64($private->serialize)); 
     211    $base->set_global_value('rsa_public_key', 
     212        $public->serialize); 
     213    return; 
     214} 
     215 
    158216 
    159217sub find_next_expire_users { 
     
    196254} 
    197255 
     256sub rename_nethost { 
     257    my ($self, $nethostname, $to, %options) = @_; 
     258    { 
     259        my $obj = $self->get_object('nethost', $nethostname); 
     260        my @cname = grep { $_ && $_ ne $to} 
     261        $obj->get_attributes('cname'); 
     262        $obj->set_c_fields(cname => [ @cname ]) or return; 
     263    } 
     264    $self->rename_object('nethost', $nethostname, $to) or return; 
     265    if ($options{'addcname'}) { 
     266        my $obj = $self->get_object('nethost', $to); 
     267        my @cname = grep { $_ } $obj->get_attributes('cname'); 
     268        $obj->set_c_fields(cname => [ @cname, $nethostname ]); 
     269    } 
     270    return 1; 
     271} 
     272 
     273sub nethost_exchange_ip { 
     274    my ($self, $ip1, $ip2) = @_; 
     275    my ($obj1, $obj2); 
     276    if (my ($host1) = $self->search_objects('nethost', "ip=$ip1")) { 
     277        $obj1 = $self->get_object('nethost', $host1); 
     278    } else { 
     279        $self->la_log(LA_ERR, "Cannot find host having $ip1"); 
     280        return; 
     281    } 
     282    if (my ($host2) = $self->search_objects('nethost', "ip=$ip2")) { 
     283        $obj2 = $self->get_object('nethost', $host2); 
     284    } else { 
     285        $self->la_log(LA_ERR, "Cannot find host having $ip2"); 
     286        return; 
     287    } 
     288    if ($obj1->id eq $obj2->id) { 
     289        $self->la_log(LA_ERR, "Both ip belong to same host (%s)", $obj1->id); 
     290        return; 
     291    } 
     292 
     293    my @ip1 = grep { $_ && $_ ne $ip1 } $obj1->get_attributes('ip'); 
     294    $obj1->set_c_fields(ip => [ @ip1 ]); 
     295    my @ip2 = grep { $_ && $_ ne $ip2 } $obj2->get_attributes('ip'); 
     296    $obj2->set_c_fields(ip => [ @ip2, $ip1 ]) or return; 
     297    $obj1->set_c_fields(ip => [ @ip1, $ip2 ]) or return; 
     298    return 1; 
     299} 
     300 
     301sub register_attribute { 
     302    my ($self, $otype, $attribute, $comment) = @_; 
     303    my $pclass = $self->_load_obj_class($otype) or return; 
     304    $pclass->register_attribute($self, $attribute, $comment); 
     305} 
     306 
     307sub get_attribute_comment { 
     308    my ($self, $otype, $attribute) = @_; 
     309    my $pclass = $self->_load_obj_class($otype) or return; 
     310    $pclass->get_attribute_comment($self, $attribute); 
     311} 
     312 
     313sub set_attribute_comment { 
     314    my ($self, $otype, $attribute, $comment) = @_; 
     315    my $pclass = $self->_load_obj_class($otype) or return; 
     316    $pclass->set_attribute_comment($self, $attribute, $comment); 
     317} 
     318 
    1983191; 
    199320 
  • LATMOS-Accounts/lib/LATMOS/Accounts/Bases/Sql/Address.pm

    r809 r861  
    4343sub has_extended_attributes { 1 } 
    4444 
    45 sub _inline_fields { 
    46     my ($self, $for, $base) = @_; 
     45sub _get_attr_schema { 
     46    my ($class, $base) = @_; 
    4747 
    48     my %fields = ( 
    49         name            => 'name', 
    50         exported        => 'exported', 
    51         user            => 'user', 
     48    $class->SUPER::_get_attr_schema($base, 
     49        { 
     50            name =>         { inline => 1, }, 
     51            exported =>     { inline => 1, }, 
     52            user =>         { inline => 1, 
     53                reference => 'user', 
     54            }, 
     55            site =>         { 
     56                reference => 'site', 
     57            }, 
     58            sn =>           { ro => 1, }, 
     59            mail =>         { ro => 1, }, 
     60            givenName =>    { ro => 1, }, 
     61            postalAddress => { ro => 1, }, 
     62            displayName =>  { ro => 1, }, 
     63            co =>           { 
     64                ro => sub { $_[0] && $_[0]->get_attributes('site') ? 1 : 0 }, 
     65            }, 
     66            l =>            { 
     67                ro => sub { $_[0] && $_[0]->get_attributes('site') ? 1 : 0 }, 
     68            }, 
     69            postalCode =>   { 
     70                ro => sub { $_[0] && $_[0]->get_attributes('site') ? 1 : 0 }, 
     71            }, 
     72            streetAddress => { 
     73                formtype => 'TEXTAREA', 
     74                ro => sub { $_[0] && $_[0]->get_attributes('site') ? 1 : 0 }, 
     75            }, 
     76            postOfficeBox => { 
     77                ro => sub { $_[0] && $_[0]->get_attributes('site') ? 1 : 0 }, 
     78            }, 
     79            st =>           { 
     80                ro => sub { $_[0] && $_[0]->get_attributes('site') ? 1 : 0 }, 
     81            }, 
     82            facsimileTelephoneNumber => { 
     83                ro => sub { $_[0] && $_[0]->get_attributes('site') ? 1 : 0 }, 
     84            }, 
     85            o =>            { 
     86                ro => sub { $_[0] && $_[0]->get_attributes('site') ? 1 : 0 }, 
     87            }, 
     88            isMainAddress => { formtype => 'CHECKBOX', }, 
     89        } 
    5290    ); 
    53     %fields 
    54 } 
    55  
    56 sub _managed_fields { 
    57     my ($self, $for, $base) = @_; 
    58     (site => 'site'), 
    59     $for !~ /w/ ? ( 
    60         sn => 'sn', 
    61         mail =>  'mail', 
    62         givenName => 'givenName', 
    63         postalAddress => 'postalAddress', 
    64         displayName => 'displayName', 
    65     ) : () 
    66 } 
    67  
    68 sub _delayed_fields { 
    69     my ($self)= @_; 
    70     return qw(); 
    7191} 
    7292 
     
    7595    $data{user} or return; 
    7696    my $user = $base->get_object('user', $data{user}); 
     97    $user or return; 
    7798    if (!$user->get_c_field('otheraddress')) { 
    7899        $data{isMainAddress} = 1; 
     
    83104sub get_field { 
    84105    my ($self, $field) = @_; 
    85     if ((grep { $field eq $_ } __PACKAGE__->_address_fields()) 
    86         && (my $fsite = $self->get_c_field('site'))) { 
     106    if ((grep { $field eq $_ } (qw( 
     107            co l 
     108            postalCode streetAddress 
     109            postOfficeBox st 
     110            facsimileTelephoneNumber o 
     111            ))) && (my $fsite = $self->get_c_field('site'))) { 
    87112        my $site = $self->base->get_object('site', $fsite); 
    88113        if ($site) { 
     
    90115        } 
    91116    } elsif ($field =~ /^(sn|givenName|mail)$/) { 
    92         my $user = $self->base->get_object('user', $self->_get_c_field('user')); 
     117        my $user = $self->base->get_object('user', $self->_get_c_field('user')) 
     118            or return; 
    93119        return $user->_get_c_field($field); 
    94120    } elsif ($field eq 'postalAddress' ) { 
     
    125151                $data{$attr}); 
    126152            if ($site) { 
    127                 foreach (__PACKAGE__->_address_fields()) { 
     153                foreach (qw(co l postalCode streetAddress postOfficeBox st 
     154                        facsimileTelephoneNumber o)) { 
    128155                    $fdata{$_} = undef; 
    129156                    $data{$_} = undef; 
  • LATMOS-Accounts/lib/LATMOS/Accounts/Bases/Sql/Aliases.pm

    r499 r861  
    4242sub key_field { 'name' } 
    4343 
    44 sub has_extended_attributes { 0 } 
     44sub has_extended_attributes { 1 } 
    4545 
    46 sub _managed_fields { 
    47     my ($class, $for, $base) = @_; 
    48     return( 
    49         $for !~ /w/ 
    50         ? ( 
    51             finalpoint => 'finalpoint', 
    52             parents => 'parents', 
    53             anyparents => 'anyparents', 
    54             sameforward => 'sameforward', 
    55             samedestination => 'samedestination', 
    56         ) 
    57         : () 
    58     ); 
     46sub _get_attr_schema { 
     47    my ($class, $base) = @_; 
     48 
     49    $class->SUPER::_get_attr_schema($base, 
     50        { 
     51            name            => { 
     52                ro => 1, 
     53            }, 
     54            forward         => { 
     55                mandatory => 1, 
     56                multiple => 1, 
     57            }, 
     58            finalpoint      => { ro => 1, }, 
     59            parents         => { ro => 1, }, 
     60            anyparents      => { ro => 1, }, 
     61            sameforward     => { ro => 1, }, 
     62            samedestination => { ro => 1, }, 
     63            user            => { 
     64                ro => 1, 
     65                reference => 'user', 
     66            }, 
     67        } 
     68    ) 
    5969} 
    6070 
  • LATMOS-Accounts/lib/LATMOS/Accounts/Bases/Sql/Group.pm

    r768 r861  
    4444sub has_extended_attributes { 1 } 
    4545 
    46 sub _inline_fields { 
    47     my ($self, $for, $base) = @_; 
    48     return ( 
    49         gidNumber       => 'gidnumber', 
    50         exported        => 'exported', 
    51         ($for !~ /w/) ? ( 
    52             name => 'name', 
    53             cn => 'name', 
    54             create => 'create', 
    55             date => 'date', 
    56         ) : (), 
    57     ); 
    58 } 
     46sub _get_attr_schema { 
     47    my ($class, $base) = @_; 
    5948 
    60 sub _managed_fields { 
    61     my ($self, $for, $base) = @_; 
    62  
    63     my %fields = ( 
    64         memberUID       => 'memberUID', 
    65         member          => 'member', 
    66         $for !~ /w/ ? ( 
    67             sAMAccountName  => 'name', 
    68             groupname => 'name', 
    69         ) : (), 
    70     ); 
    71     %fields; 
    72 } 
    73  
    74 sub _delayed_fields { 
    75     my ($self)= @_; 
    76     return qw(memberUID member); 
     49    $class->SUPER::_get_attr_schema($base, 
     50        { 
     51            gidNumber  => { inline => 1, uniq => 1, iname => 'gidnumber', 
     52                mandatory => 1, }, 
     53            gidnumber  => { inline => 1, uniq => 1, hide => 1, }, 
     54            exported   => { inline => 1, }, 
     55            name       => { inline => 1, ro => 1 }, 
     56            cn         => { inline => 1, ro => 1, iname => 'name', }, 
     57            create     => { inline => 1, ro => 1 }, 
     58            date       => { inline => 1, ro => 1 }, 
     59            memberUID  => { 
     60                reference => 'user', 
     61                multiple => 1, 
     62                delayed => 1, 
     63                ro => sub { 
     64                    $_[0] &&  
     65                    ($_[0]->_get_c_field('sutype') ||'') =~ /^(jobtype|contrattype)$/ 
     66                    ? 1 : 0  
     67                }, 
     68            }, 
     69            member     => { 
     70                reference => 'user', 
     71                multiple => 1,  
     72                delayed => 1, 
     73                can_values => sub { $base->list_objects('user') }, 
     74                ro => sub { 
     75                    $_[0] &&  
     76                    ($_[0]->_get_c_field('sutype') ||'') =~ /^(jobtype|contrattype)$/ 
     77                    ? 1 : 0  
     78                }, 
     79            }, 
     80            sAMAccountName => { iname => 'name', ro => 1 }, 
     81            groupname  => { ro => 1 }, 
     82            managedBy  => { 
     83                reference => 'user', 
     84                can_values => sub { 
     85                    my %uniq = map { $_ => 1 } grep { $_ } 
     86                    ($_[1] ? $_[1]->get_attributes('manager') : ()), 
     87                    $base->search_objects('user', 'active=*'); 
     88                    sort keys %uniq; 
     89                }, 
     90            }, 
     91            sutype => { 
     92                reference => 'sutype', 
     93            }, 
     94        } 
     95    ) 
    7796} 
    7897 
     
    130149                    $res++; 
    131150                } elsif ($member{$_}{c}) { 
     151                    if (($user->get_c_field('department') || '') eq $self->id) { 
     152                        $self->base->log(LA_WARN, 
     153                            "Don't removing user %s from group %s: is it's department", 
     154                            $user->id, $self->id); 
     155                        next; 
     156                    } 
    132157                    my $sth = $self->db->prepare_cached( 
    133158                        q{delete from group_attributes_users where value = ? and attr = ? and okey = ?} 
     
    142167    } 
    143168    if (keys %fdata) { 
    144         return $res + $self->SUPER::set_fields(%fdata); 
     169            my $setres = $self->SUPER::set_fields(%fdata); 
     170            if (defined($setres)) { return $res + $setres; } 
     171            else { return; }  
    145172    } else { 
    146173        $res 
  • LATMOS-Accounts/lib/LATMOS/Accounts/Bases/Sql/Revaliases.pm

    r353 r861  
    4444sub has_extended_attributes { 0 } 
    4545 
     46sub _get_attr_schema { 
     47    my ($class, $base) = @_; 
     48 
     49    $class->SUPER::_get_attr_schema($base, 
     50        { 
     51            name            => { reference => 'user', inline => 1, }, 
     52        } 
     53    ) 
     54} 
     55 
    4656sub _create { 
    4757    my ($class, $base, $id, %data) = @_; 
  • LATMOS-Accounts/lib/LATMOS/Accounts/Bases/Sql/Site.pm

    r769 r861  
    4343sub has_extended_attributes { 1 } 
    4444 
    45 sub _inline_fields { 
    46     my ($class, $for, $base) = @_; 
    47     return ( 
    48         expire    => 'expire', 
    49         ($for !~ /w/) ? ( 
    50             name      => 'name', 
    51             cn => 'name', 
    52             create    => 'create', 
    53             date      => 'date', 
    54         ) : (), 
    55     ); 
    56 } 
     45sub _get_attr_schema { 
     46    my ($class, $base) = @_; 
    5747 
    58 sub _managed_fields { 
    59     my ($self, $for, $base) = @_; 
    60     $for !~ /w/ ? ( 
    61         postalAddress => 'postalAddress', 
    62     ) : () 
    63 } 
    64  
    65  
    66 sub _delayed_fields { 
    67     my ($self)= @_; 
    68     return qw(); 
     48    $class->SUPER::_get_attr_schema($base, 
     49        { 
     50            name   => { ro => 1, inline => 1, }, 
     51            cn     => { ro => 1, inline => 1, iname => 'name' }, 
     52            date   => { ro => 1, inline => 1, }, 
     53            create => { ro => 1, inline => 1, }, 
     54            streetAddress => { formtype => 'TEXTAREA' }, 
     55            postalAddress => { ro => 1, }, 
     56            siteNick => { uniq => 1 }, 
     57        } 
     58    ) 
    6959} 
    7060 
  • LATMOS-Accounts/lib/LATMOS/Accounts/Bases/Sql/Sutype.pm

    r165 r861  
    4343sub has_extended_attributes { 0 } 
    4444 
    45 sub _delayed_fields { 
    46     my ($self)= @_; 
    47     return qw(); 
    48 } 
    49  
    50451; 
    5146 
  • LATMOS-Accounts/lib/LATMOS/Accounts/Bases/Sql/User.pm

    r840 r861  
    4545sub has_extended_attributes { 1 } 
    4646 
    47 sub _delayed_fields { 
    48     my ($self)= @_; 
    49     return qw(memberOf manager directReports department); 
    50 } 
    51  
    52 sub _office_address_fields { qw(telephoneNumber physicalDeliveryOfficeName site) } 
    53  
    54 sub _inline_fields { 
    55     my ($class, $for, $base) = @_; 
    56     return ( 
    57         uidNumber => 'uidnumber', 
    58         gidNumber => 'gidnumber', 
    59         exported  => 'exported', 
    60         expire    => 'expire', 
    61         ($for !~ /w/) ? ( 
    62             name      => 'name', 
    63             cn => 'name', 
    64             create    => 'create', 
    65             date      => 'date', 
    66         ) : (), 
    67     ); 
    68 } 
    69  
    70 sub _managed_fields { 
    71     my ($self, $for, $base) = @_; 
    72     return ( 
    73         memberOf        => 'memberOf', 
    74         forward => 'forward', 
    75         aliases => 'aliases', 
    76         revaliases => 'revaliases', 
    77         (map { $_ => $_ } $self->_address_fields), 
    78         (map { $_ => $_ } $self->_office_address_fields), 
    79         (($for !~ /w/) ? ( 
    80         uid => 'name', 
    81         cn => 'name', 
    82         gecos        => 'gecos', 
    83         displayName  => 'displayName', 
    84         sAMAccountName  => 'sAMAccountName', 
    85         accountExpires => 'accountExpires', 
    86         shadowExpire => 'shadowExpire', 
    87         directReports => 'directReports', 
    88         managedObjects => 'managedObjects', 
    89         otheraddress => 'otheraddress', 
    90         mainaddress => 'mainaddress', 
    91         postalAddress => 'postalAddress', 
    92         facsimileTelephoneNumber => 'facsimileTelephoneNumber', 
    93         allsite   => 'allsite', 
    94         managerContact => 'managerContact', 
    95         expireText => 'expireText', 
    96         cells  => 'cells', 
    97         departments => 'departments', 
    98         ) : ()), 
     47sub _get_attr_schema { 
     48    my ($class, $base) = @_; 
     49 
     50    $class->SUPER::_get_attr_schema($base, 
     51        { 
     52            uidNumber => { inline => 1, iname => 'uidnumber', uniq => 1, 
     53                mandatory => 1, }, 
     54            uidnumber => { inline => 1, hide => 1, }, 
     55            gidNumber => {  
     56                inline => 1, 
     57                iname => 'gidnumber', 
     58                mandatory => 1, 
     59                can_values => sub { 
     60                    map { $base->get_object('group', 
     61                            $_)->get_attributes('gidNumber') } 
     62                    $base->list_objects('group') 
     63                }, 
     64                display => sub { 
     65                    my ($self, $val) = @_; 
     66                    my ($gr) = $self->base->search_objects('group', "gidNumber=$val") 
     67                        or return; 
     68                    return $gr; 
     69                }, 
     70                reference => 'group', 
     71            }, 
     72            loginShell => { mandatory => 1 }, 
     73            gidnumber => { inline => 1, hide => 1, 
     74                can_values => sub { 
     75                    map { $_->get_attributes('gidNumber') } 
     76                    map { $base->get_object('group', $_) } 
     77                    $base->list_objects('group') 
     78                }, 
     79                mandatory => 1, 
     80                reference => 'group', 
     81            }, 
     82            exported  => { 
     83                inline => 1, 
     84                formtype => 'CHECKBOX', 
     85            }, 
     86            locked    => { 
     87                formtype => 'CHECKBOX', 
     88                formopts => { rawvalue => 1, }, 
     89            }, 
     90            expire    => { inline => 1, formtype => 'DATE', }, 
     91            name      => { inline => 1, ro => 1, }, 
     92            cn        => { inline => 1, ro => 1, iname => 'name' }, 
     93            create    => { inline => 1, ro => 1, }, 
     94            date      => { inline => 1, ro => 1, }, 
     95            memberOf  => { multiple => 1, delayed => 1, }, 
     96            forward   => {}, 
     97            aliases   => { 
     98                reference => 'aliases', 
     99                formtype => 'TEXT', 
     100                multiple => 1, 
     101            }, 
     102            revaliases => { 
     103                reference => 'revaliases', 
     104                formtype => 'TEXT', 
     105            }, 
     106            manager => { 
     107                delayed => 1, 
     108                can_values => sub { 
     109                    my %uniq = map { $_ => 1 } grep { $_ } 
     110                    ($_[1] ? $_[1]->get_attributes('manager') : ()), 
     111                    $base->search_objects('user', 'active=*'); 
     112                    sort keys %uniq; 
     113                }, 
     114                reference => 'user', 
     115            }, 
     116            department => { 
     117                reference => 'group', 
     118                can_values => sub { 
     119                    $base->search_objects('group', 'sutype=dpmt') 
     120                } 
     121            }, 
     122            contratType => { 
     123                reference => 'group', 
     124                can_values => sub { 
     125                    $base->search_objects('group', 'sutype=contrattype') 
     126                } 
     127            }, 
     128            site => { 
     129                reference => 'site', 
     130                can_values => sub { 
     131                    $base->search_objects('site') 
     132                } 
     133            }, 
     134            co => { }, 
     135            l => { }, 
     136            postalCode => { }, 
     137            streetAddress => { formtype => 'TEXTAREA', }, 
     138            postOfficeBox => { }, 
     139            st => { }, 
     140            facsimileTelephoneNumber => { }, 
     141            o => { }, 
     142            telephoneNumber => { }, 
     143            physicalDeliveryOfficeName => { }, 
     144            uid => { iname => 'name', ro => 1 }, 
     145            cn =>  { iname => 'name', ro => 1 }, 
     146            gecos => { ro => 1, }, 
     147            displayName  => { ro => 1, managed => 1, }, 
     148            sAMAccountName  => { ro => 1, managed => 1  }, 
     149            accountExpires => { ro => 1, managed => 1 }, 
     150            shadowExpire => { ro => 1, managed => 1 }, 
     151            directReports => { 
     152                reference => 'user', 
     153                ro => 1, 
     154                delayed => 1, 
     155            }, 
     156            managedObjects => { ro => 1, reference => 'group', }, 
     157            otheraddress => { ro => 1, reference => 'address', }, 
     158            mainaddress => { ro => 1, reference => 'address', }, 
     159            postalAddress => { ro => 1, }, 
     160            facsimileTelephoneNumber => { ro => 1, }, 
     161            allsite   => { 
     162                ro => 1, 
     163                reference => 'site', 
     164            }, 
     165            managerContact => { 
     166                ro => 1, 
     167                reference => 'user', 
     168            }, 
     169            expireText => { ro => 1, }, 
     170            krb5ValidEnd => { ro => 1, }, 
     171            cells  => { 
     172                ro => 1, 
     173                reference => 'group', 
     174            }, 
     175            departments => { 
     176                reference => 'group', 
     177                delayed => 1, 
     178                ro => 1, 
     179            }, 
     180            arrivalDate => { }, 
     181            expired => { ro => 1 }, 
     182            active => { ro => 1 }, 
     183                pwdAccountLockedTime => { managed => 1, ro => 1 } 
     184        } 
    99185    ) 
    100186} 
     
    177263        $res->{expire} =~ /(\d+) days\s*(\w)?/; 
    178264        return $1 + ($2 ? 1 : 0); 
     265    } elsif ($field eq 'krb5ValidEnd') { 
     266        my $sth = $self->db->prepare_cached( 
     267            sprintf( 
     268                q{select date_part('epoch', expire)::int as expire 
     269                from %s where %s = ?}, 
     270                $self->db->quote_identifier($self->object_table), 
     271                $self->db->quote_identifier($self->key_field), 
     272            ) 
     273        ); 
     274        $sth->execute($self->id); 
     275        my $res = $sth->fetchrow_hashref; 
     276        $sth->finish; 
     277        return $res->{expire} 
    179278    } elsif ($field eq 'expireText') { 
    180279        my $sth = $self->db->prepare_cached( 
     
    190289        $sth->finish; 
    191290        return $res->{expire} 
     291    } elsif ($field eq 'pwdAccountLockedTime') { 
     292        if ($self->_get_c_field('locked')) { 
     293            return '000001010000Z'; 
     294        } else { 
     295            my $sth = $self->db->prepare_cached( 
     296                sprintf( 
     297                    q{select to_char(expire AT TIME ZONE 'Z', 'YYYYMMDDHH24MISSZ') as expire 
     298                    from %s where %s = ? and expire < now()}, 
     299                    $self->db->quote_identifier($self->object_table), 
     300                    $self->db->quote_identifier($self->key_field), 
     301                ) 
     302            ); 
     303            $sth->execute($self->id); 
     304            my $res = $sth->fetchrow_hashref; 
     305            $sth->finish; 
     306            return $res->{expire} 
     307        } 
    192308    } elsif ($field eq 'otheraddress') { 
    193309        my $sth = $self->db->prepare_cached(q{ 
     
    209325        $sth->finish; 
    210326        return $res->{name}; 
    211     } elsif (grep { $field eq $_ } __PACKAGE__->_address_fields(), 
    212         $self->_office_address_fields, 'postalAddress') { 
     327    } elsif (grep { $field eq $_ } qw(postalAddress 
     328            co l postalCode streetAddress  
     329            postOfficeBox st  
     330            facsimileTelephoneNumber  
     331            o telephoneNumber  
     332            physicalDeliveryOfficeName  
     333            site 
     334        )) { 
    213335        if (my $fmainaddress = $self->_get_c_field('mainaddress')) { 
    214336            my $address = $self->base->get_object('address', $fmainaddress); 
     
    262384} 
    263385 
     386sub _get_state { 
     387    my ($self, $state) = @_; 
     388    for ($state) { 
     389        /^expired$/ and do { 
     390            my $attribute = $self->attribute('expire'); 
     391            $attribute->check_acl('r') or return; 
     392            my $sth = $self->db->prepare_cached( 
     393                q{ select coalesce(expire < now(), false) as exp from "user"  
     394                where "user".name = ?} 
     395            ); 
     396            $sth->execute($self->id); 
     397            my $res = $sth->fetchrow_hashref; 
     398            $sth->finish; 
     399            return $res->{exp} ? 1 : 0; 
     400        }; 
     401    } 
     402} 
     403 
    264404sub set_fields { 
    265405    my ($self, %data) = @_; 
     
    267407    my $res = 0; 
    268408    foreach my $attr (keys %data) { 
     409        $attr eq 'gidnumber' && $data{$attr} !~ /^\d+$/ and do { 
     410            my $group = $self->base->get_object('group', $data{$attr}) or do { 
     411                $self->base->log(LA_ERROR, 
     412                    "Can't set gidNumber to %s: no such group", $data{$attr}); 
     413                return; 
     414            }; 
     415            $data{$attr} = $group->get_attributes('gidNumber'); 
     416        }; 
    269417        $attr =~ /^memberOf$/ and do { 
    270418            my %member; 
     
    287435                    $res++; 
    288436                } elsif ($member{$_}{c}) { 
     437                    if (($self->get_c_field('department') || '') eq $group->id) { 
     438                        $self->base->log(LA_WARN, 
     439                            "Don't removing user %s from group %s: is it's department", 
     440                            $self->id, $group->id); 
     441                        next; 
     442                    } 
    289443                    my $sth = $self->db->prepare_cached( 
    290444                        q{delete from group_attributes_users where value = ? and attr = ? and okey = ?} 
     
    421575            } 
    422576        };           
    423         grep { $attr eq $_ } (__PACKAGE__->_office_address_fields, __PACKAGE__->_address_fields()) and do { 
     577        grep { $attr eq $_ } (qw(co l postalCode streetAddress  
     578            postOfficeBox st facsimileTelephoneNumber  
     579            o telephoneNumber physicalDeliveryOfficeName site)) and do { 
    424580            my $fmainaddress = $self->_get_c_field('mainaddress'); 
    425581            # set address attribute => create address object on the fly 
     
    439595            if ($fmainaddress &&  
    440596                (my $address = $self->base->get_object('address', $fmainaddress))) { 
    441                 $res += $address->set_c_fields($attr => $data{$attr}) ||0; 
     597                if ($address->attribute($attr) && 
     598                    !$address->attribute($attr)->ro) { 
     599                    $res += $address->set_c_fields($attr => $data{$attr}) ||0; 
     600                } 
    442601            } 
    443602            next; 
     
    446605    } 
    447606    if (keys %fdata) { 
    448         return $self->SUPER::set_fields(%fdata) + $res; 
     607        if (defined(my $res2 = $self->SUPER::set_fields(%fdata))) { 
     608           return $res2 + $res; 
     609       } else { 
     610           return; 
     611       } 
    449612    } else { return $res; } 
    450613} 
  • LATMOS-Accounts/lib/LATMOS/Accounts/Bases/Sql/objects.pm

    r764 r861  
    2828=cut 
    2929 
    30 # This fields are special in sense they may come from site field 
    31 sub _address_fields { qw(co l postalCode streetAddress postOfficeBox st 
    32     facsimileTelephoneNumber o) } 
    33  
    3430=head1 FUNCTIONS 
    3531 
     
    4541 
    4642=cut 
     43 
     44sub attributes_table { $_[0]->object_table . '_attributes_list' } 
    4745 
    4846sub list { 
     
    8785sub has_extended_attributes { 0 } 
    8886 
    89 # Work only for very simple case, must be override 
    90  
    91 sub _inline_fields { 
    92     my ($self, $for, $base) = @_; 
    93     if ($base->{__cache}{$self->object_table}) { 
    94         return %{$base->{__cache}{$self->object_table}}; 
    95     } 
    96     my @res; 
    97     my $sth = $base->db->prepare( 
    98         q{SELECT column_name FROM information_schema.columns 
    99           WHERE table_name = ?} 
    100     ); 
    101     $sth->execute($self->object_table); 
    102     while (my $res = $sth->fetchrow_hashref) { 
    103         if ($for =~ 'w') { 
    104             next if($res->{column_name} =~ /^(rev|date|create|ikey)$/); 
    105             next if($res->{column_name} eq $self->key_field); 
    106         } 
    107         push(@res, $res->{column_name}); 
    108     } 
    109     my %fields = map { $_ => $_ } @res; 
    110     $base->{__cache}{$self->object_table} = \%fields; 
    111     %fields 
     87sub _get_attr_schema { 
     88    my ($class, $base, $info) = @_; 
     89    $info ||= {}; 
     90    if (!$base->{__cache}{$class->object_table}{inline}) { 
     91        $base->{__cache}{$class->object_table}{inline} = []; 
     92        my $sth = $base->db->prepare( 
     93            q{SELECT column_name FROM information_schema.columns 
     94              WHERE table_name = ?} 
     95        ); 
     96        $sth->execute($class->object_table); 
     97        while (my $res = $sth->fetchrow_hashref) { 
     98            push(@{$base->{__cache}{$class->object_table}{inline}}, 
     99                $res->{column_name}); 
     100        } 
     101    } 
     102    foreach (@{$base->{__cache}{$class->object_table}{inline}}) { 
     103        $info->{$_}{inline} = 1; 
     104        if (m/^(rev|date|create|ikey)$/) { 
     105            $info->{$_}{ro} = 1 
     106        } 
     107    } 
     108    if ($class->has_extended_attributes) { 
     109        if (!$base->{__cache}{$class->object_table}{extend}) { 
     110            $base->{__cache}{$class->object_table}{extend} = []; 
     111            my $sth = $base->db->prepare_cached( 
     112                sprintf( 
     113                    q{select canonical from %s order by canonical}, 
     114                    $base->db->quote_identifier($class->attributes_table), 
     115                ) 
     116            ); 
     117            $sth->execute; 
     118            while (my $res = $sth->fetchrow_hashref) { 
     119                push(@{$base->{__cache}{$class->object_table}{extend}}, 
     120                        $res->{canonical}); 
     121            } 
     122        } 
     123        foreach (@{$base->{__cache}{$class->object_table}{extend}}) { 
     124            $info->{$_} ||= {}; 
     125        } 
     126    } 
     127    $info->{exported}   = { inline => 1, formtype => 'CHECKBOX', hide => 1, }; 
     128    $info->{unexported} = { inline => 1, formtype => 'CHECKBOX', }; 
     129 
     130    $info 
    112131} 
    113132 
     
    117136    my ($class, $for, $base) = @_; 
    118137    return(); 
    119 } 
    120  
    121 # Everything from attributes_list table 
    122 # $for is uneeded here as all this attributes are rw 
    123  
    124 sub _extended_field { 
    125     my ($class, $for, $base) = @_; 
    126     my @attr; 
    127     if ($class->has_extended_attributes) { 
    128         if ($base->{__cache}{_extended_field}{$class}) { 
    129             return map { $_ => $_ } 
    130                @{$base->{__cache}{_extended_field}{$class}}; 
    131         } 
    132         my $sth = $base->db->prepare_cached( 
    133             sprintf( 
    134                 q{select canonical from %s order by canonical}, 
    135                 $base->db->quote_identifier($class->object_table . '_attributes_list'), 
    136             ) 
    137         ); 
    138         $sth->execute; 
    139         while (my $res = $sth->fetchrow_hashref) { 
    140             push(@attr, $res->{canonical}); 
    141         } 
    142         $base->{__cache}{_extended_field}{$class} = \@attr; 
    143         return map { $_ => $_ } @attr; 
    144     } else { 
    145         return () 
    146     } 
    147 } 
    148  
    149 sub _canonical_fields { 
    150     my ($class, $base, $for) = @_; 
    151     $for ||= 'rw'; 
    152     my %inl = ( 
    153         ($class->_inline_fields($for, $base)), 
    154         ($class->_managed_fields($for, $base)), 
    155         ($class->_extended_field($for, $base)), 
    156     ); 
    157     return sort keys %inl; 
    158 } 
    159  
    160 sub _get_field_name_db { 
    161     my ($class, $c_field, $base) = @_; 
    162     $class->has_extended_attributes or return; 
    163     $class->object_table or return; 
    164     my $sth = $base->db->prepare_cached( 
    165         sprintf( 
    166             q{select ikey from %s where canonical = ?}, 
    167             $base->db->quote_identifier($class->object_table . '_attributes_list'), 
    168         ) 
    169     ); 
    170     $sth->execute($c_field); 
    171      
    172     my $res = $sth->fetchrow_hashref; 
    173     $sth->finish; 
    174     return $c_field if($res->{ikey}); 
    175 } 
    176  
    177 sub _get_field_name { 
    178     my ($class, $c_field, $base, $for) = @_; 
    179     $c_field or return; 
    180     $for ||= 'rw'; 
    181     my %fields = $class->_managed_fields($for, $base); 
    182     return $fields{$c_field} if ($fields{$c_field}); 
    183     %fields = $class->_inline_fields($for, $base); 
    184     return $fields{$c_field} if ($fields{$c_field}); 
    185     %fields = $class->_extended_field($for, $base); 
    186     return $fields{$c_field} 
    187138} 
    188139 
     
    198149    my $count = $sth->execute($id); 
    199150    $sth->finish; 
    200     $count == 1 or return; 
     151    ($count || 0) == 1 or return; 
    201152    $class->SUPER::new($base, $id); 
    202153} 
     
    223174 
    224175    # splitting inline from extended 
    225     my %inlined = $class->_inline_fields('w', $base); 
    226     my %inl = map { $_ => 1 } values %inlined; 
    227176    my (%first, %second); 
     177    # Ensure object is exported if not specified 
     178    $data{exported} = 1 if (!exists($data{exported})); 
     179    if (exists $data{unexported}) { 
     180        $data{exported} = $data{unexported} ? 0 : 1; 
     181        delete $data{unexported} 
     182    } 
    228183    foreach (keys %data) { 
    229         $_ =~ /exported/ and $data{$_} = $data{$_} ? 1 : 0; 
    230         if ($inl{$_}) { 
     184        my $attr = $base->attribute($class->type, $_) or next; 
     185        $_ =~ /^exported$/ and $data{$_} = $data{$_} ? 1 : 0; 
     186        if ($attr->{inline}) { 
    231187            $first{$_} = $data{$_}; 
    232188        } else { 
     
    276232    ); 
    277233 
    278     if ($sthr->execute($newid, $id) != 1) { 
     234    if (($sthr->execute($newid, $id) || 0) != 1) { 
    279235        $base->log(LA_ERR, "Erreur renaming %s %s to %s", 
    280236            $class->type, 
     
    303259sub get_field { 
    304260    my ($self, $field) = @_; 
    305     my %inl = $self->_inline_fields('r', $self->base); 
    306     my %inline = map { $_ => 1 } values %inl; 
    307     if ($inline{$field}) { 
     261    if ($field eq 'unexported') { 
     262        return $self->get_field('exported') ? undef : 1; 
     263    } 
     264    my $attr = $self->attribute($field) or return; 
     265    if ($attr->{inline}) { 
    308266    my $sth = $self->db->prepare_cached( 
    309267        sprintf( 
     
    335293            ) 
    336294        ); 
    337         $sth->execute($self->id); #, $field); 
     295        $sth->execute($self->id); 
    338296        delete($__cache->{$self->id}); 
    339297        $__cache->{$self->id}{__time} = time; 
     
    354312    my @vals; 
    355313    my %ext; 
    356     my %inl = $self->_inline_fields('w', $self->base); 
    357     my %inline = map { $_ => 1 } values %inl; 
     314    if (exists($data{unexported})) { 
     315        $data{exported} = $data{unexported} ? 0 : 1; 
     316    } 
    358317    foreach my $field (keys %data) { 
    359         $data{$field} = $data{$field} ? 1 : 0 if($field eq 'exported'); 
     318        my $attr = $self->attribute($field); 
     319        next if ($field eq 'unexported'); 
    360320        my $oldval = $self->get_field($field); 
    361321        next if (($data{$field} || '') eq ($oldval || '')); 
    362         if ($inline{$field}) { 
     322        if ($attr->{inline}) { 
    363323        # TODO check fields exists ! 
    364324            push(@fields, sprintf("%s = ?", $self->db->quote_identifier($field))); 
     
    378338        ); 
    379339        $sth->execute(@vals, $self->id) or do { 
    380             $self->base->log(LA_ERR, "Cannot update inline field %s" . 
    381                 $self->base->db->strerr); 
     340            $self->base->log(LA_ERR, 
     341                "Cannot update inline field for object %s, %s: %s", 
     342                $self->type, 
     343                $self->id, 
     344                $self->base->db->errstr); 
    382345            return; 
    383346        }; 
     
    392355            ), 
    393356        ); 
     357        my $sthd1 = $self->db->prepare_cached( 
     358            sprintf( 
     359                q{delete from %s where okey = ? and attr = ? and value = ?}, 
     360                $self->db->quote_identifier($self->object_table. '_attributes'), 
     361            ), 
     362        ); 
    394363        my $sthx = $self->db->prepare_cached( 
    395364            sprintf( 
     
    406375 
    407376        my $okey = $self->_get_ikey($self->base, $self->id); 
    408         foreach (keys %ext) { 
    409             if ($ext{$_}) { 
    410                 my $res = $sthu->execute($ext{$_}, $okey, $_); 
    411                 defined($res) or do { 
    412                     $self->base->log(LA_ERR, 
    413                         "Error while udapting attributes: %s", 
    414                         $self->base->db->strerr 
    415                     ); 
    416                     return; 
    417                 }; 
    418                 if ($res == 0) { 
    419                     $res = $sthx->execute($okey, $_, $ext{$_}); 
     377        foreach my $uattr (keys %ext) { 
     378            my $attr = $self->attribute($uattr); 
     379            if ($ext{$uattr}) { 
     380                if ($attr->{multiple}) { 
     381                    my $updated = 0; 
     382                    my $oldvalue = $self->get_field($uattr); 
     383                    my %newvalues = map { $_ => 1 } (ref $ext{$uattr} 
     384                        ? @{$ext{$uattr}} 
     385                        : $ext{$uattr}); 
     386                    foreach (grep { $_ } ref $oldvalue ? @{$oldvalue} : $oldvalue) { 
     387                        if(exists($newvalues{$_})) { 
     388                            $newvalues{$_} = 0; 
     389                        } else { 
     390                            defined($sthd1->execute($okey, $uattr, $_)) or do { 
     391                                $self->base->log(LA_ERR, 
     392                                    "Error while updating attributes on %s/%s %s: %s", 
     393                                    $self->type, 
     394                                    $self->id, 
     395                                    $uattr, 
     396                                    $self->base->db->errstr 
     397                                ); 
     398                                return; 
     399                            }; 
     400                            $updated++; 
     401                        } 
     402                    } 
     403                    foreach (grep { $newvalues{$_} } keys %newvalues) { 
     404                        $sthx->execute($okey, $uattr, $_) or do { 
     405                            $self->base->log(LA_ERR, 
     406                                "Error while updating attributes: %s/%s %s: %s", 
     407                                $self->type, 
     408                                $self->id, 
     409                                $uattr, 
     410                                $self->base->db->errstr 
     411                            ); 
     412                            return; 
     413                        }; 
     414                        $updated++; 
     415                    } 
     416                    $updated_attributes++ if ($updated); 
     417                } else { 
     418                    my $res = $sthu->execute($ext{$uattr}, $okey, $uattr); 
    420419                    defined($res) or do { 
    421420                        $self->base->log(LA_ERR, 
    422                             "Error while udapting attributes: %s", 
    423                             $self->base->db->strerr 
     421                            "Error while udapting attributes: %s/%s %s: %s", 
     422                            $self->type, 
     423                            $self->id, 
     424                            $uattr, 
     425                            $self->base->db->errstr 
    424426                        ); 
     427                        $updated_attributes++; 
    425428                        return; 
    426429                    }; 
     430                    if ($res == 0) { 
     431                        $res = $sthx->execute($okey, $uattr, $ext{$uattr}); 
     432                        defined($res) or do { 
     433                            $self->base->log(LA_ERR, 
     434                                "Error while updating attributes: %s/%s %s: %s", 
     435                                $self->type, 
     436                                $self->id, 
     437                                $uattr, 
     438                                $self->base->db->errstr 
     439                            ); 
     440                            $updated_attributes++; 
     441                            return; 
     442                        }; 
     443                    } 
    427444                } 
    428445            } else { 
    429                 defined($sthd->execute($okey, $_)) or do { 
     446                defined($sthd->execute($okey, $uattr)) or do { 
    430447                    $self->base->log(LA_ERR, 
    431                         "Error while deleting attributes: %s", 
    432                         $self->base->db->strerr 
     448                        "Error while deleting attributes: %s/%s %s: %s", 
     449                        $self->otype, 
     450                        $self->id, 
     451                        $uattr, 
     452                        $self->base->db->errstr 
    433453                    ); 
    434454                    return; 
     
    445465sub attributes_summary { 
    446466    my ($class, $base, $attribute) = @_; 
    447     $class->has_extended_attributes && $class->object_table or 
     467    my $attr = $base->attribute($class->type, $attribute); 
     468    if ($attr->{managed}) {  
    448469        return $class->SUPER::attributes_summary($base, $attribute); 
     470    } 
    449471    my $sth = $base->db->prepare_cached( 
    450         sprintf( 
    451             q{select value from %s where attr = ? group by value}, 
    452             $base->db->quote_identifier($class->object_table . 
    453                 '_attributes'), 
    454         ) 
    455     ); 
    456     $sth->execute($attribute); 
     472        $attr->{inline} 
     473            ? sprintf( 
     474                q{select %s as value from %s}, 
     475                $base->db->quote_identifier($attr->iname), 
     476                $base->db->quote_identifier($class->object_table), 
     477            ) 
     478            : sprintf( 
     479                q{select value from %s where attr = ? group by value}, 
     480                $base->db->quote_identifier($class->object_table . 
     481                    '_attributes'), 
     482            ) 
     483    ); 
     484    $sth->execute($attr->{inline} ? () : ($attribute)); 
    457485 
    458486    my @values; 
     
    465493sub _set_password { 
    466494    my ($self, $clear_pass) = @_; 
    467     if (my $field = $self->base->get_field_name($self->type, 'userPassword')) { 
     495    if (my $attr = $self->base->attribute($self->type, 'userPassword')) { 
     496        my $field = $attr->iname; 
    468497        my @salt_char = (('a' .. 'z'), ('A' .. 'Z'), (0 .. 9), '/', '.'); 
    469498        my $salt = join('', map { $salt_char[rand(scalar(@salt_char))] } (1 .. 8)); 
    470499        my $res = $self->set_fields($field, crypt($clear_pass, '$1$' . $salt)); 
     500        if (!$res) { 
     501            return; 
     502        } 
    471503 
    472504        if (my $serialize = $self->base->get_global_value('rsa_public_key')) { 
     
    479511                Armour     => 1, 
    480512            ) || die $self->poll->rsa->errstr(); 
    481             $self->set_c_fields('encryptedPassword', $rsa_password); 
     513            return $self->set_c_fields('encryptedPassword', $rsa_password); 
     514        } else { 
     515            return 1; 
    482516        } 
    483517    } else { 
     
    490524    my ($class, $base, @filter) = @_; 
    491525 
    492     if ($class->has_extended_attributes) { 
    493         my %attrsql; 
    494         my %attrbind; 
    495         while (my $item = shift(@filter)) { 
    496             # attr=foo => no extra white space ! 
    497             # \W is false, it is possible to have two char 
    498             my ($attr, $mode, $val) = $item =~ /^(\w+)(?:(\W)(.+))?$/ or next; 
    499             if (!$mode) { 
    500                 $mode = '~'; 
    501                 $val = shift(@filter); 
    502             } 
    503             $val ||= ''; 
    504             push(@{ $attrsql{$attr} }, 
    505                 sprintf("\n\t" . q{select okey from %s where attr=? %s} . "\n", 
    506                     $base->db->quote_identifier($class->object_table . 
    507                         '_attributes'), 
    508                     $val eq '*' 
    509                         ? '' 
    510                         : ($mode eq '~' 
    511                             ? q{and value ILIKE ?} 
    512                             : q{and value = ?} ) 
    513                 ) 
     526    my %attrsql; 
     527    my %attrbind; 
     528 
     529    while (my $item = shift(@filter)) { 
     530        # attr=foo => no extra white space ! 
     531        # \W is false, it is possible to have two char 
     532        my ($attr, $mode, $val) = $item =~ /^(\w+)(?:(\W)(.+))?$/ or next; 
     533        if (!$mode) { 
     534            $mode = '~'; 
     535            $val = shift(@filter); 
     536        } 
     537        my $attribute = $base->attribute($class->type, $attr) or do { 
     538            $base->log(LA_ERR, "Unknown attribute $attr"); 
     539            next; 
     540        }; 
     541        defined($val) or $val =  ''; 
     542        $val = $attribute->input($val); 
     543 
     544        my $sql; 
     545 
     546        # Specific case for unexported attribute, comming from exported value 
     547        if ($attribute->iname eq 'unexported') { 
     548            $sql = sprintf( 
     549                q{select ikey from %s where %s}, 
     550                $base->db->quote_identifier($class->object_table), 
     551                $val ? q{exported='f'} : q{exported='t'} 
     552            ) 
     553        } elsif ($attribute->{inline}) { 
     554            $sql = sprintf( 
     555                q{select ikey from %s where %s %s}, 
     556                $base->db->quote_identifier($class->object_table), 
     557                $base->db->quote_identifier($attribute->iname), 
     558                $val eq '*' 
     559                    ? 'is not NULL' 
     560                    : $mode eq '~' 
     561                        ? 'ILIKE ?' 
     562                        : '= ?'  
    514563            ); 
    515             push(@{$attrbind{$attr}}, $base->get_field_name($class->type, $attr, 'r')); 
    516564            push(@{$attrbind{$attr}}, $mode eq '~' ? '%' . $val . '%' : $val) unless($val eq '*'); 
    517         } 
    518         # building the query 
    519         my @sqlintersec; 
    520         if (!$base->{wexported}) { 
    521            push(@sqlintersec, sprintf( 
    522                    q{select ikey from %s where exported = true}, 
    523                    $base->db->quote_identifier($class->object_table) 
    524                ) 
    525            ); 
    526         } 
    527         my @bind; 
    528         foreach (keys %attrsql) { 
    529             push(@sqlintersec, '(' . join(" union ", @{$attrsql{$_}}) . ")\n"); 
    530             push(@bind, @{$attrbind{$_}}); 
    531         } 
    532         my $sth = $base->db->prepare( 
    533             sprintf(q{ 
    534                 select name from %s 
    535                 %s 
    536                 }, 
    537                 $base->db->quote_identifier($class->object_table), 
    538                 @sqlintersec  
    539                     ? "where ikey in (\n" . join("\n intersect\n", @sqlintersec) . ")\n" 
    540                     : '', 
    541             ) 
    542         ); 
    543         $sth->execute(@bind); 
    544         my @results; 
    545         while (my $res = $sth->fetchrow_hashref) { 
    546             push(@results, $res->{name}); 
    547         } 
    548         return(@results); 
     565        } else { 
     566            $sql = sprintf( 
     567                q{select okey from %s where attr = ? %s}, 
     568                $base->db->quote_identifier( 
     569                    $class->object_table . '_attributes' 
     570                ), 
     571                $val eq '*' 
     572                    ? '' 
     573                    : $mode eq '~' 
     574                        ? q{and value ILIKE ?} 
     575                        : q{and value = ?} 
     576 
     577            ); 
     578            push(@{$attrbind{$attr}}, $attribute->iname); 
     579            push(@{$attrbind{$attr}}, $mode eq '~' ? '%' . $val . '%' : $val) unless($val eq '*'); 
     580        } 
     581 
     582        push(@{ $attrsql{$attr} }, $sql); 
     583    } 
     584    # building the query 
     585    my @sqlintersec; 
     586    if (!$base->{wexported}) { 
     587        push(@sqlintersec, sprintf( 
     588                q{select ikey from %s where exported = true}, 
     589                $base->db->quote_identifier($class->object_table) 
     590            ) 
     591        ); 
     592    } 
     593    my @bind; 
     594    foreach (keys %attrsql) { 
     595        push(@sqlintersec, '(' . join(" union ", @{$attrsql{$_}}) . ")\n"); 
     596        push(@bind, @{$attrbind{$_} || []}); 
     597    } 
     598    my $sth = $base->db->prepare( 
     599        sprintf(q{ 
     600            select name from %s 
     601            %s 
     602            order by name 
     603            }, 
     604            $base->db->quote_identifier($class->object_table), 
     605            @sqlintersec  
     606            ? "where ikey in (\n" . join("\n intersect\n", @sqlintersec) . ")\n" 
     607            : '', 
     608        ) 
     609    ); 
     610    $sth->execute(@bind); 
     611    my @results; 
     612    while (my $res = $sth->fetchrow_hashref) { 
     613        push(@results, $res->{name}); 
     614    } 
     615    return(@results); 
     616} 
     617 
     618sub register_attribute { 
     619    my ($class, $base, $attribute, $comment) = @_; 
     620 
     621    $base->attribute($class->type, $attribute) and do { 
     622        $base->log(LA_ERR, "The attribute $attribute already exists"); 
     623        return; 
     624    }; 
     625    my $sth = $base->db->prepare( 
     626        sprintf(q{ 
     627            insert into %s (canonical, description) 
     628            values (?,?) 
     629            }, $class->attributes_table) 
     630    ); 
     631    my $res = $sth->execute($attribute, $comment); 
     632} 
     633 
     634sub get_attribute_comment { 
     635    my ($class, $base, $attribute) = @_; 
     636    $base->attribute($class->type, $attribute) or do { 
     637        $base->log(LA_ERR, "The attribute $attribute does not exists"); 
     638        return; 
     639    }; 
     640    my $sth = $base->db->prepare( 
     641        sprintf(q{ 
     642            select description from %s 
     643            where canonical = ? 
     644            }, $class->attributes_table) 
     645    ); 
     646    $sth->execute($attribute); 
     647    if (my $res = $sth->fetchrow_hashref) { 
     648        $sth->finish; 
     649        return $res->{description}; 
    549650    } else { 
    550         my @bind; 
    551         my @where; 
    552         while (my $item = shift(@filter)) { 
    553             # attr=foo => no extra white space ! 
    554             # \W is false, it is possible to have two char 
    555             my ($attr, $mode, $val) = $item =~ /^(\w+)(?:(\W)(.+))?$/ or next; 
    556             if (!$mode) { 
    557                 $mode = '~'; 
    558                 $val = shift(@filter); 
    559             } 
    560             if ($val eq '*') { 
    561                 push(@where, sprintf("%s is not NULL", 
    562                         $base->db->quote_identifier($base->get_field_name($class->type, 
    563                                 $attr, 'r')) 
    564                     ) 
    565                 ); 
    566             } else { 
    567                 push(@where, sprintf("%s %s ?", 
    568                         $base->db->quote_identifier( 
    569                             $base->get_field_name($class->type, $attr, 'r') 
    570                         ), 
    571                         $mode eq '~' ? 'ILIKE' : '=', 
    572                     )); 
    573                 push(@bind, lc($val)); 
    574             } 
    575         } 
    576         my $sth = $base->db->prepare( 
    577             sprintf(q{select name from %s where %s}, 
    578                 $base->db->quote_identifier($class->object_table), 
    579                 join(' and ', @where), 
    580             ) 
    581         ); 
    582         $sth->execute(@bind); 
    583         my @results; 
    584         while (my $res = $sth->fetchrow_hashref) { 
    585             push(@results, $res->{name}); 
    586         } 
    587         return(@results); 
    588     } 
    589 } 
     651        return; 
     652    } 
     653} 
     654 
     655sub set_attribute_comment { 
     656    my ($class, $base, $attribute, $comment) = @_; 
     657 
     658    my $attr = $base->attribute($class->type, $attribute) or do { 
     659        $base->log(LA_ERR, "The attribute $attribute does not exists"); 
     660        return; 
     661    }; 
     662    $attr->{inline} and do { 
     663        $base->log(LA_ERR, 
     664            "Cannot set comment to inline attribute, sorry, blame the author !" 
     665        ); 
     666        return; 
     667    }; 
     668    my $sth = $base->db->prepare( 
     669        sprintf(q{ 
     670            update %s set description = ? 
     671            where canonical = ? 
     672            }, $class->attributes_table) 
     673    ); 
     674    my $res = $sth->execute($comment, $attribute); 
     675} 
     676 
     677 
    590678 
    5916791; 
  • LATMOS-Accounts/lib/LATMOS/Accounts/Bases/Unix.pm

    r815 r861  
    4343     
    4444    my $base = { 
    45         passwd =>  $options{passwd} || '/etc/passwd', 
    46         shadow =>  $options{shadow} || '/etc/shadow', 
    47         group =>   $options{group} || '/etc/group', 
    48         gshadow => $options{gshadow} || '/etc/gshadow', 
    4945        # are we using shadow, default to yes 
    5046        use_shadow => (defined($options{use_shadow}) ? $options{use_shadow} : 1), 
     
    5652    }; 
    5753 
     54    foreach (qw(passwd shadow group gshadow)) { 
     55        if ($options{$_}) { 
     56            $base->{$_} = $options{$_}; 
     57        } elsif ($options{directory}) { 
     58            $base->{$_} = $options{directory} . '/' . $_; 
     59        } else { 
     60            $base->{$_} = "/etc/$_"; 
     61        } 
     62    } 
     63 
     64 
    5865    bless($base, $class); 
    59 } 
    60  
    61 sub _canonicals_fields { 
    62     my ($self, $type, $for) = @_; 
    63     $type = lc($type); 
    64     { 
    65         user => { 
    66             uidNumber       => 'uid', 
    67             gidNumber       => 'gid', 
    68             gecos           => 'gecos', 
    69             homeDirectory   => 'home', 
    70             loginShell      => 'shell', 
    71             userPassword    => ($self->{use_shadow} ? 'spassword' : 'password'), 
    72             memberOf        => 'memberOf', 
    73             locked          => 'locked', 
    74             ($for !~ /w/ ? ( 
    75             givenName       => 'givenName', 
    76             sn              => 'sn', 
    77             uid             => 'login', 
    78             sAMAccountName  => 'login', 
    79             ) : ()), 
    80             $self->{use_shadow} ? 
    81             ( 
    82             shadowLastChange => 'last_changed', 
    83             shadowMin       => 'before_ch', 
    84             shadowMax       => 'after_ch', 
    85             shadowWarning   => 'exp_warn', 
    86             shadowInactive  => 'exp_disable', 
    87             shadowExpire    => 'disable', 
    88             shadowFlag      => 'res', 
    89             ) : (),  
    90             # description => not supported 
    91         }, 
    92         group => { 
    93             ($for !~ /w/ ? ( 
    94             sAMAccountName  => 'group_name', 
    95             ) : ()), 
    96             gidNumber       => 'gid', 
    97             memberUID       => 'user_list', 
    98         }, 
    99     }->{$type} 
    100 } 
    101  
    102 sub list_canonical_fields { 
    103     my ($self, $type, $for) = @_; 
    104     $for ||= 'rw'; 
    105     keys %{ $self->_canonicals_fields($type, $for) || {} } 
    106 } 
    107  
    108 sub get_field_name { 
    109     my ($self, $type, $cfield, $for) = @_; 
    110     $for ||= 'rw'; 
    111     ($self->_canonicals_fields($type, $for) || {})->{$cfield} 
    11266} 
    11367 
     
    248202    truncate($handle, 0); 
    249203    foreach my $line (@data) { 
    250         print $handle join(':', map { defined($_) ? $_ : '' } @$line) . "\n"; 
     204        print $handle join(':', map { my $f = $_; $f =~ s/:/;/g; $f } map { defined($_) ? $_ : '' } @$line) . "\n"; 
    251205    } 
    252206    close($handle); 
  • LATMOS-Accounts/lib/LATMOS/Accounts/Bases/Unix/Group.pm

    r807 r861  
    2828=cut 
    2929 
     30sub _get_attr_schema { 
     31    my ($class, $base) = @_; 
     32    { 
     33        sAMAccountName => { 
     34            iname => 'group_name', 
     35            ro => 1, 
     36        }, 
     37        gidNumber => { 
     38            iname => 'gid', 
     39        }, 
     40        memberUID => { 
     41            iname => 'user_list', 
     42            multiple => 1, 
     43            delayed => 1, 
     44        }, 
     45    }; 
     46} 
     47 
    3048=head2 new(%options) 
    3149 
     
    4765        return bless($base->{groups}{$id}, $class); 
    4866    } else { return } 
    49 } 
    50  
    51 sub _delayed_fields { 
    52     my ($self)= @_; 
    53     return qw(memberUID); 
    5467} 
    5568 
  • LATMOS-Accounts/lib/LATMOS/Accounts/Bases/Unix/User.pm

    r806 r861  
    2828=cut 
    2929 
     30sub _get_attr_schema { 
     31    my ($class, $base) = @_; 
     32    { 
     33        uidNumber       => { iname => 'uid', uniq => 1, }, 
     34        gidNumber       => { iname => 'gid', 
     35            can_values => sub { 
     36                map { $_->get_attributes('gidNumber') } 
     37                map { $base->get_object('group', $_) } 
     38                $base->list_objects('group') 
     39            }, 
     40            reference => 'group', 
     41            mandatory => 1, 
     42        }, 
     43        gecos           => { }, 
     44        homeDirectory   => { iname => 'home' }, 
     45        loginShell      => { iname => 'shell' }, 
     46        userPassword    => { 
     47            iname => ($base->{use_shadow} ? 'spassword' : 'password') 
     48        }, 
     49        memberOf        => { delayed => 1, }, 
     50        locked          => {}, 
     51        givenName       => { ro => 1 }, 
     52        sn              => { ro => 1 }, 
     53        uid             => { iname => 'login', ro => 1 }, 
     54        sAMAccountName  => { iname => 'login', ro => 1 }, 
     55        $base->{use_shadow} ? 
     56        ( 
     57            shadowLastChange => { iname => 'last_changed' }, 
     58            shadowMin        => { iname => 'before_ch' }, 
     59            shadowMax        => { iname => 'after_ch' }, 
     60            shadowWarning    => { iname => 'exp_warn' }, 
     61            shadowInactive   => { iname => 'exp_disable' }, 
     62            shadowExpire     => { iname => 'disable' }, 
     63            shadowFlag       => { iname => 'res' }, 
     64        ) : (), 
     65    }; 
     66} 
     67 
    3068=head2 new(%options) 
    31  
    32 Create a new LATMOS::Ad object for windows AD $domain. 
    33  
    34 domain / server: either the Ad domain or directly the server 
    35  
    36 ldap_args is an optionnal list of arguments to pass to L<Net::LDAP>. 
    3769 
    3870=cut 
     
    4779        return bless($base->{users}{$id}, $class); 
    4880    } else { return } 
    49 } 
    50  
    51 sub _delayed_fields { 
    52     my ($self)= @_; 
    53     return qw(memberOf); 
    5481} 
    5582 
  • LATMOS-Accounts/lib/LATMOS/Accounts/Cli.pm

    r851 r861  
    99use Term::ReadLine; 
    1010use Text::ParseWords; 
     11use Getopt::Long; 
     12 
     13{ 
     14    open (my $fh, "/dev/tty" ) 
     15        or eval 'sub Term::ReadLine::findConsole { ("&STDIN", "&STDERR") }'; 
     16    die $@ if $@; 
     17    close ($fh); 
     18} 
    1119 
    1220my $term = Term::ReadLine->new('LA CLI'); 
     21$term->MinLine(99999); 
    1322my $OUT = $term->OUT || \*STDOUT; 
     23 
     24my $trans_mode = 0; 
    1425 
    1526sub globalenv { 
     
    2940            if ($arg eq 'yes') { 
    3041                $env->base->unexported(1); 
    31                 print $OUT "Unexported are now show"; 
     42                print $OUT "Unexported are now show\n"; 
    3243            } elsif ($arg eq 'no') { 
    3344                $env->base->unexported(0); 
    34                 print $OUT "Unexported are no longer show"; 
     45                print $OUT "Unexported are no longer show\n"; 
    3546            } elsif ($arg eq 'show') { 
    36                 print $OUT "Unexported objects " . $env->base->unexported ? 
    37                 "enable" : "disable"; 
     47                print $OUT "Unexported objects " . ($env->base->unexported ? 
     48                "enable" : "disable") . "\n"; 
    3849            } else { 
    39                 print $OUT "wrong argument"; 
     50                print $OUT "wrong argument\n"; 
    4051            } 
    4152        }, 
     
    5263                    print $OUT map { "$_\n" } $_[0]->base->list_objects($_[1]); 
    5364                } else { 
    54                     print $OUT "Object type missing"; 
     65                    print $OUT "Object type missing\n"; 
    5566                } 
    5667            }, 
     
    7182                    $env->{_lastsearchtype} = $args[0]; 
    7283                } else { 
    73                     print $OUT "Object type missing"; 
     84                    print $OUT "Object type missing\n"; 
    7485                } 
    7586            }, 
     
    112123                        @ids = @{$env->{_lastsearch}}; 
    113124                    } else { 
    114                         print $OUT "No results store from previous search"; 
     125                        print $OUT "No results store from previous search\n"; 
    115126                        return; 
    116127                    } 
    117128                } 
    118129                if (!@ids) { 
    119                     print $OUT 'not enough arguments'; 
     130                    print $OUT 'not enough arguments' . "\n"; 
    120131                    return; 
    121132                } 
    122133                foreach (@ids) { 
    123134                    my $obj = $env->base->get_object($otype, $_) or do { 
    124                         print $OUT "Cannot get $otype $_"; 
     135                        print $OUT "Cannot get $otype $_\n"; 
    125136                        return; 
    126137                    }; 
    127138                    push(@objs, $obj); 
    128139                } 
    129                 print $OUT "Selecting $otype " . join(', ', @ids); 
     140                print $OUT "Selecting $otype " . join(', ', @ids) . "\n"; 
    130141                objenv($_[0]->base, $otype, @objs)->cli(); 
    131142            }, 
    132143        }); 
     144    $env->add_func('create', { 
     145            code => sub { 
     146                my ($env, $otype) = @_; 
     147                my $helper = $env->base->ochelper($otype); 
     148                my $info = undef; 
     149                while (1) { 
     150                    my $status; 
     151                    ($status, $info) = $helper->step($info); 
     152 
     153                    if ($status ne 'NEEDINFO') { 
     154                        if ($status eq 'CREATED') { 
     155                            print $OUT "Object created\n"; 
     156                            $env->commit; 
     157                        } else { 
     158                            print $OUT "Nothing done\n"; 
     159                            $env->rollback; 
     160                        } 
     161                        return; 
     162                    } 
     163 
     164                    if ($info->{name}{ask}) { 
     165                        my $line = $term->readline("Name of the object ?"); 
     166                        $info->{name}{content} = $line; 
     167                    } 
     168                    foreach my $attr (@{$info->{ask} || []}) { 
     169                        $term->Attribs->{completion_function} = sub { 
     170                            $info->{contents}{$attr} 
     171                        }; 
     172                        my $line = $term->readline(sprintf('  %s %s? ', 
     173                                $attr, 
     174                                $info->{contents}{$attr} 
     175                                ? '(' . $info->{contents}{$attr} . ') ' 
     176                                : '' 
     177                            )); 
     178                        $info->{contents}{$attr} = $line if($line); 
     179                    } 
     180                } 
     181            }, 
     182        } 
     183    ); 
     184    $env->add_func('exchangeip',  
     185        { 
     186            help => 'Exchange two IP on host', 
     187            code => sub { 
     188                my ($env, @args) = @_; 
     189                my ($ip1, $ip2) = 
     190                    grep { $_ && $_ =~ /\d+\.\d+\.\d+\.\d+/ } @args; 
     191                if (!$ip2) { 
     192                    print $OUT "Need two ip to exchange\n"; 
     193                    return; 
     194                } 
     195                if ($env->base->nethost_exchange_ip($ip1, $ip2)) { 
     196                    print $OUT "$ip1 and $ip2 get exchange\n"; 
     197                    $env->commit; 
     198                } else { 
     199                    $env->rollback; 
     200                }    
     201            }, 
     202            completion => sub { 
     203                my ($env, $carg, @args) = @_; 
     204                if ($args[-1] && $args[-1] !~ m/\d+\.\d+\.\d+\.\d+/) { 
     205                    if (my $obj = $env->base->get_object('nethost', $args[-1])) { 
     206                        return $obj->get_attributes('ip'); 
     207                    } 
     208                } else { 
     209                    my @list =  
     210                    ($env->base->attributes_summary('nethost', 'ip'), 
     211                        $env->base->list_objects('nethost')); 
     212                    return @list; 
     213                } 
     214            }, 
     215        } 
     216    ); 
    133217    $env->add_func('user',  { alias => [qw'select user' ] }); 
    134218    $env->add_func('group', { alias => [qw'select group'] }); 
     
    153237    $objenv->{_otype} = $otype; 
    154238    $objenv->{_objects} = [ @objs ]; 
     239    $objenv->add_func('+', { 
     240        help => 'add item to selection', 
     241        code => sub { 
     242            my ($env, @ids) = @_; 
     243            my %ids = map { $_->id => 1 } @{$env->{_objects}}; 
     244            foreach (@ids) { 
     245                $ids{$_} and next; 
     246                my $o = $env->base->get_object($env->{_otype}, $_) or next; 
     247                push(@{$env->{_objects}}, $o); 
     248            } 
     249            printf $OUT "select is now %s: %s\n", $env->{_otype}, join(', ', map { 
     250                $_->id } @{$env->{_objects}}); 
     251        }, 
     252        completion => sub { 
     253            my ($env, undef, @ids) = @_; 
     254            my %ids = map { $_->id => 1 } @{$env->{_objects}}; 
     255            return ( grep { ! $ids{$_} } $env->base->list_objects($env->{_otype})); 
     256        }, 
     257        } 
     258    ); 
     259    $objenv->add_func('-', { 
     260        help => 'add item to selection', 
     261        code => sub { 
     262            my ($env, @ids) = @_; 
     263            my %ids = map { $_ => 1 } @ids; 
     264            my @newobjs = grep { !$ids{$_->id} } @{$env->{_objects}}; 
     265 
     266            if (!@newobjs) { 
     267                print $OUT "This would remove all objects from the list...\n"; 
     268                return; 
     269            } else { 
     270                @{$env->{_objects}} = @newobjs; 
     271            } 
     272            printf $OUT "select is now %s: %s\n", $env->{_otype}, join(', ', map { 
     273                $_->id } @{$env->{_objects}}); 
     274        }, 
     275        completion => sub { 
     276            my ($env, undef, @ids) = @_; 
     277            my %ids = map { $_ => 1 } @ids; 
     278            grep { !$ids{$_} } map { $_->id } @{$env->{_objects}}; 
     279        }, 
     280        } 
     281    ); 
    155282    $objenv->add_func('show', { 
    156283        help => 'show attributes - show an attributes of object', 
     
    177304        code => sub { 
    178305            my ($env, $fmt) = @_; 
     306            if (!defined($fmt)) { 
     307                print $OUT "no format given"; 
     308                return; 
     309            } 
    179310            foreach (@{$env->{_objects}}) { 
    180311                print $OUT $_->queryformat($fmt) . "\n"; 
     
    192323            foreach (@{$env->{_objects}}) { 
    193324                defined $_->set_c_fields($attr => undef) or do { 
    194                     print $OUT "cannot unset attributes $attr for " . $_->id; 
     325                    print $OUT "cannot unset attributes $attr for " . $_->id . 
     326                    "\n"; 
    195327                    return; 
    196328                }; 
    197329            } 
    198             $env->base->commit; 
    199             print $OUT "Changes applied"; 
     330            $env->commit; 
     331            print $OUT "Changes applied\n"; 
    200332        }, 
    201333        completion => sub { 
     
    211343            my ($env, $attr, @value) = @_; 
    212344            @value or do { 
    213                 print $OUT "attribute and value must be specified"; 
     345                print $OUT "attribute and value must be specified\n"; 
    214346                return; 
    215347            }; 
     
    218350                    \@value) or do { 
    219351                    $_->base->rollback; 
    220                     printf $OUT "Cannot set $attr to %s for %s", join(', ', 
     352                    printf $OUT "Cannot set $attr to %s for %s\n", join(', ', 
    221353                        @value), $_->id; 
    222354                    return; 
    223355                }; 
    224356            } 
    225             $env->base->commit; 
    226             print $OUT "done"; 
     357            $env->commit; 
     358            print $OUT "Done.\n"; 
    227359        }, 
    228360        completion => sub { 
     
    231363                return $env->base->list_canonical_fields($env->{_otype}, 'w') 
    232364            } else { 
    233                 if ($env->base->obj_attr_allowed_values($env->{_otype}, $args[0])) { 
    234                     return $env->base->obj_attr_allowed_values($env->{_otype}, $args[0]) 
    235                 } 
    236                 for ($args[0]) { 
    237                     /^manager|managedBy$/ and return 
    238                         $env->base->search_objects('user'); 
    239                     /^department$/ and return 
    240                         $env->base->search_objects('group', 'sutype=dpmt'); 
    241                     /^contratType$/ and return 
    242                         $env->base->search_objects('group', 'sutype=contrattype'); 
    243                     /^site$/ and return 
    244                         $env->base->search_objects('site'); 
    245                     if (@{$env->{_objects}} == 1) { 
    246                         return $env->{_objects}[0]->get_attributes($args[0]); 
    247                     } 
     365                my $attr = $env->base->attribute($env->{_otype}, $args[0]); 
     366                if ($attr->has_values_list) { 
     367                    $attr->can_values; 
     368                } elsif (@{$env->{_objects}} == 1) { 
     369                    return 
     370                    $env->{_objects}[0]->get_attributes($args[0]); 
     371                } 
     372            } 
     373        }, 
     374    }); 
     375    $objenv->add_func('add', { 
     376        help => 'add a value to an attribute', 
     377        code => sub { 
     378            my ($env, $attr, @value) = @_; 
     379            @value or do { 
     380                print $OUT "attribute and value must be specified\n"; 
     381                return; 
     382            }; 
     383            foreach (@{$env->{_objects}}) { 
     384                my @attrv = grep { $_ } $_->get_attributes($attr); 
     385                defined $_->set_c_fields($attr => [ @attrv, @value ]) or do { 
     386                    $_->rollback; 
     387                    printf $OUT "Cannot set $attr to %s for %s\n", join(', ', 
     388                        @value), $_->id; 
     389                    return; 
     390                }; 
     391            } 
     392            $env->commit; 
     393            print $OUT "done\n"; 
     394        }, 
     395        completion => sub { 
     396            my ($env, $lastw, @args) = @_; 
     397            if (!$args[0]) { 
     398                return grep { 
     399                    $env->base->attribute($env->{_otype}, $_)->{multiple} 
     400                } $env->base->list_canonical_fields($env->{_otype}, 'w') 
     401            } else { 
     402                my $attr = $env->base->attribute($env->{_otype}, $args[0]); 
     403                if ($attr->has_values_list) { 
     404                    $attr->can_values; 
     405                } elsif (@{$env->{_objects}} == 1) { 
     406                    return 
     407                    $env->{_objects}[0]->get_attributes($args[0]); 
     408                } 
     409            } 
     410        }, 
     411    }); 
     412    $objenv->add_func('remove', { 
     413        help => 'remove a value from an attribute', 
     414        code => sub { 
     415            my ($env, $attr, @value) = @_; 
     416            @value or do { 
     417                print $OUT "attribute and value must be specified\n"; 
     418                return; 
     419            }; 
     420            foreach (@{$env->{_objects}}) { 
     421                my @attrv = grep { $_ } $_->get_attributes($attr); 
     422                foreach my $r (@value) { 
     423                    @attrv = grep { $_ ne $r } @attrv; 
     424                } 
     425                defined $_->set_c_fields($attr => @attrv ? [ @attrv ] : undef) or do { 
     426                    $_->rollback; 
     427                    printf $OUT "Cannot set $attr to %s for %s\n", join(', ', 
     428                        @value), $_->id; 
     429                    return; 
     430                }; 
     431            } 
     432            $env->commit; 
     433            print $OUT "done\n"; 
     434        }, 
     435        completion => sub { 
     436            my ($env, $lastw, @args) = @_; 
     437            if (!$args[0]) { 
     438                return grep { 
     439                    $env->base->attribute($env->{_otype}, $_)->{multiple} 
     440                } $env->base->list_canonical_fields($env->{_otype}, 'w') 
     441            } else { 
     442                my $attr = $env->base->attribute($env->{_otype}, $args[0]); 
     443                if (@{$env->{_objects}} == 1) { 
     444                    return 
     445                    $env->{_objects}[0]->get_attributes($args[0]); 
    248446                } 
    249447            } 
     
    253451        help => 'list current selected objects', 
    254452        code => sub { 
    255             printf $OUT "%s: %s", $_[0]->{_otype}, join(', ', map { $_->id } 
     453            printf $OUT "%s: %s\n", $_[0]->{_otype}, join(', ', map { $_->id } 
    256454            @{$_[0]->{_objects}}); 
    257455        } 
     
    267465                if ($id) { 
    268466                    $obj = grep { $_->id = $id } @{$env->{_objects}} or do { 
    269                         print $OUT "$id is not part of selected objects"; 
     467                        print $OUT "$id is not part of selected objects\n"; 
    270468                        return; 
    271469                    }; 
     
    274472                } else { 
    275473                    print $OUT "multiple objects selected but can edit only one," 
    276                     . "please specify which one"; 
     474                    . "please specify which one\n"; 
    277475                    return; 
    278476                } 
     
    292490                        my $res = $obj->set_c_fields(%attr); 
    293491                        if ($res) { 
    294                             print $OUT "Changes applied"; 
    295                             $env->base->commit; 
     492                            print $OUT "Changes applied\n"; 
     493                            $env->commit; 
    296494                        } 
    297                         else { print $OUT "Error applying changes" } 
     495                        else { print $OUT "Error applying changes\n" } 
    298496                        return $res ? 1 : 0; 
    299497                    } 
     
    305503        code => sub { 
    306504            my ($env) = @_; 
    307             printf $OUT "%s: %s\ndelete selected objects ? (yes/NO) ", 
     505            printf $OUT "%s: %s\ndelete selected objects ? (yes/NO)\n", 
    308506            $env->{_otype}, join(', ', map { $_->id } @{$env->{_objects}}); 
    309507            my $reply = <STDIN> || ''; chomp($reply); 
     
    311509                foreach (@{$env->{_objects}}) { 
    312510                    $env->base->delete_object($env->{_otype}, $_->id) or do { 
    313                         print $OUT "Cannot delete " . $_->id; 
     511                        print $OUT "Cannot delete " . $_->id . "\n"; 
    314512                        return; 
    315513                    }; 
    316514                } 
    317                 $env->base->commit; 
     515                $env->commit; 
    318516                return "EXIT"; 
    319517            } else { 
    320                 print $OUT "cancel !" 
    321             } 
    322         }, 
    323     }); 
     518                print $OUT "cancel !\n" 
     519            } 
     520        }, 
     521    }); 
     522    if (grep { $objenv->base->attribute($otype, $_)->reference } 
     523        $objenv->base->list_canonical_fields($otype, 'r')) { 
     524        $objenv->add_func('select', { 
     525            help => 'select attribute [object]', 
     526            code => sub { 
     527                my ($env, $attrname, @objects) = @_; 
     528                my $totype = $env->base->attribute($env->{_otype}, 
     529                    $attrname)->reference or return; 
     530 
     531                if (! @objects) { 
     532                    @objects = grep { $_ }  
     533                      map { $_->get_attributes($attrname) } @{$env->{_objects}}; 
     534                } 
     535                { 
     536                    my %uniq = map { $_ => 1 } @objects; 
     537                    @objects = keys %uniq; 
     538                } 
     539                my @objs = (grep { $_ } map { $env->base->get_object($totype, $_) } 
     540                        @objects); 
     541                return if (!@objs); 
     542                print $OUT "Selecting $otype " . join(', ', map { $_->id } @objs) . "\n"; 
     543                objenv($_[0]->base, $totype, @objs)->cli(); 
     544            }, 
     545            completion => sub { 
     546                if ($_[2]) { 
     547                    my $totype = $_[0]->base->attribute($_[0]->{_otype}, 
     548                        $_[2])->reference or return; 
     549                    return grep { $_ } 
     550                           map { $_->get_attributes($_[2]) } 
     551                           @{$_[0]->{_objects}}; 
     552                } else { 
     553                    return grep { $_[0]->base->attribute($otype, $_)->reference } 
     554                    $_[0]->base->list_canonical_fields($otype, 'r'); 
     555                } 
     556            }, 
     557            } 
     558        ); 
     559    } 
    324560 
    325561    if (lc($otype) eq 'user') { 
     
    334570                            my $gobj = $env->base->get_object('group', $gid) or 
    335571                            do { 
    336                                 print $OUT "Cannot find group $gid"; 
     572                                print $OUT "Cannot find group $gid\n"; 
    337573                                return; 
    338574                            }; 
     
    350586                            delete($gr{$_}) foreach(@groups); 
    351587                        } else { 
    352                             print $OUT 'invalid action'; 
     588                            print $OUT 'invalid action' . "\n"; 
    353589                            return; 
    354590                        } 
    355591                        defined $obj->set_c_fields('memberOf' => [ keys %gr ]) or do { 
    356592                            print $OUT "cannot set memberOf attributes for " . 
    357                             $obj->id; 
     593                            $obj->id . "\n"; 
    358594                            return; 
    359595                        }; 
    360596                    } 
    361597                } 
    362                 $env->base->commit; 
     598                $env->commit; 
    363599            }, 
    364600            completion => sub { 
     
    366602                    return (qw(add remove primary)); 
    367603                } else { 
    368                     return $_[0]->base->search_objects('group'); 
     604                    if ($_[2] eq 'remove') { 
     605                        my %uniq = map { $_ => 1 } 
     606                            grep { $_ } 
     607                            map { $_->get_attributes('memberOf') } 
     608                            @{$_[0]->{_objects}}; 
     609                        return sort keys %uniq; 
     610                    } else { 
     611                        return $_[0]->base->search_objects('group'); 
     612                    } 
    369613                } 
    370614            }, 
     
    385629                        delete($gr{$_}) foreach(@groups); 
    386630                    } else { 
    387                         print $OUT 'invalid action'; 
     631                        print $OUT 'invalid action' . "\n"; 
    388632                        return; 
    389633                    } 
    390634                    defined $obj->set_c_fields('memberUID' => [ keys %gr ]) or do { 
    391635                        print $OUT "cannot set memberUID attributes for " . 
    392                         $obj->id; 
     636                        $obj->id . "\n"; 
    393637                        return; 
    394638                    }; 
    395639                } 
    396                 $env->base->commit; 
     640                $env->commit; 
    397641            }, 
    398642            completion => sub { 
     
    400644                    return (qw(add remove)); 
    401645                } else { 
    402                     return $_[0]->base->search_objects('user'); 
     646                    if ($_[2] eq 'remove') { 
     647                        my %uniq = map { $_ => 1 } 
     648                            grep { $_ } 
     649                            map { $_->get_attributes('member') } 
     650                            @{$_[0]->{_objects}}; 
     651                        return sort keys %uniq; 
     652                    } else { 
     653                        return $_[0]->base->search_objects('user'); 
     654                    } 
    403655                } 
    404656            }, 
     
    413665    bless($env, $class); 
    414666    $env->{_labase} = $labase; 
     667 
     668    if ($labase->is_transactionnal) { 
     669        $env->add_func( 
     670            'transaction', { 
     671                help => 'change transaction mode', 
     672                code => sub { 
     673                    $trans_mode = $_[1] eq 'on' ? 1 : 0; 
     674                }, 
     675                completion => sub { 
     676                    $trans_mode == 0 ? 'on' : 'off'; 
     677                }, 
     678            } 
     679        ); 
     680        $env->add_func( 
     681            'commit', { 
     682                help => 'commit pending change', 
     683                code => sub { 
     684                    $_[0]->_commit; 
     685                }, 
     686            } 
     687        ); 
     688        $env->add_func( 
     689            'rollback', { 
     690                help => 'commit pending change', 
     691                code => sub { 
     692                    $_[0]->_rollback; 
     693                }, 
     694            } 
     695        ); 
     696    } 
    415697    $env->add_func('quit', { help => 'quit - exit the tool', 
    416698            code => sub { print "\n"; exit(0) }, }); 
     
    425707            my ($self, $name) = @_; 
    426708            if (!$name) { 
    427                 print $OUT join(', ', sort keys %{ $self->{funcs} || {}}); 
     709                print $OUT join(', ', sort keys %{ $self->{funcs} || {}}) . "\n"; 
    428710            } elsif ($self->{funcs}{$name}{alias}) { 
    429711                print $OUT "$name is an alias for " . join(' ', 
    430                     @{$self->{funcs}{$name}{alias}}); 
     712                    @{$self->{funcs}{$name}{alias}}) . "\n"; 
    431713            } elsif ($self->{funcs}{$name}{help}) { 
    432                 print $OUT $self->{funcs}{$name}{help}; 
     714                print $OUT $self->{funcs}{$name}{help} . "\n"; 
    433715            } else { 
    434                 print $OUT "No help availlable"; 
     716                print $OUT "No help availlable\n"; 
    435717            } 
    436718        }, 
     
    448730            $self->complete($_[0], shellwords(substr($_[1], 0, $_[2]))); 
    449731        }; 
    450         defined (my $line = $term->readline($self->prompt)) or return; 
     732        defined (my $line = $term->readline($self->prompt)) or do { 
     733            print $OUT "\n"; 
     734            return; 
     735        }; 
     736        $term->addhistory($line); 
    451737        my $res = $self->run(shellwords($line)); 
    452         $self->base->rollback; 
    453         if ($res && $res eq 'EXIT') { return } 
     738        $self->rollback if (!$trans_mode); 
     739        if ($res && $res eq 'EXIT') { print $OUT "\n"; return } 
    454740    } 
    455741} 
     
    469755} 
    470756 
     757sub getoption { 
     758    my ($self, $opt, @args) = @_; 
     759    local @ARGV = @args; 
     760    Getopt::Long::Configure("pass_through"); 
     761    GetOptions(%{ $opt }); 
     762 
     763    return @ARGV; 
     764} 
     765 
    471766sub parse_arg { 
    472767    my ($self, $name, @args) = @_; 
    473     if ($self->{funcs}{$name}{opt}) { 
    474         @ARGV = @args; 
    475     } else { 
    476         return @args; 
    477     } 
    478     return @ARGV; 
     768    return @args; 
    479769} 
    480770 
     
    497787    my ($self, $name, @args) = @_; 
    498788    return if (!$name); 
    499     if ($self->{funcs}{$name}{alias}) { 
     789    if (!exists($self->{funcs}{$name})) { 
     790        print $OUT "No command $name found\n"; 
     791    } elsif ($self->{funcs}{$name}{alias}) { 
    500792        $self->run(@{$self->{funcs}{$name}{alias}}, @args); 
    501793    } elsif ($self->{funcs}{$name}{code}) { 
    502794        my @pargs = $self->parse_arg($name, @args); 
    503795        $self->{funcs}{$name}{code}->($self, @args); 
     796    } else { 
     797        print $OUT "No command $name found\n"; 
    504798    } 
    505799} 
    506800 
     801sub commit { 
     802    my ($self) = @_; 
     803    if ($trans_mode) { 
     804    } else { 
     805        $self->_commit; 
     806    } 
     807} 
     808 
     809sub _commit { 
     810    my ($self) = @_; 
     811    $self->base->commit; 
     812} 
     813 
     814sub rollback { 
     815    my ($self) = @_; 
     816    if ($trans_mode) { 
     817        print $OUT "All pending changes get rollback\n"; 
     818    } 
     819    $self->_rollback; 
     820} 
     821 
     822sub _rollback { 
     823    my ($self) = @_; 
     824    $self->base->rollback; 
     825} 
     826 
    5078271; 
  • LATMOS-Accounts/lib/LATMOS/Accounts/Log.pm

    r476 r861  
    55use Sys::Syslog qw(:standard :macros); 
    66use Exporter (); 
     7use Mail::Sendmail; 
    78 
    89=head1 NAME 
     
    113114    console => LA_NOTICE, 
    114115    callback => undef, 
     116    mail => undef, 
    115117); 
     118 
     119my @maillog = (); 
    116120 
    117121=head1 FUNCTIONS 
     
    154158sub lastmessage { 
    155159    my ($level) = @_; 
    156     return $lastmessages{$level}; 
     160    return $lastmessages{$level || LA_ERROR}; 
    157161} 
    158162 
     
    186190        $log_method{callback}->($level, $msg, @args); 
    187191    } 
     192    if ($log_method{mail}) { 
     193        # store error to send it later, only ERROR 
     194        push(@maillog, sprintf($msg, @args)) if ($level <= LA_ERROR); 
     195    } 
    188196    1; 
    189197} 
    190      
     198 
     199sub _flush_mail { 
     200    @maillog = (); 
     201} 
     202 
     203sub _send_mail_log { 
     204    @maillog or return; 
     205    sendmail( 
     206        Subject => "LATMOS::Accounts error from $0", 
     207        To => $log_method{mail}, 
     208        From => 'LATMOS-Accounts@latmos.ipsl.fr', 
     209        Message => join("\n", @maillog), 
     210    ) or la_log(LA_ERR, "Cannot sent mail: " . $Mail::Sendmail::error); 
     211    _flush_mail(); 
     212} 
     213 
     214END { 
     215    _send_mail_log() if($log_method{mail}); 
     216} 
     217 
    1912181; 
  • LATMOS-Accounts/lib/LATMOS/Accounts/Maintenance.pm

    r850 r861  
    66use LATMOS::Accounts::Log; 
    77use FindBin qw($Bin); 
    8 use Crypt::RSA; 
    9 use Crypt::RSA::Key::Public::SSH; 
    10 use Crypt::RSA::Key::Private::SSH; 
    11 use MIME::Base64; 
    128 
    139sub _base { 
    1410    my ($self) = @_; 
     11    return $self->{_maintenance_base} if ($self->{_maintenance_base}); 
    1512    my $base = $self->SUPER::default_base; 
    1613    $base->type eq 'sql' or die "This module work only with SQL base type\n"; 
    17     $base 
     14    return $self->{_maintenance_base} = $base 
    1815} 
    1916 
    2017sub find_next_expire_users { 
    2118    # Do not replace this code by $base->find_next_expire_users 
    22     # it does not exctly the same thing 
     19    # it does not exactly the same thing 
    2320    my ($self, $expire) = @_; 
    2421    my $base = $self->_base; 
     
    184181} 
    185182 
     183sub expired_account_reminder { 
     184    my ($self, %options) = @_; 
     185    $options{delay} ||= '6 month'; 
     186 
     187    require Mail::Sendmail; 
     188    require Template; 
     189 
     190    my $template = Template->new( 
     191        INCLUDE_PATH => [ 
     192            ($self->val('_default_', 'templatespath') 
     193               ? $self->val('_default_', 'templatespath') . '/mail' 
     194               : ()), 
     195            "$FindBin::Bin/../templates" . '/mail', 
     196            '/usr/share/latmos-accounts/templates/mail', 
     197        ], 
     198        POST_CHOMP   => 1, 
     199        EXTENSION    => '.mail', 
     200    ); 
     201 
     202    my @users = $self->_base->find_expired_users($options{delay}); 
     203 
     204    my %managers; 
     205    foreach my $user (@users) { 
     206        my $uobj = $self->_base->get_object('user', $user); 
     207        $uobj->get_attributes('unexported') and next; # can't happend 
     208        my $manager = $uobj->get_attributes('managerContact') || 'N/A'; 
     209        push(@{$managers{$manager}{users}}, $uobj); 
     210    } 
     211 
     212    foreach (keys %managers) { 
     213        my $oman = $self->_base->get_object('user', $_) or next; # can't happend 
     214        $managers{$_}{manager} = $oman; 
     215        my $mail = $oman->get_attributes('mail') or next; 
     216         
     217        my %mail = ( 
     218            From => $self->val('_default_', 'mailFrom', 'nomail@localhost'), 
     219            Subject => 'LATMOS expired account', 
     220            smtp => $self->val('_default_', 'smtp'), 
     221            'Content-Type' => 'text/plain; charset=utf-8', 
     222            'X-LATMOS-Accounts' => '$Rev$', 
     223            'X-LATMOS-Reason' => 'Account expiration', 
     224        ); 
     225        $mail{to} = $options{to} || $mail; 
     226        my $message; 
     227        $template->process('account_expired_reminder.mail', $managers{$oman->id}, \$message) 
     228            or do { 
     229                la_log(LA_ERR, "Cannot send expiration mail: %s, exiting", 
     230                    $template->error()); 
     231                exit(1); 
     232            }; 
     233         
     234        if (!$options{test}) { 
     235            if (Mail::Sendmail::sendmail( 
     236                    %mail, 
     237                    Message => $message, 
     238                )) { 
     239                la_log(LA_NOTICE, 
     240                    "Expired account reminder mail for %s sent to %s (cc: %s) for %s", 
     241                    $oman->id, 
     242                    $mail{to}, 
     243                    ($mail{cc} || ''), 
     244                    join(', ', map { $_->id } @{$managers{$oman->id}{users}}) 
     245                ); 
     246            } else { 
     247                la_log(LA_ERR, "Cannot send mail: %s", $Mail::Sendmail::error); 
     248            } 
     249        } 
     250    } 
     251    my @summary; 
     252    foreach my $manager (sort keys %managers) { 
     253        push(@summary, "\n" . ( 
     254            $managers{$manager}{manager} 
     255                ? $managers{$manager}{manager}->get_attributes('displayName') 
     256                : $manager) . "\n"); 
     257        foreach (@{$managers{$manager}{users}}) { 
     258            push(@summary, sprintf("  %s - %s (%s)\n", 
     259                $_->id, 
     260                $_->get_attributes('displayName'), 
     261                $_->get_attributes('expireText'), 
     262            )); 
     263        } 
     264    } 
     265 
     266    if (@summary) { 
     267        if ($options{test}) { 
     268            print join('', @summary); 
     269        } else { 
     270            if ($self->val('_default_', 'expire_summary_to')) { 
     271                my %mail = ( 
     272                    From => $self->val('_default_', 'mailFrom', 'nomail@localhost'), 
     273                    Subject => 'LATMOS expired account (to disable)', 
     274                    smtp => $self->val('_default_', 'smtp'), 
     275                    'Content-Type' => 'text/plain; charset=utf-8', 
     276                    'X-LATMOS-Accounts' => '$Rev$', 
     277                    'X-LATMOS-Reason' => 'Account expiration', 
     278                    To => $self->val('_default_', 'expire_summary_to'), 
     279                ); 
     280                if (Mail::Sendmail::sendmail( 
     281                        %mail, 
     282                        Message => join('', @summary), 
     283                    )) { 
     284                    la_log(LA_NOTICE, "Expiration summary mail sent to %s", 
     285                        $self->val('_default_', 'expire_summary_to'), 
     286                    ); 
     287                } else { 
     288                    la_log(LA_ERR, "Cannot send mail: %s", $Mail::Sendmail::error); 
     289                } 
     290            } 
     291        } 
     292    } 
     293} 
     294 
    186295sub generate_rsa_key { 
     296    # compat functions 
    187297    my ($self, $password) = @_; 
    188      
    189     my $rsa = new Crypt::RSA ES => 'PKCS1v15'; 
    190     my ($public, $private) = $rsa->keygen ( 
    191         Identity  => 'LATMOS-Accounts', 
    192         Size      => 768, 
    193         Password  => $password, 
    194         Verbosity => 0, 
    195         KF=>'SSH', 
    196     ) or die 
    197     $self->rsa->errstr(); # TODO avoid die 
    198     return ($public, $private); 
    199 } 
     298    $self->_base->generate_rsa_key($password); 
     299} 
     300 
    200301 
    201302sub store_rsa_key { 
     303    # compat functions 
    202304    my ($self, $public, $private) = @_; 
    203     my $base = $self->_base; 
    204     $base->set_global_value('rsa_private_key', 
    205         encode_base64($private->serialize)); 
    206     $base->set_global_value('rsa_public_key', 
    207         $public->serialize); 
    208     return; 
     305    $self->_base->store_rsa_key($public, $private); 
    209306} 
    210307 
    211308sub private_key { 
     309    # compat functions 
    212310    my ($self, $password) = @_; 
    213     my $base = $self->_base; 
    214     my $serialize = $base->get_global_value('rsa_private_key') or return; 
    215     my $privkey = Crypt::RSA::Key::Private::SSH->new; 
    216     $privkey->deserialize(String => [ decode_base64($serialize) ], 
    217         Passphrase => $password); 
    218     $privkey 
     311    $self->_base->private_key($password); 
    219312} 
    220313 
    221314sub get_rsa_password { 
     315    # compat functions 
    222316    my ($self) = @_; 
    223     my $base = $self->_base; 
    224     my $sth = $base->db->prepare(q{ 
    225         select "name", value from "user" join user_attributes_base 
    226         on "user".ikey = user_attributes_base.okey 
    227         where user_attributes_base.attr = 'encryptedPassword' 
    228     }); 
    229     $sth->execute; 
    230     my %users; 
    231     while (my $res = $sth->fetchrow_hashref) { 
    232         $users{$res->{name}} = $res->{value}; 
    233     } 
    234     %users 
     317    $self->_base->get_rsa_password; 
    235318} 
    236319 
  • LATMOS-Accounts/lib/LATMOS/Accounts/SynchAccess/base.pm

    r715 r861  
    2424    my ($class, $bases) = @_; 
    2525    bless { 
    26         bases => [ @{ $bases} ], 
     26        bases => [ @{ $bases } ], 
    2727    }, $class; 
    2828} 
  • LATMOS-Accounts/lib/LATMOS/Accounts/Synchro.pm

    r819 r861  
    124124    $self->load_dest and return; 
    125125    my %state = (); 
    126     $state{$self->from->label} = $self->from->wexported(0); 
     126    $state{$self->from->label} = $self->from->wexported( 
     127        $self->{options}{unexported} ? 1 : 0 
     128    ); 
    127129    foreach ($self->to) { 
    128130        $state{$_->label} = $_->wexported(1); 
     
    137139    la_log(LA_DEBUG, "Leaving synch mode"); 
    138140    $self->from->wexported($state{$self->from->label}); 
    139     foreach ($self->to) { 
    140         $_->commit; 
    141         $_->wexported($state{$_->label}); 
     141    foreach my $base (grep { $_ } $self->to) { 
     142        $base->commit; 
     143        $base->wexported($state{$base->label}); 
    142144    } 
    143145} 
     
    205207 
    206208    $self->lock or return; 
     209     
     210    if (!(my $res = $self->run_pre_synchro({}))) { 
     211        la_log(LA_ERR, "Pre synchro script failed, aborting"); 
     212        $self->unlock; 
     213        return; 
     214    } 
    207215 
    208216    my %state = $self->enter_synch_mode; 
     
    230238                            $self->from->label, $otype, $_, $destbase->label, $res, 
    231239                        ); 
     240                        if ($destbase->is_transactionnal) { 
     241                            $destbase->commit; 
     242                        } 
    232243                        $updated = 1; 
     244                    } else { 
     245                        if ($destbase->is_transactionnal) { 
     246                            $destbase->rollback; 
     247                        } 
    233248                    } 
    234249                } 
     
    241256        } 
    242257        foreach my $pass (1, 0) { 
    243             foreach my $otype ( 
    244                 sort { $a eq 'user' ? 1 : -1 } # user in last because gidNumber needed 
    245                 keys %objlist) { 
    246                 next if (!$pass && !$destbase->delayed_fields($otype)); 
     258            foreach my $otype ($destbase->ordered_objects) { 
     259                exists($objlist{$otype}) or next; 
    247260                foreach (@{$objlist{$otype} || []}) { 
    248261                    my $res = $destbase->sync_object_from($self->from, $otype, $_, 
     
    254267                                $destbase->label, $res, 
    255268                            ); 
     269                            if ($destbase->is_transactionnal) { 
     270                                $destbase->commit; 
     271                            } 
    256272                            $updated = 1; 
    257273                        } 
     
    262278                        ); 
    263279                        $desterror{$destbase->label} = 1; 
     280                        if ($destbase->is_transactionnal) { 
     281                            $destbase->rollback; 
     282                        } 
    264283                    } 
    265284 
     
    272291    my $res = $self->run_post_synchro( 
    273292        { 
    274             UPDATED => $updated, 
     293            UPDATED => $updated || undef, 
    275294        } 
    276295    ); 
     
    313332} 
    314333 
     334sub run_pre_synchro { 
     335    my ($self, $env) = @_; 
     336 
     337    $env ||= {}; 
     338    $env->{HOOK_TYPE} = 'PRE'; 
     339 
     340    foreach my $base ($self->to) { 
     341        if ($base->options('presynchro')) { 
     342            la_log LA_DEBUG, "Executing base pre synchro `%s' for %s", 
     343                $base->options('presynchro'), $base->label; 
     344            exec_command( 
     345                $base->options('presynchro'), 
     346                { 
     347                    BASE => $base->label, 
     348                    BASETYPE => $base->type, 
     349                    %{ $env }, 
     350                } 
     351            ); 
     352        } 
     353    } 
     354 
     355    $self->{options}{pre} or return 1; 
     356 
     357    la_log(LA_DEBUG, "Running post synchro `%s'", $self->{options}{pre}); 
     358 
     359    exec_command($self->{options}{post}, $env); 
     360} 
     361 
    315362sub run_post_synchro { 
    316363    my ($self, $env) = @_; 
     364     
     365    $env ||= {}; 
     366    $env->{HOOK_TYPE} = 'PRE'; 
     367 
     368    foreach my $base ($self->to) { 
     369        if ($base->options('postsynchro')) { 
     370            la_log LA_DEBUG, "Executing base post synchro `%s' for %s", 
     371                $base->options('postsynchro'), $base->label; 
     372            exec_command( 
     373                $base->options('postsynchro'), 
     374                { 
     375                    BASE => $base->label, 
     376                    BASETYPE => $base->type, 
     377                    %{ $env }, 
     378                } 
     379            ); 
     380        } 
     381    } 
    317382 
    318383    $self->{options}{post} or return 1; 
    319384 
    320     la_log(LA_INFO, "Running post synchro `%s'", $self->{options}{post}); 
    321  
     385    la_log(LA_DEBUG, "Running post synchro `%s'", $self->{options}{post}); 
     386     
    322387    exec_command($self->{options}{post}, $env); 
    323388} 
  • LATMOS-Accounts/lib/LATMOS/Accounts/Utils.pm

    r818 r861  
    1212 
    1313@ISA = qw(Exporter); 
    14 @EXPORT = qw(to_ascii exec_command); 
    15 @EXPORT_OK = qw(to_ascii exec_command); 
     14@EXPORT = qw(to_ascii exec_command switch_user run_via_sudo); 
     15@EXPORT_OK = qw(to_ascii exec_command switch_user run_via_sudo); 
    1616 
    1717sub to_ascii { 
     
    2121    $text =~ s/œ/oe/g; 
    2222    $text =~ s/Ê/ae/g; 
    23     $text =~ tr {uàâÀÂÄÀçéÚêëÉÈÊËïîÏÎÞöÎÖÔÌûÛÜ} 
    24                 {uaaaAAAceeeeEEEEiiIIoooOOuuUU}; 
     23    $text =~ tr {uàâÀÂÄÀçéÚêëÉÈÊËïîÏÎÞöÎÖÔÌûÛÜć} 
     24                {uaaaAAAceeeeEEEEiiIIoooOOuuUUc}; 
    2525    $text =~ s/([^[:ascii:]])/_/g; 
    2626    $text 
     
    2929sub exec_command { 
    3030    my ($command, $env) = @_; 
     31    my $rout = undef; 
     32    $rout = \$_[2] if(@_ > 2); 
    3133 
    3234    my @exec = ref $command 
     
    3537    la_log(LA_DEBUG, 'running command `%s\'', join(' ', @exec)); 
    3638 
     39    pipe(my $rh, my $wh); 
    3740    my $pid = fork; 
    3841    if (!defined($pid)) { 
     
    4043    } elsif ($pid) { 
    4144        # Father 
     45        close($wh); 
     46        my $header; 
     47        while (<$rh>) { 
     48            if ($rout) { 
     49                $$rout .= $_; 
     50            } else { 
     51                chomp; 
     52                if (!$header) { 
     53                    $header = 1; 
     54                    la_log(LA_NOTICE, "exec `%s'", join(' ', @exec)); 
     55                } 
     56                la_log(LA_NOTICE, "output: %s", $_); 
     57            } 
     58        } 
    4259        waitpid($pid, 0); 
    4360        if (my $exitstatus = $?) { 
     
    5067    } else { 
    5168        # Child 
     69        close($rh); 
     70        ( $ENV{LA_MODULE} ) = caller(); 
    5271        foreach (keys %{ $env || {} }) { 
    5372            $ENV{"LA_$_"} = $env->{$_}; 
    5473        } 
     74        open(STDOUT, ">&=" . fileno($wh)); 
     75        open(STDERR, ">&=" . fileno($wh)); 
    5576        exec(@exec); 
    5677        exit($!); 
     
    7899            } 
    79100        } else { 
    80             $attributes{$attr} = $value || undef; 
    81             $attr eq 'exported' && !defined $attributes{$attr} and $attributes{$attr} = 1; 
     101            $attributes{$attr} = $value eq '' ? undef : $value; 
     102            # Don't remember why this is here 
     103            #$attr eq 'exported' && !defined $attributes{$attr} and $attributes{$attr} = 1; 
    82104        } 
    83105    } 
     
    129151        if ($name !~ /^[a-z]/); 
    130152    return "must contain only a-z,0-9" 
    131         if ($name !~ /^[a-z,0-9]+$/); 
     153        if ($name !~ /^[a-z,0-9,_,-]+$/); 
    132154 
    133155    return check_oid_validity($name); 
    134156} 
    135157 
     158sub switch_user { 
     159    my ($runas) = @_; 
     160 
     161    if ($< == 0 || $> == 0) { 
     162        my @info = getpwnam($runas) or do { 
     163            warn "Can find user $runas"; 
     164            return; 
     165        }; 
     166        $> = $info[3]; 
     167        return; 
     168    } else { 
     169        warn "we are not root"; 
     170    } 
     171} 
     172 
     173sub run_via_sudo { 
     174    my ($runas) = @_; 
     175 
     176    my @info = getpwnam($runas) or do { 
     177        warn "Can find user $runas"; 
     178        return; 
     179    };  
     180    if ($< != $info[3]) { 
     181        exec('sudo', '-u', $runas, $0, @ARGV) or "Can run $!"; 
     182    } 
     183} 
     184 
    1361851; 
  • LATMOS-Accounts/t/10_bases.t

    r679 r861  
    2020    [qw(username homeDirectory) ], 
    2121), "Can get canonicals fields"); 
    22 is( $dummyb->get_field_name('user', 'homeDirectory'), "home", "can call get_fields_name"); 
     22is( $dummyb->attribute('user', 'homeDirectory')->iname, "home", "can call get_fields_name"); 
    2323ok(!$dummyb->is_transactionnal, 'Dummy driver is not transactionnal'); 
    2424 
  • LATMOS-Accounts/t/11_bases_unix.t

    r715 r861  
    2727ok($unixb->load,   "Can load unix base"); 
    2828 
    29 is( $unixb->get_field_name('user', 'homeDirectory'), "home", "can call get_fields_name"); 
     29is( $unixb->attribute('user', 'homeDirectory')->iname, "home", "can call get_fields_name"); 
    3030 
    3131ok(my $user =  $unixb->get_object('user', 'root'),  "Can get root user"); 
  • LATMOS-Accounts/t/12_bases_sql.t

    r445 r861  
    11use strict; 
    22use warnings; 
    3 use Test::More tests => 10; 
     3use Test::More tests => 12; 
    44 
    55use_ok('LATMOS::Accounts::Bases'); 
     
    1313use_ok('LATMOS::Accounts::Bases::Sql::Address'); 
    1414use_ok('LATMOS::Accounts::Bases::Sql::Onlyaddress'); 
     15use_ok('LATMOS::Accounts::Bases::Sql::Accreq'); 
    1516 
     17use_ok('LATMOS::Accounts::Bases::Sql::OCHelper::Accreq'); 
  • LATMOS-Accounts/t/15_bases_mail.t

    r305 r861  
    2626ok($mailb->load,   "Can load mail base"); 
    2727 
    28 is( $mailb->get_field_name('aliases', 'forward'), "forward", "can call get_field_name"); 
     28is( $mailb->attribute('aliases', 'forward')->iname, "forward", "can call get_field_name"); 
    2929 
    3030ok(my $alias =  $mailb->get_object('aliases', 'name'),  "Can get root user"); 
  • LATMOS-Accounts/t/20_accounts.t

    r410 r861  
    88 
    99isa_ok( 
    10     my $accounts = LATMOS::Accounts->new('testdata/config'), 
     10    my $accounts = LATMOS::Accounts->new('testdata/configdir'), 
    1111    'LATMOS::Accounts' 
    1212); 
  • LATMOS-Accounts/t/22_accounts_attributes.t

    r852 r861  
    88 
    99isa_ok( 
    10     my $accounts = LATMOS::Accounts->new('testdata/config'), 
     10    my $accounts = LATMOS::Accounts->new('testdata/configdir'), 
    1111    'LATMOS::Accounts' 
    1212); 
     
    1414ok(my $base = $accounts->base('unix'), "Can get base"); 
    1515 
    16 my $attr = LATMOS::Accounts::Bases::Attributes->new('sn', $base, 'user'); 
     16my $attr = LATMOS::Accounts::Bases::Attributes->new('memberUID', $base, 'group'); 
  • LATMOS-Accounts/t/25_la_synchro.t

    r54 r861  
    2626} 
    2727 
    28 ok($config->WriteConfig("$workdir/config.ini"), "can write config file for test"); 
     28ok($config->WriteConfig("$workdir/latmos-accounts.ini"), "can write config file for test"); 
    2929 
    3030diag("Write test done in $workdir/"); 
    3131 
    3232isa_ok( 
    33     my $accounts = LATMOS::Accounts->new("$workdir/config.ini"), 
     33    my $accounts = LATMOS::Accounts->new($workdir), 
    3434    'LATMOS::Accounts' 
    3535); 
  • LATMOS-Accounts/t/26_la_synchaccess.t

    r56 r861  
    3030} 
    3131 
    32 ok($config->WriteConfig("$workdir/config.ini"), "can write config file for test"); 
     32ok($config->WriteConfig("$workdir/latmos-accounts.ini"), "can write config file for test"); 
    3333 
    3434diag("Write test done in $workdir/"); 
    3535 
    3636isa_ok( 
    37     my $accounts = LATMOS::Accounts->new("$workdir/config.ini"), 
     37    my $accounts = LATMOS::Accounts->new($workdir), 
    3838    'LATMOS::Accounts' 
    3939); 
  • LATMOS-Accounts/templates/mail/account_expire.mail

    r786 r861  
    55sauf erreur ou ommission de notre part votre compte [% obj.id %] expire 
    66dans [% delay %] jours ([% obj.get_c_field('expire') %]). 
    7 En aucun cas vos fichiers ne seront détruit  
     7En aucun cas vos fichiers ne seront détruits.  
    88 
    9 Si ce dernier devais être prolongé merci de dire à votre responsable 
     9Si ce dernier devait être prolongé, merci de dire à votre responsable 
    1010de contacter svp@latmos.ipsl.fr afin de nous donner la nouvelle date.  
    1111 
     
    2222 
    2323If it had to be extended, please ask your manager to contact 
    24 svp@latmos.ipsl.fr to give us with the new date of expiry. 
     24svp@latmos.ipsl.fr to give us the new date of expiry. 
    2525 
    2626Best regards. 
Note: See TracChangeset for help on using the changeset viewer.