Admin: Anlegen, Bearbeiten und Löschen von Usern im Admin-Controller
authorMoritz Bunkus <m.bunkus@linet-services.de>
Fri, 7 Jun 2013 09:14:42 +0000 (11:14 +0200)
committerMoritz Bunkus <m.bunkus@linet-services.de>
Thu, 13 Jun 2013 14:31:35 +0000 (16:31 +0200)
Dazu auch "ON DELETE CASCADE" für alle foreign keys in auth.*

Fixt #2279, #2280.

17 files changed:
SL/Controller/Admin.pm
SL/DB/AuthUser.pm
bin/mozilla/admin.pl
locale/de/all
sql/Pg-upgrade2-auth/foreign_key_constraints_on_delete.sql [new file with mode: 0644]
templates/webpages/admin/backup_dataset.html
templates/webpages/admin/backup_dataset_email_done.html
templates/webpages/admin/dbadmin.html
templates/webpages/admin/dbcreate.html
templates/webpages/admin/dbdelete.html
templates/webpages/admin/dbupgrade_all_done.html
templates/webpages/admin/delete_dataset.html
templates/webpages/admin/edit_user.html
templates/webpages/admin/list_users.html [deleted file]
templates/webpages/admin/restore_dataset_start_footer.html
templates/webpages/admin/show.html [new file with mode: 0644]
templates/webpages/admin/update_dataset.html

index 04d9c75..d6e753a 100644 (file)
@@ -10,10 +10,11 @@ use SL::DB::AuthUser;
 use SL::DB::AuthGroup;
 use SL::Helper::Flash;
 use SL::Locale::String qw(t8);
+use SL::User;
 
 use Rose::Object::MakeMethods::Generic
 (
-  'scalar --get_set_init' => [ qw(client user nologin_file_name db_cfg) ],
+  'scalar --get_set_init' => [ qw(client user nologin_file_name db_cfg all_dateformats all_numberformats all_countrycodes all_stylesheets all_menustyles all_clients all_groups) ],
 );
 
 __PACKAGE__->run_before(\&setup_layout);
@@ -25,7 +26,7 @@ sub keep_auth_vars {
 }
 
 #
-# actions
+# actions: login, logout
 #
 
 sub action_login {
@@ -35,7 +36,7 @@ sub action_login {
   return                   if !$self->authenticate_root;
   return                   if !$self->check_auth_db_and_tables;
   return                   if  $self->apply_dbupgrade_scripts;
-  $self->redirect_to(action => 'list_clients_and_users');
+  $self->redirect_to(action => 'show');
 }
 
 sub action_logout {
@@ -44,11 +45,15 @@ sub action_logout {
   $self->redirect_to(action => 'login');
 }
 
+#
+# actions: creating the authentication database & tables, applying database ugprades
+#
+
 sub action_apply_dbupgrade_scripts {
   my ($self) = @_;
 
   return if $self->apply_dbupgrade_scripts;
-  $self->action_list_clients_and_users;
+  $self->action_show;
 }
 
 sub action_create_auth_db {
@@ -81,23 +86,94 @@ sub action_create_auth_tables {
   }
 }
 
-sub action_list_clients_and_users {
+#
+# actions: users
+#
+
+sub action_show {
   my ($self) = @_;
 
   $self->render(
-    "admin/list_users",
+    "admin/show",
     CLIENTS => SL::DB::Manager::AuthClient->get_all_sorted,
     USERS   => SL::DB::Manager::AuthUser->get_all_sorted,
     LOCKED  => (-e $self->nologin_file_name),
-    title   => "kivitendo " . $::locale->text('Administration'),
+    title   => "kivitendo " . t8('Administration'),
   );
 }
 
+sub action_new_user {
+  my ($self) = @_;
+
+  $self->user(SL::DB::AuthUser->new(
+    config_values => {
+      vclimit      => 200,
+      countrycode  => "de",
+      numberformat => "1.000,00",
+      dateformat   => "dd.mm.yy",
+      stylesheet   => "kivitendo.css",
+      menustyle    => "neu",
+    },
+  ));
+
+  $self->edit_user_form(title => t8('Create a new user'));
+}
+
+sub action_edit_user {
+  my ($self) = @_;
+  $self->edit_user_form(title => t8('Edit User'));
+}
+
+sub action_save_user {
+  my ($self) = @_;
+  my $params = delete($::form->{user})          || { };
+  my $props  = delete($params->{config_values}) || { };
+  my $is_new = !$params->{id};
+
+  $self->user($is_new ? SL::DB::AuthUser->new : SL::DB::AuthUser->new(id => $params->{id})->load)
+    ->assign_attributes(%{ $params })
+    ->config_values({ %{ $self->user->config_values }, %{ $props } });
+
+  my @errors = $self->user->validate;
+
+  if (@errors) {
+    flash('error', @errors);
+    $self->edit_user_form(title => $is_new ? t8('Create a new user') : t8('Edit User'));
+    return;
+  }
+
+  $self->user->save;
+
+  if ($::auth->can_change_password && $::form->{new_password}) {
+    $::auth->change_password($self->user->login, $::form->{new_password});
+  }
+
+  flash_later('info', $is_new ? t8('The user has been created.') : t8('The user has been saved.'));
+  $self->redirect_to(action => 'show');
+}
+
+sub action_delete_user {
+  my ($self) = @_;
+
+  if (!$self->user->delete) {
+    flash('error', t8('The user could not be deleted.'));
+    $self->edit_user_form(title => t8('Edit User'));
+    return;
+  }
+
+  flash_later('info', t8('The user has been deleted.'));
+  $self->redirect_to(action => 'show');
+}
+
+#
+# actions: locking, unlocking
+#
+
 sub action_unlock_system {
   my ($self) = @_;
   unlink $self->nologin_file_name;
   flash_later('info', t8('Lockfile removed!'));
-  $self->redirect_to(action => 'list_clients_and_users');
+  $self->redirect_to(action => 'show');
 }
 
 sub action_lock_system {
@@ -110,7 +186,7 @@ sub action_lock_system {
   } else {
     $fh->close;
     flash_later('info', t8('Lockfile created!'));
-    $self->redirect_to(action => 'list_clients_and_users');
+    $self->redirect_to(action => 'show');
   }
 }
 
@@ -118,10 +194,27 @@ sub action_lock_system {
 # initializers
 #
 
-sub init_db_cfg            { $::lx_office_conf{'authentication/database'}               }
-sub init_nologin_file_name { $::lx_office_conf{paths}->{userspath} . '/nologin';        }
-sub init_client            { SL::DB::AuthClient->new(id => $::form->{client_id})->load; }
-sub init_user              { SL::DB::AuthUser  ->new(id => $::form->{user_id}  )->load; }
+sub init_db_cfg            { $::lx_office_conf{'authentication/database'}                                            }
+sub init_nologin_file_name { $::lx_office_conf{paths}->{userspath} . '/nologin';                                     }
+sub init_client            { SL::DB::AuthClient->new(id => ($::form->{id} || ($::form->{client} || {})->{id}))->load }
+sub init_user              { SL::DB::AuthUser  ->new(id => ($::form->{id} || ($::form->{user}   || {})->{id}))->load }
+sub init_all_clients       { SL::DB::Manager::AuthClient->get_all_sorted                                             }
+sub init_all_groups        { SL::DB::Manager::AuthGroup->get_all_sorted                                              }
+sub init_all_dateformats   { [ qw(mm/dd/yy dd/mm/yy dd.mm.yy yyyy-mm-dd)      ]                                      }
+sub init_all_numberformats { [ qw(1,000.00 1000.00 1.000,00 1000,00)          ]                                      }
+sub init_all_stylesheets   { [ qw(lx-office-erp.css Mobile.css kivitendo.css) ]                                      }
+sub init_all_menustyles    {
+  return [
+    { id => 'old', title => $::locale->text('Old (on the side)') },
+    { id => 'v3',  title => $::locale->text('Top (CSS)') },
+    { id => 'neu', title => $::locale->text('Top (Javascript)') },
+  ];
+}
+
+sub init_all_countrycodes {
+  my %cc = User->country_codes;
+  return [ map { id => $_, title => $cc{$_} }, sort { $cc{$a} cmp $cc{$b} } keys %cc ];
+}
 
 #
 # filters
@@ -136,7 +229,7 @@ sub setup_layout {
 }
 
 #
-# helpers
+# displaying forms
 #
 
 sub login_form {
@@ -145,6 +238,17 @@ sub login_form {
   $self->render('admin/adminlogin', title => t8('kivitendo v#1 administration', $::form->{version}), %params);
 }
 
+sub edit_user_form {
+  my ($self, %params) = @_;
+
+  $::request->layout->use_javascript("${_}.js") for qw(jquery.selectboxes jquery.multiselect2side);
+  $self->render('admin/edit_user', %params);
+}
+
+#
+# helpers
+#
+
 sub check_auth_db_and_tables {
   my ($self) = @_;
 
index bd2670b..0b19421 100644 (file)
@@ -36,9 +36,8 @@ sub validate {
   my ($self) = @_;
 
   my @errors;
-  push @errors, $::locale->text('The login is missing.')          if !$self->login;
-  push @errors, $::locale->text('The login is not unique.')          if !SL::DB::Helper::Util::is_unique($self, 'login');
-  push @errors, "chunky bacon";
+  push @errors, $::locale->text('The login is missing.')    if !$self->login;
+  push @errors, $::locale->text('The login is not unique.') if !SL::DB::Helper::Util::is_unique($self, 'login');
 
   return @errors;
 }
@@ -46,7 +45,7 @@ sub validate {
 sub get_config_value {
   my ($self, $key) = @_;
 
-  my $cfg = first { $_->cfg_key eq $key } @{ $self->configs };
+  my $cfg = first { $_->cfg_key eq $key } @{ $self->configs || [] };
   return $cfg ? $cfg->cfg_value : undef;
 }
 
@@ -58,7 +57,7 @@ sub config_values {
     $self->configs([ map { SL::DB::AuthUserConfig->new(cfg_key => $_, cfg_value => $settings{$_}) } keys %settings ]);
   }
 
-  return { map { ($_->cfg_key => $_->cfg_value) } @{ $self->configs } };
+  return { map { ($_->cfg_key => $_->cfg_value) } @{ $self->configs || [] } };
 }
 
 1;
index 67c5969..45da2f9 100755 (executable)
@@ -77,15 +77,6 @@ our $form;
 our $locale;
 our $auth;
 
-my @valid_dateformats = qw(mm/dd/yy dd/mm/yy dd.mm.yy yyyy-mm-dd);
-my @valid_numberformats = ('1,000.00', '1000.00', '1.000,00', '1000,00');
-my @all_stylesheets = qw(lx-office-erp.css Mobile.css kivitendo.css);
-my @all_menustyles = (
-  { id => 'old', title => $::locale->text('Old (on the side)') },
-  { id => 'v3',  title => $::locale->text('Top (CSS)') },
-  { id => 'neu', title => $::locale->text('Top (Javascript)') },
-);
-
 sub run {
   $::lxdebug->enter_sub;
   my $session_result = shift;
@@ -131,241 +122,6 @@ sub adminlogin {
   print $form->parse_html_template('admin/adminlogin');
 }
 
-sub add_user {
-  $::form->{title}   = "kivitendo " . $::locale->text('Administration') . " / " . $::locale->text('Add User');
-
-  # User does not have a well behaved new constructor, so we'll just have to build one ourself
-  my $user     = bless {
-    "vclimit"      => 200,
-    "countrycode"  => "de",
-    "numberformat" => "1.000,00",
-    "dateformat"   => "dd.mm.yy",
-    "stylesheet"   => "kivitendo.css",
-    "menustyle"    => "neu",
-    dbport         => $::auth->{DB_config}->{port} || 5432,
-    dbuser         => $::auth->{DB_config}->{user} || 'lxoffice',
-    dbhost         => $::auth->{DB_config}->{host} || 'localhost',
-  }, 'User';
-
-  edit_user_form($user);
-}
-
-sub edit_user {
-  $::form->{title} = "kivitendo " . $::locale->text('Administration') . " / " . $::locale->text('Edit User');
-  $::form->{edit}  = 1;
-
-  # get user
-  my $user = User->new(id => $::form->{user}{id});
-
-  edit_user_form($user);
-}
-
-sub edit_user_form {
-  my ($user) = @_;
-
-  my %cc = $user->country_codes;
-  my @all_countrycodes = map { id => $_, title => $cc{$_} }, sort { $cc{$a} cmp $cc{$b} } keys %cc;
-  my ($all_dir, $all_master) = _search_templates();
-  my $groups = [];
-
-  if ($::form->{edit}) {
-    my $user_id    = $::auth->get_user_id($user->{login});
-    my $all_groups = $::auth->read_groups();
-
-    for my $group (values %{ $all_groups }) {
-      push @{ $groups }, $group if (grep { $user_id == $_ } @{ $group->{members} });
-    }
-
-    $groups = [ sort { lc $a->{name} cmp lc $b->{name} } @{ $groups } ];
-  }
-
-  $::form->header;
-  print $::form->parse_html_template("admin/edit_user", {
-    GROUPS               => $groups,
-    CAN_CHANGE_PASSWORD  => $::auth->can_change_password,
-    user                 => $user->data,
-    all_stylesheets      => \@all_stylesheets,
-    all_numberformats    => \@valid_numberformats,
-    all_dateformats      => \@valid_dateformats,
-    all_countrycodes     => \@all_countrycodes,
-    all_menustyles       => \@all_menustyles,
-    all_templates        => $all_dir,
-    all_master_templates => $all_master,
-  });
-}
-
-sub save_user {
-  my $form          = $main::form;
-  my $locale        = $main::locale;
-
-  my $user = $form->{user};
-
-  $user->{dbdriver} = 'Pg';
-
-  if (!$::form->{edit}) {
-    # no spaces allowed in login name
-    $user->{login} =~ s/\s//g;
-    $::form->show_generic_error($::locale->text('Login name missing!')) unless $user->{login};
-
-    # check for duplicates
-    my %members = $::auth->read_all_users;
-    if ($members{$user->{login}}) {
-      $::form->show_generic_error($locale->text('Another user with the login #1 does already exist.', $user->{login}), 'back_button' => 1);
-    }
-  }
-
-  # no spaces allowed in directories
-  ($::form->{newtemplates}) = split / /, $::form->{newtemplates};
-  $user->{templates} = $::form->{newtemplates} || $::form->{usetemplates} || $user->{login};
-
-  # is there a basedir
-  if (!-d $::lx_office_conf{paths}->{templates}) {
-    $::form->error(sprintf($::locale->text("The directory %s does not exist."), $::lx_office_conf{paths}->{templates}));
-  }
-
-  # add base directory to $form->{templates}
-  $user->{templates} =~ s|.*/||;
-  $user->{templates} =  $::lx_office_conf{paths}->{templates} . "/$user->{templates}";
-
-  my $myconfig = new User(id => $user->{id});
-
-  $::form->show_generic_error($::locale->text('Dataset missing!'))       unless $user->{dbname};
-  $::form->show_generic_error($::locale->text('Database User missing!')) unless $user->{dbuser};
-
-  foreach my $item (keys %{$user}) {
-    $myconfig->{$item} = $user->{$item};
-  }
-
-  $myconfig->save_member;
-
-  $user->{templates}       =~ s|.*/||;
-  $user->{templates}       =  $::lx_office_conf{paths}->{templates} . "/$user->{templates}";
-  $::form->{mastertemplates} =~ s|.*/||;
-
-  # create user template directory and copy master files
-  if (!-d "$user->{templates}") {
-    umask(002);
-
-    if (mkdir "$user->{templates}", oct("771")) {
-
-      umask(007);
-
-      # copy templates to the directory
-
-      my $oldcurrdir = getcwd();
-      if (!chdir("$::lx_office_conf{paths}->{templates}/print/$::form->{mastertemplates}")) {
-        $form->error("$ERRNO: chdir $::lx_office_conf{paths}->{templates}/print/$::form->{mastertemplates}");
-      }
-
-      my $newdir = File::Spec->catdir($oldcurrdir, $user->{templates});
-
-      find(
-        sub
-        {
-          next if ($_ eq ".");
-
-          if (-d $_) {
-            if (!mkdir (File::Spec->catdir($newdir, $File::Find::name))) {
-              chdir($oldcurrdir);
-              $form->error("$ERRNO: mkdir $File::Find::name");
-            }
-          } elsif (-l $_) {
-            if (!symlink (readlink($_),
-                          File::Spec->catfile($newdir, $File::Find::name))) {
-              chdir($oldcurrdir);
-              $form->error("$ERRNO: symlink $File::Find::name");
-            }
-          } elsif (-f $_) {
-            if (!copy($_, File::Spec->catfile($newdir, $File::Find::name))) {
-              chdir($oldcurrdir);
-              $form->error("$ERRNO: cp $File::Find::name");
-            }
-          }
-        }, "./");
-
-      chdir($oldcurrdir);
-
-    } else {
-      $form->error("$ERRNO: $user->{templates}");
-    }
-  }
-
-  # Add new user to his groups.
-  if (ref $form->{new_user_group_ids} eq 'ARRAY') {
-    my $all_groups = $main::auth->read_groups();
-    my %user       = $main::auth->read_user(login => $myconfig->{login});
-
-    foreach my $group_id (@{ $form->{new_user_group_ids} }) {
-      my $group = $all_groups->{$group_id};
-
-      next if !$group;
-
-      push @{ $group->{members} }, $user{id};
-      $main::auth->save_group($group);
-    }
-  }
-
-  if ($main::auth->can_change_password()
-      && defined $::form->{new_password}
-      && ($::form->{new_password} ne '********')) {
-    my $verifier = SL::Auth::PasswordPolicy->new;
-    my $result   = $verifier->verify($::form->{new_password}, 1);
-
-    if ($result != SL::Auth::PasswordPolicy->OK()) {
-      $form->error($::locale->text('The settings were saved, but the password was not changed.') . ' ' . join(' ', $verifier->errors($result)));
-    }
-
-    $main::auth->change_password($myconfig->{login}, $::form->{new_password});
-  }
-
-  $::form->redirect($::locale->text('User saved!'));
-}
-
-sub save_user_as_new {
-  my $form       = $main::form;
-
-  $form->{user}{login} = $::form->{new_user_login};
-  delete $form->{user}{id};
-  delete @{$form}{qw(id edit new_user_login)};
-
-  save_user();
-}
-
-sub delete_user {
-  my $form      = $main::form;
-  my $locale    = $main::locale;
-
-  my $user = $::form->{user} || {};
-
-  $::form->show_generic_error($::locale->text('Missing user id!')) unless $user->{id};
-
-  my $loaded_user = User->new(id => $user->{id});
-
-  my %members   = $main::auth->read_all_users();
-  my $templates = $members{$loaded_user->{login}}->{templates};
-
-  $main::auth->delete_user($loaded_user->{login});
-
-  if ($templates) {
-    my $templates_in_use = 0;
-
-    foreach my $login (keys %members) {
-      next if $loaded_user->{login} eq $login;
-      next if $members{$login}->{templates} ne $templates;
-      $templates_in_use = 1;
-      last;
-    }
-
-    if (!$templates_in_use && -d $templates) {
-      unlink <$templates/*>;
-      rmdir $templates;
-    }
-  }
-
-  $form->redirect($locale->text('User deleted!'));
-
-}
-
 sub login_name {
   my $login = shift;
 
index 8400806..59ad0cb 100755 (executable)
@@ -75,6 +75,7 @@ $self->{texts} = {
   'Abort'                       => 'Abbrechen',
   'Abrechnungsnummer'           => 'Abrechnungsnummer',
   'Abteilung'                   => 'Abteilung',
+  'Access to clients'           => 'Zugriff auf Mandanten',
   'Account'                     => 'Konto',
   'Account Category A'          => 'Aktiva/Mittelverwendung',
   'Account Category C'          => 'Kosten',
@@ -116,6 +117,7 @@ $self->{texts} = {
   'Accounting Group saved!'     => 'Buchungsgruppe gespeichert!',
   'Accounting method'           => 'Versteuerungsart',
   'Accrual'                     => 'Soll-Versteuerung',
+  'Actions'                     => 'Aktionen',
   'Active'                      => 'Aktiv',
   'Active?'                     => 'Aktiviert?',
   'Add'                         => 'Erfassen',
@@ -178,6 +180,7 @@ $self->{texts} = {
   'All Accounts'                => 'Alle Konten',
   'All Datasets up to date!'    => 'Alle Datenbanken sind auf aktuellem Stand.',
   'All changes in that file have been reverted.' => 'Alle &Auml;nderungen in dieser Datei wurden r&uuml;ckg&auml;ngig gemacht.',
+  'All clients'                 => 'Alle Mandanten',
   'All database upgrades have been applied.' => 'Alle Datenbankupdates wurden eingespielt.',
   'All general ledger entries'  => 'Alle Hauptbucheinträge',
   'All groups'                  => 'Alle Gruppen',
@@ -200,7 +203,6 @@ $self->{texts} = {
   'An invalid character was used (valid characters: #1).' => 'Ein ungültiges Zeichen wurde benutzt (gültige Zeichen: #1).',
   'An upper-case character is required.' => 'Ein Großbuchstabe ist vorgeschrieben.',
   'Annotations'                 => 'Anmerkungen',
-  'Another user with the login #1 does already exist.' => 'Es existiert bereits ein anderer Benutzer mit diesem Login.',
   'Any stock contents containing a best before date will be impossible to stock out otherwise.' => 'Sonst können Artikel, bei denen ein Mindesthaltbarkeitsdatum gesetzt ist, nicht mehr ausgelagert werden.',
   'Ap aging on %s'              => 'Offene Verbindlichkeiten zum %s',
   'Application Error. No Format given' => 'Fehler in der Anwendung. Das Ausgabeformat fehlt.',
@@ -436,12 +438,12 @@ $self->{texts} = {
   'City'                        => 'Stadt',
   'Cleared Balance'             => 'abgeschlossen',
   'Clearing Tax Received (No 71)' => 'Verrechnung des Erstattungsbetrages erwünscht (Zeile 71)',
-  'Click on login name to edit!' => 'Zum Bearbeiten den Benutzernamen anklicken!',
   'Client #1'                   => 'Mandant #1',
   'Client Configuration'        => 'Mandantenkonfiguration',
   'Client Configuration saved!' => 'Mandantenkonfiguration gespeichert!',
   'Client list'                 => 'Mandantenliste',
   'Client name'                 => 'Mandantenname',
+  'Clients this user has access to' => 'Mandaten, auf die Benutzer Zugriff hat',
   'Close'                       => 'Übernehmen',
   'Close Books up to'           => 'Die Bücher abschließen bis zum',
   'Close Flash'                 => 'Schließen',
@@ -497,6 +499,7 @@ $self->{texts} = {
   'Create a new department'     => 'Eine neue Abteilung erfassen',
   'Create a new payment term'   => 'Neue Zahlungsbedingungen anlegen',
   'Create a new project'        => 'Neues Projekt anlegen',
+  'Create a new user'           => 'Einen neuen Benutzer anlegen',
   'Create and edit RFQs'        => 'Lieferantenanfragen erfassen und bearbeiten',
   'Create and edit dunnings'    => 'Mahnungen erfassen und bearbeiten',
   'Create and edit invoices and credit notes' => 'Rechnungen und Gutschriften erfassen und bearbeiten',
@@ -585,13 +588,11 @@ $self->{texts} = {
   'DUNNING STARTED'             => 'Mahnprozess gestartet',
   'DUNS-Nr'                     => 'DUNS-Nr.',
   'Data'                        => 'Daten',
-  'Database'                    => 'Datenbank',
   'Database Administration'     => 'Datenbankadministration',
   'Database Connection Test'    => 'Test der Datenbankverbindung',
   'Database Host'               => 'Datenbankcomputer',
   'Database ID'                 => 'Datenbank-ID',
   'Database User'               => 'Datenbankbenutzer',
-  'Database User missing!'      => 'Datenbankbenutzer fehlt!',
   'Database backups and restorations are disabled in the configuration.' => 'Datenbanksicherungen und -wiederherstellungen sind in der Konfiguration deaktiviert.',
   'Database name'               => 'Datenbankname',
   'Database settings'           => 'Datenbankeinstellungen',
@@ -995,6 +996,7 @@ $self->{texts} = {
   'Group saved!'                => 'Warengruppe gespeichert!',
   'Groups'                      => 'Warengruppen',
   'Groups that are valid for this client for access rights' => 'Gruppen, die für diesen Mandanten gültig sind',
+  'Groups this user is a member in' => 'Gruppen, in denen Benutzer Mitglied ist',
   'Groups valid for this client' => 'Für Mandanten gültige Gruppen',
   'HTML'                        => 'HTML',
   'HTML Templates'              => 'HTML-Vorlagen',
@@ -1208,7 +1210,6 @@ $self->{texts} = {
   'Lockfile removed!'           => 'System entsperrt!',
   'Login'                       => 'Anmelden',
   'Login Name'                  => 'Benutzer',
-  'Login name missing!'         => 'Benutzer - Feld darf nicht leer sein!',
   'Login of User'               => 'Login',
   'Logout'                      => 'Abmelden',
   'Logout now'                  => 'kivitendo jetzt verlassen',
@@ -1261,7 +1262,6 @@ $self->{texts} = {
   'Missing parameter #1 in call to sub #2.' => 'Fehlender Parameter \'#1\' in Funktionsaufruf \'#2\'.',
   'Missing parameter (at least one of #1) in call to sub #2.' => 'Fehlernder Parameter (mindestens einer aus \'#1\') in Funktionsaufruf \'#2\'.',
   'Missing taxkeys in invoices with taxes.' => 'Fehlende Steuerschl&uuml;ssel in Rechnungen mit Steuern',
-  'Missing user id!'            => 'Benutzer ID fehlt!',
   'Mitarbeiter'                 => 'Mitarbeiter',
   'Mixed (requires column "type")' => 'Gemischt (erfordert Spalte "type")',
   'Mobile'                      => 'Mobiltelefon',
@@ -1289,7 +1289,7 @@ $self->{texts} = {
   'Net amount'                  => 'Nettobetrag',
   'Netto Terms'                 => 'Zahlungsziel netto',
   'New Buchungsgruppe #1'       => 'Neue Buchungsgruppe #1',
-  'New Templates'               => 'Erzeuge Vorlagen, Name',
+  'New Password'                => 'Neues Passwort',
   'New assembly'                => 'Neues Erzeugnis',
   'New bank account'            => 'Neues Bankkonto',
   'New client #1: The database configuration fields "host", "port", "name" and "user" must not be empty.' => 'Neuer Mandant #1: Die Datenbankkonfigurationsfelder "Host", "Port" und "Name" dürfen nicht leer sein.',
@@ -1335,6 +1335,7 @@ $self->{texts} = {
   'No file has been uploaded yet.' => 'Es wurde noch keine Datei hochgeladen.',
   'No group has been selected, or the group does not exist anymore.' => 'Es wurde keine Gruppe ausgew&auml;hlt, oder die Gruppe wurde in der Zwischenzeit gel&ouml;scht.',
   'No groups have been added yet.' => 'Es wurden noch keine Gruppen angelegt.',
+  'No groups have been created yet.' => 'Es wurden noch keine Gruppen angelegt.',
   'No or an unknown authenticantion module specified in "config/kivitendo.conf".' => 'Es wurde kein oder ein unbekanntes Authentifizierungsmodul in "config/kivitendo.conf" angegeben.',
   'No part was found matching the search parameters.' => 'Es wurde kein Artikel gefunden, auf den die Suchparameter zutreffen.',
   'No payment term has been created yet.' => 'Es wurden noch keine Zahlungsbedingungen angelegt.',
@@ -1806,7 +1807,6 @@ $self->{texts} = {
   'Set eMail text'              => 'eMail Text eingeben',
   'Settings'                    => 'Einstellungen',
   'Setup Menu'                  => 'Menü-Variante',
-  'Setup Templates'             => 'Vorlagen auswählen',
   'Ship to'                     => 'Lieferadresse',
   'Ship via'                    => 'Transportmittel',
   'Shipping Address'            => 'Lieferadresse',
@@ -1975,7 +1975,6 @@ $self->{texts} = {
   'Templates'                   => 'Vorlagen',
   'Terms missing in row '       => '+Tage fehlen in Zeile ',
   'Test and preview'            => 'Test und Vorschau',
-  'Test connection'             => 'Verbindung testen',
   'Text field'                  => 'Textfeld',
   'Text field variables: \'WIDTH=w HEIGHT=h\' sets the width and height of the text field. They default to 30 and 5 respectively.' => 'Textfelder: \'WIDTH=w HEIGHT=h\' setzen die Breite und die H&ouml;he des Textfeldes. Wenn nicht anders angegeben, so werden sie 30 Zeichen breit und f&uuml;nf Zeichen hoch dargestellt.',
   'Text variables: \'MAXLENGTH=n\' sets the maximum entry length to \'n\'.' => 'Textzeilen: \'MAXLENGTH=n\' setzt eine Maximall&auml;nge von n Zeichen.',
@@ -2085,6 +2084,8 @@ $self->{texts} = {
   'The items are imported accoring do their number "X" regardless of the column order inside the file.' => 'Die Einträge werden in der Reihenfolge ihrer Indizes "X" unabhängig von der Spaltenreihenfolge in der Datei importiert.',
   'The link target to add has been created from the existing record.' => 'Das auszuwählende Verknüpfungsziel wurde aus dem bestehenden Beleg erstellt.',
   'The list has been printed.'  => 'Die Liste wurde ausgedruckt.',
+  'The login is missing.'       => 'Der Loginname fehlt.',
+  'The login is not unique.'    => 'Der Loginname ist nicht eindeutig.',
   'The long description is missing.' => 'Der Langtext fehlt.',
   'The name in row %d has already been used before.' => 'Der Name in Zeile %d wurde vorher bereits benutzt.',
   'The name is missing in row %d.' => 'Der Name fehlt in Zeile %d.',
@@ -2150,7 +2151,10 @@ $self->{texts} = {
   'The unit in row %d has been used in the meantime and cannot be changed anymore.' => 'Die Einheit in Zeile %d wurde in der Zwischenzeit benutzt und kann nicht mehr ge&auml;ndert werden.',
   'The units have been saved.'  => 'Die Einheiten wurden gespeichert.',
   'The user can chose which client to connect to during login.' => 'Bei der Anmeldung kann der Benutzer auswählen, welchen Mandanten er benutzen möchte.',
-  'The user is a member in the following group(s):' => 'Der Benutzer ist Mitglied in den folgenden Gruppen:',
+  'The user could not be deleted.' => '',
+  'The user has been created.'  => 'Der Benutzer wurde angelegt.',
+  'The user has been deleted.'  => '',
+  'The user has been saved.'    => 'Der Benutzer wurde gespeichert.',
   'The variable name must only consist of letters, numbers and underscores. It must begin with a letter. Example: send_christmas_present' => 'Der Variablenname darf nur aus Zeichen (keine Umlaute), Ziffern und Unterstrichen bestehen. Er muss mit einem Buchstaben beginnen. Beispiel: weihnachtsgruss_verschicken',
   'The warehouse could not be deleted because it has already been used.' => 'Das Lager konnte nicht gel&ouml;scht werden, da es bereits in Benutzung war.',
   'The warehouse does not contain any bins.' => 'Das Lager enth&auml;lt keine Lagerpl&auml;tze.',
@@ -2215,6 +2219,8 @@ $self->{texts} = {
   'This update will change the nature the onhand of goods is tracked.' => 'Dieses update &auml;ndert die Art und Weise wie Lagermengen gez&auml;lt werden.',
   'This upgrade script tries to map all existing parts in the database to the newly created Buchungsgruppen.' => 'Dieses Upgradescript versucht, bei allen bestehenden Artikeln neu erstellte Buchungsgruppen zuzuordnen.',
   'This upgrade script tries to map all existing units in the database to the newly created units.' => 'Dieses Update-Script versucht, alle bestehenden Einheiten automatisch in die neuen Einheiten umzuwandeln.',
+  'This user is a member in the following groups' => 'Dieser Benutzer ist Mitglied in den folgenden Gruppen',
+  'This user will have access to the following clients' => 'Dieser Benutzer wird Zugriff auf die folgenden Mandanten haben',
   'This vendor number is already in use.' => 'Diese Lieferantennummer wird bereits verwendet.',
   'Three Options:'              => 'Drei Optionen:',
   'Time period for the analysis:' => 'Analysezeitraum:',
@@ -2224,8 +2230,8 @@ $self->{texts} = {
   'To (email)'                  => 'An',
   'To (time)'                   => 'Bis',
   'To Date'                     => 'Bis',
-  'To add a user to a group edit a name, change the login name and save.  A new user with the same variables will then be saved under the new login name.' => 'Um einer Gruppe einen neuen Benutzer hinzuzufügen, ändern und speichern Sie am einfachsten einen bestehenden Benutzernamen. Unter dem neuen Namen wird dann ein Benutzer mit denselben Einstellungen angelegt.',
   'To continue please change the taxkey 0 to another value.' => 'Um fortzufahren, ändern Sie bitte den Steuerschlüssel 0 auf einen anderen Wert.',
+  'To user login'               => 'Zum Benutzerlogin',
   'Top'                         => 'Oben',
   'Top (CSS)'                   => 'Oben (mit CSS)',
   'Top (Javascript)'            => 'Oben (mit Javascript)',
@@ -2318,22 +2324,17 @@ $self->{texts} = {
   'Updating the client fields in the database "#1" on host "#2:#3" failed.' => 'Die Aktualisierung der Mandantenfelder in der Datenbank "#1" auf Host "#2:#3" schlug fehl.',
   'Uploaded on #1, size #2 kB'  => 'Am #1 hochgeladen, Größe #2 kB',
   'Use As New'                  => 'Als neu verwenden',
-  'Use Templates'               => 'Benutze Vorlagen',
   'Use master default bin for Default Transfer, if no default bin for the part is configured' => 'Standardlagerplatz für Ein- / Auslagern über Standard-Lagerplatz, falls für die Ware kein expliziter Lagerplatz konfiguriert ist',
   'User'                        => 'Benutzer',
   'User Config'                 => 'Einstellungen',
-  'User Login'                  => 'Als Benutzer anmelden',
   'User access'                 => 'Benutzerzugriff',
-  'User deleted!'               => 'Benutzer gelöscht!',
   'User list'                   => 'Benutzerliste',
   'User login'                  => 'Benutzeranmeldung',
   'User name'                   => 'Benutzername',
-  'User saved!'                 => 'Benutzer gespeichert!',
   'Username'                    => 'Benutzername',
   'Users in this group'         => 'BenutzerInnen in dieser Gruppe',
   'Users with access'           => 'Benutzer mit Zugriff',
   'Users with access to this client' => 'Benutzer mit Zugriff auf diesen Mandanten',
-  'Ust-IDNr'                    => 'USt-IdNr.',
   'VAT ID'                      => 'UStdID-Nr',
   'Valid'                       => 'Gültig',
   'Valid from'                  => 'Gültig ab',
diff --git a/sql/Pg-upgrade2-auth/foreign_key_constraints_on_delete.sql b/sql/Pg-upgrade2-auth/foreign_key_constraints_on_delete.sql
new file mode 100644 (file)
index 0000000..197bd8e
--- /dev/null
@@ -0,0 +1,40 @@
+-- @tag: foreign_key_constraints_on_delete
+-- @description: Ändert "FOREIGN KEY" constraints auf "ON DELETE CASCADE"
+-- @depends: clients
+-- @charset: utf-8
+
+-- auth.clients_groups
+ALTER TABLE auth.clients_groups DROP CONSTRAINT clients_groups_client_id_fkey;
+ALTER TABLE auth.clients_groups DROP CONSTRAINT clients_groups_group_id_fkey;
+
+ALTER TABLE auth.clients_groups ADD FOREIGN KEY (client_id) REFERENCES auth.clients (id) ON DELETE CASCADE;
+ALTER TABLE auth.clients_groups ADD FOREIGN KEY (group_id)  REFERENCES auth."group" (id) ON DELETE CASCADE;
+
+-- auth.clients_users
+ALTER TABLE auth.clients_users DROP CONSTRAINT clients_users_client_id_fkey;
+ALTER TABLE auth.clients_users DROP CONSTRAINT clients_users_user_id_fkey;
+
+ALTER TABLE auth.clients_users ADD FOREIGN KEY (client_id) REFERENCES auth.clients (id) ON DELETE CASCADE;
+ALTER TABLE auth.clients_users ADD FOREIGN KEY (user_id)   REFERENCES auth."user"  (id) ON DELETE CASCADE;
+
+-- auth.group_rights
+ALTER TABLE auth.group_rights DROP CONSTRAINT group_rights_group_id_fkey;
+
+ALTER TABLE auth.group_rights ADD FOREIGN KEY (group_id) REFERENCES auth."group" (id) ON DELETE CASCADE;
+
+ -- auth.session_content
+ALTER TABLE auth.session_content DROP CONSTRAINT session_content_session_id_fkey;
+
+ALTER TABLE auth.session_content ADD FOREIGN KEY (session_id) REFERENCES auth.session (id) ON DELETE CASCADE;
+
+ -- auth.user_config
+ALTER TABLE auth.user_config DROP CONSTRAINT user_config_user_id_fkey;
+
+ALTER TABLE auth.user_config ADD FOREIGN KEY (user_id) REFERENCES auth."user" (id) ON DELETE CASCADE;
+
+-- auth.user_group
+ALTER TABLE auth.user_group DROP CONSTRAINT user_group_user_id_fkey;
+ALTER TABLE auth.user_group DROP CONSTRAINT user_group_group_id_fkey;
+
+ALTER TABLE auth.user_group ADD FOREIGN KEY (user_id)  REFERENCES auth."user"  (id) ON DELETE CASCADE;
+ALTER TABLE auth.user_group ADD FOREIGN KEY (group_id) REFERENCES auth."group" (id) ON DELETE CASCADE;
index 4306460..3df1c89 100644 (file)
@@ -82,7 +82,7 @@
 
    </table>
 
-   <input name="callback" type="hidden" value="controller.pl?action=Admin/list_clients_and_users">
+   <input name="callback" type="hidden" value="controller.pl?action=Admin/show">
    <input type="hidden" name="nextsub" value="backup_dataset_start">
 
    <hr size="3" noshade>
@@ -90,7 +90,7 @@
    <br>
 
    <input type="submit" class="submit" name="action" value="[% 'Continue' | $T8 %]">
-   <a href="controller.pl?action=Admin/list_clients_and_users">[% 'Back' | $T8 %]</a>
+   <a href="controller.pl?action=Admin/show">[% 'Back' | $T8 %]</a>
 
   </form>
 
index a70a2ee..e64b2a8 100644 (file)
@@ -5,4 +5,4 @@
 
  <p>[% LxERP.t8('The dataset backup has been sent via email to #1.', to) | html %]</p>
 
- <p>[% L.link("controller.pl?action=Admin/list_clients_and_users", LxERP.t8("Continue")) %]
+ <p>[% L.link("controller.pl?action=Admin/show", LxERP.t8("Continue")) %]
index bccd514..014a115 100644 (file)
@@ -3,7 +3,7 @@
   <h1>[% title %]</h1>
 
   <form method="post" action="admin.pl">
-   <a href="controller.pl?action=Admin/list_clients_and_users">[% 'Back' | $T8 %]</a>
+   <a href="controller.pl?action=Admin/show">[% 'Back' | $T8 %]</a>
 
    <table>
     <tr>
@@ -48,7 +48,7 @@
        </tr>
       </table>
 
-      <input name="callback" type="hidden" value="controller.pl?action=Admin/list_clients_and_users">
+      <input name="callback" type="hidden" value="controller.pl?action=Admin/show">
 
       <br>
       <input type="submit" class="submit" name="action" value="[% 'Create Dataset' | $T8 %]">
index 67a19f7..814ca83 100644 (file)
@@ -5,4 +5,4 @@
 
   <p>[% LxERP.t8('The dataset #1 has been successfully created.', db) | html %]</p>
 
-  <p>[% L.link("controller.pl?action=Admin/list_clients_and_users", LxERP.t8("Continue")) %]</p>
+  <p>[% L.link("controller.pl?action=Admin/show", LxERP.t8("Continue")) %]</p>
index 65f3311..4821cbb 100644 (file)
@@ -5,4 +5,4 @@
 
   <p>[% LxERP.t8('The database #1 has been successfully deleted.', db) | html %]</p>
 
-  <p>[% L.link("controller.pl?action=Admin/list_clients_and_users", LxERP.t8("Continue")) %]</p>
+  <p>[% L.link("controller.pl?action=Admin/show", LxERP.t8("Continue")) %]</p>
index aa38297..3d99179 100644 (file)
@@ -10,4 +10,4 @@
  <p>[% 'All database upgrades have been applied.' | $T8 %]</p>
 [% END %]
 
-<p>[% L.link("controller.pl?action=Admin/list_clients_and_users", LxERP.t8("Continue")) %]</p>
+<p>[% L.link("controller.pl?action=Admin/show", LxERP.t8("Continue")) %]</p>
index 8c99616..082a76f 100644 (file)
@@ -18,7 +18,7 @@
   <input type="hidden" name="dbpasswd"  value="[% HTML.escape(dbpasswd) %]">
   <input type="hidden" name="dbdefault" value="[% HTML.escape(dbdefault) %]">
 
-  <input name="callback" type="hidden" value="controller.pl?action=Admin/list_clients_and_users">
+  <input name="callback" type="hidden" value="controller.pl?action=Admin/show">
 
 
   <input type="hidden" name="nextsub" value="dbdelete">
index 35dabd2..1fb9eff 100644 (file)
-[%- USE T8 %]
 [%- USE HTML %]
 [%- USE L %][%- USE LxERP -%]
- <script type="text/javascript">
-  <!--
-      function open_connection_test_window() {
-        // host name port user passwd
-        var url = "admin.pl?INPUT_ENCODING=UTF-8&action=test_db_connection&" +
-          "dbhost="   + encodeURIComponent(get_input_value("user.dbhost"))   + "&" +
-          "dbport="   + encodeURIComponent(get_input_value("user.dbport"))   + "&" +
-          "dbname="   + encodeURIComponent(get_input_value("user.dbname"))   + "&" +
-          "dbuser="   + encodeURIComponent(get_input_value("user.dbuser"))   + "&" +
-          "dbpasswd=" + encodeURIComponent(get_input_value("user.dbpasswd")) + "&";
-
-        var parm = centerParms(400,300) + ",width=400,height=300,status=yes,scrollbars=yes";
-
-        window.open(url, "_new_generic", parm);
-      }
-    -->
- </script>
-
- <h1>[% title %]</h1>
-
- <form name="Form" id="Form" method="post" action="admin.pl">
-  <p><a href="admin.pl?action=list_users">[% 'Back' | $T8 %]</a></p>
-
-  <table width="100%">
-   <tr valign="top">
-    <td>
-     <table>
-      <tr>
-       <th align="right">[% 'Login Name' | $T8 %]</th>
-       <td>
-        [%- IF edit %]
-         <input type="hidden" id='user.id' name="user.id" value="[% HTML.escape(user.id) %]">[% HTML.escape(user.login) %]
-        [%- ELSE %]
-         <input name="user.login" value="[% HTML.escape(user.login) %]">
-        [%- END %]
-       </td>
-      </tr>
-
-      <tr>
-       <th align="right">[% 'Password' | $T8 %]</th>
-       <td>[% IF CAN_CHANGE_PASSWORD %]<input type="password" name="new_password" size="8" value="********">[% ELSE %]********[% END %]</td>
-      </tr>
-
-      <tr>
-       <th align="right">[% 'Name' | $T8 %]</th>
-       <td><input name="user.name" size="15" value="[% HTML.escape(user.name) %]"></td>
-      </tr>
-
-      <tr>
-       <th align="right">[% 'E-mail' | $T8 %]</th>
-       <td><input name="user.email" size="30" value="[% HTML.escape(user.email) %]"></td>
-      </tr>
-
-      <tr valign="top">
-       <th align="right">[% 'Signature' | $T8 %]</th>
-       <td><textarea name="user.signature" rows="3" cols="35">[% HTML.escape(user.signature) %]</textarea></td>
-      </tr>
-
-      <tr>
-       <th align="right">[% 'Phone' | $T8 %]</th>
-       <td><input name="user.tel" size="14" value="[% HTML.escape(user.tel) %]"></td>
-      </tr>
-
-      <tr>
-       <th align="right">[% 'Fax' | $T8 %]</th>
-       <td><input name="user.fax" size="14" value="[% HTML.escape(user.fax) %]"></td>
-      </tr>
-
-      <tr>
-       <th align="right">[% 'Company' | $T8 %]</th>
-       <td><input name="user.company" size="35" value="[% HTML.escape(user.company) %]"></td>
-      </tr>
-
-      <tr valign="top">
-       <th align="right">[% 'Address' | $T8 %]</th>
-       <td><textarea name="user.address" rows="4" cols="35">[% HTML.escape(user.address) %]</textarea></td>
-      </tr>
-
-      <tr valign="top">
-       <th align="right">[% 'Tax number' | $T8 %]</th>
-       <td><input name="user.taxnumber" size="14" value="[% HTML.escape(user.taxnumber) %]"></td>
-      </tr>
-
-      <tr valign="top">
-       <th align="right">[% 'Ust-IDNr' | $T8 %]</th>
-       <td><input name="user.co_ustid" size="14" value="[% HTML.escape(user.co_ustid) %]"></td>
-      </tr>
-
-      <tr valign="top">
-       <th align="right">[% 'DUNS-Nr' | $T8 %]</th>
-       <td><input name="user.duns" size="14" value="[% HTML.escape(user.duns) %]"></td>
-      </tr>
-
-      <tr>
-       <th align="right">[% 'SEPA creditor ID' | $T8 %]</th>
-       <td><input name="user.sepa_creditor_id" size="35" maxlength="35" value="[% HTML.escape(user.sepa_creditor_id) %]"></td>
-      </tr>
-     </table>
-    </td>
-
-    <td>
-     <table>
-      <tr>
-       <th align="right">[% 'Date Format' | $T8 %]</th>
-       <td>[% L.select_tag('user.dateformat', all_dateformats, default = user.dateformat) %]</td>
-      </tr>
-
-      <tr>
-       <th align="right">[% 'Number Format' | $T8 %]</th>
-       <td>[% L.select_tag('user.numberformat', all_numberformats, default = user.numberformat) %]</td>
-      </tr>
-
-      <tr>
-       <th align="right">[% 'Dropdown Limit' | $T8 %]</th>
-       <td><input name="user.vclimit" value="[% HTML.escape(user.vclimit) %]"></td>
-      </tr>
-
-      <tr>
-       <th align="right">[% 'Language' | $T8 %]</th>
-       <td>[% L.select_tag('user.countrycode', all_countrycodes, title_key = 'title', default = user.countrycode) %]</td>
-      </tr>
-
-      <tr>
-       <th align="right">[% 'Stylesheet' | $T8 %]</th>
-       <td>[% L.select_tag('user.stylesheet', all_stylesheets, default = user.stylesheet) %]</td>
-      </tr>
-
-      <tr>
-       <th align="right">[% 'Printer' | $T8 %]</th>
-       <td><input name="user.printer" size="20" value="[% HTML.escape(user.printer) %]"></td>
-      </tr>
-      <tr>
-       <th align="right">[% 'Use Templates' | $T8 %]</th>
-       <td>[% L.select_tag('usetemplates', all_templates, default = user.templates) %]</td>
-      </tr>
-      <tr>
-       <th align="right">[% 'New Templates' | $T8 %]</th>
-       <td><input name="newtemplates"></td>
-      </tr>
-      <tr>
-       <th align="right">[% 'Setup Templates' | $T8 %]</th>
-       <td>[% L.select_tag('mastertemplates', all_master_templates, default = 'Standard') %]</td>
-      </tr>
-      <tr>
-       <th align="right">[% 'Setup Menu' | $T8 %]</th>
-       <td>[% L.select_tag('user.menustyle', all_menustyles, title_key = 'title', default = user.menustyle) %]</td>
-      </tr>
-      <tr>
-       <th align='right'>[% 'Mandatory Departments' | $T8 %]</th>
-       <td>
-        <input type='radio' name='user.mandatory_departments' value='0' [% IF !user.mandatory_departments %] checked[% END %]> [% 'No' | $T8 %]
-        <input type='radio' name='user.mandatory_departments' value='1' [% IF  user.mandatory_departments %] checked[% END %]> [% 'Yes' | $T8 %]
-       </td>
-      </tr>
-
-      <input type="hidden" name="user.templates" value="[% HTML.escape(user.templates) %]">
-     </table>
-    </td>
-   </tr>
-
-   <tr class="listheading">
-    <th colspan="2">[% 'Database' | $T8 %]</th>
-   </tr>
-
-   <tr>
-    <td colspan="2">
-     <table>
-      <tr>
-       <th align="right">[% 'Driver' | $T8 %]</th>
-       <td>PostgreSQL</td>
-       <th align="right">[% 'Host' | $T8 %]</th>
-       <td><input name="user.dbhost" size="30" value="[% HTML.escape(user.dbhost) %]"></td>
-      </tr>
-
-      <tr>
-       <th align="right">[% 'Dataset' | $T8 %]</th>
-       <td><input name="user.dbname" size="15" value="[% HTML.escape(user.dbname) %]"></td>
-       <th align="right">[% 'Port' | $T8 %]</th>
-       <td><input name="user.dbport" size="4" value="[% HTML.escape(user.dbport) %]"></td>
-      </tr>
-
-      <tr>
-       <th align="right">[% 'Database User' | $T8 %]</th>
-       <td><input name="user.dbuser" size="15" value="[% HTML.escape(user.dbuser) %]"></td>
-       <th align="right">[% 'Password' | $T8 %]</th>
-       <td><input name="user.dbpasswd" type="password" size="10" value="[% HTML.escape(user.dbpasswd) %]"></td>
-      </tr>
-
-      <tr>
-       <td colspan="2"><input type="button" class="submit" onclick="open_connection_test_window();" value="[% 'Test connection' | $T8 %]"></td>
-      </tr>
-     </table>
-    </td>
-   </tr>
-
-   [% IF edit %]
-   <tr><td colspan="2"><hr size="3" noshade></td></tr>
-
-   <tr class="listheading">
-    <th colspan="2">[% 'Group membership' | $T8 %]</th>
-   </tr>
-
-   <tr>
-    <td colspan="2">[% 'The user is a member in the following group(s):' | $T8 %]</td>
-   </tr>
-
-   <tr>
-    <td colspan="2">[% FOREACH row = GROUPS %]<a href="admin.pl?action=edit_group&group_id=[% HTML.url(row.id) %]">[% HTML.escape(row.name) %]</a>
-     [% UNLESS loop.last %] | [% END %][% END %]</td>
-   </tr>
-   [% END %]
-
-   <tr><td colspan="2"><hr size="3" noshade></td></tr>
-
-  </table>
-
-  <input name="callback" type="hidden" value="admin.pl?action=list_users">
-
-  <a href="admin.pl?action=list_users">[% 'Back' | $T8 %]</a>
-  <input type="hidden" name="action" value="dispatcher">
-  <input type="submit" class="submit" name="action_save_user" value="[% 'Save' | $T8 %]">
-
-  [% IF edit %]
-   [% FOREACH row = GROUPS %]
-    <input type="hidden" name="new_user_group_ids[]" value="[% HTML.escape(row.id) %]">
-   [% END %]
-   <input type="hidden" name="new_user_login" id="new_user_login" value="">
-   <input type="hidden" name="action_save_user_as_new" id="action_save_user_as_new" value="">
-   <input type="button" class="submit" id="save_as_new_button" value="[% 'Save as new' | $T8 %]">
-   [% L.submit_tag("action_delete_user", LxERP.t8('Delete'), confirm=LxERP.t8('Are you sure?')) %]
-   <input type="hidden" name="edit" value="1">
-  [% END %]
-
- </form>
-
- <script type="text/javascript">
-  <!--
-    $(document).ready(function() {
-      $("#save_as_new_button").click(function() {
-        var new_user_login = prompt('[% 'Please enter the login for the new user.' | $T8 %]', '');
-        if (!new_user_login || (new_user_login == ''))
-          return;
-
-        $("#action_save_user_as_new").val('1');
-        $("#new_user_login").val(new_user_login);
-        $("#user_id").val('');
-        $("#Form").submit();
-      });
-    });
-    -->
- </script>
+
+[%- INCLUDE 'common/flash.html' %]
+
+<h1>[% title %]</h1>
+
+<p>[% L.link(SELF.url_for(action="show"), LxERP.t8("Back")) %]</p>
+
+<form method="post" action="controller.pl" id="form">
+ [% L.hidden_tag("user.id", SELF.user.id) %]
+ [% L.hidden_tag("action", "") %]
+ [%- SET props=SELF.user.config_values %]
+
+ <h2>[%- LxERP.t8("Settings") %]</h2>
+
+ <table>
+  <tr valign="top">
+   <td>
+    <table>
+     <tr>
+      <th align="right">[% LxERP.t8('Login Name') %]</th>
+      <td>[% L.input_tag("user.login", SELF.user.login) %]</td>
+     </tr>
+
+     [%- IF AUTH.can_change_password %]
+     <tr>
+      <th align="right">[% LxERP.t8("New Password") %]</th>
+      <td>[% L.input_tag("new_password", "", type="password") %]</td>
+     </tr>
+     [%- END %]
+
+     <tr>
+      <th align="right">[% LxERP.t8("Name") %]</th>
+      <td>[% L.input_tag("user.config_values.name", props.name) %]</td>
+     </tr>
+
+     <tr>
+      <th align="right">[% LxERP.t8('E-mail') %]</th>
+      <td>[% L.input_tag("user.config_values.email", props.email) %]</td>
+     </tr>
+
+     <tr valign="top">
+      <th align="right">[% LxERP.t8('Signature') %]</th>
+      <td>[% L.textarea_tag("user.config_values.signature", props.signature, rows=3, cols=35) %]</td>
+     </tr>
+
+     <tr>
+      <th align="right">[% LxERP.t8('Phone') %]</th>
+      <td>[% L.input_tag("user.config_values.tel", props.tel) %]</td>
+     </tr>
+
+     <tr>
+      <th align="right">[% LxERP.t8('Fax') %]</th>
+      <td>[% L.input_tag("user.config_values.fax", props.fax) %]</td>
+     </tr>
+    </table>
+   </td>
+
+   <td>
+    <table>
+     <tr>
+      <th align="right">[% LxERP.t8("Date Format") %]</th>
+      <td>[% L.select_tag("user.config_values.dateformat", SELF.all_dateformats, default=props.dateformat) %]</td>
+     </tr>
+
+     <tr>
+      <th align="right">[% LxERP.t8("Number Format") %]</th>
+      <td>[% L.select_tag("user.config_values.numberformat", SELF.all_numberformats, default=props.numberformat) %]</td>
+     </tr>
+
+     <tr>
+      <th align="right">[% LxERP.t8("Dropdown Limit") %]</th>
+      <td>[% L.input_tag("user.config_values.vclimit", props.vclimit) %]</td>
+     </tr>
+
+     <tr>
+      <th align="right">[% LxERP.t8("Language") %]</th>
+      <td>[% L.select_tag("user.config_values.countrycode", SELF.all_countrycodes, title_key="title", default=props.countrycode) %]</td>
+     </tr>
+
+     <tr>
+      <th align="right">[% LxERP.t8("Stylesheet") %]</th>
+      <td>[% L.select_tag("user.config_values.stylesheet", SELF.all_stylesheets, default=props.stylesheet) %]</td>
+     </tr>
+
+     <tr>
+      <th align="right">[% LxERP.t8("Setup Menu") %]</th>
+      <td>[% L.select_tag("user.config_values.menustyle", SELF.all_menustyles, title_key="title", default=props.menustyle) %]</td>
+     </tr>
+
+     <tr>
+      <th align="right">[% LxERP.t8("Mandatory Departments") %]</th>
+      <td>
+       [% L.radio_button_tag('user.config_values.mandatory_departments', value='0', id='user.config_values.mandatory_departments_0', label=LxERP.t8('No'),  checked=!props.mandatory_departments) %]
+       [% L.radio_button_tag('user.config_values.mandatory_departments', value='1', id='user.config_values.mandatory_departments_1', label=LxERP.t8('Yes'), checked= props.mandatory_departments) %]
+      </td>
+     </tr>
+    </table>
+   </td>
+  </tr>
+ </table>
+
+ <h2>[%- LxERP.t8("Access to clients") %]</h2>
+
+[% IF SELF.all_clients.size %]
+ <p>
+  [%- LxERP.t8("This user will have access to the following clients") %]:
+ </p>
+
+ <div class="clearfix">
+  [% L.select_tag("user.clients[]", SELF.all_clients, id="user_clients", title_key="name", default=SELF.user.clients, default_key='id', multiple=1) %]
+  [% L.multiselect2side("user_clients", labelsx => LxERP.t8("All clients"), labeldx => LxERP.t8("Clients this user has access to")) %]
+ </div>
+
+[%- ELSE %]
+ <p>
+  [% LxERP.t8("No clients have been created yet.") %]
+ </p>
+[%- END %]
+
+ <h2>[%- LxERP.t8("Group membership") %]</h2>
+
+[% IF SELF.all_groups.size %]
+ <p>
+  [%- LxERP.t8("This user is a member in the following groups") %]:
+ </p>
+
+ <div class="clearfix">
+  [% L.select_tag("user.groups[]", SELF.all_groups, id="user_groups", title_key="name", default=SELF.user.groups, default_key='id', multiple=1) %]
+  [% L.multiselect2side("user_groups", labelsx => LxERP.t8("All groups"), labeldx => LxERP.t8("Groups this user is a member in")) %]
+ </div>
+
+[%- ELSE %]
+ <p>
+  [% LxERP.t8("No groups have been created yet.") %]
+ </p>
+[%- END %]
+
+<hr size="3" noshade>
+
+<p>
+ [% L.link(SELF.url_for(action="show"), LxERP.t8("Back")) %]
+
+ [% L.button_tag("submit_with_action('save_user')", LxERP.t8("Save")) %]
+ [% IF SELF.user.id %]
+  [% L.button_tag("save_as_new()", LxERP.t8("Save as new")) %]
+  [% L.button_tag("submit_with_action('delete_user')", LxERP.t8("Delete"), confirm=LxERP.t8("Are you sure?")) %]
+ [%- END %]
+</p>
+
+</form>
+
+<script type="text/javascript">
+ <!--
+  function submit_with_action(action) {
+    $("#action").val("Admin/" + action);
+    $("#form").submit();
+  }
+
+  function save_as_new() {
+    var new_user_login = prompt("[% LxERP.t8("Please enter the login for the new user.") %]", "");
+    if (!new_user_login)
+      return;
+
+    $("#user_login").val(new_user_login);
+    $("#user_id").val("");
+    submit_with_action("save_user");
+  }
+   -->
+</script>
diff --git a/templates/webpages/admin/list_users.html b/templates/webpages/admin/list_users.html
deleted file mode 100644 (file)
index 0d75e6b..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-[%- USE T8 %]
-[%- USE HTML %][%- USE LxERP -%][%- USE L -%]
- <h1>[% title %]</h1>
-
- <form method="post" action="admin.pl">
-
-  <div class="tabwidget">
-   <ul>
-    <li><a href="#client_list">[%- LxERP.t8("Client list") %]</a></li>
-    <li><a href="#user_list">[%- LxERP.t8("User list") %]</a></li>
-   </ul>
-
-   <div id="client_list">
-[%- IF !CLIENTS.size %]
-    <p>
-     [% LxERP.t8("No clients have been created yet.") %]
-     [% LxERP.t8("In order to use kivitendo you have to create at least one client, one user, and grant that user access to the client.") %]
-    </p>
-
-[%- ELSE %]
-    <table width="100%">
-     <tr>
-      <th class="listtop">[% 'Client name' | $T8 %]</th>
-      <th class="listtop">[% 'Database ID' | $T8 %]</th>
-      <th class="listtop">[% 'Database name' | $T8 %]</th>
-      <th class="listtop">[% 'Database Host' | $T8 %]</th>
-      <th class="listtop">[% 'Database User' | $T8 %]</th>
-     </tr>
-
- [%- FOREACH client = CLIENTS %]
-     <tr class="listrow">
-      <td><a href="admin.pl?action=edit_client&client.id=[% HTML.url(client.id) %]">[% HTML.escape(client.name) %]</a></td>
-      <td>[% HTML.escape(client.id) %]</td>
-      <td>[% HTML.escape(client.dbname) %]</td>
-      <td>[% HTML.escape(client.dbhost) %][% IF client.dbport %]:[%- HTML.escape(client.dbport) %][%- END %]</td>
-      <td>[% HTML.escape(client.dbuser) %]</td>
-     </tr>
- [%- END %]
-    </table>
-[%- END %]
-   </div>
-
-   <div id="user_list">
-[%- IF !USERS.size %]
-    <p>
-     [% LxERP.t8("No users have been created yet.") %]
-     [% LxERP.t8("In order to use kivitendo you have to create at least one client, one user, and grant that user access to the client.") %]
-    </p>
-
-[%- ELSE %]
-    <table width="100%">
-     <tr>
-      <th class="listtop">[% 'Login Name' | $T8 %]</th>
-      <th class="listtop">[% 'Name' | $T8 %]</th>
-      <th class="listtop">[% 'Language' | $T8 %]</th>
-     </tr>
-
- [% FOREACH user = USERS %]
-  [%- SET config = user.config_values %]
-     <tr class="listrow">
-      <td><a href="admin.pl?action=edit&user.id=[% HTML.url(user.id) %]">[% HTML.escape(user.login) %]</a></td>
-      <td>[% HTML.escape(config.name) %]</td>
-      <td>[% HTML.escape(config.countrycode) %]</td>
-     </tr>
- [% END %]
-    </table>
-[%- END %]
-   </div>
-  </div>
-
-  [% L.link(SELF.url_for(action="add_client"), LxERP.t8("Add Client")) %]
-  <span class="link_separator">|</span>
-  [% L.link(SELF.url_for(action="add_user"), LxERP.t8("Add User")) %]
-  <span class="link_separator">|</span>
-  [% L.link(SELF.url_for(action="edit_groups"), LxERP.t8("Edit groups")) %]
-  <span class="link_separator">|</span>
-  [% L.link(SELF.url_for(action="pg_database_administration", controller="admin.pl"), LxERP.t8("Pg Database Administration")) %]
-  <span class="link_separator">|</span>
-  [% L.link(SELF.url_for(action="printer_management", controller="admin.pl"), LxERP.t8("Printer Management")) %]
-  <span class="link_separator">|</span>
-  [% IF LOCKED %]
-   [% L.link(SELF.url_for(action="unlock_system"), LxERP.t8("Unlock System")) %]
-  [% ELSE %]
-   [% L.link(SELF.url_for(action="lock_system"), LxERP.t8("Lock System")) %]
-  [% END %]
-  <span class="link_separator">|</span>
-  [% L.link(SELF.url_for(action="logout"), LxERP.t8("Logout")) %]
-
-  <div style="background-color: #FFFFDA; font-size: 12px; padding: 0.5em; max-width: 720px; margin: 1em;">
-  <p>[% 'Click on login name to edit!' | $T8 %]</p>
-  <p>[% 'To add a user to a group edit a name, change the login name and save.  A new user with the same variables will then be saved under the new login name.' | $T8 %]</p>
-  </div>
- </form>
-
- <hr>
-
- <h2>[% 'User Login' | $T8 %]</h2>
-
- <form method="post" action="controller.pl">
-  <input type="hidden" name="action" value="LoginScreen/login">
-
-  <table border="0">
-   <tr>
-    <th align="right">[% 'Login Name' | $T8 %]</th>
-    <td><input class="login" name="{AUTH}login"></td>
-    <td>&nbsp;</td>
-   </tr>
-   <tr>
-    <th align="right">[% 'Password' | $T8 %]</th>
-    <td><input class="login" type="password" name="{AUTH}password"></td>
-    <td><input type="submit" value="[% 'Login' | $T8 %]"></td>
-   </tr>
-  </table>
-
- </form>
index fd414dc..86ca7ae 100644 (file)
@@ -10,5 +10,5 @@
  </p>
 
  <p>
-  [% L.link("controller.pl?action=Admin/list_clients_and_users", LxERP.t8("Continue")) %]
+  [% L.link("controller.pl?action=Admin/show", LxERP.t8("Continue")) %]
  </p>
diff --git a/templates/webpages/admin/show.html b/templates/webpages/admin/show.html
new file mode 100644 (file)
index 0000000..06d0e91
--- /dev/null
@@ -0,0 +1,95 @@
+[%- USE HTML %][%- USE LxERP -%][%- USE L -%]
+
+[% INCLUDE 'common/flash.html' %]
+
+<h1>[% title %]</h1>
+
+<div>
+ [% LxERP.t8("Actions") %]:
+ <span class="link_separator"></span>
+ [% L.link(SELF.url_for(action="new_client"), LxERP.t8("Add Client")) %]
+ <span class="link_separator">|</span>
+ [% L.link(SELF.url_for(action="new_user"), LxERP.t8("Add User")) %]
+ <span class="link_separator">|</span>
+ [% L.link(SELF.url_for(action="edit_groups"), LxERP.t8("Edit groups")) %]
+ <span class="link_separator">|</span>
+ [% L.link(SELF.url_for(action="pg_database_administration", controller="admin.pl"), LxERP.t8("Pg Database Administration")) %]
+ <span class="link_separator">|</span>
+ [% L.link(SELF.url_for(action="printer_management", controller="admin.pl"), LxERP.t8("Printer Management")) %]
+ <span class="link_separator">|</span>
+ [% IF LOCKED %]
+  [% L.link(SELF.url_for(action="unlock_system"), LxERP.t8("Unlock System")) %]
+ [% ELSE %]
+  [% L.link(SELF.url_for(action="lock_system"), LxERP.t8("Lock System")) %]
+ [% END %]
+ <span class="link_separator">|</span>
+ [% L.link(SELF.url_for(action="logout"), LxERP.t8("Logout")) %]
+ <span class="link_separator">|</span>
+ [% L.link(SELF.url_for(controller="LoginScreen", action="user_login"), LxERP.t8("To user login")) %]
+</div>
+
+<hr>
+
+<div class="tabwidget">
+ <ul>
+  <li><a href="#user_list">[%- LxERP.t8("User list") %]</a></li>
+  <li><a href="#client_list">[%- LxERP.t8("Client list") %]</a></li>
+ </ul>
+
+ <div id="user_list">
+[%- IF !USERS.size %]
+  <p>
+   [% LxERP.t8("No users have been created yet.") %]
+   [% LxERP.t8("In order to use kivitendo you have to create at least one client, one user, and grant that user access to the client.") %]
+  </p>
+
+[%- ELSE %]
+  <table width="100%">
+   <tr>
+    <th class="listtop">[% LxERP.t8('Login Name') %]</th>
+    <th class="listtop">[% LxERP.t8('Name') %]</th>
+    <th class="listtop">[% LxERP.t8('Language') %]</th>
+   </tr>
+
+[% FOREACH user = USERS %]
+[%- SET config = user.config_values %]
+   <tr class="listrow">
+    <td>[% L.link(SELF.url_for(action="edit_user", id=user.id), HTML.escape(user.login)) %]</td>
+    <td>[% HTML.escape(config.name) %]</td>
+    <td>[% HTML.escape(config.countrycode) %]</td>
+   </tr>
+[% END %]
+  </table>
+[%- END %]
+ </div>
+
+ <div id="client_list">
+[%- IF !CLIENTS.size %]
+  <p>
+   [% LxERP.t8("No clients have been created yet.") %]
+   [% LxERP.t8("In order to use kivitendo you have to create at least one client, one user, and grant that user access to the client.") %]
+  </p>
+
+[%- ELSE %]
+  <table width="100%">
+   <tr>
+    <th class="listtop">[% LxERP.t8('Client name') %]</th>
+    <th class="listtop">[% LxERP.t8('Database ID') %]</th>
+    <th class="listtop">[% LxERP.t8('Database name') %]</th>
+    <th class="listtop">[% LxERP.t8('Database Host') %]</th>
+    <th class="listtop">[% LxERP.t8('Database User') %]</th>
+   </tr>
+
+[%- FOREACH client = CLIENTS %]
+   <tr class="listrow">
+    <td>[% L.link(SELF.url_for(action="edit_client", client_id=client.id), HTML.escape(client.name)) %]</td>
+    <td>[% HTML.escape(client.id) %]</td>
+    <td>[% HTML.escape(client.dbname) %]</td>
+    <td>[% HTML.escape(client.dbhost) %][% IF client.dbport %]:[%- HTML.escape(client.dbport) %][%- END %]</td>
+    <td>[% HTML.escape(client.dbuser) %]</td>
+   </tr>
+[%- END %]
+  </table>
+[%- END %]
+ </div>
+</div>
index fddf5c3..29a5e62 100644 (file)
@@ -39,7 +39,7 @@
 
    <input type="hidden" name="rowcount" value="[% NEED_UPDATES.size %]">
 
-   <input name="callback" type="hidden" value="controller.pl?action=Admin/list_clients_and_users">
+   <input name="callback" type="hidden" value="controller.pl?action=Admin/show">
    <input type="hidden" name="nextsub" value="dbupdate">
 
    <hr size="3" noshade>