Subversion Repositories DevTools

Rev

Rev 1300 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1293 dpurdie 1
###############################################################################
2
# Codestriker: Copyright (c) 2001, 2002 David Sitsky.  All rights reserved.
3
# sits@users.sourceforge.net
4
#
5
# This program is free software; you can redistribute it and modify it under
6
# the terms of the GPL.
7
 
8
# Action object for handling the submission of a new topic.
9
 
10
package Codestriker::Action::SubmitNewTopic;
11
 
12
use strict;
13
 
14
use File::Temp qw/ tempfile /;
15
use FileHandle;
16
 
17
use Codestriker::Model::Topic;
18
use Codestriker::Http::Render;
19
use Codestriker::Repository::RepositoryFactory;
20
use Codestriker::FileParser::Parser;
21
use Codestriker::Model::Project;
22
use Codestriker::TopicListeners::Manager;
23
 
24
# If the input is valid, create the appropriate topic into the database.
25
sub process($$$) {
26
    my ($type, $http_input, $http_response) = @_;
27
 
28
    my $query = $http_response->get_query();
29
 
30
    # Check that the appropriate fields have been filled in.
31
    my $topic_title = $http_input->get('topic_title');
32
    my $topic_description = $http_input->get('topic_description');
33
    my $reviewers = $http_input->get('reviewers');
34
    my $email = $http_input->get('email');
35
    my $cc = $http_input->get('cc');
36
    my $fh = $http_input->get('fh');
37
    my $topic_file = $http_input->get('fh_filename');
38
    my $fh_mime_type = $http_input->get('fh_mime_type');
39
    my $bug_ids = $http_input->get('bug_ids');
40
    my $repository_name = $http_input->get('repository');
41
    my $projectid = $http_input->get('projectid');
42
    my $project_name = $http_input->get('project_name');
43
    my $start_tag = $http_input->get('start_tag');
44
    my $end_tag = $http_input->get('end_tag');
45
    my $module = $http_input->get('module');
46
    my $obsoletes = $http_input->get('obsoletes');
47
    my $default_to_head = $http_input->get('default_to_head');
48
 
49
    my $feedback = "";
50
    my $topic_text = "";
51
 
52
    my $url_builder = Codestriker::Http::UrlBuilder->new($query);
53
 
54
    # Indicate whether the topic text needs to be retrieved by the repository
55
    # object.
56
    my $retrieve_text_from_rep = 0;
57
    if (($start_tag ne "" || $end_tag ne "") && $module ne "") {
58
	$retrieve_text_from_rep = 1;
59
 
60
	# Check if this action is permitted.
61
	if (scalar(@Codestriker::valid_repositories) == 0) {
62
	    $feedback .= "Repository functionality has been disabled.  " .
63
		"Can't create topic text usings tags.\n";
64
	}
65
    }
66
 
67
    if ($topic_title eq "") {
68
	$feedback .= "No topic title was entered.\n";
69
    }
70
    if ($topic_description eq "") {
71
	$feedback .= "No topic description was entered.\n";
72
    }
73
    if ($email eq "") {
74
	$feedback .= "No email address was entered.\n";
75
    }
76
    if (!defined $fh && $retrieve_text_from_rep == 0) {
77
	$feedback .= "No filename or module/tags were entered.\n";
78
    }
79
    if ($reviewers eq "") {
80
	$feedback .= "No reviewers were entered.\n";
81
    }
82
    if ($retrieve_text_from_rep && defined $fh) {
83
	$feedback .= "Topic text specified using tags and uploaded file.\n";
84
	$feedback .= "Please choose one topic text method, and try again.\n";
85
    }
86
 
87
    $http_response->generate_header(topic_title=>"Create New Topic",
88
				    email=>$email, reviewers=>$reviewers,
89
				    cc=>$cc, repository=>$repository_name,
90
				    projectid=>$projectid,
91
				    reload=>0, cache=>0);
92
 
93
    # Set the error_vars in case of any errors that will require forwarding
94
    # to the create topic screen again.
95
    my $error_vars = {};
96
    $error_vars->{'version'} = $Codestriker::VERSION;
97
    $error_vars->{'feedback'} = $feedback;
98
    $error_vars->{'email'} = $email;
99
    $error_vars->{'reviewers'} = $reviewers;
100
    $error_vars->{'cc'} = $cc;
101
    $error_vars->{'topic_file'} = $topic_file;
102
    $error_vars->{'topic_description'} = $topic_description;
103
    $error_vars->{'topic_title'} = $topic_title;
104
    $error_vars->{'bug_ids'} = $bug_ids;
105
    $error_vars->{'default_repository'} = $repository_name;
106
    $error_vars->{'repositories'} = \@Codestriker::valid_repository_names;
107
    $error_vars->{'start_tag'} = $start_tag;
108
    $error_vars->{'end_tag'} = $end_tag;
109
    $error_vars->{'module'} = $module;
110
    $error_vars->{'obsoletes'} = $obsoletes;
111
    $error_vars->{'default_to_head'} = $default_to_head;
112
    $error_vars->{'default_projectid'} = $projectid;
113
 
114
    my $repository = undef;
115
    my $repository_url = undef;
116
    if (scalar(@Codestriker::valid_repositories)) {
117
	# Set the repository to the default if it is not entered.
118
	if ($repository_name eq "" || scalar(@Codestriker::valid_repository_names) == 1) {
119
	    $repository_name = $Codestriker::valid_repository_names[0];
120
	}
121
 
122
	# Check if the repository argument is in fact a configured
123
        # repository.
124
        $repository_url = $Codestriker::repository_url_map->{$repository_name};
125
 
126
        if (defined $repository_url) {
127
	    $repository =
128
		Codestriker::Repository::RepositoryFactory->get($repository_url);
129
        }
130
 
131
	if (! defined $repository) {
132
	    $feedback .=
133
		"The repository value set for \"$repository_name\" is invalid.\n" .
134
		"Please correct this value in your codestriker.conf file, " .
135
		"and try again.\n";
136
	}
137
    }
138
 
139
    # Set the projectid to the first (default) if it is invalid.
140
    my @projects = Codestriker::Model::Project->list();
141
    my $found_project = 0;
142
    foreach my $project (@projects) {
143
        if ((defined $projectid && $project->{id} == $projectid) ||
144
	    (defined $project_name && $project->{name} eq $project_name)) {
145
	    $projectid = $project->{id};
146
            $found_project = 1;
147
            last;
148
        }
149
    }
150
    if ($found_project == 0) {
151
        $projectid = $projects[0]->{id};
152
    }
153
 
154
    # Make sure all the conditions from the topic listeners are satisified.
155
    $feedback .= Codestriker::TopicListeners::Manager::topic_pre_create
156
	($email, $topic_title, $topic_description,
157
	 $bug_ids, $reviewers, $cc,
158
	 $repository_url, $projectid);
159
 
160
    # If there is a problem with the input, redirect to the create screen
161
    # with the message.
162
    if ($feedback ne "") {
163
	if (defined $fh) {
164
	    $feedback .=
165
		"For security reasons, please re-enter the " .
166
		"file name to upload, if required.\n";
167
	}
168
	_forward_create_topic($error_vars, $feedback, $url_builder);
169
	$http_response->generate_footer();
170
	return;
171
    }
172
 
173
    my $topicid = Codestriker::Model::Topic::create_new_topicid();        
174
 
175
    # If the topic text needs to be retrieved from the repository object,
176
    # create a temporary file to store the topic text.
177
    my $temp_topic_fh;
178
    my $temp_error_fh;
179
 
180
    if ($retrieve_text_from_rep && defined $repository) {
181
	# Store the topic text into temporary files.
182
	if (defined $Codestriker::tmpdir && $Codestriker::tmpdir ne "") {
183
	    $temp_topic_fh = tempfile(DIR => $Codestriker::tmpdir);
184
	    $temp_error_fh = tempfile(DIR => $Codestriker::tmpdir);
185
	}
186
	else {
187
	    $temp_topic_fh = tempfile();
188
	    $temp_error_fh = tempfile();
189
	}
190
	binmode $temp_topic_fh;
191
	binmode $temp_error_fh;
192
 
193
	my $rc = $repository->getDiff($start_tag, $end_tag, $module,
194
				      $temp_topic_fh, $temp_error_fh,
195
				      $default_to_head);
196
 
197
	# Make sure the data has been flushed to disk.
198
	$temp_topic_fh->flush;
199
	$temp_error_fh->flush;
200
 
201
	# Check if the generated diff was too big, and if so, throw an error
202
	# message on the screen.
203
	if ($rc == $Codestriker::DIFF_TOO_BIG) {
204
	    $feedback .= "Generated diff file is too big.\n";
205
	} elsif ($rc == $Codestriker::UNSUPPORTED_OPERATION) {
206
	    $feedback .= "Repository \"" . $repository_name .
207
		"\" does not support tag retrieval, you have to use the text file upload.\n";
208
	} elsif ($rc != $Codestriker::OK) {
209
	    $feedback .= "Unexpected error $rc retrieving diff text.\n";
210
	}
211
 
1300 dpurdie 212
    if ($repository->{getDiffError})
213
    {
214
        $feedback .= $repository->{getDiffError};
215
    }
216
 
1293 dpurdie 217
	# Seek to the beginning of the temporary file so it can be parsed.
218
	seek($temp_topic_fh, 0, 0);
219
 
220
	# Set $fh to this file reference which contains the topic data.
221
	$fh = $temp_topic_fh;
222
    }
223
 
224
    my @deltas = ();
225
    if ($feedback eq "") {
226
	# Try to parse the topic text into its diff chunks.
227
	@deltas =
228
	    Codestriker::FileParser::Parser->parse($fh, "text/plain", $repository,
229
						   $topicid, $topic_file);
230
	if ($#deltas == -1) {
231
	    # Nothing in the file, report an error.
232
	    $feedback .= "Reviewable text in topic is empty.\n";
233
	}
234
    }
235
 
236
    if ($feedback ne "") {
237
	# If there was a problem generating the diff file, remove the
238
	# temporary files, and direct control to the create screen again.
239
	$temp_topic_fh->close if defined $temp_topic_fh;
240
	$temp_error_fh->close if defined $temp_error_fh;
241
	_forward_create_topic($error_vars, $feedback, $url_builder);
242
	$http_response->generate_footer();
243
	return;
244
    }
245
 
246
    # If the topic text has been uploaded from a file, read from it now.
247
    if (defined $fh) {
248
	while (<$fh>) {
249
	    $topic_text .= Codestriker::decode_topic_text($_);
250
	}
251
	if ($topic_text eq "") {
252
	    if (defined $temp_error_fh) {
253
		seek($temp_error_fh, 0, 0);
254
		$feedback .= "Problem generating topic text:\n\n";
255
		my $buf = "";
256
		while (read $temp_error_fh, $buf, 16384) {
257
		    $feedback .= $buf;
258
		}
259
	    }
260
	    else {
261
		$feedback = "Uploaded file doesn't exist or is empty.\n";
262
	    }
263
 
264
	    # Remove the temporary files if required, and forward control
265
	    # back to the create topic page.
266
	    $temp_topic_fh->close if defined $temp_topic_fh;
267
	    $temp_error_fh->close if defined $temp_error_fh;
268
	    _forward_create_topic($error_vars, $feedback, $url_builder);
269
	    $http_response->generate_footer();
270
	    return;
271
	}
272
    }
273
 
274
    # Remove the temporary files if required.
275
    $temp_topic_fh->close if defined $temp_topic_fh;
276
    $temp_error_fh->close if defined $temp_error_fh;
277
 
278
    # Remove \r from the topic text.
279
    $topic_text =~ s/\r//g;
280
 
281
    # Make sure the topic is not too large, count the number of \n
282
    # in the topic content text.
283
    my $new_topic_length = 0;
284
    ++$new_topic_length while ($topic_text =~ /\n/g);
285
 
286
    if (defined($Codestriker::maximum_topic_size_lines) && 
287
        $Codestriker::maximum_topic_size_lines ne "" &&
288
        $Codestriker::maximum_topic_size_lines < $new_topic_length)
289
    {        
290
	$feedback .=
291
	    "The topic length of $new_topic_length lines is too long. " . 
292
	    "Topics cannot exceed $Codestriker::maximum_topic_size_lines " . 
293
	    "lines long. Please remove content from topic, or break the " .
294
	    "topic into several independent topics.\n";
295
 
296
        _forward_create_topic($error_vars, $feedback, $url_builder);
297
        $http_response->generate_footer();
298
        return;
299
    }
300
 
301
    # Make sure the specified topicids to be obsoleted are in fact valid.
302
    if (defined $obsoletes && $obsoletes ne '') {
303
	my @data = split ',', $obsoletes;
304
	for (my $i = 0; $i <= $#data; $i+=2) {
305
	    my $id = $data[$i];
306
	    my $version = $data[$i+1];
307
 
308
	    if (! Codestriker::Model::Topic::exists($id)) {
309
		$feedback .= "Obsoleted topics specified do not exist.\n";
310
		_forward_create_topic($error_vars, $feedback, $url_builder);
311
		$http_response->generate_footer();
312
		return;
313
	    }
314
	}
315
    }
316
 
317
    # Create the topic in the model.
318
    my $topic = Codestriker::Model::Topic->new($topicid);
319
    $topic->create($topicid, $email, $topic_title,
320
		   $bug_ids, $reviewers, $cc,
321
		   $topic_description, $topic_text,
322
		   $start_tag, $end_tag, $module,
323
		   $repository_url, $projectid,
324
		   \@deltas, $obsoletes);
325
 
326
    # Obsolete any required topics.
327
    if (defined $obsoletes && $obsoletes ne '') {
328
	my @data = split ',', $obsoletes;
329
	for (my $i = 0; $i <= $#data; $i+=2) {
330
	    my $id = $data[$i];
331
	    my $version = $data[$i+1];
332
	    Codestriker::Action::SubmitEditTopicsState
333
		->update_state($id, $version, 'Obsoleted', $email);
334
	}
335
    }
336
 
337
    # Tell all of the topic listener classes that a topic has 
338
    # just been created.
339
    $feedback = Codestriker::TopicListeners::Manager::topic_create($topic);
340
 
341
    # Obtain a URL builder object and determine the URL to the topic.
342
    my $topic_url = $url_builder->view_url_extended($topicid, -1, "", "", "",
343
						    $query->url(), 0);
344
 
345
    # Indicate to the user that the topic has been created and an email has
346
    # been sent.
347
    my $vars = {};
348
    $vars->{'topic_title'} = $topic->{title};
349
    $vars->{'email'} = $email;
350
    $vars->{'topic_url'} = $topic_url;
351
    $vars->{'reviewers'} = $reviewers;
352
    $vars->{'cc'} = (defined $cc) ? $cc : "";
353
    $vars->{'feedback'} = $feedback;
354
 
355
    my $template = Codestriker::Http::Template->new("submitnewtopic");
356
    $template->process($vars);
357
 
358
    $http_response->generate_footer();
359
}
360
 
361
# Direct output to the create topic screen again, with the appropriate feedback
362
# message.
363
sub _forward_create_topic($$$) {
364
    my ($vars, $feedback, $url_builder) = @_;
365
 
366
    $feedback =~ s/\n/<BR>/g;
367
    $vars->{'feedback'} = $feedback;
368
    my @projects = Codestriker::Model::Project->list();
369
    $vars->{'projects'} = \@projects;
370
    Codestriker::Action::CreateTopic->
371
	set_obsoleted_topics_parameter($vars, $url_builder);
372
 
373
    my $template = Codestriker::Http::Template->new("createtopic");
374
    $template->process($vars);
375
}
376
 
377
1;