Exemple #1
0
    def get_roles_for_select_field(self):
        """

        :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
Exemple #2
0
    def get_roles_for_select_field(self):
        """

        :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
Exemple #3
0
def serialize_role_in_workspace(role: UserRoleInWorkspace, context: Context):
    """
    Actually, roles are serialized as users (with minimal information)
    :param role:
    :param context:
    :return:
    """
    result = DictLikeClass()
    result['id'] = role.user_id
    result['icon'] = role.icon
    result['name'] = role.user.display_name
    result['role'] = role.role
    result['style'] = role.style
    result['role_description'] = role.role_as_label()
    result['email'] = role.user.email
    result['user'] = context.toDict(role.user)
    result['notifications_subscribed'] = role.do_notify
    return result
Exemple #4
0
def serialize_role_in_workspace(role: UserRoleInWorkspace, context: Context):
    """
    Actually, roles are serialized as users (with minimal information)
    :param role:
    :param context:
    :return:
    """
    result = DictLikeClass()
    result['id'] = role.user_id
    result['icon'] = role.icon
    result['name'] = role.user.display_name
    result['role'] = role.role
    result['style'] = role.style
    result['role_description'] = role.role_as_label()
    result['email'] = role.user.email
    result['user'] = context.toDict(role.user)
    result['notifications_subscribed'] = role.do_notify
    return result
Exemple #5
0
def serialize_role_in_list_for_user(role: UserRoleInWorkspace, context: Context):
    """
    Actually, roles are serialized as users (with minimal information)
    :param role:
    :param context:
    :return:
    """
    result = DictLikeClass()
    result['id'] = role.role
    result['icon'] = role.icon
    result['label'] = role.role_as_label()
    result['style'] = RoleType(role.role).css_style
    result['workspace'] =  context.toDict(role.workspace)
    result['user'] = Context(CTX.DEFAULT).toDict(role.user)
    result['notifications_subscribed'] = role.do_notify

    # result['workspace_name'] = role.workspace.label

    return result
Exemple #6
0
def serialize_role_in_list_for_user(role: UserRoleInWorkspace, context: Context):
    """
    Actually, roles are serialized as users (with minimal information)
    :param role:
    :param context:
    :return:
    """
    result = DictLikeClass()
    result['id'] = role.role
    result['icon'] = role.icon
    result['label'] = role.role_as_label()
    result['style'] = RoleType(role.role).css_style
    result['workspace'] =  context.toDict(role.workspace)
    result['user'] = Context(CTX.DEFAULT).toDict(role.user)
    result['notifications_subscribed'] = role.do_notify

    # result['workspace_name'] = role.workspace.label

    return result
Exemple #7
0
    def _build_email_body(self, mako_template_filepath: str, role: UserRoleInWorkspace, content: Content, actor: User) -> str:
        """
        Build an email body and return it as a string
        :param mako_template_filepath: the absolute path to the mako template to be used for email body building
        :param role: the role related to user to whom the email must be sent. The role is required (and not the user only) in order to show in the mail why the user receive the notification
        :param content: the content item related to the notification
        :param actor: the user at the origin of the action / notification (for example the one who wrote a comment
        :param config: the global configuration
        :return: the built email body as string. In case of multipart email, this method must be called one time for text and one time for html
        """
        logger.debug(self, 'Building email content from MAKO template {}'.format(mako_template_filepath))

        template = Template(filename=mako_template_filepath)
        # TODO - D.A. - 2014-11-06 - move this
        # Import is here for circular import problem
        import tracim.lib.helpers as helpers

        dictified_item = Context(CTX.EMAIL_NOTIFICATION, self._global_config.WEBSITE_BASE_URL).toDict(content)
        dictified_actor = Context(CTX.DEFAULT).toDict(actor)

        main_title = dictified_item.label
        content_intro = ''
        content_text = ''
        call_to_action_text = ''

        action = content.get_last_action().id
        if ActionDescription.COMMENT == action:
            content_intro = _('<span id="content-intro-username">{}</span> added a comment:').format(actor.display_name)
            content_text = content.description
            call_to_action_text = _('Answer')

        elif ActionDescription.CREATION == action:

            # Default values (if not overriden)
            content_text = content.description
            call_to_action_text = _('View online')

            if ContentType.Thread == content.type:
                call_to_action_text = _('Answer')
                content_intro = _('<span id="content-intro-username">{}</span> started a thread entitled:').format(actor.display_name)
                content_text = '<p id="content-body-intro">{}</p>'.format(content.label) + \
                               content.get_last_comment_from(actor).description

            elif ContentType.File == content.type:
                content_intro = _('<span id="content-intro-username">{}</span> added a file entitled:').format(actor.display_name)
                if content.description:
                    content_text = content.description
                else:
                    content_text = '<span id="content-body-only-title">{}</span>'.format(content.label)

            elif ContentType.Page == content.type:
                content_intro = _('<span id="content-intro-username">{}</span> added a page entitled:').format(actor.display_name)
                content_text = '<span id="content-body-only-title">{}</span>'.format(content.label)

        elif ActionDescription.REVISION == action:
            content_text = content.description
            call_to_action_text = _('View online')

            if ContentType.File == content.type:
                content_intro = _('<span id="content-intro-username">{}</span> uploaded a new revision.').format(actor.display_name)
                content_text = ''

            elif ContentType.Page == content.type:
                content_intro = _('<span id="content-intro-username">{}</span> updated this page.').format(actor.display_name)
                previous_revision = content.get_previous_revision()
                title_diff = ''
                if previous_revision.label != content.label:
                    title_diff = htmldiff(previous_revision.label, content.label)
                content_text = _('<p id="content-body-intro">Here is an overview of the changes:</p>')+ \
                    title_diff + \
                    htmldiff(previous_revision.description, content.description)

            elif ContentType.Thread == content.type:
                content_intro = _('<span id="content-intro-username">{}</span> updated the thread description.').format(actor.display_name)
                previous_revision = content.get_previous_revision()
                title_diff = ''
                if previous_revision.label != content.label:
                    title_diff = htmldiff(previous_revision.label, content.label)
                content_text = _('<p id="content-body-intro">Here is an overview of the changes:</p>')+ \
                    title_diff + \
                    htmldiff(previous_revision.description, content.description)

            # elif ContentType.Thread == content.type:
            #     content_intro = _('<span id="content-intro-username">{}</span> updated this page.').format(actor.display_name)
            #     previous_revision = content.get_previous_revision()
            #     content_text = _('<p id="content-body-intro">Here is an overview of the changes:</p>')+ \
            #         htmldiff(previous_revision.description, content.description)

        elif ActionDescription.EDITION == action:
            call_to_action_text = _('View online')

            if ContentType.File == content.type:
                content_intro = _('<span id="content-intro-username">{}</span> updated the file description.').format(actor.display_name)
                content_text = '<p id="content-body-intro">{}</p>'.format(content.get_label()) + \
                    content.description


        if '' == content_intro and content_text == '':
            # Skip notification, but it's not normal
            logger.error(
                self, 'A notification is being sent but no content. '
                      'Here are some debug informations: [content_id: {cid}]'
                      '[action: {act}][author: {actor}]'.format(
                    cid=content.content_id, act=action, actor=actor
                )
            )
            raise ValueError('Unexpected empty notification')

        # Import done here because cyclic import
        from tracim.config.app_cfg import CFG
        body_content = template.render(
            base_url=self._global_config.WEBSITE_BASE_URL,
            _=_,
            h=helpers,
            user_display_name=role.user.display_name,
            user_role_label=role.role_as_label(),
            workspace_label=role.workspace.label,
            content_intro=content_intro,
            content_text=content_text,
            main_title=main_title,
            call_to_action_text=call_to_action_text,
            result = DictLikeClass(item=dictified_item, actor=dictified_actor),
            CFG=CFG.get_instance(),
        )

        return body_content
Exemple #8
0
    def _build_email_body(self, mako_template_filepath: str,
                          role: UserRoleInWorkspace, content: Content,
                          actor: User) -> str:
        """
        Build an email body and return it as a string
        :param mako_template_filepath: the absolute path to the mako template to be used for email body building
        :param role: the role related to user to whom the email must be sent. The role is required (and not the user only) in order to show in the mail why the user receive the notification
        :param content: the content item related to the notification
        :param actor: the user at the origin of the action / notification (for example the one who wrote a comment
        :param config: the global configuration
        :return: the built email body as string. In case of multipart email, this method must be called one time for text and one time for html
        """
        logger.debug(
            self, 'Building email content from MAKO template {}'.format(
                mako_template_filepath))

        template = Template(filename=mako_template_filepath)
        # TODO - D.A. - 2014-11-06 - move this
        # Import is here for circular import problem
        import tracim.lib.helpers as helpers

        dictified_item = Context(
            CTX.EMAIL_NOTIFICATION,
            self._global_config.WEBSITE_BASE_URL).toDict(content)
        dictified_actor = Context(CTX.DEFAULT).toDict(actor)

        main_title = dictified_item.label
        content_intro = ''
        content_text = ''
        call_to_action_text = ''

        action = content.get_last_action().id
        if ActionDescription.COMMENT == action:
            content_intro = l_(
                '<span id="content-intro-username">{}</span> added a comment:'
            ).format(actor.display_name)
            content_text = content.description
            call_to_action_text = l_('Answer')

        elif ActionDescription.CREATION == action:

            # Default values (if not overriden)
            content_text = content.description
            call_to_action_text = l_('View online')

            if ContentType.Thread == content.type:
                call_to_action_text = l_('Answer')
                content_intro = l_(
                    '<span id="content-intro-username">{}</span> started a thread entitled:'
                ).format(actor.display_name)
                content_text = '<p id="content-body-intro">{}</p>'.format(content.label) + \
                               content.get_last_comment_from(actor).description

            elif ContentType.File == content.type:
                content_intro = l_(
                    '<span id="content-intro-username">{}</span> added a file entitled:'
                ).format(actor.display_name)
                if content.description:
                    content_text = content.description
                else:
                    content_text = '<span id="content-body-only-title">{}</span>'.format(
                        content.label)

            elif ContentType.Page == content.type:
                content_intro = l_(
                    '<span id="content-intro-username">{}</span> added a page entitled:'
                ).format(actor.display_name)
                content_text = '<span id="content-body-only-title">{}</span>'.format(
                    content.label)

        elif ActionDescription.REVISION == action:
            content_text = content.description
            call_to_action_text = l_('View online')

            if ContentType.File == content.type:
                content_intro = l_(
                    '<span id="content-intro-username">{}</span> uploaded a new revision.'
                ).format(actor.display_name)
                content_text = ''

            elif ContentType.Page == content.type:
                content_intro = l_(
                    '<span id="content-intro-username">{}</span> updated this page.'
                ).format(actor.display_name)
                previous_revision = content.get_previous_revision()
                title_diff = ''
                if previous_revision.label != content.label:
                    title_diff = htmldiff(previous_revision.label,
                                          content.label)
                content_text = str(l_('<p id="content-body-intro">Here is an overview of the changes:</p>'))+ \
                    title_diff + \
                    htmldiff(previous_revision.description, content.description)

            elif ContentType.Thread == content.type:
                content_intro = l_(
                    '<span id="content-intro-username">{}</span> updated the thread description.'
                ).format(actor.display_name)
                previous_revision = content.get_previous_revision()
                title_diff = ''
                if previous_revision.label != content.label:
                    title_diff = htmldiff(previous_revision.label,
                                          content.label)
                content_text = str(l_('<p id="content-body-intro">Here is an overview of the changes:</p>'))+ \
                    title_diff + \
                    htmldiff(previous_revision.description, content.description)

            # elif ContentType.Thread == content.type:
            #     content_intro = l_('<span id="content-intro-username">{}</span> updated this page.').format(actor.display_name)
            #     previous_revision = content.get_previous_revision()
            #     content_text = l_('<p id="content-body-intro">Here is an overview of the changes:</p>')+ \
            #         htmldiff(previous_revision.description, content.description)

        elif ActionDescription.EDITION == action:
            call_to_action_text = l_('View online')

            if ContentType.File == content.type:
                content_intro = l_(
                    '<span id="content-intro-username">{}</span> updated the file description.'
                ).format(actor.display_name)
                content_text = '<p id="content-body-intro">{}</p>'.format(content.get_label()) + \
                    content.description

        elif ActionDescription.STATUS_UPDATE == action:
            call_to_action_text = l_('View online')
            intro_user_msg = l_('<span id="content-intro-username">{}</span> '
                                'updated the following status:')
            content_intro = intro_user_msg.format(actor.display_name)
            intro_body_msg = '<p id="content-body-intro">{}: {}</p>'
            content_text = intro_body_msg.format(
                content.get_label(),
                content.get_status().label,
            )

        if '' == content_intro and content_text == '':
            # Skip notification, but it's not normal
            logger.error(
                self, 'A notification is being sent but no content. '
                'Here are some debug informations: [content_id: {cid}]'
                '[action: {act}][author: {actor}]'.format(
                    cid=content.content_id, act=action, actor=actor))
            raise ValueError('Unexpected empty notification')

        # Import done here because cyclic import
        from tracim.config.app_cfg import CFG
        body_content = template.render(
            base_url=self._global_config.WEBSITE_BASE_URL,
            _=l_,
            h=helpers,
            user_display_name=role.user.display_name,
            user_role_label=role.role_as_label(),
            workspace_label=role.workspace.label,
            content_intro=content_intro,
            content_text=content_text,
            main_title=main_title,
            call_to_action_text=call_to_action_text,
            result=DictLikeClass(item=dictified_item, actor=dictified_actor),
            CFG=CFG.get_instance(),
        )

        return body_content
Exemple #9
0
    def create_role(self) -> UserRoleInWorkspace:
        role = UserRoleInWorkspace()

        return role
Exemple #10
0
class RoleApi(object):

    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,
        ],
    }

    @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 __init__(self, current_user: User):
        self._user = current_user

    def create_role(self) -> UserRoleInWorkspace:
        role = UserRoleInWorkspace()

        return role

    def _get_one_rsc(self, user_id, workspace_id):
        """
        :param user_id:
        :param workspace_id:
        :return: a Query object, filtered query but without fetching the object.
        """
        return DBSession.query(UserRoleInWorkspace).\
            filter(UserRoleInWorkspace.workspace_id==workspace_id).\
            filter(UserRoleInWorkspace.user_id==user_id)

    def get_one(self, user_id, workspace_id):
        return self._get_one_rsc(user_id, workspace_id).one()

    def create_one(self,
                   user: User,
                   workspace: Workspace,
                   role_level: int,
                   with_notif: bool,
                   flush: bool = True) -> UserRoleInWorkspace:
        role = self.create_role()
        role.user_id = user.user_id
        role.workspace = workspace
        role.role = role_level
        if with_notif is not None:
            from tracim.lib.helpers import on_off_to_boolean
            role.do_notify = on_off_to_boolean(with_notif)
        if flush:
            DBSession.flush()
        return role

    def delete_one(self, user_id, workspace_id, flush=True):
        self._get_one_rsc(user_id, workspace_id).delete()
        if flush:
            DBSession.flush()

    def _get_all_for_user(self, user_id):
        return DBSession.query(UserRoleInWorkspace).filter(
            UserRoleInWorkspace.user_id == user_id)

    def get_all_for_user(self, user_id):
        return self._get_all_for_user(user_id).all()

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

    def get_all_for_workspace(self, workspace_id):
        return DBSession.query(UserRoleInWorkspace).filter(
            UserRoleInWorkspace.workspace_id == workspace_id).all()

    def save(self, role: UserRoleInWorkspace):
        DBSession.flush()

    def get_roles_for_select_field(self):
        """

        :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