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)
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]+'...'
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
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)
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])
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
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)
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)
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]+'...'
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
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))
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
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
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
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)
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
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
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)
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)
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')
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)
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)})
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
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
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>', '')
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)