app/controllers/basil_controller.rb
class BasilController < ApplicationController
before_action :authenticate_user!, except: [:complete_commission, :about, :stats, :jam, :queue_jam_job, :commission_info]
before_action :require_admin_access, only: [:review], unless: -> { Rails.env.development? }
def index
disabled_content_types = [Universe]
@enabled_content_types = BasilService::ENABLED_PAGE_TYPES
@content_type = params[:content_type].try(:humanize) || 'Character'
if @content_type.present?
if !@enabled_content_types.include?(@content_type)
return raise "Invalid content type: #{params[:content_type]}"
end
@content = @current_user_content.fetch(@content_type, []).sort_by(&:name)
end
@generated_images_count = current_user.basil_commissions.with_deleted.count
end
def content
# Fetch the content page from our already-queried cache of current user content
@content_type = params[:content_type].humanize
@content = @current_user_content[@content_type].detect do |page|
page.id == params[:id].to_i
end
raise "No content found for #{params[:content_type]} with ID #{params[:id]} for user #{current_user.id}" if @content.nil?
# Fetch any existing Basil configurations/guidance for this character
@guidance = BasilFieldGuidance.find_or_initialize_by(
entity_type: @content.page_type,
entity_id: @content.id,
user: current_user
).try(:guidance)
@guidance ||= {}
# Fetch all the related fields for this content type and their values
# and format them into an array of [field, value] pairs to pass to the view
@relevant_fields = []
# TODO: either move this to the default field template (metadata for each field) or to a BasilService
case @content_type
when 'Character'
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Gender')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Age')
@relevant_fields.push *BasilService.include_all_fields_in_category(current_user, @content, ['Looks', 'Appearance'])
when 'Location'
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Name')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Type')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Description')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Geography', 'Area')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Geography', 'Climate')
when 'Item'
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Name')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Item Type')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Description')
@relevant_fields.push *BasilService.include_all_fields_in_category(current_user, @content, ['Looks', 'Appearance'])
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Abilities', 'Magical effects')
when 'Building'
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Name')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Type of building')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Description')
@relevant_fields.push *BasilService.include_all_fields_in_category(current_user, @content, ['Design'])
when 'Condition'
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Type of condition')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Description')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Effects', 'Symptoms')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Effects', 'Visual effects')
when 'Continent'
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Description')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Geography', 'Area')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Geography', 'Shape')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Geography', 'Topography')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Geography', 'Bodies of water')
when 'Country'
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Description')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Geography', 'Area')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Geography', 'Climate')
when 'Creature'
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Type of creature')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Description')
@relevant_fields.push *BasilService.include_all_fields_in_category(current_user, @content, ['Looks'])
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Traits', 'Method of attack')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Traits', 'Methods of defense')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Comparisons', 'Similar creatures')
when 'Deity'
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Description')
@relevant_fields.push *BasilService.include_all_fields_in_category(current_user, @content, ['Appearance'])
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Symbolism', 'Elements')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Symbolism', 'Symbols')
when 'Flora'
@relevant_fields.push *BasilService.include_all_fields_in_category(current_user, @content, ['Appearance'])
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Description')
when 'Food'
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Type of food')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Recipe', 'Ingredients')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Recipe', 'Cooking method')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Recipe', 'Color')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Recipe', 'Size')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Eating', 'Serving')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Eating', 'Texture')
when 'Government'
# DISABLE UNTIL WE HAVE A VISION OF WHAT TO GENERATE
# but yolo lets see what we get with the below
@relevant_fields.push *BasilService.include_all_fields_in_category(current_user, @content, ['Structure'])
when 'Group'
# PROBABLY NEEDS TEXTUAL INVERSION ON MEMBERS
when 'Job'
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Type of job')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Description')
when 'Landmark'
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Type of landmark')
@relevant_fields.push *BasilService.include_all_fields_in_category(current_user, @content, ['Appearance'])
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Description')
when 'Language'
# DISABLE UNTIL WE HAVE A VISION OF WHAT TO GENERATE
when 'Lore'
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Type')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Content', 'Genre')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Content', 'Tone')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Culture', 'Time period')
# TODO textual inversion of any linked pages
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'About', 'Subjects')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Description')
when 'Magic'
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Name')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Type of magic')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Description')
@relevant_fields.push *BasilService.include_all_fields_in_category(current_user, @content, ['Appearance'])
when 'Planet'
@relevant_fields.push *BasilService.include_all_fields_in_category(current_user, @content, ['Geography'])
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Astral', 'Moons')
when 'Race'
@relevant_fields.push *BasilService.include_all_fields_in_category(current_user, @content, ['Looks'])
when 'Religion'
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Beliefs', 'Places of worship')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Beliefs', 'Worship services')
when 'Scene'
# TODO hold off until we can use textual inversion of members + action + location
when 'School'
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Type of school')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Identity', 'Colors')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Description')
when 'Sport'
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Description')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Setup', 'Play area')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Setup', 'Equipment')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Setup', 'Number of players')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Setup', 'Scoring')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Culture', 'Uniforms')
when 'Technology'
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Description')
@relevant_fields.push *BasilService.include_all_fields_in_category(current_user, @content, ['Appearance'])
when 'Town'
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Description')
@relevant_fields.push *BasilService.include_all_fields_in_category(current_user, @content, ['Layout'])
when 'Tradition'
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Type of tradition')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Celebrations', 'Activities')
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Celebrations', 'Symbolism')
when 'Vehicle'
@relevant_fields.push BasilService.include_specific_field(current_user, @content, 'Overview', 'Type of vehicle')
@relevant_fields.push *BasilService.include_all_fields_in_category(current_user, @content, ['Looks'])
end
@relevant_fields.compact!
# Finally, cache some state we can reference in the view
@commissions = BasilCommission.where(entity_type: @content.page_type, entity_id: @content.id)
.where(saved_at: nil)
.order('id DESC')
.limit(10)
.includes(:basil_feedbacks, :image_blob)
@in_progress_commissions = @commissions.select { |c| c.completed_at.nil? }
@generated_images_count = current_user.basil_commissions.with_deleted.count
@can_request_another = current_user.on_premium_plan? || @generated_images_count < BasilService::FREE_IMAGE_LIMIT
@can_request_another = @can_request_another && @in_progress_commissions.count < BasilService::MAX_JOB_QUEUE_SIZE
end
def about
end
def jam
@recent_commissions = BasilCommission.where(entity_id: nil).order('id DESC').limit(24)
@total_count = BasilCommission.where(entity_id: nil).count
# For generating pie charts
@all_commissions = BasilCommission.where(entity_id: nil)
end
def queue_jam_job
created_prompt = [
jam_params[:age],
*jam_params[:features]
].compact.join(', ')
# Create our commission, then redirect back to preview it
BasilCommission.create!(
user: current_user,
entity: nil,
prompt: created_prompt,
job_id: SecureRandom.uuid,
style: ["realistic", "realistic2", "realistic3", "painting", "painting2", "painting3"].sample,
final_settings: jam_params
)
redirect_back(fallback_location: basil_jam_path, notice: "#{jam_params.fetch(:name, '').presence || 'Your character'} will be visualized shortly. Find them on this page!")
end
def commission_info
@commission = BasilCommission.find_by(job_id: params[:jobid])
raise "No BasilCommission with ID #{params[:jobid]}" if @commission.nil?
render json: {
image_url: @commission.image.url,
user_id: @commission.user_id,
prompt: @commission.prompt,
job_id: @commission.job_id,
created_at: @commission.created_at,
updated_at: @commission.updated_at,
completed_at: @commission.completed_at,
style: @commission.style,
final_settings: @commission.final_settings,
cached_seconds_taken: @commission.cached_seconds_taken,
}
end
def stats
@commissions = BasilCommission.all.with_deleted
@queued = BasilCommission.where(completed_at: nil)
@completed = BasilCommission.where.not(completed_at: nil).with_deleted
@average_wait_time = @completed.where('completed_at > ?', 24.hours.ago)
.average(:cached_seconds_taken) || 0
@seconds_over_time = @completed.where('completed_at > ?', 24.hours.ago)
.group_by { |c| ((c.cached_seconds_taken || 0) / 60).round }
.map { |minutes, list| [minutes, list.count] }
# Projected date, at our current rate, to reach 1,000,000 images
commission_counts_per_day = @commissions.group_by_day(:completed_at).values
@average_commissions_per_day = commission_counts_per_day.sum(0.0) / commission_counts_per_day.count
commissions_left = 1_000_000 - @commissions.count
@days_til_1_million_commissions = commissions_left / @average_commissions_per_day
# Feedback today
@feedback_today = BasilFeedback.where('updated_at > ?', 24.hours.ago)
.order(:score_adjustment)
.group(:score_adjustment)
.count
total = @feedback_today.values.sum
@emoji_counts_today = @feedback_today.map do |score, count|
emoji = case score
when -2 then "Very Bad :'("
when -1 then "Bad :("
when 0 then "Meh :|"
when 1 then "Good :)"
when 2 then "Very Good :D"
when 3 then "Lovely! <3"
end
[emoji, (count / total.to_f * 100).round(1)]
end
# Feedback all time
@feedback_before_today = BasilFeedback.where('updated_at < ?', 24.hours.ago)
.order(:score_adjustment)
.group(:score_adjustment)
.count
days_since_start = (Date.current - BasilFeedback.minimum(:updated_at).to_date)
days_since_start = 1 if days_since_start.zero? # no dividing by 0 lol
total = @feedback_before_today.values.sum
@emoji_counts_all_time = @feedback_before_today.map do |score, count|
emoji = case score
when -2 then "Very Bad :'("
when -1 then "Bad :("
when 0 then "Meh :|"
when 1 then "Good :)"
when 2 then "Very Good :D"
when 3 then "Lovely! <3"
end
[emoji, (count / total.to_f * 100).round(1)]
end
active_styles = [
BasilService.enabled_styles_for('Character'),
BasilService.enabled_styles_for('Location'),
# Also include anything we specifically want to track for now :)
'painting2', 'painting3', 'anime'
].flatten.compact.uniq
@total_score_per_style = BasilCommission.with_deleted
.where(style: active_styles)
.joins(:basil_feedbacks)
.group(:style)
.sum(:score_adjustment)
.map { |style, average| [style, average.round(1)] }
.sort_by(&:second)
.reverse
@average_score_per_style = BasilCommission.with_deleted
.where(style: active_styles)
.joins(:basil_feedbacks)
.group(:style)
.average(:score_adjustment)
.map { |style, average| [style, average.round(1)] }
.sort_by(&:second)
.reverse
@average_score_per_page_type = BasilCommission.with_deleted
.where.not(completed_at: nil)
.joins(:basil_feedbacks)
.group(:entity_type)
.average(:score_adjustment)
.map { |k, v| [k, (v * 100).round(1)] }.to_h
# queue size (total commissions - completed commissions)
# average time to complete today / this week
# commissions per day bar chart
# count(average time to complete) bar chart
end
def page_stats
@page_type = params[:page_type]
# TODO verify page_type is valid
@commissions = BasilCommission.where(entity_type: @page_type)
# Feedback today
@feedback_today = BasilFeedback.where('updated_at > ?', 24.hours.ago)
.where(basil_commission_id: @commissions.pluck(:id))
.order(:score_adjustment)
.group(:score_adjustment)
.count
total = @feedback_today.values.sum
@emoji_counts_today = @feedback_today.map do |score, count|
emoji = case score
when -2 then "Very Bad :'("
when -1 then "Bad :("
when 0 then "Meh :|"
when 1 then "Good :)"
when 2 then "Very Good :D"
when 3 then "Lovely! <3"
end
[emoji, (count / total.to_f * 100).round(1)]
end
# Feedback all time
@feedback_before_today = BasilFeedback.where('updated_at < ?', 24.hours.ago)
.where(basil_commission_id: @commissions.pluck(:id))
.order(:score_adjustment)
.group(:score_adjustment)
.count
days_since_start = (Date.current - BasilFeedback.minimum(:updated_at).to_date)
days_since_start = 1 if days_since_start.zero? # no dividing by 0 lol
total = @feedback_before_today.values.sum
@emoji_counts_all_time = @feedback_before_today.map do |score, count|
emoji = case score
when -2 then "Very Bad :'("
when -1 then "Bad :("
when 0 then "Meh :|"
when 1 then "Good :)"
when 2 then "Very Good :D"
when 3 then "Lovely! <3"
end
[emoji, (count / total.to_f * 100).round(1)]
end
active_styles = [
BasilService.enabled_styles_for(@page_type),
BasilService.experimental_styles_for(@page_type),
].flatten.compact.uniq
@total_score_per_style = @commissions.where(style: active_styles)
.joins(:basil_feedbacks)
.group(:style)
.sum(:score_adjustment)
.map { |style, average| [style, average.round(1)] }
.sort_by(&:second)
.reverse
@average_score_per_style = @commissions.where(style: active_styles)
.joins(:basil_feedbacks)
.group(:style)
.average(:score_adjustment)
.map { |style, average| [style, average.round(1)] }
.sort_by(&:second)
.reverse
@average_score_per_page_type = @commissions.where.not(completed_at: nil)
.joins(:basil_feedbacks)
.group(:entity_type)
.average(:score_adjustment)
.map { |k, v| [k, (v * 100).round(1)] }.to_h
# # queue size (total commissions - completed commissions)
# # average time to complete today / this week
# # commissions per day bar chart
# # count(average time to complete) bar chart
end
def review
@recent_commissions = BasilCommission.all.includes(:entity, :user).order('id DESC').limit(100)
@commissions_per_user_id = BasilCommission.with_deleted.where('created_at > ?', 48.hours.ago).group(:user_id).order('count_all DESC').limit(5).count
@unique_users_generating_count = BasilCommission.with_deleted.where('created_at > ?', 48.hours.ago).group(:user_id).count
@current_queue_items = BasilCommission.where(completed_at: nil).order('created_at ASC')
end
def commission
@generated_images_count = current_user.basil_commissions.with_deleted.count
if !current_user.on_premium_plan? && @generated_images_count > BasilService::FREE_IMAGE_LIMIT
redirect_back fallback_location: basil_path, notice: "You've reached your free image limit. Please upgrade to generate more images."
return
end
# Fetch the related content
@content = @current_user_content[commission_params.fetch(:entity_type)]
.find { |c| c.id == commission_params.fetch(:entity_id).to_i }
return raise "Invalid content commission params" if @content.nil?
current_queue_size = current_user.basil_commissions.where(completed_at: nil).where(entity: @content).count
if current_queue_size >= BasilService::MAX_JOB_QUEUE_SIZE
redirect_back fallback_location: basil_path, notice: "You can only have #{BasilService::MAX_JOB_QUEUE_SIZE} commissions per page in progress at a time. Please wait for one to complete before requesting another."
return
end
# Before creating the prompt, do a little config to tweak things to work well :)
labels_to_omit_label_text = [
"Name",
"Identifying Marks",
"Type",
"Description",
"Body Type",
"Item type",
"Type of food"
].map(&:downcase)
field_importance_multipliers = {
'hair': 1.15,
'hair color': 1.55,
'hair style': 1.10,
'skin tone': 1.05,
'race': 1.10,
'eye color': 1.05,
'gender': 1.15,
'description': 1.00,
'item type': 1.55,
'type': 1.15,
'type of building': 1.25,
'type of condition': 1.25,
'type of food': 1.25,
'type of landmark': 1.25,
'type of magic': 1.25,
'type of school': 1.25,
'type of vehicle': 1.25,
'type of creature': 1.25
}
label_value_pairs_to_skip_entirely = [
['race', 'human']
]
value_suffix_for_numerical_fields = {
'age': ' years old'
}
# Prepare our prompt components
prompt_components = []
commission_params.fetch(:field).each do |field_id, field_data|
label = field_data[:label].strip
value = field_data[:value].gsub(',', '')
.gsub("\r", '')
.gsub('(', '')
.gsub(')', '')
.gsub("\n", ' ')
.strip
importance = field_data[:importance].to_f
# Field skips
next if label_value_pairs_to_skip_entirely.include?([label.downcase, value.downcase])
# Do any per-field manipulations
importance *= field_importance_multipliers[label.downcase.to_sym] if field_importance_multipliers.key?(label.downcase.to_sym)
value += value_suffix_for_numerical_fields[label.downcase.to_sym] if value_suffix_for_numerical_fields.key?(label.downcase.to_sym)
label = '' if labels_to_omit_label_text.include?(label.downcase)
# Finally, cut down on any unnecessary precision to save more tokens
importance = importance.round(2)
component_text = "#{value} #{label}".strip
if importance == 1.0
# If the importance is exactly 1, we can omit the parentheses and save a few tokens, since the
# default attention importance is 1.
prompt_components.push "#{component_text}"
elsif importance != 0
# If the importance isn't 1 (default) or 0 (not included), we want to specify it in the prompt.
prompt_components.push "(#{component_text}:#{importance})"
end
end
# Build a prompt for Basil from the component parts
prompt = prompt_components.join(', ')
# Save our field weights as the latest guidance also
guidance = BasilFieldGuidance.find_or_initialize_by(entity_type: @content.page_type,
entity_id: @content.id,
user: current_user)
guidance_data = commission_params.fetch(:field)
.transform_values { |data| data[:importance].to_f }
.to_h
guidance.update(guidance: guidance_data)
BasilCommission.create!(
user: current_user,
entity_type: @content.page_type,
entity_id: @content.id,
prompt: prompt,
style: commission_params.fetch(:style, 'realistic'),
job_id: SecureRandom.uuid
)
redirect_to basil_content_path(@content.page_type, @content.id)
end
def complete_commission
commission = BasilCommission.find_by(job_id: params[:jobid])
raise "Tried to complete commission with invalid job ID #{params[:jobid]}" if commission.nil?
merged_settings = commission.final_settings || {}
commission.update!(completed_at: DateTime.current,
final_settings: merged_settings.merge(JSON.parse(params.fetch(:settings, "{}"))))
# Attach the image in S3 to our `image` ActiveStorage relation
key = "job-#{params[:jobid]}.png"
s3 = Aws::S3::Resource.new(region: "us-east-1")
obj = s3.bucket("basil-commissions").object(key)
params = {
filename: obj.key,
content_type: obj.content_type, # binary/octet-stream but we want image/png
byte_size: obj.size,
checksum: obj.etag.gsub('"',"")
}
blob = ActiveStorage::Blob.create_before_direct_upload!(**params)
blob.key = key
blob.service_name = :amazon_basil
blob.save!
commission.update(image: blob.signed_id)
commission.cache_after_complete!
render json: { success: true }
end
def feedback
commission = BasilCommission.find_by(job_id: params[:jobid])
score_adjustment = params[:basil_feedback][:score_adjustment].to_i
score_adjustment = score_adjustment.clamp(-3, 3)
feedback = commission.basil_feedbacks.find_or_initialize_by(user: current_user)
feedback.update!(score_adjustment: score_adjustment)
end
def help_rate
@reviewed_commission_count = BasilFeedback.where(user: current_user).where.not(score_adjustment: nil).count
@reviewed_commission_ids = BasilFeedback.where(user: current_user)
if params.key?(:rating)
@reviewed_commission_ids = @reviewed_commission_ids.where(score_adjustment: params[:rating].to_i)
@commissions = BasilCommission.where(id: @reviewed_commission_ids.pluck(:basil_commission_id))
.where.not(completed_at: nil)
.where(user: current_user)
.where.not(entity_type: nil, entity_id: nil)
.order(created_at: :desc)
.limit(50)
.includes(:entity)
.order(completed_at: :desc)
else
# Unreviewed commissions
@reviewed_commission_ids = @reviewed_commission_ids.where(score_adjustment: nil)
@commissions = BasilCommission.where.not(id: @reviewed_commission_ids)
.where.not(completed_at: nil)
.where(user: current_user)
.where.not(entity_type: nil, entity_id: nil)
.order(created_at: :desc)
.limit(50)
.includes(:entity)
.order(completed_at: :desc)
end
end
def save
@commission = BasilCommission.find_by(
id: params[:id],
user: current_user
)
@commission.update(saved_at: DateTime.current)
render json: { success: true }, status: 200
end
def delete
@commission = BasilCommission.find_by(
id: params[:id],
user: current_user
)
@commission.destroy!
render json: { success: true }, status: 200
end
private
def commission_params
params.require(:basil_commission).permit(:style, :entity_type, :entity_id, field: {})
end
def jam_params
params.require(:commission).permit(:name, :age, features: [])
end
end