From a4101923e699e49ceb9ff36e971c75417fafc9f0 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 9 Jan 2019 15:14:29 +0100 Subject: Implement contact form on server side --- server/tests/api/check-params/config.ts | 3 + server/tests/api/check-params/contact-form.ts | 92 +++++++++++++++++++++++++++ server/tests/api/check-params/index.ts | 2 +- server/tests/api/server/config.ts | 19 ++++++ server/tests/api/server/contact-form.ts | 84 ++++++++++++++++++++++++ server/tests/api/server/handle-down.ts | 11 ++-- server/tests/api/server/index.ts | 1 + server/tests/helpers/core-utils.ts | 52 ++++++++++++++- 8 files changed, 256 insertions(+), 8 deletions(-) create mode 100644 server/tests/api/check-params/contact-form.ts create mode 100644 server/tests/api/server/contact-form.ts (limited to 'server/tests') diff --git a/server/tests/api/check-params/config.ts b/server/tests/api/check-params/config.ts index b7bf41b58..4038ecbf0 100644 --- a/server/tests/api/check-params/config.ts +++ b/server/tests/api/check-params/config.ts @@ -48,6 +48,9 @@ describe('Test config API validators', function () { admin: { email: 'superadmin1@example.com' }, + contactForm: { + enabled: false + }, user: { videoQuota: 5242881, videoQuotaDaily: 318742 diff --git a/server/tests/api/check-params/contact-form.ts b/server/tests/api/check-params/contact-form.ts new file mode 100644 index 000000000..2407ac0b5 --- /dev/null +++ b/server/tests/api/check-params/contact-form.ts @@ -0,0 +1,92 @@ +/* tslint:disable:no-unused-expression */ + +import 'mocha' + +import { + flushTests, + immutableAssign, + killallServers, + reRunServer, + runServer, + ServerInfo, + setAccessTokensToServers +} from '../../../../shared/utils' +import { + checkBadCountPagination, + checkBadSortPagination, + checkBadStartPagination +} from '../../../../shared/utils/requests/check-api-params' +import { getAccount } from '../../../../shared/utils/users/accounts' +import { sendContactForm } from '../../../../shared/utils/server/contact-form' +import { MockSmtpServer } from '../../../../shared/utils/miscs/email' + +describe('Test contact form API validators', function () { + let server: ServerInfo + const emails: object[] = [] + const defaultBody = { + fromName: 'super name', + fromEmail: 'toto@example.com', + body: 'Hello, how are you?' + } + + // --------------------------------------------------------------- + + before(async function () { + this.timeout(60000) + + await flushTests() + await MockSmtpServer.Instance.collectEmails(emails) + + // Email is disabled + server = await runServer(1) + }) + + it('Should not accept a contact form if emails are disabled', async function () { + await sendContactForm(immutableAssign(defaultBody, { url: server.url, expectedStatus: 409 })) + }) + + it('Should not accept a contact form if it is disabled in the configuration', async function () { + killallServers([ server ]) + + // Contact form is disabled + await reRunServer(server, { smtp: { hostname: 'localhost' }, contact_form: { enabled: false } }) + await sendContactForm(immutableAssign(defaultBody, { url: server.url, expectedStatus: 409 })) + }) + + it('Should not accept a contact form if from email is invalid', async function () { + killallServers([ server ]) + + // Email & contact form enabled + await reRunServer(server, { smtp: { hostname: 'localhost' } }) + + await sendContactForm(immutableAssign(defaultBody, { url: server.url, expectedStatus: 400, fromEmail: 'badEmail' })) + await sendContactForm(immutableAssign(defaultBody, { url: server.url, expectedStatus: 400, fromEmail: 'badEmail@' })) + await sendContactForm(immutableAssign(defaultBody, { url: server.url, expectedStatus: 400, fromEmail: undefined })) + }) + + it('Should not accept a contact form if from name is invalid', async function () { + await sendContactForm(immutableAssign(defaultBody, { url: server.url, expectedStatus: 400, fromName: 'name'.repeat(100) })) + await sendContactForm(immutableAssign(defaultBody, { url: server.url, expectedStatus: 400, fromName: '' })) + await sendContactForm(immutableAssign(defaultBody, { url: server.url, expectedStatus: 400, fromName: undefined })) + }) + + it('Should not accept a contact form if body is invalid', async function () { + await sendContactForm(immutableAssign(defaultBody, { url: server.url, expectedStatus: 400, body: 'body'.repeat(5000) })) + await sendContactForm(immutableAssign(defaultBody, { url: server.url, expectedStatus: 400, body: 'a' })) + await sendContactForm(immutableAssign(defaultBody, { url: server.url, expectedStatus: 400, body: undefined })) + }) + + it('Should accept a contact form with the correct parameters', async function () { + await sendContactForm(immutableAssign(defaultBody, { url: server.url })) + }) + + after(async function () { + MockSmtpServer.Instance.kill() + killallServers([ server ]) + + // Keep the logs if the test failed + if (this['ok']) { + await flushTests() + } + }) +}) diff --git a/server/tests/api/check-params/index.ts b/server/tests/api/check-params/index.ts index 7a181d1d6..77c17036a 100644 --- a/server/tests/api/check-params/index.ts +++ b/server/tests/api/check-params/index.ts @@ -1,7 +1,7 @@ -// Order of the tests we want to execute import './accounts' import './blocklist' import './config' +import './contact-form' import './follows' import './jobs' import './redundancy' diff --git a/server/tests/api/server/config.ts b/server/tests/api/server/config.ts index 4c163d47d..bebfc7398 100644 --- a/server/tests/api/server/config.ts +++ b/server/tests/api/server/config.ts @@ -33,14 +33,20 @@ function checkInitialConfig (data: CustomConfig) { expect(data.instance.defaultNSFWPolicy).to.equal('display') expect(data.instance.customizations.css).to.be.empty expect(data.instance.customizations.javascript).to.be.empty + expect(data.services.twitter.username).to.equal('@Chocobozzz') expect(data.services.twitter.whitelisted).to.be.false + expect(data.cache.previews.size).to.equal(1) expect(data.cache.captions.size).to.equal(1) + expect(data.signup.enabled).to.be.true expect(data.signup.limit).to.equal(4) expect(data.signup.requiresEmailVerification).to.be.false + expect(data.admin.email).to.equal('admin1@example.com') + expect(data.contactForm.enabled).to.be.true + expect(data.user.videoQuota).to.equal(5242880) expect(data.user.videoQuotaDaily).to.equal(-1) expect(data.transcoding.enabled).to.be.false @@ -64,16 +70,23 @@ function checkUpdatedConfig (data: CustomConfig) { expect(data.instance.defaultNSFWPolicy).to.equal('blur') expect(data.instance.customizations.javascript).to.equal('alert("coucou")') expect(data.instance.customizations.css).to.equal('body { background-color: red; }') + expect(data.services.twitter.username).to.equal('@Kuja') expect(data.services.twitter.whitelisted).to.be.true + expect(data.cache.previews.size).to.equal(2) expect(data.cache.captions.size).to.equal(3) + expect(data.signup.enabled).to.be.false expect(data.signup.limit).to.equal(5) expect(data.signup.requiresEmailVerification).to.be.true + expect(data.admin.email).to.equal('superadmin1@example.com') + expect(data.contactForm.enabled).to.be.false + expect(data.user.videoQuota).to.equal(5242881) expect(data.user.videoQuotaDaily).to.equal(318742) + expect(data.transcoding.enabled).to.be.true expect(data.transcoding.threads).to.equal(1) expect(data.transcoding.allowAdditionalExtensions).to.be.true @@ -82,6 +95,7 @@ function checkUpdatedConfig (data: CustomConfig) { expect(data.transcoding.resolutions['480p']).to.be.true expect(data.transcoding.resolutions['720p']).to.be.false expect(data.transcoding.resolutions['1080p']).to.be.false + expect(data.import.videos.http.enabled).to.be.false expect(data.import.videos.torrent.enabled).to.be.false } @@ -127,6 +141,8 @@ describe('Test config', function () { expect(data.video.file.extensions).to.contain('.mp4') expect(data.video.file.extensions).to.contain('.webm') expect(data.video.file.extensions).to.contain('.ogv') + + expect(data.contactForm.enabled).to.be.true }) it('Should get the customized configuration', async function () { @@ -172,6 +188,9 @@ describe('Test config', function () { admin: { email: 'superadmin1@example.com' }, + contactForm: { + enabled: false + }, user: { videoQuota: 5242881, videoQuotaDaily: 318742 diff --git a/server/tests/api/server/contact-form.ts b/server/tests/api/server/contact-form.ts new file mode 100644 index 000000000..1a165331b --- /dev/null +++ b/server/tests/api/server/contact-form.ts @@ -0,0 +1,84 @@ +/* tslint:disable:no-unused-expression */ + +import * as chai from 'chai' +import 'mocha' +import { flushTests, killallServers, runServer, ServerInfo, setAccessTokensToServers, wait } from '../../../../shared/utils' +import { MockSmtpServer } from '../../../../shared/utils/miscs/email' +import { waitJobs } from '../../../../shared/utils/server/jobs' +import { sendContactForm } from '../../../../shared/utils/server/contact-form' + +const expect = chai.expect + +describe('Test contact form', function () { + let server: ServerInfo + const emails: object[] = [] + + before(async function () { + this.timeout(30000) + + await MockSmtpServer.Instance.collectEmails(emails) + + await flushTests() + + const overrideConfig = { + smtp: { + hostname: 'localhost' + } + } + server = await runServer(1, overrideConfig) + await setAccessTokensToServers([ server ]) + }) + + it('Should send a contact form', async function () { + await sendContactForm({ + url: server.url, + fromEmail: 'toto@example.com', + body: 'my super message', + fromName: 'Super toto' + }) + + await waitJobs(server) + + expect(emails).to.have.lengthOf(1) + + const email = emails[0] + + expect(email['from'][0]['address']).equal('toto@example.com') + expect(email['to'][0]['address']).equal('admin1@example.com') + expect(email['subject']).contains('Contact form') + expect(email['text']).contains('my super message') + }) + + it('Should not be able to send another contact form because of the anti spam checker', async function () { + await sendContactForm({ + url: server.url, + fromEmail: 'toto@example.com', + body: 'my super message', + fromName: 'Super toto' + }) + + await sendContactForm({ + url: server.url, + fromEmail: 'toto@example.com', + body: 'my super message', + fromName: 'Super toto', + expectedStatus: 403 + }) + }) + + it('Should be able to send another contact form after a while', async function () { + await wait(1000) + + await sendContactForm({ + url: server.url, + fromEmail: 'toto@example.com', + body: 'my super message', + fromName: 'Super toto' + }) + }) + + after(async function () { + MockSmtpServer.Instance.kill() + killallServers([ server ]) + }) +}) diff --git a/server/tests/api/server/handle-down.ts b/server/tests/api/server/handle-down.ts index 8e162b69e..cd7baadad 100644 --- a/server/tests/api/server/handle-down.ts +++ b/server/tests/api/server/handle-down.ts @@ -8,18 +8,17 @@ import { VideoCommentThreadTree } from '../../../../shared/models/videos/video-c import { completeVideoCheck, - getVideo, - immutableAssign, - reRunServer, - unfollow, - viewVideo, flushAndRunMultipleServers, + getVideo, getVideosList, + immutableAssign, killallServers, + reRunServer, ServerInfo, setAccessTokensToServers, - uploadVideo, + unfollow, updateVideo, + uploadVideo, wait } from '../../../../shared/utils' import { follow, getFollowersListPaginationAndSort } from '../../../../shared/utils/server/follows' diff --git a/server/tests/api/server/index.ts b/server/tests/api/server/index.ts index 6afcab1f9..1f80cc6cf 100644 --- a/server/tests/api/server/index.ts +++ b/server/tests/api/server/index.ts @@ -1,4 +1,5 @@ import './config' +import './contact-form' import './email' import './follow-constraints' import './follows' diff --git a/server/tests/helpers/core-utils.ts b/server/tests/helpers/core-utils.ts index a6d829a9f..e604cf7e3 100644 --- a/server/tests/helpers/core-utils.ts +++ b/server/tests/helpers/core-utils.ts @@ -2,13 +2,16 @@ import * as chai from 'chai' import 'mocha' +import { snakeCase, isNumber } from 'lodash' import { - parseBytes + parseBytes, objectConverter } from '../../helpers/core-utils' +import { isNumeric } from 'validator' const expect = chai.expect describe('Parse Bytes', function () { + it('Should pass when given valid value', async function () { // just return it expect(parseBytes(1024)).to.be.eq(1024) @@ -45,4 +48,51 @@ describe('Parse Bytes', function () { it('Should be invalid when given invalid value', async function () { expect(parseBytes('6GB 1GB')).to.be.eq(6) }) + + it('Should convert an object', async function () { + function keyConverter (k: string) { + return snakeCase(k) + } + + function valueConverter (v: any) { + if (isNumeric(v + '')) return parseInt('' + v, 10) + + return v + } + + const obj = { + mySuperKey: 'hello', + mySuper2Key: '45', + mySuper3Key: { + mySuperSubKey: '15', + mySuperSub2Key: 'hello', + mySuperSub3Key: [ '1', 'hello', 2 ], + mySuperSub4Key: 4 + }, + mySuper4Key: 45, + toto: { + super_key: '15', + superKey2: 'hello' + }, + super_key: { + superKey4: 15 + } + } + + const res = objectConverter(obj, keyConverter, valueConverter) + + expect(res.my_super_key).to.equal('hello') + expect(res.my_super_2_key).to.equal(45) + expect(res.my_super_3_key.my_super_sub_key).to.equal(15) + expect(res.my_super_3_key.my_super_sub_2_key).to.equal('hello') + expect(res.my_super_3_key.my_super_sub_3_key).to.deep.equal([ 1, 'hello', 2 ]) + expect(res.my_super_3_key.my_super_sub_4_key).to.equal(4) + expect(res.toto.super_key).to.equal(15) + expect(res.toto.super_key_2).to.equal('hello') + expect(res.super_key.super_key_4).to.equal(15) + + // Immutable + expect(res.mySuperKey).to.be.undefined + expect(obj['my_super_key']).to.be.undefined + }) }) -- cgit v1.2.3