Subversion Repositories DevTools

Rev

Rev 1295 | Blame | Compare with Previous | Last modification | View Log | RSS feed

###############################################################################
# Codestriker: Copyright (c) 2001, 2002 David Sitsky.  All rights reserved.
# sits@users.sourceforge.net
#
# This program is free software; you can redistribute it and modify it under
# the terms of the GPL.

# Action object for displaying a list of topics.

package Codestriker::Action::ListTopics;

use strict;
use Codestriker::Http::Template;
use Codestriker::Model::Topic;

# If the input is valid, list the appropriate topics.
sub process($$$) {
    my ($type, $http_input, $http_response) = @_;

    my $query = $http_response->get_query();

    # Check if this action is allowed.
    if ($Codestriker::allow_searchlist == 0) {
        $http_response->error("This function has been disabled");
    }

    # Obtain a new URL builder object.
    my $url_builder = Codestriker::Http::UrlBuilder->new($query);

    my $mode = $http_input->get('mode');
    my $feedback = $http_input->get('feedback');
    my $projectid = $http_input->get('projectid');

    my ( $sauthor, $sreviewer, $scc, $sbugid,
         $sstate, $sproject, $stext,
         $stitle, $sdescription,
         $scomments, $sbody, $sfilename,
         $sort_order) = get_topic_list_query_params($http_input);

    # Query the model for the specified data.
    my @topics = Codestriker::Model::Topic->query($sauthor, $sreviewer, $scc, $sbugid,
                                     $sstate, $sproject, $stext,
                                     $stitle, $sdescription,
                                     $scomments, $sbody, $sfilename,
                                     $sort_order);

    # Display the data, with each topic title linked to the view topic screen.
    # If only a single project id is being searched over, set that id in the
    # cookie.
    my @project_ids = ();
    if ($sproject ne "") {
        @project_ids = split ',', $sproject;
    }
    my $projectid_cookie = ($#project_ids == 0) ? $project_ids[0] : "";

    $http_response->generate_header(topic_title=>"Topic List", 
                                    projectid=>$projectid_cookie, 
                                    topicsort=>join(',',@$sort_order),
                                    reload=>0, cache=>0);

    # Create the hash for the template variables.
    my $vars = {};
    $vars->{'feedback'} = $feedback;

    # Store the search parameters, which become hidden fields.
    $vars->{'sauthor'} = $sauthor;
    $vars->{'sreviewer'} = $sreviewer;
    $vars->{'scc'} = $scc;
    $vars->{'sbugid'} = $sbugid;
    $vars->{'stext'} = $stext;
    $vars->{'sstate'} = $sstate;
    $vars->{'stitle'} = $stitle;
    $vars->{'sdescription'} = $sdescription;
    $vars->{'scomments'} = $scomments;
    $vars->{'sbody'} = $sbody;
    $vars->{'sfilename'} = $sfilename;

    # Collect the comment metric counts that they want to show on the main page.
    my @comment_metric_names;
    foreach my $comment_state_metric (@{$Codestriker::comment_state_metrics}) {
        if (exists($comment_state_metric->{show_on_mainpage})) {
            foreach my $value (@{$comment_state_metric->{show_on_mainpage}}) {
                push @comment_metric_names,
                     { name => $comment_state_metric->{name},
                       value => $value };
            }
        }
    }

    $vars->{'commentmetrics'} = \@comment_metric_names;

    # The url generated here includes all of the search parameters, so
    # that the current list of topics the user it viewing does not
    # revert back to the default open topic list.  The search is
    # applied each time they change the sort order.
    $vars->{'list_sort_url'} = 
        $url_builder->list_topics_url($sauthor, $sreviewer, $scc, $sbugid,
                                      $stext, $stitle,
                                      $sdescription, $scomments,
                                      $sbody, $sfilename,
                                      [ split ',', $sstate] , \@project_ids);

    $vars->{'list_sort_url_rss'} = 
        $url_builder->list_topics_url_rss($sauthor, $sreviewer, $scc, $sbugid,
                                      $stext, $stitle,
                                      $sdescription, $scomments,
                                      $sbody, $sfilename,
                                      [ split ',', $sstate] , \@project_ids);

    # The list of topics in the template toolkit.
    my @template_topics;

    # For each topic, collect all the reviewers, CC, and bugs, and display it
    # as a row in the table.  Each bug should be linked appropriately. 
    foreach my $topic (@topics) {

        # do the easy stuff first, 1 to 1 mapping into the template.
   
        my $template_topic = {};

        $template_topic->{'view_topic_url'} = 
            $url_builder->view_url($topic->{topicid}, -1, $mode,
                                   $Codestriker::default_topic_br_mode);
        
        $template_topic->{'description'} = $topic->{description};

        $template_topic->{'created'} =
            Codestriker->format_short_timestamp($topic->{creation_ts});

        $template_topic->{'id'}      = $topic->{topicid};
        $template_topic->{'title'}   = $topic->{title};

        $template_topic->{'version'} = $topic->{version};

        $template_topic->{'state'}   = $Codestriker::topic_states[$topic->{topic_state_id}];

        # Only include the username part of the email address to save space.
        my $accum_author = $topic->{author};
        $accum_author =~ s/\@.*$//o;
        $template_topic->{'author'} = $accum_author;

        # cc
        my $cc = $topic->{cc};
        $cc =~ s/\@.*$//o;
        $template_topic->{'cc'}     = $cc;

        # bug ids
        my @accum_bugs = split /, /, $topic->{bug_ids};
        for ( my $index = 0; $index < scalar(@accum_bugs); ++$index) {
            $accum_bugs[$index] =
                $query->a({href=>"$Codestriker::bugtracker$accum_bugs[$index]"},
                    $accum_bugs[$index]);
        }
        $template_topic->{'bugids'} = join ', ', @accum_bugs;

        # do the reviewers
        my @reviewers_vistited = 
            $topic->get_metrics()->get_list_of_actual_topic_participants();

        my @reviewers = split /, /, $topic->{reviewers};
        for ( my $index = 0; $index < scalar(@reviewers); ++$index) {

            my $reviewer = $reviewers[$index];

            my $is_visted = 0;
            foreach my $visted (@reviewers_vistited) {
                if ($visted eq $reviewer) {
                    $is_visted = 1;
                    last;
                }
            }

            # Output the accumulated information into the row.  Only
            # include the username part of an email address for now to
            # save some space.  This should be made a dynamic option
            # in the future.
            $reviewer =~ s/\@.*$//o;

            if ( $is_visted == 0) {
                $reviewer = "(" . $reviewer . ")";
            }           
                    
            $reviewers[$index] = $reviewer;      
                    }

        $template_topic->{'reviewer'} = join(", ",@reviewers);

        my @main_page_comment_metrics = ();
        foreach my $comment_state_metric (@{$Codestriker::comment_state_metrics}) {
        
            if ( exists($comment_state_metric->{show_on_mainpage})) {
                foreach my $value (@{$comment_state_metric->{show_on_mainpage}}) {

                    my $count = $topic->get_comment_metric_count($comment_state_metric->{name},$value);

                    my $template_comment_metric = 
                    {
                        name  => $comment_state_metric->{name},
                        value => $value,
                        count => $count
                    };

                    push @main_page_comment_metrics,$template_comment_metric;
                }
            }
        }

        $template_topic->{'commentmetrics'} = \@main_page_comment_metrics;

        push @template_topics, $template_topic;
    }

    $vars->{'topics'} = \@template_topics;
    $vars->{'states'} = \@Codestriker::topic_states;

    $vars->{'list_projects_url'} = $url_builder->list_projects_url();
    $vars->{'view_metrics_url'} = $url_builder->metric_report_url();

    my $template = Codestriker::Http::Template->new("listtopics");
    $template->process($vars);

    $http_response->generate_footer();
}

# Process the input and return the parts that will feed into the topic
# list query. Returns in the same order that the topic query function
# takes them.
sub get_topic_list_query_params {
    my ($http_input) = @_;

    # Check that the appropriate fields have been filled in.
    my $sauthor = $http_input->get('sauthor') || "";
    my $sreviewer = $http_input->get('sreviewer') || "";
    my $scc = $http_input->get('scc') || "";
    my $sbugid = $http_input->get('sbugid') || "";
    my $stext = $http_input->get('stext') || "";
    my $sstate = $http_input->get('sstate');
    my $sproject = $http_input->get('sproject');
    my $stitle = $http_input->get('stitle') || 0;
    my $sdescription = $http_input->get('sdescription') || 0;
    my $scomments = $http_input->get('scomments') || 0;
    my $sbody = $http_input->get('sbody') || 0;
    my $sfilename = $http_input->get('sfilename') || 0;
    my $projectid = $http_input->get('projectid');

    # If $sproject has been set to -1, then retrieve the value of the projectid
    # from the cookie as the project search value.  This is done to facilate
    # integration with other systems, which jump straight to this URL, and
    # set the cookie explicitly.
    if ($sproject eq "-1") {
        $sproject = (defined $projectid) ? $projectid : "";
    }
    
    # Only show open topics if codestriker.pl was run without parameters.
    if (defined($http_input->{query}->param) == 0 || !defined($sstate)) {
        $sstate = join(',', @Codestriker::default_states_indexes);
    }

    # handle the sort order of the topics.
    my @sort_order = get_topic_sort_order($http_input);

    return ( $sauthor, $sreviewer, $scc, $sbugid,
                                     $sstate, $sproject, $stext,
                                     $stitle, $sdescription,
                                     $scomments, $sbody, $sfilename,
                                     \@sort_order);
}

# Process the topic_sort_change input request (if any), and the current sort 
# cookie (topicsort), and returns a list that defines the topic sort order
# that should be used for this request. The function will ensure that 
# column types are not repeated, and will sort in the opposite direction
# if the user clicks on the same column twice.
sub get_topic_sort_order {
    my ($http_input) = @_;

    my $topic_sort_change = $http_input->get('topic_sort_change');
    my $topicsort = $http_input->get('topicsort');

    my @sort_order = split(/,/,$topicsort); # this is always from the cookie.

    if ($topic_sort_change ne "") {
        if (scalar(@sort_order) > 0) {

            # If the user clicked on the same column twice in a row, reverse
            # the direction of the sort.
            
            $sort_order[0] =~ s/\+$topic_sort_change/\-$topic_sort_change/ or
            $sort_order[0] =~ s/\-$topic_sort_change/\+$topic_sort_change/ or        
            unshift @sort_order, "+" . $topic_sort_change;
        }
        else {
            unshift @sort_order, "+" . $topic_sort_change;
        }

        # look for duplicate sort keys, and remove
        my %sort_hash;

        for ( my $index = 0; 
              $index < scalar( @sort_order); 
              # Incremented in the if...
              ) {

            # chew off the leading +-
            my $current = $sort_order[$index];

            if ($current =~ s/^[\+\-]//) {
                if (exists $sort_hash{$current}) {
                    # remove from the list.
                    splice @sort_order, $index,1;
                }
                else {
                    # have not seem this before, keep it, and look at the next
                    # string.
                    ++$index;                
                }

                $sort_hash{$current} = 1;
            } 
        }
    }

    # Pull out any elements that are not valid (from a bad cookie or from a bad
    # input.

    for (my $index = 0; $index < scalar(@sort_order) ; ++$index) {

        if ($sort_order[$index] ne "+title" && $sort_order[$index] ne "-title" &&
            $sort_order[$index] ne "+author" && $sort_order[$index] ne "-author" &&
            $sort_order[$index] ne "+created" && $sort_order[$index] ne "-created" &&
            $sort_order[$index] ne "+state" && $sort_order[$index] ne "-state") {
            
            splice @sort_order,$index,1;
            --$index;
        }
    }

    return @sort_order;
}

1;