Send an email on video abuse report
This commit is contained in:
parent
09c93c2031
commit
ba75d26859
|
@ -1,7 +1,10 @@
|
||||||
import { createTransport, Transporter } from 'nodemailer'
|
import { createTransport, Transporter } from 'nodemailer'
|
||||||
|
import { UserRight } from '../../shared/models/users'
|
||||||
import { isTestInstance } from '../helpers/core-utils'
|
import { isTestInstance } from '../helpers/core-utils'
|
||||||
import { logger } from '../helpers/logger'
|
import { logger } from '../helpers/logger'
|
||||||
import { CONFIG } from '../initializers'
|
import { CONFIG } from '../initializers'
|
||||||
|
import { UserModel } from '../models/account/user'
|
||||||
|
import { VideoModel } from '../models/video/video'
|
||||||
import { JobQueue } from './job-queue'
|
import { JobQueue } from './job-queue'
|
||||||
import { EmailPayload } from './job-queue/handlers/email'
|
import { EmailPayload } from './job-queue/handlers/email'
|
||||||
import { readFileSync } from 'fs'
|
import { readFileSync } from 'fs'
|
||||||
|
@ -82,6 +85,24 @@ class Emailer {
|
||||||
return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload })
|
return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async addVideoAbuseReport (videoId: number) {
|
||||||
|
const video = await VideoModel.load(videoId)
|
||||||
|
|
||||||
|
const text = `Hi,\n\n` +
|
||||||
|
`Your instance received an abuse for video the following video ${video.url}\n\n` +
|
||||||
|
`Cheers,\n` +
|
||||||
|
`PeerTube.`
|
||||||
|
|
||||||
|
const to = await UserModel.listEmailsWithRight(UserRight.MANAGE_VIDEO_ABUSES)
|
||||||
|
const emailPayload: EmailPayload = {
|
||||||
|
to,
|
||||||
|
subject: '[PeerTube] Received a video abuse',
|
||||||
|
text
|
||||||
|
}
|
||||||
|
|
||||||
|
return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload })
|
||||||
|
}
|
||||||
|
|
||||||
sendMail (to: string[], subject: string, text: string) {
|
sendMail (to: string[], subject: string, text: string) {
|
||||||
if (!this.transporter) {
|
if (!this.transporter) {
|
||||||
throw new Error('Cannot send mail because SMTP is not configured.')
|
throw new Error('Cannot send mail because SMTP is not configured.')
|
||||||
|
|
|
@ -4,7 +4,7 @@ import {
|
||||||
Scopes, Table, UpdatedAt
|
Scopes, Table, UpdatedAt
|
||||||
} from 'sequelize-typescript'
|
} from 'sequelize-typescript'
|
||||||
import { hasUserRight, USER_ROLE_LABELS, UserRight } from '../../../shared'
|
import { hasUserRight, USER_ROLE_LABELS, UserRight } from '../../../shared'
|
||||||
import { User } from '../../../shared/models/users'
|
import { User, UserRole } from '../../../shared/models/users'
|
||||||
import {
|
import {
|
||||||
isUserAutoPlayVideoValid, isUserDisplayNSFWValid, isUserPasswordValid, isUserRoleValid, isUserUsernameValid,
|
isUserAutoPlayVideoValid, isUserDisplayNSFWValid, isUserPasswordValid, isUserRoleValid, isUserUsernameValid,
|
||||||
isUserVideoQuotaValid
|
isUserVideoQuotaValid
|
||||||
|
@ -137,6 +137,27 @@ export class UserModel extends Model<UserModel> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static listEmailsWithRight (right: UserRight) {
|
||||||
|
const roles = Object.keys(USER_ROLE_LABELS)
|
||||||
|
.map(k => parseInt(k, 10) as UserRole)
|
||||||
|
.filter(role => hasUserRight(role, right))
|
||||||
|
|
||||||
|
console.log(roles)
|
||||||
|
|
||||||
|
const query = {
|
||||||
|
attribute: [ 'email' ],
|
||||||
|
where: {
|
||||||
|
role: {
|
||||||
|
[Sequelize.Op.in]: roles
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return UserModel.unscoped()
|
||||||
|
.findAll(query)
|
||||||
|
.then(u => u.map(u => u.email))
|
||||||
|
}
|
||||||
|
|
||||||
static loadById (id: number) {
|
static loadById (id: number) {
|
||||||
return UserModel.findById(id)
|
return UserModel.findById(id)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import { AllowNull, BelongsTo, Column, CreatedAt, ForeignKey, Is, Model, Table, UpdatedAt } from 'sequelize-typescript'
|
import { AfterCreate, AllowNull, BelongsTo, Column, CreatedAt, ForeignKey, Is, Model, Table, UpdatedAt } from 'sequelize-typescript'
|
||||||
import { VideoAbuseObject } from '../../../shared/models/activitypub/objects'
|
import { VideoAbuseObject } from '../../../shared/models/activitypub/objects'
|
||||||
import { isVideoAbuseReasonValid } from '../../helpers/custom-validators/videos'
|
import { isVideoAbuseReasonValid } from '../../helpers/custom-validators/videos'
|
||||||
import { CONFIG } from '../../initializers'
|
import { CONFIG } from '../../initializers'
|
||||||
|
import { Emailer } from '../../lib/emailer'
|
||||||
import { AccountModel } from '../account/account'
|
import { AccountModel } from '../account/account'
|
||||||
import { getSort, throwIfNotValid } from '../utils'
|
import { getSort, throwIfNotValid } from '../utils'
|
||||||
import { VideoModel } from './video'
|
import { VideoModel } from './video'
|
||||||
|
@ -54,6 +55,11 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> {
|
||||||
})
|
})
|
||||||
Video: VideoModel
|
Video: VideoModel
|
||||||
|
|
||||||
|
@AfterCreate
|
||||||
|
static sendEmailNotification (instance: VideoAbuseModel) {
|
||||||
|
return Emailer.Instance.addVideoAbuseReport(instance.videoId)
|
||||||
|
}
|
||||||
|
|
||||||
static listForApi (start: number, count: number, sort: string) {
|
static listForApi (start: number, count: number, sort: string) {
|
||||||
const query = {
|
const query = {
|
||||||
offset: start,
|
offset: start,
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import * as chai from 'chai'
|
import * as chai from 'chai'
|
||||||
import 'mocha'
|
import 'mocha'
|
||||||
import { askResetPassword, createUser, resetPassword, runServer, userLogin, wait } from '../../utils'
|
import { askResetPassword, createUser, reportVideoAbuse, resetPassword, runServer, uploadVideo, userLogin, wait } from '../../utils'
|
||||||
import { flushTests, killallServers, ServerInfo, setAccessTokensToServers } from '../../utils/index'
|
import { flushTests, killallServers, ServerInfo, setAccessTokensToServers } from '../../utils/index'
|
||||||
import { mockSmtpServer } from '../../utils/miscs/email'
|
import { mockSmtpServer } from '../../utils/miscs/email'
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ const expect = chai.expect
|
||||||
describe('Test emails', function () {
|
describe('Test emails', function () {
|
||||||
let server: ServerInfo
|
let server: ServerInfo
|
||||||
let userId: number
|
let userId: number
|
||||||
|
let videoUUID: string
|
||||||
let verificationString: string
|
let verificationString: string
|
||||||
const emails: object[] = []
|
const emails: object[] = []
|
||||||
const user = {
|
const user = {
|
||||||
|
@ -35,8 +36,18 @@ describe('Test emails', function () {
|
||||||
await wait(5000)
|
await wait(5000)
|
||||||
await setAccessTokensToServers([ server ])
|
await setAccessTokensToServers([ server ])
|
||||||
|
|
||||||
const res = await createUser(server.url, server.accessToken, user.username, user.password)
|
{
|
||||||
userId = res.body.user.id
|
const res = await createUser(server.url, server.accessToken, user.username, user.password)
|
||||||
|
userId = res.body.user.id
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const attributes = {
|
||||||
|
name: 'my super name'
|
||||||
|
}
|
||||||
|
const res = await uploadVideo(server.url, server.accessToken, attributes)
|
||||||
|
videoUUID = res.body.video.uuid
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('When resetting user password', function () {
|
describe('When resetting user password', function () {
|
||||||
|
@ -83,6 +94,25 @@ describe('Test emails', function () {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('When creating a video abuse', function () {
|
||||||
|
it('Should send the notification email', async function () {
|
||||||
|
this.timeout(10000)
|
||||||
|
|
||||||
|
const reason = 'my super bad reason'
|
||||||
|
await reportVideoAbuse(server.url, server.accessToken, videoUUID, reason)
|
||||||
|
|
||||||
|
await wait(3000)
|
||||||
|
expect(emails).to.have.lengthOf(2)
|
||||||
|
|
||||||
|
const email = emails[1]
|
||||||
|
|
||||||
|
expect(email['from'][0]['address']).equal('test-admin@localhost')
|
||||||
|
expect(email['to'][0]['address']).equal('admin1@example.com')
|
||||||
|
expect(email['subject']).contains('abuse')
|
||||||
|
expect(email['text']).contains(videoUUID)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
after(async function () {
|
after(async function () {
|
||||||
killallServers([ server ])
|
killallServers([ server ])
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import * as request from 'supertest'
|
import * as request from 'supertest'
|
||||||
|
|
||||||
function reportVideoAbuse (url: string, token: string, videoId: number, reason: string, specialStatus = 204) {
|
function reportVideoAbuse (url: string, token: string, videoId: number | string, reason: string, specialStatus = 204) {
|
||||||
const path = '/api/v1/videos/' + videoId + '/abuse'
|
const path = '/api/v1/videos/' + videoId + '/abuse'
|
||||||
|
|
||||||
return request(url)
|
return request(url)
|
||||||
|
|
|
@ -7,7 +7,8 @@ export enum UserRole {
|
||||||
USER = 2
|
USER = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
export const USER_ROLE_LABELS = {
|
// TODO: use UserRole for key once https://github.com/Microsoft/TypeScript/issues/13042 is fixed
|
||||||
|
export const USER_ROLE_LABELS: { [ id: number ]: string } = {
|
||||||
[UserRole.USER]: 'User',
|
[UserRole.USER]: 'User',
|
||||||
[UserRole.MODERATOR]: 'Moderator',
|
[UserRole.MODERATOR]: 'Moderator',
|
||||||
[UserRole.ADMINISTRATOR]: 'Administrator'
|
[UserRole.ADMINISTRATOR]: 'Administrator'
|
||||||
|
|
Loading…
Reference in New Issue
Block a user