From 9f12e63653cba0ea3656c7e17ea736bc23a7822c Mon Sep 17 00:00:00 2001 From: kristoferlund Date: Fri, 20 Jan 2023 12:28:34 +0100 Subject: [PATCH 1/8] Admin user should not be given a fake name --- packages/api/src/database/seeder/app.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/api/src/database/seeder/app.ts b/packages/api/src/database/seeder/app.ts index 2aa51cc30..511e52828 100644 --- a/packages/api/src/database/seeder/app.ts +++ b/packages/api/src/database/seeder/app.ts @@ -109,7 +109,7 @@ export const seedAdminUsers = async (): Promise => { await UserModel.create({ identityEthAddress: e, rewardsEthAddress: e, - username: faker.internet.userName(), + username: e, roles: [UserRole.ADMIN, UserRole.USER], }); } From 283ad36c341f7fa53b49bb33be6438d2af16f104 Mon Sep 17 00:00:00 2001 From: kristoferlund Date: Fri, 20 Jan 2023 13:46:01 +0100 Subject: [PATCH 2/8] Make sure user gets a user name upon activation --- packages/api/src/activate/controllers.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/api/src/activate/controllers.ts b/packages/api/src/activate/controllers.ts index 42dbac80c..963af5ce2 100644 --- a/packages/api/src/activate/controllers.ts +++ b/packages/api/src/activate/controllers.ts @@ -13,6 +13,7 @@ import { UserModel } from '@/user/entities'; import { UserAccountModel } from '@/useraccount/entities'; import { ActivateRequestBody } from './types'; import { generateActivateMessage } from './utils'; +import { generateUserNameFromAccount } from '@/user/utils/entity'; /** * Activate a useraccount and associate it with a user. @@ -65,6 +66,20 @@ const activate = async ( ); if (!user) throw new NotFoundError('User'); + // Set rewardsEthAddress if not set + if (!user.rewardsEthAddress) { + user.rewardsEthAddress = identityEthAddress; + } + + // Set username if not set + if (!user.username || user.username === identityEthAddress) { + user.username = + (await generateUserNameFromAccount(userAccount)) || identityEthAddress; + } + + // Save user changes + await user.save(); + // Link user account with user userAccount.user = user; userAccount.activateToken = undefined; From d5c5c464aa951282399a4f36c3d5fd2680a3c9b5 Mon Sep 17 00:00:00 2001 From: kristoferlund Date: Fri, 20 Jan 2023 14:28:04 +0100 Subject: [PATCH 3/8] Better error messages for status code 500 etc --- packages/frontend/src/utils/axios.ts | 38 ++++++++++++++++++---------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/packages/frontend/src/utils/axios.ts b/packages/frontend/src/utils/axios.ts index f8d751fb6..3f885cbf6 100644 --- a/packages/frontend/src/utils/axios.ts +++ b/packages/frontend/src/utils/axios.ts @@ -9,17 +9,14 @@ import { toast } from 'react-hot-toast'; export const handleErrors = (err: AxiosError): AxiosError => { // Any HTTP Code which is not 2xx will be considered as error - if (err?.response) { - const statusCode = err?.response?.status; - if (statusCode === 404) { - // Resource not found - // Redirect to 404 page - window.location.href = '/404'; - } else if ([403, 400].includes(statusCode)) { - // Forbidden or bad request - const isJsonBlob = (data): data is Blob => - data instanceof Blob && data.type === 'application/json'; - // If the response is a json blob, parse it and display the error message + const isJsonBlob = (data): data is Blob => + data instanceof Blob && data.type === 'application/json'; + + const displayMessageOrDefault = ( + err: AxiosError, + defaultMessage: string + ): void => { + if (err.response) { if (isJsonBlob(err.response.data)) { void (err.response.data as Blob).text().then((text) => { const json = JSON.parse(text); @@ -27,12 +24,27 @@ export const handleErrors = (err: AxiosError): AxiosError => { }); } else if ((err.response.data as Error).message) { toast.error((err.response.data as Error).message); - } else { - toast.error('Something went wrong'); } + } else { + toast.error(defaultMessage); + } + }; + + if (err?.response) { + const statusCode = err.response.status; + if (statusCode === 404) { + // Resource not found + // Redirect to 404 page + window.location.href = '/404'; + } else if (statusCode === 400) { + displayMessageOrDefault(err, 'Bad request'); } else if (statusCode === 401) { // Unauthorized window.location.href = '/'; + } else if (statusCode === 403) { + displayMessageOrDefault(err, 'Forbidden'); + } else if (statusCode === 500) { + displayMessageOrDefault(err, 'Internal Server Error'); } else { toast.error('Unknown Error'); } From 53a70a8c45bdafc34170cd2b9183ded4069cf948 Mon Sep 17 00:00:00 2001 From: kristoferlund Date: Fri, 20 Jan 2023 14:54:10 +0100 Subject: [PATCH 4/8] Improve username generation --- packages/api/src/user/utils/entity.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/api/src/user/utils/entity.ts b/packages/api/src/user/utils/entity.ts index da4966065..3884bd3fb 100644 --- a/packages/api/src/user/utils/entity.ts +++ b/packages/api/src/user/utils/entity.ts @@ -24,9 +24,20 @@ export const generateUserNameFromAccount = async ( username = userAccount.name; } - const exists = await UserModel.find({ username }).lean(); - if (exists.length === 0) return username; - if (userAccount.platform === 'DISCORD') return userAccount.name; + // Return username if it is not taken + let exists = await UserModel.find({ username }).lean(); + if (exists.length === 0) { + return username; + } + + // If username is taken then try to create one with the Discord discriminator + if (userAccount.platform === 'DISCORD') { + exists = await UserModel.find({ username: userAccount.name }).lean(); + if (exists.length === 0) return userAccount.name; + return userAccount.name; + } + + // Unable to generate username return null; }; From 7ef3f5e67d462936dec9c9f5f55f3d89b9e6c48a Mon Sep 17 00:00:00 2001 From: kristoferlund Date: Fri, 20 Jan 2023 15:42:04 +0100 Subject: [PATCH 5/8] Make sure activated users get usernames --- packages/api/src/activate/controllers.ts | 28 ++++++++++++++++-------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/packages/api/src/activate/controllers.ts b/packages/api/src/activate/controllers.ts index 963af5ce2..1d1f64e18 100644 --- a/packages/api/src/activate/controllers.ts +++ b/packages/api/src/activate/controllers.ts @@ -28,23 +28,28 @@ const activate = async ( ): Promise => { const { identityEthAddress, signature, accountId } = req.body; - if (!identityEthAddress || !signature || !accountId) + if (!identityEthAddress || !signature || !accountId) { throw new BadRequestError( 'identityEthAddress, signature, and accountId required' ); + } // Find previously generated token const userAccount = await UserAccountModel.findOne({ accountId }) - .select('_id user activateToken') + .select('_id user activateToken name platform') .exec(); - if (!userAccount) throw new NotFoundError('UserAccount'); - if (!userAccount.activateToken) + if (!userAccount) { + throw new NotFoundError('UserAccount'); + } + if (!userAccount.activateToken) { throw new InternalServerError('Activation token not found.'); + } // You are only allowed to activate once - if (userAccount.user) + if (userAccount.user) { throw new BadRequestError('User account already activated.'); + } // Generate expected message, token included. const generatedMsg = generateActivateMessage( @@ -56,15 +61,18 @@ const activate = async ( // Verify signature against generated message // Recover signer and compare against query address const signerAddress = ethers.utils.verifyMessage(generatedMsg, signature); - if (signerAddress !== identityEthAddress) + if (signerAddress !== identityEthAddress) { throw new UnauthorizedError('Verification failed.'); + } // Find existing user or create new const user = await UserModel.findOneAndUpdate( { identityEthAddress }, { upsert: true, new: true } ); - if (!user) throw new NotFoundError('User'); + if (!user) { + throw new NotFoundError('User'); + } // Set rewardsEthAddress if not set if (!user.rewardsEthAddress) { @@ -73,8 +81,10 @@ const activate = async ( // Set username if not set if (!user.username || user.username === identityEthAddress) { - user.username = - (await generateUserNameFromAccount(userAccount)) || identityEthAddress; + const generatedUserName = await generateUserNameFromAccount(userAccount); + if (generatedUserName) { + user.username = generatedUserName; + } } // Save user changes From e7c70fb7f738ea20445fba22ec24d10f0b86dab4 Mon Sep 17 00:00:00 2001 From: kristoferlund Date: Fri, 20 Jan 2023 15:48:30 +0100 Subject: [PATCH 6/8] Fix for lint --- packages/api/src/activate/controllers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/api/src/activate/controllers.ts b/packages/api/src/activate/controllers.ts index 1d1f64e18..7921d8225 100644 --- a/packages/api/src/activate/controllers.ts +++ b/packages/api/src/activate/controllers.ts @@ -11,9 +11,9 @@ import { logEvent } from '@/eventlog/utils'; import { TypedRequestBody } from '@/shared/types'; import { UserModel } from '@/user/entities'; import { UserAccountModel } from '@/useraccount/entities'; +import { generateUserNameFromAccount } from '@/user/utils/entity'; import { ActivateRequestBody } from './types'; import { generateActivateMessage } from './utils'; -import { generateUserNameFromAccount } from '@/user/utils/entity'; /** * Activate a useraccount and associate it with a user. From 4ba2a7f24a4fcba07f2923eceb582110aa9f42c9 Mon Sep 17 00:00:00 2001 From: kristoferlund Date: Fri, 20 Jan 2023 22:00:19 +0100 Subject: [PATCH 7/8] v0.13.1 --- CHANGELOG.md | 16 ++++++++++++++++ package.json | 2 +- packages/api/package.json | 2 +- packages/discord-bot/package.json | 2 +- packages/frontend/package.json | 2 +- packages/frontend/src/model/app.ts | 2 +- packages/mongodb/package.json | 2 +- packages/setup/package.json | 2 +- 8 files changed, 23 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index efd5286a9..86f9a5e7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Deprecated +## [0.13.1] - 2023-01-20 + +### Fixed + +- **API:** Fixed bug that prevented user activation and gave new users wrong usernames +- **Frontend:** Clicking on user popover should take you to the user page #686 +- **API:** Fixing some export issues due to changes in how the export transformer work because of the change to ses-node-json-transform for evalutaing untrusted code. #685 +- **Frontend**: Praise sort should be dark in dark mode #688 +- **Frontend**: Export dropdown gets squeezed when "close period" button is visible #684 #687 + +### Changed + +- **Devops**: Added docker-compose installation script and modified scripts #754 +- **Devops**: Allow mongodb port number to be configurable in .env #760 +- **Devops**: Enhanced the multi-setup scripts #761 + ## [0.13.0] - 2022-11-18 ### Added diff --git a/package.json b/package.json index b29f3f2e0..78814c562 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "praise", - "version": "0.13.0", + "version": "0.13.1", "license": "GPL-3.0-or-later", "description": "Praise community contributions to build a culture of giving and gratitude.", "private": true, diff --git a/packages/api/package.json b/packages/api/package.json index dd0c129bd..0760359af 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -1,6 +1,6 @@ { "name": "api", - "version": "0.13.0", + "version": "0.13.1", "license": "GPL-3.0-or-later", "description": "The Praise REST API running on Node/Express, using MongoDB for storage.", "type": "commonjs", diff --git a/packages/discord-bot/package.json b/packages/discord-bot/package.json index 406f4d64c..06d56601b 100644 --- a/packages/discord-bot/package.json +++ b/packages/discord-bot/package.json @@ -1,6 +1,6 @@ { "name": "discord-bot", - "version": "0.13.0", + "version": "0.13.1", "license": "GPL-3.0-or-later", "description": "The Praise Discord bot is the main way for users to interact with the Praise system.", "dependencies": { diff --git a/packages/frontend/package.json b/packages/frontend/package.json index ede9fe5e2..5b85d6dbc 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -1,6 +1,6 @@ { "name": "frontend", - "version": "0.13.0", + "version": "0.13.1", "license": "GPL-3.0-or-later", "description": "The Praise dashboard built on React/Recoil/Tailwind CSS.", "private": true, diff --git a/packages/frontend/src/model/app.ts b/packages/frontend/src/model/app.ts index f06a6fb96..2289062b2 100644 --- a/packages/frontend/src/model/app.ts +++ b/packages/frontend/src/model/app.ts @@ -40,7 +40,7 @@ interface PraiseAppVersion { export const usePraiseAppVersion = (): PraiseAppVersion => { const appVersion: PraiseAppVersion = { - current: '0.13.0', //TODO: get this from package.json + current: '0.13.1', //TODO: get this from package.json latest: undefined, newVersionAvailable: false, }; diff --git a/packages/mongodb/package.json b/packages/mongodb/package.json index 8bedb1d51..9d210af90 100644 --- a/packages/mongodb/package.json +++ b/packages/mongodb/package.json @@ -1,6 +1,6 @@ { "name": "mongodb", - "version": "0.13.0", + "version": "0.13.1", "license": "GPL-3.0-or-later", "description": "The Prasie data is stored in a MongoDb database." } diff --git a/packages/setup/package.json b/packages/setup/package.json index ba8ccdcd9..932d63968 100644 --- a/packages/setup/package.json +++ b/packages/setup/package.json @@ -1,6 +1,6 @@ { "name": "setup", - "version": "0.13.0", + "version": "0.13.1", "license": "GPL-3.0-or-later", "type": "commonjs", "description": "Praise ENV setup scripts.", From 1290f37cd76269711a35a310043faab81332f31c Mon Sep 17 00:00:00 2001 From: kristoferlund Date: Fri, 20 Jan 2023 22:56:18 +0100 Subject: [PATCH 8/8] CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 86f9a5e7f..253f2f761 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- **Frontend**: Better handling of relative dates #720 - **Devops**: Added docker-compose installation script and modified scripts #754 - **Devops**: Allow mongodb port number to be configurable in .env #760 - **Devops**: Enhanced the multi-setup scripts #761