Example #1
0
    def parameters(self):
        """
        Define parameters for the current new run being created
        """

        try:
            c.parameters = self._model_run_service.get_parameters_for_model_being_created(self.current_user)
        except NoResultFound:
            helpers.error_flash(u"You must create a model run before any parameters can be set")
            redirect(url(controller='model_run', action='create'))

        if not request.POST:
            html = render('model_run/parameters.html')
            parameter_values = {}
            for parameter in c.parameters:
                if parameter.parameter_values:
                    parameter_values[PARAMETER_NAME_PREFIX + str(parameter.id)] = parameter.parameter_values[0].value
            return htmlfill.render(
                html,
                defaults=parameter_values,
                errors={},
                auto_error_formatter=BaseController.error_formatter
            )
        else:

            # get the action to perform and remove it from the dictionary
            action = request.params.getone('submit')

            if action == u'Next':
                redirect(url(controller='model_run', action='submit'))
            else:
                redirect(url(controller='model_run', action='output'))
Example #2
0
    def submit(self):
        """
        Page to submit the model un
        """
        model_run = None
        try:
            model_run = \
                self._model_run_service.get_model_being_created_with_non_default_parameter_values(self.current_user)
        except NoResultFound:
            helpers.error_flash(u"You must create a model run before submitting the model run")
            redirect(url(controller='model_run', action='create'))

        if not request.POST:
            self._user_service.set_current_model_run_creation_action(self.current_user, "submit")
            summmary_helper = SummaryControllerHelper(model_run_service=self._model_run_service)
            summmary_helper.add_summary_fields_to_context(model_run, c, self.current_user)
        else:
            self._model_run_controller_helper.check_user_quota(self.current_user)
            if request.params.getone('submit') == u'Submit':
                status, message = self._model_run_service.submit_model_run(self.current_user)
                if status.name == constants.MODEL_RUN_STATUS_SUBMITTED:
                    helpers.success_flash(message)
                else:
                    helpers.error_flash(message)

                redirect(url(controller='model_run', action='index'))
            else:
                redirect(url(controller='model_run', action='output'))

        return render('model_run/submit.html')
Example #3
0
 def _single_cell_land_cover(self, model_run, values, errors):
     land_cover_controller_helper = LandCoverControllerHelper()
     if not request.POST:
         self._user_service.set_current_model_run_creation_action(self.current_user, "land_cover")
         land_cover_controller_helper.add_fractional_land_cover_to_context(c, errors, model_run, self.current_user)
         return render('model_run/fractional_land_cover.html')
     else:
         land_cover_controller_helper.save_fractional_land_cover(values, errors, model_run, self.current_user)
         if len(errors) > 0:
             if 'land_cover_frac' in errors:
                 helpers.error_flash(errors['land_cover_frac'])
             land_cover_controller_helper.add_fractional_land_cover_to_context(
                 c,
                 errors,
                 model_run,
                 self.current_user)
             c.land_cover_values = values
             del values['submit']
             html = render('model_run/fractional_land_cover.html')
             return htmlfill.render(
                 html,
                 defaults=values,
                 errors=errors,
                 auto_error_formatter=BaseController.error_formatter
             )
         else:
             self._model_run_controller_helper.check_user_quota(self.current_user)
             try:
                 action = values['submit']
             except KeyError:
                 action = None
             if action == u'Next':
                 redirect(url(controller='model_run', action='output'))
             else:
                 redirect(url(controller='model_run', action='extents'))
Example #4
0
    def _external_user_password(self, id):
        """
        Code for password resets for an external user
        :param id: user id
        :return:html to render
        """
        c.password_one = ""
        c.password_two = ""

        can_reset_password = self._valid_user_and_uuid(id)
        if can_reset_password == 'OK':
            if request.method == 'POST':
                try:
                    self._user_service.reset_password(
                        c.user.id,
                        request.params.getone('password_one'),
                        request.params.getone('password_two'))
                    helpers.success_flash("Password Reset Successful")
                    redirect(url(controller='account', action='login'))
                except ServiceException as ex:
                    helpers.error_flash("Password not reset because %s" % ex.message)
                    return render("user/forgotten_password_external.html")
            else:
                return render("user/forgotten_password_external.html")
        elif can_reset_password == 'EXPIRED':
            self._user_service.set_forgot_password(c.user.id, send_email=True)
            return render("user/expired_forgotten_password_external.html")
        else:
            return render("user/invalid_forgotten_password_external.html")
Example #5
0
    def _land_cover(self, model_run, values, errors):
        land_cover_controller_helper = LandCoverControllerHelper()
        if not request.POST:
            self._user_service.set_current_model_run_creation_action(self.current_user, "land_cover")
            land_cover_controller_helper.add_land_covers_to_context(c, errors, model_run)
            if len(errors) > 0:
                helpers.error_flash(errors['land_cover_actions'])
            return render('model_run/land_cover.html')

        else:
            land_cover_controller_helper.save_land_cover_actions(values, errors, model_run)
            if len(errors) > 0:
                helpers.error_flash(errors['land_cover_actions'])
                return render('model_run/land_cover.html')
            else:
                # Get the action to perform
                self._model_run_controller_helper.check_user_quota(self.current_user)
                try:
                    action = values['submit']
                except KeyError:
                    action = None
                if action == u'Next':
                    redirect(url(controller='model_run', action='output'))
                else:
                    redirect(url(controller='model_run', action='extents'))
Example #6
0
 def get_model_run_being_created_or_redirect(self, model_run_service):
     """
     Check whether there is a model currently being created for the user and, if not,
     redirect to the create model run page
     :param model_run_service: ModelRunService to use
     :return: ModelRun being created if there is one
     """
     try:
         return model_run_service.get_model_being_created_with_non_default_parameter_values(self.current_user)
     except NoResultFound:
         helpers.error_flash(u"You must create a model run before you can select a spatial extent")
         redirect(url(controller='model_run', action='create'))
Example #7
0
    def make_public(self, id):
        """
        Controller allowing existing model runs to be made public
        :param id: ID of model run to make public
        :return: redirect to the page you came from
        """
        if not request.method == 'POST':
            helpers.error_flash("Making a model run public must be a post")
            redirect(url(controller='model_run', action='index'))

        helpers.success_flash("Model run has been made public")
        self._model_run_service.make_public_model(self.current_user, id)
        redirect_back_to_came_from_for_model_run(id, request.params)
Example #8
0
    def output(self):
        """
        Select output parameters
        """
        # First we need to check that we are allowed to be on this page
        model_run = self.get_model_run_being_created_or_redirect(self._model_run_service)

        if not request.POST:
            self._user_service.set_current_model_run_creation_action(self.current_user, "output")
            # We need to not show the output variables which are dependent on JULES_MODEL_LEVELS::nsmax if nsmax is 0
            jules_param_nsmax = model_run.get_python_parameter_value(constants.JULES_PARAM_NSMAX)
            c.output_variables = self._model_run_service.get_output_variables(
                include_depends_on_nsmax=jules_param_nsmax > 0)

            # We want to pass the renderer a list of which output variables are already selected and for which time
            # periods so that we can render these onto the page as selected
            output_controller_helper.add_selected_outputs_to_template_context(c, model_run)

            # Finally we need to know if we must disable yearly or monthly outputs
            c.yearly_allowed = output_controller_helper.yearly_output_allowed(model_run)
            c.monthly_allowed = output_controller_helper.monthly_output_allowed(model_run)

            return render("model_run/output.html")
        else:
            values = dict(request.params)

            # Identify the requested output variables and save the appropriate parameters
            output_variable_groups = output_controller_helper.create_output_variable_groups(values,
                                                                                            self._model_run_service,
                                                                                            model_run)

            self._model_run_service.set_output_variables_for_model_being_created(output_variable_groups,
                                                                                 self.current_user)

            # Put a limit on the number of output profiles (tick-boxes) that can be submitted.
            if len(output_variable_groups) > constants.JULES_PARAM_OUTPUT_NPROFILES_MAX:
                helpers.error_flash("Cannot submit with more than " + str(constants.JULES_PARAM_OUTPUT_NPROFILES_MAX) +
                                    " output profiles. Please select fewer than " +
                                    str(constants.JULES_PARAM_OUTPUT_NPROFILES_MAX) + " tick-boxes on this page.")
                redirect(url(controller='model_run', action='output'))

            # Get the action to perform
            self._model_run_controller_helper.check_user_quota(self.current_user)
            try:
                action = values['submit']
            except KeyError:
                action = None
            if action == u'Next':
                redirect(url(controller='model_run', action='submit'))
            else:
                redirect(url(controller='model_run', action='land_cover'))
    def check_user_quota(self, current_user):
        """
        Check that the user can create a new model run
        :param current_user: the current user
        :return: the model run being created
        """
        total = 0
        for user_id, status_name, storage_in_mb in self._model_run_service.get_storage_used(current_user):
            if status_name != constants.MODEL_RUN_STATUS_PUBLISHED and status_name != constants.MODEL_RUN_STATUS_PUBLIC:
                total += storage_in_mb

        total_in_gb = utils.convert_mb_to_gb_and_round(total)

        storage_percent_used = round(total_in_gb / current_user.storage_quota_in_gb * 100.0, 0)

        if storage_percent_used >= constants.QUOTA_ABSOLUTE_LIMIT_PERCENT:
            helpers.error_flash(constants.ERROR_MESSAGE_QUOTA_EXCEEDED)
            redirect(url(controller="model_run", action="index"))
Example #10
0
    def land_cover(self):
        """
        Set the land cover options
        """
        model_run = self.get_model_run_being_created_or_redirect(self._model_run_service)
        values = dict(request.params)
        errors = {}
        multicell = not model_run.is_for_single_cell() and not 'fractional_cover' in values

        if 'reset_fractional_cover' in values:
            land_cover_controller_helper = LandCoverControllerHelper()
            land_cover_controller_helper.reset_fractional_cover(model_run)
            redirect(url(controller='model_run', action='land_cover'))

        if multicell:
            return self._land_cover(model_run, values, errors)
        else:
            latlon = model_run.get_python_parameter_value(constants.JULES_PARAM_POINTS_FILE, is_list=True)
            if latlon is None:
                helpers.error_flash(u"You must set model run extents set before you can edit the land cover")
                redirect(url(controller='model_run', action='extents'))
            return self._single_cell_land_cover(model_run, values, errors)
Example #11
0
    def delete(self, id):
        """
        Action to delete a model run for a user or admin
        :param id: the id of the model to delete
        :return: redirect to catalgue with flash message
        """

        if not request.method == 'POST':
            helpers.error_flash("Model run deletion must be a post")
            redirect(url(controller='model_run', action='index'))

        try:
            model_run_name = self._model_run_service.delete_run_model(int(id), self.current_user)
            helpers.success_flash("Model run %s deleted" % model_run_name)
        except ValueError:
            helpers.error_flash("Model run id not a number can not delete it")
        except NoResultFound:
            helpers.error_flash("Model run can not be deleted, it does not exist")
        except ModelPublished:
            helpers.error_flash("The model run you are trying to delete has been published. "
                                "Only admins can delete published model runs.")
        except ServiceException, ex:
            helpers.error_flash("Model run can not be deleted: {}".format(ex.message))
            log.exception("Problem deleting model run %s" % id)
Example #12
0
    def duplicate(self, id=None):
        """
        Duplicate a model run
        :param id: model run to duplicate
        :return: redirect
        """

        if not request.method == 'POST':
            helpers.error_flash("Model run duplication must be a post")
            redirect(url(controller='model_run', action='index'))

        try:
            self._model_run_service.duplicate_run_model(id, self.current_user)
            redirect(url=url(controller='model_run', action='submit'))
        except NoResultFound:
            helpers.error_flash("The model run was not duplicated because it no longer exists.")
        except ServiceException, ex:
            helpers.error_flash("The model run was not duplicated: %s" % ex.message)
Example #13
0
    def extents(self):
        """
        Specify the spatial and temporal extents of the model
        """
        extents_controller_helper = ExtentsControllerHelper()

        # First we need to check that we are allowed to be on this page
        model_run = self.get_model_run_being_created_or_redirect(self._model_run_service)
        c.model_run = model_run
        c.dataset = driving_data = model_run.driving_dataset
        if driving_data is None:
            helpers.error_flash(u"You must select a driving data set before you can set the extents")
            redirect(url(controller='model_run', action='driving_data'))
        errors = {}

        if not request.POST:
            self._user_service.set_current_model_run_creation_action(self.current_user, "extents")
            values = extents_controller_helper.create_values_dict_from_database(model_run, driving_data)
            extents_controller_helper.set_template_context_fields(c, model_run, driving_data)

            # We need to check that saved values for user selected spatial extent are consistent with the chosen
            # driving data (e.g. in case the user has gone back and changed their driving data).
            extents_controller_helper.validate_extents_form_values(values, model_run, driving_data, errors)

            # Finally in our GET we render the page with any errors and values we have
            return htmlfill.render(
                render('model_run/extents.html'),
                defaults=values,
                errors=errors,
                auto_error_formatter=BaseController.error_formatter)

        # This is a POST
        else:
            values = self.form_result
            extents_controller_helper.set_template_context_fields(c, model_run, driving_data)

            extents_controller_helper.validate_extents_form_values(values, model_run, driving_data, errors)

            if len(errors) > 0:
                return htmlfill.render(
                    render('model_run/extents.html'),
                    defaults=values,
                    errors=errors,
                    auto_error_formatter=BaseController.error_formatter)
            try:
                spinup_duration = constants.SPINUP_MAX_TIME_RANGE_YEARS
                science_config = \
                    self._model_run_service.get_science_configuration_by_id(model_run.science_configuration_id)
                if science_config.science_configuration_spinup_in_years is not None:
                    spinup_duration = science_config.science_configuration_spinup_in_years
                extents_controller_helper.save_extents_against_model_run(
                    values,
                    driving_data,
                    model_run,
                    spinup_duration,
                    self._parameter_service, self.current_user)

            except DapClientException as ex:
                helpers.error_flash("Error submitting extents: %s" % ex.message)
                return htmlfill.render(
                    render('model_run/extents.html'),
                    defaults=values,
                    errors=errors,
                    auto_error_formatter=BaseController.error_formatter)

            # Get the action to perform
            self._model_run_controller_helper.check_user_quota(self.current_user)
            try:
                action = values['submit']
            except KeyError:
                action = None
            if action == u'Next':
                redirect(url(controller='model_run', action='land_cover'))
            else:
                redirect(url(controller='model_run', action='driving_data'))
Example #14
0
    def driving_data(self):
        """
        Select a driving data set
        """
        driving_data_controller_helper = DrivingDataControllerHelper()

        model_run = None
        try:
            model_run = \
                self._model_run_service.get_model_being_created_with_non_default_parameter_values(self.current_user)
        except NoResultFound:
            helpers.error_flash(u"You must create a model run before you can choose a driving data set")
            redirect(url(controller='model_run', action='create'))

        driving_datasets = self._dataset_service.get_driving_datasets(self.current_user)
        user_upload_ds_id = self._dataset_service.get_id_for_user_upload_driving_dataset()
        errors = {}

        c.driving_datasets = driving_datasets
        c.user_upload_ds_id = user_upload_ds_id
        c.driving_data_rows = model_run.driving_data_rows

        if not request.POST:
            self._user_service.set_current_model_run_creation_action(self.current_user, "driving_data")

            values = driving_data_controller_helper.create_values_dict_from_database(model_run)

            if len(driving_datasets) == 0:
                abort_with_error("There are no driving datasets available - cannot create a new model run")

            # If the chosen driving dataset value is None, set it to the first in the list
            if values['driving_dataset'] is None:
                values['driving_dataset'] = driving_datasets[0].id

            c.errors = errors
            html = render('model_run/driving_data.html')
            return htmlfill.render(
                html,
                defaults=values,
                errors=errors,
                auto_error_formatter=BaseController.error_formatter)
        else:
            # This is a post
            values = dict(request.params)

            # Get the action to perform and remove it from the dictionary
            action = values['submit']
            del values['submit']

            old_driving_dataset = None
            if model_run.driving_dataset_id is not None:
                old_driving_dataset = find_by_id(driving_datasets, model_run.driving_dataset_id)

            if action == u'Upload':
                # This is a request to to upload a driving data file
                try:
                    driving_data_controller_helper.save_uploaded_driving_data(values, errors,
                                                                              self._model_run_service,
                                                                              old_driving_dataset,
                                                                              self.current_user)
                    if len(errors) == 0:
                        # Reload the current page
                        helpers.success_flash("Your driving data file has been successfully uploaded.")
                        redirect(url(controller='model_run', action='driving_data'))
                        return
                    else:
                        c.errors = errors
                        helpers.error_flash("Errors were present in the upload information: please check below.")
                        html = render('model_run/driving_data.html')
                        return htmlfill.render(
                            html,
                            defaults=values,
                            errors=errors,
                            auto_error_formatter=BaseController.error_formatter)
                except ServiceException as e:
                    helpers.error_flash(e.message)
                    redirect(url(controller='model_run', action='driving_data'))
            elif action == u'Download':
                # This is a request to to download driving data
                try:
                    file_generator = driving_data_controller_helper.download_driving_data(values, errors, response)

                    if len(errors) > 0:
                        c.errors = errors
                        helpers.error_flash("Errors were present in the download information: please check below.")
                        return htmlfill.render(
                            render('model_run/driving_data.html'),
                            defaults=values,
                            errors=errors,
                            auto_error_formatter=BaseController.error_formatter)
                    # This will stream the file to the browser without loading it all in memory
                    # BUT only if the .ini file does not have 'debug=true' enabled
                    return file_generator
                except (DapClientException, ServiceException) as e:
                    helpers.error_flash("Couldn't download data: %s." % e.message)
                    redirect(url(controller='model_run', action='driving_data'))
            else:

                try:
                    driving_dataset = find_by_id(driving_datasets, int(values['driving_dataset']))
                except (KeyNotFound, KeyError):
                    errors['driving_dataset'] = 'Driving data not recognised'
                    html = render('model_run/driving_data.html')
                    return htmlfill.render(
                        html,
                        defaults=values,
                        errors=errors,
                        auto_error_formatter=BaseController.error_formatter)
                # If the new selected driving dataset is NOT a user uploaded dataset:
                if driving_dataset.id != user_upload_ds_id:
                    # If the previous driving dataset was a user uploaded driving dataset we need to create an uploaded
                    # driving dataset so that the parameters are removed:
                    if old_driving_dataset is not None:
                        if old_driving_dataset.id == user_upload_ds_id:
                            old_driving_dataset = driving_data_controller_helper. \
                                _create_uploaded_driving_dataset(None, None, None, None, self._model_run_service)
                    self._model_run_service.save_driving_dataset_for_new_model(
                        driving_dataset,
                        old_driving_dataset,
                        self.current_user)
                else:
                    # If the selected driving dataset is the user uploaded dataset we can't proceed if the driving
                    # data has not already been uploaded:
                    if not model_run.driving_data_rows:
                        errors['driving-file'] = 'You must upload a driving data file'
                        c.errors = errors
                        html = render('model_run/driving_data.html')
                        return htmlfill.render(
                            html,
                            defaults=values,
                            errors=errors,
                            auto_error_formatter=BaseController.error_formatter)

                        # If the chosen ds_id is 'upload' and they have already uploaded data then we need do nothing

                self._model_run_controller_helper.check_user_quota(self.current_user)

                if action == u'Next':
                    redirect(url(controller='model_run', action='extents'))
                else:
                    redirect(url(controller='model_run', action='create'))
Example #15
0
    def requests(self, id):
        """
        List the account requests for approval
        :param id: id to accept or reject or None on get
        :return: nothing
        """

        if self.current_user is None or not self.current_user.is_admin():
            return render('not_found.html')

        if not request.method == 'POST':
            c.account_requests = self._account_request_service.get_account_requests()

            return render('user/requests.html')

        else:
            if id is None:
                helpers.error_flash("Request not accepted or rejected. No id included with reject or accept")
            try:
                action = request.params.getone('action')
                if action == u'accept':
                    self._account_request_service.accept_account_request(id)
                    helpers.success_flash("User account created and user emailed.")
                elif action == u'reject':
                    reason_for_rejection = request.params.getone('reason')
                    if len(reason_for_rejection.strip()) == 0:
                        helpers.error_flash(
                            "Request not rejected: A reason must be given to the user for why they are being rejected")
                    else:
                        self._account_request_service.reject_account_request(id, reason_for_rejection)
                        helpers.success_flash("User account request has been rejected and an email has been sent.")
                elif action == u'ignore':
                    self._account_request_service.ignore_account_request(id)
                    helpers.success_flash(
                        "User account request ignored; no user account created and user has not been emailed.")
                else:
                    raise KeyError()
            except KeyError:
                helpers.error_flash("Request not accepted or rejected. No action included with reject or accept")
            except NoResultFound:
                helpers.error_flash("Request could not be found, no action taken")
            except ClientException as ex:
                log.exception("Trouble accepting account request because of CROWD")
                helpers.error_flash(
                    "User account could not be created, there is a problem with CROWD: %s" % ex.message)
            except ServiceException as ex:
                log.exception("Trouble accepting or rejecting account request because of a service error")
                helpers.error_flash("User account could not be created %s" % ex.message)

            return redirect(url(controller="user", action="requests"))