Page MenuHomePhabricator

Use UserIdentity and Authority rather than User in block-related classes
Closed, ResolvedPublic


Many block-related methods are using User typehints rather than UserIdentity for the performer. Specifically:

  • UserBlockCommandFactory and the interfaces it implements
  • BlockUser and UnblockUser
  • BlockPermissionCheckerFactory and BlockPermissionChecker

I've checked whether it's possible to change this. For the most part, it is, and I could only find two issues:

  • Usage of User::getBlock() & friends (blocked on T221067)
  • User objects being passed to hooks: onBlockIp, onBlockIpComplete, onUnblockUser, onUnblockUserComplete

The first point will be easily resolved once those methods are migrated to BlockManager. As for the hooks, we cannot just change the types. The two BlockUser hooks actually have a simpler solution: deprecate them and replace with a hook mentioning "User", not "Ip", so we'd have onBlockUser and onBlockUserComplete. However, the ones in UnblockUser already have the correct name. We can either find another name (but then hooks in BlockUser should use the same convention), or add some BC hacks, for instance some StubObject-like class that could emit a deprecation warning.

Event Timeline

Tagging AHT per recent work in this area.

@Daimona Can you add some more context around why we want to use UserIdentity over User?

@Daimona Can you add some more context around why we want to use UserIdentity over User?

Sure. It is part of a general effort towards phasing out the User class: it's effectively a god/monster class, consisting of 4500 lines of legacy code with no separation of concerns, no dependency injection and whatnot. It brings in lots of dependencies and makes up for poorly testable code. More generally, User has (had) knowledge about basically everything that concerns users: permissions, blocks, DB schema, authentication data, name validation, current request and session, throttling counters, talk page manipulation, preferences, watchlist etc., all in a single class.

OTOH, UserIdentity is a lightweight interface that can be used to represent just the user itself, and it basically only knows the user's name and ID. The proper Dependency injection approach is that if some code needs to know something more about a user (e.g. whether it can perform some action, or is blocked, etc.), it should use a dedicated service to retrieve this data, and this service should only need to know about the user's name/ID to make its computation. This is opposed to passing around a User object and calling methods on that.

The "block-related classes" referred to by this task are examples of services I was talking about. As such, it should only work with lightweight UserIdentity objects, not with monster User objects.

@Daimona Thank you for the context. That's helpful.

Daimona renamed this task from Use UserIdentity rather than User in block-related classes to Use UserIdentity and Authority rather than User in block-related classes.Mar 19 2022, 12:33 PM
Daimona closed this task as Resolved.
Daimona updated the task description. (Show Details)

Calling this resolved per updated task description.