Index: openacs-4/packages/acs-authentication/sql/oracle/acs-authentication-create.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-authentication/sql/oracle/acs-authentication-create.sql,v
diff -u -N
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/acs-authentication/sql/oracle/acs-authentication-create.sql 8 Sep 2003 15:59:42 -0000 1.1
@@ -0,0 +1,8 @@
+--
+-- Data model for acs-authentication
+--
+-- $Id: acs-authentication-create.sql,v 1.1 2003/09/08 15:59:42 lars Exp $
+--
+
+@@ batch-job-tables-create.sql
+
Index: openacs-4/packages/acs-authentication/sql/oracle/acs-authentication-drop.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-authentication/sql/oracle/acs-authentication-drop.sql,v
diff -u -N
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/acs-authentication/sql/oracle/acs-authentication-drop.sql 8 Sep 2003 15:59:42 -0000 1.1
@@ -0,0 +1,8 @@
+--
+-- Drop script for acs-authentication
+--
+-- $Id: acs-authentication-drop.sql,v 1.1 2003/09/08 15:59:42 lars Exp $
+--
+
+@@ batch-job-tables-drop.sql
+
Index: openacs-4/packages/acs-authentication/sql/oracle/batch-job-tables-create.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-authentication/sql/oracle/batch-job-tables-create.sql,v
diff -u -N
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/acs-authentication/sql/oracle/batch-job-tables-create.sql 8 Sep 2003 15:59:42 -0000 1.1
@@ -0,0 +1,71 @@
+create sequence auth_batch_jobs_job_id_seq;
+
+create table auth_batch_jobs (
+ job_id integer
+ constraint auth_batch_jobs_pk
+ primary key,
+ job_start_time date default sysdate,
+ job_end_time date,
+ interactive_p char(1)
+ constraint auth_batch_jobs_interactive_ck
+ check (interactive_p in ('t', 'f'))
+ constraint auth_batch_jobs_interactive_nn
+ not null,
+ -- if interactive, by which user
+ creation_user integer
+ constraint auth_batch_job_user_fk
+ references users(user_id)
+ on delete set null,
+ -- status information for the GetDocument operation
+ doc_start_time date,
+ doc_end_time date,
+ doc_status varchar2(4000),
+ doc_message varchar2(4000),
+ document_id integer
+ constraint auth_batch_jobs_doc_fk
+ references cr_items(item_id)
+ on delete set null
+);
+
+create index auth_batch_jobs_user_idx on auth_batch_jobs(creation_user);
+create index auth_batch_jobs_document_idx on auth_batch_jobs(document_id);
+
+
+create sequence auth_batch_job_entry_id_seq;
+
+create table auth_batch_job_entries (
+ entry_id integer
+ constraint auth_batch_job_entries_pk
+ primary key,
+ job_id integer
+ constraint auth_batch_job_entries_job_fk
+ references auth_batch_jobs(job_id)
+ on delete cascade,
+ entry_time date default sysdate,
+ operation varchar(100)
+ constraint auth_batch_jobs_entries_op_ck
+ check (operation in ('insert', 'update', 'delete')),
+ authority_id integer
+ constraint auth_batch_job_entries_auth_fk
+ references auth_authorities(authority_id)
+ on delete cascade,
+ username varchar(100),
+ user_id integer
+ constraint auth_batch_job_entries_user_fk
+ references users(user_id) on delete set null,
+ success_p char(1)
+ constraint auth_batch_jobs_ent_success_ck
+ check (success_p in ('t', 'f'))
+ constraint auth_batch_jobs_ent_success_nn
+ not null,
+ message varchar2(4000),
+ element_messages clob
+);
+
+create index auth_batch_job_ent_job_idx on auth_batch_job_entries(job_id);
+create index auth_batch_job_ent_auth_idx on auth_batch_job_entries(authority_id);
+create index auth_batch_job_ent_user_idx on auth_batch_job_entries(user_id);
+
+
+
+
Index: openacs-4/packages/acs-authentication/sql/oracle/batch-job-tables-drop.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-authentication/sql/oracle/batch-job-tables-drop.sql,v
diff -u -N
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/acs-authentication/sql/oracle/batch-job-tables-drop.sql 8 Sep 2003 15:59:42 -0000 1.1
@@ -0,0 +1,6 @@
+drop sequence auth_batch_jobs_job_id_seq;
+drop sequence auth_batch_job_entry_id_seq;
+
+drop table auth_batch_job_entries;
+
+drop table auth_batch_jobs;
Index: openacs-4/packages/acs-authentication/sql/postgresql/acs-authentication-create.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-authentication/sql/postgresql/acs-authentication-create.sql,v
diff -u -N
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/acs-authentication/sql/postgresql/acs-authentication-create.sql 8 Sep 2003 15:59:43 -0000 1.1
@@ -0,0 +1,8 @@
+--
+-- Data model for acs-authentication
+--
+-- $Id: acs-authentication-create.sql,v 1.1 2003/09/08 15:59:43 lars Exp $
+--
+
+\i batch-job-tables-create.sql
+
Index: openacs-4/packages/acs-authentication/sql/postgresql/acs-authentication-drop.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-authentication/sql/postgresql/acs-authentication-drop.sql,v
diff -u -N
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/acs-authentication/sql/postgresql/acs-authentication-drop.sql 8 Sep 2003 15:59:43 -0000 1.1
@@ -0,0 +1,8 @@
+--
+-- Drop script for acs-authentication
+--
+-- $Id: acs-authentication-drop.sql,v 1.1 2003/09/08 15:59:43 lars Exp $
+--
+
+\i batch-job-tables-drop.sql
+
Index: openacs-4/packages/acs-authentication/sql/postgresql/batch-job-tables-create.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-authentication/sql/postgresql/batch-job-tables-create.sql,v
diff -u -N
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/acs-authentication/sql/postgresql/batch-job-tables-create.sql 8 Sep 2003 15:59:43 -0000 1.1
@@ -0,0 +1,66 @@
+
+create sequence auth_batch_jobs_job_id_seq;
+
+create table auth_batch_jobs (
+ job_id integer
+ constraint auth_batch_jobs_pk
+ primary key,
+ job_start_time timestamptz default current_timestamp,
+ job_end_time timestamptz,
+ interactive_p boolean
+ constraint auth_batch_jobs_interactive_nn
+ not null,
+ -- if interactive, by which user
+ creation_user integer
+ constraint auth_batch_job_user_fk
+ references users(user_id)
+ on delete set null,
+ -- status information for the GetDocument operation
+ doc_start_time timestamptz,
+ doc_end_time timestamptz,
+ doc_status text,
+ doc_message text,
+ document_id integer
+ constraint auth_batch_jobs_doc_fk
+ references cr_items(item_id)
+ on delete set null
+);
+
+create index auth_batch_jobs_user_idx on auth_batch_jobs(creation_user);
+create index auth_batch_jobs_document_idx on auth_batch_jobs(document_id);
+
+
+create sequence auth_batch_job_entry_id_seq;
+
+create table auth_batch_job_entries (
+ entry_id integer
+ constraint auth_batch_job_entries_pk
+ primary key,
+ job_id integer
+ constraint auth_batch_job_entries_job_fk
+ references auth_batch_jobs(job_id)
+ on delete cascade,
+ entry_time timestamptz default current_timestamp,
+ operation varchar(100)
+ constraint auth_batch_jobs_entries_op_ck
+ check (operation in ('insert', 'update', 'delete')),
+ authority_id integer
+ constraint auth_batch_job_entries_auth_fk
+ references auth_authorities(authority_id)
+ on delete cascade,
+ username varchar(100),
+ user_id integer
+ constraint auth_batch_job_entries_user_fk
+ references users(user_id) on delete set null,
+ success_p boolean not null,
+ message text,
+ element_messages text
+);
+
+create index auth_batch_job_ent_job_idx on auth_batch_job_entries(job_id);
+create index auth_batch_job_ent_auth_idx on auth_batch_job_entries(authority_id);
+create index auth_batch_job_ent_user_idx on auth_batch_job_entries(user_id);
+
+
+
+
Index: openacs-4/packages/acs-authentication/sql/postgresql/batch-job-tables-drop.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-authentication/sql/postgresql/batch-job-tables-drop.sql,v
diff -u -N
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/acs-authentication/sql/postgresql/batch-job-tables-drop.sql 8 Sep 2003 15:59:43 -0000 1.1
@@ -0,0 +1,6 @@
+drop sequence auth_batch_jobs_job_id_seq;
+drop sequence auth_batch_job_entry_id_seq;
+
+drop table auth_batch_job_entries;
+
+drop table auth_batch_jobs;
Index: openacs-4/packages/acs-authentication/tcl/authentication-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-authentication/tcl/authentication-procs.tcl,v
diff -u -N -r1.18 -r1.19
--- openacs-4/packages/acs-authentication/tcl/authentication-procs.tcl 4 Sep 2003 16:36:17 -0000 1.18
+++ openacs-4/packages/acs-authentication/tcl/authentication-procs.tcl 8 Sep 2003 15:59:43 -0000 1.19
@@ -608,7 +608,7 @@
{-secret_question ""}
{-secret_answer ""}
{-member_state "approved"}
- {-email_verified_p "t"}
+ {-email_verified_p ""}
} {
Create the local account for a user.
@@ -640,39 +640,41 @@
account_status ok
account_message {}
}
- array set elm_msgs [list]
- # TODO: This needs to be controlled by a parameter, to be added latter
+ # PHASE II: This needs to be controlled by a parameter
if { [empty_string_p $username] } {
set username $email
}
# Validate data
- if { [string first "<" $first_names] != -1 } {
- set element_messages(first_names) [_ acs-subsite.lt_You_cant_have_a_lt_in]
+ set user_vars { authority_id username first_names last_name email url secret_question secret_answer }
+ foreach varname $user_vars {
+ if { [info exists $varname] } {
+ set user_info($varname) [set $varname]
+ }
}
- if { [string first "<" $last_name] != -1 } {
- set element_messages(last_name) [_ acs-subsite.lt_You_cant_have_a_lt_in_1]
- }
-
- if { [empty_string_p $url] || [string equal $url "http://"] } {
- # The user left the default hint for the url
- set url {}
- } elseif { ![util_url_valid_p $url] } {
- set valid_url_example "http://openacs.org/"
- set element_messages(url) [_ acs-subsite.lt_Your_URL_doesnt_have_]
- }
- if { ![empty_string_p [cc_lookup_email_user $email]] } {
- set element_messages(email) "We already have a user with this email."
- }
- if { ![empty_string_p [acs_user::get_by_username -authority_id $authority_id -username $username]] } {
- set element_messages(username) "We already have a user with this username."
- }
+ auth::validate_user_info \
+ -user_array user_info \
+ -message_array element_messages
+
+ # Handle validation errors
if { [llength [array names element_messages]] > 0 } {
- return [list creation_status data_error creation_message {} element_messages [array get element_messages]]
+ return [list \
+ creation_status "data_error" \
+ creation_message {} \
+ element_messages [array get element_messages] \
+ ]
}
+ # Suck user info variables back out, they may have been modified by the validate helper proc
+ foreach varname $user_vars {
+ if { [info exists user_info($varname)] } {
+ set $varname $user_info($varname)
+ }
+ }
+
+
# Admin approval
if { [parameter::get -parameter RegistrationRequiresApprovalP -default 0] } {
set member_state "needs approval"
@@ -682,10 +684,12 @@
set member_state "approved"
}
- if { [parameter::get -parameter RegistrationRequiresEmailVerificationP -default 0] } {
- set email_verified_p "f"
- } else {
- set email_verified_p "t"
+ if { [empty_string_p $email_verified_p] } {
+ if { [parameter::get -parameter RegistrationRequiresEmailVerificationP -default 0] } {
+ set email_verified_p "f"
+ } else {
+ set email_verified_p "t"
+ }
}
set error_p 0
@@ -712,10 +716,8 @@
if { $error_p || $user_id == 0 } {
set result(creation_status) "failed_to_connect"
set result(creation_message) "We experienced an error while trying to register an account for you."
- if { $error_p } {
- global errorInfo
- ns_log Error "Error invoking account registratino driver for authority_id = $authority_id: $errorInfo"
- }
+ global errorInfo
+ ns_log Error "Error creating local account.\n$errorInfo"
return [array get result]
}
@@ -740,17 +742,285 @@
return [array get result]
}
+
+ad_proc -public auth::update_local_account {
+ {-authority_id:required}
+ {-username:required}
+ {-first_names ""}
+ {-last_name ""}
+ {-email ""}
+ {-url ""}
+ {-secret_question ""}
+ {-secret_answer ""}
+ {-member_state "approved"}
+ {-email_verified_p ""}
+} {
+ Update the local account for a user.
+
+ @return Array list containing the following entries:
+
+
+ - update_status: ok, data_error, update_error, failed_to_connect. Says whether user update succeeded.
+
- update_message: Information about the problem, to be relayed to the user. If update_status is not ok, then either
+ update_message or element_messages is guaranteed to be non-empty, and both are
+ guaranteed to be in the array list. May contain HTML.
+
- element_messages: list of (element_name, message, element_name, message, ...) of
+ errors on the individual elements (username, password, first_names, ...),
+ to be relayed on to the user. If update_status is not ok, then either
+ udpate_message or element_messages is guaranteed to be non-empty, and both are
+ guaranteed to be in the array list. Cannot contain HTML.
+
+
+ All entries are guaranteed to always be set, but may be empty.
+} {
+ array set result {
+ update_status update_error
+ update_message {}
+ element_messages {}
+ }
+
+ # Validate data
+
+ # Updating: Find the existing account
+ set user_vars { authority_id username first_names last_name email url secret_question secret_answer }
+ foreach varname $user_vars {
+ if { [info exists $varname] } {
+ set user_info($varname) [set $varname]
+ }
+ }
+
+ auth::validate_user_info \
+ -update \
+ -user_array user_info \
+ -message_array element_messages
+
+ # Handle validation errors
+ if { [llength [array names element_messages]] > 0 } {
+ return [list \
+ update_status "data_error" \
+ update_message {} \
+ element_messages [array get element_messages] \
+ ]
+ }
+
+ # Suck user info variables back out, they may have been modified by the validate helper proc
+ foreach varname $user_vars {
+ if { [info exists user_info($varname)] } {
+ set $varname $user_info($varname)
+ }
+ }
+ set user_id $user_info(user_id)
+
+ set error_p 0
+ with_catch errmsg {
+
+ db_transaction {
+ # Update persons: first_names, last_name
+ person::update \
+ -person_id $user_id \
+ -first_names $first_names \
+ -last_name $last_name
+
+ # Update parties: email, url
+ if { [empty_string_p $email] } {
+ set success_p 0
+ set message "Email is required"
+ }
+ party::update \
+ -party_id $user_id \
+ -email $email \
+ -url $url
+
+ # Update users: email_verified_p
+ if { ![empty_string_p $email_verified_p] } {
+ acs_user::update \
+ -user_id $user_id \
+ -email_verified_p $email_verified_p
+ }
+
+ # TODO: Portrait
+ }
+ } {
+ set error_p 1
+ }
+
+ if { $error_p } {
+ set result(update_status) "failed_to_connect"
+ set result(update_message) "We experienced an error while trying to update the account information."
+ global errorInfo
+ ns_log Error "Error updating local account.\n$errorInfo"
+ return [array get result]
+ }
+
+ # Update succeeded
+ set result(update_status) "ok"
+
+ return [array get result]
+}
+
+
+ad_proc -public auth::delete_local_account {
+ {-authority_id:required}
+ {-username:required}
+} {
+ Delete the local account for a user.
+
+ @return Array list containing the following entries:
+
+
+ - delete_status: ok, delete_error, failed_to_connect. Says whether user deletion succeeded.
+
- delete_message: Information about the problem, to be relayed to the user. If delete_status is not ok, then
+ delete_message is guaranteed to be non-empty. May contain HTML.
+
+
+ All entries are guaranteed to always be set, but may be empty.
+} {
+ array set result {
+ delete_status ok
+ delete_message {}
+ }
+
+ set user_id [acs_user::get_by_username \
+ -authority_id $authority_id \
+ -username $username]
+
+ if { [empty_string_p $user_id] } {
+ set result(delete_status) "delete_error"
+ set result(delete_messages) "No user found with this username"
+ return [array get result]
+ }
+
+ # Mark the account banned
+ acs_user::ban -user_id $user_id
+
+ return [array get result]
+}
+
+
+ad_proc -private auth::validate_user_info {
+ {-update:boolean}
+ {-user_array:required}
+ {-message_array:required}
+} {
+ Validates user info and returns errors, if any.
+
+ @param update Set this flag if you're updating an existing record, meaning we shouldn't check for duplicates.
+
+ @param user_array Name of an array in the caller's namespace which contains the user info
+ (authority_id, username, email, first_names, last_name, url, secret_question, secret_answer).
+
+ @param message_array Name of an array where you want the validation errors stored, keyed by element name.
+} {
+ upvar 1 $user_array user
+ upvar 1 $message_array element_messages
+
+ foreach elm { authority_id username first_names last_name email } {
+ if { ![exists_and_not_null user($elm)] } {
+ set element_messages(first_names) "Required"
+ }
+ }
+
+ ns_log Notice "LARS: update_p = $update_p ; user(authority_id) = $user(authority_id) ; user(username) = $user(username)"
+ if { $update_p && [exists_and_not_null user(authority_id)] && [exists_and_not_null user(username)] } {
+ set user(user_id) [acs_user::get_by_username \
+ -authority_id $user(authority_id) \
+ -username $user(username)]
+
+ ns_log Notice "LARS2: user(user_id) = $user(user_id)"
+
+ if { [empty_string_p $user(user_id)] } {
+ set element_messages(username) "No user with username '$username' found for authority [auth::authority::get_element -authority_id $authority_id -element pretty_name]"
+ }
+ }
+
+ if { [exists_and_not_null user(first_names)] && [string first "<" $user(first_names)] != -1 } {
+ set element_messages(first_names) [_ acs-subsite.lt_You_cant_have_a_lt_in]
+ }
+
+ if { [exists_and_not_null user(last_name)] && [string first "<" $user(last_name)] != -1 } {
+ set element_messages(last_name) [_ acs-subsite.lt_You_cant_have_a_lt_in_1]
+ }
+
+ if { [exists_and_not_null user(email)] && ![util_email_valid_p $user(email)] } {
+ set element_messages(email) "This is not a valid email address"
+ } else {
+ set user(email) [string tolower $user(email)]
+ }
+
+ if { ![exists_and_not_null $user(url)] || ([info exists user(url)] && [string equal $user(url) "http://"]) } {
+ # The user left the default hint for the url
+ set user(url) {}
+ } elseif { ![util_url_valid_p $user(url)] } {
+ set valid_url_example "http://openacs.org/"
+ set element_messages(url) [_ acs-subsite.lt_Your_URL_doesnt_have_]
+ }
+
+ if { [exists_and_not_null user(email)] } {
+ # Check that email is unique
+ set email $user(email)
+ ns_log Notice "LARS4: email = '$email' ; [db_list_of_lists count { select party_id, email from parties }]"
+ set email_party_id [party::get_by_email -email $user(email)]
+
+ ns_log Notice "LARS3: email_party_id = $email_party_id"
+ if { ![empty_string_p $email_party_id] && (!$update_p || $email_party_id != $user(user_id)) } {
+ # We found a user with this email, and either we're not updating, or it's not the same user_id as the one we're updating
+
+ if { ![string equal [acs_object_type $email_party_id] "user"] } {
+ set element_messages(email) "We already have a group with this email"
+ } else {
+ acs_user::get \
+ -user_id $email_party_id \
+ -array email_user
+
+ switch $email_user(member_state) {
+ banned {
+ # A user with this email does exist, but he's banned, so we can 'steal' his email address
+ # by setting it to something dummy
+ party::update \
+ -user_id $email_party_id \
+ -email "dummy-email-$email_party_id"
+ }
+ default {
+ set element_messages(email) "We already have a user with this email."
+ }
+ }
+ }
+ }
+ }
+
+ if { [exists_and_not_null user(username)] } {
+ # Check that username is unique
+ set username_user_id [acs_user::get_by_username -authority_id $user(authority_id) -username $user(username)]
+
+ if { ![empty_string_p $username_user_id] && (!$update_p || $username_user_id != $user(user_id)) } {
+ # We found a user with this username, and either we're not updating, or it's not the same user_id as the one we're updating
+
+ set username_member_state [acs_user::get_element -user_id $username_user_id -element member_state]
+ switch $username_member_state {
+ banned {
+ # A user with this username does exist, but he's banned, so we can 'steal' his username
+ # by setting it to something dummy
+ acs_user::update \
+ -user_id $usrename_user_id \
+ -username "dummy-username-$username_user_id"
+ }
+ default {
+ set element_messages(username) "We already have a user with this username."
+ }
+ }
+ }
+ }
+}
+
ad_proc -public auth::set_email_verified {
{-user_id:required}
} {
Update an OpenACS record with the fact that the email address on
record was verified.
} {
- db_dml set_email_verified {
- update users
- set email_verified_p = 't'
- where user_id = :user_id
- }
+ acs_user::update \
+ -user_id $user_id \
+ -email_verified_p "t"
}
#####
Index: openacs-4/packages/acs-authentication/tcl/sync-procs-oracle.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-authentication/tcl/sync-procs-oracle.xql,v
diff -u -N
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/acs-authentication/tcl/sync-procs-oracle.xql 8 Sep 2003 15:59:43 -0000 1.1
@@ -0,0 +1,66 @@
+
+
+
+ oracle8.1.6
+
+
+
+ select job_id,
+ job_start_time,
+ job_end_time,
+ interactive_p,
+ creation_user,
+ doc_start_time,
+ doc_end_time,
+ doc_status,
+ doc_message,
+ document_id,
+ (j.job_end_time - j.job_start_time) * 24*60*60 as run_time_seconds,
+ (select count(e1.entry_id)
+ from auth_batch_job_entries e1
+ where e1.job_id = j.job_id) as num_actions,
+ (select count(e2.entry_id)
+ from auth_batch_job_entries e2
+ where e2.job_id = j.job_id
+ and e2.success_p = 'f') as num_problems
+ from auth_batch_jobs j
+ where j.job_id = :job_id
+
+
+
+
+
+ update auth_batch_jobs
+ set doc_start_time = sysdate
+ where job_id = :job_id
+
+
+
+
+
+ update auth_batch_jobs
+ set doc_end_time = sysdate
+ doc_status = :doc_status,
+ doc_message = :doc_message,
+ document_id = :document_id
+ where job_id = :job_id
+
+
+
+
+
+
+ insert into auth_batch_job_entries
+ (entry_id, job_id, operation, authority_id, username, user_id, success_p, message, element_messages)
+ values
+ (:entry_id, :job_id, :operation, :authority_id, :username, :user_id, :success_p_db, :message, empty_clob())
+ returning element_messages into :1
+
+
+
+
+
+
+
+
+
Index: openacs-4/packages/acs-authentication/tcl/sync-procs-postgresql.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-authentication/tcl/sync-procs-postgresql.xql,v
diff -u -N
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/acs-authentication/tcl/sync-procs-postgresql.xql 8 Sep 2003 15:59:43 -0000 1.1
@@ -0,0 +1,61 @@
+
+
+
+ postgresql7.1
+
+
+
+ select job_id,
+ job_start_time,
+ job_end_time,
+ interactive_p,
+ creation_user,
+ doc_start_time,
+ doc_end_time,
+ doc_status,
+ doc_message,
+ document_id,
+ trunc(extract(epoch from (j.job_end_time - j.job_start_time))) as run_time_seconds,
+ (select count(e1.entry_id)
+ from auth_batch_job_entries e1
+ where e1.job_id = j.job_id) as num_actions,
+ (select count(e2.entry_id)
+ from auth_batch_job_entries e2
+ where e2.job_id = j.job_id
+ and e2.success_p = 'f') as num_problems
+ from auth_batch_jobs j
+ where j.job_id = :job_id
+
+
+
+
+
+ update auth_batch_jobs
+ set doc_start_time = current_timestamp
+ where job_id = :job_id
+
+
+
+
+
+ update auth_batch_jobs
+ set doc_end_time = current_timestamp,
+ doc_status = :doc_status,
+ doc_message = :doc_message,
+ document_id = :document_id
+ where job_id = :job_id
+
+
+
+
+
+
+ insert into auth_batch_job_entries
+ (entry_id, job_id, operation, authority_id, username, user_id, success_p, message, element_messages)
+ values
+ (:entry_id, :job_id, :operation, :authority_id, :username, :user_id, :success_p_db, :message, :element_messages)
+
+
+
+
+
Index: openacs-4/packages/acs-authentication/tcl/sync-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-authentication/tcl/sync-procs.tcl,v
diff -u -N
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/acs-authentication/tcl/sync-procs.tcl 8 Sep 2003 15:59:43 -0000 1.1
@@ -0,0 +1,360 @@
+ad_library {
+ API for managing synchronization of user data.
+
+ @creation-date 2003-09-05
+ @author Lars Pind (lars@collaboraid.biz)
+ @cvs-id $Id: sync-procs.tcl,v 1.1 2003/09/08 15:59:43 lars Exp $
+}
+
+namespace eval auth {}
+namespace eval auth::sync {}
+namespace eval auth::sync::job {}
+
+
+
+ad_proc -public auth::sync::job::get {
+ {-job_id:required}
+ {-array:required}
+ {-include_document:boolean}
+} {
+ Get information about a batch job in an array.
+
+ @param job_id The ID of the batch job you're ending.
+
+ @param array Name of an array into which you want the information.
+
+ @param include_document
+ Set this switch if you also want the document returned in the array.
+
+ @author Lars Pind (lars@collaboraid.biz)
+} {
+ upvar 1 $array row
+
+ db_1row select_job {} -column_array row
+
+ # TODO: This is temporary, make sure this is where the UI ends up
+ set row(log_url) [export_vars -base "[ad_url]/acs-admin/package/acs-authentication/sync-log" { job_id }]
+
+ if { $include_document_p } {
+ # TODO: Return the document once we know how we'll store it
+ set job(document) "Not implemented"
+ }
+}
+
+ad_proc -public auth::sync::job::start {
+ {-job_id ""}
+ {-authority_id:required}
+ {-interactive:boolean}
+ {-creation_user ""}
+} {
+ Record the beginning of a job.
+
+ @param authority_id The ID of the authority you're trying to sync
+
+ @param interactive Set this if this is an interactive job, i.e. it's initiated by a user.
+
+ @return job_id An ID for the new batch job. Used when calling other procs in this API.
+
+ @author Lars Pind (lars@collaboraid.biz)
+} {
+ db_transaction {
+ if { [empty_string_p $job_id] } {
+ set job_id [db_nextval "auth_batch_jobs_job_id_seq"]
+ }
+
+ if { $interactive_p && [empty_string_p $creation_user] } {
+ set creation_user [ad_conn user_id]
+ }
+
+ db_dml job_insert {
+ insert into auth_batch_jobs
+ (job_id, interactive_p, creation_user)
+ values
+ (:job_id, :interactive_p, :creation_user)
+ }
+ }
+
+ return $job_id
+}
+
+ad_proc -public auth::sync::job::end {
+ {-job_id:required}
+} {
+ Record the end of a batch job. Closes out the transaction
+ log and sends out notifications.
+
+ @param job_id The ID of the batch job you're ending.
+
+ @return array list with result of auth::sync::job::get.
+
+ @see auth::sync::job::get
+
+ @author Lars Pind (lars@collaboraid.biz)
+} {
+ db_dml set_end_time {
+ update auth_batch_jobs
+ set job_end_time = current_timestamp
+ where job_id = :job_id
+ }
+
+ # interactive_p, run_time_seconds, num_actions, num_problems
+ get -job_id $job_id -array job
+
+ if { ![template::util::is_true $job(interactive_p)] } {
+ # Only send out email if not an interactive job
+
+ with_catch errmsg {
+ ns_sendmail \
+ [ad_system_owner] \
+ [ad_system_owner] \
+ "Batch sync completed" \
+ "Batch user synchronization is complete.\n\nRunning time: $run_time_seconds seconds\nNumber of actions: $num_actions\nNumber of problems: $num_problems\n\nTo view the log, please visit\n$view_log_url"
+ } {
+ # We don't fail hard here, just log an error
+ global errorInfo
+ ns_log Error "Error sending registration confirmation to [ad_system_owner].\n$errorInfo"
+ }
+ }
+
+ return [array get job]
+}
+
+ad_proc -public auth::sync::job::start_get_document {
+ {-job_id:required}
+} {
+ Record the that we're starting to get the document.
+
+ @param job_id The ID of the batch job you're ending.
+} {
+ db_dml update_doc_start_time {}
+}
+
+ad_proc -public auth::sync::job::end_get_document {
+ {-job_id:required}
+ {-doc_status:required}
+ {-doc_message ""}
+ {-document ""}
+} {
+ Record the that we've finished getting the document, and record the status.
+
+ @param job_id The ID of the batch job you're ending.
+} {
+ # TODO: Create cr_item containing document. Talk to Jun Kyamog about a CR API
+ set document_id {}
+
+ db_dml update_doc_end {}
+}
+
+ad_proc -public auth::sync::job::create_entry {
+ {-job_id:required}
+ {-operation:required}
+ {-authority_id:required}
+ {-username:required}
+ {-user_id ""}
+ {-success:boolean}
+ {-message ""}
+ {-element_messages ""}
+} {
+ Record a batch job entry.
+
+ @param job_id The ID of the batch job you're ending.
+
+ @param operation One of 'insert', 'update', or 'delete'.
+
+ @param authority_id The authority this is about
+
+ @param username The username of the user being inserted/updated/deleted.
+
+ @param user_id The user_id of the local user account, if known.
+
+ @param success Whether or not the operation went well.
+
+ @param message Any error message to stick into the log.
+
+ @return entry_id
+} {
+ set success_p_db [ad_decode $success_p 1 "t" "f"]
+
+ set entry_id [db_nextval "auth_batch_job_entry_id_seq"]
+
+ db_dml insert_entry {} -clobs [list $element_messages]
+
+ return $entry_id
+}
+
+ad_proc -public auth::sync::job::get_entry {
+ {-entry_id:required}
+ {-array:required}
+} {
+ Get information about a log entry
+} {
+ upvar 1 $array row
+
+ db_1row select_entry {
+ select entry_id,
+ job_id,
+ entry_time,
+ operation,
+ authority_id,
+ username,
+ user_id,
+ success_p,
+ message,
+ element_messages
+ from auth_batch_job_entries
+ where entry_id = :entry_id
+ } -column_array row
+}
+
+
+ad_proc -public auth::sync::job::action {
+ {-job_id:required}
+ {-operation:required}
+ {-authority_id:required}
+ {-username:required}
+ {-first_names ""}
+ {-last_name ""}
+ {-email ""}
+ {-url ""}
+ {-portrait_url ""}
+} {
+ Inserts/updates/deletes a user, depending on the operation.
+
+ @param job_id The job which this is part of for logging purposes.
+
+ @param operation 'insert', 'update', 'delete', or 'snapshot'.
+
+ @param authority_id The authority involved
+
+ @param username The username which this action refers to.
+
+ @return entry_id of newly created entry
+} {
+ set entry_id {}
+ set user_id {}
+
+ db_transaction {
+ # We deal with insert/update in a snaphsot sync here
+ if { [string equal $operation "snapshot"] } {
+ set user_id [acs_user::get_by_username \
+ -authority_id $authority_id \
+ -username $username]
+
+ if { ![empty_string_p $user_id] } {
+ # user exists, it's an update
+ set operation "update"
+ } else {
+ # user does not exist, it's an insert
+ set operation "insert"
+ }
+ }
+
+ set success_p 1
+ array set result {
+ message {}
+ element_messages {}
+ }
+
+ with_catch errmsg {
+ switch $operation {
+ "insert" {
+ # We set email_verified_p to 't', because we trust the email we get from the remote system
+ array set result [auth::create_local_account \
+ -authority_id $authority_id \
+ -username $username \
+ -first_names $first_names \
+ -last_name $last_name \
+ -email $email \
+ -email_verified_p "t" \
+ -url $url]
+
+ if { ![string equal $result(creation_status) "ok"] } {
+ set result(message) $result(creation_message)
+ set success_p 0
+ }
+
+ # We ignore account_status
+ }
+ "update" {
+ # We set email_verified_p to 't', because we trust the email we get from the remote system
+ array set result [auth::update_local_account \
+ -authority_id $authority_id \
+ -username $username \
+ -first_names $first_names \
+ -last_name $last_name \
+ -email $email \
+ -email_verified_p "t" \
+ -url $url]
+
+ if { ![string equal $result(update_status) "ok"] } {
+ set result(message) $result(update_message)
+ set success_p 0
+ }
+ }
+ "delete" {
+ array set result [auth::delete_local_account \
+ -authority_id $authority_id \
+ -username $username]
+
+ if { ![string equal $result(delete_status) "ok"] } {
+ set result(message) $result(delete_message)
+ set success_p 0
+ }
+ }
+ }
+ } {
+ # Get errorInfo and log it
+ global errorInfo
+ ns_log Error "Error during batch syncrhonization job:\n$errorInfo"
+ set success_p 0
+ set result(message) $errorInfo
+ }
+
+ # Make a log entry
+ set entry_id [auth::sync::job::create_entry \
+ -job_id $job_id \
+ -operation $operation \
+ -authority_id $authority_id \
+ -username $username \
+ -user_id $user_id \
+ -success=$success_p \
+ -message $result(message) \
+ -element_messages $result(element_messages)]
+ }
+
+ return $entry_id
+}
+
+ad_proc -public auth::sync::job::snapshot_delete_remaining {
+ -job_id:required
+ -authority_id:required
+} {
+ Deletes the users that weren't included in the snapshot.
+} {
+ # run through users that belong to the given authority,
+ # but which don't already have an entry in the log
+ # and call auth::sync::job::action -operation "delete" on them
+
+ # TODO
+}
+
+
+
+
+
+
+ad_proc -public auth::sync::purge_jobs {} {
+ Purge jobs that are older than KeepBatchLogDays days.
+} {
+ # Don't forget to also delete the cr_item referenced by the auth_batch_jobs.document column.
+
+ # Parameter: KeepBatchLogDays - number of days to keep batch job log around. 0 = forever.
+
+ # TODO
+}
+
+
+
+
+
+
Index: openacs-4/packages/acs-authentication/tcl/test/acs-authentication-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-authentication/tcl/test/acs-authentication-procs.tcl,v
diff -u -N -r1.20 -r1.21
--- openacs-4/packages/acs-authentication/tcl/test/acs-authentication-procs.tcl 5 Sep 2003 14:40:10 -0000 1.20
+++ openacs-4/packages/acs-authentication/tcl/test/acs-authentication-procs.tcl 8 Sep 2003 15:59:43 -0000 1.21
@@ -167,31 +167,62 @@
}
- # Missing first_names
+ # Missing first_names, last_name, email
array unset user_info
array set user_info [auth::create_user \
-username "auth_create_user2" \
- -email "auth_create_user2@test_user.com" \
+ -email "" \
-first_names "" \
- -last_name "User" \
+ -last_name "" \
-password "changeme" \
-secret_question "no_question" \
-secret_answer "no_answer"]
- aa_equals "creation_status for missing first names" $user_info(creation_status) "data_error"
+ aa_equals "creation_status is data_error" $user_info(creation_status) "data_error"
aa_true "element_messages exists" [exists_and_not_null user_info(element_messages)]
if { [exists_and_not_null user_info(element_messages)] } {
array unset elm_msgs
array set elm_msgs $user_info(element_messages)
- aa_true "element_message for first_names exists" [exists_and_not_null elm_msgs(first_names)]
-
+
+ if { [aa_true "element_message(email) exists" [exists_and_not_null elm_msgs(email)]] } {
+ aa_log "element_message(email) = $elm_msgs(email)"
+ }
+ if { [aa_true "element_message(first_names) exists" [exists_and_not_null elm_msgs(first_names)]] } {
+ aa_log "element_message(first_names) = $elm_msgs(first_names)"
+ }
+ if { [aa_true "element_message(last_name) exists" [exists_and_not_null elm_msgs(last_name)]] } {
+ aa_log "element_message(last_name) = $elm_msgs(last_name)"
+ }
}
- if { [info exists user_info(element_messages)] } {
- array set element_message $user_info(element_messages)
- aa_log "user_info(element_messages) = '$user_info(element_messages)'"
- aa_true "Element message for first_names exists" [exists_and_not_null element_message(first_names)]
+ # Malformed email
+ array unset user_info
+ array set user_info [auth::create_user \
+ -username [ad_generate_random_string] \
+ -email "not an email" \
+ -first_names "[ad_generate_random_string]<[ad_generate_random_string]" \
+ -last_name "[ad_generate_random_string]<[ad_generate_random_string]" \
+ -password [ad_generate_random_string] \
+ -secret_question [ad_generate_random_string] \
+ -secret_answer [ad_generate_random_string]]
+
+ aa_equals "creation_status is data_error" $user_info(creation_status) "data_error"
+
+ aa_true "element_messages exists" [exists_and_not_null user_info(element_messages)]
+ if { [exists_and_not_null user_info(element_messages)] } {
+ array unset elm_msgs
+ array set elm_msgs $user_info(element_messages)
+
+ if { [aa_true "element_message(email) exists" [exists_and_not_null elm_msgs(email)]] } {
+ aa_log "element_message(email) = $elm_msgs(email)"
+ }
+ if { [aa_true "element_message(first_names) exists" [exists_and_not_null elm_msgs(first_names)]] } {
+ aa_log "element_message(first_names) = $elm_msgs(first_names)"
+ }
+ if { [aa_true "element_message(last_name) exists" [exists_and_not_null elm_msgs(last_name)]] } {
+ aa_log "element_message(last_name) = $elm_msgs(last_name)"
+ }
}
# Duplicate email and username
Index: openacs-4/packages/acs-authentication/tcl/test/sync-test-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-authentication/tcl/test/sync-test-procs.tcl,v
diff -u -N
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/acs-authentication/tcl/test/sync-test-procs.tcl 8 Sep 2003 15:59:43 -0000 1.1
@@ -0,0 +1,177 @@
+ad_library {
+ Automated tests for synchronization API
+
+ @author Lars Pind (lars@collaboraid.biz)
+ @creation-date 05 September 2003
+ @cvs-id $Id: sync-test-procs.tcl,v 1.1 2003/09/08 15:59:43 lars Exp $
+}
+
+aa_register_case job_start_end {
+ Test starting and ending a batch job
+} {
+ aa_run_with_teardown \
+ -rollback \
+ -test_code {
+
+
+ # TODO: Add checks that the user info actually look the way it's supposed to ... use the acs_user::get API to verify
+
+
+
+ # Start non-interactive job
+
+ set job_id [auth::sync::job::start \
+ -authority_id [auth::authority::local]]
+
+ aa_true "Returns a job_id" [exists_and_not_null job_id]
+
+
+ # Get doc
+ auth::sync::job::start_get_document -job_id $job_id
+
+ auth::sync::job::end_get_document \
+ -job_id $job_id \
+ -doc_status "ok" \
+ -doc_message "" \
+ -document {}
+
+ # Valid successful log entry
+ auth::sync::job::create_entry \
+ -job_id $job_id \
+ -operation "insert" \
+ -authority_id [auth::authority::local] \
+ -username "foobar" \
+ -user_id [ad_conn user_id] \
+ -success
+
+ # Valid unsuccessful log entry
+ auth::sync::job::create_entry \
+ -job_id $job_id \
+ -operation "insert" \
+ -authority_id [auth::authority::local] \
+ -username "foobar" \
+ -user_id [ad_conn user_id] \
+ -message "A problem" \
+ -element_messages ""
+
+ # Valid insert action
+ set username1 [ad_generate_random_string]
+ set email1 "[ad_generate_random_string]@foo.bar"
+ aa_log "--- Valid insert --- auth::sync::job::action -opration insert -username $username1 -email $email1"
+ set entry_id [auth::sync::job::action \
+ -job_id $job_id \
+ -operation "insert" \
+ -authority_id [auth::authority::local] \
+ -username $username1 \
+ -first_names [ad_generate_random_string] \
+ -last_name [ad_generate_random_string] \
+ -email $email1]
+
+ array unset entry
+ auth::sync::job::get_entry \
+ -entry_id $entry_id \
+ -array entry
+
+ aa_equals "entry.success_p" $entry(success_p) "t"
+ aa_equals "entry.message" $entry(message) {}
+ aa_equals "entry.element_messages" $entry(element_messages) {}
+ aa_log "entry.user_id = '$entry(user_id)'"
+ aa_log "entry.message = '$entry(message)'"
+ aa_log "entry.element_messages = '$entry(element_messages)'"
+
+ # Invalid insert action: Reusing username, email
+ aa_log "--- Invalid insert: reusing username, email --- auth::sync::job::action -opration insert -username $username1 -email $email1"
+ set entry_id [auth::sync::job::action \
+ -job_id $job_id \
+ -operation "insert" \
+ -authority_id [auth::authority::local] \
+ -username $username1 \
+ -first_names [ad_generate_random_string] \
+ -last_name [ad_generate_random_string] \
+ -email $email1]
+
+ array unset entry
+ auth::sync::job::get_entry \
+ -entry_id $entry_id \
+ -array entry
+
+ aa_equals "entry.success_p" $entry(success_p) "f"
+
+ if { [aa_true "entry.element_messages not empty" [exists_and_not_null entry(element_messages)]] } {
+ array unset elm_msgs
+ array set elm_msgs $entry(element_messages)
+ aa_true "username, email have problems" [util_sets_equal_p { username email } [array names elm_msgs]]
+ }
+
+ aa_log "entry.user_id = '$entry(user_id)'"
+ aa_log "entry.message = '$entry(message)'"
+ aa_log "entry.element_messages = '$entry(element_messages)'"
+
+ # Valid update action
+ aa_log "--- Valid update --- auth::sync::job::action -opration update -username $username1"
+ set entry_id [auth::sync::job::action \
+ -job_id $job_id \
+ -operation "update" \
+ -authority_id [auth::authority::local] \
+ -username $username1 \
+ -first_names [ad_generate_random_string] \
+ -last_name [ad_generate_random_string] \
+ -email "[ad_generate_random_string]@foo.bar"]
+
+ array unset entry
+ auth::sync::job::get_entry \
+ -entry_id $entry_id \
+ -array entry
+
+ aa_equals "entry.success_p" $entry(success_p) "t"
+ aa_equals "entry.message" $entry(message) {}
+ aa_equals "entry.element_messages" $entry(element_messages) {}
+ aa_log "entry.user_id = '$entry(user_id)'"
+ aa_log "entry.message = '$entry(message)'"
+ aa_log "entry.element_messages = '$entry(element_messages)'"
+
+
+ # Invalid insert action: Missing first_names, last_name invalid, email invalid
+ set username2 [ad_generate_random_string]
+ aa_log "--- Invalid insert --- auth::sync::job::action -opration update -username $username2"
+ set entry_id [auth::sync::job::action \
+ -job_id $job_id \
+ -operation "insert" \
+ -authority_id [auth::authority::local] \
+ -username $username2 \
+ -first_names {} \
+ -last_name {Foobar} \
+ -email "not_an_email"]
+
+ array unset entry
+ auth::sync::job::get_entry \
+ -entry_id $entry_id \
+ -array entry
+
+ aa_equals "entry.success_p" $entry(success_p) "f"
+ aa_log "entry.message = '$entry(message)'"
+ if { [aa_true "entry.element_messages not empty" [exists_and_not_null entry(element_messages)]] } {
+ aa_log "entry.element_messages = '$entry(element_messages)'"
+ array unset elm_msgs
+ array set elm_msgs $entry(element_messages)
+ aa_log "array names elm_msgs = '[array names elm_msgs]'"
+ aa_true "first_names, last_name, email have problems" [util_sets_equal_p { first_names last_name email } [array names elm_msgs]]
+ }
+
+ # End job
+ array set job [auth::sync::job::end -job_id $job_id]
+
+ aa_true "Elapsed time less than 30 seconds" [expr $job(run_time_seconds) < 30]
+
+ aa_false "Not interactive" [template::util::is_true $job(interactive_p)]
+
+ aa_equals "Number of actions" $job(num_actions) 6
+
+ aa_equals "Number of problems" $job(num_problems) 3
+
+ aa_false "Log URL non-empty" [empty_string_p $job(log_url)]
+
+
+ }
+}
+