Commit 3b86960a authored by cvs2svn's avatar cvs2svn

This commit was manufactured by cvs2svn to create tag 'v5-0-1-0-0'.

Sprout from master 2016-06-20 14:03:05 UTC Frank Bergmann  <frank.bergmann@project-open.com> '- Disabled Admin sub-navar'
Delete:
    sql/postgresql/upgrade/upgrade-5.0.0.0.0-5.0.0.0.1.sql
    sql/postgresql/upgrade/upgrade-5.0.0.0.1-5.0.0.0.2.sql
    sql/postgresql/upgrade/upgrade-5.0.0.0.2-5.0.0.0.3.sql
    sql/postgresql/upgrade/upgrade-5.0.0.0.3-5.0.0.0.4.sql
    sql/postgresql/upgrade/upgrade-5.0.0.0.4-5.0.0.0.5.sql
    sql/postgresql/upgrade/upgrade-5.0.0.0.5-5.0.0.0.6.sql
    sql/postgresql/upgrade/upgrade-5.0.0.0.6-5.0.0.0.7.sql
    sql/postgresql/upgrade/upgrade-5.0.0.0.7-5.0.0.0.8.sql
    sql/postgresql/upgrade/upgrade-5.0.0.0.8-5.0.0.0.9.sql
    sql/postgresql/upgrade/upgrade-5.0.0.0.9-5.0.0.1.0.sql
parent ed1fbee8
-- upgrade-5.0.0.0.0-5.0.0.0.1.sql
SELECT acs_log__debug('/packages/intranet-core/sql/postgresql/upgrade/upgrade-5.0.0.0.0-5.0.0.0.1.sql','');
drop function if exists im_object_permission_p(integer, integer, varchar);
create or replace function im_object_permission_p (integer, integer, varchar)
returns boolean as $body$
DECLARE
p_object_id alias for $1;
p_user_id alias for $2;
p_privilege alias for $3;
BEGIN
return acs_permission__permission_p(p_object_id, p_user_id, p_privilege);
END;$body$ language 'plpgsql';
update im_menus set sort_order = 2450 where label = 'rules';
update im_menus set sort_order = 2425, name = 'SQL Selectors' where label = 'selectors_admin';
update im_menus set sort_order = 850 where label = 'cvs_integration';
update im_menus set name = 'Privileges' where name = 'User Profiles';
update im_menus set name = 'User Sub-Administration' where name = 'User Matrix';
update im_menus set
name = 'Traffic Light Reports',
label = 'traffic_light_reports',
url = '/intranet-simple-survey/reporting/traffic-light-reports'
where
label = 'project_reports';
-- upgrade-5.0.0.0.1-5.0.0.0.2.sql
SELECT acs_log__debug('/packages/intranet-core/sql/postgresql/upgrade/upgrade-5.0.0.0.1-5.0.0.0.2.sql','');
-- Add metadata to Office object
SELECT im_dynfield_widget__new (
null, 'im_dynfield_widget', now(), 0, '0.0.0.0', null,
'category_office_type', 'Office Type', 'Office Type',
10007, 'integer', 'im_category_tree', 'integer',
'{custom {category_type "Intranet Office Type"}}'
);
SELECT im_dynfield_widget__new (
null, 'im_dynfield_widget', now(), 0, '0.0.0.0', null,
'category_office_status', 'Office Status', 'Office Status',
10007, 'integer', 'im_category_tree', 'integer',
'{custom {category_type "Intranet Office Status"}}'
);
SELECT im_dynfield_attribute_new ('im_office', 'office_name', 'Name', 'textbox_medium', 'string', 'f', 0, 't', 'im_offices');
SELECT im_dynfield_attribute_new ('im_office', 'office_path', 'Path', 'textbox_medium', 'string', 'f', 10, 't', 'im_offices');
SELECT im_dynfield_attribute_new ('im_office', 'office_status_id', 'Status', 'category_office_status', 'integer', 'f', 30, 't', 'im_offices');
SELECT im_dynfield_attribute_new ('im_office', 'office_type_id', 'Type', 'category_office_type', 'integer', 'f', 40, 't', 'im_offices');
SELECT im_dynfield_attribute_new ('im_office', 'phone', 'Phone', 'textbox_medium', 'string', 'f', 100, 't', 'im_offices');
SELECT im_dynfield_attribute_new ('im_office', 'fax', 'Fax', 'textbox_medium', 'string', 'f', 110, 't', 'im_offices');
SELECT im_dynfield_attribute_new ('im_office', 'address_line1', 'Address 1', 'textbox_large', 'string', 'f', 120, 't', 'im_offices');
SELECT im_dynfield_attribute_new ('im_office', 'address_line2', 'Address 2', 'textbox_large', 'string', 'f', 130, 't', 'im_offices');
SELECT im_dynfield_attribute_new ('im_office', 'address_city', 'City', 'textbox_medium', 'string', 'f', 140, 't', 'im_offices');
SELECT im_dynfield_attribute_new ('im_office', 'address_state', 'State', 'textbox_medium', 'string', 'f', 150, 't', 'im_offices');
SELECT im_dynfield_attribute_new ('im_office', 'address_postal_code', 'ZIP', 'textbox_small', 'string', 'f', 160, 't', 'im_offices');
SELECT im_dynfield_attribute_new ('im_office', 'address_country_code', 'Country', 'country_codes', 'string', 'f', 170, 't', 'im_offices');
SELECT im_dynfield_attribute_new ('im_office', 'note', 'Note', 'textarea_small', 'string', 'f', 200, 't', 'im_offices');
-- upgrade-5.0.0.0.2-5.0.0.0.3.sql
SELECT acs_log__debug('/packages/intranet-core/sql/postgresql/upgrade/upgrade-5.0.0.0.2-5.0.0.0.3.sql','');
CREATE OR REPLACE FUNCTION inline_1 ()
RETURNS INTEGER AS $BODY$
DECLARE
v_plugin_id INTEGER;
v_hr_group_id INTEGER;
BEGIN
SELECT group_id INTO v_hr_group_id FROM groups WHERE group_name = 'HR Managers';
SELECT im_component_plugin__new (
NULL, -- plugin_id
'acs_object', -- object_type
now(), -- creation_date
NULL, -- creation_user
NULL, -- creation_ip
NULL, -- context_id
'Last Projects', -- plugin_name
'intranet-core', -- package_name
'right', -- location
'/intranet/users/view', -- page_url
NULL, -- view_name
20, -- sort_order
'im_biz_object_related_objects_component -show_projects_only 1 -include_membership_rels_p 1 -hide_rel_name_p 1 -hide_object_chk_p 1 -hide_direction_pretty_p 1 -hide_object_type_pretty_p 1 -object_id $user_id -sort_order "" -suppress_invalid_objects_p 1' -- component_tcl
) INTO v_plugin_id;
-- Set title
UPDATE im_component_plugins SET title_tcl = 'lang::message::lookup "" intranet-core.LastProjects "Last Projects"' WHERE plugin_id = v_plugin_id;
-- Permissions
PERFORM im_grant_permission(v_plugin_id, v_hr_group_id, 'read');
RETURN 0;
END;$BODY$ LANGUAGE 'plpgsql';
SELECT inline_1 ();
DROP FUNCTION inline_1();
CREATE OR REPLACE FUNCTION inline_1 ()
RETURNS INTEGER AS $BODY$
DECLARE
v_plugin_id INTEGER;
v_hr_group_id INTEGER;
BEGIN
SELECT group_id INTO v_hr_group_id FROM groups WHERE group_name = 'HR Managers';
SELECT im_component_plugin__new (
NULL, -- plugin_id
'acs_object', -- object_type
now(), -- creation_date
NULL, -- creation_user
NULL, -- creation_ip
NULL, -- context_id
'Customers worked for', -- plugin_name
'intranet-core', -- package_name
'right', -- location
'/intranet/users/view', -- page_url
NULL, -- view_name
20, -- sort_order
'im_biz_object_related_objects_component -show_companies_only 1 -include_membership_rels_p 1 -hide_rel_name_p 1 -hide_object_chk_p 1 -hide_direction_pretty_p 1 -hide_object_type_pretty_p 1 -object_id $user_id -sort_order "o.object_name" -suppress_invalid_objects_p 1' -- component_tcl
) INTO v_plugin_id;
-- Set title
UPDATE im_component_plugins SET title_tcl = 'lang::message::lookup "" intranet-core.CustomersWorkedFor "Customers worked for:"' WHERE plugin_id = v_plugin_id;
-- Permissions
PERFORM im_grant_permission(v_plugin_id, v_hr_group_id, 'read');
RETURN 0;
END;$BODY$ LANGUAGE 'plpgsql';
SELECT inline_1 ();
DROP FUNCTION inline_1();
-- upgrade-5.0.0.0.3-5.0.0.0.4.sql
SELECT acs_log__debug('/packages/intranet-core/sql/postgresql/upgrade/upgrade-5.0.0.0.3-5.0.0.0.4.sql','');
-- Add a new constraint to avoid projects that end before they start.
create or replace function inline_0()
returns integer as $body$
DECLARE
v_count integer;
BEGIN
select count(*) into v_count from pg_constraint
where conname = 'im_projects_start_end_chk';
IF v_count > 0 THEN return 0; END IF;
update im_projects set end_date = start_date where end_date < start_date;
alter table im_projects add constraint im_projects_start_end_chk check(end_date >= start_date);
return 0;
END;$body$ language 'plpgsql';
select inline_0();
drop function inline_0();
-- upgrade-5.0.0.0.4-5.0.0.0.5.sql
SELECT acs_log__debug('/packages/intranet-core/sql/postgresql/upgrade/upgrade-5.0.0.0.4-5.0.0.0.5.sql','');
-- acs-mail is deprecated
-- To ensure backwards compatibility inherit acs_mail_nt__post_request using acs_mail_lite queue
create or replace function acs_mail_nt__post_request(integer,integer,boolean,varchar,text,integer,integer)
returns integer as $BODY$
declare
p_party_from alias for $1;
p_party_to alias for $2;
p_expand_group alias for $3; -- default 'f'
p_subject alias for $4;
p_message alias for $5;
p_max_retries alias for $6; -- default 0
p_package_id alias for $7; -- default null
v_header_from acs_mail_bodies.header_from%TYPE;
v_header_to acs_mail_bodies.header_to%TYPE;
v_message_id acs_mail_queue_messages.message_id%TYPE;
v_header_to_rec record;
v_creation_user acs_objects.creation_user%TYPE;
v_creation_date timestamptz;
v_locking_server varchar;
v_mime_type varchar;
begin
if p_max_retries <> 0 then
raise EXCEPTION ' -20000: max_retries parameter not implemented.';
end if;
-- get the sender email address
select max(email) into v_header_from from parties where party_id = p_party_from;
-- if sender address is null, then use site default OutgoingSender
if v_header_from is null then
select apm__get_value(package_id, 'OutgoingSender') into v_header_from from apm_packages where package_key='acs-kernel';
end if;
-- make sure that this party is in users table. If not, let creation_user
-- be null to prevent integrity constraint violations on acs_objects
select max(user_id) into v_creation_user from users where user_id = p_party_from;
-- get the recipient email address
select max(email) into v_header_to from parties where party_id = p_party_to;
-- do not let from addresses be null
if v_header_from is null then
raise EXCEPTION ' -20000: acs_mail_nt: cannot sent email from blank address.';
end if;
-- do not let any of these addresses be null
if v_header_to is null AND p_expand_group = 'f' then
raise EXCEPTION ' -20000: acs_mail_nt: cannot sent email to blank address.';
end if;
-- set vars
select now() into v_creation_date;
v_locking_server := null;
v_mime_type := 'text/plain';
if p_expand_group = 'f' then
insert into acs_mail_lite_queue
(message_id,
creation_date,
locking_server,
to_addr,
from_addr,
reply_to,
subject,
package_id,
mime_type,
body
)
values
(nextval('acs_mail_lite_id_seq'),
v_creation_date,
v_locking_server,
v_header_to,
v_header_from,
v_header_from,
p_subject ,
p_package_id,
v_mime_type,
p_message
);
else
-- expand the group
-- FIXME: need to check if this is a group and if there are members
-- if not, do we need to notify sender?
for v_header_to_rec in
select email from parties p
where party_id in (
SELECT u.user_id
FROM group_member_map m, membership_rels mr, users u
INNER JOIN (select member_id from group_approved_member_map where group_id = p_party_to) mm
ON u.user_id = mm.member_id
WHERE u.user_id = m.member_id
AND m.group_id in (acs__magic_object_id('registered_users'::CHARACTER VARYING))
AND m.rel_id = mr.rel_id AND m.container_id = m.group_id
AND m.rel_type::TEXT = 'membership_rel'::TEXT
AND mr.member_state = 'approved'
)
loop
insert into acs_mail_lite_queue
(message_id,
creation_date,
locking_server,
to_addr,
from_addr,
reply_to,
subject,
package_id,
mime_type,
body
)
values
(nextval('acs_mail_lite_id_seq'),
v_creation_date,
v_locking_server,
v_header_to_rec.email,
v_header_from,
v_header_from,
p_subject ,
p_package_id,
v_mime_type,
p_message
);
end loop;
end if;
return 1;
end;$BODY$ language 'plpgsql';
create or replace function acs_mail_nt__post_request(integer,integer,boolean,varchar,text,integer)
returns integer as $BODY$
declare
p_party_from alias for $1;
p_party_to alias for $2;
p_expand_group alias for $3; -- default 'f'
p_subject alias for $4;
p_message alias for $5;
p_max_retries alias for $6; -- default 0
v_header_from acs_mail_bodies.header_from%TYPE;
v_header_to acs_mail_bodies.header_to%TYPE;
v_message_id acs_mail_queue_messages.message_id%TYPE;
v_header_to_rec record;
v_creation_user acs_objects.creation_user%TYPE;
v_creation_date timestamptz;
v_locking_server varchar;
v_mime_type varchar;
begin
return acs_mail_nt__post_request(p_party_from, p_party_to, p_expand_group, p_subject, p_message, p_max_retries, null);
end;$BODY$ language 'plpgsql';
-- Fix translation issue
delete from lang_messages
where message_key = 'lt_Registered_from_regis' and package_key = 'intranet-core';
update im_menus set
parent_menu_id = (select menu_id from im_menus where label = 'projects'),
sort_order = 10
where label = 'project_programs';
-- upgrade-5.0.0.0.5-5.0.0.0.6.sql
SELECT acs_log__debug('/packages/intranet-core/sql/postgresql/upgrade/upgrade-5.0.0.0.5-5.0.0.0.6.sql','');
-- http://openacs.org/bugtracker/openacs/bug?bug_number=3290
create or replace function acs_object__get_attribute(int4,varchar) returns text as $BODY$
declare
object_id_in alias for $1;
attribute_name_in alias for $2;
v_table_name varchar(200);
v_column varchar(200);
v_key_sql text;
v_return text;
v_storage text;
v_rec record;
begin
v_storage := acs_object__get_attribute_storage(object_id_in, attribute_name_in);
v_column := acs_object__get_attr_storage_column(v_storage);
v_table_name := acs_object__get_attr_storage_table(v_storage);
v_key_sql := acs_object__get_attr_storage_sql(v_storage);
RAISE NOTICE 'v_column: %, v_table_name: %, v_key_sql: % ', v_column,v_table_name,v_key_sql;
for v_rec in execute 'select ' || quote_ident(v_column) || '::text as col_return from ' || quote_ident(v_table_name) || ' where ' || v_key_sql
LOOP
v_return := v_rec.col_return;
exit;
end loop;
if not FOUND then
return null;
end if;
return v_return;
end;$BODY$ language 'plpgsql';
-- upgrade-5.0.0.0.6-5.0.0.0.7.sql
SELECT acs_log__debug('/packages/intranet-core/sql/postgresql/upgrade/upgrade-5.0.0.0.6-5.0.0.0.7.sql','');
ALTER TABLE auth_authorities ALTER COLUMN short_name SET NOT NULL;
-- upgrade-5.0.0.0.7-5.0.0.0.8.sql
SELECT acs_log__debug('/packages/intranet-core/sql/postgresql/upgrade/upgrade-5.0.0.0.7-5.0.0.0.8.sql','');
-- Create the new group/profile if not already there...
create or replace function inline_0()
returns integer as $body$
DECLARE
v_count integer;
BEGIN
select count(*) into v_count from groups
where group_name = 'Skill Profile';
IF v_count > 0 THEN return 1; END IF;
PERFORM im_profile__new('Skill Profile', 'skill_profile');
return 0;
END;$body$ language 'plpgsql';
select inline_0();
drop function inline_0();
-- Set name and email of the skill profiles
update persons set first_names = 'Consultant', last_name = 'Consultant' where person_id = 8987;
update persons set first_names = 'Project', last_name = 'Manager' where person_id = 8989;
update persons set first_names = 'Administrator', last_name = 'Administrator' where person_id = 8991;
update persons set first_names = 'Database', last_name = 'Administrator' where person_id = 8999;
update persons set first_names = 'Presales', last_name = 'Presales' where person_id = 9003;
update persons set first_names = 'Tester', last_name = 'Tester' where person_id = 9005;
update persons set first_names = 'Senior', last_name = 'Developer' where person_id = 9007;
update persons set first_names = 'Junior', last_name = 'Developer' where person_id = 9013;
update parties set email = 'consultant@tigerpond.com', url = null where party_id = 8987;
update parties set email = 'project.manager', url = null where party_id = 8989;
update parties set email = 'administrator@tigerpond.com', url = null where party_id = 8991;
update parties set email = 'database.administrator', url = null where party_id = 8999;
update parties set email = 'presales@tigerpond.com', url = null where party_id = 9003;
update parties set email = 'tester@tigerpond.com', url = null where party_id = 9005;
update parties set email = 'senior.developer@tigerpond.com', url = null where party_id = 9007;
update parties set email = 'junior.developer@tigerpond.com', url = null where party_id = 9013;
-- Cleanup the contact information of the skill profile users
update users_contact set
aim_screen_name = null,
cell_phone = null,
current_information = null,
fax = null,
ha_city = null, ha_country_code = null, ha_line1 = null, ha_line2 = null, ha_postal_code = null, ha_state = null,
wa_city = null, wa_country_code = null, wa_line1 = null, wa_line2 = null, wa_postal_code = null, wa_state = null,
home_phone = null,
icq_number = null,
m_address = null,
msn_screen_name = null,
note = null,
pager = null,
work_phone = null
where
user_id in (8987, 8989, 8991, 8999, 9003, 9005, 9007, 9013);
-- Remove the skill profile users from any group except "Registered Users"
select r.object_id_two as user_id,
r.rel_id,
membership_rel__delete(r.rel_id) as del
from acs_rels r
where r.rel_type = 'membership_rel' and
r.object_id_one > 0 and
r.object_id_two in (8987, 8989, 8991, 8999, 9003, 9005, 9007, 9013);
-- Add the skill profile users to the group "Skill Profiles"
select membership_rel__new(
(select group_id from groups where group_name = 'Skill Profile'),
person_id
) as rel
from persons
where person_id in (8987, 8989, 8991, 8999, 9003, 9005, 9007, 9013);
-- upgrade-5.0.0.0.8-5.0.0.0.9.sql
SELECT acs_log__debug('/packages/intranet-core/sql/postgresql/upgrade/upgrade-5.0.0.0.8-5.0.0.0.9.sql','');
--
create or replace function im_create_profile (varchar, varchar)
returns integer as $body$
DECLARE
v_pretty_name alias for $1;
v_profile_gif alias for $2;
v_group_id integer;
v_rel_id integer;
n_groups integer;
v_category_id integer;
BEGIN
-- Check that the group does not exist before
select count(*)
into n_groups
from groups
where group_name = v_pretty_name;
-- only add the group if it did not exist before...
IF n_groups = 0 THEN
v_group_id := im_profile__new(
v_pretty_name,
v_profile_gif
);
v_rel_id := composition_rel__new (
null, -- rel_id
'composition_rel', -- rel_type
-2, -- object_id_one
v_group_id, -- object_id_two
0, -- creation_user
null -- creation_ip
);
select nextval into v_category_id from acs_object_id_seq;
-- Add the group to the Intranet User Type categories
perform im_category_new (
v_category_id, -- category_id
v_pretty_name, -- category
'Intranet User Type', -- category_type
null -- description
);
update im_categories set aux_int1 = v_group_id where category_id = v_category_id;
END IF;
return 0;
end;$body$ language 'plpgsql';
-- upgrade-5.0.0.0.9-5.0.0.1.0.sql
SELECT acs_log__debug('/packages/intranet-core/sql/postgresql/upgrade/upgrade-5.0.0.0.9-5.0.0.1.0.sql','');
create or replace function inline_0()
returns integer as $body$
DECLARE
v_count integer;
BEGIN
select count(*) into v_count from user_tab_columns
where lower(table_name) = 'im_audits';
IF v_count > 0 THEN return 1; END IF;
create sequence im_audit_seq;
create table im_audits (
audit_id integer
constraint im_audits_pk
primary key,
audit_object_id integer
constraint im_audits_object_nn
not null,
audit_object_status_id integer,
audit_action text
constraint im_audits_action_ck
check (audit_action in ('after_create','before_update','after_update','before_nuke', 'view', 'baseline')),
audit_user_id integer
constraint im_audits_user_nn
not null,
audit_date timestamptz
constraint im_audits_date_nn
not null,
audit_ip varchar(50)
constraint im_audits_ip_nn
not null,
audit_last_id integer
constraint im_audits_last_fk
references im_audits,
audit_ref_object_id integer,
audit_value text
constraint im_audits_value_nn
not null,
audit_diff text,
audit_note text,
audit_hash text
);
-- Add a link for every object to the ID of the last audit entry
alter table acs_objects add column last_audit_id integer;
-- Add a foreign key constraint on last_audit_id:
alter table acs_objects
add constraint acs_objects_last_audit_id_fkey
foreign key (last_audit_id) references im_audits;
-- Create an index for fast access of the changes of an object
create index im_audits_audit_object_id_idx on im_audits(audit_object_id);
-- Create an index for fast access of the audit date
create index im_audits_audit_date_idx on im_audits(audit_date);
comment on table im_audits is 'Generic audit table. A new row is created everytime that the value of the object is updated.';
comment on column im_audits.audit_id is 'ID of the audit log (not an OpenACS object_id).';
comment on column im_audits.audit_object_id is 'Object to be audited. ';
comment on column im_audits.audit_action is 'Type of action - one of create, update, delete, nuke or pre_update.';
comment on column im_audits.audit_user_id is 'Who has performed the change?';
comment on column im_audits.audit_date is 'When was the change performed?';
comment on column im_audits.audit_ip is 'IP address of the connection initiating the change.';
comment on column im_audits.audit_last_id is 'Pointer to the last last audit of the object or NULL before the first update.
Used to quickly find the old values for calculating a diff.';
comment on column im_audits.audit_ref_object_id is 'Optional reference to an object who initiated the change.';
comment on column im_audits.audit_value is 'List of the object fields after the update.';
comment on column im_audits.audit_diff is 'Difference between the audit_value of the audit_value of the audit_last_id and the new audit_value.';
comment on column im_audits.audit_note is 'Additional note by the user. Optional.';
comment on column im_audits.audit_hash is '
Crypto hash to ensure the integrity of the audit log.
The hash value includes the hash of the audit_last_id,
so that any modification in the audit log can be
identified.
In the case of a complete recalculation of all hashs,
the PostgreSQL OIDs will witness these changes.
';
return 0;
END;$body$ language 'plpgsql';
select inline_0();
drop function inline_0();
-----------------------------------------------------------
-- Function for accessing the values in an audit_value string
--
-- Extract the value of a specific field from an audit_value
create or replace function im_audit_value (text, text)
returns text as $body$
DECLARE
p_audit_value alias for $1;
p_var_name alias for $2;
v_expr text;
v_result text;
BEGIN
v_expr := p_var_name || '\\t([^\\n]*)';
select substring(p_audit_value from v_expr) into v_result from dual;
IF '' = v_result THEN v_result := null; END IF;
return v_result;
end; $body$ language 'plpgsql';
-- Extract the value of a specific field from an object at a specific date
create or replace function im_audit_value (integer, text, timestamptz)
returns text as $body$
DECLARE
p_object_id alias for $1;
p_var_name alias for $2;
p_audit_date alias for $3;
v_audit_value text;
v_expr text;
v_result text;
BEGIN
select a.audit_value into v_audit_value
from im_audits a
where a.audit_id = (
select max(aa.audit_id)
from im_audits aa
where aa.audit_object_id = p_object_id and
aa.audit_date <= p_audit_date
);
v_expr := p_var_name || '\\t([^\\n]*)';
select substring(v_audit_value from v_expr) into v_result from dual;
IF '' = v_result THEN v_result := null; END IF;
return v_result;
end; $body$ language 'plpgsql';
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment