f3edde8e88588b33cdc700e2359672c0fa3c2cd1
[kivitendo-erp.git] / bin / mozilla / admin.pl
1 #=====================================================================
2 # LX-Office ERP
3 # Copyright (C) 2004
4 # Based on SQL-Ledger Version 2.1.9
5 # Web http://www.lx-office.org
6 #
7 #=====================================================================
8 # SQL-Ledger Accounting
9 # Copyright (c) 2002
10 #
11 #  Author: Dieter Simader
12 #   Email: dsimader@sql-ledger.org
13 #     Web: http://www.sql-ledger.org
14 #
15 #
16 # This program is free software; you can redistribute it and/or modify
17 # it under the terms of the GNU General Public License as published by
18 # the Free Software Foundation; either version 2 of the License, or
19 # (at your option) any later version.
20 #
21 # This program is distributed in the hope that it will be useful,
22 # but WITHOUT ANY WARRANTY; without even the implied warranty of
23 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24 # GNU General Public License for more details.
25 # You should have received a copy of the GNU General Public License
26 # along with this program; if not, write to the Free Software
27 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 #======================================================================
29 #
30 # setup module
31 # add/edit/delete users
32 #
33 #======================================================================
34
35 $menufile = "menu.ini";
36
37 use DBI;
38 use CGI;
39
40 use SL::Form;
41 use SL::User;
42 use SL::Common;
43 use SL::Inifile;
44 use SL::DBUpgrade2;
45
46 require "bin/mozilla/common.pl";
47
48 our $cgi = new CGI('');
49
50 $form = new Form;
51 $form->{"root"} = "root login";
52
53 $locale = new Locale $language, "admin";
54
55 # customization
56 if (-f "bin/mozilla/custom_$form->{script}") {
57   eval { require "bin/mozilla/custom_$form->{script}"; };
58   $form->error($@) if ($@);
59 }
60
61 $form->{stylesheet} = "lx-office-erp.css";
62 $form->{favicon}    = "favicon.ico";
63
64 if ($form->{action}) {
65
66
67   $subroutine = $locale->findsub($form->{action});
68
69   if ($subroutine eq 'login') {
70     if ($form->{rpw}) {
71       $form->{rpw} = crypt $form->{rpw}, "ro";
72     }
73   }
74
75   check_password();
76
77   call_sub($subroutine);
78
79 } else {
80
81   # if there are no drivers bail out
82   $form->error($locale->text('No Database Drivers available!'))
83     unless (User->dbdrivers);
84
85   # create memberfile
86   if (!-f $memberfile) {
87     open(FH, ">$memberfile") or $form->error("$memberfile : $!");
88     print FH qq|# SQL-Ledger Accounting members
89
90 [root login]
91 password=
92
93 |;
94     close FH;
95   }
96
97   adminlogin();
98
99 }
100
101 1;
102
103 # end
104
105 sub adminlogin {
106
107   $form->{title} =
108     qq|Lx-Office ERP $form->{version} | . $locale->text('Administration');
109
110   $form->header();
111   print $form->parse_html_template('admin/adminlogin');
112 }
113
114 sub login {
115   list_users();
116 }
117
118 sub list_users {
119
120   $form->error($locale->text('File locked!')) if (-f "${memberfile}.LCK");
121
122   open(FH, "$memberfile") or $form->error("$memberfile : $!");
123
124   my %members;
125
126   while (<FH>) {
127     chomp;
128
129     if (/^\[.*\]/) {
130       $login = $_;
131       $login =~ s/(\[|\])//g;
132
133       $members{$login} = { "login" => $login };
134     }
135
136     if (/^([a-z]+)=(.*)/) {
137       $members{$login}->{$1} = $2;
138     }
139   }
140
141   close(FH);
142
143   delete $members{"root login"};
144   map { $_->{templates} =~ s|.*/||; } values %members;
145
146   $form->{title}  = "Lx-Office ERP " . $locale->text('Administration');
147   $form->{LOCKED} = -e "$userspath/nologin";
148   $form->{MEMBERS} = [ @members{sort { lc $a cmp lc $b } keys %members} ];
149
150   $form->header();
151   print $form->parse_html_template("admin/list_users");
152 }
153
154 sub add_user {
155
156   $form->{title} =
157       "Lx-Office ERP "
158     . $locale->text('Administration') . " / "
159     . $locale->text('Add User');
160
161   my $myconfig = {
162     "vclimit"      => 200,
163     "countrycode"  => "de",
164     "numberformat" => "1000,00",
165     "dateformat"   => "dd.mm.yy",
166     "stylesheet"   => "lx-office-erp.css",
167     "menustyle"    => "v3",
168   };
169
170   edit_user_form($myconfig);
171 }
172
173 sub edit {
174
175   $form->{title} =
176       "Lx-Office ERP "
177     . $locale->text('Administration') . " / "
178     . $locale->text('Edit User');
179   $form->{edit} = 1;
180
181   $form->isblank("login", $locale->text("The login is missing."));
182
183   # get user
184   my $myconfig = new User "$memberfile", "$form->{login}";
185
186   $myconfig->{signature} =~ s/\\n/\r\n/g;
187   $myconfig->{address}   =~ s/\\n/\r\n/g;
188
189   # strip basedir from templates directory
190   $myconfig->{templates} =~ s|.*/||;
191
192   edit_user_form($myconfig);
193 }
194
195 sub edit_user_form {
196   my ($myconfig) = @_;
197
198   my @valid_dateformats = qw(mm-dd-yy mm/dd/yy dd-mm-yy dd/mm/yy dd.mm.yy yyyy-mm-dd);
199   $form->{ALL_DATEFORMATS} = [ map { { "format" => $_, "selected" => $_ eq $myconfig->{dateformat} } } @valid_dateformats ];
200
201   my @valid_numberformats = qw(1,000.00 1000.00 1.000,00 1000,00);
202   $form->{ALL_NUMBERFORMATS} = [ map { { "format" => $_, "selected" => $_ eq $myconfig->{numberformat} } } @valid_numberformats ];
203
204   %countrycodes = User->country_codes;
205   $form->{ALL_COUNTRYCODES} = [];
206   foreach $countrycode (sort { $countrycodes{$a} cmp $countrycodes{$b} } keys %countrycodes) {
207     push @{ $form->{ALL_COUNTRYCODES} }, { "value"    => $countrycode,
208                                            "name"     => $countrycodes{$countrycode},
209                                            "selected" => $countrycode eq $myconfig->{countrycode} };
210   }
211
212   # is there a templates basedir
213   if (!-d "$templates") {
214     $form->error(sprintf($locale->text("The directory %s does not exist."), $templates));
215   }
216
217   opendir TEMPLATEDIR, "$templates/." or $form->error("$templates : $!");
218   my @all     = readdir(TEMPLATEDIR);
219   my @alldir  = sort grep { -d "$templates/$_" && !/^\.\.?$/ } @all;
220   my @allhtml = sort grep { -f "$templates/$_" && /\.html$/ } @all;
221   closedir TEMPLATEDIR;
222
223   @alldir = grep !/\.(html|tex|sty|odt|xml|txb)$/, @alldir;
224   @alldir = grep !/^(webpages|\.svn)$/, @alldir;
225
226   @allhtml = reverse grep !/Default/, @allhtml;
227   push @allhtml, 'Default';
228   @allhtml = reverse @allhtml;
229
230   $form->{ALL_TEMPLATES} = [ map { { "name", => $_, "selected" => $_ eq $myconfig->{templates} } } @alldir ];
231
232   $lastitem = $allhtml[0];
233   $lastitem =~ s/-.*//g;
234   $form->{ALL_MASTER_TEMPLATES} = [ { "name" => $lastitem, "selected" => $lastitem eq "German" } ];
235   foreach $item (@allhtml) {
236     $item =~ s/-.*//g;
237     next if ($item eq $lastitem);
238
239     push @{ $form->{ALL_MASTER_TEMPLATES} }, { "name" => $item, "selected" => $item eq "German" };
240     $lastitem = $item;
241   }
242
243   # css dir has styles that are not intended as general layouts.
244   # reverting to hardcoded list
245   $form->{ALL_STYLESHEETS} = [ map { { "name" => $_, "selected" => $_ eq $myconfig->{stylesheet} } } qw(lx-office-erp.css Win2000.css) ];
246
247   $form->{"menustyle_" . $myconfig->{menustyle} } = 1;
248
249   map { $form->{"myc_${_}"} = $myconfig->{$_} } keys %{ $myconfig };
250
251   # access control
252   my @acsorder = ();
253   my %acs      = ();
254   my %excl     = ();
255   open(FH, $menufile) or $form->error("$menufile : $!");
256
257   while ($item = <FH>) {
258     next unless $item =~ /\[/;
259     next if $item =~ /\#/;
260
261     $item =~ s/(\[|\])//g;
262     chomp $item;
263
264     my ($level, $menuitem);
265
266     if ($item =~ /--/) {
267       ($level, $menuitem) = split /--/, $item, 2;
268     } else {
269       $level    = $item;
270       $menuitem = $item;
271       push @acsorder, $item;
272     }
273
274     $acs{$level} ||= [];
275     push @{ $acs{$level} }, $menuitem;
276
277   }
278
279   foreach $item (split(/;/, $myconfig->{acs})) {
280     ($key, $value) = split /--/, $item, 2;
281     $excl{$key}{$value} = 1;
282   }
283
284   $form->{ACLS}    = [];
285   $form->{all_acs} = "";
286
287   foreach $key (@acsorder) {
288     my $acl = { "checked" => $form->{login} ? !$excl{$key}->{$key} : 1,
289                 "name"    => "${key}--${key}",
290                 "title"   => $key,
291                 "SUBACLS" => [], };
292     $form->{all_acs} .= "${key}--${key};";
293
294     foreach $item (@{ $acs{$key} }) {
295       next if ($key eq $item);
296
297       my $subacl = { "checked" => $form->{login} ? !$excl{$key}->{$item} : 1,
298                      "name"    => "${key}--${item}",
299                      "title"   => $item };
300       push @{ $acl->{SUBACLS} }, $subacl;
301       $form->{all_acs} .= "${key}--${item};";
302     }
303     push @{ $form->{ACLS} }, $acl;
304   }
305
306   chop $form->{all_acs};
307
308   $form->header();
309   print $form->parse_html_template("admin/edit_user");
310 }
311
312 sub save {
313
314   $form->{dbdriver} = 'Pg';
315
316   # no spaces allowed in login name
317   ($form->{login}) = split / /, $form->{login};
318
319   $form->isblank("login", $locale->text('Login name missing!'));
320
321   # check for duplicates
322   if (!$form->{edit}) {
323     $temp = new User "$memberfile", "$form->{login}";
324
325     if ($temp->{login}) {
326       $form->error("$form->{login} " . $locale->text('is already a member!'));
327     }
328   }
329
330   # no spaces allowed in directories
331   ($form->{newtemplates}) = split / /, $form->{newtemplates};
332
333   if ($form->{newtemplates}) {
334     $form->{templates} = $form->{newtemplates};
335   } else {
336     $form->{templates} =
337       ($form->{usetemplates}) ? $form->{usetemplates} : $form->{login};
338   }
339
340   # is there a basedir
341   if (!-d "$templates") {
342     $form->error(sprintf($locale->text("The directory %s does not exist."), $templates));
343   }
344
345   # add base directory to $form->{templates}
346   $form->{templates} =~ s|.*/||;
347   $form->{templates} =  "$templates/$form->{templates}";
348
349   $myconfig = new User "$memberfile", "$form->{login}";
350
351   # redo acs variable and delete all the acs codes
352   my @acs;
353   foreach $item (split m|;|, $form->{all_acs}) {
354     my $name =  "ACS_${item}";
355     $name    =~ s| |+|g;
356     push @acs, $item if !$form->{$name};
357     delete $form->{$name};
358   }
359   $form->{acs} = join ";", @acs;
360
361   $form->isblank("dbname", $locale->text('Dataset missing!'));
362   $form->isblank("dbuser", $locale->text('Database User missing!'));
363
364   foreach $item (keys %{$form}) {
365     $myconfig->{$item} = $form->{$item};
366   }
367
368   delete $myconfig->{stylesheet};
369   if ($form->{userstylesheet}) {
370     $myconfig->{stylesheet} = $form->{userstylesheet};
371   }
372
373   $myconfig->save_member($memberfile, $userspath);
374
375   if ($webdav) {
376     @webdavdirs =
377       qw(angebote bestellungen rechnungen anfragen lieferantenbestellungen einkaufsrechnungen);
378     foreach $directory (@webdavdirs) {
379       $file = "webdav/" . $directory . "/webdav-user";
380       if ($form->{$directory}) {
381         if (open(HTACCESS, "$file")) {
382           while (<HTACCESS>) {
383             ($login, $password) = split(/:/, $_);
384             if ($login ne $form->{login}) {
385               $newfile .= $_;
386             }
387           }
388           close(HTACCESS);
389         }
390         open(HTACCESS, "> $file") or die "cannot open $file $!\n";
391         $newfile .= $myconfig->{login} . ":" . $myconfig->{password} . "\n";
392         print(HTACCESS $newfile);
393         close(HTACCESS);
394       } else {
395         $form->{$directory} = 0;
396         if (open(HTACCESS, "$file")) {
397           while (<HTACCESS>) {
398             ($login, $password) = split(/:/, $_);
399             if ($login ne $form->{login}) {
400               $newfile .= $_;
401             }
402           }
403           close(HTACCESS);
404         }
405         open(HTACCESS, "> $file") or die "cannot open $file $!\n";
406         print(HTACCESS $newfile);
407         close(HTACCESS);
408       }
409     }
410   }
411
412   $form->{templates}       =~ s|.*/||;
413   $form->{templates}       =  "${templates}/$form->{templates}";
414   $form->{mastertemplates} =~ s|.*/||;
415
416   # create user template directory and copy master files
417   if (!-d "$form->{templates}") {
418     umask(002);
419
420     if (mkdir "$form->{templates}", oct("771")) {
421
422       umask(007);
423
424       # copy templates to the directory
425       opendir TEMPLATEDIR, "$templates/." or $form - error("$templates : $!");
426       @templates = grep /$form->{mastertemplates}.*?\.(html|tex|sty|xml|txb)$/,
427         readdir TEMPLATEDIR;
428       closedir TEMPLATEDIR;
429
430       foreach $file (@templates) {
431         open(TEMP, "$templates/$file")
432           or $form->error("$templates/$file : $!");
433
434         $file =~ s/$form->{mastertemplates}-//;
435         open(NEW, ">$form->{templates}/$file")
436           or $form->error("$form->{templates}/$file : $!");
437
438         while ($line = <TEMP>) {
439           print NEW $line;
440         }
441         close(TEMP);
442         close(NEW);
443       }
444     } else {
445       $form->error("$!: $form->{templates}");
446     }
447   }
448
449   $form->redirect($locale->text('User saved!'));
450
451 }
452
453 sub delete {
454   $form->error($locale->text('File locked!')) if (-f ${memberfile} . LCK);
455   open(FH, ">${memberfile}.LCK") or $form->error("${memberfile}.LCK : $!");
456   close(FH);
457
458   my $members = Inifile->new($memberfile);
459   my $templates = $members->{$form->{login}}->{templates};
460   delete $members->{$form->{login}};
461   $members->write();
462   unlink "${memberfile}.LCK";
463
464   if ($templates) {
465     my $templates_in_use = 0;
466     foreach $login (keys %{ $members }) {
467       next if $login =~ m/^[A-Z]+$/;
468       next if $members->{$login}->{templates} ne $templates;
469       $templates_in_use = 1;
470       last;
471     }
472
473     if (!$templates_in_use && -d $templates) {
474       unlink <$templates/*>;
475       rmdir $templates;
476     }
477   }
478
479   # delete config file for user
480   unlink "$userspath/$form->{login}.conf";
481
482   $form->redirect($locale->text('User deleted!'));
483
484 }
485
486 sub login_name {
487   my $login = shift;
488
489   $login =~ s/\[\]//g;
490   return ($login) ? $login : undef;
491
492 }
493
494 sub get_value {
495   my $line = shift;
496
497   my ($null, $value) = split(/=/, $line, 2);
498
499   # remove comments
500   $value =~ s/\s#.*//g;
501
502   # remove any trailing whitespace
503   $value =~ s/^\s*(.*?)\s*$/$1/;
504
505   $value;
506 }
507
508 sub change_admin_password {
509
510   $form->{title} =
511       qq|Lx-Office ERP |
512     . $locale->text('Administration') . " / "
513     . $locale->text('Change Admin Password');
514
515   $form->header();
516   print $form->parse_html_template("admin/change_admin_password");
517 }
518
519 sub change_password {
520   if ($form->{"password"} ne $form->{"password_again"}) {
521     $form->{title} =
522       qq|Lx-Office ERP |
523       . $locale->text('Administration') . " / "
524       . $locale->text('Change Admin Password');
525
526     $form->header();
527     $form->error($locale->text("The passwords do not match."));
528   }
529
530   $root->{password} = $form->{password};
531
532   $root->{'root login'} = 1;
533   $root->save_member($memberfile);
534
535   $form->{callback} =
536     "$form->{script}?action=list_users&rpw=$root->{password}";
537
538   $form->redirect($locale->text('Password changed!'));
539 }
540
541 sub check_password {
542   $root = new User "$memberfile", $form->{root};
543
544   if (!defined($root->{password}) || ($root->{password} ne $form->{rpw})) {
545     $form->error($locale->text('Incorrect Password!'));
546   }
547
548 }
549
550 sub pg_database_administration {
551
552   $form->{dbdriver} = 'Pg';
553   dbselect_source();
554
555 }
556
557 sub dbselect_source {
558   $form->{dbport}    = '5432';
559   $form->{dbuser}    = 'postgres';
560   $form->{dbdefault} = 'template1';
561   $form->{dbhost}    = 'localhost';
562
563   $form->{title}     = "Lx-Office ERP / " . $locale->text('Database Administration');
564
565   $form->header();
566   print $form->parse_html_template("admin/dbadmin");
567 }
568
569 sub continue {
570   call_sub($form->{"nextsub"});
571 }
572
573 sub update_dataset {
574   $form->{title} =
575       "Lx-Office ERP "
576     . $locale->text('Database Administration') . " / "
577     . $locale->text('Update Dataset');
578
579   my @need_updates      = User->dbneedsupdate($form);
580   $form->{NEED_UPDATES} = \@need_updates;
581   $form->{ALL_UPDATED}  = !scalar @need_updates;
582
583   $form->header();
584   print $form->parse_html_template("admin/update_dataset");
585 }
586
587 sub dbupdate {
588   $form->{stylesheet} = "lx-office-erp.css";
589   $form->{title}      = $locale->text("Dataset upgrade");
590   $form->header();
591
592   my $rowcount           = $form->{rowcount} * 1;
593   my @update_rows        = grep { $form->{"update_$_"} } (1 .. $rowcount);
594   $form->{NOTHING_TO_DO} = !scalar @update_rows;
595   my $saved_form         = save_form();
596
597   $| = 1;
598
599   print $form->parse_html_template("admin/dbupgrade_all_header");
600
601   foreach my $i (@update_rows) {
602     restore_form($saved_form);
603
604     map { $form->{$_} = $form->{"${_}_${i}"} } qw(dbname dbdriver dbhost dbport dbuser dbpasswd);
605
606     my $controls = parse_dbupdate_controls($form, $form->{dbdriver});
607
608     print $form->parse_html_template("admin/dbupgrade_header");
609
610     $form->{dbupdate}        = $form->{dbname};
611     $form->{$form->{dbname}} = 1;
612
613     User->dbupdate($form);
614     User->dbupdate2($form, $controls);
615
616     print $form->parse_html_template("admin/dbupgrade_footer");
617   }
618
619   print $form->parse_html_template("admin/dbupgrade_all_done");
620 }
621
622 sub create_dataset {
623   $form->{dbsources} = join " ", map { "[${_}]" } sort User->dbsources(\%$form);
624
625   $form->{CHARTS} = [];
626
627   opendir SQLDIR, "sql/." or $form - error($!);
628   foreach $item (sort grep /-chart\.sql\z/, readdir SQLDIR) {
629     next if ($item eq 'Default-chart.sql');
630     $item =~ s/-chart\.sql//;
631     push @{ $form->{CHARTS} }, { "name"     => $item,
632                                  "selected" => $item eq "Germany-DATEV-SKR03EU" };
633   }
634   closedir SQLDIR;
635
636   my $default_charset = $dbcharset;
637   $default_charset ||= Common::DEFAULT_CHARSET;
638
639   $form->{DBENCODINGS} = [];
640
641   foreach my $encoding (@Common::db_encodings) {
642     push @{ $form->{DBENCODINGS} }, { "dbencoding" => $encoding->{dbencoding},
643                                       "label"      => $encoding->{label},
644                                       "selected"   => $encoding->{charset} eq $default_charset };
645   }
646
647   $form->{title} =
648       "Lx-Office ERP "
649     . $locale->text('Database Administration') . " / "
650     . $locale->text('Create Dataset');
651
652   $form->header();
653   print $form->parse_html_template("admin/create_dataset");
654 }
655
656 sub dbcreate {
657   $form->isblank("db", $locale->text('Dataset missing!'));
658
659   User->dbcreate(\%$form);
660
661   $form->{title} =
662       "Lx-Office ERP "
663     . $locale->text('Database Administration') . " / "
664     . $locale->text('Create Dataset');
665
666   $form->header();
667   print $form->parse_html_template("admin/dbcreate");
668 }
669
670 sub delete_dataset {
671   @dbsources = User->dbsources_unused(\%$form, $memberfile);
672   $form->error($locale->text('Nothing to delete!')) unless @dbsources;
673
674   $form->{title} =
675       "Lx-Office ERP "
676     . $locale->text('Database Administration') . " / "
677     . $locale->text('Delete Dataset');
678   $form->{DBSOURCES} = [ map { { "name", $_ } } sort @dbsources ];
679
680   $form->header();
681   print $form->parse_html_template("admin/delete_dataset");
682 }
683
684 sub dbdelete {
685
686   if (!$form->{db}) {
687     $form->error($locale->text('No Dataset selected!'));
688   }
689
690   User->dbdelete(\%$form);
691
692   $form->{title} =
693       "Lx-Office ERP "
694     . $locale->text('Database Administration') . " / "
695     . $locale->text('Delete Dataset');
696
697   $form->header();
698   print $form->parse_html_template("admin/dbdelete");
699 }
700
701 sub unlock_system {
702
703   unlink "$userspath/nologin";
704
705   $form->{callback} =
706     "$form->{script}?action=list_users&rpw=$root->{password}";
707
708   $form->redirect($locale->text('Lockfile removed!'));
709
710 }
711
712 sub lock_system {
713
714   open(FH, ">$userspath/nologin")
715     or $form->error($locale->text('Cannot create Lock!'));
716   close(FH);
717
718   $form->{callback} =
719     "$form->{script}?action=list_users&rpw=$root->{password}";
720
721   $form->redirect($locale->text('Lockfile created!'));
722
723 }