Skip to content

Commit

Permalink
Release March 24, 2018. (openedx#2472)
Browse files Browse the repository at this point in the history
* Add ORA2 video upload option openedx#2375 (openedx#2417)

* Modified courseware page look and feel openedx#2377 (openedx#2409)

* Modified about page openedx#2379 (openedx#2413)

* Fix biz bugs. openedx#2404 (openedx#2406)

* Fix display width of popup. (openedx#2384)

(cherry picked from commit a43c935a575d15fcf629f0edeb81446c778cda95)

* Validate duplicate url-code.

* Fix bug, when course not found.

* Fix order of course as CourseOverview.

* Remove additional-info count from contract grid. openedx#2419 (openedx#2437)

* Fix order global course. openedx#2420 (openedx#2421)

* Add additional info register. openedx#2419 (openedx#2433)

* fix survey csv character encode problem openedx#2380 (openedx#2434)

* Fix bokchoy for LoginCodeEnabledBizSurveyTest. (openedx#2457)

* Fix register students confirm message. (openedx#2461)

* Add command to check playback_log. openedx#2438 (openedx#2445)

* Fix courseware page lookandfeel (openedx#2446, openedx#2439, openedx#2452, openedx#2453)

* Fix box-shadow of sequence-nav-button. openedx#2453 (openedx#2467)

* Fix bugs. openedx#2462 openedx#2463 (openedx#2464)

* Fix password message in register students page.

* Fix glass pane of processing when register additional item.

* Fix display width of popup. (openedx#2466)

* Fix min-width of sequence-nav. openedx#2468 (openedx#2469)

* Fix isRegistered javascript in about page openedx#2470 (openedx#2471)
  • Loading branch information
kawaguchi-ks authored Mar 22, 2018
1 parent d26cd4f commit 5a993a9
Show file tree
Hide file tree
Showing 83 changed files with 3,459 additions and 672 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import logging
from collections import Counter
from datetime import datetime, timedelta
from optparse import make_option

from django.conf import settings
from django.core.management.base import BaseCommand, CommandError

from biz.djangoapps.util import datetime_utils
from biz.djangoapps.util.biz_mongo_connection import BizMongoConnection
from biz.djangoapps.util.decorators import handle_command_exception

log = logging.getLogger(__name__)


class Command(BaseCommand):
help = """
Usage: python manage.py lms --settings=aws check_playback_log [--target_date=<yyyymmdd>]
"""

option_list = BaseCommand.option_list + (
make_option('--target_date',
default=None,
action='store',
help="target_date should be 'yyyymmdd' format."),
)

@handle_command_exception('/edx/var/log/biz/check_playback_log_command.txt')
def handle(self, *args, **options):

if len(args) > 0:
raise CommandError("This command requires no arguments. Use target_date option if you want.")

target_date = options.get('target_date')
if target_date:
try:
target_date = datetime.strptime(target_date, '%Y%m%d')
except ValueError:
raise CommandError("target_date should be 'yyyymmdd' format.")
else:
# By default, check for today (JST)
target_date = datetime_utils.timezone_today()

log.info("Command check_playback_log started for {}.".format(target_date.strftime('%Y/%m/%d')))

# NOTE: By default, PyMongo deals with only naive datetimes.
# NOTE: emr_aggregate_playback_log sets `created_at` to yesterday's midnight.
# For example, when it runs at 2017-11-13 06:06:07+9:00, it sets as below:
# - u'created_at': datetime.datetime(2017, 11, 12, 0, 0, tzinfo=<bson.tz_util.FixedOffset object>)
target_datetime = datetime.combine(target_date + timedelta(days=-1), datetime.min.time())

try:
store_config = settings.BIZ_MONGO['playback_log']
db_connection = BizMongoConnection(**store_config)
db = db_connection.database
collection = db[store_config['collection']]
except Exception as e:
raise e

try:
result = collection.aggregate([
{'$group': {
'_id': {
'course_id': '$course_id',
'vertical_id': '$vertical_id',
'target_id': '$target_id',
'created_at': '$created_at',
},
'total': {'$sum': 1},
}},
{'$match': {
'_id.created_at': target_datetime,
'total': {'$gt': 1},
}},
],
allowDiskUse=True,
)['result']

except Exception as e:
raise e

if result:
messages = ["{} duplicated documents are detected in playback_log for {}.".format(len(result), target_date.strftime('%Y/%m/%d'))]
for course_id, count in Counter([x['_id']['course_id'] for x in result]).most_common():
messages.append('{},{}'.format(course_id, count))
raise Exception('\n'.join(messages))
8 changes: 6 additions & 2 deletions biz/djangoapps/ga_contract/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,15 @@ def __init__(self, *args, **kargs):
super(ContractAuthForm, self).__init__(*args, **kargs)

def clean(self):
url_code = self.cleaned_data['url_code']
if not re.match(r'^{url_code}$'.format(url_code=URL_CODE_PATTERN), url_code):
url_code = self.cleaned_data['url_code'] if 'url_code' in self.cleaned_data else None
if url_code is None or not re.match(r'^{url_code}$'.format(url_code=URL_CODE_PATTERN), url_code):
raise forms.ValidationError(
_("Url code is invalid. Please enter alphanumeric {min_length}-{max_length} characters.").format(
min_length=URL_CODE_MIN_LENGTH, max_length=URL_CODE_MAX_LENGTH))

if 'contract' in self.cleaned_data and ContractAuth.objects.filter(url_code=url_code).exclude(contract=self.cleaned_data['contract']).exists():
raise forms.ValidationError(_("Url code is duplicated. Please change url code."))

return self.cleaned_data

class Meta:
Expand Down
21 changes: 7 additions & 14 deletions biz/djangoapps/ga_contract/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,19 +86,12 @@ def clean(self):
self.errors["contract"] = ErrorList([_("Contract end date is before contract start date.")])

# check contract detail inputs
course_id_list = self.data.getlist('detail_course')
detail_delete_list = self.data.getlist('detail_delete')
valid_course_id_list = [v for i, v in enumerate(course_id_list) if not detail_delete_list[i]]
if len(valid_course_id_list) != len(set(valid_course_id_list)):
self.errors["contract_detail"] = ErrorList(
[_("You can not enter duplicate values in {0}.").format(_('Contract Detail Info'))])

# check contract detail inputs
display_name_list = self.data.getlist('additional_info_display_name')
additional_info_delete_list = self.data.getlist('additional_info_delete')
valid_display_name_list = [v for i, v in enumerate(display_name_list) if not additional_info_delete_list[i]]
if len(valid_display_name_list) != len(set(valid_display_name_list)):
self.errors["additional_info"] = ErrorList(
[_("You can not enter duplicate values in {0}.").format(_('Additional Info'))])
if len(self.data.getlist('detail_id')) == len(self.data.getlist('detail_course')) == len(self.data.getlist('detail_delete')):
course_id_list = self.data.getlist('detail_course')
detail_delete_list = self.data.getlist('detail_delete')
valid_course_id_list = [v for i, v in enumerate(course_id_list) if not detail_delete_list[i]]
if len(valid_course_id_list) != len(set(valid_course_id_list)):
self.errors["contract_detail"] = ErrorList(
[_("You can not enter duplicate values in {0}.").format(_('Contract Detail Info'))])

return cleaned_data
5 changes: 5 additions & 0 deletions biz/djangoapps/ga_contract/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,11 @@ def find_by_contract_id(cls, contract_id):
"""
return cls.objects.filter(contract_id=contract_id).order_by('id')

@classmethod
def validate_and_find_by_ids(cls, contract, additional_info_ids):
additional_info_list = cls.objects.filter(contract=contract)
return None if cls.objects.filter(contract=contract).exclude(id__in=additional_info_ids).exists() else additional_info_list


class ContractAuth(models.Model):
"""
Expand Down
70 changes: 70 additions & 0 deletions biz/djangoapps/ga_contract/tests/test_admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
from mock import patch

from django.core.urlresolvers import reverse

from biz.djangoapps.util.tests.testcase import BizTestBase
from student.tests.factories import UserFactory


class ContractAuthAdminTest(BizTestBase):

def setUp(self):
super(ContractAuthAdminTest, self).setUp()

user = UserFactory.create(is_staff=True, is_superuser=True)
user.save()

self.client.login(username=user.username, password='test')

self.contract = self._create_contract()
self.contract_other = self._create_contract()
self.url_code = 'testUrlCode'

def test_initial_url_code(self):
with patch(
'biz.djangoapps.ga_contract.admin.get_random_string',
return_value=self.url_code
):
response = self.client.get(reverse('admin:ga_contract_contractauth_add'))
self.assertEqual(200, response.status_code)
self.assertIn('value="{url_code}"'.format(url_code=self.url_code), response.content)

def test_add(self):
response = self.client.post(reverse('admin:ga_contract_contractauth_add'), data={
'contract': self.contract.id,
'url_code': self.url_code,
})
self.assertRedirects(response, reverse('admin:ga_contract_contractauth_changelist'))

response = self.client.get(reverse('admin:ga_contract_contractauth_changelist'))
self.assertEqual(200, response.status_code)
self.assertIn('{contract_name}({url_code})'.format(contract_name=self.contract.contract_name, url_code=self.url_code), response.content)

def test_contract_required(self):
response = self.client.post(reverse('admin:ga_contract_contractauth_add'), data={
'url_code': self.url_code,
})
self.assertEqual(200, response.status_code)
self.assertIn('This field is required.'.format(url_code=self.url_code), response.content)

def test_url_code_required(self):
response = self.client.post(reverse('admin:ga_contract_contractauth_add'), data={
'contract': self.contract.id,
})
self.assertEqual(200, response.status_code)
self.assertIn('This field is required.'.format(url_code=self.url_code), response.content)
self.assertIn('Url code is invalid. Please enter alphanumeric 8-255 characters.'.format(url_code=self.url_code), response.content)

def test_url_code_duplicate(self):
response = self.client.post(reverse('admin:ga_contract_contractauth_add'), data={
'contract': self.contract_other.id,
'url_code': self.url_code,
})
self.assertRedirects(response, reverse('admin:ga_contract_contractauth_changelist'))

response = self.client.post(reverse('admin:ga_contract_contractauth_add'), data={
'contract': self.contract.id,
'url_code': self.url_code,
})
self.assertEqual(200, response.status_code)
self.assertIn('Url code is duplicated. Please change url code.'.format(url_code=self.url_code), response.content)
Loading

0 comments on commit 5a993a9

Please sign in to comment.