Repository: ocadotechnology/codeforlife-portal

Issue:
Redirect teachers to redesign after 2FA
2FA is currently still the old design, so needs redirecting to new pages.


Discussion:

Resolving patch:
diff --git a/example_project/example_project/settings.py b/example_project/example_project/settings.py
--- a/example_project/example_project/settings.py
+++ b/example_project/example_project/settings.py
@@ -61,6 +61,8 @@
 
 WSGI_APPLICATION = 'example_project.wsgi.application'
 
+LOGIN_REDIRECT_URL = '/portal/redesign/teach/dashboard/'
+
 INSTALLED_APPS = (
     'portal',
 )
diff --git a/portal/views/teacher/dashboard.py b/portal/views/teacher/dashboard.py
--- a/portal/views/teacher/dashboard.py
+++ b/portal/views/teacher/dashboard.py
@@ -34,25 +34,21 @@
 # copyright notice and these terms. You must not misrepresent the origins of this
 # program; modified versions of the program must be marked as such and not
 # identified as the original program.
-from functools import partial
-import json
 from recaptcha import RecaptchaClient
 
-from django.db.models import Q
 from django.shortcuts import render, get_object_or_404
-from django.http import Http404, HttpResponse, HttpResponseRedirect
+from django.http import Http404, HttpResponseRedirect
 from django.core.urlresolvers import reverse_lazy
 from django.contrib import messages as messages
 from django.contrib.auth import logout, update_session_auth_hash
 from django.contrib.auth.decorators import login_required, user_passes_test
-from django_recaptcha_field import create_form_subclass_with_recaptcha
 
 from two_factor.utils import devices_for_user
 
 from portal import app_settings, emailMessages_new
 from portal.helpers.emails import send_email, NOTIFICATION_EMAIL
-from portal.models import School, Teacher, Class
-from portal.forms.organisation import OrganisationJoinForm, OrganisationForm
+from portal.models import Teacher, Class
+from portal.forms.organisation import OrganisationForm
 from portal.forms.teach_new import ClassCreationForm, TeacherEditAccountForm
 from portal.permissions import logged_in_as_teacher
 from portal.helpers.emails_new import send_verification_email
@@ -61,9 +57,6 @@
 
 from portal.utils import using_two_factor
 
-
-from ratelimit.decorators import ratelimit
-
 recaptcha_client = RecaptchaClient(app_settings.RECAPTCHA_PRIVATE_KEY, app_settings.RECAPTCHA_PUBLIC_KEY)
 
 
@@ -91,6 +84,8 @@ def dashboard_teacher_view(request, is_admin):
 
     anchor = ''
 
+    backup_tokens = check_backup_tokens(request)
+
     if can_process_forms(request, is_admin):
         if 'update_school' in request.POST:
             anchor = 'school-details'
@@ -126,6 +121,7 @@ def dashboard_teacher_view(request, is_admin):
         'create_class_form': create_class_form,
         'update_account_form': update_account_form,
         'anchor': anchor,
+        'backup_tokens': backup_tokens,
     })
 
 
@@ -133,6 +129,18 @@ def can_process_forms(request, is_admin):
     return request.method == 'POST' and is_admin
 
 
+def check_backup_tokens(request):
+    backup_tokens = 0
+    # For teachers using 2FA, find out how many backup tokens they have
+    if using_two_factor(request.user):
+        try:
+            backup_tokens = request.user.staticdevice_set.all()[0].token_set.count()
+        except Exception:
+            backup_tokens = 0
+
+    return backup_tokens
+
+
 def process_update_school_form(request, school, old_anchor):
     update_school_form = OrganisationForm(request.POST, user=request.user, current_school=school)
     if update_school_form.is_valid():
diff --git a/portal/views/teacher/home_new.py b/portal/views/teacher/home_new.py
new file mode 100644
--- /dev/null
+++ b/portal/views/teacher/home_new.py
@@ -0,0 +1,103 @@
+# -*- coding: utf-8 -*-
+# Code for Life
+#
+# Copyright (C) 2017, Ocado Innovation Limited
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# ADDITIONAL TERMS – Section 7 GNU General Public Licence
+#
+# This licence does not grant any right, title or interest in any “Ocado” logos,
+# trade names or the trademark “Ocado” or any other trademarks or domain names
+# owned by Ocado Innovation Limited or the Ocado group of companies or any other
+# distinctive brand features of “Ocado” as may be secured from time to time. You
+# must not distribute any modification of this program using the trademark
+# “Ocado” or claim any affiliation or association with Ocado or its employees.
+#
+# You are not authorised to use the name Ocado (or any of its trade names) or
+# the names of any author or contributor in advertising or for publicity purposes
+# pertaining to the distribution of this program, without the prior written
+# authorisation of Ocado.
+#
+# Any propagation, distribution or conveyance of this program must include this
+# copyright notice and these terms. You must not misrepresent the origins of this
+# program; modified versions of the program must be marked as such and not
+# identified as the original program.
+from django.core.urlresolvers import reverse, reverse_lazy
+from django.contrib import messages as messages
+from django.contrib.auth.decorators import login_required, user_passes_test
+from django.http import HttpResponseRedirect
+from portal.utils import using_two_factor
+
+from portal.models import Teacher, Student
+from portal.permissions import logged_in_as_teacher
+
+
+@login_required(login_url=reverse_lazy('login_new'))
+@user_passes_test(logged_in_as_teacher, login_url=reverse_lazy('login_new'))
+def teacher_home(request):
+    teacher = request.user.new_teacher
+
+    pending_student_request_warning(request, teacher)
+
+    pending_teacher_request_warning(request, teacher)
+
+    two_form_authentication_warnings(request, teacher)
+
+    return HttpResponseRedirect(reverse_lazy('dashboard'))
+
+
+def pending_student_request_warning(request, teacher):
+    if Student.objects.filter(pending_class_request__teacher=teacher).exists():
+        messages.info(request,
+                      'You have pending requests from students wanting to join your classes. '
+                      '<a href="#classes">Review these requests.</a>', extra_tags='safe')
+
+
+def pending_teacher_request_warning(request, teacher):
+    if teacher.is_admin and Teacher.objects.filter(pending_join_request=teacher.school).exists():
+        messages.info(request,
+                      'You have pending requests from teachers wanting to join your school or club. '
+                      '<a href="#requests">Review these requests.</a>', extra_tags='safe')
+
+
+def two_form_authentication_warnings(request, teacher):
+    # For teachers using 2FA, warn if they don't have backup tokens set, and warn solo-admins to set up another admin
+    if using_two_factor(request.user):
+
+        backup_tokens = check_backup_tokens(request)
+        if not backup_tokens > 0:
+            link = reverse('two_factor:profile')
+            messages.warning(request,
+                             'You do not have any backup tokens set up for two factor authentication, so could lose '
+                             'access to your account if you have problems with your smartphone or tablet. '
+                             '<a href="{link}">Set up backup tokens now</a>.'.format(link=link), extra_tags='safe')
+        # check admin
+        if teacher.is_admin:
+            admins = Teacher.objects.filter(school=teacher.school, is_admin=True)
+            if len(admins) == 1:
+                messages.warning(request,
+                                 'You are the only administrator in your school and are using Two Factor '
+                                 'Authentication (2FA). We recommend you <a href="#school">set up another '
+                                 'administrator</a> who will be able to disable your 2FA should you have problems with '
+                                 'your smartphone or tablet.', extra_tags='safe')
+
+
+def check_backup_tokens(request):
+    try:
+        backup_tokens = request.user.staticdevice_set.all()[0].token_set.count()
+    except Exception:
+        backup_tokens = 0
+
+    return backup_tokens


Test patch: