Esempio n. 1
0
    def put(self, instrument_id):
        """
        ---
        description: Update instrument
        tags:
          - instruments
        parameters:
          - in: path
            name: instrument_id
            required: true
            schema:
              type: integer
        requestBody:
          content:
            application/json:
              schema: InstrumentNoID
        responses:
          200:
            content:
              application/json:
                schema: Success
          400:
            content:
              application/json:
                schema: Error
        """
        data = self.get_json()
        data['id'] = int(instrument_id)

        # permission check
        instrument = Instrument.get_if_accessible_by(
            int(instrument_id), self.current_user, mode='update'
        )
        if instrument is None:
            return self.error(f'Missing instrument with ID {instrument_id}')

        filters = instrument.filters
        sensitivity_data = data.get('sensitivity_data', None)
        if sensitivity_data:
            if not set(sensitivity_data.keys()).issubset(filters):
                return self.error(
                    'Filter names must be present in both sensitivity_data property and filters property'
                )

        field_data = data.pop("field_data", None)
        field_region = data.pop("field_region", None)

        field_fov_type = data.pop("field_fov_type", None)
        field_fov_attributes = data.pop("field_fov_attributes", None)

        if (field_region is not None) and (field_fov_type is not None):
            return self.error('must supply only one of field_region or field_fov_type')

        if field_region is not None:
            regions = Regions.parse(field_region, format='ds9')
            data['region'] = regions.serialize(format='ds9')

        if field_fov_type is not None:
            if field_fov_attributes is None:
                return self.error(
                    'field_fov_attributes required if field_fov_type supplied'
                )
            if not field_fov_type.lower() in ["circle", "rectangle"]:
                return self.error('field_fov_type must be circle or rectangle')
            if isinstance(field_fov_attributes, list):
                field_fov_attributes = [float(x) for x in field_fov_attributes]
            else:
                field_fov_attributes = [float(field_fov_attributes)]

            center = SkyCoord(0.0, 0.0, unit='deg', frame='icrs')
            if field_fov_type.lower() == "circle":
                if not len(field_fov_attributes) == 1:
                    return self.error(
                        'If field_fov_type is circle, then should supply only radius for field_fov_attributes'
                    )
                radius = field_fov_attributes[0]
                regions = CircleSkyRegion(center=center, radius=radius * u.deg)
            elif field_fov_type.lower() == "rectangle":
                if not len(field_fov_attributes) == 2:
                    return self.error(
                        'If field_fov_type is rectangle, then should supply width and height for field_fov_attributes'
                    )
                width, height = field_fov_attributes
                regions = RectangleSkyRegion(
                    center=center, width=width * u.deg, height=height * u.deg
                )
            data['region'] = regions.serialize(format='ds9')

        schema = Instrument.__schema__()
        try:
            schema.load(data, partial=True)
        except ValidationError as exc:
            return self.error(
                'Invalid/missing parameters: ' f'{exc.normalized_messages()}'
            )
        self.verify_and_commit()

        if field_data is not None:
            if (field_region is None) and (field_fov_type is None):
                return self.error(
                    'field_region or field_fov_type is required with field_data'
                )

            if type(field_data) is str:
                field_data = pd.read_table(StringIO(field_data), sep=",").to_dict(
                    orient='list'
                )

            if not {'ID', 'RA', 'Dec'}.issubset(field_data):
                return self.error("ID, RA, and Dec required in field_data.")

            log(f"Started generating fields for instrument {instrument.id}")
            # run async
            IOLoop.current().run_in_executor(
                None,
                lambda: add_tiles(instrument.id, instrument.name, regions, field_data),
            )

        self.push_all(action="skyportal/REFRESH_INSTRUMENTS")
        return self.success()
Esempio n. 2
0
    def post(self):
        # See bottom of this file for redoc docstring -- moved it there so that
        # it could be made an f-string.

        data = self.get_json()
        telescope_id = data.get('telescope_id')
        telescope = Telescope.get_if_accessible_by(
            telescope_id, self.current_user, raise_if_none=True, mode="read"
        )

        sensitivity_data = data.get("sensitivity_data", None)
        if sensitivity_data:
            filters = data.get("filters", [])
            if not set(sensitivity_data.keys()).issubset(filters):
                return self.error(
                    'Sensitivity_data filters must be a subset of the instrument filters'
                )

        field_data = data.pop("field_data", None)
        field_region = data.pop("field_region", None)

        field_fov_type = data.pop("field_fov_type", None)
        field_fov_attributes = data.pop("field_fov_attributes", None)

        if (field_region is not None) and (field_fov_type is not None):
            return self.error('must supply only one of field_region or field_fov_type')

        if field_region is not None:
            regions = Regions.parse(field_region, format='ds9')
            data['region'] = regions.serialize(format='ds9')

        if field_fov_type is not None:
            if field_fov_attributes is None:
                return self.error(
                    'field_fov_attributes required if field_fov_type supplied'
                )
            if not field_fov_type.lower() in ["circle", "rectangle"]:
                return self.error('field_fov_type must be circle or rectangle')
            if isinstance(field_fov_attributes, list):
                field_fov_attributes = [float(x) for x in field_fov_attributes]
            else:
                field_fov_attributes = [float(field_fov_attributes)]

            center = SkyCoord(0.0, 0.0, unit='deg', frame='icrs')
            if field_fov_type.lower() == "circle":
                if not len(field_fov_attributes) == 1:
                    return self.error(
                        'If field_fov_type is circle, then should supply only radius for field_fov_attributes'
                    )
                radius = field_fov_attributes[0]
                regions = CircleSkyRegion(center=center, radius=radius * u.deg)
            elif field_fov_type.lower() == "rectangle":
                if not len(field_fov_attributes) == 2:
                    return self.error(
                        'If field_fov_type is rectangle, then should supply width and height for field_fov_attributes'
                    )
                width, height = field_fov_attributes
                regions = RectangleSkyRegion(
                    center=center, width=width * u.deg, height=height * u.deg
                )
            data['region'] = regions.serialize(format='ds9')

        schema = Instrument.__schema__()
        try:
            instrument = schema.load(data)
        except ValidationError as exc:
            return self.error(
                'Invalid/missing parameters: ' f'{exc.normalized_messages()}'
            )

        existing_instrument = (
            Instrument.query_records_accessible_by(
                self.current_user,
            )
            .filter(
                Instrument.name == data.get('name'),
                Instrument.telescope_id == telescope_id,
            )
            .first()
        )
        if existing_instrument is None:
            instrument.telescope = telescope
            DBSession().add(instrument)
            DBSession().commit()
        else:
            instrument = existing_instrument

        if field_data is not None:
            if (field_region is None) and (field_fov_type is None):
                return self.error(
                    'field_region or field_fov_type is required with field_data'
                )

            if type(field_data) is str:
                field_data = pd.read_table(StringIO(field_data), sep=",").to_dict(
                    orient='list'
                )

            if not {'ID', 'RA', 'Dec'}.issubset(field_data):
                return self.error("ID, RA, and Dec required in field_data.")

            log(f"Started generating fields for instrument {instrument.id}")
            # run async
            IOLoop.current().run_in_executor(
                None,
                lambda: add_tiles(instrument.id, instrument.name, regions, field_data),
            )

        self.push_all(action="skyportal/REFRESH_INSTRUMENTS")
        return self.success(data={"id": instrument.id})