Interchange HOWTOs: A Collection of Recipes

DavorOcelic

This documentation is free; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

1. Interchange

1.1. Core

There's a built-in Interchange way to control access to pages served
from the PageDir directories.

If the directory containing the requested page contains file
named .access — and that file's size is zero bytes
— then access can be "gated" in one of the following ways:

If the file .access_gate is also present, it will be
read and scanned to perform page-based access decision. It will also
override any other method.

If the variableMV_USERDB_REMOTE_USER is set to
true value, any user logged in via UserDB will receive access
to all pages in the directory.

If the variable MV_USERDB_ACL_TABLE is set to a valid
database identifier, the UserDB module can control access with simple
ACL logic. If MV_USERDB_REMOTE_USER is set, this capability
is not available.

.access_gate file format is as follows:

PAGE_NAME: CONDITION

PAGE_NAME is the name of page to be controlled,
and the page suffix (such as .html) is optional.

Page name of "*" can be used to set a default permission, but
globbing is not possible ("ind*" will not match
"index"). The default permission has lower precedence
than any rule that matches the page name explicitly.

The CONDITION is a simple true (or
Yes) or false (or No) value
which may come, and in fact often comes, from
interpolated ITL code.
The implicit default permission is No, so leaving the default
entry unspecified results in all non-matching users being denied access.

Here's a very simple example:

pubview: Yes
*: No

Here's an example that includes ITL interpolation and is
verbose enough not to require additional explanation.

Banner display in Interchange is implemented using the banner tag.
There are two terms which need to be understood first:

Banner display - term referring to general banner display. Actual code
behavior might be affected by the
category or
weighted attributes passed to the tag.

Banner rotation - term referring to selecting exactly one banner, if
there are multiple banners defined in the
banner database field. Those
multiple banners are displayed in sequential order, with a separate
counter kept for each client.

Additionally, we need to clarify the difference between
categorized and rotated display.

Categorized display (mostly used in combination with weighting) makes
all banners matching a specific category to be displayed the appropriate
amount of time (adding weight gives a banner more visibility).

Rotated display makes multiple banners from the same
banner database field to be selected
in sequential order, for each client separately.

Both categorized/weighted and rotating techniques can be used together.

For the banner tag to work, you will need a
banner table. Here's an
example:

You might notice that the fields names and values in the tables
above are not properly aligned. This is an unfortunate nature of
tab delimited files.

To minimize the chance of confusion, you can download properly composed
banner.txt.

Field descriptions follow:

code - key for an item (of course,
the key has to be unique).

In a default non-weighted display, the category
attribute is expected to reference this unique code.

In a weighted display, the value of this field is not that
important because the choice is made by selecting database rows
regardless of their code.

category - categorize weighted ads.
If empty, the banner will be placed in category
default.

weight - banner weight. Must be an
integer equal or greater than 1 to consider the banner for
display. 0 or blank will ignore the banner when weighted ads are built.

rotate -
must contain a value if weighted banners are
not used:

Empty value will prevent the banner from being displayed.

Literal value of
0 (zero) will cause the entire content of the banner
field to be displayed when the category is matched.

Non-zero value will cause the banner field to be split into segments
using the specified or default delimiter. For each segment, the
banner will then rotate in sequence (for each website visitor
separately).
Obviously, the first banner in the sequence is more likely to be
displayed
than the last.

banner - the field containing actual
banner content. Multiple banner texts (if this feature is used) need to be
separated using the specified or default delimiter.

As usual, databases first need to be registered for use
with the catalog, and so is the case with the above text database.
The following modification to your
catalog.cfg is needed (and a
catalog reconfiguration
afterwards — see ):

Database banner banner.txt TAB
Database banner NUMERIC weight

Now that we have everything in place, we can start experimenting with the
banner tag.

To display weighted banners from a specific category (say,
tech), use
[banner weighted=1 category=tech]. The tag would look for
all banners where the
weight field is positive integer and
the category matches "tech", and
build them in the tmp/Banners/tech/
directory.

To display weighted banners regardless of the category, use
[banner weighted=1]. The tag would look for
all banners where the
weight field is positive integer, and
build them in the tmp/Banners/
directory. Note that the total sum of weights in our sample database
is 20, so each weight point is worth
100/20 = 5%. Therefore, the banners
with the weight of 7 would be displayed
35% of the time each.

To display categorized, non-rotated banners from category
tech, use
[banner category=tech], which is equal in effect to
[data table=banner field=banner key=tech foreign=category].
Note that the
value of the rotate field must be
0.

To display categorized,
rotated banners (from category
tech), use
[banner category=tech], which is equal in effect to
[data table=banner col=banner key=tech].
Note that the
value of the rotate field must be
1.

To display multilevel-categorized banners (from say, category
tech:hw:monitors), use
[banner category=tech:hw:monitors]. The colon will help Interchange
select the most specific banner available, so the difference in
respect to single-level categories is the fallback mechanism; if no
banners are found in the tech:hw:monitors category,
the banner will try a fallback to tech:hw,
and finally to tech.

With DBM-based databases, changes to the text source files
will be detected on next client access to the specific database;
Interchange will then re-read the text source file and override
the previous contents of the DBM database. (In case you want to
disable this automatic behavior, see NoImport).

With SQL databases, the import from text source files happens only
once (on database creation and initial fill).
To manually trigger the re-import for a specific database, delete file
DATABASE_NAME.sql from
the catalog's ProductDir and reconfigure the catalog.

When SQL databases are modified through the user interface, the updates
are not automatically propagated to the text source files. So when
text files are updated manually and re-imported into SQL, data that was
only present in SQL will be lost.

If you plan on modifying text source files even after initial import
into SQL, make sure to sync tables first (using export) before
making changes and re-importing.

1.3. Demo catalogs

1.3.1. "Tutorial"

Providing "quantity" field on the basket page

The page we're starting with (the one from
Interchange Guides: the Catalog Building Tutorial) displays a table of the products placed
in your shopping cart.
The Quantity field is displayed but
the only way to increase the number is to click the appropriate
Order Now button multiple times, and reducing the
quantity
is not supported.

Create an HTML form which is neccesary to submit any client information
back to Interchange:<form method='post' action='[process]'>

Replace the Quantity label
([item-quantity]) with
an HTML text field where quantity can be edited:<input type='text' size='2' name='[quantity-name]' value='[item-quantity]'/>

What we have introduced here is the quantity-name tag.
Interchange
will expand it to the appropriate field name for each item in the
cart (quantity0, quantity1,
quantity2, ...). This all happens automatically and
you have nothing to worry about.

Provide the submit button that triggers an action and sends information
back to Interchange:

1.3.2. "Standard"

At any time, you can copy pages from
lib/UI/pages/admin/
into the pages/admin/ directory
under your catalog tree to make custom versions that override the
distribution ones.

You only need to copy the pages you want to override; the rest are
automatically
picked up from the usual, default location.

1.4. E-mail

Checking for syntactical validity of e-mail addresses

Interchange has two e-mail checks, email and <check>email_only</check>, which
use a relatively simple regex in checking the syntactical validity
of an e-mail address. For a way to run those profile checks on a value,
see run-profile.

However, if you need as accurate and bullet-proof e-mail address matching
as possible, you can use code from Chapter 7 of the Jeffrey Friedl's 1997
book "Mastering Regular Expressions", published by O'Reilly:

1.5. Forms and form submissions

In mv_metadata, you cannot use the usual
width and
height fields to
set HTML <textarea> size.

Use the following instead (for a 5x50 characters box):

fieldname:
widget: textarea_5_50
height:
width:

Testing for errors in form submissions

To quickly test whether any errors were set in the last
form submission and display them, use:

[if errors]
[error all=1 show_error=1 joiner="<br>"]
[/if]

The code that works with Minivend 4.02 is as follows:

[if type=explicit compare="[error all=1 keep=1]"]
......
[/if]

1.6. Ordering

Forcibly adjusting quantities of ordered items

Your stock may be limited, or you might want to force order quantities
for other reasons.

There are a number of ways to do this. Here is one; the code should
be placed at the top of the basket and checkout pages. It operates on
the cart "main" and prevents people from ordering
more than what is available according to quantity
field in the inventory:

If you have a custom search method and want to manually support AND and
OR in search specifications while using the usual "eq"
and "rm" column operations, use something like
the following to pre-process the search specification:

Also, at catalog startup, a file named
etc/CATNAME.structure
will be created relative to the catalog root directory. A complete
configuration dump will be saved there.

Testing configuration, starting, reconfiguring, stopping

Knowing how to manage the Interchange daemon is one of the very basic
administration tasks.

Note

Since Interchange does not generally like being run with admin privileges
(user root), you will most probably have to invoke the commands listed
below under the Interchange username. To do so, you will either log in as
Interchange user, or as sufficiently-privileged user invoke
su -c 'COMMAND' INTERCHANGE_USER, or
sudo -u INTERCHANGE_USERCOMMAND.

Configuration is tested without interrupting the running processes
by invoking:

Touching a file named after the catalog within the
etc/reconfig/ directory in
ICROOT.

Interchange is stopped by one of:

/etc/init.d/interchange stop (Debian GNU)

/etc/rc.d/init.d/interchange stop (Red Hat)

interchange -stop
(tarball)

Note

Because processes that are waiting for selection can block signals on some
operating systems, it is possible that you have to wait for HouseKeeping
seconds before the server really closes down. To terminate the server with
prejudice (in the event it will not stop), use
interchange -kill.

1.9. Sessions

User sessions are kept in a particular type of database as
controlled by SessionType configuration directive.

Depending on the purpose, sessions can be dumped using tags
dump or dump_session.

If you are going to do something specific to a session, such
as process it later with an external Perl program, you could first
save it as text representation of the Perl hash to an explicitly-named
file tmp/SESSIONID.save,
by invoking something along the lines of:

1.10. Tax / VAT

The basic idea is to write a usertag that will return the tax
amount. The way usertag reaches the final amount can then be
modified or improved without having to make other changes to the configuration.
Let's create the basic tag, include it in interchange.cfg or catalog.cfg, and call it from the
salestax table.

The basic tag that returns the sum of taxes for all individual products
in user's basket is as follows:

For country-based tax selection, you could modify
salestax.asc
to invoke vat-calc with different database or field options depending
on country, and enable country lookup itself by using the following in
catalog.cfg:

SalesTax country

For category-dependent tax rates, you would modify the vat-calc tag
to take $item->{category} into account and enable
the "category" modifier as follows:

AutoModifier products:category

Implementing user-based tax/VAT scheme

To set up tax-exempt users, expand your userdb database
to add field tax_exempt.

Have your SalesTax defined as usual, as if no users will be
tax-exempt. Then, make the following changes to catalog.cfg to unset
SalesTax for tax exempt users:

2. HTML

Interchange outputs a lot of HTML markup. The markup is a bit
inconsistent in style, casing (uppercase/lowercase) and argument quoting,
but an effort has been underway to standardize on all-lowercase,
properly-quoted markup only.

Lowercasing and quoting arguments does not harm compatiblity with old web
browsers, and is a nice step towards strict XHTML compliance.

For XHTML compliance, non-container markup tags should be closed with
/> instead of just >.
Enable the XHTML configuration directive which will adjust the
output markup on internally-generated non-container HTML tags.

There's the $Vend::XTrailer variable which you can
also use in your own code to automatically output literal
'/' or nothing before the closing of a non-container
tag, according to XHTML.

6. Perl

Sometimes you want to make a data structure modifiable, without having the
changes permanently override original values. To do so, we can use Perl's
Tie::ShadowHash module.

This is an old trick, and generally not needed in Interchange, as it
already supports modification of configuration directives for the
duration of the page only (which is usually done in an Autoload
routine).