tilde.news/app/models/mod_note.rb

150 lines
4.9 KiB
Ruby

# typed: false
class ModNote < ApplicationRecord
extend TimeAgoInWords
belongs_to :moderator,
class_name: "User",
foreign_key: "moderator_user_id",
inverse_of: :moderations
belongs_to :user,
inverse_of: :mod_notes
scope :recent, -> { where("created_at >= ?", 1.week.ago).order("created_at desc") }
scope :for, ->(user) { includes(:moderator).where(user_id: user).order("created_at desc") }
validates :note, :markeddown_note, presence: true, length: {maximum: 65_535}
delegate :username, to: :user
def username=(username)
self.user_id = nil
if (u = User.find_by(username: username))
self.user_id = u.id
@username = u.username
else
errors.add(:username, "is not a valid user")
end
end
def note=(n)
self[:note] = n.to_s.strip
self.markeddown_note = generated_markeddown
end
def generated_markeddown
Markdowner.to_html(note)
end
def self.create_from_message(message, moderator)
user = (moderator.id == message.recipient.id && message.author) ?
message.author : message.recipient
ModNote.create!(
moderator: moderator,
user: user,
created_at: message.created_at,
note: <<~NOTE
*#{message.author ? message.author.username : "(System)"} #{message.hat ? message.hat.to_txt : ""}-> #{message.recipient.username}*: #{message.subject}
#{message.body}
NOTE
)
end
def self.tattle_on_invited(redeemer, invitation_code)
invitation = Invitation.find_by(code: invitation_code)
return unless invitation
invitation.update!(used_at: Time.current, new_user: nil)
sender = invitation.user
sender_url = Rails.application.routes.url_helpers.user_url(
sender,
host: Rails.application.domain
)
redeemer_url = Rails.application.routes.url_helpers.user_url(
sender,
host: Rails.application.domain
)
create_without_dupe!(
moderator: InactiveUser.inactive_user,
user: redeemer,
created_at: Time.current,
note: "Attempted to redeem invitation code #{invitation.code} while logged in:\n" \
"- sent by: [#{sender.username}](#{sender_url})\n" \
"- created_at: #{invitation.created_at}\n" \
"- used_at: #{invitation.used_at || "unused"}\n" \
"- email: #{invitation.email}\n" \
"- memo: #{invitation.memo}"
)
create_without_dupe!(
moderator: InactiveUser.inactive_user,
user: sender,
created_at: Time.current,
note: "Sent invitation #{invitation.code} another user tried to redeem while logged in:\n" \
"- attempted redeemer: [#{redeemer.username}](#{redeemer_url})\n" \
"- created_at: #{invitation.created_at}\n" \
"- used_at: #{invitation.used_at || "unused"}\n" \
"- email: #{invitation.email}\n" \
"- memo: #{invitation.memo}"
)
end
def self.tattle_on_max_depth_limit(user, parent_comment)
parent_author_url = Rails.application.routes.url_helpers.user_url(
parent_comment.user,
host: Rails.application.domain
)
comment_url = Rails.application.routes.url_helpers.comment_url(
parent_comment,
host: Rails.application.domain
)
create_without_dupe!(
moderator: InactiveUser.inactive_user,
user: user,
created_at: Time.current,
note: "Hit max comment depth replying to [#{parent_comment.short_id}](#{comment_url}) " \
"by [#{parent_comment.user.username}](#{parent_author_url})"
)
end
def self.tattle_on_new_user_tagging!(story)
create_without_dupe!(
moderator: InactiveUser.inactive_user,
user: story.user,
created_at: Time.current,
note: "Attempted to submit a story with tag(s) not allowed to new users:\n" \
"- user joined: #{time_ago_in_words(story.user.created_at)}\n" \
"- url: #{story.url}\n" \
"- title: #{story.title}\n" \
"- user_is_author: #{story.user_is_author}\n" \
"- tags: #{story.tags_a.join(" ")}\n" \
"- description: #{story.description}\n"
)
end
def self.tattle_on_story_domain!(story, reason)
create_without_dupe!(
moderator: InactiveUser.inactive_user,
user: story.user,
created_at: Time.current,
note: "Attempted to post a story from a #{reason} domain:\n" \
"- user joined: #{time_ago_in_words(story.user.created_at)}\n" \
"- url: #{story.url}\n" \
"- title: #{story.title}\n" \
"- user_is_author: #{story.user_is_author}\n" \
"- tags: #{story.tags_a.join(" ")}\n" \
"- description: #{story.description}\n"
)
end
# story validations run on preview, check_url_dupe, title fetching
# and save attempts, leading to duplicate notes
def self.create_without_dupe!(attrs)
latest = attrs[:user].mod_notes.last
return latest if latest && attrs[:moderator] == latest.moderator && attrs[:note] == latest.note
ModNote.create!(attrs)
end
end