From 43d0ea7f4b88d52097172cc0c1831edd7e492503 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 28 Aug 2019 14:40:06 +0200 Subject: Add welcome modal --- server/controllers/api/users/me.ts | 22 ++++---- server/helpers/custom-validators/users.ts | 10 ++++ server/initializers/migrations/0425-user-modals.ts | 40 +++++++++++++++ server/middlewares/validators/users.ts | 7 +++ server/models/account/user.ts | 58 +++++++++++++++++----- server/tests/api/check-params/users.ts | 20 +++++++- server/tests/api/users/users.ts | 21 +++++++- 7 files changed, 153 insertions(+), 25 deletions(-) create mode 100644 server/initializers/migrations/0425-user-modals.ts (limited to 'server') diff --git a/server/controllers/api/users/me.ts b/server/controllers/api/users/me.ts index 78e1e7fa3..fb1ddbc6d 100644 --- a/server/controllers/api/users/me.ts +++ b/server/controllers/api/users/me.ts @@ -127,7 +127,7 @@ async function getUserInformation (req: express.Request, res: express.Response) // We did not load channels in res.locals.user const user = await UserModel.loadByUsernameAndPopulateChannels(res.locals.oauth.token.user.username) - return res.json(user.toFormattedJSON({})) + return res.json(user.toFormattedJSON()) } async function getUserVideoQuotaUsed (req: express.Request, res: express.Response) { @@ -178,6 +178,8 @@ async function updateMe (req: express.Request, res: express.Response) { if (body.videosHistoryEnabled !== undefined) user.videosHistoryEnabled = body.videosHistoryEnabled if (body.videoLanguages !== undefined) user.videoLanguages = body.videoLanguages if (body.theme !== undefined) user.theme = body.theme + if (body.noInstanceConfigWarningModal !== undefined) user.noInstanceConfigWarningModal = body.noInstanceConfigWarningModal + if (body.noWelcomeModal !== undefined) user.noWelcomeModal = body.noWelcomeModal if (body.email !== undefined) { if (CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION) { @@ -188,17 +190,19 @@ async function updateMe (req: express.Request, res: express.Response) { } } - await sequelizeTypescript.transaction(async t => { - const userAccount = await AccountModel.load(user.Account.id) + if (body.displayName !== undefined || body.description !== undefined) { + await sequelizeTypescript.transaction(async t => { + const userAccount = await AccountModel.load(user.Account.id, t) - await user.save({ transaction: t }) + await user.save({ transaction: t }) - if (body.displayName !== undefined) userAccount.name = body.displayName - if (body.description !== undefined) userAccount.description = body.description - await userAccount.save({ transaction: t }) + if (body.displayName !== undefined) userAccount.name = body.displayName + if (body.description !== undefined) userAccount.description = body.description + await userAccount.save({ transaction: t }) - await sendUpdateActor(userAccount, t) - }) + await sendUpdateActor(userAccount, t) + }) + } if (sendVerificationEmail === true) { await sendVerifyUserEmail(user, true) diff --git a/server/helpers/custom-validators/users.ts b/server/helpers/custom-validators/users.ts index c56ae14ef..68e84d9eb 100644 --- a/server/helpers/custom-validators/users.ts +++ b/server/helpers/custom-validators/users.ts @@ -65,6 +65,14 @@ function isUserBlockedValid (value: any) { return isBooleanValid(value) } +function isNoInstanceConfigWarningModal (value: any) { + return isBooleanValid(value) +} + +function isNoWelcomeModal (value: any) { + return isBooleanValid(value) +} + function isUserBlockedReasonValid (value: any) { return value === null || (exists(value) && validator.isLength(value, CONSTRAINTS_FIELDS.USERS.BLOCKED_REASON)) } @@ -100,5 +108,7 @@ export { isUserAutoPlayVideoValid, isUserDisplayNameValid, isUserDescriptionValid, + isNoInstanceConfigWarningModal, + isNoWelcomeModal, isAvatarFile } diff --git a/server/initializers/migrations/0425-user-modals.ts b/server/initializers/migrations/0425-user-modals.ts new file mode 100644 index 000000000..5c2aa85b5 --- /dev/null +++ b/server/initializers/migrations/0425-user-modals.ts @@ -0,0 +1,40 @@ +import * as Sequelize from 'sequelize' + +async function up (utils: { + transaction: Sequelize.Transaction, + queryInterface: Sequelize.QueryInterface, + sequelize: Sequelize.Sequelize, + db: any +}): Promise { + { + const data = { + type: Sequelize.BOOLEAN, + allowNull: false, + defaultValue: false + } + + await utils.queryInterface.addColumn('user', 'noInstanceConfigWarningModal', data) + } + + { + const data = { + type: Sequelize.BOOLEAN, + allowNull: false, + defaultValue: true + } + + await utils.queryInterface.addColumn('user', 'noWelcomeModal', data) + data.defaultValue = false + + await utils.queryInterface.changeColumn('user', 'noWelcomeModal', data) + } +} + +function down (options) { + throw new Error('Not implemented.') +} + +export { + up, + down +} diff --git a/server/middlewares/validators/users.ts b/server/middlewares/validators/users.ts index 26f43cec7..544db76d7 100644 --- a/server/middlewares/validators/users.ts +++ b/server/middlewares/validators/users.ts @@ -4,6 +4,7 @@ import { body, param } from 'express-validator' import { omit } from 'lodash' import { isIdOrUUIDValid, toBooleanOrNull, toIntOrNull } from '../../helpers/custom-validators/misc' import { + isNoInstanceConfigWarningModal, isNoWelcomeModal, isUserAdminFlagsValid, isUserAutoPlayVideoValid, isUserBlockedReasonValid, @@ -216,6 +217,12 @@ const usersUpdateMeValidator = [ body('theme') .optional() .custom(v => isThemeNameValid(v) && isThemeRegistered(v)).withMessage('Should have a valid theme'), + body('noInstanceConfigWarningModal') + .optional() + .custom(v => isNoInstanceConfigWarningModal(v)).withMessage('Should have a valid noInstanceConfigWarningModal boolean'), + body('noWelcomeModal') + .optional() + .custom(v => isNoWelcomeModal(v)).withMessage('Should have a valid noWelcomeModal boolean'), async (req: express.Request, res: express.Response, next: express.NextFunction) => { logger.debug('Checking usersUpdateMe parameters', { parameters: omit(req.body, 'password') }) diff --git a/server/models/account/user.ts b/server/models/account/user.ts index 616dd603c..451e1fd6b 100644 --- a/server/models/account/user.ts +++ b/server/models/account/user.ts @@ -22,6 +22,7 @@ import { import { hasUserRight, USER_ROLE_LABELS, UserRight } from '../../../shared' import { User, UserRole } from '../../../shared/models/users' import { + isNoInstanceConfigWarningModal, isUserAdminFlagsValid, isUserAutoPlayVideoValid, isUserBlockedReasonValid, @@ -35,7 +36,8 @@ import { isUserVideoQuotaDailyValid, isUserVideoQuotaValid, isUserVideosHistoryEnabledValid, - isUserWebTorrentEnabledValid + isUserWebTorrentEnabledValid, + isNoWelcomeModal } from '../../helpers/custom-validators/users' import { comparePassword, cryptPassword } from '../../helpers/peertube-crypto' import { OAuthTokenModel } from '../oauth/oauth-token' @@ -203,6 +205,24 @@ export class UserModel extends Model { @Column theme: string + @AllowNull(false) + @Default(false) + @Is( + 'UserNoInstanceConfigWarningModal', + value => throwIfNotValid(value, isNoInstanceConfigWarningModal, 'no instance config warning modal') + ) + @Column + noInstanceConfigWarningModal: boolean + + @AllowNull(false) + @Default(false) + @Is( + 'UserNoInstanceConfigWarningModal', + value => throwIfNotValid(value, isNoWelcomeModal, 'no welcome modal') + ) + @Column + noWelcomeModal: boolean + @CreatedAt createdAt: Date @@ -560,40 +580,52 @@ export class UserModel extends Model { return comparePassword(password, this.password) } - toSummaryJSON - toFormattedJSON (this: MUserFormattable, parameters: { withAdminFlags?: boolean } = {}): User { const videoQuotaUsed = this.get('videoQuotaUsed') const videoQuotaUsedDaily = this.get('videoQuotaUsedDaily') - const json = { + const json: User = { id: this.id, username: this.username, email: this.email, + theme: getThemeOrDefault(this.theme, DEFAULT_USER_THEME_NAME), + pendingEmail: this.pendingEmail, emailVerified: this.emailVerified, + nsfwPolicy: this.nsfwPolicy, webTorrentEnabled: this.webTorrentEnabled, videosHistoryEnabled: this.videosHistoryEnabled, autoPlayVideo: this.autoPlayVideo, videoLanguages: this.videoLanguages, + role: this.role, - theme: getThemeOrDefault(this.theme, DEFAULT_USER_THEME_NAME), roleLabel: USER_ROLE_LABELS[ this.role ], + videoQuota: this.videoQuota, videoQuotaDaily: this.videoQuotaDaily, - createdAt: this.createdAt, + videoQuotaUsed: videoQuotaUsed !== undefined + ? parseInt(videoQuotaUsed + '', 10) + : undefined, + videoQuotaUsedDaily: videoQuotaUsedDaily !== undefined + ? parseInt(videoQuotaUsedDaily + '', 10) + : undefined, + + noInstanceConfigWarningModal: this.noInstanceConfigWarningModal, + noWelcomeModal: this.noWelcomeModal, + blocked: this.blocked, blockedReason: this.blockedReason, + account: this.Account.toFormattedJSON(), - notificationSettings: this.NotificationSetting ? this.NotificationSetting.toFormattedJSON() : undefined, + + notificationSettings: this.NotificationSetting + ? this.NotificationSetting.toFormattedJSON() + : undefined, + videoChannels: [], - videoQuotaUsed: videoQuotaUsed !== undefined - ? parseInt(videoQuotaUsed + '', 10) - : undefined, - videoQuotaUsedDaily: videoQuotaUsedDaily !== undefined - ? parseInt(videoQuotaUsedDaily + '', 10) - : undefined + + createdAt: this.createdAt } if (parameters.withAdminFlags) { diff --git a/server/tests/api/check-params/users.ts b/server/tests/api/check-params/users.ts index 939b919ed..55094795c 100644 --- a/server/tests/api/check-params/users.ts +++ b/server/tests/api/check-params/users.ts @@ -476,6 +476,22 @@ describe('Test users API validators', function () { await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields }) }) + it('Should fail with an invalid noInstanceConfigWarningModal attribute', async function () { + const fields = { + noInstanceConfigWarningModal: -1 + } + + await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields }) + }) + + it('Should fail with an invalid noWelcomeModal attribute', async function () { + const fields = { + noWelcomeModal: -1 + } + + await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields }) + }) + it('Should succeed to change password with the correct params', async function () { const fields = { currentPassword: 'my super password', @@ -483,7 +499,9 @@ describe('Test users API validators', function () { nsfwPolicy: 'blur', autoPlayVideo: false, email: 'super_email@example.com', - theme: 'default' + theme: 'default', + noInstanceConfigWarningModal: true, + noWelcomeModal: true } await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields, statusCodeExpected: 204 }) diff --git a/server/tests/api/users/users.ts b/server/tests/api/users/users.ts index 3a3fabb4c..95b1bb626 100644 --- a/server/tests/api/users/users.ts +++ b/server/tests/api/users/users.ts @@ -442,7 +442,7 @@ describe('Test users', function () { url: server.url, accessToken: accessTokenUser, currentPassword: 'super password', - newPassword: 'new password' + password: 'new password' }) user.password = 'new password' @@ -543,7 +543,7 @@ describe('Test users', function () { }) const res = await getMyUserInformation(server.url, accessTokenUser) - const user = res.body + const user: User = res.body expect(user.username).to.equal('user_1') expect(user.email).to.equal('updated@example.com') @@ -552,6 +552,8 @@ describe('Test users', function () { expect(user.id).to.be.a('number') expect(user.account.displayName).to.equal('new display name') expect(user.account.description).to.equal('my super description updated') + expect(user.noWelcomeModal).to.be.false + expect(user.noInstanceConfigWarningModal).to.be.false }) it('Should be able to update my theme', async function () { @@ -568,6 +570,21 @@ describe('Test users', function () { expect(body.theme).to.equal(theme) } }) + + it('Should be able to update my modal preferences', async function () { + await updateMyUser({ + url: server.url, + accessToken: accessTokenUser, + noInstanceConfigWarningModal: true, + noWelcomeModal: true + }) + + const res = await getMyUserInformation(server.url, accessTokenUser) + const user: User = res.body + + expect(user.noWelcomeModal).to.be.true + expect(user.noInstanceConfigWarningModal).to.be.true + }) }) describe('Updating another user', function () { -- cgit v1.2.3