remove old domain views, controllers
This commit is contained in:
@@ -1,6 +0,0 @@
|
||||
# typed: true
|
||||
class Domain::E621::PostsController < ApplicationController
|
||||
def show
|
||||
@post = Domain::E621::Post.find_by!(e621_id: params[:e621_id])
|
||||
end
|
||||
end
|
||||
@@ -7,18 +7,7 @@ class Domain::Fa::ApiController < ApplicationController
|
||||
only: %i[enqueue_objects object_statuses similar_users]
|
||||
|
||||
skip_before_action :validate_api_token!,
|
||||
only: %i[search_user_names object_statuses similar_users]
|
||||
|
||||
def search_user_names
|
||||
name = params[:name]
|
||||
limit = (params[:limit] || 5).to_i.clamp(0, 15)
|
||||
users = users_for_name(name, limit: limit)
|
||||
if !Rails.env.production? && name == "error"
|
||||
render status: 500, json: { error: "an error!" }
|
||||
else
|
||||
render json: { users: users }
|
||||
end
|
||||
end
|
||||
only: %i[object_statuses similar_users]
|
||||
|
||||
def object_statuses
|
||||
fa_ids = (params[:fa_ids] || []).reject(&:blank?).map(&:to_i)
|
||||
@@ -298,37 +287,6 @@ class Domain::Fa::ApiController < ApplicationController
|
||||
end
|
||||
end
|
||||
|
||||
def users_for_name(name, limit: 10)
|
||||
users =
|
||||
Domain::Fa::User
|
||||
.where(
|
||||
[
|
||||
"(name ilike :name) OR (url_name ilike :name)",
|
||||
{ name: "#{ReduxApplicationRecord.sanitize_sql_like(name)}%" },
|
||||
],
|
||||
)
|
||||
.includes(:avatar)
|
||||
.select(:id, :state, :state_detail, :log_entry_detail, :name, :url_name)
|
||||
.select(
|
||||
"(SELECT COUNT(*) FROM domain_fa_posts WHERE creator_id = domain_fa_users.id) as num_posts",
|
||||
)
|
||||
.order(name: :asc)
|
||||
.limit(limit)
|
||||
|
||||
users.map do |user|
|
||||
{
|
||||
id: user.id,
|
||||
name: user.name,
|
||||
url_name: user.url_name,
|
||||
thumb: helpers.fa_user_avatar_path(user, thumb: "64-avatar"),
|
||||
show_path: domain_fa_user_path(user.url_name),
|
||||
# `num_posts` is a manually added column, so we need to use T.unsafe to
|
||||
# access it
|
||||
num_posts: T.unsafe(user).num_posts,
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
sig do
|
||||
params(users_list: T::Array[Domain::User::FaUser]).returns(
|
||||
T::Array[T::Hash[Symbol, T.untyped]],
|
||||
|
||||
@@ -1,139 +0,0 @@
|
||||
# typed: true
|
||||
|
||||
class Domain::Fa::PostsController < ApplicationController
|
||||
before_action :set_ivfflat_probes!, only: %i[show]
|
||||
before_action :set_domain_fa_post, only: %i[show scan_post]
|
||||
|
||||
skip_before_action :verify_authenticity_token,
|
||||
only: %i[try_scan_post try_scan_posts]
|
||||
|
||||
skip_before_action :authenticate_user!, only: %i[show index]
|
||||
|
||||
# This action is always scoped to a user, so the :user_url_name parameter is required.
|
||||
# GET /domain/fa/users/:user_url_name/posts
|
||||
def index
|
||||
@user = Domain::Fa::User.find_by!(url_name: params[:user_url_name])
|
||||
relation = policy_scope(@user.posts)
|
||||
@posts =
|
||||
relation
|
||||
.includes(:creator, :file)
|
||||
.order(fa_id: :desc)
|
||||
.page(params[:page])
|
||||
.per(50)
|
||||
.without_count
|
||||
end
|
||||
|
||||
# GET /domain/fa/posts/:fa_id
|
||||
def show
|
||||
end
|
||||
|
||||
# GET /domain/fa/posts/:fa_id/favorites
|
||||
def favorites
|
||||
@post = Domain::Fa::Post.find_by!(fa_id: params[:fa_id])
|
||||
end
|
||||
|
||||
def scan_post
|
||||
if try_enqueue_post_scan(@post, @post.fa_id)
|
||||
redirect_to domain_fa_post_path(@post.fa_id), notice: "Enqueued for scan"
|
||||
else
|
||||
redirect_to domain_fa_post_path(@post.fa_id), notice: "Already scanned"
|
||||
end
|
||||
end
|
||||
|
||||
def try_scan_post
|
||||
fa_id = params[:fa_id]&.to_i || raise("need fa_id parameter")
|
||||
post = Domain::Fa::Post.find_by(fa_id: fa_id)
|
||||
enqueued = try_enqueue_post_scan(post, fa_id)
|
||||
|
||||
if post && (file = post.file).present? && created_at = file.created_at
|
||||
state_string =
|
||||
"downloaded #{helpers.time_ago_in_words(created_at, include_seconds: true)} ago"
|
||||
elsif post && post.scanned? && scanned_at = post.scanned_at
|
||||
state_string =
|
||||
"scanned #{helpers.time_ago_in_words(scanned_at, include_seconds: true)} ago"
|
||||
else
|
||||
state_string = []
|
||||
!post ? state_string << "not seen" : state_string << "#{post.state}"
|
||||
|
||||
state_string << "enqueued" if enqueued
|
||||
|
||||
state_string = state_string.join(", ")
|
||||
end
|
||||
|
||||
render json: {
|
||||
enqueued: enqueued,
|
||||
title: post&.title,
|
||||
state: state_string,
|
||||
is_terminal_state: post&.scanned? && post.file&.present? || false,
|
||||
}
|
||||
end
|
||||
|
||||
def try_scan_posts
|
||||
Rails.logger.info "params: #{params.inspect}"
|
||||
fa_ids = params[:fa_ids].map(&:to_i)
|
||||
fa_id_to_post =
|
||||
Domain::Fa::Post
|
||||
.where(fa_id: fa_ids)
|
||||
.map { |post| [post.fa_id, post] }
|
||||
.to_h
|
||||
|
||||
response = {}
|
||||
|
||||
fa_ids.each do |fa_id|
|
||||
post = fa_id_to_post[fa_id]
|
||||
if post.nil?
|
||||
state = "not_seen"
|
||||
elsif post.file.present?
|
||||
state = "have_file"
|
||||
elsif post.scanned?
|
||||
state = "scanned"
|
||||
else
|
||||
state = "state_#{post.state}"
|
||||
end
|
||||
|
||||
response[fa_id] = {
|
||||
state: state,
|
||||
enqueued: try_enqueue_post_scan(post, fa_id),
|
||||
}
|
||||
end
|
||||
render json: response
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def try_enqueue_post_scan(post, fa_id)
|
||||
@@already_enqueued_fa_ids ||= Set.new
|
||||
unless @@already_enqueued_fa_ids.add?(fa_id)
|
||||
Rails.logger.info "Already enqueued #{fa_id}, skipping"
|
||||
return false
|
||||
end
|
||||
|
||||
if !post || !post.scanned?
|
||||
Rails.logger.info "Enqueue scan #{fa_id}"
|
||||
Domain::Fa::Job::ScanPostJob.set(
|
||||
priority: -15,
|
||||
queue: "manual",
|
||||
).perform_later({ fa_id: fa_id })
|
||||
return true
|
||||
end
|
||||
|
||||
if post && post.file_uri && !post.file.present?
|
||||
Rails.logger.info "Enqueue file #{fa_id}"
|
||||
Domain::Fa::Job::ScanFileJob.set(
|
||||
priority: -15,
|
||||
queue: "manual",
|
||||
).perform_later({ post: post })
|
||||
return true
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
# Use callbacks to share common setup or constraints between actions.
|
||||
def set_domain_fa_post
|
||||
@post =
|
||||
Domain::Fa::Post.includes(:creator, file: :response).find_by!(
|
||||
fa_id: params[:fa_id],
|
||||
)
|
||||
end
|
||||
end
|
||||
@@ -1,28 +0,0 @@
|
||||
# typed: true
|
||||
|
||||
class Domain::Fa::UsersController < ApplicationController
|
||||
before_action :set_ivfflat_probes!, only: %i[show]
|
||||
before_action :set_user, only: %i[show]
|
||||
skip_before_action :authenticate_user!, only: %i[show]
|
||||
|
||||
# GET /domain/fa/users or /domain/fa/users.json
|
||||
def index
|
||||
authorize Domain::Fa::User
|
||||
@users =
|
||||
policy_scope(Domain::Fa::User).includes({ avatar: [:file] }).page(
|
||||
params[:page],
|
||||
)
|
||||
end
|
||||
|
||||
# GET /domain/fa/users/1 or /domain/fa/users/1.json
|
||||
def show
|
||||
authorize @user
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Use callbacks to share common setup or constraints between actions.
|
||||
def set_user
|
||||
@user = Domain::Fa::User.find_by(url_name: params[:url_name])
|
||||
end
|
||||
end
|
||||
@@ -1,19 +0,0 @@
|
||||
# typed: false
|
||||
class Domain::Inkbunny::PostsController < ApplicationController
|
||||
skip_before_action :authenticate_user!, only: %i[show index]
|
||||
|
||||
def index
|
||||
relation = Domain::Inkbunny::Post.includes(:creator, :files)
|
||||
|
||||
if params[:user_id].present?
|
||||
@user = Domain::Inkbunny::User.find(params[:user_id])
|
||||
relation = relation.where(creator: @user)
|
||||
end
|
||||
|
||||
@posts = relation.order(ib_post_id: :desc).page(params[:page]).per(50)
|
||||
end
|
||||
|
||||
def show
|
||||
@post = Domain::Inkbunny::Post.find_by!(ib_post_id: params[:ib_post_id])
|
||||
end
|
||||
end
|
||||
@@ -1,6 +0,0 @@
|
||||
# typed: true
|
||||
class Domain::Inkbunny::UsersController < ApplicationController
|
||||
def show
|
||||
@user = Domain::Inkbunny::User.find_by(name: params[:name])
|
||||
end
|
||||
end
|
||||
@@ -1,13 +0,0 @@
|
||||
# typed: false
|
||||
class IndexedPostsController < ApplicationController
|
||||
def index
|
||||
@posts = IndexedPost.all
|
||||
active_sources = (params[:sources] || SourceHelper.all_source_names)
|
||||
unless SourceHelper.has_all_sources?(active_sources)
|
||||
postable_types = SourceHelper.source_names_to_class_names(active_sources)
|
||||
@posts =
|
||||
@posts.where(postable_type: postable_types) if postable_types.any?
|
||||
end
|
||||
@posts = @posts.order(created_at: :desc).page(params[:page]).per(50)
|
||||
end
|
||||
end
|
||||
@@ -1,5 +1,7 @@
|
||||
# typed: false
|
||||
module Domain::Fa::UsersHelper
|
||||
extend T::Sig
|
||||
|
||||
def avatar_url(sha256, thumb: "32-avatar")
|
||||
blob_path(HexUtil.bin2hex(sha256), format: "jpg", thumb: thumb)
|
||||
end
|
||||
@@ -87,38 +89,31 @@ module Domain::Fa::UsersHelper
|
||||
end
|
||||
|
||||
# TODO - remove this once we've migrated similarity scores to new user model
|
||||
sig do
|
||||
params(
|
||||
user: Domain::User::FaUser,
|
||||
limit: Integer,
|
||||
exclude_followed_by: T.nilable(Domain::User::FaUser),
|
||||
).returns(T::Array[Domain::User::FaUser])
|
||||
end
|
||||
def similar_users_by_followed(user, limit: 10, exclude_followed_by: nil)
|
||||
old_user = Domain::Fa::User.find_by(url_name: user.url_name)
|
||||
old_exclude_user =
|
||||
(
|
||||
if exclude_followed_by
|
||||
Domain::Fa::User.find_by(url_name: exclude_followed_by.url_name)
|
||||
else
|
||||
nil
|
||||
end
|
||||
)
|
||||
factors = Domain::Factors::UserUserFollowToFactors.find_by(user: user)
|
||||
return [] if factors.nil?
|
||||
ReduxApplicationRecord.connection.execute("SET ivfflat.probes = 32")
|
||||
|
||||
return nil if old_user.nil?
|
||||
|
||||
if old_user.disco.nil?
|
||||
nil
|
||||
else
|
||||
ReduxApplicationRecord.connection.execute("SET ivfflat.probes = 32")
|
||||
old_users =
|
||||
old_user.similar_users_by_followed(
|
||||
exclude_followed_by: old_exclude_user,
|
||||
).limit(limit)
|
||||
|
||||
old_user_url_names = old_users.map(&:url_name)
|
||||
new_users = Domain::User::FaUser.where(url_name: old_user_url_names).to_a
|
||||
|
||||
# return in same order as old_users
|
||||
old_users
|
||||
.map do |old_user|
|
||||
new_users.find { |new_user| new_user.url_name == old_user.url_name }
|
||||
end
|
||||
.compact
|
||||
relation =
|
||||
factors
|
||||
.nearest_neighbors(:embedding, distance: "euclidean")
|
||||
.limit(limit)
|
||||
.includes(:user)
|
||||
if exclude_followed_by
|
||||
relation =
|
||||
relation.where.not(
|
||||
user_id: exclude_followed_by.followed_users.select(:to_id),
|
||||
)
|
||||
end
|
||||
|
||||
relation.map { |factor| factor.user }
|
||||
end
|
||||
|
||||
def fa_user_account_status(user)
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
# typed: false
|
||||
module IndexablePostsHelper
|
||||
def show_path(indexed_post)
|
||||
case indexed_post.postable_type
|
||||
when "Domain::Fa::Post"
|
||||
# need to use the helper here because the postable is not loaded
|
||||
Rails.application.routes.url_helpers.domain_fa_post_path(
|
||||
indexed_post.postable,
|
||||
)
|
||||
when "Domain::E621::Post"
|
||||
Rails.application.routes.url_helpers.domain_e621_post_path(
|
||||
indexed_post.postable,
|
||||
)
|
||||
when "Domain::Inkbunny::Post"
|
||||
Rails.application.routes.url_helpers.domain_inkbunny_post_path(
|
||||
indexed_post.postable,
|
||||
)
|
||||
else
|
||||
raise("Unsupported postable type: #{indexed_post.postable_type}")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,108 +0,0 @@
|
||||
<div class="mx-auto mt-4 flex w-full flex-col gap-4 pb-4 md:max-w-2xl">
|
||||
<section class="border border-slate-300 bg-slate-50 p-4 md:rounded-md">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<span class="text-md italic">
|
||||
<%= link_to "E621 Post ##{@post.e621_id}",
|
||||
"https://e621.net/posts/#{@post.e621_id}",
|
||||
class: "text-blue-600 hover:underline",
|
||||
target: "_blank" %>
|
||||
</span>
|
||||
<% if @post.artists_array.any? %>
|
||||
<span class="ml-2 italic"
|
||||
>by <%= @post.artists_array.join(", ") %></span
|
||||
>
|
||||
<% end %>
|
||||
</div>
|
||||
<i class="fa-solid fa-arrow-up-right-from-square text-slate-400"></i>
|
||||
</div>
|
||||
<% new_post = Domain::Post::E621Post.find_by(e621_id: @post.e621_id) %>
|
||||
<% if new_post %>
|
||||
<div class="py-2">
|
||||
<%= link_to "Go to new post",
|
||||
domain_post_path(new_post),
|
||||
class: "text-white bg-blue-500 hover:bg-blue-800 transition-colors duration-200 px-4 py-2 rounded-md shadow hover:shadow-lg" %>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="mt-2 flex flex-wrap gap-x-4 text-sm text-slate-600">
|
||||
<span
|
||||
><i class="fa-solid fa-star mr-1"></i>Score: <%= @post.score %></span
|
||||
>
|
||||
<span
|
||||
><i class="fa-solid fa-tag mr-1"></i>Rating:
|
||||
<%= @post.rating&.upcase || "Unknown" %></span
|
||||
>
|
||||
<span>
|
||||
<i class="fa-regular fa-calendar mr-1"></i>
|
||||
Created: <%= @post.created_at.strftime("%Y-%m-%d") %>
|
||||
(<%= time_ago_in_words(@post.created_at) %> ago)
|
||||
</span>
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
<% if @post.file %>
|
||||
<%= render partial: "log_entries/content_container",
|
||||
locals: {
|
||||
log_entry: @post.file,
|
||||
} %>
|
||||
<% else %>
|
||||
<div class="p-4 text-center italic text-slate-400">No file available</div>
|
||||
<% end %>
|
||||
</section>
|
||||
<section class="sky-section">
|
||||
<div class="section-header">Post Description</div>
|
||||
<% if @post.description.present? %>
|
||||
<div class="bg-slate-800 p-4 text-slate-200">
|
||||
<%= simple_format(@post.description) %>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="bg-slate-50 p-4 text-center italic text-slate-400">
|
||||
No description
|
||||
</div>
|
||||
<% end %>
|
||||
</section>
|
||||
<section class="sky-section">
|
||||
<div class="section-header">Tags</div>
|
||||
<div class="bg-slate-100 p-4">
|
||||
<% if @post.tags_array.any? %>
|
||||
<% tags_array =
|
||||
(
|
||||
if @post.tags_array.is_a?(Hash)
|
||||
@post.tags_array
|
||||
else
|
||||
{ "general" => @post.tags_array }
|
||||
end
|
||||
) %>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<% tag_category_order.each do |category| %>
|
||||
<% (tags_array[category.to_s] || []).each do |tag| %>
|
||||
<span
|
||||
class="<%= tag_category_tw_class(category) %> rounded px-2 py-1 text-sm text-slate-600"
|
||||
>
|
||||
<% icon = font_awesome_category_icon(category) %>
|
||||
<% if icon %>
|
||||
<i class="fa-solid <%= icon %> mr-1"></i>
|
||||
<% end %>
|
||||
<%= tag %>
|
||||
</span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="text-center italic text-slate-400">No tags</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</section>
|
||||
<% if @post.sources_array.any? %>
|
||||
<section class="sky-section">
|
||||
<div class="section-header">Sources</div>
|
||||
<div class="bg-slate-100 p-4">
|
||||
<div class="divide-y divide-slate-200">
|
||||
<% @post.sources_array.each do |source| %>
|
||||
<%= render partial: "domain/e621/posts/source_link", locals: { source: source } %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<% end %>
|
||||
</div>
|
||||
@@ -1,19 +0,0 @@
|
||||
<div class="flex items-start gap-2 py-1 first:pt-0 last:pb-0">
|
||||
<% if icon_path = icon_asset_for_url(source) %>
|
||||
<%= image_tag icon_path, class: "h-4 w-4 mt-1 flex-shrink-0" %>
|
||||
<% else %>
|
||||
<i class="fa-solid fa-link mt-1 h-4 w-4 flex-shrink-0"></i>
|
||||
<% end %>
|
||||
<%= link_to source,
|
||||
source,
|
||||
class: "text-blue-600 hover:underline truncate",
|
||||
target: "_blank" %>
|
||||
<% fa_post = fa_post_for_source(source) %>
|
||||
<% if fa_post %>
|
||||
<%= link_to domain_fa_post_path(fa_post.fa_id),
|
||||
class:
|
||||
"float-right inline-flex items-center gap-2 rounded bg-blue-600 px-3 py-1 text-sm text-white hover:bg-blue-700" do %>
|
||||
<span class="truncate"><%= fa_post.title %></span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
@@ -1,2 +0,0 @@
|
||||
<p style="color: green"><%= notice %></p>
|
||||
<%= render @post %>
|
||||
@@ -1,32 +0,0 @@
|
||||
json.user do
|
||||
json.name @user.name
|
||||
json.full_name @user.full_name
|
||||
json.url_name @user.url_name
|
||||
json.state @user.state
|
||||
|
||||
json.log_entry_detail @user.log_entry_detail
|
||||
|
||||
if @user.log_entry_detail["last_user_page_id"]
|
||||
json.user_page_log_entry do
|
||||
json.partial! "log_entries/show",
|
||||
locals: {
|
||||
log_entry:
|
||||
HttpLogEntry.find(
|
||||
@user.log_entry_detail["last_user_page_id"],
|
||||
),
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
json.user_stats do
|
||||
json.num_pageviews @user.num_pageviews
|
||||
json.num_submissions @user.num_submissions
|
||||
json.num_comments_recieved @user.num_comments_recieved
|
||||
json.num_comments_given @user.num_comments_given
|
||||
json.num_journals @user.num_journals
|
||||
json.num_favorites @user.num_favorites
|
||||
end
|
||||
|
||||
json.created_at @user.created_at
|
||||
json.updated_at @user.updated_at
|
||||
end
|
||||
@@ -1,6 +0,0 @@
|
||||
<%= link_to domain_fa_post_path(post),
|
||||
class:
|
||||
"text-sky-200 transition-all hover:text-sky-800 inline-flex items-center hover:bg-gray-100 rounded-md gap-1 px-1" do %>
|
||||
<i class="fa-regular fa-image h-4 w-4 flex-shrink-0"></i>
|
||||
<span><%= post.title %></span>
|
||||
<% end %>
|
||||
@@ -1,10 +0,0 @@
|
||||
<%= link_to domain_fa_user_path(user),
|
||||
class:
|
||||
"text-sky-200 transition-all hover:text-sky-800 inline-flex items-center hover:bg-gray-100 rounded-md gap-1 px-1 align-bottom" do %>
|
||||
<img
|
||||
src="<%= fa_user_avatar_path(user, thumb: "32-avatar") %>"
|
||||
class="inline-block h-4 w-4 flex-shrink-0 rounded-sm object-cover"
|
||||
alt="<%= user.name %>'s avatar"
|
||||
/>
|
||||
<span><%= user.name %></span>
|
||||
<% end %>
|
||||
@@ -1,15 +0,0 @@
|
||||
<tr>
|
||||
<td><%= time_ago_in_words(post.created_at) %> ago</td>
|
||||
<td><%= post.scanned_at && time_ago_in_words(post.scanned_at) || "(never)" %></td>
|
||||
<td><%= post.file && time_ago_in_words(post.file.created_at) || "(never)" %></td>
|
||||
<td><%= post_state_string(post) %></td>
|
||||
<td><%= link_to post.fa_id, domain_fa_post_path(post.fa_id) %></td>
|
||||
<td><%= post.title %></td>
|
||||
<td>
|
||||
<% if post.creator %>
|
||||
<%= link_to post.creator.name, post.creator %>
|
||||
<% else %>
|
||||
No creator
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -1,118 +0,0 @@
|
||||
<div class="mx-auto mt-4 flex w-full max-w-2xl flex-col gap-4 pb-4">
|
||||
<section class="rounded-md border border-slate-300 bg-slate-50 p-4">
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
<div class="flex min-w-0 items-center gap-4">
|
||||
<div class="flex min-w-0 items-center gap-2">
|
||||
<span class="truncate text-lg font-medium">
|
||||
<%= link_to @post.title,
|
||||
"https://www.furaffinity.net/view/#{@post.fa_id}",
|
||||
class: "text-blue-600 hover:underline",
|
||||
target: "_blank" %>
|
||||
</span>
|
||||
<i class="fa-solid fa-arrow-up-right-from-square text-slate-400"></i>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 whitespace-nowrap text-slate-600">
|
||||
by
|
||||
<%= render "domain/fa/users/inline_link",
|
||||
user: @post.creator,
|
||||
with_post_count: false %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-2 flex flex-wrap gap-x-4 text-sm text-slate-600">
|
||||
<span>
|
||||
<i class="fa-regular fa-calendar mr-1"></i>
|
||||
<% if (posted_at = @post.posted_at || @post.guess_posted_at) %>
|
||||
Posted: <%= posted_at&.strftime("%Y-%m-%d") %>
|
||||
(<%= time_ago_in_words(posted_at) if posted_at %> ago)
|
||||
<% else %>
|
||||
Posted: unknown
|
||||
<% end %>
|
||||
</span>
|
||||
<span>
|
||||
<i class="fa-solid fa-eye mr-1"></i>
|
||||
Views: <%= @post.num_views %>
|
||||
</span>
|
||||
<span>
|
||||
<i class="fa-solid fa-comment mr-1"></i>
|
||||
Comments: <%= @post.num_comments %>
|
||||
</span>
|
||||
<span>
|
||||
<i class="fa-solid fa-heart mr-1"></i>
|
||||
Favorites: <%= @post.num_favorites %>
|
||||
<% if policy(@post).view_scraper_metadata? %>
|
||||
(<%= link_to pluralize(@post.faved_by.count, "fav"),
|
||||
favorites_domain_fa_post_path(@post),
|
||||
class: "text-blue-600 hover:underline" %>)
|
||||
<% end %>
|
||||
</span>
|
||||
</div>
|
||||
<% if policy(@post).view_scraper_metadata? %>
|
||||
<% scanned_at = @post.scanned_at %>
|
||||
<% scanned_hle = @post.last_submission_page || guess_scanned_http_log_entry(@post) %>
|
||||
<% scanned_at ||= scanned_hle&.requested_at %>
|
||||
<% if scanned_at %>
|
||||
<div class="mt-2 text-sm text-slate-500">
|
||||
<div class="mt-2 text-sm text-slate-500">
|
||||
<% if scanned_hle %>
|
||||
<%= link_to "Scanned #{time_ago_in_words(scanned_at)} ago",
|
||||
log_entry_path(scanned_hle),
|
||||
class: "text-blue-600 hover:underline",
|
||||
target: "_blank" %>
|
||||
<% else %>
|
||||
<span> Scanned <%= time_ago_in_words(scanned_at) %> ago </span>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="mt-2 text-sm text-slate-500">Unknown when post scanned</div>
|
||||
<% end %>
|
||||
<% if hle = guess_file_downloaded_http_log_entry(@post) %>
|
||||
<div class="mt-2 text-sm text-slate-500">
|
||||
<%= link_to "File downloaded #{time_ago_in_words(hle.requested_at)} ago",
|
||||
log_entry_path(hle),
|
||||
class: "text-blue-600 hover:underline",
|
||||
target: "_blank" %>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="mt-2 text-sm text-slate-500">
|
||||
Unknown when file downloaded
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</section>
|
||||
<% if policy(@post).view_file? %>
|
||||
<section>
|
||||
<% if @post.file %>
|
||||
<%= render partial: "log_entries/content_container",
|
||||
locals: {
|
||||
log_entry: @post.file,
|
||||
} %>
|
||||
<% else %>
|
||||
<% if !@post.scanned? %>
|
||||
<%= button_to "Force scan post", scan_post_domain_fa_post_path(fa_id: @post.fa_id) %>
|
||||
<% elsif !@post.file %>
|
||||
<%= button_to "Force scan file", scan_post_domain_fa_post_path(fa_id: @post.fa_id) %>
|
||||
<% else %>
|
||||
Scanned and have file
|
||||
<% end %>
|
||||
<% end %>
|
||||
</section>
|
||||
<%= render partial: "log_entries/file_details_sky_section",
|
||||
locals: {
|
||||
log_entry: @post.file,
|
||||
} %>
|
||||
<% else %>
|
||||
<section class="sky-section">
|
||||
<%= link_to "https://www.furaffinity.net/view/#{@post.fa_id}/",
|
||||
target: "_blank",
|
||||
rel: "noopener noreferrer",
|
||||
class: "section-header flex items-center gap-2 hover:text-slate-600" do %>
|
||||
<span>View Post on FurAffinity</span>
|
||||
<i class="fa-solid fa-arrow-up-right-from-square"></i>
|
||||
<% end %>
|
||||
</section>
|
||||
<% end %>
|
||||
<%= render "section_description", { post: @post } %>
|
||||
<%= render "section_similar_posts", { post: @post } %>
|
||||
</div>
|
||||
@@ -1,10 +0,0 @@
|
||||
<section class="sky-section">
|
||||
<% if (post_description_html = @post.description) %>
|
||||
<div class="section-header">Post Description</div>
|
||||
<div class="bg-slate-800 p-4 text-slate-200">
|
||||
<%= fa_post_description_sanitized(post_description_html) %>
|
||||
</div>
|
||||
<% else %>
|
||||
<div>(No post description)</div>
|
||||
<% end %>
|
||||
</section>
|
||||
@@ -1,42 +0,0 @@
|
||||
<section class="sky-section">
|
||||
<div class="section-header">Similar Posts</div>
|
||||
<div
|
||||
class="grid grid-cols-[1fr_auto_auto] items-center divide-y divide-slate-300 bg-slate-100"
|
||||
>
|
||||
<% cache(post.disco, expires_in: 12.hours) do %>
|
||||
<% similar =
|
||||
post
|
||||
.disco
|
||||
&.nearest_neighbors(:for_favorite, distance: "cosine")
|
||||
&.limit(20)
|
||||
&.includes(post: { creator: :avatar }) %>
|
||||
<% if similar %>
|
||||
<% similar
|
||||
.map(&:post)
|
||||
.each do |post| %>
|
||||
<% creator = post.creator %>
|
||||
<div class="col-span-3 grid grid-cols-subgrid">
|
||||
<span class="text-md truncate px-4 py-2">
|
||||
<%= link_to post.title, domain_fa_post_path(post.fa_id), class: "underline italic" %>
|
||||
</span>
|
||||
<a href="<%= domain_fa_user_path(creator) %>" class="contents">
|
||||
<div class="px-2 py-2">
|
||||
<img
|
||||
src="<%= fa_user_avatar_path(creator, thumb: "64-avatar") %>"
|
||||
class="h-8 w-8 flex-shrink-0 rounded-md"
|
||||
/>
|
||||
</div>
|
||||
<span class="sky-link truncate px-4 py-2">
|
||||
<%= creator.url_name %>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<div class="col-span-3 p-4 text-center italic text-slate-400">
|
||||
No similar posts
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
</section>
|
||||
@@ -1,51 +0,0 @@
|
||||
<div class="mx-auto mt-4 flex w-full max-w-2xl flex-col gap-4 pb-4">
|
||||
<section class="rounded-md border border-slate-300 bg-slate-50 p-4">
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
<div class="flex min-w-0 items-center gap-2">
|
||||
<h1 class="text-lg font-medium">
|
||||
Users who favorited
|
||||
<%= link_to @post.title,
|
||||
domain_fa_post_path(@post),
|
||||
class: "text-blue-600 hover:underline" %>
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<% favs = @post.faved_by.includes(:avatar).to_a %>
|
||||
<% if favs.any? %>
|
||||
<section
|
||||
class="overflow-hidden rounded-md border border-slate-300 bg-slate-50"
|
||||
>
|
||||
<div class="divide-y divide-slate-200">
|
||||
<% favs.each do |user| %>
|
||||
<%= link_to domain_fa_user_path(user),
|
||||
class: "flex items-center gap-4 p-4 hover:bg-slate-100" do %>
|
||||
<% if user.avatar&.file_sha256.present? %>
|
||||
<%= image_tag fa_user_avatar_path(user, thumb: "64-avatar"),
|
||||
class: "h-12 w-12 rounded-md border object-cover",
|
||||
alt: user.name %>
|
||||
<% else %>
|
||||
<div
|
||||
class="flex h-12 w-12 items-center justify-center rounded-full bg-slate-200"
|
||||
>
|
||||
<i class="bi bi-person text-slate-400"></i>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="min-w-0">
|
||||
<div class="font-medium text-slate-900"><%= user.name %></div>
|
||||
<div class="text-sm text-slate-500">@<%= user.url_name %></div>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
</section>
|
||||
<% else %>
|
||||
<section
|
||||
class="rounded-md border border-slate-300 bg-slate-50 p-8 text-center"
|
||||
>
|
||||
<i class="bi bi-heart mb-3 block text-4xl text-slate-400"></i>
|
||||
<p class="text-slate-600">No users have favorited this post yet.</p>
|
||||
</section>
|
||||
<% end %>
|
||||
</div>
|
||||
@@ -1,79 +0,0 @@
|
||||
<div class="mx-auto mt-4 text-center sm:mt-6">
|
||||
<% if @user %>
|
||||
<h1 class="flex text-2xl">
|
||||
<%= link_to(@user, class: "sky-link flex items-center gap-2") do %>
|
||||
<img
|
||||
src="<%= fa_user_avatar_path(@user, thumb: "64-avatar") %>"
|
||||
class="inline-block h-8 w-8 rounded-md"
|
||||
/>
|
||||
<span><%= @user.name %></span>
|
||||
<% end %>
|
||||
<span>'s posts <%= page_str(params) %></span>
|
||||
</h1>
|
||||
<% else %>
|
||||
<h1 class="text-2xl">
|
||||
All FurAffinity posts, page <%= page_str(params) || 1 %>
|
||||
</h1>
|
||||
<% end %>
|
||||
</div>
|
||||
<%= render partial: "shared/pagination_controls", locals: { collection: @posts } %>
|
||||
<div class="mx-auto flex max-w-full flex-row flex-wrap justify-center">
|
||||
<% @posts.each do |post| %>
|
||||
<div
|
||||
class="m-4 flex flex-col rounded-lg border border-slate-300 bg-slate-50 shadow-sm"
|
||||
>
|
||||
<% if policy(post).view_file? %>
|
||||
<div
|
||||
class="flex flex-1 items-center justify-center border-b border-slate-300 p-4"
|
||||
>
|
||||
<% if post.file %>
|
||||
<%= link_to domain_fa_post_path(post.fa_id) do %>
|
||||
<img
|
||||
class="max-h-[300px] max-w-[300px] rounded-md border border-slate-300 object-contain shadow-md"
|
||||
alt="<%= post.title %>"
|
||||
src="<%= blob_path(
|
||||
HexUtil.bin2hex(post.file.response_sha256),
|
||||
format: "jpg",
|
||||
thumb: "small",
|
||||
) %>"
|
||||
/>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<span>No file for <%= post.fa_id %></span>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
<div>
|
||||
<h2 class="p-4 text-center text-lg">
|
||||
<%= link_to post.title, domain_fa_post_path(post.fa_id), class: "sky-link" %>
|
||||
</h2>
|
||||
<div class="px-4 pb-4 text-sm text-slate-600">
|
||||
<div class="flex items-start justify-between">
|
||||
<div>
|
||||
<% if post.posted_at %>
|
||||
Posted <%= post.posted_at.strftime("%Y-%m-%d") %>
|
||||
<div class="text-slate-500">
|
||||
(<%= time_ago_in_words(post.posted_at) %> ago)
|
||||
</div>
|
||||
<% else %>
|
||||
Posted date unknown
|
||||
<% end %>
|
||||
</div>
|
||||
<%= link_to "https://www.furaffinity.net/view/#{post.fa_id}",
|
||||
target: "_blank",
|
||||
rel: "noopener",
|
||||
class:
|
||||
"inline-flex items-center text-slate-500 hover:text-slate-700 ml-8 decoration-dotted underline" do %>
|
||||
<span>FA #<%= post.fa_id %></span>
|
||||
<%= render partial: "shared/icons/external_link",
|
||||
locals: {
|
||||
class_name: "w-4 h-4 ml-1",
|
||||
} %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<%= render partial: "shared/pagination_controls", locals: { collection: @posts } %>
|
||||
@@ -1 +0,0 @@
|
||||
<%= render @post %>
|
||||
@@ -1,17 +0,0 @@
|
||||
<div class="flex w-full items-center">
|
||||
<a
|
||||
class="flex grow items-center gap-2"
|
||||
href="<%= domain_fa_user_path(user) %>"
|
||||
>
|
||||
<img
|
||||
src="<%= fa_user_avatar_path(user, thumb: "64-avatar") %>"
|
||||
class="h-8 w-8 rounded-md"
|
||||
/>
|
||||
<span class="sky-link"> <%= user.url_name %> </span>
|
||||
</a>
|
||||
<% if !defined?(with_post_count) || with_post_count %>
|
||||
<span class="ml-2 text-slate-500">
|
||||
<%= pluralize(number_with_delimiter(user.posts.count, delimiter: ","), "post") %>
|
||||
</span>
|
||||
<% end %>
|
||||
</div>
|
||||
@@ -1,13 +0,0 @@
|
||||
<div class="mx-auto my-4 w-full space-y-4 md:max-w-2xl">
|
||||
<%= render "domain/fa/users/show_sections/name_icon_and_status", user: user %>
|
||||
<div class="flex flex-col gap-4 sm:flex-row">
|
||||
<div class="w-full sm:w-1/2">
|
||||
<%= render "domain/fa/users/show_sections/stats", user: user %>
|
||||
</div>
|
||||
<div class="w-full sm:w-1/2">
|
||||
<%= render "domain/fa/users/show_sections/recent_posts", user: user %>
|
||||
</div>
|
||||
</div>
|
||||
<%= render "domain/fa/users/show_sections/profile_description", user: user %>
|
||||
<%= render "domain/fa/users/show_sections/similar_users", user: user %>
|
||||
</div>
|
||||
@@ -1,53 +0,0 @@
|
||||
<section class='w-full'>
|
||||
<h1>Users</h1>
|
||||
<% @users.each do |user| %>
|
||||
<div class='mx-auto max-w-xl bg-slate-200 border-slate-300 border-2 my-2 p-2 rounded flex flex-row'>
|
||||
<% if (a = user.avatar&.log_entry) %>
|
||||
<img class='rounded-sm' alt='<%= user.name %> avatar' src='<%= contents_log_entry_path(a) %>' />
|
||||
<% else %>
|
||||
<div>(No avatar)</div>
|
||||
<% end %>
|
||||
<div class='flex-grow ml-2 flex-col'>
|
||||
<div class='flex-row'>
|
||||
<a
|
||||
class='
|
||||
text-lg text-black font-semibold
|
||||
underline decoration-dotted hover:decoration-solid'
|
||||
href='<%= domain_fa_user_path(user) %>'><%= user.name %></a>
|
||||
<a
|
||||
class='
|
||||
m-l-2 text-md text-slate-600
|
||||
underline decoration-dotted hover:decoration-solid'
|
||||
href="<%= domain_fa_user_posts_path(user) %>"
|
||||
>
|
||||
<%= pluralize(user.posts.count, "post") %>
|
||||
</a>
|
||||
</div>
|
||||
<p class='block text-md text-slate-600'>
|
||||
<% if user.scanned_page_at %>
|
||||
Scanned page <%= time_ago_in_words(user.scanned_page_at) %> ago
|
||||
<% else %>
|
||||
Not yet scanned page
|
||||
<% end %>
|
||||
</p>
|
||||
<p class='block text-md text-slate-600'>
|
||||
<% if user.scanned_gallery_at %>
|
||||
Scanned gallery <%= time_ago_in_words(user.scanned_gallery_at) %> ago
|
||||
<% else %>
|
||||
Not yet scanned gallery
|
||||
<% end %>
|
||||
</p>
|
||||
</div>
|
||||
<div class='flex'>
|
||||
<a class='
|
||||
self-start inline
|
||||
border-b text-slate-600 border-slate-600 border-dashed
|
||||
hover:border-black hover:text-black
|
||||
' target='_blank' rel='noopener noreferrer' href='https://www.furaffinity.net/user/<%= user.url_name %>'>
|
||||
FurAffinity
|
||||
<img class='w-4 h-4 align-text-top inline' src='<%= image_path("arrow-top-right-on-square.svg") %>'>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</section>
|
||||
@@ -1,2 +0,0 @@
|
||||
<p style="color: green"><%= notice %></p>
|
||||
<%= render @user %>
|
||||
@@ -1,40 +0,0 @@
|
||||
<section class="animated-shadow-sky sky-section flex divide-none p-3">
|
||||
<div class="flex grow items-center gap-4">
|
||||
<img src="<%= fa_user_avatar_path(user) %>" class="h-12 w-12 rounded-lg" />
|
||||
<div>
|
||||
<div class="text-lg font-bold text-slate-900"><%= user.url_name %></div>
|
||||
<div class="flex gap-6 text-sm text-slate-400">
|
||||
<% if policy(user).view_scraped_at_timestamps? %>
|
||||
<div class="flex flex-col">
|
||||
<span class="font-medium italic text-slate-500">Status</span>
|
||||
<span class=""><%= fa_user_account_status(user) %></span>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<span class="font-medium italic text-slate-500">State</span>
|
||||
<span class=""><%= user.state %></span>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="flex flex-col">
|
||||
<span class="font-medium italic text-slate-500">Registered</span>
|
||||
<span class="">
|
||||
<% if user.registered_at %>
|
||||
<%= time_ago_in_words(user.registered_at) %>
|
||||
ago
|
||||
<% else %>
|
||||
unknown
|
||||
<% end %>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a
|
||||
href="https://www.furaffinity.net/user/<%= user.url_name %>/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="sky-link flex items-center gap-2"
|
||||
>
|
||||
<span class="font-bold">FurAffinity</span>
|
||||
<img src="<%= image_path("domain-icons/fa.png") %>" class="h-5 w-5" />
|
||||
</a>
|
||||
</section>
|
||||
@@ -1,12 +0,0 @@
|
||||
<section class="animated-shadow-sky sky-section">
|
||||
<% if (profile_html = user.profile_html) %>
|
||||
<h2 class="section-header">Profile Description</h2>
|
||||
<div class="bg-slate-800 p-4 text-slate-200">
|
||||
<% cache(user, expires_in: 12.hours) do %>
|
||||
<%= sanitized_fa_user_profile_html(profile_html) %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="px-4 py-3 text-slate-500">No profile description available</div>
|
||||
<% end %>
|
||||
</section>
|
||||
@@ -1,32 +0,0 @@
|
||||
<section class="animated-shadow-sky sky-section">
|
||||
<h2 class="section-header">
|
||||
<span class="font-medium text-slate-900">Recent Posts</span>
|
||||
<span class="float-right">
|
||||
<%= link_to "#{user.posts.count} total",
|
||||
domain_fa_user_posts_path(user),
|
||||
class: "sky-link" %>
|
||||
</span>
|
||||
</h2>
|
||||
<% if user.posts.any? %>
|
||||
<% user
|
||||
.posts
|
||||
.order(fa_id: :desc)
|
||||
.limit(5)
|
||||
.each do |post| %>
|
||||
<div class="flex items-center px-4 py-2">
|
||||
<span class="grow truncate">
|
||||
<%= link_to post.title, domain_fa_post_path(post), class: "sky-link block truncate" %>
|
||||
</span>
|
||||
<span class="whitespace-nowrap text-slate-500">
|
||||
<% if posted_at = post.posted_at %>
|
||||
<%= time_ago_in_words(posted_at) %> ago
|
||||
<% else %>
|
||||
Unknown posted at
|
||||
<% end %>
|
||||
</span>
|
||||
</div>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<div class="px-4 py-3 text-slate-500">No posts found</div>
|
||||
<% end %>
|
||||
</section>
|
||||
@@ -1,15 +0,0 @@
|
||||
<section class="animated-shadow-sky sky-section">
|
||||
<h2 class="section-header">Similar Users</h2>
|
||||
<% cache(user.disco, expires_in: 12.hours) do %>
|
||||
<% similar = similar_users_by_followed(user)&.includes(:avatar) %>
|
||||
<% if similar %>
|
||||
<% similar.each do |user| %>
|
||||
<div class="flex items-center px-4 py-2">
|
||||
<%= render "inline_link", user: user %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<div class="px-4 py-3 text-slate-500">No similar users found</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</section>
|
||||
@@ -1,22 +0,0 @@
|
||||
<section class="sky-section animated-shadow-sky divide-y">
|
||||
<h2 class="section-header">User Stats</h2>
|
||||
<% rows = [
|
||||
["Favorites", user.num_favorites],
|
||||
["Following", user.follower_joins.count],
|
||||
["Followed by", user.followed_joins.count],
|
||||
]
|
||||
|
||||
if policy(user).view_scraped_at_timestamps?
|
||||
rows << ["Gallery scanned", user.time_ago_for_gallery_scan]
|
||||
rows << ["Page scanned", user.time_ago_for_page_scan]
|
||||
end
|
||||
|
||||
rows.each do |label, value| %>
|
||||
<div class="flex items-center px-4 py-2">
|
||||
<span class="grow text-slate-900"><%= label %></span>
|
||||
<span class="text-slate-500">
|
||||
<%= value.is_a?(Integer) ? number_with_delimiter(value, delimiter: ",") : value %>
|
||||
</span>
|
||||
</div>
|
||||
<% end %>
|
||||
</section>
|
||||
@@ -1,65 +0,0 @@
|
||||
<div class="mx-auto mt-4 text-center sm:mt-6">
|
||||
<% if @user %>
|
||||
<h1 class="text-2xl">
|
||||
<%= link_to(@user.name, @user, class: "underline") %>'s posts
|
||||
</h1>
|
||||
<% else %>
|
||||
<h1 class="text-2xl">
|
||||
Inkbunny Posts (<%= @posts.total_count %>), page <%= page_str(params) %>
|
||||
</h1>
|
||||
<% end %>
|
||||
</div>
|
||||
<div
|
||||
class="mx-auto mb-4 mt-4 w-full rounded-md border-2 border-slate-300 sm:mb-6 sm:mt-6 sm:max-w-md"
|
||||
>
|
||||
<div class="flex h-full items-stretch justify-center">
|
||||
<%= link_to "Previous page",
|
||||
path_to_prev_page(@posts),
|
||||
class:
|
||||
"hover:underline hover:bg-slate-200 hover:shadow-sm px-6 py-2 text-center border-slate-300 border-r-2 bg-slate-100 flex-1 flex items-center justify-center" %>
|
||||
<%= link_to "Next page",
|
||||
path_to_next_page(@posts),
|
||||
class:
|
||||
"hover:underline hover:bg-slate-200 hover:shadow-sm px-6 py-2 text-center bg-slate-100 flex-1 flex items-center justify-center" %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mx-2 flex-row">
|
||||
<% @posts.each do |post| %>
|
||||
<div
|
||||
class="mx-auto mb-4 max-w-6xl rounded-md border-2 border-slate-300 bg-slate-100 p-2"
|
||||
>
|
||||
<div class="mb-2 flex justify-between text-slate-800">
|
||||
<div>
|
||||
<%= link_to post.title, post, class: "hover:underline" %>
|
||||
<span class="ml-2 text-sm text-slate-500"
|
||||
>by
|
||||
<%= link_to post.creator.name, post.creator, class: "hover:underline" %></span
|
||||
>
|
||||
</div>
|
||||
<div class="text-sm text-slate-400">
|
||||
(ID: <%= post.ib_post_id %>,
|
||||
<%= pluralize(post.files.count, "file") %>)
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-row gap-2">
|
||||
<% post.files.each do |file| %>
|
||||
<% if policy(post).view_file? %>
|
||||
<% img_src_path =
|
||||
blob_path(
|
||||
HexUtil.bin2hex(file.blob_entry_sha256),
|
||||
format: "jpg",
|
||||
thumb: "small",
|
||||
) %>
|
||||
<div class="overflow-hidden rounded-md">
|
||||
<img
|
||||
class="my-2 h-32 rounded-md border-2 border-slate-400 shadow-md first:pl-0 last:pr-0"
|
||||
alt="<%= post.title %>"
|
||||
src="<%= img_src_path %>"
|
||||
/>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
@@ -1,74 +0,0 @@
|
||||
<div class="mx-auto mt-4 flex w-full max-w-2xl flex-col gap-4 pb-4">
|
||||
<section class="rounded-md border border-slate-300 bg-slate-50 p-4">
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
<div class="flex min-w-0 items-center gap-4">
|
||||
<div class="flex min-w-0 items-center gap-2">
|
||||
<span class="truncate text-lg font-medium">
|
||||
<%= link_to @post.title,
|
||||
"https://inkbunny.net/s/#{@post.ib_post_id}",
|
||||
class: "text-blue-600 hover:underline",
|
||||
target: "_blank" %>
|
||||
</span>
|
||||
<i class="fa-solid fa-arrow-up-right-from-square text-slate-400"></i>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 whitespace-nowrap text-slate-600">
|
||||
by
|
||||
<%= link_to @post.creator.name, @post.creator, class: "hover:underline" %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-2 flex flex-wrap gap-x-4 text-sm text-slate-600">
|
||||
<span>
|
||||
<i class="fa-regular fa-calendar mr-1"></i>
|
||||
Posted: <%= @post.posted_at&.strftime("%Y-%m-%d") %>
|
||||
(<%= time_ago_in_words(@post.posted_at) if @post.posted_at %> ago)
|
||||
</span>
|
||||
<span>
|
||||
<i class="fa-solid fa-tag mr-1"></i>
|
||||
Type: <%= @post.submission_type&.titleize || "Unknown" %>
|
||||
</span>
|
||||
<span>
|
||||
<i class="fa-solid fa-shield mr-1"></i>
|
||||
Rating: <%= @post.rating&.titleize || "Unknown" %>
|
||||
</span>
|
||||
</div>
|
||||
<% if policy(@post).view_scraper_metadata? %>
|
||||
<div class="mt-2 text-sm text-slate-500">
|
||||
Scanned: <%= @post.created_at.strftime("%Y-%m-%d %H:%M:%S") %>
|
||||
(<%= time_ago_in_words(@post.created_at) %> ago)
|
||||
</div>
|
||||
<% end %>
|
||||
</section>
|
||||
|
||||
<% if policy(@post).view_file? %>
|
||||
<section>
|
||||
<div class="flex flex-col gap-4">
|
||||
<% @post.files.each do |file| %>
|
||||
<% if file.blob_entry %>
|
||||
<div class="overflow-hidden rounded-lg shadow-lg">
|
||||
<img
|
||||
class="h-auto w-full"
|
||||
alt="<%= @post.title %>"
|
||||
src="<%= blob_path(HexUtil.bin2hex(file.blob_entry_sha256), format: "jpg") %>"
|
||||
/>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="text-center text-slate-600">
|
||||
File #<%= file.ib_file_id %> not yet downloaded
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
</section>
|
||||
<% else %>
|
||||
<section class="sky-section">
|
||||
<%= link_to "https://inkbunny.net/s/#{@post.ib_post_id}",
|
||||
target: "_blank",
|
||||
rel: "noopener noreferrer",
|
||||
class: "section-header flex items-center gap-2 hover:text-slate-600" do %>
|
||||
<span>View Post on Inkbunny</span>
|
||||
<i class="fa-solid fa-arrow-up-right-from-square"></i>
|
||||
<% end %>
|
||||
</section>
|
||||
<% end %>
|
||||
</div>
|
||||
@@ -1,44 +0,0 @@
|
||||
<div class="mx-auto">
|
||||
<h1 class="text-2xl"><%= @user.name %>'s Profile</h1>
|
||||
</div>
|
||||
<div class="mx-auto">
|
||||
<h2 class="mb-2 mt-4 text-xl">Posts (<%= @user.posts.count %>)</h2>
|
||||
<div class="mx-2 flex-row">
|
||||
<% @user
|
||||
.posts
|
||||
.order(posted_at: :desc)
|
||||
.limit(10)
|
||||
.each do |post| %>
|
||||
<div class="border-stone-00 mb-4 rounded-md border-2 p-4">
|
||||
<div class="mb-2 flex justify-between text-stone-800">
|
||||
<div><%= link_to post.title, post, class: "hover:underline" %></div>
|
||||
<div class="text-sm text-stone-400">
|
||||
(ID: <%= post.ib_post_id %>,
|
||||
<%= pluralize(post.files.count, "file") %>)
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-row gap-2">
|
||||
<% post.files.each do |file| %>
|
||||
<% if file.blob_entry_sha256.present? %>
|
||||
<% img_src_path =
|
||||
blob_path(
|
||||
HexUtil.bin2hex(file.blob_entry_sha256),
|
||||
format: "jpg",
|
||||
thumb: "small",
|
||||
) %>
|
||||
<% else %>
|
||||
(no media file)
|
||||
<% end %>
|
||||
<div class="overflow-hidden rounded-md">
|
||||
<img
|
||||
class="h-32 p-2 first:pl-0 last:pr-0"
|
||||
alt="<%= post.title %>"
|
||||
src="<%= img_src_path %>"
|
||||
/>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
@@ -5,7 +5,7 @@
|
||||
>
|
||||
<% factors = Domain::Factors::UserPostFavPostFactors.find_by(post: post) %>
|
||||
<% if factors %>
|
||||
<% nearest_neighbors = factors.nearest_neighbors(:embedding, distance: "cosine").includes(:post).limit(20) %>
|
||||
<% nearest_neighbors = factors.nearest_neighbors(:embedding, distance: "euclidean").includes(:post).limit(10) %>
|
||||
<% nearest_neighbors.each do |factor| %>
|
||||
<% post = factor.post %>
|
||||
<% creator = post.class.has_creators? ? post.creator : nil %>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<span class="font-medium text-slate-900">Similar Users</span>
|
||||
</h2>
|
||||
<% if factors %>
|
||||
<% nearest_neighbors = factors.nearest_neighbors(:embedding, distance: "cosine").includes(:user).limit(10) %>
|
||||
<% nearest_neighbors = factors.nearest_neighbors(:embedding, distance: "euclidean").includes(:user).limit(10) %>
|
||||
<% nearest_neighbors.each do |neighbor| %>
|
||||
<% user = neighbor.user %>
|
||||
<div class="flex items-center gap-2 whitespace-nowrap text-slate-600 justify-between w-full px-4 py-2">
|
||||
|
||||
@@ -8,14 +8,15 @@ Rails.application.routes.draw do
|
||||
registrations: "users/registrations",
|
||||
sessions: "users/sessions",
|
||||
}
|
||||
root to: "pages#root"
|
||||
get "furecs-user-script", to: "pages#furecs_user_script"
|
||||
|
||||
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
|
||||
root to: "pages#root"
|
||||
|
||||
get "furecs-user-script", to: "pages#furecs_user_script"
|
||||
get "us/:script", to: "user_scripts#get", constraints: { script: /.*/ }
|
||||
|
||||
namespace :api do
|
||||
namespace :fa do
|
||||
get :similar_users, to: "/domain/fa/api#similar_users"
|
||||
get :search_user_names, to: "/domain/fa/api#search_user_names"
|
||||
get :object_statuses, to: "/domain/fa/api#object_statuses"
|
||||
end
|
||||
end
|
||||
@@ -57,68 +58,8 @@ Rails.application.routes.draw do
|
||||
end
|
||||
end
|
||||
|
||||
# Domain::RouteHelper::DOMAIN_POST_RESOURCES.each do |resource_data|
|
||||
# resolve resource_data.klass.name do |post|
|
||||
# domain_post_path(post)
|
||||
# end
|
||||
# end
|
||||
|
||||
# Domain::RouteHelper::DOMAIN_USER_RESOURCES.each do |resource_data|
|
||||
# resources resource_data.resource_name,
|
||||
# only: [:show],
|
||||
# param: resource_data.param,
|
||||
# controller: resource_data.controller,
|
||||
# path: "users/#{resource_data.subpath}" do
|
||||
# resources :posts,
|
||||
# controller: "domain/posts",
|
||||
# only: %i[index],
|
||||
# path: "posts"
|
||||
# end
|
||||
# end
|
||||
|
||||
# Domain::RouteHelper::DOMAIN_POST_RESOURCES.each do |resource_data|
|
||||
# resources resource_data.resource_name,
|
||||
# only: %i[show],
|
||||
# param: resource_data.param,
|
||||
# controller: resource_data.controller,
|
||||
# path: "posts/#{resource_data.subpath}" do
|
||||
# get :faved_by, on: :member
|
||||
# end
|
||||
# end
|
||||
|
||||
namespace :domain do
|
||||
namespace :fa do
|
||||
resources :users,
|
||||
param: :url_name,
|
||||
only: [:show],
|
||||
constraints: {
|
||||
url_name: %r{[^/]+},
|
||||
} do
|
||||
resources :posts, controller: "/domain/fa/posts", only: %i[index]
|
||||
end
|
||||
resources :posts, param: :fa_id, only: %i[show] do
|
||||
post :scan_post, on: :member
|
||||
get :favorites, on: :member
|
||||
end
|
||||
end
|
||||
namespace :e621 do
|
||||
resources :posts, param: :e621_id, only: [:show]
|
||||
end
|
||||
|
||||
namespace :inkbunny, path: "ib" do
|
||||
resources :users, param: :name, only: [:show] do
|
||||
resources :posts, controller: "/domain/inkbunny/posts", only: %i[index]
|
||||
end
|
||||
resources :posts, param: :ib_post_id, only: %i[show]
|
||||
end
|
||||
end
|
||||
|
||||
resources :blobs, controller: :blob_entries, only: [:show], param: :sha256
|
||||
|
||||
resources :indexed_posts, only: [:index]
|
||||
|
||||
get "us/:script", to: "user_scripts#get", constraints: { script: /.*/ }
|
||||
|
||||
resources :global_states, path: "state" do
|
||||
collection do
|
||||
get "fa-cookies", to: "global_states#fa_cookies"
|
||||
@@ -141,18 +82,6 @@ Rails.application.routes.draw do
|
||||
via: :all,
|
||||
as: :prometheus
|
||||
|
||||
namespace :api do
|
||||
get "search/user/:prefix", to: "search#user"
|
||||
|
||||
namespace :fa do
|
||||
post :enqueue_objects, to: "/domain/fa/api#enqueue_objects"
|
||||
end
|
||||
namespace :twitter do
|
||||
post :enqueue_objects, to: "/domain/twitter/api#enqueue_objects"
|
||||
post :object_statuses, to: "/domain/twitter/api#object_statuses"
|
||||
end
|
||||
end
|
||||
|
||||
resources :log_entries, only: %i[index show] do
|
||||
get :stats, on: :collection
|
||||
|
||||
|
||||
1
sorbet/rbi/dsl/application_controller.rbi
generated
1
sorbet/rbi/dsl/application_controller.rbi
generated
@@ -44,7 +44,6 @@ class ApplicationController
|
||||
include ::Domain::PostGroupsHelper
|
||||
include ::DomainSourceHelper
|
||||
include ::GoodJobHelper
|
||||
include ::IndexablePostsHelper
|
||||
include ::SourceHelper
|
||||
include ::DeviseHelper
|
||||
include ::ReactOnRails::Utils::Required
|
||||
|
||||
1
sorbet/rbi/dsl/devise_controller.rbi
generated
1
sorbet/rbi/dsl/devise_controller.rbi
generated
@@ -41,7 +41,6 @@ class DeviseController
|
||||
include ::Domain::PostGroupsHelper
|
||||
include ::DomainSourceHelper
|
||||
include ::GoodJobHelper
|
||||
include ::IndexablePostsHelper
|
||||
include ::SourceHelper
|
||||
include ::DeviseHelper
|
||||
include ::ReactOnRails::Utils::Required
|
||||
|
||||
42
sorbet/rbi/dsl/generated_path_helpers_module.rbi
generated
42
sorbet/rbi/dsl/generated_path_helpers_module.rbi
generated
@@ -9,9 +9,6 @@ module GeneratedPathHelpersModule
|
||||
include ::ActionDispatch::Routing::UrlFor
|
||||
include ::ActionDispatch::Routing::PolymorphicRoutes
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def api_fa_enqueue_objects_path(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def api_fa_object_statuses_path(*args); end
|
||||
|
||||
@@ -21,15 +18,6 @@ module GeneratedPathHelpersModule
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def api_fa_similar_users_path(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def api_path(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def api_twitter_enqueue_objects_path(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def api_twitter_object_statuses_path(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def blob_path(*args); end
|
||||
|
||||
@@ -39,27 +27,6 @@ module GeneratedPathHelpersModule
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def destroy_user_session_path(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def domain_e621_post_path(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def domain_fa_post_path(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def domain_fa_user_path(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def domain_fa_user_posts_path(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def domain_inkbunny_post_path(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def domain_inkbunny_user_path(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def domain_inkbunny_user_posts_path(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def edit_global_state_path(*args); end
|
||||
|
||||
@@ -78,9 +45,6 @@ module GeneratedPathHelpersModule
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def faved_by_post_users_path(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def favorites_domain_fa_post_path(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def favorites_user_posts_path(*args); end
|
||||
|
||||
@@ -105,9 +69,6 @@ module GeneratedPathHelpersModule
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def ib_cookies_global_states_path(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def indexed_posts_path(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def log_entries_path(*args); end
|
||||
|
||||
@@ -228,9 +189,6 @@ module GeneratedPathHelpersModule
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def root_path(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def scan_post_domain_fa_post_path(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def search_by_name_users_path(*args); end
|
||||
|
||||
|
||||
42
sorbet/rbi/dsl/generated_url_helpers_module.rbi
generated
42
sorbet/rbi/dsl/generated_url_helpers_module.rbi
generated
@@ -9,9 +9,6 @@ module GeneratedUrlHelpersModule
|
||||
include ::ActionDispatch::Routing::UrlFor
|
||||
include ::ActionDispatch::Routing::PolymorphicRoutes
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def api_fa_enqueue_objects_url(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def api_fa_object_statuses_url(*args); end
|
||||
|
||||
@@ -21,15 +18,6 @@ module GeneratedUrlHelpersModule
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def api_fa_similar_users_url(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def api_twitter_enqueue_objects_url(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def api_twitter_object_statuses_url(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def api_url(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def blob_url(*args); end
|
||||
|
||||
@@ -39,27 +27,6 @@ module GeneratedUrlHelpersModule
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def destroy_user_session_url(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def domain_e621_post_url(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def domain_fa_post_url(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def domain_fa_user_posts_url(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def domain_fa_user_url(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def domain_inkbunny_post_url(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def domain_inkbunny_user_posts_url(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def domain_inkbunny_user_url(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def edit_global_state_url(*args); end
|
||||
|
||||
@@ -78,9 +45,6 @@ module GeneratedUrlHelpersModule
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def faved_by_post_users_url(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def favorites_domain_fa_post_url(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def favorites_user_posts_url(*args); end
|
||||
|
||||
@@ -105,9 +69,6 @@ module GeneratedUrlHelpersModule
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def ib_cookies_global_states_url(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def indexed_posts_url(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def log_entries_url(*args); end
|
||||
|
||||
@@ -228,9 +189,6 @@ module GeneratedUrlHelpersModule
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def root_url(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def scan_post_domain_fa_post_url(*args); end
|
||||
|
||||
sig { params(args: T.untyped).returns(String) }
|
||||
def search_by_name_users_url(*args); end
|
||||
|
||||
|
||||
1
sorbet/rbi/dsl/rails/application_controller.rbi
generated
1
sorbet/rbi/dsl/rails/application_controller.rbi
generated
@@ -44,7 +44,6 @@ class Rails::ApplicationController
|
||||
include ::Domain::PostGroupsHelper
|
||||
include ::DomainSourceHelper
|
||||
include ::GoodJobHelper
|
||||
include ::IndexablePostsHelper
|
||||
include ::SourceHelper
|
||||
include ::DeviseHelper
|
||||
include ::ReactOnRails::Utils::Required
|
||||
|
||||
@@ -44,7 +44,6 @@ class Rails::Conductor::BaseController
|
||||
include ::Domain::PostGroupsHelper
|
||||
include ::DomainSourceHelper
|
||||
include ::GoodJobHelper
|
||||
include ::IndexablePostsHelper
|
||||
include ::SourceHelper
|
||||
include ::DeviseHelper
|
||||
include ::ReactOnRails::Utils::Required
|
||||
|
||||
1
sorbet/rbi/dsl/rails/health_controller.rbi
generated
1
sorbet/rbi/dsl/rails/health_controller.rbi
generated
@@ -44,7 +44,6 @@ class Rails::HealthController
|
||||
include ::Domain::PostGroupsHelper
|
||||
include ::DomainSourceHelper
|
||||
include ::GoodJobHelper
|
||||
include ::IndexablePostsHelper
|
||||
include ::SourceHelper
|
||||
include ::DeviseHelper
|
||||
include ::ReactOnRails::Utils::Required
|
||||
|
||||
@@ -2,14 +2,6 @@
|
||||
require "rails_helper"
|
||||
|
||||
RSpec.describe Domain::Fa::ApiController, type: :controller do
|
||||
describe "GET #search_user_names" do
|
||||
it "returns matching users" do
|
||||
get :search_user_names, params: { name: "test" }
|
||||
expect(response).to be_successful
|
||||
expect(JSON.parse(response.body)).to include("users")
|
||||
end
|
||||
end
|
||||
|
||||
describe "POST #object_statuses" do
|
||||
it "returns status of posts and users" do
|
||||
post :object_statuses, params: { fa_ids: [123], url_names: ["test"] }
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
# typed: false
|
||||
require "rails_helper"
|
||||
|
||||
RSpec.describe Domain::Fa::PostsController, type: :controller do
|
||||
render_views
|
||||
|
||||
describe "GET #show" do
|
||||
let(:post) { create(:domain_fa_post, :with_creator) }
|
||||
|
||||
it "returns a successful response" do
|
||||
get :show,
|
||||
params: {
|
||||
fa_id: post.fa_id,
|
||||
user_url_name: post.creator.url_name,
|
||||
}
|
||||
expect(response).to be_successful
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET #index" do
|
||||
let(:user) { create(:domain_fa_user, :with_avatar) }
|
||||
let!(:posts) do
|
||||
[
|
||||
create(:domain_fa_post, creator: user, title: "Test Post 1"),
|
||||
create(:domain_fa_post, creator: user, title: "Test Post 2"),
|
||||
]
|
||||
end
|
||||
|
||||
before do
|
||||
allow_any_instance_of(Domain::Fa::PostPolicy).to receive(
|
||||
:view_file?,
|
||||
).and_return(true)
|
||||
end
|
||||
|
||||
it "renders index template with posts" do
|
||||
get :index, params: { user_url_name: user.url_name }
|
||||
expect(response).to be_successful
|
||||
expect(response.body).to include(user.name)
|
||||
expect(response.body).to include("posts")
|
||||
posts.each do |post|
|
||||
expect(response.body).to include(post.title)
|
||||
if post.file
|
||||
expect(response.body).to include(
|
||||
blob_path(
|
||||
HexUtil.bin2hex(post.file.response_sha256),
|
||||
format: "jpg",
|
||||
thumb: "small",
|
||||
),
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when viewing a specific user's posts" do
|
||||
it "shows the user's posts with avatar" do
|
||||
get :index, params: { user_url_name: user.url_name }
|
||||
expect(response).to be_successful
|
||||
expect(response.body).to include(user.name)
|
||||
expect(response.body).to include("posts")
|
||||
expect(response.body).to include(
|
||||
blob_path(
|
||||
HexUtil.bin2hex(user.avatar.file_sha256),
|
||||
format: "jpg",
|
||||
thumb: "64-avatar",
|
||||
),
|
||||
)
|
||||
posts.each { |post| expect(response.body).to include(post.title) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,15 +0,0 @@
|
||||
# typed: false
|
||||
require "rails_helper"
|
||||
|
||||
RSpec.describe Domain::Fa::UsersController, type: :controller do
|
||||
render_views
|
||||
|
||||
describe "GET #show" do
|
||||
let(:user) { create(:domain_fa_user, registered_at: 1.year.ago) }
|
||||
|
||||
it "returns a successful response" do
|
||||
get :show, params: { url_name: user.url_name }
|
||||
expect(response).to be_successful
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,78 +0,0 @@
|
||||
# typed: false
|
||||
require "rails_helper"
|
||||
|
||||
RSpec.describe Domain::Inkbunny::PostsController, type: :controller do
|
||||
render_views
|
||||
|
||||
describe "GET #show" do
|
||||
let(:post) { create(:domain_inkbunny_post) }
|
||||
|
||||
it "returns http success" do
|
||||
get :show, params: { ib_post_id: post.ib_post_id }
|
||||
expect(response).to be_successful
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET #index" do
|
||||
let(:user) { create(:domain_inkbunny_user, name: "Test User") }
|
||||
let!(:posts) do
|
||||
[
|
||||
create(:domain_inkbunny_post, creator: user, title: "Test Post 1"),
|
||||
create(:domain_inkbunny_post, creator: user, title: "Test Post 2"),
|
||||
]
|
||||
end
|
||||
let!(:files) do
|
||||
posts.map { |post| create(:domain_inkbunny_file, post: post) }
|
||||
end
|
||||
|
||||
context "when user is not an admin" do
|
||||
it "renders index template with posts but without thumbnails" do
|
||||
get :index, params: { user_name: user.name }
|
||||
expect(response).to be_successful
|
||||
expect(response).to render_template(:index)
|
||||
expect(response.body).to include(posts[0].title)
|
||||
expect(response.body).to include(posts[1].title)
|
||||
expect(response.body).to include(user.name)
|
||||
expect(response.body).not_to match(/<img.+blobs/)
|
||||
end
|
||||
end
|
||||
|
||||
context "when user is an admin" do
|
||||
let(:admin) { create(:user, :admin) }
|
||||
before { sign_in admin }
|
||||
|
||||
it "renders index template with posts and thumbnails" do
|
||||
get :index, params: { user_name: user.name }
|
||||
expect(response).to be_successful
|
||||
expect(response).to render_template(:index)
|
||||
expect(response.body).to include(posts[0].title)
|
||||
expect(response.body).to include(posts[1].title)
|
||||
expect(response.body).to include(user.name)
|
||||
files.each do |file|
|
||||
expect(response.body).to include(
|
||||
blob_path(
|
||||
HexUtil.bin2hex(file.blob_entry_sha256),
|
||||
format: "jpg",
|
||||
thumb: "small",
|
||||
),
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
it "requires a user_name parameter" do
|
||||
expect { get :index }.to raise_error(
|
||||
ActionController::UrlGenerationError,
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context "when viewing a specific user's posts" do
|
||||
it "shows the user's posts" do
|
||||
get :index, params: { user_name: user.name }
|
||||
expect(response).to be_successful
|
||||
expect(response.body).to include("#{user.name}")
|
||||
posts.each { |post| expect(response.body).to include(post.title) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,72 +0,0 @@
|
||||
# typed: false
|
||||
require "rails_helper"
|
||||
|
||||
RSpec.describe IndexedPostsController, type: :controller do
|
||||
render_views
|
||||
|
||||
let(:admin_user) { create(:user, role: :admin) }
|
||||
|
||||
describe "GET #index" do
|
||||
context "when user is not signed in" do
|
||||
it "redirects to the sign in page" do
|
||||
get :index
|
||||
expect(response).to redirect_to(new_user_session_path)
|
||||
end
|
||||
end
|
||||
|
||||
context "when admin user is signed in" do
|
||||
before { sign_in admin_user }
|
||||
|
||||
let(:file) { create(:http_log_entry) }
|
||||
let!(:fa_post) { create(:domain_fa_post, file: file, title: "Test Post") }
|
||||
|
||||
context "with gallery view" do
|
||||
it "renders gallery view with thumbnails" do
|
||||
get :index, params: { view: "gallery" }
|
||||
expect(response).to be_successful
|
||||
expect(response).to render_template(:index)
|
||||
expect(response.body).to include(fa_post.title)
|
||||
expect(response.body).to include(
|
||||
blob_path(
|
||||
HexUtil.bin2hex(file.response_sha256),
|
||||
format: "jpg",
|
||||
thumb: "small",
|
||||
),
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context "with table view" do
|
||||
it "renders table view with thumbnails" do
|
||||
get :index, params: { view: "table" }
|
||||
expect(response).to be_successful
|
||||
expect(response).to render_template(:index)
|
||||
expect(response.body).to include(fa_post.title)
|
||||
expect(response.body).to include(
|
||||
blob_path(
|
||||
HexUtil.bin2hex(file.response_sha256),
|
||||
format: "jpg",
|
||||
thumb: "tiny",
|
||||
),
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context "when post has no file" do
|
||||
let!(:fa_post) do
|
||||
create(:domain_fa_post, file: nil, title: "Test Post")
|
||||
end
|
||||
|
||||
it "shows appropriate message in gallery view" do
|
||||
get :index, params: { view: "gallery" }
|
||||
expect(response.body).to include("No file available")
|
||||
end
|
||||
|
||||
it "shows appropriate message in table view" do
|
||||
get :index, params: { view: "table" }
|
||||
expect(response.body).to include("(none)")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user