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"
|
||||
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"
|
||||
|
||||
|
|
|
@ -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),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>,
|
||||
#[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)]
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -66,6 +66,11 @@ export const packedUserLiteSchema = {
|
|||
nullable: false,
|
||||
optional: true,
|
||||
},
|
||||
isIndexable: {
|
||||
type: "boolean",
|
||||
nullable: false,
|
||||
optional: true,
|
||||
},
|
||||
speakAsCat: {
|
||||
type: "boolean",
|
||||
nullable: false,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
if (user.isIndexable) {
|
||||
await index(note, false);
|
||||
}
|
||||
});
|
||||
|
||||
async function renderNoteOrRenoteActivity(data: Option, note: Note) {
|
||||
|
|
|
@ -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 }) },
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue