aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--server/lib/emailer.ts21
-rw-r--r--server/models/account/user.ts23
-rw-r--r--server/models/video/video-abuse.ts8
-rw-r--r--server/tests/api/server/email.ts36
-rw-r--r--server/tests/utils/videos/video-abuses.ts2
-rw-r--r--shared/models/users/user-role.ts3
6 files changed, 86 insertions, 7 deletions
diff --git a/server/lib/emailer.ts b/server/lib/emailer.ts
index 317cec706..bc0061c99 100644
--- a/server/lib/emailer.ts
+++ b/server/lib/emailer.ts
@@ -1,7 +1,10 @@
1import { createTransport, Transporter } from 'nodemailer' 1import { createTransport, Transporter } from 'nodemailer'
2import { UserRight } from '../../shared/models/users'
2import { isTestInstance } from '../helpers/core-utils' 3import { isTestInstance } from '../helpers/core-utils'
3import { logger } from '../helpers/logger' 4import { logger } from '../helpers/logger'
4import { CONFIG } from '../initializers' 5import { CONFIG } from '../initializers'
6import { UserModel } from '../models/account/user'
7import { VideoModel } from '../models/video/video'
5import { JobQueue } from './job-queue' 8import { JobQueue } from './job-queue'
6import { EmailPayload } from './job-queue/handlers/email' 9import { EmailPayload } from './job-queue/handlers/email'
7import { readFileSync } from 'fs' 10import { readFileSync } from 'fs'
@@ -82,6 +85,24 @@ class Emailer {
82 return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) 85 return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload })
83 } 86 }
84 87
88 async addVideoAbuseReport (videoId: number) {
89 const video = await VideoModel.load(videoId)
90
91 const text = `Hi,\n\n` +
92 `Your instance received an abuse for video the following video ${video.url}\n\n` +
93 `Cheers,\n` +
94 `PeerTube.`
95
96 const to = await UserModel.listEmailsWithRight(UserRight.MANAGE_VIDEO_ABUSES)
97 const emailPayload: EmailPayload = {
98 to,
99 subject: '[PeerTube] Received a video abuse',
100 text
101 }
102
103 return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload })
104 }
105
85 sendMail (to: string[], subject: string, text: string) { 106 sendMail (to: string[], subject: string, text: string) {
86 if (!this.transporter) { 107 if (!this.transporter) {
87 throw new Error('Cannot send mail because SMTP is not configured.') 108 throw new Error('Cannot send mail because SMTP is not configured.')
diff --git a/server/models/account/user.ts b/server/models/account/user.ts
index 026a8c9a0..653921907 100644
--- a/server/models/account/user.ts
+++ b/server/models/account/user.ts
@@ -4,7 +4,7 @@ import {
4 Scopes, Table, UpdatedAt 4 Scopes, Table, UpdatedAt
5} from 'sequelize-typescript' 5} from 'sequelize-typescript'
6import { hasUserRight, USER_ROLE_LABELS, UserRight } from '../../../shared' 6import { hasUserRight, USER_ROLE_LABELS, UserRight } from '../../../shared'
7import { User } from '../../../shared/models/users' 7import { User, UserRole } from '../../../shared/models/users'
8import { 8import {
9 isUserAutoPlayVideoValid, isUserDisplayNSFWValid, isUserPasswordValid, isUserRoleValid, isUserUsernameValid, 9 isUserAutoPlayVideoValid, isUserDisplayNSFWValid, isUserPasswordValid, isUserRoleValid, isUserUsernameValid,
10 isUserVideoQuotaValid 10 isUserVideoQuotaValid
@@ -137,6 +137,27 @@ export class UserModel extends Model<UserModel> {
137 }) 137 })
138 } 138 }
139 139
140 static listEmailsWithRight (right: UserRight) {
141 const roles = Object.keys(USER_ROLE_LABELS)
142 .map(k => parseInt(k, 10) as UserRole)
143 .filter(role => hasUserRight(role, right))
144
145 console.log(roles)
146
147 const query = {
148 attribute: [ 'email' ],
149 where: {
150 role: {
151 [Sequelize.Op.in]: roles
152 }
153 }
154 }
155
156 return UserModel.unscoped()
157 .findAll(query)
158 .then(u => u.map(u => u.email))
159 }
160
140 static loadById (id: number) { 161 static loadById (id: number) {
141 return UserModel.findById(id) 162 return UserModel.findById(id)
142 } 163 }
diff --git a/server/models/video/video-abuse.ts b/server/models/video/video-abuse.ts
index 182971c4e..cc7078ae7 100644
--- a/server/models/video/video-abuse.ts
+++ b/server/models/video/video-abuse.ts
@@ -1,7 +1,8 @@
1import { AllowNull, BelongsTo, Column, CreatedAt, ForeignKey, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' 1import { AfterCreate, AllowNull, BelongsTo, Column, CreatedAt, ForeignKey, Is, Model, Table, UpdatedAt } from 'sequelize-typescript'
2import { VideoAbuseObject } from '../../../shared/models/activitypub/objects' 2import { VideoAbuseObject } from '../../../shared/models/activitypub/objects'
3import { isVideoAbuseReasonValid } from '../../helpers/custom-validators/videos' 3import { isVideoAbuseReasonValid } from '../../helpers/custom-validators/videos'
4import { CONFIG } from '../../initializers' 4import { CONFIG } from '../../initializers'
5import { Emailer } from '../../lib/emailer'
5import { AccountModel } from '../account/account' 6import { AccountModel } from '../account/account'
6import { getSort, throwIfNotValid } from '../utils' 7import { getSort, throwIfNotValid } from '../utils'
7import { VideoModel } from './video' 8import { VideoModel } from './video'
@@ -54,6 +55,11 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> {
54 }) 55 })
55 Video: VideoModel 56 Video: VideoModel
56 57
58 @AfterCreate
59 static sendEmailNotification (instance: VideoAbuseModel) {
60 return Emailer.Instance.addVideoAbuseReport(instance.videoId)
61 }
62
57 static listForApi (start: number, count: number, sort: string) { 63 static listForApi (start: number, count: number, sort: string) {
58 const query = { 64 const query = {
59 offset: start, 65 offset: start,
diff --git a/server/tests/api/server/email.ts b/server/tests/api/server/email.ts
index 8eb9c0fa4..068e820c8 100644
--- a/server/tests/api/server/email.ts
+++ b/server/tests/api/server/email.ts
@@ -2,7 +2,7 @@
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
5import { askResetPassword, createUser, resetPassword, runServer, userLogin, wait } from '../../utils' 5import { askResetPassword, createUser, reportVideoAbuse, resetPassword, runServer, uploadVideo, userLogin, wait } from '../../utils'
6import { flushTests, killallServers, ServerInfo, setAccessTokensToServers } from '../../utils/index' 6import { flushTests, killallServers, ServerInfo, setAccessTokensToServers } from '../../utils/index'
7import { mockSmtpServer } from '../../utils/miscs/email' 7import { mockSmtpServer } from '../../utils/miscs/email'
8 8
@@ -11,6 +11,7 @@ const expect = chai.expect
11describe('Test emails', function () { 11describe('Test emails', function () {
12 let server: ServerInfo 12 let server: ServerInfo
13 let userId: number 13 let userId: number
14 let videoUUID: string
14 let verificationString: string 15 let verificationString: string
15 const emails: object[] = [] 16 const emails: object[] = []
16 const user = { 17 const user = {
@@ -35,8 +36,18 @@ describe('Test emails', function () {
35 await wait(5000) 36 await wait(5000)
36 await setAccessTokensToServers([ server ]) 37 await setAccessTokensToServers([ server ])
37 38
38 const res = await createUser(server.url, server.accessToken, user.username, user.password) 39 {
39 userId = res.body.user.id 40 const res = await createUser(server.url, server.accessToken, user.username, user.password)
41 userId = res.body.user.id
42 }
43
44 {
45 const attributes = {
46 name: 'my super name'
47 }
48 const res = await uploadVideo(server.url, server.accessToken, attributes)
49 videoUUID = res.body.video.uuid
50 }
40 }) 51 })
41 52
42 describe('When resetting user password', function () { 53 describe('When resetting user password', function () {
@@ -83,6 +94,25 @@ describe('Test emails', function () {
83 }) 94 })
84 }) 95 })
85 96
97 describe('When creating a video abuse', function () {
98 it('Should send the notification email', async function () {
99 this.timeout(10000)
100
101 const reason = 'my super bad reason'
102 await reportVideoAbuse(server.url, server.accessToken, videoUUID, reason)
103
104 await wait(3000)
105 expect(emails).to.have.lengthOf(2)
106
107 const email = emails[1]
108
109 expect(email['from'][0]['address']).equal('test-admin@localhost')
110 expect(email['to'][0]['address']).equal('admin1@example.com')
111 expect(email['subject']).contains('abuse')
112 expect(email['text']).contains(videoUUID)
113 })
114 })
115
86 after(async function () { 116 after(async function () {
87 killallServers([ server ]) 117 killallServers([ server ])
88 118
diff --git a/server/tests/utils/videos/video-abuses.ts b/server/tests/utils/videos/video-abuses.ts
index f00809234..0d72bf457 100644
--- a/server/tests/utils/videos/video-abuses.ts
+++ b/server/tests/utils/videos/video-abuses.ts
@@ -1,6 +1,6 @@
1import * as request from 'supertest' 1import * as request from 'supertest'
2 2
3function reportVideoAbuse (url: string, token: string, videoId: number, reason: string, specialStatus = 204) { 3function reportVideoAbuse (url: string, token: string, videoId: number | string, reason: string, specialStatus = 204) {
4 const path = '/api/v1/videos/' + videoId + '/abuse' 4 const path = '/api/v1/videos/' + videoId + '/abuse'
5 5
6 return request(url) 6 return request(url)
diff --git a/shared/models/users/user-role.ts b/shared/models/users/user-role.ts
index 0e75444f8..271c9a46f 100644
--- a/shared/models/users/user-role.ts
+++ b/shared/models/users/user-role.ts
@@ -7,7 +7,8 @@ export enum UserRole {
7 USER = 2 7 USER = 2
8} 8}
9 9
10export const USER_ROLE_LABELS = { 10// TODO: use UserRole for key once https://github.com/Microsoft/TypeScript/issues/13042 is fixed
11export const USER_ROLE_LABELS: { [ id: number ]: string } = {
11 [UserRole.USER]: 'User', 12 [UserRole.USER]: 'User',
12 [UserRole.MODERATOR]: 'Moderator', 13 [UserRole.MODERATOR]: 'Moderator',
13 [UserRole.ADMINISTRATOR]: 'Administrator' 14 [UserRole.ADMINISTRATOR]: 'Administrator'