Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ server, in the `#code-of-conduct` channel.
4. Skip directly to the "Bot" tab of the application you created. Set the icon
and username here. These can be changed later. Click the button to reveal the
bot token. Copy this token into the `Discord token:` field in `config.yml`.
5. Turn on the "Server Members Intent" slider in the Bot tab.
5. Turn on the "Server Members Intent" slider in the Bot tab.
6. If you don't have a private Discord server to test in, make one.
7. Grab the 'Application ID' from the 'General Information' tab of the Discord
application you created (different from your bot token!)
Expand All @@ -44,6 +44,11 @@ server, in the `#code-of-conduct` channel.
10. Go to the URL and accept any prompts.
11. Run the bot through Docker using the commands below.

### Issue tracker configuration
Cryptogull uses an app password to authenticate with the Bitbucket issue tracker.

More info can be found at https://support.atlassian.com/bitbucket-cloud/docs/app-passwords/.

## Example docker commands
To build and run the bot:

Expand Down
25 changes: 3 additions & 22 deletions bot/cogs/bugs.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import io
import logging
import time

import aiohttp
import discord
from discord.ext.commands import Cog, Bot, Context
from oauthlib.oauth2 import BackendApplicationClient

from bot.shared import config, http_session

Expand All @@ -18,7 +16,7 @@ class Bugs(Cog):
def __init__(self, bot: Bot):
self.bot = bot
self.config = config['Bugs']
self.oauthclient = BackendApplicationClient(self.config['oauth2 key'])
self.auth = aiohttp.BasicAuth(self.config['bot username'], self.config['bot password'])

@Cog.listener()
async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent):
Expand Down Expand Up @@ -65,25 +63,10 @@ async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent):
except Exception as e:
log.exception(e)

async def check_oauth_token(self):
"""Create or refresh our Bitbucket OAuth2 token."""
# is our token nonexistent, expired, or expiring in the next 30 seconds?
if self.oauthclient.expires_in is None or \
self.oauthclient.expires_in < time.time() + 30:
auth = aiohttp.BasicAuth(self.config['oauth2 key'],
self.config['oauth2 secret'])
data = {'grant_type': 'client_credentials'}
async with http_session.post(url="https://bitbucket.org/site/oauth2/access_token",
data=data,
auth=auth) as response:
text = await response.text()
self.oauthclient.parse_request_body_response(text)

async def create_bitbucket_issue(self, ctx: Context, requester: discord.User):
"""Create a Bitbucket issue regarding the given Discord Context.

Return the Bitbucket API response."""
await self.check_oauth_token()
title = ctx.message.clean_content
if len(title) > self.config['title max length']:
title = title[:self.config['title max length']] + "..."
Expand All @@ -103,9 +86,8 @@ async def create_bitbucket_issue(self, ctx: Context, requester: discord.User):
'raw': content
}
}
headers = {'Authorization': f'Bearer {self.oauthclient.token["access_token"]}'}
async with http_session.post(self.config['endpoint'],
headers=headers,
auth=self.auth,
json=params) as request:
response = await request.json()
return response
Expand All @@ -114,10 +96,9 @@ async def upload_issue_attachments(self, ctx: Context, issue_id: int):
"""Upload any attachments from the given Discord Context to the issue ID."""
for num, attachment in enumerate(ctx.message.attachments):
log.info(f'Uploading attachment {num}: {attachment.filename} ({attachment.size} bytes)')
headers = {'Authorization': f'Bearer {self.oauthclient.token["access_token"]}'}
stream = io.BytesIO()
await attachment.save(stream, seek_begin=True)
data = aiohttp.FormData()
data.add_field('file', stream, filename=attachment.filename)
url = f'{self.config["endpoint"]}/{issue_id}/attachments'
await http_session.post(url, headers=headers, data=data)
await http_session.post(url, auth=self.auth, data=data)
4 changes: 2 additions & 2 deletions config.example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ Bugs:
fail reaction: ⚠️
title max length: 80
endpoint: https://api.bitbucket.org/2.0/repositories/test/test-issue-tracker/issues
oauth2 key: xxxxxxxxxxxxxxxxxx
oauth2 secret: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
bot username: xxxxxxxxxxxxxxxxxx
bot password: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Decode:
channels: [ # Channels to listen for character build codes in:
Expand Down
19 changes: 1 addition & 18 deletions poetry.lock

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

1 change: 0 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ python = "^3.13"
"discord.py" = "1.7.3"
PyYAML = "^6.0"
fuzzywuzzy = "^0.18"
oauthlib = "^3.2"
asyncpraw = "^7.6"
hagadias = {git = "https://github.com/TrashMonks/hagadias.git", branch = "main"}
Levenshtein = "^0.26"
Expand Down