Forum OpenACS Q&A: Turning a person into a user

Collapse
Posted by Sean Redmond on

I was trying to figure out how to turn an already existing person into a user (the functions for creating users all take an optional user_id, but giving them an existing person_id doesn't work) and I found a couple of mentions of this here and here, but they both imply that there is no way to do this yet.

Is this true? What's the difficulty? I was about to dive into auth::create_user but maybe someone has already done it.

Collapse
Posted by C. R. Oldham on

I think it isn't difficult, but just most OpenACS users didn't need the functionality. With the arrival of the contacts packages, I think this is more important. Below is the code we use to do it--keep in mind this is an old, heavily-patched 4.6.x installation, and in an ideal world we would have abstracted this out into functions in the auth:: namespace. It works, though. This is a snippet from packages/acs-subsite/www/register/user-new-2.tcl

if { [db_0or1row find_person "select parties.party_id as user_id, persons.first_names, persons.last_name from parties, persons where parties.party_id = persons.person_id and parties.email = lower(:email)"] && ![db_0or1row check_user "select user_id from users where user_id=:user_id"] } {
    # This person already exists but needs to be authenticated via email...
    set member_state "needs approval"
    set email_verified_p "f"
    db_transaction {
        set salt [sec_random_token]
        set hashed_password [ns_sha1 "$password$salt"]
        db_dml insert_user "insert into users (user_id, password, salt, password_question, password_answer, screen_name, email_verified_p) values (:user_id, :hashed_password, :salt, :question, :answer, null, 'f')"
        db_dml insert_user2 "insert into user_preferences (user_id, dont_spam_me_p) values (:user_id,'f')"
        db_1row select_rel_id "select acs.magic_object_id('registered_users') as magic_object_id from dual"
        relation_add -member_state $member_state "membership_rel" $magic_object_id $user_id
        permission::grant -party_id $user_id -object_id $user_id -privilege "read"
        permission::grant -party_id $user_id -object_id $user_id -privilege "write"
        acs_user_extension::user_new -user_id $user_id
    }
}
if { !$user_id } {
    ad_return_error "User Creation Failed" "We were unable to create your user record in the database."
        ad_script_abort
}

Collapse
Posted by Sean Redmond on

Thanks! With a little tweaking for ACS 5 (username in addition to screen_name) and postgresql (acs__magic_object_id) this worked.

Here's what I think is confusing. The object hierarchy and, indeed, the code of acs_user__new would seem to imply that you can create a user out of an existing person (since acs_user__new checks for this). If you only do this much, the user is created (i.e. the row in the users table) but the user still doesn't show up, for instance, on /acs-admin/users/complex-search?target=one&only_authorized_p=0, because these steps still need to be performed:

        relation_add -member_state $member_state "membership_rel" $magic_object_id $user_id
        permission::grant -party_id $user_id -object_id $user_id -privilege "read"
        permission::grant -party_id $user_id -object_id $user_id -privilege "write"
        acs_user_extension::user_new -user_id $user_id

Since you probably never add a user without adding it to "Registered Users" and granting auto-read and -write privilege, shouldn't these steps be moved into acs_user__new?