Skip to content

Fix file record and delete files (branding and avatar) #1335

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

DanielAuerX
Copy link

@DanielAuerX DanielAuerX commented May 9, 2025

  • create file_record table
  • avatar and branding files are added to file_record
  • branding files are being deleted
  • avatar files are being deleted
  • reload latest avatar (frontend) after backend state is being updated

problems addressed in the pr:

  • clean up job fails, because it cannot access file_record table
  • avatar and branding files are not added to the file_record table
  • avatar and branding files are never deleted
  • after an avatar is being updated/deleted, the old file is still being requested due to browser caching. This is causing error logs ("no such file or directory") in the backend.

cf. conversation in pr 1326

broccoli and others added 3 commits May 3, 2025 12:26
by registering the file record entitry in init_data.go, the table is being created during initialization.
+ uploaded avatar and branding files are added to the file_record table,
  so that the table provides a comprehensive overview of files in the
file system
+ a file is being deleted after its reference has been removed from
  the site info. The user has no way to access the file again. Therefore
  the file would become an orphan if not deleted.

+ an if clause had to be added to CleanOrphanUploadFiles, because it
  would otherwise remove the branding and avatar files.
@DanielAuerX DanielAuerX marked this pull request as draft May 9, 2025 13:31
broccoli added 2 commits May 11, 2025 12:29
+ a file is being deleted after its reference has been removed from the user info. The user has no way to access the file again. Therefore the file would become an orphan if not deleted.
ensuring updated user info (e.g. avatar file path) is reloaded after changes.
This prevents stale paths being cached by the browser and old resources
being requested.
@LinkinStars
Copy link
Member

Thanks for contributing. As a reminder, I see that all tasks have been completed, so if you need to review, please change the draft status to ready.

@DanielAuerX
Copy link
Author

Hi @LinkinStars! yes, the tasks of this pr are finished, unless you see something I missed.
The clean up job (CleanOrphanUploadFiles) is running now. However, I am not sure that it works as intended when it was implemented. Maybe you want to double check that.

@DanielAuerX DanielAuerX marked this pull request as ready for review May 13, 2025 17:39
@LinkinStars LinkinStars self-requested a review May 14, 2025 11:20
@LinkinStars LinkinStars self-assigned this May 14, 2025
@LinkinStars
Copy link
Member

LinkinStars commented May 15, 2025

Almost done. I find some small issues.

  1. Did you forget to submit the wire gen.go? We can't run the code directly.
  2. If a user switches avatars, for example from a customized avatar to the system default avatar, the file should not be deleted at this point. This is because the user may switch back later, and the deletion of the old avatar will only be processed when the user uploads a new custom avatar.
  3. Let me explain why we use the CleanOrphanUploadFiles function to clean the file.

When a user uploads the file, whatever category(post or avatar), the file will be saved. But after that, if the user does not save the post or profile, the file will be an orphaned file. So we need to clean its background. Of course, we will think that your handling is enough. If you need to be more perfect, it is necessary to separately determine whether the avatar is using it by users(when isBrandingOrAvatarFile is true).

...user,
...params,
});
getLoggedUserInfo().then(update);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why should this be adjusted?

The whole PR problem has nothing to do with this, and the user information pulled back after editing the user information is also up to date, so there should be no need to adjust here.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the browser caches the stale path of the old avatar. Until a new session is started, the old resource is being requested in the backend, causing an error log by the avatar middleware (resource not found).
If you can live with that, ill take it out.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you give me a step to reproduce the problem?

I don't know where else will continue to request the old avatar after the user has updated his avatar

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • checkout branch
  • remove the commit in question
  • upload a custom avatar
  • update the custom avatar with another avatar
  • check the logs and/or the uploads/avatar/ get requests

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DanielAuerX This is the only problem left in this PR. Are there any suitable steps to reproduce this problem?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DanielAuerX wait for your reply!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • checkout branch
  • remove the commit in question
  • upload a custom avatar
  • update the custom avatar with another avatar
  • check the logs and/or the uploads/avatar/ get requests

I tested it and found that this modification still cannot eliminate browser cache unless the entire application is reloaded using window.reload, however, using this method will affect the user's experience.

Because from the perspective of generation implementation, updating user information after obtaining from get interface is the same as updating from params, and it cannot eliminate browser cache.

Here are the steps I tested with your code:

  1. upload a custom avatar and save
  2. reupload a custom avatar and save
  3. Return to the question list page, and the last avatar will still be retrieved from the cache (you can see from the console's get request).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DanielAuerX Thanks for the feedback, it made us realise that there is a bit of an issue with the backend here for errors as well. Maybe just adjust the error handling on the backend.

return "", errors.InternalServer(reason.UnknownError).WithError(err).WithStack()

// There should be a 404 error here
return "", errors.NotFound(reason.UnknownError).WithError(err)

filePath, err = am.uploaderService.AvatarThumbFile(ctx, filename, size)
if err != nil {
log.Error(err)
ctx.Abort()
}
}
avatarFile, err := os.ReadFile(filePath)

filePath, err = am.uploaderService.AvatarThumbFile(ctx, filename, size)
if err != nil {
	log.Error(err)
	ctx.AbortWithStatus(http.StatusNotFound)
	// This should not be continued here, but should be returned directly, because the file no longer exists.
	return
}

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested it and found that this modification still cannot eliminate browser cache unless the entire application is reloaded using window.reload, however, using this method will affect the user's experience.

@shuashuai Just for clarification, this change is not supposed to eliminate browser cache. Its supposed to be updating the user information, so an old avatar file is not being requested after it has been removed from the user information. This is not new behavior. However, previously requesting an old resource was successful, because files were not being deleted.

Do you have a better solution? I can also just remove the commit, if you think this is acceptable.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for clarification, this change is not supposed to eliminate browser cache. Its supposed to be updating the user information, so an old avatar file is not being requested after it has been removed from the user information. This is not new behavior. However, previously requesting an old resource was successful, because files were not being deleted.

Both ways of updating the user's information are the same and there is no practical difference between them!

Do you have a better solution? I can also just remove the commit, if you think this is acceptable.

There is no better way at the moment, so let's keep the previous logic for the time being.

+ using existing AvatarInfo schema instead of redundant schema

+ improved error handling, so that the branding information is always
  being updated, even if its not possible to remove the old files.

+ added updated wire_gen.go file
@DanielAuerX
Copy link
Author

@LinkinStars First of all, thanks for the review and the explanation!

Almost done. I find some small issues.

1. Did you forget to submit the `wire gen.go`? We can't run the code directly.

now committed

2. If a user **switches** avatars, for example from a customized avatar to the system default avatar, the file **should not be deleted** at this point. This is because the user may switch back later, and the deletion of the old avatar will only be processed when the user **uploads a new custom avatar**.

the avatar file is only being deleted, if the new custom avatar is an empty string or the file name is unlike the old one. Therefore the desired behavior you are describing should already be the case. I also tested it manually. Unless i understand you wrong.

3. Let me explain why we use the `CleanOrphanUploadFiles` function to clean the file.

When a user uploads the file, whatever category(post or avatar), the file will be saved. But after that, if the user does not save the post or profile, the file will be an orphaned file. So we need to clean its background. Of course, we will think that your handling is enough. If you need to be more perfect, it is necessary to separately determine whether the avatar is using it by users(when isBrandingOrAvatarFile is true).

you are right, when one uploads an avatar/branding file and never clicks save, the file wont be deleted. I will add some logic to the clean up job, thanks.
I just noticed that the avatar_thumb files arent deleted either. I will also look into that.

@LinkinStars
Copy link
Member

@DanielAuerX

For issue 2, here are my reproduction steps.

  1. Upload an avatar and save the profile.
  2. Check the avatar dir. (The file exists)
  3. Switch the avatar to system and save the profile.
  4. Check the avatar dir. (The file not exists)
1. ➜  avatar git:(fix_file_record) ls
2. ➜  avatar git:(fix_file_record) ls
5sVCXwyhsbm.png
4. ➜  avatar git:(fix_file_record) ls
➜  avatar git:(fix_file_record) 

This is the reason for the problem.

if oldAvatar.Type == "custom" && (newAvatar.Type != "custom" || oldAvatar.Custom != newAvatar.Custom) {

At this time, newAvatar.Type != "custom" so the file will be deleted.

To make the logic simple, perhaps it could be implemented like this.

	// As long as there are no original files, there must be no need to delete
	if len(oldAvatar.Custom) == 0 {
		return
	}
	// At this point, it turns out that the old file must exist. 
	// Then delete as long as the new file and the old file are inconsistent as you say. 
	// Whatever type the user chooses.
	if oldAvatar.Custom != newAvatar.Custom {
		fileRecord, err := us.fileRecordService.GetFileRecordByURL(ctx, oldAvatar.Custom)
	}

+ added logic that removed orphaned within the clean up job. Files may
  be orphaned if a user uploads a file, but never saves it (registering
  it with the user profile or site info).

+ if a user switches avatars, for example from a customized avatar to the system default avatar, the file is not deleted anymore.
@DanielAuerX
Copy link
Author

@DanielAuerX

For issue 2, here are my reproduction steps.

  1. Upload an avatar and save the profile.
  2. Check the avatar dir. (The file exists)
  3. Switch the avatar to system and save the profile.
  4. Check the avatar dir. (The file not exists)
1. ➜  avatar git:(fix_file_record) ls
2. ➜  avatar git:(fix_file_record) ls
5sVCXwyhsbm.png
4. ➜  avatar git:(fix_file_record) ls
➜  avatar git:(fix_file_record) 

This is the reason for the problem.

if oldAvatar.Type == "custom" && (newAvatar.Type != "custom" || oldAvatar.Custom != newAvatar.Custom) {

At this time, newAvatar.Type != "custom" so the file will be deleted.

To make the logic simple, perhaps it could be implemented like this.

	// As long as there are no original files, there must be no need to delete
	if len(oldAvatar.Custom) == 0 {
		return
	}
	// At this point, it turns out that the old file must exist. 
	// Then delete as long as the new file and the old file are inconsistent as you say. 
	// Whatever type the user chooses.
	if oldAvatar.Custom != newAvatar.Custom {
		fileRecord, err := us.fileRecordService.GetFileRecordByURL(ctx, oldAvatar.Custom)
	}

Should be done now

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants