{ "policy_kind": "Trigger", "action_types": [ "slackpostmessage" ], "name": "Consensus vote in Slack with restricted voting + reminder", "description": "Allows users to trigger a vote in the #core-group slack channel. Only core group members are able to cast votes. Following community policy, all votes must pass via consensus. One day before a policy is about to be resolved by default, reminds core-group members that the vote is still open. ", "is_bundled": false, "filter": "return action.text.startswith(\"core-group-vote\")\n", "initialize": "pass", "check": "# CONSTANTS\nCHANNEL = \"C0ABC123\"\nLENGTH_OF_VOTE_IN_DAYS = 5\nMINIMUM_YES_VOTES = 2\nMAXIMUM_NO_VOTES = 0\nELIGIBLE_VOTERS = [\"U01\", \"U02\", \"U03\", \"U04\", \"U05\", \"U06\"] \n\n# save for later\nproposal.data.set(\"eligible_voters\", ELIGIBLE_VOTERS) \nproposal.data.set(\"discussion_channel\", CHANNEL)\n\nif not proposal.vote_post_id:\n return PROPOSED #the vote hasn't started yet\n\n# vote info\nconsent_votes = proposal.get_choice_votes(value=\"consent\")\nobject_votes = proposal.get_choice_votes(value=\"object\")\nabstain_votes = proposal.get_choice_votes(value=\"abstain\")\nlogger.debug(f\"{consent_votes} for, {object_votes} against, {abstain_votes} abstain\")\n\n# if everyone has consented or abstained, the vote passes\nif len(consent_votes) + len(abstain_votes) == len(ELIGIBLE_VOTERS):\n return PASSED\n\n# if voting is almost over, remind people who haven't voted\nreminder_sent = proposal.data.get('reminder_sent')\nif not reminder_sent and proposal.get_time_elapsed() > datetime.timedelta(days=LENGTH_OF_VOTE_IN_DAYS-1):\n already_voted = proposal.get_choice_votes().values_list(\"user__username\")\n already_voted_list = [voter[0] for voter in already_voted]\n nonvoter_list = [f\"<@{uid}>\" for uid in ELIGIBLE_VOTERS if uid not in already_voted_list]\n nonvoter_string = \", \".join(nonvoter_list)\n logger.debug(f\"Eligible voters: {ELIGIBLE_VOTERS}; Already voted: {already_voted}; Nonvoter list: {nonvoter_list}\")\n reminder_msg = f\"There is one day left to vote on this proposal. {nonvoter_string} have not voted yet.\"\n slack.post_message(text=reminder_msg, channel=action.channel, thread_ts=proposal.vote_post_id)\n proposal.data.set(\"reminder_sent\", True)\n\n# if time's up, resolve\nif proposal.get_time_elapsed() > datetime.timedelta(days=LENGTH_OF_VOTE_IN_DAYS):\n \n if object_votes.count() > MAXIMUM_NO_VOTES:\n return FAILED\n if consent_votes.count() < MINIMUM_YES_VOTES:\n return FAILED\n return PASSED\n\nreturn PROPOSED # still pending", "notify": "# Start a vote on Slack\ndiscussion_channel = proposal.data.get('discussion_channel')\neligible_voters = proposal.data.get('eligible_voters')\nproposal_text = action.text.replace(\"core-group-vote \", \"\").strip()\nmessage = f\"<@channel>, please respond to this proposal: {proposal_text} If all core group members respond by consenting or abstaining, or if after five days there are no objections and at least two consents, the proposal passes.\"\nslack.initiate_vote(text=message, channel=discussion_channel, \n users=eligible_voters, options=[\"consent\", \"object\", \"abstain\"])\nslack.post_message(text=\"Discuss here! :meow-wave:\", channel=discussion_channel, thread_ts=proposal.vote_post_id)", "success": "# Announce result on thread\ntext = f\"<@{action.initiator.username}>'s proposal passed!\"\nslack.post_message(text=text, channel=action.channel, thread_ts=proposal.vote_post_id)", "fail": "# Announce result on thread\ntext = f\"<@{action.initiator.username}>'s proposal failed.\"\nslack.post_message(text=text, channel=action.channel, thread_ts=proposal.vote_post_id)" }