def handle(self, *args, **kwargs): cadenced_groups = DynamicCadence.objects.filter(active=True) updated_cadences = [] for cg in cadenced_groups: strategy = get_cadence_strategy(cg.cadence_strategy)(cg) new_observations = strategy.run() if not new_observations: logger.log(msg=f'No changes from dynamic cadence {cg}', level=logging.INFO) else: logger.log( msg=f'''Cadence update completed for dynamic cadence {cg}, {len(new_observations)} new observations created.''', level=logging.INFO) updated_cadences.append(cg.observation_group) if updated_cadences: msg = 'Created new observations for dynamic cadences with observation groups: {0}.' return msg.format(', '.join([str(cg) for cg in updated_cadences])) else: return 'No new observations for any dynamic cadences.'
def form_valid(self, form): """ Runs after form validation. Submits the observation to the desired facility and creates an associated ``ObservationRecord``, then redirects to the detail page of the target to be observed. If the facility returns more than one record, a group is created and all observation records from the request are added to it. :param form: form containing observating request parameters :type form: subclass of GenericObservationForm """ # Submit the observation facility = self.get_facility_class() target = self.get_target() observation_ids = facility().submit_observation( form.observation_payload()) records = [] for observation_id in observation_ids: # Create Observation record record = ObservationRecord.objects.create( target=target, user=self.request.user, facility=facility.name, parameters=form.serialize_parameters(), observation_id=observation_id) records.append(record) # TODO: redirect to observation list for multiple observations, observation detail otherwise if len(records) > 1 or form.cleaned_data.get('cadence_strategy'): observation_group = ObservationGroup.objects.create( name=form.cleaned_data['name']) observation_group.observation_records.add(*records) assign_perm('tom_observations.view_observationgroup', self.request.user, observation_group) assign_perm('tom_observations.change_observationgroup', self.request.user, observation_group) assign_perm('tom_observations.delete_observationgroup', self.request.user, observation_group) # TODO: Add a test case that includes a dynamic cadence submission if form.cleaned_data.get('cadence_strategy'): cadence_parameters = {} cadence_form = get_cadence_strategy( form.cleaned_data.get('cadence_strategy')).form for field in cadence_form().cadence_fields: cadence_parameters[field] = form.cleaned_data.get(field) DynamicCadence.objects.create( observation_group=observation_group, cadence_strategy=form.cleaned_data.get('cadence_strategy'), cadence_parameters=cadence_parameters, active=True) if not settings.TARGET_PERMISSIONS_ONLY: groups = form.cleaned_data['groups'] for record in records: assign_perm('tom_observations.view_observationrecord', groups, record) assign_perm('tom_observations.change_observationrecord', groups, record) assign_perm('tom_observations.delete_observationrecord', groups, record) return redirect(reverse('tom_targets:detail', kwargs={'pk': target.id}))
def get_cadence_strategy_form(self): cadence_strategy = self.request.GET.get('cadence_strategy') if not cadence_strategy: return CadenceForm return get_cadence_strategy(cadence_strategy).form
def create(self, request, *args, **kwargs): """ Endpoint for submitting a new observation. Please see ObservationRecordViewSet for details on submission. """ # Initialize the observation form, validate the form data, and submit to the observatory observation_ids = [] try: facility = get_service_class(self.request.data['facility'])() observation_form_class = facility.observation_forms[ self.request.data['observation_type']] target = Target.objects.get(pk=self.request.data['target_id']) observing_parameters = self.request.data['observing_parameters'] except KeyError as ke: raise ValidationError(f'Missing required field {ke}.') except Exception as e: raise ValidationError(e) observing_parameters.update({ k: v for k, v in self.request.data.items() if k in ['name', 'target_id', 'facility'] }) observation_form = observation_form_class( self.request.data['observing_parameters']) if observation_form.is_valid(): logger.info( f'Submitting observation to {facility} with parameters {observation_form.observation_payload}' ) observation_ids = facility.submit_observation( observation_form.observation_payload()) logger.info( f'Successfully submitted to {facility}, received observation ids {observation_ids}' ) else: logger.warning( f'Unable to submit observation due to errors: {observation_form.errors}' ) raise ValidationError(observation_form.errors) # Normally related objects would be created in the serializer--however, because the ObservationRecordSerializer # may need to create multiple objects that are related to the same ObservationGroup and DynamicCadence, we are # creating the related objects in the ViewSet. cadence = self.request.data.get('cadence') observation_group = None if len(observation_ids) > 1 or cadence: # Create the observation group and assign permissions observation_group_name = observation_form.cleaned_data.get( 'name', f'{target.name} at {facility.name}') observation_group = ObservationGroup.objects.create( name=observation_group_name) assign_perm('tom_observations.view_observationgroup', self.request.user, observation_group) assign_perm('tom_observations.change_observationgroup', self.request.user, observation_group) assign_perm('tom_observations.delete_observationgroup', self.request.user, observation_group) logger.info(f'Created ObservationGroup {observation_group}.') cadence_parameters = cadence if cadence_parameters is not None: # Cadence strategy is not used for the cadence form cadence_strategy = cadence_parameters.pop( 'cadence_strategy', None) if cadence_strategy is None: raise ValidationError( 'cadence_strategy must be included to initiate a DynamicCadence.' ) else: # Validate the cadence parameters against the cadence strategy that gets passed in cadence_form_class = get_cadence_strategy( cadence_strategy).form cadence_form = cadence_form_class(cadence_parameters) if cadence_form.is_valid(): dynamic_cadence = DynamicCadence.objects.create( observation_group=observation_group, cadence_strategy=cadence_strategy, cadence_parameters=cadence_parameters, active=True) logger.info( f'Created DynamicCadence {dynamic_cadence}.') else: observation_group.delete() raise ValidationError(cadence_form.errors) # Create the serializer data used to create the observation records serializer_data = [] for obsr_id in observation_ids: obsr_data = { # TODO: at present, submitted fields have to be added to this dict manually, maybe fix? 'name': self.request.data.get('name', ''), 'target': target.id, 'user': self.request.user.id, 'facility': facility.name, 'groups': self.request.data.get('groups', []), 'parameters': observation_form.serialize_parameters(), 'observation_id': obsr_id, } serializer_data.append(obsr_data) serializer = self.get_serializer(data=serializer_data, many=True) try: # Validate the serializer data, create the observation records, and add them to the group, if necessary serializer.is_valid(raise_exception=True) self.perform_create(serializer) if observation_group is not None: observation_group.observation_records.add(*serializer.instance) except ValidationError as ve: observation_group.delete() logger.error( f'Failed to create ObservationRecord due to exception {ve}') raise ValidationError( f'''Observation submission successful, but failed to create a corresponding ObservationRecord due to exception {ve}.''' ) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)