Skip to content
This repository has been archived by the owner on Oct 24, 2018. It is now read-only.

Commit

Permalink
Merge pull request #95 from tracim/feature/611_workspace_and_workspac…
Browse files Browse the repository at this point in the history
…e_member_action_endpoints

WIP: Feature/611 workspace and workspace member action endpoints
  • Loading branch information
inkhey authored Jul 26, 2018
2 parents fbadc4b + 4146e78 commit 8659efb
Show file tree
Hide file tree
Showing 14 changed files with 1,166 additions and 118 deletions.
13 changes: 13 additions & 0 deletions tracim/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,5 +163,18 @@ class EmptyLabelNotAllowed(EmptyValueNotAllowed):
class EmptyCommentContentNotAllowed(EmptyValueNotAllowed):
pass


class RoleDoesNotExist(TracimException):
pass


class EmailValidationFailed(TracimException):
pass


class UserCreationFailed(TracimException):
pass


class ParentNotFound(NotFound):
pass
65 changes: 64 additions & 1 deletion tracim/lib/core/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,19 @@
import typing as typing

from tracim.exceptions import NotificationNotSend
from tracim.exceptions import EmailValidationFailed
from tracim.lib.mail_notifier.notifier import get_email_manager
from sqlalchemy.orm import Session

from tracim import CFG
from tracim.models.auth import User
from tracim.models.auth import Group
from sqlalchemy.orm.exc import NoResultFound
from tracim.exceptions import WrongUserPassword, UserDoesNotExist
from tracim.exceptions import UserDoesNotExist
from tracim.exceptions import WrongUserPassword
from tracim.exceptions import AuthenticationFailed
from tracim.models.context_models import UserInContext
from tracim.models.context_models import TypeUser


class UserApi(object):
Expand Down Expand Up @@ -68,7 +71,17 @@ def get_one_by_email(self, email: str) -> User:
raise UserDoesNotExist('User "{}" not found in database'.format(email)) from exc # nopep8
return user

def get_one_by_public_name(self, public_name: str) -> User:
"""
Get one user by public_name
"""
try:
user = self._base_query().filter(User.display_name == public_name).one()
except NoResultFound as exc:
raise UserDoesNotExist('User "{}" not found in database'.format(public_name)) from exc # nopep8
return user
# FIXME - G.M - 24-04-2018 - Duplicate method with get_one.

def get_one_by_id(self, id: int) -> User:
return self.get_one(user_id=id)

Expand All @@ -83,6 +96,40 @@ def get_current_user(self) -> User:
def get_all(self) -> typing.Iterable[User]:
return self._session.query(User).order_by(User.display_name).all()

def find(
self,
user_id: int=None,
email: str=None,
public_name: str=None
) -> typing.Tuple[TypeUser, User]:
"""
Find existing user from all theses params.
Check is made in this order: user_id, email, public_name
If no user found raise UserDoesNotExist exception
"""
user = None

if user_id:
try:
user = self.get_one(user_id)
return TypeUser.USER_ID, user
except UserDoesNotExist:
pass
if email:
try:
user = self.get_one_by_email(email)
return TypeUser.EMAIL, user
except UserDoesNotExist:
pass
if public_name:
try:
user = self.get_one_by_public_name(public_name)
return TypeUser.PUBLIC_NAME, user
except UserDoesNotExist:
pass

raise UserDoesNotExist('User not found with any of given params.')

# Check methods

def user_with_email_exists(self, email: str) -> bool:
Expand Down Expand Up @@ -112,6 +159,15 @@ def authenticate_user(self, email: str, password: str) -> User:

# Actions

def _check_email(self, email: str) -> bool:
# TODO - G.M - 2018-07-05 - find a better way to check email
if not email:
return False
email = email.split('@')
if len(email) != 2:
return False
return True

def update(
self,
user: User,
Expand All @@ -125,6 +181,9 @@ def update(
user.display_name = name

if email is not None:
email_exist = self._check_email(email)
if not email_exist:
raise EmailValidationFailed('Email given form {} is uncorrect'.format(email)) # nopep8
user.email = email

if password is not None:
Expand Down Expand Up @@ -176,7 +235,11 @@ def create_minimal_user(
"""Previous create_user method"""
user = User()

email_exist = self._check_email(email)
if not email_exist:
raise EmailValidationFailed('Email given form {} is uncorrect'.format(email)) # nopep8
user.email = email
user.display_name = email.split('@')[0]

for group in groups:
user.groups.append(group)
Expand Down
180 changes: 108 additions & 72 deletions tracim/lib/core/userworkspace.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from tracim import CFG
from tracim.models.context_models import UserRoleWorkspaceInContext
from tracim.models.roles import WorkspaceRoles

__author__ = 'damien'

Expand All @@ -11,40 +12,55 @@
from tracim.models.auth import User
from tracim.models.data import Workspace
from tracim.models.data import UserRoleInWorkspace
from tracim.models.data import RoleType


class RoleApi(object):

ALL_ROLE_VALUES = UserRoleInWorkspace.get_all_role_values()
# TODO - G.M - 29-06-2018 - [Cleanup] Drop this
# ALL_ROLE_VALUES = UserRoleInWorkspace.get_all_role_values()
# Dict containing readable members roles for given role
members_read_rights = {
UserRoleInWorkspace.NOT_APPLICABLE: [],
UserRoleInWorkspace.READER: [
UserRoleInWorkspace.WORKSPACE_MANAGER,
],
UserRoleInWorkspace.CONTRIBUTOR: [
UserRoleInWorkspace.WORKSPACE_MANAGER,
UserRoleInWorkspace.CONTENT_MANAGER,
UserRoleInWorkspace.CONTRIBUTOR,
],
UserRoleInWorkspace.CONTENT_MANAGER: [
UserRoleInWorkspace.WORKSPACE_MANAGER,
UserRoleInWorkspace.CONTENT_MANAGER,
UserRoleInWorkspace.CONTRIBUTOR,
UserRoleInWorkspace.READER,
],
UserRoleInWorkspace.WORKSPACE_MANAGER: [
UserRoleInWorkspace.WORKSPACE_MANAGER,
UserRoleInWorkspace.CONTENT_MANAGER,
UserRoleInWorkspace.CONTRIBUTOR,
UserRoleInWorkspace.READER,
],
}
# members_read_rights = {
# UserRoleInWorkspace.NOT_APPLICABLE: [],
# UserRoleInWorkspace.READER: [
# UserRoleInWorkspace.WORKSPACE_MANAGER,
# ],
# UserRoleInWorkspace.CONTRIBUTOR: [
# UserRoleInWorkspace.WORKSPACE_MANAGER,
# UserRoleInWorkspace.CONTENT_MANAGER,
# UserRoleInWorkspace.CONTRIBUTOR,
# ],
# UserRoleInWorkspace.CONTENT_MANAGER: [
# UserRoleInWorkspace.WORKSPACE_MANAGER,
# UserRoleInWorkspace.CONTENT_MANAGER,
# UserRoleInWorkspace.CONTRIBUTOR,
# UserRoleInWorkspace.READER,
# ],
# UserRoleInWorkspace.WORKSPACE_MANAGER: [
# UserRoleInWorkspace.WORKSPACE_MANAGER,
# UserRoleInWorkspace.CONTENT_MANAGER,
# UserRoleInWorkspace.CONTRIBUTOR,
# UserRoleInWorkspace.READER,
# ],
# }

# TODO - G.M - 29-06-2018 - [Cleanup] Drop this
# @classmethod
# def role_can_read_member_role(cls, reader_role: int, tested_role: int) \
# -> bool:
# """
# :param reader_role: role as viewer
# :param tested_role: role as viwed
# :return: True if given role can view member role in workspace.
# """
# if reader_role in cls.members_read_rights:
# return tested_role in cls.members_read_rights[reader_role]
# return False

def get_user_role_workspace_with_context(
self,
user_role: UserRoleInWorkspace
user_role: UserRoleInWorkspace,
newly_created:bool = None,
email_sent: bool = None,
) -> UserRoleWorkspaceInContext:
"""
Return WorkspaceInContext object from Workspace
Expand All @@ -54,27 +70,11 @@ def get_user_role_workspace_with_context(
user_role=user_role,
dbsession=self._session,
config=self._config,
newly_created=newly_created,
email_sent=email_sent,
)
return workspace

@classmethod
def role_can_read_member_role(cls, reader_role: int, tested_role: int) \
-> bool:
"""
:param reader_role: role as viewer
:param tested_role: role as viwed
:return: True if given role can view member role in workspace.
"""
if reader_role in cls.members_read_rights:
return tested_role in cls.members_read_rights[reader_role]
return False

@classmethod
def create_role(cls) -> UserRoleInWorkspace:
role = UserRoleInWorkspace()

return role

def __init__(
self,
session: Session,
Expand All @@ -98,6 +98,29 @@ def _get_one_rsc(self, user_id: int, workspace_id: int) -> Query:
def get_one(self, user_id: int, workspace_id: int) -> UserRoleInWorkspace:
return self._get_one_rsc(user_id, workspace_id).one()

def update_role(
self,
role: UserRoleInWorkspace,
role_level: int,
with_notif: typing.Optional[bool] = None,
save_now: bool=False,
):
"""
Update role of user in this workspace
:param role: UserRoleInWorkspace object
:param role_level: level of new role wanted
:param with_notif: is user notification enabled in this workspace ?
:param save_now: database flush
:return: updated role
"""
role.role = role_level
if with_notif is not None:
role.do_notify == with_notif
if save_now:
self.save(role)

return role

def create_one(
self,
user: User,
Expand All @@ -106,7 +129,7 @@ def create_one(
with_notif: bool,
flush: bool=True
) -> UserRoleInWorkspace:
role = self.create_role()
role = UserRoleInWorkspace()
role.user_id = user.user_id
role.workspace = workspace
role.role = role_level
Expand All @@ -120,20 +143,6 @@ def delete_one(self, user_id: int, workspace_id: int, flush=True) -> None:
if flush:
self._session.flush()

def _get_all_for_user(self, user_id) -> typing.List[UserRoleInWorkspace]:
return self._session.query(UserRoleInWorkspace)\
.filter(UserRoleInWorkspace.user_id == user_id)

def get_all_for_user(self, user: User) -> typing.List[UserRoleInWorkspace]:
return self._get_all_for_user(user.user_id).all()

def get_all_for_user_order_by_workspace(
self,
user_id: int
) -> typing.List[UserRoleInWorkspace]:
return self._get_all_for_user(user_id)\
.join(UserRoleInWorkspace.workspace).order_by(Workspace.label).all()

def get_all_for_workspace(
self,
workspace:Workspace
Expand All @@ -145,18 +154,45 @@ def get_all_for_workspace(
def save(self, role: UserRoleInWorkspace) -> None:
self._session.flush()

# TODO - G.M - 07-06-2018 - [Cleanup] Check if this method is already needed
@classmethod
def get_roles_for_select_field(cls) -> typing.List[RoleType]:
"""
:return: list of DictLikeClass instances representing available Roles
(to be used in select fields)
"""
result = list()

for role_id in UserRoleInWorkspace.get_all_role_values():
role = RoleType(role_id)
result.append(role)
# TODO - G.M - 29-06-2018 - [Cleanup] Drop this
# @classmethod
# def role_can_read_member_role(cls, reader_role: int, tested_role: int) \
# -> bool:
# """
# :param reader_role: role as viewer
# :param tested_role: role as viwed
# :return: True if given role can view member role in workspace.
# """
# if reader_role in cls.members_read_rights:
# return tested_role in cls.members_read_rights[reader_role]
# return False
# def _get_all_for_user(self, user_id) -> typing.List[UserRoleInWorkspace]:
# return self._session.query(UserRoleInWorkspace)\
# .filter(UserRoleInWorkspace.user_id == user_id)
#
# def get_all_for_user(self, user: User) -> typing.List[UserRoleInWorkspace]:
# return self._get_all_for_user(user.user_id).all()
#
# def get_all_for_user_order_by_workspace(
# self,
# user_id: int
# ) -> typing.List[UserRoleInWorkspace]:
# return self._get_all_for_user(user_id)\
# .join(UserRoleInWorkspace.workspace).order_by(Workspace.label).all()

return result
# TODO - G.M - 07-06-2018 - [Cleanup] Check if this method is already needed
# @classmethod
# def get_roles_for_select_field(cls) -> typing.List[RoleType]:
# """
#
# :return: list of DictLikeClass instances representing available Roles
# (to be used in select fields)
# """
# result = list()
#
# for role_id in UserRoleInWorkspace.get_all_role_values():
# role = RoleType(role_id)
# result.append(role)
#
# return result
Loading

0 comments on commit 8659efb

Please sign in to comment.