0
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-08-05 21:16:17 +08:00
discourse/.skills/discourse-acl-authoring/SKILL.md
Martin Brennan 7ff30d81a3
FEATURE: Support users in DAccessControl and backend (#41358)
Followup 5823e4e3b2,
this commit allows the addition of users along with
groups to access control lists, modifying DAccessControl
to support selecting a user or group from the same
search input.

Shown here is a mix of user & group permissions in the
`DAccessControl` component:

<img width="611" height="664" alt="image"
src="https://github.com/user-attachments/assets/c25e13b0-8885-4ce7-972c-5116f3acb094"
/>

When the search opens, we show the site's groups that
the user can see as preloaded values, showing only the
group name for clarity:

<img width="612" height="389" alt="image"
src="https://github.com/user-attachments/assets/df93a94b-918e-4fed-b045-ac72f02aca41"
/>

When searching a GET request is sent and users are included
in search results.

<img width="608" height="404" alt="image"
src="https://github.com/user-attachments/assets/ff17e6c0-2505-480e-ae25-e6f8309555bc"
/>

---------

Co-authored-by: Jordan Vidrine <jordan@jordanvidrine.com>
2026-07-15 09:18:06 +10:00

41 lines
3.9 KiB
Markdown
Vendored

---
name: discourse-acl-authoring
description: Use when creating, editing, or reviewing Discourse access-control-list features built on AccessControlList, AclTarget, Guardian ACL helpers, AccessControlListManager, mandatory_acl, banned_acl, Site access_control metadata, plugin ACL target registration, or the DAccessControl UI component.
---
# Discourse ACL Authoring
Use this skill before adding or reviewing ACL-backed resource permissions in Discourse core or plugins.
## Workflow
1. Identify the target resource and desired permission vocabulary. Prefer simple strings such as `view`, `edit`, and `manage`, but confirm the target's domain semantics.
2. Read [references/backend-model.md](references/backend-model.md) when touching `AccessControlList`, `AclTarget`, `Acl::Target`, `Acl::User`, `Guardian`, `User#permission_acl`, or target visibility queries.
3. Read [references/manager-and-plugin-integration.md](references/manager-and-plugin-integration.md) when writing ACLs, creating target models, registering plugin target classes, serializing ACLs, or integrating services/controllers.
4. Read [references/frontend-d-access-control.md](references/frontend-d-access-control.md) when using or customizing `DAccessControl`.
5. Read [references/testing-and-review.md](references/testing-and-review.md) when adding specs or reviewing an ACL feature.
6. Also load `.skills/discourse-service-authoring` for `Service::Base` changes, `.skills/discourse-writing-rspec-tests` for RSpec, and `.skills/discourse-writing-js-tests` for QUnit.
## Non-Negotiables
- Put authorization at the caller boundary before `AccessControlListManager.call`; the manager is a destructive replacement service and currently assumes the caller already authorized the actor.
- Always call `AccessControlListManager` for writes, including empty submitted ACL arrays, so mandatory ACLs are injected and old rows are replaced intentionally.
- Treat `AccessControlList.flattened_list` as the API shape for UI/client payloads and `AccessControlList.expand_list_for_bulk_insert` as the DB insert shape.
- Use Guardian ACL helpers or `AclTarget` visibility scopes for checks and target scopes instead of hand-querying ACL tables in controllers.
- Register plugin ACL targets with `DiscoursePluginRegistry.register_acl_target_class` so `Site#access_control` exposes mandatory and banned ACL metadata to the frontend.
- Treat `banned_acl` as a server-enforced restriction. `DAccessControl` hides banned permission choices for UX, but `AccessControlListManager` must still reject submitted banned entries.
- Do not claim user ACL support is complete. Backend support is partially wired for `allowed_user_ids` in expansion, flattening, preloading, lookup helpers, matching scopes, and cleanup jobs, but `DAccessControl` remains group-first and does not yet provide complete user ACL editing.
## Local Anchors
- Model and relation API: `app/models/access_control_list.rb`
- Target concern: `app/models/concerns/acl_target.rb`
- Permission lookup objects: `lib/acl/target.rb`, `lib/acl/user.rb`
- Guardian helpers: `lib/guardian.rb`
- User ACL cache: `app/models/user.rb`
- Write manager: `app/services/access_control_list_manager.rb`
- Deleted grantee cleanup: `app/jobs/regular/cleanup_acls_for_deleted.rb`, `app/models/group.rb`, `app/models/user.rb`
- Site metadata: `app/models/site.rb`, `app/serializers/site_serializer.rb`
- Frontend component: `frontend/discourse/app/ui-kit/d-access-control.gjs`
- Core specs: `spec/models/access_control_list_spec.rb`, `spec/models/concerns/acl_target_spec.rb`, `spec/lib/acl/target_spec.rb`, `spec/jobs/regular/cleanup_acls_for_deleted_spec.rb`, `spec/services/access_control_list_manager_spec.rb`, `spec/serializers/site_serializer_spec.rb`, `frontend/discourse/tests/integration/components/d-access-control-test.gjs`
- Plugin consumer example: `plugins/discourse-kanban` or the external `discourse-kanban` checkout when present.