Commit 0b070476 authored by Bruno Martin's avatar Bruno Martin
Browse files

[WIP] initial version of legacy code refactored to be an app

parent 2d136ecc
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth import get_user_model
from django.utils.translation import ugettext_lazy as _
User = get_user_model()
class TimtecUserAdmin(UserAdmin):
model = User
fieldsets = UserAdmin.fieldsets + (
(_('Timtec Info'), {'fields': ('accepted_terms', 'picture', 'cpf',
'occupation', 'institution')}),
)
admin.site.register(User, TimtecUserAdmin)
from django.contrib.auth import get_user_model
from django import forms
from localflavor.br.forms import BRCPFField
from django.utils.translation import ugettext_lazy as _
from django.conf import settings
User = get_user_model()
class BaseProfileEditForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(BaseProfileEditForm, self).__init__(*args, **kwargs)
fields = settings.ACCOUNT_REQUIRED_FIELDS
for field in fields:
try:
self.fields[field].required = True
self.fields[field].blank = False
except KeyError:
pass
class ProfileEditForm(BaseProfileEditForm):
email = forms.RegexField(label=_("email"), max_length=75, regex=r"^[\w.@+-]+$")
cpf = BRCPFField()
password1 = forms.CharField(widget=forms.PasswordInput, label=_("Password"), required=False)
password2 = forms.CharField(widget=forms.PasswordInput, label=_("Password (again)"), required=False)
class Meta:
model = get_user_model()
fields = ('username', 'email', 'first_name', 'last_name', 'image',
'occupation', 'city', 'site', 'biography', 'cpf')
def clean(self):
cleaned_data = super().clean()
if not self.is_valid():
self.cleaned_data['image'] = self.instance.image
return cleaned_data
# FIXME: username should be actually cleaned
def clean_username(self):
return self.instance.username
def clean_password2(self):
password1 = self.cleaned_data.get('password1')
password2 = self.cleaned_data.get('password2')
if password1 != password2:
raise forms.ValidationError(_("The two password fields didn't match."))
return password2
def save(self, commit=True):
if self.cleaned_data['password1']:
self.instance.set_password(self.cleaned_data['password1'])
return super(ProfileEditForm, self).save(commit=commit)
class ProfileEditAdminForm(BaseProfileEditForm):
email = forms.RegexField(label=_("email"), max_length=75, regex=r"^[\w.@+-]+$")
cpf = BRCPFField()
password1 = forms.CharField(widget=forms.PasswordInput, label=_("Password"), required=False)
password2 = forms.CharField(widget=forms.PasswordInput, label=_("Password (again)"), required=False)
class Meta:
model = get_user_model()
widgets = {
'groups' : forms.SelectMultiple(attrs={'class' : 'form-control',
'size' : 10 })
}
fields = ('username', 'email', 'first_name', 'last_name', 'image',
'groups', 'occupation', 'city', 'site', 'biography', 'cpf')
def clean(self):
cleaned_data = super(ProfileEditAdminForm, self).clean()
if not self.is_valid():
self.cleaned_data['image'] = self.instance.image
return cleaned_data
# FIXME: username should be actually cleaned
def clean_username(self):
return self.instance.username
def clean_password2(self):
password1 = self.cleaned_data.get('password1')
password2 = self.cleaned_data.get('password2')
if password1 != password2:
raise forms.ValidationError(_("The two password fields didn't match."))
return password2
def save(self, commit=True):
if self.cleaned_data['password1']:
self.instance.set_password(self.cleaned_data['password1'])
return super(ProfileEditAdminForm, self).save(commit=commit)
class AcceptTermsForm(forms.Form):
accept_terms = forms.BooleanField(label=_('Accept '), initial=False, required=False)
def clean_accept_terms(self):
data = self.cleaned_data['accept_terms']
if settings.TERMS_ACCEPTANCE_REQUIRED and not data:
raise forms.ValidationError(_('You must agree to the Terms of Use to use %(site_name)s.'),
params={'site_name': settings.SITE_NAME},)
return self.cleaned_data['accept_terms']
class SignupForm(ProfileEditForm, AcceptTermsForm):
occupation = forms.CharField()
institution = forms.CharField()
class Meta:
model = get_user_model()
fields = ('username', 'email', 'occupation', 'cpf', 'institution',)
def signup(self, request, user):
user.accepted_terms = self.cleaned_data['accept_terms']
user.institution = self.cleaned_data['institution']
user.occupation = self.cleaned_data['occupation']
user.cpf = self.cleaned_data['cpf']
user.save()
from rest_framework import serializers
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
class TimtecUserSerializer(serializers.ModelSerializer):
name = serializers.ReadOnlyField(source='get_full_name')
picture = serializers.ReadOnlyField(source='get_picture_thumb_url')
is_profile_filled = serializers.BooleanField()
class Meta:
model = get_user_model()
fields = ('id', 'username', 'email', 'name', 'first_name', 'last_name',
'biography', 'picture', 'is_profile_filled')
class TimtecUserAdminSerializer(TimtecUserSerializer):
class Meta:
model = get_user_model()
fields = ('id', 'username', 'name', 'email', 'is_active', 'is_superuser', 'first_name', 'last_name', 'picture', 'groups', )
depth = 1
class TimtecUserAdminCertificateSerializer(TimtecUserSerializer):
class Meta:
model = get_user_model()
fields = ('id', 'name', 'email', 'username')
class GroupAdminSerializer(serializers.ModelSerializer):
users = TimtecUserSerializer(many=True, read_only=True, source="user_set")
class Meta:
model = Group
fields = ('id', 'name', 'users', )
depth = 1
class GroupSerializer(serializers.ModelSerializer):
class Meta:
model = Group
fields = ('id', 'name')
from django.contrib.auth import get_user_model, update_session_auth_hash
from django.contrib.auth.models import Group
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
from django.urls import reverse_lazy
from django.shortcuts import get_object_or_404
from django.views.generic import UpdateView, FormView
from django.views.generic.detail import DetailView
from django.db.models import Q
from .forms import ProfileEditForm, ProfileEditAdminForm, AcceptTermsForm
from .serializers import TimtecUserSerializer, TimtecUserAdminSerializer, GroupAdminSerializer, GroupSerializer
from braces.views import LoginRequiredMixin, SuperuserRequiredMixin
from rest_framework import viewsets
from rest_framework import filters
from rest_framework import generics
from rest_framework.response import Response
from django_filters.rest_framework import DjangoFilterBackend
from ..core.permissions import IsAdmin
TimtecUser = get_user_model()
class ProfileEditView(LoginRequiredMixin, UpdateView):
model = get_user_model()
form_class = ProfileEditForm
template_name = 'profile-edit.html'
def get_success_url(self):
url = self.request.GET.get('next', None)
if url:
return url
else:
return reverse_lazy('courses_legacy:profile')
def get_object(self):
return self.request.user
def post(self, request, *args, **kwargs):
form_result = super(ProfileEditView, self) \
.post(request, *args, **kwargs)
update_session_auth_hash(self.request, self.request.user)
return form_result
class ProfileEditAdminView(LoginRequiredMixin, SuperuserRequiredMixin, UpdateView):
model = get_user_model()
form_class = ProfileEditAdminForm
template_name = 'administration/profile-edit-admin.html'
raise_exception = True
def get_success_url(self):
url = self.request.GET.get('next', None)
if url:
return url
else:
return reverse_lazy('administration.profile_edit', args=[self.kwargs['username']])
def get_object(self):
if hasattr(self, 'kwargs') and 'username' in self.kwargs:
try:
return get_object_or_404(self.model, username=self.kwargs['username'])
except:
return self.request.user
else:
return self.request.user
class ProfileView(LoginRequiredMixin, DetailView):
model = get_user_model()
template_name = 'profile.html'
context_object_name = 'profile_user'
def get_object(self):
if hasattr(self, 'kwargs') and 'username' in self.kwargs:
try:
return get_object_or_404(self.model, username=self.kwargs['username'])
except:
return self.request.user
else:
return self.request.user
class TimtecUserViewSet(viewsets.ReadOnlyModelViewSet):
model = get_user_model()
lookup_field = 'id'
filter_fields = ('groups__name',)
filter_backends = (DjangoFilterBackend, filters.OrderingFilter,)
serializer_class = TimtecUserSerializer
queryset = TimtecUser.objects.all()
ordering = ('first_name', 'username',)
class TimtecUserAdminViewSet(viewsets.ModelViewSet):
model = get_user_model()
# lookup_field = 'id'
# filter_backends = (filters.OrderingFilter,)
permission_classes = (IsAdmin, )
serializer_class = TimtecUserAdminSerializer
ordering = ('first_name', 'username',)
queryset = TimtecUser.objects.all()
# search_fields = ('first_name', 'last_name', 'username', 'email')
def get_queryset(self):
page = self.request.query_params.get('page')
keyword = self.request.query_params.get('keyword')
admin = self.request.query_params.get('admin')
blocked = self.request.query_params.get('blocked')
queryset = super(TimtecUserAdminViewSet, self).get_queryset().order_by('first_name')
if keyword:
queryset = queryset.filter(Q(first_name__icontains=keyword) |
Q(last_name__icontains=keyword) |
Q(username__icontains=keyword) |
Q(email__icontains=keyword))
if admin == 'true':
queryset = queryset.filter(is_superuser=True)
if blocked == 'true':
queryset = queryset.filter(is_active=False)
if page:
paginator = Paginator(queryset, 50)
try:
queryset = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
queryset = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999),
# deliver last page of results.
queryset = paginator.page(paginator.num_pages)
return queryset
class GroupAdminViewSet(viewsets.ModelViewSet):
queryset = Group.objects.all()
model = Group
serializer_class = GroupAdminSerializer
permission_classes = (IsAdmin, )
def put(self, request, **kwargs):
User = get_user_model()
# Does a user need to be removed from a given group?
if request.data['action'] == 'remove':
group = Group.objects.get(id=request.data['id'])
group.user_set.remove(User.objects.get(id=request.data['user']['id']))
return Response(status=200)
# Does a user nedd to be added to a given group?
# The "add" action support multiple users
if request.data['action'] == 'add':
group = Group.objects.get(id=request.data['id'])
for user in request.data.get('users', None):
group.user_set.add(User.objects.get(id=user['id']))
return Response(status=200)
if request.data['action'] == 'bulk_remove':
group = Group.objects.get(id=request.data['id'])
users = User.objects.filter(email__in=request.data['users'])
for user in users:
group.user_set.remove(user)
return Response(status=200)
if request.data['action'] == 'bulk_add':
group = Group.objects.get(id=request.data['id'])
users = User.objects.filter(email__in=request.data['users'])
for user in users:
group.user_set.add(user)
return Response(status=200)
return Response(status=404)
class GroupViewSet(viewsets.ReadOnlyModelViewSet):
"""
API endpoint that allows groups to be viewed.
"""
queryset = Group.objects.all()
serializer_class = GroupSerializer
class UserSearchView(LoginRequiredMixin, generics.ListAPIView):
model = get_user_model()
serializer_class = TimtecUserSerializer
def get_queryset(self):
queryset = self.model.objects.all()
query = self.request.query_params.get('name', None)
if query is not None:
queryset = queryset.filter(Q(first_name__icontains=query) |
Q(last_name__icontains=query) |
Q(username__icontains=query) |
Q(email__icontains=query))
return queryset
class StudentSearchView(LoginRequiredMixin, generics.ListAPIView):
model = get_user_model()
serializer_class = TimtecUserSerializer
search_fields = ('first_name', 'last_name', 'username', 'email')
def get_queryset(self):
queryset = self.model.objects.all()
course = self.request.query_params.get('course', None)
classes = self.request.user.professor_classes.all()
if classes:
queryset = queryset.filter(classes__in=classes)
else:
# FIXME: if every student is in a class, this is useless.
if course is not None:
queryset = queryset.filter(studentcourse_set=course)
query = self.request.query_params.get('name', None)
if query is not None:
queryset = queryset.filter(Q(first_name__icontains=query) |
Q(last_name__icontains=query) |
Q(username__icontains=query) |
Q(email__icontains=query))
return queryset
class AcceptTermsView(FormView):
template_name = 'accept-terms.html'
form_class = AcceptTermsForm
success_url = reverse_lazy('courses_legacy:courses')
def get_success_url(self):
next_url = self.request.POST.get('next', None)
if next_url:
return next_url
return reverse_lazy('courses_legacy:courses')
def form_valid(self, form):
# This method is called when valid form data has been POSTed.
# It should return an HttpResponse.
self.request.user.accepted_terms = True
self.request.user.save()
return super(AcceptTermsView, self).form_valid(form)
def get_context_data(self, **kwargs):
context = super(AcceptTermsView, self).get_context_data(**kwargs)
next_url = self.request.GET.get('next')
if next_url:
context['next_url'] = next_url
return context
default_app_config = 'activities.apps.ActivitiesConfig'
from django.contrib import admin
from django.forms import TextInput, Textarea
from django.db import models
from .models import Answer, Activity
class ModelAdmin(admin.ModelAdmin):
formfield_overrides = {
models.CharField: {'widget': TextInput(attrs={'class': 'span12'})},
models.TextField: {'widget': Textarea(attrs={'rows': 4, 'class': 'span12'})},
}
class ActivityAdmin(ModelAdmin):
search_fields = ('type', 'data')
list_display = ('lesson', 'unit', 'unit_position', 'type', 'question', '__unicode__')
readonly_fields = ('unit_position', 'lesson')
def unit(self, object):
try:
return object.units.first().title
except AttributeError:
return
def lesson(self, object):
try:
return object.units.first().lesson.name
except AttributeError:
return
def unit_position(self, object):
try:
return object.units.first().position
except AttributeError:
return
class AnswerAdmin(ModelAdmin):
ordering = ('timestamp',)
list_display = ('activity', 'user', 'timestamp', 'given', 'unit')
readonly_fields = ('unit',)
search_fields = ('given', 'user__username', 'user__first_name', 'user__last_name', 'user__email')
def unit(self, object):
try:
return object.activity.units.first().title
except AttributeError:
return
admin.site.register(Activity, ActivityAdmin)
admin.site.register(Answer, AnswerAdmin)
from django.apps import AppConfig
class ActivitiesConfig(AppConfig):
name = 'activities'
verbose_name = 'Activities'
def ready(self):
import activities.signals
from courses_learning_objects.models import LearningObject as Activity, Answer
from rest_framework import serializers
from discussion.models import Topic
from discussion.serializers import TopicSerializer
from .models import Activity, Answer
class ActivitySerializer(serializers.ModelSerializer):
data = serializers.JSONField()
expected = serializers.JSONField(required=False)
image_url = serializers.SerializerMethodField()
class Meta:
model = Activity
fields = ('id', 'comment', 'data', 'expected', 'type', 'unit', 'image_url')
@staticmethod
def get_image_url(obj):
if obj.image:
return obj.image.url
return ''
class ActivityImageSerializer(serializers.ModelSerializer):
class Meta:
model = Activity
fields = ('id', 'image')
class AnswerSerializer(serializers.ModelSerializer):
correct = serializers.ReadOnlyField(source='is_correct')
given = serializers.JSONField()
topic = serializers.SerializerMethodField()
class Meta:
model = Answer
allow_add_remove = True
fields = ('id', 'activity', 'correct', 'timestamp', 'given', 'topic')
def get_topic(self, obj):
try:
topic = Topic.objects.get(id=obj.given.get('topic', None))
except (Topic.DoesNotExist, AttributeError) as e:
return
return TopicSerializer(instance=topic, **{'context': self.context}).data
class ActivityExportSerializer(serializers.ModelSerializer):
data = serializers.JSONField()
expected = serializers.JSONField(required=False)
class Meta:
model = Activity
exclude = ('id', 'unit', )
class ActivityImportSerializer(ActivityExportSerializer):
id = serializers.IntegerField(required=False)
class Meta:
model = Activity
exclude = ('unit', )
from django.dispatch import receiver
from django.db.models.signals import post_save