Skip to content

Commit

Permalink
Merge pull request #476 from imas/fix/favourite_tags-latin-char
Browse files Browse the repository at this point in the history
お気に入りタグにおいて、大文字小文字を混在できないバグを修正
  • Loading branch information
takayamaki authored Jan 9, 2025
2 parents 7588ce3 + 72ed467 commit 505a1d9
Show file tree
Hide file tree
Showing 22 changed files with 424 additions and 205 deletions.
4 changes: 4 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ RSpec/FilePath:
- 'spec/config/initializers/rack_attack_spec.rb' # namespaces usually have separate folder
- 'spec/lib/sanitize_config_spec.rb' # namespaces usually have separate folder

RSpec/LetSetup:
Exclude:
- spec/imastodon/**/*

# Reason:
# https://docs.rubocop.org/rubocop-rspec/cops_rspec.html#rspecnamedsubject
RSpec/NamedSubject:
Expand Down
63 changes: 23 additions & 40 deletions app/controllers/api/v1/favourite_tags_controller.rb
Original file line number Diff line number Diff line change
@@ -1,65 +1,48 @@
# frozen_string_literal: true

class Api::V1::FavouriteTagsController < Api::BaseController
before_action :set_account
before_action -> { doorkeeper_authorize! :read, :'read:statuses' }, only: [:index]
before_action -> { doorkeeper_authorize! :write, :'write:statuses' }, except: [:index]
before_action :require_user!

respond_to :json

def index
render json: current_favourite_tags
current_account = current_user.account
orderd_favourite_tags = current_account.favourite_tags.with_order

render json: orderd_favourite_tags.map(&:to_json_for_api)
end

def create
tag = find_or_init_tag
@favourite_tag = FavouriteTag.new(account: @account, tag: tag, visibility: favourite_tag_visibility)
if @favourite_tag.save
render json: @favourite_tag.to_json_for_api
else
render json: find_fav_tag_by(tag).to_json_for_api, status: 409
current_account = current_user.account
favourite_tag = current_account.favourite_tags.find_by(name: create_params[:name], visibility: create_params[:visibility])

if favourite_tag.present?
render json: favourite_tag.to_json_for_api, status: 409
return
end

favourite_tag = FavouriteTag.new(account: current_account, name: create_params[:name], visibility: create_params[:visibility])
favourite_tag.save!
render json: favourite_tag.to_json_for_api
end

def destroy
tag = find_tag
@favourite_tag = find_fav_tag_by(tag)
if @favourite_tag.nil?
render json: { succeeded: false }, status: 404
current_account = current_user.account
favourite_tag = current_account.favourite_tags.find_by(id: params[:id])
if favourite_tag.nil?
render json: { error: 'FavouriteTag is not found' }, status: 404
else
@favourite_tag.destroy
render json: { succeeded: true }
favourite_tag.destroy!
end
end

private

def tag_params
params.permit(:tag, :visibility)
end

def set_account
@account = current_user.account
end

def find_or_init_tag
Tag.find_or_initialize_by(name: tag_params[:tag])
end

def find_tag
Tag.find_by(name: tag_params[:tag])
end

def find_fav_tag_by(tag)
@account.favourite_tags.find_by(tag: tag)
end

def favourite_tag_visibility
tag_params[:visibility].nil? ? 'public' : tag_params[:visibility]
end

def current_favourite_tags
current_account.favourite_tags.with_order.includes(:tag).map(&:to_json_for_api)
def create_params
params.permit(:name, :visibility)
params[:visibility] ||= 'public'
params
end
end
53 changes: 27 additions & 26 deletions app/controllers/settings/favourite_tags_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,63 +3,64 @@
class Settings::FavouriteTagsController < Settings::BaseController
layout 'admin'
before_action :authenticate_user!
before_action :set_account
before_action :set_favourite_tags, only: [:index, :create]
before_action :set_favourite_tag, only: [:edit, :update, :destroy]

def index
@favourite_tag = FavouriteTag.new(tag: Tag.new, visibility: FavouriteTag.visibilities[:public])
@favourite_tags = current_account.favourite_tags.with_order
@favourite_tag = FavouriteTag.new(visibility: FavouriteTag.visibilities[:public])
end

def edit
@favourite_tag
@favourite_tag = current_account.favourite_tags.find(params[:id])
end

def create
name = tag_params[:name].delete_prefix('#')
tag = Tag.find_or_initialize_by(name: name)
@favourite_tag = FavouriteTag.new(account: @account, tag: tag, visibility: favourite_tag_params[:visibility], order: favourite_tag_params[:order])
@favourite_tag = FavouriteTag.new(
account: current_account,
name: create_params[:name].delete_prefix('#'),
order: create_params[:order],
visibility: create_params[:visibility]
)

if @favourite_tag.save
redirect_to settings_favourite_tags_path, notice: I18n.t('generic.changes_saved_msg')
else
@favourite_tags = current_account.favourite_tags.with_order
render :index
end
end

def update
name = tag_params[:name].delete_prefix('#')
tag = Tag.find_or_initialize_by(name: name)
if @favourite_tag.update(tag: tag, visibility: favourite_tag_params[:visibility], order: favourite_tag_params[:order])
@favourite_tag = current_account.favourite_tags.find(params[:id])

@favourite_tag.update(
name: update_params[:name].delete_prefix('#'),
order: update_params[:order],
visibility: update_params[:visibility]
)

if @favourite_tag.save
redirect_to settings_favourite_tags_path, notice: I18n.t('generic.changes_saved_msg')
else
render :edit
end
end

def destroy
@favourite_tag.destroy
current_account.favourite_tags.destroy(params[:id])
redirect_to settings_favourite_tags_path
end

private

def tag_params
params.require(:favourite_tag).require(:tag_attributes).permit(:id, :name)
end

def favourite_tag_params
params.require(:favourite_tag).permit(:visibility, :order, { tag_attributes: [:id, :name] })
end

def set_account
@account = current_user.account
def create_params
params.require(:favourite_tag).permit(:name, :visibility, :order)
end

def set_favourite_tag
@favourite_tag = @account.favourite_tags.find(params[:id])
def update_params
params.require(:favourite_tag).permit(:name, :visibility, :order)
end

def set_favourite_tags
@favourite_tags = @account.favourite_tags.with_order.includes(:tag)
def current_account
current_user.account
end
end
6 changes: 3 additions & 3 deletions app/javascript/mastodon/actions/favourite_tags.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,17 @@ export function refreshFavouriteTags() {
export function addFavouriteTags(tag, visibility) {
return (dispatch, getState) => {
api(getState).post('/api/v1/favourite_tags', {
tag: tag,
name: tag,
visibility: visibility,
}).then(() => {
dispatch(refreshFavouriteTags());
}).catch(() => {});
};
}

export function removeFavouriteTags(tag) {
export function removeFavouriteTags(id) {
return (dispatch, getState) => {
api(getState).delete(`/api/v1/favourite_tags/${tag}`).then(() => {
api(getState).delete(`/api/v1/favourite_tags/${id}`).then(() => {
dispatch(refreshFavouriteTags());
}).catch(() => {});
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import Button from '../../../components/button';
const messages = defineMessages({
add_favourite_tags_public: { id: 'tag.add_favourite.public', defaultMessage: 'add in the favourite tags (Public)' },
add_favourite_tags_unlisted: { id: 'tag.add_favourite.unlisted', defaultMessage: 'add in the favourite tags (Unlisted)' },
remove_favourite_tags: { id: 'tag.remove_favourite', defaultMessage: 'Remove from the favourite tags' },
remove_favourite_tags_public: { id: 'tag.remove_favourite.public', defaultMessage: 'Remove from the favourite tags (Public)' },
remove_favourite_tags_unlisted: { id: 'tag.remove_favourite.unlisted', defaultMessage: 'Remove from the favourite tags (Unlisted)' },
});

class FavouriteToggle extends React.PureComponent {
Expand All @@ -18,7 +19,8 @@ class FavouriteToggle extends React.PureComponent {
tag: PropTypes.string.isRequired,
addFavouriteTags: PropTypes.func.isRequired,
removeFavouriteTags: PropTypes.func.isRequired,
isRegistered: PropTypes.bool.isRequired,
unlistedId: PropTypes.number,
publicId: PropTypes.number,
intl: PropTypes.object.isRequired,
};

Expand All @@ -34,25 +36,33 @@ class FavouriteToggle extends React.PureComponent {
this.addFavouriteTags('unlisted');
};

removeFavouriteTags = () => {
this.props.removeFavouriteTags(this.props.tag);
removeFavouriteTags = (id) => {
this.props.removeFavouriteTags(id);
};

removePublic = () => {
this.removeFavouriteTags(this.props.publicId)
}

removeUnlisted = () => {
this.removeFavouriteTags(this.props.unlistedId)
}

render () {
const { intl, isRegistered } = this.props;
const { intl, unlistedId, publicId } = this.props;

return (
<div>
{ isRegistered ?
<div className='column-settings__row'>
<Button className='favourite-tags__remove-button-in-column' text={intl.formatMessage(messages.remove_favourite_tags)} onClick={this.removeFavouriteTags} block />
</div>
:
<div className='column-settings__row'>
<Button className='favourite-tags__add-button-in-column' text={intl.formatMessage(messages.add_favourite_tags_public)} onClick={this.addPublic} block />
<Button className='favourite-tags__add-button-in-column' text={intl.formatMessage(messages.add_favourite_tags_unlisted)} onClick={this.addUnlisted} block />
</div>
}
<div className='column-settings__row'>
{
publicId != null ? <Button className='favourite-tags__remove-button-in-column' text={intl.formatMessage(messages.remove_favourite_tags_public)} onClick={this.removePublic} block />
: <Button className='favourite-tags__add-button-in-column' text={intl.formatMessage(messages.add_favourite_tags_public)} onClick={this.addPublic} block />
}
{
unlistedId != null ? <Button className='favourite-tags__remove-button-in-column' text={intl.formatMessage(messages.remove_favourite_tags_unlisted)} onClick={this.removeUnlisted} block />
: <Button className='favourite-tags__add-button-in-column' text={intl.formatMessage(messages.add_favourite_tags_unlisted)} onClick={this.addUnlisted} block />
}
</div>
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { addFavouriteTags, removeFavouriteTags } from '../../../actions/favourit
import FavouriteToggle from '../components/favourite_toggle';

const mapStateToProps = (state, { tag }) => ({
isRegistered: state.getIn(['favourite_tags', 'tags']).some(t => t.get('name') === tag),
publicId: state.getIn(['favourite_tags', 'tags']).find(t => t.get('name') === tag && t.get('visibility') === 'public')?.get('id'),
unlistedId: state.getIn(['favourite_tags', 'tags']).find(t => t.get('name') === tag && t.get('visibility') === 'unlisted')?.get('id'),
});

const mapDispatchToProps = dispatch => ({
Expand All @@ -13,8 +14,8 @@ const mapDispatchToProps = dispatch => ({
dispatch(addFavouriteTags(tag, visibility));
},

removeFavouriteTags (tag) {
dispatch(removeFavouriteTags(tag));
removeFavouriteTags (id) {
dispatch(removeFavouriteTags(id));
},

});
Expand Down
3 changes: 2 additions & 1 deletion app/javascript/mastodon/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -681,7 +681,8 @@
"tabs_bar.notifications": "Notifications",
"tag.add_favourite.public": "add in the favourite tags (Public)",
"tag.add_favourite.unlisted": "add in the favourite tags (Unlisted)",
"tag.remove_favourite": "Remove from the favourite tags",
"tag.remove_favourite.public": "Remove from the favourite tagss (Public)",
"tag.remove_favourite.unlisted": "Remove from the favourite tagsags (Unlisted)",
"time_remaining.days": "{number, plural, one {# day} other {# days}} left",
"time_remaining.hours": "{number, plural, one {# hour} other {# hours}} left",
"time_remaining.minutes": "{number, plural, one {# minute} other {# minutes}} left",
Expand Down
3 changes: 2 additions & 1 deletion app/javascript/mastodon/locales/ja-IM.json
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,8 @@
"tabs_bar.search": "検索",
"tag.add_favourite.public": "スウィーティー☆(公開資料)",
"tag.add_favourite.unlisted": "スウィーティー☆(社内資料)",
"tag.remove_favourite": "スウィーティーじゃない",
"tag.remove_favourite.public": "スウィーティーじゃない(公開)",
"tag.remove_favourite.unlisted": "スウィーティーじゃない(未収載)",
"time_remaining.days": "残り{number}日",
"time_remaining.hours": "残り{number}時間",
"time_remaining.minutes": "残り{number}分",
Expand Down
3 changes: 2 additions & 1 deletion app/javascript/mastodon/locales/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -681,7 +681,8 @@
"tabs_bar.notifications": "通知",
"tag.add_favourite.public": "お気に入り登録(公開)",
"tag.add_favourite.unlisted": "お気に入り登録(未収載)",
"tag.remove_favourite": "お気に入り解除",
"tag.remove_favourite.public": "お気に入り解除(公開)",
"tag.remove_favourite.unlisted": "お気に入り解除(未収載)",
"time_remaining.days": "残り{number}日",
"time_remaining.hours": "残り{number}時間",
"time_remaining.minutes": "残り{number}分",
Expand Down
2 changes: 1 addition & 1 deletion app/lib/friends/favourite_tags_extension.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ module FavouriteTagsExtension

def add_default_favourite_tag
DEFAULT_TAGS.each_with_index do |tag_name, i|
favourite_tags.create!(visibility: 'unlisted', tag: Tag.find_or_create_by!(name: HashtagNormalizer.new.normalize(tag_name)), order: (DEFAULT_TAGS.length - i))
favourite_tags.create!(visibility: 'unlisted', name: tag_name, order: (DEFAULT_TAGS.length - i))
end
end
end
Expand Down
14 changes: 9 additions & 5 deletions app/models/favourite_tag.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,32 @@
# updated_at :datetime not null
# visibility :integer default("public"), not null
# order :integer default(0), not null
# name :string
#

class FavouriteTag < ApplicationRecord
enum visibility: { public: 0, unlisted: 1, private: 2, direct: 3 }, _suffix: :visibility

belongs_to :account, optional: false
belongs_to :tag, optional: false
accepts_nested_attributes_for :tag
belongs_to :tag, optional: true

validates :tag, uniqueness: { scope: :account }
validates :name, format: { with: Tag::HASHTAG_NAME_RE }, uniqueness: { scope: [:account, :visibility] }
validates :visibility, presence: true
validates :order, presence: true, numericality: { only_integer: true, greater_than_or_equal_to: 0 }

scope :with_order, -> { order(order: :desc, id: :asc) }

delegate :name, to: :tag

def to_json_for_api
{
id: id,
name: name,
visibility: visibility,
}
end

def migrate_tag_name!
return if name.present?

update!(name: tag&.name)
end
end
3 changes: 1 addition & 2 deletions app/views/settings/favourite_tags/_form.html.haml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
= simple_form_for [:settings, favourite_tag] do |f|
= render 'shared/error_messages', object: favourite_tag
= f.simple_fields_for :tag do |ff|
= ff.input :name, placeholder: t('favourite_tags.name_of_tag')
= f.input :name, placeholder: t('favourite_tags.name_of_tag')
= f.input :visibility,
label: t('simple_form.labels.defaults.setting_default_privacy'),
collection: Status.visibilities.keys[0..1],
Expand Down
2 changes: 1 addition & 1 deletion app/views/settings/favourite_tags/index.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
%tr
%td
= fa_icon 'tag'
= fav_tag.tag.name
= fav_tag.name
%td
= I18n.t("statuses.visibilities.#{fav_tag.visibility}")
%td
Expand Down
Loading

0 comments on commit 505a1d9

Please sign in to comment.