Merge branch 'feat/isIndexable' into 'develop'

feat:  `indexable` User property

Co-authored-by: Namekuji <nmkj@waah.day>

Closes #10610

See merge request firefish/firefish!10585
This commit is contained in:
Kainoa Kanter 2023-09-04 02:34:04 +00:00
commit d9f7e2bede
19 changed files with 138 additions and 11 deletions

View file

@ -762,8 +762,7 @@ no: "No"
driveFilesCount: "Number of Drive files"
driveUsage: "Drive space usage"
noCrawle: "Reject crawler indexing"
noCrawleDescription: "Ask search engines to not index your profile page, posts, Pages,
etc."
noCrawleDescription: "Ask external search engines to not index your content."
lockedAccountInfo: "Unless you set your post visiblity to \"Followers only\", your
posts will be visible to anyone, even if you require followers to be manually approved."
alwaysMarkSensitive: "Mark as NSFW by default"
@ -1139,6 +1138,8 @@ confirm: "Confirm"
importZip: "Import ZIP"
exportZip: "Export ZIP"
emojiPackCreator: "Emoji pack creator"
indexable: "Indexable"
indexableDescription: "Allow built-in search to show your public posts"
languageForTranslation: "Post translation language"
detectPostLanguage: "Automatically detect the language and show a translate button for posts in foreign languages"

View file

@ -6,6 +6,7 @@ mod m20230531_180824_drop_reversi;
mod m20230627_185451_index_note_url;
mod m20230709_000510_move_antenna_to_cache;
mod m20230806_170616_fix_antenna_stream_ids;
mod m20230904_013244_is_indexable;
pub struct Migrator;
@ -17,6 +18,7 @@ impl MigratorTrait for Migrator {
Box::new(m20230627_185451_index_note_url::Migration),
Box::new(m20230709_000510_move_antenna_to_cache::Migration),
Box::new(m20230806_170616_fix_antenna_stream_ids::Migration),
Box::new(m20230904_013244_is_indexable::Migration),
]
}
}

View file

@ -0,0 +1,74 @@
use sea_orm_migration::prelude::*;
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.alter_table(
Table::alter()
.table(User::Table)
.add_column(
ColumnDef::new(User::IsIndexable)
.boolean()
.not_null()
.default(true),
)
.to_owned(),
)
.await?;
manager
.alter_table(
Table::alter()
.table(UserProfile::Table)
.add_column(
ColumnDef::new(UserProfile::IsIndexable)
.boolean()
.not_null()
.default(true),
)
.to_owned(),
)
.await?;
Ok(())
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.alter_table(
Table::alter()
.table(User::Table)
.drop_column(User::IsIndexable)
.to_owned(),
)
.await?;
manager
.alter_table(
Table::alter()
.table(UserProfile::Table)
.drop_column(UserProfile::IsIndexable)
.to_owned(),
)
.await?;
Ok(())
}
}
/// Learn more at https://docs.rs/sea-query#iden
#[derive(Iden)]
enum User {
Table,
#[iden = "isIndexable"]
IsIndexable,
}
#[derive(Iden)]
enum UserProfile {
Table,
#[iden = "isIndexable"]
IsIndexable,
}

View file

@ -71,6 +71,8 @@ pub struct Model {
pub also_known_as: Option<String>,
#[sea_orm(column_name = "speakAsCat")]
pub speak_as_cat: bool,
#[sea_orm(column_name = "isIndexable")]
pub is_indexable: bool,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]

View file

@ -75,6 +75,8 @@ pub struct Model {
pub moderation_note: String,
#[sea_orm(column_name = "preventAiLearning")]
pub prevent_ai_learning: bool,
#[sea_orm(column_name = "isIndexable")]
pub is_indexable: bool,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]

View file

@ -167,6 +167,12 @@ export class UserProfile {
})
public noCrawle: boolean;
@Column("boolean", {
default: true,
comment: "Whether User is indexable.",
})
public isIndexable: boolean;
@Column("boolean", {
default: true,
})

View file

@ -265,6 +265,13 @@ export class User {
})
public driveCapacityOverrideMb: number | null;
@Index()
@Column("boolean", {
default: true,
comment: "Whether the User is indexable.",
})
public isIndexable: boolean;
constructor(data: Partial<User>) {
if (data == null) return;

View file

@ -454,6 +454,7 @@ export const UserRepository = db.getRepository(User).extend({
isModerator: user.isModerator || falsy,
isBot: user.isBot || falsy,
isLocked: user.isLocked,
isIndexable: user.isIndexable,
isCat: user.isCat || falsy,
speakAsCat: user.speakAsCat || falsy,
instance: user.host

View file

@ -66,6 +66,11 @@ export const packedUserLiteSchema = {
nullable: false,
optional: true,
},
isIndexable: {
type: "boolean",
nullable: false,
optional: true,
},
speakAsCat: {
type: "boolean",
nullable: false,

View file

@ -205,10 +205,10 @@ export async function createPerson(
if (typeof person.followers === "string") {
try {
let data = await fetch(person.followers, {
const data = await fetch(person.followers, {
headers: { Accept: "application/json" },
});
let json_data = JSON.parse(await data.text());
const json_data = JSON.parse(await data.text());
followersCount = json_data.totalItems;
} catch {
@ -220,10 +220,10 @@ export async function createPerson(
if (typeof person.following === "string") {
try {
let data = await fetch(person.following, {
const data = await fetch(person.following, {
headers: { Accept: "application/json" },
});
let json_data = JSON.parse(await data.text());
const json_data = JSON.parse(await data.text());
followingCount = json_data.totalItems;
} catch (e) {
@ -235,10 +235,10 @@ export async function createPerson(
if (typeof person.outbox === "string") {
try {
let data = await fetch(person.outbox, {
const data = await fetch(person.outbox, {
headers: { Accept: "application/json" },
});
let json_data = JSON.parse(await data.text());
const json_data = JSON.parse(await data.text());
notesCount = json_data.totalItems;
} catch (e) {
@ -302,6 +302,7 @@ export async function createPerson(
tags,
isBot,
isCat: (person as any).isCat === true,
isIndexable: person.indexable,
}),
)) as IRemoteUser;
@ -547,6 +548,7 @@ export async function updatePerson(
tags,
isBot: getApType(object) !== "Person",
isCat: (person as any).isCat === true,
isIndexable: person.indexable,
isLocked: !!person.manuallyApprovesFollowers,
movedToUri: person.movedTo || null,
alsoKnownAs: person.alsoKnownAs || null,

View file

@ -30,6 +30,7 @@ export const renderActivity = (x: any): IActivity | null => {
Emoji: "toot:Emoji",
featured: "toot:featured",
discoverable: "toot:discoverable",
indexable: "toot:indexable",
// schema
schema: "http://schema.org#",
PropertyValue: "schema:PropertyValue",

View file

@ -81,6 +81,7 @@ export async function renderPerson(user: ILocalUser) {
discoverable: !!user.isExplorable,
publicKey: renderKey(user, keypair, "#main-key"),
isCat: user.isCat,
indexable: user.isIndexable,
attachment: attachment.length ? attachment : undefined,
} as any;

View file

@ -190,8 +190,9 @@ export interface IActor extends IObject {
movedTo?: string;
alsoKnownAs?: string[];
discoverable?: boolean;
indexable?: boolean;
inbox: string;
sharedInbox?: string; // backward compatibility.. ig
sharedInbox?: string; // Backwards compatibility
publicKey?: {
id: string;
publicKeyPem: string;

View file

@ -60,6 +60,7 @@ export default define(meta, paramDef, async (ps, me) => {
emailVerified: profile.emailVerified,
autoAcceptFollowed: profile.autoAcceptFollowed,
noCrawle: profile.noCrawle,
isIndexable: profile.isIndexable,
preventAiLearning: profile.preventAiLearning,
alwaysMarkNsfw: profile.alwaysMarkNsfw,
autoSensitive: profile.autoSensitive,

View file

@ -120,6 +120,7 @@ export const paramDef = {
isBot: { type: "boolean" },
isCat: { type: "boolean" },
speakAsCat: { type: "boolean" },
isIndexable: { type: "boolean" },
injectFeaturedNote: { type: "boolean" },
receiveAnnouncementEmail: { type: "boolean" },
alwaysMarkNsfw: { type: "boolean" },
@ -206,6 +207,10 @@ export default define(meta, paramDef, async (ps, _user, token) => {
if (typeof ps.preventAiLearning === "boolean")
profileUpdates.preventAiLearning = ps.preventAiLearning;
if (typeof ps.isCat === "boolean") updates.isCat = ps.isCat;
if (typeof ps.isIndexable === "boolean") {
updates.isIndexable = ps.isIndexable;
profileUpdates.isIndexable = ps.isIndexable;
}
if (typeof ps.speakAsCat === "boolean") updates.speakAsCat = ps.speakAsCat;
if (typeof ps.injectFeaturedNote === "boolean")
profileUpdates.injectFeaturedNote = ps.injectFeaturedNote;

View file

@ -608,7 +608,7 @@ export default define(meta, paramDef, async (ps, user) => {
throw new ApiError(meta.errors.noSuchNote);
}
if (publishing) {
if (publishing && user.isIndexable) {
index(note, true);
// Publish update event for the updated note details

View file

@ -165,6 +165,7 @@ export default async (
createdAt: User["createdAt"];
isBot: User["isBot"];
inbox?: User["inbox"];
isIndexable?: User["isIndexable"];
},
data: Option,
silent = false,
@ -652,7 +653,9 @@ export default async (
}
// Register to search database
await index(note, false);
if (user.isIndexable) {
await index(note, false);
}
});
async function renderNoteOrRenoteActivity(data: Option, note: Note) {

View file

@ -151,6 +151,7 @@ describe("ユーザー", () => {
carefulBot: user.carefulBot,
autoAcceptFollowed: user.autoAcceptFollowed,
noCrawle: user.noCrawle,
isIndexable: user.isIndexable,
preventAiLearning: user.preventAiLearning,
isExplorable: user.isExplorable,
isDeleted: user.isDeleted,
@ -529,6 +530,8 @@ describe("ユーザー", () => {
{ parameters: (): object => ({ autoAcceptFollowed: false }) },
{ parameters: (): object => ({ noCrawle: true }) },
{ parameters: (): object => ({ noCrawle: false }) },
{ parameters: (): object => ({ isIndexable: true }) },
{ parameters: (): object => ({ isIndexable: false }) },
{ parameters: (): object => ({ preventAiLearning: false }) },
{ parameters: (): object => ({ preventAiLearning: true }) },
{ parameters: (): object => ({ isBot: true }) },

View file

@ -52,6 +52,14 @@
i18n.ts.hideOnlineStatusDescription
}}</template>
</FormSwitch>
<FormSwitch
v-model="isIndexable"
class="_formBlock"
@update:modelValue="save()"
>
{{ i18n.ts.indexable }}
<template #caption>{{ i18n.ts.indexableDescription }}</template>
</FormSwitch>
<FormSwitch
v-model="noCrawle"
class="_formBlock"
@ -155,6 +163,7 @@ import { definePageMetadata } from "@/scripts/page-metadata";
const isLocked = ref($i.isLocked);
const autoAcceptFollowed = ref($i.autoAcceptFollowed);
const noCrawle = ref($i.noCrawle);
const isIndexable = ref($i.isIndexable);
const isExplorable = ref($i.isExplorable);
const hideOnlineStatus = ref($i.hideOnlineStatus);
const publicReactions = ref($i.publicReactions);
@ -178,6 +187,7 @@ function save() {
isLocked: !!isLocked.value,
autoAcceptFollowed: !!autoAcceptFollowed.value,
noCrawle: !!noCrawle.value,
isIndexable: !!isIndexable.value,
isExplorable: !!isExplorable.value,
hideOnlineStatus: !!hideOnlineStatus.value,
publicReactions: !!publicReactions.value,