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'))
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')
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'))
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")
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'))
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'))
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)
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"))
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)
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)
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)
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'))
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'))
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"))