Commit 00082115 authored by Frank Bergmann's avatar Frank Bergmann

- OpenACS 5.9

parent 6683f8d7
......@@ -11,14 +11,14 @@
<version name="1.1.3d4" url="http://openacs.org/repository/apm/packages/categories-1.1.3d4">
<owner url="mailto:timo@timohentschel.de">timo@timohentschel.de</owner>
<summary>Manage categories in category trees and let users map objects to categories.</summary>
<release-date>2013-09-08</release-date>
<release-date>2015-10-04</release-date>
<description format="text/html">Datamodel for category trees with supporting API and management pages. Provides a widget for
general categorization of arbitrary objects and tracks which package instances use which category trees. Also supports localization.</description>
<license>GPL</license>
<maturity>1</maturity>
<provides url="categories" version="1.1.3d4"/>
<requires url="acs-kernel" version="5.8.1"/>
<requires url="acs-kernel" version="5.9.0"/>
<callbacks>
......
......@@ -27,3 +27,9 @@ set catass_list [category::list::get_pretty_list \
-remove_link_eval "remove?cat=\$__category_id&object_id=$object_id" \
-remove_link_text "<b style=\"color: red\">X</b>" \
[category::get_mapped_categories $object_id]]
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -149,4 +149,9 @@ db_multirow -extend {url_one user_url new} content content "
global errorCode
set url_one $errorCode
}
}
\ No newline at end of file
}
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -28,3 +28,9 @@ db_foreach category_count "
}
category_tree::get_multirow -datasource categories -container_id [ad_conn subsite_id] -category_counts $counts
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -25,3 +25,9 @@ ad_form -extend -name catass -on_submit {
}
ad_returnredirect [get_referrer]
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -7,3 +7,9 @@ foreach category [category_tree::get_tree -all $tree_id $default_locale] {
lassign $category category_id category_name deprecated_p level
multirow append categories $category_name $level [string repeat "&nbsp;" [expr {2 * $level - 2}]]
}
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -43,3 +43,9 @@ ad_form -name tree_form \
ad_script_abort
}
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -12,3 +12,9 @@ category_tree::reset_translation_cache
category_tree::reset_cache
ad_schedule_proc -thread t -schedule_proc ns_schedule_daily [list 0 16] category_synonym::search_sweeper
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -547,3 +547,9 @@ ad_proc -private category::before_uninstall {} {
acs_sc::impl::delete -contract_name AcsObject -impl_name category_idhandler
acs_sc::impl::delete -contract_name AcsObject -impl_name category_tree_idhandler
}
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -107,3 +107,9 @@ ad_proc -public category::ad_form::fill_widgets {
set my_category_ids $categories
}
}
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -34,3 +34,9 @@ ad_proc -public category_link::delete { link_id } {
} {
db_exec_plsql delete_category_link ""
}
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -148,7 +148,7 @@ ad_proc -public category::list::get_pretty_list {
foreach category $sorted_categories {
lassign $category category_id category_name tree_id tree_name
set category_name [ad_quotehtml $category_name]
set category_name [ns_quotehtml $category_name]
if {$category_link_eval ne ""} {
set category_link [uplevel $uplevel concat $category_link_eval]
}
......@@ -167,7 +167,7 @@ ad_proc -public category::list::get_pretty_list {
if {$result ne ""} {
append result $tree_delimiter
}
set tree_name [ad_quotehtml $tree_name]
set tree_name [ns_quotehtml $tree_name]
if {$tree_link_eval ne ""} {
set tree_link [uplevel $uplevel concat $tree_link_eval]
}
......@@ -318,7 +318,7 @@ ad_proc -public category::list::prepare_display {
foreach category $tree_categories($tree_id) {
lassign $category category_id category_name
set category_name [ad_quotehtml $category_name]
set category_name [ns_quotehtml $category_name]
if {$category_link_eval ne ""} {
set category_link [uplevel 1 concat $category_link_eval]
}
......@@ -539,3 +539,9 @@ ad_proc -public category::list::rewrite_query {
}
return $new_sql
}
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -93,3 +93,9 @@ ad_proc -private category::relation::get_meta_category_internal {
db_1row get_categories {}
return [list $object_id_one $object_id_two]
}
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -101,3 +101,9 @@ ad_proc -private category_synonym::search_sweeper {
} {
db_dml delete_old_searches ""
}
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -700,3 +700,9 @@ ad_proc -public category_tree::import {
return $tree_id
}
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -125,3 +125,9 @@ ad_proc -private ::category_tree::xml::add_category {
add_category -tree_id $tree_id -parent_id $category_id $child
}
}
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -85,3 +85,9 @@ ad_proc -public install::xml::action::map-category-tree { node } {
}
}
}
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -137,3 +137,9 @@ ad_proc -public category::tagcloud::get_tags {
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -77,3 +77,9 @@ aa_register_case category_delete {
aa_equals "category was deleted succesfully" $success_p 1
}
}
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -126,7 +126,7 @@ ad_proc -public template::widget::category {
foreach mapped_tree $mapped_trees {
lassign $mapped_tree tree_id tree_name subtree_id assign_single_p require_category_p widget
set tree_name [ad_quotehtml [lang::util::localize $tree_name]]
set tree_name [ns_quotehtml [lang::util::localize $tree_name]]
set one_tree [list]
if { $require_category_p == "t" } {
......@@ -137,7 +137,7 @@ ad_proc -public template::widget::category {
foreach category [category_tree::get_tree -subtree_id $subtree_id $tree_id] {
lassign $category category_id category_name deprecated_p level
set category_name [ad_quotehtml [lang::util::localize $category_name]]
set category_name [ns_quotehtml [lang::util::localize $category_name]]
if { $level>1 } {
set category_name "[string repeat "&nbsp;" [expr {2*$level -4}]]..$category_name"
}
......@@ -293,3 +293,9 @@ ad_proc -public template::data::transform::category { element_ref } {
return $values
}
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -26,3 +26,9 @@ db_transaction {
}
ad_returnredirect [export_vars -no_empty -base tree-view {tree_id locale object_id ctx_id}]
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -62,3 +62,9 @@ template::list::create \
}
ad_return_template
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -59,3 +59,9 @@ ad_form -name category_form -action category-form \
}
ad_return_template
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -94,3 +94,9 @@ template::list::create \
}
ad_return_template
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -26,3 +26,9 @@ db_transaction {
}
ad_returnredirect [export_vars -no_empty -base category-links-view {category_id tree_id locale object_id ctx_id}]
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -30,3 +30,9 @@ db_transaction {
}
ad_returnredirect [export_vars -no_empty -base category-links-view {category_id tree_id locale object_id ctx_id}]
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -58,3 +58,9 @@ template::list::create \
}
ad_return_template
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -26,3 +26,9 @@ db_transaction {
}
ad_returnredirect [export_vars -no_empty -base category-links-view {category_id tree_id locale object_id ctx_id}]
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -81,3 +81,9 @@ template::list::create \
}
ad_return_template
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -105,3 +105,9 @@ multirow foreach category_links {
}
ad_return_template
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -18,3 +18,9 @@ permission::require_permission -object_id $tree_id -privilege category_tree_writ
category::change_parent -tree_id $tree_id -category_id $category_id -parent_id $parent_id
ad_returnredirect [export_vars -no_empty -base tree-view {tree_id locale object_id ctx_id}]
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -67,3 +67,9 @@ template::list::create \
}
ad_return_template
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -21,3 +21,9 @@ db_transaction {
category_tree::flush_cache $tree_id
ad_returnredirect [export_vars -no_empty -base tree-view { tree_id locale object_id ctx_id}]
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -21,3 +21,9 @@ db_transaction {
category_tree::flush_cache $tree_id
ad_returnredirect [export_vars -no_empty -base tree-view { tree_id locale object_id ctx_id}]
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -91,3 +91,9 @@ set object_count [paginator get_row_count $p_name]
set page_count [paginator get_page_count $p_name]
ad_return_template
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -75,3 +75,9 @@ list::create \
-elements $elements
set create_url [export_vars -no_empty -base tree-form { locale }]
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -31,3 +31,9 @@ ad_form -name locale_form -action [ad_conn url] \
-form {
{locale:text(select),optional {label "Language"} {value $locale} {options $languages}}
}
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -109,3 +109,9 @@ template::list::create \
set create_url [export_vars -no_empty -base tree-form { locale object_id ctx_id }]
ad_return_template
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -10,3 +10,9 @@ ad_page_contract {
}
ad_returnredirect [export_vars -no_empty -base object-map { locale object_id }]
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -31,3 +31,9 @@ set admin_p [permission::permission_p -object_id $package_id -privilege category
set sw_tree_p [ad_decode $tree(site_wide_p) f 0 1]
ad_return_template
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -17,3 +17,9 @@ permission::require_permission -object_id $package_id -privilege category_admin
db_dml toggle_site_wide_status ""
ad_returnredirect [export_vars -no_empty -base permission-manage {tree_id locale object_id}]
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -26,3 +26,9 @@ db_transaction {
}
ad_returnredirect [export_vars -no_empty -base synonyms-view {category_id tree_id locale object_id ctx_id}]
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -50,3 +50,9 @@ template::list::create \
}
ad_return_template
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -61,3 +61,9 @@ ad_form -name synonym_form -action synonym-form -export { category_id tree_id lo
}
ad_return_template
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -96,3 +96,9 @@ multirow foreach synonyms {
}
ad_return_template
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -19,3 +19,9 @@ permission::require_permission -object_id $tree_id -privilege category_tree_writ
category_tree::copy -source_tree $source_tree_id -dest_tree $target_tree_id
ad_returnredirect [export_vars -no_empty -base tree-view {tree_id locale object_id ctx_id}]
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -60,3 +60,9 @@ template::list::create \
}
ad_return_template
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -65,3 +65,9 @@ template::list::create \
}
ad_return_template
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -28,3 +28,9 @@ if {![info exists object_id]} {
} else {
ad_returnredirect [export_vars -no_empty -base object-map {locale object_id ctx_id}]
}
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -67,3 +67,9 @@ template::list::create \
}
ad_return_template
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -32,3 +32,9 @@ if { [info exists object_id] } {
[_ categories.cadmin]]]
}
lappend context_bar $page_title
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -82,3 +82,9 @@ ad_form -name tree_map_form -action tree-map-2 -export { tree_id category_id loc
}
ad_return_template
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -60,3 +60,9 @@ template::list::create \
}
ad_return_template
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -79,3 +79,9 @@ if {$count != $last_ind} {
}
ad_returnredirect [export_vars -no_empty -base tree-view {tree_id locale object_id ctx_id}]
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -22,3 +22,9 @@ if {$tree(site_wide_p) == "f"} {
category_tree::unmap -tree_id $tree_id -object_id $object_id
ad_returnredirect [export_vars -no_empty -base object-map {locale object_id ctx_id}]
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -39,3 +39,9 @@ set tree_name $tree(tree_name)
set context_bar [list $object_context [list [export_vars -no_empty -base object-map {locale object_id ctx_id}] [_ categories.cadmin]] "Unmap \"$tree_name\""]
ad_return_template
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -53,3 +53,9 @@ foreach instance $instance_list {
}
ad_return_template
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -2,6 +2,7 @@
<property name="page_title">@page_title;literal@</property>
<property name="context_bar">@context_bar;literal@</property>
<property name="locale">@locale;literal@</property>
<property name="tree_id">@tree_id;literal@</property>
<include src="/packages/categories/lib/tree-form" &="tree_id" &="locale" &="ctx_id">
......
......@@ -160,3 +160,9 @@ template::list::create \
-bulk_action_export_vars { tree_id locale object_id ctx_id}
ad_return_template
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -21,3 +21,9 @@ foreach tid $tree_id {
}
ad_return_template
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -179,3 +179,9 @@ set object_count [paginator get_row_count $p_name]
set page_count [paginator get_page_count $p_name]
ad_return_template
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
<property name="context">{/doc/categories {Categories}} {Categories}</property>
<property name="doc(title)">Categories</property>
<master>
<h2>Categories</h2>
<a href="o">Object Names and IdHandler Service Contract</a>
<h3>Functionality overview</h3>
Categories are organized in separate category trees.<br>
When a package admin clicks on an Administer Categories link, they
are presented with a page that shows the following items:
<ul>
<li>list of trees currently mapped to the object (this "object"
will be usually a package instance)</li><li>list of trees that can be mapped to the object , those trees
are just the trees that the admin has the 'category_read'
permission on</li><li>link to create and map a new category tree</li>
</ul>
Creating a new tree involves entering tree name and description.
The name must be unique among all the trees.<br>
Upon creation of a tree, the admin is granted the 'category_read'
and 'category_write' permisssions.<br>
Normally, the category_write permission should not be shared with
anybody else, in the rare cases when granting this permission to
another party is needed, site-wide admin intervention will be
required.
<p>In addition to mapping an entire tree to an object, admins have
the option of mapping only a subtree of an existing tree. To do
that, they have to click on a "Map subtree" link, after which they
will see a list of tree nodes.<br>
The mapped subtree will consist of all subcategories of the
category the user selected - the category itself will not be
included. Note that the mapped subtree will not be a new tree.
Therefore this option should be used only if an admin plans to use
the subtree 'as is' and has no intention of making changes to
it.</p>
<p>An alternative solution is available for admins who want to
create a tree by copying one of the existing trees and subsequently
playing around with it (moving/adding/deleting categories). To
accomplish that, they would have to create a new tree, go to the
admin page for this tree and click on a "Copy existing tree" link.
They will see a list of available trees to copy. Clicking on the
"Copy this one" link will result in creating copies of the
categories from the source trees and placing them in the new
tree.<br>
This operation can be performed several times, each time the copied
categories will be placed as toplevel categories of the tree.</p>
<p>As far as unmapping is concerned, this operation doesn't delete
the mapping between categories and objects.</p>
<p><b>Permissions</b></p>
<p>The creator of the category tree is granted the
category_tree_read, category_tree_write and
category_tree_grant_permissions privileges.<br>
</p>
<p><b>The operations one can perform on categories are:</b></p>
<ul>
<li>(a) changing of a parent</li><li>(b) adding childen</li><li>(c) deleting</li><li>(d) editing</li><li>(e) phasing in/out</li><li>(f) changing sort key</li>
</ul>
<p>ad (d) You cannot delete a category that has children. Also, you
cannot delete a category that has objects mapped to it (do we want
it or not?)<br>
ad (e) The effect of phasing out a category is that users no longer
will be able to associate objects with it, but existing
associations will still be visible<br>
Deletions and phasing it/out can be performed as bulk
operations.<br>
ad (f) sort key is used to order children of the same parent
category, that is the elements of the tree are sorted first by
parent, then by the sort key.</p>
<hr>
<b>Datamodel</b>
<p>This table actually stores the information whether the tree is
side-wide or not.</p>
<pre>
create table category_trees (
tree_id integer primary key
constraint cat_trees_tree_id_fk
references acs_objects on delete cascade,
site_wide_p char(1) default 't'
constraint cat_trees_site_wide_p_ck
check (site_wide_p in ('t','f'))
);
</pre>
<p>Here the tree's name and description is stored in different
translations.</p>
<pre>
create table category_tree_translations (
tree_id integer
constraint cat_tree_trans_tree_id_fk
references category_trees on delete cascade,
locale varchar2(5) not null
constraint cat_tree_trans_locale_fk
references ad_locales,
name varchar2(50) not null,
description varchar2(1000),
primary key (tree_id, locale)
);
</pre>
<p>This table stores the tree hierarchy by holding the information
about the parent category. The tree is ordered by a nested index
(left_ind, right_ind). Sorting is thus accomplished by means of a
nested set. You can read a <a href="http://www.intelligententerprise.com/001020/celko.jhtml?_requestid=49180">
description of how nested sets work</a>. This also <i>describes how
to write queries that sort correctly when using categories</i>.</p>
<pre>
create table categories (
category_id integer primary key
constraint cat_category_id_fk
references acs_objects on delete cascade,
tree_id integer
constraint cat_tree_id_fk
references category_trees on delete cascade,
parent_id integer
constraint cat_parent_id_fk
references categories,
deprecated_p char(1) default 'f'
constraint cat_deprecated_p_ck
check (deprecated_p in ('t','f')),
left_ind integer,
right_ind integer
);
</pre>
<p>Here the actual categories are stored together with different
translations.</p>
<pre>
create table category_translations (
category_id integer
constraint cat_trans_category_id_fk
references categories on delete cascade,
locale varchar2(5) not null
constraint cat_trans_locale_fk
references ad_locales,
name varchar2(200),
description varchar2(4000),
primary key (category_id, locale)
);
</pre>
<p>This table contains mapping between categories and objects</p>
<pre>
create table category_object_map (
category_id integer
constraint cat_object_map_category_id_fk
references categories on delete cascade,
object_id integer
constraint cat_object_map_object_id_fk
references acs_objects on delete cascade,
primary key (object_id, category_id)
) organization index;
</pre>
<p>This is the table for the relation of trees and objects.
subtree_category_id comes to play in situations when you map a
subtree of an existing tree to an object.</p>
<pre>
create table category_tree_map (
tree_id integer
constraint cat_tree_map_tree_id_fk
references category_trees on delete cascade,
object_id integer
constraint cat_tree_map_object_id_fk
references acs_objects on delete cascade,
subtree_category_id integer default null
constraint cat_tree_map_subtree_id_fk
references categories,
primary key (object_id, tree_id)
) organization index;
</pre>
<hr>
<p><b>Known Limitations</b></p>
<ul>
<li>The tree order is the same for all translations.</li><li>You can map a tree only once to a package (or other
object).</li><li>The number of objects mapped to a category is not shown yet.
These results should be cached.</li><li>When browsing categories all mapped categories should be shown
for each object.</li><li>There should be browsing widget easily used by other packages
to let the user browse through all categorized objects.</li>
</ul>
<hr>
<p><b>Integration with other packages</b></p>
<p>Here are the changes needed to be made to integrate with other
packages.</p>
<p>
<b>index.adp</b><br>
Provide an admin-link to
/categories/cadmin/one-object?object_id=\@package_id\@ to let admins
map trees to the package instance.</p>
<p>
<b>form-page.tcl</b><br>
Use this in ad_form to display all mapped category trees and
selected categories (if editing an object):</p>
<pre>
{category_ids:integer(category),multiple,optional {label "Categories"}
{html {size 4}} {value {$object_id $package_id}}}
</pre>
Alternatively, you can include the following in your adp:
<pre>
&lt;include src="/packages/categories/www/include/widget" object_id=\@object_id\@ package_id=\@package_id\@&gt;
</pre>
In the processing part of ad_form use:
<pre>
category::map_object -remove_old -object_id $object_id $category_ids
</pre>
<hr>
<address><a href="mailto:timo\@studio-k4.de">timo\@studio-k4.de</a></address>
<property name="context">{/doc/categories {Categories}} {Categories}</property>
<property name="doc(title)">Categories</property>
<master>
<div class="article" lang="en">
<div class="titlepage"><div><div><h1 class="title">
<a name="categories" id="categories"></a>Categories</h1></div></div></div><div class="toc"><dl>
<dt><span class="sect1"><a href="install">Installation</a></span></dt><dt><span class="sect1"><a href="requirements">Requirements</a></span></dt>
</dl></div><p><a href="design" target="_top">Design Document</a></p><p><a href="o" target="_top">Object Names and IdHandler
Service Contract</a></p>
</div>
<h2>Release Notes</h2>
<p>Please file bugs in the <a href="http://openacs.org/bugtracker/openacs/">Bug Tracker</a>.</p>
<hr>
<address><a href="mailto:docs\@openacs.org">docs\@openacs.org</a></address>
<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Categories</title><meta name="generator" content="DocBook XSL Stylesheets V1.62.4"><link rel="home" href="index.html" title="Categories"><link rel="next" href="install.html" title="Installation"><link rel="stylesheet" href="openacs.css" type="text/css"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><a href="http://openacs.org"><img src="/doc/images/alex.jpg" border="0" alt="Alex logo"></a><table width="100%" summary="Navigation header" border="0"><tr><td width="20%" align="left"> </td><th width="60%" align="center"></th><td width="20%" align="right"> <a accesskey="n" href="install.html">Next</a></td></tr></table><hr></div><div class="article" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="categories"></a>Categories</h2></div></div><div></div><hr></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="install.html">Installation</a></span></dt><dt><span class="sect1"><a href="requirements.html">Requirements</a></span></dt></dl></div><p><a href="design.html" target="_top">Design Document</a> </p><p><a href="o.html" target="_top">Object Names and IdHandler Service Contract</a></p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"> </td><td width="20%" align="center"></td><td width="40%" align="right"> <a accesskey="n" href="install.html">Next</a></td></tr><tr><td width="40%" align="left"> </td><td width="20%" align="center"></td><td width="40%" align="right"> Installation</td></tr></table><hr><address><a href="mailto:docs@openacs.org">docs@openacs.org</a></address></div><a name="comments"></a><center><a href="http://openacs.org/doc/index.html#comments">View comments on this page at openacs.org</a></center></body></html>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta name="generator" content=
"HTML Tidy for Mac OS X (vers 31 October 2006 - Apple Inc. build 15.15), see www.w3.org">
<meta http-equiv="Content-Type" content=
"text/html; charset=us-ascii">
<title>Categories</title>
<meta name="generator" content="DocBook XSL Stylesheets V1.62.4">
<link rel="home" href="index.html" title="Categories">
<link rel="next" href="install.html" title="Installation">
<link rel="stylesheet" href="openacs.css" type="text/css">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084"
alink="#0000FF">
<div class="article" lang="en">
<div class="titlepage">
<div>
<div>
<h1 class="title"><a name="categories" id="categories"></a>Categories</h1>
</div>
</div>
<hr></div>
<div class="toc">
<dl>
<dt><span class="sect1"><a href=
"install.html">Installation</a></span></dt>
<dt><span class="sect1"><a href=
"requirements.html">Requirements</a></span></dt>
</dl>
</div>
<p><a href="design.html" target="_top">Design Document</a></p>
<p><a href="o.html" target="_top">Object Names and IdHandler
Service Contract</a></p>
</div>
<h2>Release Notes</h2>
<p>Please file bugs in the <a href="http://openacs.org/bugtracker/openacs/">Bug Tracker</a>.</p>
<hr>
<address><a href=
"mailto:docs@openacs.org">docs@openacs.org</a></address>
</div>
</body>
</html>
<property name="context">{/doc/categories {Categories}} {Installation}</property>
<property name="doc(title)">Installation</property>
<master>
<include src="/packages/acs-core-docs/lib/navheader"
leftLink="index" leftLabel="Prev"
title=""
rightLink="requirements" rightLabel="Next">
<div class="sect1" lang="en">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="install" id="install"></a>Installation</h2></div></div></div><div class="authorblurb">
<p>by <a href="mailto:joel\@aufrecht.org" target="_top">Joel
Aufrecht</a>
</p>
OpenACS docs are written by the named authors, and may be edited by
OpenACS documentation staff.</div><p>Install normally via APM. Configure via</p>
</div>
<include src="/packages/acs-core-docs/lib/navfooter"
leftLink="index" leftLabel="Prev" leftTitle="Categories"
rightLink="requirements" rightLabel="Next" rightTitle="Requirements"
homeLink="index" homeLabel="Home"
upLink="index" upLabel="Up">
\ No newline at end of file
<property name="context">{/doc/categories {Categories}} {Object Names and IdHandler Service Contract}</property>
<property name="doc(title)">Object Names and IdHandler Service Contract</property>
<master>
<h2>Object Names and IdHandler Service Contract</h2>
<h3>Object Names</h3>
When presenting a list of objects in a package not native to the
objects (i.e. permissioning, community-member, category-usage)
there has to be a fast and easy way to figure out the name of
objects. Until now, this has been done by using something like
<pre>
acs_objects.name(object_id)
</pre>
which essential means that for every object to be displayed (and
since the mentioned pages are in no means scalable and therefore
are likely to display a huge amount of objects) this pl/sql proc
will have to figure out which package-specific pl/sql proc to call
which itself will do at least one query to get the object-name.
<p>Obviously, this is highly undesirable since it is not scalable
at all. Therefore, a new way had to be found to get the name of an
object:</p>
<pre>
-------------------
-- NAMED OBJECTS --
-------------------
create table acs_named_objects (
object_id integer not null
constraint acs_named_objs_pk primary key
constraint acs_named_objs_object_id_fk
references acs_objects(object_id) on delete cascade,
object_name varchar2(200),
package_id integer
constraint acs_named_objs_package_id_fk
references apm_packages(package_id) on delete cascade
);
create index acs_named_objs_name_ix on acs_named_objects (substr(upper(object_name),1,1));
create index acs_named_objs_package_ix on acs_named_objects(package_id);
begin
acs_object_type.create_type (
supertype =&gt; 'acs_object',
object_type =&gt; 'acs_named_object',
pretty_name =&gt; 'Named Object',
pretty_plural =&gt; 'Named Objects',
table_name =&gt; 'acs_named_objects',
id_column =&gt; 'object_id'
);
end;
/
show errors
</pre>
This means that every displayable object-type should no longer be
derived from acs_objects, but from acs_named_objects and that by
using triggers or extending the appropriate pl/sql procs, every
displayable object (certainly not acs_rels or something the like)
should have an evtry in that extension of the acs_objects table.
<p>In that way, when having to display a list of objects, one can
simply join the acs_named_objects table to get the names and
package_ids in an easy and - more importantly - fast and scalable
way.</p>
<p>The only shortcomming of this solution is the disregard of
internationalization, but in cases where there objects in more than
one language, it should be the triggers / pl/sql procs task to make
sure that acs_named_objects contains names in the default language
if possible.</p>
<h3>IdHandler Service Contract</h3>
Besides displaying the names of objects, some pages also want to
provide links to the objects. Unfortunately, there currently is no
way to do so.
<p>First, we need to know that package_id of the package
responsible for the object. This information is currently
impossible to get since we would need to go up the context
hierarchy until we finally get hold of an apm_package object. But
lets assume we get this information by using the new
acs_named_objects table, then we would need to figure out the url
to that package instance. This can be done, but again by calling a
highly unefficient pl/sql proc. But even then we would need the
local url to the page being able to display a certain object. Since
a package may have more than one type of objects (i.e. file
folders, files, file versions), we can not simply store additional
package information about which page to call to display an
object.</p>
<p>The solution to this kind of problem is by not resolving the url
at all during display-time, but doing so at the time the user
actually wants to see an object. The links would simply direct to
/o/$object_id, which is a global virtual-url-handling page that
will figure out the package instance url (by using
acs_named_objects and the pl/sql proc) and then relying upon a
Service Contract to get the local url - that means every package
holding displayable objects should implement this interface for its
objects:</p>
<pre>
declare
v_id integer;
begin
v_id := acs_sc_contract.new(
contract_name =&gt; 'AcsObject',
contract_desc =&gt; 'Acs Object Id Handler'
);
v_id := acs_sc_msg_type.new(
msg_type_name =&gt; 'AcsObject.PageUrl.InputType',
msg_type_spec =&gt; 'object_id:integer'
);
v_id := acs_sc_msg_type.new(
msg_type_name =&gt; 'AcsObject.PageUrl.OutputType',
msg_type_spec =&gt; 'page_url:string'
);
v_id := acs_sc_operation.new(
contract_name =&gt; 'AcsObject',
operation_name =&gt; 'PageUrl',
operation_desc =&gt; 'Returns the package specific url to a page
that displays an object',
operation_iscachable_p =&gt; 'f',
operation_nargs =&gt; 1,
operation_inputtype =&gt; 'AcsObject.PageUrl.InputType',
operation_outputtype =&gt; 'AcsObject.PageUrl.OutputType'
);
v_id := acs_sc_impl.new (
'AcsObject',
'apm_package_idhandler',
'acs-kernel'
);
v_id := acs_sc_impl.new_alias (
'AcsObject',
'apm_package_idhandler',
'PageUrl',
'apm_pageurl',
'TCL'
);
acs_sc_binding.new (
contract_name =&gt; 'AcsObject',
impl_name =&gt; 'apm_package_idhandler'
);
v_id := acs_sc_impl.new (
'AcsObject',
'user_idhandler',
'acs-kernel'
);
v_id := acs_sc_impl.new_alias (
'AcsObject',
'user_idhandler',
'PageUrl',
'acs_user::pageurl',
'TCL'
);
acs_sc_binding.new (
contract_name =&gt; 'AcsObject',
impl_name =&gt; 'user_idhandler'
);
end;
</pre>
The appropriate tcl-procs look like the following:
<pre>
ad_proc -public apm_pageurl { object_id } {
Service Contract Proc to resolve a url for a package_id
} {
return
}
namespace eval acs_user {
ad_proc -public pageurl { object_id } {
Service Contract Proc to resolve a url for a user_id
} {
return "shared/community-member?user_id=$object_id"
}
}
</pre>
Note that the name of the implementation has to be the object-type
followed by _idhandler.
<hr>
<address><a href="mailto:timo\@studio-k4.de">timo\@studio-k4.de</a></address>
<property name="context">{/doc/categories {Categories}} {Requirements}</property>
<property name="doc(title)">Requirements</property>
<master>
<include src="/packages/acs-core-docs/lib/navheader"
leftLink="install" leftLabel="Prev"
title=""
rightLink="" rightLabel="">
<div class="sect1" lang="en">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="requirements" id="requirements"></a>Requirements</h2></div></div></div><div class="authorblurb">
<p>by <a href="mailto:joel\@aufrecht.org" target="_top">Joel
Aufrecht</a>
</p>
OpenACS docs are written by the named authors, and may be edited by
OpenACS documentation staff.</div><div class="sect2" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="requirements-introduction" id="requirements-introduction"></a>Introduction</h3></div></div></div><p>Automated Testing provides a framework for executing tests of
all varieties and for storing and viewing the results.</p>
</div><div class="sect2" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="gatekeeper-functional-requirements" id="gatekeeper-functional-requirements"></a>Functional
Requirements</h3></div></div></div><div class="informaltable"><table cellspacing="0" border="1">
<colgroup>
<col><col><col><col>
</colgroup><thead><tr>
<th><span class="strong">Req #</span></th><th><span class="strong">Status in 5.0</span></th><th><span class="strong">Priority for 5.1 (A=required,
B=optional)</span></th><th><span class="strong">Description</span></th>
</tr></thead><tbody>
<tr>
<td>1</td><td>Done</td><td>Done</td><td>Store trees of category labels</td>
</tr><tr>
<td>1.1</td><td>?</td><td>A</td><td>Category is package-aware. (Data in one package is not visible
from another package. There is a permission-based way to accomplish
this, but it is not obvious in the UI.)</td>
</tr><tr>
<td>2</td><td>Done</td><td>Done</td><td>There is a GUI for administrators to manage category trees
(create, delete, move leaves, edit leaves).</td>
</tr><tr>
<td>3</td><td>Done</td><td>Done</td><td>An OpenACS Object can be associated with zero, one, or more
categories.</td>
</tr><tr>
<td>3.1</td><td>partial</td><td>A</td><td>There is a GUI to control which categories are associated with
an object.</td>
</tr><tr>
<td>3.1.1</td><td>Done</td><td>Done</td><td>A package administrator can choose which category trees apply
to a package or parent object. The list of category trees which
apply to an object or its parent is called the <span class="emphasis"><em>enabled tree</em></span> list.</td>
</tr><tr>
<td>3.1.2</td><td>Done</td><td>Done</td><td>There is a facility to control object/category association.
(via /categories/www/form-page.tcl.)</td>
</tr><tr>
<td>3.1.3</td><td> </td><td>Done</td><td>The <span class="emphasis"><em>enabled trees</em></span> for an
object can be added as fields in form builder. (Current ad_form
implementation supports single select and multiple select; all
enabled trees or none. <tt class="computeroutput">/categories/www/widget</tt> is a deprecated
solution.)</td>
</tr><tr>
<td>3.1.4</td><td> </td><td>B</td><td>A GUI for linking any category (even one not in the
<span class="emphasis"><em>enabled trees</em></span>) to an
object.</td>
</tr><tr>
<td>3.2</td><td>partial</td><td>A</td><td>A GUI to see an object's categories.</td>
</tr><tr>
<td>3.2.1</td><td> </td><td>A</td><td>All of the categories which an object belongs to can be
displayed via an includelet on an object view page. (<tt class="computeroutput">/categories/www/widget</tt>)</td>
</tr><tr>
<td>4</td><td> </td><td>A</td><td>List-builder can sort and filter by category. (Implemented; not
documented. single-select only.)</td>
</tr><tr>
<td>5</td><td>partial</td><td>A</td><td>Show all objects in a category. The current implementation is
deprecated - see <a href="http://openacs.org/forums/message-view?message_id=158903" target="_top">TIP #44: Service Contract to resolve the url from an
object_id</a> and <a href="http://openacs.org/forums/message-view?message_id=158875" target="_top">TIP #43: Adding object_name to acs_objects</a>
</td>
</tr>
</tbody>
</table></div>
</div><div class="sect2" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="id2831234" id="id2831234"></a>References</h3></div></div></div><div class="itemizedlist"><ul type="disc"><li><p><a href="http://openacs.org/forums/message-view?message_id=153265" target="_top">Forum Posting</a></p></li></ul></div>
</div><div class="sect2" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="revisions-history" id="revisions-history"></a>Revision History</h3></div></div></div><div class="informaltable"><table cellspacing="0" border="1">
<colgroup>
<col><col><col><col>
</colgroup><thead><tr>
<th><span class="strong">Document Revision #</span></th><th><span class="strong">Action Taken, Notes</span></th><th><span class="strong">When?</span></th><th><span class="strong">By Whom?</span></th>
</tr></thead><tbody><tr>
<td>1</td><td>Creation</td><td>18 Jan 2004</td><td>Joel Aufrecht</td>
</tr></tbody>
</table></div>
</div>
</div>
<include src="/packages/acs-core-docs/lib/navfooter"
leftLink="install" leftLabel="Prev" leftTitle="Installation"
rightLink="" rightLabel="" rightTitle=""
homeLink="index" homeLabel="Home"
upLink="index" upLabel="Up">
<center><a href="http://openacs.org/doc/requirements.html#comments">View comments
on this page at openacs.org</a></center>
......@@ -30,3 +30,9 @@ foreach tree [category_tree::get_mapped_trees $package_id] {
template::multirow append trees $tree_id $tree_name $category_id $selected_p $category_name $indent $assign_single_p $require_category_p
}
}
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -54,3 +54,9 @@ ad_form -name search_form -action . -form {
}
ad_return_template
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
......@@ -41,3 +41,9 @@ template::list::create \
}
ad_return_template
# Local variables:
# mode: tcl
# tcl-indent-level: 4
# indent-tabs-mode: nil
# End:
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