# ================================================================== # Gossamer Community # # Website : http://gossamer-threads.com/ # Support : http://gossamer-threads.com/scripts/support/ # CVS Info : # Revision : $Id: SSI.pm,v 1.24 2005/07/21 23:18:26 alex Exp $ # # Copyright (c) 2004 Gossamer Threads Inc. All Rights Reserved. # Redistribution in part or in whole strictly prohibited. Please # see LICENSE file for full details. # ================================================================== package Community::Web::SSI; # =================================================================== use strict; use Community qw/ $IN $DB $CFG comm_language comm_debug comm_fatal /; use GT::Plugins; sub process { # ------------------------------------------------------------------- my $do = shift; my %valid = ( map { $_ => 1 } qw( ssi_username ssi_login ssi_profile_form ssi_apps_form ) ); $do = exists $valid{$do} ? $do : 'ssi_username'; return GT::Plugins->dispatch( $CFG->{path_private} . '/lib/Plugins/Community', "web_$do", \&$do, @_ ); } sub ssi_username { # ------------------------------------------------------------------- my $user = $IN->cookie($CFG->{session_cookie_name_user}); my $name = (defined $user and length $user) ? $user : comm_language('SSI_GUEST'); if ($IN->param('do') eq 'ssi_username') { print $IN->header() unless ($IN->param('noheaders')); print $name; } else { return $name; } } sub ssi_login { # ------------------------------------------------------------------- my $user = $IN->cookie($CFG->{session_cookie_name_user}); my $name = (defined $user and length $user) ? $user : undef; require Community::Web::User; if ($IN->param('do') eq 'ssi_login') { print $IN->header() unless ($IN->param('noheaders')); Community::Web::User::user_page('user_ssi_login.html', { comm_username => $name }, { print => 1 }); } else { return Community::Web::User::user_page('user_ssi_login.html', { comm_username => $name }, { print => 0 }); } } sub ssi_profile_form { # ------------------------------------------------------------------- require GT::SQL::Display::HTML; require GT::SQL::Display::HTML::Table; my $opts = ref $_[0] ? shift : {@_}; my $user_tb = $DB->table('comm_users'); $opts->{col_prefix} ||= '^prof_'; # used to filter columns $opts->{tr} ||= 'class="body"'; $opts->{td_l} ||= 'class="body" width="40%" align="right"'; $opts->{td_r} ||= 'class="body" align="left"'; $opts->{mode} ||= 'edit'; # edit/search $opts->{required} ||= '*'; $opts->{show_all_fields} ||= 0; # ignore sign_restricted_profile? # Take the list of restricted profile fields # and convert it into a hashref that can be used as a lookup # to quickly determine matches, but check to see that # the system isn't being requested to display all possible profile # fields my $restricted_fields = $opts->{show_all_fields} ? {} : { map {($_=>1)} @{$CFG->{signup_restricted_profile}} }; # Choose which columns will be displayed. unless ( $opts->{cols} ) { my $cols = $opts->{cols} = []; my $skip = { map {($_=>1)} @{$opts->{col_skip}||[]} }; foreach ( $user_tb->ordered_columns ) { next if $restricted_fields->{$_}; # MOD if ($_ eq "prof_Signup_Date") { next; } # END MOD next unless /$opts->{col_prefix}/; next if $skip->{$_}; push @$cols, $_; } $opts->{cols} = $cols; } my $tags = GT::Template->tags; my $cols = {$user_tb->cols}; # request a copy of the def my $disp = $DB->html($user_tb, GT::Template->tags); my $html = ''; if ( $opts->{mode} eq 'hidden' ) { # Preserve all columns that relate to the comm_user database my $cols = $user_tb->cols; my $hidden_html = ''; foreach my $col ( keys %$cols ) { foreach my $name ( map { "$col$_" } ( '', qw( -opt -gt -lt -le -ge -ne )) ) { my $v = $tags->{$name}; next unless defined $v; my $input_html = ssi_form_control({ form_type => 'hidden', value => $v, name => $name }); $html .= $$input_html; } } return \$html; } my %search_defs = ( string => { form_names => [qw( LIKE <> = )] }, number => { form_names => [qw( = <> < <= > >= )] }, date => { form_names => [ '', qw( = <> < <= > >= )] }, radio => { form_names => [qw( = <> )] }, minimal => { form_names => [qw( = )] } ); foreach my $col (@{$opts->{cols}}) { # MOD if ($col eq "prof_Signup_Date") { next; } # END MOD my $control_opts = $cols->{$col}||{}; my $title = comm_language( $cols->{$col}{form_display} ); if ( $opts->{mode} eq 'search' ) { my $col_type; my $col_info = $cols->{$col}; if ( $col_info->{form_type} =~ /TEXT|HIDDEN|CHECKBOX/i ) { $col_type = $col_info->{type} =~ /CHAR|TEXT/i ? 'string' : $col_info->{type} =~ /INT|FLOAT|DOUBLE/i ? 'number' : $col_info->{type} =~ /DATE/i ? 'date' : ''; } elsif ( $col_info->{form_type} =~ /CHECKBOX|RADIO/i ) { unshift @{$control_opts->{form_values}}, comm_language( 'ADMIN_DB_FILTER_RADIO_ANY' ); unshift @{$control_opts->{form_names}}, ''; $col_type = 'radio'; } elsif ( $col_info->{form_type} =~ /DATE/i ) { $col_type = 'date'; } elsif ( $col_info->{form_type} =~ /SELECT/i ) { } my $option_html = \''; if ( $col_type ) { my $search_def = $search_defs{ $col_type }; $search_def->{form_values} ||= do { [ split /\|/, comm_language( 'ADMIN_DB_FILTER_' . uc( $col_type ) ) ]; }; $option_html = ssi_form_control({ name => $col . '-opt', def => $search_def, value => $tags->{$col.'-opt'}||'', form_type => 'select', blank => 0, }); } my $input_html = ssi_form_control( name => $col, def => $control_opts , value => $tags->{$col} ); $html .= qq|{tr}> {td_l}>$title: {td_r}>$$input_html $$option_html |; } else { my $input_html = ssi_form_control({ name => $col, def => $control_opts, value => $tags->{$col} }); $html .= ( $cols->{$col}->{not_null} ) ? "{tr}>{td_l}>$title:{td_r}>$$input_html $opts->{required}" : "{tr}>{td_l}>$title:{td_r}>$$input_html"; } } if ($IN->param('do') eq 'ssi_profile_form') { print $IN->header() unless ($IN->param('noheaders')); print $html; } else { return \$html; } } sub ssi_apps_form { # ------------------------------------------------------------------- my %opts = @_; $opts{mode} ||= 'edit'; # edit/search type forms $opts{tr} ||= 'class="body"'; $opts{td_l} ||= 'class="body" width="40%" align="right"'; $opts{td_r} ||= 'class="body" align="left"'; $opts{tags} ||= GT::Template->tags; my $tags = GT::Template->tags; my $apps = $DB->table('comm_apps')->select->fetchall_hashref; my $html = ''; my $status = comm_language('ADMIN_APPS_STATUS'); require Community::Apps; my $search_def = { form_names => [qw( = <> )], form_values => [ split /\|/, comm_language( 'ADMIN_DB_FILTER_RADIO' ) ] }; foreach my $app (@$apps) { if ($opts{admin}) { my $col = 'app_' . $app->{app_keyword}; my $name = $DB->table('comm_users')->cols->{$col}->{form_display} || $col; my $select = ssi_form_control({ name => $col, form_type => 'select', def => { form_values => [ comm_language('ADMIN_APPS_STATUS_NOTCREATED'), comm_language('ADMIN_APPS_STATUS_DISABLED'), comm_language('ADMIN_APPS_STATUS_ENABLED'), ], form_names => [ 0, 1, 2 ] }, value => $opts{tags}{$col}, blank => ( $opts{mode} eq 'search' ) }); $html .= qq~ $name $status $$select~; if ( $opts{mode} eq 'search' ) { my $option_html = ssi_form_control({ name => "$col-opt", def => $search_def, value => $tags->{"$col-opt"}, form_type => 'select', blank => 0 }); $html .= "$$option_html"; } $html .= ''; } unless ( $opts{mode} eq 'search' ) { $html .= Community::Apps::run($app, 'signup_form', \%opts); } } if ($IN->param('do') eq 'ssi_apps_form') { print $IN->header() unless ($IN->param('noheaders')); print $html; } else { return \$html; } } sub ssi_form_control { # ------------------------------------------------------------------- require GT::SQL::Display::HTML; require GT::SQL::Display::HTML::Table; require GT::Template; my $opts = ref $_[0] eq 'HASH' ? shift : {@_}; my $user_tb = $DB->table('comm_users'); my $tags = GT::Template->tags || {}; my $disp = $DB->html($user_tb, $tags); my $form_type = lc( $opts->{form_type} || $opts->{def}{form_type} ); exists $opts->{blank} or $opts->{blank} = $form_type eq 'select' ? 1 : 0; my $input_html = 'radio' eq $form_type ? $disp->radio( $opts ) : 'checkbox' eq $form_type ? $disp->checkbox( $opts ) : 'select' eq $form_type ? do { $opts->{form_size} ||= $opts->{def}{form_size}; $disp->select( $opts ); } : 'hidden' eq $form_type ? $disp->hidden( $opts ) : 'multiple' eq $form_type ? do { $opts->{form_size} ||= $opts->{def}{form_size}; $opts->{multiple} = $opts->{form_size}; $disp->multiple( $opts ) }: 'textarea' eq $form_type ? $disp->textarea( $opts ) : 'file' eq $form_type ? "File type not supported." : 'date' eq $form_type ? do { require GT::Date; my ($sel_year, $sel_mon, $sel_day) = split /\-/, GT::CGI::html_escape($opts->{value}); $sel_year ||= 1970; $sel_mon ||= 1; $sel_day ||= 1; my $month_sel = $disp->select({ name => "$opts->{name}-mon", value => $sel_mon, values => { map { sprintf("%02d", $_) => $GT::Date::LANGUAGE->{short_month_names}->[$_ - 1] } (1 .. 12) }, sort => [ map { sprintf("%02d", $_) } (1 .. 12) ], blank => 1 }); my $day_sel = $disp->select({ name => "$opts->{name}-day", value => $sel_day, values => { map { sprintf("%02d", $_) => $_ } (1 .. 31) }, sort => [ map { sprintf("%02d", $_) } (1 .. 31) ], blank => 1 }); qq~ $day_sel / $month_sel / ~; } : $disp->text($opts); return \$input_html; } sub ssi_select { #-------------------------------------------------------------------- # There are three ways of calling this include. # # The first is simply to provide a column name to a comm_users table # field that has an appropriately defined select display form # configured. # # The second method is to provide a single parameter that is a hashref # which contains the values as below. The main difference is that # single parameter options (ie. multiple and blank) to be active must # be a true value. # # The third method is to manually define the options that will define # how the select option will be created by using a quasi named parameter # setup. # # name : Required. name of the select box # options : Required. If the subsequent parameter is a hashref, it will # use the reference (treated as { option value => option display }) # to generate the option fields. Otherwise, it will assume that the # proceeding values are "option value", then "option display" pairs # until the parameter "/option" is encountered # value : Optional. "\n" delimited text or arrayref of currently # active values, if not provided it will extract from the # current tags based upon the name of the select box. It will then # take the values found and "select" the appropriate entries in # the select box. # order : Optional. If the subsequent parameter is an arrayref, it will # become the list of option values to force order of display. # Otherwise, it will be assumed that until the parameter "/order" # is encountered, that the following values provided are a # part of the list. # multiple : Optional. convert the select list into a multi-select form. # This is a single parameter switch. The next parameter should # follow immediately after this option. # form_size : Optional. size of the form to be displayed. # extra : Optional. extra parameters to be a part of the parameters of # the select control. This can be used to apply a style or # declare a style class onto a rendered select control. If # the subsequent parameter is a hashref but if not, the code # will assume "key", "value" pairs until "/extra" is encountered. # blank : Optional. If a true value, a blank value will be inserted as # the first option in the dropdown. This is a single parameter # switch. The next parameter should follow immediately after this # option. # my $select_opts = {}; require GT::Template; my $tags = GT::Template->tags || {}; if ( @_ == 1 and 'HASH' eq ref $_[0] ) { $select_opts = shift; } elsif ( @_ == 1 ) { my $col = shift; my $user_tb = $DB->table( 'comm_users' ); my $cols = $user_tb->cols; my $options = {}; return if ( lc $cols->{$col}->{form_type} ne 'select' ); @$options{@{$cols->{$col}{form_names}}} = @{$cols->{$col}{form_values}}; $select_opts = { form_type => 'select', name => $col, def => $cols->{$col}, options => $options, blank => 0 }; } else { while ( @_ ) { $_ = lc shift; if ( /^name$/ ) { $select_opts->{name} = shift; } elsif ( /^options$/ ) { if ( 'HASH' eq ref $_[0] ) { $select_opts->{options} = shift; } elsif ( 'ARRAY' eq ref $_[0] ) { my $order = shift; my $options = {map {($_=>$_)} @$order}; $select_opts->{options} = $options; } else { my $options = {}; while ( @_ and lc $_[0] ne '/options' ) { my ( $k, $v ) = splice @_, 0, 2; $options->{$k} = $v; } shift; $select_opts->{options} = $options; } } elsif ( /^value$/ ) { my $value = shift; if ( 'ARRAY' eq ref $value ) { $value = { map {($_=>1)} @$value }; } elsif ( not ref $value ) { my @values = split /\n/, $value; $value = { map {($_=>1)} @values }; } else {}; # assume best case: hashref $select_opts->{value} = $value; } elsif ( /^order$/ ) { if ( 'ARRAY' eq ref $_[0] ) { $select_opts->{options} = shift; } else { my $order = []; while ( @_ and lc $_[0] ne '/order' ) { push @$order, shift; } shift; $select_opts->{order} = $order; } } elsif ( /^multiple$/ ) { $select_opts->{multiple} = 1; } elsif ( /^form_size$/ ) { $select_opts->{form_size} = shift; } elsif ( /^extra$/ ) { if ( 'HASH' eq ref $_[0] ) { $select_opts->{extra} = shift; } else { my $extra = {}; while ( @_ and lc $_[0] ne '/extra' ) { my ( $k, $v ) = splice @_, 0, 2; $extra->{$k} = $v; } shift; $select_opts->{extra} = $extra; } } elsif ( /^blank$/ ) { $select_opts->{blank} = 1; } } } # Make sure we have something to work with at the very least. return unless $select_opts->{name} and $select_opts->{options}; require GT::CGI; # should already be loaded but just in case. my $name = GT::CGI->html_escape( $select_opts->{name} ); my $mult = $select_opts->{multiple} ? "multiple " : ""; my $size = $select_opts->{form_size} ? qq{size="$select_opts->{form_size}" } : ""; my $input_html = qq{{value}; unless ( $value ) { require GT::Template; my $tags_val = GT::Template->tags->{$select_opts->{name}}; $value = {}; if ( 'ARRAY' eq ref $tags_val ) { $value = {map {($_=>1)} @$tags_val}; } elsif ( 'HASH' eq ref $tags_val ) { $value = $tags_val; } else { $value = {map {($_=>1)} split /\n/, $tags_val }; } } # Options. First get a list of all the options to be included # in the list my $options = $select_opts->{options}; my @order; if ( $select_opts->{order} ) { @order = @{$select_opts->{order}}; } else { @order = sort keys %$options; } # Add a blank in the options if requested. if ( $select_opts->{blank} ) { $input_html .= qq{}; } foreach ( @order ) { my $disp = GT::CGI->html_escape($options->{$_}); my $selected = $value->{$_} ? " selected" : ""; $input_html .= qq{}; } $input_html .= ""; return \$input_html; } sub ssi_comm_fields { #-------------------------------------------------------------------- # This returns all the comm_user table fields in an arrayref with # hashrefs detailing the column info. If the parameter "all" => 1, # then all fields are returned, otherwise, a small selection of # only the most important fields will be returned. # # Options: # # show_all_fields : return all files in the comm_users table # only_with : filter return with a regex match on column names # my $opts = ref $_[0] ? shift : {@_}; my @fields; my $user_tb = $DB->table('comm_users'); my $cols = $user_tb->cols; my @sorted_cols = sort { $cols->{$a}{pos} <=> $cols->{$b}{pos} } keys %$cols; if ( $opts->{show_all_fields} ) { @fields = map {{ col_name => $_, %{$cols->{$_}} }} @sorted_cols; } elsif ( $opts->{only_with} ) { @sorted_cols = grep { /$opts->{only_with}/ } @sorted_cols; @fields = map {{ col_name => $_, %{$cols->{$_}} }} @sorted_cols; } else { my @comm_cols = qw( comm_id comm_username comm_email comm_question comm_answer comm_created comm_lastlogin comm_login_count comm_enabled ); my @prof_cols = grep /^prof_/, @sorted_cols; @fields = map {+{ col_name => $_, %{$cols->{$_}||{}} }} ( @comm_cols, @prof_cols ); my $apps = $DB->table('comm_apps')->select(['app_keyword'])->fetchall_hashref || []; my @app_cols; my $status = comm_language('ADMIN_APPS_STATUS'); foreach ( @$apps ) { my $c = "app_$_->{app_keyword}"; my $f = { col_name => $c, %{$cols->{$c}||{}} }; $f->{form_display} = ( $f->{form_display} || $_->{app_keyword} ) . ' ' . $status; push @app_cols, $f; } push @fields, @app_cols; }; return \@fields; } sub ssi_comm_fields_select { #-------------------------------------------------------------------- # This returns a comm fields select box based upon the same # parameters provided to ssi_comm_fields and ssi_select # # name : Required. Name of the select box # my $opts = ref $_[0] ? shift : {@_}; my $fields = ssi_comm_fields( @_ ) or return; my ( %options, @order ); foreach my $field ( @$fields ) { push @order, $field->{col_name}; $options{$field->{col_name}} = $field->{form_display} || $field->{col_name}; } $opts->{options} = \%options; $opts->{order} = \@order; return ssi_select( $opts ); } 1; __END__ =head1 NAME Community::Web::SSI - server side includes for Gossamer Community =head1 DESCRIPTION This module implements server side includes that can be used to display things like logged in username, etc. =head1 MAINTAINER Alex Krohn =head1 COPYRIGHT Copyright (c) 2004 Gossamer Threads Inc. All Rights Reserved. http://www.gossamer-threads.com/ =head1 VERSION Revision: $Id: SSI.pm,v 1.24 2005/07/21 23:18:26 alex Exp $ =cut