views.py 17.4 KB
from django.shortcuts import render,redirect
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from dashboard.decorator import level_required
from django.shortcuts import get_object_or_404
from dashboard.forms import UserForm
from .forms import PyrosUserCreationForm,UserPasswordResetForm
from django.core.mail import send_mail
from common.models import ScientificProgram, PyrosUser,UserLevel, SP_Period, SP_Period_User
from django.urls import reverse
from django.http import HttpResponseRedirect,HttpResponse
from obsconfig.configpyros import ConfigPyros
from django.conf import settings as pyros_settings
import os

LOGGED_PAGE = "../../dashboard/templates/dashboard/index.html"

def home(request):
    '''
        Initial login view when coming on the website
    '''
    if request.user.is_authenticated:
        return(render(request, LOGGED_PAGE, {'USER_LEVEL': request.user.get_priority(), 'base_template' : "base.html", 'weather_img': "normal"}))
    return(render(request, LOGGED_PAGE, {"USER_LEVEL" : "Visitor", 'base_template' : 'base.html', 'weather_img': "red"}))

def roles_description(request):
    return (render(request,"user_manager/roles_description.html"))
    
def create_user(request):
    '''
        View called to open the user creation form
    '''
    """
    if request.user.is_authenticated:
        return(render(request, LOGGED_PAGE, {'USER_LEVEL': request.user.get_priority(), 'base_template' : "base.html", 'weather_img': "normal"}))
    """
    form = PyrosUserCreationForm()
    return (render(request, "user_manager/home_user_creation.html", locals()))

def forgotten_password(request):
    form = UserPasswordResetForm()
    message=""
    user = None
    if request.POST:
        password = PyrosUser.objects.make_random_password()
        try:
            user = PyrosUser.objects.get(email=request.POST["email"])
        except PyrosUser.DoesNotExist:
            message = "The email adress is invalid"
        if user != None:
            user.set_password(password)
            user.save()
            send_mail(
                '[PyROS CC] Registration',
                f"Hello,\nYou recently took steps to reset the password for your PyROS account. A temporary password has been assigned, please log in with the following password: '{password}'. \n\nCordially,\n\nPyROS Control Center",
                '',
                [request.POST['email']],
                fail_silently=False,
            )
            message="The email has been send !"
        else:
            return render(request, 'user_manager/forgotten_password.html',{"form":form,"message":message})        
    return render(request, 'user_manager/forgotten_password.html',{"form":form,"message":message})

def user_signup_validation(request):
    '''
        View called to validate the user creation (form submitted)
    '''
    """
    if request.user.is_authenticated:
        return(render(request, LOGGED_PAGE, {'USER_LEVEL': request.user.get_priority(), 'base_template' : "base.html", 'weather_img': "normal"}))
    """
    form = PyrosUserCreationForm(request.POST)
    if request.POST:
        if int(request.POST.get("timer")) < 10:
            error = True
            message = "(Bot prevention) You were too quick to fill the form, please take at least 10 seconds to send the form"
        else:
            if "six" != request.POST.get("question").strip():
                error = True
                message = "Wrong answer to the question (Write the answer in letter and lowercase"
            else:
                if form.is_valid() and len(request.POST.get("iambot")) <= 0:
                    form.save()
                    message = "Account creation successful ! Login to continue"
                    success = True
                    if request.user.is_authenticated:
                        
                        if request.POST.get("next"):
                            return redirect(request.POST.get('next'))
                        else:
                            return redirect(reverse("users"))
                    else:
                        return(render(request, "user_manager/home_login.html", locals()))
                else:
                    message = "One or more fields contain errors. Please try again"
                    form_errors = form.errors
    else:
        message = "The system encountered an error. Please try again"

    error = True
    return (render(request, "user_manager/home_user_creation.html", locals()))

def login_validation(request):
    '''
        View called when the user log in (form submitted)
    '''
    if request.user.is_authenticated:
        config = ConfigPyros(os.environ["PATH_TO_OBSCONF_FILE"])
        observatory_name = config.get_obs_name()
        first_unit_name = config.get_units_name()[0]
        request.session["obsname"] = observatory_name+" "+first_unit_name
        if request.POST.get("next"):
            return redirect(request.POST.get('next'))
        # initiate variable session for telling which role the user is using if this user has multiple roles
        # default role is the role with maximum priority
        request.session["role"] = str(UserLevel.objects.get(priority=request.user.get_priority()))
        return redirect(reverse("index"))
    username = password = ''
    if request.POST:
        email = request.POST.get('email')
        password = request.POST.get('password')
        try:
            is_user_active = PyrosUser.objects.get(username=email).is_active
        except:
            is_user_active = None
        user = authenticate(username=email, password=password)
        if user is not None:
            success = False
            if user.is_active:
                login(request, user)
                request.session['user'] = email
                message = "Oui"
                success = True
                # initiate variable session for telling which role the user is using if this user has multiple roles
                # default role is the role with maximum priority
                request.session["role"] = str(UserLevel.objects.get(priority=request.user.get_priority()))
                if request.POST.get("next"):
                    return redirect(request.POST.get('next'))
                return redirect(reverse("index"))
            else:
                message = "Your account is not active, please contact the Unit-PI."
        else:
            if is_user_active != None and not is_user_active:
                message = "Your account is not active, please contact the Unit-PI."
            elif is_user_active or is_user_active == None:
                message = "Your email and/or password were incorrect."
            
    else:
        message = "An unexpected error has occurred"
    error = True
    return(render(request, "user_manager/home_login.html", locals()))


@login_required
def superoperator_return(request):
    current_user = request.user
    return(render(request, "user_manager/user_detail.html", {'user': current_user, 'admin': 0}))

@login_required
def user_logout(request):
    '''
        View called to log out. Redirects on login page.
    '''

    logout(request)
    config = ConfigPyros(os.environ["PATH_TO_OBSCONF_FILE"])
    observatory_name = config.get_obs_name()
    first_unit_name = config.get_units_name()[0]
    request.session["obsname"] = observatory_name+" "+first_unit_name
    return(render(request, LOGGED_PAGE, {'USER_LEVEL' :  "Visitor", 'base_template' : 'base.html', 'weather_img': "red"}))

def user_signin(request):
    return(render(request, "user_manager/home_login.html",{"next": request.GET.get("next")}))


@login_required
@level_required("Admin","Unit-PI")
def delete_user(request,pk):
    user_to_be_deleted = get_object_or_404(PyrosUser,pk=pk)
    if request.user != user_to_be_deleted and request.method == "POST":
        user_to_be_deleted.delete()
        return HttpResponseRedirect(reverse('users'))
    else:
        return HttpResponseRedirect(reverse("user_detail",kwargs={"pk":pk}))


@login_required
@level_required("Admin","Observer","Management","Operator","Unit-PI","TAC","Unit board")
def users(request):
    current_user = request.user
    pyros_users_with_roles = []
    admin_and_unit_users = []
    inactive_pyros_users = None
    common_scientific_programs = None
    if request.session.get("role"):
        role = request.session.get("role")
    else:
        role = current_user.get_priority()
    if role in "Admin,Unit-PI,Unit board":
        pyros_users_with_roles = PyrosUser.objects.exclude(is_active=False).order_by("-id")
        inactive_pyros_users = PyrosUser.objects.filter(is_active=False).order_by("-id")
    else:
        sp_of_current_user = SP_Period_User.objects.filter(user=current_user)
        common_scientific_programs = sp_of_current_user
        for sp in sp_of_current_user:
            for user in SP_Period_User.objects.filter(SP_Period=sp.SP_Period).exclude(user=current_user).values_list("user",flat=True):
                pyros_users_with_roles.append(PyrosUser.objects.get(id=user))
            pyros_users_with_roles.append(sp.SP_Period.scientific_program.sp_pi)
        admin_and_unit_users = PyrosUser.objects.filter(user_level__name__in=("Unit-PI","Unit-board","Admin")).distinct()
    nb_of_scientific_program = ScientificProgram.objects.count()
    CAN_ADD_USER = request.session.get("role") in ("Admin,Unit-PI,Unit board")
    # need the negative to calculate in the template for adjusting correctly the information display
    negative_nb_scientific_program = -nb_of_scientific_program
    return render(request, 'user_manager/users_management.html', {
        'pyros_users_with_roles': pyros_users_with_roles,
        "inactive_pyros_users":inactive_pyros_users,
        "nb_of_scientific_program": nb_of_scientific_program,
        "negative_nb_scientific_program":negative_nb_scientific_program,
        "common_scientific_programs":common_scientific_programs,
        "admin_and_unit_users": admin_and_unit_users,
        "CAN_ADD_USER": CAN_ADD_USER
    })                     

@login_required
@level_required("Admin","Unit-PI","Unit board")
def change_activate(request, pk, current_user_id):
    role = None
    if request.session.get("role") != None:
        role = request.session.get("role")
    else:
        role = UserLevel.objects.get(priority=request.user.get_priority()).name
    if role in ["Admin","Unit-PI","Unit board"]:
        try :
            user = get_object_or_404(PyrosUser, pk=pk)
            user.is_active = not user.is_active
            text_mail = ""
            text_object = ""
            if (user.first_time == False and user.is_active == True):
                user.first_time = True
                text_mail = "Hi,\n\nCongratulations, your registration has been approved by the PI. Welcome to the PyROS Control Center.\nIn order to submit observation sequences, you need to be associated to a scientific program.\n\nCordially,\n\nPyROS Control Center"
                text_object = "[PyROS CC] Welcome"
                user.validator = get_object_or_404(PyrosUser,pk=current_user_id)
                send_mail(text_object, text_mail, '', [user.email], fail_silently=False,)

            # We're not sending an email if the account has been desactivated or re-activated 
            # elif (user.is_active == True):
            #     text_mail = "Hi,\n\nYour account on the PyROS Control Center have been re-activated.\n\nCordially,\n\nPyROS Control Center"
            #     text_object = "[PyROS CC] Re-activation"
            # else :
            #     text_mail = "Hi,\n\nYour account on the PyROS Control Center have benn desactivated. Please contact the PI for futher information.\n\nCordially,\n\nPyROS Control Center"
            #     text_object = "[PyROS CC] Desactivation"
            
            user.save()
            
            return redirect('user_detail', pk=pk)
        except PyrosUser.DoesNotExist:
            return redirect('user_detail', pk=pk)
    else:
        return redirect("user_detail",pk=pk)
@login_required
#@level_required("Admin","Observer","Management","Operator","Unit-PI","TAC","Unit board")
def user_detail_view(request,pk):
    try:
        is_last_user = PyrosUser.objects.count() == 1
        user=PyrosUser.objects.get(pk=pk)
        current_user = request.user
        roles = current_user.get_list_of_roles()
        sp_periods = SP_Period_User.objects.filter(user=user)
        CAN_VIEW_VALIDATOR = request.user.id == pk or request.session.get("role") in ("Admin","Unit-PI","Unit-board")
        CAN_DELETE_USER = not is_last_user and request.session.get("role") in ("Admin","Unit-PI","Unit-board") and not user.is_superuser and request.user != user
        CAN_ACTIVATE_USER = not is_last_user and request.session.get("role") in ("Admin","Unit-PI","Unit-board") and not user.is_superuser and request.user != user
        CAN_EDIT_USER = request.user.id == pk or request.session.get("role") in ("Admin","Unit-PI","Unit-board")
        CAN_VIEW_MOTIVE_OF_REGISTRATION =  request.session.get("role") in ("Admin","Unit-PI","Unit-board") and len(user.motive_of_registration) > 0 
        scientific_programs = []
        for sp_period in sp_periods:
            
            scientific_programs.append(sp_period.SP_Period.scientific_program)
    except PyrosUser.DoesNotExist:
        raise Http404("User does not exist")
    return render(request, 'user_manager/user_detail.html', context={
        'user' : user,
        'current_user' : current_user,
        'is_last_user' : is_last_user,
        "roles" : roles,
        "scientific_programs":scientific_programs,
        "CAN_VIEW_VALIDATOR": CAN_VIEW_VALIDATOR,
        "CAN_DELETE_USER": CAN_DELETE_USER,
        "CAN_ACTIVATE_USER": CAN_ACTIVATE_USER,
        "CAN_EDIT_USER": CAN_EDIT_USER,
        "CAN_VIEW_MOTIVE_OF_REGISTRATION":CAN_VIEW_MOTIVE_OF_REGISTRATION
    })

@login_required
@level_required()
def user_detail_edit(request,pk):
    if request.session.get("role"):
        role = request.session.get("role")
    else:
        role = request.user.get_priority()
    # If its not his user profile or user isn't Unit-PI, Unit board, Admin or SP-PI, He can't edit this user profile and he is redirected to home page
    if (request.user.id != pk and role not in ("Admin","Unit-PI","Unit board") ):
        return HttpResponseRedirect(reverse('index'))
    edit = get_object_or_404(PyrosUser, pk=pk)
    is_sp_pi = ScientificProgram.objects.filter(sp_pi=edit).count() > 0
    form = UserForm(request.POST or None, instance=edit)
    CAN_EDIT_ROLE = request.session.get("role") in ("Admin","Unit-PI","Unit-board")
    CAN_EDIT_INSTITUTE = request.session.get("role") in ("Admin","Unit-PI","Unit-board")
    CAN_EDIT_REFEREE_THEME = request.session.get("role") != "Visitor"
    # creating list of roles for the formular excluding visitor of the list
    roles = UserLevel.objects.exclude(name="Visitor")
    if request.POST and form.is_valid():
        obj = form.save(commit=False)
        if(len(request.POST.getlist("roles"))>0):
            if("Admin" in request.POST.getlist("roles")):
                # if Admin role has been assigned, add the authorisations to access to django admin pages
                obj.is_staff = True
                obj.is_admin = True
                obj.is_superuser = True
            else:
                # just in case (for example, if user was previously an admin and has been downgraded) we're removing those authorisations 
                obj.is_staff = False
                obj.is_admin = False
            obj.user_level.set(request.POST.getlist("roles"))
        else:
            # No role has been assigned, so the user has the Visitor role
            obj.user_level.set([UserLevel.objects.get(name="Visitor")])
        if(len(request.POST.getlist("referee_themes"))>0):
            obj.referee_themes.set(request.POST.getlist("referee_themes"))
        else:
            obj.referee_themes.set([])
        obj.save()
        if request.user == obj:
            request.session["role"] = UserLevel.objects.get(priority=request.user.get_priority()).name

        return redirect('user_detail', pk=pk)
    return render(request, 'user_manager/user_detail_edit.html', {
        'form': form,
        "roles":roles,
        "pk":pk,
        "user_edit":edit,
        "is_sp_pi":is_sp_pi,
        "CAN_EDIT_ROLE": CAN_EDIT_ROLE,
        "CAN_EDIT_INSTITUTE": CAN_EDIT_INSTITUTE,
        "CAN_EDIT_REFEREE_THEME": CAN_EDIT_REFEREE_THEME
    })


def set_active_role(request):
    previous_active_role = request.session.get("role")
    if request.user.is_authenticated:
        if request.POST.get("role"):
            request.session["role"] = str(UserLevel.objects.get(name=request.POST.get("role")))
            if(previous_active_role is not None and previous_active_role != request.session.get("role")):
                messages.success(request,f"Role changed from {previous_active_role} to {request.session.get('role')}")
                text_reponse = f'<div class="alert alert-info alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>\
                Role changed from {previous_active_role} to {request.session.get("role")}</div>'
                return HttpResponse(text_reponse)