Splitting files into subdirectories in preparation for merge
This commit is contained in:
0
djangoapps/student/__init__.py
Normal file
0
djangoapps/student/__init__.py
Normal file
0
djangoapps/student/management/__init__.py
Normal file
0
djangoapps/student/management/__init__.py
Normal file
0
djangoapps/student/management/commands/__init__.py
Normal file
0
djangoapps/student/management/commands/__init__.py
Normal file
99
djangoapps/student/management/commands/assigngroups.py
Normal file
99
djangoapps/student/management/commands/assigngroups.py
Normal file
@@ -0,0 +1,99 @@
|
||||
import os.path
|
||||
|
||||
from lxml import etree
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
import mitxmako.middleware as middleware
|
||||
from student.models import UserTestGroup
|
||||
|
||||
import random
|
||||
import sys
|
||||
import datetime
|
||||
|
||||
import json
|
||||
|
||||
middleware.MakoMiddleware()
|
||||
|
||||
def group_from_value(groups, v):
|
||||
''' Given group: (('a',0.3),('b',0.4),('c',0.3)) And random value
|
||||
in [0,1], return the associated group (in the above case, return
|
||||
'a' if v<0.3, 'b' if 0.3<=v<0.7, and 'c' if v>0.7
|
||||
'''
|
||||
sum = 0
|
||||
for (g,p) in groups:
|
||||
sum = sum + p
|
||||
if sum > v:
|
||||
return g
|
||||
return g # For round-off errors
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = \
|
||||
''' Assign users to test groups. Takes a list
|
||||
of groups:
|
||||
a:0.3,b:0.4,c:0.3 file.txt "Testing something"
|
||||
Will assign each user to group a, b, or c with
|
||||
probability 0.3, 0.4, 0.3. Probabilities must
|
||||
add up to 1.
|
||||
|
||||
Will log what happened to file.txt.
|
||||
'''
|
||||
def handle(self, *args, **options):
|
||||
if len(args) != 3:
|
||||
print "Invalid number of options"
|
||||
sys.exit(-1)
|
||||
|
||||
# Extract groups from string
|
||||
group_strs = [x.split(':') for x in args[0].split(',')]
|
||||
groups = [(group,float(value)) for group,value in group_strs]
|
||||
print "Groups", groups
|
||||
|
||||
## Confirm group probabilities add up to 1
|
||||
total = sum(zip(*groups)[1])
|
||||
print "Total:", total
|
||||
if abs(total-1)>0.01:
|
||||
print "Total not 1"
|
||||
sys.exit(-1)
|
||||
|
||||
## Confirm groups don't already exist
|
||||
for group in dict(groups):
|
||||
if UserTestGroup.objects.filter(name=group).count() != 0:
|
||||
print group, "already exists!"
|
||||
sys.exit(-1)
|
||||
|
||||
group_objects = {}
|
||||
|
||||
f = open(args[1],"a+")
|
||||
|
||||
## Create groups
|
||||
for group in dict(groups):
|
||||
utg = UserTestGroup()
|
||||
utg.name=group
|
||||
utg.description = json.dumps({"description":args[2]},
|
||||
{"time":datetime.datetime.utcnow().isoformat()})
|
||||
group_objects[group]=utg
|
||||
group_objects[group].save()
|
||||
|
||||
## Assign groups
|
||||
users = list(User.objects.all())
|
||||
count = 0
|
||||
for user in users:
|
||||
if count % 1000 == 0:
|
||||
print count
|
||||
count = count + 1
|
||||
v = random.uniform(0,1)
|
||||
group = group_from_value(groups,v)
|
||||
group_objects[group].users.add(user)
|
||||
f.write("Assigned user {name} ({id}) to {group}\n".format(name=user.username,
|
||||
id=user.id,
|
||||
group=group))
|
||||
|
||||
## Save groups
|
||||
for group in group_objects:
|
||||
group_objects[group].save()
|
||||
f.close()
|
||||
|
||||
# python manage.py assigngroups summary_test:0.3,skip_summary_test:0.7 log.txt "Do previews of future materials help?"
|
||||
# python manage.py assigngroups skip_capacitor:0.3,capacitor:0.7 log.txt "Do we show capacitor in linearity tutorial?"
|
||||
23
djangoapps/student/management/commands/emaillist.py
Normal file
23
djangoapps/student/management/commands/emaillist.py
Normal file
@@ -0,0 +1,23 @@
|
||||
import os.path
|
||||
|
||||
from lxml import etree
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
import mitxmako.middleware as middleware
|
||||
|
||||
middleware.MakoMiddleware()
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = \
|
||||
''' Extract an e-mail list of all active students. '''
|
||||
def handle(self, *args, **options):
|
||||
#text = open(args[0]).read()
|
||||
#subject = open(args[1]).read()
|
||||
users = User.objects.all()
|
||||
|
||||
for user in users:
|
||||
if user.is_active:
|
||||
print user.email
|
||||
27
djangoapps/student/management/commands/massemail.py
Normal file
27
djangoapps/student/management/commands/massemail.py
Normal file
@@ -0,0 +1,27 @@
|
||||
import os.path
|
||||
|
||||
from lxml import etree
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
import mitxmako.middleware as middleware
|
||||
|
||||
middleware.MakoMiddleware()
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = \
|
||||
'''Sends an e-mail to all users. Takes a single
|
||||
parameter -- name of e-mail template -- located
|
||||
in templates/email. Adds a .txt for the message
|
||||
body, and an _subject.txt for the subject. '''
|
||||
def handle(self, *args, **options):
|
||||
#text = open(args[0]).read()
|
||||
#subject = open(args[1]).read()
|
||||
users = User.objects.all()
|
||||
text = middleware.lookup['main'].get_template('email/'+args[0]+".txt").render()
|
||||
subject = middleware.lookup['main'].get_template('email/'+args[0]+"_subject.txt").render().strip()
|
||||
for user in users:
|
||||
if user.is_active:
|
||||
user.email_user(subject, text)
|
||||
64
djangoapps/student/management/commands/massemailtxt.py
Normal file
64
djangoapps/student/management/commands/massemailtxt.py
Normal file
@@ -0,0 +1,64 @@
|
||||
import os.path
|
||||
import time
|
||||
|
||||
from lxml import etree
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
import mitxmako.middleware as middleware
|
||||
|
||||
from django.core.mail import send_mass_mail
|
||||
import sys
|
||||
|
||||
import datetime
|
||||
|
||||
middleware.MakoMiddleware()
|
||||
|
||||
def chunks(l, n):
|
||||
""" Yield successive n-sized chunks from l.
|
||||
"""
|
||||
for i in xrange(0, len(l), n):
|
||||
yield l[i:i+n]
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = \
|
||||
'''Sends an e-mail to all users in a text file.
|
||||
E.g.
|
||||
manage.py userlist.txt message logfile.txt rate
|
||||
userlist.txt -- list of all users
|
||||
message -- prefix for template with message
|
||||
logfile.txt -- where to log progress
|
||||
rate -- messages per second
|
||||
'''
|
||||
log_file = None
|
||||
|
||||
def hard_log(self, text):
|
||||
self.log_file.write(datetime.datetime.utcnow().isoformat()+' -- '+text+'\n')
|
||||
|
||||
def handle(self, *args, **options):
|
||||
global log_file
|
||||
(user_file, message_base, logfilename, ratestr) = args
|
||||
|
||||
users = [u.strip() for u in open(user_file).readlines()]
|
||||
|
||||
message = middleware.lookup['main'].get_template('emails/'+message_base+"_body.txt").render()
|
||||
subject = middleware.lookup['main'].get_template('emails/'+message_base+"_subject.txt").render().strip()
|
||||
rate = int(ratestr)
|
||||
|
||||
self.log_file = open(logfilename, "a+", buffering = 0)
|
||||
|
||||
i=0
|
||||
for users in chunks(users, rate):
|
||||
emails = [ (subject, message, settings.DEFAULT_FROM_EMAIL, [u]) for u in users ]
|
||||
self.hard_log(" ".join(users))
|
||||
send_mass_mail( emails, fail_silently = False )
|
||||
time.sleep(1)
|
||||
print datetime.datetime.utcnow().isoformat(), i
|
||||
i = i+len(users)
|
||||
# Emergency interruptor
|
||||
if os.path.exists("/tmp/stopemails.txt"):
|
||||
self.log_file.close()
|
||||
sys.exit(-1)
|
||||
self.log_file.close()
|
||||
38
djangoapps/student/management/commands/userinfo.py
Normal file
38
djangoapps/student/management/commands/userinfo.py
Normal file
@@ -0,0 +1,38 @@
|
||||
import os.path
|
||||
|
||||
from lxml import etree
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
import mitxmako.middleware as middleware
|
||||
import json
|
||||
|
||||
from student.models import UserProfile
|
||||
|
||||
middleware.MakoMiddleware()
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = \
|
||||
''' Extract full user information into a JSON file.
|
||||
Pass a single filename.'''
|
||||
def handle(self, *args, **options):
|
||||
f = open(args[0],'w')
|
||||
#text = open(args[0]).read()
|
||||
#subject = open(args[1]).read()
|
||||
users = User.objects.all()
|
||||
|
||||
l = []
|
||||
for user in users:
|
||||
up = UserProfile.objects.get(user = user)
|
||||
d = { 'username':user.username,
|
||||
'email':user.email,
|
||||
'is_active':user.is_active,
|
||||
'joined':user.date_joined.isoformat(),
|
||||
'name':up.name,
|
||||
'language':up.language,
|
||||
'location':up.location}
|
||||
l.append(d)
|
||||
json.dump(l,f)
|
||||
f.close()
|
||||
121
djangoapps/student/migrations/0001_initial.py
Normal file
121
djangoapps/student/migrations/0001_initial.py
Normal file
@@ -0,0 +1,121 @@
|
||||
# encoding: 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 'UserProfile'
|
||||
db.create_table('auth_userprofile', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], unique=True)),
|
||||
('name', self.gf('django.db.models.fields.TextField')(blank=True)),
|
||||
('language', self.gf('django.db.models.fields.TextField')(blank=True)),
|
||||
('location', self.gf('django.db.models.fields.TextField')(blank=True)),
|
||||
('meta', self.gf('django.db.models.fields.TextField')(blank=True)),
|
||||
('courseware', self.gf('django.db.models.fields.TextField')(default='course.xml', blank=True)),
|
||||
))
|
||||
db.send_create_signal('student', ['UserProfile'])
|
||||
|
||||
# Adding model 'Registration'
|
||||
db.create_table('auth_registration', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], unique=True)),
|
||||
('activation_key', self.gf('django.db.models.fields.CharField')(unique=True, max_length=32, db_index=True)),
|
||||
))
|
||||
db.send_create_signal('student', ['Registration'])
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
# Deleting model 'UserProfile'
|
||||
db.delete_table('auth_userprofile')
|
||||
|
||||
# Deleting model 'Registration'
|
||||
db.delete_table('auth_registration')
|
||||
|
||||
|
||||
models = {
|
||||
'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
|
||||
'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
|
||||
'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
|
||||
'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
|
||||
'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
|
||||
'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
'student.registration': {
|
||||
'Meta': {'object_name': 'Registration', 'db_table': "'auth_registration'"},
|
||||
'activation_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32', 'db_index': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
|
||||
},
|
||||
'student.userprofile': {
|
||||
'Meta': {'object_name': 'UserProfile', 'db_table': "'auth_userprofile'"},
|
||||
'courseware': ('django.db.models.fields.TextField', [], {'default': "'course.xml'", 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'language': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'location': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'meta': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['student']
|
||||
@@ -0,0 +1,143 @@
|
||||
# encoding: 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):
|
||||
|
||||
# Changing field 'UserProfile.name'
|
||||
db.alter_column('auth_userprofile', 'name', self.gf('django.db.models.fields.CharField')(max_length=255))
|
||||
|
||||
# Adding index on 'UserProfile', fields ['name']
|
||||
db.create_index('auth_userprofile', ['name'])
|
||||
|
||||
# Changing field 'UserProfile.language'
|
||||
db.alter_column('auth_userprofile', 'language', self.gf('django.db.models.fields.CharField')(max_length=255))
|
||||
|
||||
# Adding index on 'UserProfile', fields ['language']
|
||||
db.create_index('auth_userprofile', ['language'])
|
||||
|
||||
# Changing field 'UserProfile.courseware'
|
||||
db.alter_column('auth_userprofile', 'courseware', self.gf('django.db.models.fields.CharField')(max_length=255))
|
||||
|
||||
# Changing field 'UserProfile.meta'
|
||||
db.alter_column('auth_userprofile', 'meta', self.gf('django.db.models.fields.CharField')(max_length=255))
|
||||
|
||||
# Changing field 'UserProfile.location'
|
||||
db.alter_column('auth_userprofile', 'location', self.gf('django.db.models.fields.CharField')(max_length=255))
|
||||
|
||||
# Adding index on 'UserProfile', fields ['location']
|
||||
db.create_index('auth_userprofile', ['location'])
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
# Removing index on 'UserProfile', fields ['location']
|
||||
db.delete_index('auth_userprofile', ['location'])
|
||||
|
||||
# Removing index on 'UserProfile', fields ['language']
|
||||
db.delete_index('auth_userprofile', ['language'])
|
||||
|
||||
# Removing index on 'UserProfile', fields ['name']
|
||||
db.delete_index('auth_userprofile', ['name'])
|
||||
|
||||
# Changing field 'UserProfile.name'
|
||||
db.alter_column('auth_userprofile', 'name', self.gf('django.db.models.fields.TextField')())
|
||||
|
||||
# Changing field 'UserProfile.language'
|
||||
db.alter_column('auth_userprofile', 'language', self.gf('django.db.models.fields.TextField')())
|
||||
|
||||
# Changing field 'UserProfile.courseware'
|
||||
db.alter_column('auth_userprofile', 'courseware', self.gf('django.db.models.fields.TextField')())
|
||||
|
||||
# Changing field 'UserProfile.meta'
|
||||
db.alter_column('auth_userprofile', 'meta', self.gf('django.db.models.fields.TextField')())
|
||||
|
||||
# Changing field 'UserProfile.location'
|
||||
db.alter_column('auth_userprofile', 'location', self.gf('django.db.models.fields.TextField')())
|
||||
|
||||
|
||||
models = {
|
||||
'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
|
||||
'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
|
||||
'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
|
||||
'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
|
||||
'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
|
||||
'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
'student.registration': {
|
||||
'Meta': {'object_name': 'Registration', 'db_table': "'auth_registration'"},
|
||||
'activation_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32', 'db_index': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
|
||||
},
|
||||
'student.userprofile': {
|
||||
'Meta': {'object_name': 'UserProfile', 'db_table': "'auth_userprofile'"},
|
||||
'courseware': ('django.db.models.fields.CharField', [], {'default': "'course.xml'", 'max_length': '255', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'language': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
|
||||
'location': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
|
||||
'meta': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['student']
|
||||
124
djangoapps/student/migrations/0003_auto__add_usertestgroup.py
Normal file
124
djangoapps/student/migrations/0003_auto__add_usertestgroup.py
Normal file
@@ -0,0 +1,124 @@
|
||||
# encoding: 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 'UserTestGroup'
|
||||
db.create_table('student_usertestgroup', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('name', self.gf('django.db.models.fields.CharField')(max_length=32, db_index=True)),
|
||||
('description', self.gf('django.db.models.fields.TextField')(blank=True)),
|
||||
))
|
||||
db.send_create_signal('student', ['UserTestGroup'])
|
||||
|
||||
# Adding M2M table for field users on 'UserTestGroup'
|
||||
db.create_table('student_usertestgroup_users', (
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
|
||||
('usertestgroup', models.ForeignKey(orm['student.usertestgroup'], null=False)),
|
||||
('user', models.ForeignKey(orm['auth.user'], null=False))
|
||||
))
|
||||
db.create_unique('student_usertestgroup_users', ['usertestgroup_id', 'user_id'])
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
# Deleting model 'UserTestGroup'
|
||||
db.delete_table('student_usertestgroup')
|
||||
|
||||
# Removing M2M table for field users on 'UserTestGroup'
|
||||
db.delete_table('student_usertestgroup_users')
|
||||
|
||||
|
||||
models = {
|
||||
'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
|
||||
'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
|
||||
'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
|
||||
'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
|
||||
'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
|
||||
'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
'student.registration': {
|
||||
'Meta': {'object_name': 'Registration', 'db_table': "'auth_registration'"},
|
||||
'activation_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32', 'db_index': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
|
||||
},
|
||||
'student.userprofile': {
|
||||
'Meta': {'object_name': 'UserProfile', 'db_table': "'auth_userprofile'"},
|
||||
'courseware': ('django.db.models.fields.CharField', [], {'default': "'course.xml'", 'max_length': '255', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'language': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
|
||||
'location': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
|
||||
'meta': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
|
||||
},
|
||||
'student.usertestgroup': {
|
||||
'Meta': {'object_name': 'UserTestGroup'},
|
||||
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '32', 'db_index': 'True'}),
|
||||
'users': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.User']", 'db_index': 'True', 'symmetrical': 'False'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['student']
|
||||
106
djangoapps/student/migrations/0004_add_email_index.py
Normal file
106
djangoapps/student/migrations/0004_add_email_index.py
Normal file
@@ -0,0 +1,106 @@
|
||||
# encoding: 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):
|
||||
db.execute("create unique index email on auth_user (email)")
|
||||
pass
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
db.execute("drop index email on auth_user")
|
||||
pass
|
||||
|
||||
|
||||
models = {
|
||||
'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
|
||||
'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
|
||||
'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
|
||||
'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
|
||||
'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
|
||||
'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
|
||||
'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
|
||||
'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
'student.registration': {
|
||||
'Meta': {'object_name': 'Registration', 'db_table': "'auth_registration'"},
|
||||
'activation_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32', 'db_index': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
|
||||
},
|
||||
'student.userprofile': {
|
||||
'Meta': {'object_name': 'UserProfile', 'db_table': "'auth_userprofile'"},
|
||||
'courseware': ('django.db.models.fields.CharField', [], {'default': "'course.xml'", 'max_length': '255', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'language': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
|
||||
'location': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
|
||||
'meta': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
|
||||
},
|
||||
'student.usertestgroup': {
|
||||
'Meta': {'object_name': 'UserTestGroup'},
|
||||
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '32', 'db_index': 'True'}),
|
||||
'users': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.User']", 'db_index': 'True', 'symmetrical': 'False'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['student']
|
||||
0
djangoapps/student/migrations/__init__.py
Normal file
0
djangoapps/student/migrations/__init__.py
Normal file
130
djangoapps/student/models.py
Normal file
130
djangoapps/student/models.py
Normal file
@@ -0,0 +1,130 @@
|
||||
"""
|
||||
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
|
||||
import json
|
||||
|
||||
#from cache_toolbox import cache_model, cache_relation
|
||||
|
||||
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)
|
||||
language = models.CharField(blank=True, max_length=255, db_index=True)
|
||||
location = models.CharField(blank=True, max_length=255, db_index=True)
|
||||
meta = models.CharField(blank=True, max_length=255) # JSON dictionary for future expansion
|
||||
courseware = models.CharField(blank=True, max_length=255, default='course.xml')
|
||||
|
||||
def get_meta():
|
||||
try:
|
||||
js = json.reads(self.meta)
|
||||
except:
|
||||
js = dict()
|
||||
return json
|
||||
def set_meta(js):
|
||||
self.meta = json.dumps(js)
|
||||
|
||||
## TODO: Should be renamed to generic UserGroup, and possibly
|
||||
# Given an optional field for type of group
|
||||
class UserTestGroup(models.Model):
|
||||
users = models.ManyToManyField(User, db_index=True)
|
||||
name = models.CharField(blank=False, max_length=32, db_index=True)
|
||||
description = models.TextField(blank=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)
|
||||
|
||||
#cache_relation(User.profile)
|
||||
|
||||
#### Helper methods for use from python manage.py shell.
|
||||
|
||||
def get_user(email):
|
||||
u = User.objects.get(email = email)
|
||||
up = UserProfile.objects.get(user = u)
|
||||
return u,up
|
||||
|
||||
def user_info(email):
|
||||
u,up = get_user(email)
|
||||
print "User id", u.id
|
||||
print "Username", u.username
|
||||
print "E-mail", u.email
|
||||
print "Name", up.name
|
||||
print "Location", up.location
|
||||
print "Language", up.language
|
||||
return u,up
|
||||
|
||||
def change_email(old_email, new_email):
|
||||
u = User.objects.get(email = old_email)
|
||||
u.email = new_email
|
||||
u.save()
|
||||
|
||||
def change_name(email, new_name):
|
||||
u,up = get_user(email)
|
||||
up.name = new_name
|
||||
up.save()
|
||||
|
||||
def user_count():
|
||||
return User.objects.all().count()
|
||||
|
||||
def active_user_count():
|
||||
return User.objects.filter(is_active = True).count()
|
||||
|
||||
def create_group(name, description):
|
||||
utg = UserTestGroup()
|
||||
utg.name = name
|
||||
utg.description = description
|
||||
utg.save()
|
||||
|
||||
def add_user_to_group(group, user):
|
||||
utg = UserTestGroup.objects.get(name = group)
|
||||
utg.users.add(User.objects.get(username = user))
|
||||
utg.save()
|
||||
|
||||
def remove_user_from_group(group, user):
|
||||
utg = UserTestGroup.objects.get(name = group)
|
||||
utg.users.remove(User.objects.get(username = user))
|
||||
utg.save()
|
||||
16
djangoapps/student/tests.py
Normal file
16
djangoapps/student/tests.py
Normal file
@@ -0,0 +1,16 @@
|
||||
"""
|
||||
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)
|
||||
417
djangoapps/student/views.py
Normal file
417
djangoapps/student/views.py
Normal file
@@ -0,0 +1,417 @@
|
||||
import json
|
||||
import logging
|
||||
import random
|
||||
import string
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import logout, authenticate, login
|
||||
from django.contrib.auth.forms import PasswordResetForm
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.context_processors import csrf
|
||||
from django.core.mail import send_mail
|
||||
from django.core.validators import validate_email, validate_slug
|
||||
from django.db import connection
|
||||
from django.http import HttpResponse, Http404
|
||||
from django.shortcuts import redirect
|
||||
from mitxmako.shortcuts import render_to_response, render_to_string
|
||||
|
||||
from models import Registration, UserProfile
|
||||
from django_future.csrf import ensure_csrf_cookie
|
||||
|
||||
log = logging.getLogger("mitx.user")
|
||||
|
||||
def csrf_token(context):
|
||||
''' A csrf token that can be included in a form.
|
||||
'''
|
||||
csrf_token = context.get('csrf_token', '')
|
||||
if csrf_token == 'NOTPROVIDED':
|
||||
return ''
|
||||
return u'<div style="display:none"><input type="hidden" name="csrfmiddlewaretoken" value="%s" /></div>' % (csrf_token)
|
||||
|
||||
@ensure_csrf_cookie
|
||||
def index(request):
|
||||
''' Redirects to main page -- info page if user authenticated, or marketing if not
|
||||
'''
|
||||
if settings.COURSEWARE_ENABLED and request.user.is_authenticated():
|
||||
return redirect('/info')
|
||||
else:
|
||||
csrf_token = csrf(request)['csrf_token']
|
||||
# TODO: Clean up how 'error' is done.
|
||||
return render_to_response('index.html', {'csrf': csrf_token })
|
||||
|
||||
# Need different levels of logging
|
||||
@ensure_csrf_cookie
|
||||
def login_user(request, error=""):
|
||||
''' AJAX request to log in the user. '''
|
||||
if 'email' not in request.POST or 'password' not in request.POST:
|
||||
return HttpResponse(json.dumps({'success':False,
|
||||
'error': 'Invalid login'})) # TODO: User error message
|
||||
|
||||
email = request.POST['email']
|
||||
password = request.POST['password']
|
||||
try:
|
||||
user = User.objects.get(email=email)
|
||||
except User.DoesNotExist:
|
||||
log.warning("Login failed - Unknown user email: {0}".format(email))
|
||||
return HttpResponse(json.dumps({'success':False,
|
||||
'error': 'Invalid login'})) # TODO: User error message
|
||||
|
||||
username = user.username
|
||||
user = authenticate(username=username, password=password)
|
||||
if user is None:
|
||||
log.warning("Login failed - password for {0} is invalid".format(email))
|
||||
return HttpResponse(json.dumps({'success':False,
|
||||
'error': 'Invalid login'}))
|
||||
|
||||
if user is not None and user.is_active:
|
||||
try:
|
||||
login(request, user)
|
||||
if request.POST['remember'] == 'true':
|
||||
request.session.set_expiry(None) # or change to 604800 for 7 days
|
||||
log.debug("Setting user session to never expire")
|
||||
else:
|
||||
request.session.set_expiry(0)
|
||||
except Exception as e:
|
||||
log.critical("Login failed - Could not create session. Is memcached running?")
|
||||
log.exception(e)
|
||||
|
||||
log.info("Login success - {0} ({1})".format(username, email))
|
||||
return HttpResponse(json.dumps({'success':True}))
|
||||
|
||||
log.warning("Login failed - Account not active for user {0}".format(username))
|
||||
return HttpResponse(json.dumps({'success':False,
|
||||
'error': 'Account not active. Check your e-mail.'}))
|
||||
|
||||
@ensure_csrf_cookie
|
||||
def logout_user(request):
|
||||
''' HTTP request to log in the user. Redirects to marketing page'''
|
||||
logout(request)
|
||||
# print len(connection.queries), connection.queries
|
||||
return redirect('/')
|
||||
|
||||
@ensure_csrf_cookie
|
||||
def change_setting(request):
|
||||
if not request.user.is_authenticated():
|
||||
return redirect('/')
|
||||
up = UserProfile.objects.get(user=request.user) #request.user.profile_cache
|
||||
if 'location' in request.POST:
|
||||
# print "loc"
|
||||
up.location=request.POST['location']
|
||||
if 'language' in request.POST:
|
||||
# print "lang"
|
||||
up.language=request.POST['language']
|
||||
up.save()
|
||||
|
||||
return HttpResponse(json.dumps({'success':True,
|
||||
'language':up.language,
|
||||
'location':up.location,}))
|
||||
|
||||
@ensure_csrf_cookie
|
||||
def create_account(request, post_override=None):
|
||||
js={'success':False}
|
||||
|
||||
post_vars = post_override if post_override else request.POST
|
||||
|
||||
# Confirm we have a properly formed request
|
||||
for a in ['username', 'email', 'password', 'location', 'language', 'name']:
|
||||
if a not in post_vars:
|
||||
js['value']="Error (401 {field}). E-mail us.".format(field=a)
|
||||
return HttpResponse(json.dumps(js))
|
||||
|
||||
if post_vars['honor_code']!=u'true':
|
||||
js['value']="To enroll, you must follow the honor code.".format(field=a)
|
||||
return HttpResponse(json.dumps(js))
|
||||
|
||||
|
||||
if post_vars['terms_of_service']!=u'true':
|
||||
js['value']="You must accept the terms of service.".format(field=a)
|
||||
return HttpResponse(json.dumps(js))
|
||||
|
||||
# Confirm appropriate fields are there.
|
||||
# TODO: Check e-mail format is correct.
|
||||
# TODO: Confirm e-mail is not from a generic domain (mailinator, etc.)? Not sure if
|
||||
# this is a good idea
|
||||
# TODO: Check password is sane
|
||||
for a in ['username', 'email', 'name', 'password', 'terms_of_service', 'honor_code']:
|
||||
if len(post_vars[a])<2:
|
||||
error_str = {'username' : 'Username of length 2 or greater',
|
||||
'email' : 'Properly formatted e-mail',
|
||||
'name' : 'Your legal name ',
|
||||
'password': 'Valid password ',
|
||||
'terms_of_service': 'Accepting Terms of Service',
|
||||
'honor_code': 'Agreeing to the Honor Code'}
|
||||
js['value']="{field} is required.".format(field=error_str[a])
|
||||
return HttpResponse(json.dumps(js))
|
||||
|
||||
try:
|
||||
validate_email(post_vars['email'])
|
||||
except:
|
||||
js['value']="Valid e-mail is required.".format(field=a)
|
||||
return HttpResponse(json.dumps(js))
|
||||
|
||||
try:
|
||||
validate_slug(post_vars['username'])
|
||||
except:
|
||||
js['value']="Username should only consist of A-Z and 0-9.".format(field=a)
|
||||
return HttpResponse(json.dumps(js))
|
||||
|
||||
|
||||
|
||||
# Confirm username and e-mail are unique. TODO: This should be in a transaction
|
||||
if len(User.objects.filter(username=post_vars['username']))>0:
|
||||
js['value']="An account with this username already exists."
|
||||
return HttpResponse(json.dumps(js))
|
||||
|
||||
if len(User.objects.filter(email=post_vars['email']))>0:
|
||||
js['value']="An account with this e-mail already exists."
|
||||
return HttpResponse(json.dumps(js))
|
||||
|
||||
u=User(username=post_vars['username'],
|
||||
email=post_vars['email'],
|
||||
is_active=False)
|
||||
u.set_password(post_vars['password'])
|
||||
r=Registration()
|
||||
# TODO: Rearrange so that if part of the process fails, the whole process fails.
|
||||
# Right now, we can have e.g. no registration e-mail sent out and a zombie account
|
||||
u.save()
|
||||
r.register(u)
|
||||
|
||||
up = UserProfile(user=u)
|
||||
up.name=post_vars['name']
|
||||
up.language=post_vars['language']
|
||||
up.location=post_vars['location']
|
||||
up.save()
|
||||
|
||||
d={'name':post_vars['name'],
|
||||
'key':r.activation_key,
|
||||
'site':settings.SITE_NAME}
|
||||
|
||||
subject = render_to_string('emails/activation_email_subject.txt',d)
|
||||
# Email subject *must not* contain newlines
|
||||
subject = ''.join(subject.splitlines())
|
||||
message = render_to_string('emails/activation_email.txt',d)
|
||||
|
||||
try:
|
||||
if not settings.GENERATE_RANDOM_USER_CREDENTIALS:
|
||||
res=u.email_user(subject, message, settings.DEFAULT_FROM_EMAIL)
|
||||
except:
|
||||
js['value']='Could not send activation e-mail.'
|
||||
return HttpResponse(json.dumps(js))
|
||||
|
||||
js={'success':True,
|
||||
'value':render_to_string('registration/reg_complete.html', {'email':post_vars['email'],
|
||||
'csrf':csrf(request)['csrf_token']})}
|
||||
# print len(connection.queries), connection.queries
|
||||
return HttpResponse(json.dumps(js), mimetype="application/json")
|
||||
|
||||
def create_random_account(create_account_function):
|
||||
|
||||
def id_generator(size=6, chars=string.ascii_uppercase + string.ascii_lowercase + string.digits):
|
||||
return ''.join(random.choice(chars) for x in range(size))
|
||||
|
||||
def inner_create_random_account(request):
|
||||
post_override= {'username' : "random_" + id_generator(),
|
||||
'email' : id_generator(size=10, chars=string.ascii_lowercase) + "_dummy_test@mitx.mit.edu",
|
||||
'password' : id_generator(),
|
||||
'location' : id_generator(size=5, chars=string.ascii_uppercase),
|
||||
'language' : id_generator(size=5, chars=string.ascii_uppercase) + "ish",
|
||||
'name' : id_generator(size=5, chars=string.ascii_lowercase) + " " + id_generator(size=7, chars=string.ascii_lowercase),
|
||||
'honor_code' : u'true',
|
||||
'terms_of_service' : u'true',}
|
||||
|
||||
# print "Creating random account: " , post_override
|
||||
|
||||
return create_account_function(request, post_override = post_override)
|
||||
|
||||
return inner_create_random_account
|
||||
|
||||
if settings.GENERATE_RANDOM_USER_CREDENTIALS:
|
||||
create_account = create_random_account(create_account)
|
||||
|
||||
@ensure_csrf_cookie
|
||||
def activate_account(request, key):
|
||||
''' When link in activation e-mail is clicked
|
||||
'''
|
||||
r=Registration.objects.filter(activation_key=key)
|
||||
if len(r)==1:
|
||||
if not r[0].user.is_active:
|
||||
r[0].activate()
|
||||
resp = render_to_response("activation_complete.html",{'csrf':csrf(request)['csrf_token']})
|
||||
return resp
|
||||
resp = render_to_response("activation_active.html",{'csrf':csrf(request)['csrf_token']})
|
||||
return resp
|
||||
if len(r)==0:
|
||||
return render_to_response("activation_invalid.html",{'csrf':csrf(request)['csrf_token']})
|
||||
return HttpResponse("Unknown error. Please e-mail us to let us know how it happened.")
|
||||
|
||||
@ensure_csrf_cookie
|
||||
def password_reset(request):
|
||||
''' Attempts to send a password reset e-mail. '''
|
||||
if request.method != "POST":
|
||||
raise Http404
|
||||
form = PasswordResetForm(request.POST)
|
||||
if form.is_valid():
|
||||
form.save( use_https = request.is_secure(),
|
||||
from_email = settings.DEFAULT_FROM_EMAIL,
|
||||
request = request )
|
||||
return HttpResponse(json.dumps({'success':True,
|
||||
'value': render_to_string('registration/password_reset_done.html', {})}))
|
||||
else:
|
||||
return HttpResponse(json.dumps({'success':False,
|
||||
'error': 'Invalid e-mail'}))
|
||||
|
||||
@ensure_csrf_cookie
|
||||
def reactivation_email(request):
|
||||
''' Send an e-mail to reactivate a deactivated account, or to
|
||||
resend an activation e-mail '''
|
||||
email = request.POST['email']
|
||||
try:
|
||||
user = User.objects.get(email = 'email')
|
||||
except: # TODO: Type of exception
|
||||
return HttpResponse(json.dumps({'success':False,
|
||||
'error': 'No inactive user with this e-mail exists'}))
|
||||
|
||||
if user.is_active:
|
||||
return HttpResponse(json.dumps({'success':False,
|
||||
'error': 'User is already active'}))
|
||||
|
||||
reg = Registration.objects.get(user = user)
|
||||
reg.register(user)
|
||||
|
||||
d={'name':UserProfile.get(user = user).name,
|
||||
'key':r.activation_key,
|
||||
'site':settings.SITE_NAME}
|
||||
|
||||
subject = render_to_string('reactivation_email_subject.txt',d)
|
||||
subject = ''.join(subject.splitlines())
|
||||
message = render_to_string('reactivation_email.txt',d)
|
||||
|
||||
res=u.email_user(subject, message, settings.DEFAULT_FROM_EMAIL)
|
||||
|
||||
return HttpResponse(json.dumps({'success':True}))
|
||||
|
||||
|
||||
@ensure_csrf_cookie
|
||||
def change_email_request(request):
|
||||
''' AJAX call from the profile page. User wants a new e-mail.
|
||||
'''
|
||||
## Make sure it checks for existing e-mail conflicts
|
||||
if not request.user.is_authenticated:
|
||||
raise Http404
|
||||
|
||||
user = request.user
|
||||
|
||||
if not user.check_password(request.POST['password']):
|
||||
return HttpResponse(json.dumps({'success':False,
|
||||
'error':'Invalid password'}))
|
||||
|
||||
new_email = request.POST['new_email']
|
||||
if len(User.objects.filter(email = new_email)) != 0:
|
||||
## CRITICAL TODO: Handle case for e-mails
|
||||
return HttpResponse(json.dumps({'success':False,
|
||||
'error':'An account with this e-mail already exists.'}))
|
||||
|
||||
pec_list = PendingEmailChange.objects.filter(user = request.user)
|
||||
if len(pec_list) == 0:
|
||||
pec = PendingEmailChange()
|
||||
pec.user = user
|
||||
else :
|
||||
pec = pec_list[0]
|
||||
|
||||
pec.new_email = request.POST['new_email']
|
||||
pec.activation_key = uuid.uuid4().hex
|
||||
pec.save()
|
||||
|
||||
if pec.new_email == user.email:
|
||||
pec.delete()
|
||||
return HttpResponse(json.dumps({'success':False,
|
||||
'error':'Old email is the same as the new email.'}))
|
||||
|
||||
d = {'site':settings.SITE_NAME,
|
||||
'key':pec.activation_key,
|
||||
'old_email' : user.email,
|
||||
'new_email' : pec.email}
|
||||
|
||||
subject = render_to_string('emails/email_change_subject.txt',d)
|
||||
message = render_to_string('emails/email_change.txt',d)
|
||||
|
||||
res=send_email(subject, message, settings.DEFAULT_FROM_EMAIL, [pec.email])
|
||||
|
||||
return HttpResponse(json.dumps({'success':True}))
|
||||
|
||||
@ensure_csrf_cookie
|
||||
def confirm_email_change(request, key):
|
||||
''' User requested a new e-mail. This is called when the activation
|
||||
link is clicked. We confirm with the old e-mail, and update
|
||||
'''
|
||||
try:
|
||||
pec=PendingEmailChange.objects.get(activation_key=key)
|
||||
except:
|
||||
return render_to_response("email_invalid_key.html")
|
||||
|
||||
subject = render_to_string('emails/confirm_email_change_subject.txt',d)
|
||||
subject = ''.join(subject.splitlines())
|
||||
message = render_to_string('emails/confirm_email_change.txt',d)
|
||||
|
||||
user = pec.user
|
||||
user.email_user(subject, message, DEFAULT_FROM_EMAIL)
|
||||
up = UserProfile.objects.get( user = user )
|
||||
meta = up.get_meta()
|
||||
if 'old_emails' not in meta:
|
||||
meta['old_emails'] = []
|
||||
meta['old_emails'].append(user.email)
|
||||
up.set_meta(meta)
|
||||
up.save()
|
||||
user.email = pec.new_email
|
||||
user.save()
|
||||
pec.delete()
|
||||
|
||||
return render_to_response("email_change_successful.html")
|
||||
|
||||
@ensure_csrf_cookie
|
||||
def change_name_request(request):
|
||||
if not request.user.is_authenticated:
|
||||
raise Http404
|
||||
|
||||
pnc = PendingNameChange()
|
||||
pnc.user = request.User
|
||||
pnc.new_name = request.POST['new_name']
|
||||
pnc.rationale = request.POST['rationale']
|
||||
pnc.save()
|
||||
return HttpResponse(json.dumps({'success':True}))
|
||||
|
||||
@ensure_csrf_cookie
|
||||
def change_name_list(request):
|
||||
if not request.user.is_staff:
|
||||
raise Http404
|
||||
|
||||
changes = list(PendingNameChange.objects.all())
|
||||
json = [{'new_name': c.new_name,
|
||||
'rationale':c.rationale,
|
||||
'old_name':UserProfile.Objects.get(username=c.user).name,
|
||||
'email':c.user.email,
|
||||
'id':c.id} for c in changes]
|
||||
return render_to_response('name_changes.html', json)
|
||||
|
||||
@ensure_csrf_cookie
|
||||
def change_name_reject(request):
|
||||
''' Course staff clicks 'reject' on a given name change '''
|
||||
if not request.user.is_staff:
|
||||
raise Http404
|
||||
|
||||
pnc = PendingNameChange.objects.get(id = int(request.POST['id']))
|
||||
pnc.delete()
|
||||
return HttpResponse(json.dumps({'success':True}))
|
||||
|
||||
@ensure_csrf_cookie
|
||||
def change_name_accept(request):
|
||||
''' Course staff clicks 'accept' on a given name change '''
|
||||
pnc = PendingNameChange.objects.get(id = int(request.POST['id']))
|
||||
|
||||
u = pnc.user
|
||||
up = UserProfile.objects.get(user=u)
|
||||
up.name = pnc.name
|
||||
up.save()
|
||||
pnc.delete()
|
||||
return HttpResponse(json.dumps({'success':True}))
|
||||
|
||||
Reference in New Issue
Block a user