Commits (4)
# -*- coding: utf-8 -*-
from django.contrib import admin
from django.forms import Textarea
from django.db import models
# from ..activities.admin import ModelAdmin
from .videos.models import Video
from .models import (
Course, Lesson, Unit, CourseProfessor, CourseStudent,
StudentProgress, Class,
)
class LessonInline(admin.TabularInline):
model = Lesson
formfield_overrides = {
models.CharField: {'widget': Textarea(attrs={'rows': 3, 'class': 'span11'})},
}
@admin.register(Course)
class CourseAdmin(admin.ModelAdmin):
list_display = ('name', 'status', 'start_date',)
inlines = (LessonInline,)
class UnitInline(admin.TabularInline):
model = Unit
fields = ('title', 'video', 'position',)
@admin.register(Lesson)
class LessonAdmin(admin.ModelAdmin):
list_display = ('name', 'course',)
search_fields = ('course__name',)
inlines = (UnitInline,)
@admin.register(Unit)
class UnitAdmin(admin.ModelAdmin):
search_fields = ('title', 'lesson__name')
list_display = ('title', 'position', 'lesson', 'video',)
list_select_related = ('lesson', 'video')
@admin.register(CourseProfessor)
class CourseProfessorAdmin(admin.ModelAdmin):
list_display = ('user', 'course',)
@admin.register(Video)
class VideoAdmin(admin.ModelAdmin):
pass
@admin.register(Class)
class ClassAdmin(admin.ModelAdmin):
search_fields = ('name', 'course', 'assistants')
list_display = ('name', 'course')
filter_horizontal = ('students', )
@admin.register(StudentProgress)
class StudentProgressAdmin(admin.ModelAdmin):
search_fields = ('user__username', 'user__email', )
list_display = ('user', 'unit', 'complete', 'last_access')
@admin.register(CourseStudent)
class CourseStudentAdmin(admin.ModelAdmin):
search_fields = ('user__username',)
list_display = ('user', 'course')
......@@ -2,12 +2,10 @@ from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.utils.text import slugify
from courses.models import Course
class CourseMaterial(models.Model):
course = models.OneToOneField(
Course,
'Course',
models.CASCADE,
related_name='course_material',
verbose_name=_('Course Materials'),
......
......@@ -18,6 +18,7 @@ from .utils import hash_name
from .videos.models import Video
from .notes.models import Note
from .course_material.models import CourseMaterial
import re
......@@ -334,14 +335,14 @@ class Course(models.Model):
return iter(professors)
def is_course_assistant(self, user):
if user.is_anonymous():
if user.is_anonymous:
return False
return self.get_professor_role(user) == 'assistant'
# return role =='assistant', 'coordinator'] or user.is_superuser
def is_assistant_or_coordinator(self, user):
if user.is_anonymous():
if user.is_anonymous:
return False
if user.is_staff or user.is_superuser:
......@@ -396,18 +397,19 @@ class CourseStudent(models.Model):
def save(self, *args, **kwargs):
super(CourseStudent, self).save(*args, **kwargs)
try:
receipt = CourseCertification.objects.get(course_student=self)
except CourseCertification.DoesNotExist:
from base64 import urlsafe_b64encode as ub64
from hashlib import sha1
from time import time
h = ub64(sha1(str(time()) + self.user.last_name.encode('utf-8')).digest()[0:6])
receipt = CourseCertification(course_student=self,
course=self.course,
type=CourseCertification.TYPES[0][0],
is_valid=True, link_hash=h)
receipt.save()
# TODO Move this to Course Certification app, couse this app must not depend on Course Certification.
# try:
# receipt = CourseCertification.objects.get(course_student=self)
# except CourseCertification.DoesNotExist:
# from base64 import urlsafe_b64encode as ub64
# from hashlib import sha1
# from time import time
# h = ub64(sha1(str(time()) + self.user.last_name.encode('utf-8')).digest()[0:6])
# receipt = CourseCertification(course_student=self,
# course=self.course,
# type=CourseCertification.TYPES[0][0],
# is_valid=True, link_hash=h)
# receipt.save()
@property
def units_done(self):
......
from rest_framework import permissions
from .models import Course, CourseProfessor, CourseAuthor
class IsProfessorCoordinatorOrAdminPermissionOrReadOnly(permissions.BasePermission):
"""
Custom permission to only allow course coordinator edit Course and CourseProfessors objects instances
"""
def has_object_permission(self, request, view, obj):
# Read permissions are allowed to any request,
# so we'll always allow GET, HEAD or OPTIONS requests.
if request.method in permissions.SAFE_METHODS:
return True
elif request.user and request.user.is_superuser:
return True
elif request.user.is_authenticated and isinstance(obj, CourseProfessor) and obj.course.get_professor_role(request.user) == 'coordinator':
return True
elif request.user.is_authenticated and isinstance(obj, Course) and obj.get_professor_role(request.user) == 'coordinator':
return True
elif request.user.is_authenticated and isinstance(obj, CourseAuthor) and obj.course.get_professor_role(request.user) == 'coordinator':
return True
from django.contrib.auth import get_user_model
from rest_framework import serializers
from .videos.serializers import VideoSerializer
from .models import (Course,)
User = get_user_model()
class SimpleUserSerializer(serializers.ModelSerializer):
class Meta:
model = User
# The model must have image, biography and name fields
fields = ('id', 'image', 'name', 'biography')
class CourseSerializer(serializers.ModelSerializer):
intro_video = VideoSerializer(required=False)
home_thumbnail_url = serializers.SerializerMethodField()
professors = SimpleUserSerializer(read_only=True, many=True)
is_user_assistant = serializers.SerializerMethodField()
is_user_coordinator = serializers.SerializerMethodField()
is_assistant_or_coordinator = serializers.SerializerMethodField()
class Meta:
model = Course
fields = ("id", "slug", "name", "intro_video", "application", "requirement",
"abstract", "structure", "workload", "status",
"thumbnail_url", "home_thumbnail_url", "home_position",
"start_date", "home_published", "authors_names", "has_started",
"min_percent_to_complete", "is_user_assistant", "is_user_coordinator",
"is_assistant_or_coordinator", 'professors', )
@staticmethod
def get_home_thumbnail_url(obj):
if obj.home_thumbnail:
return obj.home_thumbnail.url
return ''
def get_is_user_assistant(self, obj):
return obj.is_course_assistant(self.context['request'].user)
def get_is_user_coordinator(self, obj):
return obj.is_course_coordinator(self.context['request'].user)
def get_is_assistant_or_coordinator(self, obj):
return obj.is_assistant_or_coordinator(self.context['request'].user)
def update(self, instance, validated_data):
intro_video_data = validated_data.pop('intro_video', None)
course = super(CourseSerializer, self).update(instance, validated_data)
if intro_video_data:
intro_video_ser = VideoSerializer(course.intro_video, data=intro_video_data)
if intro_video_ser.is_valid():
intro_video = intro_video_ser.save()
course.intro_video = intro_video
course.save()
return course
# -*- coding: utf-8 -*-
from django.conf.urls import url
from django.conf.urls import url, include
from django.views.generic import TemplateView
from . import views
from rest_framework import routers
from .views import CourseViewSet
router = routers.DefaultRouter()
router.register(r'course', CourseViewSet, base_name='course')
# router.register(r'course_carousel', views.CarouselCourseView, base_name='course_carousel')
app_name = 'courses'
urlpatterns = [
url(r'', TemplateView.as_view(template_name="base.html")),
]
urlpatterns = []
urlpatterns.extend(router.urls)
from rest_framework import serializers
from .models import Video
class VideoSerializer(serializers.ModelSerializer):
class Meta:
model = Video
fields = ('id', 'name', 'youtube_id',)
from rest_framework import viewsets
from .models import Course
from .serializers import CourseSerializer
from .permissions import IsProfessorCoordinatorOrAdminPermissionOrReadOnly
class CourseViewSet(viewsets.ModelViewSet):
model = Course
queryset = Course.objects.all()
serializer_class = CourseSerializer
lookup_field = 'id'
filter_fields = ('slug', 'home_published',)
permission_classes = (IsProfessorCoordinatorOrAdminPermissionOrReadOnly,)
def get_queryset(self):
queryset = super(CourseViewSet, self).get_queryset()
public_courses = self.request.query_params.get('public_courses', None)
if public_courses:
queryset = queryset.filter(status='published').prefetch_related('professors')
role = self.request.query_params.get('role', None)
if not self.request.user.is_superuser:
if role:
queryset = queryset.filter(
course_professors__role=role,
course_professors__user=self.request.user
).prefetch_related('professors')
# FIXME define default group policy
# queryset = queryset.filter(groups__in=self.request.user.groups.all())
return queryset.distinct()
def post(self, request, **kwargs):
course = self.get_object()
serializer = CourseSerializer(course, request.data)
if serializer.is_valid():
serializer.save()
return Response(status=200)
else:
return Response(serializer.errors, status=400)
def metadata(self, request):
data = super(CourseViewSet, self).metadata(request)
if data.get('actions'):
data.get('actions').get('POST').get('status').update({'choices': dict(Course.STATES[1:])})
return data