Merge "Allow permissions to be set for teams in worklists and boards"
This commit is contained in:
commit
cb42ebd1cb
@ -33,6 +33,7 @@ from storyboard.common import exception as exc
|
||||
from storyboard.db.api import boards as boards_api
|
||||
from storyboard.db.api import stories as stories_api
|
||||
from storyboard.db.api import tasks as tasks_api
|
||||
from storyboard.db.api import teams as teams_api
|
||||
from storyboard.db.api import timeline_events as events_api
|
||||
from storyboard.db.api import users as users_api
|
||||
from storyboard.db.api import worklists as worklists_api
|
||||
@ -159,11 +160,13 @@ class PermissionsController(rest.RestController):
|
||||
created = boards_api.create_permission(board_id, permission)
|
||||
|
||||
users = [{user.id: user.full_name} for user in created.users]
|
||||
teams = [{team.id: team.name} for team in created.teams]
|
||||
events_api.board_permission_created_event(board_id,
|
||||
user_id,
|
||||
created.id,
|
||||
created.codename,
|
||||
users)
|
||||
users,
|
||||
teams)
|
||||
|
||||
return created
|
||||
else:
|
||||
@ -193,15 +196,22 @@ class PermissionsController(rest.RestController):
|
||||
% permission['codename'])
|
||||
|
||||
old_users = {user.id: user.full_name for user in old.users}
|
||||
old_teams = {team.id: team.name for team in old.teams}
|
||||
|
||||
if boards_api.editable(board, user_id):
|
||||
updated = boards_api.update_permission(board_id, permission)
|
||||
new_users = {user.id: user.full_name for user in updated.users}
|
||||
new_teams = {team.id: team.name for team in updated.teams}
|
||||
|
||||
added = [{id: name} for id, name in six.iteritems(new_users)
|
||||
if id not in old_users]
|
||||
added.extend([{id: name} for id, name in six.iteritems(new_teams)
|
||||
if id not in old_teams])
|
||||
removed = [{id: name} for id, name in six.iteritems(old_users)
|
||||
if id not in new_users]
|
||||
removed.extend([{id: name}
|
||||
for id, name in six.iteritems(old_teams)
|
||||
if id not in new_teams])
|
||||
|
||||
if added or removed:
|
||||
events_api.board_permissions_changed_event(board.id,
|
||||
@ -210,6 +220,7 @@ class PermissionsController(rest.RestController):
|
||||
updated.codename,
|
||||
added,
|
||||
removed)
|
||||
return updated.codename
|
||||
else:
|
||||
raise exc.NotFound(_("Board %s not found") % board_id)
|
||||
|
||||
@ -328,10 +339,18 @@ class BoardsController(rest.RestController):
|
||||
lanes = board_dict.pop('lanes') or []
|
||||
owners = board_dict.pop('owners')
|
||||
users = board_dict.pop('users')
|
||||
if not owners:
|
||||
team_owners = board_dict.pop('team_owners')
|
||||
team_users = board_dict.pop('team_users')
|
||||
if not owners and not team_owners:
|
||||
owners = [user_id]
|
||||
if not owners and team_owners:
|
||||
owners = []
|
||||
if not users:
|
||||
users = []
|
||||
if not team_owners:
|
||||
team_owners = []
|
||||
if not team_users:
|
||||
team_users = []
|
||||
|
||||
# We can't set due dates when creating boards at the moment.
|
||||
if 'due_dates' in board_dict:
|
||||
@ -352,29 +371,37 @@ class BoardsController(rest.RestController):
|
||||
edit_permission = {
|
||||
'name': 'edit_board_%d' % created_board.id,
|
||||
'codename': 'edit_board',
|
||||
'users': owners
|
||||
'users': owners,
|
||||
'teams': team_owners
|
||||
}
|
||||
move_permission = {
|
||||
'name': 'move_cards_%d' % created_board.id,
|
||||
'codename': 'move_cards',
|
||||
'users': users
|
||||
'users': users,
|
||||
'teams': team_users
|
||||
}
|
||||
edit = boards_api.create_permission(created_board.id, edit_permission)
|
||||
move = boards_api.create_permission(created_board.id, move_permission)
|
||||
event_owners = [{id: users_api.user_get(id).full_name}
|
||||
for id in owners]
|
||||
event_team_owners = [{id: teams_api.team_get(id).name}
|
||||
for id in owners]
|
||||
event_users = [{id: users_api.user_get(id).full_name}
|
||||
for id in users]
|
||||
event_team_users = [{id: teams_api.team_get(id).name}
|
||||
for id in users]
|
||||
events_api.board_permission_created_event(created_board.id,
|
||||
user_id,
|
||||
edit.id,
|
||||
edit.codename,
|
||||
event_owners)
|
||||
event_owners,
|
||||
event_team_owners)
|
||||
events_api.board_permission_created_event(created_board.id,
|
||||
user_id,
|
||||
move.id,
|
||||
move.codename,
|
||||
event_users)
|
||||
event_users,
|
||||
event_team_users)
|
||||
|
||||
return wmodels.Board.from_db_model(created_board)
|
||||
|
||||
|
@ -801,6 +801,12 @@ class Worklist(base.APIBase):
|
||||
users = wtypes.ArrayType(int)
|
||||
"""A list of the IDs of the users who can move items in the worklist."""
|
||||
|
||||
team_owners = wtypes.ArrayType(int)
|
||||
"""A list of the IDs of the teams who have full permissions."""
|
||||
|
||||
team_users = wtypes.ArrayType(int)
|
||||
"""A list of the IDs of the teams who can move items in the worklist."""
|
||||
|
||||
items = wtypes.ArrayType(WorklistItem)
|
||||
"""The items in the worklist."""
|
||||
|
||||
@ -857,8 +863,10 @@ class Worklist(base.APIBase):
|
||||
|
||||
@nodoc
|
||||
def resolve_permissions(self, worklist):
|
||||
self.owners = worklists_api.get_owners(worklist)
|
||||
self.users = worklists_api.get_users(worklist)
|
||||
self.owners = worklists_api.get_user_owners(worklist)
|
||||
self.users = worklists_api.get_user_users(worklist)
|
||||
self.team_owners = worklists_api.get_team_owners(worklist)
|
||||
self.team_users = worklists_api.get_team_users(worklist)
|
||||
|
||||
@nodoc
|
||||
def resolve_filters(self, worklist):
|
||||
@ -955,6 +963,12 @@ class Board(base.APIBase):
|
||||
users = wtypes.ArrayType(int)
|
||||
"""A list of the IDs of the users who can move cards in the board."""
|
||||
|
||||
team_owners = wtypes.ArrayType(int)
|
||||
"""A list of the IDs of the teams who have full permissions."""
|
||||
|
||||
team_users = wtypes.ArrayType(int)
|
||||
"""A list of the IDs of the teams who can move cards in the board."""
|
||||
|
||||
@classmethod
|
||||
def sample(cls):
|
||||
return cls(
|
||||
@ -982,7 +996,9 @@ class Board(base.APIBase):
|
||||
items=[]))],
|
||||
due_dates=[],
|
||||
owners=[1],
|
||||
users=[])
|
||||
users=[],
|
||||
team_owners=[1, 2],
|
||||
team_users=[])
|
||||
|
||||
@nodoc
|
||||
def resolve_lanes(self, board, story_cache={}, task_cache={},
|
||||
@ -1011,5 +1027,7 @@ class Board(base.APIBase):
|
||||
@nodoc
|
||||
def resolve_permissions(self, board):
|
||||
"""Resolve the permissions groups of the board."""
|
||||
self.owners = boards_api.get_owners(board)
|
||||
self.users = boards_api.get_users(board)
|
||||
self.owners = boards_api.get_user_owners(board)
|
||||
self.users = boards_api.get_user_users(board)
|
||||
self.team_owners = boards_api.get_team_owners(board)
|
||||
self.team_users = boards_api.get_team_users(board)
|
||||
|
@ -32,6 +32,7 @@ from storyboard.common import decorators
|
||||
from storyboard.common import exception as exc
|
||||
from storyboard.db.api import stories as stories_api
|
||||
from storyboard.db.api import tasks as tasks_api
|
||||
from storyboard.db.api import teams as teams_api
|
||||
from storyboard.db.api import timeline_events as events_api
|
||||
from storyboard.db.api import users as users_api
|
||||
from storyboard.db.api import worklists as worklists_api
|
||||
@ -137,11 +138,13 @@ class PermissionsController(rest.RestController):
|
||||
created = worklists_api.create_permission(worklist_id, permission)
|
||||
|
||||
users = [{user.id: user.full_name} for user in created.users]
|
||||
teams = [{team.id: team.name} for team in created.teams]
|
||||
events_api.worklist_permission_created_event(worklist_id,
|
||||
user_id,
|
||||
created.id,
|
||||
created.codename,
|
||||
users)
|
||||
users,
|
||||
teams)
|
||||
|
||||
return created.codename
|
||||
else:
|
||||
@ -166,6 +169,10 @@ class PermissionsController(rest.RestController):
|
||||
1,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"teams": [
|
||||
1,
|
||||
6
|
||||
]
|
||||
}
|
||||
|
||||
@ -189,16 +196,23 @@ class PermissionsController(rest.RestController):
|
||||
% permission['codename'])
|
||||
|
||||
old_users = {user.id: user.full_name for user in old.users}
|
||||
old_teams = {team.id: team.name for team in old.teams}
|
||||
|
||||
if worklists_api.editable(worklist, user_id):
|
||||
updated = worklists_api.update_permission(
|
||||
worklist_id, permission)
|
||||
new_users = {user.id: user.full_name for user in updated.users}
|
||||
new_teams = {team.id: team.name for team in updated.teams}
|
||||
|
||||
added = [{id: name} for id, name in six.iteritems(new_users)
|
||||
if id not in old_users]
|
||||
added.extend([{id: name} for id, name in six.iteritems(new_teams)
|
||||
if id not in old_teams])
|
||||
removed = [{id: name} for id, name in six.iteritems(old_users)
|
||||
if id not in new_users]
|
||||
removed.extend([{id: name}
|
||||
for id, name in six.iteritems(old_teams)
|
||||
if id not in new_teams])
|
||||
|
||||
if added or removed:
|
||||
events_api.worklist_permissions_changed_event(
|
||||
@ -746,10 +760,18 @@ class WorklistsController(rest.RestController):
|
||||
filters = worklist_dict.pop('filters') or []
|
||||
owners = worklist_dict.pop('owners')
|
||||
users = worklist_dict.pop('users')
|
||||
if not owners:
|
||||
team_owners = worklist_dict.pop('team_owners')
|
||||
team_users = worklist_dict.pop('team_users')
|
||||
if not owners and not team_owners:
|
||||
owners = [user_id]
|
||||
if not owners and team_owners:
|
||||
owners = []
|
||||
if not users:
|
||||
users = []
|
||||
if not team_owners:
|
||||
team_owners = []
|
||||
if not team_users:
|
||||
team_users = []
|
||||
|
||||
created_worklist = worklists_api.create(worklist_dict)
|
||||
events_api.worklist_created_event(created_worklist.id,
|
||||
@ -759,12 +781,14 @@ class WorklistsController(rest.RestController):
|
||||
edit_permission = {
|
||||
'name': 'edit_worklist_%d' % created_worklist.id,
|
||||
'codename': 'edit_worklist',
|
||||
'users': owners
|
||||
'users': owners,
|
||||
'teams': team_owners
|
||||
}
|
||||
move_permission = {
|
||||
'name': 'move_items_%d' % created_worklist.id,
|
||||
'codename': 'move_items',
|
||||
'users': users
|
||||
'users': users,
|
||||
'teams': team_users
|
||||
}
|
||||
edit = worklists_api.create_permission(
|
||||
created_worklist.id, edit_permission)
|
||||
@ -773,19 +797,24 @@ class WorklistsController(rest.RestController):
|
||||
|
||||
event_owners = [{id: users_api.user_get(id).full_name}
|
||||
for id in owners]
|
||||
event_team_owners = [{id: teams_api.team_get(id).name}
|
||||
for id in owners]
|
||||
event_users = [{id: users_api.user_get(id).full_name}
|
||||
for id in users]
|
||||
|
||||
event_team_users = [{id: teams_api.team_get(id).name}
|
||||
for id in users]
|
||||
events_api.worklist_permission_created_event(created_worklist.id,
|
||||
user_id,
|
||||
edit.id,
|
||||
edit.codename,
|
||||
event_owners)
|
||||
event_owners,
|
||||
event_team_owners)
|
||||
events_api.worklist_permission_created_event(created_worklist.id,
|
||||
user_id,
|
||||
move.id,
|
||||
move.codename,
|
||||
event_users)
|
||||
event_users,
|
||||
event_team_users)
|
||||
|
||||
if worklist_dict['automatic']:
|
||||
for filter in filters:
|
||||
|
@ -464,6 +464,13 @@ def filter_private_worklists(query, current_user, hide_lanes=True):
|
||||
models.User.id == current_user
|
||||
)
|
||||
),
|
||||
models.Board.permissions.any(
|
||||
models.Permission.teams.any(
|
||||
models.Team.users.any(
|
||||
models.User.id == current_user
|
||||
)
|
||||
)
|
||||
),
|
||||
models.Board.private == false(),
|
||||
models.Board.id.is_(None)
|
||||
)
|
||||
@ -476,6 +483,13 @@ def filter_private_worklists(query, current_user, hide_lanes=True):
|
||||
models.User.id == current_user
|
||||
)
|
||||
),
|
||||
models.Worklist.permissions.any(
|
||||
models.Permission.teams.any(
|
||||
models.Team.users.any(
|
||||
models.User.id == current_user
|
||||
)
|
||||
)
|
||||
),
|
||||
models.Worklist.private == false(),
|
||||
models.Worklist.id.is_(None)
|
||||
)
|
||||
@ -519,6 +533,13 @@ def filter_private_boards(query, current_user):
|
||||
models.User.id == current_user
|
||||
)
|
||||
),
|
||||
models.Board.permissions.any(
|
||||
models.Permission.teams.any(
|
||||
models.Team.users.any(
|
||||
models.User.id == current_user
|
||||
)
|
||||
)
|
||||
),
|
||||
models.Board.private == false(),
|
||||
models.Board.id.is_(None)
|
||||
)
|
||||
|
@ -18,6 +18,7 @@ from wsme.exc import ClientSideError
|
||||
|
||||
from storyboard._i18n import _
|
||||
from storyboard.db.api import base as api_base
|
||||
from storyboard.db.api import teams as teams_api
|
||||
from storyboard.db.api import users as users_api
|
||||
from storyboard.db import models
|
||||
|
||||
@ -212,35 +213,54 @@ def has_card(board, item_type, item_id):
|
||||
return False
|
||||
|
||||
|
||||
def get_owners(board):
|
||||
def get_user_owners(board):
|
||||
for permission in board.permissions:
|
||||
if permission.codename == 'edit_board':
|
||||
return [user.id for user in permission.users]
|
||||
|
||||
|
||||
def get_users(board):
|
||||
def get_user_users(board):
|
||||
for permission in board.permissions:
|
||||
if permission.codename == 'move_cards':
|
||||
return [user.id for user in permission.users]
|
||||
|
||||
|
||||
def get_team_owners(board):
|
||||
for permission in board.permissions:
|
||||
if permission.codename == 'edit_board':
|
||||
return [team.id for team in permission.teams]
|
||||
|
||||
|
||||
def get_team_users(board):
|
||||
for permission in board.permissions:
|
||||
if permission.codename == 'move_cards':
|
||||
return [team.id for team in permission.teams]
|
||||
|
||||
|
||||
def get_permissions(board, user_id):
|
||||
user = users_api.user_get(user_id)
|
||||
if user is not None:
|
||||
valid_permissions = set(user.permissions)
|
||||
for team in user.teams:
|
||||
valid_permissions.update(team.permissions)
|
||||
return [permission.codename for permission in board.permissions
|
||||
if permission in user.permissions]
|
||||
if permission in valid_permissions]
|
||||
return []
|
||||
|
||||
|
||||
def create_permission(board_id, permission_dict, session=None):
|
||||
board = _board_get(board_id, session=session)
|
||||
users = permission_dict.pop('users')
|
||||
teams = permission_dict.pop('teams')
|
||||
permission = api_base.entity_create(
|
||||
models.Permission, permission_dict, session=session)
|
||||
board.permissions.append(permission)
|
||||
for user_id in users:
|
||||
user = users_api.user_get(user_id, session=session)
|
||||
user.permissions.append(permission)
|
||||
for team_id in teams:
|
||||
team = teams_api.team_get(team_id, session=session)
|
||||
team.permissions.append(permission)
|
||||
return permission
|
||||
|
||||
|
||||
@ -250,11 +270,14 @@ def update_permission(board_id, permission_dict):
|
||||
for permission in board.permissions:
|
||||
if permission.codename == permission_dict['codename']:
|
||||
id = permission.id
|
||||
users = permission_dict.pop('users')
|
||||
permission_dict['users'] = []
|
||||
for user_id in users:
|
||||
user = users_api.user_get(user_id)
|
||||
permission_dict['users'].append(user)
|
||||
users = permission_dict.pop('users', None)
|
||||
teams = permission_dict.pop('teams', None)
|
||||
if users is not None:
|
||||
permission_dict['users'] = [users_api.user_get(user_id)
|
||||
for user_id in users]
|
||||
if teams is not None:
|
||||
permission_dict['teams'] = [teams_api.team_get(team_id)
|
||||
for team_id in teams]
|
||||
|
||||
if id is None:
|
||||
raise ClientSideError(_("Permission %s does not exist")
|
||||
|
@ -339,13 +339,14 @@ def worklist_details_changed_event(worklist_id, author_id, updated, old, new):
|
||||
|
||||
|
||||
def worklist_permission_created_event(worklist_id, author_id, permission_id,
|
||||
codename, users):
|
||||
codename, users, teams):
|
||||
event_info = {
|
||||
"worklist_id": worklist_id,
|
||||
"permission_id": permission_id,
|
||||
"author_id": author_id,
|
||||
"codename": codename,
|
||||
"users": users
|
||||
"users": users,
|
||||
"teams": teams
|
||||
}
|
||||
|
||||
return event_create({
|
||||
@ -445,13 +446,14 @@ def board_details_changed_event(board_id, author_id, updated, old, new):
|
||||
|
||||
|
||||
def board_permission_created_event(board_id, author_id, permission_id,
|
||||
codename, users):
|
||||
codename, users, teams):
|
||||
event_info = {
|
||||
"board_id": board_id,
|
||||
"permission_id": permission_id,
|
||||
"author_id": author_id,
|
||||
"codename": codename,
|
||||
"users": users
|
||||
"users": users,
|
||||
"teams": teams
|
||||
}
|
||||
|
||||
return event_create({
|
||||
|
@ -23,6 +23,7 @@ from storyboard.db.api import base as api_base
|
||||
from storyboard.db.api import boards
|
||||
from storyboard.db.api import stories as stories_api
|
||||
from storyboard.db.api import tasks as tasks_api
|
||||
from storyboard.db.api import teams as teams_api
|
||||
from storyboard.db.api import users as users_api
|
||||
from storyboard.db import models
|
||||
|
||||
@ -365,35 +366,54 @@ def is_lane(worklist):
|
||||
return False
|
||||
|
||||
|
||||
def get_owners(worklist):
|
||||
def get_user_owners(worklist):
|
||||
for permission in worklist.permissions:
|
||||
if permission.codename == 'edit_worklist':
|
||||
return [user.id for user in permission.users]
|
||||
|
||||
|
||||
def get_users(worklist):
|
||||
def get_user_users(worklist):
|
||||
for permission in worklist.permissions:
|
||||
if permission.codename == 'move_items':
|
||||
return [user.id for user in permission.users]
|
||||
|
||||
|
||||
def get_team_owners(worklist):
|
||||
for permission in worklist.permissions:
|
||||
if permission.codename == 'edit_worklist':
|
||||
return [team.id for team in permission.teams]
|
||||
|
||||
|
||||
def get_team_users(worklist):
|
||||
for permission in worklist.permissions:
|
||||
if permission.codename == 'move_items':
|
||||
return [team.id for team in permission.teams]
|
||||
|
||||
|
||||
def get_permissions(worklist, user_id):
|
||||
user = users_api.user_get(user_id)
|
||||
if user is not None:
|
||||
valid_permissions = set(user.permissions)
|
||||
for team in user.teams:
|
||||
valid_permissions.update(team.permissions)
|
||||
return [permission.codename for permission in worklist.permissions
|
||||
if permission in user.permissions]
|
||||
if permission in valid_permissions]
|
||||
return []
|
||||
|
||||
|
||||
def create_permission(worklist_id, permission_dict, session=None):
|
||||
worklist = _worklist_get(worklist_id, session=session)
|
||||
users = permission_dict.pop('users')
|
||||
teams = permission_dict.pop('teams')
|
||||
permission = api_base.entity_create(
|
||||
models.Permission, permission_dict, session=session)
|
||||
worklist.permissions.append(permission)
|
||||
for user_id in users:
|
||||
user = users_api.user_get(user_id, session=session)
|
||||
user.permissions.append(permission)
|
||||
for team_id in teams:
|
||||
team = teams_api.team_get(team_id, session=session)
|
||||
team.permissions.append(permission)
|
||||
return permission
|
||||
|
||||
|
||||
@ -403,11 +423,14 @@ def update_permission(worklist_id, permission_dict):
|
||||
for permission in worklist.permissions:
|
||||
if permission.codename == permission_dict['codename']:
|
||||
id = permission.id
|
||||
users = permission_dict.pop('users')
|
||||
permission_dict['users'] = []
|
||||
for user_id in users:
|
||||
user = users_api.user_get(user_id)
|
||||
permission_dict['users'].append(user)
|
||||
users = permission_dict.pop('users', None)
|
||||
teams = permission_dict.pop('teams', None)
|
||||
if users is not None:
|
||||
permission_dict['users'] = [users_api.user_get(user_id)
|
||||
for user_id in users]
|
||||
if teams is not None:
|
||||
permission_dict['teams'] = [teams_api.team_get(team_id)
|
||||
for team_id in teams]
|
||||
|
||||
if id is None:
|
||||
raise ClientSideError(_("Permission %s does not exist")
|
||||
|
@ -643,7 +643,8 @@ class Board(FullText, ModelBuilder, Base):
|
||||
private = Column(Boolean, default=False)
|
||||
archived = Column(Boolean, default=False)
|
||||
lanes = relationship(BoardWorklist, backref='board')
|
||||
permissions = relationship("Permission", secondary="board_permissions")
|
||||
permissions = relationship("Permission", secondary="board_permissions",
|
||||
backref="boards")
|
||||
|
||||
_public_fields = ["id", "title", "description", "creator_id",
|
||||
"project_id", "permission_id", "private", "archived"]
|
||||
|
Loading…
x
Reference in New Issue
Block a user