Skip to content
This repository has been archived by the owner on Oct 21, 2024. It is now read-only.

Restructure on-boarding from Slack messages to website #301

Merged
merged 11 commits into from
Jul 26, 2020
27 changes: 2 additions & 25 deletions busy_beaver/apps/slack_integration/api/oauth.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
import logging

from finite_state_machine.exceptions import InvalidStartState
from flask import jsonify, redirect, request, url_for
from flask.views import MethodView
from flask_login import login_user

from busy_beaver.apps.slack_integration.oauth.state_machine import (
SlackInstallationOnboardUserStateMachine,
)
from busy_beaver.apps.slack_integration.oauth.workflow import (
process_slack_installation_callback,
process_slack_sign_in_callback,
send_welcome_message,
)
from busy_beaver.extensions import db

logger = logging.getLogger(__name__)

Expand All @@ -24,26 +20,7 @@ def get(self):
logger.info("Slack Workspace Installation")
callback_url = request.url
installation = process_slack_installation_callback(callback_url)

slack_installation_fsm = SlackInstallationOnboardUserStateMachine(installation)
try:
slack_installation_fsm.welcome_user()
except InvalidStartState:
pass
else:
installation.state = slack_installation_fsm.state
db.session.add(installation)
db.session.commit()

try:
slack_installation_fsm.save_new_slack_installation_information()
except InvalidStartState:
pass
else:
installation.state = slack_installation_fsm.state
db.session.add(installation)
db.session.commit()

send_welcome_message(installation)
# TODO take them an actual page
return jsonify({"Installation": "successful"})

Expand Down
47 changes: 14 additions & 33 deletions busy_beaver/apps/slack_integration/event_subscription.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
import logging

from finite_state_machine.exceptions import TransitionNotAllowed

from .blocks import AppHome
from .slash_command import HELP_TEXT
from busy_beaver.apps.slack_integration.oauth.state_machine import (
SlackInstallationOnboardUserStateMachine,
)
from busy_beaver.apps.slack_integration.oauth.workflow import (
GITHUB_SUMMARY_CHANNEL_JOIN_MESSAGE,
)
from busy_beaver.common.wrappers import SlackClient
from busy_beaver.extensions import db
from busy_beaver.models import GitHubSummaryConfiguration, SlackInstallation, SlackUser
from busy_beaver.models import SlackInstallation, SlackUser
from busy_beaver.toolbox import EventEmitter

logger = logging.getLogger(__name__)
subscription_dispatch = EventEmitter()
event_dispatch = EventEmitter()


GITHUB_SUMMARY_CHANNEL_JOIN_MESSAGE = (
"Welcome to <#{channel}>! I'm Busy Beaver. "
"I post daily summaries of public GitHub activity "
"in this channel.\n\n"
"To connect your GitHub account and share activity, "
"please register using `/busybeaver connect`."
)


def process_event_subscription_callback(data):
return subscription_dispatch.emit(data["type"], default="not_found", data=data)

Expand Down Expand Up @@ -76,32 +77,12 @@ def member_joined_channel_handler(data):

installation = SlackInstallation.query.filter_by(workspace_id=workspace_id).first()

# handle when bot is invited to channel
bot_invited_to_channel = user_id == installation.bot_user_id
if bot_invited_to_channel:
try:
installation_fsm = SlackInstallationOnboardUserStateMachine(installation)
installation_fsm.send_initial_configuration_request(channel)
except TransitionNotAllowed:
# bot invited to channel when there is already a record
# invalid start state
# TODO always store new channels somewhere
return None

github_summary_config = GitHubSummaryConfiguration(channel=channel)
github_summary_config.slack_installation = installation
db.session.add(github_summary_config)

installation.state = installation_fsm.state
db.session.add(installation)
db.session.commit()
# Handle if new user joins channel
config = installation.github_summary_config
if not config:
return None

# Handle if new user joins channel
user_joins_github_summary_channel = (
installation.github_summary_config.channel == channel
and installation.state == "active"
)
user_joins_github_summary_channel = (config.channel == channel) and config.enabled
if user_joins_github_summary_channel:
slack = SlackClient(installation.bot_access_token)
slack.post_ephemeral_message(
Expand Down
1 change: 0 additions & 1 deletion busy_beaver/apps/slack_integration/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ def __repr__(self): # pragma: no cover
scope = db.Column(db.String(800), nullable=False)
workspace_id = db.Column(db.String(20), index=True, nullable=False)
workspace_name = db.Column(db.String(255), nullable=False)
state = db.Column(db.String(20), nullable=False, default="installed")

auth_response = db.Column("auth_response", db.JSON)

Expand Down
56 changes: 0 additions & 56 deletions busy_beaver/apps/slack_integration/oauth/state_machine.py

This file was deleted.

58 changes: 15 additions & 43 deletions busy_beaver/apps/slack_integration/oauth/workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@

from busy_beaver.clients import slack_install_oauth, slack_signin_oauth
from busy_beaver.common.wrappers import SlackClient
from busy_beaver.config import BASE_URL
from busy_beaver.extensions import db
from busy_beaver.models import SlackInstallation, SlackUser
from busy_beaver.models import GitHubSummaryConfiguration, SlackInstallation, SlackUser

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -80,8 +79,7 @@ def process_slack_installation_callback(callback_url):
"Hi <@{slack_id}>! :wave:\n\n"
"I'm here to help engage tech-focused Slack communities.\n"
"Thank you for taking part in our beta program. :pray:\n\n"
":zap: To get started `/invite` me to a public channel\n"
":bulb: I recommend creating `#busy-beaver`"
":zap: `/busybeaver settings` to configure Busy Beaver\n"
)


Expand All @@ -91,59 +89,33 @@ def send_welcome_message(installation: SlackInstallation):
slack.dm(ONBOARDING_MESSAGE.format(slack_id=user_id), user_id=user_id)


CONFIRMED_MESSAGE = (
"Thanks for the invite! I will post daily summaries in <#{channel}>\n\n"
f"<{BASE_URL}/settings/github-summary|Configure when to post messages>"
)


def send_configuration_message(installation: SlackInstallation, channel):
slack = SlackClient(installation.bot_access_token)
user_id = installation.authorizing_user_id
slack.dm(CONFIRMED_MESSAGE.format(channel=channel), user_id=user_id)


ACTIVE_MESSAGE = (
"Confirmed; I will post daily summaries at {time}.\n\n"
"Busy Beaver is now active! :tada: \n\n"
"GitHub Summary feature is active! :tada: \n\n"
"You can use the following text to publicize the bot:\n"
"> Busy Beaver is a community engagement bot that shares daily "
"sumarries of public GitHub activity for registered users. "
"Find out what everybody's working on in <#{channel}>!"
)


def save_configuration(installation, time_to_post, timezone_to_post, slack_id):
def create_or_update_configuration(
installation, channel, summary_post_time, summary_post_timezone, slack_id
):
config = installation.github_summary_config
config.summary_post_time = time_to_post
config.summary_post_timezone = timezone_to_post
if config is None:
config = GitHubSummaryConfiguration()
config.slack_installation = installation
config.enabled = True
config.channel = channel
config.summary_post_time = summary_post_time
config.summary_post_timezone = summary_post_timezone
db.session.add(config)
db.session.commit()

channel = config.channel
slack = SlackClient(installation.bot_access_token)
slack.dm(
ACTIVE_MESSAGE.format(time=str(time_to_post), channel=channel), user_id=slack_id
ACTIVE_MESSAGE.format(time=str(summary_post_time), channel=channel),
user_id=slack_id,
)


REINSTALL_MESSAGE = (
"Thank you for reinstalling! I will post daily summaries in <#{channel}>\n\n"
f"<{BASE_URL}/settings/github-summary|Configure when to post messages>"
)


def reinstallation(installation):
slack = SlackClient(installation.bot_access_token)
channel = installation.github_summary_config.channel
slack_id = installation.authorizing_user_id
slack.dm(REINSTALL_MESSAGE.format(channel=channel), user_id=slack_id)


GITHUB_SUMMARY_CHANNEL_JOIN_MESSAGE = (
"Welcome to <#{channel}>! I'm Busy Beaver. "
"I post daily summaries of public GitHub activity "
"in this channel.\n\n"
"To connect your GitHub account and share activity, "
"please register using `/busybeaver connect`."
)
2 changes: 1 addition & 1 deletion busy_beaver/apps/upcoming_events/upcoming_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def _next_event_attachment(event: EventDetails) -> dict:
"""Make a Slack attachment for the event."""
return {
"mrkdwn_in": ["text", "pretext"],
"pretext": "*Next ChiPy Event:*",
"pretext": "*Next Event:*",
"title": event.name,
"title_link": event.url,
"fallback": f"{event.name}: {event.url}",
Expand Down
19 changes: 19 additions & 0 deletions busy_beaver/apps/web/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,31 @@
TZ_CHOICES = sorted(
add_gmt_offset_to_timezone(TIMEZONES), key=lambda x: int(x[1][3:5]), reverse=True
)
WEEKDAYS = [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
]


class GitHubSummaryConfigurationForm(FlaskForm):
channel = SelectField(label="Channel")

summary_post_time = TimeField(
"When to post GitHub Summary?", validators=[DataRequired()]
)
summary_post_timezone = SelectField(
label="Timezone", choices=TZ_CHOICES, default="UTC"
)


class UpcomingEventsConfigurationForm(FlaskForm):
channel = SelectField(label="Channel")

day_of_week = SelectField("Day to post", choices=WEEKDAYS, default="Monday")
post_time = TimeField("Time to post", validators=[DataRequired()])
post_timezone = SelectField(label="Timezone", choices=TZ_CHOICES, default="UTC")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Originally started working on the Upcoming Events configuration, but it makes sense to simplify onboarding before doing that work

Loading