Skip to content

WIP: feat: uploadable user avatars with moderation (v2)#2308

Draft
wreality wants to merge 4 commits into
masterfrom
feature/user-avatars-v2
Draft

WIP: feat: uploadable user avatars with moderation (v2)#2308
wreality wants to merge 4 commits into
masterfrom
feature/user-avatars-v2

Conversation

@wreality

Copy link
Copy Markdown
Contributor

WIP — recreated on fresh master, supersedes #2265.

Scope

  • Avatar upload: crop dialog, spatie/medialibrary UUID-path storage, conversions (thumb/medium).
  • Moderation: report an avatar, admin review queue with dismiss/remove + pending badge.
  • Per-user UPLOAD_AVATAR permission (granted to all roles by default); MODERATE_AVATARS app-admin only.
  • Computed GraphQL fields via User @method accessors; mutations in dedicated resolver classes.
  • Admin dashboard refactored data-driven via the useNavigation composable; users nested under a users/ section folder so detail routes stay out of the nav tree.
  • nginx /storage static-serve for dev (.lando) and prod (client/.docker).

Status

Merged latest master (fallow, record-of-review, login-oauth). Green: vue-tsc 0, lint 0 errors, client vitest 516, backend avatar+permission 56.

Avatar upload (crop dialog, medialibrary UUID storage), moderation
reporting + admin review queue, and per-user upload-block permission.

Computed GraphQL fields exposed via User @method accessors; mutations
in dedicated resolver classes. Admin dashboard refactored to be
data-driven via the navigation composable, with users nested under a
section folder so detail routes stay out of the nav tree.

nginx /storage static-serve added for dev (.lando) and prod
(client/.docker) so medialibrary uploads render.

WIP: recreated on fresh master; merged latest master (fallow,
record-of-review, login-oauth).
@wreality wreality force-pushed the feature/user-avatars-v2 branch from 2a7d4d2 to 5ab3fe2 Compare June 11, 2026 17:06
@github-actions

github-actions Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Fallow audit report

Found 13 findings.

Details
Severity Rule Location Description
minor fallow/code-duplication src/components/dialogs/AvatarCropDialog.vitest.spec.ts:4 Code clone group 1 (16 lines, 3 instances)
minor fallow/code-duplication src/components/dialogs/RemoveAvatarDialog.vitest.spec.ts:1 Code clone group 2 (23 lines, 2 instances)
minor fallow/code-duplication src/components/dialogs/RemoveAvatarDialog.vitest.spec.ts:4 Code clone group 1 (16 lines, 3 instances)
minor fallow/code-duplication src/components/dialogs/ReportAvatarDialog.vitest.spec.ts:1 Code clone group 2 (23 lines, 2 instances)
minor fallow/code-duplication src/components/dialogs/ReportAvatarDialog.vitest.spec.ts:4 Code clone group 1 (16 lines, 3 instances)
minor fallow/code-duplication src/components/molecules/AvatarUploader.vitest.spec.ts:7 Code clone group 3 (20 lines, 2 instances)
minor fallow/code-duplication src/components/molecules/AvatarUploader.vitest.spec.ts:10 Code clone group 4 (18 lines, 2 instances)
minor fallow/code-duplication src/components/molecules/ReportableAvatar.vitest.spec.ts:1 Code clone group 5 (10 lines, 2 instances)
minor fallow/code-duplication src/components/molecules/ReportableAvatar.vitest.spec.ts:7 Code clone group 3 (20 lines, 2 instances)
minor fallow/code-duplication src/routes/admin/avatar-reports.vitest.spec.ts:1 Code clone group 5 (10 lines, 2 instances)
minor fallow/code-duplication src/routes/admin/avatar-reports.vitest.spec.ts:12 Code clone group 4 (18 lines, 2 instances)
minor fallow/code-duplication src/routes/admin/avatar-reports.vitest.spec.ts:59 Code clone group 6 (20 lines, 2 instances)
minor fallow/code-duplication src/routes/admin/users/index.vue:83 Code clone group 7 (26 lines, 2 instances)

Generated by fallow.

@codecov

codecov Bot commented Jun 11, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.45455% with 56 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.33%. Comparing base (bcb672b) to head (941a480).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
client/src/routes/admin/avatar-reports.vue 63.04% 16 Missing and 1 partial ⚠️
client/src/routes/admin/users/[id].vue 41.17% 10 Missing ⚠️
client/src/components/atoms/AvatarImage.vue 55.00% 4 Missing and 5 partials ⚠️
backend/app/GraphQL/Mutations/UpdateUserAvatar.php 86.11% 5 Missing ⚠️
client/src/routes/admin/users/index.vue 64.28% 5 Missing ⚠️
client/src/components/dialogs/AvatarCropDialog.vue 92.00% 0 Missing and 2 partials ⚠️
client/src/components/molecules/AvatarUploader.vue 96.22% 2 Missing ⚠️
...ient/src/components/molecules/ReportableAvatar.vue 91.66% 1 Missing and 1 partial ⚠️
backend/app/GraphQL/Mutations/ReportUserAvatar.php 95.00% 1 Missing ⚠️
...kend/app/GraphQL/Mutations/ResolveAvatarReport.php 96.42% 1 Missing ⚠️
... and 2 more
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #2308      +/-   ##
==========================================
+ Coverage   63.30%   64.33%   +1.03%     
==========================================
  Files         322      336      +14     
  Lines        7172     7514     +342     
  Branches      704      734      +30     
==========================================
+ Hits         4540     4834     +294     
- Misses       2521     2562      +41     
- Partials      111      118       +7     
Flag Coverage Δ
backend 76.84% <94.11%> (+0.99%) ⬆️
client 59.17% <81.57%> (+0.98%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...p/GraphQL/Mutations/SetUserAvatarUploadBlocked.php 100.00% <100.00%> (ø)
backend/app/MediaLibrary/UuidPathGenerator.php 100.00% <100.00%> (ø)
backend/app/Models/AvatarReport.php 100.00% <100.00%> (ø)
backend/app/Models/User.php 97.54% <100.00%> (+0.57%) ⬆️
client/src/components/atoms/CommentHeader.vue 69.23% <100.00%> (ø)
client/src/components/atoms/UserListItem.vue 92.85% <100.00%> (ø)
...ient/src/components/dialogs/RemoveAvatarDialog.vue 100.00% <100.00%> (ø)
...ient/src/components/dialogs/ReportAvatarDialog.vue 100.00% <100.00%> (ø)
client/src/graphql/fragments.ts 100.00% <100.00%> (ø)
client/src/graphql/mutations.ts 100.00% <100.00%> (ø)
... and 21 more

fallow audit builds a base snapshot of origin/master to attribute
new-vs-inherited findings. That snapshot runs without quasar prepare,
so .quasar/tsconfig.json is absent and src/* path aliases resolve
resolver-less — `src/graphql/generated` reads as a bare `src` package.
The new avatar files' imports then surface as introduced
unlisted-dependency findings and fail the gate. The audit job's HEAD
quasar-prepare step can't reach fallow's internal base snapshot.

`src` is our path alias, never an npm package, so add it to
ignoreDependencies. (ignoreUnresolvedImports does not suppress the
dependency-level finding.)
wreality added 2 commits June 12, 2026 14:29
Add vitest specs for the user-avatars feature surface flagged by Codecov
on #2308 (client patch coverage was dragging the delta negative):

- avatar-reports route: dismiss/remove flows, dialog wiring, badge refetch
- AvatarUploader: validation, cropper->upload, remove
- ReportableAvatar: shouldShow gating, report flow
- Avatar{Crop,Remove,Report} dialogs: useDialogPluginComponent emit paths
- useAvatarReportsPendingCount: moderator gating and pending total

33 tests across 7 files.
UserAvatarField and UserAvatarBlockedField were superseded by the
@method directives in user.graphql, which resolve User.avatar and
User.avatar_upload_blocked through User::getAvatar() /
getAvatarUploadBlocked(). The standalone classes were unreferenced dead
code; the model's getAvatar() is also strictly better, falling back to
the original URL while thumb/medium conversions are still queued.
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.

1 participant