Forum OpenACS Development: User account Merge (UM)

Posted by Enrique Catalan on
Hi everyone,

"This is a good place to be if you're interested in undoing the damage done when the same person registers twice with two different email addresses or We can have duplicated accounts since more than one system manage one user account as different person"

The aim is that one person has to have only one account.

So, we have three scenarios:

1. Merge the Applications Items :

We have to move the items of each package (faqs,news, bboards, etc...) that the duplicated account owns to the good account. In this scenario, we have two possibles solutions : Service Contracts or Dynamic Queries.

1.1. Service Contracts : Here we need to write the implementation per each package. For example, if we want to merge faq, faq should have a procedure to change the owner of all the faqs.

1.2. Dynamic Queries: In this solution we avoid to write service contracts and their implementations but we need to use the pg_* system tables, for example : pg_contraint, pg_class, pg_attribute. The aim here is to look for all the childs (foreign keys) that acs_objects.object_id has, get the column and table name from pg_* tables and make the query to update each row.

2. Merge the memberships:

Where does the duplicad account belong to? Which groups?. Here we need to change the relationships/memberships, adding the good account to the groups that the duplicated account belongs to, then delete the relations between the duplicated account and its groups.

3. Delete the duplicated account:

This could be an update of the user_state setting it to the state 'deleted' or doing a really 'nuke' of the account, deleting each row of each table that has relation with the bad account.

Please, if you have questions or sugestions, I would appreciate them :).


Posted by Andrew Grumet on
A few thoughts...

We have to move the items of each package (faqs,news,
bboards, etc...) that the duplicated account owns to the
good account.

It seems like some (maybe most) of this could be done at a global level. For example,

update acs_objects set creation_user = :keep_user_id
where creation_user = :remove_user_id

A similar idea could be applied to memberships (acs_rels), though a bit of care should be applied, since if there are duplicate members and they are not the same level (e.g. "member" vs. "admin"), a *human* should probably decide which one to keep.

It's not clear to me that every package will need to take special action, and that some pages may have special user interfaces for human-assisted merging.

Posted by Enrique Catalan on
Thanks for your comments Andrew.

You are right!, the acs_rels and the acs_objects would be merged at a global level with an "update..." .

I forgot to post that I uploaded more details about it, You can check it out in In that document I wrote and example only with faqs, that's the reason I putted the join with faq table, however, when we will implement in general, we have to do it globally as you said.

With regard to that you said that every package need special action and some pages may have special user interfaces for human-assited merging:

1. The special action per each package would be needed because exist packages like "forums" that has tables with columns that reference the account to remove, for example: the table forums_messages has a column named 'user_id' that references users(user_id). In this case we have to solutions explained in the link I wrote above.

2. The aim is to use the same user interface to merge all the things you need to. I mean that we will not need special user interfaces for human-assisted mergin.

I hope that information can be useful for you and thanks for for thoughts.

If you have more suggestions or questions, please don't hesitate to ask :).


Posted by Andrew Grumet on


Looks pretty good! A couple of comments...

I'm pretty convinced that this won't be 100% automated. Consider the case of merging relations. In your document, step 3 is

> 3. Get the relations that GA hasn't and the BA has and merge them

I guess I'll have to come up with a specific example but I suspect there will be cases when the person should only have one relationship and not many. Blindly taking the sum of all relationships seems like its bound to fail.

Perhaps there are other, package-specific situations that will arise in the different packages. For this reason, I'd prefer an application-level solution rather than the foreign key approach.

As for service contracts, I'd recommend having "user" in the name of the contract, so it's clear what is being merged. So I'd use MergeUser or MergePackageUser instead of just MergePackage.

But...we're starting to explore the use of a new, simpler callback mechanism, which might be a good alternative to service contracts. Please take a look at TIP 79.

Posted by Romas Mažeika on
Small input from user perspective. In my experience I had quite a lot of cases where I needed to merge accounts (of course I've done it manually).
One of things that often pop-ups and I don't see it covered in current proposal document is handling different permissions for the same object that user has relationship with.
Real-life example: Joe the User with account A is simple member (student) of group/community XYZ, same Joe the User with account B is administrator (professor) of the same group/community XYZ.
How system would handle such case? I guess, it should stick to relationship wich has higher permission lever (in exampe case that would be administrator). Would that fit to all situations?
Posted by Enrique Catalan on
Romas, thanks for share your experience. We've had the same problem too.

In this case, the system would handle it in the 'Merge user interface'; I mean, when you will merge two accounts the 'Merge user interface' will ask you wich will be the good account(GA) and then it will take the role of the GA by default. However, we could add an option that let the user to choose wich of the roles will be setted.

I hope that answer your questions.