image admin
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
ActiveAdmin.register Image do
|
||||
permit_params :file_upload
|
||||
|
||||
menu priority: 5
|
||||
|
||||
index do
|
||||
selectable_column
|
||||
id_column
|
||||
column :original_filename
|
||||
column :content_type
|
||||
column(:preview) do |img|
|
||||
if File.exist?(img.file_path)
|
||||
image_tag("/api/image/#{img.id}", style: "max-height:60px;max-width:120px;object-fit:contain;")
|
||||
end
|
||||
end
|
||||
column :created_at
|
||||
actions
|
||||
end
|
||||
|
||||
filter :original_filename
|
||||
filter :content_type
|
||||
|
||||
show do
|
||||
attributes_table do
|
||||
row :id
|
||||
row :original_filename
|
||||
row :filename
|
||||
row :content_type
|
||||
row(:preview) do |img|
|
||||
if File.exist?(img.file_path)
|
||||
image_tag("/api/image/#{img.id}", style: "max-height:300px;max-width:100%;object-fit:contain;")
|
||||
else
|
||||
"File not found on disk"
|
||||
end
|
||||
end
|
||||
row :created_at
|
||||
row :updated_at
|
||||
end
|
||||
end
|
||||
|
||||
form html: { multipart: true } do |f|
|
||||
f.inputs do
|
||||
f.input :file_upload, as: :file, label: "Image File"
|
||||
end
|
||||
f.actions
|
||||
end
|
||||
end
|
||||
@@ -1,14 +1,24 @@
|
||||
ActiveAdmin.register Member do
|
||||
permit_params :nick, :real_nick, :motto, :avatar_filename
|
||||
permit_params :nick, :real_nick, :motto, :avatar_filename, :image_id
|
||||
|
||||
menu priority: 4
|
||||
|
||||
index do
|
||||
selectable_column
|
||||
id_column
|
||||
column :nick
|
||||
column :nick do |m|
|
||||
link_to m.nick, edit_admin_member_path(m)
|
||||
end
|
||||
column :real_nick
|
||||
column :motto do |m|
|
||||
truncate m.motto, length: 60
|
||||
end
|
||||
column :avatar_filename
|
||||
column(:image) do |m|
|
||||
if m.image && File.exist?(m.image.file_path)
|
||||
image_tag "/api/image/#{m.image.id}", style: "max-height:40px;max-width:80px;object-fit:contain;"
|
||||
end
|
||||
end
|
||||
column :created_at
|
||||
actions
|
||||
end
|
||||
@@ -16,15 +26,19 @@ ActiveAdmin.register Member do
|
||||
filter :nick
|
||||
filter :real_nick
|
||||
|
||||
show do
|
||||
attributes_table do
|
||||
row :id
|
||||
row :nick
|
||||
row :real_nick
|
||||
row :motto
|
||||
row :avatar_filename
|
||||
row :created_at
|
||||
row :updated_at
|
||||
show title: proc { |m| m.nick } do
|
||||
active_admin_form_for [:admin, resource], url: admin_member_path(resource), html: { method: :put } do |f|
|
||||
f.inputs "Edit Member" do
|
||||
f.input :nick
|
||||
f.input :real_nick
|
||||
f.input :motto
|
||||
f.input :avatar_filename,
|
||||
hint: "Fallback image filename (e.g. mr.zero.png) — only used when no image is selected above."
|
||||
f.input :image, as: :select,
|
||||
collection: Image.order(:original_filename).map { |img| [img.original_filename, img.id] },
|
||||
include_blank: "— no image (use avatar_filename) —"
|
||||
end
|
||||
f.actions
|
||||
end
|
||||
end
|
||||
|
||||
@@ -33,7 +47,11 @@ ActiveAdmin.register Member do
|
||||
f.input :nick
|
||||
f.input :real_nick
|
||||
f.input :motto
|
||||
f.input :avatar_filename
|
||||
f.input :avatar_filename,
|
||||
hint: "Fallback image filename (e.g. mr.zero.png) — only used when no image is selected above."
|
||||
f.input :image, as: :select,
|
||||
collection: Image.order(:original_filename).map { |img| [img.original_filename, img.id] },
|
||||
include_blank: "— no image (use avatar_filename) —"
|
||||
end
|
||||
f.actions
|
||||
end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
ActiveAdmin.register Software do
|
||||
permit_params :name, :title, :author, :desc, :story,
|
||||
:license, :platform, :status, :highlighted,
|
||||
:license, :platform, :status, :highlighted, :image_id,
|
||||
external_links_attributes: [:id, :label, :url, :_destroy],
|
||||
releases_attributes: [:id, :_destroy]
|
||||
|
||||
@@ -9,13 +9,20 @@ ActiveAdmin.register Software do
|
||||
index do
|
||||
selectable_column
|
||||
id_column
|
||||
column :name
|
||||
column :name do |sw|
|
||||
link_to sw.name, admin_software_path(sw)
|
||||
end
|
||||
column :title
|
||||
column :platform
|
||||
column :status do |sw|
|
||||
status_tag sw.status
|
||||
end
|
||||
column :highlighted
|
||||
column(:image) do |sw|
|
||||
if sw.image && File.exist?(sw.image.file_path)
|
||||
image_tag "/api/image/#{sw.image.id}", style: "max-height:40px;max-width:80px;object-fit:contain;"
|
||||
end
|
||||
end
|
||||
column :created_at
|
||||
actions
|
||||
end
|
||||
@@ -27,37 +34,31 @@ ActiveAdmin.register Software do
|
||||
filter :status, as: :select, collection: %w[development demo released archived]
|
||||
filter :highlighted
|
||||
|
||||
show do
|
||||
attributes_table do
|
||||
row :id
|
||||
row :name
|
||||
row :title
|
||||
row :author
|
||||
row :platform
|
||||
row :status
|
||||
row :highlighted
|
||||
row :license
|
||||
row(:desc) { |sw| simple_format sw.desc }
|
||||
row(:story) { |sw| simple_format sw.story }
|
||||
row :created_at
|
||||
row :updated_at
|
||||
end
|
||||
show title: proc { |sw| sw.title } do
|
||||
active_admin_form_for [:admin, resource], url: admin_software_path(resource), html: { method: :put } do |f|
|
||||
f.inputs "Details" do
|
||||
f.input :name
|
||||
f.input :title
|
||||
f.input :author
|
||||
f.input :platform, as: :select, collection: %w[tic80 ebitengine love]
|
||||
f.input :status, as: :select, collection: %w[development demo released archived]
|
||||
f.input :highlighted
|
||||
f.input :license
|
||||
f.input :image, as: :select,
|
||||
collection: Image.order(:original_filename).map { |img| [img.original_filename, img.id] },
|
||||
include_blank: "— no image —"
|
||||
f.input :desc, as: :text, input_html: { rows: 4 }
|
||||
f.input :story, as: :text, input_html: { rows: 8 }
|
||||
end
|
||||
|
||||
panel "External Links" do
|
||||
table_for resource.external_links do
|
||||
column :label
|
||||
column(:url) { |el| link_to el.url, el.url, target: "_blank" }
|
||||
column :created_at
|
||||
column do |el|
|
||||
link_to "Edit", edit_admin_software_external_link_path(resource, el)
|
||||
concat " "
|
||||
link_to "Delete", admin_software_external_link_path(resource, el),
|
||||
method: :delete, data: { confirm: "Are you sure?" }
|
||||
f.inputs "External Links" do
|
||||
f.has_many :external_links, allow_destroy: true, new_record: true do |el|
|
||||
el.input :label
|
||||
el.input :url
|
||||
end
|
||||
end
|
||||
br
|
||||
link_to "Add External Link",
|
||||
new_admin_software_external_link_path(resource)
|
||||
|
||||
f.actions
|
||||
end
|
||||
|
||||
panel "Releases" do
|
||||
@@ -81,6 +82,9 @@ ActiveAdmin.register Software do
|
||||
f.input :status, as: :select, collection: %w[development demo released archived]
|
||||
f.input :highlighted
|
||||
f.input :license
|
||||
f.input :image, as: :select,
|
||||
collection: Image.order(:original_filename).map { |img| [img.original_filename, img.id] },
|
||||
include_blank: "— no image —"
|
||||
f.input :desc, as: :text, input_html: { rows: 4 }
|
||||
f.input :story, as: :text, input_html: { rows: 8 }
|
||||
end
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
class Api::ImagesController < ApplicationController
|
||||
skip_before_action :verify_authenticity_token
|
||||
|
||||
def show
|
||||
image = Image.find(params[:id])
|
||||
path = image.file_path
|
||||
|
||||
return render plain: "Not Found", status: :not_found unless File.exist?(path)
|
||||
|
||||
send_file path, type: image.content_type, disposition: "inline"
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
render plain: "Not Found", status: :not_found
|
||||
end
|
||||
end
|
||||
@@ -1,7 +1,13 @@
|
||||
class Api::MembersController < ApiController
|
||||
def index
|
||||
members = Member.order(:id).map do |m|
|
||||
{ nick: m.nick, real_nick: m.real_nick, motto: m.motto, avatar_filename: m.avatar_filename }
|
||||
members = Member.includes(:image).order(:id).map do |m|
|
||||
{
|
||||
nick: m.nick,
|
||||
real_nick: m.real_nick,
|
||||
motto: m.motto,
|
||||
avatar_filename: m.avatar_filename,
|
||||
image_url: m.image_id ? "/api/image/#{m.image_id}" : nil
|
||||
}
|
||||
end
|
||||
render json: members
|
||||
end
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
class Image < ApplicationRecord
|
||||
UPLOAD_PATH = ENV.fetch("IMAGE_CONTAINER_PATH", "/images")
|
||||
|
||||
attr_accessor :file_upload
|
||||
|
||||
before_save :process_upload, if: -> { file_upload.present? }
|
||||
|
||||
def self.ransackable_attributes(auth_object = nil)
|
||||
%w[content_type created_at filename id original_filename updated_at]
|
||||
end
|
||||
|
||||
def file_path
|
||||
File.join(UPLOAD_PATH, filename.to_s)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def process_upload
|
||||
FileUtils.mkdir_p(UPLOAD_PATH)
|
||||
self.original_filename = file_upload.original_filename
|
||||
self.content_type = file_upload.content_type.presence || "application/octet-stream"
|
||||
ext = File.extname(file_upload.original_filename)
|
||||
self.filename = "#{SecureRandom.uuid}#{ext}"
|
||||
IO.copy_stream(file_upload.to_io, file_path)
|
||||
end
|
||||
end
|
||||
@@ -1,5 +1,11 @@
|
||||
class Member < ApplicationRecord
|
||||
belongs_to :image, optional: true
|
||||
|
||||
def self.ransackable_attributes(auth_object = nil)
|
||||
%w[avatar_filename created_at id motto nick real_nick updated_at]
|
||||
%w[avatar_filename created_at id image_id motto nick real_nick updated_at]
|
||||
end
|
||||
|
||||
def self.ransackable_associations(auth_object = nil)
|
||||
%w[image]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
class Software < ApplicationRecord
|
||||
self.table_name = "softwares"
|
||||
|
||||
belongs_to :image, optional: true
|
||||
|
||||
has_many :releases, foreign_key: :software_id
|
||||
has_many :external_links, foreign_key: :software_id
|
||||
|
||||
@@ -9,10 +11,10 @@ class Software < ApplicationRecord
|
||||
default_scope { where(deleted_at: nil) }
|
||||
|
||||
def self.ransackable_attributes(auth_object = nil)
|
||||
%w[author created_at desc highlighted id license name platform site status story title updated_at]
|
||||
%w[author created_at desc highlighted id image_id license name platform site status story title updated_at]
|
||||
end
|
||||
|
||||
def self.ransackable_associations(auth_object = nil)
|
||||
%w[releases external_links]
|
||||
%w[releases external_links image]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
class SoftwareHighlightedService
|
||||
def call
|
||||
software = Software.includes(:external_links)
|
||||
software = Software.includes(:external_links, :image)
|
||||
.where(highlighted: true)
|
||||
.order(id: :desc)
|
||||
.first
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
class SoftwareListService
|
||||
def call
|
||||
softwares = Software.includes(:releases, :external_links).all
|
||||
softwares = Software.includes(:releases, :external_links, :image).all
|
||||
items = softwares.map do |sw|
|
||||
SoftwareSerializer.show_data(sw, sw.releases.to_a)
|
||||
end
|
||||
|
||||
@@ -32,7 +32,8 @@ class SoftwareSerializer
|
||||
"platform" => sw.platform,
|
||||
"status" => sw.status,
|
||||
"highlighted" => sw.highlighted ? true : false,
|
||||
"externalLinks" => sw.external_links.map { |el| serialize_external_link(el) }
|
||||
"externalLinks" => sw.external_links.map { |el| serialize_external_link(el) },
|
||||
"imageUrl" => sw.image_id ? "/api/image/#{sw.image_id}" : nil
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user