site/cgi-bin/shop.pl
site/cgi-bin/user.pl
site/data/stopwords.txt
+site/data/db/sql_statements.pkey
+site/data/db/sql_statements.data
site/docs/BSE::UI::Affiliate.html
site/docs/Generate.html
site/docs/Generate::Article.html
site/templates/admin/locations/delete.tmpl
site/templates/admin/locations/edit.tmpl
site/templates/admin/locations/list.tmpl
+site/templates/admin/locations/view.tmpl
+site/templates/admin/locations/view_sessions.tmpl
site/templates/admin/order_detail.tmpl
site/templates/admin/order_list.tmpl
site/templates/admin/order_list_filled.tmpl
site/templates/admin/users/grouplist.tmpl
site/templates/admin/users/groupmembers.tmpl
site/templates/admin/users/list.tmpl
+site/templates/admin/users/view.tmpl
+site/templates/admin/users/view_bookings.tmpl
site/templates/admin/xbase.tmpl
site/templates/affiliate.tmpl
site/templates/base.tmpl
-VERSION=0.15_44
+VERSION=0.15_45
DISTNAME=bse-$(VERSION)
DISTBUILD=$(DISTNAME)
DISTTAR=../$(DISTNAME).tar
testinst: distdir
perl localinst.perl $(DISTBUILD)
perl -MExtUtils::Command -e rm_rf $(DISTBUILD)
+ cd `perl -lne 'do { print $$1; exit; } if /^base_dir\s*=\s*(.*)/' test.cfg`/util ; perl loaddata.pl ../data/db
testfiles: distdir
perl localinst.perl $(DISTBUILD) leavedb
perl -MExtUtils::Command -e rm_rf $(DISTBUILD)
+ cd `perl -lne 'do { print $$1; exit; } if /^base_dir\s*=\s*(.*)/' test.cfg`/util ; perl loaddata.pl ../data/db
test: testinst
perl -MTest::Harness=runtests -Isite/cgi-bin/modules -It -e 'runtests glob q!t/*.t!'
siteuser_id integer not null,
roll_present integer not null default 0,
+ options varchar(255) not null default '',
+ customer_instructions text not null default '',
+ support_notes text not null default '',
+
primary key(session_id, siteuser_id),
index (siteuser_id)
);
use BSE::WebUtil 'refresh_to_admin';
use DevHelp::HTML;
use BSE::Arrows;
+use BSE::CfgInfo 'product_options';
my $req = BSE::Request->new;
my $cfg = $req->cfg;
# @images = $imageEditor->images()
# if $product->{id};
my $image_index;
+ my $avail_options = product_options($cfg);
my $blank = qq!<img src="$IMAGES_URI/trans_pixel.gif" width="17" height="13" border="0" align="absbottom" />!;
ifImage => sub { $product->{imageName} },
hiddenNote => sub { $product->{listed} ? " " : "Hidden" },
alloptions =>
- sub { CGI::escapeHTML(join(',', sort keys %SHOP_PRODUCT_OPTS)) },
+ sub { CGI::escapeHTML(join(',', sort keys %$avail_options)) },
templates =>
sub {
return CGI::popup_menu(-name=>'template', -values=>\@templates,
sub cart_item_opts {
my ($cart_item, $product) = @_;
+ my $avail_options = product_options($cfg);
+
my @options = ();
my @values = split /,/, $cart_item->{options};
my @ids = split /,/, $product->{options};
for my $opt_index (0 .. $#ids) {
- my $entry = $SHOP_PRODUCT_OPTS{$ids[$opt_index]};
+ my $entry = $avail_options->{$ids[$opt_index]};
my $option = {
id=>$ids[$opt_index],
value=>$values[$opt_index],
admin/edit_img=admin/article_img
admin/edit_file=admin/filelist
+; this used to be handled via the edit target, but since CVS sucks
+; I won't rename the template
+admin/users/view_orders=admin/users/edit_orders
+
[Global permissions]
change_body = 8
change_body_no_shop = 9
display_postcode=Post code
display_telephone=Phone
+[nonajax user agents]
+ie4=MSIE
+
+[ajax user agents]
+mozilla=^Mozilla/5.0
+
+[ajax definitions]
+includes=inline:<script type="text/javascript" src="/js/prototype.js"></script>
+
[includes]
00bsecfg_d=bsecfg_d/
50local=bse-local.cfg
\ No newline at end of file
package BSE::AdminSiteUsers;
use strict;
-use base qw(BSE::UI::SiteuserCommon);
+use base qw(BSE::UI::AdminDispatch BSE::UI::SiteuserCommon);
use BSE::Util::Tags qw(tag_error_img tag_hash);
use DevHelp::HTML;
use SiteUsers;
my %actions =
(
- list=>1,
- edit=>1,
- save=>1,
- addform=>1,
- add=>1,
- grouplist=>1,
- addgroupform=>1,
- addgroup => 1,
- editgroup=>1,
- savegroup => 1,
- deletegroupform =>1,
- deletegroup=>1,
- groupmemberform => 1,
- savegroupmembers => 1,
+ list => 'bse_members_user_list',
+ edit => 'bse_members_user_edit',
+ save => 'bse_members_user_edit',
+ addform => 'bse_members_user_add',
+ add => 'bse_members_user_add',
+ view => 'bse_members_user_view',
+ grouplist => 'bse_members_group_list',
+ addgroupform => 'bse_members_group_add',
+ addgroup => 'bse_members_group_add',
+ editgroup => 'bse_members_group_edit',
+ savegroup => 'bse_members_group_edit',
+ deletegroupform => 'bse_members_group_delete',
+ deletegroup => 'bse_members_group_delete',
+ groupmemberform => 'bse_members_user_edit',
+ savegroupmembers => 'bse_members_user_edit',
);
my @donttouch = qw(id userId password email confirmed confirmSecret waitingForConfirmation flags affiliate_name previousLogon); # flags is saved separately
my %donttouch = map { $_, $_ } @donttouch;
-sub dispatch {
- my ($class, $req) = @_;
+sub default_action { 'list' }
- $req->check_admin_logon()
- or return BSE::Template->get_refresh($req->url('logon'), $req->cfg);
+sub actions {
+ \%actions
+}
- my $cgi = $req->cgi;
- my $action;
- for my $check (keys %actions) {
- if ($cgi->param("a_$check")) {
- $action = $check;
- last;
- }
- }
- $action ||= 'list';
- my $method = "req_$action";
- $class->$method($req);
+sub rights {
+ \%actions
}
sub flags {
sub req_edit {
my ($class, $req, $msg, $errors) = @_;
+ $class->_display_user($req, $msg, $errors, 'admin/users/edit');
+}
+
+sub req_view {
+ my ($class, $req, $msg, $errors) = @_;
+
+ $class->_display_user($req, $msg, $errors, 'admin/users/view');
+}
+
+sub _display_user {
+ my ($class, $req, $msg, $errors, $template) = @_;
+
my $cgi = $req->cgi;
my $id = $cgi->param('id');
defined $id
$it->make_iterator(\&iter_groups, 'group', 'groups',
undef, undef, undef, \$current_group),
ifMember => [ \&tag_ifUserMember, $siteuser, \$current_group ],
+ $it->make_iterator([ \&iter_seminar_bookings, $siteuser],
+ 'booking', 'bookings'),
);
- my $template = 'admin/users/edit';
my $t = $req->cgi->param('_t');
$template .= "_$t" if defined($t) && $t =~ /^\w+$/;
return BSE::Template->get_response($template, $req->cfg, \%acts);
}
+sub iter_seminar_bookings {
+ my ($siteuser) = @_;
+
+ return $siteuser->seminar_bookings_detail;
+}
+
sub req_save {
my ($class, $req) = @_;
use vars qw(@ISA @EXPORT_OK);
require Exporter;
@ISA = qw(Exporter);
-@EXPORT_OK = qw(custom_class admin_base_url cfg_image_dir credit_card_class);
+@EXPORT_OK = qw(custom_class admin_base_url cfg_image_dir credit_card_class product_options);
=head1 NAME
return $class->new($cfg);
}
+sub product_options {
+ my ($cfg) = @_;
+
+ my %options = %Constants::SHOP_PRODUCT_OPTS;
+
+ my %cfg_opts = $cfg->entriesCS('shop product options');
+ for my $option (keys %cfg_opts) {
+ my ($option_desc, @values) = split /;/, $cfg_opts{$option};
+ my %value_labels;
+ for my $value (@values) {
+ $value_labels{$value} = $cfg->entry("shop product option $option",
+ $value, $value);
+ }
+ $options{$option} =
+ {
+ desc => $option_desc,
+ values => \@values,
+ labels => \%value_labels,
+ };
+ }
+
+ \%options;
+}
+
1;
__END__
select * from bse_seminar_bookings where session_id = ?
SQL
seminarSessionBookUser => <<SQL,
-insert bse_seminar_bookings values(?,?,?)
+insert bse_seminar_bookings values(?,?,?,?,?,?)
SQL
seminarSessionRollCallEntries => <<SQL,
select bo.roll_present, su.id, su.userId, su.name1, su.name2, su.email
use BSE::Template;
use BSE::Util::Iterate;
use DevHelp::HTML;
+use BSE::CfgInfo 'product_options';
my %money_fields =
(
sub low_edit_tags {
my ($self, $acts, $req, $article, $articles, $msg, $errors) = @_;
+ my $product_opts = product_options($req->cfg);
+
my $cfg = $req->cfg;
my $mbcs = $cfg->entry('html', 'mbcs', 0);
my $tag_hash = $mbcs ? \&tag_hash_mbcs : \&hash_tag;
product => [ $tag_hash, $article ],
$self->SUPER::low_edit_tags($acts, $req, $article, $articles, $msg,
$errors),
- alloptions => join(",", sort keys %Constants::SHOP_PRODUCT_OPTS),
+ alloptions => join(",", sort keys %$product_opts),
$it->make_iterator
([ \&iter_subs, $req ], 'subscription', 'subscriptions'),
);
$errors->{$col} = "$money_fields{$col} invalid";
}
}
-
+
if (defined $data->{options}) {
- my @bad_opts =grep !$Constants::SHOP_PRODUCT_OPTS{$_},
+ my $avail_options = product_options($self->{cfg});
+
+ my @bad_opts = grep !$avail_options->{$_},
split /,/, $data->{options};
if (@bad_opts) {
$errors->{options} = "Bad product options '". join(",", @bad_opts)."' entered";
sub {
if (++$item_index < @$cart) {
$option_index = -1;
- @options = cart_item_opts($cart->[$item_index],
+ @options = cart_item_opts($req,
+ $cart->[$item_index],
$cart_prods->[$item_index]);
undef $sem_session;
undef $location;
}
sub cart_item_opts {
- my ($cart_item, $product) = @_;
+ my ($req, $cart_item, $product) = @_;
+
+ my $avail_options = product_options($req->cfg);
my @options = ();
my @values = split /,/, $cart_item->{options};
my @ids = split /,/, $product->{options};
for my $opt_index (0 .. $#ids) {
- my $entry = $SHOP_PRODUCT_OPTS{$ids[$opt_index]};
+ my $entry = $avail_options->{$ids[$opt_index]};
my $option = {
id=>$ids[$opt_index],
value=>$values[$opt_index],
return 1; # this will change
}
+sub sessions_detail {
+ my ($self) = @_;
+
+ BSE::DB->query(bse_locationSessionDetail => $self->{id});
+}
+
1;
BSE::DB->run(updateSessionRollPresent => $present, $self->{id}, $userid);
}
+my @attendee_attributes =
+ qw/roll_present options customer_instructions support_notes/;
+my %attendee_defaults =
+ (
+ roll_present => 0,
+ options => '',
+ customer_instructions => '',
+ support_notes => '',
+ );
+
sub add_attendee {
- my ($self, $user, $present) = @_;
+ my ($self, $user, %attr) = @_;
+
+ my %work_attr = %attendee_defaults;
+ for my $key (keys %attr) {
+ exists $work_attr{$key} or
+ Carp::confess("Unknown attendee attribute '$key'");
+ $work_attr{$key} = $attr{$key};
+ }
- $present ||= 0;
my $user_id = ref $user ? $user->{id} : $user;
- BSE::DB->run(seminarSessionBookUser => $self->{id}, $user_id, $present);
+ BSE::DB->run(seminarSessionBookUser => $self->{id}, $user_id,
+ @work_attr{@attendee_attributes});
}
1;
sub get_refresh {
my ($class, $url, $cfg) = @_;
+
+ return
+ {
+ content => '',
+ headers => [
+ "Location: $url",
+ "Status: 302"
+ ],
+ };
+
# the commented out headers were meant to help Opera, but they didn't
return
{
#qq/Expires: Thu, 01 Jan 1970 00:00:00 GMT/
],
};
-
- return
- {
- content => '',
- headers => [
- "Location: $url",
- "Status: 302"
- ],
- };
-
}
sub template_dirs {
use BSE::Template;
use BSE::Util::Iterate;
use BSE::TB::Locations;
-use DevHelp::HTML;
+use DevHelp::HTML qw(:default popup_menu);
use constant SECT_LOCATION_VALIDATION => "BSE Location Validation";
+use BSE::CfgInfo 'product_options';
my %rights =
(
locadd => 'bse_location_add',
locedit => 'bse_location_edit',
locsave => 'bse_location_edit',
+ locview => 'bse_location_view',
locdelask => 'bse_location_delete',
locdelete => 'bse_location_delete',
# detail => 'bse_subscr_detail',
my %fields = BSE::TB::Location->valid_fields();
my $cfg_fields = $req->configure_fields(\%fields, SECT_LOCATION_VALIDATION);
+ my $it = BSE::Util::Iterate->new;
+
my %acts;
%acts =
(
error_img => [ \&tag_error_img, $req->cfg, $errors ],
location => [ \&tag_hash, $location ],
field => [ \&tag_field, $cfg_fields ],
+ $it->make_iterator([ \&iter_locsessions, $location ],
+ 'session', 'sessions'),
);
+ my $t = $req->cgi->param('_t');
+ if ($t && $t =~ /^\w+$/) {
+ $template .= "_$t";
+ }
+
return $req->dyn_response($template, \%acts);
}
+sub iter_locsessions {
+ my ($location) = @_;
+
+ $location->sessions_detail;
+}
+
sub req_locedit {
my ($class, $req, $errors) = @_;
return BSE::Template->get_refresh($r, $req->cfg);
}
+sub req_locview {
+ my ($class, $req, $errors) = @_;
+
+ return $class->_loc_show_common($req, $errors, 'admin/locations/view');
+}
+
sub req_locdelask {
my ($class, $req, $errors) = @_;
($req, { seminar_id => "Unknown seminar_id" });
my $msg = $req->message($errors);
+ my $avail_options = product_options($req->cfg);
+
+ my @sem_options = map +{ id => $_, %{$avail_options->{$_}} },
+ split /,/, $seminar->{options};
+ my $current_option;
+
my @sessions = $seminar->session_info;
my %user_booked = map { $_=>1 }
$siteuser->seminar_sessions_booked($seminar_id);
message => $msg,
error_img => [ \&tag_error_img, $req->cfg, $errors ],
$it->make_iterator(undef, 'session', 'sessions', \@sessions),
+ $it->make_iterator(undef, 'option', 'options', \@sem_options,
+ undef, undef, \$current_option),
+ option_popup => [ \&tag_option_popup, $req->cgi, \$current_option ],
);
return $req->dyn_response('admin/addattendee2.tmpl', \%acts);
}
+sub tag_option_popup {
+ my ($cgi, $roption) = @_;
+
+ $$roption
+ or return '** popup_option not in options iterator **';
+
+ my $option = $$roption;
+
+ my @extras;
+ if ($cgi->param($option->{id})) {
+ push @extras, -default => $cgi->param($option->{id});
+ }
+
+ return popup_menu(-name => $option->{id},
+ -values => $option->{values},
+ -labels => $option->{labels},
+ @extras);
+}
+
sub req_addattendsave {
my ($class, $req, $errors) = @_;
or return $class->req_addattendsession
($req, { session_id => "Unknown session_id" });
+ # accumulate the options
+ my %errors;
+ my @options;
+ for my $opt_name (split /,/, $seminar->{options}) {
+ my $value = $cgi->param($opt_name);
+ defined $value
+ or return $class->req_addattendsession
+ ($req, { opt_name => "Missing value for $opt_name" });
+
+ push @options, $value;
+ }
+
+ my %more;
+ for my $name (qw/customer_instructions support_notes roll_present/) {
+ my $value = $cgi->param($name);
+ $value and $more{$name} = $value;
+ }
+ $more{roll_present} ||= 0;
+
eval {
- $session->add_attendee($siteuser, 1);
+ $session->add_attendee($siteuser,
+ %more,
+ options => join(',', @options)
+ );
};
if ($@) {
if ($@ =~ /duplicate/i) {
require BSE::TB::SeminarSessions;
my $session = BSE::TB::SeminarSessions->getByPkey($item->{session_id});
eval {
- $session->add_attendee($user, 0);
+ $session->add_attendee($user,
+ instructions => $order->{instructions},
+ options => $item->{options});
};
}
}
sub {
if (++$item_index < @items) {
$option_index = -1;
- @options = cart_item_opts($items[$item_index],
+ @options = cart_item_opts($req,
+ $items[$item_index],
$products[$item_index]);
undef $sem_session;
undef $location;
my $product = Products->getByPkey($item->{productId});
my $extended = $product->{retailPrice} * $item->{units};
my $link = $product->{link};
- $link =~ /^\w+:/ or $link = $self->{req}->cfg->entryErr('site', 'url');
+ $link =~ /^\w+:/
+ or $link = $self->{req}->cfg->entryErr('site', 'url') . $link;
push @cart,
{
( map { $_ => $product->{$_} } $product->columns ),
# report conflicts with a tag name used within reports
subreport => [ \&tag_report, $cfg ],
+ ajax => '',
+ ifAjax => 0,
+
_format =>
sub {
my ($value, $fmt) = @_;
dynreplace => \&tag_replace,
dyntoday => \&tag_today,
dynreport => [ \&tag_report, $cfg ],
+ ajax => [ \&tag_ajax, $cfg ],
+ ifAjax => [ \&tag_ifAjax, $cfg ],
);
}
return BSE::Template->replace($html, $cfg, \%acts);
}
+sub _if_ajax {
+ my ($cfg) = @_;
+
+ return
+ unless $cfg->entry('basic', 'ajax', 0);
+
+ return 1
+ if $cfg->entry('basic', 'allajax', 0);
+
+ my $ua = $ENV{HTTP_USER_AGENT};
+
+ my %fail_entries = $cfg->entries('nonajax user agents');
+ for my $re (values %fail_entries) {
+ return
+ if $ua =~ /$re/;
+ }
+
+ my %entries = $cfg->entries('ajax user agents');
+ for my $re (values %entries) {
+ return 1
+ if $ua =~ /$re/;
+ }
+
+ return;
+}
+
+sub tag_ifAjax {
+ my ($cfg) = @_;
+
+ return _if_ajax($cfg) ? 1 : 0;
+}
+
+sub tag_ajax {
+ my ($cfg, $args, $acts, $tag_name, $templater) = @_;
+
+ return '' unless _if_ajax($cfg);
+
+ my ($name, $arg_rest) = split ' ', $args, 2;
+
+ my $defn = $cfg->entry('ajax definitions', $name)
+ or return "** unknown ajax definition $name **";
+ my ($type, $rest) = split ':', $defn, 2;
+
+ if ($type eq 'inline') {
+ # just replace $1, $2, etc in the rest of the text
+ my @args = DevHelp::Tags->get_parms($arg_rest, $acts, $templater);
+ my $macro = $rest;
+ eval {
+ $macro =~ s/(\$([1-9\$]))/
+ $2 eq '$' ? '$' : $2 <= @args
+ ? die "** not enough parameters for ajax definition $name **\n" : $args[$1-1]/xge;
+ };
+ $@ and return $@;
+
+ return $macro;
+ }
+ else {
+ return "** invalid type $type for ajax definition $name **";
+ }
+}
+
1;
sub refresh_to {
my ($where) = @_;
- print "Content-Type: text/html\n";
- print qq!Refresh: 0; url=$where\n\n<html></html>\n!;
+ #print "Content-Type: text/html\n";
+ #print qq!Refresh: 0; url=$where\n\n<html></html>\n!;
+ print "Status: 302\n";
+ print "Location: $where\n\n";
}
sub refresh_to_admin {
sub baseActs {
my ($self, $articles, $acts, $article, $embedded) = @_;
+ my $cfg = $self->{cfg} || BSE::Cfg->new;
+
# used to generate the list (or not) of children to this article
my $child_index = -1;
my @children = $articles->listedChildren($article->{id});
my $top = $self->{top} || $article;
my $abs_urls = $self->abs_urls($article);
+ my $dynamic = $self->{force_dynamic}
+ || (UNIVERSAL::isa($top, 'Article') ? $top->is_dynamic : 0);
+
my @stepkids;
my @allkids;
my @stepparents;
BSE::Util::Tags->make_iterator(\@allkids, 'allkid', 'allkids', \$allkids_index),
BSE::Util::Tags->make_iterator(\@stepparents, 'stepparent', 'stepparents'),
top => [ \&tag_top, $self, $article ],
- ifDynamic => [ \&tag_ifDynamic, $self, $top ],
+ ifDynamic => $dynamic,
ifAccessControlled => [ \&tag_ifAccessControlled, $article ],
);
if ($abs_urls) {
my $oldurl = $acts{url};
- my $cfg = $self->{cfg} || BSE::Cfg->new;
my $urlbase = $cfg->entryErr('site', 'url');
$acts{url} =
sub {
return $value;
};
}
+ if ($dynamic && $cfg->entry('basic', 'ajax', 0)) {
+ # make sure the ajax tags are left until we do dynamic replacement
+ delete @acts{qw/ajax ifAjax/};
+ }
+
return %acts;
}
use Carp qw(confess);
use DevHelp::HTML;
use BSE::Util::Tags qw(tag_hash);
+use BSE::CfgInfo 'product_options';
sub edit_link {
my ($self, $id) = @_;
my @stepcats = $product->step_parents();
my $stepcat_index;
+ my $avail_options = product_options($self->{cfg});
my @options =
- map { +{ id=>$_, %{$SHOP_PRODUCT_OPTS{$_}} } }
- grep $SHOP_PRODUCT_OPTS{$_},
+ map { +{ id=>$_, %{$avail_options->{$_}} } }
+ grep $avail_options->{$_},
split /,/, $product->{options};
my $option_index;
!$self->{textOnlyMail};
}
+sub seminar_bookings_detail {
+ my ($self) = @_;
+
+ BSE::DB->query(bse_siteuserSeminarBookingsDetail => $self->{id});
+}
+
1;
#!/usr/bin/perl -w
# -d:ptkdb
-BEGIN { $ENV{DISPLAY} = '192.168.32.15:0.0' }
+BEGIN { $ENV{DISPLAY} = '192.168.32.50:0.0' }
use strict;
use FindBin;
use lib "$FindBin::Bin/modules";
--- /dev/null
+--
+name: bse_siteuserSeminarBookingsDetail
+sql_statement: <<SQL
+select ar.*, pr.*, se.*, ss.*, sb.*,
+ lo.description as loc_description,
+ lo.room as loc_room,
+ lo.street1 as loc_street1,
+ lo.street2 as loc_street2,
+ lo.suburb as loc_suburb,
+ lo.state as loc_state,
+ lo.country as loc_country,
+ lo.postcode as loc_postcode,
+ lo.public_notes as loc_public_notes,
+ lo.bookings_name as loc_bookings_name,
+ lo.bookings_phone as loc_bookings_phone,
+ lo.bookings_fax as loc_bookings_fax,
+ lo.bookings_url as loc_bookings_url
+ from article ar, product pr, bse_seminars se, bse_seminar_sessions ss,
+ bse_locations lo, bse_seminar_bookings sb
+ where sb.siteuser_id = ?
+ and sb.session_id = ss.id
+ and ss.seminar_id = ar.id
+ and ss.seminar_id = pr.articleId
+ and ss.seminar_id = se.seminar_id
+ and ss.location_id = lo.id
+SQL
+
+name: bse_locationSessionDetail
+sql_statement: <<SQL
+select ar.*, pr.*, se.*, ss.*,
+ ss.id as session_id
+ from article ar, product pr, bse_seminars se, bse_seminar_sessions ss
+ where ss.location_id = ?
+ and ss.seminar_id = ar.id
+ and ss.seminar_id = pr.articleId
+ and ss.seminar_id = se.seminar_id
+ order by ss.when_at desc
+SQL
=head1 CHANGES
+=head2 0.15_45
+
+Note: you need to cd to the util directory and run:
+
+ perl loaddata.pl ../data/db
+
+from this release onwards.
+
+=over
+
+=item *
+
+partial implementation of non-shop seminar booking (database changes,
+modifying the shop to fill in the new booking fields)
+
+=item *
+
+partial implementation of Seminar Administration (access checks, extra
+fields on the booking form, view member detail, display of booked
+seminars for a user)
+
+=item *
+
+added view location target (a_locview) to admin_seminar.pl
+
+=item *
+
+added session list for a given location (available to all location
+displays, including edit, view, implemented as a_locview with
+_t=sessions)
+
+=item *
+
+new shop product options can now be configured in bse.cfg, so you
+don't need to touch bse.cfg. I'll document this later, see
+modules/BSE/CfgInfo.pm to see the code that does the work
+
+=back
+
=head2 0.15_44
=over
</select></td>
<td><:error_img session_id:></td>
</tr>
+<:iterator begin options:>
+ <tr>
+ <th><:option desc:></th>
+ <td><:option_popup:></td>
+ <td></td>
+ </tr>
+<:iterator end options:>
+ <tr>
+ <th>Customer<br />Instructions:</th>
+ <td><textarea name="customer_instructions" cols="70" rows="10" /><:old customer_instructions:></textarea></td>
+ <td><:error_img customer_instructions:></td>
+ </tr>
+ <tr>
+ <th>Support<br />Notes:</th>
+ <td><textarea name="support_notes" cols="70" rows="10" /><:old support_notes:></textarea></td>
+ <td><:error_img support_notes:></td>
+ </tr>
<tr>
<td colspan="3"><input type="submit" name="a_addattendsave" value="Select Session >>" /></td>
</tr>
<td><:ilocation street1:> <:ilocation street2:></td>
<td><:ilocation suburb:></td>
<td align="center"><:ifIlocation disabled:>Disabled<:or:><:eif:></td>
- <td><:ifUserCan bse_location_edit:><a href="<:script:>?a_locedit=1&id=<:ilocation id:>">Edit</a><:or:><:eif:> <:ifAnd [ifRemovable] [ifUserCan bse_location_delete]:><a href="<:script:>?a_locdelask=1&id=<:ilocation id:>">Delete</a><:or:><:eif:></td>
+ <td><:ifUserCan bse_location_edit:><a href="<:script:>?a_locedit=1&id=<:ilocation id:>">Edit</a><:or:><:eif:>
+<:ifUserCan bse_location_view:><a href="<:script:>?a_locview=1&id=<:ilocation id:>">View</a> <a href="<:script:>?a_locview=1&id=<:ilocation id:>&_t=sessions">Sessions</a><:or:><:eif:>
+<:ifAnd [ifRemovable] [ifUserCan bse_location_delete]:><a href="<:script:>?a_locdelask=1&id=<:ilocation id:>">Delete</a><:or:><:eif:></td>
</tr>
<:iterator end locations:>
<:or Locations:>
--- /dev/null
+<:wrap admin/xbase.tmpl title=>"View Location":>
+<h1>View Location</h1>
+<p>
+| <a href="/cgi-bin/admin/menu.pl">Admin menu</a> |
+<:if UserCan bse_location_list :>
+<a href="<:script:>?a_loclist=1">List Locations</a> |<:or UserCan:><:eif UserCan:>
+<a href="<:script:>?a_locview=1&id=<:location id:>&_t=sessions">Sessions</a> |
+<:ifMessage:>
+<p><b><:message:></b></p>
+<:or:><:eif:>
+
+<table>
+<tr>
+ <th><:field description description:>:</th>
+ <td><:location description:></td>
+ <td><:help addlocation description:></td>
+</tr>
+<tr>
+ <th><:field room description:>:</th>
+ <td><:location room:></td>
+ <td><:help addlocation room:></td>
+</tr>
+<tr>
+ <th><:field street1 description:>:</th>
+ <td><:location street1:></td>
+ <td><:help addlocation street1:></td>
+</tr>
+<tr>
+ <th><:field street2 description:>:</th>
+ <td><:location street2:></td>
+ <td><:help addlocation street2:></td>
+</tr>
+<tr>
+ <th><:field suburb description:>:</th>
+ <td><:location suburb:></td>
+ <td><:help addlocation suburb:></td>
+</tr>
+<tr>
+ <th><:field state description:>:</th>
+ <td><:location state:></td>
+ <td><:help addlocation state:></td>
+</tr>
+<tr>
+ <th><:field country description:>:</th>
+ <td><:location country:></td>
+ <td><:help addlocation country:></td>
+</tr>
+<tr>
+ <th><:field postcode description:>:</th>
+ <td><:location postcode:></td>
+ <td><:help addlocation postcode:></td>
+</tr>
+<tr>
+ <th><:field public_notes description:>:</th>
+ <td><textarea name="public_notes" rows="<:field public_notes height:>" cols="<:field public_notes width:>" wrap="virtual" readonly="readonly"><:location public_notes:></textarea></td>
+ <td><:help addlocation public_notes:></td>
+</tr>
+<tr>
+ <th>Disabled:</th>
+ <td><img src="/images/admin/<:ifLocation disabled:>checked.gif<:or:>unchecked.gif<:eif:>" /></td>
+ <td><:help addlocation disabled:></td>
+</tr>
+<tr>
+ <th colspan="2">Bookings</th>
+</tr>
+<tr>
+ <th><:field bookings_name description:>:</th>
+ <td><:location bookings_name:></td>
+ <td><:help addlocation bookings_name:></td>
+</tr>
+<tr>
+ <th><:field bookings_phone description:>:</th>
+ <td><:location bookings_phone:></td>
+ <td><:help addlocation bookings_phone:></td>
+</tr>
+<tr>
+ <th><:field bookings_fax description:>:</th>
+ <td><:location bookings_fax:></td>
+ <td><:help addlocation bookings_fax:></td>
+</tr>
+<tr>
+ <th><:field bookings_url description:>:</th>
+ <td><:location bookings_url:></td>
+ <td><:help addlocation bookings_url:></td>
+</tr>
+<tr>
+ <th colspan="2">Facilities</th>
+</tr>
+<tr>
+ <th><:field facilities_name description:>:</th>
+ <td><:location facilities_name:></td>
+ <td><:help addlocation facilities_name:></td>
+</tr>
+<tr>
+ <th><:field facilities_phone description:>:</th>
+ <td><:location facilities_phone:></td>
+ <td><:help addlocation facilities_phone:></td>
+</tr>
+<tr>
+ <th><:field admin_notes description:>:</th>
+ <td><textarea name="admin_notes" rows="<:field admin_notes height:>" cols="<:field admin_notes width:>" wrap="virtual" readonly="readonly"><:location admin_notes:></textarea></td>
+ <td><:help addlocation admin_notes:></td>
+</tr>
+
+</table>
--- /dev/null
+<:wrap admin/xbase.tmpl title=>"View Location Sessions":>
+<h1>View Location Sessions: <:location description:></h1>
+<p>
+| <a href="/cgi-bin/admin/menu.pl">Admin menu</a>
+<:if UserCan bse_location_list :>
+| <a href="<:script:>?a_loclist=1">List Locations</a><:or UserCan:><:eif UserCan:>
+| <a href="<:script:>?a_locview=1&id=<:location id:>">Location Detail</a> |</p>
+<:ifMessage:>
+<p><b><:message:></b></p>
+<:or:><:eif:>
+
+<table>
+ <tr>
+ <th>Seminar</th>
+ <th>Date</th>
+ <th>Time</th>
+ <th></th>
+ </tr>
+<:if Sessions:>
+<:iterator begin sessions:>
+ <tr>
+ <td><a href="/cgi-bin/admin/add.pl?id=<:session seminar_id:>"><:session title:></a></td>
+ <td><:date session when_at:></td>
+ <td><:date "%I:%M %P" session when_at:></td>
+ <td>
+ <a href="/cgi-bin/admin/add.pl?a_semsessionbookings=1&id=<:session seminar_id:>&session_id=<:session session_id:>">Bookings</a>
+ </td>
+ </tr>
+<:iterator end sessions:>
+<:or Sessions:>
+ <tr>
+ <td colspan="4" align="center">No Sessions at this location</td>
+ </tr>
+<:eif Sessions:>
+</table>
\ No newline at end of file
<h1>Add Site Member</h1>
<p>
| <a href="/cgi-bin/admin/menu.pl">Admin menu</a> |
-<a href="/cgi-bin/admin/siteusers.pl">Site Members</a> |
-<a href="mailto:<:siteuser email:>">Email</a> |</p>
+<a href="/cgi-bin/admin/siteusers.pl">Site Members</a> |</p>
<:ifMessage:>
<p><b><:message:></b></p>
| <a href="/cgi-bin/admin/menu.pl">Admin menu</a> |
<a href="/cgi-bin/admin/siteusers.pl">Site Members</a> |
<a href="mailto:<:siteuser email:>">Email</a>
-<:ifUserorders:>| <a href="/cgi-bin/admin/siteusers.pl?a_edit=1&id=<:siteuser id:>&_t=orders">Orders</a><:or:><:eif:> |
+<:ifUserorders:>| <a href="/cgi-bin/admin/siteusers.pl?a_view=1&id=<:siteuser id:>&_t=orders">Orders</a><:or:><:eif:> |
<a href="/cgi-bin/admin/admin_seminar.pl?a_addattendseminar=1&siteuser_id=<:siteuser id:>">Add to seminar</a> |
+<a href="/cgi-bin/admin/siteusers.pl?a_view=1&id=<:siteuser id:>&_t=bookings">Seminar Bookings</a> |
<a href="<:script:>?a_edit=1&id=<:siteuser id:>&_t=groups">Groups</a> |
</p>
<p>
| <a href="/cgi-bin/admin/menu.pl">Admin menu</a> |
<a href="/cgi-bin/admin/siteusers.pl">Site Members</a> |
-<a href="mailto:<:siteuser email:>">Email</a>
-| <a href="/cgi-bin/admin/siteusers.pl?a_edit=1&id=<:siteuser id:>">Edit User</a> |</p>
+<a href="mailto:<:siteuser email:>">Email</a> |
+<:ifUserCan bse_members_user_edit:><a href="/cgi-bin/admin/siteusers.pl?a_edit=1&id=<:siteuser id:>">Edit User</a> |<:or:><:eif:>
+<a href="/cgi-bin/admin/siteusers.pl?a_view=1&id=<:siteuser id:>">User Details</a> |</p>
<:ifMessage:>
<p><b><:message:></b></p>
--- /dev/null
+<:wrap admin/xbase.tmpl title=>"Edit Site Member":>
+<h1>Edit Site Member</h1>
+<p>
+| <a href="/cgi-bin/admin/menu.pl">Admin menu</a> |
+<a href="/cgi-bin/admin/siteusers.pl">Site Members</a> |
+<a href="mailto:<:siteuser email:>">Email</a>
+<:ifUserorders:>| <a href="/cgi-bin/admin/siteusers.pl?a_edit=1&id=<:siteuser id:>&_t=orders">Orders</a><:or:><:eif:> |
+<a href="/cgi-bin/admin/admin_seminar.pl?a_addattendseminar=1&siteuser_id=<:siteuser id:>">Add to seminar</a> |
+<a href="/cgi-bin/admin/siteusers.pl?a_view=1&id=<:siteuser id:>&_t=bookings">Seminar Bookings</a> |
+<a href="<:script:>?a_edit=1&id=<:siteuser id:>&_t=groups">Groups</a> |
+</p>
+
+<:ifMessage:>
+<p><b><:message:></b></p>
+<:or:><:eif:>
+
+ <table border="0" cellspacing="0" cellpadding="0" bgcolor="#000000" class="table">
+ <tr>
+ <td>
+ <table cellpadding="6" border="0" cellspacing="1">
+<:ifCfg "site users" nopassword:><:or:>
+ <tr>
+ <th bgcolor="#FFFFFF" align="left">Logon: </th>
+ <td bgcolor="#FFFFFF">
+ <:siteuser userId:>
+ </td>
+ <td bgcolor="#FFFFFF"><:help editsiteuser userId:></td>
+ </tr>
+<:eif:>
+ <tr>
+ <th bgcolor="#FFFFFF" align="left">Email: </th>
+ <td bgcolor="#FFFFFF">
+ <a href="mailto:<:siteuser email:>"><:siteuser email:></a>
+ </td>
+ <td bgcolor="#FFFFFF"><:help editsiteuser email:></td>
+ </tr>
+ <tr>
+ <th bgcolor="#FFFFFF" align="left">Disabled: </th>
+ <td bgcolor="#FFFFFF">
+ <:ifSiteuser disabled:>User disabled<:or:>User enabled<:eif:>
+ </td>
+ <td bgcolor="#FFFFFF"><:help editsiteuser disabled:></td>
+ </tr>
+ <tr>
+ <th bgcolor="#FFFFFF" align="left">First Name: </th>
+ <td bgcolor="#FFFFFF">
+ <:siteuser name1:>
+ </td>
+ <td bgcolor="#FFFFFF"><:help editsiteuser name1:></td>
+ </tr>
+ <tr>
+ <th bgcolor="#FFFFFF" align="left">Last Name: </th>
+ <td bgcolor="#FFFFFF">
+ <:siteuser name2:>
+ </td>
+ <td bgcolor="#FFFFFF"><:help editsiteuser name2:></td>
+ </tr>
+ <tr>
+ <th bgcolor="#FFFFFF" align="left">address: </th>
+ <td bgcolor="#FFFFFF">
+ <:siteuser address:>
+ </td>
+ <td bgcolor="#FFFFFF"><:help editsiteuser address:></td>
+ </tr>
+ <tr>
+ <th bgcolor="#FFFFFF" align="left">city: </th>
+ <td bgcolor="#FFFFFF">
+ <:siteuser city:>
+ </td>
+ <td bgcolor="#FFFFFF"><:help editsiteuser city:></td>
+ </tr>
+ <tr>
+ <th bgcolor="#FFFFFF" align="left">state: </th>
+ <td bgcolor="#FFFFFF">
+ <:siteuser state:>
+ </td>
+ <td bgcolor="#FFFFFF"><:help editsiteuser state:></td>
+ </tr>
+ <tr>
+ <th bgcolor="#FFFFFF" align="left">postcode: </th>
+ <td bgcolor="#FFFFFF">
+ <:siteuser postcode:>
+ </td>
+ <td bgcolor="#FFFFFF"><:help editsiteuser postcode:></td>
+ </tr>
+ <tr>
+ <th bgcolor="#FFFFFF" align="left">telephone: </th>
+ <td bgcolor="#FFFFFF">
+ <:siteuser telephone:>
+ </td>
+ <td bgcolor="#FFFFFF"><:help editsiteuser telephone:></td>
+ </tr>
+ <tr>
+ <th bgcolor="#FFFFFF" align="left">mobile: </th>
+ <td bgcolor="#FFFFFF">
+ <:siteuser delivMobile:>
+ </td>
+ <td bgcolor="#FFFFFF"><:help editsiteuser delivMobile:></td>
+ </tr>
+ <tr>
+ <th bgcolor="#FFFFFF" align="left">facsimile: </th>
+ <td bgcolor="#FFFFFF">
+ <:siteuser facsimile:>
+ </td>
+ <td bgcolor="#FFFFFF"><:help editsiteuser facsimile:></td>
+ </tr>
+ <tr>
+ <th bgcolor="#FFFFFF" align="left">country: </th>
+ <td bgcolor="#FFFFFF">
+ <:siteuser country:>
+ </td>
+ <td bgcolor="#FFFFFF"><:help editsiteuser country:></td>
+ </tr>
+ <tr>
+ <th bgcolor="#FFFFFF" align="left">title: </th>
+ <td bgcolor="#FFFFFF">
+ <:siteuser title:>
+ </td>
+ <td bgcolor="#FFFFFF"><:help editsiteuser title:></td>
+ </tr>
+ <tr>
+ <th bgcolor="#FFFFFF" align="left">organization: </th>
+ <td bgcolor="#FFFFFF">
+ <:siteuser organization:>
+ </td>
+ <td bgcolor="#FFFFFF"><:help editsiteuser organization:></td>
+ </tr>
+ <tr>
+ <th bgcolor="#FFFFFF" align="left">billFirstName: </th>
+ <td bgcolor="#FFFFFF">
+ <:siteuser billFirstName:>
+ </td>
+ <td bgcolor="#FFFFFF"><:help editsiteuser billFirstName:></td>
+ </tr>
+ <tr>
+ <th bgcolor="#FFFFFF" align="left">billLastName: </th>
+ <td bgcolor="#FFFFFF">
+ <:siteuser billLastName:>
+ </td>
+ <td bgcolor="#FFFFFF"><:help editsiteuser billLastName:></td>
+ </tr>
+ <tr>
+ <th bgcolor="#FFFFFF" align="left">billStreet: </th>
+ <td bgcolor="#FFFFFF">
+ <:siteuser billStreet:>
+ </td>
+ <td bgcolor="#FFFFFF"><:help editsiteuser billStreet:></td>
+ </tr>
+ <tr>
+ <th bgcolor="#FFFFFF" align="left">billSuburb: </th>
+ <td bgcolor="#FFFFFF">
+ <:siteuser billSuburb:>
+ </td>
+ <td bgcolor="#FFFFFF"><:help editsiteuser billSuburb:></td>
+ </tr>
+ <tr>
+ <th bgcolor="#FFFFFF" align="left">billState: </th>
+ <td bgcolor="#FFFFFF">
+ <:siteuser billState:>
+ </td>
+ <td bgcolor="#FFFFFF"><:help editsiteuser billState:></td>
+ </tr>
+ <tr>
+ <th bgcolor="#FFFFFF" align="left">billPostCode: </th>
+ <td bgcolor="#FFFFFF">
+ <:siteuser billPostCode:>
+ </td>
+ <td bgcolor="#FFFFFF"><:help editsiteuser billPostCode:></td>
+ </tr>
+ <tr>
+ <th bgcolor="#FFFFFF" align="left">billCountry: </th>
+ <td bgcolor="#FFFFFF">
+ <:siteuser billCountry:>
+ </td>
+ <td bgcolor="#FFFFFF"><:help editsiteuser billCountry:></td>
+ </tr>
+ <tr>
+ <th bgcolor="#FFFFFF" align="left">instructions: </th>
+ <td bgcolor="#FFFFFF">
+ <:siteuser instructions:>
+ </td>
+ <td bgcolor="#FFFFFF"><:help editsiteuser instructions:></td>
+ </tr>
+ <tr>
+ <th bgcolor="#FFFFFF" align="left">billTelephone: </th>
+ <td bgcolor="#FFFFFF">
+ <:siteuser billTelephone:>
+ </td>
+ <td bgcolor="#FFFFFF"><:help editsiteuser billTelephone:></td>
+ </tr>
+ <tr>
+ <th bgcolor="#FFFFFF" align="left">billMobile: </th>
+ <td bgcolor="#FFFFFF">
+ <:siteuser billMobile:>
+ </td>
+ <td bgcolor="#FFFFFF"><:help editsiteuser billMobile:></td>
+ </tr>
+ <tr>
+ <th bgcolor="#FFFFFF" align="left">billFacsimile: </th>
+ <td bgcolor="#FFFFFF">
+ <:siteuser billFacsimile:>
+ </td>
+ <td bgcolor="#FFFFFF"><:help editsiteuser billFacsimile:></td>
+ </tr>
+ <tr>
+ <th bgcolor="#FFFFFF" align="left">billEmail: </th>
+ <td bgcolor="#FFFFFF">
+ <:siteuser billEmail:>
+ </td>
+ <td bgcolor="#FFFFFF"><:help editsiteuser billEmail:></td>
+ </tr>
+ <tr>
+ <th bgcolor="#FFFFFF" align="left">Affiliate Name: </th>
+ <td bgcolor="#FFFFFF">
+ <:siteuser affiliate_name:>
+ </td>
+ <td bgcolor="#FFFFFF"><:help editsiteuser affiliate_name:></td>
+ </tr>
+ <tr>
+ <th bgcolor="#FFFFFF" align="left" valign="top">Admin Notes: </th>
+ <td bgcolor="#FFFFFF">
+ <textarea name="adminNotes" wrap="soft" rows="5" cols="60" readonly="readonly"><:siteuser adminNotes:></textarea>
+ </td>
+ <td bgcolor="#FFFFFF" valign="top"><:help editsiteuser adminNotes:></td>
+ </tr>
+<:if Flags:>
+ <tr>
+ <th bgcolor="#FFFFFF" align="left" valign="top">Flags: </th>
+ <td bgcolor="#FFFFFF">
+ <:iterator begin flags:>
+ <img src="/images/admin/<:ifFlagSet [flag id]:>checked.gif<:or:>unchecked.gif<:eif:>" /> <:flag desc:>
+ <:iterator separator flags:>
+ <br />
+ <:iterator end flags:>
+ </td>
+ <td bgcolor="#FFFFFF" valign="top"><:help editsiteuser flags:></td>
+ </tr>
+<:or Flags:><:eif Flags:>
+<:if Subscriptions:>
+ <tr>
+ <th bgcolor="#FFFFFF" align="left" valign="top">Subscriptions: </th>
+ <td bgcolor="#FFFFFF">
+ <:iterator begin subscriptions:>
+ <img src="/images/admin/<:ifSubscribed:>checked.gif<:or:>unchecked.gif<:eif:>" /> <:subscription name:>
+ <:iterator separator subscriptions:>
+ <br />
+ <:iterator end subscriptions:>
+ </td>
+ <td bgcolor="#FFFFFF" valign="top"><:help editsiteuser subscriptions:></td>
+ </tr>
+<:or Subscriptions:><:eif Subscriptions:>
+<:iterator begin imagetemplates:>
+ <tr>
+ <th bgcolor="#FFFFFF" align="left"> <:imagetemplate description:>: </th>
+ <td bgcolor="#FFFFFF">
+ Alt: <:siteuser_image [imagetemplate id] alt:><br />
+ <:ifSiteuser_image [imagetemplate id]:><br /><img src="<:siteuser_image [imagetemplate id] url:>" /><:or:><:eif:>
+ </td>
+ <td bgcolor="#FFFFFF"> <:help editsiteuser images:></td>
+ </tr>
+<:iterator end imagetemplates:>
+<:include admin/users/custom_view.tmpl optional:>
+ </table>
+ </td>
+ </tr>
+ </table>
+</form>
--- /dev/null
+<:wrap admin/xbase.tmpl title=>"Site Member Seminar Bookings":>
+<h1>Site Member Seminar Bookings</h1>
+<p>
+| <a href="/cgi-bin/admin/menu.pl">Admin menu</a> |
+<a href="/cgi-bin/admin/siteusers.pl">Site Members</a> |
+<a href="mailto:<:siteuser email:>">Email</a> |
+<:ifUserCan bse_members_user_edit:><a href="/cgi-bin/admin/siteusers.pl?a_edit=1&id=<:siteuser id:>">Edit User</a> |<:or:><:eif:>
+<a href="/cgi-bin/admin/siteusers.pl?a_view=1&id=<:siteuser id:>">User Details</a> |
+<a href="/cgi-bin/admin/siteusers.pl?a_view=1&id=<:siteuser id:>&_t=orders">Orders</a> |</p>
+
+<:ifMessage:>
+<p><b><:message:></b></p>
+<:or:><:eif:>
+
+ <table border=0 cellpadding="6" cellspacing="1" width="100%">
+ <tr bgcolor="#FFFFFF">
+ <th>Id</th>
+ <th width="50%">Seminar</th>
+ <th width="50%">Location</th>
+ <th>Time</th>
+ <th>Date</th>
+ </tr>
+ <:iterator begin bookings:>
+ <tr bgcolor="#FFFFFF">
+ <td align="center" nowrap><a href="/cgi-bin/admin/add.pl?id=<:booking seminar_id:>"><:booking
+ seminar_id:></a></td>
+ <td><:booking title:></td>
+ <td><a href="/cgi-bin/admin/admin_seminar.pl?a_locview=1&id=<:booking location_id:>"><:booking loc_description:></a></td>
+ <td nowrap="nowrap"><:date "%I:%M %p" booking when_at:></td>
+ <td nowrap="nowrap"><:date booking when_at:></td>
+ </tr>
+ <:iterator end bookings:>
+ </table>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta http-equiv="Expires" content="Thu, 01 Jan 1970 00:00:00 GMT">
<link rel="stylesheet" href="/css/style-main.css">
-<:ifCfg basic ajax:><script type="text/javascript" src="/js/prototype.js"></script><:or:><:eif:>
+<:ajax includes:>
</head>
<script>
var bse_image_popup;
<td><font face="Verdana, Arial, Helvetica, sans-serif" size="-2"><input type="checkbox" name="match_all" value="1" <:ifCgi match_all:>checked="checked"<:or:><:eif:> /><b> Match all terms</b></font></td>
</tr>
</table>
-<:ifCfg basic ajax:>
+<:if Ajax:>
<script>
new Form.Element.Observer($('q'), 1.5,
function(term) {
});
});
</script>
-<:or:><:eif:>
+<:or Ajax:><:eif Ajax:>
</form>
<div id="results">
<:include include/search_results.tmpl:>
search highlight.body_suffix=</i>
search highlight.title_prefix=<i>
search highlight.title_suffix=</i>
+valid child types.Article=Article,Seminar
+
+shop product options.book_flight=Flight Booking;Book a flight;Don't book a flight