Skip to content

Commit

Permalink
Merge pull request #93 from codidact/art/articles
Browse files Browse the repository at this point in the history
  • Loading branch information
ArtOfCode- authored Jun 9, 2020
2 parents 0d78331 + fad351b commit b0571f1
Show file tree
Hide file tree
Showing 34 changed files with 470 additions and 90 deletions.
3 changes: 3 additions & 0 deletions app/assets/javascripts/articles.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
3 changes: 3 additions & 0 deletions app/assets/stylesheets/articles.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Place all the styles related to the Articles controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
9 changes: 9 additions & 0 deletions app/assets/stylesheets/posts.scss
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,12 @@ h1 .badge.is-tag.is-master-tag {
margin-bottom: 0;
}
}

.post--title {
display: flex;
align-items: center;

> .badge {
margin-left: 0.5em;
}
}
92 changes: 92 additions & 0 deletions app/controllers/articles_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
class ArticlesController < ApplicationController
before_action :set_article
before_action :check_article

def show
if @article.deleted?
check_your_privilege('ViewDeleted', @article) # || return
end
end

def share
redirect_to article_path(params[:id])
end

def edit
check_your_privilege('Edit', @article)
end

def update
return unless check_your_privilege('Edit', @article)

PostHistory.post_edited(@article, current_user, before: @article.body_markdown,
after: params[:article][:body_markdown], comment: params[:edit_comment])
body_rendered = helpers.render_markdown(params[:article][:body_markdown])
if @article.update(article_params.merge(tags_cache: params[:article][:tags_cache]&.reject { |e| e.to_s.empty? },
body: body_rendered, last_activity: DateTime.now,
last_activity_by: current_user))
redirect_to article_path(@article)
else
render :edit
end
end

def destroy
unless check_your_privilege('Delete', @article, false)
flash[:danger] = 'You must have the Delete privilege to delete posts.'
redirect_to article_path(@article) && return
end

if @article.deleted
flash[:danger] = "Can't delete a deleted post."
redirect_to article_path(@article) && return
end

if @article.update(deleted: true, deleted_at: DateTime.now, deleted_by: current_user,
last_activity: DateTime.now, last_activity_by: current_user)
PostHistory.post_deleted(@article, current_user)
else
flash[:danger] = "Can't delete this post right now. Try again later."
end
redirect_to article_path(@article)
end

def undelete
unless check_your_privilege('Delete', @article, false)
flash[:danger] = 'You must have the Delete privilege to undelete posts.'
redirect_to article_path(@article) && return
end

unless @article.deleted
flash[:danger] = "Can't undelete an undeleted post."
redirect_to article_path(@article) && return
end

if @article.update(deleted: false, deleted_at: nil, deleted_by: nil,
last_activity: DateTime.now, last_activity_by: current_user)
PostHistory.post_undeleted(@article, current_user)
else
flash[:danger] = "Can't undelete this article right now. Try again later."
end
redirect_to article_path(@article)
end

private

def set_article
@article = Article.find params[:id]
if @article.deleted && !current_user&.has_post_privilege?('ViewDeleted', @article)
not_found
end
end

def check_article
unless @article.post_type_id == Article.post_type_id
not_found
end
end

def article_params
params.require(:article).permit(:body_markdown, :title, :tags_cache)
end
end
15 changes: 2 additions & 13 deletions app/controllers/comments_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -88,21 +88,10 @@ def check_privilege
def comment_link(comment)
if comment.post.question?
question_path(comment.post, anchor: "comment-#{comment.id}")
elsif comment.post.article?
article_path(comment.post, anchor: "comment-#{comment.id}")
else
question_path(comment.post.parent, anchor: "comment-#{comment.id}")
end
end
end

# Provides a custom HTML sanitization interface to use for cleaning up the HTML in questions.
class CommentScrubber < Rails::Html::PermitScrubber
def initialize
super
self.tags = %w[a b i em strong strike del code]
self.attributes = %w[href title]
end

def skip_node?(node)
node.text?
end
end
5 changes: 3 additions & 2 deletions app/controllers/posts_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ def new

def create
@category = Category.find(params[:category_id])
@post = Post.new(post_params.merge(category: @category, user: current_user, post_type_id: params[:post_type_id],
@post = Post.new(post_params.merge(category: @category, user: current_user,
post_type_id: params[:post][:post_type_id] || params[:post_type_id],
body: helpers.render_markdown(params[:post][:body_markdown])))

if @category.min_trust_level.present? && @category.min_trust_level > current_user.trust_level
Expand All @@ -25,7 +26,7 @@ def create
end

if @post.save
redirect_to question_path(@post)
redirect_to helpers.generic_show_link(@post)
else
render :new, status: 400
end
Expand Down
10 changes: 7 additions & 3 deletions app/controllers/questions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def update
PostHistory.post_edited(@question, current_user, before: @question.body_markdown,
after: params[:question][:body_markdown], comment: params[:edit_comment])
body_rendered = helpers.render_markdown(params[:question][:body_markdown])
if @question.update(question_params.merge(tags_cache: params[:question][:tags_cache]&.reject(&:empty?),
if @question.update(question_params.merge(tags_cache: params[:question][:tags_cache]&.reject { |e| e.to_s.empty? },
body: body_rendered, last_activity: DateTime.now,
last_activity_by: current_user))
redirect_to url_for(controller: :questions, action: :show, id: @question.id)
Expand Down Expand Up @@ -191,11 +191,15 @@ def question_params
def set_question
@question = Question.find params[:id]
rescue
if current_user.has_privilege?('ViewDeleted')
if current_user&.has_privilege?('ViewDeleted')
@question ||= Question.unscoped.find params[:id]
end
if @question.nil?
render template: 'errors/not_found', status: 404
not_found
return
end
unless @question.post_type_id == Question.post_type_id
not_found
end
end
end
37 changes: 37 additions & 0 deletions app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,41 @@ def strip_markdown(markdown)

markdown
end

def generic_share_link(post)
case post.post_type_id
when Question.post_type_id
share_question_url(post)
when Answer.post_type_id
share_answer_url(qid: post.parent_id, id: post.id)
when Article.post_type_id
share_article_url(post)
else
'#'
end
end

def generic_edit_link(post)
case post.post_type_id
when Question.post_type_id
edit_question_url(post)
when Answer.post_type_id
edit_answer_url(post)
when Article.post_type_id
edit_article_url(post)
else
'#'
end
end

def generic_show_link(post)
case post.post_type_id
when Question.post_type_id
question_url(post)
when Article.post_type_id
article_url(post)
else
'#'
end
end
end
2 changes: 2 additions & 0 deletions app/helpers/articles_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module ArticlesHelper
end
5 changes: 4 additions & 1 deletion app/helpers/categories_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ def active?(category)
def expandable?
(defined?(@category) && !current_page?(new_category_path)) ||
(defined?(@post) && !@post.category.nil?) ||
(defined?(@question) && !@question.category.nil?)
(defined?(@question) && !@question.category.nil?) ||
(defined?(@article) && !@article.category.nil?)
end

def current_category
Expand All @@ -18,6 +19,8 @@ def current_category
@post.category
elsif defined?(@question) && !@question.category.nil?
@question.category
elsif defined?(@article) && !@article.category.nil?
@article.category
end
end
end
12 changes: 12 additions & 0 deletions app/helpers/comments_helper.rb
Original file line number Diff line number Diff line change
@@ -1,2 +1,14 @@
module CommentsHelper
end

class CommentScrubber < Rails::Html::PermitScrubber
def initialize
super
self.tags = %w[a b i em strong strike del code]
self.attributes = %w[href title]
end

def skip_node?(node)
node.text?
end
end
12 changes: 12 additions & 0 deletions app/helpers/post_types_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module PostTypesHelper
def post_type_badge(type)
icon_class = {
'Question' => 'fas fa-question',
'Article' => 'fas fa-newspaper'
}[type]
tag.span class: 'badge is-tag is-filled is-muted' do
tag.i(class: icon_class) + ' ' +
tag.span(type)
end
end
end
7 changes: 7 additions & 0 deletions app/models/article.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class Article < Post
default_scope { where(post_type_id: Article.post_type_id) }

def self.post_type_id
PostType.mapping['Article']
end
end
20 changes: 10 additions & 10 deletions app/models/post.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ class Post < ApplicationRecord

validates :body, presence: true, length: { minimum: 30, maximum: 30_000 }
validates :doc_slug, uniqueness: { scope: [:community_id] }, if: -> { doc_slug.present? }
validates :title, :body, :tags_cache, presence: true, if: :question?
validate :tags_in_tag_set, if: :question?
validate :maximum_tags, if: :question?
validate :maximum_tag_length, if: :question?
validate :no_spaces_in_tags, if: :question?
validate :stripped_minimum, if: :question?
validates :title, :body, :tags_cache, presence: true, if: -> { question? || article? }
validate :tags_in_tag_set, if: -> { question? || article? }
validate :maximum_tags, if: -> { question? || article? }
validate :maximum_tag_length, if: -> { question? || article? }
validate :no_spaces_in_tags, if: -> { question? || article? }
validate :stripped_minimum, if: -> { question? || article? }
validate :category_allows_post_type
validate :license_available
validate :required_tags?, if: -> { post_type_id == Question.post_type_id }
validate :required_tags?, if: -> { question? || article? }

scope :undeleted, -> { where(deleted: false) }
scope :deleted, -> { where(deleted: true) }
Expand All @@ -42,8 +42,8 @@ class Post < ApplicationRecord
after_save :modify_author_reputation
after_save :copy_last_activity_to_parent
after_save :break_description_cache
after_save :update_category_activity, if: :question?
before_validation :update_tag_associations, if: :question?
after_save :update_category_activity, if: -> { question? || article? }
before_validation :update_tag_associations, if: -> { question? || article? }
after_create :create_initial_revision
after_create :add_license_if_nil

Expand All @@ -53,7 +53,7 @@ def self.search(term)

# Double-define: initial definitions are less efficient, so if we have a record of the post type we'll
# override them later with more efficient methods.
['Question', 'Answer', 'PolicyDoc', 'HelpDoc'].each do |pt|
['Question', 'Answer', 'PolicyDoc', 'HelpDoc', 'Article'].each do |pt|
define_method "#{pt.underscore}?" do
post_type_id == pt.constantize.post_type_id
end
Expand Down
7 changes: 5 additions & 2 deletions app/models/vote.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ class Vote < ApplicationRecord
def self.total_rep_change(col)
col = col.includes(:post)
settings = SiteSetting.where(name: ['QuestionUpVoteRep', 'QuestionDownVoteRep',
'AnswerUpVoteRep', 'AnswerDownVoteRep'])
'AnswerUpVoteRep', 'AnswerDownVoteRep',
'ArticleUpVoteRep', 'ArticleDownVoteRep'])
.map { |ss| [ss.name, ss.value] }.to_h
rep_changes = PostType.mapping.map do |k, v|
vote_types = { 1 => 'Up', -1 => 'Down' }
Expand Down Expand Up @@ -45,7 +46,9 @@ def rep_change(direction)
[post_type_ids['Question'], 1] => 'QuestionUpVoteRep',
[post_type_ids['Question'], -1] => 'QuestionDownVoteRep',
[post_type_ids['Answer'], 1] => 'AnswerUpVoteRep',
[post_type_ids['Answer'], -1] => 'AnswerDownVoteRep'
[post_type_ids['Answer'], -1] => 'AnswerDownVoteRep',
[post_type_ids['Article'], 1] => 'ArticleUpVoteRep',
[post_type_ids['Article'], -1] => 'ArticleDownVoteRep'
}
rep_change = SiteSetting[setting_names[[post.post_type_id, vote_type]]] || 0
recv_user.update!(reputation: recv_user.reputation + direction * rep_change)
Expand Down
47 changes: 47 additions & 0 deletions app/views/articles/_form.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<%= render 'posts/markdown_script' %>

<% if @article.errors.any? %>
<div class="notice is-danger is-filled">
The following errors prevented this post from being saved:
<ul>
<% @article.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>

<%= render 'posts/image_upload' %>

<%= form_for @article, url: edit_article_path(@article) do |f| %>
<div class="form-group">
<%= f.label :title, "Title your post:", class: "form-element" %>
<%= f.text_field :title, class: "form-element" %>
</div>

<%= render 'shared/body_field', f: f, field_name: :body_markdown, field_label: 'Body' %>

<div class="post-preview"></div>

<div class="form-group">
<%= f.label :tags_cache, "Tags", class: "form-element" %>
<div class="form-caption">
Tags help to categorize posts. Separate them by space. Use hyphens for multiple-word tags.
</div>
<%= f.select :tags_cache, options_for_select(@article.tags_cache.map { |t| [t, t] }, selected: @article.tags_cache),
{ include_blank: true }, multiple: true, class: "form-element js-tag-select",
data: { tag_set: @article.category.tag_set.id } %>
</div>

<div class="form-group">
<%= label_tag :edit_comment, 'Edit comment', class: "form-element" %>
<div class="form-caption">
Describe&mdash;if necessary&mdash;what you are changing and why you are making this edit.
</div>
<%= text_field_tag :edit_comment, params[:edit_comment], class: 'form-element' %>
</div>

<div class="form-group">
<%= f.submit 'Save', class: "button is-filled" %><br/>
</div>
<% end %>
1 change: 1 addition & 0 deletions app/views/articles/edit.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<%= render 'form', is_edit: true %>
Loading

0 comments on commit b0571f1

Please sign in to comment.