0
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-08-07 13:19:19 +08:00
discourse/spec/requests/post_localizations_controller_spec.rb
Natalie Tay cb739f7f2d
UX: Allow user to set post and topic title language when manually creating post translations in modal (#41734)
Related:
https://meta.discourse.org/t/manual-localization-doesnt-seem-to-be-working/407319

Users have gotten tripped over and over again when manually inserting
translations for posts, not knowing they need to set the post language
first before the translation is shown (explained
[here](https://meta.discourse.org/t/manual-localization-doesnt-seem-to-be-working/407319/7?u=nat)).

This PR adds the ability to allow the user to set the post language in
the modal when they are working with translations, highlighting the fact
that they need to set the post language before translations can be shown
2026-07-16 10:43:39 +08:00

333 lines
10 KiB
Ruby
Vendored

# frozen_string_literal: true
describe PostLocalizationsController do
fab!(:user)
fab!(:group)
fab!(:post_record) { Fabricate(:post, version: 100) }
let(:locale) { "ja" }
let(:raw) { "これは翻訳です。" }
before do
SiteSetting.content_localization_enabled = true
SiteSetting.content_localization_supported_locales = "ja"
SiteSetting.content_localization_allowed_groups = group.id.to_s
group.add(user)
sign_in(user)
end
describe "#show" do
it "allows users in allowed groups to view localizations" do
Fabricate(:post_localization, post: post_record, locale:)
get "/post_localizations/#{post_record.id}.json"
expect(response.status).to eq(200)
json = response.parsed_body
expect(json["post_localizations"].length).to eq(1)
end
it "denies users not in allowed groups" do
group.remove(user)
get "/post_localizations/#{post_record.id}.json"
expect(response.status).to eq(403)
end
context "with author localization enabled" do
fab!(:author, :user)
fab!(:author_post) { Fabricate(:post, user: author) }
before do
SiteSetting.content_localization_allow_author_localization = true
group.remove(author)
end
it "allows post authors to view localizations for their own posts" do
Fabricate(:post_localization, post: author_post, locale:)
sign_in(author)
get "/post_localizations/#{author_post.id}.json"
expect(response.status).to eq(200)
json = response.parsed_body
expect(json["post_localizations"].length).to eq(1)
end
it "denies post authors from viewing localizations for others' posts" do
Fabricate(:post_localization, post: post_record, locale:)
sign_in(author)
get "/post_localizations/#{post_record.id}.json"
expect(response.status).to eq(403)
end
end
end
describe "#create_or_update" do
context "when localization does not exist" do
it "creates a new localization" do
expect {
post "/post_localizations/create_or_update.json",
params: {
post_id: post_record.id,
locale:,
raw:,
}
}.to change { PostLocalization.count }.by(1)
expect(response.status).to eq(201)
localization = PostLocalization.last
expect(localization).to have_attributes(
locale:,
raw:,
post_id: post_record.id,
post_version: post_record.version,
localizer_user_id: user.id,
)
end
end
context "when localization already exists" do
it "updates the existing localization" do
localization = Fabricate(:post_localization, post: post_record, locale:, raw: "古い翻訳")
new_user = Fabricate(:user, groups: [group])
sign_in(new_user)
expect {
post "/post_localizations/create_or_update.json",
params: {
post_id: post_record.id,
locale:,
raw:,
}
}.not_to change { PostLocalization.count }
expect(response.status).to eq(200)
localization.reload
expect(localization.raw).to eq(raw)
expect(localization.localizer_user_id).to eq(new_user.id)
end
end
it "returns forbidden if user is not in allowed group" do
group.remove(user)
post "/post_localizations/create_or_update.json",
params: {
post_id: post_record.id,
locale:,
raw:,
}
expect(response.status).to eq(403)
end
it "returns not found if post does not exist" do
post "/post_localizations/create_or_update.json", params: { post_id: -1, locale:, raw: }
expect(response.status).to eq(404)
end
end
describe "#update_locale" do
it "updates the original post locale without changing the topic locale" do
post_record.topic.update!(locale: "fr")
original_version = post_record.version
put "/post_localizations/#{post_record.id}/locale.json", params: { locale: "de" }
expect(response.status).to eq(200)
expect(response.parsed_body["locale"]).to eq("de")
expect(post_record.reload.locale).to eq("de")
expect(post_record.version).to eq(original_version)
expect(post_record.topic.reload.locale).to eq("fr")
end
it "returns forbidden when the user cannot localize the post" do
group.remove(user)
expect {
put "/post_localizations/#{post_record.id}/locale.json", params: { locale: "ja" }
}.not_to change { post_record.reload.locale }
expect(response.status).to eq(403)
end
it "rejects values that are not a single known locale" do
post_record.update!(locale: "en")
%w[not_a_locale en|ja].each do |invalid_locale|
expect {
put "/post_localizations/#{post_record.id}/locale.json",
params: {
locale: invalid_locale,
}
}.not_to change { post_record.reload.locale }
expect(response.status).to eq(400)
end
end
it "allows the original post locale to be cleared" do
post_record.update!(locale: "en")
put "/post_localizations/#{post_record.id}/locale.json", params: { locale: "" }
expect(response.status).to eq(200)
expect(response.parsed_body["locale"]).to be_nil
expect(post_record.reload.locale).to be_nil
end
end
describe "#destroy" do
it "destroys the localization" do
Fabricate(:post_localization, post: post_record, locale:)
expect {
delete "/post_localizations/destroy.json", params: { post_id: post_record.id, locale: }
}.to change { PostLocalization.count }.by(-1)
expect(response.status).to eq(204)
end
it "returns 404 if localization is missing" do
delete "/post_localizations/destroy.json", params: { post_id: post_record.id, locale: "nope" }
expect(response.status).to eq(404)
end
end
context "with author localization" do
fab!(:author, :user)
fab!(:author_post) { Fabricate(:post, user: author, version: 100) }
fab!(:other_user, :user)
before { group.remove(author) }
describe "#create_or_update for post authors" do
it "allows post author to create localization on their own post" do
sign_in(author)
SiteSetting.content_localization_allow_author_localization = false
expect {
post "/post_localizations/create_or_update.json",
params: {
post_id: author_post.id,
locale:,
raw:,
}
}.not_to change { PostLocalization.count }
SiteSetting.content_localization_allow_author_localization = true
expect {
post "/post_localizations/create_or_update.json",
params: {
post_id: author_post.id,
locale:,
raw:,
}
}.to change { PostLocalization.count }.by(1)
expect(response.status).to eq(201)
localization = PostLocalization.last
expect(localization.localizer_user_id).to eq(author.id)
end
it "denies post author from creating localization on others' posts" do
SiteSetting.content_localization_allow_author_localization = true
sign_in(author)
expect {
post "/post_localizations/create_or_update.json",
params: {
post_id: post_record.id,
locale:,
raw:,
}
}.not_to change { PostLocalization.count }
expect(response.status).to eq(403)
end
it "allows author to update their own localization" do
localization =
Fabricate(
:post_localization,
post: author_post,
locale:,
raw: "古い翻訳",
localizer_user_id: author.id,
)
sign_in(author)
SiteSetting.content_localization_allow_author_localization = false
expect {
post "/post_localizations/create_or_update.json",
params: {
post_id: author_post.id,
locale:,
raw:,
}
}.not_to change { localization.reload.raw }
SiteSetting.content_localization_allow_author_localization = true
post "/post_localizations/create_or_update.json",
params: {
post_id: author_post.id,
locale:,
raw:,
}
expect(response.status).to eq(200)
localization.reload
expect(localization.raw).to eq(raw)
end
end
describe "#destroy for post authors" do
it "allows author to delete their own localization" do
Fabricate(:post_localization, post: author_post, locale:, localizer_user_id: author.id)
sign_in(author)
SiteSetting.content_localization_allow_author_localization = false
expect {
delete "/post_localizations/destroy.json", params: { post_id: author_post.id, locale: }
}.not_to change { PostLocalization.count }
SiteSetting.content_localization_allow_author_localization = true
expect {
delete "/post_localizations/destroy.json", params: { post_id: author_post.id, locale: }
}.to change { PostLocalization.count }.by(-1)
expect(response.status).to eq(204)
end
end
it "allows users in allowed groups full access regardless of author setting" do
localization =
Fabricate(:post_localization, post: author_post, locale:, localizer_user_id: author.id)
sign_in(user)
SiteSetting.content_localization_allow_author_localization = false
expect {
post "/post_localizations/create_or_update.json",
params: {
post_id: author_post.id,
locale:,
raw: "1",
}
}.to change { localization.reload.raw }
SiteSetting.content_localization_allow_author_localization = true
expect {
post "/post_localizations/create_or_update.json",
params: {
post_id: author_post.id,
locale:,
raw: "2",
}
}.to change { localization.reload.raw }
end
end
end