Commit Graph

876 Commits

Author SHA1 Message Date
0d1ce9feb3 style(repo): expand switch expression arms for readability 2026-07-14 19:14:35 +02:00
0673017765 style(repo): convert visibility filters to switch expressions for readability 2026-07-14 19:13:20 +02:00
08c389026a fix(repo): use PagedParametersDto.MaxPageSize const instead of hardcoded 150
Replaced magic number with named constant in both interface and implementation.
2026-07-14 19:03:02 +02:00
bbb2ed8f73 fix(dto): default AssetCreateDto.Visibility to Private instead of Protected 2026-07-14 19:02:34 +02:00
fe33fe2044 fix(stats): add ProtectedAssets count, fix PrivateAssets to count only Private
Previously PrivateAssets counted everything != Public (i.e., Protected+Private combined).
Now PublicAssets=Public, ProtectedAssets=Protected, PrivateAssets=Private.
2026-07-14 19:02:07 +02:00
a449c792c1 fix(media): replace bool parameter with EAccessLevel, add deleted asset check
- GetVisibleAsset: accept EAccessLevel enum instead of bool isCuratorOrAbove
- Admin: sees all assets including deleted
- Curator: sees own deleted + all non-deleted
- Maintainer/User: only non-deleted + visibility filtering
2026-07-14 19:01:39 +02:00
9323111d0d fix(mapper): allow Maintainer to see Visibility field in DTO responses
Changed threshold from >= Curator to >= Maintainer in all three mappers (AssetsMapper, PersonMapper, AlbumMapper). FileName stays Curator+ only.
2026-07-14 19:00:57 +02:00
c2326414b4 fix(controller): add Maintainer scope to Album BulkUpdate, Delete, BulkDelete
- BulkUpdate: Maintainer can update albums of persons they maintain
- Delete: Maintainer can delete albums of persons they maintain
- BulkDelete: same scoped filtering
2026-07-14 19:00:07 +02:00
747ad77f4c fix(controller): scope Maintainer asset access to only maintained cosplayers in Get
Maintainer of the album's person sees all non-deleted assets. Otherwise applies User-level visibility filter.
2026-07-14 18:59:23 +02:00
f77a4574ac fix(controller): scope Maintainer album visibility to only maintained persons
When viewing a person they maintain, show all albums. Otherwise apply User-level visibility filter (Public + Protected only).
2026-07-14 18:58:47 +02:00
c64c1947e6 fix(repo): scope Maintainer to only maintained persons in GetAllVisible and SearchQuery
Previously Maintainer saw all people like Curator+. Now:
- Curator+: sees all people
- Maintainer: sees Public + Protected + persons they maintain
- User: sees Public + Protected only
2026-07-14 18:58:14 +02:00
1b444dab93 feat(auth): complete Maintainer role — add PersonMaintainer checks, update controller authz, pass uploadedBy search param
- AlbumSearchParametersDto: add UploadedBy field
- IPersonRepository/PersonRepository: add IsMaintainerOf method
- AlbumController: allow Maintainer to update with scope check, pass uploadedBy to SearchQuery
- PersonController: allow Maintainer to update maintained persons
- AssetController: allow Maintainer to update/delete own assets
- TagController: allow Maintainer to CRUD all tags
- Fix Authorize(Roles) to include Maintainer where appropriate
- Update WepApiTest.http: curator accessLevel 1→2
2026-07-14 18:13:15 +02:00
50bf0a2a78 feat(db): add migration for auth redesign — drop IsPubliclyShared/UserOwnerId/SharedWith, add Visibility, PersonMaintainer, rename OwnerId→UploadedBy 2026-07-14 17:45:22 +02:00
2335e8e23a feat(repos,controllers): update repositories, interfaces, controllers for auth redesign — visibility filtering, UploadedBy/Uploader rename, Maintainer support
- PersonRepository, AlbumRepository, AssetRepository, MediaRepository, StatsRepository: visibility-based filtering
- IAlbumRepository, IAssetRepository, IMediaRepository: updated signatures (FindByUploader, uploadedBy param, accessLevel)
- AlbumController, AssetController, PersonController, MediaController: replace IsPubliclyShared/SharedWith/UserOwnerId/Owner with Visibility/UploadedBy/Uploader
- FileSystemCrawlJob: IsPubliclyShared=false → Visibility=EVisibility.Private
- Asset model: nav property UploadedBy→Uploader to avoid FK/nav name collision
2026-07-14 17:44:46 +02:00
d02a010083 feat(infra): update DbContext and mappers for auth redesign — new relationships, PersonMaintainer, conditional Visibility 2026-07-14 17:40:34 +02:00
6676347353 feat(models): update models for auth redesign — rename Owner→UploadedBy, drop UserOwnerId/IsPubliclyShared, add EVisibility, PersonMaintainer 2026-07-14 17:39:48 +02:00
c9391d840b feat(butter): update DTOs for visibility, renamed Owner→UploadedBy, removed IsPublic/Owner fields 2026-07-14 17:39:01 +02:00
51323b4a64 feat(butter): add EVisibility enum, Maintainer access level, and SystemUploaderId setting 2026-07-14 17:37:42 +02:00
842ed76345 fix(jobs): use grey for queued segments in layered progress bar 2026-07-14 13:14:44 +02:00
f3ed658dd0 chore: Updated packages, removed unused packages. ImageSharp now requires a license 2026-07-14 13:14:27 +02:00
6c83b8395b fix(album-form): searchable person combobox with modal-safe positioning
Replaces the static <select> with a server-side searchable combobox
in the album edit modal. Fixes issues where the person dropdown was
empty and the name field was not pre-filled on edit.

- Server-side person search (trigram-indexed ILIKE, 20 results)
- 2-character minimum before search triggers
- pre-populates input with current person name when editing
- position: fixed via JS to escape modal-body overflow clipping

Closes #123
2026-07-14 12:43:59 +02:00
e58524ce19 Merge pull request 'refactor: reuse AlbumGrid in CosplayerDetail via FetchAlbums delegate' (#121) from refactor/120-albumgrid-cosplayerdetail into develop
Reviewed-on: #121
Reviewed-by: Samuele Lorefice <aironenerowork@gmail.com>
2026-07-14 10:22:09 +00:00
9dced21554 docs: reconcile AGENTS.md with current codebase
- Remove stale Npgsql legacy timestamp switch note (removed from code)
- Fix EF Core version mismatch description (Tools 8.0.15, not CLI)
- Expand analyzer rules to cover MS001–MS004
2026-07-14 12:09:33 +02:00
3fdf55b53c docs: add PR workflow section to AGENTS.md 2026-07-14 12:07:20 +02:00
f5b28e5a21 docs: add Gitea label levels note to AGENTS.md 2026-07-14 12:04:49 +02:00
7a380d7df5 refactor: reuse AlbumGrid in CosplayerDetail via FetchAlbums delegate
Replace manual album state management (inline AlbumCard loop, own
infinite scroll, own sentinel/observer, _ = ReloadAlbums() discard
lambdas) with <AlbumGrid> using a new FetchAlbums delegate parameter.

- AlbumGrid.razor: add FetchAlbums Func parameter; use it in
  Reload()/LoadMoreAlbums() when set
- CosplayerDetail.razor: replace manual album rendering + state with
  <AlbumGrid FetchAlbums=@FetchPersonAlbums />; remove all album
  state management fields (allAlbumsDict, currentAlbumPage, etc.),
  ReloadAlbums/LoadMoreAlbums/OnAfterRenderAsync methods, and
  IAsyncDisposable; SortFilterBar now uses clean lambdas
- CosplayerDetail.razor.css: remove unused album-grid overrides

Closes #120
2026-07-14 12:00:38 +02:00
f7d6348ea9 Merge pull request 'fix: make card components middle-clickable by using <a> instead of <div @onclick>' (#119) from fix/102-card-middle-click into develop
Reviewed-on: #119
Reviewed-by: Samuele Lorefice <aironenerowork@gmail.com>
2026-07-14 09:57:32 +00:00
46871299ca fix: remove underline from album card person link 2026-07-14 11:51:58 +02:00
c281746fdc fix: make card components middle-clickable
Convert <div @onclick> -> NavigationManager.NavigateTo() to real <a>
elements so cards support middle-click, Ctrl+click, and
'Open in new tab'.

- CosplayerGrid.razor: replace <div> with <a href='/cosplayer/{id}'>
- AlbumCard.razor: add full-card <a> overlay, keep inner person <a>
- CosplayerGrid.razor.css + AlbumCard.razor.css: add display:block,
  color:inherit, text-decoration:none for <a> card elements
- Remove OnCardClicked/OnNavigate callbacks and parent page
  navigation methods (nav is now native via <a href>)

Closes #102
2026-07-14 11:46:13 +02:00
be7532dd74 fix: implement CosplayersMissingProfile stat
Replaces the hardcoded zero with a real query counting people
without a profile picture (ProfileAssetId == null).

Renamed from CosplayersMissingCover to CosplayersMissingProfile
to reflect the actual metric.

DTO, repository, and UI label updated accordingly.

fixes #97
2026-07-14 11:40:06 +02:00
108b53a7e2 refactor: use MaxPageSize constant as default pageSize across all frontend services
AlbumService.GetAlbumsAsync, AssetService.GetAssetsAsync, PersonService.GetAllAsync
now default to PagedParametersDto.MaxPageSize (250) instead of hardcoded 30.
Also fixed AssetService.GetAssetsAsync page default from 1 to 0 for consistency
with zero-based pagination.
2026-07-14 11:27:38 +02:00
38793efe6f fix(albums): use MaxPageSize constant for unassigned album fetch
Fixes #118 - hardcoded pageSize=999 exceeded server's MaxPageSize (250),
causing 400 Bad Request and the assign-album modal to hang on loading.
2026-07-14 11:24:34 +02:00
4205188855 docs: add use case catalog for new auth/permissions model
Documents the 5-actor model (Anonymous/User/Maintainer/Curator/Admin),
77 use cases across all roles, permission matrix, visibility integration
with #93, and database schema changes including:
- Album.UserOwnerId removal
- Asset.OwnerId → UploadedBy rename
- PersonMaintainer M:N join table
- EAccessLevel enum update
2026-07-13 18:57:54 +02:00
d2daed27a8 Merge pull request 'Global "Search Anything" typeahead dropdown in navbar' (#91) from feature/global-search-dropdown into develop
Reviewed-on: #91
Reviewed-by: Samuele Lorefice <aironenerowork@gmail.com>
Reviewed-by: Fastwind <fastwind@noreply.localhost>
2026-07-13 15:18:40 +00:00
87b69d5ee8 revert: remove AllowAnonymous from AlbumController.Search and PersonController.GetAll 2026-07-13 17:03:53 +02:00
e0d46aa87b refactor: replace hardcoded 250 page size limit with PagedParametersDto.MaxPageSize 2026-07-13 17:02:13 +02:00
dbe55be63f refactor(albums): extract visibility-aware AssetCount into AlbumMapper overload
Replace inline AlbumPreviewDto construction in AlbumRepository.SearchQuery
with a call to the new ToAlbumPreviewDto(album, userId, accessLevel) mapper
overload, making the visibility logic reusable and the repository more compact.
2026-07-12 21:15:00 +02:00
28f9e7faae fix: replace untranslatable Tags navigation in TopTags stats query with direct join table query 2026-07-12 21:02:50 +02:00
820d3b1c8b fix: replace untranslatable Album navigation in stats queries with direct join table queries 2026-07-12 21:02:33 +02:00
278648aae6 Merge branch 'develop' into feature/global-search-dropdown 2026-07-12 21:00:42 +02:00
9d9491253b refactor: clean up imports, simplify checks, and add SearchDropdown component
- Remove unused using directives across C# and Razor files
- Remove unused IServiceProvider from SettingsRepository
- Simplify null/empty string checks in StatsRepository
- Add null-safe navigation for Albums/Tags in stats queries
- Initialize Asset.Hash default to prevent null refs
- Deduplicate AssetIds in AssetPicker
- Add OnStartedWaiting/OnFinishedWaiting/OnProgressChanged to Job
- Add global SearchDropdown component with keyboard nav
- Fix XML doc param mismatches
2026-07-12 20:47:24 +02:00
499c6375f6 Merge branch 'develop' into feature/global-search-dropdown
Resolved merge conflict in CosplayerDetail.razor:
- Kept SortFilterBar with instant search/sort (from feat/cosplayer-detail-search)
- Adapted allAlbums references to allAlbumsDict (from feature/global-search-dropdown)
- Kept updated PersonController.cs and PersonService.cs from both branches
2026-07-12 20:28:59 +02:00
2b150060f4 Merge pull request 'Add searchbar to cosplayer detail page for filtering albums' (#100) from feat/cosplayer-detail-search into develop
Reviewed-on: #100
Reviewed-by: Samuele Lorefice <aironenerowork@gmail.com>
2026-07-12 18:23:51 +00:00
b93cb73e0a fix(cosplayer-detail): remove search debounce, instant inline reload
Search now fires ReloadAlbums immediately on every keystroke, matching
the same instant behavior as Albums and Cosplayers pages. Since
ReloadAlbums only swaps the album grid content without touching
isLoading, focus is preserved and the page stays intact.
2026-07-12 20:21:27 +02:00
d2d584d509 fix(cosplayer-detail): debounce search, keep page intact on filter changes
- Remove OnFilterChanged from SortFilterBar to prevent per-keystroke reloads
- Debounce search input with 300ms CancellationTokenSource delay
- Sort changes (dropdown/toggle) trigger immediate ReloadAlbums
- ReloadAlbums no longer sets isLoading — updates album grid in-place
  without unmounting the page DOM, preserving focus on the search box
- Dispose searchCts on component disposal
2026-07-12 20:19:30 +02:00
8bcb408a5b fix(cosplayer-detail): prevent banner image shuffle on album search/sort
Add updateBanner parameter to LoadPerson so ReloadAlbums (triggered
by search/sort filter changes) does not regenerate the random banner
cover URLs, keeping the header fixed during filtering.
2026-07-12 20:15:09 +02:00
445b030160 feat(cosplayer-detail): add SortFilterBar for album search and sort
- Backend: accept PagedSearchParametersDto on GET /api/person/{id}
  with in-memory search (case-insensitive title Contains) and sort
  (name/created/updated/assets) before pagination
- Frontend service: add search, sortBy, sortAsc params to GetByIdAsync
- Frontend page: replace inline action buttons with reusable SortFilterBar
  component, wire search/sort state into initial load and infinite scroll
2026-07-12 20:11:06 +02:00
8195808500 docs: update AGENTS.md with missing conventions and project info
- Add Lactose.Analyzers as 5th project (DateTime.UtcNow error MS001)
- Document zero-based pagination standard with validation rules
- Add SharedWith.Any() EF Core translation gotcha
- Document pg_trgm GIN indexes and pgvector extensions
- Fix test count (66+ → 67), add env file reference
2026-07-12 19:41:10 +02:00
393ad136f6 fix: restore PageSize < 1 validation with upper limit of 250 2026-07-12 19:31:23 +02:00
00acfef28c fix: only reject Page < 0, keep original PageSize validation
Per review feedback: only Page being negative is truly invalid.
PageSize validation reverted to original < 0 (allowing 0).
PersonController keeps minimal Page < 0 check since it had none before.
JobsController aligned for consistency.
2026-07-12 19:27:10 +02:00