Commit 1c0b423d authored by azul's avatar azul

Merge remote-tracking branch 'origin/master' into staging

parents 023e8707 3644ca4b
Changes in Crabgrass 0.7.0
Changes in Crabgrass 0.6.4
--------------------------
Last stop before ruby 2.3 and then rails 5.2
This is the last release that will work with ruby 2.1 (the native ruby
on debian jessie).
We moved to a more continuous development model without releases in the
last years. For details about all the changes see the git history.
One particular focus of this release has been security and i18n improvements
developed by digitaria and cognata and sponsored by the prototype fund.
In particular users can now upload their OpenPGP public key to receive
encrypted notification messages. Content Security Policies have been
added and the usability in the tor browser has been improved.
Translations have been cleaned up and updated.
We also moved from our own permission system to pundit. The tracking
system was collecting stats that we were not exposing anywhere in the
UI. So it has been removed just like other unused code.
Changes in Crabgrass 0.6.3
......
......@@ -27,6 +27,9 @@ module Common::Posts
def destroy
authorize @post
if @post.user != current_user
Rails.logger.info "Page admin removed comment from '#{@post.user.login}' - maybe SPAM."
end
@post.destroy
respond_to do |format|
format.js { render template: 'common/posts/destroy' }
......
......@@ -21,13 +21,12 @@ class Page::PostsController < ApplicationController
def create
authorize @page, :show?
if @post = @page.add_post(current_user, post_params)
respond_to do |format|
format.js { @posts = @page.posts(pagination_params) }
format.html { redirect_to page_url(@page) + "#post-#{@post.id}" }
end
authorize @post
@post = @page.add_post(current_user, post_params)
respond_to do |format|
format.html { redirect_to page_url(@page) + "#post-#{@post.id}" }
format.js { @posts = @page.posts(pagination_params) }
end
authorize @post
end
protected
......
......@@ -35,6 +35,20 @@ module Common::Ui::PostHelper
end
end
#
# display the edit link for this post.
# sometimes, posts are not really posts. in this case, we skip the edit link.
#
def delete_post_action(post)
if post.is_a?(Post) && may_destroy?(post)
link_to :delete.t, post_path(post),
remote: true,
method: 'delete',
class: 'shy',
icon: 'trash'
end
end
def star_post_action(post)
return unless may_twinkle?(post)
if !post.starred_by?(current_user)
......
......@@ -57,6 +57,7 @@ class Post < ApplicationRecord
format_attribute :body
validates_presence_of :user, :body
validate :in_reply_to_matches_recipient
validate :no_spam
alias created_by user
......@@ -167,6 +168,12 @@ class Post < ApplicationRecord
"post_#{id}_body"
end
def with_link?
format_body
body_html.gsub(/<(\/*)a\s([^>]*?)>/) { |_m| return true }
return false
end
protected
def post_created
......@@ -190,4 +197,13 @@ class Post < ApplicationRecord
"Ugh. The user and the post you are replying to don't match."
end
end
def no_spam
page = discussion.try.page
return unless page.try.public? && with_link?
return if user.may?(:view, page)
Rails.logger.info 'Detected possible SPAM:'
Rails.logger.info body
errors.add :body, I18n.t(:spam_comment_detected)
end
end
......@@ -5,21 +5,33 @@ class PostPolicy < ApplicationPolicy
end
def update?
post and
post &&
post.user_id == user.id
end
alias destroy? update?
def destroy?
update? || (admin? && comment_by_visitor_on_public_page?)
end
def twinkle?
post.discussion.page and
page_policy.show? and
user.id and
page &&
page_policy.show? &&
user.id &&
user.id != post.user_id
end
protected
def admin?
page && page_policy.admin?
end
def comment_by_visitor_on_public_page?
page &&
page.public? &&
!post.user.may?(:view, page)
end
def page_policy
Pundit.policy!(user, page)
end
......
......@@ -7,6 +7,6 @@
%td.post_body.shy_parent{stars_for(post)}
.post_body{id: post.body_id, style: "z-index: 100;"}
.float_right
= edit_post_link(post)
= edit_post_link(post) || delete_post_action(post)
= star_post_action(post)
= post.body_html
......@@ -5,7 +5,7 @@
%td.post_author
= render 'ui/author', author: current_user
%td.post_body
= form_for @post, url: posts_path, remote: true, authenticity_token: true,
= form_for Post.new, url: posts_path, remote: true, authenticity_token: true,
html: {onsubmit: show_spinner('post')} do |f|
= f.text_area :body, rows: 8, class: 'form-control'
.buttons-right
......
......@@ -46,6 +46,9 @@ en:
select_files: "Select files"
send_button: Send
show_thing: "Show %{thing}"
spam_comment_detected: |
looks like spam we have been seeing lately.
It will probably work if you remove the links.
thing_destroyed: "%{thing} destroyed"
thing_required: "%{thing} Required"
updated: Updated
......
......@@ -39,3 +39,6 @@ purple_orange:
committee_page:
page_id: 1001
on_blues_page:
page_id: 1002
......@@ -25,3 +25,29 @@ red_on_committee_page:
type: "Post"
updated_at: "<%= 10.minutes.ago.to_s(:db) %>"
created_at: "<%= 10.minutes.ago.to_s(:db) %>"
html_link:
user_id: 4
discussion: on_blues_page
body: |
Post with a html link
<a href="http://crabgrass.example">link</a>
auto_link:
user_id: 4
discussion: on_blues_page
body: |
Post with an automatic link:
https://crabgrass.example
greencloth_link:
user_id: 4
discussion: on_blues_page
body: |
Post with a [greencloth link]
no_link:
user_id: 4
discussion: on_blues_page
body: |
Post without any link
......@@ -48,6 +48,20 @@ class CommentTest < IntegrationTest
assert_no_content 'test comment by blue that already existed'
end
def test_delete_visitor_comment
visitor = users(:penguin)
@page.public = true
visitor_comment = @page.add_post visitor,
body: 'test comment by penguin on public page'
login @blue
visit "/pages/#{@page.name_url}"
within_comment(visitor_comment) do
click_on 'Delete'
end
assert_content 'test comment by blue that already existed'
assert_no_content 'test comment by penguin on public page'
end
protected
def may_star?(comment, value)
......
require 'test_helper'
class PostTest < ActiveSupport::TestCase
fixtures :posts
def test_with_link
[:greencloth_link, :auto_link, :html_link].each do |fixture_name|
assert posts(fixture_name).with_link?,
"Post fixture '#{fixture_name}' has a link but with_link? says it doesn't."
end
fixture_name = :no_link
refute posts(fixture_name).with_link?,
"Post fixture '#{fixture_name}' has no link but with_link? says it does."
end
def test_prevent_creation_of_spam
page = pages(:public_wiki)
user = users(:penguin)
assert_raises ActiveRecord::RecordInvalid do
post = page.add_post(user, body: posts(:auto_link).body)
end
end
def test_visitor_comment_without_link
page = pages(:public_wiki)
user = users(:penguin)
post = page.add_post(user, body: posts(:no_link).body)
assert_empty post.errors
assert_predicate post, :persisted?
end
def test_allow_authorized_comment_with_link
page = pages(:public_wiki)
user = users(:gerrard)
post = page.add_post(user, body: posts(:auto_link).body)
assert_empty post.errors
assert_predicate post, :persisted?
end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment