Skip to content

Commit

Permalink
Merge pull request #273 from membermatters/feature/vikunja-integration
Browse files Browse the repository at this point in the history
added report issue vikunja integration
  • Loading branch information
jabelone authored Aug 11, 2024
2 parents 2a6a647 + e41cc6a commit 6ba7d5a
Show file tree
Hide file tree
Showing 5 changed files with 289 additions and 68 deletions.
1 change: 0 additions & 1 deletion memberportal/api_general/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ def get(self, request):
"memberbucks_topup_options": json.loads(
config.STRIPE_MEMBERBUCKS_TOPUP_OPTIONS
),
"trelloIntegration": config.ENABLE_TRELLO_INTEGRATION,
"enableProxyVoting": config.ENABLE_PROXY_VOTING,
"enableStripe": config.ENABLE_STRIPE
and len(config.STRIPE_PUBLISHABLE_KEY) > 0
Expand Down
245 changes: 196 additions & 49 deletions memberportal/api_member_tools/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@
from api_meeting.models import Meeting
from constance import config
from services.emails import send_email_to_admin
from services import discord

from random import shuffle
import requests
from django.utils import timezone

from rest_framework import status, permissions
from rest_framework.response import Response
from rest_framework.views import APIView
import logging

logger = logging.getLogger("api_member_tools")


class SwipesList(APIView):
Expand Down Expand Up @@ -100,7 +104,7 @@ def get(self, request):

class IssueDetail(APIView):
"""
post: Creates a new issue by creating a trello card or emailing the management committee
post: Creates a new issue by creating a task card or emailing the management committee
"""

permission_classes = (permissions.IsAuthenticated,)
Expand All @@ -109,64 +113,207 @@ def post(self, request):
body = request.data
title = body["title"]
description = request.user.profile.get_full_name() + ": " + body["description"]
vikunja_task_url = None
trello_card_url = None

if not (title and description):
return Response(status=status.HTTP_400_BAD_REQUEST)

use_trello = config.ENABLE_TRELLO_INTEGRATION
trello_key = config.TRELLO_API_KEY
trello_token = config.TRELLO_API_TOKEN
trello_id_list = config.TRELLO_ID_LIST

if use_trello:
url = "https://api.trello.com/1/cards"

querystring = {
"name": title,
"desc": description,
"pos": "top",
"idList": trello_id_list,
"keepFromSource": "all",
"key": trello_key,
"token": trello_token,
}
failed = False

response = requests.request("POST", url, params=querystring)
request.user.log_event(
"Submitted issue: " + title + " Content: " + description,
"generic",
)

if response.status_code == 200:
request.user.log_event(
"Submitted issue: " + title + " Content: " + description,
"generic",
)
if config.REPORT_ISSUE_ENABLE_VIKUNJA and bool(
config.VIKUNJA_DEFAULT_PROJECT_ID
):
vikunja_project_id = int(config.VIKUNJA_DEFAULT_PROJECT_ID)
vikunja_label_id = int(config.VIKUNJA_DEFAULT_LABEL_ID)

try:
task_body = {
"max_right": None,
"id": 0,
"title": title,
"description": description,
"done": False,
"done_at": None,
"priority": 0,
"labels": [],
"assignees": [],
"due_date": None,
"start_date": None,
"end_date": None,
"repeat_after": 0,
"repeat_from_current_date": False,
"repeat_mode": 0,
"reminders": [],
"parent_task_id": 0,
"hex_color": "",
"percent_done": 0,
"related_tasks": {},
"attachments": [],
"cover_image_attachment_id": None,
"identifier": "",
"index": 0,
"is_favorite": False,
"subscription": None,
"position": 64,
"reactions": {},
"created_by": {
"max_right": None,
"id": 0,
"email": "",
"username": "",
"name": "",
"exp": 0,
"type": 0,
"created": None,
"updated": None,
"settings": {
"max_right": None,
"name": "",
"email_reminders_enabled": False,
"discoverable_by_name": False,
"discoverable_by_email": True,
"overdue_tasks_reminders_enabled": False,
"week_start": 0,
"timezone": "",
"language": "en",
"frontend_settings": {
"play_sound_when_done": False,
"quick_add_magic_mode": "vikunja",
"color_schema": "auto",
"default_view": "first",
},
},
},
"created": "1970-01-01T00:00:00.000Z",
"updated": "1970-01-01T00:00:00.000Z",
"project_id": vikunja_project_id,
"bucket_id": 0,
"reminder_dates": None,
}

return Response(
{"success": True, "url": response.json()["shortUrl"]},
status=status.HTTP_201_CREATED,
task_response = requests.request(
"PUT",
f"{config.VIKUNJA_API_URL}/api/v1/projects/{vikunja_project_id}/tasks",
json=task_body,
headers={"Authorization": "Bearer " + config.VIKUNJA_API_TOKEN},
)

else:
return Response(status=status.HTTP_500_INTERNAL_SERVER_ERROR)
if (vikunja_label_id is not None) and (
task_response.status_code == 201
):
task_id = "unknown"
try:
task_id = task_response.json()["id"]
vikunja_task_url = f"{config.VIKUNJA_API_URL}/tasks/{task_id}"
label_body = {
"label_id": int(vikunja_label_id),
"created": "1970-01-01T00:00:00.000Z",
}

label_response = requests.request(
"PUT",
f"{config.VIKUNJA_API_URL}/api/v1/tasks/{task_id}/labels",
json=label_body,
headers={
"Authorization": "Bearer " + config.VIKUNJA_API_TOKEN
},
)

if label_response.status_code != 201:
logger.warning(
f"Failed to add label to Vikunja task {task_id}: %s",
label_response.json(),
)

except Exception:
logger.exception(
f"Failed to add label to Vikunja task {task_id}."
)
pass

if task_response.status_code != 201:
logger.error(
"Failed to create Vikunja task: %s", task_response.json()
)
failed = True

except Exception:
# uh oh, but don't stop processing other ones
failed = True
logger.exception("Failed to create reported issue Vikunja task.")

if config.REPORT_ISSUE_ENABLE_TRELLO:
try:
trello_key = config.TRELLO_API_KEY
trello_token = config.TRELLO_API_TOKEN
trello_id_list = config.TRELLO_ID_LIST
trello_url = "https://api.trello.com/1/cards"

querystring = {
"name": title,
"desc": description,
"pos": "top",
"idList": trello_id_list,
"keepFromSource": "all",
"key": trello_key,
"token": trello_token,
}

# if Trello isn't configured, use email instead
else:
subject = f"{request.user.profile.get_full_name()} submitted an issue about {title}"

if send_email_to_admin(
subject=subject,
template_vars={
"title": subject,
"message": description,
},
user=request.user,
reply_to=request.user.email,
):
return Response(
{"success": True},
status=status.HTTP_201_CREATED,
)
response = requests.request("POST", trello_url, params=querystring)

if response.status_code != 200:
failed = True

trello_card_url = response.json()["shortUrl"]

except Exception:
# uh oh, but don't stop processing other ones
failed = True
logger.exception("Failed to create reported issue Trello card.")

# email report
if config.REPORT_ISSUE_ENABLE_EMAIL:
try:
subject = f"{request.user.profile.get_full_name()}: {title}"

if not send_email_to_admin(
subject=subject,
template_vars={
"title": subject,
"message": description,
},
user=request.user,
reply_to=request.user.email,
):
failed = True

except Exception:
# uh oh, but don't stop processing other ones
failed = True
logger.exception("Failed to send reported issue email.")

# discord report
if config.REPORT_ISSUE_ENABLE_DISCORD:
username = request.user.profile.get_full_name()
description = body["description"]

discord.post_reported_issue_to_discord(
username, title, description, vikunja_task_url, trello_card_url
)

else:
return Response(status=status.HTTP_500_INTERNAL_SERVER_ERROR)
if failed:
return Response(status=status.HTTP_500_INTERNAL_SERVER_ERROR)
else:
return Response(
{"success": True},
status=status.HTTP_201_CREATED,
)


class MeetingList(APIView):
Expand Down
56 changes: 52 additions & 4 deletions memberportal/membermatters/constance_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,15 +120,40 @@
False,
"Enable integration with stripe for membership payments.",
),
# ==== Report Issue Services ====
# Email config
"REPORT_ISSUE_ENABLE_EMAIL": (
True,
"Enable the submit issue to email integration.",
),
# Discord config
"REPORT_ISSUE_ENABLE_DISCORD": (
False,
"Enable the submit issue to Discord integration.",
),
# Vikunja config
"REPORT_ISSUE_ENABLE_VIKUNJA": (
False,
"Enable the submit issue to Vikunja integration.",
),
"VIKUNJA_API_URL": ("", "Set this to your Vikunja instance public URL."),
"VIKUNJA_API_TOKEN": ("", "Set this to your Vikunja API token."),
"VIKUNJA_DEFAULT_PROJECT_ID": (
"",
"Set this to the ID of your default project to create issues in.",
),
"VIKUNJA_DEFAULT_LABEL_ID": (
"",
"[optional] Set this to the ID of your default label if you want new issues to be tagged.",
),
"VIKUNJA_TEAMS": (
'[{"name": "Members", "oidcID": "members", "description": "The default team for all members.", "isPublic": false}]',
"A JSON array of Vikunja teams to add users to when they login via SSO. Returned as an OIDC claim with the 'vikunja_teams' scope. Check Vikunja docs for syntax.",
),
# Trello config
"ENABLE_TRELLO_INTEGRATION": (
"REPORT_ISSUE_ENABLE_TRELLO": (
False,
"Enable the submit issue to trello integration. If disabled we'll send an email to EMAIL_ADMIN instead.",
"Enable the submit issue to trello integration.",
),
"TRELLO_API_KEY": ("", "Set this to your Trello API key."),
"TRELLO_API_TOKEN": ("", "Set this to your Trello API token."),
Expand Down Expand Up @@ -212,6 +237,10 @@
"https://discordapp.com/api/webhooks/<token>",
"Discord URL to send webhook notifications to for vending/memberbucks purchases.",
),
"DISCORD_REPORT_ISSUE_WEBHOOK": (
"https://discordapp.com/api/webhooks/<token>",
"Discord URL to send webhook notifications to when reporting issues.",
),
"ENABLE_DISCOURSE_SSO_PROTOCOL": (
False,
"Enable support for the discourse SSO protocol.",
Expand Down Expand Up @@ -416,6 +445,7 @@
"SMS_ENABLE",
"TWILIO_ACCOUNT_SID",
"TWILIO_AUTH_TOKEN",
"TWILIO_AUTH_TOKEN",
"SMS_DEFAULT_COUNTRY_CODE",
"SMS_SENDER_ID",
"SMS_MESSAGES",
Expand All @@ -432,11 +462,28 @@
"MEMBERBUCKS_CURRENCY",
),
),
("Vikunja Integration", ("VIKUNJA_TEAMS",)),
(
"Report Issue Services",
(
"REPORT_ISSUE_ENABLE_EMAIL",
"REPORT_ISSUE_ENABLE_DISCORD",
"REPORT_ISSUE_ENABLE_VIKUNJA",
"REPORT_ISSUE_ENABLE_TRELLO",
),
),
(
"Vikunja Integration",
(
"VIKUNJA_TEAMS",
"VIKUNJA_API_URL",
"VIKUNJA_API_TOKEN",
"VIKUNJA_DEFAULT_PROJECT_ID",
"VIKUNJA_DEFAULT_LABEL_ID",
),
),
(
"Trello Integration",
(
"ENABLE_TRELLO_INTEGRATION",
"TRELLO_API_KEY",
"TRELLO_API_TOKEN",
"TRELLO_ID_LIST",
Expand Down Expand Up @@ -508,6 +555,7 @@
"DISCORD_DOOR_WEBHOOK",
"DISCORD_INTERLOCK_WEBHOOK",
"DISCORD_MEMBERBUCKS_PURCHASE_WEBHOOK",
"DISCORD_REPORT_ISSUE_WEBHOOK",
),
),
]
Expand Down
Loading

0 comments on commit 6ba7d5a

Please sign in to comment.