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

Chat 1.2 - General Availability #5569

Merged
merged 62 commits into from
Jan 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
a7cf2ac
Mattermost Driver added
androolloyd Nov 29, 2019
e50e066
Initial Documentation for Gitcoin Mattermost Setup
androolloyd Dec 3, 2019
52de667
Auto reload the workers in development environments to aid in celery …
androolloyd Dec 6, 2019
3b28827
Merge branch 'master' of github.com:gitcoinco/web into chat/driver-1.2
androolloyd Dec 6, 2019
af6a0af
Merge branch 'celery/restart-workers' into chat/driver-1.2
androolloyd Dec 6, 2019
c7658d7
Add chat page
iamonuwa Dec 8, 2019
e8cc805
WIP commit, mgmt sync users to chat cmd added, chat celery tasks updated
androolloyd Dec 10, 2019
92f51ec
Settings for 1.2(mattermost driver)
androolloyd Dec 10, 2019
7dcd007
remove default token for chat driver
androolloyd Dec 10, 2019
d9fdb5a
copy and fixes small issues
owocki Dec 13, 2019
7aa0bd4
Merge pull request #5622 from iamonuwa/issue-5578-chat-page
androolloyd Dec 15, 2019
3bd47b5
adding email supression check into the oauth route
androolloyd Dec 15, 2019
b8d4682
Merge branch 'chat/driver-1.2' of github.com:gitcoinco/web into chat/…
androolloyd Dec 15, 2019
7fa064d
WIP, adding funder and hunter into the same chat channel on bounty wo…
androolloyd Dec 20, 2019
f12ae4b
set nickname to profile handle when creating a new user
androolloyd Dec 22, 2019
815ade9
when creating users in the sync task, set the nickname to the profile…
androolloyd Dec 22, 2019
f7ddb7e
Chat 1.2 - General Availability
androolloyd Jan 4, 2020
b5421ae
Merge branch 'master' of github.com:gitcoinco/web into chat/driver-1.2
androolloyd Jan 4, 2020
c99bd50
removing check for bounty.event.slug and just relying on an event exi…
androolloyd Jan 6, 2020
ab1af63
added gitcoin chat total user count into stats
androolloyd Jan 7, 2020
74fc239
notification dot added to the chat icon in the header, and a chat_unr…
androolloyd Jan 7, 2020
f5e3861
adding mention count
androolloyd Jan 7, 2020
a305fd5
Merge branch 'master' of github.com:gitcoinco/web into chat/driver-1.2
androolloyd Jan 7, 2020
85bfa2c
updated update_user job to not rely on serialized query objects
androolloyd Jan 7, 2020
5862f5f
updated code to reflect review
androolloyd Jan 8, 2020
d999b70
disabled email notify props for initial release
androolloyd Jan 8, 2020
cc84f8b
Mattermost Driver added
androolloyd Nov 29, 2019
bb474a3
Initial Documentation for Gitcoin Mattermost Setup
androolloyd Dec 3, 2019
48d1fe5
Auto reload the workers in development environments to aid in celery …
androolloyd Dec 6, 2019
ed04cb5
WIP commit, mgmt sync users to chat cmd added, chat celery tasks updated
androolloyd Dec 10, 2019
6841897
Settings for 1.2(mattermost driver)
androolloyd Dec 10, 2019
8e36e4d
remove default token for chat driver
androolloyd Dec 10, 2019
8ebe51f
adding email supression check into the oauth route
androolloyd Dec 15, 2019
7ce4f12
Add chat page
iamonuwa Dec 8, 2019
0e8ae42
copy and fixes small issues
owocki Dec 13, 2019
0320c0b
WIP, adding funder and hunter into the same chat channel on bounty wo…
androolloyd Dec 20, 2019
bd60ba8
set nickname to profile handle when creating a new user
androolloyd Dec 22, 2019
d64f4db
when creating users in the sync task, set the nickname to the profile…
androolloyd Dec 22, 2019
3cf01c3
Chat 1.2 - General Availability
androolloyd Jan 4, 2020
393f3e8
removing check for bounty.event.slug and just relying on an event exi…
androolloyd Jan 6, 2020
8062d87
added gitcoin chat total user count into stats
androolloyd Jan 7, 2020
9b64e9e
notification dot added to the chat icon in the header, and a chat_unr…
androolloyd Jan 7, 2020
daf8233
adding mention count
androolloyd Jan 7, 2020
8fb9c2b
fix geoip download
danlipert Jan 6, 2020
98caadb
fix stylelint
danlipert Jan 6, 2020
64b0a73
some small email changes as i practice gitting before 2019 ends
vs77bb Dec 25, 2019
d980117
grants index
owocki Jan 7, 2020
ec21315
chore: prettify load more grants text
thelostone-mc Jan 2, 2020
e722ed8
improve quest feedback email" (#5666)
danlipert Jan 7, 2020
44d2ba6
fixing a mistype in tar extraction for GeoLite (#5714)
Korridzy Jan 7, 2020
b36c989
updated update_user job to not rely on serialized query objects
androolloyd Jan 7, 2020
d0b7075
updated code to reflect review
androolloyd Jan 8, 2020
ff8c53b
disabled email notify props for initial release
androolloyd Jan 8, 2020
6bc2f2a
Merge branch 'chat/driver-1.2' of github.com:gitcoinco/web into chat/…
androolloyd Jan 8, 2020
8a7afab
Merge remote-tracking branch 'upstream/master' into chat/driver-1.2
thelostone-mc Jan 8, 2020
81e0b3f
lint fixes
thelostone-mc Jan 8, 2020
a50514f
fix indent
thelostone-mc Jan 8, 2020
a12014e
removed app/__init__.py
thelostone-mc Jan 8, 2020
f13c985
fixed import issues after rebase, adjusted spacing to appease stylelint
androolloyd Jan 8, 2020
463c35b
fixes for travis, the rebase, and the chat_nav being available to non…
androolloyd Jan 8, 2020
bf1afa9
Merge branch 'chat/driver-1.2' of github.com:gitcoinco/web into chat/…
androolloyd Jan 8, 2020
3e01223
redoing migrations to prevent conflict
androolloyd Jan 8, 2020
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
20 changes: 20 additions & 0 deletions app/app/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,30 @@ def preprocess(request):
callback = request.GET.get('cb')
handle_marketing_callback(callback, request)

chat_unread_messages = False

if profile and profile.chat_id:
try:
from chat.tasks import get_driver
chat_driver = get_driver()

chat_unreads_request = chat_driver.teams.get_team_unreads_for_user(
profile.chat_id
)

if 'message' not in chat_unreads_request:
for teams in chat_unreads_request:
if teams['msg_count'] > 0 or teams['mention_count'] > 0:
chat_unread_messages = True
break
except Exception as e:
logger.error(str(e))

context = {
'STATIC_URL': settings.STATIC_URL,
'MEDIA_URL': settings.MEDIA_URL,
'num_slack': num_slack,
'chat_unread_messages' : chat_unread_messages,
'github_handle': request.user.username if user_is_authenticated else False,
'email': request.user.email if user_is_authenticated else False,
'name': request.user.get_full_name() if user_is_authenticated else False,
Expand Down
10 changes: 8 additions & 2 deletions app/app/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
'health_check.contrib.s3boto3_storage',
'app',
'avatar',
'chat',
'retail',
'rest_framework',
'marketing',
Expand Down Expand Up @@ -468,6 +469,8 @@
CELERY_TASK_SERIALIZER = 'json'
# http://docs.celeryproject.org/en/latest/userguide/configuration.html#std:setting-result_serializer
CELERY_RESULT_SERIALIZER = 'json'
# http://docs.celeryproject.org/en/latest/userguide/configuration.html#std:setting-result_backend
CELERY_RESULT_BACKEND = env('CELERY_RESULT_BACKEND', default=CACHEOPS_REDIS)

DJANGO_REDIS_IGNORE_EXCEPTIONS = env.bool('REDIS_IGNORE_EXCEPTIONS', default=True)
DJANGO_REDIS_LOG_IGNORED_EXCEPTIONS = env.bool('REDIS_LOG_IGNORED_EXCEPTIONS', default=True)
Expand Down Expand Up @@ -542,8 +545,11 @@
GITHUB_APP_NAME = env('GITHUB_APP_NAME', default='gitcoin-local')

# Chat
CHAT_URL = env('CHAT_DRIVER_USER', default='') # location of where mattermost is hosted

CHAT_PORT = env('CHAT_PORT', default=8065) # port of where mattermost is hosted
CHAT_URL = env('CHAT_URL', default='http://localhost') # location of where mattermost is hosted
CHAT_DRIVER_TOKEN = env('CHAT_DRIVER_TOKEN', default='') # driver token
GITCOIN_HACK_CHAT_TEAM_ID = env('GITCOIN_HACK_CHAT_TEAM_ID', default='')
GITCOIN_CHAT_TEAM_ID = env('GITCOIN_CHAT_TEAM_ID', default='')
# Social Auth
LOGIN_URL = 'gh_login'
LOGOUT_URL = 'logout'
Expand Down
5 changes: 3 additions & 2 deletions app/app/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,9 @@
url(r'^api/v0.1/choose_persona/', dashboard.views.choose_persona, name='choose_persona'),

# chat
url(r'^chat/', chat.views.embed, name='chat'),
url(r'^chat', chat.views.embed, name='chat2'),
url(r'^chat/web', chat.views.embed, name='web_chat'),
url(r'^chat/web/', chat.views.embed, name='web_chat2'),
re_path(r'^chat/?', chat.views.chat, name='chat'),
# Health check endpoint
re_path(r'^health/', include('health_check.urls')),
re_path(r'^lbcheck/?', healthcheck.views.lbcheck, name='lbcheck'),
Expand Down
43 changes: 43 additions & 0 deletions app/assets/v2/css/chat.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
.banner {
background-color: #0d023b;
background-size: cover;
background-position: 0px 0px;
background-repeat: no-repeat;
position: relative;
color: #fff;
padding-top: 5rem;
padding-bottom: 5rem;
}

.sub-headline {
line-height: 48px;
}

.online {
color: #25e899;
}

.dot {
background-color: #25e899;
display: none;
width: 9px;
height: 9px;
border-radius: 50%;
position: absolute;
top: 0.5em;
right: 0.9em;
}

.open-app {
background-color: #0D001A;
}

img.feature {
border-radius: 80px;
}

@media (max-width: 1024px) {
.chat-img {
display: none;
}
}
Binary file added app/assets/v2/images/chat/android.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/assets/v2/images/chat/apple.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/assets/v2/images/chat/chat.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/assets/v2/images/chat/desktop.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/assets/v2/images/chat/feature_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/assets/v2/images/chat/feature_2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/assets/v2/images/chat/feature_3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/assets/v2/images/chat/mobile.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/assets/v2/images/chat/web.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/assets/v2/images/chat/windows.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions app/assets/v2/js/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -406,3 +406,7 @@ const gitcoinUpdates = (force) => {
if (document.contxt.github_handle) {
gitcoinUpdates();
}

if (document.contxt.chat_unread_messages) {
$('#chat-notification-dot').addClass('notification__dot__active');
}
1 change: 0 additions & 1 deletion app/chat/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
default_app_config = 'inbox.apps.NotificationConfig'
21 changes: 21 additions & 0 deletions app/chat/apps.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
# -*- coding: utf-8 -*-
"""Define the Dashboard application configuration.

Copyright (C) 2018 Gitcoin Core

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

"""
from __future__ import unicode_literals

from django.apps import AppConfig


Expand Down
Empty file.
Empty file.
79 changes: 79 additions & 0 deletions app/chat/management/commands/sync_users_to_chat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
'''
Copyright (C) 2018 Gitcoin Core

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

'''
from django.conf import settings
from django.core.management.base import BaseCommand
from dashboard.models import Profile
from chat.tasks import create_user
import logging
from celery import group

logger = logging.getLogger(__name__)

from marketing.utils import should_suppress_notification_email


class Command(BaseCommand):
help = "create users to Gitcoin chat, creates the user if it doesn't exist"

def handle(self, *args, **options):
try:

profiles = Profile.objects.filter(user__is_active=True, chat__id__exact='').prefetch_related('user')

tasks = []

for profile in profiles:
# if profile.chat_id is None:
androolloyd marked this conversation as resolved.
Show resolved Hide resolved
tasks.append(create_user.si(options={
"email": profile.user.email,
"username": profile.handle,
"first_name": profile.user.first_name,
"last_name": profile.user.last_name,
"nickname": profile.handle,
"auth_data": f'{profile.user.id}',
"auth_service": "gitcoin",
"locale": "en",
"props": {},
"notify_props": {
"email": "false",
"push": "mention",
"desktop": "all",
"desktop_sound": "true",
"mention_keys": f'{profile.handle}, @{profile.handle}',
"channel": "true",
"first_name": "false"
},
}, params={
"tid": settings.GITCOIN_HACK_CHAT_TEAM_ID
}))
job = group(tasks)

result = job.apply_async()
for result_req in result.get():
if 'message' not in result_req:
if 'username' in result_req and 'id' in result_req:
profile = Profile.objects.get(handle=result_req['username'])
if profile is not None:
profile.chat_id = result_req['id']
profile.save()

except ConnectionError as exec:
print(str(exec))
self.retry(30)
except Exception as e:
logger.error(str(e))
131 changes: 131 additions & 0 deletions app/chat/tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
from app.redis_service import RedisService
from celery import app, group
from celery.utils.log import get_task_logger
from dashboard.models import Profile
from django.conf import settings

from mattermostdriver import Driver

logger = get_task_logger(__name__)

redis = RedisService().redis

# Lock timeout of 2 minutes (just in the case that the application hangs to avoid a redis deadlock)
LOCK_TIMEOUT = 60 * 2

chat_driver = Driver({
'url': settings.CHAT_URL,
'port': settings.CHAT_PORT,
'token': settings.CHAT_DRIVER_TOKEN
})


def get_driver():
chat_driver.login()
return chat_driver


@app.shared_task(bind=True, max_retries=3)
def create_channel(self, options, retry: bool = True) -> None:
"""
:param options:
:param retry:
:return:
"""
with redis.lock("tasks:create_channel:%s" % options['channel_name'], timeout=LOCK_TIMEOUT):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the need for locks here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if 2 hunters requested to start work before a channel has been created, 2 messages could get queued to create the same channel, but if we lock with redis we dont have to worry about potentially trying to create 2.


try:
chat_driver.login()
new_channel = chat_driver.channels.create_channel(options={
'team_id': options['team_id'],
'name': options['channel_name'],
'display_name': options['channel_display_name'],
'type': 'O'
})

return new_channel
except ConnectionError as exc:
logger.info(str(exc))
logger.info("Retrying connection")
self.retry(30)
except Exception as e:
print("we got an exception when creating a channel")
logger.error(str(e))


@app.shared_task(bind=True, max_retries=3)
def add_to_channel(self, options, retry: bool = True) -> None:
"""
:param options:
:param retry:
:return:
"""
with redis.lock("tasks:add_to_channel:%s" % options['channel_id'], timeout=LOCK_TIMEOUT):
chat_driver.login()
try:
for x in options['profiles']:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is x here? Please use variable names that make sense to increase readability.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its a chat_id, will update

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@androolloyd you probably missed this ! Could you shoot a follow up PR?

if x is not None:
response = chat_driver.channels.add_user(options['channel_id'], options={
'user_id': x
})
except ConnectionError as exc:
logger.info(str(exc))
logger.info("Retrying connection")
self.retry(30)
except Exception as e:
logger.error(str(e))


@app.shared_task(bind=True, max_retries=1)
def create_user(self, options, params, retry: bool = True):
with redis.lock("tasks:create_user:%s" % options['username'], timeout=LOCK_TIMEOUT):
try:
chat_driver.login()
create_user_response = chat_driver.users.create_user(
options=options,
params=params
)
return create_user_response
except ConnectionError as exc:
logger.info(str(exc))
logger.info("Retrying connection")
self.retry(30)
except Exception as e:
logger.error(str(e))
return None


@app.shared_task(bind=True, max_retries=3)
def update_user(self, query_opts, update_opts, retry: bool = True) -> None:
"""
:param self:
:param query_opts:
:param update_opts:
:param retry:
:return: None
"""

if update_opts is None:
return

with redis.lock("tasks:update_user:%s" % query_opts['handle'], timeout=LOCK_TIMEOUT):

try:

if query_opts['chat_id'] is None:
chat_user = chat_driver.users.get_user_by_username(query_opts['handle'])
if 'message' not in chat_user:
chat_id = chat_user['id']
else:
chat_id = query_opts['chat_id']

user_profile = Profile.objects.filter(handle=query_opts['handle'])
user_profile.chat_id = chat_id
user_profile.save()
chat_driver.users.update_user(chat_id, options=update_opts)
except ConnectionError as exc:
logger.info(str(exc))
logger.info("Retrying connection")
self.retry(30)
except Exception as e:
logger.error(str(e))
Loading