From 2cb032b0e01b166cda372ea217b60b6705cf4c33 Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 12 Jul 2019 03:17:31 +0900 Subject: Fix #5140 --- src/models/repositories/abuse-user-report.ts | 1 + 1 file changed, 1 insertion(+) (limited to 'src/models') diff --git a/src/models/repositories/abuse-user-report.ts b/src/models/repositories/abuse-user-report.ts index 61d0d6e229..bff64c770c 100644 --- a/src/models/repositories/abuse-user-report.ts +++ b/src/models/repositories/abuse-user-report.ts @@ -14,6 +14,7 @@ export class AbuseUserReportRepository extends Repository { return await awaitAll({ id: report.id, createdAt: report.createdAt, + comment: report.comment, reporterId: report.reporterId, userId: report.userId, reporter: Users.pack(report.reporter || report.reporterId, null, { -- cgit v1.2.3-freya From b34c1379e9aac1c8612a62afa849a48069d19d74 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 14 Jul 2019 03:18:45 +0900 Subject: Resolve #3238 --- locales/ja-JP.yml | 6 +++ migration/1562869971568-ModerationLog.ts | 17 ++++++++ src/client/app/admin/views/moderators.vue | 50 +++++++++++++++++++++- src/db/postgre.ts | 2 + src/models/entities/moderation-log.ts | 32 ++++++++++++++ src/models/index.ts | 2 + src/models/repositories/moderation-logs.ts | 31 ++++++++++++++ src/server/api/endpoints/admin/emoji/add.ts | 7 ++- src/server/api/endpoints/admin/emoji/remove.ts | 7 ++- src/server/api/endpoints/admin/queue/clear.ts | 5 ++- .../api/endpoints/admin/show-moderation-logs.ts | 35 +++++++++++++++ src/server/api/endpoints/admin/silence-user.ts | 7 ++- src/server/api/endpoints/admin/suspend-user.ts | 7 ++- src/server/api/endpoints/admin/unsilence-user.ts | 7 ++- src/server/api/endpoints/admin/unsuspend-user.ts | 7 ++- src/server/api/endpoints/admin/update-meta.ts | 5 ++- src/server/api/endpoints/admin/vacuum.ts | 5 ++- src/services/insert-moderation-log.ts | 13 ++++++ 18 files changed, 234 insertions(+), 11 deletions(-) create mode 100644 migration/1562869971568-ModerationLog.ts create mode 100644 src/models/entities/moderation-log.ts create mode 100644 src/models/repositories/moderation-logs.ts create mode 100644 src/server/api/endpoints/admin/show-moderation-logs.ts create mode 100644 src/services/insert-moderation-log.ts (limited to 'src/models') diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 19bbec2de9..3e315153cb 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1529,6 +1529,12 @@ admin/views/moderators.vue: added: "モデレーターを登録しました" remove: "解除" removed: "モデレーター登録を解除しました" + logs: + title: "ログ" + moderator: "モデレーター" + type: "操作" + at: "日時" + info: "情報" admin/views/emoji.vue: add-emoji: diff --git a/migration/1562869971568-ModerationLog.ts b/migration/1562869971568-ModerationLog.ts new file mode 100644 index 0000000000..b37f38ee5d --- /dev/null +++ b/migration/1562869971568-ModerationLog.ts @@ -0,0 +1,17 @@ +import {MigrationInterface, QueryRunner} from "typeorm"; + +export class ModerationLog1562869971568 implements MigrationInterface { + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`CREATE TABLE "moderation_log" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "type" character varying(128) NOT NULL, "info" jsonb NOT NULL, CONSTRAINT "PK_d0adca6ecfd068db83e4526cc26" PRIMARY KEY ("id"))`); + await queryRunner.query(`CREATE INDEX "IDX_a08ad074601d204e0f69da9a95" ON "moderation_log" ("userId") `); + await queryRunner.query(`ALTER TABLE "moderation_log" ADD CONSTRAINT "FK_a08ad074601d204e0f69da9a954" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "moderation_log" DROP CONSTRAINT "FK_a08ad074601d204e0f69da9a954"`); + await queryRunner.query(`DROP INDEX "IDX_a08ad074601d204e0f69da9a95"`); + await queryRunner.query(`DROP TABLE "moderation_log"`); + } + +} diff --git a/src/client/app/admin/views/moderators.vue b/src/client/app/admin/views/moderators.vue index bf7d951fc7..8ceab02d97 100644 --- a/src/client/app/admin/views/moderators.vue +++ b/src/client/app/admin/views/moderators.vue @@ -12,6 +12,31 @@ + + + +
+ +
+ + + {{ $t('logs.moderator') }} + + + {{ $t('logs.type') }} + + + {{ $t('logs.at') }} + + + + {{ $t('logs.info') }} + +
+
+ {{ $t('@.load-more') }} +
+
@@ -26,10 +51,17 @@ export default Vue.extend({ data() { return { username: '', - changing: false + changing: false, + logs: [], + untilLogId: null, + existMoreLogs: false }; }, + created() { + this.fetchLogs(); + }, + methods: { async add() { this.changing = true; @@ -74,6 +106,22 @@ export default Vue.extend({ this.changing = false; }, + + fetchLogs() { + this.$root.api('admin/show-moderation-logs', { + untilId: this.untilId, + limit: 10 + 1 + }).then(logs => { + if (logs.length == 10 + 1) { + logs.pop(); + this.existMoreLogs = true; + } else { + this.existMoreLogs = false; + } + this.logs = this.logs.concat(logs); + this.untilLogId = this.logs[this.logs.length - 1].id; + }); + }, } }); diff --git a/src/db/postgre.ts b/src/db/postgre.ts index 638d5720b7..16cfbd2b2f 100644 --- a/src/db/postgre.ts +++ b/src/db/postgre.ts @@ -47,6 +47,7 @@ import { UserSecurityKey } from '../models/entities/user-security-key'; import { AttestationChallenge } from '../models/entities/attestation-challenge'; import { Page } from '../models/entities/page'; import { PageLike } from '../models/entities/page-like'; +import { ModerationLog } from '../models/entities/moderation-log'; const sqlLogger = dbLogger.createSubLogger('sql', 'white', false); @@ -124,6 +125,7 @@ export const entities = [ RegistrationTicket, MessagingMessage, Signin, + ModerationLog, ReversiGame, ReversiMatching, ...charts as any diff --git a/src/models/entities/moderation-log.ts b/src/models/entities/moderation-log.ts new file mode 100644 index 0000000000..33d3d683ae --- /dev/null +++ b/src/models/entities/moderation-log.ts @@ -0,0 +1,32 @@ +import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; +import { User } from './user'; +import { id } from '../id'; + +@Entity() +export class ModerationLog { + @PrimaryColumn(id()) + public id: string; + + @Column('timestamp with time zone', { + comment: 'The created date of the ModerationLog.' + }) + public createdAt: Date; + + @Index() + @Column(id()) + public userId: User['id']; + + @ManyToOne(type => User, { + onDelete: 'CASCADE' + }) + @JoinColumn() + public user: User | null; + + @Column('varchar', { + length: 128, + }) + public type: string; + + @Column('jsonb') + public info: Record; +} diff --git a/src/models/index.ts b/src/models/index.ts index 888fd53f36..388bdc8f6f 100644 --- a/src/models/index.ts +++ b/src/models/index.ts @@ -42,6 +42,7 @@ import { UserSecurityKey } from './entities/user-security-key'; import { HashtagRepository } from './repositories/hashtag'; import { PageRepository } from './repositories/page'; import { PageLikeRepository } from './repositories/page-like'; +import { ModerationLogRepository } from './repositories/moderation-logs'; export const Apps = getCustomRepository(AppRepository); export const Notes = getCustomRepository(NoteRepository); @@ -86,3 +87,4 @@ export const ReversiMatchings = getCustomRepository(ReversiMatchingRepository); export const Logs = getRepository(Log); export const Pages = getCustomRepository(PageRepository); export const PageLikes = getCustomRepository(PageLikeRepository); +export const ModerationLogs = getCustomRepository(ModerationLogRepository); diff --git a/src/models/repositories/moderation-logs.ts b/src/models/repositories/moderation-logs.ts new file mode 100644 index 0000000000..d6e04795bb --- /dev/null +++ b/src/models/repositories/moderation-logs.ts @@ -0,0 +1,31 @@ +import { EntityRepository, Repository } from 'typeorm'; +import { Users } from '..'; +import { ModerationLog } from '../entities/moderation-log'; +import { ensure } from '../../prelude/ensure'; +import { awaitAll } from '../../prelude/await-all'; + +@EntityRepository(ModerationLog) +export class ModerationLogRepository extends Repository { + public async pack( + src: ModerationLog['id'] | ModerationLog, + ) { + const log = typeof src === 'object' ? src : await this.findOne(src).then(ensure); + + return await awaitAll({ + id: log.id, + createdAt: log.createdAt, + type: log.type, + info: log.info, + userId: log.userId, + user: Users.pack(log.user || log.userId, null, { + detail: true + }), + }); + } + + public packMany( + reports: any[], + ) { + return Promise.all(reports.map(x => this.pack(x))); + } +} diff --git a/src/server/api/endpoints/admin/emoji/add.ts b/src/server/api/endpoints/admin/emoji/add.ts index 5ba00afde8..8c21b1c73e 100644 --- a/src/server/api/endpoints/admin/emoji/add.ts +++ b/src/server/api/endpoints/admin/emoji/add.ts @@ -4,6 +4,7 @@ import { detectUrlMine } from '../../../../../misc/detect-url-mine'; import { Emojis } from '../../../../../models'; import { genId } from '../../../../../misc/gen-id'; import { getConnection } from 'typeorm'; +import { insertModerationLog } from '../../../../../services/insert-moderation-log'; export const meta = { desc: { @@ -31,7 +32,7 @@ export const meta = { } }; -export default define(meta, async (ps) => { +export default define(meta, async (ps, me) => { const type = await detectUrlMine(ps.url); const emoji = await Emojis.save({ @@ -46,6 +47,10 @@ export default define(meta, async (ps) => { await getConnection().queryResultCache!.remove(['meta_emojis']); + insertModerationLog(me, 'addEmoji', { + emojiId: emoji.id + }); + return { id: emoji.id }; diff --git a/src/server/api/endpoints/admin/emoji/remove.ts b/src/server/api/endpoints/admin/emoji/remove.ts index 3ebf933bc6..92c5f5f8c6 100644 --- a/src/server/api/endpoints/admin/emoji/remove.ts +++ b/src/server/api/endpoints/admin/emoji/remove.ts @@ -3,6 +3,7 @@ import define from '../../../define'; import { ID } from '../../../../../misc/cafy-id'; import { Emojis } from '../../../../../models'; import { getConnection } from 'typeorm'; +import { insertModerationLog } from '../../../../../services/insert-moderation-log'; export const meta = { desc: { @@ -21,7 +22,7 @@ export const meta = { } }; -export default define(meta, async (ps) => { +export default define(meta, async (ps, me) => { const emoji = await Emojis.findOne(ps.id); if (emoji == null) throw new Error('emoji not found'); @@ -29,4 +30,8 @@ export default define(meta, async (ps) => { await Emojis.delete(emoji.id); await getConnection().queryResultCache!.remove(['meta_emojis']); + + insertModerationLog(me, 'removeEmoji', { + emoji: emoji + }); }); diff --git a/src/server/api/endpoints/admin/queue/clear.ts b/src/server/api/endpoints/admin/queue/clear.ts index f0fd00f1ad..03c1ae8463 100644 --- a/src/server/api/endpoints/admin/queue/clear.ts +++ b/src/server/api/endpoints/admin/queue/clear.ts @@ -1,5 +1,6 @@ import define from '../../../define'; import { destroy } from '../../../../../queue'; +import { insertModerationLog } from '../../../../../services/insert-moderation-log'; export const meta = { tags: ['admin'], @@ -10,8 +11,8 @@ export const meta = { params: {} }; -export default define(meta, async (ps) => { +export default define(meta, async (ps, me) => { destroy(); - return; + insertModerationLog(me, 'clearQueue'); }); diff --git a/src/server/api/endpoints/admin/show-moderation-logs.ts b/src/server/api/endpoints/admin/show-moderation-logs.ts new file mode 100644 index 0000000000..bc67b3e55b --- /dev/null +++ b/src/server/api/endpoints/admin/show-moderation-logs.ts @@ -0,0 +1,35 @@ +import $ from 'cafy'; +import { ID } from '../../../../misc/cafy-id'; +import define from '../../define'; +import { ModerationLogs } from '../../../../models'; +import { makePaginationQuery } from '../../common/make-pagination-query'; + +export const meta = { + tags: ['admin'], + + requireCredential: true, + requireModerator: true, + + params: { + limit: { + validator: $.optional.num.range(1, 100), + default: 10 + }, + + sinceId: { + validator: $.optional.type(ID), + }, + + untilId: { + validator: $.optional.type(ID), + }, + } +}; + +export default define(meta, async (ps) => { + const query = makePaginationQuery(ModerationLogs.createQueryBuilder('report'), ps.sinceId, ps.untilId); + + const reports = await query.take(ps.limit!).getMany(); + + return await ModerationLogs.packMany(reports); +}); diff --git a/src/server/api/endpoints/admin/silence-user.ts b/src/server/api/endpoints/admin/silence-user.ts index 83aa88012a..8cc84aa1cc 100644 --- a/src/server/api/endpoints/admin/silence-user.ts +++ b/src/server/api/endpoints/admin/silence-user.ts @@ -2,6 +2,7 @@ import $ from 'cafy'; import { ID } from '../../../../misc/cafy-id'; import define from '../../define'; import { Users } from '../../../../models'; +import { insertModerationLog } from '../../../../services/insert-moderation-log'; export const meta = { desc: { @@ -25,7 +26,7 @@ export const meta = { } }; -export default define(meta, async (ps) => { +export default define(meta, async (ps, me) => { const user = await Users.findOne(ps.userId as string); if (user == null) { @@ -39,4 +40,8 @@ export default define(meta, async (ps) => { await Users.update(user.id, { isSilenced: true }); + + insertModerationLog(me, 'silence', { + targetId: user.id, + }); }); diff --git a/src/server/api/endpoints/admin/suspend-user.ts b/src/server/api/endpoints/admin/suspend-user.ts index fa4d378708..09fdbb070e 100644 --- a/src/server/api/endpoints/admin/suspend-user.ts +++ b/src/server/api/endpoints/admin/suspend-user.ts @@ -4,6 +4,7 @@ import define from '../../define'; import deleteFollowing from '../../../../services/following/delete'; import { Users, Followings } from '../../../../models'; import { User } from '../../../../models/entities/user'; +import { insertModerationLog } from '../../../../services/insert-moderation-log'; export const meta = { desc: { @@ -27,7 +28,7 @@ export const meta = { } }; -export default define(meta, async (ps) => { +export default define(meta, async (ps, me) => { const user = await Users.findOne(ps.userId as string); if (user == null) { @@ -46,6 +47,10 @@ export default define(meta, async (ps) => { isSuspended: true }); + insertModerationLog(me, 'suspend', { + targetId: user.id, + }); + unFollowAll(user); }); diff --git a/src/server/api/endpoints/admin/unsilence-user.ts b/src/server/api/endpoints/admin/unsilence-user.ts index f9b173366b..607c9b699a 100644 --- a/src/server/api/endpoints/admin/unsilence-user.ts +++ b/src/server/api/endpoints/admin/unsilence-user.ts @@ -2,6 +2,7 @@ import $ from 'cafy'; import { ID } from '../../../../misc/cafy-id'; import define from '../../define'; import { Users } from '../../../../models'; +import { insertModerationLog } from '../../../../services/insert-moderation-log'; export const meta = { desc: { @@ -25,7 +26,7 @@ export const meta = { } }; -export default define(meta, async (ps) => { +export default define(meta, async (ps, me) => { const user = await Users.findOne(ps.userId as string); if (user == null) { @@ -35,4 +36,8 @@ export default define(meta, async (ps) => { await Users.update(user.id, { isSilenced: false }); + + insertModerationLog(me, 'unsilence', { + targetId: user.id, + }); }); diff --git a/src/server/api/endpoints/admin/unsuspend-user.ts b/src/server/api/endpoints/admin/unsuspend-user.ts index 08dae034d3..a1c80d3121 100644 --- a/src/server/api/endpoints/admin/unsuspend-user.ts +++ b/src/server/api/endpoints/admin/unsuspend-user.ts @@ -2,6 +2,7 @@ import $ from 'cafy'; import { ID } from '../../../../misc/cafy-id'; import define from '../../define'; import { Users } from '../../../../models'; +import { insertModerationLog } from '../../../../services/insert-moderation-log'; export const meta = { desc: { @@ -25,7 +26,7 @@ export const meta = { } }; -export default define(meta, async (ps) => { +export default define(meta, async (ps, me) => { const user = await Users.findOne(ps.userId as string); if (user == null) { @@ -35,4 +36,8 @@ export default define(meta, async (ps) => { await Users.update(user.id, { isSuspended: false }); + + insertModerationLog(me, 'unsuspend', { + targetId: user.id, + }); }); diff --git a/src/server/api/endpoints/admin/update-meta.ts b/src/server/api/endpoints/admin/update-meta.ts index 8e98d203ff..834faa42b9 100644 --- a/src/server/api/endpoints/admin/update-meta.ts +++ b/src/server/api/endpoints/admin/update-meta.ts @@ -2,6 +2,7 @@ import $ from 'cafy'; import define from '../../define'; import { getConnection } from 'typeorm'; import { Meta } from '../../../../models/entities/meta'; +import { insertModerationLog } from '../../../../services/insert-moderation-log'; export const meta = { desc: { @@ -401,7 +402,7 @@ export const meta = { } }; -export default define(meta, async (ps) => { +export default define(meta, async (ps, me) => { const set = {} as Partial; if (ps.announcements) { @@ -653,4 +654,6 @@ export default define(meta, async (ps) => { await transactionalEntityManager.save(Meta, set); } }); + + insertModerationLog(me, 'updateMeta'); }); diff --git a/src/server/api/endpoints/admin/vacuum.ts b/src/server/api/endpoints/admin/vacuum.ts index 6990706282..4921e228e5 100644 --- a/src/server/api/endpoints/admin/vacuum.ts +++ b/src/server/api/endpoints/admin/vacuum.ts @@ -1,6 +1,7 @@ import $ from 'cafy'; import define from '../../define'; import { getConnection } from 'typeorm'; +import { insertModerationLog } from '../../../../services/insert-moderation-log'; export const meta = { tags: ['admin'], @@ -18,7 +19,7 @@ export const meta = { } }; -export default define(meta, async (ps) => { +export default define(meta, async (ps, me) => { const params: string[] = []; if (ps.full) { @@ -30,4 +31,6 @@ export default define(meta, async (ps) => { } getConnection().query('VACUUM ' + params.join(' ')); + + insertModerationLog(me, 'vacuum', ps); }); diff --git a/src/services/insert-moderation-log.ts b/src/services/insert-moderation-log.ts new file mode 100644 index 0000000000..33dab97259 --- /dev/null +++ b/src/services/insert-moderation-log.ts @@ -0,0 +1,13 @@ +import { ILocalUser } from '../models/entities/user'; +import { ModerationLogs } from '../models'; +import { genId } from '../misc/gen-id'; + +export async function insertModerationLog(moderator: ILocalUser, type: string, info?: Record) { + await ModerationLogs.save({ + id: genId(), + createdAt: new Date(), + userId: moderator.id, + type: type, + info: info || {} + }); +} -- cgit v1.2.3-freya From ef44eda69eefbdeeb1efee1c8351be081938cae5 Mon Sep 17 00:00:00 2001 From: MeiMei <30769358+mei23@users.noreply.github.com> Date: Thu, 18 Jul 2019 00:11:39 +0900 Subject: Mastodonのリンクの所有者認証に対応 (#5161) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Profile metadata を設定できるように * API desc --- locales/ja-JP.yml | 3 ++ .../common/views/components/settings/profile.vue | 46 ++++++++++++++++++++++ src/models/repositories/user.ts | 1 + src/remote/activitypub/renderer/person.ts | 15 ++++++- src/server/api/endpoints/i/update.ts | 15 +++++++ src/server/web/index.ts | 10 ++++- src/server/web/views/base.pug | 1 + src/server/web/views/user.pug | 5 +++ 8 files changed, 92 insertions(+), 4 deletions(-) (limited to 'src/models') diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 76fc26381f..b6bbb7e963 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -804,6 +804,9 @@ common/views/components/profile-editor.vue: danger-zone: "危険な設定" delete-account: "アカウントを削除" account-deleted: "アカウントが削除されました。データが消えるまで時間がかかる場合があります。" + profile-metadata: "プロフィール補足情報" + metadata-label: "ラベル" + metadata-content: "内容" common/views/components/user-list-editor.vue: users: "ユーザー" diff --git a/src/client/app/common/views/components/settings/profile.vue b/src/client/app/common/views/components/settings/profile.vue index 52ec8ceda3..edfc5a9edf 100644 --- a/src/client/app/common/views/components/settings/profile.vue +++ b/src/client/app/common/views/components/settings/profile.vue @@ -51,6 +51,26 @@ +
+
{{ $t('profile-metadata') }}
+ + {{ $t('metadata-label') }} + {{ $t('metadata-content') }} + + + {{ $t('metadata-label') }} + {{ $t('metadata-content') }} + + + {{ $t('metadata-label') }} + {{ $t('metadata-content') }} + + + {{ $t('metadata-label') }} + {{ $t('metadata-content') }} + +
+ {{ $t('save') }} @@ -189,6 +209,17 @@ export default Vue.extend({ this.isLocked = this.$store.state.i.isLocked; this.carefulBot = this.$store.state.i.carefulBot; this.autoAcceptFollowed = this.$store.state.i.autoAcceptFollowed; + + if (this.$store.state.i.fields) { + this.fieldName0 = this.$store.state.i.fields[0].name; + this.fieldValue0 = this.$store.state.i.fields[0].value; + this.fieldName1 = this.$store.state.i.fields[1].name; + this.fieldValue1 = this.$store.state.i.fields[1].value; + this.fieldName2 = this.$store.state.i.fields[2].name; + this.fieldValue2 = this.$store.state.i.fields[2].value; + this.fieldName3 = this.$store.state.i.fields[3].name; + this.fieldValue3 = this.$store.state.i.fields[3].value; + } }, methods: { @@ -237,6 +268,13 @@ export default Vue.extend({ }, save(notify) { + const fields = [ + { name: this.fieldName0, value: this.fieldValue0 }, + { name: this.fieldName1, value: this.fieldValue1 }, + { name: this.fieldName2, value: this.fieldValue2 }, + { name: this.fieldName3, value: this.fieldValue3 }, + ]; + this.saving = true; this.$root.api('i/update', { @@ -247,6 +285,7 @@ export default Vue.extend({ birthday: this.birthday || null, avatarId: this.avatarId || undefined, bannerId: this.bannerId || undefined, + fields, isCat: !!this.isCat, isBot: !!this.isBot, isLocked: !!this.isLocked, @@ -389,4 +428,11 @@ export default Vue.extend({ height 72px margin auto +.fields + > header + padding 8px 0px + font-weight bold + > div + padding-left 16px + diff --git a/src/models/repositories/user.ts b/src/models/repositories/user.ts index 4e85fd7b93..a04b87f77c 100644 --- a/src/models/repositories/user.ts +++ b/src/models/repositories/user.ts @@ -148,6 +148,7 @@ export class UserRepository extends Repository { description: profile!.description, location: profile!.location, birthday: profile!.birthday, + fields: profile!.fields, followersCount: user.followersCount, followingCount: user.followingCount, notesCount: user.notesCount, diff --git a/src/remote/activitypub/renderer/person.ts b/src/remote/activitypub/renderer/person.ts index efe52cdefb..d4c018fb78 100644 --- a/src/remote/activitypub/renderer/person.ts +++ b/src/remote/activitypub/renderer/person.ts @@ -21,13 +21,24 @@ export async function renderPerson(user: ILocalUser) { ]); const attachment: { - type: string, + type: 'PropertyValue', name: string, value: string, - verified_at?: string, identifier?: IIdentifier }[] = []; + if (profile.fields) { + for (const field of profile.fields) { + attachment.push({ + type: 'PropertyValue', + name: field.name, + value: (field.value != null && field.value.match(/^https?:/)) + ? `${new URL(field.value).href}` + : field.value + }); + } + } + if (profile.twitter) { attachment.push({ type: 'PropertyValue', diff --git a/src/server/api/endpoints/i/update.ts b/src/server/api/endpoints/i/update.ts index a454cdb940..149081e50b 100644 --- a/src/server/api/endpoints/i/update.ts +++ b/src/server/api/endpoints/i/update.ts @@ -77,6 +77,13 @@ export const meta = { } }, + fields: { + validator: $.optional.arr($.object()).range(1, 4), + desc: { + 'ja-JP': 'プロフィール補足情報' + } + }, + isLocked: { validator: $.optional.bool, desc: { @@ -226,6 +233,14 @@ export default define(meta, async (ps, user, app) => { profileUpdates.pinnedPageId = null; } + if (ps.fields) { + profileUpdates.fields = ps.fields + .filter(x => typeof x.name === 'string' && x.name !== '' && typeof x.value === 'string' && x.value !== '') + .map(x => { + return { name: x.name, value: x.value }; + }); + } + //#region emojis/tags let emojis = [] as string[]; diff --git a/src/server/web/index.ts b/src/server/web/index.ts index 8cf6a75208..6c41bbde46 100644 --- a/src/server/web/index.ts +++ b/src/server/web/index.ts @@ -156,11 +156,17 @@ router.get('/@:user', async (ctx, next) => { if (user != null) { const profile = await UserProfiles.findOne(user.id).then(ensure); const meta = await fetchMeta(); + const me = profile.fields + ? profile.fields + .filter(filed => filed.value != null && filed.value.match(/^https?:/)) + .map(field => field.value) + : []; + await ctx.render('user', { - user, profile, + user, profile, me, instanceName: meta.name || 'Misskey' }); - ctx.set('Cache-Control', 'public, max-age=180'); + ctx.set('Cache-Control', 'public, max-age=30'); } else { // リモートユーザーなので await next(); diff --git a/src/server/web/views/base.pug b/src/server/web/views/base.pug index 733a306d56..16bea853e7 100644 --- a/src/server/web/views/base.pug +++ b/src/server/web/views/base.pug @@ -44,3 +44,4 @@ html + block content diff --git a/src/server/web/views/user.pug b/src/server/web/views/user.pug index 9b257afb7b..6ff86b09be 100644 --- a/src/server/web/views/user.pug +++ b/src/server/web/views/user.pug @@ -36,3 +36,8 @@ block meta link(rel='alternate' href=user.uri type='application/activity+json') if profile.url link(rel='alternate' href=profile.url type='text/html') + +block content + div#me + each m in me + a(rel='me' href=`${m}`) #{m} -- cgit v1.2.3-freya