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

Commit

Permalink
Handle Slack app_uninstalled callback event (#331)
Browse files Browse the repository at this point in the history
  • Loading branch information
alysivji authored Oct 1, 2020
1 parent 44178ac commit 720ed69
Show file tree
Hide file tree
Showing 12 changed files with 407 additions and 152 deletions.
4 changes: 3 additions & 1 deletion busy_beaver/apps/call_for_proposals/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ def __repr__(self): # pragma: no cover
enabled = db.Column(db.Boolean, default=False, nullable=False)
installation_id = db.Column(
db.Integer,
db.ForeignKey("slack_installation.id", name="fk_installation_id"),
db.ForeignKey(
"slack_installation.id", name="fk_installation_id", ondelete="CASCADE"
),
nullable=False,
)
channel = db.Column(db.String(20), nullable=False)
Expand Down
8 changes: 6 additions & 2 deletions busy_beaver/apps/github_integration/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ def __repr__(self): # pragma: no cover
enabled = db.Column(db.Boolean, default=False, nullable=False)
installation_id = db.Column(
db.Integer,
db.ForeignKey("slack_installation.id", name="fk_installation_id"),
db.ForeignKey(
"slack_installation.id", name="fk_installation_id", ondelete="CASCADE"
),
nullable=False,
)
channel = db.Column(db.String(20), nullable=False)
Expand Down Expand Up @@ -80,7 +82,9 @@ def __repr__(self): # pragma: no cover
config_id = db.Column(
db.Integer,
db.ForeignKey(
"github_summary_configuration.id", name="fk_github_summary_configuration_id"
"github_summary_configuration.id",
name="fk_github_summary_configuration_id",
ondelete="CASCADE",
),
nullable=False,
)
Expand Down
22 changes: 20 additions & 2 deletions busy_beaver/apps/slack_integration/event_subscription.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@


def process_event_subscription_callback(data):
logger.info("Process Event Subscription webhook", extra={"type": data["type"]})
return subscription_dispatch.emit(data["type"], default="not_found", data=data)


#######################
# Subscription Handlers
#######################
@subscription_dispatch.on("app_uninstalled") # TODO
@subscription_dispatch.on("not_found")
@event_dispatch.on("not_found")
def command_not_found(data):
Expand All @@ -44,7 +44,10 @@ def url_verification_handler(data):

@subscription_dispatch.on("event_callback")
def event_callback_dispatcher(data):
logger.info("[Busy Beaver] Slack -- Event Callback")
logger.info(
f"Process Event Callback -- {data['event']['type']}",
extra={"event_type": data["event"]["type"]},
)
return event_dispatch.emit(data["event"]["type"], default="not_found", data=data)


Expand Down Expand Up @@ -135,3 +138,18 @@ def app_home_handler(data):
slack = SlackClient(installation.bot_access_token)
slack.display_app_home(user_id, view=app_home.to_dict())
return None


@event_dispatch.on("app_uninstalled")
def app_uninstalled_handler(data):
workspace_id = data["team_id"]
installation = SlackInstallation.query.filter_by(workspace_id=workspace_id).first()

if not installation:
logger.error("Workspace not found", extra={"workspace_id": workspace_id})
return {}

db.session.delete(installation)
db.session.commit()

return {}
13 changes: 9 additions & 4 deletions busy_beaver/apps/slack_integration/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@ def __repr__(self): # pragma: no cover
return f"<SlackInstallation: {self.workspace_name}>"

# Attributes
access_token = db.Column(
EncryptedType(db.String, SECRET_KEY, AesEngine, "pkcs5"), nullable=False
)
authorizing_user_id = db.Column(db.String(300), nullable=False)
bot_access_token = db.Column(
EncryptedType(db.String, SECRET_KEY, AesEngine, "pkcs5"), nullable=False
Expand All @@ -38,23 +35,29 @@ def __repr__(self): # pragma: no cover
workspace_logo_url = db.Column(URLType, nullable=True)

# Relationships
slack_users = db.relationship(
"SlackUser", back_populates="installation", lazy="select", cascade="all, delete"
)
github_summary_config = db.relationship(
"GitHubSummaryConfiguration",
back_populates="slack_installation",
uselist=False,
lazy="joined",
cascade="all, delete",
)
upcoming_events_config = db.relationship(
"UpcomingEventsConfiguration",
back_populates="slack_installation",
uselist=False,
lazy="joined",
cascade="all, delete",
)
cfp_config = db.relationship(
"CallForProposalsConfiguration",
back_populates="slack_installation",
uselist=False,
lazy="joined",
cascade="all, delete",
)


Expand All @@ -65,7 +68,9 @@ class SlackUser(UserMixin, BaseModel):

installation_id = db.Column(
db.Integer,
db.ForeignKey("slack_installation.id", name="fk_installation_id"),
db.ForeignKey(
"slack_installation.id", name="fk_installation_id", ondelete="CASCADE"
),
index=True,
nullable=False,
)
Expand Down
2 changes: 0 additions & 2 deletions busy_beaver/apps/slack_integration/oauth/oauth_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
# Slack Installation
####################
class SlackOAuthInfo(NamedTuple):
access_token: str
authorizing_user_id: str
bot_access_token: str
bot_user_id: str
Expand Down Expand Up @@ -124,7 +123,6 @@ def _parse_json_response(self, code):

# TODO do this with marshmallow
output = {}
output["access_token"] = oauth_json["authed_user"]["access_token"]
output["scope"] = oauth_json["scope"]
output["authorizing_user_id"] = oauth_json["authed_user"]["id"]
output["workspace_id"] = oauth_json["team"]["id"]
Expand Down
5 changes: 4 additions & 1 deletion busy_beaver/apps/upcoming_events/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ def __repr__(self): # pragma: no cover
enabled = db.Column(db.Boolean, default=False, nullable=False)
installation_id = db.Column(
db.Integer,
db.ForeignKey("slack_installation.id", name="fk_installation_id"),
db.ForeignKey(
"slack_installation.id", name="fk_installation_id", ondelete="CASCADE"
),
nullable=False,
)

Expand Down Expand Up @@ -136,6 +138,7 @@ def __repr__(self): # pragma: no cover
db.ForeignKey(
"upcoming_events_configuration.id",
name="fk_upcoming_events_configuration_id",
ondelete="CASCADE",
),
nullable=False,
)
Expand Down
33 changes: 33 additions & 0 deletions migrations/versions/20201001_18-36-02__remove_user_token_column.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"""remove user token column
Revision ID: 1fe0aa535040
Revises: e51108c88034
Create Date: 2020-10-01 18:36:02.685882
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql

# revision identifiers, used by Alembic.
revision = "1fe0aa535040"
down_revision = "e51108c88034"
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column("slack_installation", "access_token")
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column(
"slack_installation",
sa.Column(
"access_token", postgresql.BYTEA(), autoincrement=False, nullable=True
),
)
# ### end Alembic commands ###
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
"""add cascade delete to foreign key relationships
Revision ID: b99005e9733d
Revises: 1fe0aa535040
Create Date: 2020-10-01 19:05:34.770544
"""
from alembic import op

# revision identifiers, used by Alembic.
revision = "b99005e9733d"
down_revision = "1fe0aa535040"
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(
"fk_installation_id", "call_for_proposals_configuration", type_="foreignkey"
)
op.create_foreign_key(
"fk_installation_id",
"call_for_proposals_configuration",
"slack_installation",
["installation_id"],
["id"],
ondelete="CASCADE",
)
op.drop_constraint(
"fk_installation_id", "github_summary_configuration", type_="foreignkey"
)
op.create_foreign_key(
"fk_installation_id",
"github_summary_configuration",
"slack_installation",
["installation_id"],
["id"],
ondelete="CASCADE",
)
op.drop_constraint(
"fk_github_summary_configuration_id", "github_summary_user", type_="foreignkey"
)
op.create_foreign_key(
"fk_github_summary_configuration_id",
"github_summary_user",
"github_summary_configuration",
["config_id"],
["id"],
ondelete="CASCADE",
)
op.drop_constraint("fk_installation_id", "slack_user", type_="foreignkey")
op.create_foreign_key(
"fk_installation_id",
"slack_user",
"slack_installation",
["installation_id"],
["id"],
ondelete="CASCADE",
)
op.drop_constraint(
"fk_installation_id", "upcoming_events_configuration", type_="foreignkey"
)
op.create_foreign_key(
"fk_installation_id",
"upcoming_events_configuration",
"slack_installation",
["installation_id"],
["id"],
ondelete="CASCADE",
)
op.drop_constraint(
"fk_upcoming_events_configuration_id",
"upcoming_events_group",
type_="foreignkey",
)
op.create_foreign_key(
"fk_upcoming_events_configuration_id",
"upcoming_events_group",
"upcoming_events_configuration",
["config_id"],
["id"],
ondelete="CASCADE",
)
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(
"fk_upcoming_events_configuration_id",
"upcoming_events_group",
type_="foreignkey",
)
op.create_foreign_key(
"fk_upcoming_events_configuration_id",
"upcoming_events_group",
"upcoming_events_configuration",
["config_id"],
["id"],
)
op.drop_constraint(
"fk_installation_id", "upcoming_events_configuration", type_="foreignkey"
)
op.create_foreign_key(
"fk_installation_id",
"upcoming_events_configuration",
"slack_installation",
["installation_id"],
["id"],
)
op.drop_constraint("fk_installation_id", "slack_user", type_="foreignkey")
op.create_foreign_key(
"fk_installation_id",
"slack_user",
"slack_installation",
["installation_id"],
["id"],
)
op.drop_constraint(
"fk_github_summary_configuration_id", "github_summary_user", type_="foreignkey"
)
op.create_foreign_key(
"fk_github_summary_configuration_id",
"github_summary_user",
"github_summary_configuration",
["config_id"],
["id"],
)
op.drop_constraint(
"fk_installation_id", "github_summary_configuration", type_="foreignkey"
)
op.create_foreign_key(
"fk_installation_id",
"github_summary_configuration",
"slack_installation",
["installation_id"],
["id"],
)
op.drop_constraint(
"fk_installation_id", "call_for_proposals_configuration", type_="foreignkey"
)
op.create_foreign_key(
"fk_installation_id",
"call_for_proposals_configuration",
"slack_installation",
["installation_id"],
["id"],
)
# ### end Alembic commands ###
1 change: 0 additions & 1 deletion scripts/dev/populate_database.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@
)
else:
installation = SlackInstallation(
access_token="access_token",
authorizing_user_id=authorizing_user_id,
bot_access_token=bot_token,
bot_user_id=bot_user_id,
Expand Down
1 change: 0 additions & 1 deletion tests/_utilities/factories/slack.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ class Meta:
sqlalchemy_session_persistence = "commit"
sqlalchemy_session = session

access_token = factory.Faker("uuid4")
authorizing_user_id = "abc"

bot_access_token = factory.Faker("uuid4")
Expand Down
Loading

0 comments on commit 720ed69

Please sign in to comment.