def _get_solarsimulator_measurement_by_filepath(filepath, user): """Returns the ID of a solarsimulator measurement with the given filepath. Every solarsimulator measurement consists of single measurements which are associated with a data filepath each. This function finds the measurement which contains a single (“cell”) measurement with the filepath. :param filepath: the path of the measurement file, as it is stored in the database :param user: the logged-in user :type filepath: unicode :type user: django.contrib.auth.models.User :return: the ID of the solarsimulator measurement which contains results from the given data file :rtype: int :raises permissions.PermissionError: if the user is not allowed to see the solarsimulator measurement :raises Http404: if the filepath was not found in the database """ cells = institute.models.SolarsimulatorCellMeasurement.objects.filter(data_file=filepath) if cells.exists(): measurement = cells[0].measurement else: raise Http404("No matching solarsimulator measurement found.") permissions.assert_can_view_physical_process(user, measurement) return measurement.id
def get_matching_solarsimulator_measurement(request, sample_id, irradiation, cell_position, date): """Finds the solarsimulator measurement which is best suited for the given data file. This view is to solve the problem that for non-standard-Jülich cell layouts, many single data files must be merged into one solarsimulator measurements. When importing them one by one, one has to find the already existing measurement to which they must be added. This is done by this view. It returns the ID of the measurement, or ``None`` if none was found. :param request: the HTTP request object :param sample_id: the ID of the sample which was measured :param irradiation: the irradiation (AM1.5, BG7 etc) which was used :param cell_position: the position of the cell on the layout; don't mix it up with the *index* of the cell, which is the number used in the Solarsimulator datafile in the first column :param date: the day (not the time) of the measurement in YYYY-MM-DD format :type request: HttpRequest :type sample_id: unicode :type irradiation: unicode :type cell_position: unicode :type date: unicode :return: the HTTP response object :rtype: HttpResponse """ try: filepath = request.GET["filepath"] except KeyError: raise JSONRequestException(3, '"filepath" missing') try: return respond_in_json( _get_solarsimulator_measurement_by_filepath( filepath, request.user)) except Http404: sample = get_object_or_404(models.Sample, id=sample_id) start_date = django.utils.timezone.make_aware( datetime.datetime.strptime(date, "%Y-%m-%d")) end_date = start_date + datetime.timedelta(days=1) matching_measurements = institute.models.SolarsimulatorMeasurement.objects.filter( samples__id=sample_id, irradiation=irradiation, timestamp__gte=start_date, timestamp__lt=end_date). \ exclude(cells__position=cell_position).order_by("timestamp") if matching_measurements.exists(): solarsimulator_measurement = matching_measurements[0] permissions.assert_can_fully_view_sample(request.user, sample) permissions.assert_can_view_physical_process( request.user, solarsimulator_measurement) return respond_in_json(solarsimulator_measurement.id) else: return respond_in_json(None)
def get_matching_solarsimulator_measurement(request, sample_id, irradiation, cell_position, date): """Finds the solarsimulator measurement which is best suited for the given data file. This view is to solve the problem that for non-standard-Jülich cell layouts, many single data files must be merged into one solarsimulator measurements. When importing them one by one, one has to find the already existing measurement to which they must be added. This is done by this view. It returns the ID of the measurement, or ``None`` if none was found. :param request: the HTTP request object :param sample_id: the ID of the sample which was measured :param irradiation: the irradiation (AM1.5, BG7 etc) which was used :param cell_position: the position of the cell on the layout; don't mix it up with the *index* of the cell, which is the number used in the Solarsimulator datafile in the first column :param date: the day (not the time) of the measurement in YYYY-MM-DD format :type request: HttpRequest :type sample_id: unicode :type irradiation: unicode :type cell_position: unicode :type date: unicode :return: the HTTP response object :rtype: HttpResponse """ try: filepath = request.GET["filepath"] except KeyError: raise JSONRequestException(3, '"filepath" missing') try: return respond_in_json(_get_solarsimulator_measurement_by_filepath(filepath, request.user)) except Http404: sample = get_object_or_404(models.Sample, id=sample_id) start_date = datetime.datetime.strptime(date, "%Y-%m-%d") end_date = start_date + datetime.timedelta(days=1) matching_measurements = institute.models.SolarsimulatorMeasurement.objects.filter( samples__id=sample_id, irradiation=irradiation, timestamp__gte=start_date, timestamp__lt=end_date). \ exclude(cells__position=cell_position).order_by("timestamp") if matching_measurements.exists(): solarsimulator_measurement = matching_measurements[0] permissions.assert_can_fully_view_sample(request.user, sample) permissions.assert_can_view_physical_process(request.user, solarsimulator_measurement) return respond_in_json(solarsimulator_measurement.id) else: return respond_in_json(None)
def show_process(request, process_id, process_name="Process"): """Show an existing physical process. This is some sort of fallback view in case a process doesn't provide its own show view (which is mostly the case). The ``process_id`` needn't be the ``"id"`` field: If `process_name` is not ``None``, its ``JBMeta.identifying_field``, it given, is used instead for the lookup. :param request: the current HTTP Request object :param process_id: the ID or the process's identifying field value :param process_name: the class name of the process; if ``None``, ``Process`` is assumed :type request: HttpRequest :type process_id: unicode :type process_name: unicode :return: the HTTP response object :rtype: HttpResponse """ process_class = get_all_models()[process_name] try: identifying_field = process_class.JBMeta.identifying_field except AttributeError: identifying_field = "id" try: process = get_object_or_404(process_class, **{ identifying_field: process_id }).actual_instance except ValueError: raise Http404("Invalid value for {} passed: {}".format( identifying_field, repr(process_id))) if not isinstance(process, models.PhysicalProcess): raise Http404("No physical process with that ID was found.") permissions.assert_can_view_physical_process(request.user, process) if is_json_requested(request): return respond_in_json(process.get_data()) template_context = { "title": six.text_type(process), "samples": process.samples.all(), "process": process } template_context.update(utils.digest_process(process, request.user)) return render(request, "samples/show_process.html", template_context)
def show_plot(request, process_id, plot_id, thumbnail): """Shows a particular plot. Although its response is a bitmap rather than an HTML file, it is served by Django in order to enforce user permissions. :param request: the current HTTP Request object :param process_id: the database ID of the process to show :param plot_id: the plot_id of the image. This is mostly ``u""`` because most measurement models have only one graphics. :param thumbnail: whether we serve a thumbnail instead of a real PDF plot :type request: HttpRequest :type process_id: unicode :type plot_id: unicode :type thumbnail: bool :return: the HTTP response object with the image :rtype: HttpResponse """ process = get_object_or_404(models.Process, pk=utils.convert_id_to_int(process_id)) process = process.actual_instance permissions.assert_can_view_physical_process(request.user, process) plot_filepath = process.calculate_plot_locations( plot_id)["thumbnail_file" if thumbnail else "plot_file"] datafile_name = process.get_datafile_name(plot_id) if datafile_name is None: raise Http404("No such plot available.") timestamps = [] if thumbnail else [ sample.last_modified for sample in process.samples.all() ] timestamps.append(process.last_modified) datafile_names = datafile_name if isinstance(datafile_name, list) else [datafile_name] if not all(os.path.exists(filename) for filename in datafile_names): raise Http404("One of the raw datafiles was not found.") content = get_cached_file_content( plot_filepath, partial(generate_plot, process, plot_id, thumbnail, datafile_name), datafile_names, timestamps) return static_response( content, None if thumbnail else process.get_plotfile_basename(plot_id) + ".pdf", mimetypes.guess_type(plot_filepath))
def get_current_structuring(request, sample_id): """Find the structuring process which is active for the given sample at a given timestamp. The “``timestamp``” is an optional parameter in the query string in the format ``YYYY-MM-YY HH:MM:SS``. If given, find the latest structuring process before that timestamp. Otherwise, find the lastest structuring of the sample. Typically, the timestamp is the timestamp of the process which needs the structuring, e.g. a solarsimulator measurement. It returns the ID of the structuring process, or ``None`` if none was found. :param request: the HTTP request object :param sample_id: the ID of the sample :type request: HttpRequest :type sample_id: unicode :return: the HTTP response object :rtype: HttpResponse """ sample = get_object_or_404(models.Sample, id=sample_id) try: timestamp = django.utils.timezone.make_aware( datetime.datetime.strptime( request.GET["timestamp"].partition(".")[0], "%Y-%m-%d %H:%M:%S")) except KeyError: timestamp = None except ValueError: raise JSONRequestException(5, '"timestamp" has invalid format') try: structuring = layouts.get_current_structuring(sample, timestamp) except layouts.NoStructuringFound: result = None else: permissions.assert_can_fully_view_sample(request.user, sample) permissions.assert_can_view_physical_process(request.user, structuring) result = structuring.id return respond_in_json(result)
def get_current_structuring(request, sample_id): """Find the structuring process which is active for the given sample at a given timestamp. The “``timestamp``” is an optional parameter in the query string in the format ``YYYY-MM-YY HH:MM:SS``. If given, find the latest structuring process before that timestamp. Otherwise, find the lastest structuring of the sample. Typically, the timestamp is the timestamp of the process which needs the structuring, e.g. a solarsimulator measurement. It returns the ID of the structuring process, or ``None`` if none was found. :param request: the HTTP request object :param sample_id: the ID of the sample :type request: HttpRequest :type sample_id: unicode :return: the HTTP response object :rtype: HttpResponse """ sample = get_object_or_404(models.Sample, id=sample_id) try: timestamp = datetime.datetime.strptime(request.GET["timestamp"].partition(".")[0], "%Y-%m-%d %H:%M:%S") except KeyError: timestamp = None except ValueError: raise JSONRequestException(5, '"timestamp" has invalid format') try: structuring = layouts.get_current_structuring(sample, timestamp) except layouts.NoStructuringFound: result = None else: permissions.assert_can_fully_view_sample(request.user, sample) permissions.assert_can_view_physical_process(request.user, structuring) result = structuring.id return respond_in_json(result)
def show_plot(request, process_id, plot_id, thumbnail): """Shows a particular plot. Although its response is a bitmap rather than an HTML file, it is served by Django in order to enforce user permissions. :param request: the current HTTP Request object :param process_id: the database ID of the process to show :param plot_id: the plot_id of the image. This is mostly ``u""`` because most measurement models have only one graphics. :param thumbnail: whether we serve a thumbnail instead of a real PDF plot :type request: HttpRequest :type process_id: unicode :type plot_id: unicode :type thumbnail: bool :return: the HTTP response object with the image :rtype: HttpResponse """ process = get_object_or_404(models.Process, pk=utils.convert_id_to_int(process_id)) process = process.actual_instance permissions.assert_can_view_physical_process(request.user, process) plot_filepath = process.calculate_plot_locations(plot_id)["thumbnail_file" if thumbnail else "plot_file"] datafile_name = process.get_datafile_name(plot_id) if datafile_name is None: raise Http404("No such plot available.") timestamps = [] if thumbnail else [sample.last_modified for sample in process.samples.all()] timestamps.append(process.last_modified) if datafile_name: datafile_names = datafile_name if isinstance(datafile_name, list) else [datafile_name] if not all(os.path.exists(filename) for filename in datafile_names): raise Http404("One of the raw datafiles was not found.") update_necessary = jb_common.utils.base.is_update_necessary(plot_filepath, datafile_names, timestamps) else: update_necessary = jb_common.utils.base.is_update_necessary(plot_filepath, timestamps=timestamps) if update_necessary: try: if thumbnail: figure = Figure(frameon=False, figsize=(4, 3)) canvas = FigureCanvasAgg(figure) axes = figure.add_subplot(111) axes.set_position((0.17, 0.16, 0.78, 0.78)) axes.grid(True) process.draw_plot(axes, plot_id, datafile_name, for_thumbnail=True) jb_common.utils.base.mkdirs(plot_filepath) canvas.print_figure(plot_filepath, dpi=settings.THUMBNAIL_WIDTH / 4) else: figure = Figure() canvas = FigureCanvasAgg(figure) axes = figure.add_subplot(111) axes.grid(True) axes.set_title(six.text_type(process)) process.draw_plot(axes, plot_id, datafile_name, for_thumbnail=False) # FixMe: Activate this line with Matplotlib 1.1.0. # figure.tight_layout() jb_common.utils.base.mkdirs(plot_filepath) canvas.print_figure(plot_filepath, format="pdf") storage_changed.send(models.Process) except PlotError as e: raise Http404(six.text_type(e) or "Plot could not be generated.") except ValueError as e: raise Http404("Plot could not be generated: " + e.args[0]) return jb_common.utils.base.static_file_response(plot_filepath, None if thumbnail else process.get_plotfile_basename(plot_id) + ".pdf")
def show_plot(request, process_id, plot_id, thumbnail): """Shows a particular plot. Although its response is a bitmap rather than an HTML file, it is served by Django in order to enforce user permissions. :param request: the current HTTP Request object :param process_id: the database ID of the process to show :param plot_id: the plot_id of the image. This is mostly ``u""`` because most measurement models have only one graphics. :param thumbnail: whether we serve a thumbnail instead of a real PDF plot :type request: HttpRequest :type process_id: unicode :type plot_id: unicode :type thumbnail: bool :return: the HTTP response object with the image :rtype: HttpResponse """ process = get_object_or_404(models.Process, pk=utils.convert_id_to_int(process_id)) process = process.actual_instance permissions.assert_can_view_physical_process(request.user, process) plot_filepath = process.calculate_plot_locations(plot_id)["thumbnail_file" if thumbnail else "plot_file"] datafile_name = process.get_datafile_name(plot_id) if datafile_name is None: raise Http404("No such plot available.") timestamps = [] if thumbnail else [sample.last_modified for sample in process.samples.all()] timestamps.append(process.last_modified) if datafile_name: datafile_names = datafile_name if isinstance(datafile_name, list) else [datafile_name] if not all(os.path.exists(filename) for filename in datafile_names): raise Http404("One of the raw datafiles was not found.") update_necessary = jb_common.utils.base.is_update_necessary(plot_filepath, datafile_names, timestamps) else: update_necessary = jb_common.utils.base.is_update_necessary(plot_filepath, timestamps=timestamps) if update_necessary: try: if thumbnail: figure = Figure(frameon=False, figsize=(4, 3)) canvas = FigureCanvasAgg(figure) axes = figure.add_subplot(111) axes.set_position((0.17, 0.16, 0.78, 0.78)) axes.grid(True) process.draw_plot(axes, plot_id, datafile_name, for_thumbnail=True) jb_common.utils.base.mkdirs(plot_filepath) canvas.print_figure(plot_filepath, dpi=settings.THUMBNAIL_WIDTH / 4) else: figure = Figure() canvas = FigureCanvasAgg(figure) axes = figure.add_subplot(111) axes.grid(True) axes.set_title(six.text_type(process)) process.draw_plot(axes, plot_id, datafile_name, for_thumbnail=False) # FixMe: Activate this line with Matplotlib 1.1.0. # figure.tight_layout() jb_common.utils.base.mkdirs(plot_filepath) canvas.print_figure(plot_filepath, format="pdf") storage_changed.send(models.Process) except PlotError as e: raise Http404(six.text_type(e) or "Plot could not be generated.") return jb_common.utils.base.static_file_response(plot_filepath, None if thumbnail else process.get_plotfile_basename(plot_id) + ".pdf")