import ast from src.core.pyros_django.obsconfig.obsconfig_class import OBSConfig from .forms import SequenceForm, AlbumForm, PlanForm from common.models import PyrosUser, ScientificProgram, Period from routine_manager.models import Sequence, Album, Plan import datetime import os, yaml def check_sequence_file_validity_and_save(yaml_content,request): is_simplified = yaml_content.get("simplified", False) sp_of_user = request.user.get_scientific_program() sp_list = ScientificProgram.objects.observable_programs().filter(id__in=sp_of_user) seq = Sequence.objects.create() seq.pyros_user = PyrosUser.objects.get(id=request.user.id) unit_name = os.environ["unit_name"] config = OBSConfig(os.environ["PATH_TO_OBSCONF_FILE"], unit_name) sequence_form = SequenceForm(instance=seq, data_from_config=config.getEditableAttributesOfMount(config.unit_name), layouts = config.get_layouts(config.unit_name), sp_list=sp_list) result = { "succeed": True, "errors": [], } if is_simplified: seq.scientific_program = sp_list[yaml_content["sequence"]["scientific_program"]] else: index_value_sp = yaml_content["sequence"]["scientific_program"]["value"] values = yaml_content["sequence"]["scientific_program"]["values"] if index_value_sp < 0 or index_value_sp > len(yaml_content["sequence"]["scientific_program"]["values"]): result["errors"].append(f"Value of scientific program isn't valid, index out of bounds ({index_value_sp} > {len(values)})") index_value_sp = 0 chosen_sp = ScientificProgram.objects.get(name=yaml_content["sequence"]["scientific_program"]["values"][index_value_sp]) if chosen_sp in sp_list: seq.scientific_program = ScientificProgram.objects.get(name=yaml_content["sequence"]["scientific_program"]["values"][index_value_sp]) else: result["errors"].append(f"Scientific program {chosen_sp.name} is not assigned to that user ") seq.config_attributes = {} for field in sequence_form.fields.keys(): if sequence_form.fields[field].required == False or field == "scientific_program": continue if is_simplified: value = yaml_content["sequence"][field] else: value = yaml_content["sequence"][field]["value"] if field not in yaml_content["sequence"]: result["errors"].append(f"{field} not in yaml file") else: if not is_simplified: if yaml_content["sequence"][field].get("values"): index_value = yaml_content["sequence"][field]["value"] values = yaml_content["sequence"][field]["values"] if index_value < 0 or index_value > len(yaml_content["sequence"][field]["values"]): result["errors"].append(f"Value of {field} isn't valid, index out of bounds ({index_value} > {len(values)})") index_value = 0 value = yaml_content["sequence"][field]["values"][index_value] else: if field == "start_date": if type(value) != datetime.datetime: #value = datetime.datetime.strptime(yaml_content["sequence"][field]["value"],'%d/%m/%Y %H:%M:%S') # ISO format value = datetime.datetime.strptime(value, '%Y-%m-%dT%H:%M:%S.%f') seq.__dict__[field] = value else: if sequence_form.fields[field].__dict__.get("_choices"): values = [value[0] for value in sequence_form.fields[field].__dict__.get("_choices")] value = values[value] if field in seq.__dict__.keys(): seq.__dict__[field] = value else: seq.config_attributes[field] = value albums_from_file = yaml_content["sequence"]["ALBUMS"] choosen_layout = seq.config_attributes["layout"] if type(choosen_layout) == int: layouts = config.get_layouts(config.unit_name)["layouts"] choosen_layout = list(layouts.keys())[choosen_layout] albums_of_layout = config.getLayoutByName(unit_name=config.unit_name,name_of_layout=choosen_layout)["ALBUMS"] if len(albums_of_layout) == len(albums_from_file): for album in albums_from_file: album = album["Album"] if album["name"] not in albums_of_layout: result["errors"].append(f"Album {album['name']} is not the chosen layout") else: alb = Album.objects.create(name=album["name"], sequence=seq, complete=True) else: result["errors"].append(f"The number of albums doesn't correspond to the chosen layout") for album in yaml_content["sequence"]["ALBUMS"]: album = album["Album"] plans = album.get("Plans") if plans == None: result["errors"].append(f"Album {album['name']} has no plans. Please add at least one plan") else: for plan in plans: new_plan_object = Plan.objects.create(album=Album.objects.get(name=album["name"],sequence=seq),complete=True) new_plan_object.config_attributes = {} plan = plan["Plan"] config_attributes = {} plan_form = PlanForm(data_from_config=config.getEditableAttributesOfChannel(config.unit_name,list(config.get_channels(config.unit_name).keys())[0]),edited_plan=None) for field in plan_form.fields: min_value = None max_value = None value_type = None if field not in plan.keys(): result["errors"].append(f"Missing field : '{field}' for plan {plans.index(plan)}") else: # TODO : ajouter max_value, min_value, suppression plan et album si invalides if not is_simplified: if plan[field].get("value_type"): value_type = plan[field]["value_type"] if type(plan[field]["value"]) == str and ast.literal_eval(plan[field]["value"]) != value_type: result["errors"].append(f"Field {field} value doesn't correspond to the assigned type (type required : {value_type})") if plan[field].get("min_value"): if type(plan[field]["min_value"]) == str: min_value = ast.literal_eval(plan[field]["min_value"]) else: min_value = plan[field]["min_value"] if plan[field].get("max_value"): if type(plan[field].get("max_value")) == str: max_value = ast.literal_eval(plan[field]["max_value"]) else: max_value = plan[field]["max_value"] if field == "nb_images": if is_simplified: new_plan_object.__dict__[field] = plan[field] else: new_plan_object.__dict__[field] = plan[field]["value"] else: if not is_simplified: if plan[field].get("values"): index_value = plan[field]["value"] values = plan[field]["values"] if index_value < 0 or index_value > len(plan[field]["values"]): result["errors"].append(f"Value of Plan field '{field}' isn't valid, index out of bounds ({index_value} > {len(values)})") index_value = 0 value = plan[field]["values"][index_value] try: # linked values splitted_values = value.split(";") config_attributes[field] = {} for splitted_value in splitted_values: subkey,subvalue = splitted_value.split(":") config_attributes[field][subkey] = ast.literal_eval(subvalue) except: # Do nothing, normal string config_attributes[field] = ast.literal_eval(value) new_plan_object.config_attributes[field] = config_attributes[field] else: if max_value and min_value: if plan[field]["value"] > max_value: result["errors"].append(f"Plan field {field} doesn't respect max value") if plan[field]["value"] < min_value: result["errors"].append(f"Plan field {field} doesn't respect min value") new_plan_object.config_attributes[field] = plan[field]["value"] else: new_plan_object.config_attributes[field] = plan[field] new_plan_object.save() seq.status = Sequence.TOBEPLANNED seq.complete = True period = Period.objects.exploitation_period() if Period.objects.next_period() != None and Period.objects.next_period().start_date < seq.start_date.date(): period = Period.objects.next_period() seq.period = period seq.save() if len(result["errors"]) != 0: result["succeed"] = False seq.delete() else: result["sequence_id"] = seq.id return result