Class: Post

Inherits:
ApplicationRecord show all
Includes:
CommunityRelated, PostValidations
Defined in:
app/models/post.rb

Direct Known Subclasses

Answer, Article, HelpDoc, PolicyDoc, Question

Class Method Summary collapse

Instance Method Summary collapse

Methods included from PostValidations

#maximum_tag_length, #maximum_tags, #maximum_title_length, #no_spaces_in_tags, #required_tags?, #stripped_minimum_body, #stripped_minimum_title, #tags_in_tag_set

Methods inherited from ApplicationRecord

#attributes_print, fuzzy_search, match_search, #match_search, sanitize_for_search, sanitize_name, sanitize_sql_in, useful_err_msg, with_lax_group_rules

Class Method Details

.by_slug(slug, user) ⇒ Object



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'app/models/post.rb', line 66

def self.by_slug(slug, user)
  post = Post.unscoped.where(
    doc_slug: slug,
    community_id: [RequestContext.community_id, nil]
  ).first

  if post&.help_category == '$Disabled'
    return nil
  end

  if post&.help_category == '$Moderator' && !user&.is_moderator
    return nil
  end

  post
end

.search(term) ⇒ ActiveRecord::Relation<Post>

Parameters:

  • term (String)

    the search term

Returns:

  • (ActiveRecord::Relation<Post>)


62
63
64
# File 'app/models/post.rb', line 62

def self.search(term)
  match_search term, posts: :body_markdown
end

Instance Method Details

#answer?Boolean

Returns whether this post is an answer.

Returns:

  • (Boolean)

    whether this post is an answer



160
161
162
# File 'app/models/post.rb', line 160

def answer?
  post_type_id == Answer.post_type_id
end

#article?Boolean

Returns whether this post is an article.

Returns:

  • (Boolean)

    whether this post is an article



165
166
167
# File 'app/models/post.rb', line 165

def article?
  post_type_id == Article.post_type_id
end

#body_plainString

Returns the body with all markdown stripped.

Returns:

  • (String)

    the body with all markdown stripped



150
151
152
# File 'app/models/post.rb', line 150

def body_plain
  ApplicationController.helpers.strip_markdown(body_markdown)
end

#can_access?(user) ⇒ Boolean

Returns whether the given user can view this post.

Parameters:

Returns:

  • (Boolean)

    whether the given user can view this post



215
216
217
218
219
# File 'app/models/post.rb', line 215

def can_access?(user)
  (!deleted? || user&.has_post_privilege?('flag_curate', self)) &&
    (!category.present? || !category.min_view_trust_level.present? ||
      category.min_view_trust_level <= (user&.trust_level || 0))
end

#last_activity_typeString

Returns the type of the last activity on this post.

Returns:

  • (String)

    the type of the last activity on this post



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'app/models/post.rb', line 126

def last_activity_type
  case last_activity
  when closed_at
    if closed == false
      'reopened'
    else
      if duplicate_post
        'closed as duplicate'
      else
        'closed'
      end
    end
  when locked_at
    'locked'
  when deleted_at
    'deleted'
  when last_edited_at
    'edited'
  else
    'last activity'
  end
end

#locked?Boolean

This method will update the locked status of this post if locked_until is in the past.

Returns:

  • (Boolean)

    whether this post is locked



194
195
196
197
198
199
200
201
202
203
# File 'app/models/post.rb', line 194

def locked?
  return true if locked && locked_until.nil? # permanent lock
  return true if locked && !locked_until.past?

  if locked
    update(locked: false, locked_by: nil, locked_at: nil, locked_until: nil)
  end

  false
end

#meta?Boolean

Returns:

  • (Boolean)


103
104
105
# File 'app/models/post.rb', line 103

def meta?
  false
end

#pending_suggested_editSuggestedEdit, Nil

Returns the suggested edit pending for this post (if any).

Returns:

  • (SuggestedEdit, Nil)

    the suggested edit pending for this post (if any)



175
176
177
# File 'app/models/post.rb', line 175

def pending_suggested_edit
  SuggestedEdit.where(post_id: id, active: true).last
end

#pending_suggested_edit?Boolean

Returns whether there is a suggested edit pending for this post.

Returns:

  • (Boolean)

    whether there is a suggested edit pending for this post



170
171
172
# File 'app/models/post.rb', line 170

def pending_suggested_edit?
  SuggestedEdit.where(post_id: id, active: true).any?
end

#question?Boolean

Returns whether this post is a question.

Returns:

  • (Boolean)

    whether this post is a question



155
156
157
# File 'app/models/post.rb', line 155

def question?
  post_type_id == Question.post_type_id
end

#reaction_listHash

Returns a hash with as key the reaction type and value the amount of reactions for that type.

Returns:

  • (Hash)

    a hash with as key the reaction type and value the amount of reactions for that type



222
223
224
225
# File 'app/models/post.rb', line 222

def reaction_list
  reactions.includes(:reaction_type).group_by(&:reaction_type_id)
           .to_h { |_k, v| [v.first.reaction_type, v] }
end

#reassign_user(new_user) ⇒ Object

Used in the transfer of content from SE to reassign the owner of a post to the given user.

Parameters:



109
110
111
112
113
114
115
116
117
# File 'app/models/post.rb', line 109

def reassign_user(new_user)
  new_user.ensure_community_user!

  # Three updates: one to remove rep from previous user, one to reassign, one to re-grant rep to new user
  update!(deleted: true, deleted_at: DateTime.now, deleted_by: User.find(-1))
  update!(user: new_user)
  votes.update_all(recv_user_id: new_user.id)
  update!(deleted: false, deleted_at: nil, deleted_by: nil)
end

#recalc_scoreObject

Recalculates the score of this post based on its up and downvotes



180
181
182
183
184
185
186
187
188
189
190
# File 'app/models/post.rb', line 180

def recalc_score
  variable = SiteSetting['ScoringVariable'] || 2
  sql = 'UPDATE posts SET score = (upvote_count + ?) / (upvote_count + downvote_count + (2 * ?)) WHERE id = ?'
  sanitized = ActiveRecord::Base.sanitize_sql_array([sql, variable, variable, id])
  ActiveRecord::Base.connection.execute sanitized

  # ensures the updated score is immediately available
  self.score = (upvote_count + variable).to_f / (upvote_count + downvote_count + (2 * variable))
  # prevents AR from accidentally saving the dirty state
  clear_attribute_changes([:score])
end

#remove_attribution_notice!Boolean

Removes the attribution notice from this post

Returns:

  • (Boolean)

    whether the action was successful



121
122
123
# File 'app/models/post.rb', line 121

def remove_attribution_notice!
  update(att_source: nil, att_license_link: nil, att_license_name: nil)
end

#spam_flag_pending?Boolean

The test here is for flags that are pending (no status). A spam flag could be marked helpful but the post wouldn’t be deleted, and we don’t necessarily want the post to be treated like it’s a spam risk if that happens.

Returns:

  • (Boolean)


209
210
211
# File 'app/models/post.rb', line 209

def spam_flag_pending?
  flags.any? { |flag| flag.post_flag_type&.name == "it's spam" && !flag.status }
end

#tag_setTagSet

Returns:



98
99
100
# File 'app/models/post.rb', line 98

def tag_set
  parent.nil? ? category.tag_set : parent.category.tag_set
end