FEATURE: Show user cards for inactive users (#21387)

It used to return 404 which made the user card render and then quickly disappear.
This commit is contained in:
Bianca Nenciu 2023-05-15 20:45:26 +02:00 committed by GitHub
parent e25468b2ca
commit 78022e7a5f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 116 additions and 13 deletions

View File

@ -28,7 +28,7 @@
{{else}}
<div class="card-row first-row">
<div class="user-card-avatar">
{{#if this.user.profile_hidden}}
{{#if this.contentHidden}}
<span class="card-huge-avatar">{{bound-avatar
this.user
"huge"
@ -57,7 +57,7 @@
{{this.newUser}}
{{if this.nameFirst 'full-name' 'username'}}"
>
{{#if this.user.profile_hidden}}
{{#if this.contentHidden}}
<span
id="discourse-user-card-title"
class="name-username-wrapper"
@ -193,6 +193,12 @@
<span>{{i18n "user.profile_hidden"}}</span>
</div>
</div>
{{else if this.user.inactive}}
<div class="card-row second-row">
<div class="inactive-user">
<span>{{i18n "user.inactive_user"}}</span>
</div>
</div>
{{/if}}
{{#if this.isSuspendedOrHasBio}}
@ -292,7 +298,7 @@
{{/if}}
<div class="card-row metadata-row">
{{#unless this.user.profile_hidden}}
{{#unless this.contentHidden}}
<div class="metadata">
{{#if this.user.last_posted_at}}
<h3><span class="desc">{{i18n "last_post"}}</span>

View File

@ -178,6 +178,11 @@ export default Component.extend(CardContentsBase, CanCheckEmails, CleansUp, {
return `group-${primaryGroup}`;
},
@discourseComputed("user.profile_hidden", "user.inactive")
contentHidden(profileHidden, inactive) {
return profileHidden || inactive;
},
_showCallback(username, $target) {
this._positionCard($target);
this.setProperties({ visible: true, loading: true });

View File

@ -1,3 +1,4 @@
import I18n from "I18n";
import {
acceptance,
exists,
@ -98,3 +99,68 @@ acceptance("User Card - User Status", function (needs) {
assert.notOk(exists(".user-card h3.user-status"));
});
});
acceptance("User Card - Hidden Profile", function (needs) {
needs.user();
needs.pretender((server, helper) => {
server.get("/u/eviltrout/card.json", () =>
helper.response({
user: {
id: 6,
username: "eviltrout",
name: null,
avatar_template: "/letter_avatar_proxy/v4/letter/f/8edcca/{size}.png",
profile_hidden: true,
title: null,
primary_group_name: null,
},
})
);
});
test("it shows less information", async function (assert) {
await visit("/t/this-is-a-test-topic/9");
await click('a[data-user-card="eviltrout"]');
assert.equal(
query(".user-card .name-username-wrapper").innerText,
"eviltrout"
);
assert.equal(
query(".user-card .profile-hidden").innerText,
I18n.t("user.profile_hidden")
);
});
});
acceptance("User Card - Inactive user", function (needs) {
needs.user();
needs.pretender((server, helper) => {
server.get("/u/eviltrout/card.json", () =>
helper.response({
user: {
id: 6,
username: "eviltrout",
name: null,
avatar_template: "/letter_avatar_proxy/v4/letter/f/8edcca/{size}.png",
inactive: true,
},
})
);
});
test("it shows less information", async function (assert) {
await visit("/t/this-is-a-test-topic/9");
await click('a[data-user-card="eviltrout"]');
assert.equal(
query(".user-card .name-username-wrapper").innerText,
"eviltrout"
);
assert.equal(
query(".user-card .inactive-user").innerText,
I18n.t("user.inactive_user")
);
});
});

View File

@ -171,7 +171,8 @@ $avatar_margin: -50px; // negative margin makes avatars extend above cards
font-weight: bold;
}
}
.profile-hidden {
.profile-hidden,
.inactive-user {
font-size: var(--font-up-1);
margin-top: 0.5em;
}

View File

@ -110,12 +110,15 @@ class UsersController < ApplicationController
@user =
fetch_user_from_params(
include_inactive:
current_user.try(:staff?) || (current_user && SiteSetting.show_inactive_accounts),
include_inactive: current_user&.staff? || for_card || SiteSetting.show_inactive_accounts,
)
user_serializer = nil
if guardian.can_see_profile?(@user)
if !current_user&.staff? && !@user.active?
user_serializer = InactiveUserSerializer.new(@user, scope: guardian, root: "user")
elsif !guardian.can_see_profile?(@user)
user_serializer = HiddenProfileSerializer.new(@user, scope: guardian, root: "user")
else
serializer_class = for_card ? UserCardSerializer : UserSerializer
user_serializer = serializer_class.new(@user, scope: guardian, root: "user")
@ -125,8 +128,6 @@ class UsersController < ApplicationController
topic_id => Post.secured(guardian).where(topic_id: topic_id, user_id: @user.id).count,
}
end
else
user_serializer = HiddenProfileSerializer.new(@user, scope: guardian, root: "user")
end
track_visit_to_user_profile if !params[:skip_track_visit] && (@user != current_user)

View File

@ -0,0 +1,9 @@
# frozen_string_literal: true
class InactiveUserSerializer < BasicUserSerializer
attributes :inactive
def inactive
!object.active?
end
end

View File

@ -1124,6 +1124,7 @@ en:
warning: "Are you sure you want to clear your featured topic?"
use_current_timezone: "Use Current Timezone"
profile_hidden: "This user's public profile is hidden."
inactive_user: "This user is no longer active."
expand_profile: "Expand"
sr_expand_profile: "Expand profile details"
collapse_profile: "Collapse"

View File

@ -4592,13 +4592,13 @@ RSpec.describe UsersController do
before { sign_in(user1) }
it "works correctly" do
get "/u/#{user1.username}/card.json"
get "/u/#{user.username}/card.json"
expect(response.status).to eq(200)
json = response.parsed_body
expect(json["user"]["associated_accounts"]).to eq(nil) # Not serialized in card
expect(json["user"]["username"]).to eq(user1.username)
expect(json["user"]["username"]).to eq(user.username)
end
it "returns not found when the username doesn't exist" do
@ -4606,9 +4606,23 @@ RSpec.describe UsersController do
expect(response).not_to be_successful
end
it "returns partial response when inactive user" do
user.update!(active: false)
get "/u/#{user.username}/card.json"
expect(response).to be_successful
expect(response.parsed_body["user"]["inactive"]).to eq(true)
end
it "returns partial response when hidden users" do
user.user_option.update!(hide_profile_and_presence: true)
get "/u/#{user.username}/card.json"
expect(response).to be_successful
expect(response.parsed_body["user"]["profile_hidden"]).to eq(true)
end
it "raises an error on invalid access" do
Guardian.any_instance.expects(:can_see?).with(user1).returns(false)
get "/u/#{user1.username}/card.json"
Guardian.any_instance.expects(:can_see?).with(user).returns(false)
get "/u/#{user.username}/card.json"
expect(response).to be_forbidden
end
end