From 64295f73f96b17f096c1ca6eaeae5fb9136c606d Mon Sep 17 00:00:00 2001 From: toyhammered Date: Thu, 29 Oct 2020 20:04:27 -0700 Subject: [PATCH 01/26] add lock unlock migration --- db/migrate/20201030020815_add_lock_unlock_to_post.rb | 12 ++++++++++++ db/schema.rb | 9 ++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20201030020815_add_lock_unlock_to_post.rb diff --git a/db/migrate/20201030020815_add_lock_unlock_to_post.rb b/db/migrate/20201030020815_add_lock_unlock_to_post.rb new file mode 100644 index 0000000000..6611a4df74 --- /dev/null +++ b/db/migrate/20201030020815_add_lock_unlock_to_post.rb @@ -0,0 +1,12 @@ +class AddLockUnlockToPost < ActiveRecord::Migration[5.1] + def change + add_column :posts, :locked_by, :integer + add_column :posts, :locked_at, :datetime + add_column :posts, :lock_reason, :integer + add_index :posts, :locked_by + + add_column :posts, :unlocked_by, :integer + add_column :posts, :unlocked_at, :datetime + add_index :posts, :unlocked_by + end +end diff --git a/db/schema.rb b/db/schema.rb index 409ed55d9f..6cdb7cfe5b 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20200822214657) do +ActiveRecord::Schema.define(version: 20201030020815) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -1216,12 +1216,19 @@ t.integer "community_recommendation_id" t.string "ao_id" t.integer "edited_by_id" + t.integer "locked_by" + t.datetime "locked_at" + t.integer "lock_reason" + t.integer "unlocked_by" + t.datetime "unlocked_at" t.index ["ao_id"], name: "index_posts_on_ao_id", unique: true t.index ["community_recommendation_id"], name: "index_posts_on_community_recommendation_id" t.index ["deleted_at"], name: "index_posts_on_deleted_at" + t.index ["locked_by"], name: "index_posts_on_locked_by" t.index ["media_type", "media_id"], name: "posts_media_type_media_id_idx" t.index ["target_group_id"], name: "posts_target_group_id_idx" t.index ["target_user_id"], name: "posts_target_user_id_idx" + t.index ["unlocked_by"], name: "index_posts_on_unlocked_by" t.index ["user_id"], name: "posts_user_id_idx" end From 2e27bce0ff5aa7213f0d74167227a62117761479 Mon Sep 17 00:00:00 2001 From: toyhammered Date: Thu, 29 Oct 2020 20:04:49 -0700 Subject: [PATCH 02/26] add lock_reason enum --- app/models/post.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/post.rb b/app/models/post.rb index 606b331dbf..6f03b62f2b 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -51,6 +51,7 @@ class Post < ApplicationRecord update_algolia 'AlgoliaPostsIndex' embed_links_in :content, to: :embed + enum lock_reason: { SPAM: 0, TOO_HEATED: 1 } belongs_to :user, required: true belongs_to :edited_by, class_name: 'User' belongs_to :target_user, class_name: 'User' From 4d0e7e772093638047cea83c764ff5e0010d0b6b Mon Sep 17 00:00:00 2001 From: toyhammered Date: Thu, 29 Oct 2020 20:05:10 -0700 Subject: [PATCH 03/26] update post resource --- app/resources/post_resource.rb | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/app/resources/post_resource.rb b/app/resources/post_resource.rb index 1863c6a7c2..0f6b356026 100644 --- a/app/resources/post_resource.rb +++ b/app/resources/post_resource.rb @@ -1,10 +1,13 @@ class PostResource < BaseResource caching + IMMUTABLE_FIELDS = %i[locked_by locked_at lock_reason unlocked_by unlocked_at].freeze attributes :content, :content_formatted, :comments_count, :post_likes_count, :spoiler, :nsfw, :blocked, :deleted_at, :top_level_comments_count, :edited_at, :target_interest, :embed, :embed_url + attributes(*IMMUTABLE_FIELDS) + has_one :user has_one :target_user has_one :target_group @@ -15,11 +18,19 @@ class PostResource < BaseResource has_many :comments has_many :uploads + def self.creatable_fields(context) + super - IMMUTABLE_FIELDS + end + + def self.updatable_fields(context) + super - IMMUTABLE_FIELDS + end + def target_interest=(val) _model.target_interest = val.underscore.classify end def target_interest - _model.target_interest.underscore.dasherize if _model.target_interest + _model&.target_interest&.underscore&.dasherize end end From 61494649d7569910a9fc80a6eae292cfc754501e Mon Sep 17 00:00:00 2001 From: toyhammered Date: Thu, 29 Oct 2020 20:20:31 -0700 Subject: [PATCH 04/26] update post permissions --- .ruby-version | 1 + spec/factories/posts.rb | 6 ++++++ spec/policies/post_policy_spec.rb | 7 +++++++ 3 files changed, 14 insertions(+) create mode 100644 .ruby-version diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000000..bf080da678 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.5.0 diff --git a/spec/factories/posts.rb b/spec/factories/posts.rb index a19189c93b..3fe9412513 100644 --- a/spec/factories/posts.rb +++ b/spec/factories/posts.rb @@ -46,5 +46,11 @@ factory :post do user content { Faker::Lorem.sentence } + + trait :locked do + locked_by { user.id } + locked_at { DateTime.now } + lock_reason { 0 } + end end end diff --git a/spec/policies/post_policy_spec.rb b/spec/policies/post_policy_spec.rb index 67d0697a6b..ada1ff619c 100644 --- a/spec/policies/post_policy_spec.rb +++ b/spec/policies/post_policy_spec.rb @@ -12,6 +12,13 @@ it('should allow community mod') { should permit(community_mod, post) } it('should not allow other users') { should_not permit(other, post) } it('should not allow anons') { should_not permit(nil, post) } + + context 'when post is locked' do + let(:post) { build(:post, :locked, user: owner.resource_owner) } + + it('should not allow regular user') { should_not permit(owner, post) } + it('should allow admin') { should permit(admin, post) } + end end permissions :create? do From f3fa15b008b9fce9d9fd15779a32bef51c5a5a49 Mon Sep 17 00:00:00 2001 From: toyhammered Date: Thu, 29 Oct 2020 20:32:12 -0700 Subject: [PATCH 05/26] update comment policy for locked unlocked --- app/policies/comment_policy.rb | 8 +++++++- spec/policies/comment_policy_spec.rb | 17 +++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/app/policies/comment_policy.rb b/app/policies/comment_policy.rb index 4c42ab91d3..bac069d076 100644 --- a/app/policies/comment_policy.rb +++ b/app/policies/comment_policy.rb @@ -19,7 +19,13 @@ def create? return false if banned_from_group? return false if group.closed? && !member? end - is_owner? + + # admins are allowed to create comments on locked posts + if record.post.locked_by.present? + is_owner? && is_admin? + else + is_owner? + end end def destroy? diff --git a/spec/policies/comment_policy_spec.rb b/spec/policies/comment_policy_spec.rb index 0ba23bf5ee..e1e0377327 100644 --- a/spec/policies/comment_policy_spec.rb +++ b/spec/policies/comment_policy_spec.rb @@ -12,6 +12,14 @@ it('should allow community mod') { should permit(community_mod, comment) } it('should not allow other users') { should_not permit(other, comment) } it('should not allow anons') { should_not permit(nil, comment) } + + context 'when post is locked' do + let(:post) { build(:post, :locked, user: owner.resource_owner) } + let(:comment) { build(:comment, user: admin.resource_owner, post: post) } + + it('should not allow a regular user') { should_not permit(other, comment) } + it('should allow an admin') { should permit(admin, comment) } + end end permissions :create? do @@ -19,6 +27,15 @@ it('should not allow community mod') { should_not permit(community_mod, comment) } it('should not allow random dude') { should_not permit(other, comment) } it('should not allow anon') { should_not permit(nil, comment) } + + context 'when post is locked' do + let(:post) { build(:post, :locked, user: owner.resource_owner) } + let(:admin_comment) { build(:comment, user: admin.resource_owner, post: post) } + let(:owner_comment) { build(:comment, user: owner.resource_owner, post: post) } + + it('should not allow regular owner') { should_not permit(owner, owner_comment) } + it('should only allow admin owner') { should permit(admin, admin_comment) } + end end permissions :destroy? do From 36b3c9781fd973769778675a8da39de2b9bad562 Mon Sep 17 00:00:00 2001 From: toyhammered Date: Fri, 30 Oct 2020 17:32:11 -0700 Subject: [PATCH 06/26] update migration to only include locked --- db/migrate/20201030020815_add_lock_unlock_to_post.rb | 4 ---- db/schema.rb | 3 --- 2 files changed, 7 deletions(-) diff --git a/db/migrate/20201030020815_add_lock_unlock_to_post.rb b/db/migrate/20201030020815_add_lock_unlock_to_post.rb index 6611a4df74..8d83ab5bf9 100644 --- a/db/migrate/20201030020815_add_lock_unlock_to_post.rb +++ b/db/migrate/20201030020815_add_lock_unlock_to_post.rb @@ -4,9 +4,5 @@ def change add_column :posts, :locked_at, :datetime add_column :posts, :lock_reason, :integer add_index :posts, :locked_by - - add_column :posts, :unlocked_by, :integer - add_column :posts, :unlocked_at, :datetime - add_index :posts, :unlocked_by end end diff --git a/db/schema.rb b/db/schema.rb index 6cdb7cfe5b..9c39507c2f 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1219,8 +1219,6 @@ t.integer "locked_by" t.datetime "locked_at" t.integer "lock_reason" - t.integer "unlocked_by" - t.datetime "unlocked_at" t.index ["ao_id"], name: "index_posts_on_ao_id", unique: true t.index ["community_recommendation_id"], name: "index_posts_on_community_recommendation_id" t.index ["deleted_at"], name: "index_posts_on_deleted_at" @@ -1228,7 +1226,6 @@ t.index ["media_type", "media_id"], name: "posts_media_type_media_id_idx" t.index ["target_group_id"], name: "posts_target_group_id_idx" t.index ["target_user_id"], name: "posts_target_user_id_idx" - t.index ["unlocked_by"], name: "index_posts_on_unlocked_by" t.index ["user_id"], name: "posts_user_id_idx" end From 7aef6ec185ffc2ce32d53246b3a3c0d900f6eda0 Mon Sep 17 00:00:00 2001 From: toyhammered Date: Fri, 30 Oct 2020 17:32:17 -0700 Subject: [PATCH 07/26] update post factory --- spec/factories/posts.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/factories/posts.rb b/spec/factories/posts.rb index 3fe9412513..17cee2b8a8 100644 --- a/spec/factories/posts.rb +++ b/spec/factories/posts.rb @@ -50,7 +50,7 @@ trait :locked do locked_by { user.id } locked_at { DateTime.now } - lock_reason { 0 } + lock_reason { :SPAM } end end end From 203338d93bfcbe5bc399f515b2136d2033634245 Mon Sep 17 00:00:00 2001 From: toyhammered Date: Fri, 30 Oct 2020 17:52:05 -0700 Subject: [PATCH 08/26] remove fields --- app/resources/post_resource.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/resources/post_resource.rb b/app/resources/post_resource.rb index 0f6b356026..91c6643aca 100644 --- a/app/resources/post_resource.rb +++ b/app/resources/post_resource.rb @@ -1,6 +1,6 @@ class PostResource < BaseResource caching - IMMUTABLE_FIELDS = %i[locked_by locked_at lock_reason unlocked_by unlocked_at].freeze + IMMUTABLE_FIELDS = %i[locked_by locked_at lock_reason].freeze attributes :content, :content_formatted, :comments_count, :post_likes_count, :spoiler, :nsfw, :blocked, :deleted_at, :top_level_comments_count, From b7611c7a795da45e8b4a060757a586ac8cae16f6 Mon Sep 17 00:00:00 2001 From: toyhammered Date: Sat, 31 Oct 2020 10:00:06 -0700 Subject: [PATCH 09/26] add locked? method --- app/models/post.rb | 4 ++++ app/policies/comment_policy.rb | 4 +++- app/policies/post_policy.rb | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/app/models/post.rb b/app/models/post.rb index 6f03b62f2b..be5c24a590 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -137,6 +137,10 @@ def mentioned_users User.where(id: processed_content[:mentioned_users]) end + def locked? + locked_by.present? + end + before_save do # Always check if the media is NSFW and try to force into NSFWness self.nsfw = media.try(:nsfw?) || false unless nsfw diff --git a/app/policies/comment_policy.rb b/app/policies/comment_policy.rb index bac069d076..b159e31bcd 100644 --- a/app/policies/comment_policy.rb +++ b/app/policies/comment_policy.rb @@ -6,6 +6,8 @@ def update? return false unless user return false if user.has_role?(:banned) return true if can_administrate? + # admins are allowed to update comments on locked posts + return false if record.post.locked? return true if group && has_group_permission?(:content) is_owner? end @@ -21,7 +23,7 @@ def create? end # admins are allowed to create comments on locked posts - if record.post.locked_by.present? + if record.post.locked? is_owner? && is_admin? else is_owner? diff --git a/app/policies/post_policy.rb b/app/policies/post_policy.rb index 5ff0bacffc..0ffeb13f75 100644 --- a/app/policies/post_policy.rb +++ b/app/policies/post_policy.rb @@ -6,6 +6,7 @@ def update? return false unless user return false if user.has_role?(:banned) return true if can_administrate? + return false if record.locked? return true if group && has_group_permission?(:content) is_owner? end From c4b3bad3d6b9cad3a19dca3afdce5b2a50d55191 Mon Sep 17 00:00:00 2001 From: toyhammered Date: Sat, 31 Oct 2020 13:41:19 -0700 Subject: [PATCH 10/26] update migration --- db/migrate/20201030020815_add_lock_unlock_to_post.rb | 4 ++-- db/schema.rb | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/db/migrate/20201030020815_add_lock_unlock_to_post.rb b/db/migrate/20201030020815_add_lock_unlock_to_post.rb index 8d83ab5bf9..900672fac6 100644 --- a/db/migrate/20201030020815_add_lock_unlock_to_post.rb +++ b/db/migrate/20201030020815_add_lock_unlock_to_post.rb @@ -1,8 +1,8 @@ class AddLockUnlockToPost < ActiveRecord::Migration[5.1] def change - add_column :posts, :locked_by, :integer + add_column :posts, :locked_by_id, :integer add_column :posts, :locked_at, :datetime add_column :posts, :lock_reason, :integer - add_index :posts, :locked_by + add_index :posts, :locked_by_id end end diff --git a/db/schema.rb b/db/schema.rb index 9c39507c2f..fe62565562 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1216,13 +1216,13 @@ t.integer "community_recommendation_id" t.string "ao_id" t.integer "edited_by_id" - t.integer "locked_by" + t.integer "locked_by_id" t.datetime "locked_at" t.integer "lock_reason" t.index ["ao_id"], name: "index_posts_on_ao_id", unique: true t.index ["community_recommendation_id"], name: "index_posts_on_community_recommendation_id" t.index ["deleted_at"], name: "index_posts_on_deleted_at" - t.index ["locked_by"], name: "index_posts_on_locked_by" + t.index ["locked_by_id"], name: "index_posts_on_locked_by_id" t.index ["media_type", "media_id"], name: "posts_media_type_media_id_idx" t.index ["target_group_id"], name: "posts_target_group_id_idx" t.index ["target_user_id"], name: "posts_target_user_id_idx" @@ -1735,9 +1735,12 @@ add_foreign_key "post_follows", "posts" add_foreign_key "posts", "community_recommendations" add_foreign_key "posts", "users", column: "target_user_id" + add_foreign_key "posts", "users", column: "target_user_id" add_foreign_key "profile_links", "profile_link_sites" add_foreign_key "reports", "users", column: "moderator_id" add_foreign_key "reposts", "posts" + add_foreign_key "reposts", "posts" + add_foreign_key "reposts", "users" add_foreign_key "reposts", "users" add_foreign_key "site_announcements", "users" add_foreign_key "streaming_links", "streamers" From 5f1b240b3247760bac107467e63147335455c5a0 Mon Sep 17 00:00:00 2001 From: toyhammered Date: Sat, 31 Oct 2020 13:41:31 -0700 Subject: [PATCH 11/26] update graphql post type --- app/graphql/types/post.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/app/graphql/types/post.rb b/app/graphql/types/post.rb index 5676e4ac49..eeb2cac233 100644 --- a/app/graphql/types/post.rb +++ b/app/graphql/types/post.rb @@ -32,6 +32,18 @@ class Types::Post < Types::BaseObject null: false, description: 'Html formatted content.' + field :locked_by, Types::Profile, + null: true, + description: 'The user who locked this post.' + + field :locked_at, GraphQL::Types::ISO8601DateTime, + null: true, + description: 'When this post was locked.' + + field :lock_reason, Types::Enum::LockReason, + null: true, + description: 'The reason why this post was locked.' + field :comments, Types::Comment.connection_type, null: false, description: 'All comments related to this post.' From dee308e9ed67a5563e651aad6db97221cac16987 Mon Sep 17 00:00:00 2001 From: toyhammered Date: Sat, 31 Oct 2020 13:41:48 -0700 Subject: [PATCH 12/26] update post model --- app/models/post.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/post.rb b/app/models/post.rb index be5c24a590..fed288dcab 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -59,6 +59,7 @@ class Post < ApplicationRecord belongs_to :media, polymorphic: true belongs_to :spoiled_unit, polymorphic: true belongs_to :community_recommendation + belongs_to :locked_by, class_name: 'User' has_many :post_likes, dependent: :destroy has_many :post_follows, dependent: :destroy has_many :comments, dependent: :destroy From 28e964101cbbb930d831b844f4aa6ff28629d275 Mon Sep 17 00:00:00 2001 From: toyhammered Date: Sat, 31 Oct 2020 13:41:59 -0700 Subject: [PATCH 13/26] update base input to include current_user --- app/graphql/types/input/base.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/graphql/types/input/base.rb b/app/graphql/types/input/base.rb index 352a661b75..b85f5aa022 100644 --- a/app/graphql/types/input/base.rb +++ b/app/graphql/types/input/base.rb @@ -19,4 +19,8 @@ def self.default_graphql_name def to_model to_h end + + def current_user + User.current + end end From 72555aec52d6b6dd59dc067063467e8b56f9de37 Mon Sep 17 00:00:00 2001 From: toyhammered Date: Sat, 31 Oct 2020 13:42:09 -0700 Subject: [PATCH 14/26] add spec for post model --- spec/models/post_spec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/models/post_spec.rb b/spec/models/post_spec.rb index f875e9ddcd..fe6f320ea6 100644 --- a/spec/models/post_spec.rb +++ b/spec/models/post_spec.rb @@ -51,6 +51,7 @@ it { should belong_to(:target_user).class_name('User') } it { should belong_to(:media) } it { should belong_to(:spoiled_unit) } + it { should belong_to(:locked_by).class_name('User') } it { should have_many(:post_likes).dependent(:destroy) } it { should have_many(:comments).dependent(:destroy) } it { should validate_length_of(:content).is_at_most(9_000) } From 737f14aa181f0538b2881453a8a5ae839bfa12fe Mon Sep 17 00:00:00 2001 From: toyhammered Date: Sat, 31 Oct 2020 13:54:48 -0700 Subject: [PATCH 15/26] add post lock and unlock --- app/graphql/mutations/post/lock_post.rb | 31 ++++++++++++++++++++ app/graphql/mutations/post/unlock_post.rb | 31 ++++++++++++++++++++ app/graphql/types/enum/lock_reason.rb | 4 +++ app/graphql/types/input/post/lock.rb | 8 +++++ app/graphql/types/input/post/unlock.rb | 7 +++++ app/graphql/types/mutation_type.rb | 1 + app/graphql/types/mutations/post_mutation.rb | 9 ++++++ 7 files changed, 91 insertions(+) create mode 100644 app/graphql/mutations/post/lock_post.rb create mode 100644 app/graphql/mutations/post/unlock_post.rb create mode 100644 app/graphql/types/enum/lock_reason.rb create mode 100644 app/graphql/types/input/post/lock.rb create mode 100644 app/graphql/types/input/post/unlock.rb create mode 100644 app/graphql/types/mutations/post_mutation.rb diff --git a/app/graphql/mutations/post/lock_post.rb b/app/graphql/mutations/post/lock_post.rb new file mode 100644 index 0000000000..fa30733f35 --- /dev/null +++ b/app/graphql/mutations/post/lock_post.rb @@ -0,0 +1,31 @@ +class Mutations::Post::LockPost < Mutations::Base + argument :input, + Types::Input::Post::Lock, + required: true, + description: 'Lock a Post.', + as: :post + + field :post, Types::Post, null: true + + def load_post(value) + post = ::Post.find(value.id) + post.assign_attributes(value.to_model) + post + end + + def authorized?(post:) + super(post, :update?) + end + + def resolve(post:) + post.save + + if post.errors.any? + Errors::RailsModel.graphql_error(post) + else + { + post: post + } + end + end +end diff --git a/app/graphql/mutations/post/unlock_post.rb b/app/graphql/mutations/post/unlock_post.rb new file mode 100644 index 0000000000..a37168dcf6 --- /dev/null +++ b/app/graphql/mutations/post/unlock_post.rb @@ -0,0 +1,31 @@ +class Mutations::Post::UnlockPost < Mutations::Base + argument :input, + Types::Input::Post::Unlock, + required: true, + description: 'Unlock a Post.', + as: :post + + field :post, Types::Post, null: true + + def load_post(value) + post = ::Post.find(value.id) + post.assign_attributes(value.to_model) + post + end + + def authorized?(post:) + super(post, :update?) + end + + def resolve(post:) + post.save + + if post.errors.any? + Errors::RailsModel.graphql_error(post) + else + { + post: post + } + end + end +end diff --git a/app/graphql/types/enum/lock_reason.rb b/app/graphql/types/enum/lock_reason.rb new file mode 100644 index 0000000000..90797d4546 --- /dev/null +++ b/app/graphql/types/enum/lock_reason.rb @@ -0,0 +1,4 @@ +class Types::Enum::LockReason < Types::Enum::Base + value 'SPAM' + value 'TOO_HEATED' +end diff --git a/app/graphql/types/input/post/lock.rb b/app/graphql/types/input/post/lock.rb new file mode 100644 index 0000000000..84ad609b6e --- /dev/null +++ b/app/graphql/types/input/post/lock.rb @@ -0,0 +1,8 @@ +class Types::Input::Post::Lock < Types::Input::Base + argument :id, ID, required: true + argument :lock_reason, Types::Enum::LockReason, required: true + + def to_model + to_h.merge(locked_at: DateTime.current, locked_by: current_user) + end +end diff --git a/app/graphql/types/input/post/unlock.rb b/app/graphql/types/input/post/unlock.rb new file mode 100644 index 0000000000..6ef14757f9 --- /dev/null +++ b/app/graphql/types/input/post/unlock.rb @@ -0,0 +1,7 @@ +class Types::Input::Post::Unlock < Types::Input::Base + argument :id, ID, required: true + + def to_model + to_h.merge(locked_at: nil, locked_by: nil, lock_reason: nil) + end +end diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb index 9f181eb267..845bcf3a22 100644 --- a/app/graphql/types/mutation_type.rb +++ b/app/graphql/types/mutation_type.rb @@ -4,4 +4,5 @@ class Types::MutationType < Types::BaseObject field :episode, Types::Mutations::EpisodeMutation, null: true field :library_entry, Types::Mutations::LibraryEntryMutation, null: true field :mapping, Types::Mutations::MappingMutation, null: true + field :post, Types::Mutations::PostMutation, null: true end diff --git a/app/graphql/types/mutations/post_mutation.rb b/app/graphql/types/mutations/post_mutation.rb new file mode 100644 index 0000000000..a3af01603f --- /dev/null +++ b/app/graphql/types/mutations/post_mutation.rb @@ -0,0 +1,9 @@ +class Types::Mutations::PostMutation < Types::BaseObject + field :lock, + mutation: ::Mutations::Post::LockPost, + description: 'Lock a Post.' + + field :unlock, + mutation: ::Mutations::Post::UnlockPost, + description: 'Unlock a Post.' +end From 127d606a2f51f4c2ca3f33e189cf356c8eb3ce69 Mon Sep 17 00:00:00 2001 From: toyhammered Date: Sat, 31 Oct 2020 19:08:40 -0700 Subject: [PATCH 16/26] rename all to locked_reason --- app/graphql/types/input/post/lock.rb | 2 +- app/graphql/types/input/post/unlock.rb | 2 +- app/graphql/types/post.rb | 2 +- app/models/post.rb | 2 +- app/resources/post_resource.rb | 2 +- db/migrate/20201030020815_add_lock_unlock_to_post.rb | 2 +- db/schema.rb | 2 +- spec/factories/posts.rb | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/graphql/types/input/post/lock.rb b/app/graphql/types/input/post/lock.rb index 84ad609b6e..4efb109224 100644 --- a/app/graphql/types/input/post/lock.rb +++ b/app/graphql/types/input/post/lock.rb @@ -1,6 +1,6 @@ class Types::Input::Post::Lock < Types::Input::Base argument :id, ID, required: true - argument :lock_reason, Types::Enum::LockReason, required: true + argument :locked_reason, Types::Enum::LockReason, required: true def to_model to_h.merge(locked_at: DateTime.current, locked_by: current_user) diff --git a/app/graphql/types/input/post/unlock.rb b/app/graphql/types/input/post/unlock.rb index 6ef14757f9..270117588a 100644 --- a/app/graphql/types/input/post/unlock.rb +++ b/app/graphql/types/input/post/unlock.rb @@ -2,6 +2,6 @@ class Types::Input::Post::Unlock < Types::Input::Base argument :id, ID, required: true def to_model - to_h.merge(locked_at: nil, locked_by: nil, lock_reason: nil) + to_h.merge(locked_at: nil, locked_by: nil, locked_reason: nil) end end diff --git a/app/graphql/types/post.rb b/app/graphql/types/post.rb index eeb2cac233..6ef6a26ccc 100644 --- a/app/graphql/types/post.rb +++ b/app/graphql/types/post.rb @@ -40,7 +40,7 @@ class Types::Post < Types::BaseObject null: true, description: 'When this post was locked.' - field :lock_reason, Types::Enum::LockReason, + field :locked_reason, Types::Enum::LockReason, null: true, description: 'The reason why this post was locked.' diff --git a/app/models/post.rb b/app/models/post.rb index fed288dcab..72d1e746d8 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -51,7 +51,7 @@ class Post < ApplicationRecord update_algolia 'AlgoliaPostsIndex' embed_links_in :content, to: :embed - enum lock_reason: { SPAM: 0, TOO_HEATED: 1 } + enum locked_reason: { SPAM: 0, TOO_HEATED: 1 } belongs_to :user, required: true belongs_to :edited_by, class_name: 'User' belongs_to :target_user, class_name: 'User' diff --git a/app/resources/post_resource.rb b/app/resources/post_resource.rb index 91c6643aca..efd9f8b1f8 100644 --- a/app/resources/post_resource.rb +++ b/app/resources/post_resource.rb @@ -1,6 +1,6 @@ class PostResource < BaseResource caching - IMMUTABLE_FIELDS = %i[locked_by locked_at lock_reason].freeze + IMMUTABLE_FIELDS = %i[locked_by locked_at locked_reason].freeze attributes :content, :content_formatted, :comments_count, :post_likes_count, :spoiler, :nsfw, :blocked, :deleted_at, :top_level_comments_count, diff --git a/db/migrate/20201030020815_add_lock_unlock_to_post.rb b/db/migrate/20201030020815_add_lock_unlock_to_post.rb index 900672fac6..e5e9b1d7a0 100644 --- a/db/migrate/20201030020815_add_lock_unlock_to_post.rb +++ b/db/migrate/20201030020815_add_lock_unlock_to_post.rb @@ -2,7 +2,7 @@ class AddLockUnlockToPost < ActiveRecord::Migration[5.1] def change add_column :posts, :locked_by_id, :integer add_column :posts, :locked_at, :datetime - add_column :posts, :lock_reason, :integer + add_column :posts, :locked_reason, :integer add_index :posts, :locked_by_id end end diff --git a/db/schema.rb b/db/schema.rb index fe62565562..ab6dac2538 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1218,7 +1218,7 @@ t.integer "edited_by_id" t.integer "locked_by_id" t.datetime "locked_at" - t.integer "lock_reason" + t.integer "locked_reason" t.index ["ao_id"], name: "index_posts_on_ao_id", unique: true t.index ["community_recommendation_id"], name: "index_posts_on_community_recommendation_id" t.index ["deleted_at"], name: "index_posts_on_deleted_at" diff --git a/spec/factories/posts.rb b/spec/factories/posts.rb index 17cee2b8a8..f28b8c7ca9 100644 --- a/spec/factories/posts.rb +++ b/spec/factories/posts.rb @@ -50,7 +50,7 @@ trait :locked do locked_by { user.id } locked_at { DateTime.now } - lock_reason { :SPAM } + locked_reason { :SPAM } end end end From 19c788d8664effdcabbe012e7cc1cac543dec603 Mon Sep 17 00:00:00 2001 From: toyhammered Date: Sat, 31 Oct 2020 19:39:08 -0700 Subject: [PATCH 17/26] add update_lock permission --- app/graphql/mutations/post/lock_post.rb | 2 +- app/graphql/mutations/post/unlock_post.rb | 2 +- app/policies/post_policy.rb | 7 +++++++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/app/graphql/mutations/post/lock_post.rb b/app/graphql/mutations/post/lock_post.rb index fa30733f35..2bb807be25 100644 --- a/app/graphql/mutations/post/lock_post.rb +++ b/app/graphql/mutations/post/lock_post.rb @@ -14,7 +14,7 @@ def load_post(value) end def authorized?(post:) - super(post, :update?) + super(post, :update_lock?) end def resolve(post:) diff --git a/app/graphql/mutations/post/unlock_post.rb b/app/graphql/mutations/post/unlock_post.rb index a37168dcf6..26a14b859d 100644 --- a/app/graphql/mutations/post/unlock_post.rb +++ b/app/graphql/mutations/post/unlock_post.rb @@ -14,7 +14,7 @@ def load_post(value) end def authorized?(post:) - super(post, :update?) + super(post, :update_lock?) end def resolve(post:) diff --git a/app/policies/post_policy.rb b/app/policies/post_policy.rb index 0ffeb13f75..30c7fccb6e 100644 --- a/app/policies/post_policy.rb +++ b/app/policies/post_policy.rb @@ -37,6 +37,13 @@ def group record.target_group end + def update_lock? + return true if is_admin? + return true if group && has_group_permission(:content) + + false + end + class Scope < Scope def resolve return scope if can_administrate? From 8825662c32334e7d94138e14d38662841142b362 Mon Sep 17 00:00:00 2001 From: toyhammered Date: Sat, 31 Oct 2020 20:04:01 -0700 Subject: [PATCH 18/26] update post policy spec --- spec/factories/posts.rb | 2 +- spec/policies/post_policy_spec.rb | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/spec/factories/posts.rb b/spec/factories/posts.rb index f28b8c7ca9..976a12494f 100644 --- a/spec/factories/posts.rb +++ b/spec/factories/posts.rb @@ -48,7 +48,7 @@ content { Faker::Lorem.sentence } trait :locked do - locked_by { user.id } + association :locked_by, factory: :user, strategy: :build locked_at { DateTime.now } locked_reason { :SPAM } end diff --git a/spec/policies/post_policy_spec.rb b/spec/policies/post_policy_spec.rb index ada1ff619c..3f28bf7c69 100644 --- a/spec/policies/post_policy_spec.rb +++ b/spec/policies/post_policy_spec.rb @@ -21,6 +21,13 @@ end end + permissions :update_lock? do + let(:post) { build(:post, :locked, user: owner.resource_owner) } + + it('should allow admin') { should permit(admin, post) } + it('should not allow owner') { should_not permit(owner, post) } + end + permissions :create? do it('should allow owner') { should permit(owner, post) } it('should not allow community mod') { should_not permit(community_mod, post) } From 6d75e955fa6716e608d36772bbb744a959a06b2e Mon Sep 17 00:00:00 2001 From: toyhammered Date: Sat, 31 Oct 2020 20:07:19 -0700 Subject: [PATCH 19/26] idk what happened... --- db/schema.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/db/schema.rb b/db/schema.rb index ab6dac2538..dda4fd89d9 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1735,12 +1735,9 @@ add_foreign_key "post_follows", "posts" add_foreign_key "posts", "community_recommendations" add_foreign_key "posts", "users", column: "target_user_id" - add_foreign_key "posts", "users", column: "target_user_id" add_foreign_key "profile_links", "profile_link_sites" add_foreign_key "reports", "users", column: "moderator_id" add_foreign_key "reposts", "posts" - add_foreign_key "reposts", "posts" - add_foreign_key "reposts", "users" add_foreign_key "reposts", "users" add_foreign_key "site_announcements", "users" add_foreign_key "streaming_links", "streamers" From 84ee233a0c2b920d86f1b8f74daeba79e5ff2600 Mon Sep 17 00:00:00 2001 From: toyhammered Date: Sat, 31 Oct 2020 20:55:06 -0700 Subject: [PATCH 20/26] update to use new roles --- app/policies/comment_policy.rb | 2 +- app/policies/post_policy.rb | 2 +- spec/policies/comment_policy_spec.rb | 8 ++++---- spec/policies/post_policy_spec.rb | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/policies/comment_policy.rb b/app/policies/comment_policy.rb index b159e31bcd..42df0b64e4 100644 --- a/app/policies/comment_policy.rb +++ b/app/policies/comment_policy.rb @@ -24,7 +24,7 @@ def create? # admins are allowed to create comments on locked posts if record.post.locked? - is_owner? && is_admin? + is_owner? && can_administrate? else is_owner? end diff --git a/app/policies/post_policy.rb b/app/policies/post_policy.rb index 30c7fccb6e..aa6d2c7e17 100644 --- a/app/policies/post_policy.rb +++ b/app/policies/post_policy.rb @@ -38,7 +38,7 @@ def group end def update_lock? - return true if is_admin? + return true if can_administrate? return true if group && has_group_permission(:content) false diff --git a/spec/policies/comment_policy_spec.rb b/spec/policies/comment_policy_spec.rb index e1e0377327..29fbcd9b2f 100644 --- a/spec/policies/comment_policy_spec.rb +++ b/spec/policies/comment_policy_spec.rb @@ -15,10 +15,10 @@ context 'when post is locked' do let(:post) { build(:post, :locked, user: owner.resource_owner) } - let(:comment) { build(:comment, user: admin.resource_owner, post: post) } + let(:comment) { build(:comment, user: community_mod.resource_owner, post: post) } it('should not allow a regular user') { should_not permit(other, comment) } - it('should allow an admin') { should permit(admin, comment) } + it('should allow a community_mod') { should permit(community_mod, comment) } end end @@ -30,11 +30,11 @@ context 'when post is locked' do let(:post) { build(:post, :locked, user: owner.resource_owner) } - let(:admin_comment) { build(:comment, user: admin.resource_owner, post: post) } + let(:community_mod_comment) { build(:comment, user: community_mod.resource_owner, post: post) } let(:owner_comment) { build(:comment, user: owner.resource_owner, post: post) } it('should not allow regular owner') { should_not permit(owner, owner_comment) } - it('should only allow admin owner') { should permit(admin, admin_comment) } + it('should only allow community_mod') { should permit(community_mod, community_mod_comment) } end end diff --git a/spec/policies/post_policy_spec.rb b/spec/policies/post_policy_spec.rb index 3f28bf7c69..60e5af4648 100644 --- a/spec/policies/post_policy_spec.rb +++ b/spec/policies/post_policy_spec.rb @@ -17,14 +17,14 @@ let(:post) { build(:post, :locked, user: owner.resource_owner) } it('should not allow regular user') { should_not permit(owner, post) } - it('should allow admin') { should permit(admin, post) } + it('should allow community_mod') { should permit(community_mod, post) } end end permissions :update_lock? do let(:post) { build(:post, :locked, user: owner.resource_owner) } - it('should allow admin') { should permit(admin, post) } + it('should allow community_mod') { should permit(community_mod, post) } it('should not allow owner') { should_not permit(owner, post) } end From 7fde5b4cb2a4b3fba95951aeee03239212f8626b Mon Sep 17 00:00:00 2001 From: Daniel Rassiner Date: Sat, 31 Oct 2020 20:55:52 -0700 Subject: [PATCH 21/26] Delete .ruby-version :| --- .ruby-version | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .ruby-version diff --git a/.ruby-version b/.ruby-version deleted file mode 100644 index bf080da678..0000000000 --- a/.ruby-version +++ /dev/null @@ -1 +0,0 @@ -ruby-2.5.0 From d46a8502e77123dfab7a9cdebf6d7598d64c857e Mon Sep 17 00:00:00 2001 From: Daniel Rassiner Date: Sun, 1 Nov 2020 16:17:04 -0800 Subject: [PATCH 22/26] Update app/policies/post_policy.rb fix typo Co-authored-by: Peter Lejeck --- app/policies/post_policy.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/policies/post_policy.rb b/app/policies/post_policy.rb index aa6d2c7e17..eed38d9df5 100644 --- a/app/policies/post_policy.rb +++ b/app/policies/post_policy.rb @@ -39,7 +39,7 @@ def group def update_lock? return true if can_administrate? - return true if group && has_group_permission(:content) + return true if group && has_group_permission?(:content) false end From 4c9d42c417ea3b3b7a0133f56732fa5969f80fb0 Mon Sep 17 00:00:00 2001 From: toyhammered Date: Sun, 1 Nov 2020 16:26:34 -0800 Subject: [PATCH 23/26] update to locked_reason enum --- app/graphql/types/enum/lock_reason.rb | 4 ---- app/graphql/types/enum/locked_reason.rb | 4 ++++ app/graphql/types/input/post/lock.rb | 2 +- app/graphql/types/post.rb | 2 +- app/models/post.rb | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) delete mode 100644 app/graphql/types/enum/lock_reason.rb create mode 100644 app/graphql/types/enum/locked_reason.rb diff --git a/app/graphql/types/enum/lock_reason.rb b/app/graphql/types/enum/lock_reason.rb deleted file mode 100644 index 90797d4546..0000000000 --- a/app/graphql/types/enum/lock_reason.rb +++ /dev/null @@ -1,4 +0,0 @@ -class Types::Enum::LockReason < Types::Enum::Base - value 'SPAM' - value 'TOO_HEATED' -end diff --git a/app/graphql/types/enum/locked_reason.rb b/app/graphql/types/enum/locked_reason.rb new file mode 100644 index 0000000000..6b65e661ed --- /dev/null +++ b/app/graphql/types/enum/locked_reason.rb @@ -0,0 +1,4 @@ +class Types::Enum::LockedReason < Types::Enum::Base + value 'SPAM', value: 'spam' + value 'TOO_HEATED', value: 'too_heated' +end diff --git a/app/graphql/types/input/post/lock.rb b/app/graphql/types/input/post/lock.rb index 4efb109224..9f791da8c2 100644 --- a/app/graphql/types/input/post/lock.rb +++ b/app/graphql/types/input/post/lock.rb @@ -1,6 +1,6 @@ class Types::Input::Post::Lock < Types::Input::Base argument :id, ID, required: true - argument :locked_reason, Types::Enum::LockReason, required: true + argument :locked_reason, Types::Enum::LockedReason, required: true def to_model to_h.merge(locked_at: DateTime.current, locked_by: current_user) diff --git a/app/graphql/types/post.rb b/app/graphql/types/post.rb index 6ef6a26ccc..445f5ff5e2 100644 --- a/app/graphql/types/post.rb +++ b/app/graphql/types/post.rb @@ -40,7 +40,7 @@ class Types::Post < Types::BaseObject null: true, description: 'When this post was locked.' - field :locked_reason, Types::Enum::LockReason, + field :locked_reason, Types::Enum::LockedReason, null: true, description: 'The reason why this post was locked.' diff --git a/app/models/post.rb b/app/models/post.rb index 72d1e746d8..a0a032dd39 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -51,7 +51,7 @@ class Post < ApplicationRecord update_algolia 'AlgoliaPostsIndex' embed_links_in :content, to: :embed - enum locked_reason: { SPAM: 0, TOO_HEATED: 1 } + enum locked_reason: { spam: 0, too_heated: 1 } belongs_to :user, required: true belongs_to :edited_by, class_name: 'User' belongs_to :target_user, class_name: 'User' From c6d106403bfdc7c757e28b637e4764f3b3fa086c Mon Sep 17 00:00:00 2001 From: toyhammered Date: Sun, 1 Nov 2020 19:14:51 -0800 Subject: [PATCH 24/26] fix post factory --- spec/factories/posts.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/factories/posts.rb b/spec/factories/posts.rb index 976a12494f..e3c99024e5 100644 --- a/spec/factories/posts.rb +++ b/spec/factories/posts.rb @@ -50,7 +50,7 @@ trait :locked do association :locked_by, factory: :user, strategy: :build locked_at { DateTime.now } - locked_reason { :SPAM } + locked_reason { :spam } end end end From 915fdeec45ea1d3fef27d1aff6a8f163f48bfab4 Mon Sep 17 00:00:00 2001 From: toyhammered Date: Thu, 5 Nov 2020 18:56:34 -0800 Subject: [PATCH 25/26] add addition lock reason --- app/graphql/types/enum/locked_reason.rb | 1 + app/models/post.rb | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/graphql/types/enum/locked_reason.rb b/app/graphql/types/enum/locked_reason.rb index 6b65e661ed..d9a3cc838f 100644 --- a/app/graphql/types/enum/locked_reason.rb +++ b/app/graphql/types/enum/locked_reason.rb @@ -1,4 +1,5 @@ class Types::Enum::LockedReason < Types::Enum::Base value 'SPAM', value: 'spam' value 'TOO_HEATED', value: 'too_heated' + value 'CLOSED', value: 'closed' end diff --git a/app/models/post.rb b/app/models/post.rb index a0a032dd39..6d51db76dc 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -51,7 +51,7 @@ class Post < ApplicationRecord update_algolia 'AlgoliaPostsIndex' embed_links_in :content, to: :embed - enum locked_reason: { spam: 0, too_heated: 1 } + enum locked_reason: { spam: 0, too_heated: 1, closed: 2 } belongs_to :user, required: true belongs_to :edited_by, class_name: 'User' belongs_to :target_user, class_name: 'User' From 5e9c031f48a24e920c8e7066efff835238f948a7 Mon Sep 17 00:00:00 2001 From: toyhammered Date: Thu, 5 Nov 2020 18:58:37 -0800 Subject: [PATCH 26/26] allow owners to lock own post --- app/graphql/mutations/post/lock_post.rb | 2 +- app/graphql/mutations/post/unlock_post.rb | 2 +- app/policies/post_policy.rb | 9 ++++++++- spec/policies/post_policy_spec.rb | 9 ++++++++- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/app/graphql/mutations/post/lock_post.rb b/app/graphql/mutations/post/lock_post.rb index 2bb807be25..5f91281211 100644 --- a/app/graphql/mutations/post/lock_post.rb +++ b/app/graphql/mutations/post/lock_post.rb @@ -14,7 +14,7 @@ def load_post(value) end def authorized?(post:) - super(post, :update_lock?) + super(post, :lock?) end def resolve(post:) diff --git a/app/graphql/mutations/post/unlock_post.rb b/app/graphql/mutations/post/unlock_post.rb index 26a14b859d..e175e4c8e1 100644 --- a/app/graphql/mutations/post/unlock_post.rb +++ b/app/graphql/mutations/post/unlock_post.rb @@ -14,7 +14,7 @@ def load_post(value) end def authorized?(post:) - super(post, :update_lock?) + super(post, :unlock?) end def resolve(post:) diff --git a/app/policies/post_policy.rb b/app/policies/post_policy.rb index eed38d9df5..acbf2d9715 100644 --- a/app/policies/post_policy.rb +++ b/app/policies/post_policy.rb @@ -37,7 +37,14 @@ def group record.target_group end - def update_lock? + def lock? + return true if can_administrate? || is_owner? + return true if group && has_group_permission?(:content) + + false + end + + def unlock? return true if can_administrate? return true if group && has_group_permission?(:content) diff --git a/spec/policies/post_policy_spec.rb b/spec/policies/post_policy_spec.rb index 60e5af4648..cb8386e8e8 100644 --- a/spec/policies/post_policy_spec.rb +++ b/spec/policies/post_policy_spec.rb @@ -21,7 +21,14 @@ end end - permissions :update_lock? do + permissions :lock? do + let(:post) { build(:post, :locked, user: owner.resource_owner) } + + it('should allow community_mod') { should permit(community_mod, post) } + it('should allow owner') { should permit(owner, post) } + end + + permissions :unlock? do let(:post) { build(:post, :locked, user: owner.resource_owner) } it('should allow community_mod') { should permit(community_mod, post) }