[next] Error and Logging Improvements (#2152)

* feat: added locale support for Tenant

* feat: added secret scrubbing to logs

* chore: cleanup logger

* chore: logger improvements

* feat: re-introduce scoped pretty logger

* feat: added initial error support

* refactor: replace trace-error.TraceError with talk.InternalError

* fix: fixed error logging

* refactor: replaced Error with VError

* fix: repaired issue with error management on api

* fix: patched bug with not found handler

* feat: added translations

* feat: added location path to invalid entries

* refactor: refactored error handling on graph

* fix: moved indexing operations to master node

* refactor: added throw for when the message isn't found in testing

* fix: removed duplicate log

* fix: fixed naming on environment variable
This commit is contained in:
Wyatt Johnson
2019-02-06 23:42:17 +00:00
committed by GitHub
parent 9b0e6ed53b
commit 9fa5900acc
63 changed files with 1780 additions and 373 deletions
+2 -2
View File
@@ -3,6 +3,7 @@ import uuid from "uuid";
import { Omit } from "talk-common/types";
import { dotize } from "talk-common/utils/dotize";
import { DuplicateStoryURLError } from "talk-server/errors";
import { GQLStoryMetadata } from "talk-server/graph/tenant/schema/__generated__/types";
import { createIndexFactory } from "talk-server/models/helpers/query";
import { ModerationSettings } from "talk-server/models/settings";
@@ -185,8 +186,7 @@ export async function createStory(
// Evaluate the error, if it is in regards to violating the unique index,
// then return a duplicate Story error.
if (err instanceof MongoError && err.code === 11000) {
// TODO: (wyattjoh) return better error
throw new Error("story with this url already exists");
throw new DuplicateStoryURLError(url);
}
throw err;
+8 -1
View File
@@ -3,6 +3,7 @@ import { isNull, omitBy } from "lodash";
import { Db } from "mongodb";
import uuid from "uuid";
import { LanguageCode } from "talk-common/helpers/i18n/locales";
import { DeepPartial, Omit, Sub } from "talk-common/types";
import { dotize, DotizeOptions } from "talk-common/utils/dotize";
import { GQLMODERATION_MODE } from "talk-server/graph/tenant/schema/__generated__/types";
@@ -38,6 +39,11 @@ export interface Tenant extends Settings {
// domains is the list of domains that are allowed to have the iframe load on.
domains: string[];
/**
* locale is the specified locale for this Tenant.
*/
locale: LanguageCode;
organizationName: string;
organizationURL: string;
organizationContactEmail: string;
@@ -61,10 +67,11 @@ export async function createTenantIndexes(mongo: Db) {
export type CreateTenantInput = Pick<
Tenant,
| "domain"
| "domains"
| "locale"
| "organizationName"
| "organizationURL"
| "organizationContactEmail"
| "domains"
>;
/**
+42 -63
View File
@@ -3,6 +3,16 @@ import { Db } from "mongodb";
import uuid from "uuid";
import { Omit, Sub } from "talk-common/types";
import {
DuplicateEmailError,
DuplicateUserError,
DuplicateUsernameError,
LocalProfileAlreadySetError,
LocalProfileNotSetError,
TokenNotFoundError,
UsernameAlreadySetError,
UserNotFoundError,
} from "talk-server/errors";
import { GQLUSER_ROLE } from "talk-server/graph/tenant/schema/__generated__/types";
import {
createIndexFactory,
@@ -180,8 +190,7 @@ export async function upsertUser(
// because we're returning the updated document and performing an upsert
// operation.
if (result.value!.id !== id) {
// TODO: return better error.
throw new Error("user already found");
throw new DuplicateUserError();
}
return result.value!;
@@ -259,8 +268,7 @@ export async function updateUserRole(
}
);
if (!result.value) {
// TODO: (wyattjoh) return better error
throw new Error("user not found");
throw new UserNotFoundError(id);
}
return result.value;
@@ -271,7 +279,7 @@ export async function verifyUserPassword(user: User, password: string) {
({ type }) => type === "local"
) as LocalProfile | undefined;
if (!profile) {
throw new Error("no local profile exists for this user");
throw new LocalProfileNotSetError();
}
return bcrypt.compare(password, profile.password);
@@ -310,8 +318,7 @@ export async function updateUserPassword(
if (!result.value) {
const user = await retrieveUser(mongo, tenantID, id);
if (!user) {
// TODO: (wyattjoh) return better error
throw new Error("user not found");
throw new UserNotFoundError(id);
}
if (
@@ -319,12 +326,10 @@ export async function updateUserPassword(
profile => profile.type === "local" && profile.id === user.email
)
) {
// TODO: (wyattjoh) return better error
throw new Error("user does not have a local profile");
throw new LocalProfileNotSetError();
}
// TODO: (wyattjoh) return better error
throw new Error("unexpected error occurred");
throw new Error("an unexpected error occured");
}
return result.value || null;
@@ -354,8 +359,7 @@ export async function setUserUsername(
lowercaseUsername,
});
if (user) {
// TODO: (wyattjoh) return better error
throw new Error("duplicate username found");
throw new DuplicateUsernameError(username);
}
// The username wasn't found, so add it to the user.
@@ -381,17 +385,14 @@ export async function setUserUsername(
// Try to get the current user to discover what happened.
user = await retrieveUser(mongo, tenantID, id);
if (!user) {
// TODO: (wyattjoh) return better error
throw new Error("user not found");
throw new UserNotFoundError(id);
}
if (user.username) {
// TODO: (wyattjoh) return better error
throw new Error("user already has username");
throw new UsernameAlreadySetError();
}
// TODO: (wyattjoh) return better error
throw new Error("unexpected error occurred");
throw new Error("an unexpected error occured");
}
return result.value;
@@ -420,8 +421,7 @@ export async function updateUserUsername(
lowercaseUsername,
});
if (user) {
// TODO: (wyattjoh) return better error
throw new Error("duplicate username found");
throw new DuplicateUsernameError(username);
}
// The username wasn't found, so add it to the user.
@@ -446,12 +446,10 @@ export async function updateUserUsername(
// Try to get the current user to discover what happened.
user = await retrieveUser(mongo, tenantID, id);
if (!user) {
// TODO: (wyattjoh) return better error
throw new Error("user not found");
throw new UserNotFoundError(id);
}
// TODO: (wyattjoh) return better error
throw new Error("unexpected error occurred");
throw new Error("an unexpected error occured");
}
return result.value;
@@ -495,12 +493,10 @@ export async function updateUserDisplayName(
// Try to get the current user to discover what happened.
const user = await retrieveUser(mongo, tenantID, id);
if (!user) {
// TODO: (wyattjoh) return better error
throw new Error("user not found");
throw new UserNotFoundError(id);
}
// TODO: (wyattjoh) return better error
throw new Error("unexpected error occurred");
throw new Error("an unexpected error occured");
}
return result.value;
@@ -530,8 +526,7 @@ export async function setUserEmail(
email,
});
if (user) {
// TODO: (wyattjoh) return better error
throw new Error("duplicate email found");
throw new DuplicateEmailError(email);
}
// The email wasn't found, so try to update the User.
@@ -556,17 +551,14 @@ export async function setUserEmail(
// Try to get the current user to discover what happened.
user = await retrieveUser(mongo, tenantID, id);
if (!user) {
// TODO: (wyattjoh) return better error
throw new Error("user not found");
throw new UserNotFoundError(id);
}
if (user.email) {
// TODO: (wyattjoh) return better error
throw new Error("user already has email");
throw new UsernameAlreadySetError();
}
// TODO: (wyattjoh) return better error
throw new Error("unexpected error occurred");
throw new Error("an unexpected error occured");
}
return result.value;
@@ -595,8 +587,7 @@ export async function updateUserEmail(
email,
});
if (user) {
// TODO: (wyattjoh) return better error
throw new Error("duplicate email found");
throw new DuplicateEmailError(email);
}
// The email wasn't found, so try to update the User.
@@ -620,12 +611,10 @@ export async function updateUserEmail(
// Try to get the current user to discover what happened.
user = await retrieveUser(mongo, tenantID, id);
if (!user) {
// TODO: (wyattjoh) return better error
throw new Error("user not found");
throw new UserNotFoundError(id);
}
// TODO: (wyattjoh) return better error
throw new Error("unexpected error occurred");
throw new Error("an unexpected error occured");
}
return result.value;
@@ -669,12 +658,10 @@ export async function updateUserAvatar(
// Try to get the current user to discover what happened.
const user = await retrieveUser(mongo, tenantID, id);
if (!user) {
// TODO: (wyattjoh) return better error
throw new Error("user not found");
throw new UserNotFoundError(id);
}
// TODO: (wyattjoh) return better error
throw new Error("unexpected error occurred");
throw new Error("an unexpected error occured");
}
return result.value;
@@ -707,8 +694,7 @@ export async function setUserLocalProfile(
id: email,
});
if (user) {
// TODO: (wyattjoh) return better error
throw new Error("duplicate profile found");
throw new DuplicateEmailError(email);
}
// Hash the password.
@@ -745,17 +731,14 @@ export async function setUserLocalProfile(
// Try to get the current user to discover what happened.
user = await retrieveUser(mongo, tenantID, id);
if (!user) {
// TODO: (wyattjoh) return better error
throw new Error("user not found");
throw new UserNotFoundError(id);
}
if (user.profiles.some(({ type }) => type === "local")) {
// TODO: (wyattjoh) return better error
throw new Error("user already has local profile");
throw new LocalProfileAlreadySetError();
}
// TODO: (wyattjoh) return better error
throw new Error("unexpected error occurred");
throw new Error("an unexpected error occured");
}
return result.value;
@@ -789,8 +772,7 @@ export async function createUserToken(
}
);
if (!result.value) {
// TODO: (wyattjoh) return better error
throw new Error("user not found");
throw new UserNotFoundError(userID);
}
return {
@@ -824,18 +806,15 @@ export async function deactivateUserToken(
if (!result.value) {
const user = await retrieveUser(mongo, tenantID, userID);
if (!user) {
// TODO: (wyattjoh) return better error
throw new Error("user not found");
throw new UserNotFoundError(id);
}
// Check to see if the User had that Token in the first place.
if (!user.tokens.find(t => t.id === id)) {
// TODO: (wyattjoh) return better error
throw new Error("token not found on user");
throw new TokenNotFoundError();
}
// TODO: (wyattjoh) return better error
throw new Error("could not remove the token for an unknown reason");
throw new Error("an unexpected error occured");
}
// We have to typecast here because we know at this point that the record does