Problem/Motivation

Currently it is very complicated to implement features for anonymous users. There is no API to handle anonymous users. There are multiple scenarios in which a proper API for that would come in handy: Commenting, Voting, eCommerce, etc. - All these scenarios currently mostly work through custom code and workarounds in core and contrib.

Example: In case of the core Comment module we have to make use of ugly use-case specific implementations to allow anonymous users to post comments: There are specific properties on the comment entity that are only required by anonymous users which hold the e-mail address, name, homepage, etc. On top of these properties we compute things like the author name, etc. which could easily be pulled from the user entity instead if both, registered and anonymous users would be allowed to use that entity in a unified way.

Proposed resolution

We propose to unify anonymous- and registered users in the 'user' and separating that from the actual 'account' of a user. Every visitor of a site can potentially be a user. By registering on the website a user would get an 'account' attached to his user entity through which he can identify himself as that user. Until then, this happens exclusively through the session. The idea of separating accounts from users has been moved to a follow-up/related issue at #1816218: [P-1] Separate the account information from the user entity.

Any visitor, registered or not, can become a 'user'. That means that, whenever something that should be available to anonymous users but somehow requires a user entity (or would be better of if it had one) happens on the website... we generate a user entity. Thus, a 'user' is any type of person that we want to be able to store information for. This could be anything from anonymous commenters (core) or voters (contrib) through to contacts in a complex, contributed CRM system as well as registered users who frequent the site.

Benefits

  • Adding an 'Anonymous User API'
  • A standard way of storing information about people whether they’re registered users or not. An example of the current fragmentation is the comment module, where the uid and a name, mail and homepage are currently stored as properties against a post. Then on rendering a fake account is created from this data and passed into account functions such as format_username().
  • A useful data structure for building a CRM system on top of in contrib. At the moment a lot of heavy lifting and juggling is required to attempt to manage storing data against a contact that may or not be a registered user. If everything worked with anonymous users, a CRM system would instantly have access to all of the modules that currently integrate with accounts, such as Commerce and Profile2.
  • Modules that are designed for working with Users but useful for other things (simplenews, voting api / fivestar, comment, etc.) won't have to implement their own storage or custom API's to work with anonymous users. E.g. Simplenews would no longer need the simplenews_subscriber entity - It could store any information it needed in a Profile2 type defined in code.

The way forward

We will be working in a Sandbox project for now.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

yautja_cetanu’s picture

Project: Party » Drupal core
Issue summary: View changes

added extra issue

yautja_cetanu’s picture

Issue summary: View changes

added another

fubhy’s picture

Issue summary: View changes

Writing a proper issue summary

fubhy’s picture

Title: Getting Party into Drupal 8 Core!!!! » Unify anonymous and registered users
Version: 7.x-1.x-dev » 8.x-dev
Component: Code » user.module
Category: task » feature

Updating the issue title and moving the issue to the core queue.

fubhy’s picture

Issue summary: View changes

Adding link to sandbox

rlmumford’s picture

Added a link to a google doc containing an abstract and some detailed discussion about the pros/cons and implementation plans.

rlmumford’s picture

Issue summary: View changes

Add link to google doc.

fubhy’s picture

Cleaned up and added some of the stuff from the google doc.

yautja_cetanu’s picture

https://docs.google.com/document/d/1HJSOf-OOUOXu2bYqENBR_rU8284Jrkfyb3gM...

Did you mean to remove the link to the google doc?
There are some potentially large changes from the party module that I think would be good to discuss but I dunno if we want to do it in the issue queues quite yet. I'm adding "Things we want to do in Contrib" and then we can then discuss moving some of those features into Core.

In my opinion the state of this issue is a good first step ready for us to start building it next week though.

sun’s picture

Thus, a 'user' is any type of person that we want to be able to store information for.

You do not have a persistent ID for users without an account. How do you intend to store data without an ID?

Aside from that:

You already listed #335411: Switch to Symfony2-based session handling as a related issue. Overall, the actual major aspect this proposal seems to be aiming for is an abstraction of three main components that are not properly separated currently: 1) Session, 2) Authentication, 3) Authorization.

Symfony has a Security component for that, but we've been told that it is very complex and requires lots of careful planning and design, so that most probably won't happen for D8.

andrewbelcher’s picture

You do not have a persistent ID for users without an account. How do you intend to store data without an ID?

I'm not 100% sure what you mean by that, so here a couple thoughts...

Starting off at the beginning, we sometimes need to capture information about anonymous (ie un-authenticated) users. At the moment this is done in a fragmented and somewhat hacky way, e.g. comments. Our proposal first off deals with that by capturing that information against a user entity. Comment can then deal with a random un-authenticated user in exactly the same way it deals with a registered account that frequents the site. This is achieved by separating the user and account (authentication) into two entities.

We could try and reduce the number of user objects created by a number of ways. One of those is interacting with the session. So once a session is set up for an anonymous user, we can track them against the user that is created for them. Once the session ends, that user is then 'legacy'. yautja_cetanu would like to bring in something we've dubbed acquisitions to deal with that, but I'll come back to that later.

In the case of an authenticated user, the account deals with the authentication process, but the rest of Drupal only really has to deal with the user they have authenticated as. Authorization (by which I understand to mean permissions?) will stay exactly the same as it currently is. If somebody registers while they have an anonymous user, we can attach an account to that user, turning it into an registered user, meaning they will maintain anything that have started that session. This could avoid some of the awkward logic commerce has to do with carts for example.

Coming back to acquisitions... We have a system where a user can 'acquire' the information that has been tracked about them in their anonymous user when they register based off of matching criteria. In a simple case, this could be an email address. This is obviously an extension beyond what we already have, so I am thinking that it really belongs in contrib, though I'm sure yautja_cetanu will voice his reasons!

So in summary, I think the Symfony2 related issue is really something for information and something that we may have to work with, rather than something we are trying to solve or figure out as part of this issue. We aren't really proposing that we touch authorization, just that we abstract the authentication so that everything can deal with users in a consolidated fashion, whether those users are anonymous or authenticated. I suppose we could build our accounts on the Symfony2 user, but I think that is probably beyond the scope of what we're proposing and as you said, may not be suitable for D8.

andrewbelcher’s picture

Status: Active » Needs work
FileSize
17.6 KB
75.09 KB

If people are interested, the two attached patches are where we're up to now. The first separates users and accounts into two Entities and starts refactoring some of the processes around it. The second re-factors the comment module to make use of the new anonymous users.

They are both very rough patches so far and there are a few issues in the Sandbox project that we are trying to use to keep track of the various things that need updating. There will be more to go in as well.

sun’s picture

+++ b/core/includes/install.core.inc
@@ -1988,20 +1988,30 @@ function install_configure_form_submit($form, &$form_state) {
+  $user = user_load(1);
+  $user->mail = $form_state['values']['user']['mail'];
+  $user->roles = !empty($account->roles) ? $account->roles : array();
+  $user->status = 1;
+  $user->timezone = $form_state['values']['date_default_timezone'];
+  $user->save();
+
+  $account = entity_create('account', array(
+    'uid' => $user->id(),
+    'username' => $form_state['values']['account']['username'],
+    'pass' => $form_state['values']['account']['pass'],
+    'created' => REQUEST_TIME,
+    'init' => $form_state['values']['user']['mail'],
+  ));
   $account->save();

I don't really get the separation you're making.

Why is roles, status, timezone on the user?

Why is username and created on the account?

Why is init on the account? (init is the initial mail, but mail is on the user.)

Also, Account contains an $aid and a $uid, which architecturally means that a user can have multiple accounts. That sounds bogus to me.

johnv’s picture

Just for reference: the redhen module has a similar approach: 'contacts' that can be linked to accounts.

yautja_cetanu’s picture

"I don't really get the separation you're making.

Why is roles, status, timezone on the user?"

In my mind the most important thing is that Passwords are on something different to E-mail. There are number of ways we could do this and we've picked one out of a bunch of them.

So for me I think the separation that is key is that the "Account" has a password and User has E-mail. This is because the password is something a person absolutely has to manage themselves (they have to remember it, or ask some admin for it again, etc). However an e-mail might be attached to the user in a bunch of different ways that don't require the actual person to handle. For example

In the comments case we may capture some information such as e-mail, first name and last name when someone takes a comment. Later someone might register an account on the website using the e-mail we can know they are the same person and allow that account to "acquire" the user and also all of the comments. (Note: This process I think should be something that could be extended in contrib).

Now exactly where we store that e-mail I think is up for debate. At the moment we're putting it on User. It is possible we could put that e-mail on a profile but then this means we have an e-mail stored in 2 different places and we have to deal with that.

I think Andrew has some more technical reasons of why we've done it this way now.

"Why is init on the account? (init is the initial mail, but mail is on the user.)"

Don't fully understand the purpose of the init but it seems like a wise idea to store the e-mail that was used on account creation in the case of security issues (My account got hacked, I can at least know what was the original e-mail if its been changed lots). It might be a good idea to store an init on the user and account.

"Also, Account contains an $aid and a $uid, which architecturally means that a user can have multiple accounts. That sounds bogus to me."

I agree. There is some talk about multiple authentication methods.

andrewbelcher’s picture

Thanks for taking the time to have a look sun, I'll try to explain the decisions we've made, but they are also far from final if you want to chip in:

Why is roles, status, timezone on the user?

Essentially our separation is that $account does authentication and $user does everything else. There are two core reasons for this; a) it means that you could potentially turn Accounts off and use an alternative authentication method (which is something fubhy has said could be very helpful for web services etc) and still run everything off User and b) it means less re-factoring of everything else, as most things will continue to deal with Users in the same way they did before. This also means a less dramatic API change. There is more discussion about it at this issue: #1811500: What are the roles of the user and the account?. Feel free to re-open it. There is also a follow up (#1813046: Clean up the user table) for cleaning up the User entity, which we have a couple ideas for but haven't spent too much time on it yet.

Specifically with roles, the CRM use case we have come from (Party) uses something very similar to roles to govern what data can be attached (ie profile2 typess). Ie an organisation has org details, an individual has personal details. So roles on a user provides a way for contrib modules to start building on top of User as necessary.

Why is username and created on the account?

Username is specific to authentication, not to interacting with the site. We have a display name on the User which may be the username in a standard setup, but may also be pulling from a name field attached to the user or a profile2 (as that is aiming to go into core also). The idea with that is flexibility and it's a pattern that we found worked very well in Party module. Created is handy to keep as the account may not be created at the same time as the user. It probably will in core but that's a thought for versatility of contrib modules (specifically CRM related) that may build on top of this.

Why is init on the account? (init is the initial mail, but mail is on the user.)

Again, init is (at least currently) about verification, though I'm very happy to be convinced otherwise!

Also, Account contains an $aid and a $uid, which architecturally means that a user can have multiple accounts. That sounds bogus to me.

I agree with you there. We shall clean that up.

rlmumford’s picture

Here's an updated version of the patch with an example of how comment would use it.

This makes a number of things "nicer" about the comment module. Firstly it puts an end to the hacky "let's pretend this comment entity is actually a user" behaviour in template_preprocess_comment().

Previously this had the lines:

$variables['author'] = theme('username', array('account' => $comment));
 .
 .
$variables['user_picture'] = theme_get_setting('toggle_comment_user_picture') ? theme('user_picture', array('account' => $comment)) : '';
$variables['signature'] = $comment->signature;

Here you can see that we have a $comment entity masquerading as a user. This means that implementations of hook_username_alter are sometimes passed a comment instead of a user - a pretty major DX WTF. We once came across this after implementing authentication from an external crm system.

We wanted to load the real name from the CRM system (based off of a map from Drupal uid to the contact_id in the other system). However, we frequently had WSODs on pages with comments as often the object passed hook_username_alter didn't have a uid property.

/**
 * Implements hook_username_alter.
 */
function my_module_username_alter(&$name, $account) {
  // Make sure we've got the proper account object (or at least enough to work with)
  if (!empty($account->uid)) {
    $account = user_load($account->uid);
  }
  else {
    return;
  }
  .
  .  // code to calculate name
  .
}

It shouldn't be up to implementers of this hook to check whether they have a user entity or not.

The patch ensures that every comment has a user record associated with it, whether registered or not. We can now guarantee that hook_username_alter will always be passed a User object. This is even more important with Profile2 working it's way into core Drupal.

Crell’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, comment_example.patch, failed testing.

sun’s picture

Component: user.module » user system

#12 should not be discussed/handled here, because it duplicates existing issues:
#585838: Consider a generic $entity->user property
(AFAIK there are more, but can't find them right now)

The main reason why this was/is done that way and was not changed is performance. But again, that should be discussed in existing issues and not duplicated here.

But that said, the proposed changes here certainly have a considerable impact on performance as well, since a single load turns into two ones that are not/cannot be optimized.

It also seems like the new proposed user records will partially duplicate session records, as well as a good chunk of Comment module's comment author data.

Overall, it's great that you directly jumped on proof of concept code, but I think this proposal needs to be fleshed out much more, the plan/summary needs to clarify and explain the separation between user and account properties, but should also clarify the relation/duplication of user and session data, and I'm also missing in-depth considerations about the consequences of this change proposal.

That's not to be understood as pushback - quite the contrary - I'm really happy that someone takes on this work. If done well, it will bring our architecture in a much more cleanly separated state, which is more compatible with current industry standards (as already alluded to in #5). However, an architectural change like this needs to be planned very carefully.

fubhy’s picture

But that said, the proposed changes here certainly have a considerable impact on performance as well, since a single load turns into two ones that are not/cannot be optimized.

I don't believe that there would be any problems with performance with the proposed separation of user/account entity. The account entity is only required for the authentication process. So only ONE additional entity load for the current user's account. We rarely need to load actual account data in other places. So, except for the authentication process we would not be loading any additional data. User lists, etc. are built with nothing but the user entities in our database. No need to join or attach the account entities.

It also seems like the new proposed user records will partially duplicate session records, as well as a good chunk of Comment module's comment author data.

The goal of this issue is to make working with anonymous users easy and so we would basically deprecate that custom code for anon user data in Comment module in favor of a better solution using anonymous users!

yautja_cetanu’s picture

However, an architectural change like this needs to be planned very carefully.

Just out of interest. Have you seen our Google doc and the issue queue in the sandbox?

As you say, there are quite a few consequences to consider and we have done quite a bit of work thinking this through in both the contributed party module and fubhy's sandbox. We are certainly willing to put more effort into it but my worry is that me, andrew and rlmumford could go on and on talking about this as fubhy is starting to see! So I'm concerned about doing too much work away from the pupal community and having this huge amount of information for people to digest before they see anything.

One thing that has been really helpful about having fubhy help is he's looked through all our conversations we've had and help summarise it really nicely into a post that can go into group.drupal.org. This is actually quite a simple issue, its just we do put lots of effort thinking about everything.

So basically I'm asking. This planning things careful. Do you want us to just do a lot of these planning ourselves in the sandbox/google document and then post the final output here. Or is there something we can do to help more people get involved?

(we're on IRC all the time or skype if you want to talk to us more)

Damien Tournoud’s picture

Why not storing those "anonymous users" as a user with an additional property defining that they are not "real" registered users? I don't see the point of separating the two concepts, when they are actually two stages of a "user" of the site. Those could be handled by two different bundles of the user entity, or by a "isAnonymous()" flag.

fubhy’s picture

By moving the account data out of the user entity we gain a) a clean environment for storing registere/anonymous users in the same way and b) make accounts potentially optional.

fago’s picture

I like the idea of #18. I don't really see where the line between the suggested user and account would be. If you have an anomyous users, you might want to track more data as well. Then, once the user turns into a registered user, I want to keep the same data and I want to keep working with the same thing. Nothing really chanced besides that the user can now login.

So, isn't just everything we need to do making registration for user/account entities optional?

Those could be handled by two different bundles of the user entity, or by a "isAnonymous()" flag.

As an "anonymous user" could be identified (e.g. the user who posted a comment) anonymous users sounds like being the wrong name. So maybe hasAccount() or isRegistered(). isAuthenticated() sounds wrong as well, an "anomyous users" could be authenticated as well - what tells me that our role needs a rename.

Mile23’s picture

+1 on the big idea, and +1 on #18.

Considering the use-case of anonymous voting: Who will own the votes when the session-user table is culled in cron? You'll have orphaned, anonymous votes. So sad.

Just add another constant for status (status_session_user?). The system would put a UUID in the name column, [uuid]@[sitename] for email, and maybe 0 in login.

The admin would be able to specify whether session users would be purged at cron after a certain time, or not, and how to handle content for that class of users. And of course the ability to disallow such users. There might need to be a new hook, something like hook_content_by_this_user_is_now_anonymous($user).

This would make it much easier from a DX standpoint: These session users would get all the same user and entity API hooks as an authenticated user. This is how that user's anonymous votes will be properly deleted when the time comes, for instance. If you have a separate API for session users, then everyone has to re-write their module for it.

Also, it would mean that if the user generates anonymous content, and then creates an account, Drupal can just use the existing record with updated name and email. Then their previous content already belongs to them without any other changes. (This would also be an admin setting, and a preference for the user when they create the account. Not all anon users want their anon content to follow them.)

yautja_cetanu’s picture

Then, once the user turns into a registered user, I want to keep the same data and I want to keep working with the same thing. Nothing really chanced besides that the user can now login.

In our minds our architecture would completely allow this. A User is a User whether they are anonymous or registered and hence are unified regardless of whether they are just a user who posted a comment or a user who can log in. A user who can log in is a user that also has an account which merely stores their authentication information (such as password).

With our party module we have use cases of this actually working. If someone registers for the first time with an e-mail of an anonymous user (In our module it is called a Party) they can take control and "Aquire" that party.

Then their previous content already belongs to them without any other changes.

Again, in the Google Document (which we can bring into another issue possible) we have a detailed write-up of this process called "User Acquisition"

This would also be an admin setting, and a preference for the user when they create the account. Not all anon users want their anon content to follow them.

Yes, I agree. The important thing is that we need to make sure Contrib can extend this acquisition process. If you use Drupal to store more sensitive information about anonymous users (such as in a CRM system) you may need potentially complicated stop gaps before someone is allowed to get their data. We've talked about it here:

#1742646: [Doc] Party Acquisition Security issues

Then, once the user turns into a registered user, I want to keep the same data and I want to keep working with the same thing. Nothing really chanced besides that the user can now login.

So, isn't just everything we need to do making registration for user/account entities optional?

Essentially that is our goal.

Why not storing those "anonymous users" as a user with an additional property defining that they are not "real" registered users?

So in my mind the important thing to note is that I can see no inherent advantages of doing it that way. All the potential advantages others have talked about in this thread are also possible with our architecture and we have shown this in contrib. However I think we'll spend the next couple of days investigating it. Off the top of my head there are two main advantages of our architecture.

Keeping the User and its Account information separate

  • Fully Pluggable Authentication system. The User could work without the account if web services used alternative authentication methods. May make Drupal play nicer with other software like civicrm
  • It is a cleaner architecture. It may be confusing building a CRM system for example off the other architecture if there are a bunch of fields (such as password) that you don't really need. I think I need to think about this more.

The main advantage of keeping them on the same thing is that there might be less work to do. But I don't even know if that is true.

rlmumford’s picture

Thanks everyone for taking the time to get involved in the discussion! If this is going to serve the community well then we need alot of input. In response to sun's concerns:

the proposed changes here certainly have a considerable impact on performance as well,

Ordinarily the only user for whom you'll ever be interested in the 'account' entity is the active user (or perhaps a user you are editing). At most this is one extra query per page load. For sites with many active anonymous users, the separation would cause a performance boost as the User table would be a little smaller.

It also seems like the new proposed user records will partially duplicate session records, as well as a good chunk of Comment module's comment author data.

In comment_example.patch user information (anonymous or otherwise) is no longer stored in the comment table - there's no duplication in that sense. The patch does lead to more records in the user table - but for the most part I believe they're legitimate. We could put work into finding ways of preventing duplicates (in Party we call this 'acquisitions'). With the user and account tables separated Drupal only stores what it needs for anonymous users whereas storing an anonymous flag can result in more superfluous data, especially on sites where most interactions are by anonymous users.

WRT maintaining an anonymous user for a session; I don't see how you would do it universally and safely. Storing the User in the session causes issues on public devices and doesn't necessarily solve the problem of trying to have one User record for each real-life user. I think the safest way of preventing duplicates is to match based on email.

In general, what we've found as we've worked in this problem-space is that there are a number of gripes people have that would be solved by a well designed separation between Users and Accounts:

  • Attributing actions of unregistered users to something (comment module nastiness being a prime example)
  • Properly pluggable authentication methods (in the last few days of talking to people about this patch I've heard suggestions of everything from public-private key authentication to google account authentication to "something to do with web services")
  • Storing information about people that aren't users but could possibly become users in the future (see Party and Profile2)
  • Using all the awesome stuff in contrib with people that don't have to be registered (for example simplenews, organic groups and comment_notify. Even commerce has to use some of its own bespoke, almost-hacky stuff to work with anonymous users!)

I'm still trying to process the suggestion in #18. An anonymous flag may be able to solve all of the points above (I think it fails on the second point) but something about it feels inelegant. There are constraints on the user table that are more unhelpful for anonymous users including a unique username field and a 'not null' password field (already email_registration has to work around the first of these).

Shawn DeArmond’s picture

I can think of a very good use-case for this:

A parent wants to register his children for a summer camp. Registration module is used, but currently Users (aka accounts) now have to be created for each child. And email addresses have to be unique. Well, 6-year-olds (currently) don't necessarily have email addresses, and really, the parent is the one who should be receiving all the communications anyway. On top of that, there are COPA laws that make it so you REALLY DON'T WANT children to have accounts on your site.

Separating "user" from "account" will allow the children to be "users", ideally, even without an email address, but the parent will own the "Account" and will receive all communication from the site.

Please let me know if I'm off-base here.

andrewbelcher’s picture

A parent wants to register his children for a summer camp.

This is spot on one of the scenarios that we have had to and managed to solve through contrib with the Party module. The downside of it in contrib is that we have to do a number of fiddle manipulations rather than it just automatically working with everything in the system!

Anonymous’s picture

Well, 6-year-olds (currently) don't necessarily have email addresses, and really, the parent is the one who should be receiving all the communications anyway.

Operative word in that statement is "should be". Parent's are often stupid and kids, even 6 year olds, are smart.

there are COPA laws that make it so you REALLY DON'T WANT children to have accounts on your site.

You can only protect yourself by asking for age verification. There is literally nothing between the site and the child that can prevent their access other than a parent or guardian.

The use case I was thinking of was eCommerce where the anonymous user doesn't want to register for an account.

Shawn DeArmond’s picture

You can only protect yourself by asking for age verification.

That's the issue, I WANT 6-year-olds to attend the summer camp. In fact, I NEED to know that they're 6 years old so they go in the 6-9 group, instead of the 10-12 or 13-16 group. However, I want none of them to actually be able to access that account in any way, if they're under, say, 13 (or whatever the COPA limit is). Until they get that age, the only Account should be the parent's account. Of course, they could lie and create their own parent account, but that wouldn't really do them any good.

It would be nice if, at some point, the child account can be converted to a real account once they hit 13, so they can manage their own account and start using more of the social features of the site (for example). I know what a drag it is to move a node from one content type to another.

levelos’s picture

@Shawn DeArmond, I'm the maintainer of the Registration module and we're working on a feature to address this, #1653458: Register an entity different than a user.

We (ThinkShout) are also behind RedHen CRM, another of the emerging native CRM solutions in D7. Our approach has been to define a custom contact entity, among others, which handles the abstraction of registered users and other entities (E.g., contacts, organizations) that interact with a website. As mentioned in #9, contacts are then linked to user accounts as needed. Between the core entity system and Entity API, the process of setting up custom entity types is rather trivial from a development standpoint, and things get interesting as you implement unique, use-case specific, business logic in the controllers and entity classes. I'm not sure I see a strong benefit to Drupal core defining an abstract anonymous entity type given it's already simple to do and much of the heavy lifting will still need to be done with custom code in contrib.

That said, if such a feature/concept does make it into D8 core, it seems fairly straightforward to replace our custom entity RedHen Contacts and extend Drupal anonymous instead, so I'm not suggesting we're against it. The comment module use case used in this thread is certainly a strong argument to having a unified approach to dealing with non-registered entities interacting with the website. Again, in our case, we're linking RedHen contacts to comments via an email address and are exploring a technique to "convert" these anonymous interactions into registered ones as has been discussed here already.

YesCT’s picture

I've had to do crazy stuff to implement a conference registration site for families (with children). Similar to what's mentioned in #24.

andrewbelcher’s picture

levelos, thanks for your input.

I'm not sure I see astrong benefit to Drupal core defining an abstract anonymous entity type given it's already simple to do and much of the heavy lifting will still need to be done with custom code in contrib.

rlmumford outlined a few advantages for other modules like comment and simplenews. From a CRM point of view, it's one of fragmentation. At the moment, anything that is designed for Drupal integrates with users. If you want to integrate it with a CRM system that can also cope with non-users, you are forces to deal with the data through the user. It then becomes even harder for anything that doesn't have a user. Essentially you end up having to do a lot of custom code, processes and juggling to make things work with non-user contacts. However, if everything interacted with a single unified system, whether anonymous or registered, then it would take out almost all of the complexity of the CRM module, allowing you to then invest the time and effort into building the work flows and UIs.

larowlan’s picture

fwiw this seems like a duplicate of #355513: Create an anonymous user API

Damien Tournoud’s picture

@yautja_cetanu:

Off the top of my head there are two main advantages of our architecture:

- Fully Pluggable Authentication system. The User could work without the account if web services used alternative authentication methods. May make Drupal play nicer with other software like civicrm
- It is a cleaner architecture. It may be confusing building a CRM system for example off the other architecture if there are a bunch of fields (such as password) that you don't really need. I think I need to think about this more.

^ I think you are confusing two objectives here:

  • Improving the authentication system / allowing multiple forms of authentication per user / etc.
  • Having user objects for users that are identified but have not officially registered

Those two objectives are worthy, but we don't need to try to solve them in a single go.

To satisfy the objective of having user objects for non-registered users, we can easily add a new property to the User entity, and put mechanisms in place to upgrade this non-registered User into a fully registered User.

To improve the authentication system, we are going to need to: move credentials out of the user table (maybe as a field, or as a separate "user_credential" entity), implement an authentication plugin type, etc.

I don't see any rational reason to mix those two goals, as they are by themselves very different.

@Shawn DeArmond:

Separating "user" from "account" will allow the children to be "users", ideally, even without an email address, but the parent will own the "Account" and will receive all communication from the site.

The proposed architecture doesn't cover this use case at all. One "user" can have several "accounts" (authentication information), not the other way around.

I think giving the children a "non-registered" account would satisfy most of your requirements.

rlmumford’s picture

@Damien

What are the advantages of a 'anonymous' property over the architecture proposed?

To improve the authentication system, we are going to need to: move credentials out of the user table (maybe as a field, or as a separate "user_credential" entity), implement an authentication plugin type, etc.

What is the difference between this and the architecture proposed?

yautja_cetanu’s picture

The proposed architecture doesn't cover this use case at all. One "user" can have several "accounts" (authentication information), not the other way around.

No the architecture doesn't support it OOB but will allow contrib to do so. In Contrib we use Organic Group to allow people to "Manage" a party and have permissions to edit information on the party to solve this problem.

^ I think you are confusing two objectives here:

The objective in my mind is to allow the Profile module to store information about Anonymous Users to form a basis of a CRM system. What I want is for someone to register on the site and claim that information as their own. What is interesting is that this solves a problem regarding the comment module so thats cool, they are essentially the same problem (And same with simplenews and same with voting api).

we can easily add a new property to the User entity, and put mechanisms in place to upgrade this non-registered User into a fully registered User.

I'm happy to try this method out. I'm not certain it will be easier to put those mechanisms in place, especially as we've already done it in contrib with our architecture. Also you will end up having lots of things create users with this tag.. dunno if that matters. Also it will mean in Contrib to make CRM systems we'll constantly have to hide the confusing password and username fields... but that might not matter.

So what are your feelings for why its easier to put a flag on users rather then separating the account out?

andrewbelcher’s picture

One "user" can have several "accounts" (authentication information), not the other way around

Actually, the proposal is that a User can optionally have one Account, but that Account could be replaced by an alternative system.

Those two objectives are worthy, but we don't need to try to solve them in a single go.

This is an option. However, if we go down that route we need to start dealing with things like unique indexes in the schema and it also means that for anonymous users there is a large amount of data that is irrelevant. That's not ideal from a performance/sql point of view. Ideally we'd like to see a load of the other aspects like settings being pulled off of the User entity to make it even more lightweight, but I think that's best as a follow up.

andrewbelcher’s picture

andrewbelcher’s picture

Damien Tournoud’s picture

So what are your feelings for why its easier to put a flag on users rather then separating the account out?

I am just trying to reduce the scope of the issue. While trying to extract and abstract authentication is a worthy goal, it is a complex issue that is going to require in-depth architecture discussion (and extracting the authentication information from the User entity is only one part of this story).

I think we can achieve the goal of "Unify anonymous and registered users" in a much simple way, by just storing both types of users in the same entity and marking them with a different flag. This will not impede any subsequent effort at abstracting authentication, but will guarantee that you can reach your goal in a more timely manner :)

fubhy’s picture

While I still believe that the idea of having a separation between accounts and users is very legitimate and should be done at some point I also agree with Damien in #38: It's probably out of scope for this issue. Let's keep this one simple and create a separate issue for achieving the separation of the two concepts. However, scenarios as described by #24, the comment module as well as other cases of anonymous interaction (voting, etc.) are very good and valid reason to ultimately go for a separation between user/account entities.

I set up a follow-up issue to work on untying accounts and users: #1816218: [P-1] Separate the account information from the user entity..

Let's work on the anonymous users only in here (while leaving the user entity in tact) and work on the authentication related stuff in the other issue.

fubhy’s picture

Issue summary: View changes

Added the stuff from the shared google doc.

fubhy’s picture

Issue summary: View changes

Updated issue summary.

fubhy’s picture

Status: Needs work » Active

I updated the issue summary accordingly.

levelos’s picture

However, if everything interacted with a single unified system, whether anonymous or registered, then it would take out almost all of the complexity of the CRM module, allowing you to then invest the time and effort into building the work flows and UIs.

@andrewbelcher, I definitely agree that a unified base for dealing with anonymous interaction is a great thing, freeing us to focus on the exciting parts ;) Really good to see some discussion/progress along this front. FWIW, we'll be at PNWDS this weekend if anyone's there and wants to chat.

juan_g’s picture

fubhy wrote:

Let's work on the anonymous users only in here (while leaving the user entity in tact) and work on the authentication related stuff in the other issue.

There is #355513: Create an anonymous user API, as well.

For example, how about the very simple and efficient Wikipedia system for anonymous users, with no need for long session IDs in all URLs or in also unneeded anons' cookies (only set for registered users), etc.?

sun’s picture

I couldn't agree more with @Damien Tournoud — reducing the scope was exactly what I had in mind since #5, too.

With #1816218: [P-1] Separate the account information from the user entity. being its separate issue (I hope you checked for existing issues?), that essentially leaves the isAnonymous()/isRegistered() flag for {users} here.

While a flag has its own challenges in terms of consequences to business logic, it definitely avoids very potential performance problems. Someone tried to argue against that in an earlier comment, but due to the originally suggested split-up of properties, the 99.9% use-case we have throughout Drupal core and contrib would have to load both the user and the account record. That would either require a JOIN, or subsequent separate loading (with separate caches, separate maintenance, etc.pp.). In any case, there would be a performance impact compared to now.

Also, someone else mentioned {users}.data in here. I'm actively working on eliminating that already: #347988: Move $user->data into own table

Thus, coming from Comment module's perspective, the resulting change proposal at hand would boil down to moving/adding the following properties from {comment} into {users}:

  • {comment}.hostname (== {sessions}.hostname) » {users}.hostname

    This property was overlooked in the PoC patch, and explains why #335411: Switch to Symfony2-based session handling is highly relevant. It appears to be relatively clear what the goal and intended property logic with regard to anonymous/non-registered users is, but we have to figure out what the logic for registered users would be.

    Apparently, {users}.access is frequently updated for registered users already, so we might as well just add another column/value pair to that existing update query.

  • {comment}.name » {users}.name
  • {comment}.mail » {users}.mail
  • {comment}.homepage » {users}.homepage

    This arguably could or should be converted into a field later on, but I think it would be acceptable to just move it for now.

What we inherently gain from this is a unique constraint on .name and .mail across anonymous and registered users. Some potentially unintended consequence of doing so, however, are:

  1. Sites are no longer able to decide whether they want to enforce that constraint; it is automatically enforced on all sites, regardless of your use-case.

    This apparently was a critical bug in D7: #845774: Regression: Anonymous users can post comments in the name of registered users

  2. The comment author name is an arbitrary name currently. Not a unique username. This will disallow and not support to have two (anonymous) comment authors with the same name, which could reasonably be interpreted as a serious regression, depending on your use-case for comments.

    Somewhat related: #936844: Cannot override comment author to or from Anonymous

  3. The upgrade path for all of this is going to get hairy, very hairy. You can easily migrate all records that are unique, but as soon as you hit a unique constraint violation, all hell breaks loose.

  4. If we uniquely identify and store (anonymous) users, then I'm fairly sure that we inherently run into data privacy issues.

    The epic #8: Let users cancel their accounts resolved that for all uniquely identified users since D7. We'd probably have to have at least a follow-up issue to ensure that this consequence is on the radar. Doesn't sound hard to do though.

  5. Privacy, however, seems to be a major consequence here, since every comment author essentially becomes a semi-registered user automatically on all sites. The only piece of data that's missing in the default comment author options factually is a password — there's no further difference otherwise (EDIT: This actually sounds very nice to me). Therefore, Internet users having a high/strict privacy understanding could reasonably have a problem with that.

  6. It also begs the question how completely anonymous comments can still be achieved. Those would technically end up with a hostname/IP value in {users} only, whereas it is important to save that value for many use-cases (and policies, potentially enforced by law). However, saving otherwise empty records into {users} doesn't seem to make much sense (although they could potentially be pruned out automatically after some [configurable] time).

Lastly there's also the question of how contrib would be able to extend or replace the properties for anonymous users if needed (e.g., identifying by some other value instead of e-mail, which would inherently mean that name/e-mail shouldn't be required). However, since Comment module's properties served us well over the past years, that question is borderline scope-creep and should probably be ignored for now and investigated later.

This list is essentially what I meant with thinking about the consequences of the architectural change proposal. The list is certainly not complete.

cweagans’s picture

Fabianx’s picture

Issue tags: +undefined
Fabianx’s picture

Issue tags: -undefined +Favorite-of-Dries, +anonymous users

Trying again

rszrama’s picture

The definition of "user" expanded over the course of the thread from a visitor to the site who decides to interact without registering to include a person whose information may have been entered on the site but who never personally visited the site. I'm not sure this is necessary or desirable; there are other ways to handle event registration on behalf of non-users, for example.

It's also not clear to me what happens to anonymous user data once the user's session expires. For this change to make sense, the user would become a perpetually orphaned artifact sitting in the database soaking up an email / username as sun pointed out above. Without authentication, we can't reliably associate that uid with the actions of future anonymous users, especially not if we want to promote an anonymous user to a registered user, giving them control of (or conversely blaming them for) any content / comment associated with that uid. Even if we did try to associate comments with existing anonymous users, as an anonymous commenter I'd have to remember the precise anonymous username I used for my previous comment with the same e-mail address. Bleh.

I suppose given sun's exception #2, even if this change were made, I wouldn't expect the comment module to use users for anonymous comments. It creates more UX problems than it solves (does it solve any? or just DX problems that we have the other issue for?).

Anonymous’s picture

Straying a bit off course here but ...

It would be nice if, at some point, the child account can be converted to a real account once they hit 13, so they can manage their own account and start using more of the social features of the site (for example). I know what a drag it is to move a node from one content type to another.

This can be handled by workflow of a custom module providing a birth date field and roles that adjust based on age range. A hook_cron implementation would adjust the user role as necessary.

@Shawn DeArmond:

Separating "user" from "account" will allow the children to be "users", ideally, even without an email address, but the parent will own the "Account" and will receive all communication from the site.

The proposed architecture doesn't cover this use case at all. One "user" can have several "accounts" (authentication information), not the other way around.

I think giving the children a "non-registered" account would satisfy most of your requirements.

In its simplest form a user is someone accessing the site. There is something known about that user based on that access but no common relationship to any entity or object can be established. A registered user has at least two known items (username and password) that can be used to establish a common relationship to an entity or object at which time a relationship role can be established. An anonymous or "non-registered" account has no common relationship data, you cannot create a fictitious user based on measured data obtained from the connection to the site; there is no guarantee that the connection information might not change for the session. You could create a cookie that stores a unique id for that session which would give you some percentage of probability that you can determine a user which is what most shopping cart sites use to store items in the shopping cart when the user is unauthenticated. If a tracking cookie is used you must inform the user of it for best practice policy.

I see a registered user as NAME, PASSWORD and that is all. That is the only method I see which can satisfy the scenario of children. The session can remain authenticated until such time the session connection is changed. If it is a childs account the parent can create the account and open the session for the child guarding the password from the client side of the connection. A birth date field with adjusting role based on age of that date can be used to promote the user to a new privileges. Any other information, email account, phone number, etc is profile information that may be used but would not strictly be necessary unless the site admin considers them to be.

I see a "non-registered" user as IP address. That is all we really know about the user. We could ask for a name but that name must be paired/concatenated with the IP address. The only issue is that there is no real commonality we can associate to that user.

As for registered user verification, a site may choose not to use verification. If verification is used then there could be choices presented for that verification; such as email address as we have today, a phone response from a touch tone or cell phone, some other method (including snail mail).

To bring this back to point, anonymous and registered users have one thing in common; the IP address. But that common thing does not have uniqueness. So the question becomes, how do you make the anonymous user have a unique identity? I don't think you really can totally, at least to the point of controlling how many votes an anonymous user gets in a polling issue or controlling children without being registered. You cannot really do that with registered users either, the same person could have multiple accounts and those with enough savvy can make them look uniquely different.

rszrama’s picture

And to reiterate my first comment in #47, I don't see why we're trying to expand the concept of "user" to include non-users or potential users in this issue.

yautja_cetanu’s picture

We have put up a comparison of the 2 ideas in the separate issue: #1816218: [P-1] Separate the account information from the user entity.. Here we will just respond directly to your comment

While a flag has its own challenges in terms of consequences to business logic, it definitely avoids very potential performance problems.

In the comparison we explain how our architecture of having a non-unique name on the user entity that essentially a cached entity label means there is no significant performance hit. We can run some tests on this to demonstrate this more clearly if required.

We have a couple of working development sites with the patch applied and the ‘Account’ entity is only loaded on two occasions:

  • When a user is logging in
  • When an account is being edited.

I’m not sure if there are any other operations that would need an account (after our nice names is in), but I doubt 99.9% would.

Thus, coming from Comment module's perspective, the resulting change proposal at hand would boil down to moving/adding the following properties from {comment} into {users}:

Yeah, this is how I envisioned it working with comment; the other patch implements these changes (with the exception of homepage which was dropped as there was no analogous field on users).

What we inherently gain from this is a unique constraint on .name and .mail across anonymous and registered users.

I don’t know if this is a gain, especially if you start using the anonymous user API for any more than comments.

I’ll reply to each point without quoting them:

Regarding 1-5 I feel all those points work in favour of our architecture as we both allow for all the potential cases mentioned here whilst also allowing for contrib to make work the other way.

1. Our architecture completely makes sure that that bug would never happen again as there is a complete separation between the two. Comments could output users with account differently to without accounts,
2. Again, I think there will be multiple use-cases for comments. Certainly unique names on comments is not how other people work.
3. Yes :)
4 & 5. Yes, privacy is a big deal and therefore I think on core we need to work for the most simple and secure use case but allow contrib to extend this further. We talk about this when dealing with “User Acquisitions”

6. I think it makes more sense to store the hostname on the comment if you need that. In fact even if an authenticated user posts a comment it probably still needs to store an IP address on the comment if you need that because people could log in via different computer. It doesn’t seem reasonable to assume a user always comes from the same hostname.I suggest if it is ever helpful to store an ip address against something, the Ip address should be stored against the thing rather than the user doing it. So for completely anonymous comments you won’t attach a user at all to the comment.

Lastly there's also the question of how contrib would be able to extend or replace the properties for anonymous users if needed... that question is borderline scope-creep and should probably be ignored for now and investigated later.

Whilst I am happy for the issue to reduce the scope. It is important for us (yautja_cetanu, rlmumford, andrewbelcher) to investigate the use cases alongside getting this patch in. We are coming from the point of view of having to write the Party module that does CRM and core’s inflexibility regarding the User entity has caused us lots of headaches having to integrate every single module in drupal with our module to take advantage of those modules (such as simplenews).

Our architecture is quite simple but allows for those cases. Again perfectly happy being tasked to go and investigate this a bunch of times.

A lot of these comments on this issue are regarding how contrib could extend this. Note I really don’t believe we should be getting core to do all this, but providing an architecture so that contrib can.

  • User Acquisitions: We are working frantically getting a demo of this up. We want to make a demo where you post a comment anonymously, register and take over all your comments to show how contrib could do it easily with our architecture. Detailed in our sandbox here #1816822: User Acquisitions - Accounts taking control of a previously created User
  • User Types - We need at least in contrib the ability to have different anonymous user types with different information attached to them and different registration forms. I am strongly against using bundles for this and think with the profile module in core we shouldn’t allow fields on users. Anyway further discussion is here:#1816836: Different User Types - (Party Hats)
yautja_cetanu’s picture

I'll just add a note, Sun if you'd like us to build a version of this patch in the sandbox implementing your ideas feel free to say so and we can do that so we can do a better comparison. I just wanted to at least try talking about it before we actually write this stuff.

We've written an acquisitions patch but we'll post a link to a demo tomorrow. (As most people in this thread are talking about it)
(I say we because both responses have been written by me and rlmumford)

rlmumford’s picture

As yautja_cetanu mentioned, here is a working proof of concept for acquisitions. http://d8demo.cnsuk.co.cc

yautja_cetanu’s picture

https://docs.google.com/document/d/16qMcnmEBivMuNFxIEky7C4P-LVMtgnODSCAm...

A comparison of all the different potential methods we could use and their consequences. Looking at that list I think we may be able to make a few hybrid methods. My idea for a roadmap:

1) Get anonymous users a thing - Rlmumford has made this patch
2) Get anonymous users working with the comment module - Rlmumford is working on this patch
3) Get anonymous user names working right (Most of the different methods have issues with anonymous names)
4) How much do we use profile to store anonymous information?
5) Further work - User Types, Acquisitions, Pluggable authentication.

rlmumford’s picture

So I had a crack at building the anonymous user API using the flag method described by Sun and others. You'll notice that the initial patch is fairly small. By defaulting the anonymous flag to zero, most of Drupal remains unchanged. When it comes to comment module we require some more intricate logic to do validation on the comment save.

This method means that it is no longer possible for two comments to be posted by a person with the same name which could be considered a regression. This also means the same person commenting twice would have to choose a different name each time unless we build in 'acquisitions'.

'Acquisitions' is the name we've given to a system that prevents duplicate users by attempting to match actions to existing users in the database. This is more important with this method as there is a Uniqueness constraint on the username at database level. In this case the comment module will allow a comment to be matched to an existing anonymous user if the username and email provided match.

For a more in depth discussion into the pros and cons of this method, please see the google doc linked above.

yautja_cetanu’s picture

rszrama,

I just found a comment here: #1668292: Move simplified Profile module into core you made about using profile potentially for customer profile information. I think an anonymous user api would be really helpful for you here then because billing information could attach to anonymous users and authenticated users alike.

The demo we linked to above is an example of how these anonymous user don't have to just be orphaned and I think commerce could make use of this in really interesting ways. We can explain our ideas a bit more on IRC if you'd prefer but we have had commerce in mind particularly (along with some other modules) when we've suggested our ideas.

yktdan’s picture

Let me give a use case that corresponds to what I want. Our site runs Drupal with og, ubercart - moving to commerce, and soon civiCRM. I want only one notion of user per real person. For civi I need people that have no email address. Many people are parts of the same household and may or may not have the same email address, etc. Some people need special roles that come with extra permissions. Some people have many roles and we need either the notion of being in a particular role at the moment, or having the union of their roles permissions. An example is that I have a normal userid but I am also webmaster with uid=1. So I want my payments to go on my normal account not my uid=1 account, but I need to move easily between these two accounts, e.g I am logged into both with a cookie remembering that I am logged in to both, but just hitting a special key or clicking on a link moves me from one account to the other.

In a separate issue, Drupal should support security levels in the government sense. Roles are sort of like security levels in the government where great care is taken to insure that high security levels cannot expose secrets to lower levels.

Fabianx’s picture

Status: Active » Needs review

Status: Needs review » Needs work

The last submitted patch, anonymous-flag-comment.patch, failed testing.

andrewbelcher’s picture

/**
 * Checks if a username is registered.
 *
 * @param $name
 *   A string containing the name of the user.
 *
 * @return
 *   True if the user is registered, false if they are anonymous.
 */
function user_is_registered($name) {
  $result = db_select('users')
    ->fields('users', array('name', 'uid'))
    ->condition('name', db_like($name), 'LIKE')
    ->condition('anonymous', 0)
    ->execute()->fetchObject();

  return ($result) ? TRUE : FALSE;
}

This currently returns TRUE if exists and is anonymous and FALSE if doesn't exist or is registered which doesn't match the @return. Also, should we be looking to match what user_is_blocked() does and return an object?

Also, do we want to show a different message if an anonymous account is found verses if no account is found? The existing validate process seems odd to me (query to see if it's blocked then a query to get hold of it for authentication?), but I wonder if we want to leave user_login_name_validate() as is and just have the anonymous check in user_login_authenticate_validate()?

rlmumford’s picture

This currently returns TRUE if exists and is anonymous and FALSE if doesn't exist or is registered which doesn't match the @return. Also, should we be looking to match what user_is_blocked() does and return an object?

Ok, so it doesn't distinguish between an anonymous account and no-account. But it returns true if the user exists and is NOT anonymous. So if you get TRUE back you can be sure that the user is registered and if you get FALSE back you can be sure that the user isn't registered (even if there are a couple of variants within that).

andrewbelcher’s picture

Sorry, when I read 'anonymous' I read 'registered'... :P

yautja_cetanu’s picture

Status: Needs work » Postponed

Just a status update on where we are at:

Current Issue Summary
We (Party people - andrewbelcher and rlmumford) have created two patches to try and get an anonymous user api into Drupal 8. One patch separates an "Account" from the "User". The User entity combined with Profile could be used to store information about user entities properly and the rest of Drupal (such as comment) could be built around that. We've also made a patch that instead flags a user as an anonymous user and makes the password field optional.

There were some criticisms and questions about what we were doing. We've written extensively about them in the sandbox, in this issue and in Google docs. If there are any more questions we'd be happy to ask them.

However as the feature freeze is immanent we feel it is unlikely any of this will happen for Drupal 8. Even if we had the time, it seems like too many core developers need to get involved before a patch could be committed and so instead we will continue working on this stuff in Contrib with an aim to get this in for Drupal 9. We have a number of clients migrating from some pretty hefty CRM software onto a native Drupal solution and so for Drupal 9 we'll have even more knowledge of exactly how this could be used.

Therefore, unless others want to get involved, I'm marking this as postponed.

yktdan’s picture

I think there are still some missing use cases. What you seem to consider is really making anonymous equivalent to registered in that permanent records are kept about the person (I claim that is what registered does). If you want a registered user to have more information than just name, email, then call it something else. For privacy reasons there really is a need for really anonymous in that no records at all are kept other than in the session. This is likely a severe restriction on what anonymous users can do, e.g. the records for anonymous users are all appended to a single account (anonymous). You might want to record the IP address with that just to make finding a bunch of spam posts easier. Since IP addresses permanence range from long term (static ip) to very transient, and for some use cases people really need to be anonymous (say for political reasons), recording the IP must be configurable. That is what should be called anonymous. CRMs have a different issue. They need to be able to record information about people that don't have an email address (they sent in a check by snail mail to validate their account). For these people it might be nice to trap things that would go out by email and instead print and snail mail them. They need a mechanism for dealing with multiple John Smith's who are different people. Perhaps prevent users from using pure numeric usernames and use the user number for these people.

What amount of anonymity is provided by a site must be configurable. Some want true complete anonymous. Others want to prevent anonymous from doing anything other than viewing. How much anonymous commenting or form filling out one wants to allow depends on your resources for dealing with the unavoidable spam.

yautja_cetanu’s picture

"What you seem to consider is really making anonymous equivalent to registered in that permanent records are kept about the person"

I do think the naming of what we're doing is somewhat confusing. This is why we didn't adopt the "Create an anonymous user API". However the reality is in Drupal an anonymous user can have permanent data stored about them. When an anonymous user creates a comment they can store their name, e-mail and website. My understanding is that when this happens Drupal treats the comment itself as a user in some situations (like rending a user name).

So what we're aiming to do is essentially solve that problem but solve is properly so that contrib can then deal with users flexibly in the way that it needs to. Therefore this solution has to deal with

  • anonymous users that are truly anonymous users.
  • anonymous users that want a permanent record stored in them
  • anonymous users that want a permanent record stored in them but they may even become authenticated users in the future.

In my mind the way forward is to make Drupal Core behave exactly as it currently does (Hence why we have demo-ed our changes by showing how it impacts the comment module) but create a better underlying architecture that can allow contrib to extend things more sensibly.

However, Sun rose a similar issues in #43 and I replied in #50.

Regarding Use cases. The reality is because we're dealing with this in contrib we have put lots of effort into documenting the use cases. The problem is finding some way of putting them on paper in a way that busy people can read them. Don't know how to do that so I'm thinking of waiting until people are less busy.

sun’s picture

Quick remark on the last comments:
I don't think that the reason for why this might not happen for D8 is that people are busy. Instead, my personal impression is that the discussion so far revealed that there are conceptual problems with the changes being proposed. My second impression is that the presented concept has a strong focus on the specific use-case of building a CRM, whereas other/existing use-cases in core and contrib may not have seen the same amount of attention. Nevertheless, I haven't seen a comment from anyone stating that we shouldn't improve the situation. So, in short, given a solid concept without conceptual problems, this could still happen for D8, although, indeed, time is running out.

yautja_cetanu’s picture

"Instead, my personal impression is that the discussion so far revealed that there are conceptual problems with the changes being proposed. "

Ok, this may be my bad. The reason why I felt it was due to business is because, well its looks like people are busy because there is a lot going on and secondly I felt like we had replied to all comments about the conceptual problems but no one responded to them. Finally we implemented a patch that tried to solve this problem using the method both you and DamZ suggested (an anonymous flag rather separating the user entity) but also received no response. So I assumed it was become people hadn't got to it yet. (This could be because we're terrible communicators! But then if that's the case then we'd need some help, fubhy has been great at this, but this also takes time)

I feel like we have considered a huge number of the use cases. The word "CRM" is what we specialise in but really its just a fairly pointless marketing word. The reality is a true CRM is just a system that stores information about people you relate to and Profile + user does that. If Drupal handled anonymous users well (even if to solve the comment issue) it would basically be a CRM system. As we've dealt with CRM stuff it means we've dealt with lots of modules across Drupal that would interact with anonymous users (From related, to entity reference, to panels and views, to editing forms for different registrations to rules, simplenews and commerce).

We'd be more then happy to write up and discuss all the use cases and everything we've thought up but it has already taken us a very large amount of time to write up things in this issue and the issues in our sandbox and the various google docs. I don't feel we can afford to spend more time on this unless people are willing to read and respond to this stuff.

Also the reality is, I'm kind of feeling that, really if I'm honest. It appears that the main person we need behind this is you sun. It would require lots of time for us to present all our research and arguments to you. We'd have to talk about all the use cases and how various different architectures impact all those use cases. The actual code is simple, and most of the complicated things can be done in contrib, its the understanding of what we're doing and how it impacts everything that is just time consuming.

So really, do you think you'd have the time to go through this stuff with us? If you want us to write a document going through all the use-cases in one huge Google doc we could. But my feeling is that you're involved with so many things that waiting until after Drupal 8 would make more sense and doing some of this stuff in person at Drupal cons would make sense.

What do you think? We could arrange to meet in IRC if you like?

catch’s picture

Status: Postponed » Active

Just a note I'm not personally keen on the anonymous flag on the {users} table, it'd massively bloat the table and builds the 'visitor' tracking right into core user account functionality which isn't really consistent with making it optional.

Issues should only usually be marked postponed if they're actually blocked on another issue, when it's too late to add features like this we can either mark postponed or move to 9.x but "I'm not working on it at the moment" isn't sufficient reason to drop it out of the active issues.

catch’s picture

Issue summary: View changes

Updated issue summary.

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

dpi’s picture

webflo’s picture

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.0-alpha1 will be released the week of January 30, 2017, which means new developments and disruptive changes should now be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

smustgrave’s picture

Project: Drupal core » Drupal core ideas
Version: 11.x-dev »
Component: user system » Idea

While taking a look at #1816218: [P-1] Separate the account information from the user entity. @catch found this issue and mentioned they both could be moved to the ideas queue.

@catch should receive credit for finding this though.

AaronMcHale’s picture

This is a really good idea! I have definitely wanted something like this in the past and so can really appreciate the use-cases mentioned in the summary.

If Drupal is to become a first-class Digital Experience Platform, we need the data structures to support that. Email subscribers to a newsletter are also a good example here, an email subscriber should be able to update their preferences, but they shouldn't need to have a full account just to do that or to subscribe in the first place.

krystalcode’s picture

Some thoughts on this.

The User entity in Drupal has a very specific meaning. It is not a Person, it is a User, meaning somebody that uses the system. Otherwise, it is not a user, it is something else.

Regarding some of the examples mentioned:

- Email subscribers, that would be a separate Email Subscriber entity provided by the module that provides the newsletter functionality. If the subscriber does not need to log in to update their preferences, then, there is no reason to have a User for the subscriber; the Email Subscriber entity will be updatable by an anonymous user according to whatever criteria anyway.

- CRM contact, again, that's not a User, a custom or contrib module should provide a Contact entity with all the required features, there is no reason to make a Contact be a User if they don't log into the system.

- If an entity needs extra data that should not be stored on the main entity, then the profile module or alternative should allow creating a profile or data record and attach it to other entities. That is, the solution is not to make the Contact entity a User, the solution is to attach another data record to the Contact.

- About anonymous users commenting, I'm not sure why there is a fake session created. Without knowing the reason, it seems better to me that the comment entity just holds the data for the comment and they are rendered as fields. If somebody would comment why a session is needed, that could help understand the case.

All that said, semantically speaking it is possible to stretch the meaning of the User entity a bit. For example, an anonymous user that comments also uses the system even without logging in. A user that subscribes to the emails via the website, and then visits the website to unsubscriber, also uses the system.

The argument of being able to use modules/features that are tailored to users is a strong argument as well. I disagree with it as an architect; for example, for integrating CRM Contacts with Commerce (as per the examples listed in this issue's description), the correct solution would be to improve the Commerce system to not require a User entity. Or, as mentioned above, to improve the Profile module to be able to attach profiles to any entity. However, let's be practical, it would be very useful and opening up many possibilities if we could just use those modules without having to rewrite them - who will do that?

In that case, I think that the solution would be to make the User entity bundleable. Then the default behavior will be kept exactly the same as now where the default bundle will be for Authenticated users. Then modules could add a Contact bundle, an Anonymous User bundle etc.

Modules should be very careful though if they automatically generate users for anonymous visitors, and be sure to take into account the following:

- Purge users that are not required any longer, otherwise the database can end up with an extremely large number of unnecessary entities - depending on the use case. Imagine creating a user for each session, even if the actual visitor is the same physical person on the same physical device.
- Be careful with GDPR or other privacy related requirements.
- Be cautious of potential performance impact.

In summary, I think that the best is to add support for bundles on the User entity in Drupal core without changing anything else there. And then have custom/contrib to take advantage of them as needed.

AaronMcHale’s picture

In summary, I think that the best is to add support for bundles on the User entity in Drupal core without changing anything else there. And then have custom/contrib to take advantage of them as needed.

Adding bundles to the user entity could be a really good way of enabling some of these usecases. I had a use case a while back for user bundles, where I had two types of users who had very different business requirements and it would be enough to justify two different "user types".

The User Bundle contrib module shows that adding bundles to user is definitely feasible.

Having said that, from a product perspective, does it really make sense to introduce the concept of "user types", does that just complicate things for site builders when, arguably, most sites won't have a need for that feature. Maybe it is better to just leave that to the contrib project.

The proposal in this issue though I think is still valid on its own, whether we add user bundles or not. Perhaps a better justification would be, making it easier for themes, like Olivero and Claro, to allow the user to customize some aspects of the theme (for example turn on dark mode), in a way which saves those preferences to the session, so that it still works for users who are logged out. That is a legitimate potential use case that we could have in Core, whereas the CRM or email subscriber use cases are not strictly Core use cases.