Skip to content
This repository has been archived by the owner on May 12, 2022. It is now read-only.

Commit

Permalink
Merge master branch into juniper-rebase branch.
Browse files Browse the repository at this point in the history
  • Loading branch information
attiyaIshaque committed Dec 10, 2020
2 parents f117300 + 08848a1 commit 2ab832d
Show file tree
Hide file tree
Showing 85 changed files with 1,246 additions and 267 deletions.
8 changes: 5 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@ script:
- make test

addons:
firefox: "46.0"
firefox: "52.0.3"

services:
- xvfb

before_install:
- wget "https://github.com/mozilla/geckodriver/releases/download/v0.24.0/geckodriver-v0.24.0-linux64.tar.gz"
- tar xfz geckodriver-v0.24.0-linux64.tar.gz
- sudo mv geckodriver /usr/local/bin
- "export DISPLAY=:99.0"

install:
Expand All @@ -32,5 +35,4 @@ after_success: coveralls
branches:
only:
- master
- cdodge/mcka-master
- cdodge/notification-digest
- development
59 changes: 59 additions & 0 deletions edx_notifications/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
"""
Configuration for edx_notifications Django app
"""

import logging

from django.apps import AppConfig
from django.conf import settings


log = logging.getLogger(__name__)


class EdxNotificationsConfig(AppConfig):
"""
Configuration class for edx_notifications Django app
"""
name = 'edx_notifications'
verbose_name = "Notification subsystem"

def ready(self):
if settings.FEATURES.get('ENABLE_NOTIFICATIONS', False):
startup_notification_subsystem()


def startup_notification_subsystem():
"""
Initialize the Notification subsystem
"""
try:
from openedx.core.djangoapps.course_groups.scope_resolver import CourseGroupScopeResolver # pylint: disable=import-error
from student.scope_resolver import CourseEnrollmentsScopeResolver, StudentEmailScopeResolver # pylint: disable=import-error
from edx_solutions_projects.scope_resolver import GroupProjectParticipantsScopeResolver # pylint: disable=import-error
from edx_notifications.scopes import register_user_scope_resolver
from edx_notifications.namespaces import register_namespace_resolver
from util.namespace_resolver import CourseNamespaceResolver # pylint: disable=import-error, no-name-in-module
from edx_notifications import startup

startup.initialize()

# register the scope resolvers that the runtime will be providing to edx-notifications.
register_user_scope_resolver('course_enrollments', CourseEnrollmentsScopeResolver())
register_user_scope_resolver('course_group', CourseGroupScopeResolver())
register_user_scope_resolver('group_project_participants', GroupProjectParticipantsScopeResolver())
register_user_scope_resolver('group_project_workgroup', GroupProjectParticipantsScopeResolver())
register_user_scope_resolver('user_email_resolver', StudentEmailScopeResolver())

# register namespace resolver
register_namespace_resolver(CourseNamespaceResolver())
except Exception as ex: # pylint: disable=broad-except
# Note this will fail when we try to run migrations as manage.py will call startup.py
# and startup.initialze() will try to manipulate some database tables.
# We need to research how to identify when we are being started up as part of
# a migration script
log.error(
'There was a problem initializing notifications subsystem. '
'This could be because the database tables have not yet been created and '
'./manage.py lms syncdb needs to run setup.py. Error was "%s". Continuing...', str(ex)
)
34 changes: 21 additions & 13 deletions edx_notifications/base_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
import inspect
from datetime import datetime, timedelta

import six
import dateutil.parser
from django.utils.translation import ugettext_lazy
from freezegun.api import FakeDatetime


Expand Down Expand Up @@ -129,15 +129,23 @@ class StringField(TypedField):
Specialized subclass of TypedField(unicode) as a convienence
"""

_expected_types = [six.text_type, str]
_expected_types = [str, str]


class LazyField(TypedField):
"""
Specialized subclass of TypedField(unicode) as a convienence for Translations support
"""

_expected_types = [str, str, type(ugettext_lazy())]


class IntegerField(TypedField):
"""
Specialized subclass of TypedField(int) as a convienence
"""

_expected_types = list(six.integer_types)
_expected_types = list((int,))


class BooleanField(TypedField):
Expand Down Expand Up @@ -191,8 +199,8 @@ def from_json(cls, _value):

_dict = json.loads(_value)

for key, value in six.iteritems(_dict):
if isinstance(value, six.string_types):
for key, value in _dict.items():
if isinstance(value, str):
# This could be a datetime posing as a ISO8601 formatted string
# we so have to apply some heuristics here
# to see if we want to even attempt
Expand Down Expand Up @@ -233,7 +241,7 @@ def __init__(self, **kwargs):
"""

self._allowed_values = kwargs['allowed_values']
super(EnumField, self).__init__(**kwargs)
super().__init__(**kwargs)

def __set__(self, instance, value):
"""
Expand All @@ -247,7 +255,7 @@ def __set__(self, instance, value):
).format(value=value, allowed=str(self._allowed_values))
raise ValueError(msg)

super(EnumField, self).__set__(instance, value)
super().__set__(instance, value)


class BaseDataObjectMetaClass(type):
Expand All @@ -260,7 +268,7 @@ class BaseDataObjectMetaClass(type):
def __new__(mcs, name, bases, attrs):
# Iterate over the TypedField attrs before they're bound to the class
# so that we don't accidentally trigger any __get__ methods
for attr_name, attr in six.iteritems(attrs):
for attr_name, attr in attrs.items():
if isinstance(attr, TypedField):
attr.__name__ = attr_name

Expand All @@ -269,10 +277,10 @@ def __new__(mcs, name, bases, attrs):
for attr_name, attr in inspect.getmembers(base, lambda attr: isinstance(attr, TypedField)):
attr.__name__ = attr_name

return super(BaseDataObjectMetaClass, mcs).__new__(mcs, name, bases, attrs)
return super().__new__(mcs, name, bases, attrs)


class BaseDataObject(six.with_metaclass(BaseDataObjectMetaClass, object)):
class BaseDataObject(metaclass=BaseDataObjectMetaClass):
"""
A base class for all Notification Data Objects
"""
Expand Down Expand Up @@ -312,7 +320,7 @@ def __setattr__(self, attribute, value):
).format(name=attribute)
)

super(BaseDataObject, self).__setattr__(attribute, value)
super().__setattr__(attribute, value)

def __eq__(self, other):
"""
Expand Down Expand Up @@ -348,7 +356,7 @@ def __unicode__(self):
Dump out all of our fields
"""

return six.text_type(self.get_fields())
return str(self.get_fields())

@classmethod
def clone(cls, src):
Expand Down Expand Up @@ -441,4 +449,4 @@ def __init__(self, related_type, **kwargs):

self._expected_types = [related_type]

super(RelatedObjectField, self).__init__(**kwargs)
super().__init__(**kwargs)
3 changes: 1 addition & 2 deletions edx_notifications/callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import abc
import logging

import six

from edx_notifications.scopes import resolve_user_scope
from edx_notifications.exceptions import ItemNotFoundError
Expand All @@ -21,7 +20,7 @@
log = logging.getLogger(__name__)


class NotificationCallbackTimerHandler(six.with_metaclass(abc.ABCMeta, object)):
class NotificationCallbackTimerHandler(metaclass=abc.ABCMeta):
"""
Interface for timer callbacks
"""
Expand Down
5 changes: 2 additions & 3 deletions edx_notifications/channels/channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import copy
from importlib import import_module

import six
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured

Expand All @@ -28,7 +27,7 @@ def _init_channel_providers():
if not config:
raise ImproperlyConfigured("Settings not configured with NOTIFICATION_CHANNEL_PROVIDERS!")

for key, channel_config in six.iteritems(config):
for key, channel_config in config.items():
if 'class' not in channel_config or 'options' not in channel_config:
msg = (
"Misconfigured NOTIFICATION_CHANNEL_PROVIDERS settings, "
Expand Down Expand Up @@ -167,7 +166,7 @@ def reset_notification_channels():
_CHANNEL_PROVIDERS_TYPE_MAPS.clear()


class BaseNotificationChannelProvider(six.with_metaclass(abc.ABCMeta, object)):
class BaseNotificationChannelProvider(metaclass=abc.ABCMeta):
"""
The abstract base class that all NotificationChannelProviders
need to implement
Expand Down
5 changes: 2 additions & 3 deletions edx_notifications/channels/link_resolvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@
import logging
from importlib import import_module

import six

from edx_notifications.data import NotificationMessage

log = logging.getLogger(__name__)


class BaseLinkResolver(six.with_metaclass(abc.ABCMeta, object)):
class BaseLinkResolver(metaclass=abc.ABCMeta):
"""
The abstract base class that all link resolvers will need to implement
"""
Expand Down Expand Up @@ -140,7 +139,7 @@ def _get_linked_resolved_msg(self, msg):
"""

if msg.resolve_links:
for link_name, link_params in six.iteritems(msg.resolve_links):
for link_name, link_params in msg.resolve_links.items():
resolved_link = self.resolve_msg_link(msg, link_name, link_params)
if resolved_link:
# copy the msg because we are going to alter it and we don't want to affect
Expand Down
2 changes: 1 addition & 1 deletion edx_notifications/channels/parse_push.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def __init__(self, name=None, display_name=None, display_description=None,
self.application_id = application_id
self.rest_api_key = rest_api_key

super(ParsePushNotificationChannelProvider, self).__init__(
super().__init__(
name=name,
display_name=display_name,
display_description=display_description,
Expand Down
6 changes: 3 additions & 3 deletions edx_notifications/channels/tests/test_channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def dispatch_notification_to_user(self, user_id, msg, channel_context=None):
"""
This will raise an error
"""
raise super(BadChannel, self).dispatch_notification_to_user(
raise super().dispatch_notification_to_user(
user_id,
msg,
channel_context=channel_context
Expand All @@ -107,7 +107,7 @@ def bulk_dispatch_notification(self, user_ids, msg, exclude_user_ids=None, chann
Perform a bulk dispatch of the notification message to
all user_ids that will be enumerated over in user_ids.
"""
raise super(BadChannel, self).bulk_dispatch_notification(
raise super().bulk_dispatch_notification(
user_ids,
msg,
channel_context=channel_context
Expand All @@ -117,7 +117,7 @@ def resolve_msg_link(self, msg, link_name, params, channel_context=None):
"""
Generates the appropriate link given a msg, a link_name, and params
"""
raise super(BadChannel, self).resolve_msg_link(
raise super().resolve_msg_link(
msg,
link_name,
params,
Expand Down
2 changes: 1 addition & 1 deletion edx_notifications/channels/tests/test_link_resolvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def resolve(self, msg_type_name, link_name, params, exact_match_only=False):
"""
Simply call into our parent which show throw exception
"""
return super(BadLinkResolver, self).resolve(msg_type_name, link_name, params, exact_match_only=exact_match_only)
return super().resolve(msg_type_name, link_name, params, exact_match_only=exact_match_only)


class BaseLinkResolverTests(TestCase):
Expand Down
6 changes: 2 additions & 4 deletions edx_notifications/channels/triggered_email.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,10 @@
import uuid
import logging
import datetime
from urllib import parse
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

import six.moves.urllib.error
import six.moves.urllib.parse
import six.moves.urllib.request # pylint: disable=import-error
import pytz
from django.core.mail import EmailMessage
from django.template.loader import render_to_string
Expand Down Expand Up @@ -89,7 +87,7 @@ def dispatch_notification_to_user(self, user_id, msg, channel_context=None):
if resolve_links and not click_link.startswith('http'):
click_link = const.NOTIFICATION_EMAIL_CLICK_LINK_URL_FORMAT.format(
url_path=click_link,
encoded_url_path=six.moves.urllib.parse.quote(click_link),
encoded_url_path=parse.quote(click_link),
user_msg_id=user_msg.id,
msg_id=user_msg.msg.id,
hostname=const.NOTIFICATION_APP_HOSTNAME
Expand Down
5 changes: 2 additions & 3 deletions edx_notifications/channels/urban_airship.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import json
import logging

import six
import requests
from requests.auth import HTTPBasicAuth
from requests.exceptions import RequestException
Expand All @@ -33,7 +32,7 @@ def __init__(self, name=None, display_name=None, display_description=None, link_
"""
Initializer
"""
super(UrbanAirshipNotificationChannelProvider, self).__init__(
super().__init__(
name=name,
display_name=display_name,
display_description=display_description,
Expand Down Expand Up @@ -96,7 +95,7 @@ def call_ua_push_api(self, payload, api_credentials):
)

except RequestException as ex:
log.error("Urban Airship push notifications API failed with error %s", six.text_type(ex))
log.error("Urban Airship push notifications API failed with error %s", str(ex))
return resp

def bulk_dispatch_notification(self, user_ids, msg, exclude_user_ids=None, channel_context=None):
Expand Down
11 changes: 6 additions & 5 deletions edx_notifications/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@


from django.conf import settings
from django.utils.translation import ugettext_lazy as _

NOTIFICATION_PRIORITY_NONE = 0
NOTIFICATION_PRIORITY_LOW = 1
Expand Down Expand Up @@ -101,27 +102,27 @@
'groups': {
'announcements': {
'name': 'announcements',
'display_name': 'Announcements',
'display_name': _('Announcements'),
'group_order': 1
},
'group_work': {
'name': 'group_work',
'display_name': 'Group Work',
'display_name': _('Group Work'),
'group_order': 2
},
'leaderboards': {
'name': 'leaderboards',
'display_name': 'Leaderboards',
'display_name': _('Leaderboards'),
'group_order': 3
},
'discussions': {
'name': 'discussions',
'display_name': 'Discussion',
'display_name': _('Discussion'),
'group_order': 4
},
'_default': {
'name': '_default',
'display_name': 'Other',
'display_name': _('Other'),
'group_order': 5
},
},
Expand Down
Loading

0 comments on commit 2ab832d

Please sign in to comment.