# ================================================================== # Gossamer Links - enhanced directory management system # # Website : http://gossamer-threads.com/ # Support : http://gossamer-threads.com/scripts/support/ # CVS Info : 087,071,086,086,085 # Revision : $Id: Browser.pm,v 1.132 2013/02/13 01:01:34 brewt 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. # ================================================================== package Links::Browser; # ================================================================== use strict; use vars qw/@ISA $ATTRIBS/; use Links qw/:objects :payment/; use GT::Base; use Links::Browser::Controller; use GT::AutoLoader; @ISA = qw/GT::Base/; $ATTRIBS = { load_full => 200, ctrl => undef, }; # -------------------------------------------------------------------------------------- # # Template parsing # # -------------------------------------------------------------------------------------- # sub print_template { # ------------------------------------------------------------------- # Prints out a template. # if ($IN->param('d')) { print $_[0]->_template($_[1], $_[2], { print => 0, dynamic => 1 }); } else { $_[0]->_template($_[1], $_[2], { print => 1 }); } } sub return_template { # ------------------------------------------------------------------- # Returns a template. # $_[0]->_template($_[1], $_[2], { print => 0 }); } sub _template { # ------------------------------------------------------------------- # Prints/Returns a template. # my ($self, $tpl, $vars, $opts) = @_; $vars->{enctype} = ($DB->table('Category')->_file_cols or $DB->table('Links')->_file_cols) ? ' enctype="multipart/form-data" ' : ''; $vars->{is_admin} = $self->{ctrl}->{admin_templates} ? 1 : 0; if ($self->{ctrl}->{admin_templates}) { Links->admin_page($tpl, $vars, $opts); } else { Links->user_page($tpl, $vars, $opts); } } # -------------------------------------------------------------------------------------- # # Window Initilization Functions # # -------------------------------------------------------------------------------------- # $COMPILE{main_panel_init} = __LINE__ . <<'END_OF_SUB'; sub main_panel_init { # ------------------------------------------------------------------- # $obj->main_panel_init(); # ------------------------ # Prints the HTML / Javascript that goes in the top-level # HTML page that controls the whole Javascript. # my $self = shift; my $base = $self->{ctrl}->user_base_node; my $rooted = @$base ? 1 : 0; my $owner_links = $DB->table('Links')->count({LinkOwner => $USER->{Username}}); my ($root_name, $root_id); $self->print_template ('browser.html', { id => 0, fatherid => 0, name => Links::language('LINKS_TOP'), nb_links => "null", max_load_full => $self->{load_full}, total_categories => $self->_total_categories, is_rooted => $rooted, owner_links => $owner_links, } ); return 1; } END_OF_SUB $COMPILE{tree_panel_init} = __LINE__ . <<'END_OF_SUB'; sub tree_panel_init { # ------------------------------------------------------------------- # $obj->tree_panel_init(); # ------------------------ # Prints the HTML / Javascript that goes in the left # HTML page in order to initialize the Javascript tree # and draw it. # my $self = shift; $self->print_template ('browser_tree.html', {}); } END_OF_SUB $COMPILE{info_panel_init} = __LINE__ . <<'END_OF_SUB'; sub info_panel_init { # ------------------------------------------------------------------- # $obj->_init(); # ------------------------ # Prints the HTML that goes in the info panel when # it is initialized. This normally should be a tutorial # on how to use the category browser. # my $self = shift; $self->print_template ('browser_info.html', {}); } END_OF_SUB $COMPILE{code_panel_init} = __LINE__ . <<'END_OF_SUB'; sub code_panel_init { # ------------------------------------------------------------------- # $obj->code_panel_init(); # ------------------------ # Prints the HTML / Javascript that will update # the tree with basic information. # # if the CGI param or the Controller variable load_tree # is true, then the whole tree is sent to the client, # avoiding future updates. # my $self = shift; if (($IN->param('load_tree') or $self->{ctrl}->{load_tree}) and ($self->{load_full} > $self->_total_categories())) { return $self->code_panel_reload_full (@_); } $self->print_template ('browser_code_init.html', { instructions => $self->code_panel_init_loop () }); } END_OF_SUB # -------------------------------------------------------------------------------------- # # Javascript Tree Management Functions # # -------------------------------------------------------------------------------------- # $COMPILE{code_panel_init_loop} = __LINE__ . <<'END_OF_SUB'; sub code_panel_init_loop { # ------------------------------------------------------------------- # $obj->code_panel_init_loop(); # ----------------------------- # Builds a bunch of "tree.addNode ( new LoadedNode ( $cat_id, $father_id, "$name" ) );" # javascript commands that will be used to initialize the tree's values. # my $self = shift; my $base = $self->{ctrl}->user_base_node; my $category = $DB->table ("Category"); my (@res, $sth, $set_root); if (@$base) { my $roots = '(' . join (",", @$base) . ')'; $category->select_options ('ORDER BY Name ASC'); $sth = $category->select ( GT::SQL::Condition->new('ID', 'IN', \$roots), ['ID', 'FatherID', 'Name', 'Number_of_Links'] ) or die "Database Error: $GT::SQL::error"; $set_root = 1; } else { $category->select_options ('ORDER BY Name ASC'); $sth = $category->select ( { FatherID => 0 }, ['ID', 'FatherID', 'Name', 'Number_of_Links'] ) or die "Database Error: $GT::SQL::error"; } while (my $h = $sth->fetchrow_hashref) { $h->{FatherID} = $set_root ? 0 : $h->{FatherID}; if ($self->code_panel_init_loop_is_leaf ($category, $h->{ID})) { push @res, qq~parent.tree.addNode ( new parent.LoadedNode ( $h->{ID}, $h->{FatherID}, ~ . _quote($h->{Name}) . qq~, $h->{Number_of_Links} ) );\n~; } else { push @res, qq~parent.tree.addNode ( new parent.UnloadedNode ( $h->{ID}, $h->{FatherID}, ~ . _quote($h->{Name}) . qq~, $h->{Number_of_Links} ) );\n~; } } return join '', ("\n", @res); } END_OF_SUB $COMPILE{code_panel_init_loop_is_leaf} = __LINE__ . <<'END_OF_SUB'; sub code_panel_init_loop_is_leaf { # ------------------------------------------------------------------- # $obj->code_panel_init_loop_is_leaf ($id); # ----------------------------------------- # Returns TRUE if the category which id is $id has no # childs, FALSE otherwise. # my ($self, $category, $cat_id) = @_; my $sth = $category->select ( { FatherID => $cat_id }, ['ID'] ) or die "Database Error: $GT::SQL::error"; return $sth->fetchrow_arrayref ? 0 : 1; } END_OF_SUB $COMPILE{code_panel_category_expand} = __LINE__ . <<'END_OF_SUB'; sub code_panel_category_expand { # ------------------------------------------------------------------- # $obj->code_panel_category_expand; # --------------------------------- # Returns the HTML that updates and redraws the tree # when an user clicks on an unloaded node. # my $self = shift; my $category_id = $IN->param ('category_id'); my @res = (); my $category = $DB->table ('Category'); $category->select_options ('ORDER BY Name ASC'); my $sth = $category->select ( { FatherID => $category_id }, ['ID', 'FatherID', 'Name', 'Number_of_Links'] ); while (my $h = $sth->fetchrow_hashref) { if ( $self->code_panel_init_loop_is_leaf ($category, $h->{ID}) ) { push @res, qq~parent.tree.addNode ( new parent.LoadedNode ( $h->{ID}, $h->{FatherID}, ~ . _quote($h->{Name}) . qq~, $h->{Number_of_Links} ) );\n~; } else { push @res, qq~parent.tree.addNode ( new parent.UnloadedNode ( $h->{ID}, $h->{FatherID}, ~ . _quote($h->{Name}) . qq~, $h->{Number_of_Links} ) );\n~; } } my $instructions = join '', ("\n", @res); return $self->print_template('browser_category_expand.html', { instructions => $instructions, category_id => $category_id }); } END_OF_SUB $COMPILE{code_panel_reload_empty} = __LINE__ . <<'END_OF_SUB'; sub code_panel_reload_empty { # ------------------------------------------------------------------- # $obj->code_panel_reload_empty ($id); # ------------------------------------ # Reinitialize the tree for an empty tree. # my $self = shift; $self->print_template ('browser_code_init.html', { instructions => $self->code_panel_init_loop () } ); } END_OF_SUB $COMPILE{code_panel_reload_full} = __LINE__ . <<'END_OF_SUB'; sub code_panel_reload_full { # ------------------------------------------------------------------- # $obj->code_panel_reload_full ($id); # ----------------------------------- # Reinitializes the tree, but loading all info. # my $self = shift; my $base = $self->{ctrl}->user_base_node; my $category = $DB->table ("Category"); my (@res, $sth, $set_root); if (@$base) { foreach my $node (@$base) { my $rows = 0; my $cat_r = $category->get ($node, 'HASH', ['ID', 'FatherID', 'Name', 'Full_Name', 'Number_of_Links']) or next; my $str = $cat_r->{Full_Name} . '/%'; $category->select_options ('ORDER BY Full_Name ASC'); $sth = $category->select ( GT::SQL::Condition->new('Full_Name', 'LIKE', $str), ['ID', 'FatherID', 'Name', 'Number_of_Links'] ); while (my $h = $sth->fetchrow_hashref) { if ( $self->code_panel_init_loop_is_leaf ($category, $h->{ID}) ) { push @res, qq~parent.tree.addNode ( new parent.LoadedNode ( $h->{ID}, $h->{FatherID}, ~ . _quote($h->{Name}) . qq~, $h->{Number_of_Links} ) );~; } else { push @res, qq~parent.tree.addNode ( new parent.UnloadedNode ( $h->{ID}, $h->{FatherID}, ~ . _quote($h->{Name}) . qq~, $h->{Number_of_Links} ) );~; } $rows++; } if ($rows) { unshift @res, qq~parent.tree.addNode ( new parent.UnloadedNode ( $cat_r->{ID}, 0, ~ . _quote($cat_r->{Name}) . qq~, $cat_r->{Number_of_Links} ) );~; } else { unshift @res, qq~parent.tree.addNode ( new parent.LoadedNode ( $cat_r->{ID}, 0, ~ . _quote($cat_r->{Name}) . qq~, $cat_r->{Number_of_Links} ) );~; } } } else { $category->select_options ('ORDER BY Full_Name ASC'); $sth = $category->select ( ['ID', 'FatherID', 'Name', 'Number_of_Links'] ); while (my $h = $sth->fetchrow_hashref) { if ( $self->code_panel_init_loop_is_leaf ($category, $h->{ID}) ) { push @res, qq~parent.tree.addNode ( new parent.LoadedNode ( $h->{ID}, $h->{FatherID}, ~ . _quote($h->{Name}) . qq~, $h->{Number_of_Links} ) );~; } else { push @res, qq~parent.tree.addNode ( new parent.UnloadedNode ( $h->{ID}, $h->{FatherID}, ~ . _quote($h->{Name}) . qq~, $h->{Number_of_Links} ) );~; } } } my $instructions = join "", @res; $self->print_template ('browser_code_init.html', { instructions => $instructions } ); } END_OF_SUB $COMPILE{category_click} = __LINE__ . <<'END_OF_SUB'; sub category_click { # ------------------------------------------------------------------- # $obj->category_click; # -------------------------------- # This function is invoked by the Javascript tree # whenever the user clicks on a category. # my $self = shift; my $category_id = $IN->param ('category_id'); my $category = $DB->table ("Category"); if ($category_id == 0) { my $navbar = $self->navbar ($category_id); $self->print_template ( "browser_category.html", { navbar => $navbar, Name => Links::language('LINKS_TOP'), links => '' } ); } else { my $sth = $category->select ( { ID => $category_id }, ['ID', 'Name', 'Number_of_Links'] ) or die "Database Error: $GT::SQL::error"; my $info = $sth->fetchrow_hashref or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDCATID', $category_id) ); my $navbar = $self->navbar ($category_id); my %info = $self->_links_list_html ($category_id); $self->print_template ( "browser_category.html", { navbar => $navbar, Name => $info->{Name}, %info }); } } END_OF_SUB # -------------------------------------------------------------------------------------- # # CATEGORY Management Functions # # -------------------------------------------------------------------------------------- # $COMPILE{category_add_form} = __LINE__ . <<'END_OF_SUB'; sub category_add_form { # ------------------------------------------------------------------- # $obj->category_add_form; # ----------------------------------- # Displays a form that lets the user enter a new sub-category. # my $self = shift; my $category_id = $IN->param ('category_id'); my $category = $DB->table ('Category'); my ($info, $name); if ($category_id) { my $sth = $category->select ( { ID => $category_id }, ['ID', 'Name', 'Number_of_Links'] ); my $info = $sth->fetchrow_hashref or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDCATID', $category_id) ); $name = $info->{Name}; } else { $name = Links::language('LINKS_TOP') } # --- -- - ADD CATEGORY FORM CONSTRUCTION - -- --- # my $h = $DB->html($category, { FatherID => $category_id, Has_New_Links => "No", Has_Changed_Links => "No", Number_of_Links => 0, Direct_Links => 0 }); my $navbar = $self->navbar($category_id); my @hide = qw/FatherID Full_Name Number_of_Links Direct_Links Has_New_Links Has_Changed_Links Newest_Link/; push @hide, qw/Payment_Mode Payment_Description/ unless $CFG->{payment}->{enabled}; $self->print_template("browser_category_add_form.html", { navbar => $navbar, Name => $name, form => $h->form ( { skip => [ qw/ID Timestmp/ ], hide => [ @hide ], file_field => 1, file_delete => 1, defaults => 1, code => { FatherID => undef } } ) } ); } END_OF_SUB $COMPILE{category_add} = __LINE__ . <<'END_OF_SUB'; sub category_add { # ------------------------------------------------------------------- # $obj->category_add; # ------------------------------ # Adds a category to the current working dir. # This function should do three things: # # * Add the category in the database # * List all the links in the current category # * Update the javascript tree so that we keep # it synchronized with the database. # my $self = shift; my $name = $IN->param('Name'); my $category = $DB->table('Category'); my $parent_category_id = $IN->param('FatherID') || 0; # Setup the language for GT::SQL. local $GT::SQL::ERRORS->{ILLEGALVAL} = Links::language('ADD_ILLEGALVAL') if Links::language('ADD_ILLEGALVAL') ne 'ADD_ILLEGALVAL'; local $GT::SQL::ERRORS->{UNIQUE} = Links::language('ADD_UNIQUE') if Links::language('ADD_UNIQUE') ne 'ADD_UNIQUE'; local $GT::SQL::ERRORS->{NOTNULL} = Links::language('ADD_NOTNULL') if Links::language('ADD_NOTNULL') ne 'ADD_NOTNULL'; my $child_category_id = $category->add($IN->get_hash) or return $self->javascript_error( message => Links::language('BROWSER_CATCANTADD', _format_js($GT::SQL::error)), info_go => -1 ); my $navbar = $self->navbar($parent_category_id); my $parent = $category->get( $parent_category_id, 'HASH', [ 'Name' ] ); my %info = $self->_links_list_html($parent_category_id); $self->print_template("browser_category_add.html", { navbar => $navbar, child_id => $child_category_id, father_id => $parent_category_id, child_name => $name, parent_name => $parent->{Name} || Links::language('LINKS_TOP'), %info }); } END_OF_SUB $COMPILE{category_del_form} = __LINE__ . <<'END_OF_SUB'; sub category_del_form { # ------------------------------------------------------------------- # $obj->category_del_form; # ----------------------------------- # This function prints a confirmation screen when # an user wants to delete a form. # my $self = shift; my $category_id = $IN->param ('category_id'); my $category = $DB->table ('Category'); my $navbar = $self->navbar ($category_id); my $info = $category->get ( { ID => $category_id }, 'HASH', ['ID', 'Name', 'Number_of_Links'] ) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDCATID', $category_id), hist_go => -1); $self->print_template ( "browser_category_del_form.html", { category_id => $category_id, navbar => $navbar, Name => $info->{Name} }); } END_OF_SUB $COMPILE{category_del} = __LINE__ . <<'END_OF_SUB'; sub category_del { # ------------------------------------------------------------------- # $obj->category_del; # ------------------------------ # Prints in the info pane a frame that updates the # javascript tree on the left and displays the category # which is the father of the category that has been # deleted. # my $self = shift; my $category_id = $IN->param ('category_id'); my $category = $DB->table ('Category'); my $info = $category->get ( { ID => $category_id }, 'HASH', ['ID', 'Name', 'Number_of_Links', 'FatherID'] ) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDCATID', $category_id), info_go => -1 ); my $child_name = $info->{Name}; my $father_id = $info->{FatherID}; $category->delete ( { ID => $category_id } ) or return $self->javascript_error ( message => Links::language('BROWSER_CATCANTDEL', _format_js ($GT::SQL::error)), info_go => -1 ); my ($father_name); if ($father_id == 0) { $father_name = Links::language('LINKS_TOP') } else { $info = $category->get ( { ID => $father_id }, 'HASH', ['Name'] ) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDCATID', $father_id) ); $father_name = $info->{Name}; } my $navbar = $self->navbar ($father_id); my %info = $self->_links_list_html ($father_id); $self->print_template ( "browser_category_del.html", { navbar => $navbar, father_id => $father_id, child_id => $category_id, father_name => $father_name, child_name => $child_name, %info } ); } END_OF_SUB $COMPILE{category_modify_form} = __LINE__ . <<'END_OF_SUB'; sub category_modify_form { # ------------------------------------------------------------------- # $obj->category_modify_form; # -------------------------------------- # This function prints a modification form # for the requested category. # my $self = shift; my $category_id = $IN->param ('category_id'); my $category = $DB->table ('Category'); my $info = $category->get ( { ID => $category_id } ) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDCATID', $category_id), hist_go => -1); my $navbar = $self->navbar ($category_id); my @hide = qw/FatherID Full_Name Number_of_Links Direct_Links Has_New_Links Has_Changed_Links Newest_Link Timestmp/; push @hide, qw/Payment_Mode Payment_Description/ unless $CFG->{payment}->{enabled}; my $h = $DB->html($category, $info); $self->print_template ( "browser_category_modify_form.html", { category_id => $category_id, navbar => $navbar, Name => $info->{Name}, form => $h->form ( { hide => [ @hide ], view => ['ID'], file_field => 1, file_delete => 1, code => { FatherID => undef } }) } ); } END_OF_SUB $COMPILE{category_modify} = __LINE__ . <<'END_OF_SUB'; sub category_modify { # ------------------------------------------------------------------- # $obj->category_modify; # --------------------------------- # This method performs the modification operation # on the database and updates the javascript tree. # my $self = shift; my $category_id = $IN->param ("ID"); my $name = $IN->param ('Name'); my $category = $DB->table ('Category'); my $navbar = $self->navbar ($category_id); # Setup the language for GT::SQL. local $GT::SQL::ERRORS->{ILLEGALVAL} = Links::language('ADD_ILLEGALVAL') if Links::language('ADD_ILLEGALVAL') ne 'ADD_ILLEGALVAL'; local $GT::SQL::ERRORS->{UNIQUE} = Links::language('ADD_UNIQUE') if Links::language('ADD_UNIQUE') ne 'ADD_UNIQUE'; local $GT::SQL::ERRORS->{NOTNULL} = Links::language('ADD_NOTNULL') if Links::language('ADD_NOTNULL') ne 'ADD_NOTNULL'; $category->modify ($IN->get_hash) or return $self->javascript_error ( message => Links::language('BROWSER_CANTMOD', _format_js ($GT::SQL::error)), hist_go => -1 ); my %info = $self->_links_list_html ( $category_id); $self->print_template ( "browser_category_modify.html", { category_id => $category_id, Name => $name, Name_quoted => _quote($name), navbar => $navbar, %info } ); } END_OF_SUB $COMPILE{category_move_form} = __LINE__ . <<'END_OF_SUB'; sub category_move_form { # ------------------------------------------------------------------- # $obj->category_move_form; # ------------------------------------ # This function output a category move form when the # user clicks on the "move" link of the category he / she # is browsing. # # This form should include a special javascript variable, # "move_from", that tells the tree that the user is moving # from a given category and not selecting a directory # whenever he wants to move a category. # my $self = shift; my $category_id = $IN->param ('category_id'); my $category = $DB->table ('Category'); my $navbar = $self->navbar ($category_id); my $info = $category->get ( { ID => $category_id }, 'HASH', ['ID', 'Name', 'Number_of_Links'] ) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDCATID'), hist_go => -1); $self->print_template ( "browser_category_move_form.html", { navbar => $navbar, Name => $info->{Name}, category_id => $category_id } ); } END_OF_SUB $COMPILE{category_move} = __LINE__ . <<'END_OF_SUB'; sub category_move { # ------------------------------------------------------------------- # $obj->category_move; # ------------------------------- # Moves a category based on the user input (CGI # objects and others). # my $self = shift; my $category_from = $IN->param ("category_from"); my $category_to = $IN->param ("category_to"); my $category = $DB->table ('Category'); # get some information about the category that we're moving my $info_from = $category->get ( { ID => $category_from } ) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDCATID', $category_from) ); my $old = $info_from->{FatherID}; # get some information about the category where we want to move to, my $info_to; if ($category_to) { $info_to = $category->get ( { ID => $category_to }, 'HASH', ['ID', 'FatherID', 'Full_Name', 'Name', 'Number_of_Links']) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDCAT', $category_to) ); } else { $info_to = { ID => 0, FatherID => 0, Name => Links::language('LINKS_TOP'), Full_Name => '' } } # if the source and the target categories are the same then display the user an error if ($category_from == $category_to) { return $self->javascript_error ( message => Links::language ('BROWSER_MOVESELF'), tree_redraw => $category_from ); } # if the source and the target categories have the same name then display an error if ($category_from and $category_to and ($info_from->{Name} eq $info_to->{Name})) { return $self->javascript_error ( message => Links::language ('BROWSER_MOVEDUPE'), tree_redraw => $category_from ); } # if the source is a direct child of the target then we don't have anything to do if ($info_from->{FatherID} == $info_to->{ID}) { return $self->javascript_error ( message => Links::language ('BROWSER_MOVESELF'), tree_redraw => $category_from ); } # finally check that category_to isn't a category_from descendant my $from_full_name = $info_from->{Full_Name}; my $to_full_name = $info_to->{Full_Name}; if ($to_full_name =~ m,^\Q$from_full_name\E/,) { return $self->javascript_error ( message => Links::language ('BROWSER_MOVECHILD'), tree_redraw => $category_from ); } # update the record to point to the new father. my $old_father = $info_from->{FatherID}; $info_from->{FatherID} = $info_to->{ID}; # Remove the timestmp. delete $info_from->{Timestmp}; $category->modify ($info_from) or return $self->javascript_error ( message => Links::language ('BROWSER_CANTMOD', _format_js ($GT::SQL::error)), tree_redraw => $category_from ); my $navbar = $self->navbar ($info_from->{ID}); my %info = $self->_links_list_html ($category_from); $self->print_template ( "browser_category_move.html", { old => $old_father, new => $info_from->{FatherID}, number_of_links => $info_from->{Number_of_Links} || 0, category_id => $category_from, category_to_id => $category_to, load_node_info => $self->category_move_jscriptloop ($category_to), navbar => $navbar, Name => $info_from->{Name}, %info } ); } END_OF_SUB $COMPILE{category_move_jscriptloop} = __LINE__ . <<'END_OF_SUB'; sub category_move_jscriptloop { # ------------------------------------------------------------------- # $obj->category_move_jscriptloop; # ------------------------------------------- # Returns the javascript commands that are used to # load the tree node whenever necessary. # my $self = shift; my $category = $DB->table ('Category'); my $category_to = shift; my @res = (); my $sth = $category->select ( { FatherID => $category_to }, ['ID', 'FatherID', 'Name'] ) or die "An error has occurred: $GT::SQL::error"; while (my $h = $sth->fetchrow_hashref) { my $file; if ($self->code_panel_init_loop_is_leaf ($category, $h->{ID})) { push @res, qq~parent.tree.addNode ( new parent.LoadedNode ( $h->{ID}, $h->{FatherID}, ~ . _quote($h->{Name}) . qq~ ) );~; } else { push @res, qq~parent.tree.addNode ( new parent.UnloadedNode ( $h->{ID}, $h->{FatherID}, ~ . _quote($h->{Name}) . qq~ ) );~; } } return join '', ("\n", @res); } END_OF_SUB $COMPILE{category_move_jscriptloop_is_leaf} = __LINE__ . <<'END_OF_SUB'; sub category_move_jscriptloop_is_leaf { # ------------------------------------------------------------------- # $obj->code_panel_init_loop_is_leaf ($id); # ----------------------------------------- # Returns TRUE if the category which id is $id has no # childs, FALSE otherwise. # my $self = shift; my $cat_id = shift; my $category = $DB->table ('Category'); my $sth = $category->count ( { FatherID => $cat_id } ); if ($sth->rows) { return 0 } else { return 1 } } END_OF_SUB $COMPILE{category_editors_form} = __LINE__ . <<'END_OF_SUB'; sub category_editors_form { # ------------------------------------------------------------------- # Displays a list of existing editors, and lets the person add a new editor. # my $self = shift; my $category_id = $IN->param('category_id'); my $category = $DB->table('Category'); my $cat_info = $category->get ( { ID => $category_id }, 'HASH', ['Name'] ) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDCATID', $category_id), info_go => -1); # Remove any editors. my $editor_db = $DB->table('Editors'); my @to_delete = $IN->param('delete'); foreach my $editor_name (@to_delete) { my ($name, $id) = split /\|/, $editor_name; my $tmp = $category->get ( { ID => $id }, 'HASH', ['Name'] ) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDCATID', $id), info_go => -1); $editor_db->delete ( { Username => $name, CategoryID => $id }); } # Add any editors requested. if ($IN->param('Username')) { my $ed = $IN->get_hash; $ed->{CategoryID} = $category_id; $editor_db->insert ( $ed ) or return $self->javascript_error ( message => Links::language('BROWSER_EDITORADD', $ed->{Username} ), info_go => -1 ); } # Get a list of all the editors. my $parents = $category->parents ( $category_id ); push @$parents, $category_id; $parents = '(' . join (",", @$parents) . ')'; my $sth = $editor_db->select ( GT::SQL::Condition->new('CategoryID', 'IN', \$parents) ); my $output; while (my $editor = $sth->fetchrow_hashref) { my $cat_info = $category->get ($editor->{CategoryID}, 'HASH', ['Full_Name']); $editor->{Full_Name} = $cat_info->{Full_Name}; $output .= $self->return_template ('browser_category_editors_row.html', $editor); } my $navbar = $self->navbar ($category_id); $self->print_template ( "browser_category_editors_form.html", { id => $category_id, navbar => $navbar, editors => $output, Name => $cat_info->{Name} } ); } END_OF_SUB $COMPILE{category_related_form} = __LINE__ . <<'END_OF_SUB'; sub category_related_form { # ------------------------------------------------------------------- # Adds related categories. # my $self = shift; my $category_id = $IN->param('category_id'); my $name = $IN->param('related_name'); my $category = $DB->table('Category'); my $cat_info = $category->get ( { ID => $category_id }, 'HASH', ['Name'] ) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDCATID', $category_id), info_go => -1); # Remove any relations. my @to_delete = $IN->param('delete'); my $relation_db = $DB->table('CatRelations'); foreach my $relation (@to_delete) { $relation_db->delete ( { CategoryID => $category_id, RelatedID => $relation }); } # Add any relations requested. my $id = $IN->param('related_to'); if ($id) { my $id_r = $category->get ( { ID => $id }, ['ID'] ) or return $self->javascript_error ( message => Links::language('BROWSER_RELADD', $id ), info_go => -1 ); if ($relation_db->count ( { RelatedID => $id, CategoryID => $category_id })) { return $self->javascript_error ( message => Links::language('BROWSER_RELADD', $id_r->{Name} ), info_go => -1 ); } $relation_db->insert ( { CategoryID => $category_id, RelatedID => $id, RelationName => $name }); } # Get a list of all the Relations. my $sth = $relation_db->select ( { CategoryID => $category_id }, ['RelatedID', 'RelationName']); my $output; while (my ($id, $rel_name) = $sth->fetchrow_array) { my $name_r = $category->get ( { ID => $id }, 'HASH', ['Full_Name'] ); $rel_name = $rel_name ? " ($rel_name) " : ''; my $url = $category->as_url ( $name_r->{Full_Name} ); $output .= qq~ $name_r->{Full_Name} $rel_name
~; } my $navbar = $self->navbar ($category_id); $self->print_template ( "browser_category_related_form.html", { id => $category_id, navbar => $navbar, related => $output, Name => $cat_info->{Name} } ); } END_OF_SUB # -------------------------------------------------------------------------------------- # # LINK Management Functions # # -------------------------------------------------------------------------------------- # $COMPILE{link_user_list} = __LINE__ . <<'END_OF_SUB'; sub link_user_list { # ------------------------------------------------------------------- # Displays a list of links owned by a given user. # my $self = shift; my $user = $IN->param('user'); my $category_id = $IN->param('category_id'); my $navbar = $self->navbar ($category_id); my $user_db = $DB->table('Users'); my $user_info = $user_db->get ($user, 'HASH') or return $self->javascript_error ( message => Links::language ('BROWSER_INVALIDUSER', $user), hist_go => -1 ); my %info = $self->_links_list_html ($category_id, $user); $self->print_template ( "browser_link_owner.html", { navbar => $navbar, link_owner => $user, %info, %$user_info }); } END_OF_SUB $COMPILE{link_add_form} = __LINE__ . <<'END_OF_SUB'; sub link_add_form { # ------------------------------------------------------------------- # $obj->_link_add_form; # ------------------------------- # Prints out an add form in order to let an user # add a link in a given category. # my $self = shift; my $category = $DB->table ('Category'); my $links = $DB->table ('Links'); my $category_id = $IN->param ('category_id'); my $navbar = $self->navbar ($category_id); my $category_info = $category->get ( { ID => $category_id }, 'HASH', ['ID', 'Name', 'Number_of_Links'] ) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDCATID', $category_id) ); if (! $IN->param('LinkOwener')) { $IN->param('LinkOwner', exists $self->{ctrl}->{user}->{Username} ? $self->{ctrl}->{user}->{Username} : 'admin'); } my $h = $DB->html($links, $IN); $h->defaults(1); my $defaults = $h->_get_defaults(); $self->print_template ( "browser_link_add_form.html", { %$defaults, navbar => $navbar, Name => $category_info->{Name}, category_id => $category_id, form => $h->form ( { defaults => 1, skip => [ qw /CatLinks.LinkID Timestmp/ ], hide => [qw/ID isNew isChanged isPopular Status Date_Checked Timestmp/], file_field => 1, file_delete => 1 }) . "" } ); } END_OF_SUB $COMPILE{link_add} = __LINE__ . <<'END_OF_SUB'; sub link_add { # ------------------------------------------------------------------- # adds a new link in the database system. # my $self = shift; my $category_id = $IN->param ("CatLinks.CategoryID"); my $category = $DB->table ('Category'); my $links = $DB->table ('Links'); my $navbar = $self->navbar ($category_id); my $category_info = $category->get ( { ID => $category_id }, 'HASH', ['ID', 'Name', 'Number_of_Links'] ) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDCATID', $category_id), hist_go => -1 ); # Setup the language for GT::SQL. local $GT::SQL::ERRORS->{ILLEGALVAL} = Links::language('ADD_ILLEGALVAL') if Links::language('ADD_ILLEGALVAL') ne 'ADD_ILLEGALVAL'; local $GT::SQL::ERRORS->{UNIQUE} = Links::language('ADD_UNIQUE') if Links::language('ADD_UNIQUE') ne 'ADD_UNIQUE'; local $GT::SQL::ERRORS->{NOTNULL} = Links::language('ADD_NOTNULL') if Links::language('ADD_NOTNULL') ne 'ADD_NOTNULL'; local $Links::Table::Links::ERRORS->{NOCATEGORY} = Links::language('ADD_NOCATEGORY') if Links::language('ADD_NOCATEGORY') ne 'ADD_NOCATEGORY'; $Links::Table::Links::ERRORS if 0; # silence -w my $h = $IN->get_hash; _format_insert_cgi($h, $links); $links->add ($h) or return $self->javascript_error ( message => Links::language('BROWSER_LINKCANTADD', _format_js($GT::SQL::error)), hist_go => -1 ); my %info = $self->_links_list_html ($category_id); $self->print_template ( "browser_link_add.html", { Name => $category_info->{Name}, navbar => $navbar, id => $category_id, %info } ); } END_OF_SUB $COMPILE{link_modify_form} = __LINE__ . <<'END_OF_SUB'; sub link_modify_form { # ------------------------------------------------------------------- # prints a form to modify a link # my $self = shift; my $link_id = $IN->param ('link_id'); my $category_id = $IN->param ('category_id'); my $category = $DB->table ('Category'); my $links = $DB->table ('Links'); my $catlink = $DB->table ('Category', 'CatLinks'); my $navbar = $self->navbar ($category_id); my $category_info = $category->get ( { ID => $category_id }, 'HASH', ['ID', 'Name', 'Number_of_Links'] ) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDCATID', $category_id), hist_go => -1 ); my $link_info = $links->get ( { ID => $link_id } ) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDLINKID', $link_id), hist_go => -1 ); $catlink->select_options("ORDER BY $CFG->{build_category_sort}"); my $cats = $catlink->select({ LinkID => $link_id })->fetchall_hashref; my $h = $DB->html($links, $link_info); $h->view_key(1); $h->file_field(1); $h->file_delete(1); my $file_field = $h->{file_field}; my $cols = $links->cols; foreach my $col (keys %$cols) { if (exists $cols->{$col}->{form_type} and $cols->{$col}->{form_type} eq 'FILE') { $h->{file_field} = 1; $link_info->{"${col}_filehtml"} = $h->file( { name => $col, def => $cols->{$col}, value => $link_info->{$col}, }, $link_info, { db => $links } ); } } $h->{file_field} = $file_field; $self->print_template ( "browser_link_modify_form.html", { %$link_info, Name => $category_info->{Name}, navbar => $navbar, category_id => $category_id, category_loop => $cats, form => $h->form ( { defaults => 1, skip => [ qw /CatLinks.LinkID Timestmp/ ], hide => [qw/ID isNew isChanged isPopular Status Date_Checked Timestmp/], file_field => 1, file_delete => 1 }) . "" } ); } END_OF_SUB $COMPILE{link_modify} = __LINE__ . <<'END_OF_SUB'; sub link_modify { # ------------------------------------------------------------------- # modifies a link # my $self = shift; my $link_id = $IN->param ('ID'); my $category_id = $IN->param ('category_id'); my $category = $DB->table ('Category'); my $links = $DB->table ('Links'); my $navbar = $self->navbar ($category_id); my $category_info = $category->get ( { ID => $category_id }, 'HASH', ['ID', 'Name', 'Number_of_Links'] ) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDCATID', $category_id), hist_go => -1 ); my $link_info = $links->get ( { ID => $link_id } ) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDLINKID', $link_id), hist_go => -1 ); # Setup the language for GT::SQL. local $GT::SQL::ERRORS->{ILLEGALVAL} = Links::language('ADD_ILLEGALVAL') if Links::language('ADD_ILLEGALVAL') ne 'ADD_ILLEGALVAL'; local $GT::SQL::ERRORS->{UNIQUE} = Links::language('ADD_UNIQUE') if Links::language('ADD_UNIQUE') ne 'ADD_UNIQUE'; local $GT::SQL::ERRORS->{NOTNULL} = Links::language('ADD_NOTNULL') if Links::language('ADD_NOTNULL') ne 'ADD_NOTNULL'; local $Links::Table::Links::ERRORS->{NOCATEGORY} = Links::language('ADD_NOCATEGORY') if Links::language('ADD_NOCATEGORY') ne 'ADD_NOCATEGORY'; $Links::Table::Links::ERRORS if 0; # silence -w my $h = $IN->get_hash; _format_insert_cgi($h, $links); $h->{'CatLinks.CategoryID'} = $self->_build_category_id_set ($link_id); my $ret = $links->modify ($h) or return $self->javascript_error ( message => Links::language('BROWSER_LINKCANTMOD', _format_js($GT::SQL::error)), hist_go => -1 ); my %info = $self->_links_list_html ($category_id); $self->print_template ( "browser_link_modify.html", { Name => $category_info->{Name}, navbar => $navbar, %info } ); } END_OF_SUB $COMPILE{link_del_form} = __LINE__ . <<'END_OF_SUB'; sub link_del_form { # ------------------------------------------------------------------- # outputs a link delete form # my $self = shift; my $link_id = $IN->param ('link_id'); my $category_id = $IN->param ('category_id'); my $category = $DB->table ('Category'); my $links = $DB->table ('Links'); my $navbar = $self->navbar ($category_id); my $category_info = $category->get ( { ID => $category_id }, 'HASH', ['ID', 'Name', 'Number_of_Links'] ) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDCATID', $category_id), hist_go => -1 ); my $link_info = $links->get ( { ID => $link_id }, 'HASH', ['Title'] ) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDLINKID', $link_id), hist_go => -1 ); $self->print_template ( "browser_link_del_form.html", { navbar => $navbar, Name => $category_info->{Name}, link => $link_info->{Title}, link_id => $link_id, category_id => $category_id } ); } END_OF_SUB $COMPILE{link_del} = __LINE__ . <<'END_OF_SUB'; sub link_del { # ------------------------------------------------------------------- # deletes a link from the database # my $self = shift; my $link_id = $IN->param ('link_id'); my $category_id = $IN->param ('category_id'); my $category = $DB->table ('Category'); my $links = $DB->table ('Links'); my $navbar = $self->navbar ($category_id); my $category_info = $category->get ( { ID => $category_id }, 'HASH', ['ID', 'Name', 'Number_of_Links'] ) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDCATID', $category_id), hist_go => -1 ); my $link_info = $links->get ( { ID => $link_id }, 'HASH', ['Title'] ) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDLINKID', $link_id), hist_go => -1 ); my $rows = $links->delete ( { ID => $link_id, 'CatLinks.CategoryID' => $category_id } ); if ($rows == 0) { return $self->javascript_error ( message => Links::language('BROWSER_LINKCANTDEL', _format_js($GT::SQL::error)), hist_go => -1 ); } my %info = $self->_links_list_html ($category_id); $self->print_template ( "browser_link_del.html", { id => $category_id, Name => $category_info->{Name}, navbar => $navbar, %info } ); } END_OF_SUB $COMPILE{link_move_form} = __LINE__ . <<'END_OF_SUB'; sub link_move_form { # ------------------------------------------------------------------- my $self = shift; my $link_id = $IN->param ('link_id'); my $category_id = $IN->param ('category_id'); my $category = $DB->table ('Category'); my $links = $DB->table ('Links'); my $navbar = $self->navbar ($category_id); my $category_info = $category->get ( { ID => $category_id }, 'HASH', ['Name'] ) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDCATID', $category_id), hist_go => -1 ); my $link_info = $links->get ( { ID => $link_id }, 'HASH', ['Title'] ) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDLINKID', $link_id), hist_go => -1 ); $self->print_template ( "browser_link_move_form.html", { Name => $category_info->{Name}, navbar => $navbar, old_category_id => $category_id, link_move => $link_id } ); } END_OF_SUB $COMPILE{link_move} = __LINE__ . <<'END_OF_SUB'; sub link_move { # ------------------------------------------------------------------- # moves a link into another category # my $self = shift; my $link_id = $IN->param ('link_id'); my $old_category_id = $IN->param ('old_category_id'); my $new_category_id = $IN->param ('new_category_id'); my $category = $DB->table ('Category'); my $links = $DB->table ('Links'); my $catlinks = $DB->table ('CatLinks'); my $navbar = $self->navbar ($old_category_id); # checks that the category id is not the root. if ($new_category_id == 0) { return $self->javascript_error ( message => Links::language('BROWSER_LINKMOVEROOT'), hist_go => -1 ); } my $old_category_info = $category->get ( { ID => $old_category_id }, 'HASH', ['Name'] ) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDCATID', $old_category_id), hist_go => -1 ); my $new_category_info = $category->get ( { ID => $new_category_id }, 'HASH', ['Name'] ) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDCATID', $new_category_id), hist_go => -1 ); my $link_info = $links->get ( { ID => $link_id } ) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDLINKID', $link_id), hist_go => -1 ); # checks that the link does not exists in the target category my $exists = $catlinks->get ( { LinkID => $link_id, CategoryID => $new_category_id } ); if ($exists) { return $self->javascript_error ( message => Links::language('BROWSER_LINKMOVEEXISTS'), hist_go => -1 ); } # Remove the timestamp. delete $link_info->{Timestmp}; # move the link. $link_info->{'CatLinks.CategoryID'} = $self->_build_category_id_set ($link_id, $old_category_id, $new_category_id); $links->modify ($link_info) or return $self->javascript_error ( message => Links::language('BROWSER_LINKCANTMOD', _format_js($GT::SQL::error)), hist_go => -1 ); my %info = $self->_links_list_html ($old_category_id); $self->print_template ( "browser_link_move.html", { old => $old_category_id, new => $new_category_id, Name => $old_category_info->{Name}, New_Name => $new_category_info->{Name}, navbar => $navbar, %info } ); } END_OF_SUB $COMPILE{link_copy_form} = __LINE__ . <<'END_OF_SUB'; sub link_copy_form { # ------------------------------------------------------------------- # outputs a form that can be used to copy a link # my $self = shift; my $link_id = $IN->param ('link_id'); my $category_id = $IN->param ('category_id'); my $category = $DB->table ('Category'); my $links = $DB->table ('Links'); my $navbar = $self->navbar ($category_id); my $category_info = $category->get ( { ID => $category_id }, 'HASH', ['Name'] ) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDCATID', $category_id), hist_go => -1 ); my $link_info = $links->get ( { ID => $link_id }, 'HASH', ['Title'] ) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDLINKID', $link_id), hist_go => -1 ); $self->print_template ( "browser_link_copy_form.html", { navbar => $navbar, Name => $category_info->{Name}, old_category_id => $category_id, link_copy => $link_id, } ); } END_OF_SUB $COMPILE{link_copy} = __LINE__ . <<'END_OF_SUB'; sub link_copy { # ------------------------------------------------------------------- # copies a link in another category # my $self = shift; my $link_id = $IN->param ('link_id'); my $old_category_id = $IN->param ('old_category_id'); my $new_category_id = $IN->param ('new_category_id'); my $category = $DB->table ('Category'); my $links = $DB->table ('Links'); my $catlinks = $DB->table ('CatLinks'); my $navbar = $self->navbar ($old_category_id); # checks that the category id is not the root. if ($new_category_id == 0) { return $self->javascript_error ( message => Links::language('BROWSER_LINKMOVEROOT'), hist_go => -1 ); } my $old_category_info = $category->get ( { ID => $old_category_id }, 'HASH', ['Name'] ) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDCATID', $old_category_id), hist_go => -1 ); my $new_category_info = $category->get ( { ID => $new_category_id }, 'HASH', ['Name'] ) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDCATID', $new_category_id), hist_go => -1 ); my $link_info = $links->get ( { ID => $link_id } ) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDLINKID', $link_id), hist_go => -1 ); # checks that the link does not exists in the target category my $exists = $catlinks->get ( { LinkID => $link_id, CategoryID => $new_category_id } ); if ($exists) { return $self->javascript_error ( message => Links::language('BROWSER_LINKMOVEEXISTS'), hist_go => -1 ); } # Remove the timestamp. delete $link_info->{Timestmp}; $link_info->{'CatLinks.CategoryID'} = $self->_build_category_id_set ($link_id, undef, $new_category_id); $links->modify ($link_info) or return $self->javascript_error ( message => Links::language('BROWSER_LINKCANTMOD', _format_js($GT::SQL::error)), hist_go => -1 ); my %info = $self->_links_list_html ($old_category_id); $self->print_template ( "browser_link_copy.html", { new => $new_category_id, navbar => $navbar, Name => $old_category_info->{Name}, New_Name => $new_category_info->{Name}, %info } ); } END_OF_SUB $COMPILE{link_validate_list} = __LINE__ . <<'END_OF_SUB'; sub link_validate_list { # ------------------------------------------------------------------- # Displays a list of links to validate. # my $self = shift; my ($limit, $offset, $page) = Links::limit_offset(); $limit = 200 if $limit > 200; # Safety limit; my $base = $self->{ctrl}->user_base_node; my $category_id = $IN->param('category_id'); my $navbar = $self->navbar($category_id); my $perms = $self->{ctrl}->perms($category_id); my $sb = $IN->param('sb') || $IN->param('cookie-link_validate_sb') || $IN->cookie('link_validate_sb') || ''; $sb = 'Add_Date' unless $sb =~ /^(?:ID|Title|URL|LinkOwner|Add_Date)$/; my $so = $IN->param('so') || $IN->param('cookie-link_validate_so') || $IN->cookie('link_validate_so') || ''; $so = 'DESC' if $so ne 'DESC' and $so ne 'ASC'; my $lnk_db = $DB->table('Links', 'CatLinks'); $lnk_db->select_options("ORDER BY $sb $so", "LIMIT $limit OFFSET $offset"); my $sth; my $singlecat = $IN->param('only_this_category'); if (@$base) { my $cat_db = $DB->table('Category'); my @ids; for my $id (@$base) { next if $singlecat and $category_id != 0 and $id != $category_id; if ($singlecat) { push @ids, $id; last; } else { my $children = $cat_db->children($id) or next; push @ids, $id, @$children; } } $sth = $lnk_db->select({ CategoryID => \@ids, isValidated => 'No' }); } else { if ($singlecat and $category_id != 0) { $sth = $lnk_db->select({ CategoryID => $category_id, isValidated =>, 'No' }); } else { $sth = $lnk_db->select({ isValidated =>, 'No' }); } } my $count = $lnk_db->hits; # Generate toolbar. my $tb; if ($count > $limit) { my $cgi = new GT::CGI; $cgi->param('action', 'link_validate_list'); $cgi->param('category_id', $category_id); $tb = $DB->html($lnk_db, $IN)->toolbar($page, $limit, $count, $cgi->url); } # Get list of links. my $output = ''; while (my $link = $sth->fetchrow_hashref) { $output .= $self->return_template("browser_link_list.html", { category_id => $link->{CategoryID}, hasChangeRequest => 0, linkowner_esc => GT::CGI->escape($link->{LinkOwner}), %$link, %$perms } ); } my $info = { toolbar => $tb, links => $output, count => $count, category_id => $category_id, navbar => $navbar, so => $so, sb => $sb }; $self->print_template("browser_validate_links.html", $info); } END_OF_SUB $COMPILE{link_validate_detailed} = __LINE__ . <<'END_OF_SUB'; sub link_validate_detailed { # ------------------------------------------------------------------- # Displays a list of links and forms for validation # my $self = shift; # The Browser::Controller removes all listings of entries that the user does # not have permission to validate. Thus, the following code does not perform any # additional security checks. my $db = $DB->table( 'Links' ); my $user_db = $DB->table( 'Users' ); my $cat_link = $DB->table( 'CatLinks' ); # Let's parse out the form, and group our links together. my $args = $IN->get_hash(); my (@validate, @email, @delete, @modify, @delete_change, @email_change, $tmp); while (my ($key, $param) = each %$args) { if ($key =~ /^(\d+)-(.*)$/) { $tmp->{$1}->{$2} = $param; } } my $links = {}; foreach (keys %$tmp) { $links->{$tmp->{$_}->{ID}} = $tmp->{$_}; } my ( @errors, @validated, $chng_db ); require Links::Tools; for my $link_id ( keys %$links ) { my $link_info = $links->{$link_id}; $link_info->{'CatLinks.CategoryID'} = $self->_build_category_id_set($link_id); my $error; $_ = $args->{"validate-$link_id"} or next; CASE: { /^validate$/ and do { $link_info->{_mode} = 'validate'; $error = $PLG->dispatch('validate_link', \&Links::Tools::_validate_record, $link_info); last; }; /^email$/ and do { $error = Links::Tools::_delete_email_record($db, $user_db, $link_info, $link_info->{reason}); last; }; /^delete$/ and do { Links::Tools::_delete_record( $db, $link_id ) or ($error = $GT::SQL::error); last; }; /^modify$/ and do { $link_info->{_mode} = 'modify'; $error = $PLG->dispatch('validate_link', \&Links::Tools::_validate_record, $link_info ); if (! $error) { $chng_db ||= $DB->table ('Changes'); $chng_db->delete( { LinkID => $link_id } ); } last; }; /^delete_change$/ and do { $error = Links::Tools::_delete_email_change_record($db, $user_db, $link_info, $link_info->{reason}); Links::Tools::_delete_change( $link_id ) or ($error = $GT::SQL::error); last; }; /^email_change$/ and do { $error = Links::Tools::_delete_email_change_record($db, $user_db, $link_info, $link_info->{reason}); last; }; }; push @errors, $error if $error; push @validated, $link_id; } my $val_result = ''; @validated and $val_result = @errors ? Links::language( 'BROWSER_VALIDATE_ERROR', join( "", @errors ) ) : Links::language( 'BROWSER_VALIDATE_OK' ); # Continue on with the normal display of links awaiting validation my ($limit, $offset, $page) = Links::limit_offset(); $limit = 200 if $limit > 200; # Safety limit; my $base = $self->{ctrl}->user_base_node; my $category_id = $IN->param('category_id'); my $navbar = $self->navbar($category_id); my $perms = $self->{ctrl}->perms($category_id); # Prepare the values of basic operational parameters my $sb = $IN->param('sb') || $IN->param('cookie-link_validate_detailed_sb') || $IN->cookie('link_validate_detailed_sb') || ''; $sb = 'Add_Date' unless $sb =~ /^(?:ID|Title|URL|LinkOwner|Add_Date)$/; my $so = $IN->param('so') || $IN->param('cookie-link_validate_detailed_so') || $IN->cookie('link_validate_detailed_so') || ''; $so = 'DESC' unless $so =~ /^(?:DESC|ASC)$/; my $mh = int( $IN->param('mh') || 0 ) || 25; my $update = $IN->param('update'); # Fetch the IDs of the categories the user is allowed to validate. This will # also account for the situation when the user will attempt to search # within a single category and not look within subcategories my ( @cat_ids, $cond ); my $singlecat = $IN->param('only_this_category'); my $cat_db = $DB->table( 'Category' ); if ( @$base ) { for my $cat_id ( @$base ) { # If the user has requested only a single category, we will filter out # everything but that single c ategory next if $singlecat and $category_id != 0 and $cat_id != $category_id; # Include that single category if ( $singlecat ) { push @cat_ids, $cat_id; last; } # Otherwise, include this particular category and all subcatgories else { my $children = $cat_db->children($cat_id) or next; push @cat_ids, $cat_id, @$children; } } $cond = { CategoryID => \@cat_ids }; } elsif ( $singlecat and $category_id != 0 ) { $cond = { CategoryID => $category_id }; } else { $cond = {}; }; # Now, with the list of all categories the user is permitted to access, attempt to # find the all links/changes my ( $link_hits_sth, $link_count ); # If this is an "update" search, must pull from the changes database if ( $update ) { my $cat_search_db = $DB->table( 'CatLinks', 'Changes', 'Links' ); $cat_search_db->select_options( "GROUP BY LinkID", "ORDER BY $sb $so", "LIMIT $limit OFFSET $offset" ); $link_hits_sth = $cat_search_db->select( 'Links.*', 'Changes.*', $cond ); $link_count = $cat_search_db->hits; } # This is a standard validate records search so pull from the Links database # with attention to which category the record is coming from else { my $cat_search_db = $DB->table( 'Links', 'CatLinks' ); $cat_search_db->select_options("ORDER BY $sb $so", "LIMIT $limit OFFSET $offset"); $cond->{isValidated} = 'No'; $link_hits_sth = $cat_search_db->select( $cond ); $link_count = $cat_search_db->hits; } # At this point, there is a handle to all the new links and a count of # hits available. Thus, it is possible to find out if a toolbar is required my $tb; if ($link_count > $limit) { my $cgi = GT::CGI->new( "category_id=$category_id;" . "action=link_validate_detailed;" . "mh=$mh;" . "so=$so;" . "sb=$sb;" ); $tb = $DB->html($db, $IN)->toolbar($page, $limit, $link_count, $cgi->url); } # And finally, it is posible to get a list of all the links that are available to # the user to validate my $output = ''; Links::init_date(); my $today = GT::Date::date_get(); my $i = 0; while (my $link = $link_hits_sth->fetchrow_hashref) { $i++; my $link_info = $update ? eval $link->{ChgRequest} : $link; $link->{'CatLinks.CategoryID'} = [$cat_link->select('CategoryID', { LinkID => $link_info->{ID} })->fetchall_list]; # Load reason before setting the Add_Date/Mod_Date to today. my $reason; { local $USER; my $user = $user_db->get($link_info->{LinkOwner}) || {}; $reason = Links::send_email('link_rejected.eml', { %$user, %$link_info }, { get_body => 1 }); }; # Set Add_Date/Mod_Date, so if the link gets validated, it gets set to the current date. $link_info->{Add_Date} = $today if $CFG->{link_validate_date} and not $update; $link_info->{Mod_Date} = $today; # Then, automatically create the HTML form that will allow modification to the editor my $html = $DB->html( $db, $link_info ); my $form = $html->form({ defaults => 1, multiple => $i, skip => [qw/CatLinks.LinkID Timestmp/], hide => [qw/ID isNew isChanged isPopular isValidated Status Date_Checked Timestmp/], extra_table => 0, file_field => 1, file_delete => 1, file_use_path => $update, show_diff => $update, values => $link_info }); # And add any supporting HTML that can may be used to display each record $output .= $self->return_template( 'browser_validate_detailed_form.html', { %$link_info, form => $form, update => $update, reason => $reason, } ); } my $info = { toolbar => $tb, links => $output, count => $link_count, category_id => $category_id, navbar => $navbar, result => $val_result, so => $so, sb => $sb, }; $self->print_template("browser_validate_detailed.html", $info); } END_OF_SUB $COMPILE{link_validate_changes_list} = __LINE__ . <<'END_OF_SUB'; sub link_validate_changes_list { # ------------------------------------------------------------------- # Displays a list of links to validate. # my $self = shift; my ($limit, $offset, $page) = Links::limit_offset(); $limit = 200 if $limit > 200; # Safety limit; my $base = $self->{ctrl}->user_base_node; my $category_id = $IN->param('category_id'); my $navbar = $self->navbar($category_id); my $perms = $self->{ctrl}->perms($category_id); my $sb = $IN->param('sb') || $IN->param('cookie-link_validate_changes_sb') || $IN->cookie('link_validate_changes_sb') || ''; $sb = 'Add_Date' unless $sb =~ /^(?:ID|Title|URL|LinkOwner|Add_Date)$/; my $so = $IN->param('so') || $IN->param('cookie-link_validate_changes_so') || $IN->cookie('link_validate_changes_so') || ''; $so = 'DESC' if $so ne 'DESC' and $so ne 'ASC'; my $cond; my $singlecat = $IN->param('only_this_category'); if (@$base) { my @ids; my $cat = $DB->table('Category'); for my $id (@$base) { next if $singlecat and $category_id != 0 and $id != $category_id; if ($singlecat) { push @ids, $id; last; } else { my $children = $cat->children($id) or next; push @ids, $id, @$children; } } $cond = { CategoryID => \@ids }; } elsif ($singlecat and $category_id != 0) { $cond = { CategoryID => $category_id }; } my $table = $DB->table('CatLinks', 'Changes', 'Links'); $table->select_options("GROUP BY LinkID", "ORDER BY $sb $so", "LIMIT $limit OFFSET $offset"); my $sth = $table->select('Links.*', 'CatLinks.*', $cond); my $count = $table->hits; # Generate toolbar. my $tb; if ($count > $limit) { my $cgi = new GT::CGI; $cgi->param('action', 'link_validate_changes_list'); $cgi->param('category_id', $category_id); $tb = $DB->html($DB->table('Links'), $IN)->toolbar($page, $limit, $count, $cgi->url); } # Get list of links. my $output = ''; while (my $link = $sth->fetchrow_hashref) { $output .= $self->return_template("browser_link_list.html", { category_id => $link->{CategoryID}, hasChangeRequest => 1, linkowner_esc => GT::CGI->escape($link->{LinkOwner}), %$link, %$perms } ); } my $info = { toolbar => $tb, links => $output, count => $count, category_id => $category_id, navbar => $navbar, update => 1, so => $so, sb => $sb }; $self->print_template("browser_validate_links.html", $info); } END_OF_SUB $COMPILE{link_validate_form} = __LINE__ . <<'END_OF_SUB'; sub link_validate_form { # ------------------------------------------------------------------- # Displays a link to validate. # my $self = shift; my $link_id = $IN->param ('link_id'); my $category_id = $IN->param ('category_id'); my $category = $DB->table ('Category'); my $links = $DB->table ('Links'); my $navbar = $self->navbar ($category_id); my $category_info = $category->get ( { ID => $category_id }, 'HASH', ['ID', 'Name', 'Number_of_Links'] ) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDCATID', $category_id), hist_go => -1 ); my $link_info; my $update = $IN->param('update'); if ($update) { my $change_db = $DB->table ('Changes'); my $link = $change_db->get ({ LinkID => $link_id }) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDLINKID', $GT::SQL::error), hist_go => -1 ); $link_info = eval $link->{ChgRequest}; if ($@) { die "Unable to update link: $@"; } # Old Change requests may contain ExpiryDate, which can overwrite payments made # by the user after making a modify request. Delete it so the ExpiryDate is # pulled from the current link data. delete $link_info->{ExpiryDate}; # Only the changed column data are saved in the Changes table my $orig = $links->get({ ID => $link_id }) || {}; $link_info = { %$orig, %$link_info }; # Check that the ExpiryDate is valid for the categories the link is in if ($CFG->{payment}->{enabled}) { require Links::Payment; my $expiry = Links::Payment::check_expiry_date($orig, $link_info->{'CatLinks.CategoryID'}); $link_info->{ExpiryDate} = $expiry if $expiry; } } else { $link_info = $links->get({ ID => $link_id }) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDLINKID', $link_id), hist_go => -1 ); } # Set Add_Date/Mod_Date, so if the link gets validated, it gets set to the current date. my $today = GT::Date::date_get(); $link_info->{Add_Date} = $today if $CFG->{link_validate_date} and not $update; $link_info->{Mod_Date} = $today; my $h = $DB->html($links, $link_info); my $form = $h->form({ defaults => 1, skip => [qw/CatLinks.LinkID Timestmp/], hide => [qw/ID isNew isChanged isPopular isValidated Status Date_Checked Timestmp/], extra_table => 0, file_field => 1, file_delete => 1, file_use_path => $update, show_diff => $update, values => $link_info }); if ($update) { # Hack needed to convert do=download_file into download_tmp_file, and # remove the fname parameter (which contains a full path). $form =~ s/(table('Users')->get($link_info->{LinkOwner}) || {}; my $reason = Links::send_email('link_rejected.eml', { %$user, %$link_info }, { get_body => 1 }); $USER = $curr_user; $self->print_template ( "browser_link_validate_form.html", { Name => $category_info->{Name}, navbar => $navbar, category_id => $category_id, reason => $reason, update => $update, form => $form . "", %$link_info } ); } END_OF_SUB $COMPILE{link_validate} = __LINE__ . <<'END_OF_SUB'; sub link_validate { # ------------------------------------------------------------------- # Validates a link. # my $self = shift; my $link_id = $IN->param ('ID'); my $category_id = $IN->param ('category_id'); my $category = $DB->table ('Category'); my $links = $DB->table ('Links'); my $email = $DB->table ('Users'); my $navbar = $self->navbar ($category_id); my $category_info = $category->get ( { ID => $category_id }, 'HASH', ['ID', 'Name', 'Number_of_Links'] ) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDCATID', $category_id), hist_go => -1 ); my $link_info = $links->get ( { ID => $link_id } ) or return $self->javascript_error ( message => Links::language('BROWSER_INVALIDLINKID', $link_id), hist_go => -1 ); my $h = $IN->get_hash; $h->{'CatLinks.CategoryID'} = $self->_build_category_id_set ($link_id); require Links::Tools; my $action = $IN->param('validate'); my ($error, $chng_db); CASE: { ($action eq 'validate') and do { $h->{_mode} = 'validate'; $error = $PLG->dispatch('validate_link', \&Links::Tools::_validate_record, $h); last CASE; }; ($action eq 'modify') and do { $h->{_mode} = 'modify'; $error = $PLG->dispatch('validate_link', \&Links::Tools::_validate_record, $h); if (! $error) { $chng_db ||= $DB->table ('Changes'); $chng_db->delete ( { LinkID => $h->{ID} } ); } last CASE; }; ($action eq 'delete') and do { Links::Tools::_delete_record ( $links, $link_id ) or ($error = $GT::SQL::error); last CASE; }; ($action eq 'delete_change')and do { Links::Tools::_delete_change ( $link_id ) or ($error = $GT::SQL::error); last CASE; }; ($action eq 'email') and do { $error = Links::Tools::_delete_email_record ($links, $email, $h, $h->{reason}); last CASE; }; ($action eq 'email_change') and do { $error = Links::Tools::_delete_email_change_record ($links, $email, $h, $h->{reason}); last CASE; }; } my %info = $self->_links_list_html ($category_id); $self->print_template ( "browser_link_validate.html", { id => $category_id, action => $action, error => $error, Name => $category_info->{Name}, navbar => $navbar, %info }); } END_OF_SUB $COMPILE{review_list} = __LINE__ . <<'END_OF_SUB'; sub review_list { # ------------------------------------------------------------------- # Displays a list of reviews. # my $self = shift; my ($limit, $offset, $page) = Links::limit_offset(); $limit = 200 if $limit > 200; # Safety limit; my $cat_id = $IN->param('category_id'); my $link_id = $IN->param('link_id'); my $perms = $self->{ctrl}->perms($cat_id); my $sb = $IN->param('sb') || $IN->param('cookie-review_sb') || $IN->cookie('review_sb') || ''; $sb = 'Review_Date' unless $sb =~ /^Review_(?:Owner|Date|Subject)$/; my $so = $IN->param('so') || $IN->param('cookie-review_so') || $IN->cookie('review_so') || ''; $so = 'DESC' if $so ne 'DESC' and $so ne 'ASC'; my ($tb, $sth, $count); if ($link_id) { $tb = $DB->table('Reviews', 'Links'); $tb->select_options("ORDER BY $sb $so", "LIMIT $limit OFFSET $offset"); $sth = $tb->select({ Review_LinkID => $link_id }); } else { $tb = $DB->table('Reviews', 'Links', 'CatLinks'); $tb->select_options("ORDER BY $sb $so", "LIMIT $limit OFFSET $offset"); my $singlecat = $IN->param('only_this_category'); my $base = $self->{ctrl}->user_base_node; if (@$base) { my $cat = $DB->table('Category'); my @ids; for my $id (@$base) { next if $singlecat and $cat_id != 0 and $id != $cat_id; if ($singlecat) { push @ids, $id; } else { my $children = $cat->children($id) or next; push @ids, $id, @$children; } } $sth = $tb->select({ CategoryID => \@ids, Review_Validated => 'No' }); } else { if ($singlecat and $cat_id != 0) { $sth = $tb->select({ CategoryID => $cat_id, Review_Validated => 'No' }); } else { $sth = $tb->select({ Review_Validated =>, 'No' }); } } } $count = $tb->hits; # Generate toolbar. my $toolbar; if ($count > $limit) { my $cgi = new GT::CGI; $cgi->param('action', 'review_list'); $cgi->param('category_id', $cat_id); $toolbar = $DB->html($tb, $IN)->toolbar($page, $limit, $count, $cgi->url); } # Get list of links. my $output = ''; while (my $review = $sth->fetchrow_hashref) { $output .= $self->return_template("browser_review_list.html", { category_id => $cat_id, %$review, %$perms }); } $self->print_template("browser_reviews.html", { toolbar => $toolbar, links => $output, count => $count, category_id => $cat_id, navbar => $self->navbar($cat_id), so => $so, sb => $sb, }); } END_OF_SUB $COMPILE{review_del_form} = __LINE__ . <<'END_OF_SUB'; sub review_del_form { # ------------------------------------------------------------------- # Displays a form to delete a review. # my $self = shift; my $review_id = $IN->param('review_id'); my $cat_id = $IN->param('category_id'); my $review = $DB->table('Reviews', 'Links')->select({ ReviewID => $review_id })->fetchrow_hashref; return $self->javascript_error(message => Links::language('BROWSER_INVALIDREVIEWID', $review_id), hist_go => -1) unless $review; $self->print_template("browser_review_del_form.html", { navbar => $self->navbar($cat_id), category_id => $cat_id, review_id => $review_id, %$review }); } END_OF_SUB $COMPILE{review_del} = __LINE__ . <<'END_OF_SUB'; sub review_del { # ------------------------------------------------------------------- # Delete a review. # my $self = shift; my $review_id = $IN->param('review_id'); my $cat_id = $IN->param('category_id'); my $review = $DB->table('Reviews', 'Links')->select({ ReviewID => $review_id })->fetchrow_hashref; return $self->javascript_error(message => Links::language('BROWSER_INVALIDREVIEWID', $review_id), hist_go => -1) unless $review; # Make sure the user is allowed to delete reviews in the category the review's link is in. my $base = $self->{ctrl}->user_base_node; if (@$base) { my $cat = $DB->table('Category'); my @ids; for my $id (@$base) { my $children = $cat->children($id) or next; push @ids, $id, @$children; } unless ($DB->table('CatLinks')->count({ LinkID => $review->{Review_LinkID}, CategoryID => \@ids })) { return $self->javascript_error(message => Links::language('BROWSER_UNAUTHORIZED', $review_id), hist_go => -1); } } $DB->table('Reviews')->delete({ ReviewID => $review_id }); $self->print_template("browser_review_result.html", { navbar => $self->navbar($cat_id), category_id => $cat_id, review_id => $review_id, delete => 1, %$review }); } END_OF_SUB $COMPILE{review_modify_form} = __LINE__ . <<'END_OF_SUB'; sub review_modify_form { # ------------------------------------------------------------------- # Displays a review to modify/validate. # my $self = shift; my $review_id = $IN->param('review_id'); my $cat_id = $IN->param('category_id'); my $review = $DB->table('Reviews', 'Links')->select({ ReviewID => $review_id })->fetchrow_hashref; return $self->javascript_error(message => Links::language('BROWSER_INVALIDREVIEWID', $review_id), hist_go => -1) unless $review; # We don't want $USER to contain the current user's info my $reason; if ($IN->param('validate')) { my $curr_user = $USER; $USER = {}; my $user = $DB->table('Users')->get($review->{Review_Owner}) || {}; my $link = $DB->table('Links')->get($review->{Review_LinkID}) || {}; $link->{detailed_url} = "$CFG->{build_detail_url}/" . $DB->table('Links')->detailed_url($link->{ID}); $reason = Links::send_email('review_rejected.eml', { %$user, %$link, %$review }, { get_body => 1 }); $USER = $curr_user; } $self->print_template("browser_review_modify_form.html", { navbar => $self->navbar($cat_id), category_id => $cat_id, reason => $reason, form => $DB->html($DB->table('Reviews'), $review)->form({ defaults => 1, hide => [qw/ReviewID Review_LinkID Review_Rating Review_WasHelpful Review_WasNotHelpful/], file_field => 1, file_delete => 1, extra_table => 0 }), %$review }); } END_OF_SUB $COMPILE{review_modify} = __LINE__ . <<'END_OF_SUB'; sub review_modify { # ------------------------------------------------------------------- # Modifies a review. # my $self = shift; my $review_id = $IN->param('ReviewID'); my $cat_id = $IN->param('category_id'); my $validate = $IN->param('validate'); my $action = $IN->param('do'); my $review = $DB->table('Reviews')->select({ ReviewID => $review_id })->fetchrow_hashref; return $self->javascript_error(message => Links::language('BROWSER_INVALIDREVIEWID', $review_id), hist_go => -1) unless $review; return $self->javascript_error(message => Links::language('BROWSER_REVIEWVALIDATED'), hist_go => -1) if $validate and $review->{Review_Validated} eq 'Yes'; # Make sure the user is allowed to modify reviews in the category the review's link is in. my $base = $self->{ctrl}->user_base_node; if (@$base) { my $cat = $DB->table('Category'); my @ids; for my $id (@$base) { my $children = $cat->children($id) or next; push @ids, $id, @$children; } unless ($DB->table('CatLinks')->count({ LinkID => $review->{Review_LinkID}, CategoryID => \@ids })) { return $self->javascript_error(message => Links::language('BROWSER_UNAUTHORIZED', $review_id), hist_go => -1); } } my $error; my $in = $IN->get_hash; require Links::Tools; if ($action eq 'modify') { delete $in->{ReviewID}; my $id = delete $in->{Review_LinkID}; $DB->table('Reviews')->update($in, { ReviewID => $review_id }) or $error = $GT::SQL::error; # Update the Timestmp for the link so the detailed pages get rebuilt with build changed $DB->table('Links')->update({ Timestmp => \'NOW()' }, { ID => $id }); } elsif ($action eq 'validate') { $error = $PLG->dispatch('validate_review', \&Links::Tools::_validate_review_record, $in); } elsif ($action eq 'email') { Links::Tools::_delete_email_review_record($in, $in->{reason}); } elsif ($action eq 'delete') { $DB->table('Reviews')->delete({ ReviewID => $review_id }); } $self->print_template("browser_review_result.html", { action => $action, error => $error, category_id => $cat_id, navbar => $self->navbar($cat_id) }); } END_OF_SUB $COMPILE{link_search_form} = __LINE__ . <<'END_OF_SUB'; sub link_search_form { # ------------------------------------------------------------------- # $obj->_link_search_form; # ------------------------------- # Prints out a search form in order to let a user # search for links. # my $self = shift; my $error = shift; my $category = $DB->table('Category'); my $links = $DB->table('Links'); my $category_id = $IN->param('category_id'); my $navbar = $self->navbar($category_id); my $category_info = $category->get({ ID => $category_id }, 'HASH', ['ID', 'Name', 'Number_of_Links'] ) or return $self->javascript_error( message => Links::language('BROWSER_INVALIDCATID', $category_id) ); my $h = $DB->html($links, $IN); $self->print_template( "browser_link_search_form.html", { error => $error, navbar => $navbar, Name => $category_info->{Name}, category_id => $category_id, form => $h->form ( { defaults => 0, skip => [ qw /CatLinks.LinkID Timestmp/ ], file_field => 1, file_delete => 1, search_opts => 1, }) . "" } ); } END_OF_SUB $COMPILE{link_search_results} = __LINE__ . <<'END_OF_SUB'; sub link_search_results { # ------------------------------------------------------------------- # $obj->_link_search_results; # ------------------------------ # Prints out the search results # my $self = shift; my $category_id = $IN->param('category_id'); my $change_db = $DB->table('Changes'); my ($limit, $offset, $page) = Links::limit_offset(); $limit = 200 if $limit > 200; # Safety limit my $perms = $self->{ctrl}->perms($category_id); my $navbar = $self->navbar($category_id); my $link_db = $DB->table('Links'); my $in = $IN->get_hash(); # Get the category ids that the search will be done on. # Do the search and count the results. $in->{"CatLinks.CategoryID"} = ""; if ($in->{in_category}) { $in->{"CatLinks.CategoryID"} = $in->{in_category}; } elsif (!$self->{ctrl}->admin) { my $cats = $self->{ctrl}->user_base_node; # The user is allowed to access user_base_node categories and their children. my $children = $DB->table('Category')->children($cats); for (keys %$children) { push @$cats, @{$children->{$_}}; } $in->{"CatLinks.CategoryID"} = $cats; } my $sth = $link_db->query_sth($in); my $count = $link_db->hits(); if ($count == 0) { return $self->link_search_form(Links::language('BROWSER_NOSEARCH')); } # Generate toolbar. my $tb; if ($count > $limit) { my $cgi = new GT::CGI; $cgi->param('action', 'link_search_results'); $cgi->param('category_id', $category_id); $tb = $DB->html($link_db, $IN)->toolbar($page, $limit, $count, $cgi->url); } # Get list of links that have changes. my $ids = $sth->fetchall_arrayref; my %changed; my @ids = map {$_->[0]} @$ids; my $sth2 = $change_db->select({LinkID => \@ids}); while (my ($id) = $sth2->fetchrow_array) { $changed{$id} = 1; } # Now get the actual link information. $sth = $link_db->query_sth($in); # Get list of links. my @links; my $c_table = $DB->table('CatLinks'); while (my $link = $sth->fetchrow_hashref) { $link->{CategoryID} ||= $c_table->select(['CategoryID'],{LinkID => $link->{ID}})->fetchrow_array(); push (@links,{ category_id => $category_id, hasChangeRequest => $changed{$link->{ID}} || 0, linkowner_esc => GT::CGI->escape($link->{LinkOwner}), %$link, %$perms, # $perms can contain the CategoryID (for editor's), which breaks deletion, so # make sure we override it CategoryID => $link->{CategoryID}, } ); } my $info = { toolbar => $tb, count => $count, navbar => $navbar, links => \@links}; $self->print_template('browser_link_search_results.html',$info); } END_OF_SUB # -------------------------------------------------------------------------------------- # # Private Functions # # -------------------------------------------------------------------------------------- # sub _build_category_id_set { # ------------------------------------------------------------------- # returns a set of category ids when updating # my ($self, $linkid, $remove, $add) = @_; my %res; my $catlinks = $DB->table (qw /CatLinks/); my $sth = $catlinks->select ( { LinkID => $linkid } ); while (my $h = $sth->fetchrow_hashref) { $res{$h->{CategoryID}} = 1; } delete $res{$remove} if $remove; $res{$add} = 1 if $add; return wantarray ? keys %res : [ keys %res ]; } sub _links_list_html { # ------------------------------------------------------------------- # build an HTML list of all the links in a given category # my ($self, $category_id, $username) = @_; my $change_db = $DB->table('Changes'); my ($limit, $offset, $page) = Links::limit_offset(); $limit = 200 if $limit > 200; # Safety limit my $perms = $self->{ctrl}->perms($category_id); my ($link_db, $catlink_db, $sth, $count, $tb); # Select list of ID's. $link_db = $DB->table('Links'); if ($username) { $link_db->select_options("LIMIT $limit OFFSET $offset"); $sth = $link_db->select('ID', { LinkOwner => $username }) or die "Database error: $GT::SQL::error"; $count = $link_db->hits; } else { $catlink_db = $DB->table('CatLinks', 'Links'); $catlink_db->select_options("ORDER BY $CFG->{build_sort_order_editor}", "LIMIT $limit OFFSET $offset"); $sth = $catlink_db->select('ID', { CategoryID => $category_id }) or die "Database error: $GT::SQL::error"; $count = $catlink_db->hits; } if ($count == 0) { my $info = { toolbar => '', links => '', count => $count }; return wantarray ? %$info : $info; } # Get list of links that have changes. my @ids = $sth->fetchall_list; my %changed; my $sth2 = $change_db->select({ LinkID => \@ids }); while (my ($id) = $sth2->fetchrow_array) { $changed{$id} = 1; } # Generate toolbar. if ($count > $limit) { my $cgi = new GT::CGI; # Get the base URL for the toolbar my @query_elements; if ($username) { push @query_elements, ( [ action => 'link_user_list' ], [ user => $username ] ) } else { push @query_elements, ( [ action => 'category_click' ] ); } push @query_elements, [ category_id => $category_id ]; my $url = ''; my $script = $ENV{SCRIPT_NAME} || $0; my ($path, $prog) = $script =~ m,^(.+?)[/\\]?([^/\\]*)$,; $prog =~ s,^[/\\]*|[/\\]*$,,g; $url .= $prog; if ( $ENV{PATH_INFO}) { if (defined $ENV{SERVER_SOFTWARE} && ($ENV{SERVER_SOFTWARE} =~ /IIS/)) { $ENV{PATH_INFO} =~ s,$ENV{SCRIPT_NAME},,; } $url .= $ENV{PATH_INFO}; } foreach my $p (qw( mh nh )) { next unless my $v = $IN->param( $p ); push @query_elements, [ $p => $v ]; } my @query_parameters; foreach my $p ( @query_elements ) { push @query_parameters, $IN->escape( $p->[0] ) . '=' . $IN->escape( $p->[1] ); } $url .= '?' . join "&", @query_parameters if @query_parameters; # create the toolbar html $tb = $DB->html($link_db || $catlink_db, $IN)->toolbar($page, $limit, $count, $url ); } # Now get the actual link information. $sth = $link_db->select({ ID => \@ids }); # Get list of links. my %output; while (my $link = $sth->fetchrow_hashref) { $output{$link->{ID}} = $self->return_template("browser_link_list.html", { category_id => $category_id, hasChangeRequest => $changed{$link->{ID}} || 0, hasReviews => $perms->{CanModReview} eq 'Yes' ? $DB->table('Reviews')->count({ Review_LinkID => $link->{ID} }) : 0, linkowner_esc => GT::CGI->escape($link->{LinkOwner}), %$link, %$perms } ); } my $output = join("\n", map { $output{$_} } @ids); my $info = { toolbar => $tb, links => $output, count => $count }; return wantarray ? %$info : $info; } sub navbar { # ------------------------------------------------------------------- # Prints out the navbar. # my ($self, $category_id) = @_; my $perms = $self->{ctrl}->perms ($category_id); if ($CFG->{payment}->{enabled} and $category_id) { my $mode = $DB->table('Category')->select('Payment_Mode', { ID => $category_id })->fetchrow(); if ($mode >= OPTIONAL) { # REQUIRED is > OPTIONAL $perms->{CanAddTerms} = 'Yes'; } } return $self->return_template ('browser_navbar.html', { category_id => $category_id, %$perms }); } sub javascript_error { # ------------------------------------------------------------------- # prints out an alert windows with the error information # my $self = shift; my $args; if (@_ == 1 and $_[0] eq ref {}) { $args = shift } else { $args = { @_ } } my @err = (qq /=============================================/, Links::language('GENERAL_ERROR'), qq /=============================================/, qq / /); push @err, $args->{message} if ($args->{message}); foreach (@err) { s/\\/\\\\/g; s/\n/\\n/g; s/'/\\'/g; s/"/\\"/g; } my $error = 'alert ('; $error .= join '+ "\n" +', map { '"' . $_ . '"' } @err; $error .= ');'; if ($args->{info_go}) { $error .= qq|parent.frames[parent.RIGHT_FRAME_ID].history.go($args->{info_go});\n|; } if ($args->{tree_go}) { $error .= qq|parent.frames[parent.LEFT_FRAME_ID].history.go($args->{tree_go});\n|; } if ($args->{hist_go}) { $error .= qq|history.go($args->{hist_go});\n|; } if ($args->{tree_redraw}) { require Links::Browser::JFunction; $error .= qq|parent.draw_tree(); parent.frames[parent.RIGHT_FRAME_ID].location.replace("| . Links::Browser::JFunction::tree_selectnode() . qq|&category_id=$args->{tree_redraw}");\n|; } return $self->print_template('browser_javascript_error.html', { error => $error }); } sub _format_js { # ------------------------------------------------------------------- # Format a string into something Javascript will like. # my $string = shift; my @tmp = split /\n/, $string; my $output = "\n"; foreach (@tmp) { $output .= " + $_ \n" if (defined $_); } return $output; } sub _total_categories { # ------------------------------------------------------------------- # returns the amount of categories that is being managed # by the current user. # my $self = shift; my $category = $DB->table ('Category'); return $category->count; } sub _quote { # ------------------------------------------------------------------- # Escapes text for use in javascript. # my $text = shift; return '""' if (! defined $text or ($text eq '')); $text =~ s/"/\\"/g; $text =~ s/\r//g; $text =~ s/\n/\\n/g; $text =~ s,<\s*/script\s*>,,g; return '"' . $text . '"'; } sub _format_insert_cgi { # ------------------------------------------------------------------- # Fix things with cgi on inserts/modify (similar to # GT::SQL::Admin::format_insert_cgi). Unchecked checkboxes don't return # anything, so the value needs to be set to an empty string. # my ($cgi, $table) = @_; my $cols = $table->cols; foreach (keys %$cols) { $cgi->{$_} = '' if !exists $cgi->{$_} and uc $cols->{$_}->{form_type} eq 'CHECKBOX'; } } 1;