Hide timeline events and comments of private stories
This commit fixes a bug wherein timeline events of private stories can be obtained by users without the correct permissions. Change-Id: Ifb7ef03938140930abbdb21a9bcf7e98ae39aaf6
This commit is contained in:
parent
5bafba1140
commit
4572958c28
@ -91,10 +91,13 @@ class SqlAlchemySearchImpl(search_engine.SearchEngine):
|
||||
|
||||
return query.all()
|
||||
|
||||
def comments_query(self, q, marker=None, offset=None,
|
||||
limit=None, **kwargs):
|
||||
def comments_query(self, q, marker=None, offset=None, limit=None,
|
||||
current_user=None, **kwargs):
|
||||
session = api_base.get_session()
|
||||
query = api_base.model_query(models.Comment, session)
|
||||
query = query.outerjoin(models.Story)
|
||||
query = api_base.filter_private_stories(query, current_user)
|
||||
|
||||
query = self._build_fulltext_search(models.Comment, query, q)
|
||||
query = self._apply_pagination(
|
||||
models.Comment, query, marker, offset, limit)
|
||||
|
@ -29,6 +29,7 @@ from storyboard.common import decorators
|
||||
from storyboard.common import event_types
|
||||
from storyboard.common import exception as exc
|
||||
from storyboard.db.api import comments as comments_api
|
||||
from storyboard.db.api import stories as stories_api
|
||||
from storyboard.db.api import timeline_events as events_api
|
||||
from storyboard.openstack.common.gettextutils import _ # noqa
|
||||
|
||||
@ -57,7 +58,8 @@ class TimeLineEventsController(rest.RestController):
|
||||
:param event_id: An ID of the event.
|
||||
"""
|
||||
|
||||
event = events_api.event_get(event_id)
|
||||
event = events_api.event_get(event_id,
|
||||
current_user=request.current_user_id)
|
||||
|
||||
if event:
|
||||
wsme_event = wmodels.TimeLineEvent.from_db_model(event)
|
||||
@ -87,6 +89,8 @@ class TimeLineEventsController(rest.RestController):
|
||||
:param sort_dir: Sort direction for results (asc, desc).
|
||||
"""
|
||||
|
||||
current_user = request.current_user_id
|
||||
|
||||
# Boundary check on limit.
|
||||
if limit is not None:
|
||||
limit = max(0, limit)
|
||||
@ -106,14 +110,16 @@ class TimeLineEventsController(rest.RestController):
|
||||
marker_event = events_api.event_get(marker)
|
||||
|
||||
event_count = events_api.events_get_count(story_id=story_id,
|
||||
event_type=event_type)
|
||||
event_type=event_type,
|
||||
current_user=current_user)
|
||||
events = events_api.events_get_all(story_id=story_id,
|
||||
event_type=event_type,
|
||||
marker=marker_event,
|
||||
offset=offset,
|
||||
limit=limit,
|
||||
sort_field=sort_field,
|
||||
sort_dir=sort_dir)
|
||||
sort_dir=sort_dir,
|
||||
current_user=current_user)
|
||||
|
||||
# Apply the query response headers.
|
||||
if limit:
|
||||
@ -141,6 +147,15 @@ class CommentsHistoryController(rest.RestController):
|
||||
:param comment_id: The ID of the comment to inspect history of.
|
||||
"""
|
||||
comment = comments_api.comment_get(comment_id)
|
||||
if comment is None:
|
||||
raise exc.NotFound(_("Comment %s not found") % comment_id)
|
||||
|
||||
# Check that the user can actually see the relevant story
|
||||
story = stories_api.story_get_simple(
|
||||
comment.event[0].story_id, current_user=request.current_user_id)
|
||||
if story is None:
|
||||
raise exc.NotFound(_("Comment %s not found") % comment_id)
|
||||
|
||||
return [wmodels.Comment.from_db_model(old_comment)
|
||||
for old_comment in comment.history]
|
||||
|
||||
@ -166,14 +181,18 @@ class CommentsController(rest.RestController):
|
||||
comments have their own unique ids.
|
||||
:param comment_id: An ID of the comment.
|
||||
"""
|
||||
|
||||
comment = comments_api.comment_get(comment_id)
|
||||
|
||||
if comment:
|
||||
return wmodels.Comment.from_db_model(comment)
|
||||
else:
|
||||
if comment is None:
|
||||
raise exc.NotFound(_("Comment %s not found") % comment_id)
|
||||
|
||||
# Check that the user can actually see the relevant story
|
||||
story = stories_api.story_get_simple(
|
||||
comment.event[0].story_id, current_user=request.current_user_id)
|
||||
if story is None:
|
||||
raise exc.NotFound(_("Comment %s not found") % comment_id)
|
||||
|
||||
return wmodels.Comment.from_db_model(comment)
|
||||
|
||||
@decorators.db_exceptions
|
||||
@secure(checks.guest)
|
||||
@wsme_pecan.wsexpose([wmodels.Comment], int, int, int, wtypes.text,
|
||||
@ -192,6 +211,7 @@ class CommentsController(rest.RestController):
|
||||
:param sort_field: The name of the field to sort on.
|
||||
:param sort_dir: Sort direction for results (asc, desc).
|
||||
"""
|
||||
current_user = request.current_user_id
|
||||
|
||||
# Boundary check on limit.
|
||||
if limit is not None:
|
||||
@ -202,20 +222,23 @@ class CommentsController(rest.RestController):
|
||||
if marker:
|
||||
event_query = \
|
||||
events_api.events_get_all(comment_id=marker,
|
||||
event_type=event_types.USER_COMMENT)
|
||||
event_type=event_types.USER_COMMENT,
|
||||
current_user=current_user)
|
||||
if len(event_query) > 0:
|
||||
marker_event = event_query[0]
|
||||
|
||||
events_count = events_api.events_get_count(
|
||||
story_id=story_id,
|
||||
event_type=event_types.USER_COMMENT)
|
||||
event_type=event_types.USER_COMMENT,
|
||||
current_user=current_user)
|
||||
|
||||
events = events_api.events_get_all(story_id=story_id,
|
||||
marker=marker_event,
|
||||
limit=limit,
|
||||
event_type=event_types.USER_COMMENT,
|
||||
sort_field=sort_field,
|
||||
sort_dir=sort_dir)
|
||||
sort_dir=sort_dir,
|
||||
current_user=current_user)
|
||||
|
||||
comments = [comments_api.comment_get(event.comment_id)
|
||||
for event in events]
|
||||
|
@ -472,7 +472,7 @@ def filter_private_worklists(query, current_user, hide_lanes=True):
|
||||
or_(
|
||||
and_(
|
||||
users.id == current_user,
|
||||
boards.private == true()
|
||||
models.Worklist.private == true()
|
||||
),
|
||||
models.Worklist.private == false(),
|
||||
models.Worklist.id.is_(None)
|
||||
|
@ -29,23 +29,63 @@ from storyboard.notifications.publisher import publish
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
def event_get(event_id):
|
||||
return api_base.entity_get(models.TimeLineEvent, event_id)
|
||||
def event_get(event_id, session=None, current_user=None):
|
||||
query = (api_base.model_query(models.TimeLineEvent, session)
|
||||
.filter_by(id=event_id))
|
||||
query = query.outerjoin(models.Story)
|
||||
query = api_base.filter_private_stories(query, current_user)
|
||||
|
||||
query = query.outerjoin(models.Worklist)
|
||||
query = api_base.filter_private_worklists(
|
||||
query, current_user, hide_lanes=False)
|
||||
|
||||
query = query.outerjoin(models.Board)
|
||||
query = api_base.filter_private_boards(query, current_user)
|
||||
|
||||
return query.first()
|
||||
|
||||
|
||||
def events_get_all(marker=None, limit=None, sort_field=None, sort_dir=None,
|
||||
**kwargs):
|
||||
return api_base.entity_get_all(models.TimeLineEvent,
|
||||
marker=marker,
|
||||
limit=limit,
|
||||
sort_field=sort_field,
|
||||
sort_dir=sort_dir,
|
||||
**kwargs)
|
||||
def _events_build_query(current_user=None, **kwargs):
|
||||
query = api_base.model_query(models.TimeLineEvent).distinct()
|
||||
|
||||
query = api_base.apply_query_filters(query=query,
|
||||
model=models.TimeLineEvent,
|
||||
**kwargs)
|
||||
|
||||
query = query.outerjoin(models.Story)
|
||||
query = api_base.filter_private_stories(query, current_user)
|
||||
|
||||
query = query.outerjoin(models.Worklist)
|
||||
query = api_base.filter_private_worklists(
|
||||
query, current_user, hide_lanes=False)
|
||||
|
||||
query = query.outerjoin(models.Board)
|
||||
query = api_base.filter_private_boards(query, current_user)
|
||||
|
||||
return query
|
||||
|
||||
|
||||
def events_get_count(**kwargs):
|
||||
return api_base.entity_get_count(models.TimeLineEvent,
|
||||
**kwargs)
|
||||
def events_get_all(marker=None, offset=None, limit=None, sort_field=None,
|
||||
sort_dir=None, current_user=None, **kwargs):
|
||||
if sort_field is None:
|
||||
sort_field = 'id'
|
||||
if sort_dir is None:
|
||||
sort_dir = 'asc'
|
||||
|
||||
query = _events_build_query(current_user=current_user, **kwargs)
|
||||
query = api_base.paginate_query(query=query,
|
||||
model=models.TimeLineEvent,
|
||||
marker=marker,
|
||||
limit=limit,
|
||||
offset=offset,
|
||||
sort_key=sort_field,
|
||||
sort_dir=sort_dir)
|
||||
return query.all()
|
||||
|
||||
|
||||
def events_get_count(current_user=None, **kwargs):
|
||||
query = _events_build_query(current_user=current_user, **kwargs)
|
||||
return query.count()
|
||||
|
||||
|
||||
def event_create(values):
|
||||
|
@ -490,6 +490,7 @@ class TimeLineEvent(ModelBuilder, Base):
|
||||
worklist_id = Column(Integer, ForeignKey('worklists.id'), nullable=True)
|
||||
board_id = Column(Integer, ForeignKey('boards.id'), nullable=True)
|
||||
comment_id = Column(Integer, ForeignKey('comments.id'), nullable=True)
|
||||
comment = relationship('Comment', backref='event')
|
||||
author_id = Column(Integer, ForeignKey('users.id'), nullable=True)
|
||||
|
||||
event_type = Column(Enum(*event_types.ALL), nullable=False)
|
||||
|
Loading…
x
Reference in New Issue
Block a user