diff --git a/app/assets/javascripts/discourse/widgets/topic-admin-menu.js.es6 b/app/assets/javascripts/discourse/widgets/topic-admin-menu.js.es6 index 38e420369f9..2d6e06502ba 100644 --- a/app/assets/javascripts/discourse/widgets/topic-admin-menu.js.es6 +++ b/app/assets/javascripts/discourse/widgets/topic-admin-menu.js.es6 @@ -201,7 +201,7 @@ export default createWidget("topic-admin-menu", { }); } - if (this.currentUser.admin) { + if (this.currentUser.get("staff")) { buttons.push({ className: "topic-admin-change-timestamp", buttonClass: "btn-default", diff --git a/app/controllers/topics_controller.rb b/app/controllers/topics_controller.rb index e311798f250..11ddf19a901 100644 --- a/app/controllers/topics_controller.rb +++ b/app/controllers/topics_controller.rb @@ -676,17 +676,22 @@ class TopicsController < ApplicationController end def change_timestamps - params.require(:topic_id) - params.require(:timestamp) + topic_id = params.require(:topic_id).to_i + timestamp = params.require(:timestamp).to_f guardian.ensure_can_change_post_timestamps! + topic = Topic.with_deleted.find(topic_id) + previous_timestamp = topic.first_post.created_at + begin TopicTimestampChanger.new( - topic_id: params[:topic_id].to_i, - timestamp: params[:timestamp].to_f + topic: topic, + timestamp: timestamp ).change! + StaffActionLogger.new(current_user).log_topic_timestamps_changed(topic, Time.zone.at(timestamp), previous_timestamp) + render json: success_json rescue ActiveRecord::RecordInvalid, TopicTimestampChanger::InvalidTimestampError render json: failed_json, status: 422 diff --git a/app/models/user_history.rb b/app/models/user_history.rb index 4eb345b6c08..c8ec8754396 100644 --- a/app/models/user_history.rb +++ b/app/models/user_history.rb @@ -83,7 +83,8 @@ class UserHistory < ActiveRecord::Base post_rejected: 64, merge_user: 65, entity_export: 66, - change_password: 67 + change_password: 67, + topic_timestamps_changed: 68 ) end @@ -145,7 +146,8 @@ class UserHistory < ActiveRecord::Base :post_rejected, :merge_user, :entity_export, - :change_name + :change_name, + :topic_timestamps_changed ] end diff --git a/app/services/staff_action_logger.rb b/app/services/staff_action_logger.rb index 6ebb5af059d..a270dee3536 100644 --- a/app/services/staff_action_logger.rb +++ b/app/services/staff_action_logger.rb @@ -117,6 +117,16 @@ class StaffActionLogger ) end + def log_topic_timestamps_changed(topic, new_timestamp, previous_timestamp, opts = {}) + raise Discourse::InvalidParameters.new(:topic) unless topic && topic.is_a?(Topic) + UserHistory.create!(params(opts).merge( + action: UserHistory.actions[:topic_timestamps_changed], + topic_id: topic.id, + new_value: new_timestamp, + previous_value: previous_timestamp) + ) + end + def log_post_lock(post, opts = {}) raise Discourse::InvalidParameters.new(:post) unless post && post.is_a?(Post) UserHistory.create!(params(opts).merge( diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 5c23e09ff5a..9609ee9cb73 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -3669,6 +3669,7 @@ en: merge_user: "merge user" entity_export: "export entity" change_name: "change name" + topic_timestamps_changed: "topic timestamps changed" screened_emails: title: "Screened Emails" description: "When someone tries to create a new account, the following email addresses will be checked and the registration will be blocked, or some other action performed." diff --git a/lib/guardian/post_guardian.rb b/lib/guardian/post_guardian.rb index c49d3cd22f3..f0e63f6c789 100644 --- a/lib/guardian/post_guardian.rb +++ b/lib/guardian/post_guardian.rb @@ -226,7 +226,7 @@ module PostGuardian end def can_change_post_timestamps? - is_admin? + is_staff? end def can_wiki?(post) diff --git a/spec/requests/topics_controller_spec.rb b/spec/requests/topics_controller_spec.rb index 738d17e5724..022f68f5376 100644 --- a/spec/requests/topics_controller_spec.rb +++ b/spec/requests/topics_controller_spec.rb @@ -572,19 +572,17 @@ RSpec.describe TopicsController do expect(response.status).to eq(403) end - [:moderator, :trust_level_4].each do |user| - describe "forbidden to #{user}" do - let!(user) { sign_in(Fabricate(user)) } + describe "forbidden to trust_level_4" do + let!(:trust_level_4) { sign_in(Fabricate(:trust_level_4)) } - it 'correctly denies' do - put "/t/1/change-timestamp.json", params: params - expect(response).to be_forbidden - end + it 'correctly denies' do + put "/t/1/change-timestamp.json", params: params + expect(response).to be_forbidden end end describe 'changing timestamps' do - let!(:admin) { sign_in(Fabricate(:admin)) } + let!(:moderator) { sign_in(Fabricate(:moderator)) } let(:old_timestamp) { Time.zone.now } let(:new_timestamp) { old_timestamp - 1.day } let!(:topic) { Fabricate(:topic, created_at: old_timestamp) } @@ -605,6 +603,18 @@ RSpec.describe TopicsController do expect(p1.reload.created_at).to be_within_one_second_of(new_timestamp) expect(p2.reload.created_at).to be_within_one_second_of(old_timestamp) end + + it 'should create a staff log entry' do + put "/t/#{topic.id}/change-timestamp.json", params: { + timestamp: new_timestamp.to_f + } + + log = UserHistory.last + expect(log.acting_user_id).to eq(moderator.id) + expect(log.topic_id).to eq(topic.id) + expect(log.new_value).to eq(new_timestamp.utc.to_s) + expect(log.previous_value).to eq(old_timestamp.utc.to_s) + end end end