| 1 | <?php␊ |
| 2 | /* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */␊ |
| 3 | /*␊ |
| 4 | # ***** BEGIN LICENSE BLOCK *****␊ |
| 5 | # This file is part of InDefero, an open source project management application.␊ |
| 6 | # Copyright (C) 2008-2011 CĂ©ondo Ltd and contributors.␊ |
| 7 | #␊ |
| 8 | # InDefero is free software; you can redistribute it and/or modify␊ |
| 9 | # it under the terms of the GNU General Public License as published by␊ |
| 10 | # the Free Software Foundation; either version 2 of the License, or␊ |
| 11 | # (at your option) any later version.␊ |
| 12 | #␊ |
| 13 | # InDefero is distributed in the hope that it will be useful,␊ |
| 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of␊ |
| 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the␊ |
| 16 | # GNU General Public License for more details.␊ |
| 17 | #␊ |
| 18 | # You should have received a copy of the GNU General Public License␊ |
| 19 | # along with this program; if not, write to the Free Software␊ |
| 20 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA␊ |
| 21 | #␊ |
| 22 | # ***** END LICENSE BLOCK ***** */␊ |
| 23 | ␊ |
| 24 | Pluf::loadFunction('Pluf_HTTP_URL_urlForView');␊ |
| 25 | Pluf::loadFunction('Pluf_Shortcuts_RenderToResponse');␊ |
| 26 | Pluf::loadFunction('Pluf_Shortcuts_GetObjectOr404');␊ |
| 27 | Pluf::loadFunction('Pluf_Shortcuts_GetFormForModel');␊ |
| 28 | ␊ |
| 29 | /**␊ |
| 30 | * Review views.␊ |
| 31 | */␊ |
| 32 | class IDF_Views_Review␊ |
| 33 | {␊ |
| 34 | /**␊ |
| 35 | * View list of reviews for a given project.␊ |
| 36 | */␊ |
| 37 | public $index_precond = array('IDF_Precondition::accessReview');␊ |
| 38 | public function index($request, $match)␊ |
| 39 | {␊ |
| 40 | $prj = $request->project;␊ |
| 41 | $title = sprintf(__('%s Code Reviews'), (string) $prj);␊ |
| 42 | // Paginator to paginate the pages␊ |
| 43 | $pag = new Pluf_Paginator(new IDF_Review());␊ |
| 44 | $pag->class = 'recent-issues';␊ |
| 45 | $pag->item_extra_props = array('project_m' => $prj,␊ |
| 46 | 'shortname' => $prj->shortname,␊ |
| 47 | 'current_user' => $request->user);␊ |
| 48 | $pag->summary = __('This table shows the latest reviews.');␊ |
| 49 | $pag->action = array('IDF_Views_Review::index', array($prj->shortname));␊ |
| 50 | $otags = $prj->getTagIdsByStatus('open');␊ |
| 51 | if (count($otags) == 0) $otags[] = 0;␊ |
| 52 | $pag->forced_where = new Pluf_SQL('project=%s AND status IN ('.implode(', ', $otags).')', array($prj->id));␊ |
| 53 | $pag->action = array('IDF_Views_Issue::index', array($prj->shortname));␊ |
| 54 | $pag->sort_order = array('modif_dtime', 'ASC'); // will be reverted␊ |
| 55 | $pag->sort_reverse_order = array('modif_dtime');␊ |
| 56 | $list_display = array(␊ |
| 57 | 'id' => __('Id'),␊ |
| 58 | array('summary', 'IDF_Views_Review_SummaryAndLabels', __('Summary')),␊ |
| 59 | array('status', 'IDF_Views_Issue_ShowStatus', __('Status')),␊ |
| 60 | array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')),␊ |
| 61 | );␊ |
| 62 | $pag->configure($list_display, array(), array('title', 'modif_dtime'));␊ |
| 63 | $pag->items_per_page = 25;␊ |
| 64 | $pag->no_results_text = __('No reviews were found.');␊ |
| 65 | $pag->sort_order = array('modif_dtime', 'ASC');␊ |
| 66 | $pag->setFromRequest($request);␊ |
| 67 | return Pluf_Shortcuts_RenderToResponse('idf/review/index.html',␊ |
| 68 | array(␊ |
| 69 | 'page_title' => $title,␊ |
| 70 | 'reviews' => $pag,␊ |
| 71 | ),␊ |
| 72 | $request);␊ |
| 73 | }␊ |
| 74 | ␊ |
| 75 | /**␊ |
| 76 | * Create a new code review.␊ |
| 77 | */␊ |
| 78 | public $create_precond = array('IDF_Precondition::accessReview',␊ |
| 79 | 'Pluf_Precondition::loginRequired');␊ |
| 80 | public function create($request, $match)␊ |
| 81 | {␊ |
| 82 | $prj = $request->project;␊ |
| 83 | $title = __('Start Code Review');␊ |
| 84 | if ($request->method == 'POST') {␊ |
| 85 | $form = new IDF_Form_ReviewCreate(array_merge($request->POST,␊ |
| 86 | $request->FILES),␊ |
| 87 | array('project' => $prj,␊ |
| 88 | 'user' => $request->user␊ |
| 89 | ));␊ |
| 90 | if ($form->isValid()) {␊ |
| 91 | $review = $form->save();␊ |
| 92 | $urlr = Pluf_HTTP_URL_urlForView('IDF_Views_Review::view',␊ |
| 93 | array($prj->shortname, $review->id));␊ |
| 94 | $request->user->setMessage(sprintf(__('The <a href="%1$s">code review %2$d</a> has been created.'), $urlr, $review->id));␊ |
| 95 | $url = Pluf_HTTP_URL_urlForView('IDF_Views_Review::index',␊ |
| 96 | array($prj->shortname));␊ |
| 97 | return new Pluf_HTTP_Response_Redirect($url);␊ |
| 98 | }␊ |
| 99 | } else {␊ |
| 100 | $form = new IDF_Form_ReviewCreate(null,␊ |
| 101 | array('project' => $prj,␊ |
| 102 | 'user' => $request->user));␊ |
| 103 | }␊ |
| 104 | return Pluf_Shortcuts_RenderToResponse('idf/review/create.html',␊ |
| 105 | array(␊ |
| 106 | 'page_title' => $title,␊ |
| 107 | 'form' => $form,␊ |
| 108 | ),␊ |
| 109 | $request);␊ |
| 110 | }␊ |
| 111 | ␊ |
| 112 | /**␊ |
| 113 | * Download the patch of a review.␊ |
| 114 | */␊ |
| 115 | public $getPatch_precond = array('IDF_Precondition::accessReview');␊ |
| 116 | public function getPatch($request, $match)␊ |
| 117 | {␊ |
| 118 | $prj = $request->project;␊ |
| 119 | $patch = Pluf_Shortcuts_GetObjectOr404('IDF_Review_Patch', $match[2]);␊ |
| 120 | $prj->inOr404($patch->get_review());␊ |
| 121 | $file = Pluf::f('upload_issue_path').'/'.$patch->patch;␊ |
| 122 | ␊ |
| 123 | $rep = new Pluf_HTTP_Response_File($file, 'text/plain');␊ |
| 124 | $rep->headers['Content-Disposition'] = 'attachment; filename="'.$patch->id.'.diff"';␊ |
| 125 | return $rep;␊ |
| 126 | ␊ |
| 127 | }␊ |
| 128 | ␊ |
| 129 | /**␊ |
| 130 | * View a code review.␊ |
| 131 | */␊ |
| 132 | public $view_precond = array('IDF_Precondition::accessReview');␊ |
| 133 | public function view($request, $match)␊ |
| 134 | {␊ |
| 135 | $prj = $request->project;␊ |
| 136 | $review = Pluf_Shortcuts_GetObjectOr404('IDF_Review', $match[2]);␊ |
| 137 | $prj->inOr404($review);␊ |
| 138 | $url = Pluf_HTTP_URL_urlForView('IDF_Views_Review::view',␊ |
| 139 | array($prj->shortname, $review->id));␊ |
| 140 | $title = Pluf_Template::markSafe(sprintf(__('Review <a href="%1$s">%2$d</a>: %3$s'), $url, $review->id, Pluf_esc($review->summary)));␊ |
| 141 | ␊ |
| 142 | $patches = $review->get_patches_list();␊ |
| 143 | $patch = $patches[0];␊ |
| 144 | $diff = new IDF_Diff(file_get_contents(Pluf::f('upload_issue_path').'/'.$patch->patch));␊ |
| 145 | $diff->parse();␊ |
| 146 | // The form to submit comments is based on the files in the␊ |
| 147 | // diff␊ |
| 148 | if ($request->method == 'POST' and !$request->user->isAnonymous()) {␊ |
| 149 | $form = new IDF_Form_ReviewFileComment($request->POST,␊ |
| 150 | array('files' => $diff->files,␊ |
| 151 | 'user' => $request->user,␊ |
| 152 | 'patch' => $patch,␊ |
| 153 | 'project' => $prj,␊ |
| 154 | ));␊ |
| 155 | if ($form->isValid()) {␊ |
| 156 | $review_comment = $form->save();␊ |
| 157 | $review = $patch->get_review();␊ |
| 158 | $urlr = Pluf_HTTP_URL_urlForView('IDF_Views_Review::view',␊ |
| 159 | array($prj->shortname, $review->id));␊ |
| 160 | $request->user->setMessage(sprintf(__('Your <a href="%1$s">code review %2$d</a> has been published.'), $urlr, $review->id));␊ |
| 161 | $url = Pluf_HTTP_URL_urlForView('IDF_Views_Review::index',␊ |
| 162 | array($prj->shortname));␊ |
| 163 | $review_comment->notify($request->conf);␊ |
| 164 | return new Pluf_HTTP_Response_Redirect($url);␊ |
| 165 | }␊ |
| 166 | } else {␊ |
| 167 | $form = new IDF_Form_ReviewFileComment(null,␊ |
| 168 | array('files' => $diff->files,␊ |
| 169 | 'user' => $request->user,␊ |
| 170 | 'project' => $prj,␊ |
| 171 | 'patch' => $patch,));␊ |
| 172 | }␊ |
| 173 | $scm = IDF_Scm::get($request->project);␊ |
| 174 | $files = array();␊ |
| 175 | $reviewers = array();␊ |
| 176 | foreach ($diff->files as $filename => $def) {␊ |
| 177 | $fileinfo = $scm->getPathInfo($filename, $patch->get_commit()->scm_id);␊ |
| 178 | $sql = new Pluf_SQL('cfile=%s', array($filename));␊ |
| 179 | $cts = $patch->getFileComments(array('filter'=>$sql->gen(),␊ |
| 180 | 'order'=>'creation_dtime ASC'));␊ |
| 181 | foreach ($cts as $ct) {␊ |
| 182 | $reviewers[] = $ct->get_comment()->get_submitter();␊ |
| 183 | }␊ |
| 184 | if (count($def['chunks'])) {␊ |
| 185 | $orig_file = ($fileinfo) ? $scm->getFile($fileinfo) : '';␊ |
| 186 | $files[$filename] = array(␊ |
| 187 | $diff->fileCompare($orig_file, $def, $filename),␊ |
| 188 | $form->f->{md5($filename)},␊ |
| 189 | $cts,␊ |
| 190 | );␊ |
| 191 | } else {␊ |
| 192 | $files[$filename] = array('', $form->f->{md5($filename)}, $cts);␊ |
| 193 | }␊ |
| 194 | }␊ |
| 195 | ␊ |
| 196 | $reviewers = Pluf_Model_RemoveDuplicates($reviewers);␊ |
| 197 | return Pluf_Shortcuts_RenderToResponse('idf/review/view.html',␊ |
| 198 | array_merge(␊ |
| 199 | array(␊ |
| 200 | 'page_title' => $title,␊ |
| 201 | 'review' => $review,␊ |
| 202 | 'files' => $files,␊ |
| 203 | 'diff' => $diff,␊ |
| 204 | 'patch' => $patch,␊ |
| 205 | 'comments' => $patch->get_comments_list(array('sort' => 'id ASC')),␊ |
| 206 | 'form' => $form,␊ |
| 207 | 'reviewers' => $reviewers,␊ |
| 208 | ),␊ |
| 209 | IDF_Views_Issue::autoCompleteArrays($prj)␊ |
| 210 | ),␊ |
| 211 | $request);␊ |
| 212 | }␊ |
| 213 | }␊ |
| 214 | ␊ |
| 215 | /**␊ |
| 216 | * Display the summary of an review, then on a new line, display the␊ |
| 217 | * list of labels with a link to a view "by label only".␊ |
| 218 | *␊ |
| 219 | * The summary of the review is linking to the review.␊ |
| 220 | */␊ |
| 221 | function IDF_Views_Review_SummaryAndLabels($field, $review, $extra='')␊ |
| 222 | {␊ |
| 223 | $edit = Pluf_HTTP_URL_urlForView('IDF_Views_Review::view',␊ |
| 224 | array($review->shortname, $review->id));␊ |
| 225 | $tags = array();␊ |
| 226 | foreach ($review->get_tags_list() as $tag) {␊ |
| 227 | $tags[] = Pluf_esc($tag);␊ |
| 228 | }␊ |
| 229 | $out = '';␊ |
| 230 | if (count($tags)) {␊ |
| 231 | $out = '<br /><span class="label note">'.implode(', ', $tags).'</span>';␊ |
| 232 | }␊ |
| 233 | return sprintf('<a href="%s">%s</a>', $edit, Pluf_esc($review->summary)).$out;␊ |
| 234 | }␊ |
| 235 | ␊ |
| 236 | |