class ArgumentCell(LayoutCell): model_properties = [ 'id', 'title', 'abstract', 'details', 'created_at', 'author' ] footer = Cell.fragment('argument_footer') def details_link(self): if 'details_link' in self.options: return self.options['details_link'] return self.self_link
class ArgumentRelationCell(LayoutCell): model_properties = ['id', 'proposition', 'argument', 'score'] voting = Cell.fragment('argument_relation_voting') def show_voting(self): return self._request.permitted_for_current_user( self._model, VotePermission) def show_ca_button(self): return # self.current_user is not None def vote(self): return self._model.user_vote(self.current_user) def proposition_url(self): return self.link(self._model.proposition) def argument_url(self): return self.link(self._model.argument) def proposition_title(self): proposition = self._model.proposition if proposition.voting_identifier: return proposition.voting_identifier + ': ' + proposition.title else: return proposition.title def argument_title(self): return self.argument.title def upvote_button_disabled_class(self): return 'disabled' if self.vote is not None and self.vote.weight == 1 else '' def downvote_button_disabled_class(self): return 'disabled' if self.vote is not None and self.vote.weight == -1 else '' def revoke_vote_button_disabled_class(self): return 'disabled' if self.vote is None or self.vote.weight == 0 else '' def vote_action_url(self): return self.link(self._model, 'vote')
class TestCell(Cell): model_properties = ['id', 'title'] markup_class = DummyMarkup def _get_cell_class(self, model, view): return self.__class__ def test_url(self): return "https://example.com/test" @Cell.fragment def alternate_fragment(self, **k): return self.render_template('alternate_template', **k) @Cell.fragment def fragment_without_params(self): pass cannot_call_this = None fragment_from_name = Cell.fragment('name')
class PropositionCell(LayoutCell): model_properties = [ 'abstract', 'ballot', 'content', 'created_at', 'derivations', 'external_discussion_url', 'id', 'modifies', 'motivation', 'replacements', 'replaces', 'tags', 'title' ] actions = Cell.fragment('proposition_actions') tabs = Cell.fragment('proposition_tabs') small = Cell.fragment('proposition_small') card = Cell.fragment('proposition_card') @Cell.fragment def status(self): status_to_variant = { PropositionStatus.DRAFT: 'submitted', PropositionStatus.CHANGING: 'submitted', PropositionStatus.SUBMITTED: 'submitted', PropositionStatus.ABANDONED: 'submitted', PropositionStatus.QUALIFIED: 'submitted', PropositionStatus.SCHEDULED: 'scheduled', PropositionStatus.VOTING: 'scheduled', PropositionStatus.FINISHED: 'finished', } variant = status_to_variant[self._model.status] template = f"proposition/proposition_status_{variant}.j2.jade" return self.render_template(template) @Cell.fragment def history(self): status_to_variant = { PropositionStatus.DRAFT: 'submitted', PropositionStatus.CHANGING: 'submitted', PropositionStatus.SUBMITTED: 'submitted', PropositionStatus.ABANDONED: 'submitted', PropositionStatus.QUALIFIED: 'submitted', PropositionStatus.SCHEDULED: 'scheduled', PropositionStatus.VOTING: 'scheduled', PropositionStatus.FINISHED: 'finished', } variant = status_to_variant[self._model.status] template = f"proposition/proposition_history_{variant}.j2.jade" return self.render_template(template) def associated_url(self): return self.link(self._model, 'associated') def report_url(self): return self._s.app.report_url def share_url(self): if self._app.settings.share.use_url_shortener: from ekklesia_portal.helper.url_shortener import make_tiny return make_tiny(self.self_link) else: return self.self_link[:69] @log_call def share_email_url(self): share_email_topic = (self._s.share.email_topic[self.language] .format( voting_identifier=self._model.voting_identifier, title=self._model.title[:140])) share_email_body = self._s.share.email_body[self.language] + self.share_url email_url = urllib.parse.urlencode({'subject': share_email_topic, 'body': share_email_body}, quote_via=urllib.parse.quote) email_url = 'mailto:?' + email_url return email_url @log_call def share_twitter_url(self): share_tweet_msg = (self._s.share.tweet_msg[self.language] .format( voting_identifier=self._model.voting_identifier, title=self._model.title[:70])) twitter_url = urllib.parse.urlencode({'hashtags': self._app.settings.share.hashtag, 'related': self._app.settings.share.promote_account, 'text': share_tweet_msg, 'tw_p': 'tweetbutton', 'url': self.share_url}) twitter_url = 'https://twitter.com/intent/tweet?' + twitter_url return twitter_url def ballot_url(self): return self.link(self._model.ballot) def ballot_title(self): ballot = self._model.ballot if ballot.name: return ballot.name return f'# {ballot.id}' def discussion_url(self): return self.link(self._model) def propositions_tag_url(self, tag): return self.class_link(Propositions, dict(tag=tag.name)) def is_supported_by_current_user(self): return self._model.support_by_user(self.current_user) is not None def discussion_link_class(self): return 'active' if self.options.get('active_tab') == 'discussion' else '' def associated_link_class(self): return 'active' if self.options.get('active_tab') == 'associated' else '' def new_associated_proposition_url(self, association_type): return self.class_link(Propositions, dict(association_type=association_type), '+new') def new_pro_argument_url(self): return self.class_link( ArgumentRelations, dict(proposition_id=self._model.id, relation_type=ArgumentType.PRO.name), '+new') def new_con_argument_url(self): return self.class_link( ArgumentRelations, dict(proposition_id=self._model.id, relation_type=ArgumentType.CONTRA.name), '+new') def supporter_count(self): return self._model.active_supporter_count def support_action(self): return self.link(self._model, 'support') def pro_argument_relations(self): relations = [p for p in self._model.proposition_arguments if p.argument_type == ArgumentType.PRO] return sorted(relations, key=attrgetter('score'), reverse=True) def contra_argument_relations(self): relations = [p for p in self._model.proposition_arguments if p.argument_type == ArgumentType.CONTRA] return sorted(relations, key=attrgetter('score'), reverse=True) def argument_count(self): return len(self._model.proposition_arguments) def full_title(self): if self._model.voting_identifier: return self._model.voting_identifier + ': ' + self._model.title else: return self._model.title def show_support_actions(self): return self._request.permitted_for_current_user(self._model, SupportPermission) def show_create_argument(self): return self._request.permitted_for_current_user(ArgumentRelations(), CreatePermission) def show_create_associated_proposition(self): return self._request.permitted_for_current_user(self._model, CreatePermission) def voting_phase(self): return self._model.ballot.voting def voting_result_state(self): result = self._model.ballot.result if result: try: return OpenSlidesVotingResult(result.get(self._model.voting_identifier, {}).get("state")) except ValueError: return def voting_result_symbol(self): symbols = { OpenSlidesVotingResult.ACCEPTED: "fas fa-check", OpenSlidesVotingResult.REJECTED: "fas fa-ban", OpenSlidesVotingResult.NOT_DECIDED: "fas fa-spinner" } return symbols.get(self.voting_result_state) def show_edit_button(self): return self.options.get('show_edit_button') and self._request.permitted_for_current_user(self._model, EditPermission) def edit_url(self): return self.link(self._model, 'edit') def note_url(self): tmp = self.class_link(PropositionNote, variables={'proposition_id': self._model.id, 'user_id': self._request.current_user.id}, name='edit') return tmp
class PropositionsCell(LayoutCell): model_properties = [ 'department', 'phase', 'search', 'section', 'sort', 'status_values', 'subject_area', 'tag_values', 'type', 'without_tag_values', ] pager = Cell.fragment("propositions_pager") def propositions(self): is_admin = self.current_user and self._request.identity.has_global_admin_permissions return list(self._model.propositions(self._request.q, is_admin)) def prop_count(self): is_admin = self.current_user and self._request.identity.has_global_admin_permissions return self._model.propositions(self._request.q, is_admin, count=True) def page_count(self): per_page = self.prop_per_page if per_page <= 0: return -1 else: return int(math.ceil(self.prop_count / per_page)) def prop_per_page(self): return self._model.propositions_per_page() def page(self): return self._model.page or 1 # Overrides the base method in LayoutCell def search_query(self): return self._model.build_search_query() def change_self_link(self, **kwargs): propositions = self._model.replace(**kwargs) return self.link(propositions) def voting_phase_title(self, phase): voting_phase = self._request.q(VotingPhase).filter( func.lower(VotingPhase.name) == func.lower(phase)).scalar() if voting_phase is None: return phase return voting_phase.title def proposition_type_name(self, proposition_type): proposition_type = self._request.q(PropositionType).filter( func.lower(PropositionType.abbreviation) == func.lower( proposition_type)).scalar() if proposition_type is None: return proposition_type return proposition_type.name def visibility_values(self): if self.current_user and self._request.identity.has_global_admin_permissions: return self._model.visibility_values else: return None def export_csv_url(self): return (url_change_query(self.self_link, media_type="text/csv"))
class PropositionCell(LayoutCell): _model: Proposition model_properties = [ 'abstract', 'author', 'ballot', 'content', 'created_at', 'submitted_at', 'qualified_at', 'derivations', 'external_discussion_url', 'id', 'modifies', 'motivation', 'replacements', 'replaces', 'submitter_invitation_key', 'tags', 'title', 'secret_voters_count', 'secret_voters_user_count', 'secret_voting_quorum', ] actions = Cell.fragment('proposition_actions') tabs = Cell.fragment('proposition_tabs') small = Cell.fragment('proposition_small') card = Cell.fragment('proposition_card') @Cell.fragment def status(self): status_to_variant = { PropositionStatus.DRAFT: 'draft', PropositionStatus.CHANGING: 'submitted', PropositionStatus.SUBMITTED: 'submitted', PropositionStatus.ABANDONED: 'submitted', PropositionStatus.QUALIFIED: 'submitted', PropositionStatus.SCHEDULED: 'scheduled', PropositionStatus.VOTING: 'scheduled', PropositionStatus.FINISHED: 'finished', } variant = status_to_variant[self._model.status] template = f"proposition/status/proposition_status_{variant}.j2.jade" return self.render_template(template) @Cell.fragment def history(self): status_to_variant = { PropositionStatus.DRAFT: 'draft', PropositionStatus.CHANGING: 'submitted', PropositionStatus.SUBMITTED: 'submitted', PropositionStatus.ABANDONED: 'submitted', PropositionStatus.QUALIFIED: 'submitted', PropositionStatus.SCHEDULED: 'scheduled', PropositionStatus.VOTING: 'scheduled', PropositionStatus.FINISHED: 'finished', } variant = status_to_variant[self._model.status] template = f"proposition/history/proposition_history_{variant}.j2.jade" return self.render_template(template) @Cell.fragment def detail_top(self): variant = self._model.status if variant not in (PropositionStatus.DRAFT, PropositionStatus.SUBMITTED, PropositionStatus.QUALIFIED, PropositionStatus.SCHEDULED): return "" template = f"proposition/detail_top/proposition_detail_top_{variant}.j2.jade" return self.render_template(template) def associated_url(self): return self.link(self._model, 'associated') def report_url(self): return self._s.app.report_url def share_url(self): if self._app.settings.share.use_url_shortener: return make_tiny(self.self_link) return self.self_link[:69] @log_call def share_email_url(self): share_email_topic = (self._s.share.email_topic[self.language].format( voting_identifier=self._model.voting_identifier, title=self._model.title[:140])) share_email_body = self._s.share.email_body[ self.language] + self.share_url email_url = urllib.parse.urlencode( { 'subject': share_email_topic, 'body': share_email_body }, quote_via=urllib.parse.quote) email_url = 'mailto:?' + email_url return email_url @log_call def share_twitter_url(self): share_tweet_msg = (self._s.share.tweet_msg[self.language].format( voting_identifier=self._model.voting_identifier, title=self._model.title[:70])) twitter_url = urllib.parse.urlencode({ 'hashtags': self._app.settings.share.hashtag, 'related': self._app.settings.share.promote_account, 'text': share_tweet_msg, 'tw_p': 'tweetbutton', 'url': self.share_url }) twitter_url = 'https://twitter.com/intent/tweet?' + twitter_url return twitter_url def ballot_url(self): return self.link(self._model.ballot) def ballot_title(self): ballot = self._model.ballot if ballot.name: return ballot.name return f'# {ballot.id}' def discussion_url(self): return self.link(self._model) def propositions_tag_url(self, tag): return self.class_link(Propositions, dict(tags=tag.name)) def current_user_is_supporter(self): if self.current_user is None: return False return self._model.support_by_user(self.current_user) is not None def current_user_is_submitter(self): if self.current_user is None: return False return self._model.user_is_submitter(self.current_user) def current_user_is_author(self): if self.current_user is None: return False return self._model.author == self.current_user def discussion_link_class(self): return 'active' if self.options.get( 'active_tab') == 'discussion' else '' def associated_link_class(self): return 'active' if self.options.get( 'active_tab') == 'associated' else '' def new_associated_proposition_url(self, association_type): return self.class_link(Propositions, dict(association_type=association_type), '+new') def new_pro_argument_url(self): return self.class_link( ArgumentRelations, dict(proposition_id=self._model.id, relation_type=ArgumentType.PRO.name), '+new') def new_con_argument_url(self): return self.class_link( ArgumentRelations, dict(proposition_id=self._model.id, relation_type=ArgumentType.CONTRA.name), '+new') def missing_submitters_count(self): return self._model.ballot.proposition_type.policy.submitter_minimum - self._model.submitter_count def supporter_count(self): return self._model.active_supporter_count def become_submitter_action(self): return self.link(self._model, 'become_submitter') def secret_voting_action(self): return self.link(self._model, 'secret_voting') def support_action(self): return self.link(self._model, 'support') def pro_argument_relations(self): relations = [ p for p in self._model.proposition_arguments if p.argument_type == ArgumentType.PRO ] return sorted(relations, key=attrgetter('score'), reverse=True) def contra_argument_relations(self): relations = [ p for p in self._model.proposition_arguments if p.argument_type == ArgumentType.CONTRA ] return sorted(relations, key=attrgetter('score'), reverse=True) def argument_count(self): return len(self._model.proposition_arguments) def full_title(self): if self._model.voting_identifier: return self._model.voting_identifier + ': ' + self._model.title return self._model.title def ready_to_submit(self): return self._model.ready_to_submit def show_support_actions(self): return self._model.status in ( PropositionStatus.SUBMITTED, PropositionStatus.QUALIFIED, PropositionStatus.SCHEDULED, PropositionStatus.VOTING ) and self._request.permitted_for_current_user(self._model, SupportPermission) def show_submit_draft_action(self): return self._model.ready_to_submit and self._request.permitted_for_current_user( self._model, SubmitDraftPermission) def show_create_argument(self): return self._model.status in ( PropositionStatus.SUBMITTED, PropositionStatus.QUALIFIED, PropositionStatus.SCHEDULED, PropositionStatus.VOTING, PropositionStatus.ABANDONED ) and self._request.permitted_for_current_user(ArgumentRelations(), CreatePermission) def show_goto_arguments(self): return self._model.status in (PropositionStatus.SUBMITTED, PropositionStatus.QUALIFIED, PropositionStatus.SCHEDULED, PropositionStatus.VOTING, PropositionStatus.ABANDONED) def show_create_associated_proposition(self): return self._model.status in ( PropositionStatus.DRAFT, PropositionStatus.SUBMITTED, PropositionStatus.QUALIFIED, PropositionStatus.SCHEDULED ) and self._request.permitted_for_current_user(self._model, CreatePermission) def show_submitter_names(self): if self.current_user is None: return False if self._model.ballot.area.department in self.current_user.managed_departments: return True if self._request.identity.has_global_admin_permissions: return True if self._model.user_is_submitter(self.current_user): return True if self._model.author == self.current_user: return True return False def valid_submitter_invitation_key(self): key = self._request.GET.get("submitter_invitation_key") if key is None: return False return compare_digest(self._model.submitter_invitation_key, key) def voting_phase(self): return self._model.ballot.voting def voting_result_state(self): result = self._model.ballot.result if result: try: return OpenSlidesVotingResult( result.get(self._model.voting_identifier, {}).get("state")) except ValueError: pass return None def voting_result_symbol(self): symbols = { OpenSlidesVotingResult.ACCEPTED: "fas fa-check", OpenSlidesVotingResult.REJECTED: "fas fa-ban", OpenSlidesVotingResult.NOT_DECIDED: "fas fa-spinner" } return symbols.get(self.voting_result_state) def show_edit_button(self): return self._request.permitted_for_current_user( self._model, EditPermission) def submit_draft_url(self): return self.link(self._model, 'submit_draft') def edit_url(self): return self.link(self._model, 'edit') def note_url(self): if self.current_user is None: return False return self.class_link(PropositionNote, variables={ 'proposition_id': self._model.id, 'user_id': self._request.current_user.id }, name='edit') def become_submitter_url(self): return self.self_link + f"?submitter_invitation_key={self._model.submitter_invitation_key}" def submitter_names(self): return [ pm.member.name for pm in self._model.propositions_member if pm.submitter ] def show_full_history(self): return self.options.get('show_details') def secret_voting(self): user_id = None if self.current_user is not None: user_id = self.current_user.id secret_record = self._request.db_session.query(SecretVoter).filter_by( member_id=user_id, ballot_id=self._model.ballot_id).scalar() stat = 'retracted' if secret_record is not None: stat = secret_record.status return stat == 'active'