mirror of
https://github.com/outline/outline.git
synced 2026-06-13 03:14:59 +03:00
Refactor: Move avatar sync to event-driven processor
- Remove isSync property from UploadUserAvatarTask (always check) - Create AvatarSyncProcessor that listens for users.signin events - Remove avatar sync scheduling from userProvisioner - Simplify architecture with event-driven approach
This commit is contained in:
@@ -8,8 +8,7 @@ import {
|
||||
InviteRequiredError,
|
||||
} from "@server/errors";
|
||||
import Logger from "@server/logging/Logger";
|
||||
import { Team, User, UserAuthentication, UserFlag } from "@server/models";
|
||||
import UploadUserAvatarTask from "@server/queues/tasks/UploadUserAvatarTask";
|
||||
import { Team, User, UserAuthentication } from "@server/models";
|
||||
import { sequelize } from "@server/storage/database";
|
||||
import { APIContext } from "@server/types";
|
||||
|
||||
@@ -162,15 +161,6 @@ export default async function userProvisioner(
|
||||
);
|
||||
});
|
||||
|
||||
// Schedule avatar sync task if user has an avatar URL and hasn't manually changed it
|
||||
if (avatarUrl && !existingUser.getFlag(UserFlag.AvatarChanged)) {
|
||||
await new UploadUserAvatarTask().schedule({
|
||||
userId: existingUser.id,
|
||||
avatarUrl,
|
||||
isSync: true,
|
||||
});
|
||||
}
|
||||
|
||||
if (isInvite) {
|
||||
const inviter = await existingUser.$get("invitedBy");
|
||||
if (inviter) {
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import { User } from "@server/models";
|
||||
import { UserEvent } from "@server/types";
|
||||
import UploadUserAvatarTask from "../tasks/UploadUserAvatarTask";
|
||||
import BaseProcessor from "./BaseProcessor";
|
||||
|
||||
/**
|
||||
* Processor to handle avatar synchronization on user signin events.
|
||||
* This checks if the user's avatar from their identity provider has changed
|
||||
* and updates it if necessary, unless the user has manually changed their avatar.
|
||||
*/
|
||||
export default class AvatarSyncProcessor extends BaseProcessor {
|
||||
static applicableEvents: UserEvent["name"][] = ["users.signin"];
|
||||
|
||||
async perform(event: UserEvent) {
|
||||
switch (event.name) {
|
||||
case "users.signin": {
|
||||
const user = await User.findByPk(event.userId, {
|
||||
rejectOnEmpty: true,
|
||||
});
|
||||
|
||||
// Only sync if user has an avatar URL
|
||||
if (!user.avatarUrl) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Schedule the avatar upload task which will check if update is needed
|
||||
await new UploadUserAvatarTask().schedule({
|
||||
userId: user.id,
|
||||
avatarUrl: user.avatarUrl,
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,8 +12,6 @@ type Props = {
|
||||
userId: string;
|
||||
/** The original avatarUrl from the SSO provider */
|
||||
avatarUrl: string;
|
||||
/** Whether this is a sync operation (should check for changes) */
|
||||
isSync?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -26,17 +24,14 @@ export default class UploadUserAvatarTask extends BaseTask<Props> {
|
||||
rejectOnEmpty: true,
|
||||
});
|
||||
|
||||
// If this is a sync operation, check if we need to update
|
||||
if (props.isSync) {
|
||||
// Check if user has manually changed their avatar
|
||||
if (user.getFlag(UserFlag.AvatarChanged)) {
|
||||
return; // Don't override user's manual avatar choice
|
||||
}
|
||||
// Check if user has manually changed their avatar
|
||||
if (user.getFlag(UserFlag.AvatarChanged)) {
|
||||
return; // Don't override user's manual avatar choice
|
||||
}
|
||||
|
||||
// Check if the avatar has actually changed
|
||||
if (!shouldUpdateAvatar(user.avatarUrl, props.avatarUrl)) {
|
||||
return; // No change needed
|
||||
}
|
||||
// Check if the avatar has actually changed
|
||||
if (!shouldUpdateAvatar(user.avatarUrl, props.avatarUrl)) {
|
||||
return; // No change needed
|
||||
}
|
||||
|
||||
// Use deterministic filename for change detection
|
||||
|
||||
Reference in New Issue
Block a user