Exemple #1
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)
Exemple #2
0
class Brief(SearchableEntity):
    """Brief class"""

    type_title = _('News flash')
    icon = 'lac-icon icon-brief'
    templates = {'default': 'lac:views/templates/brief_result.pt',
                 'bloc': 'lac:views/templates/brief_result_bloc.pt'}
    name = renamer()
    picture = CompositeUniqueProperty('picture')
    author = SharedUniqueProperty('author', 'contents')

    def __init__(self, **kwargs):
        self._presentation_text = None
        super(Brief, self).__init__(**kwargs)
        self.set_data(kwargs)

    def _init_presentation_text(self):
        self._presentation_text = html_to_text(
            getattr(self, 'details', ''))

    def __setattr__(self, name, value):
        super(Brief, self).__setattr__(name, value)
        if name == 'details':
            self._init_presentation_text()

    def presentation_text(self, nb_characters=400):
        text = getattr(self, '_presentation_text', None)
        if text is None:
            self._init_presentation_text()
            text = getattr(self, '_presentation_text', '')

        return text[:nb_characters]+'...'
Exemple #3
0
class BaseReview(VisualisableElement, SearchableEntity):
    """Base Review class"""

    type_title = _('Base review')
    thumbnail = CompositeUniqueProperty('thumbnail')
    picture = CompositeUniqueProperty('picture')
    author = SharedUniqueProperty('author', 'contents')
    artists = SharedMultipleProperty('artists', 'creations')

    def __init__(self, **kwargs):
        self._presentation_text = None
        super(BaseReview, self).__init__(**kwargs)
        self.set_data(kwargs)

    def _init_presentation_text(self):
        self._presentation_text = html_article_to_text(
            getattr(self, 'article', ''))

    def __setattr__(self, name, value):
        super(BaseReview, self).__setattr__(name, value)
        if name == 'article':
            self._init_presentation_text()

    @property
    def relevant_data(self):
        result = super(BaseReview, self).relevant_data
        result.extend([', '.join([a.title for a in self.artists])])
        return result

    @property
    def artists_ids(self):
        return [str(get_oid(a)) for a in self.artists]

    def presentation_text(self, nb_characters=400):
        text = getattr(self, '_presentation_text', None)
        if text is None:
            self._init_presentation_text()
            text = getattr(self, '_presentation_text', '')

        return text[:nb_characters]+'...'

    def get_visibility_filter(self):
        result = super(BaseReview, self).get_visibility_filter()
        authors = [self.author] if self.author else []
        result.update({
            'contribution_filter': {'authors': authors}})
        return result
Exemple #4
0
class StructureBase(VisualisableElement, Entity):
    """Structure class"""

    picture = CompositeUniqueProperty('picture')

    def __init__(self, **kwargs):
        super(StructureBase, self).__init__(**kwargs)
        self.set_data(kwargs)
class Organization(VisualisableElement, Group):
    """Organization class"""

    templates = {
        'default': 'novaideo:views/templates/organization_result.pt',
        'popover': 'novaideo:views/templates/organization_popover.pt',
        'small': 'novaideo:views/templates/small_organization_result.pt',
        'header': 'novaideo:views/templates/organization_header.pt',
    }
    icon = 'glyphicon glyphicon-home'
    name = renamer()
    managers = managers()
    members = SharedMultipleProperty('members', 'organization')
    logo = CompositeUniqueProperty('logo')
    cover_picture = CompositeUniqueProperty('cover_picture')

    def __init__(self, **kwargs):
        super(Organization, self).__init__(**kwargs)
        self.set_data(kwargs)
Exemple #6
0
class Advertising(VisualisableElement, SearchableEntity):
    """Advertising class"""

    picture = CompositeUniqueProperty('picture')
    author = SharedUniqueProperty('author', 'contents')
    internal_type = True

    def __init__(self, **kwargs):
        super(Advertising, self).__init__(**kwargs)
        self.access_control = PersistentList([self.source_site])
Exemple #7
0
class Newsletter(VisualisableElement, Entity):
    """Newsletter class"""

    type_title = _('Newsletter')
    icon = 'glyphicon glyphicon-envelope'
    templates = {
        'default': 'lac:views/templates/newsletter_result.pt',
        'bloc': 'lac:views/templates/newsletter_result.pt'
    }
    name = renamer()
    content_template = CompositeUniqueProperty('content_template')
    site = SharedUniqueProperty('site', 'newsletters')

    def __init__(self, **kwargs):
        super(Newsletter, self).__init__(**kwargs)
        self.set_data(kwargs)
        self.subscribed = PersistentDict()

    def get_content_template(self):
        if self.content_template:
            try:
                return self.content_template.fp.readall().decode()
            except Exception as error:
                log.warning(error)

        return ''

    def get_sending_date(self):
        return datetime.datetime.combine(
            getattr(self, 'sending_date', datetime.datetime.now(tz=pytz.UTC)),
            datetime.time(0, 0, 0, tzinfo=pytz.UTC))

    def get_next_sending_date(self, date=None):
        if date is None:
            date = self.get_sending_date()

        default = REC_DEFAULT.get('days')
        nb_rec = getattr(self, 'recurrence_nb', default)
        return (date +
                datetime.timedelta(days=nb_rec)).replace(tzinfo=pytz.UTC)

    def can_send(self):
        template = self.get_content_template()
        content_ = getattr(self, 'content', '')
        return content_ and content_ != template

    def reset_content(self):
        if self.content_template:
            content_ = self.get_content_template()
            if not getattr(self, 'content', ''):
                setattr(self, 'content', content_)

    def is_subscribed(self, user):
        email = getattr(user, 'email', None)
        return email and email in self.subscribed
Exemple #8
0
class Advertising(SearchableEntity):
    """Advertising class"""

    picture = CompositeUniqueProperty('picture')
    author = SharedUniqueProperty('author')
    visibility_dates = dates('visibility_dates')
    internal_type = True

    def __init__(self, **kwargs):
        super(Advertising, self).__init__(**kwargs)
        self.set_data(kwargs)
Exemple #9
0
class Label(VisualisableElement, Entity):

    picture = CompositeUniqueProperty('picture')

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

    @property
    def relevant_data(self):
        return [getattr(self, 'title', ''),
                getattr(self, 'description', '')]
class FilmSchedule(SearchableEntity, Schedule):
    """Film schedule class"""

    type_title = _('Film schedule')
    icon = 'glyphicon glyphicon-film'
    templates = {
        'default': 'lac:views/templates/film_schedule_result.pt',
        'bloc': 'lac:views/templates/film_schedule_result.pt',
        'extraction': 'lac:views/templates/extraction/film_schedule_result.pt'
    }
    picture = CompositeUniqueProperty('picture')

    def __init__(self, **kwargs):
        super(FilmSchedule, self).__init__(**kwargs)
Exemple #11
0
class FilmSynopses(SearchableEntity):
    """FilmSynopses class"""

    type_title = _('Film synopsis')
    icon = 'lac-icon icon-film-synopses'
    templates = {'default': 'lac:views/templates/film_synopses_result.pt',
                 'bloc': 'lac:views/templates/film_synopses_result_bloc.pt'}
    name = renamer()
    picture = CompositeUniqueProperty('picture')
    author = SharedUniqueProperty('author', 'contents')
    artists = SharedMultipleProperty('artists', 'creations')
    directors = SharedMultipleProperty('directors', 'productions')

    def __init__(self, **kwargs):
        self._presentation_text = None
        super(FilmSynopses, self).__init__(**kwargs)
        self.set_data(kwargs)

    def _init_presentation_text(self):
        self._presentation_text = html_to_text(
            getattr(self, 'abstract', ''))

    def __setattr__(self, name, value):
        super(FilmSynopses, self).__setattr__(name, value)
        if name == 'abstract':
            self._init_presentation_text()

    @property
    def artists_ids(self):
        return [str(get_oid(a)) for a in self.artists]

    @property
    def directors_ids(self):
        return [str(get_oid(a)) for a in self.directors]

    @property
    def relevant_data(self):
        result = super(FilmSynopses, self).relevant_data
        result.extend([', '.join([a.title for a in self.directors]),
                       ', '.join([a.title for a in self.artists])])
        return result

    def presentation_text(self, nb_characters=400):
        text = getattr(self, '_presentation_text', None)
        if text is None:
            self._init_presentation_text()
            text = getattr(self, '_presentation_text', '')

        return text[:nb_characters]+'...'
Exemple #12
0
class Bot(Machine):
    """Bot class"""

    icon = 'icon glyphicon glyphicon-user'
    name = renamer()
    picture = CompositeUniqueProperty('picture')

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

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

        return default
Exemple #13
0
class Organization(Group):
    """Organization class"""

    type_title = _('Organization')
    icon = 'glyphicon glyphicon-cog'
    templates = {
        'default': 'lac:views/templates/organization_result.pt',
        'bloc': 'lac:views/templates/organization_result.pt'
    }
    name = renamer()
    logo = CompositeUniqueProperty('logo')
    is_organization = True

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

    @property
    def managers(self):
        return get_users_with_role(role=('OrganizationResponsible', self))
Exemple #14
0
class Game(VisualisableElement, SearchableEntity):
    """Game class"""

    type_title = _('Game')
    icon = 'glyphicon glyphicon-bishop'
    templates = {
        'default': 'lac:views/templates/game_result.pt',
        'bloc': 'lac:views/templates/game_result.pt'
    }
    name = renamer()
    picture = CompositeUniqueProperty('picture')
    author = SharedUniqueProperty('author', 'contents')
    announcement = SharedUniqueProperty('announcement')

    def __init__(self, **kwargs):
        self.click = 0
        super(Game, self).__init__(**kwargs)
        self.access_control = [self.source_site]
        self.participants = PersistentDict()
        self.winners = PersistentDict()

    def _init_presentation_text(self):
        self._presentation_text = html_to_text(getattr(self, 'description',
                                                       ''))

    def presentation_text(self, nb_characters=400):
        text = getattr(self, '_presentation_text', None)
        if text is None:
            self._init_presentation_text()
            text = getattr(self, '_presentation_text', '')

        return text[:nb_characters] + '...'

    def get_participants_by_mail(self, mails):
        result = {}
        for mail in [m for m in mails if m in self.participants]:
            result[mail] = self.participants[mail]

        return result
Exemple #15
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
Exemple #16
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
Exemple #17
0
class VersionableEntity(Entity):
    """ A Versionable entity is an entity that can be versioned"""

    version = CompositeUniqueProperty('version', 'nextversion')
    nextversion = SharedUniqueProperty('nextversion', 'version')

    @property
    def current_version(self):
        """ Return the current version"""

        if self.nextversion is None:
            return self
        else:
            return self.nextversion.current_version

    @property
    def history(self):
        """ Return all versions"""

        result = []
        if self.version is None:
            return [self]
        else:
            result.append(self)
            result.extend(self.version.history)

        return result

    def destroy(self):
        """Remove branch"""

        if self.version:
            self.version.destroy()

        if self.nextversion:
            self.nextversion.delfromproperty('version', self)
Exemple #18
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
Exemple #19
0
class Newsletter(VisualisableElement, Entity):
    """Newsletter class"""

    type_title = _('Newsletter')
    icon = 'glyphicon glyphicon-envelope'
    templates = {
        'default': 'novaideo:views/templates/newsletter_result.pt',
        'bloc': 'novaideo:views/templates/newsletter_result.pt'
    }
    name = renamer()
    content_template = CompositeUniqueProperty('content_template')

    def __init__(self, **kwargs):
        super(Newsletter, self).__init__(**kwargs)
        self.set_data(kwargs)
        self.subscribed = PersistentDict()

    @property
    def working_params_conf(self):
        return self.get_data(omit(NewsletterWorkingParamConf(),
                                  '_csrf_token_'))

    @property
    def rec_conf(self):
        return self.get_data(omit(NewsletterRecConf(), '_csrf_token_'))

    def get_content_template(self):
        if self.content_template:
            try:
                return self.content_template.fp.readall().decode()
            except Exception as error:
                log.warning(error)

        return ''

    def get_sending_date(self):
        return datetime.datetime.combine(
            getattr(self, 'sending_date', datetime.datetime.now(tz=pytz.UTC)),
            datetime.time(0, 0, 0, tzinfo=pytz.UTC))

    def get_next_sending_date(self, date=None):
        if date is None:
            date = self.get_sending_date()

        default = REC_DEFAULT.get('days')
        nb_rec = getattr(self, 'recurrence_nb', default)
        return (date +
                datetime.timedelta(days=nb_rec)).replace(tzinfo=pytz.UTC)

    def validate_content(self):
        content = getattr(self, 'content', '')
        if content:
            if not getattr(self, 'allow_unsubscribing', True):
                return content.find('{unsubscribeurl}') < 0

            return True

        return False

    def reset_content(self):
        if self.content_template:
            setattr(self, 'content', self.get_content_template())

    def subscribe(self, first_name, last_name, email, id_=None):
        if not id_:
            id_ = gen_random_token()

        user_data = {
            'first_name': first_name,
            'last_name': last_name,
            'email': email,
            'id': id_,
            'title': first_name + ' ' + last_name
        }

        self.subscribed[email] = user_data

    def is_subscribed(self, user):
        email = getattr(user, 'email', None)
        return email and email in self.subscribed
Exemple #20
0
class Ballot(VisualisableElement, Entity):
    """Ballot class"""
    name = renamer()
    ballot_box = CompositeUniqueProperty('ballot_box')
    report = CompositeUniqueProperty('report', 'ballot')
    initiator = SharedUniqueProperty('initiator')
    subjects = SharedMultipleProperty('subjects')

    def __init__(self, ballot_type, electors, contexts, duration, **kwargs):
        super(Ballot, self).__init__(**kwargs)
        kwargs.pop('subjects', None)
        self.setproperty('ballot_box', BallotBox())
        self.setproperty('report',
                         Report(ballot_type, electors, contexts, **kwargs))
        self.run_at = None
        self.duration = duration
        self.finished_at = None
        self.period_validity = kwargs.get('period_validity', None)
        self.group = kwargs.get('group', DEFAULT_BALLOT_GROUP)
        self.uid = uuid.uuid4().hex
        self.__name__ = self.uid

    @property
    def group_id(self):
        group = getattr(self, 'group', DEFAULT_BALLOT_GROUP)
        return group.get('group_id', None)

    @property
    def is_finished(self):
        if 'finished' in self.state:
            return True

        now = datetime.datetime.now(tz=pytz.UTC)
        if now > self.finished_at:
            self.state.append('finished')
            return True

        return False

    @property
    def decision_is_valide(self):
        if 'expired' in self.state:
            return False

        if self.period_validity is None:
            return True

        now = datetime.datetime.now(tz=pytz.UTC)
        end_decision = self.finished_at + self.period_validity
        if now > end_decision:
            self.state.append('expired')
            return False

        return True

    def get_url(self, request):
        ballot_oid = get_oid(self, '')
        return request.resource_url(
            request.root, '@@seeballot', query={'id': ballot_oid}) \
            if ballot_oid else None

    def finish_ballot(self):
        if 'finished' not in self.state:
            self.finished_at = datetime.datetime.now(tz=pytz.UTC)
            self.state = PersistentList(['finished'])

    def run_ballot(self, context=None):
        """Run the ballot"""
        self.run_at = datetime.datetime.now(tz=pytz.UTC)
        self.finished_at = self.run_at + self.duration
        return self.report.ballottype.run_ballot(context)
Exemple #21
0
class ArtistInformationSheet(VisualisableElement, DuplicableEntity,
                             ParticipativeEntity, SearchableEntity):
    """Artist information sheet class"""

    type_title = _('Artist information sheet')
    icon = 'glyphicon glyphicon-star'
    templates = {'default': 'lac:views/templates/artist_result.pt',
                 'bloc': 'lac:views/templates/artist_result.pt',
                 'diff': 'lac:views/templates/diff_artist_template.pt',
                 'duplicates': 'lac:views/templates/artist_duplicates.pt'}
    picture = CompositeUniqueProperty('picture')
    author = SharedUniqueProperty('author', 'contents')
    creations = SharedMultipleProperty('creations', 'artists')
    productions = SharedMultipleProperty('productions', 'artists')

    def __init__(self, **kwargs):
        super(ArtistInformationSheet, self).__init__(**kwargs)
        self.hash_picture = None
        self.hash_artist = None
        self.hash_picture_fp()
        self.hash_artist_data()

    @property
    def id(self):
        return self.get_id()

    def hash_picture_fp(self):
        if self.picture:
            m = hashlib.md5()
            picture_r = self.picture.fp.readall()
            self.picture.fp.seek(0)
            m.update(picture_r)
            self.hash_picture = m.digest()
        else:
            self.hash_picture = None

    @property
    def related_contents(self):
        result = list(self.creations)
        result.extend(list(self.productions))
        return result

    @property
    def improved_artist(self):
        original = getattr(self, 'original', None)
        return original if original is not self else None

    def get_id(self):
        return str(get_oid(self, 0))

    def replace_by(self, source):
        if self is not source:
            creations = source.creations
            productions = source.productions
            connections_to = source.connections_to
            for creation in self.creations:
                if creation not in creations:
                    source.addtoproperty('creations', creation)
                    creation.reindex()

            self.setproperty('creations', [])
            for production in self.productions:
                if production not in productions:
                    source.addtoproperty('productions', production)
                    production.reindex()

            self.setproperty('productions', [])
            for connection in self.connections_to:
                if connection not in connections_to:
                    source.addtoproperty('connections_to', connection)

            self.setproperty('connections_to', [])
            for branch in self.branches:
                source.addtoproperty('branches', branch)

            original = self.original
            if original and original is not source:
                source.setproperty('original', original)
                self.setproperty('original', None)

            source.add_contributors(self.contributors)
            self.setproperty('branches', [])
            return True

        return False

    def reject(self):
        original = self.original
        if original:
            self.replace_by(original)

    def hash_artist_data(self):
        result = self.title
        result += getattr(self, 'description', '')
        result += getattr(self, 'biography', '')
        result += str(getattr(self, 'is_director', False))
        result += str(self.hash_picture)
        result = result.replace(' ', '').strip()
        m = hashlib.md5()
        m.update(result.encode())
        self.hash_artist = m.digest()

    def eq(self, other):
        hash_artist = getattr(self, 'hash_artist', None)
        other_hash_artist = getattr(other, 'hash_artist', None)
        if hash_artist != other_hash_artist:
            return False

        return True

    def get_more_contents_criteria(self):
        "return specific query, filter values"
        artists = reduce(lambda result, x: result + getattr(x, 'artists', []),
                         filter(lambda x: 'published' in x.state, self.creations), [])
        artists = filter(lambda x: 'published' in x.state, artists)
        return None, {'objects': set(artists)}

    def get_duplicates(self, states=('published', )):
        return find_duplicates_artist(self, states)
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)
Exemple #23
0
class Service(VisualisableElement, Product):
    """Service class"""

    type_title = _('Service')
    name = renamer()
    delegate = SharedUniqueProperty('delegate', 'supervise')
    perimeter = SharedUniqueProperty('perimeter', 'services')
    customer = SharedUniqueProperty('customer', 'services')
    unit_definition = CompositeUniqueProperty('unit_definition')
    units = SharedMultipleProperty('units', 'service')

    def __init__(self, definition, **kwargs):
        super(Service, self).__init__(**kwargs)
        self.set_data(kwargs)
        self.definition_id = definition.service_id
        self.subscription = definition.subscription
        self.unit_definition = None
        if definition.unit_definition:
            self.addtoproperty('unit_definition', definition.unit_definition())

    def get_unit_definition(self):
        unit_def = getattr(self, 'unit_definition', None)
        if not unit_def:
            if self.definition.unit_definition:
                self.addtoproperty('unit_definition',
                                   self.definition.unit_definition())

        return getattr(self, 'unit_definition', None)

    def get_price(self):
        subscription = getattr(self, 'subscription', None)
        if subscription:
            return subscription.get('price')

        return 0

    def configure(self, context, user, is_copy=False):
        self.start_date = datetime.datetime.now(tz=pytz.UTC)
        self.state.append('active')

    def subscribe(self, context, user, **kwargs):
        if not hasattr(user, 'customeraccount'):
            user = getattr(context, 'author', None)

        if not user and hasattr(context, 'customer') and\
           context.customer:
            user = context.customer.user

        if getattr(user, 'customeraccount', _marker) is None:
            user.add_customeraccount()

        customeraccount = getattr(user, 'customeraccount', None)
        if customeraccount:
            customeraccount.addtoproperty('services', self)
            self.setproperty('perimeter', context)
            grant_roles(user=user, roles=(("Owner", self), ))
            self.reindex()
            return True

        return False

    def unsubscribe(self, context, user, **kwargs):
        if not hasattr(user, 'customeraccount'):
            user = getattr(self, 'customer', None)

        if not user and hasattr(context, 'customer') and\
           context.customer:
            user = context.customer.user

        customeraccount = getattr(user, 'customeraccount', None)
        if customeraccount:
            revoke_roles(user=user, roles=(("Owner", self), ))
            customeraccount.delfromproperty('services', self)

        if context:
            context.delfromproperty('services', self)

    def delegated_to(self, user):
        delegate = self.delegate
        groups = list(getattr(user, 'groups', []))
        groups.append(user)
        return delegate in groups

    def validated_payment(self):
        return self.order is None or \
            'paid' in self.order.state

    def is_expired(self):
        return False

    def is_valid(self, context, user):
        return not self.is_expired() and\
            self.validated_payment()

    def get_unit(self, **kwargs):
        unit_def = self.get_unit_definition()
        if unit_def:
            if 'delegate' not in kwargs:
                kwargs['delegate'] = self.delegate

            if 'title' not in kwargs:
                kwargs['title'] = self.title

            return unit_def(**kwargs)

    @property
    def definition(self):
        root = getSite(self)
        if root:
            return root.get_services_definition().get(self.definition_id, None)

        return None

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

    @property
    def service_description(self):
        return self.definition.description

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

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

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

    @property
    def price_str(self):
        subscription = getattr(self, 'subscription', None)
        if subscription:
            subscription_type = subscription.get('subscription_type')
            price = subscription.get('price')
            if price == 0:
                return _('Free')

            if subscription_type == 'subscription':
                return str(price) + '€/Month'

            return str(price) + '€/Unit'

        return _('Free')
Exemple #24
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)
Exemple #25
0
class SmartFolder(VisualisableElement, Entity):
    """SmartFolder class"""

    default_icon = 'glyphicon glyphicon-briefcase'
    templates = {
        'default': 'novaideo:views/templates/folder_result.pt',
        'bloc': 'novaideo:views/templates/folder_result.pt',
        'header': 'novaideo:views/templates/folder_header.pt',
    }
    name = renamer()
    children = SharedMultipleProperty('children', 'parents')
    parents = SharedMultipleProperty('parents', 'children')
    author = SharedUniqueProperty('author', 'folders')
    contents = SharedMultipleProperty('contents')
    cover_picture = CompositeUniqueProperty('cover_picture')

    def __init__(self, **kwargs):
        super(SmartFolder, self).__init__(**kwargs)
        self.set_data(kwargs)
        self.folder_order = None

    @property
    def parent(self):
        parents = self.parents
        return parents[0] if parents else None

    @property
    def root(self):
        parent = self.parent
        return parent.root if parent else self

    @property
    def folder_lineage(self):
        result = [self]
        parent = self.parent
        if parent:
            parent_result = parent.folder_lineage
            parent_result.extend(result)
            result = parent_result

        return result

    @property
    def icon(self):
        icon = getattr(self, 'icon_data', {})
        if icon:
            return icon.get('icon_class') + ' ' + icon.get('icon')
        else:
            return self.default_icon

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

    def contains(self, folder):
        if folder is None:
            return False

        if folder is self:
            return True

        return any(c.contains(folder) for c in self.children)

    def all_sub_folders(self, state=None):
        if state:
            result = [f for f in self.children if state in f.state]
        else:
            result = list(self.children)

        for sub_f in list(result):
            result.extend(sub_f.all_sub_folders(state))

        return list(set(result))

    def get_order(self):
        folder_order = getattr(self, 'folder_order', None)
        if folder_order is None:
            root = self.__parent__
            folders = root.smart_folders
            if self in folders:
                self.set_order(folders.index(self))

        return getattr(self, 'folder_order', None)

    def set_order(self, order):
        self.folder_order = order

    def get_url(self, request):
        return request.resource_url(request.root,
                                    'open',
                                    query={'folderid': get_oid(self)})
Exemple #26
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
Exemple #27
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
Exemple #28
0
class Correction(VisualisableElement, Entity):
    """Correction class"""
    name = renamer()
    author = SharedUniqueProperty('author')
    proposal = SharedUniqueProperty('proposal', 'corrections')
    current_version = CompositeUniqueProperty('current_version')

    def __init__(self, **kwargs):
        super(Correction, self).__init__(**kwargs)
        self.set_data(kwargs)
        self.corrections = {}

    def _adapt_correction(self, correction_tag, is_favour):
        """
        Add 'correction-favour-vote' css_class to the 'correction_tag'
        if 'is_favour' is True
        """

        correction_tag.find("span", id="correction_actions").decompose()
        vote_class = 'correction-favour-vote'
        if not is_favour:
            vote_class = 'correction-against-vote'

        correction_tag['class'] = vote_class

    def _get_adapted_content(self, user, text):
        """Return the appropriate text to the user"""

        user_ = self.proposal.working_group.get_member(user)
        user_ = user_ or user
        soup = BeautifulSoup(text)
        corrections = soup.find_all("span", id='correction')
        # if user is self.author:
        #     for correction in corrections:
        #         self._adapt_correction(correction, True)
        # else:
        for correction in corrections:
            correction_data = self.corrections[correction["data-item"]]
            voters_favour = any((get_obj(v) is user_
                                 for v in correction_data['favour']))
            if voters_favour:
                self._adapt_correction(correction, True)
                continue

            voters_against = any((get_obj(v) is user_
                                  for v in correction_data['against']))
            if voters_against:
                self._adapt_correction(correction, False)

        return html_diff_wrapper.soup_to_text(soup)

    def get_adapted_description(self, user):
        """Return the appropriate description to the user"""

        return self._get_adapted_content(user, self.description)

    def get_adapted_text(self, user):
        """Return the appropriate text to the user"""

        return self._get_adapted_content(user, self.text)

    def get_adapted_title(self, user):
        """Return the appropriate text to the user"""

        return self._get_adapted_content(user, self.title).replace('<p>', '').replace('</p>', '')
Exemple #29
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
class CulturalEvent(VisualisableElement, DuplicableEntity, ParticipativeEntity,
                    SearchableEntity):
    """Cultural_event class"""

    type_title = _('Cultural event')
    icon = 'lac-icon icon-bullhorn'
    templates = {
        'default': 'lac:views/templates/culturalevent_result.pt',
        'bloc': 'lac:views/templates/culturalevent_result.pt',
        'diff': 'lac:views/templates/diff_event_template.pt',
        'extraction': 'lac:views/templates/extraction/culturalevent_result.pt',
        'duplicates': 'lac:views/templates/culturalevent_duplicates.pt',
        'map': 'lac:views/templates/map/cultural_event.pt'
    }
    name = renamer()
    schedules = SharedMultipleProperty("schedules", "cultural_event")
    picture = CompositeUniqueProperty('picture')
    artists = SharedMultipleProperty('artists', 'creations')
    author = SharedUniqueProperty('author', 'contents')

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

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

    @property
    def dates_end_date(self):
        if not self.schedules:
            return datetime.datetime.combine(
                datetime.datetime.now(), datetime.time(0,
                                                       0,
                                                       0,
                                                       tzinfo=pytz.UTC))

        return max([
            getattr(schedule, 'dates_end_date', None)
            for schedule in self.schedules
            if getattr(schedule, 'dates_end_date', None)
        ])

    @property
    def dates_start_date(self):
        if not self.schedules:
            return datetime.datetime.combine(
                datetime.datetime.now(), datetime.time(0,
                                                       0,
                                                       0,
                                                       tzinfo=pytz.UTC))

        return min([
            getattr(schedule, 'dates_start_date', None)
            for schedule in self.schedules
            if getattr(schedule, 'dates_start_date', None)
        ])

    @property
    def dates_recurrence(self):
        return '\n'.join([
            getattr(schedule, 'dates_recurrence', None)
            for schedule in self.schedules
        ])

    @property
    def artists_ids(self):
        return [str(get_oid(a)) for a in self.artists]

    @property
    def relevant_data(self):
        result = super(CulturalEvent, self).relevant_data
        result.extend([
            ', '.join([a.title for a in self.artists]), ', '.join([
                to_localized_time(d,
                                  format_id='direct_literal',
                                  add_day_name=True,
                                  translate=True)
                for d in occurences_start(self, 'dates')
            ]), ', '.join([s.venue.city for s in self.schedules if s.venue]),
            ', '.join([s.venue.title for s in self.schedules if s.venue])
        ])
        return result

    @property
    def improved_cultural_event(self):
        original = getattr(self, 'original', None)
        return original if original is not self else None

    @property
    def substitutions(self):
        return [s for s in self.schedules if 'archived' not in s.state]

    @property
    def venues(self):
        return [s.venue for s in self.schedules if s.venue]

    def get_ticketing_url(self):
        ticketing_url = getattr(self, 'ticketing_url', None)
        if ticketing_url:
            return ticketing_url

        schedules = [
            s for s in self.schedules
            if 'archived' not in s.state and getattr(s, 'ticketing_url', None)
            and s.ticket_type != 'Free admission'
        ]
        if schedules:
            return schedules[0].ticketing_url

        return None

    def get_contacts(self):
        if getattr(self, 'contacts', []):
            return getattr(self, 'contacts')
        else:
            return [
                venue.contacts[0] for venue in set(self.venues)
                if venue.contacts
            ]

    def get_zipcodes(self):
        zipcodes = [s.venue.zipcodes for s in self.schedules if s.venue]
        return [item for sublist in zipcodes for item in sublist]

    def get_more_contents_criteria(self):
        "return specific query, filter values"
        query, args = super(CulturalEvent, self).get_more_contents_criteria()
        zipcodes = self.get_zipcodes()
        if zipcodes:
            args['geographic_filter'] = {
                'valid_zipcodes': zipcodes,
                'zipcode': zipcodes
            }

        return query, args

    def get_visibility_filter(self):
        result = super(CulturalEvent, self).get_visibility_filter()
        zipcodes = self.get_zipcodes()
        authors = [self.author] if self.author else []
        result.update({
            'contribution_filter': {
                'authors': authors
            },
            'geographic_filter': {
                'valid_zipcodes': zipcodes,
                'zipcode': zipcodes
            }
        })
        return result

    def get_valid_schedules(self):
        return [s for s in self.schedules if 'archived' not in s.state]

    def get_duplicates(self, states=('published', )):
        return find_duplicates_cultural_events(self, states)