Commit 7023eb4c by John Jarvis

resolving merge conflicts

parents 0d5c6ba3 a03134b3
...@@ -4,8 +4,24 @@ Test for User Creation from Micro-Sites ...@@ -4,8 +4,24 @@ Test for User Creation from Micro-Sites
from django.test import TestCase from django.test import TestCase
from student.models import UserSignupSource from student.models import UserSignupSource
import mock import mock
import json
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.contrib.auth.models import User
FAKE_MICROSITE = {
"SITE_NAME": "openedx.localhost",
"REGISTRATION_EXTRA_FIELDS": {
"address1": "required",
"city": "required",
"state": "required",
"country": "required",
"company": "required",
"title": "required"
},
"extended_profile_fields": [
"address1", "state", "company", "title"
]
}
def fake_site_name(name, default=None): # pylint: disable=W0613 def fake_site_name(name, default=None): # pylint: disable=W0613
""" """
...@@ -14,8 +30,13 @@ def fake_site_name(name, default=None): # pylint: disable=W0613 ...@@ -14,8 +30,13 @@ def fake_site_name(name, default=None): # pylint: disable=W0613
if name == 'SITE_NAME': if name == 'SITE_NAME':
return 'openedx.localhost' return 'openedx.localhost'
else: else:
return None return default
def fake_microsite_get_value(name, default=None): # pylint: disable=W0613
"""
create a fake microsite site name
"""
return FAKE_MICROSITE.get(name, default)
class TestMicrosite(TestCase): class TestMicrosite(TestCase):
"""Test for Account Creation from a white labeled Micro-Sites""" """Test for Account Creation from a white labeled Micro-Sites"""
...@@ -30,6 +51,14 @@ class TestMicrosite(TestCase): ...@@ -30,6 +51,14 @@ class TestMicrosite(TestCase):
"honor_code": "true", "honor_code": "true",
"terms_of_service": "true", "terms_of_service": "true",
} }
self.extended_params = dict(self.params.items() + {
"address1": "foo",
"city": "foo",
"state": "foo",
"country": "foo",
"company": "foo",
"title": "foo"
}.items())
@mock.patch("microsite_configuration.microsite.get_value", fake_site_name) @mock.patch("microsite_configuration.microsite.get_value", fake_site_name)
def test_user_signup_source(self): def test_user_signup_source(self):
...@@ -49,3 +78,27 @@ class TestMicrosite(TestCase): ...@@ -49,3 +78,27 @@ class TestMicrosite(TestCase):
response = self.client.post(self.url, self.params) response = self.client.post(self.url, self.params)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual(len(UserSignupSource.objects.filter(site='openedx.localhost')), 0) self.assertEqual(len(UserSignupSource.objects.filter(site='openedx.localhost')), 0)
@mock.patch("microsite_configuration.microsite.get_value", fake_microsite_get_value)
def test_user_signup_missing_enhanced_profile(self):
"""
test to create a user form the microsite but don't provide any of the microsite specific
profile information
"""
response = self.client.post(self.url, self.params)
self.assertEqual(response.status_code, 400)
@mock.patch("microsite_configuration.microsite.get_value", fake_microsite_get_value)
def test_user_signup_including_enhanced_profile(self):
"""
test to create a user form the microsite but don't provide any of the microsite specific
profile information
"""
response = self.client.post(self.url, self.extended_params)
self.assertEqual(response.status_code, 200)
user = User.objects.get(username=self.username)
meta = json.loads(user.profile.meta)
self.assertEqual(meta['address1'], 'foo')
self.assertEqual(meta['state'], 'foo')
self.assertEqual(meta['company'], 'foo')
self.assertEqual(meta['title'], 'foo')
...@@ -6,6 +6,7 @@ import logging ...@@ -6,6 +6,7 @@ import logging
import re import re
import uuid import uuid
import time import time
import json
from collections import defaultdict from collections import defaultdict
from pytz import UTC from pytz import UTC
...@@ -1039,7 +1040,7 @@ def user_signup_handler(sender, **kwargs): # pylint: disable=W0613 ...@@ -1039,7 +1040,7 @@ def user_signup_handler(sender, **kwargs): # pylint: disable=W0613
log.info(u'user {} originated from a white labeled "Microsite"'.format(kwargs['instance'].id)) log.info(u'user {} originated from a white labeled "Microsite"'.format(kwargs['instance'].id))
def _do_create_account(post_vars): def _do_create_account(post_vars, extended_profile=None):
""" """
Given cleaned post variables, create the User and UserProfile objects, as well as the Given cleaned post variables, create the User and UserProfile objects, as well as the
registration for this user. registration for this user.
...@@ -1089,6 +1090,10 @@ def _do_create_account(post_vars): ...@@ -1089,6 +1090,10 @@ def _do_create_account(post_vars):
profile.country = post_vars.get('country') profile.country = post_vars.get('country')
profile.goals = post_vars.get('goals') profile.goals = post_vars.get('goals')
# add any extended profile information in the denormalized 'meta' field in the profile
if extended_profile:
profile.meta = json.dumps(extended_profile)
try: try:
profile.year_of_birth = int(post_vars['year_of_birth']) profile.year_of_birth = int(post_vars['year_of_birth'])
except (ValueError, KeyError): except (ValueError, KeyError):
...@@ -1115,7 +1120,12 @@ def create_account(request, post_override=None): # pylint: disable-msg=too-many ...@@ -1115,7 +1120,12 @@ def create_account(request, post_override=None): # pylint: disable-msg=too-many
js = {'success': False} # pylint: disable-msg=invalid-name js = {'success': False} # pylint: disable-msg=invalid-name
post_vars = post_override if post_override else request.POST post_vars = post_override if post_override else request.POST
extra_fields = getattr(settings, 'REGISTRATION_EXTRA_FIELDS', {})
# allow for microsites to define their own set of required/optional/hidden fields
extra_fields = microsite.get_value(
'REGISTRATION_EXTRA_FIELDS',
getattr(settings, 'REGISTRATION_EXTRA_FIELDS', {})
)
if settings.FEATURES.get('ENABLE_THIRD_PARTY_AUTH') and pipeline.running(request): if settings.FEATURES.get('ENABLE_THIRD_PARTY_AUTH') and pipeline.running(request):
post_vars = dict(post_vars.items()) post_vars = dict(post_vars.items())
...@@ -1188,7 +1198,7 @@ def create_account(request, post_override=None): # pylint: disable-msg=too-many ...@@ -1188,7 +1198,7 @@ def create_account(request, post_override=None): # pylint: disable-msg=too-many
else: else:
min_length = 2 min_length = 2
if len(post_vars[field_name]) < min_length: if field_name not in post_vars or len(post_vars[field_name]) < min_length:
error_str = { error_str = {
'username': _('Username must be minimum of two characters long'), 'username': _('Username must be minimum of two characters long'),
'email': _('A properly formatted e-mail is required'), 'email': _('A properly formatted e-mail is required'),
...@@ -1204,7 +1214,12 @@ def create_account(request, post_override=None): # pylint: disable-msg=too-many ...@@ -1204,7 +1214,12 @@ def create_account(request, post_override=None): # pylint: disable-msg=too-many
'city': _('A city is required'), 'city': _('A city is required'),
'country': _('A country is required') 'country': _('A country is required')
} }
js['value'] = error_str[field_name]
if field_name in error_str:
js['value'] = error_str[field_name]
else:
js['value'] = _('You are missing one or more required fields')
js['field'] = field_name js['field'] = field_name
return JsonResponse(js, status=400) return JsonResponse(js, status=400)
...@@ -1248,10 +1263,22 @@ def create_account(request, post_override=None): # pylint: disable-msg=too-many ...@@ -1248,10 +1263,22 @@ def create_account(request, post_override=None): # pylint: disable-msg=too-many
js['field'] = 'password' js['field'] = 'password'
return JsonResponse(js, status=400) return JsonResponse(js, status=400)
# allow microsites to define 'extended profile fields' which are
# captured on user signup (for example via an overriden registration.html)
# and then stored in the UserProfile
extended_profile_fields = microsite.get_value('extended_profile_fields', [])
extended_profile = None
for field in extended_profile_fields:
if field in post_vars:
if not extended_profile:
extended_profile = {}
extended_profile[field] = post_vars[field]
# Ok, looks like everything is legit. Create the account. # Ok, looks like everything is legit. Create the account.
try: try:
with transaction.commit_on_success(): with transaction.commit_on_success():
ret = _do_create_account(post_vars) ret = _do_create_account(post_vars, extended_profile)
except AccountValidationError as e: except AccountValidationError as e:
return JsonResponse({'success': False, 'value': e.message, 'field': e.field}, status=400) return JsonResponse({'success': False, 'value': e.message, 'field': e.field}, status=400)
......
...@@ -632,7 +632,12 @@ class DraftModuleStore(MongoModuleStore): ...@@ -632,7 +632,12 @@ class DraftModuleStore(MongoModuleStore):
""" """
Depth first publishing from the given location Depth first publishing from the given location
""" """
item = self.get_item(item_location) try:
# handle child does not exist w/o killing publish
item = self.get_item(item_location)
except ItemNotFoundError:
log.warning('Cannot find: %s', item_location)
return
# publish the children first # publish the children first
if item.has_children: if item.has_children:
......
...@@ -19,5 +19,8 @@ def user_has_cart_context_processor(request): ...@@ -19,5 +19,8 @@ def user_has_cart_context_processor(request):
request.user.is_authenticated() and # user is logged in and request.user.is_authenticated() and # user is logged in and
settings.FEATURES.get('ENABLE_PAID_COURSE_REGISTRATION') and # settings enable paid course reg and settings.FEATURES.get('ENABLE_PAID_COURSE_REGISTRATION') and # settings enable paid course reg and
settings.FEATURES.get('ENABLE_SHOPPING_CART') and # settings enable shopping cart and settings.FEATURES.get('ENABLE_SHOPPING_CART') and # settings enable shopping cart and
shoppingcart.models.Order.user_cart_has_items(request.user) # user's cart has items shoppingcart.models.Order.user_cart_has_items(
request.user,
shoppingcart.models.PaidCourseRegistration
) # user's cart has PaidCourseRegistrations
)} )}
...@@ -87,15 +87,17 @@ class Order(models.Model): ...@@ -87,15 +87,17 @@ class Order(models.Model):
return cart_order return cart_order
@classmethod @classmethod
def user_cart_has_items(cls, user): def user_cart_has_items(cls, user, item_type=None):
""" """
Returns true if the user (anonymous user ok) has Returns true if the user (anonymous user ok) has
a cart with items in it. (Which means it should be displayed. a cart with items in it. (Which means it should be displayed.
If a item_type is passed in, then we check to see if the cart has at least one of
those types of OrderItems
""" """
if not user.is_authenticated(): if not user.is_authenticated():
return False return False
cart = cls.get_cart_for_user(user) cart = cls.get_cart_for_user(user)
return cart.has_items() return cart.has_items(item_type)
@property @property
def total_cost(self): def total_cost(self):
...@@ -105,11 +107,19 @@ class Order(models.Model): ...@@ -105,11 +107,19 @@ class Order(models.Model):
""" """
return sum(i.line_cost for i in self.orderitem_set.filter(status=self.status)) # pylint: disable=E1101 return sum(i.line_cost for i in self.orderitem_set.filter(status=self.status)) # pylint: disable=E1101
def has_items(self): def has_items(self, item_type=None):
""" """
Does the cart have any items in it? Does the cart have any items in it?
If an item_type is passed in then we check to see if there are any items of that class type
""" """
return self.orderitem_set.exists() # pylint: disable=E1101 if not item_type:
return self.orderitem_set.exists() # pylint: disable=E1101
else:
items = self.orderitem_set.all().select_subclasses()
for item in items:
if isinstance(item, item_type):
return True
return False
def clear(self): def clear(self):
""" """
......
...@@ -52,6 +52,21 @@ class OrderTest(ModuleStoreTestCase): ...@@ -52,6 +52,21 @@ class OrderTest(ModuleStoreTestCase):
item = OrderItem(order=cart, user=self.user) item = OrderItem(order=cart, user=self.user)
item.save() item.save()
self.assertTrue(Order.user_cart_has_items(self.user)) self.assertTrue(Order.user_cart_has_items(self.user))
self.assertFalse(Order.user_cart_has_items(self.user, CertificateItem))
self.assertFalse(Order.user_cart_has_items(self.user, PaidCourseRegistration))
def test_user_cart_has_paid_course_registration_items(self):
cart = Order.get_cart_for_user(self.user)
item = PaidCourseRegistration(order=cart, user=self.user)
item.save()
self.assertTrue(Order.user_cart_has_items(self.user, PaidCourseRegistration))
self.assertFalse(Order.user_cart_has_items(self.user, CertificateItem))
def test_user_cart_has_certificate_items(self):
cart = Order.get_cart_for_user(self.user)
CertificateItem.add_to_order(cart, self.course_key, self.cost, 'honor')
self.assertTrue(Order.user_cart_has_items(self.user, CertificateItem))
self.assertFalse(Order.user_cart_has_items(self.user, PaidCourseRegistration))
def test_cart_clear(self): def test_cart_clear(self):
cart = Order.get_cart_for_user(user=self.user) cart = Order.get_cart_for_user(user=self.user)
......
{% load i18n %}{% load url from future %}{% autoescape off %} {% load i18n %}{% load url from future %}{% autoescape off %}
{% blocktrans with site_name=site_name %}You're receiving this e-mail because you requested a password reset for your user account at {{ site_name }}.{% endblocktrans %} {% blocktrans %}You're receiving this e-mail because you requested a password reset for your user account at edx.org.{% endblocktrans %}
{% trans "Please go to the following page and choose a new password:" %} {% trans "Please go to the following page and choose a new password:" %}
{% block reset_link %} {% block reset_link %}
...@@ -10,6 +10,6 @@ http{% if is_secure %}s{% endif %}://{{domain}}{% url 'student.views.password_re ...@@ -10,6 +10,6 @@ http{% if is_secure %}s{% endif %}://{{domain}}{% url 'student.views.password_re
{% trans "Thanks for using our site!" %} {% trans "Thanks for using our site!" %}
{% blocktrans with platform_name=platform_name %}The {{ platform_name }} Team{% endblocktrans %} {% blocktrans %}The edX Team{% endblocktrans %}
{% endautoescape %} {% endautoescape %}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment