11from abc import ABC , abstractmethod
22import logging
3- from typing import List , Tuple
3+ from typing import List
4+ from urllib .parse import urlencode
45
56from django .conf import settings
67from django .apps import apps
78from django .utils .module_loading import import_string
9+ from django .db import IntegrityError
10+ from django .utils .safestring import mark_safe
11+ from django .contrib import messages
12+ from django .urls import reverse
813
9- from tom_targets .models import TargetName
14+ from guardian .shortcuts import assign_perm
15+
16+ from tom_targets .models import TargetName , Target
1017
1118logger = logging .getLogger (__name__ )
1219
@@ -119,6 +126,22 @@ def build_query_parameters(self, parameters, **kwargs):
119126 """Builds the query parameters from the form data"""
120127 raise NotImplementedError (f'build_query_parameters method has not been implemented for { self .name } ' )
121128
129+ # Include this method if you wish for the TOM to be able to query data for an individual Target.
130+ # def build_query_parameters_from_target(self, target, **kwargs):
131+ # """
132+ # This is a method that builds query parameters based on an existing target object that will be recognized by
133+ # `query_service()`.
134+ # This can be done by either by re-creating the form fields set by the Data Service Form and then calling
135+ # `self.build_query_parameters()` with the results, or we can reproduce a limited set of parameters uniquely for
136+ # a target query.
137+
138+ # :param target: A target object to be queried
139+ # :return: query_parameters (usually a dict) that can be understood by `query_service()`
140+ # """
141+ # raise NotImplementedError('build_query_parameters_from_target method has not been implemented' +
142+ # f'for {self.name}.'
143+ # )
144+
122145 def build_headers (self , * args , ** kwargs ):
123146 """Builds the headers for the query"""
124147 return {}
@@ -193,31 +216,33 @@ def get_success_message(self, **kwargs):
193216 """Returns a success message to display in the UI after making the query."""
194217 return "Query completed successfully."
195218
196- def get_simple_form_partial (self ):
197- """Returns a path to a simplified bare-minimum partial form that can be used to access the DataService."""
198- return None
199-
200- def get_advanced_form_partial (self ):
201- """Returns a path to a full or advanced partial form that can be used to access the DataService."""
202- return None
203-
204219 def query_forced_photometry (self , query_parameters , ** kwargs ):
205220 """Set up and run a specialized query for a DataService’s forced photometry service."""
206- return self . query_service ( query_parameters , ** kwargs )
221+ raise NotImplementedError ( f'query_forced_photometry method has not been implemented for { self . name } ' )
207222
208223 def query_photometry (self , query_parameters , ** kwargs ):
209224 """Set up and run a specialized query for a DataService’s photometry service."""
210- return self . query_service ( query_parameters , ** kwargs )
225+ raise NotImplementedError ( f'query_photometry method has not been implemented for { self . name } ' )
211226
212227 def query_spectroscopy (self , query_parameters , ** kwargs ):
213228 """Set up and run a specialized query for a DataService’s spectroscopy service."""
214- return self . query_service ( query_parameters , ** kwargs )
229+ raise NotImplementedError ( f'query_spectroscopy method has not been implemented for { self . name } ' )
215230
216- def query_reduced_data (self , query_parameters , ** kwargs ):
231+ def query_reduced_data (self , target , ** kwargs ):
217232 """Set up and run a specialized query to retrieve Reduced Datums from a Data Service"""
218- phot_results = self .query_photometry (query_parameters , ** kwargs )
219- spec_results = self .query_spectroscopy (query_parameters , ** kwargs )
220- forced_phot_results = self .query_forced_photometry (query_parameters , ** kwargs )
233+ query_parameters = self .build_query_parameters_from_target (target )
234+ try :
235+ phot_results = self .query_photometry (query_parameters , ** kwargs )
236+ except NotImplementedError :
237+ phot_results = []
238+ try :
239+ spec_results = self .query_spectroscopy (query_parameters , ** kwargs )
240+ except NotImplementedError :
241+ spec_results = []
242+ try :
243+ forced_phot_results = self .query_forced_photometry (query_parameters , ** kwargs )
244+ except NotImplementedError :
245+ forced_phot_results = []
221246 return {'photometry' : phot_results ,
222247 'spectroscopy' : spec_results ,
223248 'forced_photometry' : forced_phot_results }
@@ -242,7 +267,7 @@ def query_targets(self, query_parameters, **kwargs) -> List[dict]:
242267
243268 :param query_parameters: This is the output from build_query_parameters()
244269 :return: A list of dictionaries describing the resulting targets. Include 'reduced_datums' and/or 'aliases' as
245- keys in this dictionary to add associated data and alternate names without perfoming additional queries.
270+ keys in this dictionary to add associated data and alternate names without performing additional queries.
246271 :rtype: List[dict]
247272 """
248273 return [{}]
@@ -271,19 +296,28 @@ def to_reduced_datums(self, target, data_results=None, **kwargs):
271296 of query_reduced_data() to create_reduced_datums_from_query()
272297 :param target: Target object to associate with the ReducedDatum
273298 :param data_results: Query results from the DataService storing observation data. This should be a dictionary
274- with each key being a data_type (i.e. Photometry, Spectroscopy, etc.)
299+ with each key being a data_type (i.e. Photometry, Spectroscopy, etc.)
275300 """
276301 if not data_results :
277302 raise MissingDataException ('No Reduced Data dictionary found.' )
303+ reduced_datum_list = []
278304 for key in data_results .keys ():
279- self .create_reduced_datums_from_query (target , data_results [key ], key , ** kwargs )
280- return
305+ reduced_datum_list += self .create_reduced_datums_from_query (target , data_results [key ], key , ** kwargs )
306+ return reduced_datum_list
307+
308+ def create_reduced_datums_from_query (self , target , data : List , data_type = None , ** kwargs ) -> List :
309+ """
310+ Create and save new reduced_datums of the appropriate data_type from the query results
311+ Be sure to use `ReducedDatum.objects.get_or_create()` when creating new objects.
281312
282- def create_reduced_datums_from_query (self , target , data = None , data_type = None , ** kwargs ):
283- """Create and save new reduced_datums of the appropriate data_type from the query results"""
313+ :param target: Target Object to be associated with the reduced data
314+ :param data: List of data dictionaries of the appropriate `data_type`
315+ :param data_type: An appropriate data type as listed in tom_dataproducts.models.DATA_TYPE_CHOICES
316+ :return: List of Reduced datums (either retrieved or created)
317+ """
284318 raise NotImplementedError
285319
286- def to_target (self , target_result = None , ** kwargs ) -> Tuple [ dict , dict , dict ] :
320+ def to_target (self , target_result = None , ** kwargs ):
287321 """
288322 Upper level function to create a new target from the query results
289323 This method is not intended to be extended. This method passes a single instance of the output
@@ -292,15 +326,38 @@ def to_target(self, target_result=None, **kwargs) -> Tuple[dict, dict, dict]:
292326 Intended usage: Call to_target on each element of the target_data list of dictionaries from query_target.
293327 (see views.py::CreateTargetFromQueryView)
294328 :param target_results: Dictionary containing target information.
295- :returns: Target object, dictionary of target_extras, and list of aliases
329+ :returns: Target object
296330 """
297331 if not target_result :
298332 raise MissingDataException ('No query results. Did you call query_service()?' )
299333 else :
300334 target = self .create_target_from_query (target_result , ** kwargs )
301335 extras = self .create_target_extras_from_query (target_result , ** kwargs )
302336 aliases = self .create_aliases_from_query (target_result .get ('aliases' , []), ** kwargs )
303- return target , extras , aliases
337+
338+ request = kwargs .get ('request' )
339+ try :
340+ target .save (extras = extras , names = aliases )
341+ # Give the user access to the target they created
342+ if request :
343+ target .give_user_access (request .user )
344+ for group in request .user .groups .all ():
345+ assign_perm ('tom_targets.view_target' , group , target )
346+ assign_perm ('tom_targets.change_target' , group , target )
347+ assign_perm ('tom_targets.delete_target' , group , target )
348+ except IntegrityError :
349+ # errors.append(target.name)
350+ target = Target .objects .get (name = target .name )
351+ messages .warning (request ,
352+ mark_safe (
353+ f"""The target,
354+ <a href="{ reverse ('targets:detail' , kwargs = {'pk' : target .id })} ">
355+ { target .name } </a> already exists, any new data has been ingested.
356+ You can <a href="{ reverse ('targets:create' ) + '?' +
357+ urlencode (target .as_dict ())} ">create</a> a new target anyway.
358+ """ )
359+ )
360+ return target
304361
305362 def create_target_from_query (self , target_result , ** kwargs ):
306363 """Create a new target from a single instance of the target results.
0 commit comments