Skip to content

Commit

Permalink
Merge pull request #790 from givepraise/fix/usernames_etc
Browse files Browse the repository at this point in the history
v0.13.1
  • Loading branch information
kristoferlund authored Jan 20, 2023
2 parents feadeb0 + 1290f37 commit c9dc54d
Show file tree
Hide file tree
Showing 12 changed files with 96 additions and 31 deletions.
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,23 @@ 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

- **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

## [0.13.0] - 2022-11-18

### Added
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
2 changes: 1 addition & 1 deletion packages/api/package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
39 changes: 32 additions & 7 deletions packages/api/src/activate/controllers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ 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';

Expand All @@ -27,23 +28,28 @@ const activate = async (
): Promise<void> => {
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(
Expand All @@ -55,15 +61,34 @@ 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) {
user.rewardsEthAddress = identityEthAddress;
}

// Set username if not set
if (!user.username || user.username === identityEthAddress) {
const generatedUserName = await generateUserNameFromAccount(userAccount);
if (generatedUserName) {
user.username = generatedUserName;
}
}

// Save user changes
await user.save();

// Link user account with user
userAccount.user = user;
Expand Down
2 changes: 1 addition & 1 deletion packages/api/src/database/seeder/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export const seedAdminUsers = async (): Promise<void> => {
await UserModel.create({
identityEthAddress: e,
rewardsEthAddress: e,
username: faker.internet.userName(),
username: e,
roles: [UserRole.ADMIN, UserRole.USER],
});
}
Expand Down
17 changes: 14 additions & 3 deletions packages/api/src/user/utils/entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down
2 changes: 1 addition & 1 deletion packages/discord-bot/package.json
Original file line number Diff line number Diff line change
@@ -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": {
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/package.json
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/src/model/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down
38 changes: 25 additions & 13 deletions packages/frontend/src/utils/axios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,42 @@ 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);
toast.error(json.message);
});
} 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');
}
Expand Down
2 changes: 1 addition & 1 deletion packages/mongodb/package.json
Original file line number Diff line number Diff line change
@@ -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."
}
2 changes: 1 addition & 1 deletion packages/setup/package.json
Original file line number Diff line number Diff line change
@@ -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.",
Expand Down

0 comments on commit c9dc54d

Please sign in to comment.