Skip to content

Commit

Permalink
Merge pull request #28 from Sarthak5598/shifting-to-bolt
Browse files Browse the repository at this point in the history
Introducing Slack Bolt 🎉🎉
  • Loading branch information
Sarthak5598 authored Jul 29, 2024
2 parents e64718a + e5e07c9 commit 56ffbd0
Show file tree
Hide file tree
Showing 12 changed files with 220 additions and 480 deletions.
210 changes: 141 additions & 69 deletions app.py
Original file line number Diff line number Diff line change
@@ -1,73 +1,145 @@
import os

import requests
from dotenv import load_dotenv
from flask import Flask, jsonify
from slack import WebClient
from slackeventsapi import SlackEventAdapter

DEPLOYS_CHANNEL_NAME = "#slack_bot_deploys"
JOINS_CHANNEL_ID = "C0762DHUUH1"

GITHUB_API_URL = "https://github.com/OWASP-BLT/BLT"
load_dotenv()


app = Flask(__name__)

slack_events_adapter = SlackEventAdapter(os.environ["SIGNING_SECRET"], "/slack/events", app)
client = WebClient(token=os.environ["SLACK_TOKEN"])
client.chat_postMessage(channel=DEPLOYS_CHANNEL_NAME, text="bot started v1.8 24-05-28 top")


def fetch_github_data(owner, repo):
prs = requests.get(f"{GITHUB_API_URL}/repos/{owner}/{repo}/pulls?state=closed").json()
issues = requests.get(f"{GITHUB_API_URL}/repos/{owner}/{repo}/issues?state=closed").json()
comments = requests.get(f"{GITHUB_API_URL}/repos/{owner}/{repo}/issues/comments").json()
return prs, issues, comments


def format_data(prs, issues, comments):
user_data = {}

for pr in prs:
user = pr["user"]["login"]
if user not in user_data:
user_data[user] = {"prs": 0, "issues": 0, "comments": 0}
user_data[user]["prs"] += 1

for issue in issues:
user = issue["user"]["login"]
if user not in user_data:
user_data[user] = {"prs": 0, "issues": 0, "comments": 0}
user_data[user]["issues"] += 1

for comment in comments:
user = comment["user"]["login"]
if user not in user_data:
user_data[user] = {"prs": 0, "issues": 0, "comments": 0}
user_data[user]["comments"] += 1
import json
import logging
import re
from datetime import datetime, timedelta

from dotenv import dotenv_values
from github import Github
from slack_bolt.adapter.socket_mode import SocketModeHandler
from slack_bolt.app import App

import settings
from src.sammich.plugins.contributors import fetch_github_data, format_data
from src.sammich.plugins.project import show_project_page

PROJECTS_PER_PAGE = 100
# Load environment variables
secrets = dotenv_values(".secrets")

SLACK_APP_TOKEN = secrets["SLACK_APP_TOKEN"]
SLACK_BOT_TOKEN = secrets["SLACK_BOT_TOKEN"]
GITHUB_TOKEN = secrets["GITHUB_TOKEN"]

# Initialize Slack App
app = App(token=SLACK_BOT_TOKEN)


@app.command("/contributors")
def contributors(ack, say, command):
ack()
since_date = (datetime.now() - timedelta(days=7)).date()
prs, issues, comments = fetch_github_data("OWASP-BLT", "Lettuce", since_date)
formatted_data = format_data(prs, issues, comments)
if not formatted_data:
formatted_data = [
{"type": "section", "text": {"type": "mrkdwn", "text": "No data available"}}
]
say(text="Contributors Activity", blocks=formatted_data)


@app.command("/ghissue")
async def createissue(self, command):
channel_id = command._cmd_payload["channel_id"]
title = command.text.strip()
github = Github(GITHUB_TOKEN)
try:
repo = github.get_repo(
f"{settings.GITHUB_REPOSITORY_OWNER}/{settings.GITHUB_REPOSITORY_NAME}"
)
issue = repo.create_issue(title=title)
await self.say(channel_id, f"Issue created successfully: {issue.html_url}")
except Exception:
logging.error("Failed to create issue")
await self.say(channel_id, "Failed to create issue")


with open("data/projects.json") as f:
project_data = json.load(f)

with open("data/repos.json") as f:
repo_data = json.load(f)


@app.command("/project")
def project(ack, command, say):
ack() # Acknowledge the command
project_name = command["text"].strip().lower()
channel_id = command["channel_id"]
project = project_data.get(project_name)
if project:
project_list = "\n".join(project)
message = f"Hello, here is the information about '{project_name}':\n{project_list}"
say(message)
else:
show_project_page(channel_id, say)


@app.action(re.compile(r"project_select_action_.*"))
def handle_dropdown_selection(ack, body, say):
ack() # Acknowledge the interaction
selected_project = body["actions"][0]["selected_option"]["value"]
project = project_data.get(selected_project)
project_list = "\n".join(project)
message = f"Hello, here is the information about '{selected_project}':\n{project_list}"
say(message)


@app.command("/repo")
def repo(ack, command, say):
ack()
tech_name = command["text"].strip().lower()
channel_id = command["channel_id"]

repos = repo_data.get(tech_name)
if repos:
repos_list = "\n".join(repos)
message = f"Hello, you can implement your '{tech_name}' knowledge here:\n{repos_list}"
say(message)
else:
fallback_message = "Available technologies:"
message_preview = {
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "Here are the available technologies to choose from:",
},
},
{
"type": "actions",
"block_id": "tech_select_block",
"elements": [
{
"type": "button",
"text": {"type": "plain_text", "text": tech},
"value": tech,
"action_id": f"plugin_repo_button_{tech}",
}
for tech in repo_data.keys()
],
},
]
}

table = (
"User | PRs Merged | Issues Resolved | Comments\n"
" ---- | ---------- | --------------- | --------\n"
say(
channel=channel_id,
blocks=message_preview["blocks"],
text=fallback_message,
)


@app.action(re.compile(r"plugin_repo_button_.*"))
def handle_button_click(ack, body, say):
ack()
clicked_button_value = body["actions"][0]["value"]
repos = repo_data.get(clicked_button_value)
repos_list = "\n".join(repos)
message = (
f"Hello, you can implement your '{clicked_button_value}' knowledge here:\n{repos_list}"
)
for user, counts in user_data.items():
table += f"{user} | {counts['prs']} | {counts['issues']} | {counts['comments']}\n"

return table
say(message)


@app.route("/contributors", methods=["POST"])
def contributors():
owner = "OWASP-BLT"
repo = "BLT"

prs, issues, comments = fetch_github_data(owner, repo)

return jsonify(
{
"response_type": "in_channel",
"text": format_data(prs, issues, comments) or "No data available",
}
)
if __name__ == "__main__":
SocketModeHandler(app, SLACK_APP_TOKEN).start()
16 changes: 15 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ slackeventsapi = "^3.0.1"
requests = "^2.32.3"
dateparser = "^1.2.0"
pygithub = "^2.3.0"
slack-bolt = "^1.19.1"

[tool.poetry.group.dev.dependencies]
pytest = "^8.2.2"
Expand Down
15 changes: 0 additions & 15 deletions src/local_settings.py

This file was deleted.

52 changes: 20 additions & 32 deletions src/sammich/plugins/contributors.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
import os

import requests
from dotenv import load_dotenv
from machine.plugins.base import MachineBasePlugin
from machine.plugins.decorators import command
from dotenv import dotenv_values

load_dotenv()
secrets = dotenv_values(".secrets")

GITHUB_API_URL = "https://api.github.com"
GITHUB_TOKEN = os.getenv("GITHUB_TOKEN")
GITHUB_TOKEN = secrets["GITHUB_TOKEN"]


def fetch_github_data(owner, repo):
def fetch_github_data(owner, repo, since_date):
headers = {"Authorization": f"token {GITHUB_TOKEN}"}
prs = requests.get(
f"{GITHUB_API_URL}/repos/{owner}/{repo}/pulls?state=closed", headers=headers
).json()
issues = requests.get(
f"{GITHUB_API_URL}/repos/{owner}/{repo}/issues?state=closed", headers=headers
).json()
comments = requests.get(
f"{GITHUB_API_URL}/repos/{owner}/{repo}/issues/comments", headers=headers
).json()
try:
prs = requests.get(
f"{GITHUB_API_URL}/repos/{owner}/{repo}/pulls?state=merged&since={since_date}",
headers=headers,
).json()
issues = requests.get(
f"{GITHUB_API_URL}/repos/{owner}/{repo}/issues?state=closed&since={since_date}",
headers=headers,
).json()
comments = requests.get(
f"{GITHUB_API_URL}/repos/{owner}/{repo}/issues/comments?&since={since_date}",
headers=headers,
).json()
except requests.RequestException as e:
print(f"Error fetching GitHub data: {e}")
return [], [], []
return prs, issues, comments


Expand Down Expand Up @@ -86,18 +89,3 @@ def format_data(prs, issues, comments):
"text": {"type": "mrkdwn", "text": f"*Contributor Data*\n```\n{table}\n```"},
}
]


class ContributorPlugin(MachineBasePlugin):
"""Contributor plugin"""

@command("/contributors")
async def contributors(self, command):
prs, issues, comments = fetch_github_data("OWASP-BLT", "BLT")
formatted_data = format_data(prs, issues, comments)
if not formatted_data:
formatted_data = [
{"type": "section", "text": {"type": "mrkdwn", "text": "No data available"}}
]

await command.say(text="Contributors Activity", blocks=formatted_data)
31 changes: 0 additions & 31 deletions src/sammich/plugins/create_issue.py

This file was deleted.

10 changes: 0 additions & 10 deletions src/sammich/plugins/demo.py

This file was deleted.

Loading

0 comments on commit 56ffbd0

Please sign in to comment.