# ================================================================== # Gossamer Forum - Advanced web community # # Website : http://gossamer-threads.com/ # Support : http://gossamer-threads.com/scripts/support/ # Revision : $Id: Do.pm,v 1.9 2001/12/07 23:42:27 jagerman Exp $ # # Copyright (c) 2001 Gossamer Threads Inc. All Rights Reserved. # Redistribution in part or in whole strictly prohibited. Please # see LICENSE file for full details. # ================================================================== # # This is for managing all do= functions from the admin # package GForum::Do; use GForum qw/$CFG $IN $DB/; use strict; use vars qw/$VALID_FUNC_RE $Error/; $VALID_FUNC_RE = 'action|page|page-add|page-del|function|description|min_user_status|user_groups|user_groups-add|user_groups-del|disabled|hidden'; # Fields: # # - action - 'function' or 'page' # - page - if action is 'function' - a hash of page names to page filenames # - if action is 'page' - a filename for the do= # - function - only for 'function' - the function to run # - description - the description (used in Who's Online) # - min_user_status - the minimum user status allowed (0-3) # - user_groups - a hash ref { group_id => 1, group_id2 => 1, ... }. These groups # are allowed to access the function if the user_min_status doesn't match. # - disabled - normally not set, if this _is_ set no one may use this do=. # - customizable - a hash reference with keys as the above, 1 or 0 as the value, # 1 indicating that the admin can change it, 0 indicating they cannot. # customizable->{removable} should be 1 only if the function may be removed. # Returns a hash reference containing a single k/v pair - 'do_loop' whose value is a template loop of all do=actions # Inside the loop three things are available - name, description, and can_delete. sub do_loop { my @keys = sort { lc $a cmp lc $b } keys %{$CFG->{functions}}; return { do_loop => sub { my $do = shift @keys or return; return { name => $do, description => $CFG->{functions}->{$do}->{description}, can_delete => $CFG->{functions}->{$do}->{customizable}->{removable} } } } } # Called from the templates, this returns a loop of all groups, with "group_set" set for ones in $IN->param('user_groups') sub load_groups { return if $IN->param('ignore_user_groups'); require GForum::Group; my $aref = GForum::Group::load_groups()->{groups}; my %groups = map { $_ => 1 } $IN->param('user_groups'); for (@$aref) { $_->{group_set} = 1 if $groups{$_->{group_id}}; } return { user_groups => $aref }; } # Retrieves all the information of a do= function that you pass in. sub get { my $do = shift or $Error = "No action entered", return; my $function = hash_copy($CFG->{functions}->{$do}) or $Error = "Action does not exist", return; $function->{function} ||= ''; $function->{description} ||= ''; $function->{min_user_status} ||= 0; $function->{user_groups} ||= { }; $function->{disabled} ||= 0; $function->{page} ||= { } if $function->{action} eq 'function'; $function->{hidden} ||= 0; $function->{customizable}->{removable} ||= 0; $function->{customizable}->{action} ||= 0; $function->{customizable}->{page} ||= 0; $function->{customizable}->{'page-add'} = $function->{customizable}->{'page-del'} = $function->{customizable}->{page}; $function->{customizable}->{function} ||= 0; $function->{customizable}->{description} ||= 0; $function->{customizable}->{disabled} = 1 unless exists $function->{customizable}->{disabled}; $function->{customizable}->{user_groups} ||= 0; $function->{customizable}->{'user_groups-add'} = $function->{customizable}->{'user_groups-del'} = $function->{customizable}->{user_groups}; $function->{customizable}->{hidden} ||= 1; # By default, anything can be hidden $function; } # Just like get, but formats in a template-compatible way sub tpl_get { my $function = get(shift) or return { tpl_get_error => "Invalid action" }; for (keys %{$function->{customizable}}) { $function->{"customizable_$_"} = delete $function->{customizable}->{$_}; } delete $function->{customizable}; # user_groups is a template loop of ALL groups, with group_set => 1 for the ones permitted for the action my @groups = @{$DB->table('Grouping')->select()->fetchall_hashref}; for (@groups) { $_->{group_set} = 1 if $function->{user_groups}->{$_->{group_id}}; } $function->{num_user_groups} = scalar keys %{$function->{user_groups}}; $function->{user_groups} = \@groups; if ($function->{action} eq 'function') { my @pages; if (ref $funcion->{page} eq 'HASH') { while (my ($name, $value) = each %{$function->{page}}) { push @pages, { name => $name, page => $value }; } $function->{pages} = \@pages; delete $function->{page}; } } $function; } # Takes two arguments: a function name, and a hash reference of config values to save. # Note - for the "page" parameter, you need to pass them as: # page-add => { page => "page.html", page2 => "page2.html" } to add or overwrite existing values # page-del => [ page, page2 ] to delete existing pages # page => { page => "page.html", page2 => "page2.html" } will replace the existing page hash # The user_groups work the same way: # user_groups-add => [ $group_id, $group_id2, ...] will add the group(s). # user_groups-del => [ $group_id, $group_id2, ...] will delete the group(s). # user_groups => [ $group_id, $group_id2, ...] will delete any existing groups and add the ones specified. # NOTE: things that you don't pass are NOT changed, so pass things that should be removed as undef or 0. # - the only exception is the "hidden" parameter sub set { my $do = shift; my $new_vals = shift; my $function = get($do) or $Error = "Invalid action: action does not exist", return; for (grep /^(?:$VALID_FUNC_RE)$/ && $function->{customizable}->{$_}, keys %$new_vals) { if (/^(page|user_groups)(-del|-add)?$/ and ($function->{action} eq 'function' or $1 eq 'user_groups')) { if ($2 eq '-add') { my %h; if (ref $new_vals->{$_} eq 'ARRAY') { @h{@{$new_vals->{$_}}} = (1) x @{$new_vals->{$_}}; } elsif (ref $new_vals->{$_} eq 'HASH') { %h = %{$new_vals->{$_}}; } else { %h = ($new_vals->{$_} => 1); } @{$function->{$1}}{keys %h} = values %h; } elsif ($2 eq '-del') { for my $k (@{$new_vals->{$_}}) { delete $function->{$1}->{$k}; } } else { my %h; if (ref $new_vals->{$_} eq 'ARRAY') { @h{@{$new_vals->{$_}}} = (1) x @{$new_vals->{$_}}; } else { %h = %{$new_vals->{$_}}; } $function->{$_} = \%h; } } else { $function->{$_} = $new_vals->{$_}; } } for (keys %{$function->{customizable}}) { delete $function->{customizable}->{$_} unless $function->{customizable}->{$_}; } for (keys %$function) { delete $function->{$_} unless $function->{$_}; } delete $function->{user_groups} unless $function->{user_groups} and keys %{$function->{user_groups}}; $CFG->{functions}->{$do} = $function; $CFG->save(); 1; } # Works like set(), but it looks at $IN->param for the input. The first argument (the function # name) should still be passed in. This is meant to be called from the templates, and so discards # the actual first argument, which is the Template object's $VARS hashref. sub tpl_set { my $do = shift; my $new_vals = $IN->get_hash(); $new_vals->{disabled} = 0 unless $new_vals->{disabled}; if ($new_vals->{action} eq 'function') { delete $new_vals->{page}; for (keys %$new_vals) { if (/^page-(.*)/) { my $page_name = $1; my $page_html = $new_vals->{$_}; $new_vals->{page}->{$page_name} = $page_html; } } } else { $new_vals->{page} = delete $new_vals->{action_page}; } delete $new_vals->{'page-add'}; delete $new_vals->{'page-del'}; $new_vals->{user_groups} = [] unless delete $new_vals->{use_user_groups}; $new_vals->{user_groups} = [$new_vals->{user_groups}] if $new_vals->{user_groups} and not ref $new_vals->{user_groups}; my $success = set($do, $new_vals); return $success ? { set_success => 1 } : { reason => $Error }; } sub del { my $do = shift; $Error = "Action does not exist", return unless exists $CFG->{functions}->{$do}; $Error = "Action cannot be removed", return unless $CFG->{functions}->{$do}->{customizable}->{removable}; delete $CFG->{functions}->{$do}; $CFG->save(); 1; } sub tpl_del { my $success = del(@_); return $success ? { del_success => 1 } : { reason => $Error }; } # Takes two arguments - the name of the function to add, and the values for the function. sub add { my ($name, $function) = @_; $Error = "Action '$name' already exists", return if exists $CFG->{functions}->{$name}; my $customizable = delete $function->{customizable} || { }; for (qw/action page function description min_user_status user_groups disabled hidden removable/) { $customizable->{$_} = 1 unless exists $customizable->{$_}; } for (keys %$customizable) { delete $customizable->{$_} unless $customizable->{$_}; } for (keys %$function) { if (ref $function->{$_} eq 'HASH') { delete $function->{$_} unless keys %{$function->{$_}}; } elsif (ref $function->{$_} eq 'ARRAY') { delete $function->{$_} unless @{$function->{$_}}; } delete $function->{$_} unless $function->{$_}; } delete $function->{page} unless $function->{action} eq 'function' ? ($function->{page} and keys %{$function->{page}}) : $function->{page}; delete $function->{user_groups} unless $function->{user_groups} and keys %{$function->{user_groups}}; for (grep ! /^(?:$VALID_FUNC_RE|removable)$/, keys %$function) { delete $function->{$_}; } $CFG->{functions}->{$name} = $function; $CFG->{functions}->{$name}->{customizable} = $customizable; $CFG->save(); 1; } sub tpl_add { my $do = shift; my $input = $IN->get_hash(); $input->{action} = 'page'; $input->{page} = delete $input->{action_page}; if (delete $input->{use_user_groups}) { my @groups = ref $input->{user_groups} eq 'ARRAY' ? @{$input->{user_groups}} : $input->{user_groups}; $input->{user_groups} = { map { $_ => 1 } @groups }; } else { delete $input->{user_groups}; } my $success = add($do => $input); return $success ? { add_success => 1 } : { reason => $Error }; } # Takes a hash ref (possibly of hash refs) and copies it. It follows hash references, but not any other kind of reference sub hash_copy { my $href = shift; my $copy; for (keys %$href) { if (ref $href->{$_} eq 'HASH') { $copy->{$_} = hash_copy($href->{$_}); } else { $copy->{$_} = $href->{$_}; } } $copy; } 1;