Commit cabcc0c1 by Calen Pennington Committed by Matthew Mongeau

Allow login in the cms, and read a particular course from mongo

parent 33854734
"""
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 mitx dir
2. ./manage.py schemamigration user --auto description_of_your_change
3. Add the migration file created in mitx/courseware/migrations/
"""
import uuid
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
class Meta:
db_table = "auth_userprofile"
## CRITICAL TODO/SECURITY
# Sanitize all fields.
# This is not visible to other users, but could introduce holes later
user = models.OneToOneField(User, unique=True, db_index=True, related_name='profile')
name = models.CharField(blank=True, max_length=255, db_index=True)
org = models.CharField(blank=True, max_length=255, db_index=True)
class Registration(models.Model):
''' Allows us to wait for e-mail before user is registered. A
registration profile is created when the user creates an
account, but that account is inactive. Once the user clicks
on the activation key, it becomes active. '''
class Meta:
db_table = "auth_registration"
user = models.ForeignKey(User, unique=True)
activation_key = models.CharField(('activation key'), max_length=32, unique=True, db_index=True)
def register(self, user):
# MINOR TODO: Switch to crypto-secure key
self.activation_key = uuid.uuid4().hex
self.user = user
self.save()
def activate(self):
self.user.is_active = True
self.user.save()
#self.delete()
class PendingNameChange(models.Model):
user = models.OneToOneField(User, unique=True, db_index=True)
new_name = models.CharField(blank=True, max_length=255)
rationale = models.CharField(blank=True, max_length=1024)
class PendingEmailChange(models.Model):
user = models.OneToOneField(User, unique=True, db_index=True)
new_email = models.CharField(blank=True, max_length=255, db_index=True)
activation_key = models.CharField(('activation key'), max_length=32, unique=True, db_index=True)
"""
This file demonstrates writing tests using the unittest module. These will pass
when you run "manage.py test".
Replace this with more appropriate tests for your application.
"""
from django.test import TestCase
class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.
"""
self.assertEqual(1 + 1, 2)
import logging
from django.views.decorators.http import require_http_methods, require_POST, require_GET
from django.contrib.auth import logout, authenticate, login
from django.shortcuts import redirect
from mitxmako.shortcuts import render_to_response
from django_future.csrf import ensure_csrf_cookie
log = logging.getLogger("mitx.student")
@require_http_methods(['GET', 'POST'])
def do_login(request):
if request.method == 'POST':
return post_login(request)
elif request.method == 'GET':
return get_login(request)
@require_POST
@ensure_csrf_cookie
def post_login(request):
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
return redirect(request.POST.get('next', '/'))
else:
raise Exception("Can't log in, account disabled")
else:
raise Exception("Can't log in, invalid authentication")
@require_GET
@ensure_csrf_cookie
def get_login(request):
return render_to_response('login.html', {
'next': request.GET.get('next')
})
@ensure_csrf_cookie
def logout_user(request):
''' HTTP request to log in the user. Redirects to marketing page'''
logout(request)
return redirect('/')
...@@ -6,6 +6,12 @@ from .common import * ...@@ -6,6 +6,12 @@ from .common import *
DEBUG = True DEBUG = True
TEMPLATE_DEBUG = DEBUG TEMPLATE_DEBUG = DEBUG
KEYSTORE = {
'host': 'localhost',
'db': 'mongo_base',
'collection': 'key_store',
}
DATABASES = { DATABASES = {
'default': { 'default': {
'ENGINE': 'django.db.backends.sqlite3', 'ENGINE': 'django.db.backends.sqlite3',
......
"""
This module provides an abstraction for working objects that conceptually have
the following attributes:
location: An identifier for an item, of which there might be many revisions
children: A list of urls for other items required to fully define this object
data: A set of nested data needed to define this object
editor: The editor/owner of the object
parents: Url pointers for objects that this object was derived from
revision: What revision of the item this is
"""
class Location(object):
''' Encodes a location.
Can be:
* String (url)
* Tuple
* Dictionary
'''
def __init__(self, location):
self.update(location)
def update(self, location):
if isinstance(location, basestring):
self.tag = location.split('/')[0][:-1]
(self.org, self.course, self.category, self.name) = location.split('/')[2:]
elif isinstance(location, list):
(self.tag, self.org, self.course, self.category, self.name) = location
elif isinstance(location, dict):
self.tag = location['tag']
self.org = location['org']
self.course = location['course']
self.category = location['category']
self.name = location['name']
elif isinstance(location, Location):
self.update(location.list())
def url(self):
return "i4x://{org}/{course}/{category}/{name}".format(**self.dict())
def list(self):
return [self.tag, self.org, self.course, self.category, self.name]
def dict(self):
return {'tag': self.tag,
'org': self.org,
'course': self.course,
'category': self.category,
'name': self.name}
def to_json(self):
return self.dict()
class KeyStore(object):
def get_children_for_item(self, location):
"""
Returns the children for the most recent revision of the object
with the specified location.
If no object is found at that location, raises keystore.exceptions.ItemNotFoundError
"""
raise NotImplementedError
class KeyStoreItem(object):
"""
An object from a KeyStore, which can be saved back to that keystore
"""
def __init__(self, location, children, data, editor, parents, revision):
self.location = location
self.children = children
self.data = data
self.editor = editor
self.parents = parents
self.revision = revision
def save(self):
raise NotImplementedError
"""
Module that provides a connection to the keystore specified in the django settings.
Passes settings.KEYSTORE as kwargs to MongoKeyStore
"""
from __future__ import absolute_import
from django.conf import settings
from .mongo import MongoKeyStore
keystore = MongoKeyStore(**settings.KEYSTORE)
"""
Exceptions thrown by KeyStore objects
"""
class ItemNotFoundError(Exception):
pass
import pymongo
from . import KeyStore
from .exceptions import ItemNotFoundError
class MongoKeyStore(KeyStore):
"""
A Mongodb backed KeyStore
"""
def __init__(self, host, db, collection, port=27017):
self.collection = pymongo.connection.Connection(
host=host,
port=port
)[db][collection]
def get_children_for_item(self, location):
item = self.collection.find_one(
{'location': location.dict()},
fields={'children': True},
sort=[('revision', pymongo.ASCENDING)],
)
if item is None:
raise ItemNotFoundError()
return item['children']
<form name="login" action="login", method="post">
<input type="hidden" name="csrfmiddlewaretoken" value="${csrf_token}"/>
% if next is not None:
<input type="hidden" name="next" value="${next}"/>
% endif
Username: <input type="text" name="username" />
Possword: <input type="password" name="password" />
<input type="submit" value="Submit" />
</form>
...@@ -4,6 +4,7 @@ from django.conf.urls.defaults import patterns, url ...@@ -4,6 +4,7 @@ from django.conf.urls.defaults import patterns, url
# from django.contrib import admin # from django.contrib import admin
# admin.autodiscover() # admin.autodiscover()
urlpatterns = patterns('cms.views', urlpatterns = patterns('',
url(r'^(?P<course>[^/]+)/calendar/', 'calendar', name='calendar'), url(r'^(?P<org>[^/]+)/(?P<course>[^/]+)/calendar/', 'cms.views.calendar', name='calendar'),
url(r'^accounts/login/', 'instructor.views.do_login', name='login'),
) )
from mitxmako.shortcuts import render_to_response from mitxmako.shortcuts import render_to_response
from keystore import Location
from keystore.django import keystore
from django.contrib.auth.decorators import login_required
def calendar(request, course): @login_required
return render_to_response('calendar.html', {}) def calendar(request, org, course):
weeks = keystore.get_children_for_item(
Location(['i4x', org, course, 'Course', 'course'])
)
return render_to_response('calendar.html', {'weeks': weeks})
...@@ -23,3 +23,4 @@ requests ...@@ -23,3 +23,4 @@ requests
sympy sympy
newrelic newrelic
glob2 glob2
pymongo
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