summaryrefslogtreecommitdiff
path: root/perl-lib/PgCommitFest/CommitFest.pm
blob: a4115b2ef5398d93342bcabc0c2a388ba003260f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
package PgCommitFest::CommitFest;
use strict;
use warnings;

sub delete {
	my ($r) = @_;
	$r->authenticate('require_login' => 1, 'require_administrator' => 1);
	$r->set_title('Delete CommitFest');
	my $d;
	eval {
		$d = $r->db->select_one(<<EOM, $r->cgi_required_id);
DELETE FROM commitfest WHERE id = ? RETURNING id
EOM
	};
	my $err = $@;
	if (! $err) {
		$r->error_exit('CommitFest not found.') if !defined $d;
		$r->db->commit;
		$r->redirect('/');
	}
	if ($err =~ /commitfest_topic_commitfest_id_fkey/) {
		$r->error_exit(<<EOM);
This CommitFest contains one or more topics and can't be deleted.
EOM
	}
	$r->error_exit("Internal error: $@");
}

sub form {
	my ($r) = @_;
	$r->authenticate('require_login' => 1, 'require_administrator' => 1);

	# Decide whether this is a new commitfest or an edit of an existing
	# commitfest, and if editing reload data from database.
	my $d;
	my $id = $r->cgi_id();
	if (defined $id) {
		$r->set_title('Edit CommitFest');
		$d = $r->db->select_one(<<EOM, $id);
SELECT id, name, commitfest_status_id AS commitfest_status FROM commitfest
WHERE id = ?
EOM
		$r->error_exit('CommitFest not found.') if !defined $d;
		$r->redirect('/action/commitfest_view?id=' . $id) if $r->cgi('cancel');
	}
	else {
		$r->set_title('New CommitFest');
		$r->redirect('/') if $r->cgi('cancel');
	}

	# Add controls.
	$r->add_control('name', 'text', 'Name', 'required' => 1);
	$r->add_control('commitfest_status', 'select', 'Status', 'required' => 1);
	$r->control('commitfest_status')->choice($r->db->select(<<EOM));
SELECT id, name FROM commitfest_status ORDER BY id
EOM
	my %value = $r->initialize_controls($d);

	# Handle commit.
	if ($r->cgi('go') && ! $r->is_error()) {
		if (defined $id) {
			$r->db->update('commitfest', { 'id' => $id }, \%value);
		}
		else {
			$id = $r->db->insert_returning_id('commitfest', \%value);
		}
		$r->db->commit;
		$r->redirect('/action/commitfest_view?id=' . $id);
	}

	# Display template.
	$r->render_template('commitfest_form', { 'id' => $id });
}

sub search {
	my ($r) = @_;
	my $aa = $r->authenticate();
	$r->set_title('CommitFest Index');
	if (defined $aa && $aa->{'is_administrator'}) {
		$r->add_link('/action/commitfest_form', 'New CommitFest');
	}
	my $list = $r->db->select(<<EOM);
SELECT id, name, commitfest_status FROM commitfest_view ORDER BY name DESC
EOM
	$r->render_template('commitfest_search', { 'list' => $list });
}

sub view {
	my ($r, $extrapath) = @_;
	my $aa = $r->authenticate();

	# Target commitfest can be specified either by ID, or we allow special
	# magic to fetch it by 
	my $id = $r->cgi_id();
	my $sqlbit;
	if (defined $id) {
		$sqlbit = "WHERE id = " . $r->db->quote($id);
	}
	elsif (defined $extrapath) {
		if ($extrapath eq 'open') {
			$sqlbit =
				"WHERE commitfest_status_id = 2 ORDER BY name DESC LIMIT 1";
		}
		elsif ($extrapath eq 'inprogress') {
			$sqlbit = <<EOM;
WHERE commitfest_status_id IN (2, 3)
	ORDER BY commitfest_status_id DESC, name DESC LIMIT 1
EOM
		}
		elsif ($extrapath eq 'previous') {
			$sqlbit =
				"WHERE commitfest_status_id = 4 ORDER BY name DESC LIMIT 1";
		}
	}
	if (!defined $sqlbit) {
		$r->error_exit("Unable to identify target CommitFest.");
	}

	# Fetch target commitfest from database.
	my $d = $r->db->select_one(<<EOM);
SELECT id, name, commitfest_status FROM commitfest_view $sqlbit
EOM
	$r->error_exit('CommitFest not found.') if !defined $d;
	$r->set_title('CommitFest %s (%s)', $d->{'name'},
		$d->{'commitfest_status'});

	# Load list of patches.
	my $previous_topic;
	my %patch_grouping;
	my %patch_index;
	my $patch_list = $r->db->select(<<EOM, $d->{'id'});
SELECT id, name, patch_status_id, patch_status, author, reviewers,
	commitfest_topic_id, commitfest_topic, commitfest_id, date_closed
FROM patch_view WHERE commitfest_id = ?
	ORDER BY date_closed, commitfest_topic_sortorder, commitfest_topic, id
EOM
	for my $p (@$patch_list) {
		if (grep { $_ eq $p->{'patch_status_id'} } qw(4 5 6)) {
			push @{$patch_grouping{$p->{'patch_status_id'}}}, $p;
		}
		else {
			if (!defined $previous_topic
				|| $previous_topic ne $p->{'commitfest_topic'}) {
				push @{$patch_grouping{'p'}}, {
					'topic_header' => 1,
					'commitfest_topic' => $p->{'commitfest_topic'}
				};
				$previous_topic = $p->{'commitfest_topic'};
			}
			push @{$patch_grouping{'p'}}, $p;
		}
		$patch_index{$p->{'id'}} = $p;
	}

	# Load list of comments.
	my $comment_list = $r->db->select(<<EOM, $d->{'id'});
SELECT v.id, v.patch_id, v.patch_comment_type, v.message_id, v.content,
	v.creator, to_char(v.creation_time, 'YYYY-MM-DD') AS creation_time
FROM most_recent_comments(?) v
EOM
	for my $c (@$comment_list) {
		my $p = $patch_index{$c->{'patch_id'}};
		unshift @{$p->{'comment_list'}}, $c;
	}

	# Add links and render template.
	$r->add_link('/action/patch_form?commitfest=' . $id, 'New Patch');
	$r->add_link('/action/commitfest_topic_search?id=' . $id,
		'CommitFest Topics');
	if (defined $aa && $aa->{'is_administrator'}) {
		$r->add_link('/action/commitfest_form?id=' . $id, 'Edit CommitFest');
		$r->add_link('/action/commitfest_delete?id=' . $id,
			'Delete CommitFest',
			'Are you sure you want to delete this CommitFest?');
	}
	$r->render_template('commitfest_view', { 'd' => $d, 'patch_grouping' => [
		{
			'name' => 'Pending Patches',
			'patch_list' => $patch_grouping{'p'},
			'closed' => 0
		},
		{
			'name' => 'Committed Patches',
			'patch_list' => $patch_grouping{'4'},
			'closed' => 1
		},
		{
			'name' => 'Returned with Feedback',
			'patch_list' => $patch_grouping{'5'},
			'closed' => 1
		},
		{
			'name' => 'Rejected Patches',
			'patch_list' => $patch_grouping{'6'},
			'closed' => 1
		},
	]});
}

1;