summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorivan <ivan>2005-02-08 20:22:46 +0000
committerivan <ivan>2005-02-08 20:22:46 +0000
commitfc9e97f6cab72de473288470c0681534caf25ea5 (patch)
tree1aa26f5ab82003b2fb01eb77936b5771c056129c
parent85b4db91819ef43709a7d9728af3a7f1aa37b07a (diff)
make self-service session cache module configurable, start framework for in-database session cache
-rw-r--r--FS/FS.pm28
-rw-r--r--FS/FS/ClientAPI/Agent.pm23
-rw-r--r--FS/FS/ClientAPI/MyAccount.pm37
-rw-r--r--FS/FS/ClientAPI/Signup.pm5
-rw-r--r--FS/FS/ClientAPI_SessionCache.pm78
-rw-r--r--FS/FS/Conf.pm7
-rw-r--r--FS/FS/clientapi_session.pm121
-rw-r--r--FS/FS/clientapi_session_field.pm126
-rw-r--r--FS/MANIFEST11
-rwxr-xr-xFS/bin/freeside-setup29
-rw-r--r--FS/t/ClientAPI_SessionCache.t5
-rw-r--r--FS/t/clientapi_session.t5
-rw-r--r--FS/t/clientapi_session_field.t5
-rw-r--r--README.1.5.0pre717
-rw-r--r--httemplate/docs/install.html2
-rw-r--r--httemplate/docs/schema.html15
-rw-r--r--httemplate/docs/upgrade10.html19
17 files changed, 487 insertions, 46 deletions
diff --git a/FS/FS.pm b/FS/FS.pm
index 57a1f6c..f5b2b96 100644
--- a/FS/FS.pm
+++ b/FS/FS.pm
@@ -160,6 +160,24 @@ L<FS::queue_depend> - Job dependencies
L<FS::msgcat> - Message catalogs
+L<FS::clientapi_session>
+
+L<FS::clientapi_session_field>
+
+=head1 Client API
+
+L<FS::ClientAPI>
+
+L<FS::ClientAPI_SessionCache>
+
+L<FS::ClientAPI::Signup>
+
+L<FS::ClientAPI::passwd>
+
+L<FS::ClientAPI::MyAccount>
+
+L<FS::ClientAPI::Agent>
+
=head1 Remote API modules
L<FS::SelfService>
@@ -194,15 +212,9 @@ L<freeside-bill>
L<freeside-overdue>
-=head2 User Interface classes (under (stalled) development; not yet usable)
-
-L<FS::UI::Base> - User-interface base class
-
-L<FS::UI::Gtk> - Gtk user-interface class
-
-L<FS::UI::CGI> - CGI (HTML) user-interface class
+=head2 User Interface classes
-L<FS::UI::agent> - agent table user-interface class
+L<FS::UI::Web> - Web user-interface class
=head2 Notes
diff --git a/FS/FS/ClientAPI/Agent.pm b/FS/FS/ClientAPI/Agent.pm
index e4a58c0..daede59 100644
--- a/FS/FS/ClientAPI/Agent.pm
+++ b/FS/FS/ClientAPI/Agent.pm
@@ -4,16 +4,18 @@ package FS::ClientAPI::Agent;
use strict;
use vars qw($cache);
+use subs qw(_cache);
use Digest::MD5 qw(md5_hex);
-use Cache::SharedMemoryCache; #store in db?
use FS::Record qw(qsearchs); # qsearch dbdef dbh);
+use FS::ClientAPI_SessionCache;
use FS::agent;
use FS::cust_main qw(smart_search);
-#store in db?
-my $cache = new Cache::SharedMemoryCache( {
- 'namespace' => 'FS::ClientAPI::Agent',
-} );
+sub _cache {
+ $cache ||= new FS::ClientAPI_SessionCache( {
+ 'namespace' => 'FS::ClientAPI::Agent',
+ } );
+}
sub agent_login {
my $p = shift;
@@ -37,9 +39,9 @@ sub agent_login {
my $session_id;
do {
$session_id = md5_hex(md5_hex(time(). {}. rand(). $$))
- } until ( ! defined $cache->get($session_id) ); #just in case
+ } until ( ! defined _cache->get($session_id) ); #just in case
- $cache->set( $session_id, $session, '1 hour' );
+ _cache->set( $session_id, $session, '1 hour' );
{ 'error' => '',
'session_id' => $session_id,
@@ -49,7 +51,7 @@ sub agent_login {
sub agent_logout {
my $p = shift;
if ( $p->{'session_id'} ) {
- $cache->remove($p->{'session_id'});
+ _cache->remove($p->{'session_id'});
return { 'error' => '' };
} else {
return { 'error' => "Can't resume session" }; #better error message
@@ -59,7 +61,7 @@ sub agent_logout {
sub agent_info {
my $p = shift;
- my $session = $cache->get($p->{'session_id'})
+ my $session = _cache->get($p->{'session_id'})
or return { 'error' => "Can't resume session" }; #better error message
#my %return;
@@ -84,7 +86,7 @@ sub agent_info {
sub agent_list_customers {
my $p = shift;
- my $session = $cache->get($p->{'session_id'})
+ my $session = _cache->get($p->{'session_id'})
or return { 'error' => "Can't resume session" }; #better error message
#my %return;
@@ -120,3 +122,4 @@ sub agent_list_customers {
}
+1;
diff --git a/FS/FS/ClientAPI/MyAccount.pm b/FS/FS/ClientAPI/MyAccount.pm
index 58966b3..d18a6e4 100644
--- a/FS/FS/ClientAPI/MyAccount.pm
+++ b/FS/FS/ClientAPI/MyAccount.pm
@@ -2,14 +2,15 @@ package FS::ClientAPI::MyAccount;
use strict;
use vars qw($cache);
+use subs qw(_cache);
use Digest::MD5 qw(md5_hex);
use Date::Format;
use Business::CreditCard;
-use Cache::SharedMemoryCache; #store in db?
use FS::CGI qw(small_custview); #doh
use FS::Conf;
use FS::Record qw(qsearch qsearchs);
use FS::Msgcat qw(gettext);
+use FS::ClientAPI_SessionCache;
use FS::svc_acct;
use FS::svc_domain;
use FS::svc_external;
@@ -30,10 +31,11 @@ use vars qw( @cust_main_editable_fields );
use subs qw(_provision);
-#store in db?
-my $cache = new Cache::SharedMemoryCache( {
- 'namespace' => 'FS::ClientAPI::MyAccount',
-} );
+sub _cache {
+ $cache ||= new FS::ClientAPI_SessionCache( {
+ 'namespace' => 'FS::ClientAPI::MyAccount',
+ } );
+}
#false laziness w/FS::ClientAPI::passwd::passwd
sub login {
@@ -69,9 +71,9 @@ sub login {
my $session_id;
do {
$session_id = md5_hex(md5_hex(time(). {}. rand(). $$))
- } until ( ! defined $cache->get($session_id) ); #just in case
+ } until ( ! defined _cache->get($session_id) ); #just in case
- $cache->set( $session_id, $session, '1 hour' );
+ _cache->set( $session_id, $session, '1 hour' );
return { 'error' => '',
'session_id' => $session_id,
@@ -81,7 +83,7 @@ sub login {
sub logout {
my $p = shift;
if ( $p->{'session_id'} ) {
- $cache->remove($p->{'session_id'});
+ _cache->remove($p->{'session_id'});
return { 'error' => '' };
} else {
return { 'error' => "Can't resume session" }; #better error message
@@ -150,7 +152,7 @@ sub customer_info {
sub edit_info {
my $p = shift;
- my $session = $cache->get($p->{'session_id'})
+ my $session = _cache->get($p->{'session_id'})
or return { 'error' => "Can't resume session" }; #better error message
my $custnum = $session->{'custnum'}
@@ -190,7 +192,7 @@ sub edit_info {
sub payment_info {
my $p = shift;
- my $session = $cache->get($p->{'session_id'})
+ my $session = _cache->get($p->{'session_id'})
or return { 'error' => "Can't resume session" }; #better error message
##
@@ -267,7 +269,7 @@ sub process_payment {
my $p = shift;
- my $session = $cache->get($p->{'session_id'})
+ my $session = _cache->get($p->{'session_id'})
or return { 'error' => "Can't resume session" }; #better error message
my %return;
@@ -357,7 +359,7 @@ sub process_payment {
sub invoice {
my $p = shift;
- my $session = $cache->get($p->{'session_id'})
+ my $session = _cache->get($p->{'session_id'})
or return { 'error' => "Can't resume session" }; #better error message
my $custnum = $session->{'custnum'};
@@ -379,7 +381,7 @@ sub invoice {
sub list_invoices {
my $p = shift;
- my $session = $cache->get($p->{'session_id'})
+ my $session = _cache->get($p->{'session_id'})
or return { 'error' => "Can't resume session" }; #better error message
my $custnum = $session->{'custnum'};
@@ -400,7 +402,7 @@ sub list_invoices {
sub cancel {
my $p = shift;
- my $session = $cache->get($p->{'session_id'})
+ my $session = _cache->get($p->{'session_id'})
or return { 'error' => "Can't resume session" }; #better error message
my $custnum = $session->{'custnum'};
@@ -571,7 +573,7 @@ sub order_pkg {
sub cancel_pkg {
my $p = shift;
- my $session = $cache->get($p->{'session_id'})
+ my $session = _cache->get($p->{'session_id'})
or return { 'error' => "Can't resume session" }; #better error message
my $custnum = $session->{'custnum'};
@@ -740,14 +742,14 @@ sub _custoragent_session_custnum {
if ( $p->{'session_id'} ) {
$context = 'customer';
- $session = $cache->get($p->{'session_id'})
+ $session = _cache->get($p->{'session_id'})
or return { 'error' => "Can't resume session" }; #better error message
$custnum = $session->{'custnum'};
} elsif ( $p->{'agent_session_id'} ) {
$context = 'agent';
- my $agent_cache = new Cache::SharedMemoryCache( {
+ my $agent_cache = new FS::ClientAPI_SessionCache( {
'namespace' => 'FS::ClientAPI::Agent',
} );
$session = $agent_cache->get($p->{'agent_session_id'})
@@ -762,6 +764,5 @@ sub _custoragent_session_custnum {
}
-
1;
diff --git a/FS/FS/ClientAPI/Signup.pm b/FS/FS/ClientAPI/Signup.pm
index 4947a64..ede7ba9 100644
--- a/FS/FS/ClientAPI/Signup.pm
+++ b/FS/FS/ClientAPI/Signup.pm
@@ -5,6 +5,7 @@ use Tie::RefHash;
use FS::Conf;
use FS::Record qw(qsearch qsearchs dbdef);
use FS::Msgcat qw(gettext);
+use FS::ClientAPI_SessionCache;
use FS::agent;
use FS::cust_main_county;
use FS::part_pkg;
@@ -88,7 +89,7 @@ sub signup_info {
my $session = '';
if ( exists $packet->{'session_id'} ) {
- my $cache = new Cache::SharedMemoryCache( {
+ my $cache = new FS::ClientAPI_SessionCache( {
'namespace' => 'FS::ClientAPI::Agent',
} );
$session = $cache->get($packet->{'session_id'});
@@ -164,7 +165,7 @@ sub new_customer {
my $agentnum;
if ( exists $packet->{'session_id'} ) {
- my $cache = new Cache::SharedMemoryCache( {
+ my $cache = new FS::ClientAPI_SessionCache( {
'namespace' => 'FS::ClientAPI::Agent',
} );
my $session = $cache->get($packet->{'session_id'});
diff --git a/FS/FS/ClientAPI_SessionCache.pm b/FS/FS/ClientAPI_SessionCache.pm
new file mode 100644
index 0000000..b722484
--- /dev/null
+++ b/FS/FS/ClientAPI_SessionCache.pm
@@ -0,0 +1,78 @@
+package FS::ClientAPI_SessionCache;
+
+use strict;
+use vars qw($module);
+use FS::UID qw(datasrc);
+
+#ask FS::UID to run this stuff for us later
+install_callback FS::UID sub {
+ my $conf = new FS::Conf;
+ $module = $conf->config('selfservice_server-cache_module')
+ || 'Cache::SharedMemoryCache';
+};
+
+=head1 NAME
+
+FS::ClientAPI_SessionCache;
+
+=head1 SYNOPSIS
+
+=head1 DESCRIPTION
+
+Minimal Cache::Cache-alike interface for storing session cache information.
+Backends to Cache::SharedMemoryCache, Cache::FileCache, or an internal
+implementation which stores information in the clientapi_session and
+clientapi_session_field database tables.
+
+=head1 METHODS
+
+=over 4
+
+=item new
+
+=cut
+
+sub new {
+ my $proto = shift;
+ my $class = ref($proto) || $proto;
+ unless ( $module =~ /^_Database$/ ) {
+ eval "use $module;";
+ die $@ if $@;
+ my $self = $module->new(@_);
+ $self->set_cache_root('/usr/local/etc/freeside/clientapi_session.'.datasrc)
+ if $module =~ /^Cache::FileCache$/;
+ $self;
+ } else {
+ my $self = shift;
+ bless ($self, $class);
+ }
+}
+
+sub get {
+ my($self, $session_id) = @_;
+ die '_Database self-service session cache not yet implemented';
+}
+
+sub set {
+ my($self, $session_id, $session, $expiration) = @_;
+ die '_Database self-service session cache not yet implemented';
+}
+
+sub remove {
+ my($self, $session_id) = @_;
+ die '_Database self-service session cache not yet implemented';
+}
+
+=back
+
+=head1 BUGS
+
+Minimal documentation.
+
+=head1 SEE ALSO
+
+L<Cache::Cache>, L<FS::clientapi_session>, L<FS::clientapi_session_field>
+
+=cut
+
+1;
diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm
index 187a6f9..8ce5138 100644
--- a/FS/FS/Conf.pm
+++ b/FS/FS/Conf.pm
@@ -1383,6 +1383,13 @@ httemplate/docs/config.html
'type' => 'checkbox',
},
+ { 'key' => 'selfservice_server-cache_module',
+ 'section' => '',
+ 'description' => 'Module used to store self-service session information. All modules handle any number of self-service servers. Cache::SharedMemoryCache is appropriate for a single database / single Freeside server. Cache::FileCache is useful for multiple databases on a single server, or when IPC::ShareLite is not available (i.e. FreeBSD).', # _Database stores session information in the database and is appropriate for multiple Freeside servers, but may be slower.',
+ 'type' => 'select',
+ 'select_enum' => [ 'Cache::SharedMemoryCache', 'Cache::FileCache', ], # '_Database' ],
+ },
+
);
1;
diff --git a/FS/FS/clientapi_session.pm b/FS/FS/clientapi_session.pm
new file mode 100644
index 0000000..f71a126
--- /dev/null
+++ b/FS/FS/clientapi_session.pm
@@ -0,0 +1,121 @@
+package FS::clientapi_session;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearch qsearchs );
+
+@ISA = qw(FS::Record);
+
+=head1 NAME
+
+FS::clientapi_session - Object methods for clientapi_session records
+
+=head1 SYNOPSIS
+
+ use FS::clientapi_session;
+
+ $record = new FS::clientapi_session \%hash;
+ $record = new FS::clientapi_session { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::clientapi_session object represents an FS::ClientAPI session.
+FS::clientapi_session inherits from FS::Record. The following fields are
+currently supported:
+
+=over 4
+
+=item sessionnum - primary key
+
+=item sessionid - session ID
+
+=item namespace - session namespace
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new record. To add the record to the database, see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+# the new method can be inherited from FS::Record, if a table method is defined
+
+sub table { 'clientapi_session'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+# the insert method can be inherited from FS::Record
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+# the delete method can be inherited from FS::Record
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+# the replace method can be inherited from FS::Record
+
+=item check
+
+Checks all fields to make sure this is a valid record. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and replace methods.
+
+=cut
+
+# the check method should currently be supplied - FS::Record contains some
+# data checking routines
+
+sub check {
+ my $self = shift;
+
+ my $error =
+ $self->ut_numbern('primary_key')
+ || $self->ut_number('validate_other_fields')
+ ;
+ return $error if $error;
+
+ $self->SUPER::check;
+}
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::ClientAPI>, <FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/clientapi_session_field.pm b/FS/FS/clientapi_session_field.pm
new file mode 100644
index 0000000..f790da8
--- /dev/null
+++ b/FS/FS/clientapi_session_field.pm
@@ -0,0 +1,126 @@
+package FS::clientapi_session_field;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearch qsearchs );
+
+@ISA = qw(FS::Record);
+
+=head1 NAME
+
+FS::clientapi_session_field - Object methods for clientapi_session_field records
+
+=head1 SYNOPSIS
+
+ use FS::clientapi_session_field;
+
+ $record = new FS::clientapi_session_field \%hash;
+ $record = new FS::clientapi_session_field { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::clientapi_session_field object represents a FS::ClientAPI session data
+field. FS::clientapi_session_field inherits from FS::Record. The following
+fields are currently supported:
+
+=over 4
+
+=item fieldnum - primary key
+
+=item sessionnum - Base ClientAPI sesison (see L<FS::clientapi_session>)
+
+=item fieldname
+
+=item fieldvalie
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new record. To add the record to the database, see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to. You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+# the new method can be inherited from FS::Record, if a table method is defined
+
+sub table { 'clientapi_session_field'; }
+
+=item insert
+
+Adds this record to the database. If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+# the insert method can be inherited from FS::Record
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+# the delete method can be inherited from FS::Record
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+# the replace method can be inherited from FS::Record
+
+=item check
+
+Checks all fields to make sure this is a valid record. If there is
+an error, returns the error, otherwise returns false. Called by the insert
+and replace methods.
+
+=cut
+
+# the check method should currently be supplied - FS::Record contains some
+# data checking routines
+
+sub check {
+ my $self = shift;
+
+ my $error =
+ $self->ut_numbern('primary_key')
+ || $self->ut_number('validate_other_fields')
+ ;
+ return $error if $error;
+
+ $self->SUPER::check;
+}
+
+=back
+
+=head1 BUGS
+
+The author forgot to customize this manpage.
+
+=head1 SEE ALSO
+
+L<FS::clientapi_session>, L<FS::ClientAPI, L<FS::Record>, schema.html from the
+base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/MANIFEST b/FS/MANIFEST
index 4e33efe..921bbc9 100644
--- a/FS/MANIFEST
+++ b/FS/MANIFEST
@@ -28,6 +28,7 @@ FS.pm
FS/CGI.pm
FS/InitHandler.pm
FS/ClientAPI.pm
+FS/ClientAPI_SessionCache.pm
FS/ClientAPI/passwd.pm
FS/ClientAPI/MyAccount.pm
FS/Conf.pm
@@ -38,10 +39,7 @@ FS/Report.pm
FS/Report/Table.pm
FS/Report/Table/Monthly.pm
FS/SearchCache.pm
-FS/UI/Base.pm
-FS/UI/CGI.pm
-FS/UI/Gtk.pm
-FS/UI/agent.pm
+FS/UI/Web.pm
FS/UID.pm
FS/Msgcat.pm
FS/acct_snarf.pm
@@ -149,11 +147,14 @@ FS/queue_arg.pm
FS/queue_depend.pm
FS/msgcat.pm
FS/cust_tax_exempt.pm
+FS/clientapi_session.pm
+FS/clientapi_session_field.pm
t/agent.t
t/agent_type.t
t/CGI.t
t/InitHandler.t
t/ClientAPI.t
+t/ClientAPI_SessionCache.t
t/Conf.t
t/ConfItem.t
t/Misc.t
@@ -267,3 +268,5 @@ t/queue_arg.t
t/queue_depend.t
t/msgcat.t
t/raddb.t
+t/clientapi_session.t
+t/clientapi_session_field.t
diff --git a/FS/bin/freeside-setup b/FS/bin/freeside-setup
index 24b0685..5ab6eb9 100755
--- a/FS/bin/freeside-setup
+++ b/FS/bin/freeside-setup
@@ -142,7 +142,11 @@ foreach $attribute (@check_attributes) {
}
#create history tables (false laziness w/create-history-tables)
-foreach my $table ( grep { ! /^h_/ } $dbdef->tables ) {
+foreach my $table (
+ grep { ! /^clientapi_session/ }
+ grep { ! /^h_/ }
+ $dbdef->tables
+) {
my $tableobj = $dbdef->table($table)
or die "unknown table $table";
@@ -1230,6 +1234,29 @@ sub tables_hash_hack {
'index' => [ [ 'codenum' ] ],
},
+ 'clientapi_session' => {
+ 'columns' => [
+ 'sessionnum', 'serial', '', '',
+ 'sessionid', 'varchar', '', $char_d,
+ 'namespace', 'varchar', '', $char_d,
+ ],
+ 'primary_key' => 'sessionnum',
+ 'unique' => [ [ 'sessionid', 'namespace' ] ],
+ 'index' => [],
+ },
+
+ 'clientapi_session_field' => {
+ 'columns' => [
+ 'fieldnum', 'serial', '', '',
+ 'sessionnum', 'int', '', '',
+ 'fieldname', 'varchar', '', $char_d,
+ 'fieldvalue', 'text', 'NULL', '',
+ ],
+ 'primary_key' => 'fieldnum',
+ 'unique' => [ [ 'sessionnum', 'fieldname' ] ],
+ 'index' => [],
+ },
+
);
%tables;
diff --git a/FS/t/ClientAPI_SessionCache.t b/FS/t/ClientAPI_SessionCache.t
new file mode 100644
index 0000000..4ba88e2
--- /dev/null
+++ b/FS/t/ClientAPI_SessionCache.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::ClientAPI::SessionCache;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/clientapi_session.t b/FS/t/clientapi_session.t
new file mode 100644
index 0000000..a6414c3
--- /dev/null
+++ b/FS/t/clientapi_session.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::clientapi_session;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/clientapi_session_field.t b/FS/t/clientapi_session_field.t
new file mode 100644
index 0000000..a9d4fa9
--- /dev/null
+++ b/FS/t/clientapi_session_field.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::clientapi_session_field;
+$loaded=1;
+print "ok 1\n";
diff --git a/README.1.5.0pre7 b/README.1.5.0pre7
index 5c136ab..67554c8 100644
--- a/README.1.5.0pre7
+++ b/README.1.5.0pre7
@@ -47,6 +47,23 @@ CREATE TABLE reg_code_pkg (
CREATE UNIQUE INDEX reg_code_pkg1 ON reg_code_pkg ( codenum, pkgpart );
CREATE INDEX reg_code_pkg2 ON reg_code_pkg ( codenum );
+CREATE TABLE clientapi_session (
+ sessionnum serial NOT NULL,
+ sessionid varchar(80) NOT NULL,
+ namespace varchar(80) NOT NULL,
+ PRIMARY KEY (sessionnum)
+);
+CREATE UNIQUE INDEX clientapi_session1 ON clientapi_session ( sessionid, namespace );
+
+CREATE TABLE clientapi_session_field (
+ fieldnum serial NOT NULL,
+ sessionnum int NOT NULL,
+ fieldname varchar(80) NOT NULL,
+ fieldvalue text NULL,
+ PRIMARY KEY (fieldnum)
+);
+CREATE UNIQUE INDEX clientapi_session_field1 ON clientapi_session_field ( sessionnum, fieldname );
+
ALTER TABLE part_pkg ADD promo_code varchar(80) NULL;
ALTER TABLE h_part_pkg ADD promo_code varchar(80) NULL;
CREATE INDEX part_pkg2 ON part_pkg ( promo_code );
diff --git a/httemplate/docs/install.html b/httemplate/docs/install.html
index a880d91..51c700b 100644
--- a/httemplate/docs/install.html
+++ b/httemplate/docs/install.html
@@ -54,7 +54,7 @@ Before installing, you need:
<li><a href="http://search.cpan.org/search?dist=Time-Duration">Time-Duration</a>
<li><a href="http://search.cpan.org/search?dist=HTML-Widgets-SelectLayers">HTML-Widgets-SelectLayers</a>
<li><a href="http://search.cpan.org/search?dist=Storable">Storable</a>
-<!-- MyAccounts, maybe only for dev <li><a href="http://search.cpan.org/search?dist=Cache-Cache">Cache::Cache</a> -->
+ <li><a href="http://search.cpan.org/search?dist=Cache-Cache">Cache::Cache</a>
<li><a href="http://search.cpan.org/search?dist=NetAddr-IP">NetAddr-IP</a>
<li><a href="http://search.cpan.org/search?dist=Chart">Chart</a>
<li><a href="http://search.cpan.org/search?dist=Crypt-PasswdMD5">Crypt::PasswdMD5</a>
diff --git a/httemplate/docs/schema.html b/httemplate/docs/schema.html
index 8af8aa9..63c7953 100644
--- a/httemplate/docs/schema.html
+++ b/httemplate/docs/schema.html
@@ -487,7 +487,7 @@
<li><a name="rate_prefix" href="man/FS/rate_prefix.html">rate_prefix</a> - Call rate prefix
<ul>
<li>prefixnum - primary key
- <li>regionnum <a href="#rate_region">rate region</a>
+ <li>regionnum - <a href="#rate_region">rate region</a>
<li>countrycode
<li>npa
<li>nxx
@@ -499,5 +499,18 @@
<li>locale - locale
<li>msg - Message text
</ul>
+ <li><a name="clientapi_session" href="man/FS/clientapi_session.html">clientapi_session</a> - ClientAPI session store
+ <ul>
+ <li>sessionnum - primary key
+ <li>sessionid - session ID
+ <li>namespace - session namespace
+ </ul>
+ <li><a name="clientapi_session_field" href="man/FS/clientapi_session_field.html">clientapi_session_field</a> - Client API session store data
+ <ul>
+ <li>fieldnum - primary key
+ <li>sessionnum - <a href="#session">session</a>
+ <li>fieldname
+ <li>fieldvalue
+ </ul>
</ul>
</body>
diff --git a/httemplate/docs/upgrade10.html b/httemplate/docs/upgrade10.html
index 7441cf1..977755b 100644
--- a/httemplate/docs/upgrade10.html
+++ b/httemplate/docs/upgrade10.html
@@ -8,7 +8,7 @@ install Net::SSH 0.08
- In httpd.conf, change &lt;Files ~ \.cgi&gt; to &lt;Files ~ (\.cgi|\.html)&gt;
- In httpd.conf, change <b>AddHandler perl-script .cgi</b> or <b>SetHandler perl-script</b> to <b>AddHandler perl-script .cgi .html</b>
-install NetAddr::IP, Chart::Base, IPC::ShareLite, Locale::SubCountry,
+install NetAddr::IP, Chart::Base, Locale::SubCountry,
JavaScript::RPC (JavaScript::RPC::Server::CGI) <!-- and Crypt::YAPassGen-->
INSERT INTO msgcat ( msgnum, msgcode, locale, msg ) VALUES ( 20, 'svc_external-id', 'en_US', 'External ID' );
@@ -240,6 +240,23 @@ CREATE TABLE reg_code_pkg (
CREATE UNIQUE INDEX reg_code_pkg1 ON reg_code_pkg ( codenum, pkgpart );
CREATE INDEX reg_code_pkg2 ON reg_code_pkg ( codenum );
+CREATE TABLE clientapi_session (
+ sessionnum serial NOT NULL,
+ sessionid varchar(80) NOT NULL,
+ namespace varchar(80) NOT NULL,
+ PRIMARY KEY (sessionnum)
+);
+CREATE UNIQUE INDEX clientapi_session1 ON clientapi_session ( sessionid, namespace );
+
+CREATE TABLE clientapi_session_field (
+ fieldnum serial NOT NULL,
+ sessionnum int NOT NULL,
+ fieldname varchar(80) NOT NULL,
+ fieldvalue text NULL,
+ PRIMARY KEY (fieldnum)
+);
+CREATE UNIQUE INDEX clientapi_session_field1 ON clientapi_session_field ( sessionnum, fieldname );
+
DROP INDEX cust_bill_pkg1;
ALTER TABLE cust_bill_pkg ADD itemdesc varchar(80) NULL;