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
}