0
0
Fork 0
This commit is contained in:
Xeltica 2021-01-06 22:48:04 +09:00
parent 033c4bb12c
commit 52685eb3a4
6 changed files with 153 additions and 14 deletions

View file

@ -0,0 +1,22 @@
import {MigrationInterface, QueryRunner} from 'typeorm';
export class visibility1609938844427 implements MigrationInterface {
name = 'visibility1609938844427'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query('CREATE TYPE "user_visibility_enum" AS ENUM(\'public\', \'home\', \'followers\', \'users\')');
await queryRunner.query('ALTER TABLE "user" ADD "visibility" "user_visibility_enum" NOT NULL DEFAULT \'home\'');
await queryRunner.query('ALTER TABLE "user" ADD "localOnly" boolean NOT NULL DEFAULT false');
await queryRunner.query('ALTER TABLE "user" ADD "remoteFollowersOnly" boolean NOT NULL DEFAULT false');
await queryRunner.query('ALTER TABLE "user" ALTER COLUMN "alertMode" SET DEFAULT \'notification\'');
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query('ALTER TABLE "user" ALTER COLUMN "alertMode" SET DEFAULT \'note\'');
await queryRunner.query('ALTER TABLE "user" DROP COLUMN "remoteFollowersOnly"');
await queryRunner.query('ALTER TABLE "user" DROP COLUMN "localOnly"');
await queryRunner.query('ALTER TABLE "user" DROP COLUMN "visibility"');
await queryRunner.query('DROP TYPE "user_visibility_enum"');
}
}

View file

@ -1,5 +1,6 @@
import { Entity, Column, PrimaryGeneratedColumn, Index } from 'typeorm'; import { Entity, Column, PrimaryGeneratedColumn, Index } from 'typeorm';
import { AlertMode, alertModes } from '../../types/AlertMode'; import { AlertMode, alertModes } from '../../types/AlertMode';
import { visibilities, Visibility } from '../../types/Visibility';
@Entity() @Entity()
@Index([ 'username', 'host' ], { unique: true }) @Index([ 'username', 'host' ], { unique: true })
@ -52,4 +53,23 @@ export class User {
default: 'notification' default: 'notification'
}) })
public alertMode: AlertMode; public alertMode: AlertMode;
@Column({
type: 'enum',
enum: visibilities,
default: 'home',
})
public visibility: Visibility;
@Column({
type: 'boolean',
default: false,
})
public localOnly: boolean;
@Column({
type: 'boolean',
default: false,
})
public remoteFollowersOnly: boolean;
} }

View file

@ -12,6 +12,7 @@ import { getScores } from '../functions/get-scores';
import { AlertMode, alertModes } from '../types/AlertMode'; import { AlertMode, alertModes } from '../types/AlertMode';
import { Users } from '../models'; import { Users } from '../models';
import { send } from '../services/send'; import { send } from '../services/send';
import { visibilities, Visibility } from '../types/Visibility';
export const router = new Router<DefaultState, Context>(); export const router = new Router<DefaultState, Context>();
@ -59,9 +60,13 @@ router.get('/', async ctx => {
const user = token ? await getUserByMisshaiToken(token) : undefined; const user = token ? await getUserByMisshaiToken(token) : undefined;
const isAvailable = user && await apiAvailable(user.host, user.token); const isAvailable = user && await apiAvailable(user.host, user.token);
if (user && isAvailable) { if (user && isAvailable) {
const meta = await api<{ version: string }>(user?.host, 'meta', {});
await ctx.render('mypage', { await ctx.render('mypage', {
user, user,
// To Activate Groundpolis Mode
isGroundpolis: meta.version.includes('gp'),
usersCount: await getUserCount(), usersCount: await getUserCount(),
score: await getScores(user), score: await getScores(user),
from: ctx.query.from, from: ctx.query.from,
@ -195,6 +200,14 @@ router.post('/update-settings', async ctx => {
await die(ctx, `${mode} is an invalid value`); await die(ctx, `${mode} is an invalid value`);
return; return;
} }
const visibility = ctx.request.body.visibility as Visibility;
// 一応型チェック
if (!visibilities.includes(visibility)) {
await die(ctx, `${mode} is an invalid value`);
return;
}
const flag = ctx.request.body.flag;
const token = ctx.cookies.get('token'); const token = ctx.cookies.get('token');
if (!token) { if (!token) {
@ -209,7 +222,12 @@ router.post('/update-settings', async ctx => {
return; return;
} }
await Users.update(u.id, { alertMode: mode }); await Users.update(u.id, {
alertMode: mode,
localOnly: flag === 'localOnly',
remoteFollowersOnly: flag === 'remoteFollowersOnly',
visibility,
});
ctx.redirect('/?from=updateSettings'); ctx.redirect('/?from=updateSettings');
}); });

View file

@ -8,9 +8,13 @@ export const send = async (user: User): Promise<void> => {
if (user.alertMode === 'note') { if (user.alertMode === 'note') {
console.info(`send ${user.username}@${user.host}'s misshaialert as a note`); console.info(`send ${user.username}@${user.host}'s misshaialert as a note`);
const res = await api<Record<string, unknown>>(user.host, 'notes/create', { const opts = {
text, text,
}, user.token); visibility: user.visibility,
} as Record<string, unknown>;
if (user.localOnly) opts.localOnly = user.localOnly;
if (user.remoteFollowersOnly) opts.remoteFollowersOnly = user.remoteFollowersOnly;
const res = await api<Record<string, unknown>>(user.host, 'notes/create', opts, user.token);
if (res.error) { if (res.error) {
throw res.error || res; throw res.error || res;
} }

8
src/types/Visibility.ts Normal file
View file

@ -0,0 +1,8 @@
export const visibilities = [
'public', // パブリック
'home', // ホーム
'followers', // フォロワー
'users' // ログインユーザー (Groundpolis 限定)
] as const;
export type Visibility = typeof visibilities[number];

View file

@ -49,6 +49,19 @@ block content
td !{score.followersDelta} td !{score.followersDelta}
section.xd-card#settings section.xd-card#settings
-
const visibilities = [
[ 'public', 'パブリック'],
[ 'home', isGroundpolis ? '未収載' : 'ホーム'],
[ 'followers', 'フォロワー'],
];
if (isGroundpolis) visibilities.push(['users', 'ログインユーザー']);
const alertModes = [
[ 'note', '自動的にノートを投稿' ],
[ 'notification', 'Misskeyに通知(標準)' ],
[ 'nothing', '通知しない' ],
];
const currentAlertModeLabel = alertModes.find(a => a[0] === user.alertMode)[1];
.header .header
h1.title 設定 h1.title 設定
.body .body
@ -57,21 +70,75 @@ block content
| スコア通知方法に「Misskey に通知」を選んでいる場合、Groundpolis v3 および Misskey v12 の最新版以外では動作しません。めいすきーや古いバージョンをお使いの方は、「自動的にノートを投稿」をお使いください。 | スコア通知方法に「Misskey に通知」を選んでいる場合、Groundpolis v3 および Misskey v12 の最新版以外では動作しません。めいすきーや古いバージョンをお使いの方は、「自動的にノートを投稿」をお使いください。
form(method="post", action="/update-settings") form(method="post", action="/update-settings")
p: label スコア通知方法: p: label スコア通知方法:
select(name="alertMode") select(name="alertMode", tabindex=1)
option(value="note", selected=user.alertMode === 'note') 自動的にノートを投稿 (標準) each set in alertModes
option(value="notification", selected=user.alertMode === 'notification') Misskey に通知 option(value=set[0], selected=(user.alertMode === set[0]))= set[1]
option(value="nothing", selected=user.alertMode === 'nothing') 通知しない p: label 公開範囲:
p: label タイムゾーン:(coming soon) select(name="visibility", tabindex=2)
button.primary(type="submit") 保存 each set in visibilities
option(value=set[0], selected=(user.visibility === set[0]))= set[1]
p
| フラグ <br />
label
input(type="radio", name="flag", value="none", checked=!user.localOnly && !user.remoteFollowersOnly, tabindex=3)
| なし(標準)<br />
label
input(type="radio", name="flag", value="localOnly", checked=user.localOnly, tabindex=4)
| ローカルのみ<br />
if isGroundpolis
label
input(type="radio", name="flag", value="remoteFollowersOnly", checked=user.remoteFollowersOnly, tabindex=5)
| リモートフォロワーとローカル<br />
div
label 投稿テンプレート
div: textarea(name="template", disabled, tabindex=6)
details(tabindex=7)
summary ヘルプ
p
code {notesCount}
| などのテキストを挿入することで、投稿時に自動的に値が埋め込まれます。これを変数といいます。変数の表を次に示します。
table
thead: tr
th 変数
th 説明
tbody
tr
td {notesCount}
td ノート数
tr
td {followingCount}
td フォロー数
tr
td {followersCount}
td フォロワー数
tr
td {notesDelta}
td 昨日とのノート数の差
tr
td {followingDelta}
td 昨日とのフォロー数の差
tr
td {followersDelta}
td 昨日とのフォロワー数の差
tr
td {url}
td みす廃アラートのURL
tr
td {ranking}
td みす廃ランキングの順位
tr
td {rating}
td みす廃レート
button.primary(type="submit", tabindex=8) 保存
section.xd-card#settings section.xd-card#settings
.header .header
h1.title 操作 h1.title 操作
.body .body
form.mb-2(action="/send", method="post"): button#send(style="display: inline-block") アラートをテスト送信 form.mb-2(action="/send", method="post", tabindex=9): button#send(style="display: inline-block") アラートをテスト送信
form.mb-2(action="/logout", method="post"): button#logout(style="display: inline-block") ログアウト form.mb-2(action="/logout", method="post", tabindex=10): button#logout(style="display: inline-block") ログアウト
form.mb-2(action="/optout", method="post"): button.danger#optout(style="display: inline-block") アカウント連携を解除する form.mb-2(action="/optout", method="post", tabindex=11): button.danger#optout(style="display: inline-block") アカウント連携を解除する
block script block script
script. script.