Commit Graph
1238 Commits
Author SHA1 Message Date
REDCODE 963e897fe5 feat: add Unlink cosplayer button to AlbumDetail.razor 2026-07-16 19:31:39 +02:00
REDCODE f9fe91e975 feat: add Merge Albums button to CosplayerDetail.razor 2026-07-16 19:31:12 +02:00
REDCODE 01fc121bc3 feat: add Merge button to Cosplayers.razor with CosplayerGrid preview access 2026-07-16 19:30:22 +02:00
REDCODE da8a5ad539 feat: add Merge button to Albums.razor with AlbumGrid preview access 2026-07-16 19:29:41 +02:00
REDCODE ff2ed4f7cd feat: add MergeModal shared component for merge destination selection 2026-07-16 19:28:45 +02:00
REDCODE 2c292d2d81 feat: add frontend service methods for merge, bulk update, and bulk delete people 2026-07-16 19:27:48 +02:00
REDCODE f064277c31 Merge pull request 'feat: add rate limiting with configurable buckets' (#139) from feature/rate-limit into develop
Reviewed-on: #139
2026-07-16 17:17:53 +00:00
REDCODE c5ea749517 test: added rate limiting stress test 2026-07-16 19:17:37 +02:00
REDCODE ebe83fe691 chore: use record for config classes 2026-07-16 19:06:35 +02:00
REDCODE ab58ac7dd8 Merge branch 'develop' into feature/rate-limit 2026-07-16 16:56:33 +00:00
REDCODE 17d3f0f2a7 Merge pull request 'feat: backend merge endpoints, bulk visibility fix, and tests' (#138) from feat/backend-merge-endpoints into develop
Reviewed-on: #138
Reviewed-by: Samuele Lorefice <aironenerowork@gmail.com>
Reviewed-by: Fastwind <fastwind@noreply.localhost>
2026-07-16 16:46:52 +00:00
REDCODE 1e2bc83b20 fix: guard against null PersonOwnerId in MergePeople albums query
Replace PersonOwnerId ?? Guid.Empty with explicit null check to
avoid matching albums with no owner if sourceIds contained Guid.Empty.
2026-07-16 18:30:23 +02:00
MrFastwind 58014a37bd feat: apply rate-limit buckets to controllers
- AuthController: auth bucket (10 req/60s) — anti-brute-force
- MediaController.GetImage: media_original bucket (50 req/60s)
- MediaController.GetThumb: media_thumb bucket (200 req/60s)
- MediaController.GetPreview: media_preview bucket (200 req/60s)
- JobsController: jobs bucket (30 req/10s) — quick refresh for long-polling
- All other endpoints: global bucket (100 req/60s) via default
2026-07-16 18:26:39 +02:00
MrFastwind c79ed47e41 feat: add rate limiting with configurable buckets
Add fixed-window rate limiting to Lactose with 6 configurable buckets:
- Global (100 req/60s) for all generic calls
- Auth (10 req/60s) strict anti-brute-force
- MediaOriginal (50 req/60s) for full-size media
- MediaThumb (200 req/60s) for thumbnails
- MediaPreview (200 req/60s) for previews
- Jobs (30 req/10s) quick refresh for long-polling

All buckets configurable via appsettings.json RateLimiting section.
Rejected requests return HTTP 429 with JSON body and Retry-After header.
2026-07-16 18:17:58 +02:00
REDCODE e48da562fa test: flatten test numbering to sequential 1–137
Renumber all test blocks flatly with no gaps or sub-letter suffixes.
Split the remaining multi-request block in the bulk visibility section.
2026-07-16 18:08:17 +02:00
REDCODE b943d2e595 fix: split multi-request test blocks into single-request blocks
REST Client only processes the first request per ### block.
Split 99f into 99f/99f1 and 99i2 into 99i2/99i2b so dynamic
variables set by response handlers are available in subsequent tests.
2026-07-16 18:04:40 +02:00
REDCODE 0950106609 test: add merge and bulk visibility tests to WepApiTest.http
Covers: album merge validation and e2e, person merge validation and e2e,
bulk visibility update (people + assets), authorization gating.
2026-07-16 17:58:14 +02:00
REDCODE 7ba1ab1551 feat: add merge endpoints to AlbumController and PersonController
POST /api/album/merge — Curator/Admin, validates DestinationId not in SourceIds
POST /api/person/merge — Admin/Curator, validates DestinationId not in SourceIds
2026-07-16 17:56:52 +02:00
REDCODE 656e6fa9bf feat: add MergePeople to person repository
Reassigns albums (PersonOwnerId), faces (PersonId), and maintainers
from source people to destination, then hard-deletes source people.
2026-07-16 17:56:24 +02:00
REDCODE 5e1306e466 feat: add MergeAlbums to album repository
Loads destination + source albums with assets, moves all assets
from sources to destination (deduplicated), then hard-deletes sources.
2026-07-16 17:55:46 +02:00
REDCODE 22565c4f92 feat: add AlbumMergeDto and PersonMergeDto
New DTOs for merge endpoints. Both require DestinationId and SourceIds,
with DestinationId validated to not appear in SourceIds by the controller.
2026-07-16 17:55:15 +02:00
REDCODE e62a567e4e fix: apply Visibility and MaintainerUserIds in PersonController.BulkUpdate
The bulk update path was ignoring Visibility and MaintainerUserIds
from PersonUpdateDto, unlike the single-update path.
2026-07-16 17:55:00 +02:00
REDCODE e5ffe86077 feat: add visibility-colored borders to cosplayer cards in selection mode
Adds border-warning for non-Public cosplayers and preserves the
cosplayer-card-select accent outline, matching the AlbumCard pattern.
2026-07-16 17:26:26 +02:00
REDCODE d4a53cb2dc fix(UI): make the delete cosplayer button in cosplayer detail page be just an icon to conform with albums detail page 2026-07-16 16:09:34 +02:00
REDCODE 548b0d5bfd Merge pull request 'feat: add reusable ConfirmDialog component for deletion operations' (#135) from issue-57-confirm-dialog into develop
Reviewed-on: #135
Reviewed-by: Samuele Lorefice <aironenerowork@gmail.com>
2026-07-16 13:59:26 +00:00
REDCODE 92fb5a0149 fix: add ConfirmDialog to Settings folder deletion flow
FolderBox now delegates deletion to parent via OnDeleteRequested
callback instead of deleting directly. Settings.razor shows a
ConfirmDialog before removing the folder.
2026-07-16 15:11:33 +02:00
REDCODE 6542dcafd6 fix: add ConfirmDialog to Cosplayers bulk delete flow
Adds confirmation before bulk-deleting selected cosplayers.
2026-07-16 15:10:37 +02:00
REDCODE b7690b5828 fix: add ConfirmDialog to Albums bulk delete flow
Adds confirmation before bulk-deleting selected albums.
2026-07-16 15:10:20 +02:00
REDCODE f3f2bdba02 fix: add ConfirmDialog to CosplayerDetail delete flows
Adds confirmation before deleting a cosplayer or bulk-deleting selected
albums. Uses a single ConfirmDialog with dynamic message and stored
callback for either action.
2026-07-16 15:10:03 +02:00
REDCODE 8bf6405c64 fix: add ConfirmDialog to AlbumDetail delete flows
Adds confirmation before deleting an album or bulk-deleting selected
assets. Uses a single ConfirmDialog with dynamic message and stored
callback for either action.
2026-07-16 15:09:36 +02:00
REDCODE c1b1feef4d fix: add ConfirmDialog to User delete user flow
Replaces browser window.confirm() with the reusable ConfirmDialog
component.
2026-07-16 15:09:06 +02:00
REDCODE 0e9820f7c3 fix: add ConfirmDialog to AdminUsers delete user flow
Replaces browser window.confirm() with the reusable ConfirmDialog
component for a consistent, styled confirmation experience.
2026-07-16 15:08:42 +02:00
REDCODE 133c697176 feat: add reusable ConfirmDialog component
A shared confirmation dialog wrapping ModalFrame for delete operations.
Supports plain text Message or custom Body RenderFragment, configurable
confirm button text and styling, and OnConfirm/OnCancel event callbacks.
2026-07-16 15:08:13 +02:00
REDCODE 8f07d7c445 Merge pull request 'feat: bulk cosplayer assignment for albums from multiselection mode' (#134) from issue-122-bulk-assign-cosplayer into develop
Reviewed-on: #134
Reviewed-by: Samuele Lorefice <aironenerowork@gmail.com>
2026-07-16 11:25:22 +00:00
REDCODE c7e83ed97b feat: bulk cosplayer assignment for albums from multiselect mode
Adds a shared LinkToCosplayerModal component with person typeahead
search and wires it into the albums list page's multiselect topbar.

The backend already supports bulk person assignment via POST /api/album
with BulkDto<AlbumUpdateDto> { Data.Person = ... }, so no backend
changes are needed.

Also adds API tests for the bulk album person assignment flow.

Part of #128, closes #122
2026-07-16 02:59:15 +02:00
REDCODE 7db1738678 fix: soft-delete users in UserController.Delete instead of hard-delete
UserController.Delete was calling userRepository.Delete(user) which performed
a hard delete (context.Users.Remove), violating the project's soft-delete
convention. Changed to set user.DeletedAt = DateTime.UtcNow, matching the
pattern used in AssetController.Delete.

Also removed the now-unused Delete method from IUserRepository and
UserRepository for consistency with AssetRepository (which also has no
Delete method).

Extended REST tests 103-104 to verify deletedAt is set after deletion.

Closes #130
2026-07-16 02:31:52 +02:00
REDCODE 3e099987a3 fix: album detail back button uses history.back() with fallback to /albums
Replaces the hardcoded <a href="/albums"> back link with a button
that calls history.back() via JS interop, falling back to NavigateTo("/albums")
when there is no browser history. Fixes #133.
2026-07-16 02:17:24 +02:00
REDCODE ca50554108 feat: wire up SystemUploaderId setting — seed, UI, and crawl job backfill
- Seed SystemUploaderId in DefaultSettings.json (empty = no default owner)
- Read setting once per crawl and apply UploadedBy on new assets
- Backfill UploadedBy on existing assets that are missing it
- Add UserSelect display type for user-picker setting
- Create SettingUserSelect component with search dropdown
- Add setting to Scanning group in Settings UI
2026-07-16 01:18:46 +02:00
REDCODE 2bfa370989 Merge pull request 'feat: role-visible colored borders, AlbumDetail bulk actions, and cascading visibility (#78)' (#131) from issue-78-role-visible-borders into develop
Reviewed-on: #131
Reviewed-by: Samuele Lorefice <aironenerowork@gmail.com>
2026-07-15 22:59:59 +00:00
REDCODE dbd5d15fa1 fix: label Delete button and cropper modal overlay
- CosplayerDetail: label desktop Delete button and mobile dropdown as
  'Delete Cosplayer' (was 'Delete' / 'Delete person')
- ProfileCropper: move instruction text into modal footer to prevent
  overlap with Cancel/Save buttons; darken overlay background to
  rgba(0,0,0,0.85) instead of semi-transparent rgba(0,0,0,0.6)
2026-07-16 00:57:30 +02:00
REDCODE b1f32844a9 fix: homepage preview navigation, grid observer crash, and cascade labels
- fix: @for closure bug in Home.razor causing preview to show only previous arrow
- guard NavigatePreview against flatList rebuilds during infinite scroll
- fix IntersectionObserver crash when sentinel not in DOM during reload (CosplayerGrid, AlbumGrid)
- align cascade checkbox labels with actual cascade logic (skips private/deleted)
2026-07-16 00:02:46 +02:00
REDCODE 3bf98cbfed fix: prevent private assets with null UploadedBy leaking to anonymous users
Adds userId.HasValue guard to the private-visibility condition in both
AssetRepository and MediaRepository, preventing the null==null match
when an anonymous visitor (userId=null) encounters an asset with null
UploadedBy.
2026-07-15 23:33:08 +02:00
REDCODE 80c9c8bd6f fix: Cosplayers page bugs
- Restore New Cosplayer button on desktop
- Fix ToggleSelectAll via CosplayerGrid.GetCurrentPersonIds()
- Fix ApplyVisibility wiping data — fetch person first, include all fields
- Add GetCurrentPersonIds() to CosplayerGrid for Select All support
2026-07-15 23:10:23 +02:00
REDCODE 7086fb127f feat: add multiselect editing controls to Cosplayers page
- Visibility modal with cascade to albums and assets
- Desktop inline + mobile dropdown action buttons
- Select All / Deselect All button
- Uses PersonService single-update for visibility, AlbumService cascade
2026-07-15 23:03:02 +02:00
REDCODE 19ab8c0975 refactor: centralize cascade visibility logic in AlbumService.CascadeVisibilityToAssetsAsync
- Add CascadeVisibilityToAssetsAsync to AlbumService (skips private/deleted)
- Replace duplicated loop+filter in Albums, CosplayerDetail, PersonForm with single call
- Update labels to describe skip-private/deleted behavior
2026-07-15 23:01:41 +02:00
REDCODE d7f8350ae7 fix: add cascade checkbox to CosplayerDetail album visibility modal 2026-07-15 22:58:36 +02:00
REDCODE f0e3cc9c37 feat: cascade visibility to albums and assets with lower-only rule
- VisibilityModal: add optional CascadeLabel + CascadeEnabled for checkbox
- Albums page: checkbox to cascade album visibility to non-deleted assets
  (lower-only: never raise asset visibility)
- PersonForm: cascade checkboxes when editing cosplayer visibility
  - Cascade to albums (lower only)
  - Cascade to assets in every album (only if album cascade enabled)
- Inject AssetService in Albums page and PersonForm
2026-07-15 22:41:13 +02:00
REDCODE 4f56af252b refactor: extract VisibilityModal shared component, add editing controls to Albums page
- Create MilkStream.Client/Components/Shared/VisibilityModal.razor
- Replace duplicated modal markup in AlbumDetail, CosplayerDetail, Albums
- Add Select All/Deselect All to Albums via AlbumGrid ref
- Add Delete, Visibility modal to Albums select mode
- Add mobile dropdown to Albums action buttons
- Add GetCurrentAlbumIds() to AlbumGrid for Select All support
2026-07-15 22:31:41 +02:00
REDCODE 8aeb4df064 fix: wrap CosplayerDetail action buttons into mobile dropdown 2026-07-15 22:24:07 +02:00
REDCODE dc2983ae55 fix: album-card-select and cosplayer-card-select only on selected cards 2026-07-15 22:23:01 +02:00