Django-admin for Embargo feature
Allows specification of countries to embargo, what course(s) should apply embargo restrictions, and whitelist/blacklist capability for specific individual IP addresses.
This commit is contained in:
61
common/djangoapps/embargo/admin.py
Normal file
61
common/djangoapps/embargo/admin.py
Normal file
@@ -0,0 +1,61 @@
|
||||
"""
|
||||
Django admin page for embargo models
|
||||
"""
|
||||
from django.contrib import admin
|
||||
|
||||
from config_models.admin import ConfigurationModelAdmin
|
||||
from embargo.models import EmbargoedCourse, EmbargoedState, IPException
|
||||
from embargo.forms import EmbargoedCourseForm, EmbargoedStateForm, IPExceptionForm
|
||||
|
||||
|
||||
class EmbargoedCourseAdmin(admin.ModelAdmin):
|
||||
"""Admin for embargoed course ids"""
|
||||
form = EmbargoedCourseForm
|
||||
fieldsets = (
|
||||
(None, {
|
||||
'fields': ('course_id', 'embargoed'),
|
||||
'description': '''
|
||||
Enter a course id in the following box. Do not enter leading or trailing slashes. There is no need to surround the course ID with quotes.
|
||||
|
||||
Validation will be performed on the course name, and if it is invalid, an error message will display.
|
||||
|
||||
To enable embargos against this course (restrict course access from embargoed states), check the "Embargoed" box, then click "Save".
|
||||
'''
|
||||
}),
|
||||
)
|
||||
|
||||
|
||||
class EmbargoedStateAdmin(ConfigurationModelAdmin):
|
||||
"""Admin for embargoed countries"""
|
||||
form = EmbargoedStateForm
|
||||
fieldsets = (
|
||||
(None, {
|
||||
'fields': ('embargoed_countries',),
|
||||
'description': '''
|
||||
Enter the two-letter ISO-3166-1 Alpha-2 code of the country or countries to embargo
|
||||
in the following box. For help, see
|
||||
<a href="http://en.wikipedia.org/wiki/ISO_3166-1#Officially_assigned_code_elements">
|
||||
this list of ISO-3166-1 country codes</a>.
|
||||
|
||||
Enter the embargoed country codes separated by a comma. Do not surround with quotes.
|
||||
'''
|
||||
}),
|
||||
)
|
||||
|
||||
|
||||
class IPExceptionAdmin(ConfigurationModelAdmin):
|
||||
"""Admin for blacklisting/whitelisting specific IP addresses"""
|
||||
form = IPExceptionForm
|
||||
fieldsets = (
|
||||
(None, {
|
||||
'fields': ('whitelist', 'blacklist'),
|
||||
'description': '''
|
||||
Enter specific IP addresses to explicitly whitelist (not block) or blacklist (block) in
|
||||
the appropriate box below. Separate IP addresses with a comma. Do not surround with quotes.
|
||||
'''
|
||||
}),
|
||||
)
|
||||
|
||||
admin.site.register(EmbargoedCourse, EmbargoedCourseAdmin)
|
||||
admin.site.register(EmbargoedState, EmbargoedStateAdmin)
|
||||
admin.site.register(IPException, IPExceptionAdmin)
|
||||
0
common/djangoapps/embargo/fixtures/__init__.py
Normal file
0
common/djangoapps/embargo/fixtures/__init__.py
Normal file
25
common/djangoapps/embargo/fixtures/country_codes.py
Normal file
25
common/djangoapps/embargo/fixtures/country_codes.py
Normal file
@@ -0,0 +1,25 @@
|
||||
"""
|
||||
List of valid ISO 3166-1 Alpha-2 country codes, used for
|
||||
validating entries on entered country codes on django-admin page.
|
||||
"""
|
||||
|
||||
COUNTRY_CODES = set([
|
||||
"AC", "AD", "AE", "AF", "AG", "AI", "AL", "AM", "AN", "AO", "AQ", "AR", "AS", "AT",
|
||||
"AU", "AW", "AX", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BM",
|
||||
"BN", "BO", "BR", "BS", "BT", "BV", "BW", "BY", "BZ", "CA", "CC", "CD", "CF", "CG",
|
||||
"CH", "CI", "CK", "CL", "CM", "CN", "CO", "CR", "CU", "CV", "CX", "CY", "CZ", "DE",
|
||||
"DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ER", "ES", "ET", "FI", "FJ", "FK",
|
||||
"FM", "FO", "FR", "GA", "GB", "GD", "GE", "GF", "GG", "GH", "GI", "GL", "GM", "GN",
|
||||
"GP", "GQ", "GR", "GS", "GT", "GU", "GW", "GY", "HK", "HM", "HN", "HR", "HT", "HU",
|
||||
"ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR", "IS", "IT", "JE", "JM", "JO", "JP",
|
||||
"KE", "KG", "KH", "KI", "KM", "KN", "KP", "KR", "KW", "KY", "KZ", "LA", "LB", "LC",
|
||||
"LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH",
|
||||
"MK", "ML", "MM", "MN", "MO", "MP", "MQ", "MR", "MS", "MT", "MU", "MV", "MW", "MX",
|
||||
"MY", "MZ", "NA", "NC", "NE", "NF", "NG", "NI", "NL", "NO", "NP", "NR", "NU", "NZ",
|
||||
"OM", "PA", "PE", "PF", "PG", "PH", "PK", "PL", "PM", "PN", "PR", "PT", "PW", "PY",
|
||||
"QA", "RE", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SD", "SE", "SG", "SH", "SI",
|
||||
"SJ", "SK", "SL", "SM", "SN", "SO", "SR", "ST", "SV", "SY", "SZ", "TA", "TC", "TD",
|
||||
"TF", "TG", "TH", "TJ", "TK", "TL", "TM", "TN", "TO", "TR", "TT", "TV", "TW", "TZ",
|
||||
"UA", "UG", "UM", "US", "UY", "UZ", "VA", "VC", "VE", "VG", "VI", "VN", "VU", "WF",
|
||||
"WS", "YE", "YT", "ZA", "ZM", "ZW"
|
||||
])
|
||||
127
common/djangoapps/embargo/forms.py
Normal file
127
common/djangoapps/embargo/forms.py
Normal file
@@ -0,0 +1,127 @@
|
||||
"""
|
||||
Defines forms for providing validation of embargo admin details.
|
||||
"""
|
||||
|
||||
from django import forms
|
||||
|
||||
from embargo.models import EmbargoedCourse, EmbargoedState, IPException
|
||||
from embargo.fixtures.country_codes import COUNTRY_CODES
|
||||
|
||||
import socket
|
||||
|
||||
from xmodule.course_module import CourseDescriptor
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from xmodule.modulestore.exceptions import ItemNotFoundError, InvalidLocationError
|
||||
|
||||
|
||||
class EmbargoedCourseForm(forms.ModelForm): # pylint: disable=incomplete-protocol
|
||||
"""Form providing validation of entered Course IDs."""
|
||||
|
||||
class Meta: # pylint: disable=missing-docstring
|
||||
model = EmbargoedCourse
|
||||
|
||||
def clean_course_id(self):
|
||||
"""Validate the course id"""
|
||||
course_id = self.cleaned_data["course_id"]
|
||||
try:
|
||||
# Try to get the course descriptor, if we can do that,
|
||||
# it's a real course.
|
||||
course_loc = CourseDescriptor.id_to_location(course_id)
|
||||
modulestore().get_instance(course_id, course_loc, depth=1)
|
||||
except (KeyError, ItemNotFoundError):
|
||||
msg = 'COURSE NOT FOUND'
|
||||
msg += u' --- Entered course id was: "{0}". '.format(course_id)
|
||||
msg += 'Please recheck that you have supplied a valid course id.'
|
||||
raise forms.ValidationError(msg)
|
||||
except (ValueError, InvalidLocationError):
|
||||
msg = 'INVALID LOCATION'
|
||||
msg += u' --- Entered course id was: "{0}". '.format(course_id)
|
||||
msg += 'Please recheck that you have supplied a valid course id.'
|
||||
raise forms.ValidationError(msg)
|
||||
|
||||
return course_id
|
||||
|
||||
|
||||
class EmbargoedStateForm(forms.ModelForm): # pylint: disable=incomplete-protocol
|
||||
"""Form validating entry of states to embargo"""
|
||||
|
||||
class Meta: # pylint: disable=missing-docstring
|
||||
model = EmbargoedState
|
||||
|
||||
def _is_valid_code(self, code):
|
||||
"""Whether or not code is a valid country code"""
|
||||
if len(code) == 2 and code in COUNTRY_CODES:
|
||||
return True
|
||||
return False
|
||||
|
||||
def clean_embargoed_countries(self):
|
||||
"""Validate the country list"""
|
||||
embargoed_countries = self.cleaned_data["embargoed_countries"]
|
||||
error_countries = []
|
||||
|
||||
for country in embargoed_countries.split(','):
|
||||
country = country.strip().upper()
|
||||
if not self._is_valid_code(country):
|
||||
error_countries.append(country)
|
||||
|
||||
if error_countries:
|
||||
msg = 'COULD NOT PARSE COUNTRY CODE(S) FOR: {0}'.format(error_countries)
|
||||
msg += ' Please check the list of country codes and verify your entries.'
|
||||
raise forms.ValidationError(msg)
|
||||
|
||||
return embargoed_countries
|
||||
|
||||
|
||||
class IPExceptionForm(forms.ModelForm): # pylint: disable=incomplete-protocol
|
||||
"""Form validating entry of IP addresses"""
|
||||
|
||||
class Meta: # pylint: disable=missing-docstring
|
||||
model = IPException
|
||||
|
||||
def _is_valid_ipv4(self, address):
|
||||
"""Whether or not address is a valid ipv4 address"""
|
||||
try:
|
||||
# Is this an ipv4 address?
|
||||
socket.inet_pton(socket.AF_INET, address)
|
||||
except socket.error:
|
||||
return False
|
||||
return True
|
||||
|
||||
def _is_valid_ipv6(self, address):
|
||||
"""Whether or not address is a valid ipv6 address"""
|
||||
try:
|
||||
# Is this an ipv6 address?
|
||||
socket.inet_pton(socket.AF_INET6, address)
|
||||
except socket.error:
|
||||
return False
|
||||
return True
|
||||
|
||||
def _valid_ip_addresses(self, addresses):
|
||||
"""
|
||||
Checks if a csv string of IP addresses contains valid values.
|
||||
|
||||
If not, raises a ValidationError.
|
||||
"""
|
||||
if addresses == '':
|
||||
return ''
|
||||
error_addresses = []
|
||||
for addr in addresses.split(','):
|
||||
address = addr.strip()
|
||||
if not (self._is_valid_ipv4(address) or self._is_valid_ipv6(address)):
|
||||
error_addresses.append(address)
|
||||
if error_addresses:
|
||||
msg = 'Invalid IP Address(es): {0}'.format(error_addresses)
|
||||
msg += ' Please fix the error(s) and try again.'
|
||||
raise forms.ValidationError(msg)
|
||||
|
||||
return addresses
|
||||
|
||||
def clean_whitelist(self):
|
||||
"""Validates the whitelist"""
|
||||
whitelist = self.cleaned_data["whitelist"]
|
||||
return self._valid_ip_addresses(whitelist)
|
||||
|
||||
def clean_blacklist(self):
|
||||
"""Validates the blacklist"""
|
||||
blacklist = self.cleaned_data["blacklist"]
|
||||
return self._valid_ip_addresses(blacklist)
|
||||
@@ -5,7 +5,7 @@ Middleware for embargoing courses.
|
||||
|
||||
from django.shortcuts import redirect
|
||||
from util.request import course_id_from_url
|
||||
from embargo.models import EmbargoConfig
|
||||
from embargo.models import EmbargoedCourse, EmbargoedState, IPException
|
||||
from ipware.ip import get_ip
|
||||
import pygeoip
|
||||
from django.conf import settings
|
||||
@@ -27,11 +27,16 @@ class EmbargoMiddleware(object):
|
||||
course_id = course_id_from_url(url)
|
||||
|
||||
# If they're trying to access a course that cares about embargoes
|
||||
if course_id in EmbargoConfig.current().embargoed_courses_list:
|
||||
if EmbargoedCourse.is_embargoed(course_id):
|
||||
|
||||
# If we're having performance issues, add caching here
|
||||
ip = get_ip(request)
|
||||
country_code_from_ip = pygeoip.GeoIP(settings.GEOIP_PATH).country_code_by_addr(ip)
|
||||
is_embargoed = (country_code_from_ip in EmbargoConfig.current().embargoed_countries_list)
|
||||
if is_embargoed:
|
||||
ip_addr = get_ip(request)
|
||||
# if blacklisted, immediately fail
|
||||
if ip_addr in IPException.current().blacklist_ips:
|
||||
return redirect('embargo')
|
||||
|
||||
country_code_from_ip = pygeoip.GeoIP(settings.GEOIP_PATH).country_code_by_addr(ip_addr)
|
||||
is_embargoed = country_code_from_ip in EmbargoedState.current().embargoed_countries_list
|
||||
# Fail if country is embargoed and the ip address isn't explicitly whitelisted
|
||||
if is_embargoed and ip_addr not in IPException.current().whitelist_ips:
|
||||
return redirect('embargo')
|
||||
|
||||
@@ -8,21 +8,45 @@ from django.db import models
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
# Adding model 'EmbargoConfig'
|
||||
db.create_table('embargo_embargoconfig', (
|
||||
# Adding model 'EmbargoedCourse'
|
||||
db.create_table('embargo_embargoedcourse', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('course_id', self.gf('django.db.models.fields.CharField')(unique=True, max_length=255, db_index=True)),
|
||||
('embargoed', self.gf('django.db.models.fields.BooleanField')(default=False)),
|
||||
))
|
||||
db.send_create_signal('embargo', ['EmbargoedCourse'])
|
||||
|
||||
# Adding model 'EmbargoedState'
|
||||
db.create_table('embargo_embargoedstate', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('change_date', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
|
||||
('changed_by', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True, on_delete=models.PROTECT)),
|
||||
('enabled', self.gf('django.db.models.fields.BooleanField')(default=False)),
|
||||
('embargoed_countries', self.gf('django.db.models.fields.TextField')(blank=True)),
|
||||
('embargoed_courses', self.gf('django.db.models.fields.TextField')(blank=True)),
|
||||
))
|
||||
db.send_create_signal('embargo', ['EmbargoConfig'])
|
||||
db.send_create_signal('embargo', ['EmbargoedState'])
|
||||
|
||||
# Adding model 'IPException'
|
||||
db.create_table('embargo_ipexception', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('change_date', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
|
||||
('changed_by', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True, on_delete=models.PROTECT)),
|
||||
('enabled', self.gf('django.db.models.fields.BooleanField')(default=False)),
|
||||
('whitelist', self.gf('django.db.models.fields.TextField')(blank=True)),
|
||||
('blacklist', self.gf('django.db.models.fields.TextField')(blank=True)),
|
||||
))
|
||||
db.send_create_signal('embargo', ['IPException'])
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
# Deleting model 'EmbargoConfig'
|
||||
db.delete_table('embargo_embargoconfig')
|
||||
# Deleting model 'EmbargoedCourse'
|
||||
db.delete_table('embargo_embargoedcourse')
|
||||
|
||||
# Deleting model 'EmbargoedState'
|
||||
db.delete_table('embargo_embargoedstate')
|
||||
|
||||
# Deleting model 'IPException'
|
||||
db.delete_table('embargo_ipexception')
|
||||
|
||||
|
||||
models = {
|
||||
@@ -62,14 +86,28 @@ class Migration(SchemaMigration):
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
'embargo.embargoconfig': {
|
||||
'Meta': {'object_name': 'EmbargoConfig'},
|
||||
'embargo.embargoedcourse': {
|
||||
'Meta': {'object_name': 'EmbargoedCourse'},
|
||||
'course_id': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'}),
|
||||
'embargoed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||
},
|
||||
'embargo.embargoedstate': {
|
||||
'Meta': {'object_name': 'EmbargoedState'},
|
||||
'change_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'changed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'on_delete': 'models.PROTECT'}),
|
||||
'embargoed_countries': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'embargoed_courses': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||
},
|
||||
'embargo.ipexception': {
|
||||
'Meta': {'object_name': 'IPException'},
|
||||
'blacklist': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'change_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'changed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'on_delete': 'models.PROTECT'}),
|
||||
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'whitelist': ('django.db.models.fields.TextField', [], {'blank': 'True'})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
0
common/djangoapps/embargo/migrations/__init__.py
Normal file
0
common/djangoapps/embargo/migrations/__init__.py
Normal file
@@ -1,39 +1,92 @@
|
||||
"""
|
||||
Models for embargoing countries
|
||||
Models for embargoing visits to certain courses by IP address.
|
||||
|
||||
WE'RE USING MIGRATIONS!
|
||||
|
||||
If you make changes to this model, be sure to create an appropriate migration
|
||||
file and check it in at the same time as your model changes. To do that,
|
||||
|
||||
1. Go to the edx-platform dir
|
||||
2. ./manage.py lms schemamigration embargo --auto description_of_your_change
|
||||
3. Add the migration file created in edx-platform/common/djangoapps/embargo/migrations/
|
||||
"""
|
||||
from django.db import models
|
||||
|
||||
from config_models.models import ConfigurationModel
|
||||
|
||||
|
||||
class EmbargoConfig(ConfigurationModel):
|
||||
class EmbargoedCourse(models.Model):
|
||||
"""
|
||||
Configuration for the embargo feature
|
||||
Enable course embargo on a course-by-course basis.
|
||||
"""
|
||||
# The course to embargo
|
||||
course_id = models.CharField(max_length=255, db_index=True, unique=True)
|
||||
|
||||
# Whether or not to embargo
|
||||
embargoed = models.BooleanField(default=False)
|
||||
|
||||
@classmethod
|
||||
def is_embargoed(cls, course_id):
|
||||
"""
|
||||
Returns whether or not the given course id is embargoed.
|
||||
|
||||
If course has not been explicitly embargoed, returns False.
|
||||
"""
|
||||
try:
|
||||
record = cls.objects.get(course_id=course_id)
|
||||
return record.embargoed
|
||||
except cls.DoesNotExist:
|
||||
return False
|
||||
|
||||
def __unicode__(self):
|
||||
not_em = "Not "
|
||||
if self.embargoed:
|
||||
not_em = ""
|
||||
return u"Course '{}' is {}Embargoed".format(self.course_id, not_em)
|
||||
|
||||
|
||||
class EmbargoedState(ConfigurationModel):
|
||||
"""
|
||||
Register countries to be embargoed.
|
||||
"""
|
||||
# The countries to embargo
|
||||
embargoed_countries = models.TextField(
|
||||
blank=True,
|
||||
help_text="A comma-separated list of country codes that fall under U.S. embargo restrictions"
|
||||
)
|
||||
|
||||
embargoed_courses = models.TextField(
|
||||
blank=True,
|
||||
help_text="A comma-separated list of course IDs that we are enforcing the embargo for"
|
||||
)
|
||||
|
||||
@property
|
||||
def embargoed_countries_list(self):
|
||||
"""
|
||||
Returns list of embargoed countries
|
||||
Return a list of upper case country codes
|
||||
"""
|
||||
if not self.embargoed_countries.strip():
|
||||
return []
|
||||
return [country.strip() for country in self.embargoed_countries.split(',')]
|
||||
return [country.strip().upper() for country in self.embargoed_countries.split(',')] # pylint: disable=no-member
|
||||
|
||||
|
||||
class IPException(ConfigurationModel):
|
||||
"""
|
||||
Register specific IP addresses to explicitly block or unblock.
|
||||
"""
|
||||
whitelist = models.TextField(
|
||||
blank=True,
|
||||
help_text="A comma-separated list of IP addresses that should not fall under embargo restrictions."
|
||||
)
|
||||
|
||||
blacklist = models.TextField(
|
||||
blank=True,
|
||||
help_text="A comma-separated list of IP addresses that should fall under embargo restrictions."
|
||||
)
|
||||
|
||||
@property
|
||||
def embargoed_courses_list(self):
|
||||
def whitelist_ips(self):
|
||||
"""
|
||||
Returns list of embargoed courses
|
||||
Return a list of valid IP addresses to whitelist
|
||||
"""
|
||||
if not self.embargoed_courses.strip():
|
||||
return []
|
||||
return [course.strip() for course in self.embargoed_courses.split(',')]
|
||||
return [addr.strip() for addr in self.whitelist.split(',')] # pylint: disable=no-member
|
||||
|
||||
@property
|
||||
def blacklist_ips(self):
|
||||
"""
|
||||
Return a list of valid IP addresses to blacklist
|
||||
"""
|
||||
return [addr.strip() for addr in self.blacklist.split(',')] # pylint: disable=no-member
|
||||
|
||||
@@ -6,7 +6,7 @@ from xmodule.modulestore.tests.factories import CourseFactory
|
||||
from django.test import TestCase
|
||||
from django.test.utils import override_settings
|
||||
from courseware.tests.tests import TEST_DATA_MONGO_MODULESTORE
|
||||
from embargo.models import EmbargoConfig
|
||||
from embargo.models import EmbargoedCourse, EmbargoedState
|
||||
from django.test import Client
|
||||
from student.models import CourseEnrollment
|
||||
from student.tests.factories import UserFactory
|
||||
@@ -29,18 +29,18 @@ class EmbargoMiddlewareTests(TestCase):
|
||||
self.regular_course.save()
|
||||
self.embargoed_page = '/courses/' + self.embargo_course.id + '/info'
|
||||
self.regular_page = '/courses/' + self.regular_course.id + '/info'
|
||||
EmbargoConfig(
|
||||
embargoed_countries="CU, IR, SY,SD",
|
||||
embargoed_courses=self.embargo_course.id,
|
||||
EmbargoedCourse(course_id=self.embargo_course.id, embargoed=True).save()
|
||||
EmbargoedState(
|
||||
embargoed_countries="cu, ir, Sy, SD",
|
||||
changed_by=self.user,
|
||||
enabled=True
|
||||
).save()
|
||||
|
||||
# TODO need to set up & test whitelist/blacklist IPs (IPException model)
|
||||
CourseEnrollment.enroll(self.user, self.regular_course.id)
|
||||
CourseEnrollment.enroll(self.user, self.embargo_course.id)
|
||||
|
||||
def test_countries(self):
|
||||
def mock_country_code_by_addr(ip):
|
||||
def mock_country_code_by_addr(ip_addr):
|
||||
"""
|
||||
Gives us a fake set of IPs
|
||||
"""
|
||||
@@ -50,7 +50,7 @@ class EmbargoMiddlewareTests(TestCase):
|
||||
'3.0.0.0': 'SY',
|
||||
'4.0.0.0': 'SD',
|
||||
}
|
||||
return ip_dict.get(ip, 'US')
|
||||
return ip_dict.get(ip_addr, 'US')
|
||||
|
||||
with mock.patch.object(pygeoip.GeoIP, 'country_code_by_addr') as mocked_method:
|
||||
mocked_method.side_effect = mock_country_code_by_addr
|
||||
|
||||
@@ -140,7 +140,7 @@ def _get_date_for_press(publish_date):
|
||||
return date
|
||||
|
||||
|
||||
def embargo(request):
|
||||
def embargo(_request):
|
||||
"""
|
||||
Render the embargo page.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user