See also:
Control flow / Conditions
Check for existing variable
- [exists_and_not_null project_id]
- [info exists project_id]
Localization
Find message in DB:
select * from lang_messages where message like '%Type%'
OpenACS string localization:
[lang::message::lookup "" intranet-core.Execution_Project "Create an 'Execution Project'"]
OpenACS string localization (short version):
#intranet-core.Filter_Projects#
Localize date to user-locale:
[lc_time_fmt '2009-12-15' %x]
Add message:
SELECT im_lang_add_message('en_US','intranet-audit','Earned_Value','Earned Value');
Localize numbers / beautifying them for output:
/intranet-invoices/www/view.tcl
set rounding_precision 2
set locale [lang::user::locale]
set amount_pretty [lc_numeric [im_numeric_add_trailing_zeros [expr $amount+0] $rounding_precision] "" $locale]
set val_hours_output [format "%0.2f" $val_hours]
Localize labels etc.
[lang::message::lookup "" intranet-core.Execution_Project "Create an Execution Project"]
Localize categories
Pls. see below
Categories
Create new Category
SELECT im_category_new ('71', 'Potential', 'Intranet Project Status');
Create new Category Hierarchy
SELECT im_category_hierarchy_new (58, 56);
Return id of categories with name CATEGORY_NAME
[im_sub_categories CATEGORY_NAME]
Returns name of category
[im_category_from_id CATEGORY_ID]
Transitive closure – Returns categories including sub-categories
im_sub_categories [ -include_disabled_p include_disabled_p ] category_list
Note: category_list is a list of category id’s (integer)
Category drop-down in ad_form – Default
Currently return an empty entry for ‘All’
...
-form {
{absence_type_id:text(im_category_tree),optional {label "[_ intranet-timesheet2.Absence_Type]"} {value $absence_type_id} {custom {category_type "Intranet Absence Type" translate_p 1} } }
..
}
Category drop-down in ad_form – Custom, using VIEW
set absences_types [im_memoize_list select_absences_types "select absence_type_id, absence_type from im_absence_types order by lower(ABSENCE_TYPE)"]
set absences_types [linsert $absences_types 0 "All"]
set absences_types [linsert $absences_types 0 -1]
set absence_type_list [list]
foreach { value text } $absences_types {
regsub -all " " $text "_" category_key
set text [lang::message::lookup "" intranet-core.$category_key $text]
lappend absence_type_list [list $text $value]
}
...
-form {
{absence_type_id:text(select),optional {label "[_ intranet-timesheet2.Absence_Type]"} {options $absence_type_list }} ..
}
Plain SQL
SELECT
im_categories.category_id,
im_categories.category AS absence_type
FROM
im_categories
WHERE
im_categories.category_type::text = 'Intranet Absence Type'::text;
Permissions for pages
Is User logged in?:
set current_user_id [ad_maybe_redirect_for_registration]
Using existing permission procedures:
im_timesheet_task_permissions $current_user_id $project_id view read write admin
sets variables $read $write $admin to true/false
Checking privilege:
if {![im_permission $current_user_id "view_projects_all"]} {
ad_return_complaint 1 "[_ intranet-core.lt_You_dont_have_suffici_2]"
}
Search for privileges:
SELECT * FROM acs_privileges WHERE pretty_name LIKE '%assign%';
Permissions & Privileges
Create a new privilege:
select acs_privilege__create_privilege('add_tickets','Add Tickets','');
select acs_privilege__add_child('admin', 'add_tickets_for_customers');
select im_priv_create('add_tickets', 'P/O Admins');
select im_priv_create('add_tickets', 'Senior Managers');
select im_priv_create('add_tickets', 'Project Managers');
select im_priv_create('add_tickets', 'Employees');
select im_priv_create('add_tickets', 'Customers');
Check if user has privilege
[im_permission $user_id view_costs]
Remove priviliges
delete from acs_permissions where privilege = 'add_view_internal_rates';
delete from acs_privilege_hierarchy where child_privilege = 'add_view_internal_rates';
delete from acs_privileges where privilege = 'add_view_internal_rates';
Packages
Parameters
[parameter::get -package_id [apm_package_id_from_key intranet-mail-import] -parameter "ScanMails" -default 60]
Does PAckage exist
set im_survey_installed_p [llength [info proc [db_string get_view_id "select package_id from apm_packages where package_key = 'intranet-simple-survey'" -default 0]]]
OR
set survey_exists_p [llength [info commands im_package_survsimp_id]]
Dynfields
Create DynField
SELECT im_dynfield_attribute_new (
'im_timesheet_task', 'effort_driven_type_id', 'Fixed Task Type', 'gantt_fixed_task_type', 'integer', 'f', 0, 'f', 'im_timesheet_tasks'
);
Set DynField permissions
PERFORM acs_permission__grant_permission(v_dynfield_id, (select group_id from groups where group_name=''Employees''), ''read'');
create or replace function inline_0 ()
returns integer as '
declare
v_dynfield_id integer;
begin
SELECT im_dynfield_attribute_new (
'im_timesheet_task', 'effort_driven_type_id', 'Fixed Task Type', 'gantt_fixed_task_type', 'integer', 'f', 0, 'f', 'im_timesheet_tasks'
);
PERFORM acs_permission__grant_permission(v_dynfield_id, (select group_id from groups where group_name=''Employees''), ''read'');
PERFORM acs_permission__grant_permission(v_dynfield_id, (select group_id from groups where group_name=''Employees''), ''write'');
return 0;
end;' language 'plpgsql';
select inline_0 ();
drop function inline_0 ();
Views
Create View
insert into im_views (view_id, view_name, visible_for, view_type_id)
values (80, 'office_list', 'view_offices', 1400);
Create View Columns
insert into im_view_columns (column_id, view_id, group_id, column_name, column_render_tcl,
extra_select, extra_where, sort_order, visible_for) values (2221,22,NULL,'Quote',
'$quote_date','','',18,'');
User Management
Is user member of a project?
[im_biz_object_member_p $user_id $project_id]
Is user employee?
[im_user_is_employee_p $user_id]
Is user employee?
[im_profile::member_p -profile_id [im_employee_group_id] -user_id $user_id]
Is user customer?
[im_profile::member_p -profile_id [im_customer_group_id] -user_id $user_id]
Is user freelancer?
[im_profile::member_p -profile_id [im_freelance_group_id] -user_id $user_id]
Is user customer?
[im_profile::member_p -profile_id [im_customer_group_id] -user_id $user_id]
Is user Project Manager?
[im_biz_object_admin_p $user_id $project_id]
Is user admin?
[im_is_user_site_wide_or_intranet_admin $user_id]
Current user
po34klaus=# select current_user;
current_user
--------------
po34klaus
(1 row)
Database
db_foreach
set column_sql "
select
*
from
im_view_columns
where
view_id=:view_id
and group_id is null
order by
sort_order
"
db_foreach column_list_sql $column_sql {
if {"" == $visible_for || [eval $visible_for]} {
lappend column_headers "$column_name"
lappend column_vars "$column_render_tcl"
}
....
}
db_1row
Use: Set variables for a query returning exactly one row.
Sample:
db_1row sender_get_info_1 "
select
pe.first_names as accounting_first_name,
pe.last_name as accounting_last_name
from
persons
where
person_id = $accounting_contact_id
"
db_0or1row
Like db_1row but returns an error if more than one row is returned.
db_string
Use: Getting a single string value from the db
Sample:
set view_id [db_string get_view_id "select view_id from im_views where view_name=:view_name" -default 0]
db_dml – performs a dml statement
db_dml delete "
delete from im_object_freelance_skill_map
where
object_id = :object_id
and skill_type_id = :skill_type_id
and skill_id in ([join $skill_id ","])
"
Create a sequence
create sequence im_inquiries_files_seq start 1;
Get id from sequence
set inquiry_files_id [db_string nextval "select nextval('im_inquiries_files_seq');"]
Check if table exists
<ul>
<li>db_table_exists TABLE_NAME </li>
<li>[im_table_exists im_freelance_rfqs]</li>
</ul>
DB Transactions
db_transaction {
db_dml test "nonsense"
} on_error {
ad_return_error "Error in blah/foo/bar" "The error was: $errmsg"
}
String operations
String concatenation
Alternative to concat & append – in case var’s are ambigious:
set var_amount "amount.${user_id}_$project_type_id"
</p>
<strong>Check for empty string</strong>
<ul>
<li>empty_string_p [VAR]</li>
</ul>
Sample:
if { ![empty_string_p $where_clause] } {
set where_clause " and $where_clause"
}
Compare strings in tcl
if { -1 != [string compare $list_order_by "min(p.price)"] } {
ad_return_complaint 1 "here"
set sorted_table_rows [qsort $table_rows [lambda {s} { lindex $s 2 }]]
} else {
set sorted_table_rows $table_rows
}
Formating for amounts, etc.
set amount_pretty [im_numeric_add_trailing_zeros [expr $amount+0] 2]
Error handling
Handling expr error
if {"" != $visible_tcl} {
set visible 0
set errmsg ""
if [catch {
set visible [expr $visible_tcl]
} errmsg] {
ad_return_complaint 1 "$visible_tcl\n$errmsg"
}
if {!$visible} { continue }
}
Handling db error
if {[catch { db_dml target_languages " select * from im_projects" } errmsg ]} {
append errors "..."
}
Page contract
Optional parameters
ad_proc im_costs_base_component { user_id {company_id ""} {project_id ""} } {
Returns a HTML table containing a list of costs for a particular
company or project.
} {
...
}
Passing URL parameters
set primary_contact_link "<a href=primary-contact?[export_url_vars company_id limit_to_users_in_group_id]>Add primary contact</a>\n"
Forms
Arrays – Create form
<input type='checkbox' name='payed_p.$cost_id'>
Arrays – Handle form
ad_proc im_costs_base_component {
...
} {
payed_p:array,optional
}
Add hidden vars to form
[export_form_vars company_id return_url]
Create list from form var array:
set payed_p_list [array names payed_p]
set hours_list [array names hours]
foreach hour_rec $hours_list {
ns_log NOTICE "hour_rec $hour_rec / value: $hours($hour_rec)"
}
Sanity checks
if {![im_column_exists im_hours internal_note]} {
ad_return_complaint 1 "Internal error in intranet-timesheet2:<br>
The field im_hours.internal_note is missing.<br>
Please notify your system administrator to upgrade
your system to the latest version.<br>
"
ad_script_abort
}
Date & Time operations
Moved to:
http://www.project-open.org/documentation/date_and_time_operations
Math operations
using round in sql
/packages/intranet-reporting-finance/www/finance-expenses.tcl
select
...
round((c.paid_amount * im_exchange_rate(c.effective_date::date, c.currency, 'EUR')) :: numeric, 2) as paid_amount_converted,
from ...
Menus
Add menu:
create or replace function inline_1 ()
returns integer as '
declare
v_menu integer;
v_parent_menu integer;
v_employees integer;
begin
select group_id into v_employees from groups where group_name = ''Employees'';
select menu_id into v_parent_menu
from im_menus where label = ''projects_admin'';
v_menu := im_menu__new (
null, -- p_menu_id
''im_menu'', -- object_type
now(), -- creation_date
null, -- creation_user
null, -- creation_ip
null, -- context_id
''intranet-cust-kw'', -- package_name
''project_closure_wf'', -- label
''Close Project'', -- name
''/intranet-cust-kw/workflow-close-project?project_id=$project_id'', -- url
-10, -- sort_order
v_parent_menu, -- parent_menu_id
null -- p_visible_tcl
);
PERFORM acs_permission__grant_permission(v_menu, v_employees, ''read'');
return 0;
end;' language 'plpgsql';
select inline_1 ();
drop function inline_1();
Get menu items for side menu:
[im_menu_ul_list -no_uls 1 "projects_admin" {}]
Setting Subnavbar:
# Setup the subnavbar
set bind_vars [ns_set create]
ns_set put $bind_vars project_id $project_id
set project_menu_id [db_string parent_menu "select menu_id from im_menus where label='project'" -default 0]
set sub_navbar [im_sub_navbar \
-components \
-base_url "/intranet/projects/view?project_id=$project_id" \
$project_menu_id \
$bind_vars "" "pagedesriptionbar" "project_timesheet_task"]
Setting menu label active:
set menu_label "reporting-finance-expenses"
Context Help
a) Add to [file].tcl
set show_context_help_p 1
b) Add to [file].adp
<property name="show_context_help_p">@show_context_help_p;noquote@</property>
AOL Server API
Avoid absolute file paths when using ‘ns_returnredirect’
ns_returnredirect "upload-files.tcl?inq_id=$security_token"
ns_returnfile 200 "application/zip" $filepath
ns_return 200 text/html 1
set result [ad_parse_template -params $params "/packages/intranet-core/www/related-objects-component"]
[ns_conn url] #returns for example: /intranet/projects
[im_url_with_query] # returns for example: /intranet/projects/view?project%5fid=34352
Portlet/Plugin
Create Plugin
SELECT im_component_plugin__new (
null, -- plugin_id
'acs_object', -- object_type
now(), -- creation_date
null, -- creation_user
null, -- creation_ip
null, -- context_id
'Home Random Portrait', -- plugin_name
'intranet-core', -- package_name
'right', -- location
'/intranet/index', -- page_url
null, -- view_name
5, -- sort_order
'im_random_employee_component' -- component_tcl
);
Set permissions for plugin
select plugin_id
into v_plugin_id
from im_component_plugins pl
where plugin_name = ''Requests for Quote'';
PERFORM im_grant_permission(v_plugin_id, v_cust_id, ''read'');
Workflow
Actions
im_workflow__set_object_status_id
im_workflow__assign_to_owner
Templates / Control structures in ADP pages
VAR replacements
<%= [eval ad_context_bar $context_bar] %>
Control Structures & Loops
<multiple name="user_stuff">
<if @user_stuff.age@ le 21>
<tr bgcolor="red">
</if>
<else>
<tr bgcolor="green">
</else>
<td>@user_stuff.user_name@</td>
<td>@user_stuff.age@</td>
<td>@user_stuff.shoesize@</td>
</tr>
</multiple>
Callbacks
Define Callback:
Callbacks require a callback definition in *-init.tcl:
Example: intranet-core-init.tcl
ad_proc -public -callback im_dynfield_attribute_after_update {
{-object_type:required}
{-attribute_name:required}
} {
Callback to be executed after an attribute has been changed
} -
Please note the hyphen at the end of the code!
Callback implementation:
Add the function to your [PACKAGE_NAME]-procs.tcl:
ad_proc -public -callback im_dynfield_attribute_after_update -impl intranet-core {
{-object_type:required}
{-attribute_name:required}
} {
<< EXPLAIN >>
} {
<< FUNCTION BODY >>
}
Callback Call
Place a call to the callback anywhere in your code
callback im_dynfield_attribute_after_update -object_type "im_project" -attribute_name "christmas_card"
Include JS/CSS ( ]po[ V4.0 )
template::head::add_css -href "/intranet-sencha/css/ext-all.css" -media "screen" -order 1
template::head::add_javascript -src "/intranet-sencha/js/ext-all-debug-w-comments.js" -order 1
Parameters
UPDATE
apm_parameter_values
SET
attr_value=0
WHERE
parameter_id in (
select
parameter_id
from
apm_parameters
where
parameter_name = 'SuppressHttpPort' and
package_key = 'acs-tcl'
)
Notifications:
/intranet-helpdesk/www/new.tcl
notification::new \
-type_id [notification::type::get_type_id -short_name ticket_notif] \
-object_id $ticket_id \
-response_id “” \
-notif_subject $ticket_name \
-notif_text $message