[interchange] * Add the ability to set valref and scratchref options with strings
Mike Heins
interchange-cvs at icdevgroup.org
Sun Jul 17 15:13:24 UTC 2016
commit 74015158052e0437e742521cd6a3bb55a2e25273
Author: Mike Heins <mike at perusion.com>
Date: Sun Jul 17 11:12:11 2016 -0400
* Add the ability to set valref and scratchref options with strings
instead of perl references.
* Add some documentation for the [userdb] tag.
lib/Vend/UserDB.pm | 467 +++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 465 insertions(+), 2 deletions(-)
---
diff --git a/lib/Vend/UserDB.pm b/lib/Vend/UserDB.pm
index 28fc212..df22165 100644
--- a/lib/Vend/UserDB.pm
+++ b/lib/Vend/UserDB.pm
@@ -985,8 +985,54 @@ sub clear_values {
sub get_values {
my($self, $valref, $scratchref) = @_;
- $valref = $::Values unless ref($valref);
- $scratchref = $::Scratch unless ref($scratchref);
+ my $same;
+ if($valref eq $scratchref) {
+ $same = 1;
+ }
+
+ if(ref($valref) eq 'HASH') {
+ ## do nothing
+ }
+ elsif($valref and ! ref($valref) ) {
+ my @things = split /:+/, $valref;
+ $valref = $Vend::Session;
+ for(@things) {
+ my $clear = s/\*+$//;
+ if($clear) {
+ $valref = $valref->{$_} = {};
+ }
+ else {
+ $valref = $valref->{$_} ||= {};
+ }
+ }
+ }
+ else {
+ $valref = $::Values;
+ }
+
+ if($same) {
+ $scratchref = $valref;
+ }
+ elsif(ref($scratchref) eq 'HASH') {
+ ## do nothing
+ }
+ elsif($scratchref and ! ref($scratchref) ) {
+ my @things = split /:+/, $scratchref;
+ $scratchref = $Vend::Session;
+ for(@things) {
+ my $clear = s/\*+$//;
+ if($clear) {
+ $scratchref = $scratchref->{$_} = {};
+ }
+ else {
+ $scratchref = $scratchref->{$_} ||= {};
+ }
+ }
+ }
+ else {
+ $scratchref = $::Scratch;
+ }
+
my $constref = $Vend::Session->{constant} ||= {};
my @fields = @{ $self->{DB_FIELDS} };
@@ -2446,6 +2492,423 @@ sub set_cart {
}
+
+=head2 The [userdb ...] tag
+
+Interchange provides a C<[userdb ...]> tag to access the UserDB functions.
+
+ [userdb
+ function=function_name
+ username="username"
+ assign_username=1
+ username_mask=REGEX
+ password="password"
+ verify="password"
+ oldpass="old password"
+ crypt="1|0"
+ bcrypt=1
+ promote=1
+ md5=1
+ md5_salted=1
+ sha1=1
+ valref=user_record
+ scratchref=user_record
+ shipping="fields for shipping save"
+ billing="fields for billing save"
+ preferences="fields for preferences save"
+ ignore_case="1|0"
+ force_lower=1
+ param1=value
+ param2=value
+ ...
+ ]
+
+All parameters are optional except for the function. Normally, parameters
+are set in catalog.cfg with the I<UserDB> directive.
+
+It is normally called in an C<mv_click> or C<mv_check> setting, as in:
+
+ [set Login]
+ mv_todo=return
+ mv_nextpage=welcome
+ [userdb function=login]
+ [/set]
+
+ <FORM ACTION="[process-target]" METHOD=POST>
+ <INPUT TYPE=hidden NAME=mv_click VALUE=Login>
+ Username <INPUT NAME=mv_username SIZE=10>
+ Password <INPUT NAME=mv_password SIZE=10>
+ </FORM>
+
+There are several global parameters that apply to any use of
+the C<userdb> functions. Most importantly, by default the database
+table is set to be I<userdb>. If you must use another table name,
+then you should include a C<database=table> parameter with any
+call to C<userdb>. The global parameters (default in parens):
+
+ database Sets user database table (userdb)
+ show Show the return value of certain functions
+ or the error message, if any (0)
+ force_lower Force possibly upper-case database fields
+ to lower case session variable names (0)
+ billing Set the billing fields (see Accounts)
+ shipping Set the shipping fields (see Address Book)
+ preferences Set the preferences fields (see Preferences)
+ bill_field Set field name for accounts (accounts)
+ addr_field Set field name for address book (address_book)
+ pref_field Set field name for preferences (preferences)
+ cart_field Set field name for cart storage (carts)
+ pass_field Set field name for password (password)
+ time_field Set field for storing last login time (time)
+ expire_field Set field for expiration date (expire_date)
+ acl Set field for simple access control storage (acl)
+ file_acl Set field for file access control storage (file_acl)
+ db_acl Set field for database access control storage (db_acl)
+
+By default the system crypt() call will be used to compare the
+password. This is minimal security, but at least the passwords in the user
+database will not be human readable. For better security, in descending
+order of security, use:
+
+ bcrypt Bcrypt, most secure
+ sha1 SHA1 digest, more secure than MD5
+ md5 Not so easily stored in cracklib as md5 unsalted
+ md5 Better security than crypt
+
+If you don't keep actual user information, don't have users creating
+accounts and setting the passwords themselvs, and don't do Interchange
+administration via the C<UserDB> capability, then you may
+wish to use the <UserDB> directive (described below) to set
+encryption off by default:
+
+ UserDB default crypt 0
+
+That will set encryption off by default. You can still set encryption
+on by passing C<crypt=1> with any call to a C<new_account>, C<change_pass>,
+or C<login> call.
+
+WARNING: Using unencrypted passwords is never recommended if you have users
+setting their passwords. They will use the same passwords as other systems,
+possibly compromising important information.
+
+=head2 Setting defaults with the UserDB directive
+
+The I<UserDB> directive provides a way to set defaults for
+the user database. For example, if you always wanted to save
+and recall the scratch variable C<tickets> in the user database
+instead of the form variable C<tickets>, you could set:
+
+ UserDB default scratch tickets
+
+That makes every call to C<[userdb function=login]> be equivalent
+to C<[userdb function=login scratch=tickets]>.
+
+If you wish to override that default for one call only, you can
+use C<[userdb function=login scratch="passes"]>.
+
+If you wish to log failed access authorizations, set the C<UserDB>
+profile parameter C<log_failed> true:
+
+ UserDB default log_failed 1
+
+To disable logging of failed access authorizations (the default), set
+the C<UserDB> profile parameter C<log_failed> to 0:
+
+ UserDB default log_failed 0
+
+The I<UserDB> directive uses the same key-value pair settings
+as the I<Locale> and I<Route> directives, and you may have more
+than one set of defaults. You can set them in a hash structure:
+
+ UserDB case_crypt scratch tickets
+ UserDB case_crypt bcrypt 1
+ UserDB case_crypt ignore_case 0
+
+ UserDB default scratch tickets
+ UserDB default sha1 1
+ UserDB default ignore_case 1
+
+The last one to be set becomes the default.
+
+The option C<profile> selects the set to use. So if you wanted
+usernames and passwords to be case sensitive with bcrypt encryption,
+you could pass this call:
+
+ [userdb function=new_account profile=case_crypt]
+
+The username and password will be stored as typed in, and the
+password will be encrypted in the database.
+
+=head2 User Database functions
+
+The user database features are implemented as a series of functions
+attached to the C<userdb> tag. The functions are:
+
+=over 4
+
+=item login
+
+Log in to Interchange. By default, the username is contained in the
+form variable C<mv_username> and the password in C<mv_password>.
+If the login is successful, the session value C<username>
+(C<[data session username]>) will be set to the user name.
+
+This will recall the values of all non-special fields in the user
+database and place them in their corresponding user form variables.
+
+=item logout
+
+Log out of Interchange. No additional parameters are needed.
+
+=item new_account
+
+Create a new account. It requires the C<username>, C<password>, and
+C<verify> parameters, which are by default contained in the form
+variables C<mv_username>, C<mv_password>, C<mv_verify> respectively.
+
+If you set the C<assign_username> parameter, then UserDB will assign
+a sequential username. The C<counter> parameter can be used to set
+the filename (must be absolute), or you can accept the default of
+CATALOG_DIR/etc/username.counter. The first username will be "U0001"
+if the counter doesn't exist already.
+
+The C<ignore_case> parameter forces the username and password to
+lower case in the database, in effect rendering the username and
+password case-insensitive.
+
+If you set C<username_mask> to a valid Perl regular expression (without
+the surrounding / /) then any username containing a matching string will
+not be allowed for use. For example, to screen out order numbers from
+being used by a random user:
+
+ [userdb function=new_account
+ username_mask="^[A-Z]*[0-9]"
+ ]
+
+The I<CookieLogin> directive (catalog.cfg) allows users to save
+their username/password in a cookie. Expiration time is set by
+I<SaveExpire>, renewed every time they log in. To cause the cookie to
+be generated originally, the form variable C<mv_cookie_password> or
+C<mv_cookie_username> must be set in the login form. The former causes
+both username and password to be saved, the latter just the username.
+
+If you want to automatically create an account for every order,
+you can do in the I<OrderReport> file:
+
+ [userdb function=new_account
+ username="[value mv_order_number]"
+ password="[value zip]"
+ verify="[value zip]"
+ database="orders"
+ ]
+
+This would be coupled with a login form that asked for order number and
+zip code; thereupon allowing you to display the contents of a transaction
+database with (presumably updated) order status information or a shipping
+company tracking number.
+
+=item change_pass
+
+Change the password on the currently logged-in account. It requires
+the C<username>, C<password>, C<verify>, and C<oldpass> parameters,
+which are by default contained in the form variables C<mv_username>,
+C<mv_password>, C<mv_verify>, C<mv_password_old> respectively.
+
+=item set_shipping
+
+Active parameters: nickname, shipping, ship_field
+
+Place an entry in the shipping Address book. Example:
+
+ [userdb function=set_shipping nickname=Dad]
+
+See I<Address Book> below.
+
+=item get_shipping
+
+Active parameters: nickname, shipping, ship_field
+
+Recall an entry from the shipping Address book. Example:
+
+ [userdb function=get_shipping nickname=Dad]
+
+See I<Address Book> below.
+
+=item get_shipping_names
+
+Active parameters: ship_field
+
+Gets the names of shipping address book entries and places
+them in the variable C<address_book>. By default, it does not return
+the values; if you wish them to be returned you can set
+the parameter C<show> to 1, as in:
+
+ [set name=shipping_nicknames
+ interpolate=1]
+ [userdb function=get_shipping_names show=1]
+ [/set]
+
+=item set_billing
+
+Active parameters: nickname, billing, bill_field
+
+Place an entry in the billing accounts book. Example:
+
+ [userdb function=set_billing nickname=discover]
+
+See I<Accounts Book> below.
+
+=item get_billing
+
+Active parameters: nickname, billing, bill_field
+
+Recall an entry from the billing accounts book. Example:
+
+ [userdb function=get_billing nickname=visa]
+
+See I<Accounts Book> below.
+
+=item save
+
+Saves all non-special form values that have columns in the user database.
+
+=item load
+
+Performs the transfer of user values to the values space, scratch space, and
+constant space. Performed automatically upon login.
+
+If you pass the C<valref> option, that will be used instead of C<$Values> for
+the values space. It can either be a real hash reference, or a scalar that
+will be a key directly in C<$Vend::Session>. If it contains a colon (C<:>), it
+will be a subreference in C<$Vend::Session>. For example:
+
+ [userdb function=load valref=`$Session->{user_record} ||= {}`]
+
+Will store the values in C<$Vend::Session->{user_record}>, clearing it first.
+The below accomplishes the same thing:
+
+ [userdb function=load valref=user_record]
+
+If you want to place it a couple of levels down, do:
+
+ [userdb function=load valref=`$Session->{values_repository}{userdb} ||= {}`]
+
+or
+
+ [userdb function=load valref="values_repository:userdb"]
+
+To clear the record instead of add to the existing values, add an
+asterisk at the end:
+
+ [userdb function=load valref="values_repository:userdb*"]
+
+Which is equivalent to:
+
+ [userdb function=load valref=`$Session->{values_repository}{userdb} = {}`]
+
+The C<scratchref> option is the same as C<valref>, but for the scratch values
+passed with C<UserDB scratch>.
+
+=item set_cart
+
+Save the contents of a shopping cart.
+
+ [userdb function=set_cart nickname=christmas]
+
+See I<Carts> below.
+
+=item get_cart
+
+Active parameters: nickname, carts_field, target
+
+Recall a saved shopping cart.
+
+ [userdb function=get_cart nickname=mom_birthday]
+
+Setting C<target> saves to a different shopping cart than the
+default main cart. The C<carts_field> controls the database
+field used for storage.
+
+=item set_acl
+
+Active parameters: location, acl_field, delete
+
+Set a simple acl. Example:
+
+ [userdb function=set_acl location=cartcfg/editcart]
+
+This allows the current user to access the page "cartcfg/editcart" if
+it is access-protected.
+
+To delete access, do:
+
+ [userdb function=set_acl location=cartcfg/editcart delete=1]
+
+To display the setting at the same time as setting use the
+C<show> attribute:
+
+ [userdb function=set_acl location=cartcf/editcart show=1]
+
+=item check_acl
+
+Active parameters: location, acl_field
+
+Checks the simple access control listing for a location, returning
+1 if allowed and the empty string if not allowed.
+
+ [if type=explicit
+ compare="[userdb
+ function=check_acl
+ location=cartcfg/editcart]"
+ ]
+ [page cartcfg/editcart]Edit your cart configuration[/page]
+ [/if]
+
+=item set_file_acl, set_db_acl
+
+Active parameters: location, mode, db_acl_field, file_acl_field, delete
+
+Sets a complex access control value. Takes the form:
+
+ [userdb function=set_file_acl
+ mode=rw
+ location=products/inventory.txt]
+
+where mode is any value you wish to check for with check_file_acl. As
+with the simple ACL, you can use delete=1 to delete the location entirely.
+
+=item check_file_acl, check_db_acl
+
+Active parameters: location, mode, db_acl_field, file_acl_field
+
+Checks a complex access control value and returns a true/false (1/0)
+value. Takes the form:
+
+ [userdb function=check_db_acl
+ mode=w
+ location=inventory]
+
+where mode is any value you wish to check for with check_file_acl. It
+will return true if the mode string is contained within the entry
+for that location. Example:
+
+ [if type=explicit
+ compare="[userdb
+ function=check_db_acl
+ mode=w
+ location=inventory]"
+ ]
+ [userdb function=set_acl location=cartcfg/edit_inventory]
+ [page cartcfg/edit_inventory]You may edit the inventory database[/page]
+ [else]
+ [userdb function=set_acl location=cartcfg/edit_inventory delete=1]
+ Sorry, you can't edit inventory.
+ [/if]
+
+=back
+
+=cut
+
sub userdb {
my $function = shift;
my $opt = shift;
More information about the interchange-cvs
mailing list