Commits

Marcin Kuzminski committed 7694722

Implemented initial code-review status of changesets

Comments (0)

Files changed (9)

rhodecode/controllers/changeset.py

 from rhodecode.lib.utils import EmptyChangeset
 from rhodecode.lib.compat import OrderedDict
 from rhodecode.lib import diffs
-from rhodecode.model.db import ChangesetComment
+from rhodecode.model.db import ChangesetComment, ChangesetStatus
 from rhodecode.model.comment import ChangesetCommentsModel
 from rhodecode.model.changeset_status import ChangesetStatusModel
 from rhodecode.model.meta import Session
 
         cumulative_diff = 0
         c.cut_off = False  # defines if cut off limit is reached
-
+        c.changeset_statuses = ChangesetStatus.STATUSES
         c.comments = []
         c.statuses = []
         c.inline_comments = []
         # Iterate over ranges (default changeset view is always one changeset)
         for changeset in c.cs_ranges:
 
-            c.statuses.extend(ChangesetStatusModel()\
+            c.statuses.extend([ChangesetStatusModel()\
                               .get_status(c.rhodecode_db_repo.repo_id,
-                                          changeset.raw_id))
+                                          changeset.raw_id)])
 
             c.comments.extend(ChangesetCommentsModel()\
                               .get_comments(c.rhodecode_db_repo.repo_id,
             f_path=request.POST.get('f_path'),
             line_no=request.POST.get('line')
         )
+
+        # get status if set !
+        status = request.POST.get('changeset_status')
+        if status and request.POST.get('change_changeset_status'):
+            ChangesetStatusModel().set_status(
+                c.rhodecode_db_repo.repo_id, 
+                revision,
+                status,
+                c.rhodecode_user.user_id,
+            )
+
         Session.commit()
         if not request.environ.get('HTTP_X_PARTIAL_XHR'):
             return redirect(h.url('changeset_home', repo_name=repo_name,

rhodecode/lib/helpers.py

 from rhodecode.lib.utils2 import str2bool, safe_unicode, safe_str, \
     get_changeset_safe
 from rhodecode.lib.markup_renderer import MarkupRenderer
+from rhodecode.model.changeset_status import ChangesetStatusModel
 
 log = logging.getLogger(__name__)
 
 
         return ''.join(links)
 
-
     # urlify changesets - extrac revisions and make link out of them
     text_ = urlify_changesets(escaper(text_), repository)
 
     """
     return literal('<div class="rst-block">%s</div>' %
                    MarkupRenderer.rst_with_mentions(source))
+
+
+def changeset_status(repo, revision):
+    return ChangesetStatusModel().get_status(repo, revision)

rhodecode/model/changeset_status.py

 from pylons.i18n.translation import _
 
 from rhodecode.lib.utils2 import safe_unicode
-from rhodecode.lib import helpers as h
 from rhodecode.model import BaseModel
-from rhodecode.model.db import ChangesetStatus
+from rhodecode.model.db import ChangesetStatus, Repository, User
 
 log = logging.getLogger(__name__)
 
     def __get_changeset_status(self, changeset_status):
         return self._get_instance(ChangesetStatus, changeset_status)
 
+    def __get_repo(self, repository):
+        return self._get_instance(Repository, repository,
+                                  callback=Repository.get_by_repo_name)
+
+    def __get_user(self, user):
+        return self._get_instance(User, user, callback=User.get_by_username)
+
     def get_status(self, repo, revision):
-        return 'status'
+        """
+        Returns status of changeset for given revision
+
+        :param repo:
+        :type repo:
+        :param revision: 40char hash
+        :type revision: str
+        """
+        repo = self.__get_repo(repo)
+
+        status = ChangesetStatus.query()\
+            .filter(ChangesetStatus.repo == repo)\
+            .filter(ChangesetStatus.revision == revision).scalar()
+        status = status.status if status else status
+        st = status or ChangesetStatus.DEFAULT
+        return str(st)
+
+    def set_status(self, repo, revision, status, user):
+        """
+        Creates new status for changeset or updates the old one
+
+        :param repo:
+        :type repo:
+        :param revision:
+        :type revision:
+        :param status:
+        :type status:
+        :param user:
+        :type user:
+        """
+        repo = self.__get_repo(repo)
+
+        cur_status = ChangesetStatus.query()\
+            .filter(ChangesetStatus.repo == repo)\
+            .filter(ChangesetStatus.revision == revision)\
+            .scalar()
+        new_status = cur_status or ChangesetStatus()
+        new_status.author = self.__get_user(user)
+        new_status.repo = self.__get_repo(repo)
+        new_status.status = status
+        new_status.revision = revision
+        self.sa.add(new_status)
+        return new_status
+

rhodecode/model/db.py

     def statuses(self, revisions=None):
         """
         Returns statuses for this repository
+
         :param revisions: list of revisions to get statuses for
         :type revisions: list
         """
             .filter(ChangesetStatus.repo == self)
         if revisions:
             statuses = statuses.filter(ChangesetStatus.revision.in_(revisions))
-        grouped = defaultdict(list)
+        grouped = {}
         for stat in statuses.all():
-            grouped[statuses.revision].append(stat)
+            grouped[stat.revision] = [str(stat.status), stat.status_lbl]
         return grouped
 
-        
     #==========================================================================
     # SCM CACHE INSTANCE
     #==========================================================================
 class ChangesetStatus(Base, BaseModel):
     __tablename__ = 'changeset_statuses'
     __table_args__ = (
+        UniqueConstraint('repo_id', 'revision'),
         {'extend_existing': True, 'mysql_engine': 'InnoDB',
          'mysql_charset': 'utf8'}
     )
         ('rejected', _("Rejected")),
         ('under_review', _("Under Review")),
     ]
+    DEFAULT = STATUSES[0][0]
 
     changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
     repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
     user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
     revision = Column('revision', String(40), nullable=False)
-    status = Column('status', String(128), nullable=False, default=STATUSES[0][0])
+    status = Column('status', String(128), nullable=False, default=DEFAULT)
     modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
 
     author = relationship('User', lazy='joined')
     repo = relationship('Repository')
 
+    @property
+    def status_lbl(self):
+        return dict(self.STATUSES).get(self.status)
+
 
 class ChangesetStatusHistory(Base, BaseModel):
     __tablename__ = 'changeset_statuses_history'

rhodecode/model/notification.py

     def mark_all_read_for_user(self, user):
         user = self.__get_user(user)
         UserNotification.query()\
-            .filter(UserNotification.read==False)\
+            .filter(UserNotification.read == False)\
             .update({'read': True})
 
     def get_unread_cnt_for_user(self, user):

rhodecode/public/css/style.css

     font-weight: bold !important;
 }
 
+.right .changeset-status-container{
+    padding-right: 5px;
+    margin-top:1px;
+    float:right;
+    height:14px;
+}
+.right .changeset-status-container .changeset-status-lbl{
+	color: rgb(136, 136, 136);
+    float: left;
+    padding: 0px 4px 0px 0px;	
+}
 .right .comments-container{
 	padding-right: 5px;
 	margin-top:1px;
 
 /** comment form **/
 
+.status-block{
+    height:80px;
+    clear:both	
+}
+
 .comment-form .clearfix{
 	background: #EEE;
     -webkit-border-radius: 4px;

rhodecode/templates/changelog/changelog.html

 						<div class="right">
 									<div id="${cs.raw_id}_changes_info" class="changes">
                                         <div id="${cs.raw_id}"  style="float:right;" class="changed_total tooltip" title="${_('Affected number of files, click to show more details')}">${len(cs.affected_files)}</div>
-                                        <div class="changeset-status-container">${c.statuses.get(cs.raw_id)}</div>
                                         <div class="comments-container">
                                         %if len(c.comments.get(cs.raw_id,[])) > 0:
                                             <div class="comments-cnt" title="${('comments')}">
                                             </div>
                                         %endif
                                         </div>
+                                        <div class="changeset-status-container">
+                                            %if c.statuses.get(cs.raw_id):
+                                              <img src="${h.url('/images/icons/flag_status_%s.png' % c.statuses.get(cs.raw_id)[0])}" />
+                                              <div class="changeset-status-lbl">${c.statuses.get(cs.raw_id)[1]}</div>
+                                            %endif
+                                        </div>
 									</div>
 								   %if cs.parents:
 									%for p_cs in reversed(cs.parents):

rhodecode/templates/changeset/changeset.html

                   ${c.context_url(request.GET)}
                 </div>
                 <div class="comments-number" style="float:right;padding-right:5px">${len(c.comments)} comment(s) (${c.inline_cnt} ${_('inline')})</div>
-			</div>
+            </div>       
 		</div>
 	    <div id="changeset_content">
 			<div class="container">
           // inject comments into they proper positions
           var file_comments = YUQ('.inline-comment-placeholder');
           renderInlineComments(file_comments);
+          
+          YUE.on(YUD.get('show_changeset_status_box'),'change',function(e){
+        	  if(e.currentTarget.checked){
+        		  YUD.setStyle('status_block_container','display','');  
+        	  }
+        	  else{
+        		  YUD.setStyle('status_block_container','display','none');
+        	  }
+          })
       })
 
     </script>

rhodecode/templates/changeset/changeset_file_comment.html

           <div class="comment-help">${_('Commenting on line')} {1}. ${_('Comments parsed using')}
           <a href="${h.url('rst_help')}">RST</a> ${_('syntax')} ${_('with')}
           <span style="color:#003367" class="tooltip" title="${_('Use @username inside this text to send notification to this RhodeCode user')}">@mention</span> ${_('support')}
-          </div>
+          </div>          
           <textarea id="text_{1}" name="text"></textarea>
       </div>
       <div class="comment-button">
 
 </%def>
 
+## MAIN COMMENT FORM
 <%def name="comments(changeset)">
 
 <div class="comments">
             <div class="comment-help">
                 ${_('Comments parsed using')} <a href="${h.url('rst_help')}">RST</a> ${_('syntax')}
                 ${_('with')} <span style="color:#003367" class="tooltip" title="${_('Use @username inside this text to send notification to this RhodeCode user')}">@mention</span> ${_('support')}
+                | <span class="tooltip" title="${_('Check this to change current status of code-review for this changeset')}"> ${_('change status')}
+                  <input style="vertical-align: bottom;margin-bottom:-2px" id="show_changeset_status_box" type="checkbox" name="change_changeset_status" />
+                  </span> 
             </div>
-                ${h.textarea('text')}
+            <div id="status_block_container" class="status-block" style="display:none">
+                %for status,lbl in c.changeset_statuses:
+                    <div class="">
+                        <img src="${h.url('/images/icons/flag_status_%s.png' % status)}" /> <input ${'checked="checked"' if status == h.changeset_status(c.rhodecode_db_repo, c.changeset.raw_id) else ''}" type="radio" name="changeset_status" value="${status}"> <label>${lbl}</label>
+                    </div>                    
+                %endfor
+            </div>                 
+            ${h.textarea('text')}
         </div>
         <div class="comment-button">
         ${h.submit('save', _('Comment'), class_='ui-button')}