chore: Move initial avatar upload to background worker (#3727)
* chore: Async user avatar upload processor * chore: Async team avatar upload * Refactor to task for retries * Docs Include avatarUrl in task props to prevent race condition Remove transaction around upload fetch request
This commit is contained in:
@@ -61,6 +61,7 @@ async function accountProvisioner({
|
||||
subdomain: teamParams.subdomain,
|
||||
avatarUrl: teamParams.avatarUrl,
|
||||
authenticationProvider: authenticationProviderParams,
|
||||
ip,
|
||||
});
|
||||
} catch (err) {
|
||||
throw AuthenticationError(err.message);
|
||||
|
||||
@@ -7,6 +7,8 @@ import teamCreator from "./teamCreator";
|
||||
beforeEach(() => flushdb());
|
||||
|
||||
describe("teamCreator", () => {
|
||||
const ip = "127.0.0.1";
|
||||
|
||||
it("should create team and authentication provider", async () => {
|
||||
env.DEPLOYMENT = "hosted";
|
||||
const result = await teamCreator({
|
||||
@@ -17,6 +19,7 @@ describe("teamCreator", () => {
|
||||
name: "google",
|
||||
providerId: "example.com",
|
||||
},
|
||||
ip,
|
||||
});
|
||||
const { team, authenticationProvider, isNewTeam } = result;
|
||||
expect(authenticationProvider.name).toEqual("google");
|
||||
@@ -40,6 +43,7 @@ describe("teamCreator", () => {
|
||||
name: "google",
|
||||
providerId: "example.com",
|
||||
},
|
||||
ip,
|
||||
});
|
||||
|
||||
expect(result.team.subdomain).toEqual("myteam1");
|
||||
@@ -62,6 +66,7 @@ describe("teamCreator", () => {
|
||||
name: "google",
|
||||
providerId: "example.com",
|
||||
},
|
||||
ip,
|
||||
});
|
||||
|
||||
expect(result.team.subdomain).toEqual("myteam2");
|
||||
@@ -82,6 +87,7 @@ describe("teamCreator", () => {
|
||||
name: "google",
|
||||
providerId: "example.com",
|
||||
},
|
||||
ip,
|
||||
});
|
||||
} catch (err) {
|
||||
error = err;
|
||||
@@ -109,6 +115,7 @@ describe("teamCreator", () => {
|
||||
name: "google",
|
||||
providerId: "allowed-domain.com",
|
||||
},
|
||||
ip,
|
||||
});
|
||||
const { team, authenticationProvider, isNewTeam } = result;
|
||||
expect(team.id).toEqual(existing.id);
|
||||
@@ -142,6 +149,7 @@ describe("teamCreator", () => {
|
||||
name: "google",
|
||||
providerId: "other-domain.com",
|
||||
},
|
||||
ip,
|
||||
});
|
||||
} catch (err) {
|
||||
error = err;
|
||||
@@ -164,6 +172,7 @@ describe("teamCreator", () => {
|
||||
name: "Updated name",
|
||||
subdomain: "example",
|
||||
authenticationProvider,
|
||||
ip,
|
||||
});
|
||||
const { team, isNewTeam } = result;
|
||||
expect(team.id).toEqual(existing.id);
|
||||
|
||||
@@ -3,7 +3,7 @@ import env from "@server/env";
|
||||
import { DomainNotAllowedError, MaximumTeamsError } from "@server/errors";
|
||||
import Logger from "@server/logging/Logger";
|
||||
import { APM } from "@server/logging/tracing";
|
||||
import { Team, AuthenticationProvider } from "@server/models";
|
||||
import { Team, AuthenticationProvider, Event } from "@server/models";
|
||||
import { generateAvatarUrl } from "@server/utils/avatars";
|
||||
|
||||
type TeamCreatorResult = {
|
||||
@@ -21,6 +21,7 @@ type Props = {
|
||||
name: string;
|
||||
providerId: string;
|
||||
};
|
||||
ip: string;
|
||||
};
|
||||
|
||||
async function teamCreator({
|
||||
@@ -29,6 +30,7 @@ async function teamCreator({
|
||||
subdomain,
|
||||
avatarUrl,
|
||||
authenticationProvider,
|
||||
ip,
|
||||
}: Props): Promise<TeamCreatorResult> {
|
||||
let authP = await AuthenticationProvider.findOne({
|
||||
where: authenticationProvider,
|
||||
@@ -90,7 +92,7 @@ async function teamCreator({
|
||||
}
|
||||
|
||||
const team = await sequelize.transaction(async (transaction) => {
|
||||
return Team.create(
|
||||
const team = await Team.create(
|
||||
{
|
||||
name,
|
||||
avatarUrl,
|
||||
@@ -101,6 +103,19 @@ async function teamCreator({
|
||||
transaction,
|
||||
}
|
||||
);
|
||||
|
||||
await Event.create(
|
||||
{
|
||||
name: "teams.create",
|
||||
teamId: team.id,
|
||||
ip,
|
||||
},
|
||||
{
|
||||
transaction,
|
||||
}
|
||||
);
|
||||
|
||||
return team;
|
||||
});
|
||||
|
||||
// Note provisioning the subdomain is done outside of the transaction as
|
||||
|
||||
@@ -102,7 +102,8 @@ export default async function userCreator({
|
||||
});
|
||||
|
||||
// We have an existing invite for his user, so we need to update it with our
|
||||
// new details and link up the authentication method
|
||||
// new details, link up the authentication method, and count this as a new
|
||||
// user creation.
|
||||
if (invite && !invite.authentications.length) {
|
||||
const auth = await sequelize.transaction(async (transaction) => {
|
||||
await invite.update(
|
||||
@@ -114,6 +115,21 @@ export default async function userCreator({
|
||||
transaction,
|
||||
}
|
||||
);
|
||||
await Event.create(
|
||||
{
|
||||
name: "users.create",
|
||||
actorId: invite.id,
|
||||
userId: invite.id,
|
||||
teamId: invite.teamId,
|
||||
data: {
|
||||
name,
|
||||
},
|
||||
ip,
|
||||
},
|
||||
{
|
||||
transaction,
|
||||
}
|
||||
);
|
||||
return await invite.$create<UserAuthentication>(
|
||||
"authentication",
|
||||
authentication,
|
||||
|
||||
Reference in New Issue
Block a user