From b068c113a8d91d47e4ae8dfef74468d24c0364eb Mon Sep 17 00:00:00 2001 From: evazion Date: Sun, 14 Mar 2021 20:08:54 -0500 Subject: [PATCH] Add MediaAsset model. A MediaAsset represents an image or video file uploaded to Danbooru. It stores the metadata associated with the image or video. This is to work on decoupling files from posts so that images can be uploaded separately from posts. --- app/controllers/media_assets_controller.rb | 8 ++ app/logical/upload_service.rb | 7 ++ app/models/media_asset.rb | 7 ++ app/models/post.rb | 1 + app/policies/media_asset_policy.rb | 5 + config/routes.rb | 1 + .../20210901230931_create_media_assets.rb | 19 ++++ db/structure.sql | 100 ++++++++++++++++++ test/factories/media_asset.rb | 9 ++ .../media_assets_controller_test.rb | 14 +++ test/unit/upload_service_test.rb | 11 ++ 11 files changed, 182 insertions(+) create mode 100644 app/controllers/media_assets_controller.rb create mode 100644 app/models/media_asset.rb create mode 100644 app/policies/media_asset_policy.rb create mode 100644 db/migrate/20210901230931_create_media_assets.rb create mode 100644 test/factories/media_asset.rb create mode 100644 test/functional/media_assets_controller_test.rb diff --git a/app/controllers/media_assets_controller.rb b/app/controllers/media_assets_controller.rb new file mode 100644 index 000000000..cd8c37c91 --- /dev/null +++ b/app/controllers/media_assets_controller.rb @@ -0,0 +1,8 @@ +class MediaAssetsController < ApplicationController + respond_to :json, :xml + + def index + @media_assets = authorize MediaAsset.visible(CurrentUser.user).paginated_search(params, count_pages: true) + respond_with(@media_assets) + end +end diff --git a/app/logical/upload_service.rb b/app/logical/upload_service.rb index 12e95d90f..5279d0325 100644 --- a/app/logical/upload_service.rb +++ b/app/logical/upload_service.rb @@ -104,6 +104,13 @@ class UploadService p.uploader_id = upload.uploader_id p.uploader_ip_addr = upload.uploader_ip_addr p.parent_id = upload.parent_id + p.media_asset = MediaAsset.new( + md5: upload.md5, + file_ext: upload.file_ext, + file_size: upload.file_size, + image_width: upload.image_width, + image_height: upload.image_height, + ) if !upload.uploader.can_upload_free? || upload.upload_as_pending? p.is_pending = true diff --git a/app/models/media_asset.rb b/app/models/media_asset.rb new file mode 100644 index 000000000..5dd15c7ba --- /dev/null +++ b/app/models/media_asset.rb @@ -0,0 +1,7 @@ +class MediaAsset < ApplicationRecord + def self.search(params) + q = search_attributes(params, :id, :created_at, :updated_at, :md5, :file_ext, :file_size, :image_width, :image_height) + q = q.apply_default_order(params) + q + end +end diff --git a/app/models/post.rb b/app/models/post.rb index c578326ae..40babeb7e 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -40,6 +40,7 @@ class Post < ApplicationRecord belongs_to :approver, class_name: "User", optional: true belongs_to :uploader, :class_name => "User", :counter_cache => "post_upload_count" belongs_to :parent, class_name: "Post", optional: true + has_one :media_asset, foreign_key: :md5, primary_key: :md5 has_one :upload, :dependent => :destroy has_one :artist_commentary, :dependent => :destroy has_one :pixiv_ugoira_frame_data, :class_name => "PixivUgoiraFrameData", :dependent => :destroy diff --git a/app/policies/media_asset_policy.rb b/app/policies/media_asset_policy.rb new file mode 100644 index 000000000..ebef2da96 --- /dev/null +++ b/app/policies/media_asset_policy.rb @@ -0,0 +1,5 @@ +class MediaAssetPolicy < ApplicationPolicy + def index? + true + end +end diff --git a/config/routes.rb b/config/routes.rb index d15d2e9e7..c63eb34f6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -154,6 +154,7 @@ Rails.application.routes.draw do get :check, to: redirect {|path_params, req| "/iqdb_queries?#{req.query_string}"} end end + resources :media_assets, only: [:index] resources :mod_actions resources :moderation_reports, only: [:new, :create, :index, :show] resources :modqueue, only: [:index] diff --git a/db/migrate/20210901230931_create_media_assets.rb b/db/migrate/20210901230931_create_media_assets.rb new file mode 100644 index 000000000..035da53d4 --- /dev/null +++ b/db/migrate/20210901230931_create_media_assets.rb @@ -0,0 +1,19 @@ +class CreateMediaAssets < ActiveRecord::Migration[6.1] + def change + create_table :media_assets do |t| + t.timestamps null: false, index: true + + t.string :md5, null: false, index: true, unique: true + t.string :file_ext, null: false, index: true + t.integer :file_size, null: false, index: true + t.integer :image_width, null: false, index: true + t.integer :image_height, null: false, index: true + end + + reversible do |dir| + dir.up do + execute "INSERT INTO media_assets (created_at, updated_at, md5, file_ext, file_size, image_width, image_height) SELECT created_at, created_at AS updated_at, md5, file_ext, file_size, image_width, image_height FROM posts ORDER BY id ASC" + end + end + end +end diff --git a/db/structure.sql b/db/structure.sql index 4325545d1..464cdcc52 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -2461,6 +2461,41 @@ CREATE SEQUENCE public.ip_geolocations_id_seq ALTER SEQUENCE public.ip_geolocations_id_seq OWNED BY public.ip_geolocations.id; +-- +-- Name: media_assets; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.media_assets ( + id bigint NOT NULL, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL, + md5 character varying NOT NULL, + file_ext character varying NOT NULL, + file_size integer NOT NULL, + image_width integer NOT NULL, + image_height integer NOT NULL +); + + +-- +-- Name: media_assets_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.media_assets_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: media_assets_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.media_assets_id_seq OWNED BY public.media_assets.id; + + -- -- Name: mod_actions; Type: TABLE; Schema: public; Owner: - -- @@ -4279,6 +4314,13 @@ ALTER TABLE ONLY public.ip_bans ALTER COLUMN id SET DEFAULT nextval('public.ip_b ALTER TABLE ONLY public.ip_geolocations ALTER COLUMN id SET DEFAULT nextval('public.ip_geolocations_id_seq'::regclass); +-- +-- Name: media_assets id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.media_assets ALTER COLUMN id SET DEFAULT nextval('public.media_assets_id_seq'::regclass); + + -- -- Name: mod_actions id; Type: DEFAULT; Schema: public; Owner: - -- @@ -4659,6 +4701,14 @@ ALTER TABLE ONLY public.ip_geolocations ADD CONSTRAINT ip_geolocations_pkey PRIMARY KEY (id); +-- +-- Name: media_assets media_assets_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.media_assets + ADD CONSTRAINT media_assets_pkey PRIMARY KEY (id); + + -- -- Name: mod_actions mod_actions_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- @@ -6935,6 +6985,55 @@ CREATE INDEX index_ip_geolocations_on_time_zone ON public.ip_geolocations USING CREATE INDEX index_ip_geolocations_on_updated_at ON public.ip_geolocations USING btree (updated_at); +-- +-- Name: index_media_assets_on_created_at; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_media_assets_on_created_at ON public.media_assets USING btree (created_at); + + +-- +-- Name: index_media_assets_on_file_ext; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_media_assets_on_file_ext ON public.media_assets USING btree (file_ext); + + +-- +-- Name: index_media_assets_on_file_size; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_media_assets_on_file_size ON public.media_assets USING btree (file_size); + + +-- +-- Name: index_media_assets_on_image_height; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_media_assets_on_image_height ON public.media_assets USING btree (image_height); + + +-- +-- Name: index_media_assets_on_image_width; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_media_assets_on_image_width ON public.media_assets USING btree (image_width); + + +-- +-- Name: index_media_assets_on_md5; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_media_assets_on_md5 ON public.media_assets USING btree (md5); + + +-- +-- Name: index_media_assets_on_updated_at; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_media_assets_on_updated_at ON public.media_assets USING btree (updated_at); + + -- -- Name: index_mod_actions_on_created_at; Type: INDEX; Schema: public; Owner: - -- @@ -8016,5 +8115,6 @@ INSERT INTO "schema_migrations" (version) VALUES ('20210310221248'), ('20210330003356'), ('20210330093133'); +('20210901230931'); diff --git a/test/factories/media_asset.rb b/test/factories/media_asset.rb new file mode 100644 index 000000000..9fe45e086 --- /dev/null +++ b/test/factories/media_asset.rb @@ -0,0 +1,9 @@ +FactoryBot.define do + factory(:media_asset) do + md5 { SecureRandom.hex(32) } + file_ext { "jpg" } + file_size { 1_000_000 } + image_width { 1000 } + image_height { 1000 } + end +end diff --git a/test/functional/media_assets_controller_test.rb b/test/functional/media_assets_controller_test.rb new file mode 100644 index 000000000..a652dc9d6 --- /dev/null +++ b/test/functional/media_assets_controller_test.rb @@ -0,0 +1,14 @@ +require 'test_helper' + +class MediaAssetsControllerTest < ActionDispatch::IntegrationTest + context "The media assets controller" do + context "index action" do + should "render" do + create(:media_asset) + get media_assets_path, as: :json + + assert_response :success + end + end + end +end diff --git a/test/unit/upload_service_test.rb b/test/unit/upload_service_test.rb index 2828b30ab..3b9de7c70 100644 --- a/test/unit/upload_service_test.rb +++ b/test/unit/upload_service_test.rb @@ -937,6 +937,17 @@ class UploadServiceTest < ActiveSupport::TestCase assert_equal([], post.errors.full_messages) assert_not_nil(post.id) end + + should "create a media asset" do + post = subject.new({}).create_post_from_upload(@upload) + + assert_not_nil(post.media_asset) + assert_equal("12345", post.media_asset.md5) + assert_equal("jpg", post.media_asset.file_ext) + assert_equal(1000, post.media_asset.file_size) + assert_equal(100, post.media_asset.image_width) + assert_equal(100, post.media_asset.image_height) + end end end