Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/uncredentialed facility pages #770

Merged
merged 8 commits into from
Dec 7, 2023
2 changes: 2 additions & 0 deletions tom_base/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,8 @@
'tom_observations.facilities.lco.LCOFacility',
'tom_observations.facilities.gemini.GEMFacility',
'tom_observations.facilities.soar.SOARFacility',
'tom_observations.facilities.lt.LTFacility',

]

# Define MATCH_MANAGERS here.
Expand Down
19 changes: 10 additions & 9 deletions tom_observations/facilities/lco.py
Original file line number Diff line number Diff line change
Expand Up @@ -668,7 +668,8 @@ def __init__(self, *args, **kwargs):
if self.fields.get(f'c_{j+1}_ic_{i+1}_grating', None):
self.fields[f'c_{j+1}_ic_{i+1}_grating'].help_text = 'Only for SOAR'
self.fields[f'c_{j+1}_ic_{i+1}_grating'].choices.insert(0, ('None', 'None'))
self.fields[f'c_{j+1}_ic_{i+1}_slit'].help_text = 'Only for Floyds'
if self.fields.get(f'c_{j+1}_ic_{i+1}_slit', None):
self.fields[f'c_{j+1}_ic_{i+1}_slit'].help_text = 'Only for Floyds'

def convert_old_observation_payload_to_fields(self, data):
data = super().convert_old_observation_payload_to_fields(data)
Expand Down Expand Up @@ -753,7 +754,7 @@ class LCOPhotometricSequenceForm(LCOOldStyleObservationForm):
configuration of multiple filters, as well as a more intuitive proactive cadence form.
"""
valid_instruments = ['1M0-SCICAM-SINISTRO', '0M4-SCICAM-SBIG', '2M0-SPECTRAL-AG']
valid_filters = ['U', 'B', 'V', 'R', 'I', 'up', 'gp', 'rp', 'ip', 'zs', 'w']
valid_filters = ['U', 'B', 'V', 'R', 'I', 'up', 'gp', 'rp', 'ip', 'zs', 'w', 'unknown']
cadence_frequency = forms.IntegerField(required=True, help_text='in hours')

def __init__(self, *args, **kwargs):
Expand Down Expand Up @@ -800,13 +801,13 @@ def _build_instrument_configs(self):
instrument configurations in the appropriate manner.
"""
instrument_configs = []
for filter_name in self.valid_filters:
if len(self.cleaned_data[filter_name]) > 0:
for filter_code, _ in self.all_optical_element_choices():
if len(self.cleaned_data[filter_code]) > 0:
instrument_configs.append({
'exposure_count': self.cleaned_data[filter_name][1],
'exposure_time': self.cleaned_data[filter_name][0],
'exposure_count': self.cleaned_data[filter_code][1],
'exposure_time': self.cleaned_data[filter_code][0],
'optical_elements': {
'filter': filter_name
'filter': filter_code
}
})

Expand Down Expand Up @@ -888,8 +889,8 @@ def layout(self):
Column(HTML('Block No.')),
)
)
for filter_name in self.valid_filters:
filter_layout.append(Row(MultiWidgetField(filter_name, attrs={'min': 0})))
for filter_code, _ in self.all_optical_element_choices():
filter_layout.append(Row(MultiWidgetField(filter_code, attrs={'min': 0})))

return Row(
Column(
Expand Down
4 changes: 3 additions & 1 deletion tom_observations/facilities/lt.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ class LTQueryForm(GenericObservationForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
target_id = self.initial.get('target_id')
self.helper.inputs.pop()
self.helper.layout = Layout(
HTML('''
<p>
Expand All @@ -21,6 +20,9 @@ def __init__(self, *args, **kwargs):

class LTFacility(GenericObservationFacility):
name = 'LT'
observation_forms = {
'ALL': LTQueryForm,
}
observation_types = [('Default', '')]

def get_form(self, observation_type):
Expand Down
67 changes: 54 additions & 13 deletions tom_observations/facilities/ocs.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from astropy import units as u
from crispy_forms.bootstrap import Accordion, AccordionGroup, TabHolder, Tab, Alert
from crispy_forms.layout import Div, HTML, Layout
from crispy_forms.layout import Div, HTML, Layout, ButtonHolder, Submit
from dateutil.parser import parse
from django import forms
from django.conf import settings
Expand All @@ -32,6 +32,22 @@ class OCSSettings():
'max_instrument_configs': 5,
'max_configurations': 5
}
default_instrument_config = {'No Instrument Found': {
'type': 'NONE',
'optical_elements': {'filters': [{
'name': 'Unknown Filter',
'code': 'unknown',
'schedulable': True,
'default': True}]},
'configuration_types': {
'None': {
'name': 'No Configurations found',
'code': 'NONE',
}
},
'default_configuration_type': 'None',
}}

# These class variables describe default help text for a variety of OCS fields.
# Override them as desired for a specific OCS implementation.
ipp_value_help = """
Expand Down Expand Up @@ -81,6 +97,12 @@ def __init__(self, facility_name):
def get_setting(self, key):
return settings.FACILITIES.get(self.facility_name, self.default_settings).get(key, self.default_settings[key])

def check_configuration(self):
"""
Check that the settings for this facility are present, and return list of any required settings that are blank.
"""
return [key for key in self.default_settings.keys() if not self.get_setting(key)]

def get_observing_states(self):
return [
'PENDING', 'COMPLETED', 'WINDOW_EXPIRED', 'CANCELED', 'FAILURE_LIMIT_REACHED', 'NOT_ATTEMPTED'
Expand Down Expand Up @@ -191,15 +213,17 @@ def target_group_choices(self, include_self=True):

def _get_instruments(self):
cached_instruments = cache.get(f'{self.facility_settings.facility_name}_instruments')

if not cached_instruments:
logger.warning("Instruments not cached, getting them again!!!")
response = make_request(
'GET',
urljoin(self.facility_settings.get_setting('portal_url'), '/api/instruments/'),
headers={'Authorization': 'Token {0}'.format(self.facility_settings.get_setting('api_key'))}
)
cached_instruments = {k: v for k, v in response.json().items()}
try:
response = make_request(
'GET',
urljoin(self.facility_settings.get_setting('portal_url'), '/api/instruments/'),
headers={'Authorization': 'Token {0}'.format(self.facility_settings.get_setting('api_key'))}
)
cached_instruments = {k: v for k, v in response.json().items()}
except ImproperCredentialsException:
cached_instruments = self.facility_settings.default_instrument_config
cache.set(f'{self.facility_settings.facility_name}_instruments', cached_instruments, 3600)
return cached_instruments

Expand Down Expand Up @@ -253,11 +277,14 @@ def configuration_type_choices(self):
def proposal_choices(self):
cached_proposals = cache.get(f'{self.facility_settings.facility_name}_proposals')
if not cached_proposals:
response = make_request(
'GET',
urljoin(self.facility_settings.get_setting('portal_url'), '/api/profile/'),
headers={'Authorization': 'Token {0}'.format(self.facility_settings.get_setting('api_key'))}
)
try:
response = make_request(
'GET',
urljoin(self.facility_settings.get_setting('portal_url'), '/api/profile/'),
headers={'Authorization': 'Token {0}'.format(self.facility_settings.get_setting('api_key'))}
)
except ImproperCredentialsException:
return [(0, 'No proposals found')]
cached_proposals = []
for p in response.json()['proposals']:
if p['current']:
Expand Down Expand Up @@ -963,6 +990,20 @@ def __init__(self, *args, **kwargs):
if isinstance(self, CadenceForm):
self.helper.layout.insert(2, self.cadence_layout())

def button_layout(self):
"""
Override Button layout from BaseObservationForm.
Submit button will be disabled if there are any unconfigured settings found by check_configuration().
"""
target_id = self.initial.get('target_id')
jchate6 marked this conversation as resolved.
Show resolved Hide resolved

return ButtonHolder(
Submit('submit', 'Submit', disabled=bool(self.facility_settings.check_configuration())),
Submit('validate', 'Validate'),
HTML(f'''<a class="btn btn-outline-primary" href={{% url 'tom_targets:detail' {target_id} %}}>
Back</a>''')
)

def form_name(self):
return 'base'

Expand Down
1 change: 0 additions & 1 deletion tom_observations/facility.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
'tom_observations.facilities.lco.LCOFacility',
'tom_observations.facilities.gemini.GEMFacility',
'tom_observations.facilities.soar.SOARFacility',
'tom_observations.facilities.lt.LTFacility'
]

try:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
{% endblock %}
{% block content %}
{{ form|as_crispy_errors }}
<h3>Submit an observation to {{ form.facility.value }}</h3>
<h3>Submit an observation to {{ form.facility.value }} for <a href="{% url 'targets:detail' pk=target.id %}">{{target.name}}</a></h3>
{% if unconfigured %}
<div class="alert alert-danger">Some {{ form.facility.value }} Facility settings ({{ unconfigured }}) are not configured.</div>
{% endif %}
{% if target.type == 'SIDEREAL' %}
<div class="row">
<div class="col">
Expand Down
5 changes: 5 additions & 0 deletions tom_observations/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,11 @@ def get_context_data(self, **kwargs):
facility_context = facility.get_facility_context_data(target=target)
context.update(facility_context)

try:
context['unconfigured'] = ", ".join(facility.facility_settings.check_configuration())
jchate6 marked this conversation as resolved.
Show resolved Hide resolved
except AttributeError:
context['unconfigured'] = ''

return context

def get_form_class(self):
Expand Down
1 change: 0 additions & 1 deletion tom_setup/templates/tom_setup/settings.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,6 @@ TOM_FACILITY_CLASSES = [
'tom_observations.facilities.lco.LCOFacility',
'tom_observations.facilities.gemini.GEMFacility',
'tom_observations.facilities.soar.SOARFacility',
'tom_observations.facilities.lt.LTFacility'
]

TOM_ALERT_CLASSES = [
Expand Down
Loading