views.py 15.4 KB
from django.http import HttpResponse
from django.shortcuts import render, redirect

from django.contrib.auth.decorators import login_required
import datetime
from common.models import Log, WeatherWatch, SiteWatch, ScientificProgram, Config, PyrosUser, PlcDeviceStatus
from django.core import serializers
import utils.Logger as l
from django.forms import modelformset_factory
from dashboard.forms import ConfigForm, UserForm
from dashboard.decorator import level_required
from django.views.generic.edit import UpdateView
from django.shortcuts import get_object_or_404
from django.utils.decorators import method_decorator
from django.urls import reverse_lazy, reverse
from django.http import Http404
import json
from random import randint
from devices.Telescope import TelescopeController
from devices.TelescopeRemoteControlDefault import TelescopeRemoteControlDefault
from django.core.mail import send_mail
import time
import utils.celme as celme

SUN_ELEV_DAY_THRESHOLD = -10

log = l.setupLogger("dashboard", "dashboard")

def index(request):
    if request.user.is_authenticated:
        return render(request, 'dashboard/index.html', {'USER_LEVEL': request.user.user_level.priority, 'base_template' : "base.html"})                              # return the initial view (the dashboard's one)
    return render(request, 'dashboard/index.html', {'USER_LEVEL': 0, 'base_template' : "base_unlogged.html"})                              # return the initial view (the dashboard's one)

def retrieve_env(request):
    '''
        TODO: integrate Alain's code do determine day/night with sunelev and switch to utc time when the plc will use it
    '''
    try:
        weather_status = WeatherWatch.objects.latest('updated')
        plc_device_status = PlcDeviceStatus.objects.exclude(plc_mode=None).latest('created')
        plc_timeout = Config.objects.get(pk=1).plc_timeout_seconds
        timeout = (datetime.datetime.now() - plc_device_status.created).total_seconds()
        timeout_affichage = datetime.datetime.now() - datetime.timedelta(seconds=timeout)
        sunelev = get_sunelev()
        t = datetime.datetime.now() + datetime.timedelta(hours=-7)
        isDay = False
        if sunelev >= SUN_ELEV_DAY_THRESHOLD:
            isDay = True
        return render(request, 'dashboard/observation_status_env.html', locals())
    except WeatherWatch.DoesNotExist:
            raise Http404("No WeatherWatch matches the given query.")


'''
        Function that call celme code to determine sun elevation, maybe it should be moved somewhere else ?
'''

def get_sunelev():
    date = celme.dates.Date("now")
    site = celme.Site("MPC 244.5367  0.85792  +0.51292") # coords of san pedro martir site
    skyobj= {'planet':'Sun'}
    outputs = ['name','ra','dec','elev']

    target = celme.Target()
    target.define(skyobj)
    output0s = ['ra','dec']
    results = target.ephem(date,site,output0s)
    ra = results['RA']
    dec = results['DEC']
    skyobj= {'RA':ra , 'DEC':dec }
    target.define(skyobj)
    results = target.ephem(date,site,outputs)
    elev = round(results['ELEV'],2)
    return elev

def retrieve_env_navbar(request):
    if request.is_ajax():
        try:
            weather_status = WeatherWatch.objects.latest('updated')
            plc_device_status = PlcDeviceStatus.objects.exclude(plc_mode=None).latest('created')
            plc_mode = plc_device_status.plc_mode
            is_safe = plc_device_status.is_safe
            weather = serializers.serialize('json', [weather_status])
            weather = json.loads(weather)
            ack = Config.objects.get(id=1).ack
            plc_timeout = Config.objects.get(pk=1).plc_timeout_seconds
            timeout = (datetime.datetime.now() - plc_device_status.created).total_seconds()
            weather[0]['max_sunelev'] = SUN_ELEV_DAY_THRESHOLD
            weather[0]['sunelev'] = get_sunelev()
            weather[0]["plc_mode"] = plc_mode
            weather[0]["is_safe"] = is_safe
            weather[0]["ACK"] = ack
            weather[0]["plc_timeout"] = timeout
            weather[0]["max_plc_timeout"] = plc_timeout
            return HttpResponse(json.dumps(weather), content_type="application/json")
        except WeatherWatch.DoesNotExist:
            raise Http404("No WeatherWatch matches the given query.")

def retrieve_main_icon(request):
    if request.is_ajax():
        try:
            weather_status = WeatherWatch.objects.latest('updated')
            plc_mode = PlcDeviceStatus.objects.exclude(plc_mode=None).latest('created').plc_mode

            weather = serializers.serialize('json', [weather_status])
            weather = json.loads(weather)
            weather[0]["plc_mode"] = plc_mode

            return HttpResponse(json.dumps(weather), content_type="application/json")
        except WeatherWatch.DoesNotExist:
            raise Http404("No WeatherWatch matches the given query.")

@login_required
@level_required(6)
def users(request):
    instance = PyrosUser.objects.order_by("-id")
    return render(request, 'dashboard/users_management.html', {'instance': instance})                     # return the initial view (the users management's one) 

@login_required
@level_required(2)
def routines(request):
    url_ = reverse('admin:common_request_changelist')
    return redirect(url_)

def weather(request):
    if request.user.is_authenticated:
        return render(request, 'dashboard/reload_weather.html', {'base_template' : "base.html"})                                                                     # return the needed html file
    return render(request, 'dashboard/reload_weather.html', {'base_template' : "base_unlogged.html"})

def weather_current(request):
    try:
        if (len(Config.objects.all()) == 1):
            monitoring = int(int(Config.objects.get(id=1).row_data_save_frequency) / 5)
        else:
            monitoring = 60
        if (len(WeatherWatch.objects.all()) > 0):
            weather_info = WeatherWatch.objects.order_by("-id")[:monitoring]                                                            # Use 300 seconds by default with an iteration every 5 seconds                                                                                     # Get the number of data available
        else:                                                                                                                           
            weather_info = None
        return render(request, 'dashboard/current_weather.html', {'weather_info' : weather_info, 'iteration' : monitoring})
    except Config.DoesNotExist:
        return render(request, 'dashboard/current_weather.html', {'weather_info' : None, 'iteration' : 60})

def site(request):
    if request.user.is_authenticated:
        return render(request, 'dashboard/reload_site.html', {'base_template' : "base.html"})                        # return the needed html file
    return render(request, 'dashboard/reload_site.html', {'base_template' : "base_unlogged.html"})                        # return the needed html file

def site_current(request):
    try:
        if (len(Config.objects.all()) == 1):
            monitoring = int(int(Config.objects.get(id=1).row_data_save_frequency) / 5)
        else:
            monitoring = 60
        if (len(SiteWatch.objects.all()) > 0):
            site_info = SiteWatch.objects.order_by("-id")[:monitoring]                                                               
        else:                                                                                                                           
            site_info = None
        return render(request, 'dashboard/current_site.html', {'site_info' : site_info, 'iteration' : monitoring})
    except Config.DoesNotExist:
        return render(request, 'dashboard/current_site.html', {'site_info' : None, 'iteration' : 60})

@login_required
@level_required(2)
def proposal(request):
    if (len(ScientificProgram.objects.all()) > 0):                              # checking if the observatory table is empty
        proposal_info = ScientificProgram.objects.order_by("-id")[:100]         # Sorting Weather table
        nb_info_proposal = len(proposal_info)                                   # Get the number of data available

    else:                                                                       # if empty set everything to 0 / None (variables are checked in src/templates/scheduler/current_weather.html)
        proposal_info = None
        nb_info_proposal = 0

    return render(request, 'dashboard/proposal.html', {'proposal_info' : proposal_info, 'nb_info_proposal' : nb_info_proposal})

@login_required
@level_required(5)
def configUpdate(request):
    instance = get_object_or_404(Config, id=1)
    form = ConfigForm(request.POST or None, instance=instance)
    if form.is_valid():
        form.save()
        return redirect('../user_manager/profile')
    return render(request, 'dashboard/configuration.html', {'form': form}) 
    

@login_required
def devices(request):
    url_ = reverse('admin:common_device_changelist')
    return redirect(url_)

@login_required
def system(request):
    return render(request, 'dashboard/system.html')

@login_required
def system_retrieve_logs(request):
    '''
        Called by the dashboard system page with ajax request every seconds, to get the logs and print them
    '''
    if request.is_ajax():
        alert_logs = Log.objects.filter(agent='Alert manager')
        scheduler_logs = Log.objects.filter(agent='Scheduler')
        majordome_logs = Log.objects.filter(agent='Majordome')
        obs_logs = Log.objects.filter(agent='Observation manager')
        analyzer_logs = Log.objects.filter(agent='Analyzer')
        monitoring_logs = Log.objects.filter(agent='Monitoring')
        return render(request, 'dashboard/system_logs.html', locals())


def schedule(request):
    url_ = reverse('admin:common_schedule_changelist')
    return redirect(url_)


@login_required
@level_required(6)
def quotas(request):
    url_ = reverse('admin:common_pyrosuser_changelist')
    return redirect(url_)

@login_required
@level_required(3)
def change_globalMode(request):
    try :
        config = get_object_or_404(Config, id=1)
        plc_device_status = PlcDeviceStatus.objects.exclude(plc_mode=None).latest('created')
        if config.global_mode == False and plc_device_status.is_safe == False:
            return redirect('states')
        config.global_mode = not config.global_mode
        config.save()
        return redirect('states')
    except Config.DoesNotExist:
        return redirect('states')

@login_required
@level_required(4)
def change_bypass(request):
    try :
        config = get_object_or_404(Config, id=1)
        plc_device_status = PlcDeviceStatus.objects.exclude(plc_mode=None).latest('created')
        if plc_device_status.is_safe == True:
            return redirect('states')
        config.bypass = not config.bypass
        config.save()
        return redirect('states')
    except Config.DoesNotExist:
        return redirect('states')

@login_required
@level_required(3)
def change_lock(request):
    try :
        config = get_object_or_404(Config, id=1)
        plc_device_status = PlcDeviceStatus.objects.exclude(plc_mode=None).latest('created')
        if config.lock == False and plc_device_status.is_safe == False:
            return redirect('states')
        config.lock = not config.lock
        config.save()
        return redirect('states')
    except Config.DoesNotExist:
        return redirect('states')

@login_required
@level_required(6)
def change_activate(request, pk):
    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 approuved by the PI. Welcome to the Colibri Control Center.\n\nCordialy,\n\nColibri Control Center"
            text_object = "[COLIBRI CC] Welcome"
        elif (user.is_active == True):
            text_mail = "Hi,\n\nYour account on the Colibri Control Center have been re-activated.\n\nCordialy,\n\nColibri Control Center"
            text_object = "[COLIBRI CC] Re-activation"
        else :
            text_mail = "Hi,\n\nYour account on the Colibri Control Center have benn desactivated. Please contact the PI for futher information.\n\nCordialy,\n\nColibri Control Center"
            text_object = "[COLIBRI CC] Desactivation"
        user.save()
        send_mail(text_object, text_mail, '', [user.email], fail_silently=False,)
        return redirect('user-detail', pk=pk)
    except PyrosUser.DoesNotExist:
        return redirect('user-detail', pk=pk)

@login_required
@level_required(3)
def send_command_to_telescope(request):
    data = "lol"
    with open('../simulators/config/grammar.json') as f:
        data = json.load(f)
        json_str = json.dumps(data)
    return render(request, "dashboard/send_command_telescope.html", locals())

@login_required
@level_required(3)
def submit_command_to_telescope(request):
    if request.method == 'POST':
        commands = [request.POST.get("first_command"), request.POST.get("first_param")]
        try: #TODO faire un truc plus joli pour gérer les params queqlue soit leur nombre
            input_0 = request.POST.get("input_number_0")
            input_1 = request.POST.get("input_number_1")
            input_2 = request.POST.get("input_number_2")
            if input_0:
                commands.append(input_0)
            if input_1:
                commands.append(input_1)
            if input_2:
                commands.append(input_2)
        except Exception:
            pass
        response = TelescopeRemoteControlDefault(commands, False).exec_command()
        #TODO passer en JS pour send les réponses en  AJAX
    return redirect('send_command_to_telescope')

@login_required
@level_required(3)
def submit_command_to_telescope_expert(request):
    #import os
    if request.method == 'POST':
        param = request.POST.get("commande_expert")
        if param:
            response = TelescopeRemoteControlDefault(param, expert_mode=True).exec_command()
            #os.system("echo \"status :" + response + "\" >> /home/portos/IRAP/pyros/src/status")
            return HttpResponse(json.dumps({'message': "Command send OK", 'response': response}))
        return HttpResponse(json.dumps({'message': "Missing command data"}))
    return redirect('submit_command_to_telescope')

@login_required
@level_required(2)
def user_detail_view(request,pk):
    try:
        user_id=PyrosUser.objects.get(pk=pk)
        current_user = request.user
    except PyrosUser.DoesNotExist:
        raise Http404("User does not exist")
    return render(request, 'dashboard/user_detail.html', context={'user' : user_id, 'current_user' : current_user, 'USER_LEVEL': request.user.user_level.priority})

@login_required
@level_required(6)
def user_detail_edit(request,pk):
    edit = get_object_or_404(PyrosUser, pk=pk)
    form = UserForm(request.POST or None, instance=edit)
    if form.is_valid():
        form.save()
        return redirect('user-detail', pk=pk)
    return render(request, 'dashboard/user_detail_edit.html', {'form': form})

@login_required
@level_required(3)
def operator_state(request):
    instance = get_object_or_404(Config, id=1)
    plc_device_status = PlcDeviceStatus.objects.exclude(plc_mode=None).latest('created')
    return render(request, 'dashboard/operator_state.html', {'config' : instance, 'is_safe' : plc_device_status.is_safe})

@login_required
@level_required(3)
def simulator(request):
    return(render(request, 'dashboard/simulator.html'))