From 9f8d34620b6fa502da683f3775805bf2a5474f92 Mon Sep 17 00:00:00 2001 From: fusagiko / takayamaki <24884114+takayamaki@users.noreply.github.com> Date: Mon, 17 Apr 2023 14:07:27 +0900 Subject: [PATCH 1/7] Rewrite AvatarOverlay component with React hooks (#24543) --- .../avatar_overlay-test.jsx.snap | 6 +-- .../mastodon/components/avatar_overlay.jsx | 51 ------------------- .../mastodon/components/avatar_overlay.tsx | 51 +++++++++++++++++++ 3 files changed, 53 insertions(+), 55 deletions(-) delete mode 100644 app/javascript/mastodon/components/avatar_overlay.jsx create mode 100644 app/javascript/mastodon/components/avatar_overlay.tsx diff --git a/app/javascript/mastodon/components/__tests__/__snapshots__/avatar_overlay-test.jsx.snap b/app/javascript/mastodon/components/__tests__/__snapshots__/avatar_overlay-test.jsx.snap index f8385357a3..fbd44ecc5e 100644 --- a/app/javascript/mastodon/components/__tests__/__snapshots__/avatar_overlay-test.jsx.snap +++ b/app/javascript/mastodon/components/__tests__/__snapshots__/avatar_overlay-test.jsx.snap @@ -3,6 +3,8 @@ exports[`
{ - if (this.props.animate) return; - this.setState({ hovering: true }); - }; - - handleMouseLeave = () => { - if (this.props.animate) return; - this.setState({ hovering: false }); - }; - - render() { - const { account, friend, animate, size, baseSize, overlaySize } = this.props; - const { hovering } = this.state; - - return ( -
-
-
-
- ); - } - -} diff --git a/app/javascript/mastodon/components/avatar_overlay.tsx b/app/javascript/mastodon/components/avatar_overlay.tsx new file mode 100644 index 0000000000..5c65a928c5 --- /dev/null +++ b/app/javascript/mastodon/components/avatar_overlay.tsx @@ -0,0 +1,51 @@ +import React from 'react'; +import type { Account } from '../../types/resources'; +import { useHovering } from '../../hooks/useHovering'; +import { autoPlayGif } from '../initial_state'; + +type Props = { + account: Account; + friend: Account; + size?: number; + baseSize?: number; + overlaySize?: number; +}; + +export const AvatarOverlay: React.FC = ({ + account, + friend, + size = 46, + baseSize = 36, + overlaySize = 24, +}) => { + const { hovering, handleMouseEnter, handleMouseLeave } = useHovering(autoPlayGif); + const accountSrc = hovering ? account?.get('avatar') : account?.get('avatar_static'); + const friendSrc = hovering ? friend?.get('avatar') : friend?.get('avatar_static'); + + return ( +
+
+
+ {accountSrc && {account?.get('acct')}} +
+
+
+
+ {friendSrc && {friend?.get('acct')}} +
+
+
+ ); +}; + +export default AvatarOverlay; From ca447d3007b091c4b45d8509f9a9064942a93f2d Mon Sep 17 00:00:00 2001 From: Nick Schonning Date: Mon, 17 Apr 2023 04:12:04 -0400 Subject: [PATCH 2/7] Update Jest testing to include Typescript (#24555) --- .github/workflows/test-js.yml | 4 ++++ jest.config.js | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-js.yml b/.github/workflows/test-js.yml index 6a1cacb3f0..1c4958550e 100644 --- a/.github/workflows/test-js.yml +++ b/.github/workflows/test-js.yml @@ -9,6 +9,8 @@ on: - '.nvmrc' - '**/*.js' - '**/*.jsx' + - '**/*.ts' + - '**/*.tsx' - '**/*.snap' - '.github/workflows/test-js.yml' @@ -19,6 +21,8 @@ on: - '.nvmrc' - '**/*.js' - '**/*.jsx' + - '**/*.ts' + - '**/*.tsx' - '**/*.snap' - '.github/workflows/test-js.yml' diff --git a/jest.config.js b/jest.config.js index 69222ea357..f447cf285d 100644 --- a/jest.config.js +++ b/jest.config.js @@ -12,7 +12,7 @@ const config = { setupFiles: ['raf/polyfill'], setupFilesAfterEnv: ['/app/javascript/mastodon/test_setup.js'], collectCoverageFrom: [ - 'app/javascript/mastodon/**/*.js', + 'app/javascript/mastodon/**/*.{js,jsx,ts,tsx}', '!app/javascript/mastodon/features/emoji/emoji_compressed.js', '!app/javascript/mastodon/locales/locale-data/*.js', '!app/javascript/mastodon/service_worker/entry.js', From bc4745f4824c3863d9ec939618b3e9414f3622bb Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 17 Apr 2023 10:15:21 +0200 Subject: [PATCH 3/7] Fix crash when trying to open the filter modal (#24556) --- app/javascript/mastodon/features/ui/components/filter_modal.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/mastodon/features/ui/components/filter_modal.jsx b/app/javascript/mastodon/features/ui/components/filter_modal.jsx index 32ebaf7b79..8d77fb3dfe 100644 --- a/app/javascript/mastodon/features/ui/components/filter_modal.jsx +++ b/app/javascript/mastodon/features/ui/components/filter_modal.jsx @@ -131,4 +131,4 @@ class FilterModal extends ImmutablePureComponent { } -export default connect(injectIntl(FilterModal)); +export default connect()(injectIntl(FilterModal)); From 4601e0dcbb1c10dba16708662145dfa2595fee33 Mon Sep 17 00:00:00 2001 From: Heitor de Melo Cardozo Date: Mon, 17 Apr 2023 06:06:06 -0300 Subject: [PATCH 4/7] Add user handle to notification mail recipient address (#24240) Co-authored-by: luccamps Co-authored-by: Leonardo Negreiros de Oliveira Co-authored-by: Marcio Flavio Co-authored-by: Gabriel Quaresma --- app/mailers/notification_mailer.rb | 10 +++++----- spec/mailers/notification_mailer_spec.rb | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/mailers/notification_mailer.rb b/app/mailers/notification_mailer.rb index ab73826ab3..c428fd30d6 100644 --- a/app/mailers/notification_mailer.rb +++ b/app/mailers/notification_mailer.rb @@ -14,7 +14,7 @@ class NotificationMailer < ApplicationMailer locale_for_account(@me) do thread_by_conversation(@status.conversation) - mail to: @me.user.email, subject: I18n.t('notification_mailer.mention.subject', name: @status.account.acct) + mail to: email_address_with_name(@me.user.email, @me.user.account.username), subject: I18n.t('notification_mailer.mention.subject', name: @status.account.acct) end end @@ -25,7 +25,7 @@ class NotificationMailer < ApplicationMailer return unless @me.user.functional? locale_for_account(@me) do - mail to: @me.user.email, subject: I18n.t('notification_mailer.follow.subject', name: @account.acct) + mail to: email_address_with_name(@me.user.email, @me.user.account.username), subject: I18n.t('notification_mailer.follow.subject', name: @account.acct) end end @@ -38,7 +38,7 @@ class NotificationMailer < ApplicationMailer locale_for_account(@me) do thread_by_conversation(@status.conversation) - mail to: @me.user.email, subject: I18n.t('notification_mailer.favourite.subject', name: @account.acct) + mail to: email_address_with_name(@me.user.email, @me.user.account.username), subject: I18n.t('notification_mailer.favourite.subject', name: @account.acct) end end @@ -51,7 +51,7 @@ class NotificationMailer < ApplicationMailer locale_for_account(@me) do thread_by_conversation(@status.conversation) - mail to: @me.user.email, subject: I18n.t('notification_mailer.reblog.subject', name: @account.acct) + mail to: email_address_with_name(@me.user.email, @me.user.account.username), subject: I18n.t('notification_mailer.reblog.subject', name: @account.acct) end end @@ -62,7 +62,7 @@ class NotificationMailer < ApplicationMailer return unless @me.user.functional? locale_for_account(@me) do - mail to: @me.user.email, subject: I18n.t('notification_mailer.follow_request.subject', name: @account.acct) + mail to: email_address_with_name(@me.user.email, @me.user.account.username), subject: I18n.t('notification_mailer.follow_request.subject', name: @account.acct) end end diff --git a/spec/mailers/notification_mailer_spec.rb b/spec/mailers/notification_mailer_spec.rb index a6db08d850..341fe6f233 100644 --- a/spec/mailers/notification_mailer_spec.rb +++ b/spec/mailers/notification_mailer_spec.rb @@ -29,7 +29,7 @@ RSpec.describe NotificationMailer, type: :mailer do it 'renders the headers' do expect(mail.subject).to eq('You were mentioned by bob') - expect(mail.to).to eq([receiver.email]) + expect(mail[:to].value).to eq("#{receiver.account.username} <#{receiver.email}>") end it 'renders the body' do @@ -46,7 +46,7 @@ RSpec.describe NotificationMailer, type: :mailer do it 'renders the headers' do expect(mail.subject).to eq('bob is now following you') - expect(mail.to).to eq([receiver.email]) + expect(mail[:to].value).to eq("#{receiver.account.username} <#{receiver.email}>") end it 'renders the body' do @@ -62,7 +62,7 @@ RSpec.describe NotificationMailer, type: :mailer do it 'renders the headers' do expect(mail.subject).to eq('bob favourited your post') - expect(mail.to).to eq([receiver.email]) + expect(mail[:to].value).to eq("#{receiver.account.username} <#{receiver.email}>") end it 'renders the body' do @@ -79,7 +79,7 @@ RSpec.describe NotificationMailer, type: :mailer do it 'renders the headers' do expect(mail.subject).to eq('bob boosted your post') - expect(mail.to).to eq([receiver.email]) + expect(mail[:to].value).to eq("#{receiver.account.username} <#{receiver.email}>") end it 'renders the body' do @@ -96,7 +96,7 @@ RSpec.describe NotificationMailer, type: :mailer do it 'renders the headers' do expect(mail.subject).to eq('Pending follower: bob') - expect(mail.to).to eq([receiver.email]) + expect(mail[:to].value).to eq("#{receiver.account.username} <#{receiver.email}>") end it 'renders the body' do From 85b1b4582053927830503c7c3d2d0c120efe4c93 Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 17 Apr 2023 13:13:36 +0200 Subject: [PATCH 5/7] Fix crash in NotifyService when trying to send an email notification for polls (#24558) --- app/services/notify_service.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/services/notify_service.rb b/app/services/notify_service.rb index 069f370cfc..ad9e6e3d63 100644 --- a/app/services/notify_service.rb +++ b/app/services/notify_service.rb @@ -7,6 +7,7 @@ class NotifyService < BaseService admin.report admin.sign_up update + poll ).freeze def call(recipient, type, activity) From ab740f464a8e5aa6b5f78c0ddab3c8e18698d810 Mon Sep 17 00:00:00 2001 From: fusagiko / takayamaki <24884114+takayamaki@users.noreply.github.com> Date: Mon, 17 Apr 2023 20:25:15 +0900 Subject: [PATCH 6/7] Rewrite AnimatedNumber component with React hooks (#24559) --- .../mastodon/components/animated_number.jsx | 76 ------------------- .../mastodon/components/animated_number.tsx | 58 ++++++++++++++ 2 files changed, 58 insertions(+), 76 deletions(-) delete mode 100644 app/javascript/mastodon/components/animated_number.jsx create mode 100644 app/javascript/mastodon/components/animated_number.tsx diff --git a/app/javascript/mastodon/components/animated_number.jsx b/app/javascript/mastodon/components/animated_number.jsx deleted file mode 100644 index ce688f04f2..0000000000 --- a/app/javascript/mastodon/components/animated_number.jsx +++ /dev/null @@ -1,76 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import ShortNumber from 'mastodon/components/short_number'; -import TransitionMotion from 'react-motion/lib/TransitionMotion'; -import spring from 'react-motion/lib/spring'; -import { reduceMotion } from 'mastodon/initial_state'; - -const obfuscatedCount = count => { - if (count < 0) { - return 0; - } else if (count <= 1) { - return count; - } else { - return '1+'; - } -}; - -export default class AnimatedNumber extends React.PureComponent { - - static propTypes = { - value: PropTypes.number.isRequired, - obfuscate: PropTypes.bool, - }; - - state = { - direction: 1, - }; - - componentWillReceiveProps (nextProps) { - if (nextProps.value > this.props.value) { - this.setState({ direction: 1 }); - } else if (nextProps.value < this.props.value) { - this.setState({ direction: -1 }); - } - } - - willEnter = () => { - const { direction } = this.state; - - return { y: -1 * direction }; - }; - - willLeave = () => { - const { direction } = this.state; - - return { y: spring(1 * direction, { damping: 35, stiffness: 400 }) }; - }; - - render () { - const { value, obfuscate } = this.props; - const { direction } = this.state; - - if (reduceMotion) { - return obfuscate ? obfuscatedCount(value) : ; - } - - const styles = [{ - key: `${value}`, - data: value, - style: { y: spring(0, { damping: 35, stiffness: 400 }) }, - }]; - - return ( - - {items => ( - - {items.map(({ key, data, style }) => ( - 0 ? 'absolute' : 'static', transform: `translateY(${style.y * 100}%)` }}>{obfuscate ? obfuscatedCount(data) : } - ))} - - )} - - ); - } - -} diff --git a/app/javascript/mastodon/components/animated_number.tsx b/app/javascript/mastodon/components/animated_number.tsx new file mode 100644 index 0000000000..1673ff41bb --- /dev/null +++ b/app/javascript/mastodon/components/animated_number.tsx @@ -0,0 +1,58 @@ +import React, { useCallback, useState } from 'react'; +import ShortNumber from './short_number'; +import { TransitionMotion, spring } from 'react-motion'; +import { reduceMotion } from '../initial_state'; + +const obfuscatedCount = (count: number) => { + if (count < 0) { + return 0; + } else if (count <= 1) { + return count; + } else { + return '1+'; + } +}; + +type Props = { + value: number; + obfuscate?: boolean; +} +export const AnimatedNumber: React.FC = ({ + value, + obfuscate, +})=> { + const [previousValue, setPreviousValue] = useState(value); + const [direction, setDirection] = useState<1|-1>(1); + + if (previousValue !== value) { + setPreviousValue(value); + setDirection(value > previousValue ? 1 : -1); + } + + const willEnter = useCallback(() => ({ y: -1 * direction }), [direction]); + const willLeave = useCallback(() => ({ y: spring(1 * direction, { damping: 35, stiffness: 400 }) }), [direction]); + + if (reduceMotion) { + return obfuscate ? <>{obfuscatedCount(value)} : ; + } + + const styles = [{ + key: `${value}`, + data: value, + style: { y: spring(0, { damping: 35, stiffness: 400 }) }, + }]; + + return ( + + {items => ( + + {items.map(({ key, data, style }) => ( + 0 ? 'absolute' : 'static', transform: `translateY(${style.y * 100}%)` }}>{obfuscate ? obfuscatedCount(data) : } + ))} + + )} + + ); +}; + +export default AnimatedNumber; From bc75e62ca6e16d3dad43fd35ccca335de547cfb3 Mon Sep 17 00:00:00 2001 From: Heitor de Melo Cardozo Date: Mon, 17 Apr 2023 09:16:36 -0300 Subject: [PATCH 7/7] Change moderation search an account using the username with @ (#24242) --- app/models/account_filter.rb | 2 +- spec/models/account_filter_spec.rb | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/app/models/account_filter.rb b/app/models/account_filter.rb index 1666ea883a..55d34e85c3 100644 --- a/app/models/account_filter.rb +++ b/app/models/account_filter.rb @@ -55,7 +55,7 @@ class AccountFilter when 'by_domain' Account.where(domain: value.to_s.strip) when 'username' - Account.matches_username(value.to_s.strip) + Account.matches_username(value.to_s.strip.delete_prefix('@')) when 'display_name' Account.matches_display_name(value.to_s.strip) when 'email' diff --git a/spec/models/account_filter_spec.rb b/spec/models/account_filter_spec.rb index 3032260fef..cb00e76096 100644 --- a/spec/models/account_filter_spec.rb +++ b/spec/models/account_filter_spec.rb @@ -44,4 +44,23 @@ describe AccountFilter do expect(filter.results).to match_array [remote_account_one] end end + + describe 'with username' do + let!(:local_account) { Fabricate(:account, domain: nil, username: 'validUserName') } + + it 'works with @ at the beginning of the username' do + filter = described_class.new(username: '@validUserName') + expect(filter.results).to match_array [local_account] + end + + it 'does not work with more than one @ at the beginning of the username' do + filter = described_class.new(username: '@@validUserName') + expect(filter.results).to_not match_array [local_account] + end + + it 'does not work with @ outside the beginning of the username' do + filter = described_class.new(username: 'validUserName@') + expect(filter.results).to_not match_array [local_account] + end + end end