Skip to content

Commit

Permalink
Merge pull request openedx#840 from eduNEXT/and/rocket_chat_djangoapp
Browse files Browse the repository at this point in the history
Create rocketChat djangoapp
  • Loading branch information
jfavellar90 authored Jul 27, 2018
2 parents ea6f134 + 32373fa commit 270df62
Show file tree
Hide file tree
Showing 14 changed files with 297 additions and 2 deletions.
Empty file.
3 changes: 3 additions & 0 deletions common/djangoapps/rocket_chat/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.contrib import admin

# Register your models here.
Empty file.
3 changes: 3 additions & 0 deletions common/djangoapps/rocket_chat/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.db import models

# Create your models here.
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<%page expression_filter="h"/>
<%inherit file="../main.html" />
<%def name="online_help_token()"><% return "courseinfo" %></%def>
<%namespace name='static' file='../static_content.html'/>
<%!
from datetime import datetime
from pytz import timezone, utc

from django.core.urlresolvers import reverse
from django.utils.translation import ugettext as _
from courseware.courses import get_course_date_blocks
from openedx.core.djangolib.markup import HTML, Text
%>

<%block name="pagetitle">${_("{course_number} Course Info").format(course_number=course.display_number_with_default)}</%block>

<%block name="headextra">
<%static:css group='style-course-vendor'/>
<%static:css group='style-course'/>
</%block>

<%include file="/courseware/course_navigation.html" args="active_page='rocketchat'" />

<%static:require_module_async module_name="js/courseware/toggle_element_visibility" class_name="ToggleElementVisibility">
ToggleElementVisibility();
</%static:require_module_async>
<%static:require_module_async module_name="js/courseware/course_info_events" class_name="CourseInfoEvents">
CourseInfoEvents();
</%static:require_module_async>

<%block name="bodyclass">view-in-course view-course-info ${course.css_class or ''}</%block>

<main id="main" aria-label="Content" tabindex="-1">
<div class="container"
% if getattr(course, 'language'):
lang="${course.language}"
% endif
>
<div class="course-view page-content-container">
<div class="page-header">
<h2 class="hd hd-3 page-title">
${_("{course_title}").format(course_title=course_title)}
</h2>
</div>
<div class="page-content">
% if user.is_authenticated() and rocket_chat_error_message is None:
<iframe class="rocket-chat-view" src="${rocket_chat_url}/home?authToken=${rocket_chat_data['authToken']}&userId=${rocket_chat_data['userId']}"></iframe>
% else:
<h1 class="rocket_chat_error_message">${rocket_chat_error_message}</h1>
% endif
</div>
</div>

</div>
</main>

3 changes: 3 additions & 0 deletions common/djangoapps/rocket_chat/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.test import TestCase

# Create your tests here.
9 changes: 9 additions & 0 deletions common/djangoapps/rocket_chat/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

from django.conf.urls import url

from rocket_chat import views

urlpatterns = [

url(r'', views.rocket_chat_discussion, name='rocket_chat_discussion'),
]
57 changes: 57 additions & 0 deletions common/djangoapps/rocket_chat/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import logging
import re

from django.conf import settings

from student.models import anonymous_id_for_user, get_user

LOG = logging.getLogger(__name__)


def get_rocket_chat_settings():
"""Return dict with rocket chat settings"""
try:
return settings.ROCKET_CHAT_SETTINGS
except AttributeError, settings_error:
LOG.warning('Get settings warning: %s', settings_error)
pass
try:
xblock_settings = settings.XBLOCK_SETTINGS
return xblock_settings.get('RocketChatXBlock', None)
except AttributeError, xblock_settings_error:
LOG.warning('Get settings warning: %s', xblock_settings_error)
pass

return None


def create_user(api_rocket_chat, user, course_key):
"""Create a user in rocketChat"""
user, u_prof = get_user(user.email)
anonymous_id = anonymous_id_for_user(user, course_key)
api_rocket_chat.users_create(
email=user.email,
name=u_prof.name,
password=anonymous_id,
username=user.username
)


def create_course_group(api_rocket_chat, course_id, user_id, username):
"""
Add an user to the course group
"""
room_name = re.sub('[^A-Za-z0-9]+', '', course_id)
response = api_rocket_chat.groups_info(room_name=room_name)
try:
response = response.json()

if response['success']:
api_rocket_chat.groups_invite(response['group']['_id'], user_id)
else:
kwargs = {'members': [username]}
api_rocket_chat.groups_create(name=room_name, **kwargs)

except AttributeError:
LOG.error("Create Course Group error: response with status code = %s", response.status_code)
pass
128 changes: 128 additions & 0 deletions common/djangoapps/rocket_chat/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import logging

from django.http import Http404
from django.contrib.auth.decorators import login_required

from edxmako.shortcuts import render_to_response
from opaque_keys.edx.keys import CourseKey

from courseware.access import has_access
from courseware.courses import get_course_with_access
from student.models import CourseEnrollment

from xmodule.modulestore.django import modulestore
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers

from rocketchat_API.rocketchat import RocketChat as ApiRocketChat
from rocketchat_API.APIExceptions.RocketExceptions import RocketAuthenticationException, RocketConnectionException

from .utils import create_course_group, create_user, get_rocket_chat_settings

LOG = logging.getLogger(__name__)


@login_required
def rocket_chat_discussion(request, course_id):

if not configuration_helpers.get_value('ENABLE_ROCKET_CHAT_SERVICE'):
raise Http404

course_key = CourseKey.from_string(course_id)

with modulestore().bulk_operations(course_key):

user = request.user
course = get_course_with_access(user, 'load', course_key)

staff_access = has_access(user, 'staff', course)
user_is_enrolled = CourseEnrollment.is_enrolled(user, course.id)

course_homepage_invert_title = configuration_helpers.get_value(
'COURSE_HOMEPAGE_INVERT_TITLE', False)

course_title = course.display_name_with_default
if course_homepage_invert_title:
course_title = course.display_number_with_default

context = {
'request': request,
'cache': None,
'course': course,
'course_title': course_title,
'staff_access': staff_access,
'user_is_enrolled': user_is_enrolled,
}

rocket_chat_settings = get_rocket_chat_settings()

if rocket_chat_settings:

admin_user = rocket_chat_settings.get('admin_user', None)
admin_pass = rocket_chat_settings.get('admin_pass', None)
url_service = rocket_chat_settings.get('public_url_service', None)

if not admin_user or not admin_pass or not url_service:
LOG.error(
'RocketChat settings error: admin_user = %s, admin_pass= %s, public_url_service= %s',
admin_user,
admin_pass,
url_service
)
context['rocket_chat_error_message'] = 'Rocket chat service is currently not available'
return render_to_response('rocket_chat/rocket_chat.html', context)

try:
api_rocket_chat = ApiRocketChat(
admin_user,
admin_pass,
url_service
)
except RocketAuthenticationException:

LOG.error('ApiRocketChat error: RocketAuthenticationException')
context['rocket_chat_error_message'] = 'Rocket chat service is currently not available'

return render_to_response('rocket_chat/rocket_chat.html', context)

except RocketConnectionException:

LOG.error('ApiRocketChat error: RocketConnectionException')
context['rocket_chat_error_message'] = 'Rocket chat service is currently not available'

return render_to_response('rocket_chat/rocket_chat.html', context)

user_info = api_rocket_chat.users_info(username=user.username)

try:
user_info = user_info.json()
except AttributeError:
create_user(api_rocket_chat, user, course_key)

if 'success' in user_info and not user_info['success']:
create_user(api_rocket_chat, user, course_key)

response = api_rocket_chat.users_create_token(
username=user.username)

try:
response = response.json()
except AttributeError:
context['rocket_chat_error_message'] = 'status_code = {}'.format(
response.status_code)
return render_to_response('rocket_chat/rocket_chat.html', context)

if response['success']:
context['rocket_chat_data'] = response['data']
context['rocket_chat_url'] = rocket_chat_settings['public_url_service']
context['rocket_chat_error_message'] = None

create_course_group(api_rocket_chat, course_id, response['data']['userId'], user.username)

elif 'error' in response:
context['rocket_chat_error_message'] = response['error']

return render_to_response('rocket_chat/rocket_chat.html', context)

context['rocket_chat_error_message'] = 'Rocket chat service is currently not available'

return render_to_response('rocket_chat/rocket_chat.html', context)
19 changes: 19 additions & 0 deletions lms/djangoapps/courseware/tabs.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from django.conf import settings
from django.utils.translation import ugettext as _
from django.utils.translation import ugettext_noop
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
from openedx.core.lib.course_tabs import CourseTabPluginManager
from openedx.features.course_experience import UNIFIED_COURSE_TAB_FLAG, default_course_url_name
from student.models import CourseEnrollment
Expand Down Expand Up @@ -302,11 +303,29 @@ def link_func(course, reverse_func, index=index):
def to_json(self):
raise NotImplementedError('SingleTextbookTab should not be serialized.')

class RocketChatTab(EnrolledTab):
"""
The representation of the course rocketchat view type.
"""

type = "rocketchat"
title = ugettext_noop("RocketChat")
view_name = "rocket_chat_discussion"

@classmethod
def is_enabled(cls, course, user=None):
"""Returns true if rocketChat feature is enabled in the course.
"""
return configuration_helpers.get_value('ENABLE_ROCKET_CHAT_SERVICE')

def get_course_tab_list(request, course):
"""
Retrieves the course tab list from xmodule.tabs and manipulates the set as necessary
"""
if RocketChatTab.is_enabled(course):
course.tabs.extend([
RocketChatTab({"name": "RocketChat"}),
])
user = request.user
xmodule_tab_list = CourseTabList.iterate_displayable(course, user=user)

Expand Down
6 changes: 6 additions & 0 deletions lms/djangoapps/discussion/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,13 @@
get_group_names_by_id,
is_commentable_divided,
merge_dict,
is_discussion_enabled,
strip_none
)
from django_comment_common.utils import ThreadContext, get_course_discussion_settings, set_course_discussion_settings
from openedx.core.djangoapps.plugin_api.views import EdxFragmentView
from openedx.core.djangoapps.monitoring_utils import function_trace
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
from student.models import CourseEnrollment
from util.json_request import JsonResponse, expect_json
from xmodule.modulestore.django import modulestore
Expand Down Expand Up @@ -237,6 +239,10 @@ def forum_form_discussion(request, course_key):
"""
Renders the main Discussion page, potentially filtered by a search query
"""

if not is_discussion_enabled(course_key):
raise Http404

course = get_course_with_access(request.user, 'load', course_key, check_if_enrolled=True)
if request.is_ajax():
user = cc.User.from_django_user(request.user)
Expand Down
3 changes: 2 additions & 1 deletion lms/djangoapps/django_comment_client/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from openedx.core.djangoapps.content.course_structures.models import CourseStructure
from openedx.core.djangoapps.course_groups.cohorts import get_cohort_id, get_cohort_names, is_course_cohorted
from openedx.core.djangoapps.request_cache.middleware import request_cached
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
from student.models import get_user_by_username_or_email
from student.roles import GlobalStaff
from xmodule.modulestore.django import modulestore
Expand Down Expand Up @@ -1020,7 +1021,7 @@ def is_discussion_enabled(course_id):
"""
Return True if discussions are enabled; else False
"""
return settings.FEATURES.get('ENABLE_DISCUSSION_SERVICE')
return configuration_helpers.get_value('ENABLE_DISCUSSION_SERVICE', settings.FEATURES.get('ENABLE_DISCUSSION_SERVICE'))


def is_content_authored_by(content, user):
Expand Down
9 changes: 9 additions & 0 deletions lms/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,15 @@
),
]

urlpatterns += [
url(
r'^courses/{}/rocketchat/'.format(
settings.COURSE_ID_PATTERN,
),
include('rocket_chat.urls')
),
]

urlpatterns += [
url(
r'^courses/{}/tab/(?P<tab_type>[^/]+)/$'.format(
Expand Down
3 changes: 2 additions & 1 deletion requirements/edx/github.txt
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,5 @@ git+https://github.com/proversity-org/agnostic-content-xblock.git#egg=agnostic-c
git+https://github.com/proversity-org/rocket-chat-extension.git@v0.2.18#egg=rocketc-xblock==0.2.18


git+https://github.com/edx/edx-analytics-data-api-client.git#egg=edx-analytics-data-api-client
git+https://github.com/edx/edx-analytics-data-api-client.git#egg=edx-analytics-data-api-client
git+https://github.com/jadolg/rocketchat_API.git@v0.6.21#egg=rocketchat-API==0.6.21

0 comments on commit 270df62

Please sign in to comment.