2019-06-06 16:34:53 +02:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
# Project is the documentation about an object built by a fab-user
|
|
|
|
# It can describe the steps taken by the fab-user to build his object, provide photos, description, attached CAO files, etc.
|
2015-05-05 03:10:25 +02:00
|
|
|
class Project < ActiveRecord::Base
|
|
|
|
include AASM
|
|
|
|
include NotifyWith::NotificationAttachedObject
|
2016-04-20 18:13:36 +02:00
|
|
|
include OpenlabSync
|
2015-05-05 03:10:25 +02:00
|
|
|
|
2016-03-23 18:39:41 +01:00
|
|
|
# elastic initialisations
|
|
|
|
include Elasticsearch::Model
|
|
|
|
index_name 'fablab'
|
|
|
|
document_type 'projects'
|
|
|
|
|
|
|
|
# kaminari
|
2019-06-06 16:34:53 +02:00
|
|
|
# -- dependency in app/assets/javascripts/controllers/projects.js.erb
|
|
|
|
paginates_per 16
|
2016-03-23 18:39:41 +01:00
|
|
|
|
|
|
|
# friendlyId
|
2015-05-05 03:10:25 +02:00
|
|
|
extend FriendlyId
|
|
|
|
friendly_id :name, use: :slugged
|
|
|
|
|
|
|
|
has_one :project_image, as: :viewable, dependent: :destroy
|
|
|
|
accepts_nested_attributes_for :project_image, allow_destroy: true
|
|
|
|
has_many :project_caos, as: :viewable, dependent: :destroy
|
2015-05-18 10:16:21 +02:00
|
|
|
accepts_nested_attributes_for :project_caos, allow_destroy: true, reject_if: :all_blank
|
2015-05-05 03:10:25 +02:00
|
|
|
|
2019-06-06 16:34:53 +02:00
|
|
|
has_and_belongs_to_many :machines, join_table: 'projects_machines'
|
|
|
|
has_and_belongs_to_many :spaces, join_table: 'projects_spaces'
|
|
|
|
has_and_belongs_to_many :components, join_table: 'projects_components'
|
|
|
|
has_and_belongs_to_many :themes, join_table: 'projects_themes'
|
2015-05-05 03:10:25 +02:00
|
|
|
|
|
|
|
has_many :project_users, dependent: :destroy
|
|
|
|
has_many :users, through: :project_users
|
|
|
|
|
2019-06-06 16:34:53 +02:00
|
|
|
belongs_to :author, foreign_key: :author_statistic_profile_id, class_name: 'StatisticProfile'
|
2015-05-05 03:10:25 +02:00
|
|
|
belongs_to :licence, foreign_key: :licence_id
|
|
|
|
|
|
|
|
has_many :project_steps, dependent: :destroy
|
|
|
|
accepts_nested_attributes_for :project_steps, allow_destroy: true
|
2016-04-21 17:10:50 +02:00
|
|
|
|
|
|
|
# validations
|
|
|
|
validates :author, :name, presence: true
|
2015-05-05 03:10:25 +02:00
|
|
|
|
|
|
|
after_save :after_save_and_publish
|
|
|
|
|
2019-06-06 16:34:53 +02:00
|
|
|
aasm column: 'state' do
|
2015-05-05 03:10:25 +02:00
|
|
|
state :draft, initial: true
|
|
|
|
state :published
|
|
|
|
|
2019-06-06 16:34:53 +02:00
|
|
|
event :publish, after: :notify_admin_when_project_published do
|
|
|
|
transitions from: :draft, to: :published
|
2015-05-05 03:10:25 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-06-06 16:34:53 +02:00
|
|
|
# scopes
|
2015-05-05 03:10:25 +02:00
|
|
|
scope :published, -> { where("state = 'published'") }
|
|
|
|
|
2016-03-23 18:39:41 +01:00
|
|
|
## elastic
|
|
|
|
# callbacks
|
2019-06-06 16:34:53 +02:00
|
|
|
after_save { ProjectIndexerWorker.perform_async(:index, id) }
|
|
|
|
after_destroy { ProjectIndexerWorker.perform_async(:delete, id) }
|
2016-03-23 18:39:41 +01:00
|
|
|
|
2018-04-04 14:05:48 +02:00
|
|
|
# mapping
|
|
|
|
settings index: { number_of_replicas: 0 } do
|
2016-03-23 18:39:41 +01:00
|
|
|
mappings dynamic: 'true' do
|
|
|
|
indexes 'state', analyzer: 'simple'
|
|
|
|
indexes 'tags', analyzer: Rails.application.secrets.elasticsearch_language_analyzer
|
|
|
|
indexes 'name', analyzer: Rails.application.secrets.elasticsearch_language_analyzer
|
|
|
|
indexes 'description', analyzer: Rails.application.secrets.elasticsearch_language_analyzer
|
|
|
|
indexes 'project_steps' do
|
2019-06-06 16:34:53 +02:00
|
|
|
indexes 'title', analyzer: Rails.application.secrets.elasticsearch_language_analyzer
|
|
|
|
indexes 'description', analyzer: Rails.application.secrets.elasticsearch_language_analyzer
|
2016-03-23 18:39:41 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-06-13 16:29:12 +02:00
|
|
|
# the resulting JSON will be indexed in ElasticSearch, as /fablab/projects
|
2016-03-23 18:39:41 +01:00
|
|
|
def as_indexed_json
|
2019-06-06 16:34:53 +02:00
|
|
|
ApplicationController.new.view_context.render(
|
|
|
|
partial: 'api/projects/indexed',
|
|
|
|
locals: { project: self },
|
|
|
|
formats: [:json],
|
|
|
|
handlers: [:jbuilder]
|
|
|
|
)
|
2016-03-23 18:39:41 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def self.search(params, current_user)
|
|
|
|
Project.__elasticsearch__.search(build_search_query_from_context(params, current_user))
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.build_search_query_from_context(params, current_user)
|
|
|
|
search = {
|
|
|
|
query: {
|
2018-06-05 12:30:08 +02:00
|
|
|
bool: {
|
|
|
|
must: [],
|
|
|
|
should: [],
|
2019-06-06 16:34:53 +02:00
|
|
|
filter: []
|
2016-03-23 18:39:41 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-06 16:34:53 +02:00
|
|
|
# we sort by created_at if there isn't a query
|
|
|
|
if params['q'].blank?
|
2016-03-23 18:39:41 +01:00
|
|
|
search[:sort] = { created_at: { order: :desc } }
|
2019-06-06 16:34:53 +02:00
|
|
|
else
|
|
|
|
# otherwise we search for the word (q) in various fields
|
2018-06-05 12:30:08 +02:00
|
|
|
search[:query][:bool][:must] << {
|
2016-03-23 18:39:41 +01:00
|
|
|
multi_match: {
|
|
|
|
query: params['q'],
|
|
|
|
type: 'most_fields',
|
2019-06-06 16:34:53 +02:00
|
|
|
fields: %w[tags^4 name^5 description^3 project_steps.title^2 project_steps.description]
|
2016-03-23 18:39:41 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2019-06-06 16:34:53 +02:00
|
|
|
# we filter by themes, components, machines
|
|
|
|
params.each do |name, value|
|
2016-03-23 18:39:41 +01:00
|
|
|
if name =~ /(.+_id$)/
|
2018-06-05 12:30:08 +02:00
|
|
|
search[:query][:bool][:filter] << { term: { "#{name}s" => value } } if value
|
2016-03-23 18:39:41 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-06-06 16:34:53 +02:00
|
|
|
# if use select filter 'my project' or 'my collaborations'
|
|
|
|
if current_user && params.key?('from')
|
|
|
|
search[:query][:bool][:filter] << { term: { author_id: current_user.id } } if params['from'] == 'mine'
|
|
|
|
search[:query][:bool][:filter] << { term: { user_ids: current_user.id } } if params['from'] == 'collaboration'
|
2016-03-23 18:39:41 +01:00
|
|
|
end
|
|
|
|
|
2019-06-06 16:34:53 +02:00
|
|
|
# if user is connected, also display his draft projects
|
|
|
|
if current_user
|
2018-06-05 12:30:08 +02:00
|
|
|
search[:query][:bool][:should] << { term: { state: 'published' } }
|
|
|
|
search[:query][:bool][:should] << { term: { author_id: current_user.id } }
|
|
|
|
search[:query][:bool][:should] << { term: { user_ids: current_user.id } }
|
2019-06-06 16:34:53 +02:00
|
|
|
else
|
|
|
|
# otherwise display only published projects
|
2018-06-05 12:30:08 +02:00
|
|
|
search[:query][:bool][:must] << { term: { state: 'published' } }
|
2016-03-23 18:39:41 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
search
|
|
|
|
end
|
|
|
|
|
2015-05-05 03:10:25 +02:00
|
|
|
private
|
2019-06-06 16:34:53 +02:00
|
|
|
|
2015-05-05 03:10:25 +02:00
|
|
|
def notify_admin_when_project_published
|
|
|
|
NotificationCenter.call type: 'notify_admin_when_project_published',
|
|
|
|
receiver: User.admins,
|
|
|
|
attached_object: self
|
|
|
|
end
|
|
|
|
|
|
|
|
def after_save_and_publish
|
2019-06-06 16:34:53 +02:00
|
|
|
return unless state_changed? && published?
|
|
|
|
|
|
|
|
update_columns(published_at: Time.now)
|
|
|
|
notify_admin_when_project_published
|
2015-05-05 03:10:25 +02:00
|
|
|
end
|
|
|
|
end
|