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:
commit
d9f7e2bede
19 changed files with 138 additions and 11 deletions
|
@ -762,8 +762,7 @@ no: "No"
|
||||||
driveFilesCount: "Number of Drive files"
|
driveFilesCount: "Number of Drive files"
|
||||||
driveUsage: "Drive space usage"
|
driveUsage: "Drive space usage"
|
||||||
noCrawle: "Reject crawler indexing"
|
noCrawle: "Reject crawler indexing"
|
||||||
noCrawleDescription: "Ask search engines to not index your profile page, posts, Pages,
|
noCrawleDescription: "Ask external search engines to not index your content."
|
||||||
etc."
|
|
||||||
lockedAccountInfo: "Unless you set your post visiblity to \"Followers only\", your
|
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."
|
posts will be visible to anyone, even if you require followers to be manually approved."
|
||||||
alwaysMarkSensitive: "Mark as NSFW by default"
|
alwaysMarkSensitive: "Mark as NSFW by default"
|
||||||
|
@ -1139,6 +1138,8 @@ confirm: "Confirm"
|
||||||
importZip: "Import ZIP"
|
importZip: "Import ZIP"
|
||||||
exportZip: "Export ZIP"
|
exportZip: "Export ZIP"
|
||||||
emojiPackCreator: "Emoji pack creator"
|
emojiPackCreator: "Emoji pack creator"
|
||||||
|
indexable: "Indexable"
|
||||||
|
indexableDescription: "Allow built-in search to show your public posts"
|
||||||
languageForTranslation: "Post translation language"
|
languageForTranslation: "Post translation language"
|
||||||
detectPostLanguage: "Automatically detect the language and show a translate button for posts in foreign languages"
|
detectPostLanguage: "Automatically detect the language and show a translate button for posts in foreign languages"
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ mod m20230531_180824_drop_reversi;
|
||||||
mod m20230627_185451_index_note_url;
|
mod m20230627_185451_index_note_url;
|
||||||
mod m20230709_000510_move_antenna_to_cache;
|
mod m20230709_000510_move_antenna_to_cache;
|
||||||
mod m20230806_170616_fix_antenna_stream_ids;
|
mod m20230806_170616_fix_antenna_stream_ids;
|
||||||
|
mod m20230904_013244_is_indexable;
|
||||||
|
|
||||||
pub struct Migrator;
|
pub struct Migrator;
|
||||||
|
|
||||||
|
@ -17,6 +18,7 @@ impl MigratorTrait for Migrator {
|
||||||
Box::new(m20230627_185451_index_note_url::Migration),
|
Box::new(m20230627_185451_index_note_url::Migration),
|
||||||
Box::new(m20230709_000510_move_antenna_to_cache::Migration),
|
Box::new(m20230709_000510_move_antenna_to_cache::Migration),
|
||||||
Box::new(m20230806_170616_fix_antenna_stream_ids::Migration),
|
Box::new(m20230806_170616_fix_antenna_stream_ids::Migration),
|
||||||
|
Box::new(m20230904_013244_is_indexable::Migration),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
}
|
|
@ -71,6 +71,8 @@ pub struct Model {
|
||||||
pub also_known_as: Option<String>,
|
pub also_known_as: Option<String>,
|
||||||
#[sea_orm(column_name = "speakAsCat")]
|
#[sea_orm(column_name = "speakAsCat")]
|
||||||
pub speak_as_cat: bool,
|
pub speak_as_cat: bool,
|
||||||
|
#[sea_orm(column_name = "isIndexable")]
|
||||||
|
pub is_indexable: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
|
|
|
@ -75,6 +75,8 @@ pub struct Model {
|
||||||
pub moderation_note: String,
|
pub moderation_note: String,
|
||||||
#[sea_orm(column_name = "preventAiLearning")]
|
#[sea_orm(column_name = "preventAiLearning")]
|
||||||
pub prevent_ai_learning: bool,
|
pub prevent_ai_learning: bool,
|
||||||
|
#[sea_orm(column_name = "isIndexable")]
|
||||||
|
pub is_indexable: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
|
|
|
@ -167,6 +167,12 @@ export class UserProfile {
|
||||||
})
|
})
|
||||||
public noCrawle: boolean;
|
public noCrawle: boolean;
|
||||||
|
|
||||||
|
@Column("boolean", {
|
||||||
|
default: true,
|
||||||
|
comment: "Whether User is indexable.",
|
||||||
|
})
|
||||||
|
public isIndexable: boolean;
|
||||||
|
|
||||||
@Column("boolean", {
|
@Column("boolean", {
|
||||||
default: true,
|
default: true,
|
||||||
})
|
})
|
||||||
|
|
|
@ -265,6 +265,13 @@ export class User {
|
||||||
})
|
})
|
||||||
public driveCapacityOverrideMb: number | null;
|
public driveCapacityOverrideMb: number | null;
|
||||||
|
|
||||||
|
@Index()
|
||||||
|
@Column("boolean", {
|
||||||
|
default: true,
|
||||||
|
comment: "Whether the User is indexable.",
|
||||||
|
})
|
||||||
|
public isIndexable: boolean;
|
||||||
|
|
||||||
constructor(data: Partial<User>) {
|
constructor(data: Partial<User>) {
|
||||||
if (data == null) return;
|
if (data == null) return;
|
||||||
|
|
||||||
|
|
|
@ -454,6 +454,7 @@ export const UserRepository = db.getRepository(User).extend({
|
||||||
isModerator: user.isModerator || falsy,
|
isModerator: user.isModerator || falsy,
|
||||||
isBot: user.isBot || falsy,
|
isBot: user.isBot || falsy,
|
||||||
isLocked: user.isLocked,
|
isLocked: user.isLocked,
|
||||||
|
isIndexable: user.isIndexable,
|
||||||
isCat: user.isCat || falsy,
|
isCat: user.isCat || falsy,
|
||||||
speakAsCat: user.speakAsCat || falsy,
|
speakAsCat: user.speakAsCat || falsy,
|
||||||
instance: user.host
|
instance: user.host
|
||||||
|
|
|
@ -66,6 +66,11 @@ export const packedUserLiteSchema = {
|
||||||
nullable: false,
|
nullable: false,
|
||||||
optional: true,
|
optional: true,
|
||||||
},
|
},
|
||||||
|
isIndexable: {
|
||||||
|
type: "boolean",
|
||||||
|
nullable: false,
|
||||||
|
optional: true,
|
||||||
|
},
|
||||||
speakAsCat: {
|
speakAsCat: {
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
nullable: false,
|
nullable: false,
|
||||||
|
|
|
@ -205,10 +205,10 @@ export async function createPerson(
|
||||||
|
|
||||||
if (typeof person.followers === "string") {
|
if (typeof person.followers === "string") {
|
||||||
try {
|
try {
|
||||||
let data = await fetch(person.followers, {
|
const data = await fetch(person.followers, {
|
||||||
headers: { Accept: "application/json" },
|
headers: { Accept: "application/json" },
|
||||||
});
|
});
|
||||||
let json_data = JSON.parse(await data.text());
|
const json_data = JSON.parse(await data.text());
|
||||||
|
|
||||||
followersCount = json_data.totalItems;
|
followersCount = json_data.totalItems;
|
||||||
} catch {
|
} catch {
|
||||||
|
@ -220,10 +220,10 @@ export async function createPerson(
|
||||||
|
|
||||||
if (typeof person.following === "string") {
|
if (typeof person.following === "string") {
|
||||||
try {
|
try {
|
||||||
let data = await fetch(person.following, {
|
const data = await fetch(person.following, {
|
||||||
headers: { Accept: "application/json" },
|
headers: { Accept: "application/json" },
|
||||||
});
|
});
|
||||||
let json_data = JSON.parse(await data.text());
|
const json_data = JSON.parse(await data.text());
|
||||||
|
|
||||||
followingCount = json_data.totalItems;
|
followingCount = json_data.totalItems;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -235,10 +235,10 @@ export async function createPerson(
|
||||||
|
|
||||||
if (typeof person.outbox === "string") {
|
if (typeof person.outbox === "string") {
|
||||||
try {
|
try {
|
||||||
let data = await fetch(person.outbox, {
|
const data = await fetch(person.outbox, {
|
||||||
headers: { Accept: "application/json" },
|
headers: { Accept: "application/json" },
|
||||||
});
|
});
|
||||||
let json_data = JSON.parse(await data.text());
|
const json_data = JSON.parse(await data.text());
|
||||||
|
|
||||||
notesCount = json_data.totalItems;
|
notesCount = json_data.totalItems;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -302,6 +302,7 @@ export async function createPerson(
|
||||||
tags,
|
tags,
|
||||||
isBot,
|
isBot,
|
||||||
isCat: (person as any).isCat === true,
|
isCat: (person as any).isCat === true,
|
||||||
|
isIndexable: person.indexable,
|
||||||
}),
|
}),
|
||||||
)) as IRemoteUser;
|
)) as IRemoteUser;
|
||||||
|
|
||||||
|
@ -547,6 +548,7 @@ export async function updatePerson(
|
||||||
tags,
|
tags,
|
||||||
isBot: getApType(object) !== "Person",
|
isBot: getApType(object) !== "Person",
|
||||||
isCat: (person as any).isCat === true,
|
isCat: (person as any).isCat === true,
|
||||||
|
isIndexable: person.indexable,
|
||||||
isLocked: !!person.manuallyApprovesFollowers,
|
isLocked: !!person.manuallyApprovesFollowers,
|
||||||
movedToUri: person.movedTo || null,
|
movedToUri: person.movedTo || null,
|
||||||
alsoKnownAs: person.alsoKnownAs || null,
|
alsoKnownAs: person.alsoKnownAs || null,
|
||||||
|
|
|
@ -30,6 +30,7 @@ export const renderActivity = (x: any): IActivity | null => {
|
||||||
Emoji: "toot:Emoji",
|
Emoji: "toot:Emoji",
|
||||||
featured: "toot:featured",
|
featured: "toot:featured",
|
||||||
discoverable: "toot:discoverable",
|
discoverable: "toot:discoverable",
|
||||||
|
indexable: "toot:indexable",
|
||||||
// schema
|
// schema
|
||||||
schema: "http://schema.org#",
|
schema: "http://schema.org#",
|
||||||
PropertyValue: "schema:PropertyValue",
|
PropertyValue: "schema:PropertyValue",
|
||||||
|
|
|
@ -81,6 +81,7 @@ export async function renderPerson(user: ILocalUser) {
|
||||||
discoverable: !!user.isExplorable,
|
discoverable: !!user.isExplorable,
|
||||||
publicKey: renderKey(user, keypair, "#main-key"),
|
publicKey: renderKey(user, keypair, "#main-key"),
|
||||||
isCat: user.isCat,
|
isCat: user.isCat,
|
||||||
|
indexable: user.isIndexable,
|
||||||
attachment: attachment.length ? attachment : undefined,
|
attachment: attachment.length ? attachment : undefined,
|
||||||
} as any;
|
} as any;
|
||||||
|
|
||||||
|
|
|
@ -190,8 +190,9 @@ export interface IActor extends IObject {
|
||||||
movedTo?: string;
|
movedTo?: string;
|
||||||
alsoKnownAs?: string[];
|
alsoKnownAs?: string[];
|
||||||
discoverable?: boolean;
|
discoverable?: boolean;
|
||||||
|
indexable?: boolean;
|
||||||
inbox: string;
|
inbox: string;
|
||||||
sharedInbox?: string; // backward compatibility.. ig
|
sharedInbox?: string; // Backwards compatibility
|
||||||
publicKey?: {
|
publicKey?: {
|
||||||
id: string;
|
id: string;
|
||||||
publicKeyPem: string;
|
publicKeyPem: string;
|
||||||
|
|
|
@ -60,6 +60,7 @@ export default define(meta, paramDef, async (ps, me) => {
|
||||||
emailVerified: profile.emailVerified,
|
emailVerified: profile.emailVerified,
|
||||||
autoAcceptFollowed: profile.autoAcceptFollowed,
|
autoAcceptFollowed: profile.autoAcceptFollowed,
|
||||||
noCrawle: profile.noCrawle,
|
noCrawle: profile.noCrawle,
|
||||||
|
isIndexable: profile.isIndexable,
|
||||||
preventAiLearning: profile.preventAiLearning,
|
preventAiLearning: profile.preventAiLearning,
|
||||||
alwaysMarkNsfw: profile.alwaysMarkNsfw,
|
alwaysMarkNsfw: profile.alwaysMarkNsfw,
|
||||||
autoSensitive: profile.autoSensitive,
|
autoSensitive: profile.autoSensitive,
|
||||||
|
|
|
@ -120,6 +120,7 @@ export const paramDef = {
|
||||||
isBot: { type: "boolean" },
|
isBot: { type: "boolean" },
|
||||||
isCat: { type: "boolean" },
|
isCat: { type: "boolean" },
|
||||||
speakAsCat: { type: "boolean" },
|
speakAsCat: { type: "boolean" },
|
||||||
|
isIndexable: { type: "boolean" },
|
||||||
injectFeaturedNote: { type: "boolean" },
|
injectFeaturedNote: { type: "boolean" },
|
||||||
receiveAnnouncementEmail: { type: "boolean" },
|
receiveAnnouncementEmail: { type: "boolean" },
|
||||||
alwaysMarkNsfw: { type: "boolean" },
|
alwaysMarkNsfw: { type: "boolean" },
|
||||||
|
@ -206,6 +207,10 @@ export default define(meta, paramDef, async (ps, _user, token) => {
|
||||||
if (typeof ps.preventAiLearning === "boolean")
|
if (typeof ps.preventAiLearning === "boolean")
|
||||||
profileUpdates.preventAiLearning = ps.preventAiLearning;
|
profileUpdates.preventAiLearning = ps.preventAiLearning;
|
||||||
if (typeof ps.isCat === "boolean") updates.isCat = ps.isCat;
|
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.speakAsCat === "boolean") updates.speakAsCat = ps.speakAsCat;
|
||||||
if (typeof ps.injectFeaturedNote === "boolean")
|
if (typeof ps.injectFeaturedNote === "boolean")
|
||||||
profileUpdates.injectFeaturedNote = ps.injectFeaturedNote;
|
profileUpdates.injectFeaturedNote = ps.injectFeaturedNote;
|
||||||
|
|
|
@ -608,7 +608,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
throw new ApiError(meta.errors.noSuchNote);
|
throw new ApiError(meta.errors.noSuchNote);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (publishing) {
|
if (publishing && user.isIndexable) {
|
||||||
index(note, true);
|
index(note, true);
|
||||||
|
|
||||||
// Publish update event for the updated note details
|
// Publish update event for the updated note details
|
||||||
|
|
|
@ -165,6 +165,7 @@ export default async (
|
||||||
createdAt: User["createdAt"];
|
createdAt: User["createdAt"];
|
||||||
isBot: User["isBot"];
|
isBot: User["isBot"];
|
||||||
inbox?: User["inbox"];
|
inbox?: User["inbox"];
|
||||||
|
isIndexable?: User["isIndexable"];
|
||||||
},
|
},
|
||||||
data: Option,
|
data: Option,
|
||||||
silent = false,
|
silent = false,
|
||||||
|
@ -652,7 +653,9 @@ export default async (
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register to search database
|
// Register to search database
|
||||||
|
if (user.isIndexable) {
|
||||||
await index(note, false);
|
await index(note, false);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
async function renderNoteOrRenoteActivity(data: Option, note: Note) {
|
async function renderNoteOrRenoteActivity(data: Option, note: Note) {
|
||||||
|
|
|
@ -151,6 +151,7 @@ describe("ユーザー", () => {
|
||||||
carefulBot: user.carefulBot,
|
carefulBot: user.carefulBot,
|
||||||
autoAcceptFollowed: user.autoAcceptFollowed,
|
autoAcceptFollowed: user.autoAcceptFollowed,
|
||||||
noCrawle: user.noCrawle,
|
noCrawle: user.noCrawle,
|
||||||
|
isIndexable: user.isIndexable,
|
||||||
preventAiLearning: user.preventAiLearning,
|
preventAiLearning: user.preventAiLearning,
|
||||||
isExplorable: user.isExplorable,
|
isExplorable: user.isExplorable,
|
||||||
isDeleted: user.isDeleted,
|
isDeleted: user.isDeleted,
|
||||||
|
@ -529,6 +530,8 @@ describe("ユーザー", () => {
|
||||||
{ parameters: (): object => ({ autoAcceptFollowed: false }) },
|
{ parameters: (): object => ({ autoAcceptFollowed: false }) },
|
||||||
{ parameters: (): object => ({ noCrawle: true }) },
|
{ parameters: (): object => ({ noCrawle: true }) },
|
||||||
{ parameters: (): object => ({ noCrawle: false }) },
|
{ parameters: (): object => ({ noCrawle: false }) },
|
||||||
|
{ parameters: (): object => ({ isIndexable: true }) },
|
||||||
|
{ parameters: (): object => ({ isIndexable: false }) },
|
||||||
{ parameters: (): object => ({ preventAiLearning: false }) },
|
{ parameters: (): object => ({ preventAiLearning: false }) },
|
||||||
{ parameters: (): object => ({ preventAiLearning: true }) },
|
{ parameters: (): object => ({ preventAiLearning: true }) },
|
||||||
{ parameters: (): object => ({ isBot: true }) },
|
{ parameters: (): object => ({ isBot: true }) },
|
||||||
|
|
|
@ -52,6 +52,14 @@
|
||||||
i18n.ts.hideOnlineStatusDescription
|
i18n.ts.hideOnlineStatusDescription
|
||||||
}}</template>
|
}}</template>
|
||||||
</FormSwitch>
|
</FormSwitch>
|
||||||
|
<FormSwitch
|
||||||
|
v-model="isIndexable"
|
||||||
|
class="_formBlock"
|
||||||
|
@update:modelValue="save()"
|
||||||
|
>
|
||||||
|
{{ i18n.ts.indexable }}
|
||||||
|
<template #caption>{{ i18n.ts.indexableDescription }}</template>
|
||||||
|
</FormSwitch>
|
||||||
<FormSwitch
|
<FormSwitch
|
||||||
v-model="noCrawle"
|
v-model="noCrawle"
|
||||||
class="_formBlock"
|
class="_formBlock"
|
||||||
|
@ -155,6 +163,7 @@ import { definePageMetadata } from "@/scripts/page-metadata";
|
||||||
const isLocked = ref($i.isLocked);
|
const isLocked = ref($i.isLocked);
|
||||||
const autoAcceptFollowed = ref($i.autoAcceptFollowed);
|
const autoAcceptFollowed = ref($i.autoAcceptFollowed);
|
||||||
const noCrawle = ref($i.noCrawle);
|
const noCrawle = ref($i.noCrawle);
|
||||||
|
const isIndexable = ref($i.isIndexable);
|
||||||
const isExplorable = ref($i.isExplorable);
|
const isExplorable = ref($i.isExplorable);
|
||||||
const hideOnlineStatus = ref($i.hideOnlineStatus);
|
const hideOnlineStatus = ref($i.hideOnlineStatus);
|
||||||
const publicReactions = ref($i.publicReactions);
|
const publicReactions = ref($i.publicReactions);
|
||||||
|
@ -178,6 +187,7 @@ function save() {
|
||||||
isLocked: !!isLocked.value,
|
isLocked: !!isLocked.value,
|
||||||
autoAcceptFollowed: !!autoAcceptFollowed.value,
|
autoAcceptFollowed: !!autoAcceptFollowed.value,
|
||||||
noCrawle: !!noCrawle.value,
|
noCrawle: !!noCrawle.value,
|
||||||
|
isIndexable: !!isIndexable.value,
|
||||||
isExplorable: !!isExplorable.value,
|
isExplorable: !!isExplorable.value,
|
||||||
hideOnlineStatus: !!hideOnlineStatus.value,
|
hideOnlineStatus: !!hideOnlineStatus.value,
|
||||||
publicReactions: !!publicReactions.value,
|
publicReactions: !!publicReactions.value,
|
||||||
|
|
Loading…
Reference in a new issue