diff --git a/app/controllers/api/docs_controller.rb b/app/controllers/api/docs_controller.rb
index 5dc76c0bb..675177632 100644
--- a/app/controllers/api/docs_controller.rb
+++ b/app/controllers/api/docs_controller.rb
@@ -4,6 +4,7 @@ module Api
# The API's own description, for Swagger UI at /api-docs.
class DocsController < ActionController::API
def show
+ expires_in 1.hour, public: true
render json: ApiDocs.openapi
end
end
diff --git a/app/controllers/api/v1/base_controller.rb b/app/controllers/api/v1/base_controller.rb
index a6fd2570d..37e3950e9 100644
--- a/app/controllers/api/v1/base_controller.rb
+++ b/app/controllers/api/v1/base_controller.rb
@@ -39,7 +39,7 @@ module Api
def update
resource = resource_class.find(params)
- # As it is now; the resource hook then checks what it would become.
+ # The record as it is; the resource then checks what the changes would make of it.
authorize! :update, resource.data
render_write resource, resource.update_attributes
end
@@ -89,12 +89,7 @@ module Api
def authenticate_member_from_token!
authenticate_with_http_token do |token, _options|
- auth = Authentication.find_by(token: token, provider: 'api')
- if auth.present?
- @current_user = auth.member
-
- return true
- end
+ @current_user = Authentication.find_by(token: token, provider: 'api')&.member
end
end
end
diff --git a/app/resources/application_resource.rb b/app/resources/application_resource.rb
index 42a9d2b1d..62a0bf585 100644
--- a/app/resources/application_resource.rb
+++ b/app/resources/application_resource.rb
@@ -31,19 +31,6 @@ class ApplicationResource < Graphiti::Resource
context.authorize!(:destroy, record) if written?(record)
end
- def written?(record)
- record.instance_of?(context.resource_class.model)
- end
-
- # A foreign key that points at nothing is a request for something that is not there, not a server error.
- def linked_records_exist!(record)
- record.class.reflect_on_all_associations(:belongs_to).reject(&:polymorphic?).each do |association|
- next if record[association.foreign_key].blank? || record.association(association.name).reader
-
- raise ActiveRecord::RecordNotFound, "Couldn't find #{association.klass.name} with id #{record[association.foreign_key]}"
- end
- end
-
# Photos are attached to plantings, gardens and harvests through the polymorphic photo_associations table.
# This is the `photos` relationship of one of those; filter[photo_id] on that resource is how photos link back.
def self.photos_of(type)
@@ -81,4 +68,30 @@ class ApplicationResource < Graphiti::Resource
def self.filter_only(name, type)
attribute name, type, readable: false, writable: false
end
+
+ # Read only: it can be listed and shown, and nothing else.
+ def self.read_only
+ primary_endpoint "/#{type}", %i(index show)
+ end
+
+ # The member a record belongs to. It is the member holding the token that wrote it, so it is never set by a request.
+ def self.owned
+ filter_only :owner_id, :integer
+ belongs_to :owner, resource: MemberResource
+ end
+
+ private
+
+ def written?(record)
+ record.instance_of?(context.resource_class.model)
+ end
+
+ # A foreign key that points at nothing is a request for something that is not there, not a server error.
+ def linked_records_exist!(record)
+ record.class.reflect_on_all_associations(:belongs_to).reject(&:polymorphic?).each do |association|
+ next if record[association.foreign_key].blank? || record.association(association.name).reader
+
+ raise ActiveRecord::RecordNotFound, "Couldn't find #{association.klass.name} with id #{record[association.foreign_key]}"
+ end
+ end
end
diff --git a/app/resources/crop_resource.rb b/app/resources/crop_resource.rb
index 1af61678f..b6097777b 100644
--- a/app/resources/crop_resource.rb
+++ b/app/resources/crop_resource.rb
@@ -2,15 +2,15 @@
class CropResource < ApplicationResource
self.model = Crop
- primary_endpoint '/crops', %i(index show)
+ read_only
secondary_endpoint '/crops/search', [:search]
- attribute :name, :string, writable: false
- attribute :en_wikipedia_url, :string, writable: false
- attribute :perennial, :boolean, writable: false
- attribute :median_lifespan, :integer, writable: false
- attribute :median_days_to_first_harvest, :integer, writable: false
- attribute :median_days_to_last_harvest, :integer, writable: false
+ attribute :name, :string
+ attribute :en_wikipedia_url, :string
+ attribute :perennial, :boolean
+ attribute :median_lifespan, :integer
+ attribute :median_days_to_first_harvest, :integer
+ attribute :median_days_to_last_harvest, :integer
filter_only :approval_status, :string
default_filter :approval_status do |scope|
diff --git a/app/resources/garden_resource.rb b/app/resources/garden_resource.rb
index 402427122..781ff15af 100644
--- a/app/resources/garden_resource.rb
+++ b/app/resources/garden_resource.rb
@@ -7,10 +7,9 @@ class GardenResource < ApplicationResource
filter_only :slug, :string
filter_only :active, :boolean
filter_only :location, :string
- filter_only :owner_id, :integer
filter_only :garden_type_id, :integer
- belongs_to :owner, resource: MemberResource
+ owned
has_many :plantings
photos_of 'Garden'
end
diff --git a/app/resources/harvest_resource.rb b/app/resources/harvest_resource.rb
index b09d8abfa..f3fc46843 100644
--- a/app/resources/harvest_resource.rb
+++ b/app/resources/harvest_resource.rb
@@ -12,12 +12,11 @@ class HarvestResource < ApplicationResource
attribute :crop_id, :integer, readable: false
attribute :planting_id, :integer, readable: false
- filter_only :owner_id, :integer
filter_only :plant_part_id, :integer
belongs_to :crop
belongs_to :planting
- belongs_to :owner, resource: MemberResource
+ owned
photos_of 'Harvest'
before_save do |harvest|
diff --git a/app/resources/job_resource.rb b/app/resources/job_resource.rb
index eb7737e3d..77b04246e 100644
--- a/app/resources/job_resource.rb
+++ b/app/resources/job_resource.rb
@@ -12,8 +12,7 @@ class JobResource < ApplicationResource
attribute :action, :string
attribute :garden_id, :integer, readable: false
- filter_only :owner_id, :integer
belongs_to :garden
- belongs_to :owner, resource: MemberResource
+ owned
end
diff --git a/app/resources/member_resource.rb b/app/resources/member_resource.rb
index 97cf87dba..cc4e507f0 100644
--- a/app/resources/member_resource.rb
+++ b/app/resources/member_resource.rb
@@ -2,10 +2,10 @@
class MemberResource < ApplicationResource
self.model = Member
- primary_endpoint '/members', %i(index show)
+ read_only
- attribute :login_name, :string, writable: false
- attribute :slug, :string, writable: false
+ attribute :login_name, :string
+ attribute :slug, :string
has_many :gardens, foreign_key: :owner_id
has_many :plantings, foreign_key: :owner_id
diff --git a/app/resources/photo_resource.rb b/app/resources/photo_resource.rb
index 005389d9e..e8bb4ef28 100644
--- a/app/resources/photo_resource.rb
+++ b/app/resources/photo_resource.rb
@@ -2,19 +2,18 @@
class PhotoResource < ApplicationResource
self.model = Photo
- primary_endpoint '/photos', %i(index show)
+ read_only
- attribute :thumbnail_url, :string, writable: false
- attribute :fullsize_url, :string, writable: false
- attribute :license_name, :string, writable: false
- attribute :link_url, :string, writable: false
- attribute :title, :string, writable: false
- filter_only :owner_id, :integer
+ attribute :thumbnail_url, :string
+ attribute :fullsize_url, :string
+ attribute :license_name, :string
+ attribute :link_url, :string
+ attribute :title, :string
filter :crop_id, :integer do
eq { |scope, ids| scope.where(id: PhotoAssociation.where(crop_id: ids).select(:photo_id)) }
end
- belongs_to :owner, resource: MemberResource
+ owned
%w(Planting Garden Harvest).each { |type| photographed type }
end
diff --git a/app/resources/planting_resource.rb b/app/resources/planting_resource.rb
index 9aa68cc19..f63fe9db6 100644
--- a/app/resources/planting_resource.rb
+++ b/app/resources/planting_resource.rb
@@ -31,7 +31,6 @@ class PlantingResource < ApplicationResource
attribute :crop_id, :integer, readable: false
attribute :garden_id, :integer, readable: false
- filter_only :owner_id, :integer
filter :active, :boolean do
eq { |scope, value| value ? scope.active : scope }
@@ -42,7 +41,7 @@ class PlantingResource < ApplicationResource
belongs_to :garden
belongs_to :crop
- belongs_to :owner, resource: MemberResource
+ owned
has_many :harvests
photos_of 'Planting'
end
diff --git a/app/resources/seed_resource.rb b/app/resources/seed_resource.rb
index 79bcfcdbd..71af7d129 100644
--- a/app/resources/seed_resource.rb
+++ b/app/resources/seed_resource.rb
@@ -14,8 +14,7 @@ class SeedResource < ApplicationResource
attribute :heirloom, :string
attribute :crop_id, :integer, readable: false
- filter_only :owner_id, :integer
belongs_to :crop
- belongs_to :owner, resource: MemberResource
+ owned
end
diff --git a/config/environments/production.rb b/config/environments/production.rb
index 55ccabc37..77547b3ef 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -98,7 +98,7 @@ Rails.application.configure do
ActionMailer::Base.delivery_method = :smtp
config.host = ENV.fetch('HOST', nil)
- config.x.api_base_url = "https://#{config.host}" if config.host.present? && ENV['API_BASE_URL'].blank?
+ config.x.api_base_url = ENV.fetch('API_BASE_URL') { "https://#{config.host}" }
config.analytics_code = <<-GET_CLICKY_SCRIPT