commit
f3f0d13b6e
@ -0,0 +1,87 @@
|
|||||||
|
class LibrariesController < ApplicationController
|
||||||
|
include PaginateHelper
|
||||||
|
|
||||||
|
before_action :require_login, :check_auth, except: %i[index show]
|
||||||
|
|
||||||
|
helper_method :current_library, :library_manageable?
|
||||||
|
|
||||||
|
def index
|
||||||
|
libraries = Library.all
|
||||||
|
|
||||||
|
libraries =
|
||||||
|
if User.current&.logged? && params[:type] == 'mine'
|
||||||
|
libraries.where(user_id: current_user.id).order(created_at: :desc)
|
||||||
|
else
|
||||||
|
libraries.where(status: :published).order(visited_count: :desc)
|
||||||
|
end
|
||||||
|
|
||||||
|
keyword = params[:keyword].to_s.strip
|
||||||
|
if keyword.present?
|
||||||
|
libraries = libraries.where('title LIKE :keyword OR author_name LIKE :keyword OR author_school_name LIKE :keyword',
|
||||||
|
keyword: "%#{keyword}%")
|
||||||
|
end
|
||||||
|
|
||||||
|
@count = libraries.count
|
||||||
|
@libraries = paginate libraries.includes(:library_tags, :praise_tread_cache, user: :user_extension)
|
||||||
|
|
||||||
|
ids = @libraries.map(&:id)
|
||||||
|
@download_count_map = Attachment.where(container_type: 'Library', container_id: ids)
|
||||||
|
.group(:container_id).sum(:downloads)
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
unless current_library.published? || library_manageable?(current_library)
|
||||||
|
return render_forbidden
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
library = current_user.libraries.new
|
||||||
|
Libraries::SaveService.call(library, current_user, save_params)
|
||||||
|
render_ok
|
||||||
|
rescue Libraries::SaveService::Error => ex
|
||||||
|
render_error(ex.message)
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
return render_forbidden unless library_manageable?(current_library)
|
||||||
|
|
||||||
|
Libraries::SaveService.call(current_library, current_user, save_params)
|
||||||
|
render_ok
|
||||||
|
rescue Libraries::SaveService::Error => ex
|
||||||
|
render_error(ex.message)
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
if admin_or_business?
|
||||||
|
current_library.destroy!
|
||||||
|
elsif current_library.user_id == current_user&.id
|
||||||
|
unless current_library.pending?
|
||||||
|
render_error('只有草稿才能删除')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
current_library.destroy!
|
||||||
|
else
|
||||||
|
render_forbidden
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
render_ok
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def current_library
|
||||||
|
@_current_library ||= Library.find(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def library_manageable?(library)
|
||||||
|
current_user&.id == library.user_id || admin_or_business?
|
||||||
|
end
|
||||||
|
|
||||||
|
def save_params
|
||||||
|
params.permit(:title, :content, :author_name, :author_school_name,
|
||||||
|
:cover_id, :publish, attachment_ids: [], tag_ids: [])
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,5 @@
|
|||||||
|
module LibraryDecorator
|
||||||
|
extend ApplicationDecorator
|
||||||
|
|
||||||
|
display_time_method :published_at, :created_at, :updated_at
|
||||||
|
end
|
@ -0,0 +1,12 @@
|
|||||||
|
class Libraries::SaveForm
|
||||||
|
include ActiveModel::Model
|
||||||
|
|
||||||
|
attr_accessor :title, :content, :author_name, :author_school_name, :cover_id,
|
||||||
|
:publish, :attachment_ids, :tag_ids
|
||||||
|
|
||||||
|
validates :title, presence: true, length: { maximum: 255 }
|
||||||
|
validates :content, presence: true
|
||||||
|
validates :author_name, presence: true, length: { maximum: 10 }
|
||||||
|
validates :author_school_name, presence: true, length: { maximum: 50 }
|
||||||
|
validates :attachment_ids, presence: true
|
||||||
|
end
|
@ -0,0 +1,9 @@
|
|||||||
|
module Util
|
||||||
|
module UUID
|
||||||
|
module_function
|
||||||
|
|
||||||
|
def time_uuid(format: '%Y%m%d%H%M%S', suffix: 8)
|
||||||
|
"#{Time.zone.now.strftime(format)}#{Random.rand(10**suffix).to_i}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,43 @@
|
|||||||
|
class Library < ApplicationRecord
|
||||||
|
include AASM
|
||||||
|
|
||||||
|
belongs_to :user
|
||||||
|
belongs_to :cover, class_name: 'Attachment', foreign_key: :cover_id, optional: true
|
||||||
|
|
||||||
|
has_many :library_applies, dependent: :delete_all
|
||||||
|
has_many :library_library_tags, dependent: :delete_all
|
||||||
|
has_many :library_tags, through: :library_library_tags
|
||||||
|
|
||||||
|
has_many :attachments, as: :container
|
||||||
|
has_one :praise_tread_cache, foreign_key: :object_id
|
||||||
|
|
||||||
|
validates :uuid, presence: true, uniqueness: true
|
||||||
|
|
||||||
|
aasm(:status) do
|
||||||
|
state :pending, initiali: true
|
||||||
|
state :processing
|
||||||
|
state :refused
|
||||||
|
state :published
|
||||||
|
|
||||||
|
event :submit do
|
||||||
|
transitions from: [:pending, :refused], to: :processing
|
||||||
|
end
|
||||||
|
|
||||||
|
event :refuse do
|
||||||
|
transitions from: :processing, to: :refused
|
||||||
|
end
|
||||||
|
|
||||||
|
event :publish do
|
||||||
|
transitions from: :processing, to: :published
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate_uuid
|
||||||
|
uuid = Util::UUID.time_uuid
|
||||||
|
while Library.exists?(uuid: uuid)
|
||||||
|
uuid = Util::UUID.time_uuid
|
||||||
|
end
|
||||||
|
|
||||||
|
self.uuid = uuid
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,19 @@
|
|||||||
|
class LibraryApply < ApplicationRecord
|
||||||
|
include AASM
|
||||||
|
|
||||||
|
belongs_to :library
|
||||||
|
|
||||||
|
aasm(:status) do
|
||||||
|
state :pending, initiali: true
|
||||||
|
state :refused
|
||||||
|
state :agreed
|
||||||
|
|
||||||
|
event :refuse do
|
||||||
|
transitions from: :pending, to: :refused
|
||||||
|
end
|
||||||
|
|
||||||
|
event :agree do
|
||||||
|
transitions from: :pending, to: :agreed
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,4 @@
|
|||||||
|
class LibraryLibraryTag < ApplicationRecord
|
||||||
|
belongs_to :library
|
||||||
|
belongs_to :library_tag
|
||||||
|
end
|
@ -0,0 +1,6 @@
|
|||||||
|
class LibraryTag < ApplicationRecord
|
||||||
|
has_many :library_library_tags, dependent: :delete_all
|
||||||
|
has_many :libraries, through: :library_library_tags
|
||||||
|
|
||||||
|
validates :name, presence: true, uniqueness: true
|
||||||
|
end
|
@ -0,0 +1,32 @@
|
|||||||
|
class Libraries::AgreeApplyService < ApplicationService
|
||||||
|
Error = Class.new(StandardError)
|
||||||
|
|
||||||
|
attr_reader :library_apply, :library, :user
|
||||||
|
|
||||||
|
def initialize(library_apply, user)
|
||||||
|
@library_apply = library_apply
|
||||||
|
@library = library_apply.library
|
||||||
|
@user = user
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
raise Error, '该状态下不能进行此操作' unless library_apply.may_agree?
|
||||||
|
|
||||||
|
ActiveRecord::Base.transaction do
|
||||||
|
library_apply.agree!
|
||||||
|
library_apply.library.publish!
|
||||||
|
|
||||||
|
# 将消息改为已处理
|
||||||
|
Tiding.where(container_id: library.id, container_type: 'Library', tiding_type: 'Apply', status: 0).update_all(status: 1)
|
||||||
|
notify_library_author!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def notify_library_author!
|
||||||
|
Tiding.create!(user_id: library.user_id, trigger_user_id: 1,
|
||||||
|
container_id: library.id, container_type: 'Library',
|
||||||
|
tiding_type: 'System', status: 1)
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,39 @@
|
|||||||
|
class Libraries::RefuseApplyService < ApplicationService
|
||||||
|
Error = Class.new(StandardError)
|
||||||
|
|
||||||
|
attr_reader :library_apply, :library, :user, :params
|
||||||
|
|
||||||
|
def initialize(library_apply, user, params)
|
||||||
|
@library_apply = library_apply
|
||||||
|
@library = library_apply.library
|
||||||
|
@user = user
|
||||||
|
@params = params
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
reason = params[:reason].to_s.strip
|
||||||
|
raise Error, '原因不能为空' if reason.blank?
|
||||||
|
raise Error, '该状态下不能进行此操作' unless library_apply.may_refuse?
|
||||||
|
|
||||||
|
ActiveRecord::Base.transaction do
|
||||||
|
library_apply.reason = reason
|
||||||
|
library_apply.refused_at = Time.current
|
||||||
|
library_apply.refuse
|
||||||
|
library_apply.save!
|
||||||
|
|
||||||
|
library.refuse!
|
||||||
|
|
||||||
|
# 将消息改为已处理
|
||||||
|
Tiding.where(container_id: library.id, container_type: 'Library', tiding_type: 'Apply', status: 0).update_all(status: 1)
|
||||||
|
notify_library_author!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def notify_library_author!
|
||||||
|
Tiding.create!(user_id: library.user_id, trigger_user_id: 1,
|
||||||
|
container_id: library.id, container_type: 'Library',
|
||||||
|
tiding_type: 'System', status: 2, extra: library_apply.reason)
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,69 @@
|
|||||||
|
class Libraries::SaveService < ApplicationService
|
||||||
|
Error = Class.new(StandardError)
|
||||||
|
|
||||||
|
attr_reader :library, :user, :params
|
||||||
|
|
||||||
|
def initialize(library, user, params)
|
||||||
|
@library = library
|
||||||
|
@user = user
|
||||||
|
@params = params
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
Libraries::SaveForm.new(params).validate!
|
||||||
|
|
||||||
|
if library.new_record?
|
||||||
|
library.user_id = user.id
|
||||||
|
library.generate_uuid
|
||||||
|
end
|
||||||
|
|
||||||
|
ActiveRecord::Base.transaction do
|
||||||
|
library.assign_attributes(library_params)
|
||||||
|
library.save!
|
||||||
|
|
||||||
|
deal_library_tag!
|
||||||
|
deal_attachments!
|
||||||
|
|
||||||
|
Libraries::SubmitService.call(library) if with_publish?
|
||||||
|
end
|
||||||
|
|
||||||
|
library
|
||||||
|
rescue Libraries::SubmitService::Error => ex
|
||||||
|
raise Error, ex.message
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def deal_library_tag!
|
||||||
|
new_tag_ids = LibraryTag.where(id: Array.wrap(params[:tag_ids]).compact).pluck(:id)
|
||||||
|
old_tag_ids = library.library_library_tags.pluck(:library_tag_id)
|
||||||
|
|
||||||
|
# 删除标签
|
||||||
|
destroy_ids = old_tag_ids - new_tag_ids
|
||||||
|
library.library_library_tags.where(library_tag_id: destroy_ids).delete_all
|
||||||
|
|
||||||
|
# 创建标签
|
||||||
|
created_ids = new_tag_ids - old_tag_ids
|
||||||
|
created_ids.each do |id|
|
||||||
|
library.library_library_tags.create!(library_tag_id: id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def deal_attachments!
|
||||||
|
attachment_ids = Array.wrap(params[:attachment_ids]).compact.map(&:to_i)
|
||||||
|
old_attachment_id = library.attachments.pluck(:id)
|
||||||
|
|
||||||
|
destroy_ids = old_attachment_id - attachment_ids
|
||||||
|
library.attachments.where(id: destroy_ids).delete_all
|
||||||
|
|
||||||
|
Attachment.where(id: attachment_ids, author_id: user.id).update_all(container: library)
|
||||||
|
end
|
||||||
|
|
||||||
|
def library_params
|
||||||
|
params.slice(*%i[title content author_name author_school_name cover_id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def with_publish?
|
||||||
|
params[:publish].to_s == 'true'
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,32 @@
|
|||||||
|
class Libraries::SubmitService < ApplicationService
|
||||||
|
Error = Class.new(StandardError)
|
||||||
|
|
||||||
|
attr_reader :library
|
||||||
|
|
||||||
|
def initialize(library)
|
||||||
|
@library = library
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
return if library.processing? || library.published?
|
||||||
|
|
||||||
|
raise Error, '该状态下不能提交审核' unless library.may_submit?
|
||||||
|
|
||||||
|
ActiveRecord::Base.transaction do
|
||||||
|
library.published_at = Time.current
|
||||||
|
library.submit
|
||||||
|
library.save!
|
||||||
|
|
||||||
|
library.library_applies.create!
|
||||||
|
send_library_apply_notify!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def send_library_apply_notify!
|
||||||
|
Tiding.create!(user_id: 1, trigger_user_id: library.user_id,
|
||||||
|
container_id: library.id, container_type: 'Library',
|
||||||
|
tiding_type: 'Apply', status: 0)
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,16 @@
|
|||||||
|
json.count @count
|
||||||
|
json.libraries do
|
||||||
|
json.array! @libraries.each do |library|
|
||||||
|
json.extract! library, :id, :title, :content, :author_name, :author_school_name, :status, :visited_count
|
||||||
|
|
||||||
|
json.cover_url library.cover_id.present? ? download_url(library.cover) : nil
|
||||||
|
|
||||||
|
json.praise_count library.praise_tread_cache&.praise_num || 0
|
||||||
|
json.download_count @download_count_map.fetch(library.id, 0)
|
||||||
|
|
||||||
|
json.published_at library.display_published_at
|
||||||
|
json.created_at library.display_created_at
|
||||||
|
|
||||||
|
json.tags library.library_tags.map(&:name)
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,46 @@
|
|||||||
|
library = current_library
|
||||||
|
|
||||||
|
json.extract! library, :id, :uuid, :title, :content, :author_name, :author_school_name, :status, :visited_count
|
||||||
|
|
||||||
|
json.praise_count library.praise_tread_cache&.praise_num || 0
|
||||||
|
|
||||||
|
json.published_at library.display_published_at
|
||||||
|
json.created_at library.display_created_at
|
||||||
|
|
||||||
|
# 创建者
|
||||||
|
json.creator do
|
||||||
|
json.partial! 'users/user_simple', user: library.user
|
||||||
|
end
|
||||||
|
|
||||||
|
# 封面
|
||||||
|
if library.cover_id.present?
|
||||||
|
json.cover do
|
||||||
|
json.partial! 'attachments/attachment_simple', attachment: library.cover
|
||||||
|
end
|
||||||
|
else
|
||||||
|
json.cover nil
|
||||||
|
end
|
||||||
|
|
||||||
|
json.attachments library.attachments, partial: 'attachments/attachment_small', as: :attachment
|
||||||
|
|
||||||
|
# 标签
|
||||||
|
json.tags do
|
||||||
|
json.array! library.library_tags.each do |tag|
|
||||||
|
json.extract! tag, :id, :name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# 操作权限
|
||||||
|
json.operation do
|
||||||
|
if current_user&.logged?
|
||||||
|
manageable = library_manageable?(library)
|
||||||
|
|
||||||
|
json.can_deletable manageable
|
||||||
|
json.can_editable manageable
|
||||||
|
json.user_praised PraiseTread.exists?(user_id: current_user&.id)
|
||||||
|
else
|
||||||
|
json.can_deletable false
|
||||||
|
json.can_editable false
|
||||||
|
json.user_praised false
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,12 @@
|
|||||||
|
'zh-CN':
|
||||||
|
activemodel:
|
||||||
|
attributes:
|
||||||
|
libraries/save_form:
|
||||||
|
title: 标题
|
||||||
|
content: 描述
|
||||||
|
author_name: 作者名称
|
||||||
|
author_school_name: 作者单位
|
||||||
|
cover_id: 封面
|
||||||
|
publish: ''
|
||||||
|
attachment_ids: 附件
|
||||||
|
tag_ids: 标签
|
Loading…
Reference in new issue