FIX: handle correctly the case when several subscribers call trackStatus() on the user model (#17497)

This commit is contained in:
Andrei Prigorshnev 2022-07-26 15:28:26 +04:00 committed by GitHub
parent 17e733b6a8
commit 517e2f7dc4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 45 additions and 14 deletions

View File

@ -1180,23 +1180,37 @@ User.reopenClass(Singleton, {
// user status tracking
User.reopen(Evented, {
_subscribersCount: 0,
_clearStatusTimerId: null,
// always call stopTrackingStatus() when done with a user
trackStatus() {
this.addObserver("status", this, "_statusChanged");
if (this._subscribersCount === 0) {
this.addObserver("status", this, "_statusChanged");
this.appEvents.on("user-status:changed", this, this._updateStatus);
this.appEvents.on("user-status:changed", this, this._updateStatus);
if (this.status && this.status.ends_at) {
this._scheduleStatusClearing(this.status.ends_at);
if (this.status && this.status.ends_at) {
this._scheduleStatusClearing(this.status.ends_at);
}
}
this._subscribersCount++;
},
stopTrackingStatus() {
this.removeObserver("status", this, "_statusChanged");
this.appEvents.off("user-status:changed", this, this._updateStatus);
this._unscheduleStatusClearing();
if (this._subscribersCount === 0) {
return;
}
if (this._subscribersCount === 1) {
// the last subscriber is unsubscribing
this.removeObserver("status", this, "_statusChanged");
this.appEvents.off("user-status:changed", this, this._updateStatus);
this._unscheduleStatusClearing();
}
this._subscribersCount--;
},
_statusChanged(sender, key) {

View File

@ -5,13 +5,7 @@ import PreloadStore from "discourse/lib/preload-store";
import sinon from "sinon";
import { settled } from "@ember/test-helpers";
module("Unit | Model | user", function (hooks) {
hooks.afterEach(function () {
if (this.clock) {
this.clock.restore();
}
});
module("Unit | Model | user", function () {
test("staff", function (assert) {
let user = User.create({ id: 1, username: "eviltrout" });
@ -112,6 +106,29 @@ module("Unit | Model | user", function (hooks) {
assert.ok(spyMomentGuess.notCalled);
});
test("subsequent calls to trackStatus and stopTrackingStatus increase and decrease subscribers counter", function (assert) {
const user = User.create();
assert.equal(user._subscribersCount, 0);
user.trackStatus();
assert.equal(user._subscribersCount, 1);
user.trackStatus();
assert.equal(user._subscribersCount, 2);
user.stopTrackingStatus();
assert.equal(user._subscribersCount, 1);
user.stopTrackingStatus();
assert.equal(user._subscribersCount, 0);
});
test("attempt to stop tracking status if status wasn't tracked doesn't throw", function (assert) {
const user = User.create();
user.stopTrackingStatus();
assert.ok(true);
});
test("clears statuses of several users correctly when receiving status updates via appEvents", function (assert) {
const status1 = {
description: "user1 status",