keep URL of reported object separate

Instead of putting the URL in the report text, it is stored separately
so that users do not accidentally change or remove it.

This way it can easily be used when forwarding reports to different
instances to tell them what exactly was reported.
This commit is contained in:
Johann150 2022-01-21 18:37:22 +01:00
parent 1ec756519e
commit 9ca504784a
Signed by untrusted user: Johann150
GPG key ID: 9EE6577A2A06F8F1
8 changed files with 33 additions and 5 deletions

View file

@ -0,0 +1,11 @@
export class reportedUrls1642698156335 {
name = 'reportedUrls1642698156335';
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "abuse_user_report" ADD "urls" character varying (512) array NOT NULL DEFAULT '{}'::varchar[]`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "abuse_user_report" DROP COLUMN "urls"`);
}
};

View file

@ -56,6 +56,11 @@ export class AbuseUserReport {
}) })
public forwarded: boolean; public forwarded: boolean;
@Column('varchar', {
length: 512, array: true, default: '{}',
})
public urls: string[];
@Column('varchar', { @Column('varchar', {
length: 2048, length: 2048,
}) })

View file

@ -27,6 +27,7 @@ export const AbuseUserReportRepository = db.getRepository(AbuseUserReport).exten
detail: true, detail: true,
}) : null, }) : null,
forwarded: report.forwarded, forwarded: report.forwarded,
urls: report.urls,
}); });
}, },

View file

@ -33,7 +33,7 @@ export default define(meta, paramDef, async (ps, me) => {
const actor = await getInstanceActor(); const actor = await getInstanceActor();
const targetUser = await Users.findOneByOrFail({ id: report.targetUserId }); const targetUser = await Users.findOneByOrFail({ id: report.targetUserId });
deliver(actor, renderActivity(renderFlag(actor, [targetUser.uri!], report.comment)), targetUser.inbox); deliver(actor, renderActivity(renderFlag(actor, report.urls, report.comment)), targetUser.inbox);
} }
await AbuseUserReports.update(report.id, { await AbuseUserReports.update(report.id, {

View file

@ -1,4 +1,5 @@
import * as sanitizeHtml from 'sanitize-html'; import * as sanitizeHtml from 'sanitize-html';
import config from '@/config/index.js';
import { publishAdminStream } from '@/services/stream.js'; import { publishAdminStream } from '@/services/stream.js';
import { AbuseUserReports, Users } from '@/models/index.js'; import { AbuseUserReports, Users } from '@/models/index.js';
import { genId } from '@/misc/gen-id.js'; import { genId } from '@/misc/gen-id.js';
@ -40,6 +41,7 @@ export const paramDef = {
type: 'object', type: 'object',
properties: { properties: {
userId: { type: 'string', format: 'misskey:id' }, userId: { type: 'string', format: 'misskey:id' },
urls: { type: 'array', items: { type: 'string' }, nullable: true, uniqueItems: true },
comment: { type: 'string', minLength: 1, maxLength: 2048 }, comment: { type: 'string', minLength: 1, maxLength: 2048 },
}, },
required: ['userId', 'comment'], required: ['userId', 'comment'],
@ -61,6 +63,11 @@ export default define(meta, paramDef, async (ps, me) => {
throw new ApiError(meta.errors.cannotReportAdmin); throw new ApiError(meta.errors.cannotReportAdmin);
} }
const uri = user.host == null ? `${config.url}/users/${user.id}` : user.uri;
if (!ps.urls.includes(uri)) {
ps.urls.push(uri);
}
const report = await AbuseUserReports.insert({ const report = await AbuseUserReports.insert({
id: genId(), id: genId(),
createdAt: new Date(), createdAt: new Date(),
@ -69,6 +76,7 @@ export default define(meta, paramDef, async (ps, me) => {
reporterId: me.id, reporterId: me.id,
reporterHost: null, reporterHost: null,
comment: ps.comment, comment: ps.comment,
urls: ps.urls,
}).then(x => AbuseUserReports.findOneByOrFail(x.identifiers[0])); }).then(x => AbuseUserReports.findOneByOrFail(x.identifiers[0]));
// Publish event to moderators // Publish event to moderators
@ -87,6 +95,7 @@ export default define(meta, paramDef, async (ps, me) => {
targetUserId: report.targetUserId, targetUserId: report.targetUserId,
reporterId: report.reporterId, reporterId: report.reporterId,
comment: report.comment, comment: report.comment,
urls: report.urls,
}); });
} }

View file

@ -173,6 +173,7 @@ export interface AdminStreamTypes {
targetUserId: User['id'], targetUserId: User['id'],
reporterId: User['id'], reporterId: User['id'],
comment: string; comment: string;
urls: string[];
}; };
} }
//#endregion //#endregion

View file

@ -33,7 +33,7 @@ import { i18n } from '@/i18n';
const props = defineProps<{ const props = defineProps<{
user: Misskey.entities.User; user: Misskey.entities.User;
initialComment?: string; urls?: string[];
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{
@ -41,11 +41,12 @@ const emit = defineEmits<{
}>(); }>();
const uiWindow = ref<InstanceType<typeof XWindow>>(); const uiWindow = ref<InstanceType<typeof XWindow>>();
const comment = ref(props.initialComment || ''); const comment = ref('');
function send() { function send() {
os.apiWithDialog('users/report-abuse', { os.apiWithDialog('users/report-abuse', {
userId: props.user.id, userId: props.user.id,
urls: props.urls || [],
comment: comment.value, comment: comment.value,
}).then(res => { }).then(res => {
os.alert({ os.alert({

View file

@ -291,9 +291,9 @@ export function getNoteMenu(props: {
const u = appearNote.url || appearNote.uri || `${url}/notes/${appearNote.id}`; const u = appearNote.url || appearNote.uri || `${url}/notes/${appearNote.id}`;
os.popup(defineAsyncComponent(() => import('@/components/abuse-report-window.vue')), { os.popup(defineAsyncComponent(() => import('@/components/abuse-report-window.vue')), {
user: appearNote.user, user: appearNote.user,
initialComment: `Note: ${u}\n-----\n`, urls: [u]
}, {}, 'closed'); }, {}, 'closed');
}, }
}] }]
: [] : []
), ),