From b7a6ccfef916aac26bc2b4df8ba366ca75d0d979 Mon Sep 17 00:00:00 2001
From: Hazelnoot <acomputerdog@gmail.com>
Date: Mon, 9 Dec 2024 09:29:42 -0500
Subject: [PATCH 1/3] enable hideOnlineStatus by default for new users

---
 ...069260-alter_user_hideOnlineStatus_default_true.js | 11 +++++++++++
 packages/backend/src/models/User.ts                   |  4 ++--
 .../src/components/MkUserSetupDialog.Privacy.vue      |  2 +-
 3 files changed, 14 insertions(+), 3 deletions(-)
 create mode 100644 packages/backend/migration/1733754069260-alter_user_hideOnlineStatus_default_true.js

diff --git a/packages/backend/migration/1733754069260-alter_user_hideOnlineStatus_default_true.js b/packages/backend/migration/1733754069260-alter_user_hideOnlineStatus_default_true.js
new file mode 100644
index 0000000000..c0db48ceea
--- /dev/null
+++ b/packages/backend/migration/1733754069260-alter_user_hideOnlineStatus_default_true.js
@@ -0,0 +1,11 @@
+export class AlterUserHideOnlineStatusDefaultTrue1733754069260 {
+    name = 'AlterUserHideOnlineStatusDefaultTrue1733754069260'
+
+    async up(queryRunner) {
+			await queryRunner.query(`ALTER TABLE "user" ALTER COLUMN "hideOnlineStatus" SET DEFAULT true`);
+		}
+
+    async down(queryRunner) {
+				await queryRunner.query(`ALTER TABLE "user" ALTER COLUMN "hideOnlineStatus" SET DEFAULT false`);
+		}
+}
diff --git a/packages/backend/src/models/User.ts b/packages/backend/src/models/User.ts
index c7ecccf1cf..73a44de558 100644
--- a/packages/backend/src/models/User.ts
+++ b/packages/backend/src/models/User.ts
@@ -32,7 +32,7 @@ export class MiUser {
 	public lastActiveDate: Date | null;
 
 	@Column('boolean', {
-		default: false,
+		default: true,
 	})
 	public hideOnlineStatus: boolean;
 
@@ -160,7 +160,7 @@ export class MiUser {
 		length: 128, nullable: true,
 	})
 	public backgroundBlurhash: string | null;
-	
+
 	@Column('jsonb', {
 		default: [],
 	})
diff --git a/packages/frontend/src/components/MkUserSetupDialog.Privacy.vue b/packages/frontend/src/components/MkUserSetupDialog.Privacy.vue
index bc998d6158..fb4a2b1c78 100644
--- a/packages/frontend/src/components/MkUserSetupDialog.Privacy.vue
+++ b/packages/frontend/src/components/MkUserSetupDialog.Privacy.vue
@@ -44,7 +44,7 @@ import MkFolder from '@/components/MkFolder.vue';
 import { misskeyApi } from '@/scripts/misskey-api.js';
 
 const isLocked = ref(false);
-const hideOnlineStatus = ref(false);
+const hideOnlineStatus = ref(true);
 const noCrawle = ref(false);
 
 watch([isLocked, hideOnlineStatus, noCrawle], () => {
-- 
GitLab


From 5af843272515389cac0e9b6757fea052e9e842e7 Mon Sep 17 00:00:00 2001
From: Hazelnoot <acomputerdog@gmail.com>
Date: Mon, 9 Dec 2024 09:36:23 -0500
Subject: [PATCH 2/3] federate hideOnlineStatus

---
 packages/backend/src/core/activitypub/ApRendererService.ts    | 1 +
 packages/backend/src/core/activitypub/misc/contexts.ts        | 1 +
 .../backend/src/core/activitypub/models/ApPersonService.ts    | 4 ++++
 packages/backend/src/core/activitypub/type.ts                 | 1 +
 4 files changed, 7 insertions(+)

diff --git a/packages/backend/src/core/activitypub/ApRendererService.ts b/packages/backend/src/core/activitypub/ApRendererService.ts
index 89e5217285..ff909778e8 100644
--- a/packages/backend/src/core/activitypub/ApRendererService.ts
+++ b/packages/backend/src/core/activitypub/ApRendererService.ts
@@ -528,6 +528,7 @@ export class ApRendererService {
 			discoverable: user.isExplorable,
 			publicKey: this.renderKey(user, keypair, '#main-key'),
 			isCat: user.isCat,
+			hideOnlineStatus: user.hideOnlineStatus,
 			noindex: user.noindex,
 			indexable: !user.noindex,
 			speakAsCat: user.speakAsCat,
diff --git a/packages/backend/src/core/activitypub/misc/contexts.ts b/packages/backend/src/core/activitypub/misc/contexts.ts
index da75fc1d42..1c4239502e 100644
--- a/packages/backend/src/core/activitypub/misc/contexts.ts
+++ b/packages/backend/src/core/activitypub/misc/contexts.ts
@@ -564,6 +564,7 @@ const extension_context_definition = {
 	speakAsCat: 'firefish:speakAsCat',
 	// Sharkey
 	sharkey: 'https://joinsharkey.org/ns#',
+	hideOnlineStatus: 'sharkey:hideOnlineStatus',
 	backgroundUrl: 'sharkey:backgroundUrl',
 	listenbrainz: 'sharkey:listenbrainz',
 	// vcard
diff --git a/packages/backend/src/core/activitypub/models/ApPersonService.ts b/packages/backend/src/core/activitypub/models/ApPersonService.ts
index 598486cd84..2cb31b1f09 100644
--- a/packages/backend/src/core/activitypub/models/ApPersonService.ts
+++ b/packages/backend/src/core/activitypub/models/ApPersonService.ts
@@ -389,6 +389,8 @@ export class ApPersonService implements OnModuleInit {
 					movedToUri: person.movedTo,
 					movedAt: person.movedTo ? new Date() : null,
 					alsoKnownAs: person.alsoKnownAs,
+					// We use "!== false" to handle incorrect types, missing / null values, and "default to true" logic.
+					hideOnlineStatus: person.hideOnlineStatus !== false,
 					isExplorable: person.discoverable,
 					username: person.preferredUsername,
 					approved: true,
@@ -585,6 +587,8 @@ export class ApPersonService implements OnModuleInit {
 			isLocked: person.manuallyApprovesFollowers,
 			movedToUri: person.movedTo ?? null,
 			alsoKnownAs: person.alsoKnownAs ?? null,
+			// We use "!== false" to handle incorrect types, missing / null values, and "default to true" logic.
+			hideOnlineStatus: person.hideOnlineStatus !== false,
 			isExplorable: person.discoverable,
 			...(await this.resolveAvatarAndBanner(exist, person.icon, person.image, person.backgroundUrl).catch(() => ({}))),
 		} as Partial<MiRemoteUser> & Pick<MiRemoteUser, 'isBot' | 'isCat' | 'speakAsCat' | 'isLocked' | 'movedToUri' | 'alsoKnownAs' | 'isExplorable'>;
diff --git a/packages/backend/src/core/activitypub/type.ts b/packages/backend/src/core/activitypub/type.ts
index c9e20e0168..a0a5ae00dc 100644
--- a/packages/backend/src/core/activitypub/type.ts
+++ b/packages/backend/src/core/activitypub/type.ts
@@ -215,6 +215,7 @@ export interface IActor extends IObject {
 	};
 	'vcard:bday'?: string;
 	'vcard:Address'?: string;
+	hideOnlineStatus?: boolean;
 	noindex?: boolean;
 	listenbrainz?: string;
 	backgroundUrl?: string;
-- 
GitLab


From 00c4637b1186fa78a3955e8b5103c05c2e2b4431 Mon Sep 17 00:00:00 2001
From: Hazelnoot <acomputerdog@gmail.com>
Date: Thu, 12 Dec 2024 07:34:14 -0500
Subject: [PATCH 3/3] federate profile when `hideOnlineStatus` changes

---
 packages/backend/src/server/api/endpoints/i/update.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts
index 8e61b8f784..c640caee75 100644
--- a/packages/backend/src/server/api/endpoints/i/update.ts
+++ b/packages/backend/src/server/api/endpoints/i/update.ts
@@ -587,7 +587,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 	// these two methods need to be kept in sync with
 	// `ApRendererService.renderPerson`
 	private userNeedsPublishing(oldUser: MiLocalUser, newUser: Partial<MiUser>): boolean {
-		for (const field of ['avatarId', 'bannerId', 'backgroundId', 'isBot', 'username', 'name', 'isLocked', 'isExplorable', 'isCat', 'noindex', 'speakAsCat', 'movedToUri', 'alsoKnownAs'] as (keyof MiUser)[]) {
+		for (const field of ['avatarId', 'bannerId', 'backgroundId', 'isBot', 'username', 'name', 'isLocked', 'isExplorable', 'isCat', 'noindex', 'speakAsCat', 'movedToUri', 'alsoKnownAs', 'hideOnlineStatus'] as (keyof MiUser)[]) {
 			if ((field in newUser) && oldUser[field] !== newUser[field]) {
 				return true;
 			}
-- 
GitLab