Example #1
0
class Correlation(Debatable):
    """Correlation class"""
    name = renamer()
    source = SharedUniqueProperty('source', 'source_correlations')
    targets = SharedMultipleProperty('targets', 'target_correlations')
    context = SharedUniqueProperty('context', 'contextualized_correlations')
    author = SharedUniqueProperty('author')
    channels = CompositeMultipleProperty('channels', 'subject')
    comments = CompositeMultipleProperty('comments')

    def __init__(self, **kwargs):
        super(Correlation, self).__init__(**kwargs)
        self.set_data(kwargs)
        self.type = CorrelationType.weak
        self.tags = PersistentList()
        # self.addtoproperty('channels', Channel(title=_("General")))

    @property
    def ends(self):
        """Return the ends of the correlation"""
        result = list(self.targets)
        result.append(self.source)
        return result

    @property
    def channel(self):
        channels = getattr(self, 'channels', [])
        return channels[0] if channels else None

    @property
    def type_name(self):
        return CorrelationType.type_name(self.type)
Example #2
0
class Commentable(VisualisableElement, Entity):
    """ A Commentable entity is an entity that can be comment"""

    name = renamer()
    comments = CompositeMultipleProperty('comments')

    def __init__(self, **kwargs):
        super(Commentable, self).__init__(**kwargs)
        self.len_comments = 0

    def update_len_comments(self):
        result = len(self.comments)
        result += sum([c.update_len_comments() for c in self.comments])
        self.len_comments = result
        return self.len_comments

    def addtoproperty(self, name, value, moving=None):
        super(Commentable, self).addtoproperty(name, value, moving)
        if name == 'comments':
            channel = getattr(self, 'channel', self)
            channel.len_comments += 1
            if self is not channel:
                self.len_comments += 1

    def delfromproperty(self, name, value, moving=None):
        super(Commentable, self).delfromproperty(name, value, moving)
        if name == 'comments':
            channel = getattr(self, 'channel', self)
            channel.len_comments -= 1
            if self is not channel:
                self.len_comments -= 1
Example #3
0
class Object1(Object):
    composition_u = CompositeUniqueProperty('composition_u', 'shared2_u',
                                            False)
    composition_m = CompositeMultipleProperty('composition_m', 'shared21_u',
                                              False)
    shared_u = SharedUniqueProperty('shared_u', 'shared22_u', False)
    shared_m = SharedMultipleProperty('shared_m', 'shared23_u', False)
Example #4
0
class Debatable(VisualisableElement, Entity):
    """ A Debatable entity is an entity that can be comment"""

    channels = CompositeMultipleProperty('channels', 'subject')

    def __init__(self, **kwargs):
        super(Debatable, self).__init__(**kwargs)

    @property
    def channel(self):
        channels = getattr(self, 'channels', [])
        return channels[0] if channels else None

    def get_channel(self, user):
        return self.channel

    def get_title(self, user=None):
        return getattr(self, 'title', '')

    def subscribe_to_channel(self, user):
        channel = getattr(self, 'channel', None)
        if channel and (user not in channel.members):
            channel.addtoproperty('members', user)

    def add_new_channel(self):
        self.addtoproperty('channels', Channel())
Example #5
0
class EventObject(Entity):
    """EventObject class"""

    events = CompositeMultipleProperty('events', 'subject')

    def __init__(self, **kwargs):
        super(EventObject, self).__init__(**kwargs)
        self.set_data(kwargs)
Example #6
0
class BaseWorkItem(LockableElement, Object):

    actions = CompositeMultipleProperty('actions')
    context = None

    def __init__(self, node):
        LockableElement.__init__(self)
        Object.__init__(self)
        self.node = node
        self.is_valide = True

    def _init_actions(self):
        for action_context in self.node.definition.contexts:
            action = action_context(self)
            action.__name__ = action.behavior_id
            self.addtoproperty('actions', action)

    @property
    def process_id(self):
        return self.node.process.id

    @property
    def node_id(self):
        return self.node.id

    @property
    def process(self):
        return self.node.process

    def start(self):
        pass # pragma: no cover

    def add_action(self, action):
        action.workitem = self
        if getattr(action, '__parent__', None):
            action.__parent__.move(
                action.__name__, (self, 'actions'),
                newname=action.behavior_id)
        else:
            action.__name__ = action.behavior_id
            self.addtoproperty('actions', action)

    def set_actions(self, actions):
        self.setproperty('actions', [])
        for action in actions:
            self.add_action(action)
            if getattr(action, 'dont_lock', False):
                action.dont_lock = False
                action.call(action)

    def validate(self):
        raise NotImplementedError # pragma: no cover

    def concerned_nodes(self):
        return {self.node}
Example #7
0
class BallotBox(VisualisableElement, Entity):
    """Ballot box class"""
    name = renamer()
    votes = CompositeMultipleProperty('votes')

    def __init__(self, **kwargs):
        super(BallotBox, self).__init__(**kwargs)
        self.vote_len = 0

    def addtoproperty(self, name, value, moving=None):
        super(BallotBox, self).addtoproperty(name, value, moving)
        if name == 'votes':
            self.vote_len += 1
Example #8
0
class ProcessDefinitionContainer(Entity):

    definitions = CompositeMultipleProperty('definitions', None, False)

    def __init__(self, **kwargs):
        super(ProcessDefinitionContainer, self).__init__(**kwargs)

    def add_definition(self, definition):
        definition.__name__ = definition.id
        self.addtoproperty('definitions', definition)
        definition._init_definition()

    def get_definition(self, name):
        # Don't iterate on self.definitions property for performance reason.
        return self.get(name, None)
Example #9
0
class Workspace(VisualisableElement, Entity):
    """Working group class"""

    name = renamer()
    type_title = _('Resources')
    template = 'pontus:templates/visualisable_templates/object.pt'
    files = CompositeMultipleProperty('files')
    working_group = SharedUniqueProperty('working_group', 'workspace')

    def __init__(self, **kwargs):
        super(Workspace, self).__init__(**kwargs)
        self.set_data(kwargs)

    @property
    def proposal(self):
        return self.working_group.proposal
Example #10
0
class Preregistration(VisualisableElement, Entity):
    """Preregistration class"""
    icon = 'typcn typcn-user-add'
    templates = {
        'default': 'novaideo:views/templates/preregistration_result.pt',
        'bloc': 'novaideo:views/templates/preregistration_result.pt'
    }
    name = renamer()
    ballots = CompositeMultipleProperty('ballots')
    ballot_processes = SharedMultipleProperty('ballot_processes')
    organization = SharedUniqueProperty('organization')

    def __init__(self, **kwargs):
        super(Preregistration, self).__init__(**kwargs)
        initial_password = kwargs.pop('password', None)
        if initial_password:
            initial_password = User.pwd_manager.encode(initial_password)

        self.initial_password = initial_password
        self.set_data(kwargs)
        self.title = self.first_name + ' ' + \
                     self.last_name

    def init_deadline(self, date):
        self.deadline_date = date\
            + datetime.timedelta(seconds=DEADLINE_PREREGISTRATION)
        return self.deadline_date

    def get_deadline_date(self):
        if getattr(self, 'deadline_date', None) is not None:
            return self.deadline_date

        self.deadline_date = self.created_at\
            + datetime.timedelta(seconds=DEADLINE_PREREGISTRATION)
        return self.deadline_date

    def has_trusted_email(self, trusted_emails):
        email = getattr(self, 'email', None)
        if email and trusted_emails:
            return any(email.find(t) >= 0 for t in trusted_emails)

        return True

    @property
    def is_expired(self):
        return datetime.datetime.now(tz=pytz.UTC) > self.get_deadline_date()
Example #11
0
class ProcessDefinitionContainer(Entity):

    definitions = CompositeMultipleProperty('definitions', None, False)

    def __init__(self, **kwargs):
        super(ProcessDefinitionContainer, self).__init__(**kwargs)

    def add_definition(self, definition):
        definition.__name__ = definition.id
        self.addtoproperty('definitions', definition)
        definition._init_definition()

    def get_definition(self, name):
        for definition in self.definitions:
            if definition.id == name:
                return definition

        return None
Example #12
0
class FlowNode(BPMNElement):

    incoming = SharedMultipleProperty('incoming', 'target', False)
    outgoing = SharedMultipleProperty('outgoing', 'source', False)
    workitems = CompositeMultipleProperty('workitems', None, False)
    process = SharedUniqueProperty('process', 'nodes', False)

    def __init__(self, definition, **kwargs):
        super(FlowNode,self).__init__( definition, **kwargs)

    def prepare(self):
        registry = get_current_registry()
        registry.notify(ActivityPrepared(self))

    def __call__(self, transaction):
        self.start(transaction)

    def find_executable_paths(self, source_path, source):
        pass# pragma: no cover

    def start(self, transaction):
        raise NotImplementedError# pragma: no cover

    def play(self, transitions):
        registry = get_current_registry()
        registry.notify(ActivityFinished(self))
        self.process.play_transitions(self, transitions)

    def replay_path(self, decision, transaction):
        pass# pragma: no cover

    def stop(self):
        pass# pragma: no cover

    @property
    def definition(self):
        return self.process.definition[self.__name__]

    def __repr__(self):# pragma: no cover
        return "%s(%r)" % (
            self.__class__.__name__,
            self.id
            )
Example #13
0
class SignalableEntity(Entity):

    reports = CompositeMultipleProperty('reports')
    censoring_reason = CompositeUniqueProperty('censoring_reason')

    def __init__(self, **kwargs):
        super(SignalableEntity, self).__init__(**kwargs)
        self.len_reports = 0
        self.init_len_current_reports()

    @property
    def subject(self):
        return self.__parent__

    def init_len_current_reports(self):
        self.len_current_reports = 0

    def addtoproperty(self, name, value, moving=None):
        super(SignalableEntity, self).addtoproperty(name, value, moving)
        if name == 'reports':
            self.len_current_reports = getattr(self, 'len_current_reports', 0)
            self.len_reports = getattr(self, 'len_reports', 0)
            self.len_current_reports += 1
            self.len_reports += 1

    def get_decision_ballot(self):
        ballots = [
            b for b in self.ballots
            if b.group_id == 'vote_moderation' and b.is_finished
        ]
        # return only the last ballot
        ballots = sorted(
            ballots, key=lambda e: getattr(e, 'release_date', e.modified_at))
        if ballots:
            return ballots[-1]

        return None
Example #14
0
class SignalableEntity(Entity):

    reports = CompositeMultipleProperty('reports')
    censoring_reason = CompositeUniqueProperty('censoring_reason')

    def __init__(self, **kwargs):
        super(SignalableEntity, self).__init__(**kwargs)
        self.len_reports = 0
        self.init_len_current_reports()

    @property
    def subject(self):
        return self.__parent__

    def init_len_current_reports(self):
        self.len_current_reports = 0

    def addtoproperty(self, name, value, moving=None):
        super(SignalableEntity, self).addtoproperty(name, value, moving)
        if name == 'reports':
            self.len_current_reports = getattr(self, 'len_current_reports', 0)
            self.len_reports = getattr(self, 'len_reports', 0)
            self.len_current_reports += 1
            self.len_reports += 1
Example #15
0
class Runtime(Entity):

    processes = CompositeMultipleProperty('processes', None, False)

    def getprocesses(self):
        return self.processes
Example #16
0
class ObjectA(Entity):
    composition_mu = CompositeMultipleProperty('composition_mu', None, False)
Example #17
0
class Idea(VersionableEntity, DuplicableEntity,
           SearchableEntity, CorrelableEntity, PresentableEntity,
           ExaminableEntity, Node, Emojiable, SignalableEntity, Debatable,
           Tokenable, EventObject):
    """Idea class"""

    type_title = _('Idea')
    icon = 'icon novaideo-icon icon-idea'
    templates = {'default': 'novaideo:views/templates/idea_result.pt',
                 'bloc': 'novaideo:views/templates/idea_bloc.pt',
                 'small': 'novaideo:views/templates/small_idea_result.pt',
                 'popover': 'novaideo:views/templates/idea_popover.pt'}
    template = 'novaideo:views/templates/idea_list_element.pt'
    name = renamer()
    author = SharedUniqueProperty('author', 'ideas')
    organization = SharedUniqueProperty('organization')
    attached_files = CompositeMultipleProperty('attached_files')
    url_files = CompositeMultipleProperty('url_files')
    challenge = SharedUniqueProperty('challenge', 'ideas')
    ballots = CompositeMultipleProperty('ballots')
    ballot_processes = SharedMultipleProperty('ballot_processes')
    opinions_base = OPINIONS

    def __init__(self, **kwargs):
        super(Idea, self).__init__(**kwargs)
        self.set_data(kwargs)
        self.addtoproperty('channels', Channel())
        self.urls = PersistentDict({})

    @property
    def is_workable(self):
        request = get_current_request()
        idea_to_examine = 'idea' in request.content_to_examine
        if idea_to_examine:
            return True if 'favorable' in self.state else False

        return True

    @property
    def related_proposals(self):
        """Return all proposals that uses this idea"""
        return [proposal[0] for proposal in self.get_related_contents(
            CorrelationType.solid, ['related_proposals'])]

    @property
    def related_contents(self):
        """Return all related contents"""
        return [content[0] for content in self.all_related_contents]

    @property
    def transformed_from(self):
        """Return all related contents"""
        transformed_from = [correlation[1].context for correlation
                            in self.get_related_contents(
                                CorrelationType.solid, ['transformation'])
                            if correlation[1].context]
        return transformed_from[0] if transformed_from else None

    @property
    def authors(self):
        return [self.author]

    @property
    def relevant_data(self):
        return [getattr(self, 'title', ''),
                getattr(self, 'text', ''),
                ', '.join(self.branches)]

    def __setattr__(self, name, value):
        super(Idea, self).__setattr__(name, value)
        if name == 'author':
            self.init_organization()

    def init_organization(self):
        if not self.organization:
            organization = getattr(self.author, 'organization', None)
            if organization:
                self.setproperty('organization', organization)

    def init_published_at(self):
        setattr(self, 'published_at', datetime.datetime.now(tz=pytz.UTC))

    def init_examined_at(self):
        setattr(self, 'examined_at', datetime.datetime.now(tz=pytz.UTC))

    def presentation_text(self, nb_characters=400):
        return truncate_text(getattr(self, 'text', ""), nb_characters)

    def get_more_contents_criteria(self):
        "return specific query, filter values"
        return None, {
            'metadata_filter': {
                'content_types': ['proposal', 'idea']
            },
            'keywords': list(self.branches)
        }

    def get_attached_files_data(self):
        return get_files_data(self.attached_files)

    def get_node_descriminator(self):
        return 'idea'

    def format(self, request):
        text = getattr(self, 'text', '')
        all_urls, url_files, text_urls, formatted_text = text_urls_format(
            text, request)
        self.urls = PersistentDict(all_urls)
        self.setproperty('url_files', url_files)
        self.formatted_text = formatted_text
        self.formatted_urls = text_urls
Example #18
0
class Comment(Commentable, CorrelableEntity, Emojiable, SignalableEntity):
    """Comment class"""
    icon = 'icon ion-chatbubbles'
    templates = {'default': 'novaideo:views/templates/comment_result.pt'}
    name = renamer()
    author = SharedUniqueProperty('author')
    files = CompositeMultipleProperty('files')
    url_files = CompositeMultipleProperty('url_files')
    related_correlation = SharedUniqueProperty('related_correlation',
                                               'targets')
    contextualized_correlations = SharedMultipleProperty(
        'contextualized_correlations', 'context')

    def __init__(self, **kwargs):
        super(Comment, self).__init__(**kwargs)
        self.set_data(kwargs)
        self.urls = PersistentDict({})
        self.edited = False
        self.pinned = False

    @property
    def channel(self):
        """Return the channel of th commented entity"""

        if not isinstance(self.__parent__, Comment):
            return self.__parent__
        else:
            return self.__parent__.channel

    @property
    def root(self):
        """Return the root comment"""

        if not isinstance(self.__parent__, Comment):
            return self
        else:
            return self.__parent__.root

    @property
    def comment_parent(self):
        """Return the root comment"""

        if isinstance(self.__parent__, Comment):
            return self.__parent__
        else:
            return None

    @property
    def subject(self):
        """Return the commented entity"""
        return self.channel.get_subject()

    @property
    def challenge(self):
        return getattr(self.subject, 'challenge', None)

    @property
    def relevant_data(self):
        return [
            getattr(self, 'comment', ''),
            getattr(self.author, 'title', getattr(self.author, '__name__', ''))
        ]

    @property
    def related_contents(self):
        subject = self.subject
        return [
            content[0] for content in self.contextualized_contents
            if content[0] is not subject
        ]

    @property
    def associated_contents(self):
        subject = self.subject
        return [
            content[0] for content in self.contextualized_contents if
            content[0] is not subject and not getattr(content[1], 'tags', [])
        ]

    def set_associated_contents(self, associated_contents, user):
        subject = self.subject
        current_associated_contents = self.associated_contents
        associated_contents_to_add = [
            i for i in associated_contents
            if i not in current_associated_contents
        ]
        associated_contents_to_del = [
            i for i in current_associated_contents
            if i not in associated_contents
            and i not in associated_contents_to_add
        ]
        correlations = connect(
            subject,
            associated_contents_to_add,
            {
                'comment': _('Add related contents'),
                'type': _('Edit the comment')
            },
            author=user,
        )
        for correlation in correlations:
            correlation.setproperty('context', self)

        disconnect(subject, associated_contents_to_del)

    def get_title(self):
        return self.subject.title

    def presentation_text(self, nb_characters=400):
        return getattr(self, 'comment', "")[:nb_characters] + '...'

    def get_discuss_url(self, request, user):
        subject = self.channel.get_subject(user)
        return request.resource_url(subject, "@@index") + '#comment-' + str(
            get_oid(self, 'None'))

    def get_url(self, request):
        return request.resource_url(request.root,
                                    "@@seecomment",
                                    query={'comment_id': get_oid(self)})

    def get_related_contents(self, user):
        return [r for r in self.related_contents if can_access(user, r)]

    def format(self, request, is_html=False):
        comment = getattr(self, 'comment', '')
        all_urls, url_files, text_urls, formatted_text = text_urls_format(
            comment, request, is_html)
        self.urls = PersistentDict(all_urls)
        self.setproperty('url_files', url_files)
        self.formatted_comment = formatted_text
        self.formatted_urls = text_urls

    def get_attached_files_data(self):
        return get_files_data(self.files)

    def can_add_reaction(self, user, process):
        return True
Example #19
0
class Process(Entity):

    nodes = CompositeMultipleProperty('nodes', 'process', True)
    transitions = CompositeMultipleProperty('transitions', 'process', True)
    execution_context = CompositeUniqueProperty('execution_context', 'process',
                                                True)

    _started = False
    _finished = False
    # if attached to a subprocess
    attachedTo = None

    def __init__(self, definition, startTransition, **kwargs):
        super(Process, self).__init__(**kwargs)
        self.id = definition.id
        self.global_transaction = Transaction()
        self.startTransition = startTransition
        if not self.title:
            self.title = definition.title

        if not self.description:
            self.description = definition.description

        execution_context = ExecutionContext()
        execution_context.__name__ = 'execution_context'
        self.setproperty('execution_context', execution_context)
        # do a commit so all events have a _p_oid
        # mail delivery doesn't support savepoint
        try:
            transaction.commit()
        except Exception:
            transaction.abort()

    def defineGraph(self, definition):
        for nodedef in definition.nodes:
            node = nodedef.create()
            node.id = nodedef.id
            node.__name__ = nodedef.__name__
            self.addtoproperty('nodes', node)
            if isinstance(nodedef, EventHandlerDefinition):
                node._init_boundaryEvents(nodedef)

        for transitiondef in definition.transitions:
            transition = transitiondef.create()
            transition.__name__ = transitiondef.__name__
            self.addtoproperty('transitions', transition)
            transition._init_ends(self, transitiondef)

    def definition(self):
        def_container = find_service('process_definition_container')
        pd = None
        if def_container is not None:
            pd = def_container.get_definition(self.id)

        return pd

    definition = property(definition)

    @property
    def discriminator(self):
        return self.definition.discriminator

    @property
    def isSubProcess(self):
        return self.definition.isSubProcess

    def replay_path(self, decision, transaction):
        path = decision.path
        first_transitions = decision.first_transitions
        self.replay_transitions(decision, first_transitions, transaction)
        executed_transitions = first_transitions
        next_transitions = set()
        for transition in first_transitions:
            next_transitions = next_transitions.union(
                set(path.next(transition)))

        for next_transition in set(next_transitions):
            if next_transition in executed_transitions:
                next_transitions.remove(next_transition)

        while next_transitions:
            self.replay_transitions(decision, next_transitions, transaction)
            executed_transitions.extend(next_transitions)
            next_ts = set()
            for next_transition in next_transitions:
                next_ts = next_ts.union(set(path.next(next_transition)))

            for next_transition in list(next_ts):
                if next_transition in executed_transitions:
                    next_ts.remove(next_transition)

            next_transitions = next_ts

    def replay_transitions(self, decision, transitions, transaction):
        executed_nodes = []
        for transition in transitions:
            node = transition.source
            if not (node in executed_nodes):
                executed_nodes.append(node)
                node.replay_path(decision, transaction)

    def getWorkItems(self):
        dace_catalog = find_catalog('dace')
        process_inst_uid_index = dace_catalog['process_inst_uid']
        object_provides_index = dace_catalog['object_provides']
        p_uid = get_oid(self, None)
        query = object_provides_index.any((IWorkItem.__identifier__,)) & \
                process_inst_uid_index.any((int(p_uid),))
        workitems = query.execute().all()
        result = {}
        self.result_multiple = {}  # for tests
        for wi in workitems:
            if isinstance(wi.node, SubProcess) and wi.node.sub_processes:
                for sub_process in wi.node.sub_processes:
                    result.update(sub_process.getWorkItems())

            if wi.node.id in result:
                self.result_multiple[wi.node.id].append(wi)
            else:
                result[wi.node.id] = wi
                self.result_multiple[wi.node.id] = [wi]

        return result

    def getAllWorkItems(self, node_id=None):
        dace_catalog = find_catalog('dace')
        process_inst_uid_index = dace_catalog['process_inst_uid']
        object_provides_index = dace_catalog['object_provides']
        p_uid = get_oid(self, None)
        query = object_provides_index.any((IWorkItem.__identifier__,)) & \
                process_inst_uid_index.any((int(p_uid),))
        if node_id is not None:
            node_id_index = dace_catalog['node_id']
            query = query & node_id_index.eq(self.id + '.' + node_id)

        workitems = query.execute().all()
        result = []
        for wi in workitems:
            if wi is None:
                log.error(
                    'getAllWorkItems: one of the wi is None for process %s',
                    p_uid)
                continue

            if isinstance(wi.node, SubProcess) and wi.node.sub_processes:
                for sub_process in wi.node.sub_processes:
                    result.extend(sub_process.getAllWorkItems())

            if not (wi in result):
                result.append(wi)

        return result

    def start(self):
        if self._started:
            raise TypeError("Already started")

        self._started = True
        setattr(self.definition, '_isIntanciated_', True)
        registry = get_current_registry()
        registry.notify(ProcessStarted(self))

    def execute(self):
        start_events = [self[s.__name__] for s in \
                        self.definition._get_start_events()]
        for start_event in start_events:
            start_event.prepare()
            start_event.prepare_for_execution()
            if self._started:
                break

    def play_transitions(self, node, transitions):
        registry = get_current_registry()
        if transitions:
            for transition in transitions:
                next_node = transition.target
                registry.notify(transition)
                next_node.prepare()
                if isinstance(next_node, Event):
                    next_node.prepare_for_execution()

            for transition in transitions:
                next_node = transition.target
                starttransaction = self.global_transaction.start_subtransaction(
                    'Start',
                    transitions=(transition, ),
                    initiator=transition.source)
                next_node(starttransaction)
                if self._finished:
                    break

    def execute_action(self,
                       context,
                       request,
                       action_id,
                       appstruct,
                       ignor_validation=True):
        try:
            workitems = self.getWorkItems()
            workitem = workitems[self.id + '.' + action_id]
            action = workitem.actions[0]
            if not ignor_validation:
                action.validate(context, request)

            action.before_execution(context, request)
            action.execute(context, request, appstruct)
            return True
        except Exception:
            return False

    def get_actions(self, action_id):
        try:
            workitems = self.getWorkItems()
            workitem = workitems[self.id + '.' + action_id]
            return workitem.actions
        except Exception:
            return []

    def reindex(self):
        event = ObjectModified(self)
        registry = get_current_registry()
        registry.subscribers((event, self), None)
        wis = [n.workitems for n in self.nodes]
        wis = [item for sublist in wis for item in sublist]
        actions = [w.actions for w in wis]
        actions = [item for sublist in actions for item in sublist]
        for action in actions:
            action.reindex()

    def __repr__(self):  # pragma: no cover
        return "Process(%r)" % self.definition.id
Example #20
0
class Challenge(SearchableEntity, CorrelableEntity, PresentableEntity,
                ExaminableEntity, Node, Emojiable, SignalableEntity,
                Debatable):
    """Challenge class"""
    type_title = _('Challenge')
    icon = 'ion-trophy'
    templates = {
        'default': 'novaideo:views/templates/challenge_result.pt',
        'bloc': 'novaideo:views/templates/challenge_card.pt',
        'small': 'novaideo:views/templates/small_challenge_result.pt',
        'popover': 'novaideo:views/templates/challenge_popover.pt',
        'card': 'novaideo:views/templates/challenge_card.pt'
    }
    name = renamer()
    author = SharedUniqueProperty('author', 'challenges')
    image = CompositeUniqueProperty('image')
    proposals = SharedMultipleProperty('proposals', 'challenge')
    ideas = SharedMultipleProperty('ideas', 'challenge')
    questions = SharedMultipleProperty('questions', 'challenge')
    attached_files = CompositeMultipleProperty('attached_files')
    invited_users = SharedMultipleProperty('invited_users')
    url_files = CompositeMultipleProperty('url_files')

    def __init__(self, **kwargs):
        super(Challenge, self).__init__(**kwargs)
        self.set_data(kwargs)
        self.addtoproperty('channels', Channel())
        self.urls = PersistentDict({})

    def __setattr__(self, name, value):
        super(Challenge, self).__setattr__(name, value)
        if name in ('deadline', 'published_at', 'created_at') and value:
            self.init_total_days()

    @property
    def related_contents(self):
        return [content[0] for content in self.all_related_contents]

    @property
    def challenge(self):
        return self

    @property
    def transformed_from(self):
        """Return all related contents"""
        transformed_from = [
            correlation[1].context
            for correlation in self.get_related_contents(
                CorrelationType.solid, ['transformation'])
            if correlation[1].context
        ]
        return transformed_from[0] if transformed_from else None

    @property
    def is_expired(self):
        if 'closed' in self.state:
            return True

        deadline = getattr(self, 'deadline', None)
        if deadline is not None:
            now = datetime.datetime.now(tz=pytz.UTC)
            return now.date() >= deadline

        return False

    @property
    def can_add_content(self):
        return not self.is_expired and 'pending' in self.state

    @property
    def remaining_duration(self):
        deadline = getattr(self, 'deadline', None)
        duration = getattr(self, 'duration', None)
        if deadline is not None and duration is not None:
            now = datetime.datetime.now(tz=pytz.UTC)
            remaining = (deadline - now.date()).days
            return remaining if remaining >= 0 else 0

        return None

    def init_published_at(self):
        setattr(self, 'published_at', datetime.datetime.now(tz=pytz.UTC))

    def init_support_history(self):
        if not hasattr(self, '_support_history'):
            setattr(self, '_support_history', PersistentList())

    def init_total_days(self):
        deadline = getattr(self, 'deadline', None)
        date = getattr(self, 'published_at', None)
        date = date if date else getattr(self, 'created_at', None)
        if deadline is not None and date is not None:
            duration = (deadline - date.date()).days
            setattr(self, 'duration', duration)

    def is_managed(self, root):
        return root.manage_challenges

    def get_attached_files_data(self):
        return get_files_data(self.attached_files)

    def get_all_attached_files_data(self):
        files = list(self.attached_files)
        files.append(self.image)
        return get_files_data(files)

    def get_node_descriminator(self):
        return 'challenge'

    def format(self, request):
        text = getattr(self, 'text', '')
        all_urls, url_files, text_urls, formatted_text = text_urls_format(
            text, request, True)
        self.urls = PersistentDict(all_urls)
        self.setproperty('url_files', url_files)
        self.formatted_text = formatted_text
        self.formatted_urls = text_urls
Example #21
0
class WorkingGroup(VisualisableElement, Entity):
    """Working group class"""

    name = renamer()
    template = 'pontus:templates/visualisable_templates/object.pt'
    proposal = SharedUniqueProperty('proposal', 'working_group')
    members = SharedMultipleProperty('members', 'working_groups')
    wating_list = SharedMultipleProperty('wating_list')
    ballots = CompositeMultipleProperty('ballots')
    improvement_cycle_proc = SharedUniqueProperty('improvement_cycle_proc')
    workspace = CompositeUniqueProperty('workspace', 'working_group')

    def init_workspace(self):
        self.addtoproperty('workspace', Workspace(title="Workspace"))

    @property
    def work_mode(self):
        mode_id = getattr(self, 'work_mode_id', None)
        if mode_id:
            return WORK_MODES.get(mode_id, None)

        root = self.__parent__
        if hasattr(root, 'get_work_modes') and len(root.get_work_modes()) == 1:
            return root.get_default_work_mode()

        return None

    @property
    def challenge(self):
        return getattr(self.proposal, 'challenge', None)

    def get_state(self, request, user):
        return get_states_mapping(user, self,
                                  getattr(self, 'state_or_none', [None])[0])

    def empty(self, remove_author=True):
        author = self.proposal.author
        self.state = PersistentList(['deactivated'])
        self.setproperty('wating_list', [])
        if hasattr(self, 'first_improvement_cycle'):
            del self.first_improvement_cycle

        if hasattr(self, 'first_vote'):
            del self.first_vote

        members = self.members
        if remove_author and author in members:
            members.remove(author)

        for member in members:
            self.delfromproperty('members', member)
            revoke_roles(member, (('Participant', self.proposal), ))

        self.init_nonproductive_cycle()

    def inc_iteration(self):
        self.iteration = getattr(self, 'iteration', 0) + 1

    def init_nonproductive_cycle(self):
        self.nonproductive_cycle = 0

    def inc_nonproductive_cycle(self):
        self.nonproductive_cycle = getattr(self, 'nonproductive_cycle', 0) + 1

    def is_member(self, user):
        mask = getattr(user, 'mask', None)
        return user in self.members or (mask and mask in self.members)

    def in_wating_list(self, user):
        mask = getattr(user, 'mask', None)
        return user in self.wating_list or (mask and mask in self.wating_list)

    def get_member(self, user):
        if not self.is_member(user):
            return None

        if user in self.members:
            return user

        mask = getattr(user, 'mask', None)
        if mask and mask in self.members:
            return mask

        return None

    def get_member_in_wating_list(self, user):
        if not self.in_wating_list(user):
            return None

        if user in self.wating_list:
            return user

        mask = getattr(user, 'mask', None)
        if mask and mask in self.wating_list:
            return mask

        return None
Example #22
0
class Person(User, SearchableEntity, CorrelableEntity, Debatable):
    """Person class"""

    type_title = _('Person')
    icon = 'icon glyphicon glyphicon-user'  #'icon novaideo-icon icon-user'
    templates = {
        'default': 'novaideo:views/templates/person_result.pt',
        'bloc': 'novaideo:views/templates/person_bloc.pt',
        'small': 'novaideo:views/templates/small_person_result.pt',
        'popover': 'novaideo:views/templates/person_popover.pt',
        'card': 'novaideo:views/templates/person_card.pt',
        'header': 'novaideo:views/templates/person_header.pt',
    }
    default_picture = 'novaideo:static/images/user100.png'
    name = renamer()
    tokens = CompositeMultipleProperty('tokens')
    tokens_ref = SharedMultipleProperty('tokens_ref')
    organization = SharedUniqueProperty('organization', 'members')
    events = SharedMultipleProperty('events', 'author')
    picture = CompositeUniqueProperty('picture')
    cover_picture = CompositeUniqueProperty('cover_picture')
    ideas = SharedMultipleProperty('ideas', 'author')
    selections = SharedMultipleProperty('selections')
    working_groups = SharedMultipleProperty('working_groups', 'members')
    wg_participations = SharedMultipleProperty('wg_participations',
                                               'wating_list_participation')
    old_alerts = SharedMultipleProperty('old_alerts')
    following_channels = SharedMultipleProperty('following_channels',
                                                'members')
    folders = SharedMultipleProperty('folders', 'author')
    questions = SharedMultipleProperty('questions', 'author')
    challenges = SharedMultipleProperty('challenges', 'author')
    ballots = CompositeMultipleProperty('ballots')
    mask = SharedUniqueProperty('mask', 'member')

    def __init__(self, **kwargs):
        self.branches = PersistentList()
        self.keywords = PersistentList()
        super(Person, self).__init__(**kwargs)
        kwargs.pop('password', None)
        self.set_data(kwargs)
        self.set_title()
        self.last_connection = datetime.datetime.now(tz=pytz.UTC)
        self._read_at = OOBTree()
        self.guide_tour_data = PersistentDict({})
        self.confidence_index = 0
        self._notes = OOBTree()
        self.allocated_tokens = OOBTree()
        self.len_allocated_tokens = PersistentDict({})
        self.reserved_tokens = PersistentList([])
        self._submited_at = OOBTree()
        self._reported_at = OOBTree()

    def __setattr__(self, name, value):
        super(Person, self).__setattr__(name, value)
        if name == 'organization' and value:
            self.init_contents_organizations()

    def get_len_tokens(self, root=None, exclude_reserved_tokens=False):
        root = root or getSite()
        return root.tokens_mini if exclude_reserved_tokens \
            else root.tokens_mini + len(self.reserved_tokens)

    def get_len_evaluations(self, exclude_reserved_tokens=False):
        total = self.len_allocated_tokens.get(Evaluations.support, 0) + \
            self.len_allocated_tokens.get(Evaluations.oppose, 0)
        if exclude_reserved_tokens:
            return total - len([
                o for o in self.reserved_tokens if o in self.allocated_tokens
            ])
        return total

    def get_len_free_tokens(self, root=None, exclude_reserved_tokens=False):
        root = root or getSite()
        return self.get_len_tokens(root, exclude_reserved_tokens) - \
            self.get_len_evaluations(exclude_reserved_tokens)

    def has_token(self, obj=None, root=None):
        root = root or getSite()
        obj_oid = get_oid(obj, None)
        if obj_oid and obj_oid in self.reserved_tokens:
            return obj_oid not in self.allocated_tokens

        return self.get_len_free_tokens(root, True) > 0

    def add_token(self, obj, evaluation_type, root=None):
        if self.has_token(obj, root):
            self.allocated_tokens[get_oid(obj)] = evaluation_type
            self.len_allocated_tokens.setdefault(evaluation_type, 0)
            self.len_allocated_tokens[evaluation_type] += 1

    def remove_token(self, obj):
        obj_oid = get_oid(obj)
        if obj_oid in self.allocated_tokens:
            evaluation_type = self.allocated_tokens.pop(obj_oid)
            self.len_allocated_tokens.setdefault(evaluation_type, 0)
            self.len_allocated_tokens[evaluation_type] -= 1

    def add_reserved_token(self, obj):
        obj_oid = get_oid(obj)
        if obj_oid not in self.reserved_tokens:
            self.reserved_tokens.append(obj_oid)

    def remove_reserved_token(self, obj):
        obj_oid = get_oid(obj)
        if obj_oid in self.reserved_tokens:
            self.reserved_tokens.remove(obj_oid)

    def evaluated_objs(self, evaluation_type=None):
        if evaluation_type:
            return [
                get_obj(key) for value, key in self.allocated_tokens.byValue(
                    evaluation_type)
            ]

        return [get_obj(key) for key in self.allocated_tokens.keys()]

    def evaluated_objs_ids(self, evaluation_type=None):
        if evaluation_type:
            return [
                key for value, key in self.allocated_tokens.byValue(
                    evaluation_type)
            ]

        return list(self.allocated_tokens.keys())

    def init_contents_organizations(self):
        novaideo_catalog = find_catalog('novaideo')
        dace_catalog = find_catalog('dace')
        organizations_index = novaideo_catalog['organizations']
        object_authors_index = novaideo_catalog['object_authors']
        object_provides_index = dace_catalog['object_provides']
        query = object_authors_index.any([get_oid(self)]) & \
            object_provides_index.any(
                [Iidea.__identifier__, IProposal.__identifier__]) & \
            organizations_index.any([0])

        for entity in query.execute().all():
            entity.init_organization()
            entity.reindex()

    def set_read_date(self, channel, date):
        self._read_at[get_oid(channel)] = date

    def get_read_date(self, channel):
        return self._read_at.get(get_oid(channel),
                                 datetime.datetime.now(tz=pytz.UTC))

    def get_channel(self, user):
        all_channels = list(self.channels)
        all_channels.extend(list(getattr(user, 'channels', [])))
        for channel in all_channels:
            if user in channel.members and self in channel.members:
                return channel

        return None

    def addtoproperty(self, name, value, moving=None):
        super(Person, self).addtoproperty(name, value, moving)
        if name == 'selections':
            value.len_selections = getattr(value, 'len_selections', 0)
            value.len_selections += 1

    def delfromproperty(self, name, value, moving=None):
        super(Person, self).delfromproperty(name, value, moving)
        if name == 'selections':
            value.len_selections = getattr(value, 'len_selections', 0)
            if value.len_selections > 0:
                value.len_selections -= 1

    def set_title(self):
        if getattr(self, 'pseudonym', ''):
            self.title = self.pseudonym
        else:
            self.title = getattr(self, 'first_name', '') + ' ' + \
                getattr(self, 'last_name', '')

    def add_note(self, user, context, note, date, time_constant):
        self._notes[date] = (get_oid(user), get_oid(context), note)
        self.calculate_confidence_index(time_constant)

    def get_questions(self, user):
        if user is self:
            return self.questions + getattr(self.mask, 'questions', [])

        return self.questions

    def get_ideas(self, user):
        if user is self:
            return self.ideas + getattr(self.mask, 'ideas', [])

        return self.ideas

    def get_working_groups(self, user):
        if user is self:
            return self.working_groups + getattr(self.mask, 'working_groups',
                                                 [])

        return self.working_groups

    @property
    def proposals(self):
        return [wg.proposal for wg in self.working_groups]

    def get_proposals(self, user):
        if user is self:
            return self.proposals + getattr(self.mask, 'proposals', [])

        return self.proposals

    @property
    def contacts(self):
        return [s for s in self.selections if isinstance(s, Person)]

    @property
    def participations(self):
        result = [
            p for p in list(self.proposals) if any(s in p.state for s in [
                'amendable', 'open to a working group', 'votes for publishing',
                'votes for amendments'
            ])
        ]
        return result

    def get_participations(self, user):
        if user is self:
            return self.participations + getattr(self.mask, 'participations',
                                                 [])

        return self.participations

    @property
    def contents(self):
        result = [i for i in list(self.ideas) if i is i.current_version]
        result.extend(self.proposals)
        result.extend(self.questions)
        result.extend(self.challenges)
        result.extend(self.events)
        return result

    def get_contents(self, user):
        if user is self:
            return self.contents + getattr(self.mask, 'contents', [])

        return self.contents

    @property
    def active_working_groups(self):
        return [p.working_group for p in self.participations]

    def get_active_working_groups(self, user):
        if user is self:
            return self.active_working_groups + getattr(
                self.mask, 'active_working_groups', [])

        return self.active_working_groups

    def get_wg_participations(self, user):
        if user is self:
            return self.wg_participations + getattr(self.mask,
                                                    'wg_participations', [])

        return self.wg_participations

    @property
    def is_published(self):
        return 'active' in self.state

    @property
    def managed_organization(self):
        return get_objects_with_role(user=self, role='OrganizationResponsible')

    def get_confidence_index(self):
        return getattr(self, 'confidence_index', 0)

    def reindex(self):
        super(Person, self).reindex()
        root = getSite()
        self.__access_keys__ = PersistentList(generate_access_keys(self, root))

    def get_picture_url(self, kind, default):
        if self.picture:
            img = getattr(self.picture, kind, None)
            if img:
                return img.url

        return default

    def get_more_contents_criteria(self):
        "return specific query, filter values"
        return None, None

    def set_organization(self, organization):
        current_organization = self.organization
        if organization:
            if current_organization is not organization:
                is_manager = current_organization and has_role(
                    ('OrganizationResponsible', current_organization),
                    self,
                    ignore_superiors=True)
                if current_organization and is_manager:
                    revoke_roles(
                        self,
                        (('OrganizationResponsible', current_organization), ))

                self.setproperty('organization', organization)
        elif current_organization:
            is_manager = has_role(
                ('OrganizationResponsible', current_organization),
                self,
                ignore_superiors=True)
            if is_manager:
                revoke_roles(
                    self,
                    (('OrganizationResponsible', current_organization), ))

            self.delfromproperty('organization', current_organization)

    @property
    def all_alerts(self):
        novaideo_catalog = find_catalog('novaideo')
        dace_catalog = find_catalog('dace')
        alert_keys_index = novaideo_catalog['alert_keys']
        alert_exclude_keys_index = novaideo_catalog['alert_exclude_keys']
        object_provides_index = dace_catalog['object_provides']
        exclude = [str(get_oid(self))]
        if self.mask:
            exclude.append(str(get_oid(self.mask)))

        query = object_provides_index.any([IAlert.__identifier__]) & \
            alert_keys_index.any(self.get_alerts_keys()) & \
            alert_exclude_keys_index.notany(exclude)
        return query.execute()

    @property
    def alerts(self):
        old_alerts = [get_oid(a) for a in self.old_alerts]
        result = self.all_alerts

        def exclude(result_set, docids):
            filtered_ids = list(result_set.ids)
            for _id in docids:
                if _id in docids and _id in filtered_ids:
                    filtered_ids.remove(_id)

            return result_set.__class__(filtered_ids, len(filtered_ids),
                                        result_set.resolver)

        return exclude(result, old_alerts)

    def get_alerts_keys(self):
        result = ['all', str(get_oid(self))]
        if self.mask:
            result.append(str(get_oid(self.mask)))

        return result

    def get_alerts(self, alerts=None, kind=None, subject=None, **kwargs):
        if alerts is None:
            alerts = self.alerts

        if kind:
            alerts = [a for a in alerts if a.is_kind_of(kind)]

        if subject:
            alerts = [a for a in alerts if subject in a.subjects]

        if kwargs:
            alerts = [a for a in alerts if a.has_args(**kwargs)]

        return alerts

    def calculate_confidence_index(self, time_constant):
        now = datetime.datetime.utcnow().timestamp()
        notes = np.array([v[2] for v in self._notes.values()])
        dates = np.array([int(t.timestamp()) for t in self._notes.keys()])
        time_c = time_constant * 86400
        confidence_index = np.sum(
            np.dot(notes, np.exp(-np.log(2) * (now - dates) / time_c)))
        self.confidence_index = round(confidence_index, 1)

    @property
    def user_groups(self):
        groups = list(self.groups)
        if self.organization:
            groups.append(self.organization)

        if self.mask:
            groups.append(self.mask)

        return groups

    @property
    def user_locale(self):
        locale = getattr(self, 'locale', None)
        if not locale:
            locale = getSite(self).locale

        return locale

    def _init_mask(self, root):
        if not self.mask:
            mask = Mask()
            root.addtoproperty('masks', mask)
            self.setproperty('mask', mask)

    def get_mask(self, root=None):
        root = root if root else getSite()
        if not getattr(root, 'anonymisation', False):
            return self

        self._init_mask(root)
        return self.mask

    def add_submission(self, obj):
        now = datetime.datetime.now(tz=pytz.UTC)
        self._submited_at[now] = get_oid(obj)

    def add_report(self, obj):
        now = datetime.datetime.now(tz=pytz.UTC)
        self._reported_at[now] = get_oid(obj)

    def can_submit_idea(self, root=None):
        root = root if root else getSite()
        now = datetime.datetime.now(tz=pytz.UTC)
        monday = datetime.datetime.combine((now - datetime.timedelta(days=7)),
                                           datetime.time(0,
                                                         0,
                                                         0,
                                                         tzinfo=pytz.UTC))
        return len(self._submited_at.values(min=monday, max=now)) < getattr(
            root, 'nb_submission_maxi', 3)

    def can_report(self, root=None):
        root = root if root else getSite()
        now = datetime.datetime.now(tz=pytz.UTC)
        monday = datetime.datetime.combine((now - datetime.timedelta(days=7)),
                                           datetime.time(0,
                                                         0,
                                                         0,
                                                         tzinfo=pytz.UTC))
        return len(self._reported_at.values(min=monday, max=now)) < getattr(
            root, 'nb_reports_maxi', 3)
Example #23
0
class SiteFolder(VisualisableElement, ServiceableEntity):
    """SiteFolder class"""

    icon = 'glyphicon glyphicon-globe'
    templates = {
        'default': 'lac:views/templates/site_folder_result.pt',
        'bloc': 'lac:views/templates/site_folder_result.pt'
    }
    name = renamer()
    tree = synchronize_tree()
    files = CompositeMultipleProperty('files')
    newsletters = CompositeMultipleProperty('newsletters', 'site')
    picture = CompositeUniqueProperty('picture')
    favicon = CompositeUniqueProperty('favicon')
    extraction_template = CompositeUniqueProperty('extraction_template')
    theme = CompositeUniqueProperty('theme')
    customer = SharedUniqueProperty('customer', 'sites')
    applications = CompositeMultipleProperty('applications', 'site')
    # controleur de publication
    current_cover = CompositeUniqueProperty('current_cover')
    alerts = CompositeMultipleProperty('alerts')

    def __init__(self, **kwargs):
        super(SiteFolder, self).__init__(**kwargs)
        self.set_data(kwargs)
        self.init_informations()
        self._keywords_ = []
        self._init_keywords()

    @property
    def mail_conf(self):
        return self.get_data(
            omit(MailTemplatesConfigurationSchema(), '_csrf_token_'))

    @property
    def filter_conf(self):
        result = self.get_data(
            omit(FilterConfigurationSchema(), '_csrf_token_'))
        return result

    @property
    def pub_conf(self):
        return self.get_data(
            omit(PublicationConfigurationSchema(), '_csrf_token_'))

    @property
    def ui_conf(self):
        return self.get_data(
            omit(UserInterfaceConfigurationSchema(), '_csrf_token_'))

    @property
    def keywords_conf(self):
        return self.get_data(omit(KeywordsConfSchema(), '_csrf_token_'))

    @property
    def other_conf(self):
        return self.get_data(omit(OtherSchema(), '_csrf_token_'))

    @property
    def real_closing_date(self):
        now = datetime.datetime.now(tz=pytz.UTC)
        closing_date = getattr(self, 'closing_date', _marker)
        closing_frequence = getattr(self, 'closing_frequence', 0)
        if closing_date is _marker:
            closing_date = now

        last_closing_date = closing_date - datetime.timedelta(
            days=closing_frequence)
        if now < last_closing_date:
            return last_closing_date

        return closing_date

    @property
    def publication_date(self):
        closing_date = self.real_closing_date
        closing_frequence = getattr(self, 'closing_frequence', 0)
        delay_before_publication = getattr(self, 'delay_before_publication', 0)
        delay = delay_before_publication - closing_frequence
        return datetime.timedelta(days=delay) + closing_date

    @property
    def sections(self):
        levels = self.get_keywords_by_level()
        if len(levels) >= 2:
            return sorted(levels[1])

        return []

    def __setattr__(self, name, value):
        super(SiteFolder, self).__setattr__(name, value)
        if name == 'filters':
            self._init_keywords()

    def init_informations(self):
        self.closing_frequence = DEFAULT_CLOSING_FREQUENCE
        self.delay_before_publication = DEFAULT_DELAY_BEFORE_PUBLICATION
        self.days_visibility = DEFAULT_DAYS_VISIBILITY
        self.publication_number = 0
        self.closing_date = datetime.datetime.now(tz=pytz.UTC) +\
            datetime.timedelta(days=self.closing_frequence)
        self._tree = PersistentDict()
        self.keywords = PersistentList()
        self.tree = DEFAULT_TREE
        self.init_files()

    def get_keywords_by_level(self):
        return get_keywords_by_level(dict(self.tree), ROOT_TREE)

    def get_tree_nodes_by_level(self):
        return get_tree_nodes_by_level(dict(self.tree))

    def get_all_branches(self):
        return get_all_branches(self.tree)

    def merge_tree(self, tree):
        mapping = getattr(self, 'keywords_mapping', {}).get('mapping', [])
        self.tree = merge_tree(dict(self.tree), tree, mapping)

    def get_normalized_tree(self, tree, type_='out'):
        mapping = getattr(self, 'keywords_mapping', {}).get('mapping', [])
        return normalize_tree(tree, mapping, type_)

    def get_normalized_keywords(self, keywords, type_='out'):
        mapping = getattr(self, 'keywords_mapping', {}).get('mapping', [])
        return normalize_keywords(keywords, mapping, type_)

    def get_tree_branches(self):
        return get_branches(getattr(self, 'tree', {}))

    def init_files(self):
        for information in DEFAULT_SITE_INFORMATIONS:
            if not self.get(information['name'], None):
                info_file = FileEntity(title=information['title'])
                info_file.text = information['content']
                info_file.__name__ = information['name']
                self.addtoproperty('files', info_file)

    def next_publication_date(self, week_number=0):
        closing_date = self.real_closing_date
        delay_before_publication = getattr(self, 'delay_before_publication', 0)
        days = getattr(self, 'closing_frequence', 0) * week_number
        return datetime.timedelta(days=delay_before_publication) +\
            closing_date +\
            datetime.timedelta(days=days)

    def get_mail_template(self, id):
        for mail in getattr(self, 'mail_templates', {}):
            if mail.get('mail_id', None) == id:
                return mail

        template = DEFAULT_SITE_MAILS.get(id, None)
        if template:
            template = template.copy()
            template['mail_id'] = id

        return template

    def get_site_sender(self):
        registry = get_current_registry()
        default_sender = registry.settings['lac.admin_email']
        return getattr(self, 'site_sender', default_sender)

    def _init_keywords(self):
        alltrees = [
            f.get('metadata_filter', {}).get('tree', {})
            for f in getattr(self, 'filters', [])
        ]
        keywords = [tree_to_keywords(tree) for tree in alltrees]
        keywords = list(set([item for sublist in keywords
                             for item in sublist]))
        self._keywords_ = keywords

    def get_all_keywords(self):
        if hasattr(self, '_keywords_'):
            return self._keywords_
        self._init_keywords()
        return self._keywords_.copy()

    def get_group(self):
        if not self.customer:
            return []

        sites = list(self.customer.sites)
        if self in sites:
            sites.remove(self)

        return sites
Example #24
0
class SearchableEntity(ServiceableEntity):
    """ A Searchable entity is an entity that can be searched"""

    icon = 'glyphicon glyphicon-question-sign'
    templates = {'default': 'lac:views/templates/default_result.pt',
                 'bloc': 'lac:views/templates/default_result_bloc.pt',
                 'extraction': 'lac:views/templates/extraction/default_result.pt'}
    tree = synchronize_tree()
    type_title = ''
    files = CompositeMultipleProperty('files')
    connections_from = SharedMultipleProperty(
        'connections_from', 'connections_to')
    connections_to = SharedMultipleProperty(
        'connections_to', 'connections_from')
    visibility_dates = dates('visibility_dates')
    labels = SharedMultipleProperty('labels')

    def __init__(self, **kwargs):
        super(SearchableEntity, self).__init__(**kwargs)
        self._tree = PersistentDict()
        self.keywords = PersistentList()
        self.set_data(kwargs)
        self.source_site = get_oid(get_site_folder(True),
                                   None)
        self._keywords_ = []
        self._init_keywords()

    def __setattr__(self, name, value):
        super(SearchableEntity, self).__setattr__(name, value)
        if name == 'description':
            self._init_presentation_text()

    @property
    def object_labels(self):
        return {'labels': self.labels}

    @property
    def metadata(self):
        return self.get_data(omit(MetadataSchema(),
                                 '_csrf_token_'))

    @property
    def is_published(self):
        return 'published' in self.state

    @property
    def object_id(self):
        source_data = getattr(self, 'source_data', {})
        obj_id = source_data.get('id', '') + '_' +\
            source_data.get('source_id', '')
        if obj_id == '_':
            obj_id = str(getattr(self, '__oid__', None))+'_lac'

        return obj_id

    @property
    def json_tree(self):
        return json.dumps(dict(self.tree))

    @property
    def is_imported(self):
        source_id = getattr(self, 'source_data', {}).get('source_id', None)
        return True if source_id and source_id in list(IMPORT_SOURCES.keys())\
               else False

    @property
    def relevant_data(self):
        return [getattr(self, 'title', ''),
                getattr(self, 'description', ''),
                ', '.join(self.keywords)]

    @property
    def sections(self):
        tree = dict(self.get_normalized_tree())
        levels = get_keywords_by_level(tree, ROOT_TREE)
        if len(levels) >= 2:
            return sorted(levels[1])

        return []

    @property
    def substitutions(self):
        return [self]

    def _init_presentation_text(self):
        pass

    def _init_keywords(self):
        pass

    def get_all_keywords(self):
        return self.keywords

    def get_more_contents_criteria(self):
        "return specific query, filter values"
        keywords = list(self.keywords)
        root_tree = ROOT_TREE.lower()
        if root_tree in keywords:
            keywords.remove(root_tree)

        return None, {'keywords': keywords}

    def get_release_date(self):
        return getattr(self, 'release_date', self.modified_at)

    def presentation_text(self, nb_characters=400):
        return getattr(self, 'description', "")[:nb_characters]+'...'

    def get_normalized_tree(self, type_='out'):
        site = get_site_folder(True)
        return site.get_normalized_tree(getattr(self, 'tree', {}), type_)

    def get_visibility_filter(self):
        registry = get_current_registry()
        return {
            'metadata_filter': {
                'tree': deepcopy(self.tree),
                'content_types': [registry.content.typeof(self)],
                'states': list(getattr(self, 'state', []))
            }
        }

    def set_metadata(self, appstruct):
        if 'site' not in appstruct:
            site = get_site_folder(True)

        if 'accessibility' in appstruct:
            object_set_access_control(appstruct.get('accessibility'), self, site)
            appstruct.pop('accessibility')

        data = {}
        for key in MetadataSchema():
            name = key.name
            if name in appstruct:
                data[name] = appstruct.pop(name)

        if 'object_labels' in data:
            new_labels = [label['_object_data'] for label
                          in data['object_labels']['new_labels']]
            all_labels = []
            if new_labels:
                root = site.__parent__
                for label in new_labels:
                    root.addtoproperty('labels', label)
                    all_labels.append(label)

            all_labels.extend(data['object_labels']['labels'])
            data['labels'] = all_labels
            data.pop('object_labels')

        self.set_data(data)
        self.release_date = getattr(
            self, 'release_date', self.created_at).replace(
            tzinfo=pytz.UTC)

    def labels_data(self, site):
        labels = getattr(self, 'labels', [])
        labels_data = [{'title': l.title,
                        'img': l.picture.url} for l in labels]
        site_oid = get_oid(site)
        if site_oid != self.source_site:
            orig_site = get_obj(self.source_site)
            if orig_site.favicon:
                labels_data.append({'title': orig_site.title,
                                    'img': orig_site.favicon.url})

        return labels_data
Example #25
0
class Event(SearchableEntity):
    """Event class"""

    type_title = _('Discussion event')
    icon = 'glyphicon glyphicon-calendar'
    templates = {
        'default': 'novaideo:views/templates/event_result.pt',
        'bloc': 'novaideo:views/templates/event_bloc.pt',
        'small': 'novaideo:views/templates/small_event_result.pt',
        'popover': 'novaideo:views/templates/event_popover.pt'
    }
    template = 'novaideo:views/templates/event_list_element.pt'
    name = renamer()
    author = SharedUniqueProperty('author', 'events')
    subject = SharedUniqueProperty('subject', 'events')
    url_files = CompositeMultipleProperty('url_files')

    def __init__(self, **kwargs):
        super(Event, self).__init__(**kwargs)
        self.set_data(kwargs)
        self.urls = PersistentDict({})

    @property
    def relevant_data(self):
        subject_relevant_data = getattr(self.subject, 'relevant_data', [])
        subject_relevant_data.extend([getattr(self, 'title', '')])
        return subject_relevant_data

    def init_published_at(self):
        setattr(self, 'published_at', datetime.datetime.now(tz=pytz.UTC))

    def presentation_text(self, nb_characters=400):
        return truncate_text(getattr(self, 'text', ""), nb_characters)

    def update(self):
        if 'expired' not in self.state and self.is_expired:
            self.state = PersistentList(['expired'])
            self.reindex()

    @property
    def is_expired(self):
        if 'expired' in self.state:
            return True
        try:
            now = datetime.datetime.now(tz=pytz.timezone(self.tzname))
            return self.date < now
        except Exception as e:
            return True

    def get_description(self, request, locale=None):
        return get_event_description_template(request, locale)

    def get_mode(self):
        return KINDS.get(self.kind)

    def get_locale(self):
        return EUROPEAN_LOCALES.get(self.locale)

    def format(self, request):
        text = getattr(self, 'text', '')
        all_urls, url_files, text_urls, formatted_text = text_urls_format(
            text, request)
        self.urls = PersistentDict(all_urls)
        self.setproperty('url_files', url_files)
        self.formatted_text = formatted_text
        self.formatted_urls = text_urls
class NovaIdeoApplication(CorrelableEntity, Debatable, Application):
    """Nova-Ideo class (Root)"""

    name = renamer()
    preregistrations = CompositeMultipleProperty('preregistrations')
    challenges = CompositeMultipleProperty('challenges')
    working_groups = CompositeMultipleProperty('working_groups')
    proposals = CompositeMultipleProperty('proposals')
    organizations = CompositeMultipleProperty('organizations')
    invitations = CompositeMultipleProperty('invitations')
    ideas = CompositeMultipleProperty('ideas')
    questions = CompositeMultipleProperty('questions')
    correlations = CompositeMultipleProperty('correlations')
    files = CompositeMultipleProperty('files')
    alerts = CompositeMultipleProperty('alerts')
    picture = CompositeUniqueProperty('picture')
    homepage_picture = CompositeUniqueProperty('homepage_picture')
    favicon = CompositeUniqueProperty('favicon')
    theme = CompositeUniqueProperty('theme')
    proposal_template = CompositeUniqueProperty('proposal_template')
    advertisings = CompositeMultipleProperty('advertisings')
    news_letter_members = SharedMultipleProperty('news_letter_members')
    general_chanel = SharedUniqueProperty('general_chanel')
    newsletters = CompositeMultipleProperty('newsletters')
    smart_folders = CompositeMultipleProperty('smart_folders')
    connectors = CompositeMultipleProperty('connectors')
    masks = CompositeMultipleProperty('masks')

    def __init__(self, **kwargs):
        super(NovaIdeoApplication, self).__init__(**kwargs)
        self.keywords = PersistentList()
        self.initialization()

    def __setattr__(self, name, value):
        super(NovaIdeoApplication, self).__setattr__(name, value)
        if name == 'mail_templates' and value:
            result = {}
            for template in value:
                mail_id = template.get('mail_id')
                languages = template.get('languages', [])
                languages = {m['locale']: m for m in languages}
                result[mail_id] = {
                    'title': template.get('title'),
                    'languages': languages
                }

            self._mail_templates = PersistentDict(result)

    @property
    def mail_conf(self):
        return self.get_data(
            omit(MailTemplatesConfigurationSchema(), '_csrf_token_'))

    @property
    def work_conf(self):
        result = self.get_data(
            omit(WorkParamsConfigurationSchema(), '_csrf_token_'))
        return result

    @property
    def user_conf(self):
        return self.get_data(
            omit(UserParamsConfigurationSchema(), '_csrf_token_'))

    @property
    def keywords_conf(self):
        return self.get_data(omit(KeywordsConfSchema(), '_csrf_token_'))

    @property
    def ui_conf(self):
        return self.get_data(
            omit(UserInterfaceConfigurationSchema(), '_csrf_token_'))

    @property
    def homepage_conf(self):
        return self.get_data(
            omit(HomepageConfigurationSchema(), '_csrf_token_'))

    @property
    def other_conf(self):
        return self.get_data(omit(OtherSchema(), '_csrf_token_'))

    @property
    def notif_conf(self):
        return self.get_data(
            omit(NotificationConfigurationSchema(), '_csrf_token_'))

    def get_newsletters_for_registration(self):
        return [
            nl for nl in self.newsletters
            if getattr(nl, 'propose_to_registration', True)
        ]

    def get_newsletters_automatic_registration(self):
        """Get newsletters with automatic registration"""
        return [
            nl for nl in self.newsletters
            if getattr(nl, 'automatic_registration', True)
        ]

    def initialization(self):
        self.reset_default_values()
        self.deadlines = PersistentList([datetime.datetime.now(tz=pytz.UTC)])
        self.work_modes = list(WORK_MODES.keys())
        self.colors_mapping = PersistentDict(DEFAULT_COLORS)

    def init_channels(self):
        if not self.general_chanel:
            self.addtoproperty('channels', Channel(title=_("General")))
            self.setproperty('general_chanel', self.channels[0])

    def reset_default_values(self):
        self.participants_mini = 3
        self.participants_maxi = 12
        self.participations_maxi = 5
        self.tokens_mini = 7

    @property
    def moderate_proposals(self):
        return 'proposal' in getattr(self, 'content_to_moderate', [])

    @property
    def moderate_ideas(self):
        return 'idea' in getattr(self, 'content_to_moderate', [])

    @property
    def examine_proposals(self):
        return 'proposal' in getattr(self, 'content_to_examine', [])

    @property
    def examine_ideas(self):
        return 'idea' in getattr(self, 'content_to_examine', [])

    @property
    def support_proposals(self):
        return 'proposal' in getattr(self, 'content_to_support', [])

    @property
    def support_ideas(self):
        return 'idea' in getattr(self, 'content_to_support', [])

    @property
    def manage_challenges(self):
        return 'challenge' in getattr(self, 'content_to_manage',
                                      DEFAULT_CONTENT_TO_MANAGE)

    @property
    def manage_questions(self):
        return 'question' in getattr(self, 'content_to_manage',
                                     DEFAULT_CONTENT_TO_MANAGE)

    @property
    def manage_proposals(self):
        return 'proposal' in getattr(self, 'content_to_manage',
                                     DEFAULT_CONTENT_TO_MANAGE)

    @property
    def titles(self):
        return DEFAULT_TITLES

    @property
    def comment_intentions(self):
        return DEFAULT_COMMENT_INTENTIONS

    @property
    def correlation_intentions(self):
        return DEFAULT_CORRELATION_INTENTIONS

    @property
    def idea_intentions(self):
        return DEFAULT_IDEA_INTENTIONS

    @property
    def amendment_intentions(self):
        return DEFAULT_AMENDMENT_INTENTIONS

    @property
    def channel(self):
        return getattr(self, 'general_chanel', None)

    def get_nonproductive_cycle_nb(self):
        return getattr(self, 'nonproductive_cycle_nb', 2)

    def init_files(self):
        for information in DEFAULT_FILES:
            if not self.get(information['name'], None):
                info_file = FileEntity(title=information['title'])
                content = information.get('content', '')
                content_file = information.get('content_file', None)
                if content_file:
                    content_path = os.path.join(os.path.dirname(__file__),
                                                'static', 'default_files',
                                                content_file)
                    if os.path.exists(content_path):
                        content = open(content_path).read()

                info_file.text = content
                info_file.__name__ = information['name']
                self.addtoproperty('files', info_file)
                info_file.state = PersistentList(['draft'])
                setattr(self, information['name'], info_file)

    def get_mail_template(self, id, locale=None):
        if locale is None:
            locale = self.locale

        mail = getattr(self, '_mail_templates', {}).get(id, None)
        if not mail:
            mail = DEFAULT_SITE_MAILS.get(id, None)

        template = mail.get('languages').get(locale, None)
        if not template:
            template = mail.get('languages').get(self.locale, None)

        return template

    def get_mail(self, id):
        for mail in getattr(self, 'mail_templates', {}):
            if mail.get('mail_id', None) == id:
                return mail

        template = DEFAULT_SITE_MAILS.get(id, None)
        if template:
            template = template.copy()
            template['mail_id'] = id
            template['languages'] = list(template['languages'].values())

        return template

    def get_site_sender(self):
        registry = get_current_registry()
        default_sender = registry.settings['mail.default_sender']
        return default_sender

    def get_work_modes(self):
        modes = getattr(self, 'work_modes', [])
        modes = {m: WORK_MODES[m] for m in modes if m in WORK_MODES}
        if modes:
            return modes

        return WORK_MODES

    def get_default_work_mode(self):
        modes = list(self.get_work_modes().values())
        modes = sorted(modes, key=lambda e: e.order)
        return modes[0]

    def add_colors_mapping(self, keys):
        if not hasattr(self, 'colors_mapping'):
            self.colors_mapping = PersistentDict(DEFAULT_COLORS)

        new_keywords = [k for k in keys if k not in self.colors_mapping]
        colors = random_color(len(new_keywords))
        for index, keyword in enumerate(new_keywords):
            self.colors_mapping[keyword] = {'color': colors[index]}

    def get_color(self, key):
        if key in getattr(self, 'colors_mapping', {}):
            return self.colors_mapping[key]

        self.add_colors_mapping([key])
        return self.colors_mapping[key]

    def merge_keywords(self, newkeywords):
        current_keywords = list(self.keywords)
        current_keywords.extend(newkeywords)
        self.keywords = PersistentList(list(set(current_keywords)))

    def get_title(self, user=None):
        return getattr(self, 'title', '')

    def get_connectors(self, connector_id):
        return filter(lambda c: c.connector_id == connector_id,
                      self.connectors)
Example #27
0
class Tokenable(Entity):
    """Question class"""

    tokens_opposition = CompositeMultipleProperty('tokens_opposition')
    tokens_support = CompositeMultipleProperty('tokens_support')

    def __init__(self, **kwargs):
        super(Tokenable, self).__init__(**kwargs)
        self.set_data(kwargs)
        self.allocated_tokens = OOBTree()
        self.len_allocated_tokens = PersistentDict({})

    def add_token(self, user, evaluation_type):
        user_oid = get_oid(user)
        if user_oid in self.allocated_tokens:
            self.remove_token(user)

        self.allocated_tokens[user_oid] = evaluation_type
        self.len_allocated_tokens.setdefault(evaluation_type, 0)
        self.len_allocated_tokens[evaluation_type] += 1

    def remove_token(self, user):
        user_oid = get_oid(user)
        if user_oid in self.allocated_tokens:
            evaluation_type = self.allocated_tokens.pop(user_oid)
            self.len_allocated_tokens.setdefault(evaluation_type, 0)
            self.len_allocated_tokens[evaluation_type] -= 1

    def evaluators(self, evaluation_type=None):
        if evaluation_type:
            return [
                get_obj(key) for value, key in self.allocated_tokens.byValue(
                    evaluation_type)
            ]

        return [get_obj(key) for key in self.allocated_tokens.keys()]

    def evaluation(self, user):
        user_oid = get_oid(user, None)
        return self.allocated_tokens.get(user_oid, None)

    def remove_tokens(self, force=False):
        evaluators = self.evaluators()
        for user in evaluators:
            user.remove_token(self)
            if force:
                self.remove_token(user)

    def user_has_token(self, user, root=None):
        if hasattr(user, 'has_token'):
            return user.has_token(self, root)

        return False

    def init_support_history(self):
        # [(user_oid, date, support_type), ...], support_type = {1:support, 0:oppose, -1:withdraw}
        if not hasattr(self, '_support_history'):
            setattr(self, '_support_history', PersistentList())

    @property
    def len_support(self):
        return self.len_allocated_tokens.get(Evaluations.support, 0)

    @property
    def len_opposition(self):
        return self.len_allocated_tokens.get(Evaluations.oppose, 0)
Example #28
0
class Proposal(VersionableEntity,
               SearchableEntity,
               DuplicableEntity,
               CorrelableEntity,
               PresentableEntity,
               ExaminableEntity,
               Node,
               Emojiable,
               SignalableEntity,
               Debatable,
               Tokenable):
    """Proposal class"""

    type_title = _('Proposal')
    icon = 'icon novaideo-icon icon-proposal'
    templates = {'default': 'novaideo:views/templates/proposal_result.pt',
                 'small': 'novaideo:views/templates/small_proposal_result.pt',
                 'popover': 'novaideo:views/templates/proposal_popover.pt',
                 'bloc': 'novaideo:views/templates/proposal_bloc.pt'}
    template = 'novaideo:views/templates/proposal_list_element.pt'
    name = renamer()
    author = SharedUniqueProperty('author')
    organization = SharedUniqueProperty('organization')
    working_group = SharedUniqueProperty('working_group', 'proposal')
    amendments = CompositeMultipleProperty('amendments', 'proposal')
    corrections = CompositeMultipleProperty('corrections', 'proposal')
    attached_files = SharedMultipleProperty('attached_files')
    challenge = SharedUniqueProperty('challenge', 'proposals')
    opinions_base = OPINIONS

    def __init__(self, **kwargs):
        super(Proposal, self).__init__(**kwargs)
        self.set_data(kwargs)
        self._amendments_counter = 1
        self.addtoproperty('channels', Channel())

    @property
    def related_ideas(self):
        return [idea[0] for idea in self.get_related_contents(
            CorrelationType.solid, ['related_ideas'])]

    @property
    def related_contents(self):
        return [content[0] for content in self.all_related_contents]

    @property
    def is_published(self):
        return 'published' in self.state

    @property
    def authors(self):
        authors = self.working_group.members
        author = self.author
        if author not in authors:
            authors.append(author)

        return authors

    @property
    def workspace(self):
        working_group = self.working_group
        if working_group:
            return working_group.workspace

        if self.current_version is not self:
            return getattr(self.current_version, 'workspace', None)

        return None

    def __setattr__(self, name, value):
        super(Proposal, self).__setattr__(name, value)
        if name == 'author':
            self.init_organization()

    def init_organization(self):
        if not self.organization:
            organization = getattr(self.author, 'organization', None)
            if organization:
                self.setproperty('organization', organization)

    def init_published_at(self):
        setattr(self, 'published_at', datetime.datetime.now(tz=pytz.UTC))

    def init_examined_at(self):
        setattr(self, 'examined_at', datetime.datetime.now(tz=pytz.UTC))

    def is_managed(self, root):
        return root.manage_proposals

    def get_more_contents_criteria(self):
        "return specific query, filter values"
        return None, {
            'metadata_filter': {
                'content_types': ['proposal', 'idea'],
                'keywords': list(self.keywords)
            }
        }

    def get_attached_files_data(self):
        return get_files_data(self.attached_files)

    def set_related_ideas(self, relatedideas, user):
        current_related_ideas = self.related_ideas
        related_ideas_to_add = [i for i in relatedideas
                                if i not in current_related_ideas]
        related_ideas_to_del = [i for i in current_related_ideas
                                if i not in relatedideas and
                                i not in related_ideas_to_add]
        connect(self,
                related_ideas_to_add,
                {'comment': _('Add related ideas'),
                 'type': _('Edit the proposal')},
                user,
                ['related_proposals', 'related_ideas'],
                CorrelationType.solid,
                True)
        disconnect(self,
                   related_ideas_to_del,
                   'related_ideas',
                   CorrelationType.solid)

    def get_version(self, user, parent):
        old_version = self.version
        copy_of_proposal = copy(
            self, parent,
            omit=('len_selections', 'graph'),
            roles=True)
        if old_version:
            copy_of_proposal.setproperty('version', old_version)

        copy_of_proposal.init_graph()
        copy_of_proposal.state = PersistentList(['version', 'archived'])
        copy_of_proposal.setproperty('author', self.author)
        copy_of_proposal.setproperty('originalentity', self.originalentity)
        for amendment in self.amendments:
            copy_of_proposal.addtoproperty('amendments', amendment)

        for correction in self.corrections:
            copy_of_proposal.addtoproperty('corrections', correction)

        for file_ in self.attached_files:
            copy_of_proposal.addtoproperty('attached_files', file_)

        copy_of_proposal.set_related_ideas(
            self.related_ideas, user)
        copy_of_proposal.reindex()
        return copy_of_proposal

    def remove_tokens(self, force=False):
        evaluators = self.evaluators()
        for user in evaluators:
            user.remove_token(self)
            user.remove_reserved_token(self)
            if force:
                self.remove_token(user)

    def get_node_descriminator(self):
        return 'proposal'
Example #29
0
class File(DaceObject, OriginFile):

    variants = CompositeMultipleProperty('variants')

    def __init__(self, fp, mimetype=None, filename=None, **kwargs):
        if not filename:
            filename = self.title

        DaceObject.__init__(self, **kwargs)
        if fp:
            fp.seek(0)
        else:
            fp = None

        if not mimetype or mimetype == 'application/x-download':
            hint = USE_MAGIC
        else:
            hint = mimetype

        OriginFile.__init__(self, fp, hint, filename)
        self.set_data(kwargs)


    @property
    def fp(self):
        return self.blob.open('r')

    @property
    def filename(self):
        return self.title

    @property
    def uid(self):
        return str(get_oid(self, None))

    @property
    def is_image(self):
        return self.mimetype.startswith('image')

    @property
    def url(self):
        request = get_current_request()
        return request.resource_url(self)

    def set_data(self, appstruct, omit=('_csrf_token_', '__objectoid__')):
        super(File, self).set_data(appstruct, omit)
        if not appstruct.get('elementary', False):
            try:
                self.generate_variants()
            except Exception as e:
                log.warning(e)

    def generate_variants(self):
        if self.is_image:
            results = generate_images(self.fp, self.filename)
            self.setproperty('variants', [])
            for img in results:
                img_val = Image(img['fp'], self.mimetype,
                                self.filename, elementary=True)
                img_val.__name__ = img['id']
                self.addtoproperty('variants', img_val)
                try:
                    delattr(self, img_val.__name__)
                except AttributeError:
                    pass

    def __getattr__(self, name):
        if name in AVAILABLE_FORMATS:
            attr = self.get(name)
            if attr is None:
                raise AttributeError(name)

            return attr
        else:
            return super(File, self).__getattr__(name)

    def get_data(self, node):
        result = {}
        result['filename'] = self.title
        result['uid'] = getattr(self, 'uid', None)
        result['mimetype'] = self.mimetype
        result['size'] = self.get_size()
        result['fp'] = self.blob.open('r')
        return result

    def get_size(self):
        try:
            return OriginFile.get_size(self)
        except BlobError:
            transaction.commit()
            return OriginFile.get_size(self)

    def __setattr__(self, name, value):
        if name == 'fp':
            self.blob = Blob()
            self.upload(value, mimetype_hint=USE_MAGIC)
        elif name == 'filename':
            self.title = value
        elif name == 'uid':
            pass
        else:
            super(File, self).__setattr__(name, value)

    def copy(self):
        data = self.get_data(None)
        data.pop('uid')
        return self.__class__(**data)
Example #30
0
class ProcessDefinition(Entity):

    nodes = CompositeMultipleProperty('nodes', 'process', True)
    transitions = CompositeMultipleProperty('transitions', 'process', True)
    TransitionDefinitionFactory = TransitionDefinition
    isControlled = False
    isSubProcess = False
    isVolatile = False
    isUnique = False
    discriminator = 'Application'

    def __init__(self, **kwargs):
        super(ProcessDefinition, self).__init__(**kwargs)
        self.contexts = PersistentList()
        self.id = None
        if 'id' in kwargs:
            self.id = kwargs['id']

    def _init_definition(self):
        pass

    def __call__(self, **kwargs):
        return Process(self, self._startTransition, **kwargs)

    def _dirty(self):
        try:
            del self._startTransition
        except AttributeError:
            pass

    def __repr__(self):  # pragma: no cover
        return "ProcessDefinition(%r)" % self.id

    def defineNodes(self, **nodes):
        self._dirty()
        for name, node in nodes.items():
            node.id = self.id + '.' + name
            node.__name__ = name
            self.addtoproperty('nodes', node)
            if hasattr(node, 'init_process_contexts'):
                node.init_process_contexts(self)

    def defineTransitions(self, *transitions):
        self._dirty()
        for transition in transitions:
            transition.__name__ = transition.id
            self.addtoproperty('transitions', transition)
            transition._init_ends()

    def _is_start_orphan(self, node):
        return not isinstance(node, StartEventDefinition) and not node.incoming

    def _is_end_orphan(self, node):
        return not isinstance(node, EndEventDefinition) and not node.outgoing

    def _normalize_definition(self):
        new_transitions = ()
        orphan_nodes = [node for node in self.nodes \
                        if self._is_start_orphan(node)]
        if orphan_nodes:
            start_events = self._get_start_events()
            empty_start_event = None
            if start_events:
                for s_e in start_events:
                    if s_e.eventKind is None:
                        empty_start_event = s_e
                        break

            if empty_start_event is None:
                empty_start_event = StartEventDefinition()

            p_g = ParallelGatewayDefinition()
            if not (empty_start_event in self.nodes):
                self.defineNodes(emptystart=empty_start_event, startpg=p_g)
            else:
                self.defineNodes(startpg=p_g)

            oldtransitions = list(empty_start_event.outgoing)
            for oldtransition in oldtransitions:
                oldtransition.set_source(p_g)

            new_transitions += (TransitionDefinition(
                empty_start_event.__name__, 'startpg'), )
            for o_n in orphan_nodes:
                new_transitions += (TransitionDefinition(
                    'startpg', o_n.__name__), )

        if new_transitions:
            self.defineTransitions(*new_transitions)
            new_transitions = ()

        orphan_nodes = [node for node in self.nodes \
                        if self._is_end_orphan(node)]
        if orphan_nodes:
            end_events = self._get_end_events()
            empty_end_event = None
            if end_events:
                for e_e in end_events:
                    if e_e.eventKind is None:
                        empty_end_event = e_e
                        break

            if empty_end_event is None:
                empty_end_event = EndEventDefinition()

            e_g = ExclusiveGatewayDefinition()
            if not (empty_end_event in self.nodes):
                self.defineNodes(emptyend=empty_end_event, endeg=e_g)
            else:
                self.defineNodes(endeg=e_g)

            oldtransitions = list(empty_end_event.incoming)
            for oldtransition in oldtransitions:
                oldtransition.set_target(e_g)

            new_transitions += (TransitionDefinition(
                'endeg', empty_end_event.__name__), )
            for o_n in orphan_nodes:
                new_transitions += (TransitionDefinition(
                    o_n.__name__, 'endeg'), )

        if new_transitions:
            self.defineTransitions(*new_transitions)

        self._normalize_startevents()
        self._normalize_endevents()

    def _normalize_startevents(self):
        start_events = self._get_start_events()
        for s_e in start_events:
            if len(s_e.outgoing) > 1:
                p_g = ParallelGatewayDefinition()
                self.defineNodes(mergepg=p_g)
                oldtransitions = list(s_e.outgoing)
                for oldtransition in oldtransitions:
                    oldtransition.set_source(p_g)

                self.defineTransitions(
                    TransitionDefinition(s_e.__name__, 'mergepg'))

    def _normalize_endevents(self):
        end_events = self._get_end_events()
        for e_e in end_events:
            if len(e_e.incoming) > 1:
                e_g = ExclusiveGatewayDefinition()
                self.defineNodes(mergeeg=e_g)
                oldtransitions = list(e_e.incoming)
                for oldtransition in oldtransitions:
                    oldtransition.set_target(e_g)

                self.defineTransitions(
                    TransitionDefinition('mergeeg', e_e.__name__))

    def _get_start_events(self):
        result = []
        for node in self.nodes:
            if isinstance(node, StartEventDefinition):
                result.append(node)

        return result

    def _get_end_events(self):
        result = []
        for node in self.nodes:
            if isinstance(node, EndEventDefinition):
                result.append(node)

        return result

    @reify
    def _startTransition(self):
        start_events = self._get_start_events()
        if len(start_events) != 1:
            raise InvalidProcessDefinition("Multiple start events",
                                           [id for (id, a) in start_events])

        return start_events[0].outgoing[0]

    def start_process(self, node_name=None):
        if self.isUnique and self.started_processes:
            if node_name:
                return {node_name: None}

            return {}
        #une transaction globale pour chaque demande
        global_transaction = Transaction()
        start_transition = self._startTransition
        startevent = start_transition.source
        # une transaction pour un evenement (pour l'instant c'est un evenement)
        sub_transaction = global_transaction.start_subtransaction(
            type='Find', initiator=self)
        start_workitems = startevent.start_process(sub_transaction)
        if node_name is None:
            start_workitems = {wi.node.__name__: wi for wi in start_workitems}
            return start_workitems

        for wi in start_workitems:
            if node_name == wi.node.__name__:
                return {node_name: wi}

        return {node_name: None}

    @property
    def started_processes(self):
        dace_catalog = find_catalog('dace')
        object_provides_index = dace_catalog['object_provides']
        processid_index = dace_catalog['process_id']
        query = object_provides_index.any((IProcess.__identifier__,)) & \
                processid_index.eq(self.id)
        results = query.execute().all()
        processes = [p for p in results]
        #processes.sort()
        return processes