From 5cc716688abdf7eaafc58d804209510601190791 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 26 Feb 2018 01:31:44 +0100 Subject: Ensure the app does not even start if OTP_SECRET is not set (#6557) * Ensure the app does not even start if OTP_SECRET is not set * Remove PAPERCLIP_SECRET (it's not used by anything, actually) Imports are for internal consumption and the url option isn't even used correctly, so we can remove the hash stuff from them --- app/models/import.rb | 2 +- app/models/user.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'app/models') diff --git a/app/models/import.rb b/app/models/import.rb index ba88435bf..fdb4c6b80 100644 --- a/app/models/import.rb +++ b/app/models/import.rb @@ -26,7 +26,7 @@ class Import < ApplicationRecord validates :type, presence: true - has_attached_file :data, url: '/system/:hash.:extension', hash_secret: ENV['PAPERCLIP_SECRET'] + has_attached_file :data validates_attachment_content_type :data, content_type: FILE_TYPES validates_attachment_presence :data end diff --git a/app/models/user.rb b/app/models/user.rb index fcd574f8b..b053292da 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -44,7 +44,7 @@ class User < ApplicationRecord ACTIVE_DURATION = 14.days devise :two_factor_authenticatable, - otp_secret_encryption_key: ENV['OTP_SECRET'] + otp_secret_encryption_key: ENV.fetch('OTP_SECRET') devise :two_factor_backupable, otp_number_of_backup_codes: 10 -- cgit From c33931b613c7da4cc2c22ff8411c38556dc579cb Mon Sep 17 00:00:00 2001 From: Ian McCowan Date: Sun, 25 Feb 2018 18:31:28 -0800 Subject: Fix prev/next links on public profile page (#6497) * Fix prev/next links on public profile page * Don't make pagination urls if no available statuses * Fix empty check method * Put left chevron before prev page link * Add scope for pagination "starting at" a given id * Status pagination try 2: s/prev/older and s/next/newer "older" on left, "newer" on right Use new scope for "newer" link Extract magic 20 page size to constant Remove max_id from feed pagination as it's not respected * Reinstate max_id for accounts atom stream * normalize --- app/controllers/accounts_controller.rb | 36 ++++++++++++++++++++++------ app/javascript/styles/mastodon/accounts.scss | 16 ++++++------- app/models/concerns/paginable.rb | 9 +++++++ app/views/accounts/show.html.haml | 7 ++++-- config/locales/en.yml | 2 ++ 5 files changed, 53 insertions(+), 17 deletions(-) (limited to 'app/models') diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index 69fd20e27..7bf35825f 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class AccountsController < ApplicationController + PAGE_SIZE = 20 + include AccountControllerConcern before_action :set_cache_headers @@ -16,13 +18,16 @@ class AccountsController < ApplicationController end @pinned_statuses = cache_collection(@account.pinned_statuses, Status) if show_pinned_statuses? - @statuses = filtered_statuses.paginate_by_max_id(20, params[:max_id], params[:since_id]) + @statuses = filtered_status_page(params) @statuses = cache_collection(@statuses, Status) - @next_url = next_url unless @statuses.empty? + unless @statuses.empty? + @older_url = older_url if @statuses.last.id > filtered_statuses.last.id + @newer_url = newer_url if @statuses.first.id < filtered_statuses.first.id + end end format.atom do - @entries = @account.stream_entries.where(hidden: false).with_includes.paginate_by_max_id(20, params[:max_id], params[:since_id]) + @entries = @account.stream_entries.where(hidden: false).with_includes.paginate_by_max_id(PAGE_SIZE, params[:max_id], params[:since_id]) render xml: OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.feed(@account, @entries.reject { |entry| entry.status.nil? })) end @@ -69,13 +74,22 @@ class AccountsController < ApplicationController @account = Account.find_local!(params[:username]) end - def next_url + def older_url + ::Rails.logger.info("older: max_id #{@statuses.last.id}, url #{pagination_url(max_id: @statuses.last.id)}") + pagination_url(max_id: @statuses.last.id) + end + + def newer_url + pagination_url(min_id: @statuses.first.id) + end + + def pagination_url(max_id: nil, min_id: nil) if media_requested? - short_account_media_url(@account, max_id: @statuses.last.id) + short_account_media_url(@account, max_id: max_id, min_id: min_id) elsif replies_requested? - short_account_with_replies_url(@account, max_id: @statuses.last.id) + short_account_with_replies_url(@account, max_id: max_id, min_id: min_id) else - short_account_url(@account, max_id: @statuses.last.id) + short_account_url(@account, max_id: max_id, min_id: min_id) end end @@ -86,4 +100,12 @@ class AccountsController < ApplicationController def replies_requested? request.path.ends_with?('/with_replies') end + + def filtered_status_page(params) + if params[:min_id].present? + filtered_statuses.paginate_by_min_id(PAGE_SIZE, params[:min_id]).reverse + else + filtered_statuses.paginate_by_max_id(PAGE_SIZE, params[:max_id], params[:since_id]).to_a + end + end end diff --git a/app/javascript/styles/mastodon/accounts.scss b/app/javascript/styles/mastodon/accounts.scss index 9015d04cb..c812766a1 100644 --- a/app/javascript/styles/mastodon/accounts.scss +++ b/app/javascript/styles/mastodon/accounts.scss @@ -233,8 +233,8 @@ a, .current, - .next, - .prev, + .newer, + .older, .page, .gap { font-size: 14px; @@ -257,13 +257,13 @@ cursor: default; } - .prev, - .next { + .older, + .newer { text-transform: uppercase; color: $ui-secondary-color; } - .prev { + .older { float: left; padding-left: 0; @@ -273,7 +273,7 @@ } } - .next { + .newer { float: right; padding-right: 0; @@ -295,8 +295,8 @@ display: none; } - .next, - .prev { + .newer, + .older { display: inline-block; } } diff --git a/app/models/concerns/paginable.rb b/app/models/concerns/paginable.rb index 6061bf9bd..66695677e 100644 --- a/app/models/concerns/paginable.rb +++ b/app/models/concerns/paginable.rb @@ -10,5 +10,14 @@ module Paginable query = query.where(arel_table[:id].gt(since_id)) if since_id.present? query } + + # Differs from :paginate_by_max_id in that it gives the results immediately following min_id, + # whereas since_id gives the items with largest id, but with since_id as a cutoff. + # Results will be in ascending order by id. + scope :paginate_by_min_id, ->(limit, min_id = nil) { + query = reorder(arel_table[:id]).limit(limit) + query = query.where(arel_table[:id].gt(min_id)) if min_id.present? + query + } end end diff --git a/app/views/accounts/show.html.haml b/app/views/accounts/show.html.haml index accad5f78..21c585dab 100644 --- a/app/views/accounts/show.html.haml +++ b/app/views/accounts/show.html.haml @@ -39,6 +39,9 @@ = render partial: 'stream_entries/status', collection: @statuses, as: :status - - if @statuses.size == 20 + - if @newer_url || @older_url .pagination - = link_to safe_join([t('pagination.next'), fa_icon('chevron-right')], ' '), @next_url, class: 'next', rel: 'next' + - if @older_url + = link_to safe_join([fa_icon('chevron-left'), t('pagination.older')], ' '), @older_url, class: 'older', rel: 'older' + - if @newer_url + = link_to safe_join([t('pagination.newer'), fa_icon('chevron-right')], ' '), @newer_url, class: 'newer', rel: 'newer' diff --git a/config/locales/en.yml b/config/locales/en.yml index 071c41290..026426c84 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -545,7 +545,9 @@ en: trillion: T unit: '' pagination: + newer: Newer next: Next + older: Older prev: Prev truncate: "…" preferences: -- cgit From 41a01bec2337e7021634f2e9c78d86a1c3002fcf Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 28 Feb 2018 06:54:55 +0100 Subject: Federated reports (#6570) * Fix #2176: Federated reports * UI for federated reports * Add spec for ActivityPub Flag handler * Add spec for ReportService --- app/controllers/api/v1/reports_controller.rb | 12 ++-- app/javascript/mastodon/actions/reports.js | 9 +++ .../features/ui/components/report_modal.js | 44 ++++++++---- app/javascript/mastodon/reducers/reports.js | 4 ++ app/javascript/styles/mastodon/components.scss | 84 ++++++++++++++++++++-- app/lib/activitypub/activity.rb | 2 + app/lib/activitypub/activity/flag.rb | 25 +++++++ app/models/report.rb | 4 ++ app/serializers/activitypub/flag_serializer.rb | 27 +++++++ app/services/report_service.rb | 54 ++++++++++++++ db/schema.rb | 1 + spec/lib/activitypub/activity/flag_spec.rb | 37 ++++++++++ spec/services/report_service_spec.rb | 25 +++++++ 13 files changed, 306 insertions(+), 22 deletions(-) create mode 100644 app/lib/activitypub/activity/flag.rb create mode 100644 app/serializers/activitypub/flag_serializer.rb create mode 100644 app/services/report_service.rb create mode 100644 spec/lib/activitypub/activity/flag_spec.rb create mode 100644 spec/services/report_service_spec.rb (limited to 'app/models') diff --git a/app/controllers/api/v1/reports_controller.rb b/app/controllers/api/v1/reports_controller.rb index 22828217d..f5095e073 100644 --- a/app/controllers/api/v1/reports_controller.rb +++ b/app/controllers/api/v1/reports_controller.rb @@ -13,14 +13,14 @@ class Api::V1::ReportsController < Api::BaseController end def create - @report = current_account.reports.create!( - target_account: reported_account, + @report = ReportService.new.call( + current_account, + reported_account, status_ids: reported_status_ids, - comment: report_params[:comment] + comment: report_params[:comment], + forward: report_params[:forward] ) - User.staff.includes(:account).each { |u| AdminMailer.new_report(u.account, @report).deliver_later } - render json: @report, serializer: REST::ReportSerializer end @@ -39,6 +39,6 @@ class Api::V1::ReportsController < Api::BaseController end def report_params - params.permit(:account_id, :comment, status_ids: []) + params.permit(:account_id, :comment, :forward, status_ids: []) end end diff --git a/app/javascript/mastodon/actions/reports.js b/app/javascript/mastodon/actions/reports.js index b19a07285..afa0c3412 100644 --- a/app/javascript/mastodon/actions/reports.js +++ b/app/javascript/mastodon/actions/reports.js @@ -10,6 +10,7 @@ export const REPORT_SUBMIT_FAIL = 'REPORT_SUBMIT_FAIL'; export const REPORT_STATUS_TOGGLE = 'REPORT_STATUS_TOGGLE'; export const REPORT_COMMENT_CHANGE = 'REPORT_COMMENT_CHANGE'; +export const REPORT_FORWARD_CHANGE = 'REPORT_FORWARD_CHANGE'; export function initReport(account, status) { return dispatch => { @@ -45,6 +46,7 @@ export function submitReport() { account_id: getState().getIn(['reports', 'new', 'account_id']), status_ids: getState().getIn(['reports', 'new', 'status_ids']), comment: getState().getIn(['reports', 'new', 'comment']), + forward: getState().getIn(['reports', 'new', 'forward']), }).then(response => { dispatch(closeModal()); dispatch(submitReportSuccess(response.data)); @@ -78,3 +80,10 @@ export function changeReportComment(comment) { comment, }; }; + +export function changeReportForward(forward) { + return { + type: REPORT_FORWARD_CHANGE, + forward, + }; +}; diff --git a/app/javascript/mastodon/features/ui/components/report_modal.js b/app/javascript/mastodon/features/ui/components/report_modal.js index b5dfa422e..3a7e4df76 100644 --- a/app/javascript/mastodon/features/ui/components/report_modal.js +++ b/app/javascript/mastodon/features/ui/components/report_modal.js @@ -1,6 +1,6 @@ import React from 'react'; import { connect } from 'react-redux'; -import { changeReportComment, submitReport } from '../../../actions/reports'; +import { changeReportComment, changeReportForward, submitReport } from '../../../actions/reports'; import { refreshAccountTimeline } from '../../../actions/timelines'; import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; @@ -10,6 +10,7 @@ import StatusCheckBox from '../../report/containers/status_check_box_container'; import { OrderedSet } from 'immutable'; import ImmutablePureComponent from 'react-immutable-pure-component'; import Button from '../../../components/button'; +import Toggle from 'react-toggle'; const messages = defineMessages({ placeholder: { id: 'report.placeholder', defaultMessage: 'Additional comments' }, @@ -26,6 +27,7 @@ const makeMapStateToProps = () => { isSubmitting: state.getIn(['reports', 'new', 'isSubmitting']), account: getAccount(state, accountId), comment: state.getIn(['reports', 'new', 'comment']), + forward: state.getIn(['reports', 'new', 'forward']), statusIds: OrderedSet(state.getIn(['timelines', `account:${accountId}`, 'items'])).union(state.getIn(['reports', 'new', 'status_ids'])), }; }; @@ -42,14 +44,19 @@ export default class ReportModal extends ImmutablePureComponent { account: ImmutablePropTypes.map, statusIds: ImmutablePropTypes.orderedSet.isRequired, comment: PropTypes.string.isRequired, + forward: PropTypes.bool, dispatch: PropTypes.func.isRequired, intl: PropTypes.object.isRequired, }; - handleCommentChange = (e) => { + handleCommentChange = e => { this.props.dispatch(changeReportComment(e.target.value)); } + handleForwardChange = e => { + this.props.dispatch(changeReportForward(e.target.checked)); + } + handleSubmit = () => { this.props.dispatch(submitReport()); } @@ -65,12 +72,14 @@ export default class ReportModal extends ImmutablePureComponent { } render () { - const { account, comment, intl, statusIds, isSubmitting } = this.props; + const { account, comment, intl, statusIds, isSubmitting, forward } = this.props; if (!account) { return null; } + const domain = account.get('acct').split('@')[1]; + return (
@@ -78,13 +87,9 @@ export default class ReportModal extends ImmutablePureComponent {
-
-
- {statusIds.map(statusId => )} -
-
-
+

+