diff --git a/src/IDF/Form/ReviewCommentFile.php b/src/IDF/Form/ReviewCommentFile.php deleted file mode 100644 index e7c90a1..0000000 --- a/src/IDF/Form/ReviewCommentFile.php +++ /dev/null @@ -1,203 +0,0 @@ -user = $extra['user']; - $this->project = $extra['project']; - if ($this->user->hasPerm('IDF.project-owner', $this->project) - or $this->user->hasPerm('IDF.project-member', $this->project)) { - $this->show_full = true; - } - $this->fields['title'] = new Pluf_Form_Field_Varchar( - array('required' => true, - 'label' => __('Page title'), - 'initial' => __('PageName'), - 'widget_attrs' => array( - 'maxlength' => 200, - 'size' => 67, - ), - 'help_text' => __('The page name must contains only letters, digits and the dash (-) character.'), - )); - $this->fields['summary'] = new Pluf_Form_Field_Varchar( - array('required' => true, - 'label' => __('Description'), - 'help_text' => __('This one line description is displayed in the list of pages.'), - 'initial' => '', - 'widget_attrs' => array( - 'maxlength' => 200, - 'size' => 67, - ), - )); - $this->fields['content'] = new Pluf_Form_Field_Varchar( - array('required' => true, - 'label' => __('Content'), - 'initial' => $initial, - 'widget' => 'Pluf_Form_Widget_TextareaInput', - 'widget_attrs' => array( - 'cols' => 58, - 'rows' => 26, - ), - )); - - if ($this->show_full) { - for ($i=1;$i<4;$i++) { - $this->fields['label'.$i] = new Pluf_Form_Field_Varchar( - array('required' => false, - 'label' => __('Labels'), - 'initial' => '', - 'widget_attrs' => array( - 'maxlength' => 50, - 'size' => 20, - ), - )); - } - } - } - - public function clean_title() - { - $title = $this->cleaned_data['title']; - if (preg_match('/[^a-zA-Z0-9\-]/', $title)) { - throw new Pluf_Form_Invalid(__('The title contains invalid characters.')); - } - $sql = new Pluf_SQL('project=%s AND title=%s', - array($this->project->id, $title)); - $pages = Pluf::factory('IDF_WikiPage')->getList(array('filter'=>$sql->gen())); - if ($pages->count() > 0) { - throw new Pluf_Form_Invalid(__('A page with this title already exists.')); - } - return $title; - } - - /** - * Validate the interconnection in the form. - */ - public function clean() - { - if (!$this->show_full) { - return $this->cleaned_data; - } - $conf = new IDF_Conf(); - $conf->setProject($this->project); - $onemax = array(); - foreach (split(',', $conf->getVal('labels_wiki_one_max', IDF_Form_WikiConf::init_one_max)) as $class) { - if (trim($class) != '') { - $onemax[] = mb_strtolower(trim($class)); - } - } - $count = array(); - for ($i=1;$i<4;$i++) { - $this->cleaned_data['label'.$i] = trim($this->cleaned_data['label'.$i]); - if (strpos($this->cleaned_data['label'.$i], ':') !== false) { - list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2); - list($class, $name) = array(mb_strtolower(trim($class)), - trim($name)); - } else { - $class = 'other'; - $name = $this->cleaned_data['label'.$i]; - } - if (!isset($count[$class])) $count[$class] = 1; - else $count[$class] += 1; - if (in_array($class, $onemax) and $count[$class] > 1) { - if (!isset($this->errors['label'.$i])) $this->errors['label'.$i] = array(); - $this->errors['label'.$i][] = sprintf(__('You cannot provide more than label from the %s class to a page.'), $class); - throw new Pluf_Form_Invalid(__('You provided an invalid label.')); - } - } - return $this->cleaned_data; - } - - /** - * Save the model in the database. - * - * @param bool Commit in the database or not. If not, the object - * is returned but not saved in the database. - * @return Object Model with data set from the form. - */ - function save($commit=true) - { - if (!$this->isValid()) { - throw new Exception(__('Cannot save the model from an invalid form.')); - } - // Add a tag for each label - $tags = array(); - if ($this->show_full) { - for ($i=1;$i<4;$i++) { - if (strlen($this->cleaned_data['label'.$i]) > 0) { - if (strpos($this->cleaned_data['label'.$i], ':') !== false) { - list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2); - list($class, $name) = array(trim($class), trim($name)); - } else { - $class = 'Other'; - $name = trim($this->cleaned_data['label'.$i]); - } - $tags[] = IDF_Tag::add($name, $this->project, $class); - } - } - } - // Create the page - $page = new IDF_WikiPage(); - $page->project = $this->project; - $page->submitter = $this->user; - $page->summary = trim($this->cleaned_data['summary']); - $page->title = trim($this->cleaned_data['title']); - $page->create(); - foreach ($tags as $tag) { - $page->setAssoc($tag); - } - // add the first revision - $rev = new IDF_WikiRevision(); - $rev->wikipage = $page; - $rev->content = $this->cleaned_data['content']; - $rev->submitter = $this->user; - $rev->summary = __('Initial page creation'); - $rev->create(); - return $page; - } -} diff --git a/src/IDF/Form/ReviewFileComment.php b/src/IDF/Form/ReviewFileComment.php index 12d3604..a0da84b 100644 --- a/src/IDF/Form/ReviewFileComment.php +++ b/src/IDF/Form/ReviewFileComment.php @@ -76,13 +76,17 @@ class IDF_Form_ReviewFileComment extends Pluf_Form if (!$this->isValid()) { throw new Exception(__('Cannot save the model from an invalid form.')); } + // create a base comment + $bc = new IDF_Review_Comment(); + $bc->patch = $this->patch; + $bc->submitter = $this->user; + $bc->create(); foreach ($this->files as $filename => $def) { if (!empty($this->cleaned_data[md5($filename)])) { // Add a comment. $c = new IDF_Review_FileComment(); - $c->patch = $this->patch; + $c->comment = $bc; $c->cfile = $filename; - $c->submitter = $this->user; $c->content = $this->cleaned_data[md5($filename)]; $c->create(); } diff --git a/src/IDF/Migrations/13NewReview.php b/src/IDF/Migrations/13NewReview.php new file mode 100644 index 0000000..b3d34e5 --- /dev/null +++ b/src/IDF/Migrations/13NewReview.php @@ -0,0 +1,60 @@ +execute('DROP TABLE IF EXISTS '.$pfx.$table.$extra); + } + $models = array( + 'IDF_Review', + 'IDF_Review_Patch', + 'IDF_Review_Comment', + 'IDF_Review_FileComment', + ); + $db = Pluf::db(); + $schema = new Pluf_DB_Schema($db); + foreach ($models as $model) { + $schema->model = new $model(); + $schema->createTables(); + } +} + +function IDF_Migrations_13NewReview_down($params=null) +{ + // We do nothing as we cannot go back to the old reviews +} \ No newline at end of file diff --git a/src/IDF/Migrations/Install.php b/src/IDF/Migrations/Install.php index feb4e0b..d947513 100644 --- a/src/IDF/Migrations/Install.php +++ b/src/IDF/Migrations/Install.php @@ -43,6 +43,7 @@ function IDF_Migrations_Install_setup($params=null) 'IDF_WikiPage', 'IDF_WikiRevision', 'IDF_Review', + 'IDF_Review_Comment', 'IDF_Review_Patch', 'IDF_Review_FileComment', 'IDF_Key', @@ -88,6 +89,7 @@ function IDF_Migrations_Install_teardown($params=null) 'IDF_Key', 'IDF_Review_FileComment', 'IDF_Review_Patch', + 'IDF_Review_Comment', 'IDF_Review', 'IDF_WikiRevision', 'IDF_WikiPage', diff --git a/src/IDF/Review.php b/src/IDF/Review.php index 5f14a34..4cc9d60 100644 --- a/src/IDF/Review.php +++ b/src/IDF/Review.php @@ -126,11 +126,25 @@ class IDF_Review extends Pluf_Model 'join_tags' => array( 'join' => 'LEFT JOIN '.$table - .' ON idf_issue_id=id', + .' ON idf_review_id=id', ), ); } + /** + * Iterate through the patches and comments to get the reviewers. + */ + function getReviewers() + { + $rev = new ArrayObject(); + foreach ($this->get_patches_list() as $p) { + foreach ($p->get_comments_list() as $c) { + $rev[] = $c->get_submitter(); + } + } + return Pluf_Model_RemoveDuplicates($rev); + } + function __toString() { return $this->id.' - '.$this->summary; @@ -149,7 +163,7 @@ class IDF_Review extends Pluf_Model function preSave($create=false) { - if ($this->id == '') { + if ($create) { $this->creation_dtime = gmdate('Y-m-d H:i:s'); } $this->modif_dtime = gmdate('Y-m-d H:i:s'); diff --git a/src/IDF/Review/Comment.php b/src/IDF/Review/Comment.php new file mode 100644 index 0000000..4cda7ed --- /dev/null +++ b/src/IDF/Review/Comment.php @@ -0,0 +1,143 @@ +_a['table'] = 'idf_review_comments'; + $this->_a['model'] = __CLASS__; + $this->_a['cols'] = array( + // It is mandatory to have an "id" column. + 'id' => + array( + 'type' => 'Pluf_DB_Field_Sequence', + 'blank' => true, + ), + 'patch' => + array( + 'type' => 'Pluf_DB_Field_Foreignkey', + 'model' => 'IDF_Review_Patch', + 'blank' => false, + 'verbose' => __('patch'), + 'relate_name' => 'comments', + ), + 'content' => + array( + 'type' => 'Pluf_DB_Field_Text', + 'blank' => true, // if only commented on lines + 'verbose' => __('comment'), + ), + 'submitter' => + array( + 'type' => 'Pluf_DB_Field_Foreignkey', + 'model' => 'Pluf_User', + 'blank' => false, + 'verbose' => __('submitter'), + ), + 'changes' => + array( + 'type' => 'Pluf_DB_Field_Serialized', + 'blank' => true, + 'verbose' => __('changes'), + 'help_text' => 'Serialized array of the changes in the review.', + ), + 'vote' => + array( + 'type' => 'Pluf_DB_Field_Integer', + 'default' => 0, + 'blank' => true, + 'verbose' => __('vote'), + 'help_text' => '1, 0 or -1 for positive, neutral or negative vote.', + ), + 'creation_dtime' => + array( + 'type' => 'Pluf_DB_Field_Datetime', + 'blank' => true, + 'verbose' => __('creation date'), + 'index' => true, + ), + ); + } + + function changedReview() + { + return (is_array($this->changes) and count($this->changes) > 0); + } + + function _toIndex() + { + return $this->content; + } + + function preDelete() + { + IDF_Timeline::remove($this); + } + + function preSave($create=false) + { + if ($create) { + $this->creation_dtime = gmdate('Y-m-d H:i:s'); + } + } + + function postSave($create=false) + { + if (0 and $create) { + // Check if more than one comment for this patch. We do + // not want to insert the first comment in the timeline as + // the patch itself is inserted. + $sql = new Pluf_SQL('patch=%s', array($this->patch)); + $co = Pluf::factory(__CLASS__)->getList(array('filter'=>$sql->gen())); + if ($co->count() > 1) { + IDF_Timeline::insert($this, $this->get_patch()->get_review()->get_project(), + $this->get_submitter()); + } + } + IDF_Search::index($this->get_patch()->get_review()); + } + + public function timelineFragment($request) + { + return ''; + } + + public function feedFragment($request) + { + return ''; + } +} diff --git a/src/IDF/Review/FileComment.php b/src/IDF/Review/FileComment.php index 3975ffc..4e63a7c 100644 --- a/src/IDF/Review/FileComment.php +++ b/src/IDF/Review/FileComment.php @@ -40,13 +40,13 @@ class IDF_Review_FileComment extends Pluf_Model 'type' => 'Pluf_DB_Field_Sequence', 'blank' => true, ), - 'patch' => + 'comment' => array( 'type' => 'Pluf_DB_Field_Foreignkey', - 'model' => 'IDF_Review_Patch', + 'model' => 'IDF_Review_Comment', 'blank' => false, - 'verbose' => __('patch'), 'relate_name' => 'filecomments', + 'verbose' => __('comment'), ), 'cfile' => array( @@ -55,32 +55,25 @@ class IDF_Review_FileComment extends Pluf_Model 'size' => 250, 'help_text' => 'The changed file, for example src/foo/bar.txt, this is the path to access it in the repository.', ), + 'cline' => + array( + 'type' => 'Pluf_DB_Field_Integer', + 'blank' => false, + 'default' => 0, + 'help_text' => 'The commented line, negative value is the old file, positive the new, 0 general comment.', + ), 'content' => array( 'type' => 'Pluf_DB_Field_Text', 'blank' => false, 'verbose' => __('comment'), ), - 'submitter' => - array( - 'type' => 'Pluf_DB_Field_Foreignkey', - 'model' => 'Pluf_User', - 'blank' => false, - 'verbose' => __('submitter'), - 'relate_name' => 'commented_patched_files', - ), 'creation_dtime' => array( 'type' => 'Pluf_DB_Field_Datetime', 'blank' => true, 'verbose' => __('creation date'), - ), - ); - $this->_a['idx'] = array( - 'creation_dtime_idx' => - array( - 'col' => 'creation_dtime', - 'type' => 'normal', + 'index' => true, ), ); } @@ -92,12 +85,11 @@ class IDF_Review_FileComment extends Pluf_Model function preDelete() { - IDF_Timeline::remove($this); } function preSave($create=false) { - if ($this->id == '') { + if ($create) { $this->creation_dtime = gmdate('Y-m-d H:i:s'); } } diff --git a/src/IDF/Review/Patch.php b/src/IDF/Review/Patch.php index 343cccb..decf17f 100644 --- a/src/IDF/Review/Patch.php +++ b/src/IDF/Review/Patch.php @@ -85,15 +85,28 @@ class IDF_Review_Patch extends Pluf_Model 'type' => 'Pluf_DB_Field_Datetime', 'blank' => true, 'verbose' => __('creation date'), + 'index' => true, ), ); - $this->_a['idx'] = array( - 'creation_dtime_idx' => - array( - 'col' => 'creation_dtime', - 'type' => 'normal', - ), - ); + } + + /** + * Get the list of file comments. + * + * It will go through the patch comments and find for each the + * file comments. + * + * @param array Filter to apply to the file comment list (array()) + */ + function getFileComments($filter=array()) + { + $files = new ArrayObject(); + foreach ($this->get_comments_list(array('order'=>'creation_dtime ASC')) as $ct) { + foreach ($ct->get_filecomments_list($filter) as $fc) { + $files[] = $fc; + } + } + return $files; } function _toIndex() @@ -107,7 +120,7 @@ class IDF_Review_Patch extends Pluf_Model function preSave($create=false) { - if ($this->id == '') { + if ($create) { $this->creation_dtime = gmdate('Y-m-d H:i:s'); } } @@ -118,6 +131,7 @@ class IDF_Review_Patch extends Pluf_Model public function timelineFragment($request) { + return ''; } public function feedFragment($request) diff --git a/src/IDF/Views/Review.php b/src/IDF/Views/Review.php index 67596ef..4dd0798 100644 --- a/src/IDF/Views/Review.php +++ b/src/IDF/Views/Review.php @@ -160,11 +160,11 @@ class IDF_Views_Review $url = Pluf_HTTP_URL_urlForView('IDF_Views_Review::index', array($prj->shortname)); // Get the list of reviewers + submitter - $reviewers = $review->get_reviewers_list(); + $reviewers = $review->getReviewers(); if (!Pluf_Model_InArray($review->get_submitter(), $reviewers)) { $reviewers[] = $review->get_submitter(); } - $comments = $patch->get_filecomments_list(array('order' => 'id DESC')); + $comments = $patch->getFileComments(array('order' => 'id DESC')); $context = new Pluf_Template_Context( array( 'review' => $review, @@ -209,10 +209,10 @@ class IDF_Views_Review foreach ($diff->files as $filename => $def) { $fileinfo = $scm->getPathInfo($filename, $patch->get_commit()->scm_id); $sql = new Pluf_SQL('cfile=%s', array($filename)); - $cts = $patch->get_filecomments_list(array('filter'=>$sql->gen(), - 'order'=>'creation_dtime ASC')); + $cts = $patch->getFileComments(array('filter'=>$sql->gen(), + 'order'=>'creation_dtime ASC')); foreach ($cts as $ct) { - $reviewers[] = $ct->get_submitter(); + $reviewers[] = $ct->get_comment()->get_submitter(); } if (count($def['chunks'])) { $orig_file = ($fileinfo) ? $scm->getFile($fileinfo) : ''; diff --git a/src/IDF/relations.php b/src/IDF/relations.php index b0d7da2..a3c933f 100644 --- a/src/IDF/relations.php +++ b/src/IDF/relations.php @@ -36,7 +36,8 @@ $m['IDF_WikiRevision'] = array('relate_to' => array('IDF_WikiPage', 'Pluf_User') $m['IDF_Review'] = array('relate_to' => array('IDF_Project', 'Pluf_User', 'IDF_Tag'), 'relate_to_many' => array('IDF_Tag', 'Pluf_User')); $m['IDF_Review_Patch'] = array('relate_to' => array('IDF_Review', 'Pluf_User')); -$m['IDF_Review_FileComment'] = array('relate_to' => array('IDF_Review_Patch', 'Pluf_User')); +$m['IDF_Review_Comment'] = array('relate_to' => array('IDF_Review_Patch', 'Pluf_User')); +$m['IDF_Review_FileComment'] = array('relate_to' => array('IDF_Review_Comment', 'Pluf_User')); $m['IDF_Key'] = array('relate_to' => array('Pluf_User')); $m['IDF_Conf'] = array('relate_to' => array('IDF_Project')); $m['IDF_Commit'] = array('relate_to' => array('IDF_Project', 'Pluf_User')); diff --git a/src/IDF/templates/idf/review/review-updated-email.txt b/src/IDF/templates/idf/review/review-updated-email.txt index e75c5ba..7562da2 100644 --- a/src/IDF/templates/idf/review/review-updated-email.txt +++ b/src/IDF/templates/idf/review/review-updated-email.txt @@ -12,7 +12,7 @@ {/foreach} {/if}{trans 'Comments (last first):'} -{foreach $comments as $c}{assign $who = $c.get_submitter()}# {blocktrans}By {$who|safe}, {$c.creation_dtime|date}, on file: +{foreach $comments as $c}{assign $who = $c.get_comment().get_submitter()}# {blocktrans}By {$who|safe}, {$c.creation_dtime|date}, on file: {$c.cfile|safe} {/blocktrans} diff --git a/src/IDF/templates/idf/review/view.html b/src/IDF/templates/idf/review/view.html index cb2ca7c..a5ffba4 100644 --- a/src/IDF/templates/idf/review/view.html +++ b/src/IDF/templates/idf/review/view.html @@ -82,7 +82,7 @@ to propose more contributions. {assign $nc = $comments.count()} {assign $i = 1} {foreach $comments as $c} -
{assign $who = $c.get_submitter()}{aurl 'whourl', 'IDF_Views_User::view', array($who.login)} +
{assign $who = $c.get_comment().get_submitter()}{aurl 'whourl', 'IDF_Views_User::view', array($who.login)} {aurl 'url', 'IDF_Views_Review::view', array($project.shortname, $review.id)} {assign $id = $c.id} {assign $url = $url~'#ic'~$c.id}