Merge branch 'feat/update_email_tips' into 'develop'
feat: update email tips See merge request firefish/firefish!10716
This commit is contained in:
commit
dd4d16c687
|
@ -1083,6 +1083,12 @@ recommendedInstancesDescription: "Recommended servers separated by line breaks t
|
|||
caption: "Auto description"
|
||||
splash: "Splash Screen"
|
||||
updateAvailable: "There might be an update available!"
|
||||
updateEmailTips: "Update Email Tips"
|
||||
updateEmailTipsInfo: "To receive email tips when Firefish releases a new version. You need to
|
||||
correctly set up email sending and maintainer email for it to take effect."
|
||||
updateEmailTipsSecurityOnly: "Only receive security update tips"
|
||||
updateEmailTipsSecurityOnlyInfo: "Firefish using rolling update and new versions may be
|
||||
released frequently. This option is used to only receive email tips for security version update."
|
||||
swipeOnMobile: "Allow swiping between pages"
|
||||
swipeOnDesktop: "Allow mobile-style swiping on desktop"
|
||||
logoImageUrl: "Logo image URL"
|
||||
|
|
|
@ -1872,6 +1872,10 @@ showAds: 显示社区横幅
|
|||
enterSendsMessage: 按回车键发送信息(关闭则是 Ctrl + Return 发送)
|
||||
recommendedInstances: 推荐服务器
|
||||
updateAvailable: 可能有可用更新!
|
||||
updateEmailTips: 更新提醒邮件
|
||||
updateEmailTipsInfo: 在 Firefish 发布新版本时接收更新提醒邮件。需要您正确设置发送邮件功能和管理员邮箱才会生效。
|
||||
updateEmailTipsSecurityOnly: 只接收安全版本更新提醒
|
||||
updateEmailTipsSecurityOnlyInfo: Firefish 采用滚动更新模式因此新版本可能会频繁发布。此选项用于只在安全更新发布时接收更新提醒邮件。
|
||||
swipeOnMobile: 允许在页面之间滑动
|
||||
swipeOnDesktop: 允许在桌面端以移动设备方式滑动
|
||||
logoImageUrl: Logo 图像 URL
|
||||
|
|
|
@ -50,5 +50,8 @@
|
|||
"execa": "8.0.1",
|
||||
"pnpm": "8.15.7",
|
||||
"typescript": "5.4.5"
|
||||
},
|
||||
"firefishCustomFields": {
|
||||
"lastSecurityUpdate": "20240330"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -128,6 +128,12 @@ pub struct Model {
|
|||
pub secure_mode: Option<bool>,
|
||||
#[sea_orm(column_name = "privateMode")]
|
||||
pub private_mode: Option<bool>,
|
||||
#[sea_orm(column_name = "updateEmailTips")]
|
||||
pub update_email_tips: Option<bool>,
|
||||
#[sea_orm(column_name = "updateEmailTipsSecurityOnly")]
|
||||
pub update_email_tips_security_only: Option<bool>,
|
||||
#[sea_orm(column_name = "updateTipsVersion")]
|
||||
pub update_tips_version: Option<String>,
|
||||
#[sea_orm(column_name = "deeplAuthKey")]
|
||||
pub deepl_auth_key: Option<String>,
|
||||
#[sea_orm(column_name = "deeplIsPro")]
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
import type { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class updateEmailTips1711616400000 implements MigrationInterface {
|
||||
async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "meta" ADD "updateEmailTips" bool default true`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "meta" ADD "updateEmailTipsSecurityOnly" bool default true`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "meta" ADD "updateTipsVersion" character varying(512)`,
|
||||
);
|
||||
}
|
||||
|
||||
async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "updateEmailTips"`);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "meta" DROP COLUMN "updateEmailTipsSecurityOnly"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "meta" DROP COLUMN "updateTipsVersion"`,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -152,6 +152,22 @@ export class Meta {
|
|||
})
|
||||
public allowedHosts: string[];
|
||||
|
||||
@Column("boolean", {
|
||||
default: true,
|
||||
})
|
||||
public updateEmailTips: boolean;
|
||||
|
||||
@Column("boolean", {
|
||||
default: true,
|
||||
})
|
||||
public updateEmailTipsSecurityOnly: boolean;
|
||||
|
||||
@Column("varchar", {
|
||||
length: 512,
|
||||
nullable: true,
|
||||
})
|
||||
public updateTipsVersion: string | null;
|
||||
|
||||
@Column("varchar", {
|
||||
length: 512,
|
||||
array: true,
|
||||
|
|
|
@ -559,6 +559,16 @@ export default function () {
|
|||
},
|
||||
);
|
||||
|
||||
systemQueue.add(
|
||||
"updateEmailTips",
|
||||
{},
|
||||
{
|
||||
repeat: { cron: "0 0 * * 0" },
|
||||
removeOnComplete: true,
|
||||
removeOnFail: true,
|
||||
},
|
||||
);
|
||||
|
||||
processSystemQueue(systemQueue);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import { checkExpiredMutings } from "./check-expired-mutings.js";
|
|||
import { clean } from "./clean.js";
|
||||
import { setLocalEmojiSizes } from "./local-emoji-size.js";
|
||||
import { verifyLinks } from "./verify-links.js";
|
||||
import { updateEmailTips } from "./update-email-tips.js";
|
||||
|
||||
const jobs = {
|
||||
cleanCharts,
|
||||
|
@ -11,6 +12,7 @@ const jobs = {
|
|||
clean,
|
||||
setLocalEmojiSizes,
|
||||
verifyLinks,
|
||||
updateEmailTips,
|
||||
} as Record<
|
||||
string,
|
||||
| Bull.ProcessCallbackFunction<Record<string, unknown>>
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
import type Bull from "bull";
|
||||
|
||||
import { Meta } from "@/models/entities/meta.js";
|
||||
import fetch from "node-fetch";
|
||||
import { queueLogger } from "../../logger.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { db } from "@/db/postgre.js";
|
||||
import { sendEmail } from "@/services/send-email.js";
|
||||
|
||||
const logger = queueLogger.createSubLogger("update-email-tips");
|
||||
|
||||
export async function updateEmailTips(
|
||||
job: Bull.Job<Record<string, unknown>>,
|
||||
done: any,
|
||||
): Promise<void> {
|
||||
logger.info("Checking firefish Update...");
|
||||
|
||||
const instance = await fetchMeta(true);
|
||||
|
||||
if (!instance.updateEmailTips) {
|
||||
logger.info("Exit due to not enable update email tips.");
|
||||
} else if (!instance.enableEmail) {
|
||||
logger.info("Exit due to not enable email.");
|
||||
} else if (
|
||||
instance.maintainerEmail === null ||
|
||||
typeof instance.maintainerEmail !== "string"
|
||||
) {
|
||||
logger.info("Exit due to not vaild maintainer email.");
|
||||
} else {
|
||||
const url =
|
||||
"https://firefish.dev/firefish/firefish/-/raw/main/package.json";
|
||||
|
||||
const res = await fetch(url).catch((e) => {
|
||||
logger.info("Exit due to network error.");
|
||||
});
|
||||
|
||||
if (res !== null) {
|
||||
const packageData = await res.json();
|
||||
const version = instance.updateEmailTipsSecurityOnly
|
||||
? packageData.firefishCustomFields.lastSecurityUpdate
|
||||
: packageData.version;
|
||||
|
||||
if (instance.updateTipsVersion === null) {
|
||||
await db.transaction(async (transactionalEntityManager) => {
|
||||
const metas = await transactionalEntityManager.find(Meta, {
|
||||
order: {
|
||||
id: "DESC",
|
||||
},
|
||||
});
|
||||
|
||||
await transactionalEntityManager.update(Meta, metas[0].id, {
|
||||
updateTipsVersion: version,
|
||||
});
|
||||
});
|
||||
|
||||
logger.info("Exit due to first time update.");
|
||||
} else if (instance.updateTipsVersion < version) {
|
||||
if (
|
||||
packageData.firefishCustomFields.lastSecurityUpdate ===
|
||||
packageData.version
|
||||
) {
|
||||
logger.info(
|
||||
`Found security update version ${version}, last check version is ${instance.updateTipsVersion}`,
|
||||
);
|
||||
|
||||
await sendEmail(
|
||||
instance.maintainerEmail,
|
||||
"Security Update Tips",
|
||||
`Firefish has released a new security update version ${version}, please update as soon as possible to ensure the security of your site.<br>The changelog can be viewed at the following url: <a href="https://firefish.dev/firefish/firefish/-/blob/develop/docs/changelog.md">https://firefish.dev/firefish/firefish/-/blob/develop/docs/changelog.md</a>`,
|
||||
`Firefish has released a new security update version ${version}, please update as soon as possible to ensure the security of your site.\nThe changelog can be viewed at the following url: https://firefish.dev/firefish/firefish/-/blob/develop/docs/changelog.md`,
|
||||
);
|
||||
} else {
|
||||
logger.info(
|
||||
`Found version ${version}, last check version is ${instance.updateTipsVersion}`,
|
||||
);
|
||||
|
||||
await sendEmail(
|
||||
instance.maintainerEmail,
|
||||
"Update Tips",
|
||||
`Firefish has released a new version ${version}.<br>The changelog can be viewed at the following url: <a href="https://firefish.dev/firefish/firefish/-/blob/develop/docs/changelog.md">https://firefish.dev/firefish/firefish/-/blob/develop/docs/changelog.md</a>`,
|
||||
`Firefish has released a new version ${version}.\nThe changelog can be viewed at the following url: https://firefish.dev/firefish/firefish/-/blob/develop/docs/changelog.md`,
|
||||
);
|
||||
}
|
||||
|
||||
await db.transaction(async (transactionalEntityManager) => {
|
||||
const metas = await transactionalEntityManager.find(Meta, {
|
||||
order: {
|
||||
id: "DESC",
|
||||
},
|
||||
});
|
||||
|
||||
await transactionalEntityManager.update(Meta, metas[0].id, {
|
||||
updateTipsVersion: version,
|
||||
});
|
||||
});
|
||||
|
||||
logger.info("Email send.");
|
||||
} else {
|
||||
logger.info("No new update.");
|
||||
}
|
||||
logger.succ("Checking firefish update successfully.");
|
||||
}
|
||||
}
|
||||
done();
|
||||
}
|
|
@ -288,6 +288,18 @@ export const meta = {
|
|||
optional: true,
|
||||
nullable: true,
|
||||
},
|
||||
updateEmailTips: {
|
||||
type: "boolean",
|
||||
optional: true,
|
||||
nullable: false,
|
||||
default: true,
|
||||
},
|
||||
updateEmailTipsSecurityOnly: {
|
||||
type: "boolean",
|
||||
optional: true,
|
||||
nullable: false,
|
||||
default: true,
|
||||
},
|
||||
recaptchaSecretKey: {
|
||||
type: "string",
|
||||
optional: true,
|
||||
|
@ -528,6 +540,8 @@ export default define(meta, paramDef, async () => {
|
|||
allowedHosts: instance.allowedHosts,
|
||||
privateMode: instance.privateMode,
|
||||
secureMode: instance.secureMode,
|
||||
updateEmailTips: instance.updateEmailTips,
|
||||
updateEmailTipsSecurityOnly: instance.updateEmailTipsSecurityOnly,
|
||||
hcaptchaSecretKey: instance.hcaptchaSecretKey,
|
||||
recaptchaSecretKey: instance.recaptchaSecretKey,
|
||||
proxyAccountId: instance.proxyAccountId,
|
||||
|
|
|
@ -77,6 +77,8 @@ export const paramDef = {
|
|||
},
|
||||
secureMode: { type: "boolean", nullable: true },
|
||||
privateMode: { type: "boolean", nullable: true },
|
||||
updateEmailTips: { type: "boolean", nullable: true },
|
||||
updateEmailTipsSecurityOnly: { type: "boolean", nullable: true },
|
||||
themeColor: {
|
||||
type: "string",
|
||||
nullable: true,
|
||||
|
@ -280,6 +282,14 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
set.secureMode = ps.secureMode;
|
||||
}
|
||||
|
||||
if (typeof ps.updateEmailTips === "boolean") {
|
||||
set.updateEmailTips = ps.updateEmailTips;
|
||||
}
|
||||
|
||||
if (typeof ps.updateEmailTipsSecurityOnly === "boolean") {
|
||||
set.updateEmailTipsSecurityOnly = ps.updateEmailTipsSecurityOnly;
|
||||
}
|
||||
|
||||
if (ps.mascotImageUrl !== undefined) {
|
||||
set.mascotImageUrl = ps.mascotImageUrl;
|
||||
}
|
||||
|
|
|
@ -134,6 +134,41 @@
|
|||
>
|
||||
</div>
|
||||
</FormFolder>
|
||||
|
||||
<FormFolder class="_formBlock">
|
||||
<template #label>{{
|
||||
i18n.ts.updateEmailTips
|
||||
}}</template>
|
||||
|
||||
<div class="_formRoot">
|
||||
<FormSwitch v-model="updateEmailTips">
|
||||
<template #label>{{
|
||||
i18n.ts.updateEmailTips
|
||||
}}</template>
|
||||
<template #caption>{{
|
||||
i18n.ts.updateEmailTipsInfo
|
||||
}}</template>
|
||||
</FormSwitch>
|
||||
<FormSwitch
|
||||
v-if="updateEmailTips"
|
||||
v-model="updateEmailTipsSecurityOnly"
|
||||
>
|
||||
<template #label>{{
|
||||
i18n.ts.updateEmailTipsSecurityOnly
|
||||
}}</template>
|
||||
<template #caption>{{
|
||||
i18n.ts.updateEmailTipsSecurityOnlyInfo
|
||||
}}</template>
|
||||
</FormSwitch>
|
||||
<FormButton
|
||||
primary
|
||||
class="_formBlock"
|
||||
@click="saveUpdateEmailTips"
|
||||
><i :class="icon('ph-floppy-disk-back')"></i>
|
||||
{{ i18n.ts.save }}</FormButton
|
||||
>
|
||||
</div>
|
||||
</FormFolder>
|
||||
</div>
|
||||
</FormSuspense>
|
||||
</MkSpacer>
|
||||
|
@ -166,6 +201,9 @@ const secureMode = ref(false);
|
|||
const privateMode = ref(false);
|
||||
const allowedHosts = ref("");
|
||||
|
||||
const updateEmailTips = ref(false);
|
||||
const updateEmailTipsSecurityOnly = ref(false);
|
||||
|
||||
async function init() {
|
||||
const meta = await os.api("admin/meta");
|
||||
summalyProxy.value = meta.summalyProxy;
|
||||
|
@ -177,6 +215,9 @@ async function init() {
|
|||
secureMode.value = meta.secureMode;
|
||||
privateMode.value = meta.privateMode;
|
||||
allowedHosts.value = meta.allowedHosts.join("\n");
|
||||
|
||||
updateEmailTips.value = meta.updateEmailTips;
|
||||
updateEmailTipsSecurityOnly.value = meta.updateEmailTipsSecurityOnly;
|
||||
}
|
||||
|
||||
function save() {
|
||||
|
@ -199,6 +240,15 @@ function saveInstance() {
|
|||
});
|
||||
}
|
||||
|
||||
function saveUpdateEmailTips() {
|
||||
os.apiWithDialog("admin/update-meta", {
|
||||
updateEmailTips: updateEmailTips.value,
|
||||
updateEmailTipsSecurityOnly: updateEmailTipsSecurityOnly.value,
|
||||
}).then(() => {
|
||||
fetchInstance();
|
||||
});
|
||||
}
|
||||
|
||||
const headerActions = computed(() => []);
|
||||
|
||||
const headerTabs = computed(() => []);
|
||||
|
|
Loading…
Reference in New Issue