comments: added immutable parameter to forbid editing/deleting certain comments
This commit is contained in:
parent
0cc11b1d08
commit
ef2b6c8a1c
8 changed files with 96 additions and 9 deletions
|
|
@ -48,7 +48,7 @@ PYRAMID_SETTINGS = {}
|
|||
EXTENSIONS = {}
|
||||
|
||||
__version__ = ('.'.join((str(each) for each in VERSION[:3])))
|
||||
__dbversion__ = 105 # defines current db version for migrations
|
||||
__dbversion__ = 106 # defines current db version for migrations
|
||||
__platform__ = platform.system()
|
||||
__license__ = 'AGPLv3, and Commercial License'
|
||||
__author__ = 'RhodeCode GmbH'
|
||||
|
|
|
|||
|
|
@ -220,7 +220,7 @@ def db():
|
|||
'pr_comment_url': 'http://comment-url',
|
||||
'pr_comment_reply_url': 'http://comment-url#reply',
|
||||
|
||||
'comment_file': 'rhodecode/model/db.py',
|
||||
'comment_file': 'rhodecode/model/get_flow_commits',
|
||||
'comment_line': 'o1210',
|
||||
'comment_type': 'todo',
|
||||
'comment_body': '''
|
||||
|
|
|
|||
|
|
@ -22,8 +22,7 @@ import pytest
|
|||
|
||||
from rhodecode.tests import TestController
|
||||
|
||||
from rhodecode.model.db import (
|
||||
ChangesetComment, Notification, UserNotification)
|
||||
from rhodecode.model.db import ChangesetComment, Notification
|
||||
from rhodecode.model.meta import Session
|
||||
from rhodecode.lib import helpers as h
|
||||
|
||||
|
|
@ -269,7 +268,36 @@ class TestRepoCommitCommentsView(TestController):
|
|||
repo_name=backend.repo_name, commit_id=commit_id))
|
||||
assert_comment_links(response, 0, 0)
|
||||
|
||||
@pytest.mark.parametrize('renderer, input, output', [
|
||||
def test_delete_forbidden_for_immutable_comments(self, backend):
|
||||
self.log_user()
|
||||
commit_id = backend.repo.get_commit('300').raw_id
|
||||
text = u'CommentOnCommit'
|
||||
|
||||
params = {'text': text, 'csrf_token': self.csrf_token}
|
||||
self.app.post(
|
||||
route_path(
|
||||
'repo_commit_comment_create',
|
||||
repo_name=backend.repo_name, commit_id=commit_id),
|
||||
params=params)
|
||||
|
||||
comments = ChangesetComment.query().all()
|
||||
assert len(comments) == 1
|
||||
comment_id = comments[0].comment_id
|
||||
|
||||
comment = ChangesetComment.get(comment_id)
|
||||
comment.immutable_state = ChangesetComment.OP_IMMUTABLE
|
||||
Session().add(comment)
|
||||
Session().commit()
|
||||
|
||||
self.app.post(
|
||||
route_path('repo_commit_comment_delete',
|
||||
repo_name=backend.repo_name,
|
||||
commit_id=commit_id,
|
||||
comment_id=comment_id),
|
||||
params={'csrf_token': self.csrf_token},
|
||||
status=403)
|
||||
|
||||
@pytest.mark.parametrize('renderer, text_input, output', [
|
||||
('rst', 'plain text', '<p>plain text</p>'),
|
||||
('rst', 'header\n======', '<h1 class="title">header</h1>'),
|
||||
('rst', '*italics*', '<em>italics</em>'),
|
||||
|
|
@ -280,11 +308,11 @@ class TestRepoCommitCommentsView(TestController):
|
|||
('markdown', '**bold**', '<strong>bold</strong>'),
|
||||
], ids=['rst-plain', 'rst-header', 'rst-italics', 'rst-bold', 'md-plain',
|
||||
'md-header', 'md-italics', 'md-bold', ])
|
||||
def test_preview(self, renderer, input, output, backend, xhr_header):
|
||||
def test_preview(self, renderer, text_input, output, backend, xhr_header):
|
||||
self.log_user()
|
||||
params = {
|
||||
'renderer': renderer,
|
||||
'text': input,
|
||||
'text': text_input,
|
||||
'csrf_token': self.csrf_token
|
||||
}
|
||||
commit_id = '0' * 16 # fake this for tests
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
import logging
|
||||
import collections
|
||||
|
||||
from pyramid.httpexceptions import HTTPNotFound, HTTPBadRequest, HTTPFound
|
||||
from pyramid.httpexceptions import HTTPNotFound, HTTPBadRequest, HTTPFound, HTTPForbidden
|
||||
from pyramid.view import view_config
|
||||
from pyramid.renderers import render
|
||||
from pyramid.response import Response
|
||||
|
|
@ -538,6 +538,10 @@ class RepoCommitsView(RepoAppView):
|
|||
# comment already deleted in another call probably
|
||||
return True
|
||||
|
||||
if comment.immutable:
|
||||
# don't allow deleting comments that are immutable
|
||||
raise HTTPForbidden()
|
||||
|
||||
is_repo_admin = h.HasRepoPermissionAny('repository.admin')(self.db_repo_name)
|
||||
super_admin = h.HasPermissionAny('hg.admin')()
|
||||
comment_owner = (comment.author.user_id == self._rhodecode_db_user.user_id)
|
||||
|
|
|
|||
|
|
@ -1473,6 +1473,10 @@ class RepoPullRequestsView(RepoAppView, DataGridAppView):
|
|||
self.request.matchdict['comment_id'])
|
||||
comment_id = comment.comment_id
|
||||
|
||||
if comment.immutable:
|
||||
# don't allow deleting comments that are immutable
|
||||
raise HTTPForbidden()
|
||||
|
||||
if pull_request.is_closed():
|
||||
log.debug('comment: forbidden because pull request is closed')
|
||||
raise HTTPForbidden()
|
||||
|
|
|
|||
43
rhodecode/lib/dbmigrate/versions/106_version_4_19_0.py
Normal file
43
rhodecode/lib/dbmigrate/versions/106_version_4_19_0.py
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import logging
|
||||
from sqlalchemy import *
|
||||
|
||||
from alembic.migration import MigrationContext
|
||||
from alembic.operations import Operations
|
||||
from sqlalchemy import BigInteger
|
||||
|
||||
from rhodecode.lib.dbmigrate.versions import _reset_base
|
||||
from rhodecode.model import init_model_encryption
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def upgrade(migrate_engine):
|
||||
"""
|
||||
Upgrade operations go here.
|
||||
Don't create your own engine; bind migrate_engine to your metadata
|
||||
"""
|
||||
_reset_base(migrate_engine)
|
||||
from rhodecode.lib.dbmigrate.schema import db_4_18_0_1 as db
|
||||
|
||||
init_model_encryption(db)
|
||||
|
||||
context = MigrationContext.configure(migrate_engine.connect())
|
||||
op = Operations(context)
|
||||
|
||||
comments = db.ChangesetComment.__table__
|
||||
|
||||
with op.batch_alter_table(comments.name) as batch_op:
|
||||
new_column = Column('immutable_state', Unicode(128), nullable=True)
|
||||
batch_op.add_column(new_column)
|
||||
|
||||
|
||||
def downgrade(migrate_engine):
|
||||
meta = MetaData()
|
||||
meta.bind = migrate_engine
|
||||
|
||||
|
||||
def fixups(models, _SESSION):
|
||||
pass
|
||||
|
|
@ -3711,6 +3711,9 @@ class ChangesetComment(Base, BaseModel):
|
|||
COMMENT_TYPE_TODO = u'todo'
|
||||
COMMENT_TYPES = [COMMENT_TYPE_NOTE, COMMENT_TYPE_TODO]
|
||||
|
||||
OP_IMMUTABLE = u'immutable'
|
||||
OP_CHANGEABLE = u'changeable'
|
||||
|
||||
comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
|
||||
repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
|
||||
revision = Column('revision', String(40), nullable=True)
|
||||
|
|
@ -3725,6 +3728,7 @@ class ChangesetComment(Base, BaseModel):
|
|||
modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
|
||||
renderer = Column('renderer', Unicode(64), nullable=True)
|
||||
display_state = Column('display_state', Unicode(128), nullable=True)
|
||||
immutable_state = Column('immutable_state', Unicode(128), nullable=True, default=OP_CHANGEABLE)
|
||||
|
||||
comment_type = Column('comment_type', Unicode(128), nullable=True, default=COMMENT_TYPE_NOTE)
|
||||
resolved_comment_id = Column('resolved_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'), nullable=True)
|
||||
|
|
@ -3767,6 +3771,10 @@ class ChangesetComment(Base, BaseModel):
|
|||
def outdated(self):
|
||||
return self.display_state == self.COMMENT_OUTDATED
|
||||
|
||||
@property
|
||||
def immutable(self):
|
||||
return self.immutable_state == self.OP_IMMUTABLE
|
||||
|
||||
def outdated_at_version(self, version):
|
||||
"""
|
||||
Checks if comment is outdated for given pull request version
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@
|
|||
## only super-admin, repo admin OR comment owner can delete, also hide delete if currently viewed comment is outdated
|
||||
%if not outdated_at_ver and (not comment.pull_request or (comment.pull_request and not comment.pull_request.is_closed())):
|
||||
## permissions to delete
|
||||
%if c.is_super_admin or h.HasRepoPermissionAny('repository.admin')(c.repo_name) or comment.author.user_id == c.rhodecode_user.user_id:
|
||||
%if comment.immutable is False and (c.is_super_admin or h.HasRepoPermissionAny('repository.admin')(c.repo_name) or comment.author.user_id == c.rhodecode_user.user_id):
|
||||
## TODO: dan: add edit comment here
|
||||
<a onclick="return Rhodecode.comments.deleteComment(this);" class="delete-comment"> ${_('Delete')}</a>
|
||||
%else:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue