mirror of
https://iceshrimp.dev/limepotato/jormungandr-bite.git
synced 2024-11-22 09:57:29 -07:00
Remove support for ads
This commit is contained in:
parent
a3fb1f19e0
commit
5a2ca61f26
33 changed files with 76 additions and 794 deletions
|
@ -119,11 +119,11 @@
|
||||||
- [DragonflyDB](https://dragonflydb.io/) support as a Redis alternative
|
- [DragonflyDB](https://dragonflydb.io/) support as a Redis alternative
|
||||||
- Link verification
|
- Link verification
|
||||||
- Importing posts from other Misskey/Mastodon/Pleroma/Akkoma instances
|
- Importing posts from other Misskey/Mastodon/Pleroma/Akkoma instances
|
||||||
|
- Removed ability to serve ads
|
||||||
|
|
||||||
## Implemented (remote)
|
## Implemented (remote)
|
||||||
|
|
||||||
- MissV: [fix Misskey Forkbomb](https://code.vtopia.live/Vtopia/MissV/commit/40b23c070bd4adbb3188c73546c6c625138fb3c1)
|
- MissV: [fix Misskey Forkbomb](https://code.vtopia.live/Vtopia/MissV/commit/40b23c070bd4adbb3188c73546c6c625138fb3c1)
|
||||||
- [Make showing ads optional](https://github.com/misskey-dev/misskey/pull/8996)
|
|
||||||
- [Tapping avatar in mobile opens account modal](https://github.com/misskey-dev/misskey/pull/9056)
|
- [Tapping avatar in mobile opens account modal](https://github.com/misskey-dev/misskey/pull/9056)
|
||||||
- [OAuth bearer token authentication](https://github.com/misskey-dev/misskey/pull/9021)
|
- [OAuth bearer token authentication](https://github.com/misskey-dev/misskey/pull/9021)
|
||||||
- [Styled Repair Tools](https://github.com/misskey-dev/misskey/pull/8956)
|
- [Styled Repair Tools](https://github.com/misskey-dev/misskey/pull/8956)
|
||||||
|
|
|
@ -3,6 +3,7 @@ pub use sea_orm_migration::prelude::*;
|
||||||
mod m20230531_180824_drop_reversi;
|
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 m20230726_213530_drop_ads;
|
||||||
|
|
||||||
pub struct Migrator;
|
pub struct Migrator;
|
||||||
|
|
||||||
|
@ -13,6 +14,7 @@ impl MigratorTrait for Migrator {
|
||||||
Box::new(m20230531_180824_drop_reversi::Migration),
|
Box::new(m20230531_180824_drop_reversi::Migration),
|
||||||
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(m20230726_213530_drop_ads::Migration),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
use sea_orm::entity::prelude::*;
|
||||||
|
use sea_orm::Schema;
|
||||||
|
|
||||||
|
use sea_orm_migration::{
|
||||||
|
prelude::*,
|
||||||
|
sea_orm::{DbBackend, Statement},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(DeriveMigrationName)]
|
||||||
|
pub struct Migration;
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl MigrationTrait for Migration {
|
||||||
|
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
if manager.get_database_backend() == DbBackend::Sqlite {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let db = manager.get_connection();
|
||||||
|
db.query_one(Statement::from_string(
|
||||||
|
DbBackend::Postgres,
|
||||||
|
Table::drop()
|
||||||
|
.table(Entity)
|
||||||
|
.if_exists()
|
||||||
|
.to_string(PostgresQueryBuilder),
|
||||||
|
))
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
if manager.get_database_backend() == DbBackend::Sqlite {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let db = manager.get_connection();
|
||||||
|
let builder = db.get_database_backend();
|
||||||
|
let schema = Schema::new(builder);
|
||||||
|
|
||||||
|
db.execute(builder.build(&schema.create_table_from_entity(Entity)))
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
|
||||||
|
#[sea_orm(table_name = "ad")]
|
||||||
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id: String,
|
||||||
|
#[sea_orm(column_name = "createdAt")]
|
||||||
|
pub created_at: DateTimeWithTimeZone,
|
||||||
|
#[sea_orm(column_name = "expiresAt")]
|
||||||
|
pub expires_at: DateTimeWithTimeZone,
|
||||||
|
pub place: String,
|
||||||
|
pub priority: String,
|
||||||
|
pub url: String,
|
||||||
|
#[sea_orm(column_name = "imageUrl")]
|
||||||
|
pub image_url: String,
|
||||||
|
pub memo: String,
|
||||||
|
pub ratio: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
|
pub enum Relation {}
|
||||||
|
|
||||||
|
impl ActiveModelBehavior for ActiveModel {}
|
|
@ -4,7 +4,6 @@ pub mod prelude;
|
||||||
|
|
||||||
pub mod abuse_user_report;
|
pub mod abuse_user_report;
|
||||||
pub mod access_token;
|
pub mod access_token;
|
||||||
pub mod ad;
|
|
||||||
pub mod announcement;
|
pub mod announcement;
|
||||||
pub mod announcement_read;
|
pub mod announcement_read;
|
||||||
pub mod antenna;
|
pub mod antenna;
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
|
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
|
|
||||||
#[sea_orm(table_name = "ad")]
|
|
||||||
pub struct Model {
|
|
||||||
#[sea_orm(primary_key, auto_increment = false)]
|
|
||||||
pub id: String,
|
|
||||||
#[sea_orm(column_name = "createdAt")]
|
|
||||||
pub created_at: DateTimeWithTimeZone,
|
|
||||||
#[sea_orm(column_name = "expiresAt")]
|
|
||||||
pub expires_at: DateTimeWithTimeZone,
|
|
||||||
pub place: String,
|
|
||||||
pub priority: String,
|
|
||||||
pub url: String,
|
|
||||||
#[sea_orm(column_name = "imageUrl")]
|
|
||||||
pub image_url: String,
|
|
||||||
pub memo: String,
|
|
||||||
pub ratio: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
|
||||||
pub enum Relation {}
|
|
||||||
|
|
||||||
impl ActiveModelBehavior for ActiveModel {}
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
pub use super::abuse_user_report::Entity as AbuseUserReport;
|
pub use super::abuse_user_report::Entity as AbuseUserReport;
|
||||||
pub use super::access_token::Entity as AccessToken;
|
pub use super::access_token::Entity as AccessToken;
|
||||||
pub use super::ad::Entity as Ad;
|
|
||||||
pub use super::announcement::Entity as Announcement;
|
pub use super::announcement::Entity as Announcement;
|
||||||
pub use super::announcement_read::Entity as AnnouncementRead;
|
pub use super::announcement_read::Entity as AnnouncementRead;
|
||||||
pub use super::antenna::Entity as Antenna;
|
pub use super::antenna::Entity as Antenna;
|
||||||
|
|
|
@ -66,7 +66,6 @@ import { Channel } from "@/models/entities/channel.js";
|
||||||
import { ChannelFollowing } from "@/models/entities/channel-following.js";
|
import { ChannelFollowing } from "@/models/entities/channel-following.js";
|
||||||
import { ChannelNotePining } from "@/models/entities/channel-note-pining.js";
|
import { ChannelNotePining } from "@/models/entities/channel-note-pining.js";
|
||||||
import { RegistryItem } from "@/models/entities/registry-item.js";
|
import { RegistryItem } from "@/models/entities/registry-item.js";
|
||||||
import { Ad } from "@/models/entities/ad.js";
|
|
||||||
import { PasswordResetRequest } from "@/models/entities/password-reset-request.js";
|
import { PasswordResetRequest } from "@/models/entities/password-reset-request.js";
|
||||||
import { UserPending } from "@/models/entities/user-pending.js";
|
import { UserPending } from "@/models/entities/user-pending.js";
|
||||||
import { Webhook } from "@/models/entities/webhook.js";
|
import { Webhook } from "@/models/entities/webhook.js";
|
||||||
|
@ -175,7 +174,6 @@ export const entities = [
|
||||||
ChannelFollowing,
|
ChannelFollowing,
|
||||||
ChannelNotePining,
|
ChannelNotePining,
|
||||||
RegistryItem,
|
RegistryItem,
|
||||||
Ad,
|
|
||||||
PasswordResetRequest,
|
PasswordResetRequest,
|
||||||
UserPending,
|
UserPending,
|
||||||
Webhook,
|
Webhook,
|
||||||
|
|
|
@ -1,65 +0,0 @@
|
||||||
import { Entity, Index, Column, PrimaryColumn } from "typeorm";
|
|
||||||
import { id } from "../id.js";
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
export class Ad {
|
|
||||||
@PrimaryColumn(id())
|
|
||||||
public id: string;
|
|
||||||
|
|
||||||
@Index()
|
|
||||||
@Column("timestamp with time zone", {
|
|
||||||
comment: "The created date of the Ad.",
|
|
||||||
})
|
|
||||||
public createdAt: Date;
|
|
||||||
|
|
||||||
@Index()
|
|
||||||
@Column("timestamp with time zone", {
|
|
||||||
comment: "The expired date of the Ad.",
|
|
||||||
})
|
|
||||||
public expiresAt: Date;
|
|
||||||
|
|
||||||
@Column("varchar", {
|
|
||||||
length: 32,
|
|
||||||
nullable: false,
|
|
||||||
})
|
|
||||||
public place: string;
|
|
||||||
|
|
||||||
// 今は使われていないが将来的に活用される可能性はある
|
|
||||||
@Column("varchar", {
|
|
||||||
length: 32,
|
|
||||||
nullable: false,
|
|
||||||
})
|
|
||||||
public priority: string;
|
|
||||||
|
|
||||||
@Column("integer", {
|
|
||||||
default: 1,
|
|
||||||
nullable: false,
|
|
||||||
})
|
|
||||||
public ratio: number;
|
|
||||||
|
|
||||||
@Column("varchar", {
|
|
||||||
length: 1024,
|
|
||||||
nullable: false,
|
|
||||||
})
|
|
||||||
public url: string;
|
|
||||||
|
|
||||||
@Column("varchar", {
|
|
||||||
length: 1024,
|
|
||||||
nullable: false,
|
|
||||||
})
|
|
||||||
public imageUrl: string;
|
|
||||||
|
|
||||||
@Column("varchar", {
|
|
||||||
length: 8192,
|
|
||||||
nullable: false,
|
|
||||||
})
|
|
||||||
public memo: string;
|
|
||||||
|
|
||||||
constructor(data: Partial<Ad>) {
|
|
||||||
if (data == null) return;
|
|
||||||
|
|
||||||
for (const [k, v] of Object.entries(data)) {
|
|
||||||
(this as any)[k] = v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -60,7 +60,6 @@ import { MutedNote } from "./entities/muted-note.js";
|
||||||
import { ChannelFollowing } from "./entities/channel-following.js";
|
import { ChannelFollowing } from "./entities/channel-following.js";
|
||||||
import { ChannelNotePining } from "./entities/channel-note-pining.js";
|
import { ChannelNotePining } from "./entities/channel-note-pining.js";
|
||||||
import { RegistryItem } from "./entities/registry-item.js";
|
import { RegistryItem } from "./entities/registry-item.js";
|
||||||
import { Ad } from "./entities/ad.js";
|
|
||||||
import { PasswordResetRequest } from "./entities/password-reset-request.js";
|
import { PasswordResetRequest } from "./entities/password-reset-request.js";
|
||||||
import { UserPending } from "./entities/user-pending.js";
|
import { UserPending } from "./entities/user-pending.js";
|
||||||
import { InstanceRepository } from "./repositories/instance.js";
|
import { InstanceRepository } from "./repositories/instance.js";
|
||||||
|
@ -131,5 +130,4 @@ export const ChannelFollowings = db.getRepository(ChannelFollowing);
|
||||||
export const ChannelNotePinings = db.getRepository(ChannelNotePining);
|
export const ChannelNotePinings = db.getRepository(ChannelNotePining);
|
||||||
export const RegistryItems = db.getRepository(RegistryItem);
|
export const RegistryItems = db.getRepository(RegistryItem);
|
||||||
export const Webhooks = db.getRepository(Webhook);
|
export const Webhooks = db.getRepository(Webhook);
|
||||||
export const Ads = db.getRepository(Ad);
|
|
||||||
export const PasswordResetRequests = db.getRepository(PasswordResetRequest);
|
export const PasswordResetRequests = db.getRepository(PasswordResetRequest);
|
||||||
|
|
|
@ -5,10 +5,6 @@ import * as ep___admin_abuseUserReports from "./endpoints/admin/abuse-user-repor
|
||||||
import * as ep___admin_accounts_create from "./endpoints/admin/accounts/create.js";
|
import * as ep___admin_accounts_create from "./endpoints/admin/accounts/create.js";
|
||||||
import * as ep___admin_accounts_delete from "./endpoints/admin/accounts/delete.js";
|
import * as ep___admin_accounts_delete from "./endpoints/admin/accounts/delete.js";
|
||||||
import * as ep___admin_accounts_hosted from "./endpoints/admin/accounts/hosted.js";
|
import * as ep___admin_accounts_hosted from "./endpoints/admin/accounts/hosted.js";
|
||||||
import * as ep___admin_ad_create from "./endpoints/admin/ad/create.js";
|
|
||||||
import * as ep___admin_ad_delete from "./endpoints/admin/ad/delete.js";
|
|
||||||
import * as ep___admin_ad_list from "./endpoints/admin/ad/list.js";
|
|
||||||
import * as ep___admin_ad_update from "./endpoints/admin/ad/update.js";
|
|
||||||
import * as ep___admin_announcements_create from "./endpoints/admin/announcements/create.js";
|
import * as ep___admin_announcements_create from "./endpoints/admin/announcements/create.js";
|
||||||
import * as ep___admin_announcements_delete from "./endpoints/admin/announcements/delete.js";
|
import * as ep___admin_announcements_delete from "./endpoints/admin/announcements/delete.js";
|
||||||
import * as ep___admin_announcements_list from "./endpoints/admin/announcements/list.js";
|
import * as ep___admin_announcements_list from "./endpoints/admin/announcements/list.js";
|
||||||
|
@ -351,10 +347,6 @@ const eps = [
|
||||||
["admin/accounts/create", ep___admin_accounts_create],
|
["admin/accounts/create", ep___admin_accounts_create],
|
||||||
["admin/accounts/delete", ep___admin_accounts_delete],
|
["admin/accounts/delete", ep___admin_accounts_delete],
|
||||||
["admin/accounts/hosted", ep___admin_accounts_hosted],
|
["admin/accounts/hosted", ep___admin_accounts_hosted],
|
||||||
["admin/ad/create", ep___admin_ad_create],
|
|
||||||
["admin/ad/delete", ep___admin_ad_delete],
|
|
||||||
["admin/ad/list", ep___admin_ad_list],
|
|
||||||
["admin/ad/update", ep___admin_ad_update],
|
|
||||||
["admin/announcements/create", ep___admin_announcements_create],
|
["admin/announcements/create", ep___admin_announcements_create],
|
||||||
["admin/announcements/delete", ep___admin_announcements_delete],
|
["admin/announcements/delete", ep___admin_announcements_delete],
|
||||||
["admin/announcements/list", ep___admin_announcements_list],
|
["admin/announcements/list", ep___admin_announcements_list],
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
import define from "../../../define.js";
|
|
||||||
import { Ads } from "@/models/index.js";
|
|
||||||
import { genId } from "@/misc/gen-id.js";
|
|
||||||
|
|
||||||
export const meta = {
|
|
||||||
tags: ["admin"],
|
|
||||||
|
|
||||||
requireCredential: true,
|
|
||||||
requireModerator: true,
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
export const paramDef = {
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
url: { type: "string", minLength: 1 },
|
|
||||||
memo: { type: "string" },
|
|
||||||
place: { type: "string" },
|
|
||||||
priority: { type: "string" },
|
|
||||||
ratio: { type: "integer" },
|
|
||||||
expiresAt: { type: "integer" },
|
|
||||||
imageUrl: { type: "string", minLength: 1 },
|
|
||||||
},
|
|
||||||
required: [
|
|
||||||
"url",
|
|
||||||
"memo",
|
|
||||||
"place",
|
|
||||||
"priority",
|
|
||||||
"ratio",
|
|
||||||
"expiresAt",
|
|
||||||
"imageUrl",
|
|
||||||
],
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
export default define(meta, paramDef, async (ps) => {
|
|
||||||
await Ads.insert({
|
|
||||||
id: genId(),
|
|
||||||
createdAt: new Date(),
|
|
||||||
expiresAt: new Date(ps.expiresAt),
|
|
||||||
url: ps.url,
|
|
||||||
imageUrl: ps.imageUrl,
|
|
||||||
priority: ps.priority,
|
|
||||||
ratio: ps.ratio,
|
|
||||||
place: ps.place,
|
|
||||||
memo: ps.memo,
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,34 +0,0 @@
|
||||||
import define from "../../../define.js";
|
|
||||||
import { Ads } from "@/models/index.js";
|
|
||||||
import { ApiError } from "../../../error.js";
|
|
||||||
|
|
||||||
export const meta = {
|
|
||||||
tags: ["admin"],
|
|
||||||
|
|
||||||
requireCredential: true,
|
|
||||||
requireModerator: true,
|
|
||||||
|
|
||||||
errors: {
|
|
||||||
noSuchAd: {
|
|
||||||
message: "No such ad.",
|
|
||||||
code: "NO_SUCH_AD",
|
|
||||||
id: "ccac9863-3a03-416e-b899-8a64041118b1",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
export const paramDef = {
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
id: { type: "string", format: "misskey:id" },
|
|
||||||
},
|
|
||||||
required: ["id"],
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
export default define(meta, paramDef, async (ps, me) => {
|
|
||||||
const ad = await Ads.findOneBy({ id: ps.id });
|
|
||||||
|
|
||||||
if (ad == null) throw new ApiError(meta.errors.noSuchAd);
|
|
||||||
|
|
||||||
await Ads.delete(ad.id);
|
|
||||||
});
|
|
|
@ -1,32 +0,0 @@
|
||||||
import define from "../../../define.js";
|
|
||||||
import { Ads } from "@/models/index.js";
|
|
||||||
import { makePaginationQuery } from "../../../common/make-pagination-query.js";
|
|
||||||
|
|
||||||
export const meta = {
|
|
||||||
tags: ["admin"],
|
|
||||||
|
|
||||||
requireCredential: true,
|
|
||||||
requireModerator: true,
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
export const paramDef = {
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
limit: { type: "integer", minimum: 1, maximum: 100, default: 10 },
|
|
||||||
sinceId: { type: "string", format: "misskey:id" },
|
|
||||||
untilId: { type: "string", format: "misskey:id" },
|
|
||||||
},
|
|
||||||
required: [],
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
export default define(meta, paramDef, async (ps) => {
|
|
||||||
const query = makePaginationQuery(
|
|
||||||
Ads.createQueryBuilder("ad"),
|
|
||||||
ps.sinceId,
|
|
||||||
ps.untilId,
|
|
||||||
).andWhere("ad.expiresAt > :now", { now: new Date() });
|
|
||||||
|
|
||||||
const ads = await query.take(ps.limit).getMany();
|
|
||||||
|
|
||||||
return ads;
|
|
||||||
});
|
|
|
@ -1,58 +0,0 @@
|
||||||
import define from "../../../define.js";
|
|
||||||
import { Ads } from "@/models/index.js";
|
|
||||||
import { ApiError } from "../../../error.js";
|
|
||||||
|
|
||||||
export const meta = {
|
|
||||||
tags: ["admin"],
|
|
||||||
|
|
||||||
requireCredential: true,
|
|
||||||
requireModerator: true,
|
|
||||||
|
|
||||||
errors: {
|
|
||||||
noSuchAd: {
|
|
||||||
message: "No such ad.",
|
|
||||||
code: "NO_SUCH_AD",
|
|
||||||
id: "b7aa1727-1354-47bc-a182-3a9c3973d300",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
export const paramDef = {
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
id: { type: "string", format: "misskey:id" },
|
|
||||||
memo: { type: "string" },
|
|
||||||
url: { type: "string", minLength: 1 },
|
|
||||||
imageUrl: { type: "string", minLength: 1 },
|
|
||||||
place: { type: "string" },
|
|
||||||
priority: { type: "string" },
|
|
||||||
ratio: { type: "integer" },
|
|
||||||
expiresAt: { type: "integer" },
|
|
||||||
},
|
|
||||||
required: [
|
|
||||||
"id",
|
|
||||||
"memo",
|
|
||||||
"url",
|
|
||||||
"imageUrl",
|
|
||||||
"place",
|
|
||||||
"priority",
|
|
||||||
"ratio",
|
|
||||||
"expiresAt",
|
|
||||||
],
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
export default define(meta, paramDef, async (ps, me) => {
|
|
||||||
const ad = await Ads.findOneBy({ id: ps.id });
|
|
||||||
|
|
||||||
if (ad == null) throw new ApiError(meta.errors.noSuchAd);
|
|
||||||
|
|
||||||
await Ads.update(ad.id, {
|
|
||||||
url: ps.url,
|
|
||||||
place: ps.place,
|
|
||||||
priority: ps.priority,
|
|
||||||
ratio: ps.ratio,
|
|
||||||
memo: ps.memo,
|
|
||||||
imageUrl: ps.imageUrl,
|
|
||||||
expiresAt: new Date(ps.expiresAt),
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -136,35 +136,6 @@ export const meta = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ads: {
|
|
||||||
type: "array",
|
|
||||||
optional: false,
|
|
||||||
nullable: false,
|
|
||||||
items: {
|
|
||||||
type: "object",
|
|
||||||
optional: false,
|
|
||||||
nullable: false,
|
|
||||||
properties: {
|
|
||||||
place: {
|
|
||||||
type: "string",
|
|
||||||
optional: false,
|
|
||||||
nullable: false,
|
|
||||||
},
|
|
||||||
url: {
|
|
||||||
type: "string",
|
|
||||||
optional: false,
|
|
||||||
nullable: false,
|
|
||||||
format: "url",
|
|
||||||
},
|
|
||||||
imageUrl: {
|
|
||||||
type: "string",
|
|
||||||
optional: false,
|
|
||||||
nullable: false,
|
|
||||||
format: "url",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
enableEmail: {
|
enableEmail: {
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
optional: false,
|
optional: false,
|
||||||
|
|
|
@ -2,7 +2,7 @@ import JSON5 from "json5";
|
||||||
import { IsNull, MoreThan } from "typeorm";
|
import { IsNull, MoreThan } from "typeorm";
|
||||||
import config from "@/config/index.js";
|
import config from "@/config/index.js";
|
||||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||||
import { Ads, Emojis, Users } from "@/models/index.js";
|
import { Emojis, Users } from "@/models/index.js";
|
||||||
import { MAX_NOTE_TEXT_LENGTH, MAX_CAPTION_TEXT_LENGTH } from "@/const.js";
|
import { MAX_NOTE_TEXT_LENGTH, MAX_CAPTION_TEXT_LENGTH } from "@/const.js";
|
||||||
import define from "../define.js";
|
import define from "../define.js";
|
||||||
|
|
||||||
|
@ -228,35 +228,6 @@ export const meta = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ads: {
|
|
||||||
type: "array",
|
|
||||||
optional: false,
|
|
||||||
nullable: false,
|
|
||||||
items: {
|
|
||||||
type: "object",
|
|
||||||
optional: false,
|
|
||||||
nullable: false,
|
|
||||||
properties: {
|
|
||||||
place: {
|
|
||||||
type: "string",
|
|
||||||
optional: false,
|
|
||||||
nullable: false,
|
|
||||||
},
|
|
||||||
url: {
|
|
||||||
type: "string",
|
|
||||||
optional: false,
|
|
||||||
nullable: false,
|
|
||||||
format: "url",
|
|
||||||
},
|
|
||||||
imageUrl: {
|
|
||||||
type: "string",
|
|
||||||
optional: false,
|
|
||||||
nullable: false,
|
|
||||||
format: "url",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
requireSetup: {
|
requireSetup: {
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
optional: false,
|
optional: false,
|
||||||
|
@ -423,12 +394,6 @@ export default define(meta, paramDef, async (ps, me) => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const ads = await Ads.find({
|
|
||||||
where: {
|
|
||||||
expiresAt: MoreThan(new Date()),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const response: any = {
|
const response: any = {
|
||||||
maintainerName: instance.maintainerName,
|
maintainerName: instance.maintainerName,
|
||||||
maintainerEmail: instance.maintainerEmail,
|
maintainerEmail: instance.maintainerEmail,
|
||||||
|
@ -475,16 +440,7 @@ export default define(meta, paramDef, async (ps, me) => {
|
||||||
defaultDarkTheme: instance.defaultDarkTheme
|
defaultDarkTheme: instance.defaultDarkTheme
|
||||||
? JSON.stringify(JSON5.parse(instance.defaultDarkTheme))
|
? JSON.stringify(JSON5.parse(instance.defaultDarkTheme))
|
||||||
: null,
|
: null,
|
||||||
ads:
|
|
||||||
instance.privateMode && !me
|
|
||||||
? []
|
|
||||||
: ads.map((ad) => ({
|
|
||||||
id: ad.id,
|
|
||||||
url: ad.url,
|
|
||||||
place: ad.place,
|
|
||||||
ratio: ad.ratio,
|
|
||||||
imageUrl: ad.imageUrl,
|
|
||||||
})),
|
|
||||||
enableEmail: instance.enableEmail,
|
enableEmail: instance.enableEmail,
|
||||||
|
|
||||||
enableTwitterIntegration: instance.enableTwitterIntegration,
|
enableTwitterIntegration: instance.enableTwitterIntegration,
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
import { TransitionGroup, defineComponent, h } from "vue";
|
import { TransitionGroup, defineComponent, h } from "vue";
|
||||||
import MkAd from "@/components/global/MkAd.vue";
|
|
||||||
import { i18n } from "@/i18n";
|
import { i18n } from "@/i18n";
|
||||||
import { defaultStore } from "@/store";
|
import { defaultStore } from "@/store";
|
||||||
|
|
||||||
|
@ -27,12 +26,7 @@ export default defineComponent({
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: false,
|
required: false,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
}
|
||||||
ad: {
|
|
||||||
type: Boolean,
|
|
||||||
required: false,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
|
||||||
setup(props, { slots, expose }) {
|
setup(props, { slots, expose }) {
|
||||||
|
@ -91,18 +85,7 @@ export default defineComponent({
|
||||||
|
|
||||||
return [el, separator];
|
return [el, separator];
|
||||||
} else {
|
} else {
|
||||||
if (props.ad && item._shouldInsertAd_) {
|
return el;
|
||||||
return [
|
|
||||||
h(MkAd, {
|
|
||||||
class: "a", // advertiseの意(ブロッカー対策)
|
|
||||||
key: item.id + ":ad",
|
|
||||||
prefer: ["inline", "inline-big"],
|
|
||||||
}),
|
|
||||||
el,
|
|
||||||
];
|
|
||||||
} else {
|
|
||||||
return el;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
:direction="pagination.reversed ? 'up' : 'down'"
|
:direction="pagination.reversed ? 'up' : 'down'"
|
||||||
:reversed="pagination.reversed"
|
:reversed="pagination.reversed"
|
||||||
:no-gap="noGap"
|
:no-gap="noGap"
|
||||||
:ad="true"
|
|
||||||
class="notes"
|
class="notes"
|
||||||
>
|
>
|
||||||
<XNote
|
<XNote
|
||||||
|
|
|
@ -1,222 +0,0 @@
|
||||||
<template>
|
|
||||||
<div
|
|
||||||
v-for="chosenItem in chosen"
|
|
||||||
v-if="chosen && chosen.length > 0 && defaultStore.state.showAds"
|
|
||||||
class="qiivuoyo"
|
|
||||||
>
|
|
||||||
<div v-if="!showMenu" class="main" :class="chosenItem.place">
|
|
||||||
<a :href="chosenItem.url" target="_blank">
|
|
||||||
<img :src="chosenItem.imageUrl" />
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div v-else-if="chosen && defaultStore.state.showAds" class="qiivuoyo">
|
|
||||||
<div v-if="!showMenu" class="main" :class="chosen.place">
|
|
||||||
<a :href="chosen.url" target="_blank">
|
|
||||||
<img :src="chosen.imageUrl" />
|
|
||||||
<button class="_button menu" @click.prevent.stop="toggleMenu">
|
|
||||||
<span class="ph-info ph-bold ph-lg info-circle"></span>
|
|
||||||
</button>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div v-else class="menu">
|
|
||||||
<div class="body">
|
|
||||||
<div>Ads by {{ host }}</div>
|
|
||||||
<!--<MkButton class="button" primary>{{ i18n.ts._ad.like }}</MkButton>-->
|
|
||||||
<MkButton
|
|
||||||
v-if="chosen.ratio !== 0"
|
|
||||||
class="button"
|
|
||||||
@click="reduceFrequency"
|
|
||||||
>{{ i18n.ts._ad.reduceFrequencyOfThisAd }}</MkButton
|
|
||||||
>
|
|
||||||
<button class="_textButton" @click="toggleMenu">
|
|
||||||
{{ i18n.ts._ad.back }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div v-else></div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { ref } from "vue";
|
|
||||||
import { instance } from "@/instance";
|
|
||||||
import { host } from "@/config";
|
|
||||||
import MkButton from "@/components/MkButton.vue";
|
|
||||||
import { defaultStore } from "@/store";
|
|
||||||
import * as os from "@/os";
|
|
||||||
import { i18n } from "@/i18n";
|
|
||||||
|
|
||||||
type Ad = (typeof instance)["ads"][number];
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
prefer: string[];
|
|
||||||
specify?: Ad;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const showMenu = ref(false);
|
|
||||||
const toggleMenu = (): void => {
|
|
||||||
showMenu.value = !showMenu.value;
|
|
||||||
};
|
|
||||||
|
|
||||||
const choseAd = (): Ad | null => {
|
|
||||||
if (props.specify) {
|
|
||||||
return props.specify;
|
|
||||||
}
|
|
||||||
|
|
||||||
const allAds = instance.ads.map((ad) =>
|
|
||||||
defaultStore.state.mutedAds.includes(ad.id)
|
|
||||||
? {
|
|
||||||
...ad,
|
|
||||||
ratio: 0,
|
|
||||||
}
|
|
||||||
: ad,
|
|
||||||
);
|
|
||||||
|
|
||||||
let ads = allAds.filter((ad) => props.prefer.includes(ad.place));
|
|
||||||
|
|
||||||
if (ads.length === 0) {
|
|
||||||
ads = allAds.filter((ad) => ad.place === "square");
|
|
||||||
}
|
|
||||||
|
|
||||||
const lowPriorityAds = ads.filter((ad) => ad.ratio === 0);
|
|
||||||
const widgetAds = ads.filter((ad) => ad.place === "widget");
|
|
||||||
ads = ads.filter((ad) => ad.ratio !== 0);
|
|
||||||
|
|
||||||
if (widgetAds.length !== 0) {
|
|
||||||
return widgetAds;
|
|
||||||
} else if (ads.length === 0) {
|
|
||||||
if (lowPriorityAds.length !== 0) {
|
|
||||||
return lowPriorityAds[
|
|
||||||
Math.floor(Math.random() * lowPriorityAds.length)
|
|
||||||
];
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const totalFactor = ads.reduce((a, b) => a + b.ratio, 0);
|
|
||||||
const r = Math.random() * totalFactor;
|
|
||||||
|
|
||||||
let stackedFactor = 0;
|
|
||||||
for (const ad of ads) {
|
|
||||||
if (r >= stackedFactor && r <= stackedFactor + ad.ratio) {
|
|
||||||
return ad;
|
|
||||||
} else {
|
|
||||||
stackedFactor += ad.ratio;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
const chosen = ref(choseAd());
|
|
||||||
|
|
||||||
function reduceFrequency(): void {
|
|
||||||
if (chosen.value == null) return;
|
|
||||||
if (defaultStore.state.mutedAds.includes(chosen.value.id)) return;
|
|
||||||
defaultStore.push("mutedAds", chosen.value.id);
|
|
||||||
os.success();
|
|
||||||
chosen.value = choseAd();
|
|
||||||
showMenu.value = false;
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.qiivuoyo {
|
|
||||||
background-size: auto auto;
|
|
||||||
background-image: repeating-linear-gradient(
|
|
||||||
45deg,
|
|
||||||
transparent,
|
|
||||||
transparent 8px,
|
|
||||||
var(--ad) 8px,
|
|
||||||
var(--ad) 14px
|
|
||||||
);
|
|
||||||
|
|
||||||
> .main {
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
> a {
|
|
||||||
display: inline-block;
|
|
||||||
position: relative;
|
|
||||||
vertical-align: bottom;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
> img {
|
|
||||||
filter: contrast(120%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> img {
|
|
||||||
display: block;
|
|
||||||
object-fit: contain;
|
|
||||||
margin: auto;
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .menu {
|
|
||||||
position: absolute;
|
|
||||||
top: 1px;
|
|
||||||
right: 1px;
|
|
||||||
|
|
||||||
> .info-circle {
|
|
||||||
border: 3px solid var(--panel);
|
|
||||||
border-radius: 50%;
|
|
||||||
background: var(--panel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.widget {
|
|
||||||
> a,
|
|
||||||
> a > img {
|
|
||||||
max-width: min(300px, 100%);
|
|
||||||
max-height: 300px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.inline {
|
|
||||||
padding: 8px;
|
|
||||||
|
|
||||||
> a,
|
|
||||||
> a > img {
|
|
||||||
max-width: min(600px, 100%);
|
|
||||||
max-height: 80px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.inline-big {
|
|
||||||
padding: 8px;
|
|
||||||
|
|
||||||
> a,
|
|
||||||
> a > img {
|
|
||||||
max-width: min(600px, 100%);
|
|
||||||
max-height: 250px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.vertical {
|
|
||||||
> a,
|
|
||||||
> a > img {
|
|
||||||
max-width: min(100px, 100%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .menu {
|
|
||||||
padding: 8px;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
> .body {
|
|
||||||
padding: 8px;
|
|
||||||
margin: 0 auto;
|
|
||||||
max-width: 400px;
|
|
||||||
border: solid 1px var(--divider);
|
|
||||||
|
|
||||||
> .button {
|
|
||||||
margin: 8px auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -13,7 +13,6 @@ import I18n from "./global/i18n";
|
||||||
import RouterView from "./global/RouterView.vue";
|
import RouterView from "./global/RouterView.vue";
|
||||||
import MkLoading from "./global/MkLoading.vue";
|
import MkLoading from "./global/MkLoading.vue";
|
||||||
import MkError from "./global/MkError.vue";
|
import MkError from "./global/MkError.vue";
|
||||||
import MkAd from "./global/MkAd.vue";
|
|
||||||
import MkPageHeader from "./global/MkPageHeader.vue";
|
import MkPageHeader from "./global/MkPageHeader.vue";
|
||||||
import MkSpacer from "./global/MkSpacer.vue";
|
import MkSpacer from "./global/MkSpacer.vue";
|
||||||
import MkStickyContainer from "./global/MkStickyContainer.vue";
|
import MkStickyContainer from "./global/MkStickyContainer.vue";
|
||||||
|
@ -32,7 +31,6 @@ export default function (app: App) {
|
||||||
app.component("MkUrl", MkUrl);
|
app.component("MkUrl", MkUrl);
|
||||||
app.component("MkLoading", MkLoading);
|
app.component("MkLoading", MkLoading);
|
||||||
app.component("MkError", MkError);
|
app.component("MkError", MkError);
|
||||||
app.component("MkAd", MkAd);
|
|
||||||
app.component("MkPageHeader", MkPageHeader);
|
app.component("MkPageHeader", MkPageHeader);
|
||||||
app.component("MkSpacer", MkSpacer);
|
app.component("MkSpacer", MkSpacer);
|
||||||
app.component("MkStickyContainer", MkStickyContainer);
|
app.component("MkStickyContainer", MkStickyContainer);
|
||||||
|
@ -53,7 +51,6 @@ declare module "@vue/runtime-core" {
|
||||||
MkUrl: typeof MkUrl;
|
MkUrl: typeof MkUrl;
|
||||||
MkLoading: typeof MkLoading;
|
MkLoading: typeof MkLoading;
|
||||||
MkError: typeof MkError;
|
MkError: typeof MkError;
|
||||||
MkAd: typeof MkAd;
|
|
||||||
MkPageHeader: typeof MkPageHeader;
|
MkPageHeader: typeof MkPageHeader;
|
||||||
MkSpacer: typeof MkSpacer;
|
MkSpacer: typeof MkSpacer;
|
||||||
MkStickyContainer: typeof MkStickyContainer;
|
MkStickyContainer: typeof MkStickyContainer;
|
||||||
|
|
|
@ -218,12 +218,6 @@ const menuDef = $computed(() => [
|
||||||
to: "/admin/announcements",
|
to: "/admin/announcements",
|
||||||
active: currentPage?.route.name === "announcements",
|
active: currentPage?.route.name === "announcements",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
icon: "ph-money ph-bold ph-lg",
|
|
||||||
text: i18n.ts.ads,
|
|
||||||
to: "/admin/ads",
|
|
||||||
active: currentPage?.route.name === "ads",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
icon: "ph-warning-circle ph-bold ph-lg",
|
icon: "ph-warning-circle ph-bold ph-lg",
|
||||||
text: i18n.ts.abuseReports,
|
text: i18n.ts.abuseReports,
|
||||||
|
|
|
@ -1,158 +0,0 @@
|
||||||
<template>
|
|
||||||
<MkStickyContainer>
|
|
||||||
<template #header
|
|
||||||
><MkPageHeader
|
|
||||||
:actions="headerActions"
|
|
||||||
:tabs="headerTabs"
|
|
||||||
:display-back-button="true"
|
|
||||||
/></template>
|
|
||||||
<MkSpacer :content-max="900">
|
|
||||||
<div class="uqshojas">
|
|
||||||
<div v-for="ad in ads" class="_panel _formRoot ad">
|
|
||||||
<MkAd v-if="ad.url" :specify="ad" />
|
|
||||||
<MkInput v-model="ad.url" type="url" class="_formBlock">
|
|
||||||
<template #label>URL</template>
|
|
||||||
</MkInput>
|
|
||||||
<MkInput v-model="ad.imageUrl" class="_formBlock">
|
|
||||||
<template #label>{{ i18n.ts.imageUrl }}</template>
|
|
||||||
</MkInput>
|
|
||||||
<FormRadios v-model="ad.place" class="_formBlock">
|
|
||||||
<template #label>Form</template>
|
|
||||||
<option value="widget">widget</option>
|
|
||||||
<option value="inline">inline</option>
|
|
||||||
<option value="inline-big">inline-big</option>
|
|
||||||
</FormRadios>
|
|
||||||
<FormSplit>
|
|
||||||
<MkInput
|
|
||||||
:disabled="ad.place === 'widget'"
|
|
||||||
v-model="ad.ratio"
|
|
||||||
type="number"
|
|
||||||
>
|
|
||||||
<template #label>{{ i18n.ts.ratio }}</template>
|
|
||||||
</MkInput>
|
|
||||||
<MkInput v-model="ad.expiresAt" type="date">
|
|
||||||
<template #label>{{ i18n.ts.expiration }}</template>
|
|
||||||
</MkInput>
|
|
||||||
</FormSplit>
|
|
||||||
<MkTextarea v-model="ad.memo" class="_formBlock">
|
|
||||||
<template #label>{{ i18n.ts.memo }}</template>
|
|
||||||
</MkTextarea>
|
|
||||||
<div class="buttons _formBlock">
|
|
||||||
<MkButton
|
|
||||||
class="button"
|
|
||||||
inline
|
|
||||||
primary
|
|
||||||
style="margin-right: 12px"
|
|
||||||
@click="save(ad)"
|
|
||||||
><i class="ph-floppy-disk-back ph-bold ph-lg"></i>
|
|
||||||
{{ i18n.ts.save }}</MkButton
|
|
||||||
>
|
|
||||||
<MkButton
|
|
||||||
class="button"
|
|
||||||
inline
|
|
||||||
danger
|
|
||||||
@click="remove(ad)"
|
|
||||||
><i class="ph-trash ph-bold ph-lg"></i>
|
|
||||||
{{ i18n.ts.remove }}</MkButton
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</MkSpacer>
|
|
||||||
</MkStickyContainer>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import {} from "vue";
|
|
||||||
import MkButton from "@/components/MkButton.vue";
|
|
||||||
import MkInput from "@/components/form/input.vue";
|
|
||||||
import MkTextarea from "@/components/form/textarea.vue";
|
|
||||||
import FormRadios from "@/components/form/radios.vue";
|
|
||||||
import FormSplit from "@/components/form/split.vue";
|
|
||||||
import * as os from "@/os";
|
|
||||||
import { i18n } from "@/i18n";
|
|
||||||
import { definePageMetadata } from "@/scripts/page-metadata";
|
|
||||||
import { formatDateTimeString } from "@/scripts/format-time-string";
|
|
||||||
|
|
||||||
let ads: any[] = $ref([]);
|
|
||||||
|
|
||||||
os.api("admin/ad/list").then((adsResponse) => {
|
|
||||||
ads = adsResponse;
|
|
||||||
// The date format should be changed to yyyy-MM-dd in order to be properly displayed
|
|
||||||
for (let i in ads) {
|
|
||||||
ads[i].expiresAt = ads[i].expiresAt.substr(0, 10);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function add() {
|
|
||||||
const tomorrow = formatDateTimeString(
|
|
||||||
new Date(new Date().setDate(new Date().getDate() + 1)),
|
|
||||||
"yyyy-MM-dd",
|
|
||||||
);
|
|
||||||
ads.unshift({
|
|
||||||
id: null,
|
|
||||||
memo: "",
|
|
||||||
place: "widget",
|
|
||||||
priority: "middle",
|
|
||||||
ratio: 1,
|
|
||||||
url: "",
|
|
||||||
imageUrl: null,
|
|
||||||
expiresAt: tomorrow,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function remove(ad) {
|
|
||||||
os.confirm({
|
|
||||||
type: "warning",
|
|
||||||
text: i18n.t("removeAreYouSure", { x: ad.url }),
|
|
||||||
}).then(({ canceled }) => {
|
|
||||||
if (canceled) return;
|
|
||||||
ads = ads.filter((x) => x !== ad);
|
|
||||||
os.apiWithDialog("admin/ad/delete", {
|
|
||||||
id: ad.id,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function save(ad) {
|
|
||||||
if (ad.id == null) {
|
|
||||||
os.apiWithDialog("admin/ad/create", {
|
|
||||||
...ad,
|
|
||||||
expiresAt: new Date(ad.expiresAt).getTime(),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
os.apiWithDialog("admin/ad/update", {
|
|
||||||
...ad,
|
|
||||||
expiresAt: new Date(ad.expiresAt).getTime(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const headerActions = $computed(() => [
|
|
||||||
{
|
|
||||||
asFullButton: true,
|
|
||||||
icon: "ph-plus ph-bold ph-lg",
|
|
||||||
text: i18n.ts.add,
|
|
||||||
handler: add,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
const headerTabs = $computed(() => []);
|
|
||||||
|
|
||||||
definePageMetadata({
|
|
||||||
title: i18n.ts.ads,
|
|
||||||
icon: "ph-money ph-bold ph-lg",
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.uqshojas {
|
|
||||||
> .ad {
|
|
||||||
padding: 32px;
|
|
||||||
|
|
||||||
&:not(:last-child) {
|
|
||||||
margin-bottom: var(--margin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -20,7 +20,6 @@
|
||||||
:items="items"
|
:items="items"
|
||||||
:direction="'down'"
|
:direction="'down'"
|
||||||
:no-gap="false"
|
:no-gap="false"
|
||||||
:ad="false"
|
|
||||||
>
|
>
|
||||||
<XNote
|
<XNote
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
|
|
|
@ -111,7 +111,6 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<MkAd :prefer="['inline', 'inline-big']" />
|
|
||||||
<MkContainer
|
<MkContainer
|
||||||
:max-height="300"
|
:max-height="300"
|
||||||
:foldable="true"
|
:foldable="true"
|
||||||
|
|
|
@ -168,7 +168,6 @@
|
||||||
</template>
|
</template>
|
||||||
</div> -->
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
<MkAd :prefer="['inline', 'inline-big']" />
|
|
||||||
<MkContainer
|
<MkContainer
|
||||||
:max-height="300"
|
:max-height="300"
|
||||||
:foldable="true"
|
:foldable="true"
|
||||||
|
|
|
@ -155,9 +155,6 @@
|
||||||
|
|
||||||
<FormSection>
|
<FormSection>
|
||||||
<template #label>{{ i18n.ts.appearance }}</template>
|
<template #label>{{ i18n.ts.appearance }}</template>
|
||||||
<FormSwitch v-model="showAds" class="_formBlock">{{
|
|
||||||
i18n.ts.showAds
|
|
||||||
}}</FormSwitch>
|
|
||||||
<FormSwitch v-model="useBlurEffect" class="_formBlock">{{
|
<FormSwitch v-model="useBlurEffect" class="_formBlock">{{
|
||||||
i18n.ts.useBlurEffect
|
i18n.ts.useBlurEffect
|
||||||
}}</FormSwitch>
|
}}</FormSwitch>
|
||||||
|
@ -298,7 +295,6 @@ const useBlurEffect = computed(defaultStore.makeGetterSetter("useBlurEffect"));
|
||||||
const showGapBetweenNotesInTimeline = computed(
|
const showGapBetweenNotesInTimeline = computed(
|
||||||
defaultStore.makeGetterSetter("showGapBetweenNotesInTimeline"),
|
defaultStore.makeGetterSetter("showGapBetweenNotesInTimeline"),
|
||||||
);
|
);
|
||||||
const showAds = computed(defaultStore.makeGetterSetter("showAds"));
|
|
||||||
const advancedMfm = computed(defaultStore.makeGetterSetter("advancedMfm"));
|
const advancedMfm = computed(defaultStore.makeGetterSetter("advancedMfm"));
|
||||||
const autoplayMfm = computed(
|
const autoplayMfm = computed(
|
||||||
defaultStore.makeGetterSetter(
|
defaultStore.makeGetterSetter(
|
||||||
|
@ -392,7 +388,6 @@ watch(
|
||||||
showGapBetweenNotesInTimeline,
|
showGapBetweenNotesInTimeline,
|
||||||
instanceTicker,
|
instanceTicker,
|
||||||
overridedDeviceKind,
|
overridedDeviceKind,
|
||||||
showAds,
|
|
||||||
showUpdates,
|
showUpdates,
|
||||||
swipeOnMobile,
|
swipeOnMobile,
|
||||||
swipeOnDesktop,
|
swipeOnDesktop,
|
||||||
|
|
|
@ -83,7 +83,6 @@ const defaultStoreSaveKeys: (keyof (typeof defaultStore)["state"])[] = [
|
||||||
"overridedDeviceKind",
|
"overridedDeviceKind",
|
||||||
"serverDisconnectedBehavior",
|
"serverDisconnectedBehavior",
|
||||||
"nsfw",
|
"nsfw",
|
||||||
"showAds",
|
|
||||||
"animation",
|
"animation",
|
||||||
"animatedMfm",
|
"animatedMfm",
|
||||||
"loadRawImages",
|
"loadRawImages",
|
||||||
|
|
|
@ -484,11 +484,6 @@ export const routes = [
|
||||||
name: "announcements",
|
name: "announcements",
|
||||||
component: page(() => import("./pages/admin/announcements.vue")),
|
component: page(() => import("./pages/admin/announcements.vue")),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: "/ads",
|
|
||||||
name: "ads",
|
|
||||||
component: page(() => import("./pages/admin/promotions.vue")),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: "/database",
|
path: "/database",
|
||||||
name: "database",
|
name: "database",
|
||||||
|
|
|
@ -102,14 +102,6 @@ export const defaultStore = markRaw(
|
||||||
where: "account",
|
where: "account",
|
||||||
default: [],
|
default: [],
|
||||||
},
|
},
|
||||||
mutedAds: {
|
|
||||||
where: "account",
|
|
||||||
default: [] as string[],
|
|
||||||
},
|
|
||||||
showAds: {
|
|
||||||
where: "account",
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
menu: {
|
menu: {
|
||||||
where: "deviceAccount",
|
where: "deviceAccount",
|
||||||
default: menuOptions,
|
default: menuOptions,
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
>{{ column.name }}</template
|
>{{ column.name }}</template
|
||||||
>
|
>
|
||||||
<div class="wtdtxvec">
|
<div class="wtdtxvec">
|
||||||
<MkAd class="a" :prefer="['widget']" />
|
|
||||||
<div
|
<div
|
||||||
v-if="!(column.widgets && column.widgets.length > 0) && !edit"
|
v-if="!(column.widgets && column.widgets.length > 0) && !edit"
|
||||||
class="intro"
|
class="intro"
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<aside class="widgets" :aria-label="i18n.ts._deck._columns.widgets">
|
<aside class="widgets" :aria-label="i18n.ts._deck._columns.widgets">
|
||||||
<MkAd class="a" :prefer="['widget']" />
|
|
||||||
<XWidgets
|
<XWidgets
|
||||||
:edit="editMode"
|
:edit="editMode"
|
||||||
:widgets="defaultStore.reactiveState.widgets.value"
|
:widgets="defaultStore.reactiveState.widgets.value"
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import {
|
import {
|
||||||
Ad,
|
|
||||||
Announcement,
|
Announcement,
|
||||||
Antenna,
|
Antenna,
|
||||||
App,
|
App,
|
||||||
|
|
|
@ -301,13 +301,6 @@ export type LiteInstanceMetadata = {
|
||||||
enableDiscordIntegration: boolean;
|
enableDiscordIntegration: boolean;
|
||||||
enableServiceWorker: boolean;
|
enableServiceWorker: boolean;
|
||||||
emojis: CustomEmoji[];
|
emojis: CustomEmoji[];
|
||||||
ads: {
|
|
||||||
id: ID;
|
|
||||||
ratio: number;
|
|
||||||
place: string;
|
|
||||||
url: string;
|
|
||||||
imageUrl: string;
|
|
||||||
}[];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type DetailedInstanceMetadata = LiteInstanceMetadata & {
|
export type DetailedInstanceMetadata = LiteInstanceMetadata & {
|
||||||
|
@ -407,8 +400,6 @@ export type AuthSession = {
|
||||||
token: string;
|
token: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Ad = TODO;
|
|
||||||
|
|
||||||
export type Clip = TODO;
|
export type Clip = TODO;
|
||||||
|
|
||||||
export type NoteFavorite = {
|
export type NoteFavorite = {
|
||||||
|
|
Loading…
Reference in a new issue