Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add slack bot integration #934

Closed
wants to merge 1 commit into from
Closed
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
1 change: 1 addition & 0 deletions app/app/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@
url(r'^settings/privacy/?', marketing.views.privacy_settings, name='privacy_settings'),
url(r'^settings/matching/?', marketing.views.matching_settings, name='matching_settings'),
url(r'^settings/feedback/?', marketing.views.feedback_settings, name='feedback_settings'),
url(r'^settings/slack/?', marketing.views.slack_settings, name='slack_settings'),
url(r'^settings/(.*)?', marketing.views.email_settings, name='feedback_settings'),

# marketing views
Expand Down
3 changes: 3 additions & 0 deletions app/dashboard/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from dashboard.models import Bounty, BountyFulfillment, BountySyncRequest, UserAction
from dashboard.notifications import (
maybe_market_to_email, maybe_market_to_github, maybe_market_to_slack, maybe_market_to_twitter,
maybe_market_to_user_slack,
)
from economy.utils import convert_amount
from github.utils import _AUTH
Expand Down Expand Up @@ -556,6 +557,7 @@ def process_bounty_changes(old_bounty, new_bounty):
print("============ posting ==============")
did_post_to_twitter = maybe_market_to_twitter(new_bounty, event_name)
did_post_to_slack = maybe_market_to_slack(new_bounty, event_name)
did_post_to_user_slack = maybe_market_to_user_slack(new_bounty, event_name)
did_post_to_github = maybe_market_to_github(new_bounty, event_name, profile_pairs)
did_post_to_email = maybe_market_to_email(new_bounty, event_name)
print("============ done posting ==============")
Expand All @@ -566,6 +568,7 @@ def process_bounty_changes(old_bounty, new_bounty):
'did_post_to_email': did_post_to_email,
'did_post_to_github': did_post_to_github,
'did_post_to_slack': did_post_to_slack,
'did_post_to_user_slack': did_post_to_user_slack,
'did_post_to_twitter': did_post_to_twitter,
}

Expand Down
64 changes: 60 additions & 4 deletions app/dashboard/notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,27 +171,83 @@ def maybe_market_to_slack(bounty, event_name):
if bounty.network != settings.ENABLE_NOTIFICATIONS_ON_NETWORK:
return False

msg = build_message_for_slack(bounty, event_name)
if not msg:
return False

try:
channel = 'notif-gitcoin'
sc = SlackClient(settings.SLACK_TOKEN)
sc.api_call("chat.postMessage", channel=channel, text=msg)
except Exception as e:
print(e)
return False
return True


def build_message_for_slack(bounty, event_name):
conv_details = ""
usdt_details = ""
try:
conv_details = f"@ (${round(convert_token_to_usdt(bounty.token_name),2)}/{bounty.token_name})"
usdt_details = f"({bounty.value_in_usdt_now} USD {conv_details} "
except Exception:
pass # no USD conversion rate
except Exception as e:
print(e)
return False

title = bounty.title if bounty.title else bounty.github_url
msg = f"{event_name.replace('bounty', 'funded_issue')} worth {round(bounty.get_natural_value(), 4)} {bounty.token_name} " \
f"{usdt_details}" \
f"{bounty.token_name}: {title} \n\n{bounty.get_absolute_url()}"
return msg


def maybe_market_to_user_slack(bounty, event_name):
"""Send a Slack message to the user's slack channel for the specified Bounty.

Args:
bounty (dashboard.models.Bounty): The Bounty to be marketed.
event_name (str): The name of the event.

Returns:
bool: Whether or not the Slack notification was sent successfully.

"""
from marketing.models import EmailSubscriber
if bounty.get_natural_value() < 0.0001:
return False
if bounty.network != settings.ENABLE_NOTIFICATIONS_ON_NETWORK:
return False

msg = build_message_for_slack(bounty, event_name)
if not msg:
return False

url = bounty.github_url
uri = parse(url).path
uri_array = uri.split('/')
sent = False
try:
channel = 'notif-gitcoin'
sc = SlackClient(settings.SLACK_TOKEN)
sc.api_call("chat.postMessage", channel=channel, text=msg)
username = uri_array[1]
repo = uri_array[2]
subscribers = EmailSubscriber.objects.filter(profile__handle=username, repos__contains=[repo])
subscribers = subscribers & EmailSubscriber.objects.exclude(slack_token='', slack_channel='')
for subscriber in subscribers:
try:
sc = SlackClient(subscriber.slack_token)
sc.api_call("chat.postMessage", channel=subscriber.slack_channel, text=msg)
sent = True
except Exception as e:
print(e)
except IndexError:
return False
except Exception as e:
print(e)
return False
return True

return sent

def maybe_market_tip_to_email(tip, emails):
"""Send an email for the specified Tip.
Expand Down
5 changes: 4 additions & 1 deletion app/dashboard/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
)
from dashboard.notifications import (
maybe_market_tip_to_email, maybe_market_tip_to_github, maybe_market_tip_to_slack, maybe_market_to_slack,
maybe_market_to_twitter,
maybe_market_to_twitter, maybe_market_to_user_slack,
)
from dashboard.utils import get_bounty, get_bounty_id, has_tx_mined, web3_process_bounty
from gas.utils import conf_time_spread, eth_usd_conv_rate, recommend_min_gas_price_to_confirm_in_time
Expand Down Expand Up @@ -114,6 +114,7 @@ def create_new_interest_helper(bounty, user):
bounty.interested.add(interest)
record_user_action(user, 'start_work', interest)
maybe_market_to_slack(bounty, 'start_work')
maybe_market_to_user_slack(bounty, 'start_work')
maybe_market_to_twitter(bounty, 'start_work')
return interest

Expand Down Expand Up @@ -230,6 +231,7 @@ def remove_interest(request, bounty_id):
bounty.interested.remove(interest)
interest.delete()
maybe_market_to_slack(bounty, 'stop_work')
maybe_market_to_user_slack(bounty, 'stop_work')
maybe_market_to_twitter(bounty, 'stop_work')
except Interest.DoesNotExist:
return JsonResponse({
Expand Down Expand Up @@ -279,6 +281,7 @@ def uninterested(request, bounty_id, profile_id):
interest = Interest.objects.get(profile_id=profile_id, bounty=bounty)
bounty.interested.remove(interest)
maybe_market_to_slack(bounty, 'stop_work')
maybe_market_to_user_slack(bounty, 'stop_work')
interest.delete()
except Interest.DoesNotExist:
return JsonResponse({
Expand Down
30 changes: 30 additions & 0 deletions app/marketing/migrations/0022_auto_20180419_1517.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Generated by Django 2.0.4 on 2018-04-19 15:17

import django.contrib.postgres.fields
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('marketing', '0021_emailsubscriber_profile'),
]

operations = [
migrations.AddField(
model_name='emailsubscriber',
name='repos',
field=django.contrib.postgres.fields.ArrayField(
base_field=models.CharField(max_length=200), blank=True, default=[], size=None),
),
migrations.AddField(
model_name='emailsubscriber',
name='slack_channel',
field=models.CharField(default='', max_length=255),
),
migrations.AddField(
model_name='emailsubscriber',
name='slack_token',
field=models.CharField(default='', max_length=255),
),
]
3 changes: 3 additions & 0 deletions app/marketing/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ class EmailSubscriber(SuperModel):
priv = models.CharField(max_length=30, default='')
github = models.CharField(max_length=255, default='')
keywords = ArrayField(models.CharField(max_length=200), blank=True, default=[])
repos = ArrayField(models.CharField(max_length=200), blank=True, default=[])
slack_token = models.CharField(max_length=255, default='')
slack_channel = models.CharField(max_length=255, default='')
profile = models.ForeignKey(
'dashboard.Profile',
on_delete=models.CASCADE,
Expand Down
42 changes: 42 additions & 0 deletions app/marketing/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,10 @@ def funnel(request):
'body': 'Feedback',
'href': '/settings/feedback',
},
{
'body': 'Slack',
'href': '/settings/slack',
},
]


Expand Down Expand Up @@ -615,6 +619,44 @@ def email_settings(request, key):
return TemplateResponse(request, 'settings/email.html', context)


def slack_settings(request):

# setup
profile, es, user, is_logged_in = settings_helper_get_auth(request)
if not es:
login_redirect = redirect('/login/github?next=' + request.get_full_path())
return login_redirect

msg = ''

if request.POST and request.POST.get('submit'):
token = request.POST.get('token', '')
repos = request.POST.get('repos').split(',')
channel = request.POST.get('channel', '')
es.slack_token = token
es.repos = repos
es.slack_channel = channel
ip = get_ip(request)
if not es.metadata.get('ip', False):
es.metadata['ip'] = [ip]
else:
es.metadata['ip'].append(ip)
es.save()
msg = "Updated your preferences. "

context = {
'repos': ",".join(es.repos),
'is_logged_in': is_logged_in,
'nav': 'internal',
'active': '/settings/slack',
'title': _('Slack Settings'),
'navs': settings_navs,
'es': es,
'msg': msg,
}
return TemplateResponse(request, 'settings/slack.html', context)


def _leaderboard(request):
return leaderboard(request, '')

Expand Down
23 changes: 23 additions & 0 deletions app/retail/templates/settings/slack.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{% extends 'settings/settings.html' %}
{% load i18n static %}

{% block settings_content %}
<form id="settings" method="POST">
<div class="form-group">
<h5>{% trans "Slack Integration" %}</h5>
<label class="form__label" for="token">{% trans "Slack API token" %}</label>
<input type="text" name="token" class="form__input" placeholder='API token' value="{{ es.slack_token }}">
</div>
<div class="form-group">
<label class="form__label" for="repos">{% trans "Github repos to monitor" %}</label>
<input type="text" name="repos" class="form__input" placeholder='comma, separated, list' value="{{ repos }}">
</div>
<div class="form-group">
<label class="form__label" for="channel">{% trans "Slack channel to post to" %}</label>
<input type="text" name="channel" class="form__input" value="{{ es.slack_channel }}">
</div>
{% csrf_token %}
<input class='button button--primary' type='submit' name='submit' value="Go">
</form>
</div>
{% endblock %}