Skip to content

Create marked-per-object user types, and list users who only have a profile - #130

Merged
ericof merged 3 commits into
mainfrom
issue-129
Sep 30, 2026
Merged

ericof merged 3 commits into
mainfrom
issue-129

Conversation

@ericof

@ericof ericof commented Sep 30, 2026 •

Copy link
Copy Markdown
Member

Two fixes that kitconcept-core hit on the upgrade to 1.0.0a12, where Person is the site's user type.

#129: a user type whose objects are marked one by one

Since 1.0.0a12 (#127), ensure_profile refused any user type whose FTI does not provide IUserProfile. That broke sites that keep accounts and plain pages in one type and mark only the accounts from an add subscriber, as kitconcept-core does with collective.person's Person. On those sites a first federated or source_users login created no profile and synced no claims.

ensure_profile now:

  1. Asks the type for IUserContent, the same check doAddUser makes.
  2. Declines, with a log line, when the principals container does not allow the type. It checks this before creating anything, so a declined login leaves no container behind. Without this check, the change above brings back Honour user_content_type / group_content_type instead of hardcoding UserProfile/UserGroup #127's InvalidParameterError for a site that creates its user objects itself.
  3. Creates the object, then asks the object for IUserProfile. If the object is not marked, it is deleted again and the call answers None. Left in place, the object would make the next login's create fail with BadRequest (id already in use) during the login.

A type that provides IUserProfile at the type level (UserProfile, or a type with principal_user) behaves as before.

The identity catalog's subscribers are bound to the marker, and for a given event they are looked up before any handler runs. So a subscriber that marks an object on IObjectAddedEvent has to file it itself with profile_moved, as kitconcept-core already does. The how-to now shows that subscriber and explains why.

#131: listing users who only have a profile

identity_profile implemented IGroupIntrospection but not IUserIntrospection. So api.user.get_users(), listMembers() and acl_users.getUserIds()/getUserNames()/getUsers() left out every user with a profile and no source_users row, while searches found them.

  • The plugin now answers those calls from the enumeration-active profile brains.
  • PlonePAS concatenates what every introspector returns without removing duplicates. A user added through api.user.create has both a profile and a source_users credential, so the plugin lists only the userids no other introspector lists. Each user appears once, whatever the plugin order.
  • Install activates the interface. Upgrade step 1010 activates it on existing sites without re-running the install handler, which would also move the plugin to the top of IPropertiesPlugin.

Tests

  • tests/core/principal_types/test_own_user_type.py covers:
    • a type marked one object at a time;
    • an object left unmarked;
    • a type that is not a user;
    • a full federated login (_handle → sync_claims) on a type marked on add.
  • tests/core/pas/test_external_user_record.py covers the container guard: a declined login creates no container.
  • tests/core/pas/test_user_introspection.py and tests/setuphandlers/upgrades/test_v1010.py cover identity_profile does not implement IUserIntrospection, so api.user.get_users() misses its users #131.
  • Each change turns its own tests red when mutated, including the de-duplication (2 == 1) and the upgrade.
  • 3837 tests pass and coverage is 98.08%. Lint, check-imports, docs-build and vale pass.

kitconcept-core ran its site against the #129 part of this branch, and it fixes #129 there.

Docs

  • reference/user-content.md: what a login does for each kind of user type, and which PAS interface answers a search and which a listing.
  • how-to-guides/extend/use-your-own-user-type.md: "When only some objects of your type are users".
  • The upgrade guide lists step 1010, and the profile version is 1010 throughout.

Closes #129
Closes #131

Since 1.0.0a12, ensure_profile asked the FTI for IUserProfile and refused
any type that did not provide it. A site that keeps accounts and plain
pages in one type, and marks only the accounts from an add subscriber,
got no profile on a first federated or source_users login.

ensure_profile now asks the type for IUserContent, as doAddUser does,
and asks the created object for IUserProfile. An object left unmarked is
deleted again: left in place, the next login's create collides with its
id and raises BadRequest inside the login. A user type the principals
container does not allow is declined before creating, which keeps the
case where the site creates the object itself from failing with
InvalidParameterError.

Closes #129
ensure_profile resolved the Profile container with create=True and only
then asked whether it allows the user type, so a login that went on to
decline still created the container. The question is now asked first,
of the existing container's FTI or, when there is none yet, of the type
get_container would create it as.

Also drive a federated login end to end on a type marked on add, so
the claims sync onto a type other than UserProfile is covered: the
account is created, its name and address are synced, and a later login
updates the name.

Refs #129
identity_profile implemented IGroupIntrospection but not
IUserIntrospection, so api.user.get_users(), listMembers() and
acl_users.getUserIds()/getUserNames()/getUsers() left out every user
with a Profile and no source_users row, while searches found them.

The plugin now answers those calls from the enumeration-active Profile
brains. PlonePAS concatenates what every introspector returns without
removing duplicates, and a user added through api.user.create has both
a Profile and a source_users credential, so the plugin lists only the
userids no other introspector lists.

Install activates the interface, and upgrade step 1010 activates it on
existing sites without re-running the install handler, which would also
move the plugin to the top of IPropertiesPlugin.

Closes #131
@ericof ericof changed the title Create a user type whose objects are marked as profiles one by one Create marked-per-object user types, and list users who only have a profile Sep 30, 2026
@ericof
ericof merged commit 4beb907 into main Sep 30, 2026
21 checks passed
@ericof
ericof deleted the issue-129 branch September 30, 2026 18:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant