summaryrefslogtreecommitdiff
path: root/LedgerSMB/User.pm
blob: 89033ed11a61e6751bac7f6dd9cd1c118c1f2380 (plain)
  1. =head1 NAME
  2. LedgerSMB::User
  3. =head1 SYNOPSIS
  4. This module provides user support and database management functions.
  5. =head1 STATUS
  6. Deprecated
  7. =head1 COPYRIGHT
  8. #====================================================================
  9. # LedgerSMB
  10. # Small Medium Business Accounting software
  11. # http://www.ledgersmb.org/
  12. #
  13. # Copyright (C) 2006
  14. # This work contains copyrighted information from a number of sources
  15. # all used with permission.
  16. #
  17. # This file contains source code included with or based on SQL-Ledger
  18. # which is Copyright Dieter Simader and DWS Systems Inc. 2000-2005
  19. # and licensed under the GNU General Public License version 2 or, at
  20. # your option, any later version. For a full list including contact
  21. # information of contributors, maintainers, and copyright holders,
  22. # see the CONTRIBUTORS file.
  23. #
  24. # Original Copyright Notice from SQL-Ledger 2.6.17 (before the fork):
  25. # Copyright (C) 2000
  26. #
  27. # Author: DWS Systems Inc.
  28. # Web: http://www.sql-ledger.org
  29. #
  30. # Contributors: Jim Rawlings <jim@your-dba.com>
  31. #
  32. #====================================================================
  33. #
  34. # This file has undergone whitespace cleanup.
  35. #
  36. #====================================================================
  37. #
  38. # user related functions
  39. #
  40. #====================================================================
  41. =head1 METHODS
  42. =over
  43. =cut
  44. # inline documentation
  45. package LedgerSMB::User;
  46. use LedgerSMB::Sysconfig;
  47. use LedgerSMB::Session;
  48. use Data::Dumper;
  49. =item LedgerSMB::User->new($login);
  50. Create a LedgerSMB::User object. If the user $login exists, set the fields
  51. with values retrieved from the database.
  52. =cut
  53. sub new {
  54. my ( $type, $login ) = @_;
  55. my $self = {};
  56. if ( $login ne "" ) {
  57. # use central db
  58. my $dbh = ${LedgerSMB::Sysconfig::GLOBALDBH};
  59. # for now, this is querying the table directly... ugly
  60. my $fetchUserPrefs = $dbh->prepare(
  61. "SELECT acs, address, businessnumber,
  62. company, countrycode, currency,
  63. dateformat, dbdriver, dbhost, dbname,
  64. dboptions, dbpasswd, dbport, dbuser,
  65. email, fax, menuwidth, name, numberformat,
  66. password, print, printer, role, sid,
  67. signature, stylesheet, tel, templates,
  68. timeout, vclimit, u.username
  69. FROM users_conf as uc, users as u
  70. WHERE u.username = ?
  71. AND u.id = uc.id;"
  72. );
  73. $fetchUserPrefs->execute($login);
  74. my $userHashRef = $fetchUserPrefs->fetchrow_hashref;
  75. while ( my ( $key, $value ) = each( %{$userHashRef} ) ) {
  76. $self->{$key} = $value;
  77. }
  78. chomp( $self->{dbport} );
  79. chomp( $self->{dbname} );
  80. chomp( $self->{dbhost} );
  81. $self->{dbconnect} =
  82. 'dbi:Pg:dbname='
  83. . $self->{dbname}
  84. . ';host='
  85. . $self->{dbhost}
  86. . ';port='
  87. . $self->{dbport};
  88. if ( $self->{username} ) {
  89. $self->{login} = $login;
  90. }
  91. }
  92. bless $self, $type;
  93. }
  94. =item LedgerSMB::User->country_codes();
  95. Returns a hash where the keys are registered locales and the values are the
  96. textual representation of the locale name.
  97. =cut
  98. sub country_codes {
  99. use Locale::Country;
  100. use Locale::Language;
  101. my %cc = ();
  102. # scan the locale directory and read in the LANGUAGE files
  103. opendir DIR, "${LedgerSMB::Sysconfig::localepath}";
  104. my @dir = grep !/^\..*$/, readdir DIR;
  105. foreach my $dir (@dir) {
  106. $dir = substr( $dir, 0, -3 );
  107. $cc{$dir} = code2language( substr( $dir, 0, 2 ) );
  108. $cc{$dir} .= ( "/" . code2country( substr( $dir, 3, 2 ) ) )
  109. if length($dir) > 2;
  110. $cc{$dir} .= ( " " . substr( $dir, 6 ) ) if length($dir) > 5;
  111. }
  112. closedir(DIR);
  113. %cc;
  114. }
  115. =item LedgerSMB::User->fetch_config($login);
  116. Returns a reference to a hash that contains the user config for the user $login.
  117. If that user does not exist, output 'Access denied' if in CGI and die in all
  118. cases.
  119. =cut
  120. sub fetch_config {
  121. #I'm hoping that this function will go and is a temporary bridge
  122. #until we get rid of %myconfig elsewhere in the code
  123. my ( $self, $login ) = @_;
  124. if ( !$login ) {
  125. &error( $self, "Access Denied" );
  126. }
  127. # use central db
  128. my $dbh = ${LedgerSMB::Sysconfig::GLOBALDBH};
  129. # for now, this is querying the table directly... ugly
  130. # my $fetchUserPrefs = $dbh->prepare(
  131. # "SELECT acs, address, businessnumber,
  132. # company, countrycode, currency,
  133. # dateformat, dbdriver, dbhost, dbname,
  134. # dboptions, dbpasswd, dbport, dbuser,
  135. # email, fax, menuwidth, name, numberformat,
  136. # password, print, printer, role, sid,
  137. # signature, stylesheet, tel, templates,
  138. # timeout, vclimit, u.username
  139. # FROM users_conf as uc, users as u
  140. # WHERE u.username = ?
  141. # AND u.id = uc.id;"
  142. # );
  143. my $fetchUserSettings = $dbh->prepare("
  144. SELECT
  145. u.username,
  146. uc.dbname,
  147. uc.port,
  148. uc.host
  149. FROM users u
  150. JOIN user_connection uc ON uc.user_id = u.id
  151. WHERE u.username = ?
  152. ");
  153. $fetchUserSettings->execute($login);
  154. #$fetchUserPrefs->execute($login);
  155. my $userHashRef = $fetchUserSettings->fetchrow_hashref;
  156. if ( !$userHashRef ) {
  157. &error( $self, "Access Denied" );
  158. }
  159. while ( my ( $key, $value ) = each( %{$userHashRef} ) ) {
  160. $myconfig{$key} = $value;
  161. }
  162. chomp( $myconfig{'port'} );
  163. chomp( $myconfig{'dbname'} );
  164. chomp( $myconfig{'host'} );
  165. $myconfig{'login'} = $login;
  166. $myconfig{'dbconnect'} =
  167. 'dbi:Pg:dbname='
  168. . $myconfig{'dbname'}
  169. . ';host='
  170. . $myconfig{'host'}
  171. . ';port='
  172. . $myconfig{'port'};
  173. return \%myconfig;
  174. }
  175. =item $user->login($form);
  176. Disused auth function.
  177. =cut
  178. sub login {
  179. my ( $self, $form ) = @_;
  180. my $rc = -1;
  181. if ( $self->{login} ne "" ) {
  182. if (
  183. !Session::password_check(
  184. $form, $form->{login}, $form->{password}
  185. )
  186. )
  187. {
  188. return -1;
  189. }
  190. #this is really dumb, but %myconfig will have to stay until 1.3
  191. while ( my ( $key, $value ) = each( %{$self} ) ) {
  192. $myconfig{$key} = $value;
  193. }
  194. # check if database is down
  195. my $dbh =
  196. DBI->connect( $myconfig{dbconnect}, $myconfig{dbuser},
  197. $myconfig{dbpasswd} )
  198. or $self->error( __FILE__ . ':' . __LINE__ . ': ' . $DBI::errstr );
  199. $dbh->{pg_enable_utf8} = 1;
  200. # we got a connection, check the version
  201. my $query = qq|
  202. SELECT value FROM defaults
  203. WHERE setting_key = 'version'|;
  204. my $sth = $dbh->prepare($query);
  205. $sth->execute || $form->dberror( __FILE__ . ':' . __LINE__ . $query );
  206. my ($dbversion) = $sth->fetchrow_array;
  207. $sth->finish;
  208. # add login to employee table if it does not exist
  209. # no error check for employee table, ignore if it does not exist
  210. my $login = $self->{login};
  211. $login =~ s/@.*//;
  212. $query = qq|SELECT entity_id FROM employee WHERE login = ?|;
  213. $sth = $dbh->prepare($query);
  214. $sth->execute($login);
  215. my ($id) = $sth->fetchrow_array;
  216. $sth->finish;
  217. if ( !$id ) {
  218. my ($employeenumber) =
  219. $form->update_defaults( \%myconfig, "employeenumber", $dbh );
  220. $query = qq|
  221. INSERT INTO employee
  222. (login, employeenumber, name,
  223. workphone, role)
  224. VALUES (?, ?, ?, ?, ?)|;
  225. $sth = $dbh->prepare($query);
  226. $sth->execute(
  227. $login, $employeenumber, $myconfig{name},
  228. $myconfig{tel}, $myconfig{role}
  229. );
  230. }
  231. $dbh->disconnect;
  232. $rc = 0;
  233. if ( $form->{dbversion} ne $dbversion ) {
  234. $rc = -3;
  235. $dbupdate =
  236. ( calc_version($dbversion) < calc_version( $form->{dbversion} ) );
  237. }
  238. if ($dbupdate) {
  239. $rc = -4;
  240. # if DB2 bale out
  241. if ( $myconfig{dbdriver} eq 'DB2' ) {
  242. $rc = -2;
  243. }
  244. }
  245. }
  246. $rc;
  247. }
  248. =item LedgerSMB::User->check_recurring($form);
  249. Disused function to return the number of current recurring events.
  250. =cut
  251. sub check_recurring {
  252. my ( $self, $form ) = @_;
  253. my $dbh =
  254. DBI->connect( $self->{dbconnect}, $self->{dbuser}, $self->{dbpasswd} )
  255. or $form->dberror( __FILE__ . ':' . __LINE__ );
  256. $dbh->{pg_encode_utf8} = 1;
  257. my $query = qq|
  258. SELECT count(*) FROM recurring
  259. WHERE enddate >= current_date AND nextdate <= current_date|;
  260. ($_) = $dbh->selectrow_array($query);
  261. $dbh->disconnect;
  262. $_;
  263. }
  264. =item LedgerSMB::User::dbconnect_vars($form, $db);
  265. Converts individual $form values into $form->{dboptions} and $form->{dbconnect}.
  266. =cut
  267. sub dbconnect_vars {
  268. my ( $form, $db ) = @_;
  269. my %dboptions = (
  270. 'Pg' => {
  271. 'yy-mm-dd' => 'set DateStyle to \'ISO\'',
  272. 'mm/dd/yy' => 'set DateStyle to \'SQL, US\'',
  273. 'mm-dd-yy' => 'set DateStyle to \'POSTGRES, US\'',
  274. 'dd/mm/yy' => 'set DateStyle to \'SQL, EUROPEAN\'',
  275. 'dd-mm-yy' => 'set DateStyle to \'POSTGRES, EUROPEAN\'',
  276. 'dd.mm.yy' => 'set DateStyle to \'GERMAN\''
  277. }
  278. );
  279. $form->{dboptions} = $dboptions{ $form->{dbdriver} }{ $form->{dateformat} };
  280. $form->{dbconnect} = "dbi:$form->{dbdriver}:dbname=$db";
  281. $form->{dbconnect} .= ";host=$form->{dbhost}";
  282. $form->{dbconnect} .= ";port=$form->{dbport}";
  283. }
  284. =item LedgerSMB::User->dbdrivers();
  285. Returns a list of all drivers set up with DBI whose names end in 'Pg'.
  286. =cut
  287. sub dbdrivers {
  288. my @drivers = DBI->available_drivers();
  289. # return (grep { /(Pg|Oracle|DB2)/ } @drivers);
  290. return ( grep { /Pg$/ } @drivers );
  291. }
  292. =item LedgerSMB::User->dbsources($form);
  293. Returns a list of all databases in the same cluster as the database that $form
  294. is set to. If $form->{only_acc_db} is set, only non-template databases that
  295. have a defaults table owned by $form->{dbuser} are returned.
  296. =cut
  297. sub dbsources {
  298. my ( $self, $form ) = @_;
  299. my @dbsources = ();
  300. my ( $sth, $query );
  301. $form->{dbdefault} = $form->{dbuser} unless $form->{dbdefault};
  302. $form->{sid} = $form->{dbdefault};
  303. &dbconnect_vars( $form, $form->{dbdefault} );
  304. my $dbh =
  305. DBI->connect( $form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd} )
  306. or $form->dberror( __FILE__ . ':' . __LINE__ );
  307. $dbh->{pg_enable_utf8} = 1;
  308. if ( $form->{dbdriver} eq 'Pg' ) {
  309. $query = qq|SELECT datname FROM pg_database|;
  310. $sth = $dbh->prepare($query);
  311. $sth->execute || $form->dberror( __FILE__ . ':' . __LINE__ . $query );
  312. while ( my ($db) = $sth->fetchrow_array ) {
  313. if ( $form->{only_acc_db} ) {
  314. next if ( $db =~ /^template/ );
  315. &dbconnect_vars( $form, $db );
  316. my $dbh =
  317. DBI->connect( $form->{dbconnect}, $form->{dbuser},
  318. $form->{dbpasswd} )
  319. or $form->dberror( __FILE__ . ':' . __LINE__ );
  320. $dbh->{pg_enable_utf8} = 1;
  321. $query = qq|
  322. SELECT tablename FROM pg_tables
  323. WHERE tablename = 'defaults'
  324. AND tableowner = ?|;
  325. my $sth = $dbh->prepare($query);
  326. $sth->execute( $form->{dbuser} )
  327. || $form->dberror( __FILE__ . ':' . __LINE__ . $query );
  328. if ( $sth->fetchrow_array ) {
  329. push @dbsources, $db;
  330. }
  331. $sth->finish;
  332. $dbh->disconnect;
  333. next;
  334. }
  335. push @dbsources, $db;
  336. }
  337. }
  338. $sth->finish;
  339. $dbh->disconnect;
  340. return @dbsources;
  341. }
  342. =item LedgerSMB::User->dbcreate($form);
  343. Create the database indicated by $form->{db} and load Pg-database.sql, the chart
  344. indicated by $form->{chart} and custom tables and functions
  345. (Pg-custom_tables.sql and Pg-custom_functions).
  346. =cut
  347. sub dbcreate {
  348. my ( $self, $form ) = @_;
  349. my %dbcreate =
  350. ( 'Pg' => qq|CREATE DATABASE "$form->{db}" WITH ENCODING = 'UNICODE'| );
  351. $form->{sid} = $form->{dbdefault};
  352. &dbconnect_vars( $form, $form->{dbdefault} );
  353. # The below line connects to Template1 or another template file in order
  354. # to create the db. One must disconnect and reconnect later.
  355. if ( $form->{dbsuperuser} ) {
  356. my $superdbh =
  357. DBI->connect( $form->{dbconnect}, $form->{dbsuperuser},
  358. $form->{dbsuperpasswd} )
  359. or $form->dberror( __FILE__ . ':' . __LINE__ );
  360. $superdbh->{pg_enable_utf8} = 1;
  361. my $query = qq|$dbcreate{$form->{dbdriver}}|;
  362. $superdbh->do($query)
  363. || $form->dberror( __FILE__ . ':' . __LINE__ . $query );
  364. $superdbh->disconnect;
  365. }
  366. #Reassign for the work below
  367. &dbconnect_vars( $form, $form->{db} );
  368. my $dbh =
  369. DBI->connect( $form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd} )
  370. or $form->dberror( __FILE__ . ':' . __LINE__ );
  371. $dbh->{pg_enable_utf8} = 1;
  372. if ( $form->{dbsuperuser} ) {
  373. my $superdbh =
  374. DBI->connect( $form->{dbconnect}, $form->{dbsuperuser},
  375. $form->{dbsuperpasswd} )
  376. or $form->dberror( __FILE__ . ':' . __LINE__ );
  377. $superdbh->{pg_enable_utf8} = 1;
  378. # JD: We need to check for plpgsql,
  379. # if it isn't there create it, if we can't error
  380. # Good chance I will have to do this twice as I get
  381. # used to the way the code is structured
  382. my %langcreate = ( 'Pg' => qq|CREATE LANGUAGE plpgsql| );
  383. my $query = qq|$langcreate{$form->{dbdriver}}|;
  384. $superdbh->do($query);
  385. $superdbh->disconnect;
  386. }
  387. # create the tables
  388. my $dbdriver =
  389. ( $form->{dbdriver} =~ /Pg/ )
  390. ? 'Pg'
  391. : $form->{dbdriver};
  392. my $filename = qq|sql/Pg-database.sql|;
  393. $self->process_query( $form, $dbh, $filename );
  394. # load gifi
  395. ($filename) = split /_/, $form->{chart};
  396. $filename =~ s/_//;
  397. $self->process_query( $form, $dbh, "sql/${filename}-gifi.sql" );
  398. # load chart of accounts
  399. $filename = qq|sql/$form->{chart}-chart.sql|;
  400. $self->process_query( $form, $dbh, $filename );
  401. # create custom tables and functions
  402. my $item;
  403. foreach $item (qw(tables functions)) {
  404. $filename = "sql/${dbdriver}-custom_${item}.sql";
  405. if ( -f "$filename" ) {
  406. $self->process_query( $form, $dbh, $filename );
  407. }
  408. }
  409. $dbh->disconnect;
  410. }
  411. =item LedgerSMB::User->process_query($form, $dbh, $filename);
  412. Load the file $filename into the database indicated through form using psql.
  413. $dbh is ignored.
  414. =cut
  415. sub process_query {
  416. my ( $self, $form, $dbh, $filename ) = @_;
  417. return unless ( -f $filename );
  418. $ENV{PGPASSWORD} = $form->{dbpasswd};
  419. $ENV{PGUSER} = $form->{dbuser};
  420. $ENV{PGDATABASE} = $form->{db};
  421. $ENV{PGHOST} = $form->{dbhost};
  422. $ENV{PGPORT} = $form->{dbport};
  423. $results = `psql -f $filename 2>&1`;
  424. if ($?) {
  425. $form->error($!);
  426. }
  427. elsif ( $results =~ /error/i ) {
  428. $form->error($results);
  429. }
  430. }
  431. =item LedgerSMB::User->dbdelete($form);
  432. Disused function to drop the database $form->{db}.
  433. =cut
  434. sub dbdelete {
  435. my ( $self, $form ) = @_;
  436. $form->{sid} = $form->{dbdefault};
  437. &dbconnect_vars( $form, $form->{dbdefault} );
  438. my $dbh =
  439. DBI->connect( $form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd} )
  440. or $form->dberror( __FILE__ . ':' . __LINE__ );
  441. $dbh->{pg_enable_utf8} = 1;
  442. my $query = qq|DROP DATABASE "$form->{db}"|;
  443. $dbh->do($query) || $form->dberror( __FILE__ . ':' . __LINE__ . $query );
  444. $dbh->disconnect;
  445. }
  446. =item LedgerSMB::User->dbsources_unused($form, $memfile);
  447. Disused function to identify all databases in a cluster with a defaults table
  448. that are not mentioned in the memberfile $memfile.
  449. =cut
  450. sub dbsources_unused {
  451. my ( $self, $form, $memfile ) = @_;
  452. my @dbexcl = ();
  453. my @dbsources = ();
  454. $form->error( __FILE__ . ':' . __LINE__ . ": $memfile locked!" )
  455. if ( -f "${memfile}.LCK" );
  456. # open members file
  457. open( FH, '<', "$memfile" )
  458. or $form->error( __FILE__ . ':' . __LINE__ . ": $memfile : $!" );
  459. while (<FH>) {
  460. if (/^dbname=/) {
  461. my ( $null, $item ) = split /=/;
  462. push @dbexcl, $item;
  463. }
  464. }
  465. close FH;
  466. $form->{only_acc_db} = 1;
  467. my @db = &dbsources( "", $form );
  468. push @dbexcl, $form->{dbdefault};
  469. foreach $item (@db) {
  470. unless ( grep /$item$/, @dbexcl ) {
  471. push @dbsources, $item;
  472. }
  473. }
  474. return @dbsources;
  475. }
  476. =item LedgerSMB::User->dbneedsupdate($form);
  477. Disused function to locate all databases owned by $form->{dbuser} that are not
  478. a template* database which have a defaults table with a version entry.
  479. =cut
  480. sub dbneedsupdate {
  481. my ( $self, $form ) = @_;
  482. my %dbsources = ();
  483. my $query;
  484. $form->{sid} = $form->{dbdefault};
  485. &dbconnect_vars( $form, $form->{dbdefault} );
  486. my $dbh =
  487. DBI->connect( $form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd} )
  488. or $form->dberror( __FILE__ . ':' . __LINE__ );
  489. $dbh->{pg_enable_utf8} = 1;
  490. if ( $form->{dbdriver} =~ /Pg/ ) {
  491. $query = qq|
  492. SELECT d.datname
  493. FROM pg_database d, pg_user u
  494. WHERE d.datdba = u.usesysid
  495. AND u.usename = ?|;
  496. my $sth = $dbh->prepare($query);
  497. $sth->execute( $form->{dbuser} )
  498. || $form->dberror( __FILE__ . ':' . __LINE__ . $query );
  499. while ( my ($db) = $sth->fetchrow_array ) {
  500. next if ( $db =~ /^template/ );
  501. &dbconnect_vars( $form, $db );
  502. my $dbh =
  503. DBI->connect( $form->{dbconnect}, $form->{dbuser},
  504. $form->{dbpasswd} )
  505. or $form->dberror( __FILE__ . ':' . __LINE__ );
  506. $dbh->{pg_enable_utf8};
  507. $query = qq|
  508. SELECT tablename
  509. FROM pg_tables
  510. WHERE tablename = 'defaults'|;
  511. my $sth = $dbh->prepare($query);
  512. $sth->execute
  513. || $form->dberror( __FILE__ . ':' . __LINE__ . $query );
  514. if ( $sth->fetchrow_array ) {
  515. $query = qq|
  516. SELECT value FROM defaults
  517. WHERE setting_key = 'version'|;
  518. my $sth = $dbh->prepare($query);
  519. $sth->execute;
  520. if ( my ($version) = $sth->fetchrow_array ) {
  521. $dbsources{$db} = $version;
  522. }
  523. $sth->finish;
  524. }
  525. $sth->finish;
  526. $dbh->disconnect;
  527. }
  528. $sth->finish;
  529. }
  530. $dbh->disconnect;
  531. %dbsources;
  532. }
  533. =item LedgerSMB::User->dbupdate($form);
  534. Applies database upgrade scripts to upgrade the database to the current level.
  535. =cut
  536. sub dbupdate {
  537. my ( $self, $form ) = @_;
  538. $form->{sid} = $form->{dbdefault};
  539. my @upgradescripts = ();
  540. my $query;
  541. my $rc = -2;
  542. if ( $form->{dbupdate} ) {
  543. # read update scripts into memory
  544. opendir SQLDIR, "sql/."
  545. or $form->error( __FILE__ . ':' . __LINE__ . ': ' . $! );
  546. @upgradescripts =
  547. sort script_version grep /$form->{dbdriver}-upgrade-.*?\.sql$/,
  548. readdir SQLDIR;
  549. closedir SQLDIR;
  550. }
  551. foreach my $db ( split / /, $form->{dbupdate} ) {
  552. next unless $form->{$db};
  553. # strip db from dataset
  554. $db =~ s/^db//;
  555. &dbconnect_vars( $form, $db );
  556. my $dbh = DBI->connect(
  557. $form->{dbconnect}, $form->{dbuser},
  558. $form->{dbpasswd}, { AutoCommit => 0 }
  559. ) or $form->dberror( __FILE__ . ':' . __LINE__ );
  560. $dbh->{pg_enable_utf8} = 1;
  561. # check version
  562. $query = qq|
  563. SELECT value FROM defaults
  564. WHERE setting_key = 'version'|;
  565. my $sth = $dbh->prepare($query);
  566. # no error check, let it fall through
  567. $sth->execute;
  568. my $version = $sth->fetchrow_array;
  569. $sth->finish;
  570. next unless $version;
  571. $version = calc_version($version);
  572. my $dbversion = calc_version( $form->{dbversion} );
  573. foreach my $upgradescript (@upgradescripts) {
  574. my $a = $upgradescript;
  575. $a =~ s/(^$form->{dbdriver}-upgrade-|\.sql$)//g;
  576. my ( $mindb, $maxdb ) = split /-/, $a;
  577. $mindb = calc_version($mindb);
  578. $maxdb = calc_version($maxdb);
  579. next if ( $version >= $maxdb );
  580. # exit if there is no upgrade script or version == mindb
  581. last if ( $version < $mindb || $version >= $dbversion );
  582. # apply upgrade
  583. $self->process_query( $form, $dbh, "sql/$upgradescript" );
  584. $dbh->commit;
  585. $version = $maxdb;
  586. }
  587. $rc = 0;
  588. $dbh->disconnect;
  589. }
  590. $rc;
  591. }
  592. =item calc_version($version);
  593. Returns a numeric form for the version passed in. The numeric form is derived
  594. by converting each dotted portion of the version to a three-digit number and
  595. appending them.
  596. +----------+------------+
  597. | $version | returned |
  598. +----------+------------+
  599. | 1.0.0 | 1000000 |
  600. | 1.2.33 | 1002033 |
  601. | 189.2.33 | 189002033 |
  602. | 1.2.3.4 | 1002003004 |
  603. +----------+------------+
  604. =cut
  605. sub calc_version {
  606. my @v = split /\./, $_[0];
  607. my $version = 0;
  608. my $i;
  609. for ( $i = 0 ; $i <= $#v ; $i++ ) {
  610. $version *= 1000;
  611. $version += $v[$i];
  612. }
  613. return $version;
  614. }
  615. =item script_version
  616. Sorting function for database upgrade scripts.
  617. =cut
  618. sub script_version {
  619. my ( $my_a, $my_b ) = ( $a, $b );
  620. my ( $a_from, $a_to, $b_from, $b_to );
  621. my ( $res_a, $res_b, $i );
  622. $my_a =~ s/.*-upgrade-//;
  623. $my_a =~ s/.sql$//;
  624. $my_b =~ s/.*-upgrade-//;
  625. $my_b =~ s/.sql$//;
  626. ( $a_from, $a_to ) = split( /-/, $my_a );
  627. ( $b_from, $b_to ) = split( /-/, $my_b );
  628. $res_a = calc_version($a_from);
  629. $res_b = calc_version($b_from);
  630. if ( $res_a == $res_b ) {
  631. $res_a = calc_version($a_to);
  632. $res_b = calc_version($b_to);
  633. }
  634. return $res_a <=> $res_b;
  635. }
  636. =item $user->save_member();
  637. Updates the user config in the database for the user $user. If no config for
  638. the user exists, the user to the database.
  639. =cut
  640. sub save_member {
  641. my ($self) = @_;
  642. # replace \r\n with \n
  643. for (qw(address signature)) { $self->{$_} =~ s/\r?\n/\\n/g }
  644. # use central db
  645. my $dbh = ${LedgerSMB::Sysconfig::GLOBALDBH};
  646. #check to see if the user exists already
  647. my $userCheck = $dbh->prepare("SELECT id FROM users WHERE username = ?");
  648. $userCheck->execute( $self->{login} );
  649. my ($userID) = $userCheck->fetchrow_array;
  650. if ( !$self->{dbhost} ) {
  651. $self->{dbhost} = 'localhost';
  652. }
  653. if ( !$self->{dbport} ) {
  654. $self->{dbport} = '5432';
  655. }
  656. my $userConfExists = 0;
  657. if ($userID) {
  658. #got an id, check to see if it's in the users_conf table
  659. my $userConfCheck =
  660. $dbh->prepare("SELECT password, 1 FROM users_conf WHERE id = ?");
  661. $userConfCheck->execute($userID);
  662. ( $oldPassword, $userConfExists ) = $userConfCheck->fetchrow_array;
  663. }
  664. else {
  665. my $userConfAdd = $dbh->prepare("SELECT create_user(?);");
  666. $userConfAdd->execute( $self->{login} );
  667. ($userID) = $userConfAdd->fetchrow_array;
  668. }
  669. if ($userConfExists) {
  670. # for now, this is updating the table directly... ugly
  671. my $userConfUpdate = $dbh->prepare(
  672. "UPDATE users_conf
  673. SET acs = ?, address = ?, businessnumber = ?,
  674. company = ?, countrycode = ?, currency = ?,
  675. dateformat = ?, dbdriver = ?,
  676. dbhost = ?, dbname = ?, dboptions = ?,
  677. dbpasswd = ?, dbport = ?, dbuser = ?,
  678. email = ?, fax = ?, menuwidth = ?,
  679. name = ?, numberformat = ?,
  680. print = ?, printer = ?, role = ?,
  681. sid = ?, signature = ?, stylesheet = ?,
  682. tel = ?, templates = ?, timeout = ?,
  683. vclimit = ?
  684. WHERE id = ?;"
  685. );
  686. $userConfUpdate->execute(
  687. $self->{acs}, $self->{address},
  688. $self->{businessnumber}, $self->{company},
  689. $self->{countrycode}, $self->{currency},
  690. $self->{dateformat}, $self->{dbdriver},
  691. $self->{dbhost}, $self->{dbname},
  692. $self->{dboptions}, $self->{dbpasswd},
  693. $self->{dbport}, $self->{dbuser},
  694. $self->{email}, $self->{fax},
  695. $self->{menuwidth}, $self->{name},
  696. $self->{numberformat}, $self->{print},
  697. $self->{printer}, $self->{role},
  698. $self->{sid}, $self->{signature},
  699. $self->{stylesheet}, $self->{tel},
  700. $self->{templates}, $self->{timeout},
  701. $self->{vclimit}, $userID
  702. );
  703. if ( $oldPassword ne $self->{password} ) {
  704. # if they're supplying a 32 char password that matches their old password
  705. # assume they don't want to change passwords
  706. $userConfUpdate = $dbh->prepare(
  707. "UPDATE users_conf
  708. SET password = md5(?)
  709. WHERE id = ?"
  710. );
  711. $userConfUpdate->execute( $self->{password}, $userID );
  712. }
  713. }
  714. else {
  715. my $userConfInsert = $dbh->prepare(
  716. "INSERT INTO users_conf(acs, address, businessnumber,
  717. company, countrycode, currency,
  718. dateformat, dbdriver,
  719. dbhost, dbname, dboptions, dbpasswd,
  720. dbport, dbuser, email, fax, menuwidth,
  721. name, numberformat, print, printer, role,
  722. sid, signature, stylesheet, tel, templates,
  723. timeout, vclimit, id, password)
  724. VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
  725. ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
  726. ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, md5(?));"
  727. );
  728. $userConfInsert->execute(
  729. $self->{acs}, $self->{address},
  730. $self->{businessnumber}, $self->{company},
  731. $self->{countrycode}, $self->{currency},
  732. $self->{dateformat}, $self->{dbdriver},
  733. $self->{dbhost}, $self->{dbname},
  734. $self->{dboptions}, $self->{dbpasswd},
  735. $self->{dbport}, $self->{dbuser},
  736. $self->{email}, $self->{fax},
  737. $self->{menuwidth}, $self->{name},
  738. $self->{numberformat}, $self->{print},
  739. $self->{printer}, $self->{role},
  740. $self->{sid}, $self->{signature},
  741. $self->{stylesheet}, $self->{tel},
  742. $self->{templates}, $self->{timeout},
  743. $self->{vclimit}, $userID,
  744. $self->{password}
  745. );
  746. }
  747. if ( !$self->{'admin'} ) {
  748. $self->{dbpasswd} =~ s/\\'/'/g;
  749. $self->{dbpasswd} =~ s/\\\\/\\/g;
  750. # format dbconnect and dboptions string
  751. &dbconnect_vars( $self, $self->{dbname} );
  752. # check if login is in database
  753. my $dbh = DBI->connect(
  754. $self->{dbconnect}, $self->{dbuser},
  755. $self->{dbpasswd}, { AutoCommit => 0 }
  756. ) or $self->error($DBI::errstr);
  757. $dbh->{pg_enable_utf8} = 1;
  758. # add login to employees table if it does not exist
  759. my $login = $self->{login};
  760. $login =~ s/@.*//;
  761. my $sth = $dbh->prepare("SELECT entity_id FROM employee WHERE login = ?;");
  762. $sth->execute($login);
  763. my ($id) = $sth->fetchrow_array;
  764. $sth->finish;
  765. my $employeenumber;
  766. my @values;
  767. if ($id) {
  768. $query = qq|UPDATE employee SET
  769. role = ?,
  770. email = ?,
  771. name = ?
  772. WHERE login = ?|;
  773. @values = ( $self->{role}, $self->{email}, $self->{name}, $login );
  774. }
  775. else {
  776. my ($employeenumber) =
  777. Form::update_defaults( "", \%$self, "employeenumber", $dbh );
  778. $query = qq|
  779. INSERT INTO employee
  780. (login, employeenumber, name,
  781. workphone, role, email, sales)
  782. VALUES (?, ?, ?, ?, ?, ?, '1')|;
  783. @values = (
  784. $login, $employeenumber, $self->{name},
  785. $self->{tel}, $self->{role}, $self->{email}
  786. );
  787. }
  788. $sth = $dbh->prepare($query);
  789. $sth->execute(@values);
  790. $dbh->commit;
  791. $dbh->disconnect;
  792. }
  793. }
  794. =item LedgerSMB::User->delete_login($form);
  795. Disused function to delete the user $form->{login}.
  796. =cut
  797. sub delete_login {
  798. my ( $self, $form ) = @_;
  799. my $dbh = DBI->connect(
  800. $form->{dbconnect}, $form->{dbuser},
  801. $form->{dbpasswd}, { AutoCommit => 0 }
  802. ) or $form->dberror( __FILE__ . ':' . __LINE__ );
  803. $dbh->{pg_enable_utf8} = 1;
  804. my $login = $form->{login};
  805. $login =~ s/@.*//;
  806. my $query = qq|SELECT entity_id FROM employee WHERE login = ?|;
  807. my $sth = $dbh->prepare($query);
  808. $sth->execute($login)
  809. || $form->dberror( __FILE__ . ':' . __LINE__ . ': ' . $query );
  810. my ($id) = $sth->fetchrow_array;
  811. $sth->finish;
  812. my $query = qq|
  813. UPDATE employee
  814. SET login = NULL,
  815. enddate = current_date
  816. WHERE login = ?|;
  817. $sth = $dbh->prepare($query);
  818. $sth->execute($login);
  819. $dbh->commit;
  820. $dbh->disconnect;
  821. }
  822. =item LedgerSMB::User->config_vars();
  823. Disused function that returns a list of user config variable names.
  824. =cut
  825. sub config_vars {
  826. my @conf = qw(acs address businessnumber company countrycode
  827. currency dateformat dbconnect dbdriver dbhost dbname dboptions
  828. dbpasswd dbport dbuser email fax menuwidth name numberformat
  829. password printer role sid signature stylesheet tel templates
  830. timeout vclimit);
  831. @conf;
  832. }
  833. =item $self->error($msg);
  834. Privately used error function. Used in places where the more typically used
  835. $form->error cannot be used. Always dies.
  836. =cut
  837. sub error {
  838. my ( $self, $msg ) = @_;
  839. if ( $ENV{GATEWAY_INTERFACE} ) {
  840. print qq|Content-Type: text/html\n\n|
  841. . qq|<body bgcolor=ffffff>\n\n|
  842. . qq|<h2><font color=red>Error!</font></h2>\n|
  843. . qq|<p><b>$msg</b>|;
  844. }
  845. die "Error: $msg\n";
  846. }
  847. 1;
  848. =back