Skip to content

Commit

Permalink
Merge pull request #2024 from MushroomObserver/njw-field-slips
Browse files Browse the repository at this point in the history
Field Slips
  • Loading branch information
mo-nathan committed Mar 26, 2024
2 parents dcffad0 + 246e7d4 commit a2a9bb1
Show file tree
Hide file tree
Showing 45 changed files with 920 additions and 34 deletions.
5 changes: 4 additions & 1 deletion app/classes/api2/project_api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def query_params
has_summary: parse(:boolean, :has_summary),
title_has: parse(:string, :title_has, help: 1),
summary_has: parse(:string, :summary_has, help: 1),
field_slip_prefix_has: parse(:string, :field_slip_prefix_has, help: 1),
comments_has: parse(:string, :comments_has, help: 1)
}
end
Expand All @@ -52,6 +53,7 @@ def create_params
{
title: parse(:string, :title, limit: 100),
summary: parse(:string, :summary, default: ""),
field_slip_prefix: parse(:string, :field_slip_prefix, default: ""),
user: @user
}
end
Expand All @@ -60,7 +62,8 @@ def update_params
parse_update_params
{
title: parse(:string, :set_title, limit: 100, not_blank: true),
summary: parse(:string, :set_summary)
summary: parse(:string, :set_summary),
field_slip_prefix: parse(:string, :set_field_slip_prefix)
}
end

Expand Down
5 changes: 5 additions & 0 deletions app/classes/query/project_base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ def parameter_declarations
has_summary?: :boolean,
title_has?: :string,
summary_has?: :string,
field_slip_prefix_has?: :string,
comments_has?: :string,
member?: User
)
Expand Down Expand Up @@ -59,6 +60,10 @@ def initialize_search_parameters
"projects.summary",
params[:summary_has]
)
add_search_condition(
"projects.field_slip_prefix",
params[:field_slip_prefix_has]
)
add_search_condition(
"CONCAT(comments.summary,COALESCE(comments.comment,''))",
params[:comments_has],
Expand Down
3 changes: 2 additions & 1 deletion app/classes/query/project_pattern_search.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ def initialize_flavor
def search_fields
"CONCAT(" \
"projects.title," \
"COALESCE(projects.summary,'')" \
"COALESCE(projects.summary,'')," \
"COALESCE(projects.field_slip_prefix,'')" \
")"
end
end
144 changes: 144 additions & 0 deletions app/controllers/field_slips_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# frozen_string_literal: true

class FieldSlipsController < ApplicationController
before_action :set_field_slip, only: [:edit, :update, :destroy]
before_action :login_required, except: [:show]

# GET /field_slips or /field_slips.json
def index
@field_slips = FieldSlip.includes(
[{ observation: [:location, :name, :namings, :rss_log, :user] },
:project, :user]
)
end

# GET /field_slips/1 or /field_slips/1.json
def show
obs = nil
if params[:id].match?(/^\d+$/)
set_field_slip
else
@field_slip = FieldSlip.find_by(code: params[:id].upcase)
obs = @field_slip&.observation
end
if @field_slip
redirect_to(observation_url(id: obs.id)) if obs
else
redirect_to(new_field_slip_url(code: params[:id].upcase))
end
end

# GET /field_slips/new
def new
@field_slip = FieldSlip.new
@field_slip.code = params[:code].upcase if params.include?(:code)
end

# GET /field_slips/1/edit
def edit
return unless @field_slip.user != User.current

redirect_to(field_slip_url(id: @field_slip.id))
end

# POST /field_slips or /field_slips.json
def create
@field_slip = FieldSlip.new(field_slip_params)

respond_to do |format|
check_project_membership
check_for_last_obs
if params[:commit] == :field_slip_last_obs.t
@field_slip.observation = ObservationView.last(User.current)
end
if @field_slip.save
format.html do
if params[:commit] == :field_slip_create_obs.t
redirect_to(new_observation_url(field_code: @field_slip.code))
else
redirect_to(field_slip_url(@field_slip),
notice: :field_slip_created.t)
end
end
format.json { render(:show, status: :created, location: @field_slip) }
else
format.html { render(:new, status: :unprocessable_entity) }
format.json do
render(json: @field_slip.errors, status: :unprocessable_entity)
end
end
end
end

# PATCH/PUT /field_slips/1 or /field_slips/1.json
def update
respond_to do |format|
check_for_last_obs
if @field_slip.update(field_slip_params)
format.html do
if params[:commit] == :field_slip_create_obs.t
redirect_to(new_observation_url(field_code: @field_slip.code))
else
redirect_to(field_slip_url(@field_slip),
notice: :field_slip_updated.t)
end
end
format.json { render(:show, status: :ok, location: @field_slip) }
else
format.html { render(:edit, status: :unprocessable_entity) }
format.json do
render(json: @field_slip.errors, status: :unprocessable_entity)
end
end
end
end

# DELETE /field_slips/1 or /field_slips/1.json
def destroy
if @field_slip.user != User.current
redirect_to(field_slip_url(id: @field_slip.id))
return
end

@field_slip.destroy!

respond_to do |format|
format.html do
redirect_to(field_slips_url,
notice: :field_slip_destroyed.t)
end
format.json { head(:no_content) }
end
end

private

# Use callbacks to share common setup or constraints between actions.
def set_field_slip
@field_slip = FieldSlip.find(params[:id])
end

# Only allow a list of trusted parameters through.
def field_slip_params
params.require(:field_slip).permit(:observation_id, :project_id, :code)
end

def check_project_membership
project = @field_slip&.project
return unless project&.can_join?(User.current)

project.user_group.users << User.current
flash_notice(:field_slip_welcome.t(title: project.title))
end

def check_for_last_obs
return unless params[:commit] == :field_slip_last_obs.t

obs = ObservationView.last(User.current)
@field_slip.observation = obs
project = @field_slip.project
return unless obs && project&.user_can_add_observation?(obs, User.current)

project.add_observation(obs)
end
end
4 changes: 3 additions & 1 deletion app/controllers/herbarium_records_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,9 @@ def default_herbarium_record
end

def default_accession_number
if @observation.collection_numbers.length == 1
if @observation.field_slips.length == 1
@observation.field_slips.first.code
elsif @observation.collection_numbers.length == 1
@observation.collection_numbers.first.format_name
else
"MO #{@observation.id}"
Expand Down
41 changes: 27 additions & 14 deletions app/controllers/observations_controller/new_and_create.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,12 @@ def new
@reasons = @naming.init_reasons
@images = []
@good_images = []
@field_code = params[:field_code]
init_specimen_vars
init_project_vars_for_create
init_list_vars
defaults_from_last_observation_created
add_field_slip_project(@field_code)
end

##############################################################################
Expand Down Expand Up @@ -83,6 +85,14 @@ def defaults_from_last_observation_created
end
end

def add_field_slip_project(code)
project = FieldSlip.find_by(code: code)&.project
return unless project
return unless project&.member?(User.current)

@project_checks[project.id] = true
end

##############################################################################

public
Expand All @@ -102,20 +112,14 @@ def create
success = false if @name && !@vote.value.nil? && !validate_object(@vote)
success = false if @bad_images != []
success = false if success && !save_observation(@observation)

# Once observation is saved we can save everything else.
if success
@observation.log(:log_observation_created)
# should always succeed
save_everything_else(params.dig(:naming, :reasons))
strip_images! if @observation.gps_hidden
flash_notice(:runtime_observation_success.t(id: @observation.id))
redirect_to_next_page

# If anything failed reload the form.
else
reload_new_form(params.dig(:naming, :reasons))
end
return reload_new_form(params.dig(:naming, :reasons)) unless success

@observation.log(:log_observation_created)
save_everything_else(params.dig(:naming, :reasons))
strip_images! if @observation.gps_hidden
update_field_slip(@observation, params[:field_code])
flash_notice(:runtime_observation_success.t(id: @observation.id))
redirect_to_next_page
end

##############################################################################
Expand Down Expand Up @@ -309,10 +313,19 @@ def reload_new_form(reasons)
@reasons = @naming.init_reasons(reasons)
@images = @bad_images
@new_image.when = @observation.when
@field_code = params[:field_code]
init_specimen_vars_for_reload
init_project_vars_for_create
init_project_vars_for_reload(@observation)
init_list_vars_for_reload(@observation)
render(action: :new, location: new_observation_path(q: get_query_param))
end

def update_field_slip(observation, field_code)
field_slip = FieldSlip.find_by(code: field_code)
return unless field_slip

field_slip.observation = observation
field_slip.save
end
end
3 changes: 2 additions & 1 deletion app/controllers/projects_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ def update

upload_image_if_present
@summary = params[:project][:summary]
@field_slip_prefix = params[:project][:field_slip_prefix]
if valid_title && valid_where && valid_dates
if @project.update(project_create_params)
override_fixed_dates
Expand Down Expand Up @@ -242,7 +243,7 @@ def show_selected_projects(query, args = {})

def project_create_params
params.require(:project).
permit(:title, :summary, :open_membership,
permit(:title, :summary, :open_membership, :field_slip_prefix,
"start_date(1i)", "start_date(2i)", "start_date(3i)",
"end_date(1i)", "end_date(2i)", "end_date(3i)")
end
Expand Down
9 changes: 9 additions & 0 deletions app/helpers/field_slips_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

module FieldSlipsHelper
def last_observation
return unless User.current

ObservationView.last(User.current)
end
end
42 changes: 42 additions & 0 deletions app/models/field_slip.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# frozen_string_literal: true

class FieldSlip < AbstractModel
belongs_to :observation
belongs_to :project
belongs_to :user

validates :code, uniqueness: true
validates :code, presence: true
validate do |field_slip|
unless field_slip.code.match?(/[^\d.-]/)
errors.add(:code, :format, message: :field_slip_code_format_error.t)
end
end

def code=(val)
self[:code] = val.upcase
return if project

prefix_match = code.match(/(^.+)[ -]\d+$/)
return unless prefix_match

self.project = Project.find_by(field_slip_prefix: prefix_match[1])
end

def title
code
end

def projects
@projects ||= find_projects
end

def find_projects
result = Project.includes(:project_members).where(
project_members: { user: User.current }
).order(:title).pluck(:title, :id)
return result unless project && result.exclude?([project.title, project.id])

result.unshift([project.title, project.id])
end
end
8 changes: 6 additions & 2 deletions app/models/observation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ class Observation < AbstractModel # rubocop:disable Metrics/ClassLength

has_many :observation_collection_numbers, dependent: :destroy
has_many :collection_numbers, through: :observation_collection_numbers
has_many :field_slips, dependent: :destroy

has_many :observation_herbarium_records, dependent: :destroy
has_many :herbarium_records, through: :observation_herbarium_records
Expand Down Expand Up @@ -503,6 +504,7 @@ class Observation < AbstractModel # rubocop:disable Metrics/ClassLength
scope :show_includes, lambda {
strict_loading.includes(
:collection_numbers,
:field_slips,
{ comments: :user },
{ external_links: { external_site: { project: :user_group } } },
{ herbarium_records: [{ herbarium: :curators }, :user] },
Expand Down Expand Up @@ -1076,8 +1078,9 @@ def add_image(img)
def remove_image(img)
if images.include?(img) || thumb_image_id == img.id
images.delete(img)
update(thumb_image: images.empty? ? nil : images.first) \
if thumb_image_id == img.id
if thumb_image_id == img.id
update(thumb_image: images.empty? ? nil : images.first)
end
notify_users(:removed_image)
end
img
Expand Down Expand Up @@ -1105,6 +1108,7 @@ def turn_off_specimen_if_no_more_records
return unless collection_numbers.empty?
return unless herbarium_records.empty?
return unless sequences.empty?
return unless field_slips.empty?

update(specimen: false)
end
Expand Down

0 comments on commit a2a9bb1

Please sign in to comment.