Commit f8a528f3 by Diana Huang

Merge branch 'master' into feature/diana/rubric-input

parents 8bb91563 e4dff3f7
...@@ -40,7 +40,7 @@ from xmodule.modulestore.exceptions import ItemNotFoundError ...@@ -40,7 +40,7 @@ from xmodule.modulestore.exceptions import ItemNotFoundError
from datetime import date from datetime import date
from collections import namedtuple from collections import namedtuple
from courseware.courses import get_courses_by_university from courseware.courses import get_courses
from courseware.access import has_access from courseware.access import has_access
from statsd import statsd from statsd import statsd
...@@ -74,16 +74,21 @@ def index(request, extra_context={}, user=None): ...@@ -74,16 +74,21 @@ def index(request, extra_context={}, user=None):
domain = settings.MITX_FEATURES.get('FORCE_UNIVERSITY_DOMAIN') # normally False domain = settings.MITX_FEATURES.get('FORCE_UNIVERSITY_DOMAIN') # normally False
if domain==False: # do explicit check, because domain=None is valid if domain==False: # do explicit check, because domain=None is valid
domain = request.META.get('HTTP_HOST') domain = request.META.get('HTTP_HOST')
universities = get_courses_by_university(None,
domain=domain) courses = get_courses(None, domain=domain)
# Sort courses by how far are they from they start day
key = lambda course: course.metadata['days_to_start']
courses = sorted(courses, key=key, reverse=True)
# Get the 3 most recent news # Get the 3 most recent news
top_news = _get_news(top=3) top_news = _get_news(top=3)
context = {'universities': universities, 'news': top_news} context = {'courses': courses, 'news': top_news}
context.update(extra_context) context.update(extra_context)
return render_to_response('index.html', context) return render_to_response('index.html', context)
def course_from_id(course_id): def course_from_id(course_id):
"""Return the CourseDescriptor corresponding to this course_id""" """Return the CourseDescriptor corresponding to this course_id"""
course_loc = CourseDescriptor.id_to_location(course_id) course_loc = CourseDescriptor.id_to_location(course_id)
......
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'TrackingLog'
db.create_table('track_trackinglog', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('dtcreated', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
('username', self.gf('django.db.models.fields.CharField')(max_length=32, blank=True)),
('ip', self.gf('django.db.models.fields.CharField')(max_length=32, blank=True)),
('event_source', self.gf('django.db.models.fields.CharField')(max_length=32)),
('event_type', self.gf('django.db.models.fields.CharField')(max_length=32, blank=True)),
('event', self.gf('django.db.models.fields.TextField')(blank=True)),
('agent', self.gf('django.db.models.fields.CharField')(max_length=256, blank=True)),
('page', self.gf('django.db.models.fields.CharField')(max_length=32, null=True, blank=True)),
('time', self.gf('django.db.models.fields.DateTimeField')()),
))
db.send_create_signal('track', ['TrackingLog'])
def backwards(self, orm):
# Deleting model 'TrackingLog'
db.delete_table('track_trackinglog')
models = {
'track.trackinglog': {
'Meta': {'object_name': 'TrackingLog'},
'agent': ('django.db.models.fields.CharField', [], {'max_length': '256', 'blank': 'True'}),
'dtcreated': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'event': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'event_source': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
'event_type': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'ip': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}),
'page': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}),
'time': ('django.db.models.fields.DateTimeField', [], {}),
'username': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'})
}
}
complete_apps = ['track']
\ No newline at end of file
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'TrackingLog.host'
db.add_column('track_trackinglog', 'host',
self.gf('django.db.models.fields.CharField')(default='', max_length=64, blank=True),
keep_default=False)
# Changing field 'TrackingLog.event_type'
db.alter_column('track_trackinglog', 'event_type', self.gf('django.db.models.fields.CharField')(max_length=512))
# Changing field 'TrackingLog.page'
db.alter_column('track_trackinglog', 'page', self.gf('django.db.models.fields.CharField')(max_length=512, null=True))
def backwards(self, orm):
# Deleting field 'TrackingLog.host'
db.delete_column('track_trackinglog', 'host')
# Changing field 'TrackingLog.event_type'
db.alter_column('track_trackinglog', 'event_type', self.gf('django.db.models.fields.CharField')(max_length=32))
# Changing field 'TrackingLog.page'
db.alter_column('track_trackinglog', 'page', self.gf('django.db.models.fields.CharField')(max_length=32, null=True))
models = {
'track.trackinglog': {
'Meta': {'object_name': 'TrackingLog'},
'agent': ('django.db.models.fields.CharField', [], {'max_length': '256', 'blank': 'True'}),
'dtcreated': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'event': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'event_source': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
'event_type': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
'host': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'ip': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}),
'page': ('django.db.models.fields.CharField', [], {'max_length': '512', 'null': 'True', 'blank': 'True'}),
'time': ('django.db.models.fields.DateTimeField', [], {}),
'username': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'})
}
}
complete_apps = ['track']
\ No newline at end of file
...@@ -7,11 +7,12 @@ class TrackingLog(models.Model): ...@@ -7,11 +7,12 @@ class TrackingLog(models.Model):
username = models.CharField(max_length=32,blank=True) username = models.CharField(max_length=32,blank=True)
ip = models.CharField(max_length=32,blank=True) ip = models.CharField(max_length=32,blank=True)
event_source = models.CharField(max_length=32) event_source = models.CharField(max_length=32)
event_type = models.CharField(max_length=32,blank=True) event_type = models.CharField(max_length=512,blank=True)
event = models.TextField(blank=True) event = models.TextField(blank=True)
agent = models.CharField(max_length=256,blank=True) agent = models.CharField(max_length=256,blank=True)
page = models.CharField(max_length=32,blank=True,null=True) page = models.CharField(max_length=512,blank=True,null=True)
time = models.DateTimeField('event time') time = models.DateTimeField('event time')
host = models.CharField(max_length=64,blank=True)
def __unicode__(self): def __unicode__(self):
s = "[%s] %s@%s: %s | %s | %s | %s" % (self.time, self.username, self.ip, self.event_source, s = "[%s] %s@%s: %s | %s | %s | %s" % (self.time, self.username, self.ip, self.event_source,
......
...@@ -17,7 +17,7 @@ from track.models import TrackingLog ...@@ -17,7 +17,7 @@ from track.models import TrackingLog
log = logging.getLogger("tracking") log = logging.getLogger("tracking")
LOGFIELDS = ['username','ip','event_source','event_type','event','agent','page','time'] LOGFIELDS = ['username','ip','event_source','event_type','event','agent','page','time','host']
def log_event(event): def log_event(event):
event_str = json.dumps(event) event_str = json.dumps(event)
...@@ -58,6 +58,7 @@ def user_track(request): ...@@ -58,6 +58,7 @@ def user_track(request):
"agent": agent, "agent": agent,
"page": request.GET['page'], "page": request.GET['page'],
"time": datetime.datetime.utcnow().isoformat(), "time": datetime.datetime.utcnow().isoformat(),
"host": request.META['SERVER_NAME'],
} }
log_event(event) log_event(event)
return HttpResponse('success') return HttpResponse('success')
...@@ -83,6 +84,7 @@ def server_track(request, event_type, event, page=None): ...@@ -83,6 +84,7 @@ def server_track(request, event_type, event, page=None):
"agent": agent, "agent": agent,
"page": page, "page": page,
"time": datetime.datetime.utcnow().isoformat(), "time": datetime.datetime.utcnow().isoformat(),
"host": request.META['SERVER_NAME'],
} }
if event_type.startswith("/event_logs") and request.user.is_staff: # don't log if event_type.startswith("/event_logs") and request.user.is_staff: # don't log
......
...@@ -217,11 +217,51 @@ def get_courses_by_university(user, domain=None): ...@@ -217,11 +217,51 @@ def get_courses_by_university(user, domain=None):
''' '''
# TODO: Clean up how 'error' is done. # TODO: Clean up how 'error' is done.
# filter out any courses that errored. # filter out any courses that errored.
visible_courses = branding.get_visible_courses(domain) visible_courses = get_courses(user, domain)
universities = defaultdict(list) universities = defaultdict(list)
for course in visible_courses: for course in visible_courses:
if not has_access(user, course, 'see_exists'):
continue
universities[course.org].append(course) universities[course.org].append(course)
return universities return universities
def get_courses(user, domain=None):
'''
Returns a list of courses available, sorted by course.number
'''
courses = branding.get_visible_courses(domain)
courses = [c for c in courses if has_access(user, c, 'see_exists')]
# Add metadata about the start day and if the course is new
for course in courses:
days_to_start = _get_course_days_to_start(course)
metadata = course.metadata
metadata['days_to_start'] = days_to_start
metadata['is_new'] = course.metadata.get('is_new', days_to_start > 1)
courses = sorted(courses, key=lambda course:course.number)
return courses
def _get_course_days_to_start(course):
from datetime import datetime as dt
from time import mktime, gmtime
convert_to_datetime = lambda ts: dt.fromtimestamp(mktime(ts))
start_date = convert_to_datetime(course.start)
# If the course has a valid advertised date, use that instead
advertised_start = course.metadata.get('advertised_start', None)
if advertised_start:
try:
start_date = dt.strptime(advertised_start, "%Y-%m-%dT%H:%M")
except ValueError:
pass # Invalid date, keep using course.start
now = convert_to_datetime(gmtime())
days_to_start = (start_date - now).days
return days_to_start
...@@ -17,7 +17,7 @@ from django.views.decorators.cache import cache_control ...@@ -17,7 +17,7 @@ from django.views.decorators.cache import cache_control
from courseware import grades from courseware import grades
from courseware.access import has_access from courseware.access import has_access
from courseware.courses import (get_course_with_access, get_courses_by_university) from courseware.courses import (get_courses, get_course_with_access, get_courses_by_university)
import courseware.tabs as tabs import courseware.tabs as tabs
from courseware.models import StudentModuleCache from courseware.models import StudentModuleCache
from module_render import toc_for_course, get_module, get_instance_module from module_render import toc_for_course, get_module, get_instance_module
...@@ -61,16 +61,19 @@ def user_groups(user): ...@@ -61,16 +61,19 @@ def user_groups(user):
return group_names return group_names
@ensure_csrf_cookie @ensure_csrf_cookie
@cache_if_anonymous @cache_if_anonymous
def courses(request): def courses(request):
''' '''
Render "find courses" page. The course selection work is done in courseware.courses. Render "find courses" page. The course selection work is done in courseware.courses.
''' '''
universities = get_courses_by_university(request.user, courses = get_courses(request.user, domain=request.META.get('HTTP_HOST'))
domain=request.META.get('HTTP_HOST'))
return render_to_response("courseware/courses.html", {'universities': universities}) # Sort courses by how far are they from they start day
key = lambda course: course.metadata['days_to_start']
courses = sorted(courses, key=key, reverse=True)
return render_to_response("courseware/courses.html", {'courses': courses})
def render_accordion(request, course, chapter, section): def render_accordion(request, course, chapter, section):
...@@ -435,6 +438,11 @@ def university_profile(request, org_id): ...@@ -435,6 +438,11 @@ def university_profile(request, org_id):
# Only grab courses for this org... # Only grab courses for this org...
courses = get_courses_by_university(request.user, courses = get_courses_by_university(request.user,
domain=request.META.get('HTTP_HOST'))[org_id] domain=request.META.get('HTTP_HOST'))[org_id]
# Sort courses by how far are they from they start day
key = lambda course: course.metadata['days_to_start']
courses = sorted(courses, key=key, reverse=True)
context = dict(courses=courses, org_id=org_id) context = dict(courses=courses, org_id=org_id)
template_file = "university_profile/{0}.html".format(org_id).lower() template_file = "university_profile/{0}.html".format(org_id).lower()
......
...@@ -44,12 +44,6 @@ STATUS_MESSAGE_PATH = TEST_ROOT / "status_message.json" ...@@ -44,12 +44,6 @@ STATUS_MESSAGE_PATH = TEST_ROOT / "status_message.json"
COURSES_ROOT = TEST_ROOT / "data" COURSES_ROOT = TEST_ROOT / "data"
DATA_DIR = COURSES_ROOT DATA_DIR = COURSES_ROOT
LOGGING = get_logger_config(TEST_ROOT / "log",
logging_env="dev",
tracking_filename="tracking.log",
dev_env=True,
debug=True)
COMMON_TEST_DATA_ROOT = COMMON_ROOT / "test" / "data" COMMON_TEST_DATA_ROOT = COMMON_ROOT / "test" / "data"
# Where the content data is checked out. This may not exist on jenkins. # Where the content data is checked out. This may not exist on jenkins.
GITHUB_REPO_ROOT = ENV_ROOT / "data" GITHUB_REPO_ROOT = ENV_ROOT / "data"
......
...@@ -13,6 +13,23 @@ ...@@ -13,6 +13,23 @@
} }
} }
.courses-listing {
@include clearfix();
margin: 0;
padding: 0;
list-style: none;
.courses-listing-item {
width: flex-grid(4);
margin-right: flex-gutter();
float: left;
&:nth-child(3n+3) {
margin-right: 0;
}
}
}
.course { .course {
background: rgb(250,250,250); background: rgb(250,250,250);
border: 1px solid rgb(180,180,180); border: 1px solid rgb(180,180,180);
...@@ -24,6 +41,31 @@ ...@@ -24,6 +41,31 @@
width: 100%; width: 100%;
@include transition(all, 0.15s, linear); @include transition(all, 0.15s, linear);
.status {
background: $blue;
color: white;
font-size: 10px;
left: 10px;
padding: 2px 10px;
@include border-radius(2px);
position: absolute;
text-transform: uppercase;
top: -6px;
z-index: 100;
}
.status:after {
border-bottom: 6px solid shade($blue, 50%);
border-right: 6px solid transparent;
content: "";
display: block;
height: 0;
position: absolute;
right: -6px;
top: 0;
width: 0;
}
a:hover { a:hover {
text-decoration: none; text-decoration: none;
} }
......
...@@ -5,6 +5,9 @@ ...@@ -5,6 +5,9 @@
%> %>
<%page args="course" /> <%page args="course" />
<article id="${course.id}" class="course"> <article id="${course.id}" class="course">
%if course.metadata.get('is_new'):
<span class="status">New</span>
%endif
<a href="${reverse('about_course', args=[course.id])}"> <a href="${reverse('about_course', args=[course.id])}">
<div class="inner-wrapper"> <div class="inner-wrapper">
<header class="course-preview"> <header class="course-preview">
......
...@@ -20,21 +20,13 @@ ...@@ -20,21 +20,13 @@
## I'm removing this for now since we aren't using it for the fall. ## I'm removing this for now since we aren't using it for the fall.
## <%include file="course_filter.html" /> ## <%include file="course_filter.html" />
<section class="courses"> <section class="courses">
<section class='university-column'> <ul class="courses-listing">
%for course in universities['MITx']: %for course in courses:
<li class="courses-listing-item">
<%include file="../course.html" args="course=course" /> <%include file="../course.html" args="course=course" />
</li>
%endfor %endfor
</section> </ul>
<section class='university-column'>
%for course in universities['HarvardX']:
<%include file="../course.html" args="course=course" />
%endfor
</section>
<section class='university-column last'>
%for course in universities['BerkeleyX']:
<%include file="../course.html" args="course=course" />
%endfor
</section>
</section> </section>
</section> </section>
</section> </section>
...@@ -106,21 +106,13 @@ ...@@ -106,21 +106,13 @@
</section> </section>
<section class="courses"> <section class="courses">
<section class='university-column'> <ul class="courses-listing">
%for course in universities['MITx']: %for course in courses:
<%include file="course.html" args="course=course" /> <li class="courses-listing-item">
%endfor
</section>
<section class='university-column'>
%for course in universities['HarvardX']:
<%include file="course.html" args="course=course" />
%endfor
</section>
<section class='university-column last'>
%for course in universities['BerkeleyX']:
<%include file="course.html" args="course=course" /> <%include file="course.html" args="course=course" />
</li>
%endfor %endfor
</section> </ul>
</section> </section>
</section> </section>
</section> </section>
......
...@@ -309,16 +309,22 @@ task :builddocs do ...@@ -309,16 +309,22 @@ task :builddocs do
end end
end end
desc "Show doc in browser (mac only for now) TODO add linux support" desc "Show docs in browser (mac and ubuntu)."
task :showdocs do task :showdocs do
Dir.chdir('docs/build/html') do Dir.chdir('docs/build/html') do
if RUBY_PLATFORM.include? 'darwin' # mac os
sh('open index.html') sh('open index.html')
elsif RUBY_PLATFORM.include? 'linux' # make more ubuntu specific?
sh('sensible-browser index.html') # ubuntu
else
raise "\nUndefined how to run browser on your machine.
Please use 'rake builddocs' and then manually open
'mitx/docs/build/html/index.html."
end
end end
end end
desc "Build docs and show them in browser" desc "Build docs and show them in browser"
task :doc => :builddocs do task :doc => :builddocs do
Dir.chdir('docs/build/html') do Rake::Task["showdocs"].invoke
sh('open index.html')
end
end end
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