Forum OpenACS Development: convert person to user

Posted by Jeff Rogers on

My application has an existing list of people (email addresses) with imported content that they own (i.e., the content has a fk to persons.person_id), but I want to enable these same people to sign up for new accounts, going through the otherwise normal process (i.e., setting their own password, email confirmation, etc).

Is it possible to create persons with email addresses and have those automatically looked up and reused by a users entry when someone signs up with an existing email? The naïve approach of calling person__new with an appropriate email and just going on from there doesn't work - attempting to sign up as that email errors with "email already exists", but attempting password recovery gives an error.

2: Re: convert person to user (response to 1)
Posted by Antonio Pisano on
Dear Jeff,

my two cents here: to promote a person to a full-fledged user is a matter of adding the appropriate entry in the users table. Probably other operations are required, e.g. adding membership to the main subsite etc, but should be absolutely possible to figure it out and put it into some proc or so.

What we would need to discuss IMO is the UI interaction for this. One possibility might be:
- user tries to log in using an email that already belongs to a party/person
- user is informed and invited to decide whether to "promote" itself or use another email
- upon choice, the "upgrade" is executed

I expect there to be corner cases though: what impact can have on the business logics of my application that something that before was "just" a person has now become a user? I think this is tricky to answer in general. One problem I can think about is e.g. when a user decide to leave a community. We might still want to retain its information as a "person" for our application (something like a "downgrade" to person).

Maybe somebody else want to chime in.



3: Re: convert person to user (response to 2)
Posted by Keith Paskett on
I have a package that, among other things, promotes a person to a user and demotes a user to a person.

I could share those two procs.

5: Re: convert person to user (response to 3)
Posted by Gustaf Neumann on
having such two procs in the OpenACS API seems to be a good idea to me. Keith, can you open a ticket in the bug tracker and submit it there?
6: Re: convert person to user (response to 5)
Posted by Gustaf Neumann on
Keith has provided 2 such procs, that i've added to oacs-5-10.

While promoting is straightforward, demoting has certain limitations in case this user has created several objects before (check to FK relations of users). Therefore, demoting is rather a low-level helper function and not intended as a replacement of "acs_user::change_state" which can be used to deactivate users in various ways.

4: Re: convert person to user (response to 1)
Posted by Brian Fenton on
Hi Jeff

here's a block of code that I have that upgrades a party to a user. Could be a good starting point for you.

db_dml upgrade_user {update acs_objects set object_type = 'user' where object_id = :user_id}

db_dml insert_user {insert into users (user_id, authority_id, username, email_verified_p) values (:user_id, :authority_id, :username, 't')}

# Make sure that we we did not store user preferences before
if {![db_string user_prefs_p "select 1 from user_preferences where user_id = :user_id" -default "0"]} {
  set locale [lang::system::locale -site_wide ] 
  db_dml update_user_prefs {insert into user_preferences (user_id, locale) values (:user_id, :locale)}
} else {
  db_dml update_user_prefs {update user_preferences 
              set locale = :locale
              where user_id = :user_id }            

group::add_member -no_perm_check -group_id "-2" -user_id $person_id -rel_type "membership_rel"

if {[empty_string_p $password]} {
  # we reset the password in admin mode. this means that an email
  # will not automatically be sent unless acs-subsite.EmailChangedPasswordP is 1.

  array set passwordresults [auth::password::reset -authority_id [auth::authority::local] -username $username -admin]

  set password "$passwordresults(password)"
} else {
  # Change the password to the password provided

  if { [catch { ad_change_password $user_id $password } errmsg] } {
    ns_log notice "Error changing local password for username $username, user_id $user_id: \n$errorInfo"

# Grant the user to update the password on himself
permission::grant -party_id $user_id -object_id $user_id -privilege write