Index: openacs-4/contrib/obsolete-packages/library/library.info
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/library.info,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/library.info 2 Jul 2003 12:19:40 -0000 1.1
@@ -0,0 +1,390 @@
+
+
+
+
+ Library
+ Libraries
+ f
+ f
+
+
+
+ oracle
+ postgresql
+
+ Dirk Gomez
+ Red Hat Knowledge Library for ACS4.0
+ Red Hat Knowledge Library for ACS4.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: openacs-4/contrib/obsolete-packages/library/license.txt
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/license.txt,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/license.txt 2 Jul 2003 12:19:40 -0000 1.1
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ , 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
Index: openacs-4/contrib/obsolete-packages/library/readme.txt
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/readme.txt,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/readme.txt 2 Jul 2003 12:19:40 -0000 1.1
@@ -0,0 +1,6 @@
+Knowledge Management Package
+
+This package is based on the commercial acs version from the year 2000.
+You can define different knowledge objects, questions and link the information variable.
+It is not tested with the openacs version 4.6.3.
+
Index: openacs-4/contrib/obsolete-packages/library/sql/oracle/library-create.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/sql/oracle/library-create.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/sql/oracle/library-create.sql 2 Jul 2003 12:19:42 -0000 1.1
@@ -0,0 +1,994 @@
+
+--
+-- packages/library/sql/library-create.sql
+--
+-- Credit for the ACS 3 version of this module goes to:
+-- @author Branimir Dolicki (branimir@arsdigita.com)
+-- @author Carsten Clasohm (carsten@arsdigita.com)
+-- @author Sarah Arnold (zylonne@web.de)
+--
+-- The upgrade of this module to ACS 4 was done by
+-- @author Dirk Gomez (dirk@arsdigita.com)
+-- in June/July 2001.
+--
+-- @creation-date 22-June 2001
+-- @cvs-id $Id: library-create.sql,v 1.1 2003/07/02 12:19:42 peterm Exp $
+
+-- Changes, (at least those made by me) in reverse chronological order
+
+-- (bran 006) 2001-09-18 Moved everything having to do with linking to a --
+-- separate package - sn_links. So basically changes 001, 002, 004 and 005 are
+-- there and not here but in packages/sn-links/sql/oracle/sn-links.
+
+-- (bran 005) 2001-09-12 As we are using the low-tech approach w/o objects we
+-- need a sequence to generate link_id's.
+
+-- (bran 004) 2001-09-10 There ain't gonna be any stinkin' objects here. Links
+-- are just rows in a table. Period. Removed acs_object_type.create_type. Same
+-- goes for acs_rel_type.create_role and friends
+
+-- (bran 003) 2001-09-10 Removed question_id from sn_links because it is
+-- library-specific. We have a new table in library:
+-- sn_question_link_map
+
+-- (bran 002) 2001-09-10 Removed the sn_link_comments table and put that stuff
+-- into sn_links. Finally we admit that it doesn't make sense to have one comment
+-- on two links!
+
+-- (bran 001) 2001-09-10 Removed the link_type_id column from sn_link_types.
+-- We are now refering to link types by link_type and not by link_type_id.
+
+------------------------------------------------------------------------------
+-- The questions table holds all of the data about the kinds of
+-- questions that can be asked about a knowledge object.
+
+create table sn_questions (
+ question_id
+ integer
+ constraint sn_questions_question_id_fk
+ references acs_objects (object_id)
+ constraint sn_questions_question_id_pk
+ primary key,
+ pretty_name
+ varchar(4000),
+ abstract_data_type
+ varchar(50)
+ constraint sn_questions_abstract_data_nn not null,
+ presentation_type
+ varchar(100)
+ constraint sn_questions_presentation_t_nn not null,
+ -- for all questions which display lists
+ order_by
+ varchar(100),
+ -- default for input forms
+ default_value
+ varchar(4000),
+ entry_explanation
+ varchar(4000),
+ tag_width
+ integer,
+ tag_height
+ integer,
+ help_text
+ varchar(4000),
+ -- for object_link: which type to link to
+ target_object_type_id
+ integer,
+ -- that is merged in from a change I (and Carsten ;) already did in
+ -- 7.1
+ defaults_question_id
+ integer default null
+ constraint sn_questions_defaults_qu_id_fk
+ references sn_questions(question_id),
+ references_question_id
+ integer
+ constraint sn_questions_referenc_qu_id_fk
+ references sn_questions(question_id),
+ -- for question of data type category
+ tree_id
+ integer
+ constraint sn_questions_tree_ref references generic_trees,
+ node_id
+ integer
+ constraint sn_questions_node_ref references sw_category_dim,
+ browse_p
+ varchar(1) default 't'
+ constraint sn_questions_browse_p_ck
+ check (browse_p in ('t','f')),
+ -- This is only used during data migration from ShareNet 7.
+ category_id
+ integer,
+ max_categories
+ integer default null,
+ -- this is only for abstract_data_type date to specify what years
+ -- should be in the select box in respect to the default date.
+ year_from
+ integer default -5,
+ year_to
+ integer default 5
+);
+
+
+begin
+ acs_object_type.create_type (
+ supertype => 'acs_object',
+ object_type => 'sn_question',
+ pretty_name => 'Question',
+ pretty_plural => 'Questions',
+ table_name => 'SN_QUESTIONS',
+ id_column => 'QUESTION_ID'
+ );
+end;
+/
+show errors
+
+insert into sn_questions (question_id, pretty_name, abstract_data_type, presentation_type)
+select object_id, name, 'dummy', 'dummy' from
+acs_magic_objects where name = 'km_dummy_object';
+
+------------------------------------------------------------------------------
+-- Together with sn_question_object_type_map, table sn_object_types defines
+-- the possible types of knowledge objects.
+
+create table sn_types_map_short_name (
+ object_type_id
+ integer,
+ short_description
+ integer
+ constraint sn_types_map_short_desc_id_fk
+ references sn_questions (question_id),
+ position
+ integer,
+ constraint sn_types_map_short_name_pk
+ primary key (object_type_id, short_description)
+);
+
+create table sn_object_types (
+ object_type_id
+ integer
+ constraint sn_object_types_pk
+ primary key,
+ context_id
+ constraint sn_object_types_context_id_fk
+ references apm_packages (package_id)
+ on delete cascade,
+ short_name
+ varchar(100),
+ pretty_name
+ varchar(100)
+ constraint sn_object_types_pretty_name_nn not null,
+ pretty_plural
+ varchar(100),
+ -- filename for the graphic icon. This is always
+ -- $object_type_id.extension
+ graphic
+ varchar(200),
+ graphic_p
+ char(1)
+ default 'f'
+ constraint sn_object_types_graphic_p_nn not null,
+ constraint sn_object_types_graphic_p_ck
+ check (graphic_p in ('t', 'f')),
+ deleted_p
+ char(1)
+ default 'f'
+ constraint sn_object_types_deleted_p_nn not null,
+ constraint sn_object_types_deleted_p_ck
+ check (deleted_p in ('t', 'f')),
+ browse_p
+ char(1)
+ default 't'
+ constraint sn_object_types_browse_p_nn not null,
+ constraint sn_object_types_browse_p_ck
+ check (browse_p in ('t', 'f')),
+ -- If the object type is not public, consult sn_object_type_access
+ -- to determine if a user may access this type.
+ public_p
+ char(1) default 't'
+ constraint sn_object_types_public_p_nn not null,
+ constraint sn_object_types_public_p_ck
+ check (public_p in ('t','f')),
+ -- to be able to prevent standalone objects of this object type
+ -- (meaning objects which didnt created as child or nephew)
+ -- needed this for people sharenet - demand descriptions
+ create_p
+ char(1) default 't'
+ constraint sn_object_types_create_p_nn not null,
+ constraint sn_object_types_create_p_ck
+ check (create_p in ('t','f')),
+ sort_key
+ integer,
+ -- The admin can define which question is the name, overview or
+ -- public_until date for this object type:
+ short_description
+ integer
+ constraint sn_object_typ_short_desc_id_fk
+ references sn_questions (question_id),
+ long_description
+ integer
+ constraint sn_object_type_long_desc_id_fk
+ references sn_questions (question_id),
+ public_until
+ integer
+ constraint sn_object_t_public_until_id_fk
+ references sn_questions (question_id),
+ -- these two links to date questions have been added for
+ -- people sharenet (project start/end date):
+ start_date
+ integer
+ constraint sn_object_t_start_date_id_fk
+ references sn_questions (question_id),
+ end_date
+ integer
+ constraint sn_object_t_end_date_id_fk
+ references sn_questions (question_id),
+ -- that is merged in from a change I (and Carsten ;) already did in
+ -- 7.1
+ linked_question_id
+ integer
+ constraint sn_object_t_linked_quest_id_fk
+ references sn_questions(question_id),
+ default_age_filter
+ integer default 365,
+ -- can objects of this type be archived?
+ archive_p
+ char(1)
+ default 'f'
+ constraint sn_object_types_archive_p_nn not null,
+ constraint sn_object_types_archive_p_ck
+ check (archive_p in ('t', 'f')),
+ -- are you allowed to copy objects of this type?
+ copy_p
+ char(1)
+ default 'f'
+ constraint sn_object_types_copy_p_nn not null,
+ constraint sn_object_types_copy_p_ck
+ check (copy_p in ('t', 'f')),
+ -- which sweeper should be checking for old objects?
+ -- outdated: objects haven't been modified for a certain time
+ -- expired: public_until date has been exceeded
+ sweeper
+ varchar(10)
+ default 'none'
+ constraint sn_object_types_sweeper_nn not null,
+ constraint sn_object_types_sweeper_ck
+ check (sweeper in ('none','outdated','expired')),
+ -- action to be performed on the objects by the sweeper
+ sweeper_action
+ varchar(10)
+ default 'private'
+ constraint sn_object_types_sw_action_nn not null,
+ constraint sn_object_types_sw_action_ck
+ check (sweeper_action in ('private','archive')),
+ -- if >0 a warning email will be sent if the object is outdated/expired
+ -- specifies the amount of days the action should be performed after
+ -- the warning email
+ sweeper_warning_time
+ integer
+ default 0
+ constraint sn_object_types_warning_nn not null,
+ -- specified the amount of days after which an unchanged objects is
+ -- regarded as outdated
+ sweeper_outdated_time
+ integer
+ default 30
+);
+
+
+begin
+ acs_object_type.create_type (
+ supertype => 'acs_object',
+ object_type => 'sn_object_type',
+ pretty_name => 'Object Type',
+ pretty_plural => 'Object Types',
+ table_name => 'SN_OBJECT_TYPES',
+ id_column => 'OBJECT_TYPE_ID'
+ );
+end;
+/
+show errors
+
+-- We can only add this foreign key after creating the object_type_table.
+alter table sn_questions
+ add constraint sn_questions_object_type_id_fk
+ foreign key (target_object_type_id)
+ references sn_object_types(object_type_id);
+
+alter table sn_types_map_short_name
+ add constraint sn_types_map_object_type_id
+ foreign key (object_type_id)
+ references sn_object_types(object_type_id);
+
+
+------------------------------------------------------------------------------
+-- This table holds the objects.
+
+create table sn_objects (
+ object_id
+ integer
+ constraint sn_objects_id_pk
+ primary key,
+ object_type_id
+ integer
+ constraint sn_objects_object_type_id_fk
+ references sn_object_types (object_type_id),
+ -- objects should be subsite-aware as well
+ context_id
+ constraint sn_objects_context_id_fk
+ references apm_packages (package_id)
+ on delete cascade,
+ one_line_description
+ varchar(4000),
+ overview
+ varchar(4000),
+ overview_html_p
+ char(1)
+ constraint sn_objects_overview_html_p_ck
+ check (overview_html_p in ('t','f')),
+ creation_date
+ date,
+ original_author_id
+ integer
+ constraint sn_objects_orig_author_id_fk
+ references users (user_id),
+ last_modified
+ date,
+ last_modifying_user_id
+ integer
+ constraint sn_objects_last_mod_user_id_fk
+ references users (user_id),
+ user_checkoff_date date,
+ -- id of last publisher (user with km_publish permission) (BPM)
+ publisher_id
+ integer
+ constraint sn_objects_publisher_id_fk
+ references users (user_id),
+ expiration_date
+ date default '9999-12-31'
+ constraint sn_objects_expiration_date_nn not null,
+ public_until date,
+ -- these two dates got added for people sharenet:
+ start_date date,
+ end_date date,
+ public_p
+ char(1) default 'f'
+ constraint sn_objects_public_p_ck
+ check (public_p in ('t','f')),
+ archived_p
+ char(1) default 'f'
+ constraint sn_objects_archived_p_ck
+ check (archived_p in ('t','f')),
+ -- to mark object (i.e. nephews) that should be reviewd (BPM)
+ in_review_p
+ char(1) default 'f'
+ constraint sn_objects_in_review_p_ck
+ check (in_review_p in ('t','f')),
+ access_total integer default 0,
+ access_month integer default 0,
+ -- date the object got archived
+ archiving_date
+ date
+ default null,
+ -- date a warning email got sent that object is outdated
+ outdated_warning_date
+ date
+ default null,
+ -- date a warning email got sent that object is expired (public_until)
+ expired_warning_date
+ date
+ default null
+);
+
+
+begin
+ acs_object_type.create_type (
+ supertype => 'acs_object',
+ object_type => 'sn_object',
+ pretty_name => 'Library Object',
+ pretty_plural => 'Library Objects',
+ table_name => 'SN_OBJECTS',
+ id_column => 'OBJECT_ID'
+ ); end;
+/
+show errors
+
+
+-- Create some indexes for performance.
+
+create index sn_objects_expiration_date_ix on sn_objects (expiration_date);
+
+create index sn_objects_public_until_ix on sn_objects (public_until);
+
+create index sn_objects_start_date_ix on sn_objects (start_date);
+
+create index sn_objects_end_date_ix on sn_objects (end_date);
+
+create index sn_objects_checkoff_date_ix on sn_objects (user_checkoff_date);
+
+create index sn_objects_last_modified_ix on sn_objects (last_modified);
+
+create index sn_objects_new_stuff_ix on sn_objects (last_modified,
+user_checkoff_date, expiration_date, object_type_id);
+
+create index sn_objects_type_id_ix on sn_objects (object_type_id);
+
+create index sn_objects_browse_ix on sn_objects (object_type_id, context_id, expiration_date, last_modified, public_p, archived_p, object_id);
+
+create index sn_objects_one_line_desc_ix on sn_objects (substr(upper(one_line_description),1,1));
+
+create index sn_objects_archived_p_ix on sn_objects (archived_p);
+
+create index sn_objects_o_warning_date_ix on sn_objects (outdated_warning_date);
+
+create index sn_objects_e_warning_date_ix on sn_objects (expired_warning_date);
+
+create index sn_object_publisher_id_ix on sn_objects (publisher_id);
+
+------------------------------------------------------------------------------
+-- This defines the set of questions associated with a given object
+-- type. Questions can be used in common between object types and grouped
+-- together under one parent_question_id for composite questions.
+create table sn_question_object_type_map (
+ question_id
+ integer
+ constraint sn_question_otm_question_id_fk
+ references sn_questions (question_id),
+ object_type_id
+ integer
+ constraint sn_question_otm_object_t_id_fk
+ references sn_object_types (object_type_id),
+ sort_key
+ integer,
+ form_number
+ integer,
+ mandatory_p
+ char(1)
+ constraint sn_question_otm_mandatory_p_ck
+ check (mandatory_p in ('t','f')),
+ question_state
+ varchar(100)
+ constraint sn_question_otm_question_st_ck
+ check(question_state in
+ ('active','deprecated','read-only','invisible')),
+ -- used for composite and branches
+ -- -50 is the magic object from acs_magic_objects where name='km_dummy_object'. Don't change it!
+ parent_question_id
+ integer
+ default -50
+ constraint sn_question_otm_parent_q_id_nn not null
+ constraint sn_question_otm_parent_q_id_fk
+ references sn_questions (question_id),
+ -- t if this question itself is a branch, NOT if this question LEADS to branches
+ branch_p
+ char(1)
+ constraint sn_question_otm_branch_p_ck
+ check (branch_p in ('t','f')),
+ -- applies to the question as the parent node of a branch
+ branch_operator
+ varchar(4000),
+ -- the answers apply to the child nodes
+ branch_answer
+ varchar(4000),
+ -- can reference categories or sn_answer_options
+ branch_answer_foreign_key
+ integer,
+ default_branch
+ integer
+ constraint sn_question_otm_default_bra_fk
+ references sn_questions (question_id),
+ constraint sn_question_object_type_map_pk
+ primary key (question_id, object_type_id)
+);
+
+------------------------------------------------------------------------------
+-- ***** Object Data *****
+
+-- This table stores the content of the one-to-one questions having abstract
+-- data type "text" for any given object.
+
+-- The questions_id shows which question the content answers. If a single
+-- question has more than one answer, then that data belongs in the
+-- multiple-choice answers tables (sn_answer_options and sn_object_option_map)
+-- having the abstract data type "multiple_choice" or should be constructed as
+-- composite question having the abstract data type "composite".
+
+create table sn_content (
+ object_id
+ integer
+ constraint sn_content_object_id_fk
+ references sn_objects(object_id),
+ question_id
+ integer
+ constraint sn_content_question_id_fk
+ references sn_questions(question_id),
+ content
+ clob,
+ html_p
+ char(1)
+ constraint sn_content_html_p_ck
+ check (html_p in ('t', 'f')),
+ constraint sn_content_pk
+ primary key (object_id, question_id)
+);
+
+------------------------------------------------------------------------------
+-- ***** Auditing *****
+-- Whenever the content of an object is changed then we store it here. We
+-- don't store changes in the categorization, linking or multiple choice
+-- questions.
+
+create table sn_audit_table (
+ object_id
+ integer
+ constraint sn_audit_table_object_id_fk
+ references sn_objects(object_id),
+ question_id
+ integer
+ constraint sn_audit_table_question_id_fk
+ references sn_questions(question_id),
+ --this refers to the question being modified
+ last_modified
+ date
+ constraint sn_audit_table_last_modifie_nn not null,
+ last_modifying_user_id
+ integer
+ constraint sn_audit_table_last_mo_u_id_fk
+ references users (user_id),
+ content
+ varchar(4000)
+);
+
+create index audit_table_ix on sn_audit_table(object_id);
+
+-- The ShareNet admins want to give a reason for object deletion to supervise
+-- the incentive system more efficiently.
+
+create table sn_object_delete_reasons (
+ object_id
+ integer
+ constraint sn_object_delete_rea_obj_id_fk
+ references sn_objects(object_id)
+ constraint sn_object_delete_reasons_pk
+ primary key,
+ reason_for_deleting
+ varchar(4000),
+ deleted_on
+ date default sysdate
+);
+
+-- For the archive
+
+create table sn_object_archive_reasons (
+ object_id
+ integer
+ constraint sn_object_archive_re_obj_id_fk
+ references sn_objects(object_id),
+ reason_for_archiving
+ varchar(4000),
+ archived_on
+ date default sysdate,
+ constraint sn_object_archive_reasons_pk
+ primary key (object_id, archived_on)
+);
+
+------------------------------------------------------------------------------
+-- This table holds the answers to multiple choice questions
+create table sn_answer_options (
+ option_id
+ integer
+ constraint sn_answer_options_option_id_pk
+ primary key,
+ question_id
+ integer
+ constraint sn_answer_options_questi_id_fk
+ references sn_questions(question_id),
+ answer_option
+ varchar(4000),
+ sort_key
+ integer
+);
+
+------------------------------------------------------------------------------
+-- This table links multiple-choice answers to objects
+create table sn_object_option_map (
+ object_id
+ integer
+ constraint sn_object_option_map_obj_id_fk
+ references sn_objects(object_id),
+ option_id
+ integer
+ constraint sn_object_option_map_opt_id_fk
+ references sn_answer_options(option_id)
+);
+
+------------------------------------------------------------------------------
+-- (bran 003)
+-- When linking was library-specific thing we
+-- had question_id column in the sn_links table.
+-- Now we have a special table which answers the
+-- question: "Given a link_id, to which question
+-- was the user answering when he created that link?"
+create table sn_question_link_map (
+ link_id
+ integer
+ constraint sn_question_link_ma_link_id_fk
+ references sn_links (link_id)
+ on delete cascade
+ constraint sn_question_link_map_pk
+ primary key,
+ question_id
+ integer
+ constraint sn_question_lin_question_id_fk
+ references sn_questions (question_id)
+ constraint sn_question_lin_question_id_nn
+ not null
+);
+
+create index sn_question_link_ma_q_id_ix on sn_question_link_map (question_id);
+
+------------------------------------------------------------------------------
+-- Excursions & Navigation
+
+create table km_path (
+ path_id
+ integer
+ constraint km_path_pk
+ primary key
+ constraint km_path_path_id_nn not null ,
+ last_path_id
+ integer,
+ action
+ varchar(100),
+ values_list
+ varchar(4000),
+ return_to
+ varchar(4000),
+ start_time
+ date
+);
+
+------------------------------------------------------------------------------
+-- access counting
+create table sn_access_counts (
+ object_id
+ integer
+ constraint sn_access_counts_object_id_fk
+ references sn_objects(object_id),
+ access_count
+ integer,
+ access_date
+ date,
+ constraint sn_access_counts_pk
+ primary key (object_id,access_date)
+);
+
+create index sn_access_counts_composite_ix on sn_access_counts (object_id,access_date,access_count);
+
+------------------------------------------------------------------------------
+-- For backwards compatibility. Old-style URLs looked like this:
+-- /library/browse-one-type.tcl?object_type=market
+-- and they need to be converted to /library/browse-one-type.tcl?object_type_id
+
+create table sn_table_name_map (
+ object_type_id
+ integer
+ constraint sn_table_name_map_pk
+ primary key,
+ context_id
+ constraint sn_table_name_map_cont_id_fk
+ references apm_packages (package_id)
+ on delete cascade,
+ object_type_name varchar(100)
+);
+
+------------------------------------------------------------------------------
+-- We're maintaining km_flat_object_hierarchy with triggers that fire
+-- on insert or delete from sn_links for link type parent_child.
+-- Since it's not allowed to access sn_links from triggers defined on it
+-- (table is mutating etc etc), we keep the copy of the relevant data in
+-- flat_object_hierarchy itself. Suppose we have following hierarchy:
+
+-- --------------
+-- 102
+-- 106
+-- 107
+-- 141
+-- 121
+-- --------------
+--
+-- From source sn_links table:
+
+-- SITE_WIDE_ID_A SITE_WIDE_ID_B
+-- ------------------ -----------------
+-- 102 106
+-- 106 107
+-- 141 121
+-- 102 141
+
+
+-- ... we arrive on flat_object_hierarchy
+
+
+-- PARENT CHILD DISTANCE
+-- --------- ---------- --------
+-- 141 121 1
+-- 102 121 2
+-- 102 141 1
+-- 102 106 1
+-- 102 107 2
+-- 106 107 1
+
+
+create table km_flat_object_hierarchy (
+ object_hierarchy_id
+ integer
+ constraint km_flat_object_hierarchy_id_pk
+ primary key,
+ parent
+ integer
+ constraint km_flat_object_hier_parent_nn not null
+ constraint km_flat_object_hier_parent_fk
+ references acs_objects (object_id),
+ child
+ integer
+ constraint km_flat_object_hier_child_nn not null
+ constraint km_flat_object_hier_child_fk
+ references acs_objects (object_id),
+ distance
+ integer,
+ link_type
+ varchar2(100),
+ constraint km_flat_object_hier_unique unique (parent, child)
+);
+
+create index km_flat_object_hier_child_ix on km_flat_object_hierarchy(child);
+
+
+------------------------------------------------------------------------------
+-- This table is pretty damn useful if you want to track long-running
+-- transaction. It is being filled by a pl/sql procedure that commits
+-- within a autonomous transaction.
+
+create table km_logger_table (
+ log_date
+ date
+ default sysdate,
+ who_is_logging
+ varchar2(4000),
+ log_text
+ varchar2(4000)
+);
+
+
+-----------------------------------------------------------------------------
+-- This table is for the library sweeper proc that takes care of outdated
+-- or expired objects and sets them to private or archive them if
+-- the user didn't take action after a warning email
+
+create table km_sweeper (
+ user_id
+ integer
+ constraint km_sweeper_user_id_fk
+ references users,
+ package_id
+ integer
+ constraint km_sweeper_package_id_fk
+ references apm_packages,
+ object_type_id
+ integer
+ constraint km_sweeper_obj_type_id_fk
+ references sn_object_types,
+ object_id
+ integer
+ constraint km_sweeper_object_id_fk
+ references sn_objects,
+ object_name
+ varchar2(4000),
+ content
+ varchar2(4000),
+ primary key (user_id, object_id)
+);
+
+-- this table holds the library sweeper emails for publishers
+create table km_sweeper_publisher (
+ user_id
+ integer
+ constraint km_sweeper_publ_user_id_fk
+ references users,
+ package_id
+ integer
+ constraint km_sweeper_publ_package_id_fk
+ references apm_packages,
+ object_type_id
+ integer
+ constraint km_sweeper_publ_obj_type_id_fk
+ references sn_object_types,
+ object_id
+ integer
+ constraint km_sweeper_publ_object_id_fk
+ references sn_objects,
+ object_name
+ varchar2(4000),
+ content
+ varchar2(4000),
+ primary key (user_id, object_id)
+);
+
+
+------------------------------------------------------------------------------
+create table km_library_searches (
+ km_library_searches_id
+ integer
+ constraint km_library_searches_id_pk
+ primary key,
+ user_id
+ integer
+ constraint km_library_searches_user_id_fk
+ references users (user_id),
+ name
+ varchar(200),
+ url_params
+ clob,
+ creation_date
+ date
+ default sysdate
+);
+
+create table km_advanced_search_settings (
+ search_id
+ integer
+ constraint km_advanced_ss_search_id_fk
+ references km_library_searches(km_library_searches_id),
+ parameter_key
+ varchar(4000),
+ parameter_value
+ clob
+);
+
+------------------------------------------------------------------------------
+create table sn_owner_history (
+ object_id
+ integer
+ constraint sn_own_hist_object_id_fk
+ references sn_objects(object_id),
+ change_user_id
+ integer
+ constraint sn_own_hist_change_user_id_fk
+ references users(user_id),
+ old_user_id
+ integer
+ constraint sn_own_hist_old_user_id_fk
+ references users(user_id),
+ new_user_id
+ integer
+ constraint sn_own_hist_new_user_id_fk
+ references users(user_id),
+ change_date
+ date,
+ reason
+ varchar(4000)
+);
+
+------------------------------------------------------------------------------
+-- th 2001-10-22 tables added for people sharenet: application form
+------------------
+create table psn_res_applications (
+ application_id integer primary key,
+ object_id constraint psn_res_app_object_id_fk references sn_objects on delete cascade,
+ resource_req_id constraint psn_res_app_res_req_id_fk references sn_objects on delete cascade,
+ user_id constraint psn_res_app_user_id_fk references users,
+ creation_date date default sysdate,
+ application_date date default null,
+ sent_p char(1) default 'f' constraint psn_res_app_sent_p_ck check (sent_p in ('t','f')),
+ recipient varchar2(4000),
+ subject varchar2(1000),
+ contact_data varchar2(4000),
+ nationality varchar2(4000),
+ manager_email varchar2(4000),
+ working_area varchar2(4000),
+ role_other varchar2(1000),
+ first_language varchar2(1000),
+ second_language_id integer,
+ third_language_id integer,
+ first_language_prof_id integer,
+ second_language_prof_id integer,
+ third_language_prof_id integer,
+ other_language varchar2(4000),
+ from_date date,
+ to_date date,
+ strengths varchar2(4000),
+ leadership varchar2(4000),
+ intercultural varchar2(4000),
+ comments varchar2(4000),
+ conditions varchar2(4000)
+);
+
+create index psn_res_app_object_idx on psn_res_applications (object_id);
+
+create index psn_res_app_res_idx on psn_res_applications (resource_req_id);
+
+create index psn_res_app_user_idx on psn_res_applications (user_id);
+
+create table psn_res_application_roles (
+ application_id integer constraint psn_res_app_roles_app_fk references psn_res_applications on delete cascade,
+ role_id integer,
+ primary key (application_id, role_id)
+);
+
+create table psn_category_trees (
+ package_id integer primary key,
+ role_magic_id constraint psn_cat_trees_role_fk references acs_objects (object_id) on delete set null,
+ language_magic_id constraint psn_cat_trees_lang_fk references acs_objects (object_id) on delete set null,
+ proficiency_magic_id constraint psn_cat_trees_prof_fk references acs_objects (object_id) on delete set null
+);
+
+create table psn_attachments (
+ attachment_id integer primary key,
+ application_id constraint psn_attach_appl_id_fk references psn_res_applications on delete cascade,
+ title varchar2(1000),
+ mime_type varchar2(200) default 'text/plain',
+ filename varchar2(200),
+ attachment blob default empty_blob()
+);
+
+create index psn_attach_appl_id_idx on psn_attachments(application_id);
+
+create sequence psn_attachment_id_seq start with 1;
+
+begin
+ acs_object_type.create_type (
+ supertype => 'acs_object',
+ object_type => 'psn_tree_object',
+ pretty_name => 'Demand Application Form',
+ pretty_plural => 'Demand Application Forms',
+ table_name => 'PSN_CATEGORY_TREES'
+ );
+end;
+/
+show errors
+
+begin
+ acs_object_type.create_type (
+ supertype => 'acs_object',
+ object_type => 'psn_application',
+ pretty_name => 'Demand Application',
+ pretty_plural => 'Demand Applications',
+ table_name => 'PSN_RES_APPLICATIONS',
+ id_column => 'APPLICATION_ID'
+ );
+end;
+/
+show errors
+
+
+create table approval_coordinators (
+ package_id integer
+ constraint sn_approval_coord_packag_id_fk
+ references apm_packages (package_id)
+ on delete cascade,
+ coordinator_id
+ integer
+ constraint sn_approval_coord_coord_id_fk
+ references users (user_id),
+ constraint approval_coordinators_pk
+ primary key (package_id, coordinator_id)
+);
+
+------------------------------------------------------------------------------
+-- now go on and create the packages
+
+@@library-temp-tables
+@@library-packages
+@@library-package-bodies
+@@library-triggers
+@@library-workflow-create
+@@library-workflow-packages
+
+begin
+ acs_privilege.create_privilege('km_publish');
+ acs_privilege.add_child('km_publish','read');
+ acs_privilege.add_child('km_publish','write');
+ acs_privilege.add_child('km_publish','delete');
+end;
+/
+show errors
Index: openacs-4/contrib/obsolete-packages/library/sql/oracle/library-drop.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/sql/oracle/library-drop.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/sql/oracle/library-drop.sql 2 Jul 2003 12:19:42 -0000 1.1
@@ -0,0 +1,146 @@
+--
+-- packages/library/sql/library-drop.sql
+--
+-- Credit for the ACS 3 version of this module goes to:
+-- @author Branimir Dolicki (branimir@arsdigita.com)
+-- @author Carsten Clasohm (carsten@arsdigita.com)
+-- @author Sarah Arnold (no idea)
+--
+-- The upgrade of this module to ACS 4 was done by
+-- @author Dirk Gomez (dirk@arsdigita.com)
+-- @author Jens Kordsmeier (jak@arsdigita.com)
+-- in June/July 2000.
+--
+-- @creation-date 22-June 2001
+-- @cvs-id $Id
+
+-- Delete all library question objects and corresponding acs objects
+
+-- declare
+-- cursor c_question_id
+-- is
+-- select question_id
+-- from sn_questions
+-- where parent_id not in (select question_id from sn_questions);
+-- begin
+-- for v_question_id in c_question_id loop
+-- question.delete(v_question_id.question_id);
+-- end loop;
+-- end;
+-- /
+-- show errors
+
+-- delete acs_permissions
+-- Drop permission metadata
+delete from acs_permissions
+ where privilege in
+ ('km_instance_admin','km_object_type_read',
+ 'km_object_type_create','km_object_read',
+ 'km_object_write','km_publish');
+
+delete from acs_privilege_hierarchy
+ where privilege in
+ ('km_instance_admin','km_object_type_read',
+ 'km_object_type_create','km_object_read',
+ 'km_object_write','km_publish');
+
+delete from acs_privilege_hierarchy
+ where child_privilege in
+ ('km_instance_admin','km_object_type_read',
+ 'km_object_type_create','km_object_read',
+ 'km_object_write','km_publish');
+
+delete from acs_privileges
+ where privilege in
+ ('km_instance_admin','km_object_type_read',
+ 'km_object_type_create','km_object_read',
+ 'km_object_write','km_publish');
+
+
+declare
+ cursor c1 is
+ select package_id from apm_packages where package_key='library';
+begin
+ for pac_rec in c1 loop
+ object_type.delete_all_object_types(pac_rec.package_id);
+ end loop;
+end;
+/
+
+alter table sn_questions
+ drop constraint sn_questions_object_type_id_fk;
+drop table psn_attachments;
+drop table psn_category_trees;
+drop table psn_res_application_roles;
+drop table psn_res_applications;
+drop table km_sweeper;
+drop table km_sweeper_publisher;
+drop table sn_object_archive_reasons;
+drop table km_advanced_search_settings;
+drop table km_library_searches;
+drop table km_logger_table;
+drop table km_flat_object_hierarchy;
+drop table sn_question_link_map;
+drop table sn_table_name_map;
+drop table sn_access_counts;
+drop table sn_object_option_map;
+drop table sn_answer_options;
+drop table sn_object_delete_reasons;
+drop table km_object_archive_reasons;
+drop table sn_audit_table;
+drop table sn_content;
+drop table sn_question_object_type_map;
+drop table sn_objects;
+drop table sn_object_types;
+drop table sn_questions;
+drop table km_path;
+
+delete from bm_bookmarkable_types where object_type = 'sn_object';
+
+delete from subsite_callbacks where object_type = 'sn_object';
+
+delete from acs_objects_description where object_id in (select object_id from acs_objects where object_type='sn_object');
+
+delete from acs_permissions where object_id in (select object_id from acs_objects where object_type='sn_object');
+
+-- Yeah I know it's stupid. But it works.
+delete from acs_objects o where object_type='sn_object' and not exists (select 1 from acs_objects i where context_id = o.object_id);
+delete from acs_objects o where object_type='sn_object' and not exists (select 1 from acs_objects i where context_id = o.object_id);
+delete from acs_objects o where object_type='sn_object' and not exists (select 1 from acs_objects i where context_id = o.object_id);
+delete from acs_objects o where object_type='sn_object' and not exists (select 1 from acs_objects i where context_id = o.object_id);
+delete from acs_objects o where object_type='sn_object' and not exists (select 1 from acs_objects i where context_id = o.object_id);
+delete from acs_objects o where object_type='sn_object' and not exists (select 1 from acs_objects i where context_id = o.object_id);
+delete from acs_objects o where object_type='sn_object' and not exists (select 1 from acs_objects i where context_id = o.object_id);
+delete from acs_objects o where object_type='sn_object' and not exists (select 1 from acs_objects i where context_id = o.object_id);
+delete from acs_objects o where object_type='sn_object' and not exists (select 1 from acs_objects i where context_id = o.object_id);
+delete from acs_objects o where object_type='sn_object' and not exists (select 1 from acs_objects i where context_id = o.object_id);
+
+-- This is even more...
+delete from acs_objects where object_type='sn_comment' and context_id in (select object_id from acs_objects where object_type='sn_object');
+
+delete from acs_objects where object_type = 'sn_object_type';
+delete from acs_objects where object_type = 'sn_question';
+delete from acs_objects where object_type = 'psn_tree_object';
+delete from acs_objects where object_type = 'psn_application';
+
+begin
+ acs_object_type.drop_type ('sn_object');
+ acs_object_type.drop_type ('sn_object_type');
+ acs_object_type.drop_type ('sn_question');
+ acs_object_type.drop_type ('psn_tree_object');
+ acs_object_type.drop_type ('psn_application');
+end;
+/
+show errors
+
+------------------------------------------------------------------------------
+------------------------------------------------------------------------------
+------------------------------------------------------------------------------
+-- Those procedures will be deleted one after another once the analog ACS4
+-- stuff is done.
+
+
+drop table sn_links;
+drop table sn_link_types;
+drop sequence sn_links_seq;
+drop sequence psn_attachment_id_seq;
Index: openacs-4/contrib/obsolete-packages/library/sql/oracle/library-functions.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/sql/oracle/library-functions.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/sql/oracle/library-functions.sql 2 Jul 2003 12:19:42 -0000 1.1
@@ -0,0 +1,13 @@
+create or replace function sn_check_type (p_object_id integer,
+ p_object_type_id integer)
+return integer
+as
+ result integer;
+begin
+ select decode(object_type_id, p_object_type_id, 1, 0) into result
+ from sn_objects
+ where object_id=p_object_id;
+ return result;
+end;
+/
+show errors
Index: openacs-4/contrib/obsolete-packages/library/sql/oracle/library-package-bodies.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/sql/oracle/library-package-bodies.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/sql/oracle/library-package-bodies.sql 2 Jul 2003 12:19:42 -0000 1.1
@@ -0,0 +1,1736 @@
+create or replace package body library
+as
+ procedure copy (
+ src_package_id in apm_packages.package_id%TYPE,
+ dst_package_id in apm_packages.package_id%TYPE,
+ creation_user in acs_objects.creation_user%TYPE,
+ creation_ip in acs_objects.creation_ip%TYPE
+ )
+ is
+ begin
+ object_type.copy_all_object_types (
+ src_package_id => src_package_id,
+ dst_package_id => dst_package_id,
+ creation_user => creation_user,
+ creation_ip => creation_ip
+ );
+
+ psn_res_application.copy (
+ src_package_id => src_package_id,
+ dst_package_id => dst_package_id,
+ creation_user => creation_user,
+ creation_ip => creation_ip
+ );
+
+ end copy;
+
+end library;
+/
+show errors
+
+create or replace package body object_type
+as
+ procedure copy_all_object_types (
+ src_package_id in acs_objects.context_id%TYPE,
+ dst_package_id in acs_objects.context_id%TYPE,
+ creation_user in acs_objects.creation_user%TYPE,
+ creation_ip in acs_objects.creation_ip%TYPE
+ )
+ is
+ cursor c_questions (src_package_id integer) is
+ select question_id, pretty_name, abstract_data_type, presentation_type,
+ order_by, entry_explanation, tag_width, tag_height, help_text,
+ target_object_type_id, references_question_id, tree_id, node_id,
+ category_id, year_from, year_to, default_value, max_categories,
+ defaults_question_id
+ from sn_questions
+ where question_id in
+ (select map.question_id
+ from sn_question_object_type_map map, sn_object_types ot
+ where map.object_type_id = ot.object_type_id
+ and ot.context_id = src_package_id);
+
+ cursor c_object_types (src_package_id integer) is
+ select object_type_id, short_name, pretty_name, pretty_plural, graphic,
+ graphic_p, deleted_p, browse_p, public_p, create_p, sort_key,
+ q1.new_id as new_short_description, q2.new_id as new_long_description,
+ q3.new_id as new_public_until, q4.new_id as new_linked_question_id,
+ default_age_filter, dst_package_id, archive_p, copy_p,
+ sweeper, sweeper_action, sweeper_warning_time, sweeper_outdated_time,
+ start_date, end_date
+ from sn_object_types ot, km_temp_questions q1, km_temp_questions q2,
+ km_temp_questions q3, km_temp_questions q4
+ where ot.context_id = src_package_id
+ and q1.old_id(+) = ot.short_description
+ and q2.old_id(+) = ot.long_description
+ and q3.old_id(+) = ot.public_until
+ and q4.old_id(+) = ot.linked_question_id;
+
+ cursor c_answer_options is
+ select option_id, tq.new_id as new_question_id, answer_option, sort_key
+ from sn_answer_options ao, km_temp_questions tq
+ where ao.question_id = tq.old_id;
+ v_new_question_id sn_questions.question_id%type;
+ v_new_object_type_id sn_object_types.object_type_id%type;
+ v_new_answer_option_id sn_answer_options.option_id%type;
+ v_count integer;
+ v_new_target_object_type_id integer;
+ begin
+ -- Clean up data from previous call in this transaction.
+ delete from km_temp_questions;
+ delete from km_temp_object_types;
+ delete from km_temp_answer_options;
+
+ -- copy the questions
+ for c1 in c_questions(src_package_id) loop
+ v_new_question_id := question.insert_question (
+ v_pretty_name => c1.pretty_name,
+ v_abstract_data_type => c1.abstract_data_type,
+ v_order_by => c1.order_by,
+ v_default_value => c1.default_value,
+ v_entry_explanation => c1.entry_explanation,
+ v_creation_user => creation_user,
+ v_creation_ip => creation_ip,
+ v_references_q_id => null);
+
+ update sn_questions
+ set presentation_type=c1.presentation_type, tag_width=c1.tag_width,
+ tag_height = c1.tag_height, help_text = c1.help_text, tree_id =
+ c1.tree_id, node_id = c1.node_id, category_id = c1.category_id,
+ year_from = c1.year_from, year_to = c1.year_to,
+ target_object_type_id = c1.target_object_type_id,
+ max_categories = c1.max_categories,
+ defaults_question_id = c1.defaults_question_id
+ where question_id=v_new_question_id;
+ insert into km_temp_questions
+ (old_id, new_id)
+ values
+ (c1.question_id, v_new_question_id);
+ end loop;
+
+ -- correct references_question_id
+ update sn_questions q
+ set references_question_id = (select new_id
+ from km_temp_questions
+ where old_id = q.references_question_id )
+ where question_id in
+ (select old_id from km_temp_questions);
+
+ -- correct defaults_question_id
+ update sn_questions q
+ set defaults_question_id = (select new_id
+ from km_temp_questions
+ where old_id = q.defaults_question_id )
+ where question_id in
+ (select old_id from km_temp_questions);
+
+ for c2 in c_object_types(src_package_id) loop
+ -- create the new object type
+ v_new_object_type_id := acs_object.new (
+ object_type => 'sn_object_type',
+ creation_date => sysdate,
+ creation_user => creation_user,
+ creation_ip => creation_ip,
+ context_id => dst_package_id
+ );
+
+ insert into sn_object_types
+ (object_type_id, short_name, pretty_name, pretty_plural, graphic,
+ graphic_p, deleted_p, browse_p, public_p, create_p, sort_key,
+ short_description, long_description, public_until, linked_question_id,
+ default_age_filter, context_id, archive_p, copy_p, sweeper,
+ sweeper_action, sweeper_warning_time, sweeper_outdated_time,
+ start_date, end_date)
+ values
+ (v_new_object_type_id, c2.short_name, c2.pretty_name, c2.pretty_plural, c2.graphic,
+ c2.graphic_p, c2.deleted_p, c2.browse_p, c2.public_p, c2.create_p, c2.sort_key,
+ c2.new_short_description, c2.new_long_description,
+ c2.new_public_until, c2.new_linked_question_id,
+ c2.default_age_filter, c2.dst_package_id, c2.archive_p,
+ c2.copy_p, c2.sweeper, c2.sweeper_action, c2.sweeper_warning_time,
+ c2.sweeper_outdated_time, c2.start_date, c2.end_date);
+
+ insert into km_temp_object_types
+ (old_id, new_id)
+ values
+ (c2.object_type_id, v_new_object_type_id);
+ end loop;
+
+ -- now map the shortname
+ for c3 in (select tot.new_id as object_type_id, tq.new_id as short_description, map.position
+ from sn_types_map_short_name map, km_temp_questions tq,
+ km_temp_object_types tot
+ where map.short_description = tq.old_id
+ and map.object_type_id = tot.old_id)
+ loop
+ begin
+ insert into sn_types_map_short_name
+ (object_type_id, short_description, position)
+ values
+ (c3.object_type_id, c3.short_description, c3.position );
+ exception
+ when others then
+ null;
+ end;
+ end loop;
+
+ -- map the answer options
+ for c4 in c_answer_options loop
+ select acs_object_id_seq.nextval into v_new_answer_option_id from dual;
+ insert into sn_answer_options
+ (option_id, question_id, answer_option, sort_key)
+ values
+ (v_new_answer_option_id, c4.new_question_id, c4.answer_option,
+ c4.sort_key);
+ insert into km_temp_answer_options
+ (old_id, new_id)
+ values
+ (c4.option_id, v_new_answer_option_id);
+ end loop;
+
+ -- -50 is the dummy question id
+ insert into km_temp_questions values (-50,-50);
+
+ -- and now map the frigging questions to the more frigging object type
+ for c5 in (select tq1.new_id as new_question_id, tot.new_id as new_object_type_id,
+ sort_key, form_number, mandatory_p, question_state, tq2.new_id as
+ new_parent_question_id, branch_p, branch_operator, branch_answer,
+ tao.new_id as new_branch_answer_foreign_key, tq3.new_id as
+ new_default_branch
+ from sn_question_object_type_map map, km_temp_questions tq1,
+ km_temp_questions tq2, km_temp_questions tq3, km_temp_answer_options tao,
+ km_temp_object_types tot
+ where map.question_id = tq1.old_id
+ and map.object_type_id = tot.old_id
+ and map.parent_question_id = tq2.old_id(+)
+ and map.default_branch = tq3.old_id(+)
+ and map.branch_answer_foreign_key = tao.old_id(+)) loop
+
+ begin
+ insert into sn_question_object_type_map
+ (question_id, object_type_id, sort_key, form_number, mandatory_p,
+ question_state, parent_question_id, branch_p, branch_operator,
+ branch_answer, branch_answer_foreign_key, default_branch)
+ values
+ (c5.new_question_id, c5.new_object_type_id,
+ c5.sort_key, c5.form_number, c5.mandatory_p, c5.question_state,
+ c5.new_parent_question_id, c5.branch_p, c5.branch_operator, c5.branch_answer,
+ c5.new_branch_answer_foreign_key, c5.new_default_branch);
+ exception
+ when others then
+ null;
+ end;
+ end loop;
+ -- and correct the target object type ids
+ for c6 in (
+ select q2.target_object_type_id, q1.question_id
+ from sn_questions q1, sn_questions q2,
+ km_temp_questions tq
+ where q1.question_id = tq.new_id
+ and q2.question_id = tq.old_id
+ and q2.target_object_type_id is not null
+ and q1.question_id in
+ (select new_id from km_temp_questions)
+ ) loop
+ select new_id
+ into v_new_target_object_type_id
+ from km_temp_object_types tot
+ where tot.old_id = c6.target_object_type_id;
+
+ update sn_questions q
+ set target_object_type_id = v_new_target_object_type_id
+ where question_id = c6.question_id;
+ end loop;
+ end copy_all_object_types;
+
+ procedure copy_object_type (
+ v_object_type_id in sn_object_types.object_type_id%TYPE,
+ v_target_context_id in acs_objects.context_id%TYPE,
+ v_creation_user in acs_objects.creation_user%TYPE,
+ v_creation_ip in acs_objects.creation_ip%TYPE
+ )
+ is
+ cursor c_questions (v_object_type_id integer) is
+ select question_id, pretty_name, abstract_data_type, presentation_type,
+ order_by, entry_explanation, tag_width, tag_height, help_text,
+ target_object_type_id, references_question_id, tree_id, node_id,
+ category_id, year_from, year_to, default_value, max_categories,
+ defaults_question_id
+ from sn_questions
+ where question_id in
+ (select map.question_id
+ from sn_question_object_type_map map
+ where map.object_type_id = v_object_type_id);
+ cursor c_answer_options is
+ select option_id, tq.new_id as new_question_id, answer_option, sort_key
+ from sn_answer_options ao, km_temp_questions tq
+ where ao.question_id = tq.old_id;
+ v_new_question_id sn_questions.question_id%TYPE;
+ v_new_object_type_id sn_object_types.object_type_id%TYPE;
+ v_new_answer_option_id sn_answer_options.option_id%TYPE;
+ v_count integer;
+ begin
+ -- Clean up data from previous call in this transaction.
+ delete from km_temp_questions;
+ delete from km_temp_answer_options;
+
+ -- copy the questions
+ -- target_object_type_id has to be nullified as it doesn't exist
+ -- in the target community
+ for c1 in c_questions(v_object_type_id) loop
+ v_new_question_id := question.insert_question (
+ v_pretty_name => c1.pretty_name,
+ v_abstract_data_type => c1.abstract_data_type,
+ v_order_by => c1.order_by,
+ v_default_value => c1.default_value,
+ v_entry_explanation => c1.entry_explanation,
+ v_creation_user => v_creation_user,
+ v_creation_ip => v_creation_ip,
+ v_references_q_id => null);
+ update sn_questions
+ set presentation_type=c1.presentation_type, tag_width=c1.tag_width,
+ tag_height = c1.tag_height, help_text = c1.help_text, tree_id =
+ c1.tree_id, node_id = c1.node_id, category_id = c1.category_id,
+ year_from = c1.year_from, year_to = c1.year_to,
+ max_categories = c1.max_categories,
+ defaults_question_id = c1.defaults_question_id
+ where question_id=v_new_question_id;
+ insert into km_temp_questions
+ (old_id, new_id)
+ values
+ (c1.question_id, v_new_question_id);
+ end loop;
+
+ -- correct references_question_id
+ update sn_questions q
+ set references_question_id = (select new_id
+ from km_temp_questions
+ where old_id = q.references_question_id )
+ where question_id in
+ (select old_id from km_temp_questions);
+
+ -- correct defaults_question_id
+ update sn_questions q
+ set defaults_question_id = (select new_id
+ from km_temp_questions
+ where old_id = q.defaults_question_id )
+ where question_id in
+ (select old_id from km_temp_questions);
+
+ -- create the new object type
+ v_new_object_type_id := acs_object.new (
+ object_type => 'sn_object_type',
+ creation_date => sysdate,
+ creation_user => v_creation_user,
+ creation_ip => v_creation_ip,
+ context_id => v_target_context_id
+ );
+
+ insert into sn_object_types
+ (object_type_id, short_name, pretty_name, pretty_plural, graphic,
+ graphic_p, deleted_p, browse_p, public_p, create_p, sort_key,
+ short_description, long_description, public_until, linked_question_id,
+ default_age_filter, context_id, archive_p, copy_p, sweeper,
+ sweeper_action, sweeper_warning_time, sweeper_outdated_time,
+ start_date, end_date)
+ (select v_new_object_type_id, short_name, pretty_name, pretty_plural, graphic,
+ graphic_p, deleted_p, browse_p, public_p, create_p, sort_key,
+ q1.new_id as new_short_description, q2.new_id as new_long_description,
+ q3.new_id as new_public_until, q4.new_id as new_linked_question_id,
+ default_age_filter, v_target_context_id, archive_p, copy_p, sweeper,
+ sweeper_action, sweeper_warning_time, sweeper_outdated_time,
+ start_date, end_date
+ from sn_object_types ot, km_temp_questions q1, km_temp_questions q2,
+ km_temp_questions q3, km_temp_questions q4
+ where ot.object_type_id = v_object_type_id
+ and q1.old_id(+) = ot.short_description
+ and q2.old_id(+) = ot.long_description
+ and q3.old_id(+) = ot.public_until
+ and q4.old_id(+) = ot.linked_question_id);
+
+ -- now map the shortname
+ insert into sn_types_map_short_name
+ (object_type_id, short_description, position )
+ (select v_new_object_type_id, tq.new_id, map.position
+ from sn_types_map_short_name map, km_temp_questions tq
+ where map.short_description = tq.old_id);
+
+ -- map the answer options
+ for c3 in c_answer_options loop
+ select acs_object_id_seq.nextval into v_new_answer_option_id from dual;
+ insert into sn_answer_options
+ (option_id, question_id, answer_option, sort_key)
+ values
+ (v_new_answer_option_id, c3.new_question_id, c3.answer_option,
+ c3.sort_key);
+ insert into km_temp_answer_options
+ (old_id, new_id)
+ values
+ (c3.option_id, v_new_answer_option_id);
+ end loop;
+
+ -- -50 is the dummy question id
+ insert into km_temp_questions values (-50,-50);
+
+ -- and now map the frigging questions to the more frigging object type
+ insert into sn_question_object_type_map
+ (question_id, object_type_id, sort_key, form_number, mandatory_p,
+ question_state, parent_question_id, branch_p, branch_operator,
+ branch_answer, branch_answer_foreign_key, default_branch)
+ (select tq1.new_id as new_question_id, v_new_object_type_id,
+ sort_key, form_number, mandatory_p, question_state, tq2.new_id as
+ new_parent_question_id, branch_p, branch_operator, branch_answer,
+ tao.new_id as new_branch_answer_foreign_key, tq3.new_id as
+ new_default_branch
+ from sn_question_object_type_map map, km_temp_questions tq1,
+ km_temp_questions tq2, km_temp_questions tq3, km_temp_answer_options tao
+ where map.question_id = tq1.old_id
+ and map.parent_question_id = tq2.old_id(+)
+ and map.default_branch = tq3.old_id(+)
+ and map.branch_answer_foreign_key = tao.old_id(+));
+ end copy_object_type;
+
+ procedure delete_all_object_types (
+ v_context_id in acs_objects.context_id%TYPE default null
+ )
+ is
+ cursor c_delete_all_object_types is
+ select object_type_id
+ from sn_object_types
+ where context_id = v_context_id;
+ begin
+ for v_delete_all_object_types in c_delete_all_object_types loop
+ object_type.delete_object_type(v_delete_all_object_types.object_type_id);
+ end loop;
+ end delete_all_object_types;
+
+ function insert_object_type (
+ v_pretty_name in sn_object_types.pretty_name%TYPE,
+ v_pretty_plural in sn_object_types.pretty_plural%TYPE,
+ v_graphic in sn_object_types.graphic%TYPE,
+ v_deleted_p in sn_object_types.deleted_p%TYPE,
+ v_browse_p in sn_object_types.browse_p%TYPE,
+ v_public_p in sn_object_types.public_p%TYPE,
+ v_sort_key in sn_object_types.sort_key%TYPE,
+ v_short_description in sn_object_types.short_description%TYPE,
+ v_long_description in sn_object_types.long_description%TYPE,
+ v_linked_question_id in sn_object_types.linked_question_id%TYPE,
+ v_public_until in sn_object_types.public_until%TYPE,
+ v_default_age_filter in sn_object_types.default_age_filter%TYPE,
+ v_creation_user in acs_objects.creation_user%TYPE default null,
+ v_creation_ip in acs_objects.creation_ip%TYPE default null,
+ v_context_id in acs_objects.context_id%TYPE,
+ v_short_name in sn_object_types.short_name%TYPE default null,
+ v_insertion_date in acs_objects.creation_date%TYPE default sysdate
+ ) return sn_object_types.object_type_id%TYPE
+ is
+ v_return_object_type_id acs_objects.object_id%TYPE;
+ begin
+ v_return_object_type_id := acs_object.new (
+ object_type => 'sn_object_type',
+ creation_date => v_insertion_date,
+ creation_user => v_creation_user,
+ creation_ip => v_creation_ip,
+ context_id => v_context_id
+ );
+
+ insert into sn_object_types
+ (object_type_id,pretty_name, pretty_plural, graphic, deleted_p,
+ browse_p, public_p, sort_key, long_description,
+ public_until, default_age_filter,context_id, short_name )
+ values (v_return_object_type_id,v_pretty_name, v_pretty_plural,
+ v_graphic, v_deleted_p, v_browse_p, v_public_p, v_sort_key,
+ v_long_description, v_public_until,
+ v_default_age_filter, v_context_id, v_short_name);
+
+ -- this function is _only_ used by the migration scripts. In the past
+ -- we didn't have composite short descriptions. Hence the hack here is
+ -- more than okay.
+
+ if v_short_description is not null then
+ insert into sn_types_map_short_name
+ (object_type_id, short_description, position)
+ values
+ (v_return_object_type_id, v_short_description, 1);
+ end if;
+ return v_return_object_type_id;
+ end insert_object_type;
+
+
+ function insert_object_type (
+ v_pretty_name in sn_object_types.pretty_name%TYPE,
+ v_pretty_plural in sn_object_types.pretty_plural%TYPE,
+ v_browse_p in sn_object_types.browse_p%TYPE,
+ v_default_age_filter in sn_object_types.default_age_filter%TYPE,
+ v_creation_user in acs_objects.creation_user%TYPE default null,
+ v_creation_ip in acs_objects.creation_ip%TYPE default null,
+ v_context_id in acs_objects.context_id%TYPE default null,
+ v_short_name in sn_object_types.short_name%TYPE default null,
+ v_insertion_date in acs_objects.creation_date%TYPE default sysdate
+ ) return sn_object_types.object_type_id%TYPE
+ is
+ v_return_object_type_id acs_objects.object_id%TYPE;
+ begin
+ v_return_object_type_id := acs_object.new (
+ object_type => 'sn_object_type',
+ creation_date => v_insertion_date,
+ creation_user => v_creation_user,
+ creation_ip => v_creation_ip,
+ context_id => v_context_id
+ );
+
+ insert into sn_object_types
+ (object_type_id,pretty_name, pretty_plural,
+ browse_p, default_age_filter, context_id, short_name )
+ values (v_return_object_type_id,v_pretty_name, v_pretty_plural,
+ v_browse_p, v_default_age_filter, v_context_id, v_short_name);
+
+ return v_return_object_type_id;
+ end insert_object_type;
+
+ procedure delete_object_type (
+ v_object_type_id in sn_object_types.object_type_id%TYPE
+ )
+ is
+ cursor cur_question_object_type_map is
+ select question_id
+ from sn_question_object_type_map
+ where object_type_id = v_object_type_id;
+ begin
+ object.delete_all_objects_of_a_type(v_object_type_id);
+
+ update sn_object_types set
+ long_description = null,
+ linked_question_id = null,
+ public_until = null
+ where object_type_id = v_object_type_id;
+
+ update sn_questions
+ set target_object_type_id = null
+ where target_object_type_id = v_object_type_id;
+
+ for v_question_object_type_map in cur_question_object_type_map loop
+ question.delete_question(v_question_object_type_map.question_id);
+ end loop;
+
+ delete from sn_types_map_short_name where object_type_id = v_object_type_id;
+ delete from sn_table_name_map where object_type_id = v_object_type_id;
+ delete from acs_permissions where object_id = v_object_type_id;
+ acs_object.delete(v_object_type_id);
+ delete from sn_object_types where object_type_id=v_object_type_id;
+ end delete_object_type;
+
+end object_type;
+/
+show errors
+
+-- @cvs-id $Id: library-package-bodies.sql,v 1.1 2003/07/02 12:19:42 peterm Exp $
+-- turn off sql plus variables substitution
+set define off
+
+create or replace package body object
+as
+ function name (
+ object_id in sn_objects.object_id%TYPE
+ ) return varchar2
+ is
+ v_result sn_objects.one_line_description%TYPE;
+ begin
+ select nvl(one_line_description,'Unnamed ' || ot.pretty_name) into v_result
+ from sn_objects o, sn_object_types ot
+ where o.object_type_id = ot.object_type_id
+ and o.object_id = name.object_id;
+
+ return v_result;
+ end name;
+
+
+ procedure save_content (
+ v_object_id in sn_objects.object_id%TYPE,
+ v_question_id in sn_questions.question_id%TYPE,
+ v_html_p in sn_content.html_p%TYPE,
+ v_content_length in integer,
+ v_modifying_user in acs_objects.creation_user%TYPE,
+ v_modifying_ip in acs_objects.modifying_ip%TYPE,
+ v_update_date in acs_objects.last_modified%TYPE default sysdate
+ )
+ is
+ v_count_exists integer default 0;
+ begin
+ update sn_objects
+ set last_modified = v_update_date,
+ last_modifying_user_id = v_modifying_user
+ where object_id = v_object_id;
+
+ update acs_objects_description
+ set datastore = 'a'
+ where object_id = v_object_id;
+
+ acs_object.last_modified (
+ v_object_id => v_object_id,
+ v_modifying_user => v_modifying_user,
+ v_modifying_ip => v_modifying_ip,
+ v_last_modified => v_update_date);
+
+ select count(*)
+ into v_count_exists
+ from sn_content
+ where object_id=v_object_id
+ and question_id=v_question_id;
+
+ if v_count_exists = 0 then
+ insert into sn_content (object_id, question_id, html_p)
+ values (v_object_id, v_question_id, v_html_p);
+ else
+ if v_content_length = 0 then
+ delete from sn_content
+ where object_id=v_object_id
+ and question_id=v_question_id;
+ else
+ update sn_content
+ set html_p = v_html_p
+ where object_id=v_object_id
+ and question_id=v_question_id;
+ end if;
+ end if;
+ end save_content;
+
+ function insert_object (
+ v_object_type_id in sn_objects.object_type_id%TYPE,
+ v_creation_user in acs_objects.creation_user%TYPE default null,
+ v_creation_ip in acs_objects.creation_ip%TYPE default null,
+ v_context_id in acs_objects.context_id%TYPE default null,
+ v_insertion_date in acs_objects.creation_date%TYPE default sysdate
+ ) return sn_objects.object_id%TYPE
+ is
+ v_return_object_id acs_objects.object_id%TYPE;
+ begin
+ v_return_object_id := acs_object.new (
+ object_type => 'sn_object',
+ creation_date => v_insertion_date,
+ creation_user => v_creation_user,
+ creation_ip => v_creation_ip,
+ context_id => v_context_id
+ );
+
+ insert into sn_objects
+ (object_id, original_author_id, creation_date, last_modifying_user_id,
+ last_modified, object_type_id,context_id)
+ values (v_return_object_id, v_creation_user, v_insertion_date, v_creation_user,
+ v_insertion_date, v_object_type_id,v_context_id);
+
+ return v_return_object_id;
+ end insert_object;
+
+
+ function insert_object (
+ v_object_id in acs_objects.object_id%TYPE,
+ v_object_type_id in sn_objects.object_type_id%TYPE,
+ v_creation_user in acs_objects.creation_user%TYPE default null,
+ v_creation_ip in acs_objects.creation_ip%TYPE default null,
+ v_context_id in acs_objects.context_id%TYPE default null,
+ v_insertion_date in acs_objects.creation_date%TYPE default sysdate
+ ) return sn_objects.object_id%TYPE
+ is
+ v_return_object_id acs_objects.object_id%TYPE;
+ begin
+ v_return_object_id := acs_object.new (
+ object_id => v_object_id,
+ object_type => 'sn_object',
+ creation_date => v_insertion_date,
+ creation_user => v_creation_user,
+ creation_ip => v_creation_ip,
+ context_id => v_context_id
+ );
+
+ insert into sn_objects
+ (object_id, original_author_id, creation_date, last_modifying_user_id,
+ last_modified, object_type_id,context_id)
+ values (v_return_object_id, v_creation_user, v_insertion_date, v_creation_user,
+ v_insertion_date, v_object_type_id,v_context_id);
+
+ return v_return_object_id;
+ end insert_object;
+
+
+ function copy_object (
+ v_object_id in acs_objects.object_id%TYPE,
+ v_target_id in acs_objects.object_id%TYPE default null,
+ v_creation_user in acs_objects.creation_user%TYPE default null,
+ v_creation_ip in acs_objects.creation_ip%TYPE default null,
+ v_context_id in acs_objects.context_id%TYPE default null
+ ) return sn_objects.object_id%TYPE
+ is
+ v_new_link_id sn_links.link_id%TYPE;
+ v_return_object_id acs_objects.object_id%TYPE;
+ begin
+ v_return_object_id := acs_object.new (
+ object_type => 'sn_object',
+ object_id => v_target_id,
+ creation_date => sysdate,
+ creation_user => v_creation_user,
+ creation_ip => v_creation_ip,
+ context_id => v_context_id
+ );
+
+ acs_object.last_modified (
+ v_object_id => v_return_object_id,
+ v_modifying_user => v_creation_user,
+ v_modifying_ip => v_creation_ip,
+ v_last_modified => sysdate
+ );
+
+ -- copy sn_object
+ insert into sn_objects
+ (object_id, object_type_id, context_id, one_line_description,
+ overview, overview_html_p, creation_date, original_author_id,
+ last_modified, last_modifying_user_id, user_checkoff_date,
+ public_until, public_p, archived_p, access_total,
+ access_month, archiving_date, outdated_warning_date,
+ expired_warning_date)
+ (select v_return_object_id as object_id, object_type_id, context_id,
+ one_line_description, overview, overview_html_p,
+ sysdate as creation_date, v_creation_user as original_author_id,
+ sysdate as last_modified, v_creation_user as last_modifying_user_id,
+ null as user_checkoff_date, public_until, 'f' as public_p,
+ 'f' as archived_p, 0 as access_total, 0 as access_month,
+ null as archiving_date, null as outdated_warning_date,
+ null as expired_warning_date
+ from sn_objects o
+ where o.object_id = v_object_id);
+
+ -- copy categories
+ insert into sw_object_category_map (category_id, object_id)
+ (select category_id, v_return_object_id as object_id
+ from sw_object_category_map ocm
+ where ocm.object_id = v_object_id);
+
+ -- copy options
+ insert into sn_object_option_map (object_id, option_id)
+ (select v_return_object_id as object_id, option_id
+ from sn_object_option_map oom
+ where oom.object_id = v_object_id
+ and oom.option_id in (select ao.option_id
+ from sn_question_object_type_map qotm,
+ sn_objects o, sn_answer_options ao
+ where qotm.object_type_id = o.object_type_id
+ and qotm.question_state = 'active'
+ and qotm.question_id = ao.question_id
+ and o.object_id = v_object_id) );
+
+ -- copy content
+ insert into sn_content (object_id, question_id, content, html_p)
+ (select v_return_object_id as object_id, question_id, content, html_p
+ from sn_content c
+ where c.object_id = v_object_id
+ and c.question_id in (select qotm.question_id
+ from sn_question_object_type_map qotm,
+ sn_objects o
+ where qotm.object_type_id = o.object_type_id
+ and qotm.question_state = 'active'
+ and o.object_id = v_object_id) );
+
+ -- copy links
+ for link in (select qlm.link_id, qlm.question_id
+ from sn_question_link_map qlm, sn_objects o,
+ sn_question_object_type_map qotm, sn_links l
+ where qotm.object_type_id = o.object_type_id
+ and qotm.question_state = 'active'
+ and qlm.question_id = qotm.question_id
+ and l.link_id = qlm.link_id
+ and l.link_type = 'bi_directional'
+ and o.object_id = v_object_id
+ and l.object_id_a = o.object_id)
+ loop
+ select sn_links_seq.nextval into v_new_link_id from dual;
+
+ insert into sn_links
+ (link_id, link_type, object_id_a, object_id_b, link_comment,
+ html_p, creation_user, creation_date)
+ (select v_new_link_id, link_type,
+ decode(object_id_a,v_object_id,v_return_object_id,object_id_a),
+ decode(object_id_b,v_object_id,v_return_object_id,object_id_b),
+ link_comment, html_p, v_creation_user as creation_user,
+ sysdate as creation_date
+ from sn_links l
+ where l.link_id = link.link_id);
+
+ insert into sn_question_link_map (link_id, question_id)
+ values (v_new_link_id, link.question_id);
+ end loop;
+
+ return v_return_object_id;
+ end copy_object;
+
+ procedure audit_object (
+ v_object_id in sn_objects.object_id%TYPE,
+ v_question_id in sn_questions.question_id%TYPE,
+ v_last_modifying_user_id in acs_objects.modifying_ip%TYPE,
+ v_modifying_ip in acs_objects.modifying_ip%TYPE,
+ v_content in sn_audit_table.content%TYPE,
+ v_last_modified in acs_objects.last_modified%TYPE default sysdate
+ )
+ is
+ begin
+ insert into sn_audit_table
+ (object_id, question_id, last_modified, last_modifying_user_id, content)
+ values (v_object_id, v_question_id, v_last_modified, v_last_modifying_user_id, v_content);
+
+ update sn_objects
+ set last_modified = v_last_modified,
+ last_modifying_user_id = v_last_modifying_user_id,
+ outdated_warning_date = null
+ where object_id = v_object_id;
+
+ update acs_objects_description
+ set datastore = 'a'
+ where object_id = v_object_id;
+
+ acs_object.last_modified (
+ v_object_id => v_object_id,
+ v_modifying_user => v_last_modifying_user_id,
+ v_modifying_ip => v_modifying_ip,
+ v_last_modified => v_last_modified);
+ end audit_object;
+
+ procedure delete_object (
+ v_object_id in sn_objects.object_id%TYPE
+ )
+ is
+ cursor sn_comments is
+ select comment_id
+ from sn_comments
+ where object_id= v_object_id;
+ cursor bookmarks is
+ select bookmark_id
+ from bm_bookmarks
+ where object_id= v_object_id;
+
+ begin
+ delete from recommendations_log
+ where object_id = v_object_id;
+ delete from sn_question_link_map where link_id in
+ (select link_id
+ from sn_links
+ where object_id_a = v_object_id or object_id_b=v_object_id);
+ delete from psn_attachments where application_id in
+ (select application_id
+ from psn_res_applications
+ where object_id=v_object_id);
+ delete from psn_res_application_roles where application_id in
+ (select application_id
+ from psn_res_applications
+ where object_id=v_object_id);
+ delete from psn_res_applications where object_id=v_object_id;
+ delete from sn_links where object_id_a = v_object_id or object_id_b=v_object_id;
+ delete from user_alert_history where object_id=v_object_id;
+ delete from alerts where object_id=v_object_id;
+ delete from user_alerts where object_id=v_object_id;
+ for cur_val in bookmarks loop
+ acs_object.delete(cur_val.bookmark_id);
+ delete from bm_bookmarks where bookmark_id=cur_val.bookmark_id;
+ end loop;
+
+ delete from bm_shopping_cart where object_id= v_object_id;
+ -- ratings
+ for cur_val in sn_comments loop
+ acs_object.delete(cur_val.comment_id);
+ end loop;
+ delete from sn_owner_history where object_id=v_object_id;
+ delete from sn_content where object_id=v_object_id;
+ delete from sn_audit_table where object_id=v_object_id;
+ delete from sn_object_delete_reasons where object_id=v_object_id;
+ delete from sn_object_option_map where object_id=v_object_id;
+ delete from sn_access_counts where object_id = v_object_id;
+ delete from acs_permissions where object_id = v_object_id;
+ delete from sn_objects where object_id=v_object_id;
+ acs_object.delete(v_object_id);
+ end;
+
+ procedure delete_all_objects_of_a_type (
+ v_object_type_id in sn_object_types.object_type_id%TYPE
+ )
+ is
+ cursor cur_objects_of_a_type is
+ select object_id
+ from sn_objects
+ where object_type_id = v_object_type_id;
+ rows_processed boolean ;
+ begin
+ -- delete dependencies
+ update acs_objects set context_id=null where context_id in (select object_id
+ from sn_objects
+ where object_type_id = v_object_type_id);
+
+ delete from user_alert_history where content_type_id=v_object_type_id;
+ delete from alerts where content_type_id=v_object_type_id;
+ delete from user_alerts where content_type_id=v_object_type_id;
+ for v_objects_of_a_type in cur_objects_of_a_type loop
+ object.delete_object(v_objects_of_a_type.object_id);
+ end loop;
+ end;
+
+ procedure delete_all_objects_of_an_inst (
+ v_context_id in acs_objects.context_id%TYPE
+ )
+ is
+ begin
+ for v_all_objects_of_inst in (
+ select object_id from sn_objects
+ where context_id = v_context_id
+ )
+ loop
+ object.delete_object(v_all_objects_of_inst.object_id);
+ end loop;
+ end;
+
+end object;
+/
+show errors
+
+create or replace package body question
+as
+ -- Returns true if this question is a root of a branch (at any level)
+ function root_branch_p (
+ v_question_id in sn_questions.question_id%TYPE
+ ) return char
+ is
+ v_result char(1);
+ begin
+ select decode(count(*),0,'f','t')
+ into v_result
+ from sn_question_object_type_map
+ where parent_question_id=v_question_id and branch_p='t';
+
+ return v_result;
+ end root_branch_p;
+
+ PROCEDURE map_question_on_object (
+ v_question_id in sn_questions.question_id%TYPE,
+ v_object_type_id in sn_objects.object_type_id%TYPE,
+ v_form_number in sn_question_object_type_map.form_number%TYPE,
+ v_mandatory_p in sn_question_object_type_map.mandatory_p%TYPE,
+ v_question_state in sn_question_object_type_map.question_state%TYPE
+ ) IS
+ v_max_sort_key sn_question_object_type_map.sort_key%TYPE;
+ BEGIN
+ select max(sort_key)
+ into v_max_sort_key
+ from sn_question_object_type_map
+ where object_type_id = v_object_type_id;
+
+ v_max_sort_key := v_max_sort_key + 10;
+ insert into sn_question_object_type_map
+ (object_type_id, question_id, form_number, mandatory_p, question_state, branch_p, sort_key)
+ values (v_object_type_id, v_question_id, v_form_number, v_mandatory_p, v_question_state, 'f', v_max_sort_key);
+ -- DIRK: update last_modified_date
+ END map_question_on_object;
+
+ PROCEDURE delete_question (
+ v_question_id in sn_questions.question_id%TYPE
+ )
+ is
+ cursor cur_child_questions is
+ select question_id
+ from sn_question_object_type_map
+ where parent_question_id = v_question_id;
+ begin
+ -- nullify all short or long descriptions or linked_question-id or
+ -- public_until
+ delete from sn_types_map_short_name
+ where short_description = v_question_id;
+
+ update sn_object_types set
+ short_description = null
+ where short_description = v_question_id;
+
+ update sn_object_types set
+ long_description = null
+ where long_description = v_question_id;
+
+ update sn_object_types set
+ linked_question_id = null
+ where linked_question_id = v_question_id;
+
+ update sn_object_types set
+ public_until = null
+ where public_until = v_question_id;
+
+ update sn_questions set
+ references_question_id = null
+ where references_question_id = v_question_id;
+
+ -- delete all child questions
+ for v_child_questions in cur_child_questions loop
+ question.delete_question(v_child_questions.question_id);
+ end loop;
+
+ delete from sn_links where link_id in
+ (select link_id
+ from sn_question_link_map
+ where question_id = v_question_id);
+ delete from sn_question_link_map
+ where question_id = v_question_id;
+ delete from sn_question_object_type_map
+ where question_id = v_question_id;
+ delete from sn_content where question_id = v_question_id;
+ delete from sn_audit_table where question_id = v_question_id;
+ delete from sn_object_option_map where option_id in (select option_id
+ from sn_answer_options where question_id = v_question_id);
+ delete from sn_answer_options where question_id = v_question_id;
+
+ acs_object.delete(v_question_id);
+ delete from sn_questions where question_id = v_question_id;
+ end delete_question;
+
+ function insert_question (
+ v_question_id in sn_questions.question_id%TYPE default null,
+ v_pretty_name in sn_questions.pretty_name%TYPE,
+ v_abstract_data_type in sn_questions.abstract_data_type%TYPE,
+ v_order_by in sn_questions.order_by%TYPE,
+ v_default_value in sn_questions.default_value%TYPE,
+ v_entry_explanation in sn_questions.entry_explanation%TYPE,
+ v_creation_user in acs_objects.creation_user%TYPE default null,
+ v_creation_ip in acs_objects.creation_ip%TYPE default null,
+ v_context_id in acs_objects.context_id%TYPE default null,
+ v_insertion_date in acs_objects.creation_date%TYPE default sysdate,
+ v_references_q_id in sn_questions.question_id%TYPE
+ ) return sn_questions.question_id%TYPE
+ is
+ v_return_question_id acs_objects.object_id%TYPE;
+ v_presentation_type sn_questions.presentation_type%TYPE;
+ v_max_sort_key sn_question_object_type_map.sort_key%TYPE;
+ begin
+ if v_question_id is null then
+ v_return_question_id := acs_object.new (
+ object_type => 'sn_question',
+ creation_date => v_insertion_date,
+ creation_user => v_creation_user,
+ creation_ip => v_creation_ip,
+ context_id => null
+ );
+ else
+ v_return_question_id := acs_object.new (
+ object_id => v_question_id,
+ object_type => 'sn_question',
+ creation_date => v_insertion_date,
+ creation_user => v_creation_user,
+ creation_ip => v_creation_ip,
+ context_id => null
+ );
+ end if;
+
+ if v_abstract_data_type = 'category' then
+ v_presentation_type := 'select';
+ elsif v_abstract_data_type = 'other_category' then
+ v_presentation_type := 'select';
+ elsif v_abstract_data_type = 'option' then
+ v_presentation_type := 'select';
+ elsif v_abstract_data_type = 'integer' then
+ v_presentation_type := 'shorttext';
+ else
+ v_presentation_type := 'custom';
+ end if;
+
+ insert into sn_questions
+ (question_id, pretty_name, abstract_data_type, presentation_type,
+ order_by, default_value, entry_explanation, references_question_id)
+ values
+ (v_return_question_id, v_pretty_name, v_abstract_data_type,
+ v_presentation_type, v_order_by, v_default_value, v_entry_explanation, v_references_q_id);
+
+ return v_return_question_id;
+ end insert_question;
+
+ procedure update_question (
+ v_question_id in sn_questions.question_id%TYPE,
+ v_pretty_name in sn_questions.pretty_name%TYPE,
+ v_abstract_data_type in sn_questions.abstract_data_type%TYPE,
+ v_order_by in sn_questions.order_by%TYPE,
+ v_default_value in sn_questions.default_value%TYPE,
+ v_entry_explanation in sn_questions.entry_explanation%TYPE,
+ v_modifying_user in acs_objects.creation_user%TYPE,
+ v_modifying_ip in acs_objects.modifying_ip%TYPE,
+ v_update_date in acs_objects.last_modified%TYPE default sysdate,
+ v_references_q_id in sn_questions.question_id%TYPE,
+ v_def_question_id in sn_questions.question_id%TYPE default null,
+ v_max_categories in sn_questions.max_categories%TYPE default null,
+ v_browse_p in sn_questions.browse_p%TYPE default 't'
+ )
+ is
+ begin
+ update sn_questions
+ set pretty_name = v_pretty_name,
+ entry_explanation = v_entry_explanation,
+ abstract_data_type = v_abstract_data_type,
+ order_by = v_order_by,
+ default_value = v_default_value,
+ references_question_id = v_references_q_id,
+ defaults_question_id = v_def_question_id,
+ max_categories = v_max_categories,
+ browse_p = v_browse_p
+ where question_id = v_question_id;
+ acs_object.last_modified (
+ v_object_id => v_question_id,
+ v_modifying_user => v_modifying_user,
+ v_modifying_ip => v_modifying_ip,
+ v_last_modified => v_update_date);
+ end update_question;
+
+ procedure delete_all_questions(
+ v_context_id in acs_objects.context_id%TYPE default null
+ ) is
+ cursor c_delete_all_questions is
+ select q.question_id
+ from sn_questions q, sn_question_object_type_map map, sn_object_types ot
+ where ot.context_id = v_context_id
+ and ot.object_type_id = map.object_type_id
+ and map.question_id = q.question_id;
+ begin
+ for v_delete_all_questions in c_delete_all_questions loop
+ question.delete_question(v_delete_all_questions.question_id);
+ end loop;
+ end delete_all_questions;
+end question;
+/
+show errors
+
+
+create or replace package body km_utilities
+as
+ function km_ancestor_list (
+ v_object_id in integer)
+ return varchar
+ is
+ result varchar(4000);
+ begin
+ for c1_rec in (
+ select '{' || sno.object_id || ' {' || sno.one_line_description || '}}' as l
+ from sn_objects sno, km_flat_object_hierarchy fo
+ where fo.child = v_object_id and fo.parent = sno.object_id
+ order by distance desc
+ )
+ loop
+ result := concat(result, c1_rec.l || ' ');
+ end loop;
+ return substr(result, 1, length(result) - 1);
+ end km_ancestor_list;
+
+ function km_category_list (
+ v_object_id in integer,
+ v_parent_node_id in varchar)
+ return varchar
+ is
+ the_list varchar(4000);
+ begin
+ for c1_rec in (
+ select long_name
+ from categories c, sw_flat_cat fc, sw_object_category_map cm
+ where fc.parent = v_parent_node_id
+ and fc.child_category_id = c.category_id
+ and cm.category_id = c.category_id
+ and cm.object_id = v_object_id
+ )
+ loop
+ the_list := concat(the_list, c1_rec.long_name || ', ');
+ end loop;
+ return substr(the_list, 1, length(the_list) - 2);
+ end km_category_list;
+
+ function km_string2xml (str varchar2) return varchar2
+ is
+ retval varchar2(4000);
+ begin
+ retval := replace(str,'&','&');
+ retval := replace(retval,'<','<');
+ retval := replace(retval,'>','>');
+ return retval;
+ end km_string2xml;
+
+ procedure km_clob2xml (dest in out clob, source in clob)
+ is
+ offset integer := 1;
+ len integer;
+ text varchar2(4000);
+ begin
+ len := dbms_lob.getlength(source);
+ WHILE len > offset LOOP
+ text := DBMS_LOB.SUBSTR(source,3000, offset);
+ text := replace(text,'&','&');
+ text := replace(text,'<','<');
+ text := replace(text,'>','>');
+ dbms_lob.writeappend(dest,length(text),text);
+ offset := offset + 3000;
+ END LOOP;
+ end km_clob2xml;
+
+ procedure km_string2xmlclob (dest in out clob, source varchar2)
+ is
+ offset integer := 1;
+ len integer;
+ text varchar2(4000);
+ begin
+ len := length(source);
+ WHILE len > offset LOOP
+ text := substr(source,offset,3000);
+ text := replace(text,'&','&');
+ text := replace(text,'<','<');
+ text := replace(text,'>','>');
+ dbms_lob.writeappend(dest,length(text),text);
+ offset := offset + 3000;
+ END LOOP;
+ end km_string2xmlclob;
+
+ function km_xml ( id sn_objects.object_id%type) RETURN CLOB
+ is
+ v_pretty_name sn_object_types.pretty_name%TYPE;
+
+ -- CONSTANTS
+ CR CONSTANT VARCHAR2(2) := CHR(13);
+ sn_objects_rec sn_objects%ROWTYPE;
+ CURSOR km_cursor (p_object_type_id integer) IS
+ SELECT b.question_id, b.pretty_name, b.abstract_data_type
+ FROM sn_question_object_type_map a, sn_questions b
+ WHERE a.object_type_id = p_object_type_id
+ AND a.question_id = b.question_id
+ AND abstract_data_type NOT IN (/*'child_object',*/ 'file', /*'user_link',*/ 'composite')
+ AND question_state <> 'invisible'
+ ORDER BY sort_key;
+
+ CURSOR km_category (p_object_id integer) IS
+ SELECT c.category_id, c.short_name
+ FROM sw_object_category_map m, categories c
+ WHERE m.object_id = p_object_id
+ AND c.category_id = m.category_id;
+
+ CURSOR g_comments (p_object_id integer) IS
+ SELECT content FROM sn_comments WHERE object_id = p_object_id;
+
+ CURSOR km_links (p_object_id integer, p_question_id integer) IS
+ SELECT c.object_id linked_id, b.link_type link_type, b.object_id_b
+ FROM sn_links b, sn_objects c, sn_question_link_map map
+ WHERE b.object_id_a = p_object_id
+ AND b.link_id = map.link_id
+ AND map.question_id = p_question_id
+ AND b.object_id_b = c.object_id
+ and c.object_id is not null;
+
+ CURSOR km_content (p_object_id integer, p_question_id integer) IS
+ SELECT dbms_lob.substr(content,3999,1) answer FROM sn_content WHERE object_id = p_object_id AND question_id = p_question_id and content is not null
+ UNION
+ SELECT answer_option answer
+ FROM sn_object_option_map a, sn_answer_options b
+ WHERE a.object_id = p_object_id
+ AND a.option_id = b.option_id
+ AND b.question_id = p_question_id;
+ tag_object varchar2(4000);
+ tag_owner varchar(300);
+ tag_text varchar(4000);
+ tag_category varchar(4000);
+ tag_comments clob;
+ tag_content clob;
+ text varchar (4000);
+
+ i integer;
+
+ /* -- VARIABLES -- */
+ tlob clob; /* variable for store function output*/
+ BEGIN
+ DBMS_LOB.CREATETEMPORARY(tlob, TRUE, DBMS_LOB.SESSION);
+ -- prepare temorary lob for store COMMENTS tag
+ DBMS_LOB.CREATETEMPORARY(tag_comments, TRUE, DBMS_LOB.SESSION);
+ -- prepare temorary lob for store object_content tag
+ DBMS_LOB.CREATETEMPORARY(tag_content, TRUE, DBMS_LOB.SESSION);
+
+ -- get various info on table and columns to index
+ SELECT * INTO sn_objects_rec FROM sn_objects WHERE object_id = id ;
+
+ SELECT pretty_name
+ into v_pretty_name
+ FROM sn_object_types a
+ WHERE a.object_type_id = sn_objects_rec.object_type_id;
+
+ v_pretty_name := km_string2xml(v_pretty_name);
+
+ SELECT ''||CR||'');
+ return tlob;
+ END km_xml;
+
+ procedure km_populate_flat_object_hier
+ IS
+ CURSOR child_cursor IS
+ select object_id_b as object_id from sn_links where link_type in ('parent_child','uncle_nephew');
+ BEGIN
+ delete from km_flat_object_hierarchy;
+
+ FOR child IN child_cursor LOOP
+ insert into km_flat_object_hierarchy
+ select acs_object_id_seq.nextval, object_id_a, child.object_id, level, link_type
+ from sn_links start with object_id_b = child.object_id and link_type in ('parent_child','uncle_nephew')
+ connect by object_id_b = prior object_id_a and link_type in ('parent_child','uncle_nephew');
+ END LOOP;
+ END km_populate_flat_object_hier;
+
+ procedure km_logger (
+ v_who_is_logging varchar2,
+ v_log_text varchar2)
+ as
+ pragma autonomous_transaction;
+ begin
+ insert into km_logger_table values (sysdate, v_who_is_logging, v_log_text );
+ commit;
+ end km_logger;
+
+ function shortname_string (p_object_id in sn_objects.object_id%TYPE,
+ p_question_id1 in sn_questions.question_id%TYPE,
+ p_question_id2 in sn_questions.question_id%TYPE,
+ p_question_id3 in sn_questions.question_id%TYPE default 0)
+ return varchar2
+ is
+ v_result_string varchar2(4000) := '';
+ v_result_string1 varchar2(4000) := '';
+ v_result_string2 varchar2(4000) := '';
+ v_result_string3 varchar2(4000) := '';
+ v_length_string1 integer;
+ v_length_string2 integer;
+ v_length_string3 integer;
+ begin
+ begin
+ select trim(dbms_lob.substr(content,1300,1))
+ into v_result_string1
+ from sn_content
+ where question_id=p_question_id1
+ and object_id=p_object_id;
+ exception
+ when others then
+ v_result_string1 := '';
+ end;
+
+ begin
+ select trim(dbms_lob.substr(content,1300,1))
+ into v_result_string2
+ from sn_content
+ where question_id=p_question_id2
+ and object_id=p_object_id;
+ exception
+ when others then
+ v_result_string2 := '';
+ end;
+
+ begin
+ if p_question_id3 > 0 then
+ select trim(dbms_lob.substr(content,1300,1))
+ into v_result_string3
+ from sn_content
+ where question_id=p_question_id3
+ and object_id=p_object_id;
+ end if;
+ exception
+ when others then
+ v_result_string3 := '';
+ end;
+
+ v_length_string1 := length(v_result_string1);
+ v_length_string2 := length(v_result_string2);
+ v_length_string3 := length(v_result_string3);
+
+ if (v_length_string1 > 0) then
+ v_result_string := v_result_string1;
+ if (v_length_string2 > 0) then
+ v_result_string := v_result_string || ', ' || v_result_string2;
+ end if;
+ if (v_length_string3 > 0) then
+ v_result_string := v_result_string || ', ' || v_result_string3;
+ end if;
+ else
+ if (v_length_string2 > 0) then
+ v_result_string := v_result_string2;
+ if (v_length_string3 > 0) then
+ v_result_string := v_result_string || ', ' || v_result_string3;
+ end if;
+ else
+ if (v_length_string3 > 0) then
+ v_result_string := v_result_string3;
+ end if;
+ end if;
+ end if;
+ return v_result_string;
+ end shortname_string;
+
+ function strip_html ( input_text in varchar2)
+ return varchar2
+ is
+ output varchar2(4000);
+ i number;
+ tag_start number;
+ tag_end number;
+ char_count number;
+ begin
+
+ i := 1;
+ output := '';
+ while instr(input_text, '<', i) >= i
+ loop
+ tag_start := instr(input_text, '<', i);
+ tag_end := instr(input_text, '>', tag_start);
+ if tag_end > 0 then
+ char_count := tag_start - i;
+
+ if char_count > 0 then
+ output := output || substr(input_text, i, char_count);
+ end if;
+
+ i := tag_end + 1;
+ else
+ exit;
+ end if;
+ end loop;
+
+ output := output || substr(input_text, i);
+
+ select replace(output, '\<', '<') into output from dual;
+ select replace(output, '\>', '>') into output from dual;
+ select replace(output, '\"', '"') into output from dual;
+ return (output);
+ end strip_html;
+
+ function strip_html_and_limit_size
+ (p_overview in sn_objects.overview%TYPE)
+ return VARCHAR2
+ is
+ v_overview sn_objects.overview%TYPE;
+ begin
+ v_overview := strip_html(p_overview);
+ if (length(p_overview)>200) then
+ v_overview := substr(v_overview,1,200) || '...';
+ end if;
+ return v_overview;
+ end strip_html_and_limit_size;
+end km_utilities;
+/
+show errors
+
+
+
+create or replace trigger km_flat_object_hier_insert_tr
+before insert on sn_links for each row
+begin
+ if :new.link_type = 'parent_child' or :new.link_type = 'uncle_nephew' then
+ insert into km_flat_object_hierarchy (object_hierarchy_id, parent, child, distance, link_type)
+ values (acs_object_id_seq.nextval, :new.object_id_a, :new.object_id_b, 1, :new.link_type);
+
+ insert into km_flat_object_hierarchy (object_hierarchy_id, parent, child, distance, link_type)
+ select acs_object_id_seq.nextval, parent, :new.object_id_b, distance+1, :new.link_type
+ from km_flat_object_hierarchy
+ where child = :new.object_id_a;
+ end if;
+end ;
+/
+show errors
+
+
+create or replace trigger km_flat_object_hier_delete_tr
+before delete on sn_links for each row
+begin
+ if :old.link_type = 'parent_child' or :old.link_type = 'uncle_nephew' then
+ delete from km_flat_object_hierarchy
+ where child = :old.object_id_b;
+ end if;
+end ;
+/
+show errors
+
+create or replace function im_convert(
+ query in varchar2 default null
+ ) return varchar2
+is
+ i number :=0;
+ len number :=0;
+ char varchar2(1);
+ minusString varchar2(4000);
+ plusString varchar2(4000);
+ mainString varchar2(4000);
+ mainAboutString varchar2(4000);
+ finalString varchar2(4000);
+ hasMain number :=0;
+ hasPlus number :=0;
+ hasMinus number :=0;
+ token varchar2(4000);
+ tokenStart number :=1;
+ tokenFinish number :=0;
+ inPhrase number :=0;
+ inPlus number :=0;
+ inWord number :=0;
+ inMinus number :=0;
+ completePhrase number :=0;
+ completeWord number :=0;
+ code number :=0;
+begin
+
+ len := length(query);
+
+-- we iterate over the string to find special web operators
+ for i in 1..len loop
+ char := substr(query,i,1);
+ if(char = '"') then
+ if(inPhrase = 0) then
+ inPhrase := 1;
+ tokenStart := i;
+ else
+ inPhrase := 0;
+ completePhrase := 1;
+ tokenFinish := i-1;
+ end if;
+ elsif(char = ' ') then
+ if(inPhrase = 0) then
+ completeWord := 1;
+ tokenFinish := i-1;
+ end if;
+ elsif(char = '+') then
+ inPlus := 1;
+ tokenStart := i+1;
+ elsif((char = '-') and (i = tokenStart)) then
+ inMinus :=1;
+ tokenStart := i+1;
+ end if;
+
+ if(completeWord=1) then
+ token := '{ '||substr(query,tokenStart,tokenFinish-tokenStart+1)||' }';
+ if(inPlus=1) then
+ plusString := plusString||','||token||'*10';
+ hasPlus :=1;
+ elsif(inMinus=1) then
+ minusString := minusString||'OR '||token||' ';
+ hasMinus :=1;
+ else
+ mainString := mainString||' NEAR '||token;
+ mainAboutString := mainAboutString||' '||token;
+ hasMain :=1;
+ end if;
+ tokenStart :=i+1;
+ tokenFinish :=0;
+ inPlus := 0;
+ inMinus :=0;
+ end if;
+ completePhrase := 0;
+ completeWord :=0;
+ end loop;
+
+ -- find the last token
+ token := '{ '||substr(query,tokenStart,len-tokenStart+1)||' }';
+ if(inPlus=1) then
+ plusString := plusString||','||token||'*10';
+ hasPlus :=1;
+ elsif(inMinus=1) then
+ minusString := minusString||'OR '||token||' ';
+ hasMinus :=1;
+ else
+ mainString := mainString||' NEAR '||token;
+ mainAboutString := mainAboutString||' '||token;
+ hasMain :=1;
+ end if;
+
+
+ mainString := substr(mainString,6,length(mainString)-5);
+ mainAboutString := replace(mainAboutString,'{',' ');
+ mainAboutString := replace(mainAboutString,'}',' ');
+ plusString := substr(plusString,2,length(plusString)-1);
+ minusString := substr(minusString,4,length(minusString)-4);
+
+ -- we find the components present and then process them based on the specific combinations
+ code := hasMain*4+hasPlus*2+hasMinus;
+ if(code = 7) then
+ finalString := '('||plusString||','||mainString||'*2.0,about('||mainAboutString||')*0.5) NOT ('||minusString||')';
+ elsif (code = 6) then
+ finalString := plusString||','||mainString||'*2.0'||',about('||mainAboutString||')*0.5';
+ elsif (code = 5) then
+ finalString := '('||mainString||',about('||mainAboutString||')) NOT ('||minusString||')';
+ elsif (code = 4) then
+ finalString := mainString;
+ finalString := replace(finalString,'*1,',NULL);
+ finalString := '('||finalString||')*2.0,about('||mainAboutString||')';
+ elsif (code = 3) then
+ finalString := '('||plusString||') NOT ('||minusString||')';
+ elsif (code = 2) then
+ finalString := plusString;
+ elsif (code = 1) then
+ -- not is a binary operator for intermedia text
+ finalString := 'totallyImpossibleString'||' NOT ('||minusString||')';
+ elsif (code = 0) then
+ finalString := '';
+ end if;
+
+ return finalString;
+end;
+/
+
+create or replace package body psn_res_application
+as
+ procedure create_magic_objects (
+ package_id in apm_packages.package_id%TYPE,
+ creation_user in acs_objects.creation_user%TYPE default null,
+ creation_ip in acs_objects.creation_ip%TYPE default null
+ )
+ is
+ v_role_object_id acs_objects.object_id%TYPE;
+ v_language_object_id acs_objects.object_id%TYPE;
+ v_proficiency_object_id acs_objects.object_id%TYPE;
+ begin
+ v_role_object_id := acs_object.new (
+ object_type => 'psn_tree_object',
+ creation_date => sysdate,
+ creation_user => creation_user,
+ creation_ip => creation_ip,
+ context_id => package_id
+ );
+ acs_object.new_description (
+ v_object_id => v_role_object_id,
+ v_shortname => 'Role Category Tree',
+ v_overview => 'Role Category Tree for Knowledge Library #' || package_id,
+ v_overview_html_p => 'f',
+ v_package_id => package_id
+ );
+ v_language_object_id := acs_object.new (
+ object_type => 'psn_tree_object',
+ creation_date => sysdate,
+ creation_user => creation_user,
+ creation_ip => creation_ip,
+ context_id => package_id
+ );
+ acs_object.new_description (
+ v_object_id => v_language_object_id,
+ v_shortname => 'Language Category Tree',
+ v_overview => 'Language Category Tree for Knowledge Library #' || package_id,
+ v_overview_html_p => 'f',
+ v_package_id => package_id
+ );
+ v_proficiency_object_id := acs_object.new (
+ object_type => 'psn_tree_object',
+ creation_date => sysdate,
+ creation_user => creation_user,
+ creation_ip => creation_ip,
+ context_id => package_id
+ );
+ acs_object.new_description (
+ v_object_id => v_proficiency_object_id,
+ v_shortname => 'Language Proficiency Category Tree',
+ v_overview => 'Language Proficiency Category Tree for Knowledge Library #' || package_id,
+ v_overview_html_p => 'f',
+ v_package_id => package_id
+ );
+
+ insert into psn_category_trees (package_id, role_magic_id, language_magic_id, proficiency_magic_id)
+ values (package_id, v_role_object_id, v_language_object_id, v_proficiency_object_id);
+
+ end create_magic_objects;
+
+ procedure copy (
+ src_package_id in apm_packages.package_id%TYPE,
+ dst_package_id in apm_packages.package_id%TYPE,
+ creation_user in acs_objects.creation_user%TYPE,
+ creation_ip in acs_objects.creation_ip%TYPE
+ )
+ is
+ begin
+
+ -- Copy relations between magic objects and category trees.
+ -- We do this with a cursor because some of the relations may not exist.
+
+ for c in (
+ select r.object_id_two as tree_id, octr.subtree_root_node_id as node_id, ct2.role_magic_id as object_id
+ from psn_category_trees ct1, psn_category_trees ct2, acs_rels r,
+ object_category_tree_rels octr
+ where ct1.package_id = src_package_id
+ and ct2.package_id = dst_package_id
+ and r.object_id_one = ct1.role_magic_id
+ and r.rel_type = 'object_category_tree_rel'
+ and octr.rel_id = r.rel_id
+ union all
+ select r.object_id_two, octr.subtree_root_node_id, ct2.language_magic_id
+ from psn_category_trees ct1, psn_category_trees ct2, acs_rels r,
+ object_category_tree_rels octr
+ where ct1.package_id = src_package_id
+ and ct2.package_id = dst_package_id
+ and r.object_id_one = ct1.language_magic_id
+ and r.rel_type = 'object_category_tree_rel'
+ and octr.rel_id = r.rel_id
+ union all
+ select r.object_id_two, octr.subtree_root_node_id, ct2.proficiency_magic_id
+ from psn_category_trees ct1, psn_category_trees ct2, acs_rels r,
+ object_category_tree_rels octr
+ where ct1.package_id = src_package_id
+ and ct2.package_id = dst_package_id
+ and r.object_id_one = ct1.proficiency_magic_id
+ and r.rel_type = 'object_category_tree_rel'
+ and octr.rel_id = r.rel_id
+ ) loop
+ category.map_tree(c.object_id, c.node_id, c.tree_id);
+ end loop;
+
+ end copy;
+
+end psn_res_application;
+/
+show errors
Index: openacs-4/contrib/obsolete-packages/library/sql/oracle/library-packages.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/sql/oracle/library-packages.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/sql/oracle/library-packages.sql 2 Jul 2003 12:19:42 -0000 1.1
@@ -0,0 +1,251 @@
+-- @cvs-id $Id: library-packages.sql,v 1.1 2003/07/02 12:19:42 peterm Exp $
+
+create or replace package library
+as
+ procedure copy (
+ src_package_id in apm_packages.package_id%TYPE,
+ dst_package_id in apm_packages.package_id%TYPE,
+ creation_user in acs_objects.creation_user%TYPE,
+ creation_ip in acs_objects.creation_ip%TYPE
+ );
+end library;
+/
+
+create or replace package question
+as
+ function insert_question (
+ v_question_id in sn_questions.question_id%TYPE default null,
+ v_pretty_name in sn_questions.pretty_name%TYPE,
+ v_abstract_data_type in sn_questions.abstract_data_type%TYPE,
+ v_order_by in sn_questions.order_by%TYPE,
+ v_default_value in sn_questions.default_value%TYPE,
+ v_entry_explanation in sn_questions.entry_explanation%TYPE,
+ v_creation_user in acs_objects.creation_user%TYPE,
+ v_creation_ip in acs_objects.creation_ip%TYPE,
+ v_context_id in acs_objects.context_id%TYPE default null,
+ v_insertion_date in acs_objects.creation_date%TYPE default sysdate,
+ v_references_q_id in sn_questions.question_id%TYPE default null
+ ) return sn_questions.question_id%TYPE;
+
+ procedure update_question (
+ v_question_id in sn_questions.question_id%TYPE,
+ v_pretty_name in sn_questions.pretty_name%TYPE,
+ v_abstract_data_type in sn_questions.abstract_data_type%TYPE,
+ v_order_by in sn_questions.order_by%TYPE,
+ v_default_value in sn_questions.default_value%TYPE,
+ v_entry_explanation in sn_questions.entry_explanation%TYPE,
+ v_modifying_user in acs_objects.creation_user%TYPE,
+ v_modifying_ip in acs_objects.modifying_ip%TYPE,
+ v_update_date in acs_objects.last_modified%TYPE default sysdate,
+ v_references_q_id in sn_questions.question_id%TYPE default null,
+ v_def_question_id in sn_questions.question_id%TYPE default null,
+ v_max_categories in sn_questions.max_categories%TYPE default null,
+ v_browse_p in sn_questions.browse_p%TYPE default 't'
+ );
+
+ procedure delete_question (
+ v_question_id in sn_questions.question_id%TYPE
+ );
+
+ procedure map_question_on_object (
+ v_question_id in sn_questions.question_id%TYPE,
+ v_object_type_id in sn_objects.object_type_id%TYPE,
+ v_form_number in sn_question_object_type_map.form_number%TYPE,
+ v_mandatory_p in sn_question_object_type_map.mandatory_p%TYPE,
+ v_question_state in sn_question_object_type_map.question_state%TYPE
+ );
+
+ function root_branch_p (
+ v_question_id in sn_questions.question_id%TYPE
+ ) return char;
+
+ procedure delete_all_questions(
+ v_context_id in acs_objects.context_id%TYPE
+ ) ;
+
+end question;
+/
+show errors
+
+create or replace package object_type
+as
+ function insert_object_type (
+ v_pretty_name in sn_object_types.pretty_name%TYPE,
+ v_pretty_plural in sn_object_types.pretty_plural%TYPE,
+ v_graphic in sn_object_types.graphic%TYPE,
+ v_deleted_p in sn_object_types.deleted_p%TYPE,
+ v_browse_p in sn_object_types.browse_p%TYPE,
+ v_public_p in sn_object_types.public_p%TYPE,
+ v_sort_key in sn_object_types.sort_key%TYPE,
+ v_short_description in sn_object_types.short_description%TYPE,
+ v_long_description in sn_object_types.long_description%TYPE,
+ v_linked_question_id in sn_object_types.linked_question_id%TYPE,
+ v_public_until in sn_object_types.public_until%TYPE,
+ v_default_age_filter in sn_object_types.default_age_filter%TYPE,
+ v_creation_user in acs_objects.creation_user%TYPE,
+ v_creation_ip in acs_objects.creation_ip%TYPE,
+ v_context_id in acs_objects.context_id%TYPE,
+ v_short_name in sn_object_types.short_name%TYPE default null,
+ v_insertion_date in acs_objects.creation_date%TYPE default sysdate
+ ) return sn_object_types.object_type_id%TYPE;
+
+ function insert_object_type (
+ v_pretty_name in sn_object_types.pretty_name%TYPE,
+ v_pretty_plural in sn_object_types.pretty_plural%TYPE,
+ v_browse_p in sn_object_types.browse_p%TYPE,
+ v_default_age_filter in sn_object_types.default_age_filter%TYPE,
+ v_creation_user in acs_objects.creation_user%TYPE,
+ v_creation_ip in acs_objects.creation_ip%TYPE,
+ v_context_id in acs_objects.context_id%TYPE,
+ v_short_name in sn_object_types.short_name%TYPE default null,
+ v_insertion_date in acs_objects.creation_date%TYPE default sysdate
+ ) return sn_object_types.object_type_id%TYPE;
+
+ procedure delete_object_type (
+ v_object_type_id in sn_object_types.object_type_id%TYPE
+ );
+
+ procedure delete_all_object_types (
+ v_context_id in acs_objects.context_id%TYPE
+ );
+
+ procedure copy_object_type (
+ v_object_type_id in sn_object_types.object_type_id%TYPE,
+ v_target_context_id in acs_objects.context_id%TYPE,
+ v_creation_user in acs_objects.creation_user%TYPE,
+ v_creation_ip in acs_objects.creation_ip%TYPE
+ );
+
+ procedure copy_all_object_types (
+ src_package_id in acs_objects.context_id%TYPE,
+ dst_package_id in acs_objects.context_id%TYPE,
+ creation_user in acs_objects.creation_user%TYPE,
+ creation_ip in acs_objects.creation_ip%TYPE
+ );
+
+end object_type;
+/
+show errors
+
+create or replace package object
+as
+ function name (
+ object_id in sn_objects.object_id%TYPE
+ ) return varchar2;
+
+ function insert_object (
+ v_object_type_id in sn_objects.object_type_id%TYPE,
+ v_creation_user in acs_objects.creation_user%TYPE,
+ v_creation_ip in acs_objects.creation_ip%TYPE,
+ v_context_id in acs_objects.context_id%TYPE,
+ v_insertion_date in acs_objects.creation_date%TYPE default sysdate
+ ) return sn_objects.object_id%TYPE;
+
+ function insert_object (
+ v_object_id in acs_objects.object_id%TYPE,
+ v_object_type_id in sn_objects.object_type_id%TYPE,
+ v_creation_user in acs_objects.creation_user%TYPE default null,
+ v_creation_ip in acs_objects.creation_ip%TYPE default null,
+ v_context_id in acs_objects.context_id%TYPE default null,
+ v_insertion_date in acs_objects.creation_date%TYPE default sysdate
+ ) return sn_objects.object_id%TYPE;
+
+ procedure delete_object (
+ v_object_id in sn_objects.object_id%TYPE
+ );
+
+ procedure save_content (
+ v_object_id in sn_objects.object_id%TYPE,
+ v_question_id in sn_questions.question_id%TYPE,
+ v_html_p in sn_content.html_p%TYPE,
+ v_content_length in integer,
+ v_modifying_user in acs_objects.creation_user%TYPE,
+ v_modifying_ip in acs_objects.modifying_ip%TYPE,
+ v_update_date in acs_objects.last_modified%TYPE default sysdate
+ );
+
+ procedure delete_all_objects_of_a_type (
+ v_object_type_id in sn_object_types.object_type_id%TYPE
+ );
+
+ procedure delete_all_objects_of_an_inst (
+ v_context_id in acs_objects.context_id%TYPE
+ );
+
+ procedure audit_object (
+ v_object_id in sn_objects.object_id%TYPE,
+ v_question_id in sn_questions.question_id%TYPE,
+ v_last_modifying_user_id in acs_objects.modifying_ip%TYPE,
+ v_modifying_ip in acs_objects.modifying_ip%TYPE,
+ v_content in sn_audit_table.content%TYPE,
+ v_last_modified in acs_objects.last_modified%TYPE default sysdate
+ );
+
+ function copy_object (
+ v_object_id in acs_objects.object_id%TYPE,
+ v_target_id in acs_objects.object_id%TYPE default null,
+ v_creation_user in acs_objects.creation_user%TYPE default null,
+ v_creation_ip in acs_objects.creation_ip%TYPE default null,
+ v_context_id in acs_objects.context_id%TYPE default null
+ ) return sn_objects.object_id%TYPE;
+
+end object;
+/
+show errors
+
+
+create or replace package km_utilities
+as
+ function km_ancestor_list (
+ v_object_id in integer)
+ return varchar;
+
+ function km_category_list (
+ v_object_id in integer,
+ v_parent_node_id in varchar)
+ return varchar;
+
+ function km_xml (
+ id sn_objects.object_id%type)
+ return clob;
+
+ procedure km_populate_flat_object_hier;
+
+ procedure km_logger (
+ v_who_is_logging varchar2,
+ v_log_text varchar2);
+
+ function shortname_string (
+ p_object_id in sn_objects.object_id%TYPE,
+ p_question_id1 in sn_questions.question_id%TYPE,
+ p_question_id2 in sn_questions.question_id%TYPE,
+ p_question_id3 in sn_questions.question_id%TYPE default 0)
+ return varchar2;
+
+ function strip_html_and_limit_size
+ (p_overview in sn_objects.overview%TYPE)
+ return VARCHAR2;
+
+end km_utilities;
+/
+show errors
+
+create or replace package psn_res_application
+as
+
+ procedure create_magic_objects (
+ package_id in apm_packages.package_id%TYPE,
+ creation_user in acs_objects.creation_user%TYPE default null,
+ creation_ip in acs_objects.creation_ip%TYPE default null
+ );
+
+ procedure copy (
+ src_package_id in apm_packages.package_id%TYPE,
+ dst_package_id in apm_packages.package_id%TYPE,
+ creation_user in acs_objects.creation_user%TYPE,
+ creation_ip in acs_objects.creation_ip%TYPE
+ );
+
+end psn_res_application;
+/
+show errors
Index: openacs-4/contrib/obsolete-packages/library/sql/oracle/library-temp-tables.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/sql/oracle/library-temp-tables.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/sql/oracle/library-temp-tables.sql 2 Jul 2003 12:19:42 -0000 1.1
@@ -0,0 +1,18 @@
+-- Here are the temporary tables that are being used by library-internal
+-- functions. Read Tom Kyte's book if you want to understand why I'm using
+-- temporary tables.
+
+create global temporary table km_temp_questions
+ (old_id integer ,
+ new_id integer)
+ on commit delete rows ;
+
+create global temporary table km_temp_object_types
+ (old_id integer ,
+ new_id integer)
+ on commit delete rows ;
+
+create global temporary table km_temp_answer_options
+ (old_id integer ,
+ new_id integer)
+ on commit delete rows ;
Index: openacs-4/contrib/obsolete-packages/library/sql/oracle/library-triggers.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/sql/oracle/library-triggers.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/sql/oracle/library-triggers.sql 2 Jul 2003 12:19:42 -0000 1.1
@@ -0,0 +1,175 @@
+create or replace trigger sn_object_types_in_tr
+after insert on sn_object_types
+for each row
+begin
+ acs_object.new_description(
+ v_object_id => :new.object_type_id,
+ v_shortname => :new.pretty_name,
+ v_package_id => :new.context_id);
+end sn_objects_in_tr;
+/
+show errors
+
+create or replace trigger sn_object_types_up_tr
+after update on sn_object_types
+for each row
+declare
+begin
+ acs_object.set_shortname(
+ v_object_id => :new.object_type_id,
+ v_shortname => :new.pretty_name);
+
+ acs_object.set_package_id(
+ v_object_id => :new.object_type_id,
+ v_package_id => :new.context_id);
+
+end sn_object_types_up_tr;
+/
+show errors
+
+
+create or replace trigger sn_objects_in_tr
+after insert on sn_objects
+for each row
+declare
+ v_new_one_line_description sn_objects.one_line_description%TYPE;
+ v_creation_date acs_objects.creation_date%TYPE;
+begin
+ if :new.one_line_description is null or length(trim(:new.one_line_description)) = 0 then
+ select 'Unnamed ' || pretty_name
+ into v_new_one_line_description
+ from sn_object_types
+ where object_type_id = :new.object_type_id;
+ else
+ v_new_one_line_description := :new.one_line_description;
+ end if;
+
+ select creation_date into v_creation_date
+ from acs_objects
+ where object_id = :new.object_id;
+
+ acs_object.new_description(
+ v_object_id => :new.object_id,
+ v_shortname => substr(v_new_one_line_description,0,199),
+ v_overview => :new.overview,
+ v_presentation => 'presentation=private,object_type_id=' || :new.object_type_id,
+ v_overview_html_p => :new.overview_html_p,
+ v_package_id => :new.context_id,
+ v_publish_date => v_creation_date);
+
+ -- Fill the content areas
+ insert into acs_object_areas
+ (object_id, area_id, package_id)
+ values
+ (:new.object_id, :new.object_type_id, :new.context_id);
+end sn_objects_in_tr;
+/
+show errors
+
+create or replace trigger sn_objects_up_tr
+after update of one_line_description, overview, overview_html_p, context_id, public_p,
+ archived_p, in_review_p, expiration_date, user_checkoff_date, original_author_id on sn_objects
+for each row
+declare
+ v_new_one_line_description sn_objects.one_line_description%TYPE;
+ v_presentation acs_objects_description.presentation%TYPE;
+ v_state acs_objects_description.state%TYPE;
+ v_creation_date acs_objects.creation_date%TYPE;
+begin
+ if :new.one_line_description is null or length(trim(:new.one_line_description)) = 0 then
+ select 'Unnamed ' || pretty_name
+ into v_new_one_line_description
+ from sn_object_types
+ where object_type_id = :new.object_type_id;
+ else
+ v_new_one_line_description := :new.one_line_description;
+ end if;
+
+ if :new.original_author_id <> :old.original_author_id then
+ update acs_objects set creation_user = :new.original_author_id
+ where object_id = :new.object_id;
+ end if;
+
+ acs_object.set_shortname(
+ v_object_id => :new.object_id,
+ v_shortname => substr(v_new_one_line_description,0,199));
+
+ acs_object.set_overview(
+ v_object_id => :new.object_id,
+ v_overview => :new.overview,
+ v_overview_html_p => :new.overview_html_p);
+
+ if :new.context_id <> :old.context_id then
+ acs_object.set_package_id(
+ v_object_id => :new.object_id,
+ v_package_id => :new.context_id);
+
+ update acs_object_areas
+ set area_id = :new.object_type_id,
+ package_id= :new.context_id
+ where object_id = :new.object_id;
+ end if;
+
+ if :new.public_p <> :old.public_p
+ or :new.archived_p <> :old.archived_p
+ or :new.in_review_p <> :old.in_review_p then
+
+ if :new.public_p = 't' then
+ v_presentation := 'presentation=public';
+ elsif :new.public_p = 'f' then
+ v_presentation := 'presentation=private';
+ end if;
+
+ v_presentation := v_presentation || ',object_type_id=' || :new.object_type_id;
+
+ if :new.archived_p = 't' then
+ v_presentation := v_presentation || ',archived';
+ end if;
+
+ if :new.in_review_p = 't' then
+ v_presentation := v_presentation || ',in_review';
+ end if;
+
+ acs_object.set_presentation(
+ v_object_id => :new.object_id,
+ v_presentation => v_presentation);
+ end if;
+
+ if :new.expiration_date <> :old.expiration_date
+ or :new.archived_p <> :old.archived_p then
+ if :new.expiration_date <= sysdate then
+ v_state := 'd';
+ else
+ if :new.archived_p = 't' then
+ v_state := 'a';
+ elsif :new.archived_p = 'f' then
+ v_state := 'l';
+ end if;
+ end if;
+
+ acs_object.set_state(
+ v_object_id => :new.object_id,
+ v_state => v_state);
+ end if;
+
+ if :new.user_checkoff_date <> :old.user_checkoff_date
+ or (:new.user_checkoff_date is not null and :old.user_checkoff_date is null) then
+ acs_object.set_publish_date(
+ v_object_id => :new.object_id,
+ v_publish_date => :new.user_checkoff_date);
+ end if;
+
+ if :new.user_checkoff_date is null and :old.user_checkoff_date is not null then
+ select creation_date
+ into v_creation_date
+ from acs_objects
+ where object_id = :new.object_id;
+
+ acs_object.set_publish_date(
+ v_object_id => :new.object_id,
+ v_publish_date => v_creation_date);
+ end if;
+
+end sn_objects_up_tr;
+/
+show errors
Index: openacs-4/contrib/obsolete-packages/library/sql/oracle/library-workflow-create.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/sql/oracle/library-workflow-create.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/sql/oracle/library-workflow-create.sql 2 Jul 2003 12:19:42 -0000 1.1
@@ -0,0 +1,355 @@
+/*
+ * Business Process Definition: Library Approval (library_approval_wf)
+ *
+ * Auto-generated by ACS Workflow Export, version 4.0.2
+ *
+ * Context: default
+ */
+
+-- This table will be used to queue email notifications from Oracle,
+-- which will then be composed and sent by a scheduled Tcl procedure.
+create table wf_library_notifications (
+ notification_id
+ integer
+ constraint wf_libr_notifications_pk
+ primary key,
+ task_id
+ integer
+ constraint wf_libr_n_task_id_fk
+ references wf_tasks
+ constraint wf_libr_n_task_id_nn
+ not null,
+ template_key
+ varchar2(64)
+ constraint wf_libr_n_template_fk
+ references et_templates(key)
+ constraint wf_libr_n_template_nn
+ not null,
+ recipient_id
+ integer
+ constraint wf_libr_n_recipient_fk
+ references users
+ constraint wf_libr_n_recipient_nn
+ not null,
+ sender_id
+ integer
+ constraint wf_libr_n_sender_fk
+ references users
+ constraint wf_libr_n_sender_nn
+ not null,
+ body
+ varchar2(4000)
+ default null
+);
+
+create sequence library_notification_id_seq start with 1;
+
+create or replace trigger wf_library_notifications_itrg
+ before insert on wf_library_notifications for each row
+begin
+ select library_notification_id_seq.nextval into :new.notification_id from dual;
+end;
+/
+show errors
+
+-- This table will hold one row for each case using this workflow.
+create table wf_library_approval_cases (
+ case_id integer
+ constraint wf_library_appr_cases_pk
+ primary key
+ constraint wf_library_appr_cases_case_fk
+ references wf_cases
+);
+
+declare
+ v_workflow_key wf_workflows.workflow_key%TYPE;
+begin
+ v_workflow_key := workflow.create_workflow(
+ workflow_key => 'library_approval_wf',
+ pretty_name => 'Library Approval Process',
+ pretty_plural => 'Library Approval Process',
+ description => 'Workflow for Approving a Knowledge Object Publication in the Library',
+ table_name => 'wf_library_approval_cases'
+ );
+
+ -- Creating places
+ workflow.add_place (
+ workflow_key => 'library_approval_wf',
+ place_key => 'start',
+ place_name => 'Needs to be reviewed',
+ sort_order => 1
+ );
+ workflow.add_place (
+ workflow_key => 'library_approval_wf',
+ place_key => 'to_be_clarified',
+ place_name => 'Needs to be clarified',
+ sort_order => 2
+ );
+ workflow.add_place (
+ workflow_key => 'library_approval_wf',
+ place_key => 'ready_for_publication',
+ place_name => 'Ready for Publication',
+ sort_order => 3
+ );
+ workflow.add_place (
+ workflow_key => 'library_approval_wf',
+ place_key => 'end',
+ place_name => 'Closed',
+ sort_order => 4
+ );
+
+ -- Creating transitions
+ workflow.add_transition (
+ workflow_key => 'library_approval_wf',
+ transition_key => 'library_review',
+ transition_name => 'Review Knowledge Object',
+ sort_order => 1,
+ trigger_type => 'user'
+ );
+ workflow.add_transition (
+ workflow_key => 'library_approval_wf',
+ transition_key => 'library_clarify',
+ transition_name => 'Clarify Knowledge Object',
+ sort_order => 2,
+ trigger_type => 'user'
+ );
+ workflow.add_transition (
+ workflow_key => 'library_approval_wf',
+ transition_key => 'library_publish',
+ transition_name => 'Publish Knowledge Object',
+ sort_order => 3,
+ trigger_type => 'automatic'
+ );
+end;
+/
+show errors
+
+begin
+ -- creating arcs
+ -- review in
+ -- in
+ workflow.add_arc (
+ workflow_key => 'library_approval_wf',
+ transition_key => 'library_review',
+ place_key => 'start',
+ direction => 'in'
+ );
+ -- out
+ workflow.add_arc (
+ workflow_key => 'library_approval_wf',
+ transition_key => 'library_review',
+ place_key => 'to_be_clarified',
+ direction => 'out',
+ guard_callback => 'wf_callback.guard_attribute_true',
+ guard_custom_arg => 'library_object_needs_clarification',
+ guard_description => 'Knowledge Object needs clarification'
+ );
+ workflow.add_arc (
+ workflow_key => 'library_approval_wf',
+ transition_key => 'library_review',
+ place_key => 'ready_for_publication',
+ direction => 'out',
+ guard_callback => '#',
+ guard_description => 'Knowledge Object ready for publication'
+ );
+
+ -- clarify
+ -- in
+ workflow.add_arc (
+ workflow_key => 'library_approval_wf',
+ transition_key => 'library_clarify',
+ place_key => 'to_be_clarified',
+ direction => 'in'
+ );
+ -- out
+ workflow.add_arc (
+ workflow_key => 'library_approval_wf',
+ transition_key => 'library_clarify',
+ place_key => 'start',
+ direction => 'out'
+ );
+
+ -- publish
+ -- in
+ workflow.add_arc (
+ workflow_key => 'library_approval_wf',
+ transition_key => 'library_publish',
+ place_key => 'ready_for_publication',
+ direction => 'in'
+ );
+
+ -- out
+ workflow.add_arc (
+ workflow_key => 'library_approval_wf',
+ transition_key => 'library_publish',
+ place_key => 'end',
+ direction => 'out',
+ guard_callback => 'wf_callback.guard_attribute_true',
+ guard_custom_arg => 'library_object_published',
+ guard_description => 'Knowledge Object published'
+ );
+
+end;
+/
+show errors
+
+declare
+ v_attribute_id acs_attributes.attribute_id%TYPE;
+begin
+ v_attribute_id := workflow.create_attribute(
+ workflow_key => 'library_approval_wf',
+ attribute_name => 'library_object_needs_clarification',
+ datatype => 'boolean',
+ pretty_name => 'Knowledge Object needs clarification',
+ default_value => 'f'
+ );
+
+ insert into wf_transition_attribute_map
+ (workflow_key, transition_key, attribute_id, sort_order)
+ values
+ ('library_approval_wf', 'library_review', v_attribute_id, 1);
+
+ v_attribute_id := workflow.create_attribute(
+ workflow_key => 'library_approval_wf',
+ attribute_name => 'verified',
+ datatype => 'boolean',
+ pretty_name => 'Result is okay',
+ default_value => 't'
+ );
+
+ v_attribute_id := workflow.create_attribute(
+ workflow_key => 'library_approval_wf',
+ attribute_name => 'library_object_published',
+ datatype => 'boolean',
+ pretty_name => 'Knowledge Object published',
+ default_value => 't'
+ );
+
+end;
+/
+show errors
+
+insert into wf_context_transition_info (
+ context_key,
+ workflow_key,
+ transition_key,
+ assignment_callback,
+ fire_callback,
+ notification_callback,
+ notification_custom_arg,
+ unassigned_callback,
+ access_privilege
+) values (
+ 'default',
+ 'library_approval_wf',
+ 'library_review',
+ 'library_callback.assign_task_to_assignee',
+ 'library_callback.review_fire',
+ 'library_callback.notification',
+ 'library_review_object',
+ 'library_callback.notify_admin',
+ 'write'
+);
+
+insert into wf_context_transition_info (
+ context_key,
+ workflow_key,
+ transition_key,
+ assignment_callback,
+ fire_callback,
+ notification_callback,
+ notification_custom_arg,
+ access_privilege
+) values (
+ 'default',
+ 'library_approval_wf',
+ 'library_clarify',
+ 'library_callback.assign_task_to_submitter',
+ 'library_callback.clarify_fire',
+ 'library_callback.notification',
+ 'library_clarify_object',
+ 'admin'
+);
+
+insert into wf_context_transition_info (
+ context_key,
+ workflow_key,
+ transition_key,
+ fire_callback,
+ notification_callback,
+ notification_custom_arg,
+ access_privilege
+) values (
+ 'default',
+ 'library_approval_wf',
+ 'library_publish',
+ 'library_callback.publish_fire',
+ 'library_callback.notification',
+ 'library_published',
+ 'admin'
+);
+insert into wf_context_task_panels (
+ context_key,
+ workflow_key,
+ transition_key,
+ sort_key,
+ header,
+ template_url
+) values (
+ 'default',
+ 'library_approval_wf',
+ 'library_review',
+ 1,
+ 'Knowledge Object Info',
+ '/packages/library/wf-templates/object-info'
+);
+
+insert into wf_context_task_panels (
+ context_key,
+ workflow_key,
+ transition_key,
+ sort_key,
+ header,
+ template_url
+) values (
+ 'default',
+ 'library_approval_wf',
+ 'library_review',
+ 2,
+ 'What to do',
+ '/packages/library/wf-templates/review'
+);
+
+insert into wf_context_task_panels (
+ context_key,
+ workflow_key,
+ transition_key,
+ sort_key,
+ header,
+ template_url
+) values (
+ 'default',
+ 'library_approval_wf',
+ 'library_clarify',
+ 1,
+ 'Knowledge Object Info',
+ '/packages/library/wf-templates/object-info'
+);
+
+insert into wf_context_task_panels (
+ context_key,
+ workflow_key,
+ transition_key,
+ sort_key,
+ header,
+ template_url
+) values (
+ 'default',
+ 'library_approval_wf',
+ 'library_clarify',
+ 2,
+ 'What to do',
+ '/packages/library/wf-templates/clarify'
+);
+
+commit;
Index: openacs-4/contrib/obsolete-packages/library/sql/oracle/library-workflow-drop.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/sql/oracle/library-workflow-drop.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/sql/oracle/library-workflow-drop.sql 2 Jul 2003 12:19:42 -0000 1.1
@@ -0,0 +1,30 @@
+--
+-- packages/library/sql/library-workflow-drop.sql
+--
+--
+-- @author Dirk Gomez (sharenet@dirkgomez.de)
+-- @author Timo Hentschel (timo@arsidigta.com)
+--
+-- @creation-date 2002-02-22
+--
+-- @cvs-id $Id: library-workflow-drop.sql,v 1.1 2003/07/02 12:19:42 peterm Exp $
+--
+
+truncate table wf_library_notifications;
+truncate table wf_ttracker_notifications;
+
+begin
+ workflow.delete_cases('library_approval_wf');
+end;
+/
+show errors
+
+drop table wf_library_approval_cases;
+begin
+ workflow.drop_workflow('library_approval_wf');
+end;
+/
+show errors
+
+drop table wf_library_notifications;
+drop sequence library_notification_id_seq;
Index: openacs-4/contrib/obsolete-packages/library/sql/oracle/library-workflow-packages.sql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/sql/oracle/library-workflow-packages.sql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/sql/oracle/library-workflow-packages.sql 2 Jul 2003 12:19:42 -0000 1.1
@@ -0,0 +1,458 @@
+create or replace package library_workflow
+as
+ function new_workflow_case (
+ p_object_id in sn_objects.object_id%TYPE,
+ p_creation_date in acs_objects.creation_date%TYPE default sysdate,
+ p_creation_user in acs_objects.creation_user%TYPE,
+ p_creation_ip in acs_objects.creation_ip%TYPE default null,
+ p_publisher_id in sn_objects.publisher_id%TYPE default null
+ ) return integer;
+
+ procedure delete_workflow_case (
+ object_id in sn_objects.object_id%TYPE
+ );
+
+ function workflow_url (
+ absolute_p in char default 't'
+ ) return varchar2;
+
+ function notification_sender (
+ package_id in apm_packages.package_id%TYPE
+ ) return users.user_id%TYPE;
+
+end library_workflow;
+/
+show errors
+
+
+create or replace package body library_workflow
+as
+ function new_workflow_case (
+ p_object_id in sn_objects.object_id%TYPE,
+ p_creation_date in acs_objects.creation_date%TYPE default sysdate,
+ p_creation_user in acs_objects.creation_user%TYPE,
+ p_creation_ip in acs_objects.creation_ip%TYPE default null,
+ p_publisher_id in sn_objects.publisher_id%TYPE default null
+ ) return integer
+ is
+ v_case_id wf_cases.case_id%TYPE;
+ begin
+ -- create a new case
+ v_case_id := workflow_case.new (
+ workflow_key => 'library_approval_wf',
+ object_id => p_object_id,
+ creation_user => p_creation_user,
+ creation_ip => p_creation_ip
+ );
+
+ -- start the case
+ workflow_case.start_case (
+ case_id => v_case_id,
+ creation_user => p_creation_user,
+ creation_ip => p_creation_ip
+ );
+
+ -- now automatically assign the task to the coordinator. The workflow
+ -- package requires static assignment otherwise.
+ return v_case_id;
+ end new_workflow_case ;
+
+ procedure delete_workflow_case (
+ object_id in sn_objects.object_id%TYPE
+ )
+ is
+ cursor case_cur is
+ select case_id
+ from wf_cases
+ where object_id = object_id;
+ case_rec case_cur%ROWTYPE;
+ begin
+ open case_cur;
+ fetch case_cur into case_rec;
+
+ -- delete the workflow case that's associated with this object
+
+ if case_cur%FOUND then
+ workflow_case.delete(case_rec.case_id);
+ end if;
+
+ close case_cur;
+ end delete_workflow_case ;
+
+ function workflow_url (
+ absolute_p in char default 't'
+ ) return varchar2
+ is
+ v_system_url apm_parameter_values.attr_value%TYPE;
+ cursor node_cur is
+ select sn.node_id
+ from site_nodes sn,
+ apm_packages ap
+ where ap.package_key = 'acs-workflow'
+ and sn.object_id = ap.package_id;
+ node_rec node_cur%ROWTYPE;
+ begin
+ -- try to get the id of the site node that contains acs workflow
+ open node_cur;
+ fetch node_cur into node_rec;
+ if node_cur%NOTFOUND then
+ close node_cur;
+ raise_application_error(-20000, 'ACS Workflow must be mounted');
+ end if;
+ close node_cur;
+
+ -- if only relative url is needed
+ if absolute_p <> 't' then
+ return site_node.url(node_rec.node_id);
+ end if;
+
+ -- since there's only 1 instance of the kernel
+ -- it's ok to use select.. into..
+ select apv.attr_value into v_system_url
+ from apm_parameter_values apv,
+ apm_parameters ap
+ where ap.package_key = 'acs-kernel'
+ and ap.parameter_name = 'SystemURL'
+ and ap.parameter_id = apv.parameter_id;
+
+ return v_system_url||site_node.url(node_rec.node_id);
+
+ end workflow_url;
+
+ function notification_sender (
+ package_id in apm_packages.package_id%TYPE
+ ) return users.user_id%TYPE
+ is
+ v_result users.user_id%TYPE;
+ begin
+ select nvl(apm.get_value(notification_sender.package_id,'NotificationSender'),-1)
+ into v_result
+ from dual;
+
+ return v_result;
+ end notification_sender;
+
+end library_workflow;
+/
+show errors
+
+create or replace package library_callback
+as
+ procedure assign_task_to_submitter (
+ task_id in number,
+ custom_arg in varchar2
+ );
+
+ procedure assign_task_to_assignee (
+ task_id in number,
+ custom_arg in varchar2
+ );
+
+ procedure publish_fire (
+ case_id in number,
+ transition_key in varchar2,
+ custom_arg in varchar2
+ );
+
+ procedure clarify_fire (
+ case_id in number,
+ transition_key in varchar2,
+ custom_arg in varchar2
+ );
+
+ procedure review_fire (
+ case_id in number,
+ transition_key in varchar2,
+ custom_arg in varchar2
+ );
+
+ procedure notification (
+ task_id in number,
+ custom_arg in varchar2,
+ party_to in integer,
+ party_from in out integer,
+ subject in out varchar2,
+ body in out varchar2,
+ sent_p in out char
+ );
+
+ procedure notify_admin (
+ task_id in number,
+ custom_arg in varchar2
+ ) ;
+
+end library_callback;
+/
+show errors
+
+create or replace package body library_callback
+as
+ procedure assign_task_to_assignee (
+ task_id in number,
+ custom_arg in varchar2
+ )
+ is
+ v_publisher_id users.user_id%TYPE;
+ v_case_id wf_tasks.case_id%TYPE;
+ v_transition_key wf_tasks.transition_key%TYPE;
+ begin
+ begin
+ -- let's look up the last publisher.
+ select o.publisher_id, wt.case_id, wt.transition_key
+ into v_publisher_id, v_case_id, v_transition_key
+ from sn_objects o, wf_tasks wt, wf_cases wc
+ where wt.task_id = assign_task_to_assignee.task_id
+ and wt.case_id = wc.case_id
+ and wc.object_id = o.object_id
+ and o.publisher_id is not null
+ and (acs_permission.permission_p(o.object_id, o.publisher_id , 'km_publish'))='t';
+
+ workflow_case.add_task_assignment(assign_task_to_assignee.task_id, v_publisher_id);
+ workflow_case.add_manual_assignment (
+ case_id => v_case_id,
+ transition_key => v_transition_key,
+ party_id => v_publisher_id
+ );
+
+ exception
+ when no_data_found then
+ -- find the default assignees for this community
+
+ for v_approval_coordinators in (
+ select ac.coordinator_id,
+ wt.case_id,
+ wt.transition_key
+ from acs_objects ao, wf_tasks wt,wf_cases wc,
+ approval_coordinators ac
+ where wt.task_id = assign_task_to_assignee.task_id
+ and wt.case_id = wc.case_id
+ and wc.object_id = ao.object_id
+ and ac.package_id = ao.context_id )
+ loop
+ workflow_case.add_task_assignment(assign_task_to_assignee.task_id, v_approval_coordinators.coordinator_id);
+ workflow_case.add_manual_assignment (
+ case_id => v_approval_coordinators.case_id,
+ transition_key => v_approval_coordinators.transition_key,
+ party_id => v_approval_coordinators.coordinator_id
+ );
+ end loop;
+ end;
+ end assign_task_to_assignee;
+
+ procedure assign_task_to_submitter (
+ task_id in number,
+ custom_arg in varchar2
+ )
+ is
+ cursor object_cur is
+ select ao.creation_user,
+ wt.case_id,
+ wt.transition_key
+ from acs_objects ao, wf_tasks wt,wf_cases wc
+ where wt.task_id = assign_task_to_submitter.task_id
+ and wt.case_id = wc.case_id
+ and wc.object_id = ao.object_id;
+ object_rec object_cur%ROWTYPE;
+ begin
+ -- find the creation user of the object (submitter)
+ open object_cur;
+ fetch object_cur into object_rec;
+ close object_cur;
+
+ -- assign the task to the object submitter
+ workflow_case.add_task_assignment(assign_task_to_submitter.task_id, object_rec.creation_user);
+ workflow_case.add_manual_assignment (
+ case_id => object_rec.case_id,
+ transition_key => object_rec.transition_key,
+ party_id => object_rec.creation_user
+ );
+
+ end assign_task_to_submitter;
+
+ procedure publish_fire (
+ case_id in number,
+ transition_key in varchar2,
+ custom_arg in varchar2
+ )
+ is
+ v_journal_id journal_entries.journal_id%TYPE;
+ v_task_id wf_tasks.task_id%TYPE;
+ v_party_from users.user_id%TYPE;
+ v_party_to users.user_id%TYPE;
+ v_author_id users.user_id%TYPE;
+ v_subject varchar2(4000);
+ v_body varchar2(4000);
+ v_request_id integer;
+ v_sent_p char(1);
+ begin
+ select distinct(task_id) into v_task_id
+ from wf_tasks t
+ where case_id = publish_fire.case_id
+ and rownum = 1
+ order by task_id desc;
+
+ select ao.creation_user, so.original_author_id
+ into v_party_to, v_author_id
+ from acs_objects ao, wf_cases c, sn_objects so
+ where ao.object_id = c.case_id
+ and c.case_id = publish_fire.case_id
+ and so.object_id = c.object_id;
+
+ v_party_from := -1;
+ v_subject := 'default';
+ v_body := 'default';
+ v_sent_p := 'f';
+
+ library_callback.notification (
+ task_id => v_task_id,
+ custom_arg => 'library_published',
+ party_to => v_party_to,
+ party_from => v_party_from,
+ subject => v_subject,
+ body => v_body,
+ sent_p => v_sent_p
+ );
+
+ if v_party_to != v_author_id then
+ library_callback.notification (
+ task_id => v_task_id,
+ custom_arg => 'library_published',
+ party_to => v_author_id,
+ party_from => v_party_from,
+ subject => v_subject,
+ body => v_body,
+ sent_p => v_sent_p
+ );
+ end if;
+
+ v_journal_id := journal_entry.new (
+ object_id => case_id,
+ action => 'modify',
+ action_pretty => 'Attribute Change',
+ msg => 'Automatic action by the workflow process'
+ );
+ workflow_case.set_attribute_value (
+ journal_id => v_journal_id,
+ attribute_name => 'library_object_published',
+ value => 't'
+ );
+
+ end publish_fire;
+
+ procedure clarify_fire (
+ case_id in number,
+ transition_key in varchar2,
+ custom_arg in varchar2
+ )
+ is
+ v_journal_id journal_entries.journal_id%TYPE;
+ begin
+ v_journal_id := journal_entry.new (
+ object_id => case_id,
+ action => 'modify',
+ action_pretty => 'Attribute Change',
+ msg => 'Automatic action by the workflow process'
+ );
+ workflow_case.set_attribute_value (
+ journal_id => v_journal_id,
+ attribute_name => 'library_object_needs_clarification',
+ value => 'f'
+ );
+
+ end clarify_fire;
+
+ procedure review_fire (
+ case_id in number,
+ transition_key in varchar2,
+ custom_arg in varchar2
+ )
+ is
+ v_journal_id journal_entries.journal_id%TYPE;
+ begin
+ v_journal_id := journal_entry.new (
+ object_id => case_id,
+ action => 'modify',
+ action_pretty => 'Attribute Change',
+ msg => 'Automatic action by the workflow process'
+ );
+ workflow_case.set_attribute_value (
+ journal_id => v_journal_id,
+ attribute_name => 'verified',
+ value => 't'
+ );
+ end review_fire;
+
+ procedure notification (
+ task_id in number,
+ custom_arg in varchar2,
+ party_to in integer,
+ party_from in out integer,
+ subject in out varchar2,
+ body in out varchar2,
+ sent_p in out char
+ )
+ is
+ begin
+ select o.creation_user, j.msg into notification.party_from, notification.body
+ from acs_objects o, journal_entries j
+ where o.object_id = j.journal_id
+ and j.journal_id = (select max(j2.journal_id) from journal_entries j2, wf_tasks t, acs_objects o2
+ where t.case_id = j2.object_id
+ and t.task_id = notification.task_id
+ and o2.object_id = j2.journal_id
+ and o2.creation_user is not null);
+
+ insert into wf_library_notifications (task_id, template_key, recipient_id, sender_id, body)
+ values (notification.task_id, notification.custom_arg, notification.party_to,
+ notification.party_from, notification.body);
+
+ sent_p := 't';
+ end notification;
+
+ procedure notify_admin (
+ task_id in number,
+ custom_arg in varchar2
+ )
+ is
+ -- uses 2 separate queries to find out who has 'admin' privilege on this package
+ -- because we don't want to join any table with acs_object_party_privilege_map
+ -- unless we absolutely have to (in this case, users table)
+ -- the first query is only used to gather object info and package id
+ cursor object_cur is
+ select o.object_id,
+ o.one_line_description,
+ o.context_id as package_id
+ from sn_objects o,
+ wf_cases wc,
+ wf_tasks wt
+ where wt.task_id = notify_admin.task_id
+ and wc.case_id = wt.case_id
+ and wc.object_id = o.object_id;
+ object_rec object_cur%ROWTYPE;
+ cursor admin_cur is
+ select u.user_id
+ from users u,
+ acs_object_party_privilege_map m
+ where m.object_id = object_rec.package_id
+ and m.party_id = u.user_id
+ and m.privilege = 'admin';
+ v_request_id integer;
+ begin
+ open object_cur;
+ fetch object_cur into object_rec;
+ close object_cur;
+ for admin_rec in admin_cur loop
+ v_request_id := nt.post_request (
+ party_from => library_workflow.notification_sender(object_rec.package_id),
+ party_to => admin_rec.user_id,
+ expand_group => 'f',
+ subject => 'Object #'||object_rec.object_id||' -- '||'Assign Object',
+ message => 'Subject: '||object_rec.one_line_description||'To do: '||'Assign Object Manage via: '||library_workflow.workflow_url||'task?task_id='||task_id,
+ max_retries => 3
+ );
+ end loop;
+ end notify_admin;
+
+end library_callback;
+/
+show errors
Index: openacs-4/contrib/obsolete-packages/library/tcl/km-00-defs-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/tcl/km-00-defs-procs.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/tcl/km-00-defs-procs.tcl 2 Jul 2003 12:19:41 -0000 1.1
@@ -0,0 +1,1337 @@
+# /tcl/km-00-defs.tcl
+#
+# $Id: km-00-defs-procs.tcl,v 1.1 2003/07/02 12:19:41 peterm Exp $
+
+util_report_library_entry
+proc km_file_path {} { return [ad_parameter FilePath library "[acs_root_dir]/library-files"] }
+
+ad_proc util_GetUserAgentHeader {} {
+ get users browser etc
+} {
+ set header [ns_conn headers]
+ set userag [ns_set iget $header "USER-AGENT"]
+ return $userag
+}
+
+ad_proc km_get_community_name {} {
+ returns the name of the current community
+} {
+ array set node [site_node_closest_ancestor_site_node "acs-subsite"]
+ return $node(instance_name)
+}
+
+ad_proc msie_p {} {
+ check if browser is microsoft or other
+} {
+ return [regexp -nocase {msie} [util_GetUserAgentHeader]]
+}
+
+ad_proc -public km_conn {args} {
+
+ km_conn works much like ad_conn. It caches http-session specific
+ information.
+
+ Example:
+ set admin_p [km_conn admin_p]
+
+} {
+ global km_conn
+
+ set flag [lindex $args 0]
+ if {[string index $flag 0] != "-"} {
+ set var $flag
+ set flag "-get"
+ } else {
+ set var [lindex $args 1]
+ }
+
+ switch -- $flag {
+ -set {
+ set km_conn($var) [lindex $args 2]
+ }
+
+ -unset {
+ unset km_conn($var)
+ }
+
+ -reset {
+ if {[info exists km_conn]} {
+ unset km_conn
+ }
+ array set km_conn {
+ admin_p ""
+ publish_p ""
+ read_p ""
+ write_p ""
+ delete_p ""
+ create_p ""
+ public_p ""
+ archived_p ""
+ deleted_p ""
+ expiration_date ""
+ object_type_id ""
+ object_name ""
+ overview ""
+ last_modified ""
+ creation_date ""
+ user_checkoff_date ""
+ original_author_id ""
+ original_author_name ""
+ access_total ""
+ access_month ""
+ public_until ""
+ start_date ""
+ end_date ""
+ publisher_id ""
+ in_review_p ""
+ review_state ""
+ }
+ }
+
+ -get {
+ if { [info exists km_conn($var)] } {
+ return $km_conn($var)
+ } else {
+ return ""
+ }
+ }
+
+ default {
+ error "km_conn: unknown flag $flag"
+ }
+ }
+}
+
+
+
+ad_proc -public km_static {args} {
+
+ km_static caches information about objects whose value is more or
+ less static throughout the system's life time. The first time a
+ particular information is being looked for, this information is being
+ loaded from the database into the cache. km_static does _not_ do any
+ error checking at the moment. It is also not the smartest caching
+ system under the sun (not yet at least).
+
+ - There should be proc that loads the cache on server
+ startup.
+
+ Example:
+ set pretty_type_plural [km_static object_type_pretty_plural $object_type_id]
+
+} {
+# global km_static
+
+ set flag [lindex $args 0]
+ if {[string index $flag 0] != "-"} {
+ set var $flag
+ set flag "-get"
+ set array_index [lindex $args 1]
+ set value [lindex $args 2]
+ } else {
+ set var [lindex $args 1]
+ set array_index [lindex $args 2]
+ set value [lindex $args 3]
+ }
+
+ if {[empty_string_p $array_index]} {
+ set var_index "${var}"
+ } else {
+ set var_index "${var}${array_index}"
+ }
+
+ switch -- $flag {
+ -set {
+ nsv_set km_static ${var_index} $value
+ }
+
+ -reset {
+ server_cluster_httpget_from_peers "/SYSTEM/flush-km-static-cache.tcl?id=$var"
+ km_static_reset $var
+ }
+
+ -get {
+ if { [nsv_exists km_static $var_index] } {
+ set retval [nsv_get km_static $var_index]
+ return $retval
+ } else {
+ switch -regexp $var {
+ {package_object_types} {
+ set package_object_types_list [list]
+ db_foreach km_static_10 {select pretty_name, object_type_id
+ from sn_object_types
+ where context_id=:array_index} {
+ lappend package_object_types_list [list $pretty_name $object_type_id]
+ }
+ km_static -set package_object_types $array_index $package_object_types_list
+ return $package_object_types_list
+ }
+ {^object_type} {
+ db_1row object_type_info {
+ select pretty_name, pretty_plural,
+ graphic, graphic_p,
+ decode(deleted_p,'t',1,0) as deleted_p,
+ decode(browse_p,'t',1,0) as browse_p,
+ decode(public_p,'t',1,0) as public_p,
+ decode(create_p,'t',1,0) as create_p,
+ decode(archive_p,'t',1,0) as archive_p,
+ decode(copy_p,'t',1,0) as copy_p,
+ default_age_filter, start_date, end_date,
+ long_description,
+ public_until, linked_question_id, short_name
+ from sn_object_types
+ where object_type_id=:array_index}
+ set short_description [db_list get_short_description_list {
+ select short_description
+ from sn_types_map_short_name
+ where object_type_id=:array_index
+ order by position}]
+ km_static -set object_type_pretty_name $array_index $pretty_name
+ km_static -set object_type_short_name $array_index $short_name
+ km_static -set object_type_pretty_plural $array_index $pretty_plural
+ km_static -set object_type_graphic $array_index $graphic
+ km_static -set object_type_graphic_p $array_index $graphic_p
+ km_static -set object_type_deleted_p $array_index $deleted_p
+ km_static -set object_type_browse_p $array_index $browse_p
+ km_static -set object_type_public_p $array_index $public_p
+ km_static -set object_type_create_p $array_index $create_p
+ km_static -set object_type_archive_p $array_index $archive_p
+ km_static -set object_type_copy_p $array_index $copy_p
+ km_static -set object_type_default_age_filter $array_index $default_age_filter
+ km_static -set object_type_short_description $array_index $short_description
+ km_static -set object_type_long_description $array_index $long_description
+ km_static -set object_type_public_until $array_index $public_until
+ km_static -set object_type_start_date $array_index $start_date
+ km_static -set object_type_end_date $array_index $end_date
+ km_static -set object_type_linked_question_id $array_index $linked_question_id
+ regsub {object_type_} $var "" var
+ return [set $var]
+ }
+ {^question_} {
+ db_1row km_static_30 {
+ select pretty_name, abstract_data_type, order_by, target_object_type_id,
+ presentation_type, defaults_question_id, max_categories
+ from sn_questions
+ where question_id=:array_index}
+ km_static -set question_pretty_name $array_index $pretty_name
+ km_static -set question_abstract_data_type $array_index $abstract_data_type
+ km_static -set question_order_by $array_index $order_by
+ km_static -set question_target_object_type_id $array_index $target_object_type_id
+ km_static -set question_presentation_type $array_index $presentation_type
+ km_static -set question_defaults_question_id $array_index $defaults_question_id
+ km_static -set question_max_categories $array_index $max_categories
+ return [km_static ${var} ${array_index}]
+ }
+ {km_dummy_object_id} {
+ set new_km_dummy_object_id [db_string km_static_40 {
+ select object_id
+ from acs_magic_objects
+ where name='km_dummy_object'}]
+ km_static -set km_dummy_object_id $new_km_dummy_object_id
+ return $new_km_dummy_object_id
+ }
+ {^approval_} {
+ set coordinators [db_list km_static_10 {
+ select coordinator_id
+ from approval_coordinators
+ where package_id=:array_index
+ }]
+ km_static -set approval_coordinators $array_index $coordinators
+ if {[empty_string_p $coordinators]} {
+ km_static -set approval_p $array_index 0
+ } else {
+ km_static -set approval_p $array_index 1
+ }
+ return [km_static ${var} ${array_index}]
+ }
+ default {
+ error "km_static: unknown flag $flag"
+ }
+ }
+ }
+ }
+
+ default {
+ error "km_static: unknown flag $flag"
+ }
+}
+}
+
+ad_proc -public km_static_reset { id } {
+ Actually flush the km_static cache.
+} {
+ set all_the_cached_crud [nsv_array names km_static]
+ foreach cached_crud_item $all_the_cached_crud {
+ if {[regexp "$id\$" $cached_crud_item match matched_id]} {
+ nsv_unset km_static $cached_crud_item
+ }
+ }
+}
+
+ad_proc approval_coordinator_p {user_id} {
+
+ checks whether the user with user_id is approval coordinator
+} {
+ set package_id [ad_conn package_id]
+ if {[lsearch [km_static approval_coordinators $package_id] $user_id] > -1} {
+ return 1
+ } else {
+ return 0
+ }
+}
+
+proc_doc km_question_attributes {question_id_list} {
+
+ Returns the question_id, abstract_data_type, pretty_name as triples
+ for each question_id in the list.
+
+} {
+ set integer_list [filter_integers $question_id_list]
+ if {![null_p $integer_list]} {
+
+
+ if {[llength $integer_list] > 1} {
+ set where_clauses "where question_id in ([join $integer_list ","])"
+ } else {
+ set question_id [lindex $integer_list 0]
+ set where_clauses "where question_id = :question_id"
+ }
+
+
+ set sql "
+ select question_id, pretty_name, abstract_data_type
+ from sn_questions
+ $where_clauses
+ "
+ set result [db_list_of_lists km_question_attributes $sql]
+ return $result
+ }
+}
+
+# ********** Metadata **********
+
+ad_proc km_get_all_object_types {
+ {
+ -browsable_only_p 1
+ -createable_only_p 0
+ }
+} {
+ Returns a list of object_type_id, pretty_name, pretty_plural, browse_p, graphic, sort_key
+} {
+ set user_id [ad_conn user_id]
+ set package_id [ad_conn package_id]
+
+ if {$browsable_only_p} {
+ set browse_not "and browse_p='t'"
+ } else {
+ set browse_not ""
+ }
+
+ if {$createable_only_p} {
+ set privilege "create"
+ } else {
+ set privilege "read"
+ }
+
+ set result [db_list_of_lists object_types "
+ select object_type_id, pretty_name, pretty_plural,
+ decode(browse_p,'t',1,0), graphic, sort_key
+ from sn_object_types
+ where deleted_p = 'f'
+ and context_id = :package_id
+ $browse_not
+ and acs_permission.permission_p(object_type_id, :user_id, :privilege) = 't'
+ order by sort_key
+ "]
+
+ return $result
+}
+
+ad_proc km_get_questions {
+ {
+ -all_properties_p 0
+ -form_view ""
+ -root_node_p 1
+ -branch_children_p 1
+ -question_ids {}
+ -object_id 0
+ -object_type_id 0
+ -question_states {active}
+ -answers_p 0
+ -answered_p 0
+ -mandatory_p 0
+ }
+} {
+
+ Returns the column_name, pretty_name, abstract_data_type of all
+ questions for this object type or for this object as a *keyed* list.
+ root_node_p means it returns only top level questions for
+ branches. branch_children_p true means that branch children will ALSO be
+ listed individually
+
+} {
+ set columns {q.question_id q.pretty_name q.abstract_data_type}
+ set order_by ""
+ set tables {"sn_questions q" "sn_question_object_type_map m"}
+
+ if ![null_p $question_ids] {
+ # Return information about the given question.
+
+ lappend where_clauses "q.question_id=m.question_id"
+
+ if {[llength $question_ids] > 1} {
+ lappend where_clauses "q.question_id in ([join $question_ids ","])"
+ } else {
+ set question_id [lindex $question_ids 0]
+ lappend where_clauses "q.question_id = :question_id"
+ }
+ set order_by "order by m.sort_key"
+ } else {
+ if { $object_id } { set object_type_id [km_get_object_type $object_id] }
+
+ lappend join_tables "sn_questions q" "sn_question_object_type_map m"
+ lappend where_clauses "(m.object_type_id=$object_type_id and q.question_id=m.question_id)"
+ set order_by "order by m.sort_key"
+ }
+
+ if { $form_view == 1 } {
+ lappend where_clauses "form_number=1"
+ } elseif { $form_view == 2 } {
+ lappend where_clauses "q.abstract_data_type in ('text', 'option', 'category', 'other_category', 'date', 'file', 'integer', 'object_link', 'content_link', 'user_link', 'child_object', 'nephew_object')"
+ }
+
+ if {$answers_p} {
+ lappend columns "content as answer" "decode(nvl(html_p,'f'),'t',1,0) as html_p"
+ lappend where_clauses "c.object_id=$object_id and c.question_id=m.question_id"
+ lappend tables "sn_content c"
+ }
+
+ # we only want to know here, _if_ there is an answer. If html_p is null,
+ # then the outer join has retrieved a null row for sn_content, so there is
+ # no answer. Otherwise there is an answer.
+ if {$answered_p} {
+ lappend columns "nvl2(c.object_id,1,0) as answered_p"
+ lappend where_clauses "c.object_id(+)=$object_id and c.question_id(+)=m.question_id"
+ lappend tables "sn_content c"
+ }
+
+ if { $all_properties_p } {
+ lappend columns presentation_type tag_height tag_width entry_explanation year_from year_to \
+ m.mandatory_p m.question_state m.form_number m.sort_key q.node_id q.defaults_question_id \
+ q.order_by q.default_value q.target_object_type_id q.references_question_id m.object_type_id \
+ "decode(m.branch_p,'t',1,0) as branch_p" q.max_categories browse_p \
+ "(select decode(count(*),0,0,1) from dual
+ where exists (select 1
+ from sn_question_object_type_map m2
+ where m2.parent_question_id = q.question_id
+ and m2.branch_p='t'
+ and m2.object_type_id=$object_type_id)) as root_branch_p" \
+ parent_question_id
+ }
+
+ # Both branch and composite questions can have have parent and child questions
+ if { $root_node_p && !$branch_children_p } {
+
+ # We want to include questions at the root of branches in the selection but no children of branches
+ lappend where_clauses " m.parent_question_id=[km_static km_dummy_object_id]"
+
+ } elseif { $root_node_p } {
+
+ # We want branch children, too, but no composite children
+ lappend where_clauses " ( m.parent_question_id=[km_static km_dummy_object_id] or branch_p='t')"
+ }
+
+ if ![null_p $question_states] {
+ lappend where_clauses "m.question_state in ('[join $question_states "','"]')"
+ }
+
+ if { $mandatory_p } { lappend where_clauses "m.mandatory_p = 't'" }
+
+ # Get the question attributes out of the table
+ set sql_km_get_questions "
+ select [join $columns ", "]
+ from [join $tables ", "]
+ where [join $where_clauses " and "]
+ $order_by"
+ set result [km_db_to_named_list_list km_get_questions $sql_km_get_questions]
+
+ return $result
+}
+
+ad_proc km_get_question {
+ {
+ -previous_p 0
+ -next_p 0
+ -object_id 0
+ -entry_explanation_p 0
+ -all_types_p 0
+ }
+ question_id object_type_id
+} {
+
+ Returns the question_id, pretty_name, abstract_data_type, question_state,
+ optionally the entry_explanation as a list.
+
+ Set previous_p to 1 and it returns the previous question in the series
+ that belongs to this object type. Set next_p to 1 and it returns the
+ next in the series. This proc does NOT do branch analysis.
+ See km-branch.tcl.
+
+ What it does do is search for the next unanswered question that is not
+ in a branch when called with a branch question - not necessarily higher
+ on the sort key list.
+
+} {
+ if { $entry_explanation_p } {
+ set entry_string ", q.entry_explanation"
+ } else {
+ set entry_string ""
+ }
+
+ set sql_km_get_question_1 "select sort_key, decode(branch_p,'t',1,0)
+ as branch_p, sort_key as current_sort_key, question_state
+ from sn_question_object_type_map
+ where question_id=:question_id and object_type_id=:object_type_id"
+
+ if { ![db_0or1row km_get_question_1 $sql_km_get_question_1]} {
+ return ""
+ }
+
+ if { $next_p || $previous_p } {
+ # We need some extra limitations here so that we don't pull out composite questions or branches.
+
+ set question_state_sql "and question_state <> 'invisible'"
+ if { $all_types_p } {
+ set question_state_sql ""
+ }
+ if { $next_p } {
+
+ if { $branch_p } {
+ # This is a branch leaf. We determine the next question
+ # relative to its root.
+ set root_id [km_get_root_branch $question_id $object_type_id]
+ set current_sort_key "(select sort_key from sn_question_object_type_map where question_id=:root_id and object_type_id = :object_type_id)"
+ }
+ set limitation " and qm.sort_key = (
+ select min(sort_key)
+ from sn_question_object_type_map
+ where object_type_id=:object_type_id
+ and sort_key > :current_sort_key
+ $question_state_sql
+ and branch_p='f'
+ and parent_question_id=[km_static km_dummy_object_id])"
+
+ } elseif { $previous_p } {
+ set limitation " and qm.sort_key = (
+ select max(sort_key) from sn_question_object_type_map
+ where object_type_id=:object_type_id
+ and sort_key < :current_sort_key
+ $question_state_sql
+ and branch_p='f'
+ and parent_question_id=[km_static km_dummy_object_id])"
+ }
+ } else {
+ set limitation "and q.question_id=:question_id"
+ }
+
+ set question_state_sql "and qm.question_state <> 'invisible'"
+ if { $all_types_p } {
+ set question_state_sql ""
+ }
+ set result [km_db_1row_to_list km_get_question_2 "
+ select q.question_id, q.pretty_name, q.abstract_data_type, qm.question_state $entry_string
+ from sn_questions q, sn_question_object_type_map qm
+ where qm.question_id = q.question_id
+ and qm.object_type_id = :object_type_id
+ $question_state_sql
+ $limitation"]
+
+ if { ($next_p || $previous_p) && ![empty_string_p $result] } {
+ # We want to skip deprecated and read-only questions
+ # which have not been answered.
+
+ set new_question_id [fst $result]
+ set new_abstract_data_type [thd $result]
+ set new_question_state [lindex $result 3]
+
+ set answer [fst [km_get_object_data -questions [list {question_id pretty_name abstract_data_type question_state} $result] $object_id]]
+
+ if { $new_question_state != "active" && ![km_answered_p $new_abstract_data_type $answer] } {
+ set result [km_get_question -next_p $next_p -previous_p $previous_p -entry_explanation_p $entry_explanation_p -object_id $object_id $new_question_id $object_type_id]
+ }
+ }
+
+ return $result
+}
+
+proc_doc km_get_child_questions {composite_id} {
+ Returns a list of child question_ids for this composite question.
+} {
+ set sql "select question_id from sn_question_object_type_map
+ where parent_question_id = :composite_id and branch_p='f' and question_state <> 'invisible'"
+ set result [db_list km_get_child_questions $sql]
+ return $result
+}
+
+proc_doc km_get_answer_options {question_id} {
+
+ Returns the list of key-value-sort_key tuples of answer options
+ for this question_id, assuming that this question is actually
+ a question of type option.
+
+} {
+ set result [db_list_of_lists km_get_answer_options "
+ select option_id, answer_option, sort_key
+ from sn_answer_options
+ where question_id = :question_id
+ order by sort_key"]
+ return $result
+}
+
+proc_doc km_answer_option {option_id} {
+ Returns an the pretty name of an answer option.
+} {
+ set sql "select answer_option from sn_answer_options where option_id = :option_id"
+ set result [db_string km_answer_option $sql -default ""]
+ return $result
+}
+
+proc km_pretty_question_state { question_state } {
+ switch $question_state {
+ "active" { return "Active" }
+ "deprecated" { return "To be phased out" }
+ "read-only" { return "Read-Only" }
+ "invisible" { return "Invisible" }
+ }
+}
+
+# ******************** Input checking ********************
+
+proc_doc km_sort_form { key_value_tuples } {
+ Sorts form vars into a list of tuples of keys and value_lists. Date variables are assembled to make one value. Note that
+ even if one key has only one value associated with it that this value will be represented as a single element list.
+} {
+ set sorted_tuples [list]
+ set sister_tag_p 0
+
+ #Put dates together
+ set tuples [km_assemble_dates -filter_p 0 [fst [transpose $key_value_tuples]] [snd [transpose $key_value_tuples]]]
+ # Sort the tuple values into new value_lists by key
+ foreach tuple $tuples {
+
+ set key [fst $tuple]
+ set value [snd $tuple]
+
+ # Put textareas and their sister html_p tags together
+ if {[regexp {(.*)\.html_p} $key match x] } {
+ set key $x
+ set sister_tag_p 1
+ }
+
+ # Get the index of the element in sorted_tuples to be manipulated
+ set ix [lsearch [fst [transpose $sorted_tuples]] $key]
+
+ if {$ix >= 0} {
+
+ # This key is already in sorted_tuples list so add this value to the value_list in the tuple
+ set new_value_list [concat [snd [lindex $sorted_tuples $ix]] $value]
+
+ # Replace the old element of sorted_tuples with the new tuple
+ set sorted_tuples [lreplace $sorted_tuples $ix $ix [list $key $new_value_list]]
+ set sister_tag_p 0
+
+ } elseif {$sister_tag_p} {
+
+ # Then this is an html_p tag that has no sister textarea tag: i.e. the textarea tag is an empty string
+ lappend sorted_tuples [list $key [list "" $value]]
+ set sister_tag_p 0
+
+ } else {
+
+
+ # This key isn't yet in the sorted_tuple list so append a new tuple to it
+ lappend sorted_tuples [list $key [list $value]]
+
+ }
+ }
+ return $sorted_tuples
+}
+
+proc_doc km_filter_valid_keys { key_value_list} {
+ Returns the tuple if it is valid- i.e. it has an integer key value.
+} {
+ set filtered_tuples [list]
+ foreach tuple $key_value_list {
+ if {[integer_p [fst $tuple]]} {lappend filtered_tuples $tuple}
+ }
+ return $filtered_tuples
+}
+
+proc_doc km_filter_other_category_keys { key_value_list} {
+ Returns the tuple if it is originating from extra input field for category 'Other'
+} {
+ set filtered_tuples [list]
+ foreach tuple $key_value_list {
+ set key [fst $tuple]
+ if { [regexp {([0-9]+)_other$} $key match question_id] && [integer_p $question_id] } {
+ lappend filtered_tuples [list $question_id [snd $tuple]]
+ }
+ }
+ return $filtered_tuples
+}
+
+proc_doc km_required_questions {object_id} {
+ Returns a list of required (or mandatory) questions for this object.
+} {
+ set context_id [ad_conn package_id]
+ set result [db_list km_required_questions "
+ select q.question_id
+ from sn_questions q, sn_question_object_type_map qm, sn_objects o
+ where q.question_id = qm.question_id
+ and qm.object_type_id = o.object_type_id
+ and o.object_id = :object_id
+ and qm.question_state = 'active'
+ and o.context_id=:context_id
+ and qm.mandatory_p = 't'"]
+ return $result
+}
+
+ad_proc km_mandatory_child_p { { -parent_id 0 -child_ids {} } } {
+
+ Returns 1 if this composite parent has a mandatory child
+ or if one of the child_ids passed is mandatory.
+
+} {
+ if { $parent_id } { set child_ids [km_get_child_questions $parent_id] }
+
+ if [null_p $child_ids] { return 0 }
+ set children [km_get_questions -all_properties_p 1 -branch_children_p 1 -root_node_p 0 -question_ids $child_ids]
+ set key [fst $children]
+ set children [tail $children]
+
+ foreach child $children {
+ set mandatory_p [ad_decode [lindex $child [lsearch $key mandatory_p]] t 1 0]
+ if { $mandatory_p } { return 1 }
+ }
+
+ return 0
+}
+
+ad_proc km_is_required {
+ {
+ -object_id 0
+ -object_type_id 0
+ }
+ question_id
+} {
+ Checks if a question is mandatory.
+} {
+ if !$object_type_id { set object_type_id [km_get_object_type $object_id] }
+ set result [db_list km_is_required "
+ select decode(mandatory_p,'t',1,0)
+ from sn_question_object_type_map
+ where question_id=:question_id and object_type_id=:object_type_id"]
+ return $result
+}
+
+proc_doc km_answered_p { abstract_data_type answer } {
+ Determines on the basis of the abstract_data_type if this question has been answered or is empty.
+} {
+ switch $abstract_data_type {
+ "object_link" { return [expr ![null_p [tail $answer]]] }
+ "composite" {
+ # This is a bit tricky. Composite questions come in as little
+ # packets of other questions from km_object_data.
+ # A composite question is considered answered if at least one
+ # child has been answered.
+
+ foreach item $answer {
+ if [km_answered_p [lindex $item 3] [fst $item]] { return 1 }
+ }
+ return 0
+ }
+ "option" - "other_category" -
+ "category" { return [expr ![null_p $answer]] }
+ "integer" -
+ "text" { return [expr ![empty_string_p [fst $answer]]] }
+ default { return [expr ![empty_string_p $answer]]}
+ }
+}
+
+ad_proc km_check_input {
+ {
+ -required_p 0
+ -complete_p 0
+ }
+ object_id
+ key_value_list
+} {
+
+ This proc determines if the list of question_ids and their value
+ are valid entries according to their abstract data type.
+ It will also check if the set of keys and values submitted are
+ enough to make this object complete if complete_p is true. Or it will
+ check if a each key is a required question and if so, it will
+ check if that question is answered when required_p is true.
+
+ This proc returns a tuple for ad_return_complaint if it has reason
+ to complain.
+
+} {
+ set invalid_questions {}
+ set missing_ids {}
+ set required_ids {}
+
+ #Remove any key value tuples that do not have an integer key
+ set key_value_list [km_filter_valid_keys $key_value_list]
+
+ # The keys in key value tuples are the question_ids
+ set submitted_ids [fst [transpose $key_value_list]]
+ set values [snd [transpose $key_value_list]]
+
+ #Get a list of required questions to check for completeness
+ if {$complete_p || $required_p} { set required_ids [km_required_questions $object_id] }
+
+ # Get the abstract data types and pretty_names of the questions
+ set questions [km_question_attributes [concat $submitted_ids $required_ids]]
+ set question_ids [fst [transpose $questions]]
+ set abstract_data_types [thd [transpose $questions]]
+ set pretty_names [snd [transpose $questions]]
+
+ foreach submitted_id $submitted_ids {
+
+ # check the input
+ set abstract_data_type [lindex $abstract_data_types [lsearch $question_ids $submitted_id]]
+ set value_list [lindex $values [lsearch $submitted_ids $submitted_id]]
+
+ switch $abstract_data_type {
+ "text" {
+ if {($complete_p || $required_p) && ([elem_p $submitted_id $required_ids] && ([null_p $value_list] \
+ || [empty_string_p [fst $value_list]])) } {
+ lappend missing_ids $submitted_id
+ }
+ }
+ "category" - "other_category" - "option" {
+ set max_categories [km_static question_max_categories $submitted_id]
+ if {($complete_p || $required_p) && [elem_p $submitted_id $required_ids] && [null_p $value_list]} {
+ lappend missing_ids $submitted_id
+ } elseif {![empty_string_p $max_categories] && ([llength $value_list] > $max_categories)} {
+ lappend invalid_questions [list $submitted_id "more than the allowed $max_categories categories chosen"]
+ }
+ }
+ "date" {
+ if {($complete_p || $required_p) && [elem_p $submitted_id $required_ids] && [empty_date_p $value_list]} {
+ lappend missing_ids $submitted_id
+ } elseif {![empty_date_p $value_list] && ![date_p $value_list]} {
+ lappend invalid_questions [list $submitted_id "no valid date"]
+ }
+ }
+ "integer" {
+ if {($complete_p || $required_p) && ([elem_p $submitted_id $required_ids] && ([null_p $value_list] \
+ || [empty_string_p [fst $value_list]])) } {
+ lappend missing_ids $submitted_id
+ } elseif {![integer_p [fst $value_list]]} {
+ lappend invalid_questions [list $submitted_id "no valid number"]
+ }
+ }
+ "file" {
+ set client_filename [fst $value_list]
+
+ if {($complete_p || $required_p) && [elem_p $submitted_id $required_ids] } {
+ if [empty_string_p $client_filename] {
+ # Go to the db and see if a file already exists for this variable.
+ if ![km_upload_exists_p $object_id $submitted_id] {
+ lappend missing_ids $submitted_id
+ }
+ }
+ }
+
+ if { ![empty_string_p $client_filename] } {
+ # If the temporary file is empty, there has been an error.
+ set tmpfilename [ns_queryget $submitted_id.tmpfile]
+ if ![file size $tmpfilename] {
+ lappend invalid_questions [list $submitted_id "invalid file"]
+ }
+ }
+ }
+ default { continue }
+ }
+ }
+
+ foreach question_id $required_ids {
+ set abstract_data_type [lindex $abstract_data_types [lsearch [fst [transpose $questions]] $question_id]]
+ switch $abstract_data_type {
+ "user_link" {
+ if ![null_p [km8_get_to_links $object_id $question_id]] {
+ # If there already are links for this question, we pretend
+ # it has been submitted.
+ lappend submitted_ids $question_id
+ }
+ }
+ "file" {
+ if ![km_upload_exists_p $submitted_id $object_id] {
+ lappend submitted_ids $question_id
+ }
+ }
+ "child_object" {
+ if {![null_p [km_get_child_objects $object_id $question_id]] } {
+ lappend submitted_ids $question_id
+ }
+ }
+ "nephew_object" {
+ if {![null_p [km_get_nephew_objects $object_id $question_id]] } {
+ lappend submitted_ids $question_id
+ }
+ }
+ }
+ }
+
+ # Check if there are some other keys that also should be submitted to make this complete
+ if { $complete_p } { set missing_ids [concat $missing_ids [minus $required_ids $submitted_ids]] }
+
+ #Prepare the complaint messages
+ foreach missing_id $missing_ids {
+ set pretty_name [lindex $pretty_names [lsearch $question_ids $missing_id]]
+ append message "You must supply a value for $pretty_name "
+ }
+ foreach invalid_question $invalid_questions {
+ set invalid_id [fst $invalid_question]
+ set invalid_msg [snd $invalid_question]
+ set pretty_name [lindex $pretty_names [lsearch $question_ids $invalid_id]]
+ append message "You have entered an invalid entry for $pretty_name ($invalid_msg) "
+ }
+ set i [expr [llength $invalid_questions] + [llength $missing_ids]]
+ if { $i } {
+ return [list $i $message]
+ } else {
+ return
+ }
+}
+
+proc_doc km_upload_exists_p { object_id question_id } {
+ Looks if a file has been uploaded for this object_id and question_id
+} {
+ set client_filename [db_string km_upload_exists_p "
+ select content from sn_content
+ where object_id=:object_id
+ and question_id=:question_id" -default ""]
+
+ if ![empty_string_p $client_filename] {
+ return 1
+ } else {
+ return 0
+ }
+}
+
+ad_proc km_original_author_p { user_id object_id } {
+ Test if the user is the original author of this object.
+} {
+ set context_id [ad_conn package_id]
+ set result [db_string km_original_author_p "
+ select count(*) from sn_objects where object_id=:object_id and original_author_id=:user_id and context_id=:context_id"]
+
+ return $result
+}
+
+proc_doc km_type_has_data_type_p { object_type_id data_type } {
+ Determines if an object type has a column of the given abstract datatype.
+} {
+ return [db_string km_type_has_data_type_p "
+ select decode(count(*),0,0,1) from dual where exists (select 1
+ from sn_questions q, sn_question_object_type_map qm
+ where qm.question_id = q.question_id
+ and qm.object_type_id = :object_type_id
+ and qm.question_state <> 'invisible'
+ and q.abstract_data_type = :data_type)"]
+}
+
+# ******************** Date Procs ********************
+
+proc_doc month_list {} {
+ Returns a list of months, the second row holds the corresponding 2 digit values.
+} {
+ set months [list Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec]
+ set values [list 01 02 03 04 05 06 07 08 09 10 11 12]
+ return [list $months $values]
+}
+
+proc_doc km_default_date {question_id} {
+ Calculates a default date based on the question_id
+} {
+ set default_value [db_string km_default_date_1 "
+ select default_value from sn_questions where question_id=:question_id" -default ""]
+ if [empty_string_p $default_value] {
+ set result {}
+ } else {
+ if { ![catch {set default_date [db_string km_default_date_2 "select $default_value from dual"]}] } {
+ set result [km_break_date $default_date]
+ } else {
+ set result {}
+ }
+ }
+ return $result
+}
+
+ad_proc km_get_year_range {question_id} {
+ Calculates the year range for this date question
+} {
+ db_1row get_year_range {
+ select (to_char(add_months(sysdate,12*year_from),'YYYY')) as year_from,
+ (to_char(add_months(sysdate,12*year_to),'YYYY')) as year_to
+ from sn_questions
+ where question_id = :question_id
+ }
+ return [list $year_from $year_to]
+}
+
+ad_proc km_assemble_dates { {-filter_p 1} keys values } {
+
+ Given a list of keys and values, this proc searches for all keys with the form
+ key_name:month, key_name:year, key_name:day, which is how km-date-tags
+ returns them in this module. It returns a list of key value tuples
+ of the form: key_name YYYY-MM-DD. It does not check if these are valid dates, that's
+ what date_p does. If filter_p is set to 1, it returns only the date tuples back.
+ Otherwise it returns all other keys and values in the same order.
+
+} {
+ # we need a list of key_name tags and their values, sort them so that
+ # all key_names are grouped together and that :day, :month, :year
+ # will be evaluated in that order
+
+ set key_name ""
+ set tuples [zip $keys $values]
+ set tuples [qsort $tuples]
+ set last_key_name ""
+ set result [list]
+
+ set counter 0
+ foreach tuple $tuples {
+
+ if { [regexp {(.*)\.(month|year|day)} [fst $tuple] match key_name] } {
+ # Looks like a date value.
+
+ if { [string compare $key_name $last_key_name] == 0 } {
+ lappend ${key_name}_value [snd $tuple]
+ } else {
+
+ # It's a different key_name so append the last_key_name and
+ # its date to the list (if there is one).
+
+ if ![empty_string_p $last_key_name] {
+ lappend dates [list $last_key_name [set ${last_key_name}_value]]
+ }
+
+ # Start assembling the next date
+ lappend ${key_name}_value [snd $tuple]
+ }
+
+ set last_key_name $key_name
+ incr counter
+
+ } elseif !$filter_p {
+ # No date value, but we are not allowed to filter other values out.
+ # So just copy it.
+
+ lappend result $tuple
+ }
+ }
+
+ if { $counter } {
+
+ # Append the last last_key_name and its date to the list.
+ lappend dates [list $last_key_name [set ${last_key_name}_value]]
+
+ # Oracle will want the date YYY-MM-DD instead of a list DD MM YYYY,
+ # so split the tuples up again and format the date part.
+
+ set formatted_dates [map {flip join "-"} [map reverse [snd [transpose $dates]]]]
+
+ # Pack them up again to be returned as a list of tuples.
+ set result "$result [zip [fst [transpose $dates]] $formatted_dates]"
+ }
+
+ return $result
+}
+
+
+# ******************** Navigation ********************
+
+proc_doc generate_path_id {} {
+
+ Generates a random number to uniquely define this excursion state in
+ the knowledge management library.
+
+ This number will be passed from one form to the next throughout the excursion.
+
+} {
+ while 1 {
+ # Note that ns_rand only gives us six digits - so we call it twice.
+ set path_id "[ns_rand 1000000][ns_rand 1000000]"
+
+ if ![db_string generate_path_id "select count(*) from km_path where path_id=:path_id"] {
+ return $path_id
+ }
+ }
+}
+
+ad_proc set_path_values {{-question_id ""} object_id category_id } {
+
+ Returns a simple list of name and value tuples that should be stored
+ for library excursions in the km_excursion_path table
+
+} {
+
+ if ![empty_string_p $question_id] {
+ set values [list object_id $object_id question_id $question_id category_id $category_id]
+ } else {
+ set values [list object_id $object_id category_id $category_id]
+ }
+ return $values
+}
+
+ad_proc init_path {
+ {
+ -last_path_id ""
+ }
+ values_list return_to action
+} {
+
+ Initializes the path variable for an excursion through the library.
+
+ Begins an excursion by saving all the information that will be
+ necessary at the end of this excursion to return to the same place it
+ started. It is assumed that an excursion is only occuring while
+ editing, creating or linking an object. In all other cases there will
+ be no excursion state and also no object_id. Important! The
+ last_path_id that is being passed is the id of the excursion state out
+ of which this excursion is being launched!
+
+} {
+ set path_id [generate_path_id]
+ if [empty_string_p $last_path_id] { set last_path_id [db_null] }
+
+ # Insert the info about this particular excursion into the database
+
+ db_dml init_path "insert into km_path
+ (path_id, last_path_id, action, values_list, return_to, start_time)
+ values (:path_id, :last_path_id, :action,
+ :values_list, :return_to, sysdate)"
+
+ return $path_id
+}
+
+proc_doc get_path_return_url {path_id} {
+
+ Returns the destination of a path if it's a valid path, otherwise
+ it returns an empty string.
+
+} {
+ if [empty_string_p $path_id] { return "" }
+
+ set calc_excursion_timeout [expr [excursion_timeout]/24]
+ set sql "select return_to from km_path
+ where path_id=:path_id and sysdate - start_time < :calc_excursion_timeout"
+
+ if {[catch {set destination [db_string get_path_return_url $sql]}]} {
+ set result ""
+ } else {
+ set result $destination
+ }
+
+ return $result
+}
+
+ad_proc get_path_values { {-action_only_p 1} path_id } {
+
+ Given an excursion's path_id, this proc returns the action of this
+ excursion as a two-part list: {action action_value}. This is often
+ necessary for a page to know what it is supposed to do. If the option
+ action_only_p is set to 0 then a simple list is returned with the name
+ and value of the variables in the same order that they were given to
+ km_set_path_values
+
+} {
+
+ set timeout [excursion_timeout]
+
+ if !$action_only_p {
+ # Return a list with all excursion details
+ set values ", values_list "
+ } else {
+ set values ""
+ }
+
+ # Get out the action and the list of values from oracle and
+ # turn it into a list of action and the other values
+
+ set values_list {}
+ if { ![db_0or1row get_path_values "
+ select action $values from km_path
+ where path_id=:path_id and sysdate - start_time < :timeout/24"]} {
+ set result {}
+ } else {
+
+ split $values_list
+
+ set result {}
+ foreach value $values_list { lappend result $value }
+ lappend result action $action
+ }
+
+ return $result
+}
+
+proc_doc get_path_action {path_id} {
+ Returns the path's action as a plain value.
+} {
+ return [snd [get_path_values $path_id]]
+}
+
+proc_doc get_last_path {path_id} {
+
+ If this was an excursion launched within another excursion then we
+ want to return the path_id of that excursion.
+
+} {
+ set last_path_id [db_string get_last_path "
+ select last_path_id from km_path where path_id=:path_id" -default ""]
+
+ return $last_path_id
+}
+
+proc_doc path_valid_p {path_id} {
+ Checks if the given path (still) exists.
+} {
+ if [empty_string_p $path_id] { return 0 }
+
+ set calc_excursion_timeout [expr [excursion_timeout]/24]
+ set result [db_string path_valid_p "
+ select count(*) from km_path
+ where path_id=:path_id and sysdate - start_time <= :calc_excursion_timeout"]
+ return $result
+}
+
+proc_doc value_from_tuples {key_values key} {
+
+ Given a list of key/value tuples, returns the value associated with
+ the given key.
+
+} {
+ if { [lsearch $key_values $key] == -1 } {
+ return ""
+ } else {
+ return [lindex $key_values [expr [lsearch $key_values $key] + 1]]
+ }
+}
+
+ad_proc sn_success_story_id {} {
+ Returns the object_type_id for the Success Stories.
+} {
+ set context_id [ad_conn package_id]
+ set result [db_string sn_success_story_id "
+ select object_type_id from sn_object_types
+ where upper(pretty_name) = upper('success story') and context_id=:context_id" -default "0"]
+
+ return $result
+}
+
+
+ad_proc km_workflow_task_per_object {object_id} {
+ Return information about the current workflow task for this object_id
+} {
+ # dirk: remove the rownum - it's only in for debugging purposes.
+ if {[db_0or1row km_workflow_task_per_object {
+ select t.task_id,
+ t.case_id,
+ t.transition_key,
+ t.state,
+ t.transition_name as task_name
+ from wf_cases c,
+ wf_user_tasks t
+ where c.case_id = t.case_id
+ and c.object_id=:object_id
+ and rownum=1}]} {
+ return [list \
+ workflow_task_p t \
+ task_id $task_id \
+ case_id $case_id \
+ transition_key $transition_key \
+ state $state \
+ task_name $task_name]
+ } else {
+ return [list \
+ workflow_task_p f \
+ task_id "" \
+ case_id "" \
+ transition_key "" \
+ state "" \
+ task_name ""]
+ }
+ return ""
+}
+
+
+ad_proc library_approval_process_notifications {} {
+
+ Processes the notifications queued in table wf_library_notifications.
+
+} {
+ # Make sure that only one thread is processing the queue at a time.
+ if {[nsv_incr library library_notifications_p] > 1} {
+ nsv_incr library library_notifications_p -1
+ return
+ }
+
+ with_finally {
+
+ db_foreach get_notifications {
+ select notification_id, task_id, template_key, recipient_id, sender_id, body
+ from wf_library_notifications
+ } {
+
+ db_1row ticket_info {
+ select o.object_id,
+ o.one_line_description as shortname, sn.node_id,
+ u1.email as sender_email, u2.email as recipient_email,
+ u1.first_names || ' ' || u1.last_name as sender_name,
+ u2.first_names || ' ' || u2.last_name as recipient_name,
+ apm_package.name(o.context_id) as package_name
+ from wf_tasks wt, wf_cases wc, sn_objects o, users u2,
+ site_nodes sn, users u1
+ where u1.user_id = :sender_id
+ and u2.user_id = :recipient_id
+ and wc.case_id = wt.case_id
+ and wt.task_id = :task_id
+ and o.object_id = wc.object_id
+ and sn.object_id = o.context_id
+ }
+
+ set community_id [sn_community::leaf_community $node_id]
+
+ set replacement_list \
+ [list \
+ object_id $object_id \
+ object_link "[ad_url]/o/$object_id" \
+ package_name $package_name \
+ shortname $shortname \
+ submitter_name $sender_name \
+ submitter_email $sender_email \
+ recipient_email $recipient_email \
+ notification_sender $sender_email \
+ body $body]
+
+ db_dml delete_notification {
+ delete from wf_library_notifications
+ where notification_id = :notification_id
+ }
+
+ et_send_email [et_process -community_id $community_id $template_key $replacement_list]
+ }
+
+ } finally {
+ nsv_incr library library_notifications_p -1
+ }
+}
+
+
+util_report_successful_library_load
Index: openacs-4/contrib/obsolete-packages/library/tcl/km-access-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/tcl/km-access-procs.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/tcl/km-access-procs.tcl 2 Jul 2003 12:19:41 -0000 1.1
@@ -0,0 +1,315 @@
+# /tcl/km-access-procs.tcl
+#
+# Functions related to access control.
+#
+# Created by carsten@arsdigita.com in June 2000
+#
+# $Id: km-access-procs.tcl,v 1.1 2003/07/02 12:19:41 peterm Exp $
+
+ad_proc km_check_object_id {
+ {
+ -check_deleted_p 1
+ -check_read_p 1
+ -check_edit_p 0
+ -check_delete_p 0
+ -print_errors_p 1
+ }
+ object_id
+} {
+
+ Check if the object exists, and print an error message if it
+ doesn't. Returns 0 if the object_id is invalid.
+
+ If check_deleted_p is 1, also checks if the object has been deleted.
+ If check_read_p is 1, also checks if the user may view the object.
+ If check_edit_p is 1, also checks if the user may edit the object.
+ Only complains to the user if print_errors_p is 1.
+
+} {
+ set package_id [ad_conn package_id]
+ set user_id [ad_conn user_id]
+
+ if { ![db_0or1row get_object_info "
+ select decode(sign(sysdate-o.expiration_date),1,1,0,1,0) as deleted_p,
+ o.original_author_id, o.expiration_date, o.object_type_id,
+ o.one_line_description as object_name, o.overview,
+ o.last_modifying_user_id, o.start_date, o.end_date,
+ decode(o.public_p,'t',1,0) as public_p, o.public_until,
+ decode(o.archived_p,'t',1,0) as archived_p,
+ o.original_author_id, to_char(o.creation_date) as creation_date,
+ to_char(o.last_modified) as last_modified,
+ to_char(o.user_checkoff_date) as user_checkoff_date,
+ u.first_names || ' ' || u.last_name as original_author_name,
+ u.email as original_author_email, o.publisher_id,
+ decode([tcl_permission_p ":object_id" ":user_id" "'read'"],'t',1,0) as read_p,
+ decode([tcl_permission_p ":object_id" ":user_id" "'write'"],'t',1,0) as write_p,
+ decode([tcl_permission_p ":object_id" ":user_id" "'delete'"],'t',1,0) as delete_p,
+ decode([tcl_permission_p ":package_id" ":user_id" "'admin'"],'t',1,0) as admin_p,
+ decode([tcl_permission_p ":package_id" ":user_id" "'km_publish'"],'t',1,0) as publish_p,
+ decode(acs_permission.permission_p(o.object_type_id, :user_id, 'create'),'t',1,0) as create_p,
+ nvl(o.access_total,0) as access_total, nvl(o.access_month,0) as access_month,
+ decode(o.in_review_p,'t',1,0) as in_review_p
+ from sn_objects o, users u
+ where o.object_id = :object_id
+ and u.user_id = o.original_author_id
+ "] } {
+ # Error: The object does not exist.
+
+ if { $print_errors_p } {
+ ad_return_exception_page 404 "Entry does not exist." "
+ The entry with id $object_id does not exist.
+ We never really delete object IDs from the database so this is quite
+ unusual. Unless you tried to hack the URL manually this might be a bug
+ in our software."
+ }
+ return 0
+ }
+
+ if { [empty_string_p $object_name] } {
+ set object_name "Unnamed [km_static object_type_pretty_name $object_type_id]"
+ }
+ # review process enabled?
+ if { [km_static approval_p $package_id] && !$publish_p } {
+ if {$public_p || $in_review_p} {
+ # revoke delete permission from object owners if object is
+ # public or review process started
+ set delete_p $admin_p
+ }
+ }
+
+ # The state of a workflow task is user-dependant!
+ if {$in_review_p} {
+ set state [db_string workflow_case_state {select distinct t.transition_key
+ from wf_cases c,
+ wf_user_tasks t
+ where c.case_id = t.case_id
+ and c.object_id=:object_id
+ and c.state = 'active'
+ and rownum = 1
+ order by t.transition_key desc} -default ""]
+ } else {
+ set state ""
+ }
+## and t.user_id = :user_id
+
+ km_conn -reset
+ km_conn -set public_p $public_p
+ km_conn -set archived_p $archived_p
+ km_conn -set deleted_p $deleted_p
+ km_conn -set expiration_date $expiration_date
+ km_conn -set object_type_id $object_type_id
+ km_conn -set object_name $object_name
+ km_conn -set overview $overview
+ km_conn -set original_author_id $original_author_id
+ km_conn -set original_author_name $original_author_name
+ km_conn -set original_author_email $original_author_email
+ km_conn -set creation_date $creation_date
+ km_conn -set last_modified $last_modified
+ km_conn -set user_checkoff_date $user_checkoff_date
+ km_conn -set admin_p $admin_p
+ km_conn -set publish_p $publish_p
+ km_conn -set read_p $read_p
+ km_conn -set write_p $write_p
+ km_conn -set delete_p $delete_p
+ km_conn -set create_p $create_p
+ km_conn -set last_modifying_user_id $last_modifying_user_id
+ km_conn -set access_total $access_total
+ km_conn -set access_month $access_month
+ km_conn -set public_until $public_until
+ km_conn -set start_date $start_date
+ km_conn -set end_date $end_date
+ km_conn -set publisher_id $publisher_id
+ km_conn -set in_review_p $in_review_p
+ km_conn -set review_state $state
+
+ if { $check_deleted_p && $deleted_p } {
+ # Error: The object has been deleted.
+
+ set expiration_date [util_AnsiDatetoPrettyDate $expiration_date]
+
+ if {![empty_string_p $last_modifying_user_id]} {
+ # If we know who deleted the object, we want to give the
+ # user a link to that user's community page.
+
+ set deletor_name [db_string km_check_object_id_2 "
+ select first_names || ' ' || last_name
+ from users where user_id=:last_modifying_user_id"]
+
+ set deletion_text "This object was deleted on $expiration_date by [ad_present_user $last_modifying_user_id $deletor_name]."
+
+ set reason_for_deleting [db_string km_check_object_id_3 "
+ select reason_for_deleting
+ from sn_object_delete_reasons
+ where object_id=:object_id" -default ""]
+
+ if {![empty_string_p $reason_for_deleting]} {
+ append deletion_text "
Reason:
$reason_for_deleting
"
+ }
+
+ } else {
+ set deletion_text "This object was deleted on $expiration_date."
+ }
+
+ if { $print_errors_p } { ad_returnredirect "object-deleted?object_id=$object_id" }
+
+ return 0
+ }
+
+ if { $check_read_p && !$read_p } {
+ # A user only has read access if the object is public,
+ # or he has been given read permission.
+
+ if { $print_errors_p } {
+ ad_return_forbidden "Not Authorized" \
+ "You are not authorized to view this object."
+ }
+ return 0
+ } elseif { $check_edit_p && !$admin_p && (!$write_p || $archived_p) } {
+ if { $print_errors_p } {
+ ad_return_forbidden "Not Authorized" \
+ "You are not authorized to edit this object."
+ }
+ return 0
+ } elseif { $check_delete_p && !$admin_p && !$delete_p } {
+ if { $print_errors_p } {
+ ad_return_forbidden "Not Authorized" \
+ "You are not authorized to delete this object."
+ }
+ return 0
+ }
+
+ # Check if the object type (still) exists, and if the user is allowed
+ # to view it.
+
+ if { [km_static object_type_deleted_p $object_type_id] } {
+ if { $print_errors_p } {
+ # Only complain to the user if we were told so.
+
+ set pretty_type [km_static object_type_pretty_name $object_type_id]
+ ad_return_exception_page 404 "The object type \"$pretty_type\" has been removed from the system." "The object type \"$pretty_type\" has been removed from the system.
+You therefore cannot view this object"
+ }
+ return 0
+ }
+
+ if { $check_read_p && ![km_static object_type_public_p $object_type_id] && !$admin_p } {
+ # The object type may not be viewed by this user.
+
+ if { $print_errors_p } {
+ ad_return_forbidden "Not Authorized" \
+ "You are not authorized to view this object."
+ }
+ return 0
+ }
+
+ return 1
+}
+
+ad_proc km_check_object_type_id {
+ {
+ -check_view_p 1
+ -check_create_p 0
+ -print_errors_p 1
+ }
+ object_type_id
+} {
+
+ Check if the user may access the given object type. Checks for
+ read and create permissions, whether the object type
+ has been deleted, and whether it belongs to the current package.
+
+ If check_create_p is set, also complains when the object type
+ is not browsable.
+
+} {
+ set package_id [ad_conn package_id]
+ set user_id [ad_conn user_id]
+
+ if { ![db_0or1row km_check_object_type_id "
+ select deleted_p, browse_p, public_p,
+ decode([tcl_permission_p ":package_id" ":user_id" "'admin'"],'t',1,0) as admin_p,
+ decode([tcl_permission_p ":object_type_id" ":user_id" "'create'"],'t',1,0) as create_p
+ from sn_object_types
+ where object_type_id = :object_type_id
+ and context_id = :package_id
+ "] } {
+ if { $print_errors_p } {
+ ad_return_exception_page 404 "Invalid object_type_id" \
+ "The given object_type_id is invalid."
+ }
+ return 0
+ }
+
+ km_conn -reset
+ km_conn -set admin_p $admin_p
+ km_conn -set create_p $create_p
+
+ if { $deleted_p == "t" } {
+ if { $print_errors_p } {
+ ad_return_exception_page 410 "Object type no longer exists" \
+ "This object type has been removed from the system."
+ }
+ return 0
+ }
+
+ if { $check_view_p && $public_p == "f" && !$admin_p } {
+ if { $print_errors_p } {
+ ad_return_forbidden "Not Authorized" \
+ "You are not authorized to view objects of this type."
+ }
+ return 0
+ }
+
+ if { $check_create_p && ($public_p == "f" || !$create_p) && !$admin_p } {
+ if { $print_errors_p } {
+ ad_return_forbidden "Not Authorized" \
+ "You are not authorized to create objects of this type."
+ }
+ return 0
+ }
+
+ return 1
+}
+
+ad_proc km_check_owner_change {
+ {
+ -print_errors_p 1
+ }
+ object_id
+} {
+
+ Checks if the user may change the ownership of the given
+ object. This is only allowed for the object owner and administrators.
+
+} {
+ set user_id [ad_conn user_id]
+ set package_id [ad_conn package_id]
+
+ set result [db_string check_owner_change "
+ select decode(count(*),0,0,1) from dual where exists
+ (select 1
+ from sn_objects
+ where object_id = :object_id
+ and context_id = :package_id
+ and (original_author_id = :user_id or
+ [tcl_permission_p ":package_id" ":user_id" "'admin'"] = 't'))
+ "]
+
+ if { !$result && $print_errors_p } {
+ ad_return_forbidden "Not Authorized" \
+ "You are not authorized to change the ownership of this object."
+ }
+
+ return $result
+}
+
+proc_doc km_object_type_private_p {object_type_id} {
+ Checks if an object type is not visible to the public.
+} {
+ set context_id [ad_conn package_id]
+ set result [db_string km_object_type_private_p "
+ select decode(public_p,'t',0,1)
+ from sn_object_types where object_type_id=:object_type_id" -default ""]
+
+ return $result
+}
Index: openacs-4/contrib/obsolete-packages/library/tcl/km-admin-lib-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/tcl/km-admin-lib-procs.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/tcl/km-admin-lib-procs.tcl 2 Jul 2003 12:19:41 -0000 1.1
@@ -0,0 +1,161 @@
+ad_proc km_db_1row_to_list { statement_name sql args } {
+
+ Performs the SQL query $sql. Returns a list of the results.
+
+} {
+ ad_arg_parser { bind } $args
+
+ # Query Dispatcher (OpenACS - ben)
+ set full_statement_name [db_qd_get_fullname $statement_name]
+
+ db_with_handle db {
+ set selection [db_exec 0or1row $db $full_statement_name $sql]
+ }
+
+ if { [empty_string_p $selection] } {
+ return ""
+ }
+
+ set list_to_return ""
+
+ for { set i 0 } { $i < [ns_set size $selection] } { incr i } {
+ lappend list_to_return [ns_set value $selection $i]
+ }
+
+
+ for { set i 0 } { $i < [ns_set size $selection] } { incr i } {
+ upvar 1 [ns_set key $selection $i] value
+ set value [ns_set value $selection $i]
+ }
+
+ return $list_to_return
+}
+
+ad_proc km_db_to_named_list_list { statement_name sql args} {
+ Returns a list of Tcl lists, with each sublist containing the columns returned
+ by the database; if no rows are returned by the database, returns the
+ empty list (empty string in Tcl 7.x and 8.x)"
+} {
+ ad_arg_parser { bind } $args
+
+ # Query Dispatcher (OpenACS )
+ set full_statement_name [db_qd_get_fullname $statement_name]
+
+ db_with_handle db {
+ set selection [db_exec select $db $full_statement_name $sql]
+
+ set keys [list]
+ for {set i 0} {$i<[ns_set size $selection]} {incr i} {
+ lappend keys [ns_set key $selection $i]
+ }
+ set list_to_return [list $keys]
+ while {[ns_db getrow $db $selection]} {
+ set row_list ""
+ set size [ns_set size $selection]
+ set i 0
+ while {$i<$size} {
+ lappend row_list [ns_set value $selection $i]
+ incr i
+ }
+ lappend list_to_return $row_list
+ }
+ }
+
+ return $list_to_return
+}
+
+proc_doc km_new_acs_object_id {} {
+ Returns a new acs_object_id
+} {
+ set result [db_string km_new_acs_object_id "select acs_object_id_seq.nextval from dual"]
+ return $result
+}
+
+proc_doc km_sort_key_list { object_type_id } {
+
+ Returns a list of sort_keys available for this object_type
+ (sort_keys are offered as increments of 10 and should *NEVER* be
+ the same for 2 questions of one object_type)
+
+} {
+ set result ""
+ set existing_keys [db_list km_sort_key_list "select sort_key from
+ sn_question_object_type_map
+ where object_type_id=$object_type_id"]
+ set i 0
+ while { $i < 400 } {
+
+ set i [expr $i + 10]
+ if {[elem_p $i $existing_keys]} {
+ continue
+ } else {
+ lappend result $i
+ }
+ }
+ return $result
+}
+
+ad_proc km_adt_list { { -pretty_names_p 0 } } {
+ Returns a list of abstract data types as a list or as a list of tuples
+ with the pretty name as the second element.
+} {
+ set adts {
+ text option category other_category integer date file composite
+ object_link user_link content_link child_object nephew_object
+ other_category
+ }
+ set pretty_names {
+ Text "Multiple Choice" Category "Category with 'Other' field" Number Date File
+ Composite "Object-Object Link" "Object-User Link" "Object-Content Link"
+ "Child Object Type" "Nephew Object Type"
+
+ }
+
+ if { $pretty_names_p } {
+ return [zip $adts $pretty_names]
+ } else {
+ return $adts
+ }
+}
+
+proc_doc km_pretty_adt { abstract_data_type } {
+ Returns the pretty abstract data type
+} {
+ switch $abstract_data_type {
+ "text" { return Text }
+ "option" { return "Multiple Choice" }
+ "category" { return "Category" }
+ "other_category" { return "Category with 'Other' field" }
+ "date" { return "Date" }
+ "file" { return "Attachment" }
+ "composite" { return "Composite" }
+ "object_link" { return "Object Link" }
+ "user_link" { return "User Link" }
+ "content_link" { return "Content Link" }
+ "child_object" { return "Child Object Type" }
+ "nephew_object" { return "Nephew Object Type" }
+ "integer" { return "Number" }
+ default { return}
+ }
+}
+
+
+proc_doc km_pretty_tag { presentation_type } {
+ Returns the pretty tag name
+} {
+ switch $presentation_type {
+ "shorttext" { return "Short Text" }
+ "text" { return "Short Text" }
+ "textarea" {return "Textarea" }
+ "textarea_with_refs" {return "Textarea with Reference Buttons"}
+ "select" { return Select}
+ "selectmultiple" {return "Select Multiple" }
+ "checkbox" {return "Checkbox"}
+ "radio" {return "Radio Buttons"}
+ "custom" { return "Custom"}
+ "application" { return "Application Form"}
+ default { return }
+ }
+}
+
+
Index: openacs-4/contrib/obsolete-packages/library/tcl/km-branch-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/tcl/km-branch-procs.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/tcl/km-branch-procs.tcl 2 Jul 2003 12:19:41 -0000 1.1
@@ -0,0 +1,319 @@
+# /tcl/km-branch.tcl
+#
+# These procs have to do with the branches to questions. Branches are
+# answer-dependent questions that follow other questions.
+#
+# $Id: km-branch-procs.tcl,v 1.1 2003/07/02 12:19:41 peterm Exp $
+
+ad_proc km_get_branches {
+ {
+ -question_attributes_p 0
+ -branch_id 0
+ }
+ root_question_id
+ object_type_id
+} {
+ Returns a list of the question_ids directly beneath this question_id in the branch tree. If
+ this question is not a branched question then it returns nothing.
+} {
+
+ set join_tables [list "sn_question_object_type_map m1" "sn_question_object_type_map m2"]
+ set join_clause ""
+ set columns ""
+ set limitation ""
+
+ if { $question_attributes_p } {
+
+ # We need to know the abstract_data_type of the parent question to know
+ # if the answer is stored as an option or as a foreign key in the branch recipe.
+
+ set abstract_data_type [thd [km_get_question $root_question_id $object_type_id]]
+
+ switch $abstract_data_type {
+ "integer" -
+ "text" {
+ append columns ", m1.branch_answer branch_answer"
+ }
+ "category" - "other_category" {
+ append columns ",c.category_id, c.long_name branch_answer"
+ lappend join_tables "categories c"
+ append join_clause " and m1.branch_answer_foreign_key = c.category_id(+)"
+ }
+ "option" {
+ append columns ", ao.option_id, ao.answer_option branch_answer"
+ lappend join_tables "sn_answer_options ao"
+ append join_clause " and m1.branch_answer_foreign_key = ao.option_id(+)"
+ }
+ default { return }
+ }
+ lappend join_tables " sn_questions q"
+ append join_clause " and q.question_id = m1.question_id"
+ append columns ", m1.branch_operator, pretty_name, q.entry_explanation, q.presentation_type, q.abstract_data_type"
+ }
+ if { $branch_id } { set limitation " and m1.question_id = :branch_id " }
+
+ set sql "select m1.question_id $columns from [join $join_tables ","]
+ where m2.question_id = m1.parent_question_id
+ and m1.branch_p = 't'
+ and m1.object_type_id = :object_type_id
+ and m1.parent_question_id = :root_question_id
+ $join_clause $limitation"
+ set result [km_db_to_named_list_list km_get_branches $sql]
+ return $result
+}
+
+proc_doc km_default_branch { root_branch_id } {
+ Returns the default branch of a branch node.
+} {
+ set default_branch [db_string km_default_branch "
+ select default_branch
+ from sn_question_object_type_map qm
+ where question_id=$root_branch_id
+ and (select qm2.branch_p
+ from sn_question_object_type_map qm2
+ where qm2.question_id = qm.default_branch) = 't'" -default ""]
+
+ return $default_branch
+}
+
+proc_doc km_branch_parent { question_id object_type_id } {
+ Returns the parent_question_id of this question iff this is a branch.
+} {
+ set result [db_string km_branch_parent "
+ select parent_question_id
+ from sn_question_object_type_map
+ where question_id=:question_id
+ and branch_p='t'
+ and object_type_id=:object_type_id" -default ""]
+
+ return $result
+}
+
+proc_doc km_composite_parent { question_id object_type_id } {
+ Returns the parent_question_id of this question if this is a composite child.
+} {
+ set result [db_string km_composite_parent "
+ select parent_question_id
+ from sn_question_object_type_map
+ where question_id=:question_id
+ and branch_p='f'
+ and object_type_id=:object_type_id" -default ""]
+ if {$result == [km_static km_dummy_object_id]} {
+ return ""
+ }
+ return $result
+}
+
+proc_doc km_get_root_branch { question_id object_type_id} {
+ Returns the id of the root question of this branch.
+} {
+ set result [db_string km_get_root_branch "
+ select question_id
+ from sn_question_object_type_map
+ where question_id <> :question_id and branch_p='f'
+ start with question_id=:question_id and object_type_id=:object_type_id
+ connect by question_id = prior parent_question_id" -default ""]
+
+ return $result
+}
+
+proc_doc km_root_branch_p { question_id } {
+ Returns true if this question is a root of a branch (at any level)
+} {
+ return [db_string km_root_branch_p {
+ select decode(count(*),0,0,1) from dual where exists
+ (select 1
+ from sn_question_object_type_map
+ where parent_question_id = :question_id and branch_p='t')
+ }]
+}
+
+proc_doc km_composite_child_p { question_id object_type_id } {
+ Returns 1 if this question is the child of a composite question, 0 otherwise.
+ Included here because the distinction between branches and composite children is slight.
+} {
+ set result [db_string km_composite_child_p "
+ select decode(parent_question_id,[km_static km_dummy_object_id],0,1)
+ from sn_question_object_type_map
+ where branch_p='f'
+ and question_id=:question_id
+ and object_type_id=:object_type_id" -default "0"]
+
+ return 0
+}
+
+proc_doc km_active_branch_path { root_question_id object_id object_type_id } {
+
+ Returns the sequence of questions after this root branch question that
+ are part of the active branch path for this object.
+
+} {
+ set branch_id $root_question_id
+ set branch_list {}
+ if ![km_root_branch_p $root_question_id] { return $branch_list }
+
+ # Loop through hierarchy until we reach a leaf node or an unanswered question.
+ set i 0
+ while { 1 == 1 } {
+ # Get object data for the branch_id.
+ set question [km_get_question $branch_id $object_type_id]
+ if [empty_string_p $question] {
+ ns_log Error "Question $branch_id not found in km_active_branch_path"
+ return
+ }
+
+ set answer [fst [km_get_object_data -answers_only_p 0 -questions [list {question_id pretty_name abstract_data_type} $question] $object_id]]
+ set value [fst $answer]
+ set abstract_data_type [lindex $answer 3]
+
+ # Append this question to the list
+ lappend branch_list $branch_id
+
+ if ![km_answered_p $abstract_data_type $value] {
+ # the answer is empty so return the list
+ return $branch_list
+ } else {
+ # Get next branch
+ set branch_id [km_next_branch -abstract_data_type $abstract_data_type $branch_id $value $object_type_id]
+ if [empty_string_p $branch_id ] { return $branch_list }
+ }
+
+ incr i
+ if { $i > 100 } {
+ ns_log Error "Endless loop in km_active_branch_path"
+ return
+ }
+ }
+}
+
+proc_doc km_active_path_p { question_id object_id object_type_id } {
+
+ Returns 1 if this question is on an active branch path or is not on a branch at all.
+ Returns 0 if this question is not on a central branch path (i.e. it is decoupled
+ from the normal question sequence)
+
+} {
+ set root_question_id [km_get_root_branch $question_id $object_type_id]
+ if [empty_string_p $root_question_id] { return 1 }
+
+ set active_branches [km_active_branch_path $root_question_id $object_id $object_type_id]
+ if [elem_p $question_id $active_branches] {
+ return 1
+ } else {
+ return 0
+ }
+}
+
+ad_proc km_next_branch { { -abstract_data_type "" } root_branch_id answer object_type_id } {
+
+ Returns the question_id that should follow this question as a result of
+ the answers. It returns the default question if the answer hasn't been matched or is empty.
+ If it can't figure out the next question it returns nothing.
+
+} {
+ if [empty_string_p $abstract_data_type] {
+ set abstract_data_type [km_static question_abstract_data_type $root_branch_id]
+ }
+
+ # If it's not one of these abstract data types then this proc should never have been called!
+ if { [lsearch {"category" "other_category" "option"} $abstract_data_type] >= 0 } {
+
+ # Data answers are always tuples - we need the first value of the first pair
+ set answer [fst [fst $answer]]
+
+ # Then the answer is the integer value of the option, a foreign key
+ set column "branch_answer_foreign_key"
+
+ if { [empty_string_p $answer] || ![integer_p $answer] } { return }
+
+ } elseif { [lsearch {"text" "integer"} $abstract_data_type] >= 0 } {
+ set column "branch_answer"
+ set answer [fst $answer]
+ if { [empty_string_p $answer] || ![integer_p $answer] } { return }
+ } else {
+ return ""
+ }
+
+ set default_branch [km_default_branch $root_branch_id]
+
+ set branches [db_list_of_lists km_next_branch "
+ select question_id, branch_operator, $column
+ from sn_question_object_type_map
+ where parent_question_id=$root_branch_id
+ and object_type_id=$object_type_id"]
+
+ # Go through each of the branches and see if the operator matches this value
+ foreach branch $branches {
+ set branch_id [fst $branch]
+ set operator [snd $branch]
+ set branch_answer [thd $branch]
+
+ if [eval_binary $operator $answer $branch_answer] { return $branch_id }
+ }
+
+ return $default_branch
+}
+
+proc km_pretty_operator { operator } {
+ switch $operator {
+ "=" { return "Equals =" }
+ "<" { return "Less Than <" }
+ ">" { return "Greater Than >" }
+ default { return }
+ }
+}
+
+ad_proc km_branch_questions {
+ {
+ -branch_id 0
+ -all_properties_p 1
+ -root_question_id 0
+ -composite_children_p 1
+ }
+ object_type_id
+} {
+
+ This proc returns keyed question lists with attributes on the basis of variable branch
+ properties. i.e. It can return a list that shows all questions of an object_type that
+ are NOT branches, or these plus the one that IS this branch_id.
+
+ This proc has become more a general admin questions list, since it can do some stuff
+ for composite questions, too.
+
+} {
+ if { $all_properties_p } {
+ set additional_columns ",presentation_type, tag_height, tag_width, entry_explanation, qm.mandatory_p, qm.question_state, qm.form_number, qm.sort_key "
+ }
+
+ set limitation "parent_question_id=[km_static km_dummy_object_id] and question_state <> 'invisible'"
+ set counter 1
+
+ if { $root_question_id } {
+ append limitation " and qm.question_id != :root_question_id"
+ incr counter
+ }
+ if { $branch_id } {
+ append limitation " or qm.question_id = :branch_id "
+ incr counter
+ }
+ if { $counter > 1 } {
+ set limitation " and ($limitation)"
+ } else {
+ set limitation " and $limitation"
+ }
+ if { $composite_children_p } {
+ append limitation "
+and q.abstract_data_type in ('text', 'option', 'category', 'other_category', 'date', 'file', 'integer', 'object_link', 'content_link', 'user_link', 'child_object', 'nephew_object')
+and q.question_id not in (select parent_question_id from sn_question_object_type_map where object_type_id=:object_type_id and branch_p='t')"
+ }
+ set result [km_db_to_named_list_list km_branch_questions "
+ select q.question_id, q.pretty_name, q.abstract_data_type
+ $additional_columns
+ from sn_questions q, sn_question_object_type_map qm
+ where q.question_id=qm.question_id
+ and qm.object_type_id = :object_type_id
+ $limitation
+ order by qm.sort_key"]
+
+ return $result
+}
Index: openacs-4/contrib/obsolete-packages/library/tcl/km-browse-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/tcl/km-browse-procs.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/tcl/km-browse-procs.tcl 2 Jul 2003 12:19:41 -0000 1.1
@@ -0,0 +1,375 @@
+# /tcl/km-browsing.tcl
+#
+# Browsing of knowledge objects.
+# Created by carsten@arsdigita.com in June 2000
+#
+# $Id: km-browse-procs.tcl,v 1.1 2003/07/02 12:19:41 peterm Exp $
+
+proc_doc km_ancestors_context_list {ancestors {category_id ""} {pre_url ""}} {
+
+ Get a list of links to the parent objects, plus a link
+ to the root parent's object type.
+
+} {
+ set root_object_id [fst [fst $ancestors]]
+
+ db_1row get_root_info {
+ select o.one_line_description as ancestor_name,
+ o.object_type_id as ancestor_object_type_id,
+ ot.pretty_plural as ancestor_object_type,
+ o.archived_p as ancestor_archived_p
+ from sn_objects o, sn_object_types ot
+ where o.object_id = :root_object_id
+ and ot.object_type_id = o.object_type_id
+ }
+
+ if {$ancestor_archived_p == "t"} {
+ set ancestor_object_type "$ancestor_object_type (Archived)"
+ set archive t
+ }
+ lappend result [list "${pre_url}browse-one-type?[export_vars [list [list object_type_id $ancestor_object_type_id] archive]]" $ancestor_object_type]
+
+ if {![empty_string_p $category_id] && $category_id != "none"} {
+ if {[db_string is_object_of_category {select count(*) from sw_object_category_map where category_id = :category_id and object_id = :root_object_id}] > 0} {
+ lappend result [list "${pre_url}browse-one-category?[export_vars [list [list object_type_id $ancestor_object_type_id] category_id archive]]" [km_category_name $category_id]]
+ }
+ }
+
+ foreach ancestor $ancestors {
+ set name [sn_striphtml [snd $ancestor]]
+ if {[empty_string_p $name]} {
+ set name "Unnamed [km_static object_type_pretty_name [thd $ancestor]]"
+ }
+ lappend result [list "${pre_url}object-view?object_id=[fst $ancestor]&category_id=$category_id" $name]
+ }
+
+ return $result
+}
+
+proc_doc km_sort_by_bar { sort_by child_type_p } {
+ Sort: Object name | Modification date
+} {
+ set sort_by_list {{name "name"} {last_modified "modification date"}}
+ lappend sort_by_list {average_rating "user rating"}
+ if { $child_type_p } { lappend sort_by_list {parent "parent object"} }
+
+ foreach sort_item $sort_by_list {
+ set sort_column [lindex $sort_item 0]
+ set sort_description [lindex $sort_item 1]
+
+ if {$sort_column == $sort_by} {
+ lappend sort_text "$sort_description"
+ } else {
+ lappend sort_text "$sort_description"
+ }
+ }
+
+ return "\[ [join [concat $sort_text] " | "] \]"
+}
+
+proc_doc km_category_display_limit {} {
+
+ If the object list contains more than this many objects,
+ no categorization will be shown.
+
+} {
+ return [ad_parameter CategoryDisplayLimit library 20]
+}
+
+ad_proc km8_output_object_list {
+ {
+ -object_type_id 0
+ -header ""
+ -current_action ""
+ -path_id ""
+ -pool all
+ -age all
+ -sort_by ""
+ -show short
+ -category_id ""
+ -question_id 0
+ -where_clauses {}
+ -minus_join_tables {}
+ -minus_where_clauses {}
+ -first_row 0
+ -last_row 0
+ -begin_letter ""
+ -archived "f"
+ -start_date ""
+ -end_date ""
+ -more_join_tables {}
+ }
+} {
+
+ Output a list of objects.
+
+} {
+ ! Entered km8_output_object_list +more_join_tables
+ set user_id [ad_conn user_id]
+ set package_id [ad_conn package_id]
+ set instance_read_p [ad_permission_p $package_id "read"]
+
+ template::multirow create object_list public_p archived_p review_p object_view_link object_name user_link last_modified number_ratings rating_avg rating_avg_img rating_max rating_max_img access_total access_month overview categories_html
+
+ set child_type_p [db_string km_output_object_list_1 "
+ select decode(count(*),0,0,1) from sn_questions
+ where abstract_data_type in ('child_object','nephew_object')
+ and target_object_type_id = :object_type_id"]
+
+ # If the user is linking, or adding a SN reference,
+ # we add a button to each object.
+
+ # Make sure the user cannot see expired or private objects.
+ # Exceptions: Administrators, Sharenet Managers, and users who have been granted
+ # view permission for the object.
+
+ set join_tables [list "sn_objects obj"]
+
+ set package_id [ad_conn package_id]
+ lappend where_clauses \
+ "obj.expiration_date > sysdate" \
+ "obj.object_type_id = :object_type_id" \
+ "obj.context_id = :package_id" \
+ "obj.archived_p = :archived"
+
+ if { !$instance_read_p && $pool == "all" } {
+ # Only count published objects, or objects for which the user
+ # has view permission.
+
+ # Note that we only check direct read permission on flat
+ # groups and users. Since the context_id of private objects is
+ # NULL, and we only grant permissions to private groups, this
+ # is sufficient.
+
+ lappend where_clauses \
+ "(obj.public_p = 't' or obj.object_id in (
+ select object_id from acs_permissions
+ where (grantee_id = :user_id
+ or grantee_id in (select group_id from membership_rels
+ where person_id = :user_id))
+ and privilege = 'read'))"
+ }
+
+ if { [string compare $age all] != 0 } {
+ # Filter by time of last modification.
+ lappend where_clauses "sysdate - obj.last_modified < :age"
+ }
+
+ # Filter by author and co-owners.
+ switch $pool {
+ own { lappend where_clauses "obj.original_author_id = :user_id" }
+ coown {
+ lappend join_tables "acs_permissions p"
+
+ lappend where_clauses \
+ "obj.object_id = p.object_id" \
+ "p.privilege = 'write'" \
+ "(p.grantee_id = :user_id
+ or p.grantee_id in (select group_id from membership_rels where person_id = :user_id))"
+ }
+ }
+
+ # Sort by time of last modification or by name.
+ set columns {1}
+ switch $sort_by {
+ average_rating {
+ set sort_by_clause "nvl(cr.rating_sum,0) / nvl(cr.rating_count,1) desc, obj.last_modified desc"
+ set sort_by_clause2 "rating_avg desc, last_modified desc"
+ }
+ last_modified {
+ set sort_by_clause "obj.last_modified desc, lower(obj.one_line_description)"
+ set sort_by_clause2 "last_modified desc, lower(name)"
+ }
+ name {
+ set sort_by_clause "lower(obj.one_line_description), obj.last_modified desc"
+ set sort_by_clause2 "lower(name), last_modified desc"
+ }
+ parent {
+ set sort_by_clause "lower(obj2.one_line_description), lower(obj.one_line_description), obj.last_modified desc"
+ set sort_by_clause2 "lower(parent_name), lower(name), last_modified desc"
+
+ lappend columns "obj2.one_line_description as parent_name"
+ lappend join_tables "km_flat_object_hierarchy fo" "sn_objects obj2"
+ lappend where_clauses \
+ "fo.child(+) = obj.object_id" \
+ "(fo.distance = 1 or fo.distance is null)" \
+ "fo.parent = obj2.object_id(+)"
+ }
+ default {
+ set sort_by_clause "$sort_by, obj.last_modified desc"
+ set sort_by_clause2 "$sort_by, last_modified desc"
+ }
+ }
+
+ if { ![string equal $begin_letter all] } {
+ if { ![string equal $begin_letter other] } {
+ lappend where_clauses "substr(upper(obj.one_line_description),1,1) = '[string toupper $begin_letter]'"
+ } else {
+ lappend where_clauses "(substr(upper(obj.one_line_description),1,1) < 'A' or substr(upper(obj.one_line_description),1,1) > 'Z')"
+ }
+ }
+
+ if { ![empty_string_p $start_date] && ![empty_string_p $end_date]} {
+ lappend where_clauses "obj.start_date <= :end_date" "obj.end_date >= :start_date"
+ }
+
+ set join_tables [concat $join_tables $more_join_tables]
+
+ # We first need to get the number of listed objects, because
+ # depending on this number, we will or will not display object
+ # categorization.
+
+ ! Get the number of listed objects
+ set num_found_objects [db_string count_all_objects "
+ select count(unique obj.object_id)
+ from [join $join_tables ", "]
+ where [join $where_clauses "\nand "]"]
+ ! Got the number of listed objects +num_found_objects
+
+ if { ![null_p $minus_join_tables] } {
+ ! Get the number of excluded objects
+ set num_excluded_objects [db_string count_excluded_objects "
+ select count(unique obj.object_id)
+ from [join [concat $join_tables $minus_join_tables] ", "]
+ where [join [concat $where_clauses $minus_where_clauses] "\nand "]"]
+ ! Got the number of excluded objects +num_excluded_objects
+
+ set num_found_objects [expr $num_found_objects - $num_excluded_objects]
+ }
+
+ if { $child_type_p } {
+ lappend columns "km_utilities.km_ancestor_list(obj.object_id) as ancestors"
+ }
+
+ set display_limit [km_category_display_limit]
+ set category_questions {}
+ if { $num_found_objects < $display_limit } {
+ # Get node_id, category, question_id, question_pretty_name.
+ set category_questions [km_node_question_list $object_type_id]
+
+ foreach category_tuple $category_questions {
+ set root_node_id [fst $category_tuple]
+ lappend columns "km_utilities.km_category_list(obj.object_id, $root_node_id) as cat$root_node_id"
+ }
+ }
+
+ if { [null_p $minus_join_tables] } {
+ set sql "
+ select * from (select obj.object_id,
+ decode(obj.public_p,'t',1,0) as public_p,
+ decode(obj.archived_p,'t',1,0) as archived_p,
+ decode(obj.in_review_p,'t',1,0) as review_p,
+ u.first_names || ' ' || u.last_name as owner, u.user_id as owner_id,
+ obj.one_line_description as name, obj.overview,
+ decode(obj.overview_html_p,'t',1,0) as overview_html_p,
+ obj.last_modified, nvl(obj.access_total,0) as access_total,
+ nvl(obj.access_month,0) as access_month,
+ round(nvl(cr.rating_sum,0) / nvl(cr.rating_count,1),1) as rating_avg,
+ nvl(cr.rating_max,0) as rating_max,
+ nvl(cr.rating_count,0) as number_ratings,
+ dense_rank() over (order by $sort_by_clause) dr,
+ [join $columns ", "]
+ from [join $join_tables ", "], sn_comments_ratings cr, users u
+ where u.user_id = obj.original_author_id
+ and cr.object_id(+) = obj.object_id
+ and [join $where_clauses "\nand "])
+ where dr >= :first_row and (:last_row = 0 or dr <= :last_row)
+ order by $sort_by_clause2"
+ } else {
+ # This will be a bit complicated. We were called from browse-one-category
+ # to display a list of uncategorized objects. The fastest way to do this
+ # is with a MINUS, using only the object_id column. We then join the result
+ # with the query we would normally use to get the data we want.
+
+ set sql "
+select * from (select obj.object_id,
+ decode(obj.public_p,'t',1,0) as public_p,
+ decode(obj.archived_p,'t',1,0) as archived_p,
+ decode(obj.in_review_p,'t',1,0) as review_p,
+ u.first_names || ' ' || u.last_name as owner, u.user_id as owner_id,
+ obj.one_line_description as name, obj.overview,
+ decode(obj.overview_html_p,'t',1,0) as overview_html_p,
+ obj.last_modified, nvl(obj.access_total,0) as access_total,
+ nvl(obj.access_month,0) as access_month,
+ round(nvl(cr.rating_sum,0) / nvl(cr.rating_count,1),1) as rating_avg,
+ nvl(cr.rating_max,0) as rating_max,
+ nvl(cr.rating_count,0) as number_ratings,
+ dense_rank() over (order by $sort_by_clause) dr,
+ [join $columns ", "]
+from [join $join_tables ", "], sn_comments_ratings cr, users u,
+ (select obj.object_id
+ from [join $join_tables ", "]
+ where [join $where_clauses "\nand "]
+ minus
+ select /*+ORDERED*/ obj.object_id
+ from [join [concat $join_tables $minus_join_tables] ", "]
+ where [join [concat $where_clauses $minus_where_clauses] "\nand "]) filtered
+where u.user_id = obj.original_author_id
+ and cr.object_id(+) = obj.object_id
+ and obj.object_id = filtered.object_id)
+where dr >= :first_row and (:last_row = 0 or dr <= :last_row)
+order by $sort_by_clause2"
+ }
+
+ # We pass use a path to pass a couple of values to object-view,
+ # so they can be used as return URLs. (This is important because
+ # we want to preserve the user's filter and sort settings.)
+
+ set value_list [list browse_type [export_url_vars pool age sort_by show begin_letter]]
+ set parameters ""
+ if { ![empty_string_p $category_id] } {
+ set value_list [concat $value_list [list browse_category [export_url_vars pool age sort_by show begin_letter question_id column_name]]]
+ set parameters "&category_id=$category_id"
+ }
+ set new_path_id [init_path -last_path_id $path_id $value_list "" "browse"]
+
+ ! Getting the object list
+ set old_rank "0"
+ db_foreach get_object_list $sql {
+ ## filter out duplicate rows with the same dense_rank than the row
+ ## before
+ if {$dr == $old_rank} {
+ continue
+ }
+ set old_rank $dr
+ set categories_html ""
+
+ # Display the object's parent.
+ if { $child_type_p && ![empty_string_p $ancestors] } {
+ append categories_html "Related Objects: "
+ foreach ancestor $ancestors {
+ append categories_html "[snd $ancestor]; "
+ }
+ set categories_html [string range $categories_html 0 end-2]
+ }
+
+ if { $num_found_objects <= $display_limit && ![null_p $category_questions] } {
+ # List the object's categories.
+ foreach category_pair $category_questions {
+ set root_node_id [fst $category_pair]
+ set question_name [lindex $category_pair 3]
+ set category_value [set cat$root_node_id]
+
+ if ![empty_string_p $category_value] {
+ if ![empty_string_p $categories_html] { append categories_html "; " }
+ append categories_html "$question_name: $category_value"
+ }
+ }
+ }
+
+ if ![empty_string_p $overview] {
+ set overview [util_trim_string_with_hrefs [sn_striphtml $overview]]
+ }
+
+ if [empty_string_p $name] {
+ set name "Unnamed [km_static object_type_pretty_name $object_type_id]"
+ }
+
+ set object_view_link "object-view?object_id=$object_id$parameters&path_id=$new_path_id"
+ template::multirow append object_list $public_p $archived_p $review_p $object_view_link [sn_striphtml $name] [ad_present_user $owner_id $owner] [util_AnsiDatetoPrettyDate $last_modified] $number_ratings $rating_avg [gf_feedback_points_img $rating_avg 5] $rating_max [gf_feedback_points_img $rating_max 5] $access_total $access_month $overview $categories_html
+ }
+ ! Got the object list
+
+ ! Exiting km8_output_object_list
+ return $num_found_objects
+}
Index: openacs-4/contrib/obsolete-packages/library/tcl/km-callback-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/tcl/km-callback-procs.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/tcl/km-callback-procs.tcl 2 Jul 2003 12:19:41 -0000 1.1
@@ -0,0 +1,200 @@
+# /tcl/km-callback-procs.tcl
+#
+# Procs called from other modules.
+#
+# @author Carsten Clasohm (carsten@arsdigita.de)
+# @creation-date 2001-10-10
+# @cvs-id $Id: km-callback-procs.tcl,v 1.1 2003/07/02 12:19:41 peterm Exp $
+
+ad_proc -public library_post_instantiation {
+ package_id
+} {
+ This is the TCL proc that is called automatically by the APM
+ whenever a new instance of the application is created.
+} {
+ sn_community::grant_role_permissions $package_id {
+ maintainer {access create km_publish}
+ member {access create}
+ guest {access}
+ }
+ db_exec_plsql create_magic_psn_category_objects {
+ begin
+ psn_res_application.create_magic_objects (
+ package_id => :package_id
+ );
+ end;
+ }
+}
+
+ad_proc -public library_supported_privileges {} {
+
+ Returns a list of instance-level privileges supported by the Library.
+ Used by sn-communities to set permissions for role groups.
+
+} {
+ return {
+ {admin "Administer"}
+ {access "Access"}
+ {create "Create new objects"}
+ {read "Read private objects"}
+ {write "Edit all objects"}
+ {delete "Delete all objects"}
+ {km_publish "Publish an object if approval process is true"}
+ }
+}
+
+ad_proc -public library_copy_data {source_package_id target_package_id} {
+ Copy object type structure to the target package.
+} {
+ set ip_address [ns_conn peeraddr]
+ set user_id [ad_get_user_id]
+
+ db_exec_plsql copy_all_object_types {
+ begin
+ library.copy (
+ src_package_id => :source_package_id,
+ dst_package_id => :target_package_id,
+ creation_user => :user_id,
+ creation_ip => :ip_address);
+ end;
+ }
+}
+
+ad_proc -public library_get_category_trees {package_id} {
+
+ Returns a list of all category trees used by this instance.
+ Used during community copying, to grant permissions on the trees.
+
+} {
+
+ return [db_list get_categories {
+ -- Categories used for object type questions.
+ select tree_id
+ from sn_object_types ot, sn_question_object_type_map qm, sn_questions q
+ where ot.context_id = :package_id
+ and qm.object_type_id = ot.object_type_id
+ and q.question_id = qm.question_id
+ and q.abstract_data_type in ('category', 'other_category')
+ and q.tree_id is not null
+ union
+ -- Categories used for object feedback.
+ select object_id_two
+ from acs_rels
+ where rel_type = 'object_category_tree_rel'
+ and object_id_one = :package_id
+ union
+ -- Categories used on the PeopleShareNet application form.
+ select object_id_two
+ from acs_rels r, psn_category_trees ct
+ where r.rel_type = 'object_category_tree_rel'
+ and ct.package_id = :package_id
+ and (r.object_id_one = ct.role_magic_id
+ or r.object_id_one = ct.language_magic_id
+ or r.object_id_one = ct.proficiency_magic_id)
+
+ }]
+
+}
+
+namespace eval categories::packages::library {
+ ad_proc -public get_instances { tree_id } {
+ Returns a list of all library instances using a certain category tree
+ } {
+ set instance_list [list]
+ set user_id [ad_conn user_id]
+
+ db_foreach get_library_instances_for_tree {
+ select v.object_id, p.instance_name, v.object_name,
+ ci.community_id, p2.instance_name as community_name,
+ acs_permission.permission_p(p.package_id, :user_id, 'access') as show_p
+ from apm_packages p, apm_packages p2, sn_community_instances_all ci,
+ (select distinct q.question_id, ot.object_type_id as object_id,
+ ot.pretty_plural || ' (Question "' || q.pretty_name || '")' as object_name,
+ ot.context_id as package_id
+ from sn_object_types ot, sn_questions q,
+ sn_question_object_type_map qm, sw_category_dim d
+ where d.parent_node_id = q.node_id
+ and d.tree_id = :tree_id
+ and q.question_id = qm.question_id
+ and qm.object_type_id = ot.object_type_id
+ union
+ select 0 as question_id, p.package_id as object_id,
+ 'Feedback' as object_name, p.package_id
+ from acs_rels r, apm_packages p
+ where r.object_id_two = :tree_id
+ and r.rel_type = 'object_category_tree_rel'
+ and r.object_id_one = p.package_id
+ and p.package_key = 'library') v
+ where p.package_id = v.package_id
+ and ci.package_id = v.package_id
+ and p2.package_id = ci.community_id
+ order by p2.instance_name, p.instance_name, v.object_name
+ } {
+ lappend instance_list [list Libraries $object_id $object_name $instance_name $community_id $community_name $show_p $show_p]
+ }
+ return $instance_list
+ }
+}
+
+namespace eval sn_presentation::types::sn_object {
+ ad_proc linkable_item {object_id url object_data_var} {
+ upvar 1 $object_data_var object_data
+
+ set public_p 0
+ if { [string first "presentation=public" $object_data(presentation)] != -1 } {
+ set public_p 1
+ }
+ set archived_p 0
+ if { [string first "archived" $object_data(presentation)] != -1 } {
+ set archived_p 1
+ }
+ set in_review_p 0
+ if { [string first "in_review" $object_data(presentation)] != -1 } {
+ set in_review_p 1
+ }
+
+ set result "[sn_striphtml $object_data(name)]"
+ if { !$public_p } { append result " \[Private\]" }
+ if { $archived_p } { append result " \[Archived\]" }
+ if { $in_review_p } { append result " \[In review\]" }
+ return $result
+ }
+
+ ad_proc item {object_id object_data_var} {
+ upvar 1 $object_data_var object_data
+
+ set public_p 0
+ if { [string first "presentation=public" $object_data(presentation)] != -1 } {
+ set public_p 1
+ }
+ set archived_p 0
+ if { [string first "archived" $object_data(presentation)] != -1 } {
+ set archived_p 1
+ }
+ set in_review_p 0
+ if { [string first "in_review" $object_data(presentation)] != -1 } {
+ set in_review_p 1
+ }
+
+ set result [sn_striphtml $object_data(name)]
+ if { !$public_p } { append result " \[Private\]" }
+ if { $archived_p } { append result " \[Archived\]" }
+ if { $in_review_p } { append result " \[In review\]" }
+ return $result
+ }
+}
+
+namespace eval alerts {
+ namespace eval types {
+ namespace eval sn_object {
+ ad_proc -public get_object {object_id} {
+ } {
+ if { [catch { set object_as_clob [db_string object_public_object_clob \
+ {select site_wide_search.indexed_content(:object_id) from dual}]} errmsg] } {
+ return [list "" 0]
+ }
+ return [list $object_as_clob 0]
+ }
+ }
+ }
+}
Index: openacs-4/contrib/obsolete-packages/library/tcl/km-categories-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/tcl/km-categories-procs.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/tcl/km-categories-procs.tcl 2 Jul 2003 12:19:41 -0000 1.1
@@ -0,0 +1,876 @@
+# /tcl/km-categories.tcl
+#
+# Categorization of knowledge objects.
+#
+# Created by carsten@arsdigita.com in June 2000
+#
+# Modified by tvujec@arsdigita.com in August 2001
+#
+# $Id: km-categories-procs.tcl,v 1.1 2003/07/02 12:19:41 peterm Exp $
+
+# Category hierarchy
+#
+# location [Placeholder]
+# Global [Location]
+
+ad_proc km_category_table {
+ {
+ -object_type_id 0
+ -question_id 0
+ -parent_node_id 0
+ -uncategorized_p 1
+ -target {}
+ -category_counts {}
+ -maximum_sub_columns 1
+ }
+} {
+
+ Generate the table of links for a category tree. Returns 0 if
+ the table is empty, otherwise returns a non-zero integer.
+
+} {
+ template::multirow create categorization_widget category target category_id sum_count parent_node_id question_id
+ template::multirow create categorization_widget_header header_name
+ if { !$parent_node_id } {
+
+ # If no parent categories have been specified, we get all the
+ # categories that can be associated with the given object type
+ # and question.
+
+ set questions [db_list_of_lists get_category_questions {
+ select q.question_id, q.node_id, q.pretty_name
+ from sn_questions q, sn_question_object_type_map qm
+ where qm.object_type_id = :object_type_id
+ and qm.question_id = q.question_id
+ and qm.question_state <> 'invisible'
+ and q.browse_p = 't'
+ and q.abstract_data_type in ('category','other_category')
+ order by qm.sort_key}]
+
+ if [null_p $questions] { return 0 }
+ } else {
+ set pretty_question [db_string get_pretty_question {
+ select pretty_name
+ from sn_questions
+ where question_id = :question_id}]
+ set questions [list [list $question_id $parent_node_id $pretty_question]]
+ }
+
+ set category_list {}
+ foreach question $questions {
+ # For each of the parent categories we display the child categories.
+
+ set question_id [fst $question]
+ set parent_node_id [snd $question]
+ set pretty_question [thd $question]
+
+ if { $uncategorized_p && ![empty_string_p $category_counts] } {
+ set uncategorized_target "${target}none&question_id=$question_id"
+ set uncategorized_count [ns_set get $category_counts "uncat $question_id"]
+ } else {
+ set uncategorized_target ""
+ set uncategorized_count 0
+ }
+
+ set elem [km8_categorization_widget \
+ -uncategorized_p $uncategorized_p \
+ -parent_node_id $parent_node_id -target $target \
+ -question_id $question_id \
+ -category_count $category_counts \
+ -uncategorized_target $uncategorized_target \
+ -uncategorized_count $uncategorized_count \
+ -maximum_columns $maximum_sub_columns]
+
+ if ![null_p $elem] {
+ lappend category_list [list $pretty_question $elem]
+ }
+ }
+
+ set n_total 0
+ set i 0
+ set category_type_count [llength $category_list]
+ while { $i < $category_type_count } {
+ template::multirow append categorization_widget_header [fst [lindex $category_list $i]]
+ incr i
+ }
+
+ return $i
+}
+
+proc_doc km_get_child_categories {question_id} {
+
+ Returns all the categories associated with the given question
+ as a list of tuples holding the category_id and the indented
+ category name.
+
+} {
+ set root_node_id [db_string get_node_id {
+ select node_id from sn_questions
+ where question_id = :question_id
+ }]
+
+ if ![empty_string_p $root_node_id] {
+ set result [util_memoize "swc_get_category_tree $root_node_id 0 {}"]
+ } else {
+ set result {}
+ }
+
+ return $result
+}
+
+proc_doc km_get_node_id {question_id} {
+
+ Returns the node_id for this question_id or an empty string.
+
+} {
+ set result [db_string km_get_category_id "
+ select node_id from sn_questions where question_id=:question_id" -default ""]
+ return $result
+}
+
+proc_doc km_categorize_object { question_id object_id category_ids } {
+
+ Inserts a row into the sw_object_category_map which maps each
+ object to a list of categories.
+
+ Also takes care of removing old categorizations which are of the same type
+ as the given category_ids.
+
+ Returns a list of 1 for each successfully inserted and 0 for each
+ failed category_id.
+
+} {
+ foreach category_id $category_ids {
+ if ![empty_string_p $category_id] {
+ lappend nonempty_category_ids $category_id
+ }
+ }
+ if {![info exists nonempty_category_ids]} {
+ km_uncategorize_object $object_id $question_id
+ return
+ }
+ set category_ids $nonempty_category_ids
+
+ set user_id [ad_conn user_id]
+ set ip_address [ns_conn peeraddr]
+
+ db_transaction {
+ # First get rid of any old categorizations of this object
+ # that belongs to the same question.
+
+ db_dml uncategorize {
+ delete from sw_object_category_map
+ where object_id = :object_id
+ and category_id in (select child_category_id from sw_flat_cat
+ where parent = (select node_id from sn_questions
+ where question_id = :question_id))
+ }
+
+ # Insert the new categorization.
+ # The insert query gracefully ignores duplicate categorization.
+
+ foreach category_id $category_ids {
+ db_dml categorize {
+ insert into sw_object_category_map (object_id, category_id)
+ select :object_id, :category_id
+ from dual
+ where not exists (select 1 from sw_object_category_map
+ where object_id = :object_id
+ and category_id = :category_id)
+ }
+ }
+
+ db_exec_plsql last_modified {
+ begin
+ acs_object.last_modified (
+ v_object_id => :object_id,
+ v_modifying_user => :user_id,
+ v_modifying_ip => :ip_address
+ );
+ end;
+ }
+
+ set pretty_categories [db_list km_categorize_object_50 "
+ select long_name from categories
+ where category_id in ([join $category_ids ","])"]
+
+ if { [llength $pretty_categories] > 1 } {
+ set label "categories"
+ } else {
+ set label "category"
+ }
+
+ set content "Set $label [DoubleApos [join $pretty_categories ", "]]."
+ db_exec_plsql km_categorize_object_6 {
+ begin
+ object.audit_object (
+ v_object_id => :object_id,
+ v_question_id => :question_id,
+ v_last_modifying_user_id => :user_id,
+ v_modifying_ip => :ip_address,
+ v_content => :content
+ );
+ end;
+ }
+ }
+
+ # After the user has changed the categorization of an object, we
+ # want to give him up-to-date category counts. So we flush the
+ # memoized km_get_category_count results for him.
+ km_flush_category_count -object_id $object_id
+}
+
+ad_proc km_flush_category_count {
+ {
+ -object_id 0
+ -object_type_id 0
+ -user_id 0
+ -local 0
+ }
+} {
+ Clears the cached category count for the current user.
+ Note that we only flush for "begin_letter all". Flushing
+ for all letters would take too much time.
+} {
+ if !$user_id { set user_id [ad_conn user_id] }
+ if !$object_type_id { set object_type_id [km_get_object_type $object_id] }
+
+ if !$local {
+ server_cluster_httpget_from_peers "/SYSTEM/flush-category-count.tcl?[export_url_vars object_type_id user_id]"
+ }
+
+ foreach pool {all own coown} {
+ foreach age {90 180 365 730 all} {
+ foreach archived {t f} {
+ util_memoize_flush_local "km_get_category_count_internal -age $age -pool $pool -begin_letter all -archived $archived $object_type_id $user_id"
+ }
+ }
+ }
+}
+
+ad_proc km_uncategorize_object { object_id question_id } {
+
+ Removes all categorization of this object for this question.
+ This is used for non-mandatory fields were the user hasn't selected
+ any categories.
+
+} {
+ db_transaction {
+ db_dml uncategorize {
+ delete from sw_object_category_map
+ where object_id = :object_id
+ and category_id in (select child_category_id from sw_flat_cat
+ where parent = (select node_id from sn_questions
+ where question_id = :question_id))
+ }
+
+ set user_id [ad_conn user_id]
+ set ip_address [ns_conn peeraddr]
+
+ db_exec_plsql km_uncategorize_object_10 {
+ begin
+ acs_object.last_modified (
+ v_object_id => :object_id,
+ v_modifying_user => :user_id,
+ v_modifying_ip => :ip_address
+ );
+ end;
+ }
+
+ set content "Deleted all categories."
+ set ip_address [ns_conn peeraddr]
+ db_exec_plsql km_uncategorize_object_3 {
+ begin
+ object.audit_object (
+ v_object_id => :object_id,
+ v_question_id => :question_id,
+ v_last_modifying_user_id => :user_id,
+ v_modifying_ip => :ip_address,
+ v_content => :content
+ );
+ end;
+ }
+ }
+
+ km_flush_category_count -object_id $object_id
+}
+
+ad_proc km_get_categories {object_id question_id } {
+ Returns a list of {category_id category} mapped to this object and this question.
+} {
+ return [db_list_of_lists get_categories {
+ select c.category_id, c.long_name
+ from categories c, sw_flat_cat fc, sw_object_category_map cm, sn_questions q
+ where cm.object_id = :object_id
+ and q.question_id = :question_id
+ and fc.parent = q.node_id
+ and c.category_id = fc.child_category_id
+ and cm.category_id = c.category_id
+ }]
+}
+
+ad_proc km_get_category_counts {
+ {
+ -age "all"
+ -pool "all"
+ -begin_letter "all"
+ -start_category_id 0
+ -archived "f"
+ -start_date ""
+ -end_date ""
+ }
+ object_type_id result
+} {
+
+ Returns the count of number of objects as a new ns_set.
+ Caches things for a few minutes.
+
+} {
+ set category_count_timeout [ad_parameter CategoryCountTimeout library 300]
+ set user_id [ad_conn user_id]
+
+ set category_count_list [util_memoize "km_get_category_count_internal -age $age -pool $pool -begin_letter $begin_letter -start_category_id $start_category_id -archived $archived -start_date $start_date -end_date $end_date $object_type_id $user_id" $category_count_timeout]
+
+ foreach elem $category_count_list {
+ ns_set put $result [lindex $elem 0] [lindex $elem 1]
+ }
+
+ return $result
+}
+
+ad_proc km_get_category_count_internal {
+ {
+ -age "all"
+ -pool "all"
+ -begin_letter "all"
+ -start_category_id 0
+ -archived "f"
+ -start_date ""
+ -end_date ""
+ }
+ object_type_id user_id
+} {
+
+ Counts the number of objects the user can view, grouped by
+ category. (Internal version.)
+
+} {
+ ! We're not caching. Entering km_get_category_count_internal
+ set package_id [ad_conn package_id]
+ set instance_read_p [ad_permission_p $package_id "read"]
+
+ set category_count_list {}
+
+ lappend where_clauses \
+ "o.object_type_id = :object_type_id" \
+ "o.context_id = :package_id" \
+ "o.expiration_date > sysdate" \
+ "o.archived_p = :archived"
+
+ set tables "sw_category_dim swcd, sw_flat_cat fc, sw_object_category_map swcm, sn_objects o"
+ set total_tables "sn_objects o"
+ if { !$instance_read_p && $pool == "all" } {
+ # Only count published objects, or objects for which the user
+ # has view permission.
+
+ # Note that we only check direct read permission on flat
+ # groups and users. Since the context_id of private objects is
+ # NULL, and we only grant permissions to private groups, this
+ # is sufficient.
+
+ lappend where_clauses \
+ "(o.public_p = 't' or o.object_id in (
+ select object_id from acs_permissions
+ where (grantee_id = :user_id
+ or grantee_id in (select group_id from membership_rels
+ where person_id = :user_id))
+ and privilege = 'read'))"
+ }
+
+ if { $age != "all" } { lappend where_clauses "sysdate - o.last_modified < :age" }
+
+ # Filter by author.
+ switch $pool {
+ own {
+ lappend where_clauses "o.original_author_id = :user_id"
+ }
+ coown {
+ set tables "(select group_id as grantee_id from membership_rels where person_id = :user_id union select $user_id as grantee_id from dual) g, acs_permissions p, sn_objects o, sw_object_category_map swcm, sw_flat_cat fc, sw_category_dim swcd"
+ set total_tables "(select group_id as grantee_id from membership_rels where person_id = :user_id union select $user_id as grantee_id from dual) g, acs_permissions p, sn_objects o"
+ lappend where_clauses \
+ "o.object_id = p.object_id" \
+ "p.grantee_id = g.grantee_id" \
+ "p.privilege = 'write'"
+ }
+ }
+
+ if { ![string equal $begin_letter all] } {
+ if { ![string equal $begin_letter other] } {
+ lappend where_clauses "upper(o.one_line_description) like '[string toupper $begin_letter]%'"
+ } else {
+ lappend where_clauses "(upper(o.one_line_description) < 'A' or upper(o.one_line_description) > 'Z')"
+ }
+ }
+
+ if { ![empty_string_p $start_date] && ![empty_string_p $end_date]} {
+ lappend where_clauses "o.start_date <= :end_date" "o.end_date >= :start_date"
+ }
+
+ # Count the total number of viewable objects.
+
+ set total_viewable_objects_count [db_string get_total_count [subst {
+ select count(unique o.object_id)
+ from $total_tables
+ where [join $where_clauses "\nand "]
+ }]]
+
+ lappend category_count_list [list total $total_viewable_objects_count]
+
+ if { $start_category_id == 0 } {
+
+ # Count the uncategorized stuff for each question.
+ # We do this by counting all the categorized objects
+ # and subtracting the resulting number from the total number
+ # of objects. This is much faster than letting Oracle do
+ # the job.
+
+ set questions [km_node_question_list -browse_p $object_type_id]
+
+ foreach question $questions {
+ util_unlist $question question_node_id dummy question_id
+
+ set count [db_string count_categorized_objects [subst {
+ select /*+ORDERED*/ count(unique o.object_id)
+ from $total_tables, sw_object_category_map swcm, sw_flat_cat fc
+ where [join $where_clauses "\n and "]
+ and swcm.object_id = o.object_id
+ and swcm.category_id = fc.child_category_id
+ and fc.parent = :question_node_id
+ }]]
+
+ lappend category_count_list \
+ [list "uncat $question_id" [expr $total_viewable_objects_count - $count]]
+
+ # Count categorized stuff by category on the first level below the question.
+
+ db_foreach get_category_counts [subst {
+ select /*+ORDERED*/ fc.parent_category_id,
+ count(unique o.object_id) as object_count
+ from $tables
+ where [join $where_clauses "\n and "]
+ and swcd.parent_node_id = :question_node_id
+ and fc.parent = swcd.node_id
+ and swcm.category_id = fc.child_category_id
+ and swcm.object_id = o.object_id
+ group by fc.parent_category_id
+ }] {
+ lappend category_count_list [list $parent_category_id $object_count]
+ }
+ }
+
+ } else {
+
+ # Get counts below a certain root category.
+
+ set count [db_string count_categorized_objects [subst {
+ select /*+ORDERED*/ count(unique o.object_id)
+ from $total_tables, sw_object_category_map swcm, sw_flat_cat fc
+ where [join $where_clauses "\n and "]
+ and swcm.object_id = o.object_id
+ and swcm.category_id = fc.child_category_id
+ and fc.parent_category_id = :start_category_id
+ }]]
+
+ lappend category_count_list \
+ [list $start_category_id $count] \
+ [list "uncat" [expr $total_viewable_objects_count - $count]]
+
+ # Count categorized stuff by category on the first level below the question.
+
+ set node_id [db_string get_start_node_id {
+ select node_id
+ from sw_category_dim
+ where object_id = :start_category_id
+ }]
+
+ db_foreach get_category_counts [subst {
+ select /*+ORDERED*/ fc.parent_category_id,
+ count(unique o.object_id) as object_count
+ from $tables
+ where [join $where_clauses "\n and "]
+ and swcd.parent_node_id = :node_id
+ and fc.parent = swcd.node_id
+ and swcm.category_id = fc.child_category_id
+ and swcm.object_id = o.object_id
+ group by fc.parent_category_id
+ }] {
+ lappend category_count_list [list $parent_category_id $object_count]
+ }
+
+ }
+
+ ! Exiting km_get_category_count_internal
+ return $category_count_list
+}
+
+ad_proc km_node_question_list { {-browse_p:boolean 0} object_type_id } {
+
+ Returns a list of questions that are categorizations for the given
+ object type, each element being a list of
+ node ID, category or tree name, question ID, pretty_name.
+ if -browse_p is given, it will return only browseable category
+ questions.
+
+} {
+ if {$browse_p} {
+ set browse_clause "and q.browse_p = 't'"
+ } else {
+ set browse_clause ""
+ }
+
+ set result [db_list_of_lists km_node_question_list "
+ select q.node_id, g.tree_name, q.question_id, q.pretty_name
+ from sn_questions q, sn_question_object_type_map qm, generic_trees g
+ where q.question_id = qm.question_id
+ and g.tree_id = q.tree_id
+ and qm.object_type_id = :object_type_id
+ and qm.question_state <> 'invisible'
+ $browse_clause
+ order by qm.sort_key"]
+
+ return $result
+}
+
+ad_proc km_question_in_object_type { } {
+ Replaces the PL/SQL function sn_question_in_object_type.
+ Returns an exists clause that should be much faster than the previous
+PL/SQL function.
+} {
+ return "and 1= (select count(*)
+ from sn_question_object_type_map
+ where object_type_id = :object_type_id
+ and question_id = :question_id
+ and question_state <> 'invisible')"
+}
+
+proc_doc km_node_question { object_type_id node_id } {
+
+ Given an object type and a top-level node ID, determine
+ which question this category belongs to.
+
+} {
+ # rownum=1 added by dirk (11-july-2001). remove it...it's most likely
+ # wrong, but I just want to get this big piece of software to run
+
+ set result [db_string km_node_question "
+ select question_id from sn_questions
+ where node_id=:node_id
+ [km_question_in_object_type] and rownum=1" -default ""]
+ return $result
+}
+
+ad_proc km_node_question_parent { object_type_id node_id } {
+
+ Given an object type and a node ID, determine which question this
+ category belongs to.
+
+} {
+ return [km_db_1row_to_list km_node_question_parent {
+ select q.question_id, q.node_id
+ from sn_questions q, sw_flat_cat fc, sn_question_object_type_map qm
+ where fc.child = :node_id
+ and fc.parent = q.node_id
+ and qm.object_type_id = :object_type_id
+ and qm.question_id = q.question_id
+ and qm.question_state <> 'invisible'
+ }]
+}
+
+ad_proc km_category_name { category_id } {
+ Get the name of the of a category
+} {
+ if [empty_string_p $category_id] { return -code error "Missing category_id" }
+ if {[string equal $category_id none]} {
+ return ""
+ }
+ set result [db_string km_category_name "
+ select long_name from categories
+ where category_id = :category_id" -default ""]
+
+ return $result
+}
+
+ad_proc km_root_node {
+ {
+ -question_id 0
+ }
+ object_type_id
+} {
+
+ Get the parent node_id for a given object type.
+
+ If question_id is 0, a list of the parents for all the questions
+ of this object type is returned.
+ Else, the parent for the given question_id is returned.
+
+} {
+ if !$question_id {
+ # Select all categorization questions.
+
+ set result [db_list km_root_node "
+ select node_id
+ from sn_questions q, sn_question_object_type_map qm
+ where q.node_id is not null
+ and qm.object_type_id = :object_type_id
+ and qm.question_id = q.question_id
+ and qm.question_state <> 'invisible'
+ order by sort_key"]
+ } else {
+ set result [db_string km_root_node_2 "
+ select node_id from sn_questions where question_id=:question_id" -default ""]
+ }
+
+ return $result
+}
+
+ad_proc km_object_filter_bar {
+ {
+ -child_type_p 0
+ }
+ pool age sort_by
+} {
+
+ Filters and sorting options displayed on the top of most category pages.
+ Note that *you* have to provide the TABLE tag.
+
+} {
+ return "
+
Owner:
[km_ownership_bar $pool]
+
Sort:
[km_sort_by_bar $sort_by $child_type_p]
"
+}
+
+proc_doc km_object_view_bar_top_level { show short_title all_title } {
+ View: Just category descriptions | All objects
+} {
+ set show_list [list [list short $short_title] [list all $all_title]]
+
+ foreach show_pair $show_list {
+ set show_value [lindex $show_pair 0]
+ set show_annotation [lindex $show_pair 1]
+
+ if {$show == $show_value} {
+ lappend show_bar "$show_annotation"
+ } else {
+ lappend show_bar "$show_annotation"
+ }
+ }
+
+ return "\[ [join $show_bar " | "] \]"
+}
+
+proc_doc km_ownership_bar { current_pool } {
+ Filter: My objects | My objects & co-owner | All
+} {
+ return [ad_choice_bar \
+ { "my objects" "my objects & co-owner" "all" } \
+ "[ns_conn url]?[export_ns_set_vars url {pool}]&pool=\$value" \
+ { own coown all } \
+ $current_pool]
+}
+
+proc_doc km_archive_bar { current_archive } {
+ Filter: Live Objects | Archived Objects
+} {
+ return [ad_choice_bar \
+ { "live objects" "archived objects" } \
+ "[ns_conn url]?[export_ns_set_vars url {archive}]&archive=\$value" \
+ { f t } \
+ $current_archive]
+}
+
+proc_doc km_age_bar { current_age } {
+ Filter: 3 6 12 24 months | All
+} {
+ proc mk_link { default parms } {
+ set label [fst $parms]
+ set value [snd $parms]
+
+ if { $value == $default } {
+ return "$label"
+ } else {
+ return "$label"
+ }
+ }
+
+ return "[join [map "mk_link $current_age" [list "3 90" "6 180" "12 365" "24 730"]] " "] months | [mk_link $current_age "All all"]"
+}
+
+ad_proc km8_categorization_widget {
+ {
+ -parent_node_id {}
+ -uncategorized_p 0
+ -target {}
+ -question_id {}
+ -category_count {}
+ -uncategorized_target {}
+ -uncategorized_count {}
+ -maximum_columns 1
+ }
+} {
+
+ Build the table showing category counts for a given parent category.
+
+} {
+ # Translate ns_set category_count into a Tcl array
+ #
+ if { ![null_p $category_count] } {
+ for {set i 0} {$i < [ns_set size $category_count]} {incr i} {
+ set sum_count([ns_set key $category_count $i]) [ns_set value $category_count $i]
+ }
+ }
+
+ # Fetch the category hierarchy.
+ #
+
+ set ordered {}
+ set select_size 0
+ db_foreach categories {
+ select c.long_name as category, c.category_id
+ from categories c, sw_category_dim d
+ where d.parent_node_id = :parent_node_id
+ and c.category_id = d.object_id
+ order by nvl(c.sort_key,9999)
+ } {
+ if { [empty_string_p $category_count] ||
+ ([info exists sum_count($category_id)] && $sum_count($category_id) > 0) } {
+ lappend ordered [list $category $category_id]
+ incr select_size
+ }
+ }
+
+ if { !$select_size } { return "" }
+
+ # Generate the widget open tag, now that we know the size
+ if { $maximum_columns > 1 } {
+ if { $select_size < 15 } {
+ set maximum_columns 1
+ } else {
+ set column_size [expr $select_size / $maximum_columns]
+ }
+ }
+
+ # What column are we currently writing to
+ set column_no 1
+ # How many rows have we written to that
+ set column_count 0
+ set show_category_p 0
+
+ # Iterate to generate the HTML
+ #
+ foreach elem $ordered {
+ set category [fst $elem]
+ set category_id [snd $elem]
+
+ set option ""
+
+ if { $maximum_columns > 1 } {
+ incr column_count
+ if { $column_count > $column_size && $column_no < $maximum_columns } {
+ incr column_no
+ set column_count 0
+ }
+ }
+
+ if {![info exists sum_count($category_id)]} {
+ set sum_count($category_id) ""
+ }
+
+ set show_category_p 1
+ template::multirow append categorization_widget $category $target $category_id "$sum_count($category_id)" $parent_node_id $question_id
+
+ }
+ # foreach
+
+ if { $uncategorized_p } {
+ if {![empty_string_p $uncategorized_count] && $uncategorized_count != 0} {
+ if { ![empty_string_p $uncategorized_target]} {
+ set target ${uncategorized_target}
+ }
+ set show_category_p 1
+ template::multirow append categorization_widget Uncategorized $target "" $uncategorized_count $parent_node_id
+
+ }
+ }
+ return $show_category_p
+}
+
+
+proc_doc ad_category_parentage_list {category_id {known_parent_id ""}} {
+
+ Returns a list of lists, where each sublist is one line of
+ parentage up from the specified category to the hierarchy root. In
+ turn, each parentage line list consists of two-item lists: category_id
+ and long_name. A list of lists is needed since a category can have
+ multiple parents. If this category has no parents, then return the
+ empty list.
+
+} {
+
+ set n_parents [db_string ad_category_parentage_list_10 "select count(*) from sw_category_dim where object_id = :category_id"]
+
+ if { $n_parents == 0 } {
+ return [list]
+ }
+
+ set sql_ad_category_parentage_list_20 "SELECT c.category_id AS parent_id, c.long_name AS parent_category, hc.level_col
+FROM categories c,
+(SELECT h.object_id as child, LEVEL AS level_col, ROWNUM AS row_col
+ FROM sw_category_dim h
+ START WITH h.object_id = :category_id
+ CONNECT BY h.node_id = PRIOR h.parent_node_id) hc
+WHERE c.category_id = hc.child
+ORDER BY hc.row_col"
+
+ set parentage_list [list]
+ set parentage_line [list]
+ set prior_level 0
+ set stop_everything 0
+ db_foreach ad_category_parentage_list_20 $sql_ad_category_parentage_list_20 {
+ if {$stop_everything== 1} {
+
+ if {$level_col <= $prior_level} {
+ # Parent line is now completed, flush it
+ lappend parentage_list $parentage_line
+
+ # Keep the last bit of the parentage chain
+ # lars@pinds.com, Feb 2000
+ #
+ set parentage_line [lrange $parentage_line [expr $prior_level - $level_col + 1] end]
+ }
+
+ set prior_level $level_col
+
+ # We're moving up the hierarchy so put this category at
+ # the beginning of the parentage line.
+ #
+ set parentage_line [concat [list [list $parent_id $parent_category]] $parentage_line]
+
+ if { ![empty_string_p $known_parent_id] && $known_parent_id == $parent_id } {
+ set stop_everything 1
+ }
+ }
+
+ }
+
+ if {$stop_everything == 1} {
+ # you cannot return from within db_foreach
+ return $parentage_line
+ }
+ if { [empty_string_p $known_parent_id] } {
+ # Don't forget the last parentage line
+ return [lappend parentage_list $parentage_line]
+ } else {
+ # We didn't find the wanted parent
+ return [list]
+ }
+}
Index: openacs-4/contrib/obsolete-packages/library/tcl/km-display-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/tcl/km-display-procs.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/tcl/km-display-procs.tcl 2 Jul 2003 12:19:41 -0000 1.1
@@ -0,0 +1,490 @@
+# /tcl/km-display-procs.tcl
+#
+# Display of data.
+#
+# $Id: km-display-procs.tcl,v 1.1 2003/07/02 12:19:41 peterm Exp $
+
+# ********** Display procs for questions of various abstract data types- No Form **********
+proc_doc km_display_category_value {category_value_list} {
+ Formats a list of category_id and category value tuples for simple display.
+} {
+ set category_names [snd [transpose $category_value_list]]
+ set formatted_values [join $category_names ", "]
+ return $formatted_values
+}
+
+proc_doc km_display_other_category_value {category_value_list object_id question_id} {
+ Formats a list of category_id and category value tuples for simple display.
+} {
+ set other_value [snd [fst [km_get_object_content -question_ids [list $question_id] $object_id]]]
+ set category_names [snd [transpose $category_value_list]]
+ set category_list [list]
+ foreach category $category_names {
+ if { [string equal [string toupper $category] "OTHER"] && ![empty_string_p $other_value] } {
+ append category " ($other_value)"
+ }
+ lappend category_list $category
+ }
+ set formatted_values [join $category_list ", "]
+ return $formatted_values
+}
+
+proc_doc km_display_options {answer_option_list} {
+ Displays tuples in an option list for simple display.
+} {
+ return [join [snd [transpose $answer_option_list]] ", "]
+}
+
+# *********Buttons**********
+
+ad_proc km_get_button_names {} {
+ Returns a list of all the constant submit button names in the km library.
+} {
+
+ return {
+ proceed
+ finish
+ details
+ add_web_ref
+ add_sn_ref
+ add_user_ref
+ add_content_ref
+ next_question
+ last_question
+ link
+ browse
+ all_questions
+ unanswered
+ answered
+ add_child
+ add_nephew
+ copy_child
+ copy_nephew
+ volunteer
+ previous_question
+ next_question
+ delete
+ }
+}
+
+proc_doc km8_button_panel {question_id object_id object_type_id} {
+
+ This proc returns the submit button-panel.
+
+ Note that I'm getting the buttons to the same size manually, since netscape 4x
+ can't do width as a style for an input button. You have to pass the object_id
+ since the active branch path can only be determined from object data.
+
+ } {
+ set captions {}
+ set button_values ""
+ set next_value ""
+ set next_name ""
+
+ # If this question leads to a branch, we set the default answer as next question.
+ set root_branch_p [km_root_branch_p $question_id]
+
+ # If this question is a branch, then we need to know its parent.
+ set branch_parent [km_branch_parent $question_id $object_type_id]
+
+ # Determine the next question.
+ if { $root_branch_p } {
+ # The branch continues - so we don't know where to go to yet.
+ set next_question 0
+ } elseif ![empty_string_p $branch_parent] {
+ # End of branch. We determine the next question relative to the branch root.
+ set branch_root [km_get_root_branch $question_id $object_type_id]
+ set next_question [km_get_question -next_p 1 -object_id $object_id $branch_root $object_type_id]
+ } else {
+ # This is no branch. So just use the current question_id for determining
+ # the next.
+ set next_question [km_get_question -next_p 1 -object_id $object_id $question_id $object_type_id]
+ }
+
+ # Determine the previous question.
+ if ![empty_string_p $branch_parent] {
+ # When in a branch, Previous always takes us back to our parent.
+ set previous_question $branch_parent
+ } else {
+ set previous_question [km_get_question -previous_p 1 -object_id $object_id $question_id $object_type_id]
+ if ![empty_string_p $previous_question] {
+ if [km_root_branch_p [fst $previous_question]] {
+ # The previous question is the root of a branch. To find the actual "previous"
+ # question, we have to traverse this branch until the last active question.
+ set active_branches [km_active_branch_path [fst $previous_question] $object_id $object_type_id]
+ set previous_question [fst [reverse $active_branches]]
+ }
+ }
+ }
+
+ set button_values {" << " " >> "}
+ if ![empty_string_p $previous_question] {
+ set previous_value [fst $button_values]
+ set previous_name "previous_question.[fst $previous_question]"
+ }
+ if ![empty_string_p $next_question] {
+ set next_value [snd $button_values]
+ set next_name "next_question.[fst $next_question]"
+ }
+
+ set button_1 ""
+ set button_2 ""
+ if { ![empty_string_p $previous_question] && ![empty_string_p $next_question] } {
+ set button_1 $previous_name
+ set button_2 $next_name
+ } elseif ![empty_string_p $previous_question] {
+ set button_1 $previous_name
+ } elseif ![empty_string_p $next_question] {
+ set button_2 $next_name
+ }
+
+ set button_names {"all_questions." "unanswered." "answered."}
+ set button_values {"All Questions" "Completed Content"}
+ return [list $button_1 \
+ [fst $button_names] \
+ [snd $button_names] \
+ [thd $button_names] \
+ $button_2]
+}
+
+# ********** Basic Display Procs **********
+proc_doc km_count_object_view { user_id object_id } {
+ Record an object view.
+} {
+ if {![km_original_author_p $user_id $object_id]} {
+ db_dml km_count_object_view_10 "
+ update sn_access_counts
+ set access_count = access_count + 1
+ where object_id=:object_id
+ and access_date = (trunc(sysdate,'month'))"
+
+ if {![db_resultrows]} {
+ db_dml insert_access_count {
+ insert into sn_access_counts (object_id, access_count, access_date)
+ select :object_id, 1, (trunc(sysdate,'month')) from dual
+ where not exists (select 1 from sn_access_counts
+ where object_id=:object_id
+ and access_date = (trunc(sysdate,'month')))
+ }
+ db_dml reset_sn_object_monthly_count {
+ update sn_objects
+ set access_total = access_total +1,
+ access_month = 1
+ where object_id = :object_id
+ }
+ } else {
+ db_dml increment_sn_object_count {
+ update sn_objects
+ set access_total = access_total +1,
+ access_month = access_month +1
+ where object_id = :object_id
+ }
+ }
+ }
+}
+
+proc_doc km_get_access_count { object_id } {
+} {
+ return [db_string access_count {
+ select nvl(sum(access_count),0)
+ from sn_access_counts
+ where object_id = :object_id
+ }]
+}
+
+proc_doc km_get_access_count_month { object_id } {
+} {
+ return [db_string access_count_month {
+ select nvl(sum(access_count),0)
+ from sn_access_counts
+ where object_id = :object_id
+ and access_date = (trunc(sysdate,'month'))
+ }]
+}
+
+
+proc_doc km_object_access_toolbar {object_id {category_id ""}} {
+ Toolbar: [Private] Make public | Access Control | Delete Object
+} {
+ set user_id [ad_conn user_id]
+ set package_id [ad_conn package_id]
+
+ set return_url "object-view?[export_url_vars object_id category_id]"
+
+ set result {}
+ set write_p [km_conn write_p]
+ set admin_p [km_conn admin_p]
+ set publish_p [km_conn publish_p]
+ set public_p [km_conn public_p]
+ set archived_p [km_conn archived_p]
+ set archive_p [km_static object_type_archive_p [km_conn object_type_id]]
+ set approval_p [km_static approval_p $package_id]
+ set in_review_p [km_conn in_review_p]
+ set review_state [km_conn review_state]
+
+ # admins or users with write permission (if object is not archived)
+ # can make object public/private
+ if {$admin_p || ($approval_p && $publish_p)} {
+ if {!$public_p} {
+ if {$approval_p && $in_review_p} {
+ if {[string equal $review_state library_review]} {
+ lappend result "\[Private\] \[In review\] Make public"
+ } else {
+ lappend result "\[Private\] \[Needs clarification\] Make public"
+ }
+ } else {
+ lappend result "\[Private\] Make public"
+ }
+ } else {
+ lappend result "\[Public\] Make private"
+ }
+ } elseif {$write_p && !$archived_p} {
+ if { !$public_p } {
+ if {!$in_review_p && $approval_p} {
+ lappend result "\[Private\] Propose to publish"
+ } elseif {!$in_review_p} {
+ lappend result "\[Private\] Make public"
+ } else {
+ # The state of a workflow task is user-dependant, hence we need the
+ # else clause. A task might be in review, but there's nothing going
+ # on for the user.
+ db_1row get_workflow_task {
+ select distinct(ut.task_id)
+ from wf_cases c, wf_user_tasks ut
+ where c.object_id = :object_id
+ and c.case_id = ut.case_id
+ and c.state = 'active'
+ and rownum = 1
+ order by ut.task_id desc
+ }
+ if {[string equal $review_state library_review]} {
+ lappend result "\[Private\] In review"
+ } elseif {[string equal $review_state library_clarify]} {
+ lappend result "\[Private\] Review: Needs clarification"
+ } else {
+ lappend result "\[Private\] \[In review\]"
+ }
+ }
+ } elseif {!$approval_p} {
+ lappend result "\[Public\] Make private"
+ } else {
+ lappend result "\[Public\]"
+ }
+ } else {
+ if { $in_review_p } {
+ lappend result "\[Private\] \[In review\]"
+ } elseif { !$public_p } {
+ lappend result "\[Private\]"
+ }
+ }
+ ## users with write permission can archive/unarchive object
+ ## (and admins and publishers)
+ if {$write_p || $admin_p || ($approval_p && $publish_p)} {
+ if {$archived_p} {
+ lappend result "\[Archived\] Remove from archive"
+ }
+ if {$archive_p && !$archived_p && ($admin_p || $publish_p || !$approval_p || (!$public_p && !$in_review_p))} {
+ lappend result "Put in archive"
+ }
+ }
+ # admins or users with write permission (if object is not archived)
+ # can change permissions on the object
+ if {$admin_p || ($write_p && !$archived_p)} {
+ lappend result "Access Control"
+ }
+ # users with delete permissions (owner or admins) can delete an object
+ if [km_conn delete_p] {
+ if {[empty_string_p $category_id] || $category_id == "none"} {
+ set return_delete "browse-one-type?object_type_id=[km_conn object_type_id]"
+ } else {
+ set return_delete "browse-one-category?object_type_id=[km_conn object_type_id]&category_id=$category_id"
+ }
+ lappend result "Delete Object"
+ }
+
+ # admins or publishers have access to the approval task
+ if {$approval_p && $in_review_p && ($publish_p || $admin_p)} {
+ db_1row get_workflow_task {
+ select distinct(ut.task_id)
+ from wf_cases c, wf_user_tasks ut
+ where c.object_id = :object_id
+ and c.case_id = ut.case_id
+ and c.state = 'active'
+ and rownum = 1
+ order by ut.task_id desc
+ }
+ lappend result "Manage Approval"
+ }
+
+ return [join $result " | "]
+}
+
+proc_doc km_shorten_question { question } {
+ Shortens a question up to the question mark in the question.
+} {
+ set line_end [string first ? $question]
+ if { $line_end >= 0 } {
+ return [string range $question 0 $line_end]
+ } else {
+ return $question
+ }
+}
+
+#--------------------------------------------------------
+
+
+proc_doc util_trim_string_with_hrefs { string_to_trim { final_length 200 } } {
+ Will return the trimmed string without cutting off an href before the tag.
+} {
+
+ if {[string length $string_to_trim] < $final_length} {
+ return $string_to_trim
+ }
+
+ set string_trimmed [string range $string_to_trim 0 $final_length]
+ set string_trimmed_lower [string tolower $string_trimmed]
+
+ # find the last occurance of "
+ set last_href_close [string last "" $string_trimmed_lower]
+
+ # if there is no after the last $last_href_close} {
+ set string_trimmed [string range $string_trimmed 0 [expr $last_href - 1]]
+ }
+ }
+
+ return "$string_trimmed..."
+}
+
+
+proc_doc util_make_href_and_mailto_links { text } {
+ Changes http:// and https:// to links and email formats to mailto's
+} {
+ # (bd) if there are any A HREF or IMG SRCs this guy know how to use them
+ # so we don't touch his HTML. It may be hard to see but I am using
+ # carriage returns, # newlines, tabs and spaces (in that order) in these
+ # regexps:
+ set text " $text"
+ if {!([regexp -nocase {<[
+ ]*a[
+ ]*href[
+ ]*=} $text] || [regexp -nocase {<[
+ ]*img[
+ ]*src[
+ ]*=} $text])} {
+ # if something is " http://" or " https://"
+ # we assume it is a link to an outside source.
+
+ # (bd) The only purpose of thiese sTaRtUrL and
+ # eNdUrL markers is to get rid of trailing dots,
+ # commas and things like that. Note that there
+ # is a TAB before and after each marker.
+
+ regsub -nocase -all {"} $text {"} text
+ regsub -nocase -all {"} $text {"} text
+ regsub -nocase -all {([^a-zA-Z0-9]+)(http://[^\(\)"<>
+ ]+)} $text {\1 sTaRtUrL\2eNdUrL } text
+ regsub -nocase -all {([^a-zA-Z0-9]+)(https://[^\(\)"<>
+ ]+)} $text {\1 sTaRtUrL\2eNdUrL } text
+ regsub -nocase -all {([^a-zA-Z0-9]+)(ftp://[^\(\)"<>
+ ]+)} $text {\1 sTaRtUrL\2eNdUrL } text
+
+ # email links have the form xxx@xxx.xxx
+ regsub -nocase -all {([^a-zA-Z0-9]+)([^\(\)
+ :;,@<>]+@[^\(\)
+ .:;,@<>]+[.][^\(\)
+ :;,@<>]+)} $text {\1 sTaRtEmAiL\2eNdEmAiL } text
+ #
+ regsub -all {([]!?.:;,<>\(\)\}-]+)(eNdUrL )} $text {\2\1} text
+ regsub -all {([]!?.:;,<>\(\)\}-]+)(eNdEmAiL )} $text {\2\1} text
+ regsub -all { sTaRtUrL([^ ]*)eNdUrL } $text {\1} text
+ regsub -all { sTaRtEmAiL([^ ]*)eNdEmAiL } $text {\1} text
+ }
+ return [string trimleft $text]
+}
+
+proc_doc util_make_href_and_mailto_links_and_convert_to_html { text {html_p 0} } {
+
+ util_make_href_and_mailto_links interferes badly with util_convert_to_html.
+ That's why I had to write a special procedure that does both things correctly.
+ See those two procs for details.
+
+} {
+
+ if { $html_p } { return $text }
+
+ set text " $text"
+ # if something is " http://" or " https://"
+ # we assume it is a link to an outside source.
+
+ # (bd) The only purpose of thiese sTaRtUrL and
+ # eNdUrL markers is to get rid of trailing dots,
+ # commas and things like that. Note that there
+ # is a TAB before and after each marker.
+
+ regsub -nocase -all {([^a-zA-Z0-9]+)(http://[^\(\)"<>
+ ]+)} $text {\1 sTaRtUrL\2eNdUrL } text
+ regsub -nocase -all {([^a-zA-Z0-9]+)(https://[^\(\)"<>
+ ]+)} $text {\1 sTaRtUrL\2eNdUrL } text
+ regsub -nocase -all {([^a-zA-Z0-9]+)(ftp://[^\(\)"<>
+ ]+)} $text {\1 sTaRtUrL\2eNdUrL } text
+
+ # email links have the form xxx@xxx.xxx
+ regsub -nocase -all {([^a-zA-Z0-9]+)([^\(\)
+ :;,@<>]+@[^\(\)
+ .:;,@<>]+[.][^\(\)
+ :;,@<>]+)} $text {\1 sTaRtEmAiL\2eNdEmAiL } text
+ # At this point, before inserting some of our own <, >, and "'s
+ # we quote the ones entered by the user:
+ set text [util_quotehtml $text]
+ # turn CRLFCRLF into
\ No newline at end of file
Index: openacs-4/contrib/obsolete-packages/library/www/add-sharenet-ref.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/add-sharenet-ref.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/add-sharenet-ref.tcl 2 Jul 2003 12:19:42 -0000 1.1
@@ -0,0 +1,52 @@
+ad_page_contract {
+ /www/library/add-sharenet-ref.tcl
+
+ Called after the user has selected an existing or created a new
+ object. Appends a reference to this object to the question
+ associated with the current path.
+
+ @cvs-id $Id: add-sharenet-ref.tcl,v 1.1 2003/07/02 12:19:42 peterm Exp $
+} {
+ path_id:notnull
+ object_id:notnull,integer
+}
+csrf::authenticate
+
+if ![path_valid_p $path_id] {
+ ad_return_error "Invalid Path" \
+ "The current path ID is invalid. Perhaps you used your browser's Back button
+ and tried to press the Link button a second time?"
+ return
+}
+
+set user_id [ad_maybe_redirect_for_registration]
+
+
+# Determine to which object we are going to add the href,
+# and if the current user is allowed to do this.
+
+set values [get_path_values -action_only_p 0 $path_id]
+set original_object_id [value_from_tuples $values object_id]
+set sub_object_id [value_from_tuples $values sub_object_id]
+
+if ![km_check_object_id -check_edit_p 1 $original_object_id] { return }
+
+
+# OK, let's insert it.
+
+if [empty_string_p $sub_object_id] {
+ set question_id [value_from_tuples $values question_id]
+ set row_id $original_object_id
+} else {
+ set question_id [value_from_tuples $values subquestion_id]
+ set row_id $sub_object_id
+}
+
+km_append_object_content -html_p "t" $row_id $question_id \
+ "[km_get_object_name $object_id]"
+
+km_check_public_status_after_edit $row_id
+
+# All done, back to the path's origin.
+
+ad_returnredirect [get_path_return_url $path_id]
Index: openacs-4/contrib/obsolete-packages/library/www/add-web-ref-2.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/add-web-ref-2.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/add-web-ref-2.tcl 2 Jul 2003 12:19:42 -0000 1.1
@@ -0,0 +1,87 @@
+ad_page_contract {
+ /www/library/add-web-ref-2.tcl
+
+ Verify Web or email reference, and append it to the column given as
+ part of the path.
+
+ @cvs-id $Id: add-web-ref-2.tcl,v 1.1 2003/07/02 12:19:42 peterm Exp $
+} {
+ path_id:notnull,integer
+ url
+ url_title
+}
+csrf::authenticate
+
+if ![path_valid_p $path_id] {
+ ad_return_error "Invalid Path" \
+ "The current path ID is invalid. Perhaps you used your browser's Back button
+ and tried to enter another Web/email reference?"
+ return
+}
+
+set user_id [ad_maybe_redirect_for_registration]
+
+# Determine to which object we are going to add the href,
+# and if the current user is allowed to do this.
+
+set values [get_path_values -action_only_p 0 $path_id]
+set object_id [value_from_tuples $values object_id]
+set sub_object_id [value_from_tuples $values sub_object_id]
+
+
+# Check the user input.
+
+if ![km_check_object_id -check_edit_p 1 $object_id] { return }
+
+set examples "
+
+
A valid URL would be something like http://photo.net/philg/,
+
A valid E-mail address would be something like: philg@mit.edu.
+
"
+
+set exception_count 0
+set exception_text ""
+
+if { ![empty_string_p $url] && ![util_url_valid_p $url] && ![util_email_valid_p $url] } {
+ # There is a URL or email, but it doesn't match our REGEXP.
+
+ incr exception_count
+ append exception_text "
The text you entered: $url looks
+ neither like an URL nor like an E-mail address.
+ $examples
+ "
+}
+
+if [empty_string_p $url] {
+ incr exception_count
+ append exception_text "
Please add a comment to your feedback. The system will include
+ it in the feedback E-Mail to the user.
+ Here you shall explain, describe or comment your feedback
+ (i.e. what project did you reuse the information for,
+ what did you learn, why do you think it's outdated or should have
+ more details, etc.).
+
+ What comment would you like to add to the above @object_type@?
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ checked>
+Add this comment as a public comment to the knowledge object
+
+
+
+
+
+
+
+
+
Index: openacs-4/contrib/obsolete-packages/library/www/comment-add-2.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/comment-add-2.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/comment-add-2.tcl 2 Jul 2003 12:19:42 -0000 1.1
@@ -0,0 +1,123 @@
+ad_page_contract {
+ /packages/library/www/comment-add-2.tcl
+
+ Let the user enter a comment and the number of reuse points.
+
+ @author Carsten Clasohm (carsten@arsdigita.com)
+ @author Bernd Schmeil (bernd@arsdigita.com) - did modifications
+ @author Timo Hentschel (timo@arsdigita.com)
+
+ @cvs-id $Id: comment-add-2.tcl,v 1.1 2003/07/02 12:19:42 peterm Exp $
+} {
+ object_id:notnull,integer
+ {feedback_category_id:integer ""}
+ {category_id ""}
+ {path_id:integer ""}
+ {comment ""}
+ {html_p:oneof(t|f) "f"}
+ {public_p:optional "t"}
+ {reuse_points:integer "-1"}
+} -properties {
+ title:onevalue
+ headline:onevalue
+ object_name:onevalue
+ object_type:onevalue
+ form_vars:onevalue
+ feedback_category:onevalue
+ feedback_category_id:onevalue
+ ratings:multirow
+ overview_with_href_and_mailto:onevalue
+ author_id:onevalue
+ author_name:onevalue
+ subsite_url:onevalue
+ subsite_name:onevalue
+ header_stuff:onevalue
+ comment:onevalue
+ html_p:onevalue
+ public_p:onevalue
+ reuse_points:onevalue
+}
+
+set user_id [ad_maybe_redirect_for_registration]
+set package_id [ad_conn package_id]
+
+array set node [site_node_closest_ancestor_site_node "acs-subsite"]
+set community_id $node(package_id)
+
+if ![km_check_object_id $object_id] { return }
+set author_id [km_conn original_author_id]
+set author_name [km_conn original_author_name]
+
+if {$feedback_category_id == 0} {
+ ad_return_complaint 1 "Please select a feedback category!"
+ return
+}
+
+if {[km_conn archived_p]} {
+ ad_return_complaint 1 "Only feedback for not archived knowledge objects is allowed!"
+ return
+}
+
+set object_name [km_conn object_name]
+set object_type [km_static object_type_pretty_name [km_conn object_type_id]]
+
+array set node [site_node_closest_ancestor_site_node "acs-subsite"]
+set subsite_url $node(url)
+set subsite_name $node(instance_name)
+set header_stuff ""
+
+if {![empty_string_p $feedback_category_id]} {
+ set feedback_category [db_string get_category_name {
+ select long_name from categories
+ where category_id = :feedback_category_id} -default ""]
+
+ # don't let user give feedback points if user is author
+ # or object is private
+ if {($user_id == $author_id) || ![km_conn public_p] || ![db_0or1row get_rating_scale {
+ select rating_p as reuse_p, scale
+ from sn_comments_category_settings
+ where object_id = :package_id
+ and category_id = :feedback_category_id }]} {
+ set reuse_p "f"
+ set scale 0
+ }
+} else {
+ set reuse_p "f"
+ set scale 0
+ set feedback_category ""
+}
+
+if {$reuse_p=="t"} {
+ set what "Give feedback"
+ set headline "Give Feedback"
+ set title "Give feedback for \"$object_name\""
+} else {
+ set what "Add comment"
+ set headline "Your Comment"
+ set title "Add a comment to \"$object_name\""
+}
+
+set_the_usual_klib_context_bar $object_id $category_id
+if {[empty_string_p $feedback_category_id]} {
+ append_context_bar_data $what
+} else {
+ append_context_bar_data [list "comment-add?[export_url_vars object_id category_id path_id]" "Feedback category"] $what
+}
+
+set overview_with_href_and_mailto [util_make_href_and_mailto_links [km_conn overview]]
+set form_vars [export_form_vars object_id feedback_category_id category_id path_id]
+set original_author_p [km_original_author_p $user_id $object_id]
+
+template::multirow create ratings number
+
+if { $reuse_p=="t" } {
+ # Generate the list of valid reuse points.
+ if { $scale > 0} {
+ for { set counter 0 } { $counter <= $scale } { incr counter } {
+ template::multirow append ratings $counter
+ }
+ }
+}
+
+ad_return_template
+
Index: openacs-4/contrib/obsolete-packages/library/www/comment-add-3.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/comment-add-3.adp,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/comment-add-3.adp 2 Jul 2003 12:19:42 -0000 1.1
@@ -0,0 +1,71 @@
+
+@title;noquote@
+
+The following is your comment as it would appear on the page
+@object_name@. If it looks incorrect, please use the back button
+on your browser to return and correct it. Otherwise, press
+"Continue".
+
+
+
+
Feedback type: @feedback_category@
+
+
Comment:
@comment;noquote@
+
+
+
+ This comment will appear as a comment below the @object_type@ "@object_name@".
+
+
+ This comment will only get sent to the author
+ @author_name@ of the
+ @object_type@ "@object_name@"
+ and will NOT appear as a comment below the @object_type@.
+
+
+
+
+
Note: If the comment has lost all of its paragraph breaks then you
+ probably should have selected "Plain Text" rather than "HTML".
+
+
Note: If the comment has a bunch of visible HTML tags then you probably
+ should have selected "HTML" rather than "Plain Text". Use your
+ browser's Back button to return to the submission form.
+
+
+
+
+
You will receive the following shares:
+
+
@own_shares.bank_name@: @own_shares.amount@ @own_shares.currency@ (New balance: @own_shares.balance@ @own_shares.currency@)
+
+
+ @author_name@
+
+
+ is about to receive no shares since you rated the object with 0.
+
+ is about to receive no shares since no shares will be awarded for this feedback type.
+
+
+ is about to receive the following shares proportional to @reuse_points@
+ points you awarded his knowledge object:
+
+ Feedback author: @author@
+ Feedback type: @feedback_category@
+ Rating: @rating@ out of @scale@ points
+
Comment:
@content;noquote@
+
+
+
Do you really want to delete this feedback?
+
Please be aware that the shares awarded for this feedback will NOT
+be taken away by this action - you have to do these things in the Incentive system.
+
Index: openacs-4/contrib/obsolete-packages/library/www/km-display-nephew-object.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/km-display-nephew-object.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/km-display-nephew-object.tcl 2 Jul 2003 12:19:43 -0000 1.1
@@ -0,0 +1,88 @@
+# Takes a list of nephew_object_data and displays the short_description and
+# long description in a blue box.
+
+if {![info exists edit_p]} {
+ set edit_p 0
+}
+
+if {![info exists category_id]} {
+ set category_id ""
+}
+
+if {![info exists nephew_object_type]} {
+ set nephew_object_type 0
+}
+
+if {![info exists question_state]} {
+ set question_state "active"
+}
+
+# question_id user_id object_id nephews
+
+# Takes a list of nephew_object_data and displays the short_description and
+# long description in a blue box.
+
+
+if { $edit_p } {
+ set action_caption "
Action
"
+} else {
+ set action_caption ""
+}
+if !$nephew_object_type {
+ set nephew_object_type [km_static question_target_object_type_id $question_id]
+}
+set context_id [ad_conn package_id]
+
+# We need the pretty name of the short and long descriptions:
+db_1row question_info_long_desc {
+ select nvl2(q.question_id,1,0) as long_p, q.pretty_name as long_pretty_name
+ from sn_questions q, sn_object_types ot
+ where ot.long_description = q.question_id(+)
+ and ot.object_type_id = :nephew_object_type
+ and ot.context_id = :context_id
+}
+
+set short_desc_list ""
+db_foreach question_info_short_desc {
+ select q1.pretty_name as short_pretty_name
+ from sn_questions q1, sn_types_map_short_name map, sn_object_types ot
+ where map.short_description = q1.question_id(+)
+ and map.object_type_id = :nephew_object_type
+ and map.object_type_id = ot.object_type_id
+ and ot.context_id = :context_id
+ order by position
+} {
+ if {![empty_string_p $short_desc_list]} {
+ append short_desc_list ", $short_pretty_name"
+ } else {
+ set short_desc_list $short_pretty_name
+ }
+}
+
+if {![empty_string_p $short_desc_list]} {
+ set short_p 1
+ set short_desc_list [join $short_desc_list ", "]
+} else {
+ set short_p 0
+}
+
+set table ""
+
+set i 1
+template::multirow create nephews_list edit_p question_state i short_p long_p short_description public_p archived_p review_p url_vars long_description
+
+foreach nephew $nephews {
+ util_unlist $nephew object_id public_p archived_p review_p short_description long_description
+
+ set short_description ""
+ if { $short_p } {
+ if {[empty_string_p $short_description]} {
+ set short_description [km_get_object_name $object_id]
+ }
+ set short_description [sn_striphtml $short_description]
+ }
+
+ template::multirow append nephews_list $edit_p $question_state $i $short_p $long_p $short_description $public_p $archived_p $review_p [export_url_vars object_id category_id] [util_trim_string_with_hrefs $long_description]
+ incr i
+}
+
Index: openacs-4/contrib/obsolete-packages/library/www/km-display-question-answer.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/km-display-question-answer.adp,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/km-display-question-answer.adp 2 Jul 2003 12:19:43 -0000 1.1
@@ -0,0 +1,68 @@
+
+
+
Access has been granted to @grantee_name@.
+
+You may return to where
+you were, or also grant access to the linked objects below. To do
+so, select any number of objects and press Proceed.
+
+
Index: openacs-4/contrib/obsolete-packages/library/www/object-access-add.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/object-access-add.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/object-access-add.tcl 2 Jul 2003 12:19:43 -0000 1.1
@@ -0,0 +1,116 @@
+ad_page_contract {
+ /www/library/object-access-add.tcl
+
+ Add a user or group to the object's access control list.
+ List all linked objects and let the user select the ones that should
+ be assigned the same permissions.
+
+ @cvs-id $Id: object-access-add.tcl,v 1.1 2003/07/02 12:19:43 peterm Exp $
+} {
+ object_id:notnull,integer
+ {category_id ""}
+ {view_p:boolean 1}
+ {edit_p:boolean 1}
+ {user_id_from_search:integer,optional}
+ {group_id:integer,optional}
+} -properties {
+ title:onevalue
+ form_vars:onevalue
+ object_id:onevalue
+ links:multirow
+}
+csrf::authenticate
+
+set user_id [ad_maybe_redirect_for_registration]
+if ![km_check_object_id -check_edit_p 1 $object_id] { return }
+
+set object_type_id [km_conn object_type_id]
+set object_name [km_conn object_name]
+set graphic [km_static object_type_graphic $object_type_id]
+
+set title "Access control for \"$object_name\""
+set_the_usual_klib_context_bar $object_id $category_id
+append_context_bar_data [list "object-access?[export_url_vars object_id category_id]" "Access control"] "Linked Objects"
+
+if { [info exists user_id_from_search] } {
+ set grantee_name [db_string user_name {
+ select first_names || ' ' || last_name
+ from users
+ where user_id = :user_id_from_search
+ }]
+ set grantee_id $user_id_from_search
+} else {
+ set grantee_name [db_string group_name {
+ select group_name
+ from groups
+ where group_id = :group_id
+ }]
+ set grantee_id $group_id
+}
+
+if { $view_p } {
+ db_exec_plsql grant_read {
+ begin
+ acs_permission.grant_permission(:object_id, :grantee_id, 'read');
+ end;
+ }
+}
+
+if { $edit_p } {
+ db_exec_plsql grant_write {
+ begin
+ acs_permission.grant_permission(:object_id, :grantee_id, 'write');
+ end;
+ }
+}
+
+# List the linked objects for which the current user may set
+# permissions.
+
+set linked_objects [km_get_linked_objects -from_p 1 -to_p 1 $user_id $object_id]
+
+set linked_object_ix [lsearch [fst $linked_objects] linked_object_id]
+set linked_object_type_id_ix [lsearch [fst $linked_objects] linked_object_type]
+set name_ix [lsearch [fst $linked_objects] name]
+set overview_ix [lsearch [fst $linked_objects] overview]
+set form_vars [export_form_vars object_id category_id view_p edit_p grantee_id]
+
+set counter 0
+template::multirow create links linked_object_type_id graphic pretty_type_plural object_id object_name short_description overview
+
+foreach link [tail $linked_objects] {
+ set linked_object_id [lindex $link $linked_object_ix]
+ set linked_object_type_id [lindex $link $linked_object_type_id_ix]
+ set linked_object_name [lindex $link $name_ix]
+
+ if { $overview_ix != -1 } {
+ set overview [lindex $link $overview_ix]
+ } else {
+ set overview ""
+ }
+
+ if [km_check_object_id -check_edit_p 1 -print_errors_p 0 $linked_object_id] {
+ # Only show the object if the user may change the
+ # permissions for it.
+
+ set pretty_type_plural [km_static object_type_pretty_plural $linked_object_type_id]
+ set graphic [km_static object_type_graphic $linked_object_type_id]
+ if ![empty_string_p $overview] {
+ set overview [util_trim_string_with_hrefs $overview]
+ set snd_column "-"
+ } else {
+ set snd_column ""
+ }
+
+ incr counter
+
+ template::multirow append links $linked_object_type_id $graphic $pretty_type_plural $linked_object_id $linked_object_name $snd_column $overview
+ }
+}
+
+if !$counter {
+ ad_returnredirect "object-access?[export_url_vars object_id category_id]"
+ return
+}
+
+ad_return_template
Index: openacs-4/contrib/obsolete-packages/library/www/object-access-change.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/object-access-change.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/object-access-change.tcl 2 Jul 2003 12:19:43 -0000 1.1
@@ -0,0 +1,50 @@
+ad_page_contract {
+ /packages/library/www/object-access-change.tcl
+
+ Grant or revoke direct read/write permissions on an object.
+
+ @cvs-id $Id: object-access-change.tcl,v 1.1 2003/07/02 12:19:43 peterm Exp $
+} {
+ object_id:notnull,integer
+ {category_id ""}
+ party_ids:integer,multiple
+ allow_edit:optional
+ disallow_edit:optional
+ disallow_access:optional
+}
+csrf::authenticate
+
+if ![km_check_object_id -check_edit_p 1 $object_id] { return }
+
+db_transaction {
+
+if [info exists allow_edit] {
+ foreach party_id $party_ids {
+ db_exec_plsql grant_write {
+ begin
+ acs_permission.grant_permission(:object_id, :party_id, 'write');
+ end;
+ }
+ }
+} elseif [info exists disallow_edit] {
+ foreach party_id $party_ids {
+ db_exec_plsql grant_write {
+ begin
+ acs_permission.revoke_permission(:object_id, :party_id, 'write');
+ end;
+ }
+ }
+} elseif [info exists disallow_access] {
+ foreach party_id $party_ids {
+ db_exec_plsql grant_write {
+ begin
+ acs_permission.revoke_permission(:object_id, :party_id, 'read');
+ acs_permission.revoke_permission(:object_id, :party_id, 'write');
+ end;
+ }
+ }
+}
+
+}
+
+ad_returnredirect "object-access?object_id=$object_id&category_id=$category_id"
Index: openacs-4/contrib/obsolete-packages/library/www/object-access.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/object-access.adp,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/object-access.adp 2 Jul 2003 12:19:43 -0000 1.1
@@ -0,0 +1,148 @@
+
+@title;noquote@
+
+
At least one mandatory question has not been answered. Please
+ edit
+ the object and add any missing data."
+ return
+}
+
+db_transaction {
+
+ # Check if a user already got shares for this entry (by making
+ # it public). If not, give him the shares. This is ignoring
+ # the issue of different banks, but that's OK because we just
+ # want to know if he was rewarded for publishing the object,
+ # not where and how the reward took place.
+ set awardedp [db_string object_awarded_shares {
+ select count(*) from ir_share_transactions
+ where cc_name = 'kl_object_publish' and object_id = :object_id
+ }]
+
+ if {!$awardedp && ![km_is_nephew_p $object_id]} {
+ foreach bank_id [incentives::bank_list -user_id $original_author_id $package_id] {
+ set amount [incentives::charge_value -key $object_type_id \
+ kl_object_publish $bank_id]
+ incentives::award_shares -user_id $original_author_id \
+ kl_object_publish $amount $bank_id $object_id
+ }
+ }
+
+ # Actually publish the object.
+ km_object_publish $descendents
+
+ # Generate alerts.
+ set published_objects_list [db_list_of_lists get_published_objects "
+ select object_id, object_type_id
+ from sn_objects
+ where public_p = 't'
+ and object_id in ([join $descendents ,])
+ "]
+
+ foreach published_object $published_objects_list {
+ util_unlist $published_object published_object_id published_object_type_id
+
+ alerts::generate_alert -package_id $package_id -content_type_id $published_object_type_id -action insert -link_only $published_object_id
+ }
+
+ ## but what if the task is at a clarify state? can we close it then
+ ## with this code?
+ if ![info exists task_id] {
+ db_0or1row get_workflow_case {
+ select case_id
+ from wf_cases
+ where object_id = :object_id
+ and state = 'active'
+ and rownum = 1
+ order by case_id desc
+ }
+ if [info exists case_id] {
+ db_dml delete_task_assignments {
+ delete from wf_task_assignments
+ where task_id in (select task_id from wf_tasks where case_id = :case_id)
+ }
+ db_dml finish_tasks {
+ update wf_tasks
+ set state = 'finished'
+ where case_id = :case_id
+ }
+ db_dml delete_tokens {
+ delete from wf_tokens
+ where case_id = :case_id
+ }
+ db_1row get_task_id {
+ select wf_task_id_seq.nextval as task_id from dual
+ }
+ db_dml insert_transition_key {
+ insert into wf_tasks
+ (task_id, case_id, workflow_key, transition_key, state, started_date, holding_user)
+ values (:task_id, :case_id, 'library_approval_wf', 'library_review', 'started', sysdate, :user_id)
+ }
+ set msg "Object Published"
+ }
+ }
+
+ if [info exists task_id] {
+ # update publisher_id
+ db_dml update_publisher_id "
+ update sn_objects
+ set publisher_id = :user_id
+ where object_id in ([join $descendents ,])
+ "
+
+ #finish workflow task
+ set journal_id [wf_task_action -user_id $user_id -msg $msg -attributes [list library_object_needs_clarification f] $task_id finish]
+ }
+}
+
+ad_returnredirect $return_url
Index: openacs-4/contrib/obsolete-packages/library/www/object-publish.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/object-publish.adp,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/object-publish.adp 2 Jul 2003 12:19:43 -0000 1.1
@@ -0,0 +1,66 @@
+
+@title;noquote@
+
+
+
The @uncle_object_type@ "@uncle_name@"
+ and all the linked @descendent_object_types@ may need to be made private if this is the last public archived
+ @object_type@ of "@uncle_name@".
+
+
+
+
Please select the objects that should be removed from the archive together
+ with this @object_type@ '@object_name@':
+
+
The @uncle_object_type@ "@uncle_name@"
+ and all the linked @descendent_object_types@ may need to be made private as well if this is the last public
+ @object_type@ of "@uncle_name@".
+
+
+
Together with this @object_type@ all @descendent_object_types@ will be made private as well.
+
On this page you see all links that exist to or from the @pretty_type@
+"@object_name@". Along with the object itself, the linking direction
+and the question that led to the link are displayed:
+
+
+
+
+
+There are no links to or from other objects.
+
+
+
+
@object_access_toolbar;noquote@
Index: openacs-4/contrib/obsolete-packages/library/www/object-view.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/object-view.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/object-view.tcl 2 Jul 2003 12:19:43 -0000 1.1
@@ -0,0 +1,316 @@
+ad_page_contract {
+ object-view.tcl
+
+ Display the completed content of an object.
+
+ @author Timo Hentschel (timo@arsdigita.com)
+ $Id: object-view.tcl,v 1.1 2003/07/02 12:19:43 peterm Exp $
+} {
+ object_id:integer
+ {category_id ""}
+ {path_id:integer ""}
+} -properties {
+ title:onevalue
+ write_feedback_of_object:onevalue
+ object_id:onevalue
+ object_type_id:onevalue
+ pretty_type:onevalue
+ date_created:onevalue
+ public_p:onevalue
+ checkoff_date:onevalue
+ pretty_checkoff_date:onevalue
+ date_last_modified:onevalue
+ author_id:onevalue
+ author_name:onevalue
+ length_linked_objects:onevalue
+ object_list:onevalue
+ read_only_child_p:onevalue
+ object_access_toolbar:onevalue
+ display_object_data:multirow
+ linked_urls_list:onevalue
+ workspace_toolbar:onevalue
+ access_count:onevalue
+ access_count_month:onevalue
+ edit_p:onevalue
+ admin_p:onevalue
+ delete_p:onevalue
+ change_owner_p:onevalue
+ change_publisher_p:onevalue
+ user_id:onevalue
+ reuse_p:onevalue
+ comments:multirow
+ path_id:onevalue
+ category_id:onevalue
+ subsite_url:onevalue
+ subsite_name:onevalue
+ community_id:onevalue
+ public_p:onevalue
+ bookmarked_p:onevalue
+ shopping_cart_p:onevalue
+ child_p:onevalue
+ nephew_p:onevalue
+ application_p:onevalue
+ application_form_vars:onevalue
+ ancestor_object_id:onevalue
+ ancestor_object_type:onevalue
+ ancestor_name:onevalue
+ ancestor_public_p:onevalue
+ ancestor_archived_p:onevalue
+ ancestor_review_p:onevalue
+ publisher_id:onevalue
+ publisher_name:onevalue
+ ot_create_p:onevalue
+ ot_copy_p:onevalue
+ ot_archive_p:onevalue
+ review_p:onevalue
+ task_id:onevalue
+ archived_p:onevalue
+ approval_p:onevalue
+ review_state:onevalue
+ create_p:onevalue
+}
+
+set user_id [ad_conn user_id]
+set package_id [ad_conn package_id]
+set instance_name [ad_conn instance_name]
+
+if ![km_check_object_id $object_id] { return }
+
+set object_type_id [km_conn object_type_id]
+set read_only_child_p 0
+set pretty_type [km_static object_type_pretty_name $object_type_id]
+set pretty_type_plural [km_static object_type_pretty_plural $object_type_id]
+set graphic [km_static object_type_graphic $object_type_id]
+
+array set node [site_node_closest_ancestor_site_node "acs-subsite"]
+set community_id $node(package_id)
+set subsite_url $node(url)
+set subsite_name $node(instance_name)
+set public_p [km_conn public_p]
+set review_p [km_conn in_review_p]
+set review_state [km_conn review_state]
+set original_author_id [km_conn original_author_id]
+set object_name [km_conn object_name]
+set stripped_name [sn_striphtml $object_name]
+set approval_p [km_static approval_p $package_id]
+set ancestor_object_id 0
+set publisher_id [km_conn publisher_id]
+if ![empty_string_p $publisher_id] {
+ set publisher_name [db_string get_publisher_name {select first_names || ' ' || last_name from users where user_id = :publisher_id}]
+} else {
+ set publisher_name ""
+}
+
+# Determine which permissions the viewing user has.
+set admin_p [km_conn admin_p]
+set publish_p [km_conn publish_p]
+set edit_p [km_conn write_p]
+set delete_p [km_conn delete_p]
+set create_p [km_conn create_p]
+set archived_p [km_conn archived_p]
+set ot_archive_p [km_static object_type_archive_p $object_type_id]
+set ot_create_p [km_static object_type_create_p $object_type_id]
+set ot_copy_p [km_static object_type_copy_p $object_type_id]
+set publisher_id [km_conn publisher_id]
+set title "$pretty_type: $stripped_name"
+
+if { ($user_id == $original_author_id && !$archived_p) || $admin_p } {
+ set change_owner_p 1
+} else {
+ set change_owner_p 0
+}
+
+if { $admin_p || $publish_p || $publisher_id == $user_id} {
+ set change_publisher_p 1
+} else {
+ set change_publisher_p 0
+}
+
+## get the task_id of the workflow task if object is in review
+if { $review_p } {
+ set task_id [db_string get_workflow_task {
+ select distinct(ut.task_id)
+ from wf_cases c, wf_user_tasks ut
+ where c.object_id = :object_id
+ and c.case_id = ut.case_id
+ and c.state = 'active'
+ and rownum = 1
+ order by ut.task_id desc
+ } -default ""]
+} else {
+ set task_id ""
+}
+
+# Determine how often the object has been viewed in total, and this month.
+if { $user_id } { km_count_object_view $user_id $object_id }
+
+set access_count [km_conn access_total]
+set access_count_month [km_conn access_month]
+
+# This object may have some parents.
+# The proc returns pairs of parent_object_id and the object name
+set ancestors [reverse [km_get_object_ancestors $object_id]]
+
+if ![null_p $ancestors] {
+ set ancestor [fst $ancestors]
+ set ancestor_object_id [fst $ancestor]
+ set ancestor_object_type [km_static object_type_pretty_name [thd $ancestor]]
+ set ancestor_name [snd $ancestor]
+ db_1row get_public_archived_status {
+ select decode(public_p,'t',1,0) as ancestor_public_p,
+ decode(archived_p,'t',1,0) as ancestor_archived_p,
+ decode(in_review_p,'t',1,0) as ancestor_review_p
+ from sn_objects
+ where object_id = :ancestor_object_id
+ }
+
+ if { !$admin_p } {
+ set ancestor_object_type_id [thd $ancestor]
+ if {[llength $ancestors] > 1} {
+ set ancestor_linked_object_id [fst [snd $ancestors]]
+ } else {
+ set ancestor_linked_object_id $object_id
+ }
+ set ancestor_question_state [db_string object_view_10 "
+ select qm.question_state
+ from sn_question_object_type_map qm, sn_links l, sn_question_link_map map
+ where l.object_id_a = :ancestor_object_id
+ and l.object_id_b = :ancestor_linked_object_id
+ and l.link_id = map.link_id
+ and map.question_id = qm.question_id
+ and qm.object_type_id = :ancestor_object_type_id"]
+ if { $ancestor_question_state == "read-only" } {
+ set edit_p 0
+ set read_only_child_p 1
+ }
+ }
+ set child_p 1
+} else {
+ set child_p 0
+}
+
+set nephew_p [km_is_nephew_p $object_id]
+
+if {$child_p && !$nephew_p} {
+ if {$ot_archive_p} {
+ set return_url "object-view?[export_url_vars object_id]"
+ if { $archived_p && $edit_p } {
+ set object_access_toolbar "\[Archived\] Remove from archive"
+ } else {
+ set object_access_toolbar "Put in archive"
+ }
+ } else {
+ set object_access_toolbar ""
+ }
+} else {
+ set object_access_toolbar [km_object_access_toolbar $object_id $category_id]
+}
+
+if {$nephew_p && [string equal [km_get_presentation_type_of_nephew_question $object_id] "application"]} {
+ set application_p 1
+ set resource_req_id [fst [km_get_uncle $object_id]]
+ set return_url "object-view?[ad_conn query]"
+ set application_form_vars [export_form_vars object_id category_id resource_req_id return_url]
+} else {
+ set application_p 0
+ set application_form_vars ""
+}
+
+if { ![empty_string_p $path_id] && [path_valid_p $path_id] } {
+ set path_values [get_path_values -action_only_p 0 $path_id]
+ set last_path_id [get_last_path $path_id]
+ set browse_type [snd $path_values]
+ set browse_category [lindex $path_values 3]
+
+ set browse_type "browse-one-type?[export_url_vars object_type_id]&path_id=$last_path_id&$browse_type"
+ set browse_category "browse-one-category?[export_url_vars object_type_id category_id]&path_id=$last_path_id&$browse_category"
+} else {
+ set browse_type "browse-one-type?[export_url_vars object_type_id]"
+ set browse_category "browse-one-category?[export_url_vars object_type_id category_id]"
+}
+
+# Set up the context bar. This is so complicated because we
+# not only provide a link to browse-one-type.tcl, but also
+# to browse-one-category.tcl (if needed).
+
+## if {$child_p && !$nephew_p} {
+## set workspace_toolbar ""
+##} else {
+ set workspace_toolbar [km_workspace_toolbar $object_id $category_id $child_p]
+##}
+set_the_usual_klib_context_bar $object_id $category_id
+
+if { $public_p } {
+ set write_feedback_of_object [get_feedback_statistics_for_object $object_id feedback_statistics]
+} else {
+ set write_feedback_of_object 0
+ set feedback_statistics ""
+}
+
+# Display questions and answers (omitting unanswered questions).
+set date_created [util_AnsiDatetoPrettyDate [km_conn creation_date]]
+set date_last_modified [util_AnsiDatetoPrettyDate [km_conn last_modified]]
+set checkoff_date [km_conn user_checkoff_date]
+set pretty_checkoff_date [util_AnsiDatetoPrettyDate [km_conn user_checkoff_date]]
+
+set author_name [km_conn original_author_name]
+set author_id [km_conn original_author_id]
+
+# Retrieve all data for this object as a list of lists in this Special Form:
+# question_id, pretty_question, abstract_data_type, value
+set object_data [km_get_object_data -answers_only_p 0 $object_id]
+
+template::multirow create display_object_data object_id question_id abstract_data_type branch_p root_branch_p pretty_question value edit_p
+
+foreach item $object_data {
+ set value [fst $item]
+ set question_id [snd $item]
+ set pretty_question [thd $item]
+ set abstract_data_type [lindex $item 3]
+ set branch_p [lindex $item 4]
+ set root_branch_p [lindex $item 5]
+
+ if {[empty_string_p $branch_p]} {
+ set branch_p 0
+}
+ if { !$branch_p || [km_active_path_p $question_id $object_id $object_type_id] } {
+ template::multirow append display_object_data $object_id $question_id $abstract_data_type $branch_p $root_branch_p $pretty_question $value $edit_p
+ }
+}
+
+set linked_objects [km_get_linked_objects -to_p 1 -reference_links_p 0 -family_members_p 0 $user_id $object_id]
+if {[llength $linked_objects] <= 1} {
+ set linked_objects ""
+}
+
+set reuse_p 0
+if { $public_p && $original_author_id != $user_id } {
+ # Prevent private objects from getting shares.
+ set reuse_p 1
+}
+
+get_feedback_for_object $object_id comments
+
+if {![empty_string_p $category_id] && ![string equal $category_id none]} {
+ query get_category_tree_info tree_info onerow {
+ select gt.tree_name, gt.tree_id, c.short_name
+ from sw_category_dim scd, generic_trees gt, categories c
+ where scd.object_id = :category_id
+ and scd.tree_id = gt.tree_id
+ and c.category_id = :category_id
+ }
+ set search_contexts [list \
+ [list "lcat:$object_type_id,$tree_info(tree_id),$category_id" "$tree_info(short_name)"] \
+ [list "ltype:$object_type_id" "$pretty_type_plural"] \
+ [list "lib:$package_id" "$instance_name"] \
+ [list "sc:$community_id" "$subsite_name"] \
+ [sws_km_site_search_context]]
+} else {
+ set search_contexts [list \
+ [list "ltype:$object_type_id" "$pretty_type_plural"] \
+ [list "lib:$package_id" "$instance_name"] \
+ [list "sc:$community_id" "$subsite_name"] \
+ [sws_km_site_search_context]]
+}
+
+ad_return_template
Index: openacs-4/contrib/obsolete-packages/library/www/object-xml.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/object-xml.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/object-xml.tcl 2 Jul 2003 12:19:43 -0000 1.1
@@ -0,0 +1,29 @@
+ad_page_contract {
+ /www/library/object-indexed.tcl
+
+ Show intemedia index contents for given object instance
+
+ created by akananov@arsdigita.com 18.10.2000
+
+ @cvs-id $Id:
+} {
+ object_id:notnull,integer
+ {msie_p:boolean 0}
+}
+
+if ![km_check_object_id $object_id] { return }
+if {![km_conn admin_p]} { return }
+
+set sql "
+ select km_utilities.km_xml(object_id) xml_doc from sn_objects
+ where object_id = :object_id"
+
+db_1row object_xml_10 $sql
+
+if {[msie_p]} {
+ set mime application/xml
+} else {
+ set mime text/plain
+}
+
+ns_return 200 $mime $xml_doc
Index: openacs-4/contrib/obsolete-packages/library/www/one-question-edit-2.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/one-question-edit-2.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/one-question-edit-2.tcl 2 Jul 2003 12:19:43 -0000 1.1
@@ -0,0 +1,278 @@
+ad_page_contract {
+ /www/library/one-question-edit-2.tcl
+
+ First save the data from one-question-edit.tcl, then redirect the user
+ to his destination.
+
+ @cvs-id $Id: one-question-edit-2.tcl,v 1.1 2003/07/02 12:19:43 peterm Exp $
+} {
+ question_id:integer
+}
+csrf::authenticate
+
+set key_values {}
+set_the_usual_form_variables
+set button_name ""
+set new_question ""
+set branch_id ""
+set action ""
+
+# We need some information about this question
+set pretty_name [km_static question_pretty_name $question_id]
+set abstract_data_type [km_static question_abstract_data_type $question_id]
+
+# expecting: object_id path_id
+# In the form: the submit button name, the question's column_name
+# and its value to be stored in the database
+
+set form_size [ns_set size $Vform]
+
+# Go through the form and pick out the data we need for the path from
+# the data that needs to go to Oracle.
+set counter 0
+
+while { $counter < $form_size } {
+
+ set key [ns_set key $Vform $counter]
+ set value [ns_set value $Vform $counter]
+ incr counter
+
+ # Isolate the general name of this form field.
+ # A submit button has the form general_name.question_id
+
+ regexp {(.*)\.} $key match button_name
+
+ # See if this is the form's submit button.
+ if { [lsearch [km_get_button_names] $button_name] >= 0 } {
+ regexp {\.(.*)} $key match button_target
+
+ # This IS the form's submit button which sets the path action.
+ # We want to get the question_id out of it as well.
+
+ set action $button_name
+
+ # The second half of the submit button name is the question_id
+ # for the next/previous question to be edited
+ if { $button_name == "next_question" || $button_name == "previous_question" } {
+ set new_question_id $button_target
+ }
+
+ } else {
+
+ switch $key {
+ "path_id" { set path_id $value }
+ "object_id" { set object_id $value }
+ "object_type_id" { set object_type_id $value }
+ "parent_object_id" { set parent_object_id $value }
+ "uncle_object_id" { set uncle_object_id $value }
+ "question_id" { set question_id $value }
+ "category_id" { set category_id $value }
+ "default" { lappend key_values [list $key $value] }
+ }
+ }
+}
+
+if {![km_check_object_id -check_edit_p 1 $object_id]} {
+ return
+}
+
+set user_id [ad_maybe_redirect_for_registration]
+set archived_p [km_conn archived_p]
+set admin_p [km_conn admin_p]
+set all_types_p 0
+if {$admin_p && $archived_p} {
+ set all_types_p 1
+}
+
+set question [km_get_question -all_types_p $all_types_p $question_id $object_type_id]
+set question_state [lindex $question 3]
+
+if ![info exists path_id] { set path_id "" }
+
+if {[lsearch [list category other_category option] $abstract_data_type] != -1} {
+ set valid_keys [km_filter_valid_keys $key_values]
+ if {![null_p $valid_keys] && [empty_string_p [snd [fst $valid_keys]]]} {
+ set key_values [list]
+ }
+}
+
+if { $action == "delete" } {
+ set results [km_delete_object_data $object_id $button_target]
+}
+
+if { $action == "delete" || ($question_state == "read-only" && !$admin_p) } {
+ # If the user cannot edit or has deleted the content,
+ # then there won't be bad input, and nothing should be saved.
+ set results ""
+} elseif {![null_p [km_filter_valid_keys $key_values]] || [string equal $abstract_data_type date]} {
+
+ # Do some error checking
+ set key_values [km_sort_form $key_values]
+ set bad_input [km_check_input -required_p 1 $object_id $key_values]
+
+ if ![null_p $bad_input] {
+ ad_return_complaint [fst $bad_input] [snd $bad_input]
+ return
+ } else {
+ # Save the data
+ set results [km_save_object_data $object_id $user_id $key_values]
+ }
+
+} elseif { [string equal $abstract_data_type "category"] || [string equal $abstract_data_type "other_category"] } {
+
+ # We have to handle this differently because it is possible that
+ # no variable is carried thru from the one-question-edit.tcl, and
+ # yet this variable may be required.
+
+ if { [elem_p $question_id [km_required_questions $object_id]] } {
+ # Some important variable has not passed that is required
+ ad_return_complaint 1 "
You must supply a value for $pretty_name"
+ return
+ } else {
+ # this isn't a required field
+ km_uncategorize_object $object_id $question_id
+ if { $abstract_data_type == "other_category" } {
+ km_save_object_content -html_p 0 $question_id $object_id $user_id ""
+ }
+ set results {}
+ }
+} elseif { $abstract_data_type == "option" } {
+
+ if { [elem_p $question_id [km_required_questions $object_id]] } {
+ # Some important variable has not passed that is required
+ ad_return_complaint 1 "
You must supply a value for $pretty_name"
+ return
+ } else {
+ # this isn't a required field so we need to save an empty string
+ set results [km_unoptionize_object $object_id $question_id]
+ }
+
+} else {
+ # If the form has no input fields then there won't be bad input.
+ set results ""
+}
+
+km_check_public_status_after_edit $object_id
+
+if [empty_string_p [snd $results]] {
+ # If there was no message then we can assume the editing was a success.
+ # So where do we go now?
+
+ switch $action {
+ "previous_question" -
+ "next_question" {
+
+ # First, this question might lead off to a branch
+ if { [lsearch {"option" "category" "other_category" "integer" "text"} $abstract_data_type] >= 0 &&
+ $action == "next_question" } {
+ if { $question_state == "read-only" && !$admin_p } {
+ # There was no form on one-question-edit.tcl.
+ # So we have to retrieve the answer from the database.
+
+ set question_fields {question_id pretty_name abstract_data_type question_state}
+ set question [list $question_fields [list $question_id $pretty_name $abstract_data_type $question_state]]
+ set answer [fst [km_get_object_data -questions $question $object_id]]
+ } else {
+ set answer [snd [fst $key_values]]
+ }
+ set branch_id [km_next_branch -abstract_data_type $abstract_data_type $question_id $answer $object_type_id]
+ if ![empty_string_p $branch_id] {
+ set new_question_id $branch_id
+ } elseif { [km_root_branch_p $question_id] } {
+ set new_question_id [fst [km_get_question -next_p 1 -all_types_p $all_types_p $question_id $object_type_id]]
+ }
+ }
+
+ # Set the destination
+ if ![empty_string_p $new_question_id] {
+ set question_id $new_question_id
+ set new_abstract_data_type [km_static question_abstract_data_type $question_id]
+
+ if { $new_abstract_data_type == "object_link" } {
+ set destination "object-link?[export_url_vars object_id category_id question_id]"
+ } elseif ![empty_string_p $question_id] {
+ set destination "one-question-edit?[export_url_vars object_id category_id question_id parent_object_id]"
+ } else {
+ set destination "object-view?[export_url_vars object_id category_id]"
+ }
+ } else {
+ # redirect to answered questions if the answer to this branch
+ # question doesn't lead to a branch and this question
+ # is the last question
+ set destination "object-view?edit_p=1&[export_url_vars object_id category_id parent_object_id]"
+ }
+ }
+ "all_questions" {
+ set destination "questions?view_questions=all&[export_url_vars object_id category_id parent_object_id]"
+ }
+ "answered" {
+ set destination "object-view?edit_p=1&[export_url_vars object_id category_id parent_object_id]"
+ }
+ "unanswered" {
+ set destination "questions?view_questions=unanswered&[export_url_vars object_id category_id parent_object_id]"
+ }
+ "add_web_ref" {
+ set return_url "one-question-edit?[export_url_vars object_id category_id question_id]"
+ set path_vars [list question_id $button_target object_id $object_id category_id $category_id]
+ set path_id [init_path $path_vars $return_url $action]
+ set destination "add-web-ref?[export_url_vars path_id]"
+ }
+ "add_sn_ref" {
+ set return_url "one-question-edit?[export_url_vars object_id category_id question_id]"
+ set path_vars [list question_id $button_target object_id $object_id category_id $category_id]
+ set path_id [init_path $path_vars $return_url $action]
+ array set node [site_node_closest_ancestor_site_node "acs-subsite"]
+ set community_id $node(package_id)
+ set destination "linking/?community_id=$community_id&source_id=$object_id&pass=$path_id"
+ }
+ "add_user_ref" {
+ set target "user-link-add"
+ set passthrough {path_id}
+ set keyword [set user_link.$button_target]
+ set return_url "one-question-edit?[export_url_vars object_id category_id question_id]"
+ set path_vars [list question_id $button_target object_id $object_id category_id $category_id]
+ set path_id [init_path $path_vars $return_url $action]
+
+ set context_bar [list "one-question-edit?[export_url_vars object_id category_id question_id]" "Edit"]
+ set destination "user-search?[export_url_vars keyword target passthrough path_id context_bar object_id category_id]"
+ }
+ "add_content_ref" {
+ set target "content-link-add"
+ set query_string $content_query
+ set table_name $content_table
+ set return_url "one-question-edit?[export_url_vars object_id category_id question_id]"
+ set path_vars [list question_id $button_target object_id $object_id category_id $category_id]
+ set path_id [init_path $path_vars $return_url $action]
+ set destination "/shared/sw-search-2?[export_url_vars query_string table_name target path_id]"
+ }
+ "add_nephew" {
+ set return_url "one-question-edit?[export_url_vars object_id category_id question_id path_id]"
+ set path_vars [list question_id $button_target uncle_object_id $object_id category_id $category_id]
+ set path_id [init_path $path_vars $return_url $action]
+ set destination "object-edit?[export_url_vars path_id]&uncle_object_id=$object_id&question_id=$button_target"
+ }
+ "add_child" {
+ set return_url "one-question-edit?[export_url_vars object_id category_id question_id path_id]"
+ set path_vars [list question_id $button_target parent_object_id $object_id category_id $category_id]
+ set path_id [init_path $path_vars $return_url $action]
+ set destination "object-edit?[export_url_vars path_id]&parent_object_id=$object_id&question_id=$button_target"
+ }
+ "copy_nephew" {
+ set return_url "one-question-edit?[export_url_vars object_id category_id question_id path_id]"
+ set path_vars [list question_id $button_target uncle_object_id $object_id category_id $category_id]
+ set path_id [init_path $path_vars $return_url $action]
+ set destination "object-copy?[export_url_vars path_id category_id]&parent_id=$object_id&question_id=$button_target"
+ }
+ "copy_child" {
+ set return_url "one-question-edit?[export_url_vars object_id category_id question_id path_id]"
+ set path_vars [list question_id $button_target parent_object_id $object_id category_id $category_id]
+ set path_id [init_path $path_vars $return_url $action]
+ set destination "object-copy?[export_url_vars path_id category_id]&parent_id=$object_id&question_id=$button_target"
+ }
+ default { set destination "questions?view_questions=all&[export_url_vars object_id category_id]" }
+ }
+} else {
+ set destination "/global/error.html"
+}
+
+ad_returnredirect $destination
Index: openacs-4/contrib/obsolete-packages/library/www/one-question-edit.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/one-question-edit.adp,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/one-question-edit.adp 2 Jul 2003 12:19:43 -0000 1.1
@@ -0,0 +1,45 @@
+
+@title;noquote@
+@graphic@
+@graphic_width@
+
+
+
Index: openacs-4/contrib/obsolete-packages/library/www/question-field-content-link.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/question-field-content-link.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/question-field-content-link.tcl 2 Jul 2003 12:19:43 -0000 1.1
@@ -0,0 +1,47 @@
+# Displays this field for a form field.
+# Lists all of the existing links between ACS content and this
+# object. Shows the button that leads to content linking excursion.
+
+if {![info exists value]} {
+ set value ""
+}
+
+if {![info exists edit_p]} {
+ set edit_p 0
+}
+
+if {![info exists category_id]} {
+ set category_id ""
+}
+
+if {![info exists size]} {
+ set size 30
+}
+
+if {![info exists maxlength]} {
+ set maxlength 50
+}
+
+if {![info exists hit_database_p]} {
+ set hit_database_p 1
+}
+
+if [empty_string_p $value] { set value "Link" }
+
+set return_url "one-question-edit?[export_url_vars object_id question_id category_id]"
+set path_vars [list question_id $question_id object_id $object_id category_id $category_id]
+set path_id [init_path $path_vars $return_url add_content_ref]
+set admin_p [km_conn admin_p]
+
+if { $question_state != "read-only" || [km_conn admin_p] } {
+ array set node [site_node_closest_ancestor_site_node "acs-subsite"]
+ set community_id $node(package_id)
+}
+
+if { $hit_database_p } {
+ set existing_links [km8_get_to_links $object_id $question_id]
+ set pass [ns_urlencode "$path_id:exclude [map fst $existing_links]"]
+} else {
+ set existing_links {}
+ set pass $path_id
+}
Index: openacs-4/contrib/obsolete-packages/library/www/question-field-date.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/question-field-date.adp,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/question-field-date.adp 2 Jul 2003 12:19:43 -0000 1.1
@@ -0,0 +1,9 @@
+
+
+
@formatted_value;noquote@
+
"
+
+
+
+
+
Index: openacs-4/contrib/obsolete-packages/library/www/question-field-date.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/question-field-date.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/question-field-date.tcl 2 Jul 2003 12:19:43 -0000 1.1
@@ -0,0 +1,31 @@
+# Displays a date field. It knows what default dates it should use for
+# different object types that have dates.
+
+if {![info exists value]} {
+ set value ""
+}
+
+if {![info exists object_type_id]} {
+ set object_type_id 0
+}
+
+if {!$object_type_id} {
+ set object_type_id [km_get_object_type $object_id]
+}
+
+if {![empty_string_p $value]} {
+ if { $question_state == "read-only" && ![km_conn admin_p] } {
+ set read_only_p t
+ set formatted_value [util_AnsiDatetoPrettyDate $value]
+ } else {
+ #break it up into form tag boxes
+ set read_only_p f
+ set date [km_break_date $value]
+ util_unlist $date year_value month_value day_value
+ }
+} else {
+ set read_only_p f
+ set date [km_default_date $question_id]
+ util_unlist $date year_value month_value day_value
+}
+
Index: openacs-4/contrib/obsolete-packages/library/www/question-field-file.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/question-field-file.adp,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/question-field-file.adp 2 Jul 2003 12:19:43 -0000 1.1
@@ -0,0 +1,21 @@
+
+
The current file was retrieved from
+
+
+
+ To overwrite it with a new file, enter the filename below.
+
+ You may also remove the file.
+
+
+
+ Since the question is read-only, you may only
+ remove
+ the file.
+
+
Index: openacs-4/contrib/obsolete-packages/library/www/admin/approval-process-toggle.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/admin/approval-process-toggle.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/admin/approval-process-toggle.tcl 2 Jul 2003 12:19:44 -0000 1.1
@@ -0,0 +1,42 @@
+ad_page_contract {
+ /packages/library/www/admin/approval-process-toggle.tck
+
+ @author Dirk Gomez (dirk@arsdigita.com)
+
+ @cvs-id $Id: approval-process-toggle.tcl,v 1.1 2003/07/02 12:19:44 peterm Exp $
+} {
+ {approvalprocessp:oneof(t|f) "f"}
+} -properties {
+ title:onevalue
+}
+csrf::authenticate
+
+set package_id [ad_conn package_id]
+
+if {[string equal $approvalprocessp t]} {
+ # Set up variables for user-search.tcl.
+ set passthrough {}
+ set target "approval-process-toggle-2"
+ set show_myself_p t
+ set object_id_dependent f
+ set extra_permission km_publish
+ set extra_package_id $package_id
+ set context_bar [list "approval-process-toggle?[export_url_vars approvalprocessp]" "Add Approval Coordinator"]
+ set form_vars_search [export_form_vars target passthrough show_myself_p object_id_dependent extra_permission extra_package_id context_bar]
+ set title "Add Approval Coordinator"
+ set_context_bar_data $title
+ ad_return_template
+} else {
+ db_dml approval_process_toggle_2_10 {
+ delete from approval_coordinators
+ where package_id=:package_id
+ }
+ km_static -reset $package_id
+
+ ad_returnredirect .
+ return
+}
+
+
+
+
Index: openacs-4/contrib/obsolete-packages/library/www/admin/branch-tree.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/admin/branch-tree.adp,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/admin/branch-tree.adp 2 Jul 2003 12:19:44 -0000 1.1
@@ -0,0 +1,17 @@
+
+@title;noquote@
+@graphic;noquote@
+@graphic_width;noquote@
+
+
+The tree below shows all branch questions for this object_type:
+
+
+There are no branches for this object type.
+
+
+
+
+@questions.indentation;noquote@@questions.link;noquote@
+
+
Index: openacs-4/contrib/obsolete-packages/library/www/admin/branch-tree.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/admin/branch-tree.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/admin/branch-tree.tcl 2 Jul 2003 12:19:44 -0000 1.1
@@ -0,0 +1,41 @@
+ad_page_contract {
+ /packages/library/www/admin/branch-tree.tcl
+
+ @author Carsten Clasohm (carsten@arsdigita.com)
+ @author Dirk Gomez (dirk@arsdigita.com)
+
+ @cvs-id $Id: branch-tree.tcl,v 1.1 2003/07/02 12:19:44 peterm Exp $
+} {
+ object_type_id
+} -properties {
+ questions:multirow
+}
+
+# Object type info for page display
+set pretty_type [km_static object_type_pretty_name $object_type_id]
+set graphic [km_static object_type_graphic $object_type_id]
+set graphic_width [library_icon_width]
+
+set sql_branch_tree_10 "
+select question_id, level
+from sn_question_object_type_map
+where object_type_id = $object_type_id
+ and (branch_p = 't'
+ or question_id in (select parent_question_id from sn_question_object_type_map where branch_p = 't' and object_type_id = $object_type_id))
+start with parent_question_id=[km_static km_dummy_object_id] and object_type_id=$object_type_id
+ and question_id in (select parent_question_id from sn_question_object_type_map where object_type_id = $object_type_id)
+connect by prior question_id = parent_question_id and object_type_id = $object_type_id"
+
+# Construct a tree with links to the individual branches
+
+template::multirow create questions indentation_level indentation link
+db_foreach branch_tree_10 $sql_branch_tree_10 {
+ set pretty_question [snd [km_get_question $question_id $object_type_id]]
+
+ template::multirow append questions $level [space -size [expr $level *5]] "$pretty_question"
+
+}
+
+set title "Branch Tree for $pretty_type"
+set_context_bar_data [list "view-questions?object_type_id=$object_type_id" "$pretty_type Questions"] $title
+ad_return_template
Index: openacs-4/contrib/obsolete-packages/library/www/admin/choose-category-2.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/admin/choose-category-2.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/admin/choose-category-2.tcl 2 Jul 2003 12:19:44 -0000 1.1
@@ -0,0 +1,70 @@
+ad_page_contract {
+ /packages/library/www/admin/create-category-2.tcl
+
+ @author Carsten Clasohm (carsten@arsdigita.com)
+ @author Dirk Gomez (dirk@arsdigita.com)
+ @author Jens Kordsmeier (jak@arsdigita.com)
+
+ @cvs-id $Id: choose-category-2.tcl,v 1.1 2003/07/02 12:19:44 peterm Exp $
+} {
+ question_id
+ object_type_id
+ tree_id
+ reset_categorization:optional
+} -properties {
+}
+csrf::authenticate
+
+# Get node_id for tree root
+set node_id [db_string get_root_node {
+ select root_node_id
+ from generic_trees
+ where tree_id = :tree_id
+}]
+
+# Test if another visible question is already using this category.
+set used_p [db_string check_uniqueness {
+ select count(*)
+ from sn_questions q, sn_question_object_type_map qm
+ where q.node_id = :node_id
+ and q.question_id = qm.question_id
+ and qm.object_type_id = :object_type_id
+ and qm.question_state <> 'invisible'
+ and q.question_id <> :question_id
+}]
+
+if { $used_p } {
+ ad_return_complaint 1 "
The selected category is already used by another question of this object type."
+ return
+}
+
+set old_node_id [km_get_node_id $question_id]
+
+db_transaction {
+ if { [info exists reset_categorization] && ![empty_string_p $old_node_id] &&
+ $node_id != $old_node_id } {
+
+ # Remove categorization which may be left over from a previous
+ # use of this category tree.
+
+ db_dml delete_categorization {
+ delete from sw_object_category_map
+ where category_id in (select child_category_id
+ from sw_flat_cat
+ where parent = :node_id)
+ and object_id in (select object_id
+ from sn_objects
+ where object_type_id = :object_type_id)
+ }
+ }
+
+ db_dml set_tree {
+ update sn_questions
+ set tree_id = :tree_id, node_id = :node_id
+ where question_id = :question_id
+ }
+}
+
+km_static -reset $question_id
+
+ad_returnredirect "view-questions?[export_url_vars object_type_id]"
Index: openacs-4/contrib/obsolete-packages/library/www/admin/choose-category.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/admin/choose-category.adp,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/admin/choose-category.adp 2 Jul 2003 12:19:44 -0000 1.1
@@ -0,0 +1,50 @@
+
+@title;noquote@
+
+
+
+
+
+
Please select the category tree for question
+@pretty_question@ of object type
+@pretty_type@ below.
+
+
+
+
+
Question @pretty_question@ is associated with category
+tree @tree_name@. You may either edit
+this category tree, or assign a different tree below.
+
+
+
+
When you assign a new tree, you may remove existing object
+categorizations for the newly assigned tree. This is useful when the
+tree was used for a different question of this object type in the
+past.
+
+
Administer Categories
Index: openacs-4/contrib/obsolete-packages/library/www/admin/choose-category.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/admin/choose-category.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/admin/choose-category.tcl 2 Jul 2003 12:19:44 -0000 1.1
@@ -0,0 +1,68 @@
+ad_page_contract {
+ /packages/library/www/admin/choose-category.tcl
+
+ After creating a new question, let the user associate it
+ with a category tree.
+
+ @author Carsten Clasohm (carsten@arsdigita.com)
+ @author Dirk Gomez (dirk@arsdigita.com)
+ @author Jens Kordsmeier (jak@arsdigita.com)
+
+ @cvs-id $Id: choose-category.tcl,v 1.1 2003/07/02 12:19:44 peterm Exp $
+} {
+ question_id
+ object_type_id
+} -properties {
+}
+
+set pretty_type [km_static object_type_pretty_name $object_type_id]
+set pretty_plural [km_static object_type_pretty_plural $object_type_id]
+set graphic [km_static object_type_graphic $object_type_id]
+
+set user_id [ad_verify_and_get_user_id]
+
+set tree_id [db_string get_current_tree {
+ select tree_id
+ from sn_questions
+ where question_id = :question_id
+}]
+
+db_multirow category_trees category_trees "
+ select g.tree_id, g.tree_name
+ from generic_tree_types t, generic_trees g
+ where t.tree_struct_table = 'sw_category_dim'
+ and t.type_id = g.type_id
+ and g.hidden_p = 'f'
+ and (g.site_wide_p = 't'
+ [ad_decode $tree_id "" "" "or g.tree_id = :tree_id"]
+ or [tcl_permission_for_bind_vars_p "g.tree_id" ":user_id" "'category_tree_read'"] = 't')
+ and g.root_node_id not in (select q.node_id
+ from sn_questions q, sn_question_object_type_map qm
+ where q.node_id is not null
+ and q.question_id = qm.question_id
+ and qm.object_type_id = :object_type_id
+ and qm.question_state <> 'invisible'
+ and q.question_id <> :question_id)
+ order by lower(tree_name)
+"
+
+set pretty_question [snd [km_get_question $question_id $object_type_id]]
+
+set title "Categories"
+set_context_bar_data \
+ [list "view-questions?object_type_id=$object_type_id" "$pretty_type Questions"] \
+ $title
+
+if { [empty_string_p $tree_id] } {
+ set tree_name ""
+} else {
+ set tree_name [db_string choose_category_10 {
+ select tree_name
+ from generic_trees
+ where tree_id = :tree_id
+ }]
+}
+
+set form_vars [export_form_vars question_id object_type_id]
+
+ad_return_template
Index: openacs-4/contrib/obsolete-packages/library/www/admin/choose-object-type.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/admin/choose-object-type.adp,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/admin/choose-object-type.adp 2 Jul 2003 12:19:44 -0000 1.1
@@ -0,0 +1,28 @@
+
+@title;noquote@
+
+
+
+
+
+Please select an object type from the list below as a target object type for @pretty_type@:
+
+
+Please select an object type from the list below for this linking question:
+
+
Select the HTML form tag that should appear for this question:
+
+
+
+
@presentation_type_tags.radio_row;noquote@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Select the height and width of the tag (leave blank to use default height 60 and width 15).
+
Width:
+ Height:
+
+
+
+
Select the year range to be displayed in the select box in respect of the default.
+
From:
+ To:
+
+
+
+
+
+
+
+
+
Index: openacs-4/contrib/obsolete-packages/library/www/admin/choose-presentation-type.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/admin/choose-presentation-type.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/admin/choose-presentation-type.tcl 2 Jul 2003 12:19:44 -0000 1.1
@@ -0,0 +1,119 @@
+ad_page_contract {
+ /packages/library/www/admin/choose-presentation-type.tcl
+
+ @author Carsten Clasohm (carsten@arsdigita.com)
+ @author Dirk Gomez (dirk@arsdigita.com)
+ @author Timo Hentschel (timo@arsdigita.com)
+ @author Jens Kordsmeier (jak@arsdigita.com)
+
+ @cvs-id $Id: choose-presentation-type.tcl,v 1.1 2003/07/02 12:19:44 peterm Exp $
+} {
+ question_id
+ object_type_id
+ {abstract_data_type ""}
+ {presentation_type ""}
+} -properties {
+ tag_height:onevalue
+ tag_width:onevalue
+ presentation_type:onevalue
+ pretty_question:onevalue
+ abstract_data_type:onevalue
+ title:onevalue
+ form_vars:onevalue
+ presentation_type_tags:multirow
+ count_tags:onevalue
+}
+
+if [empty_string_p $abstract_data_type] {
+
+ set attributes [km_get_questions -question_states {} -all_properties_p 1 -root_node_p 0 -question_ids [list $question_id]]
+ set key [fst $attributes]
+ set question [snd $attributes]
+ set pretty_question [snd $question]
+ set question_id [lindex $question [lsearch $key question_id]]
+ set abstract_data_type [lindex $question [lsearch $key abstract_data_type]]
+ set presentation_type [lindex $question [lsearch $key presentation_type]]
+ set tag_height [lindex $question [lsearch $key tag_height]]
+ set tag_width [lindex $question [lsearch $key tag_width]]
+ set year_from [lindex $question [lsearch $key year_from]]
+ set year_to [lindex $question [lsearch $key year_to]]
+
+} else {
+
+ set tag_height ""
+ set tag_width ""
+ set year_from "-5"
+ set year_to "5"
+ set presentation_type ""
+ set pretty_question [db_string choose_presentation_type_10 "
+ select pretty_name from sn_questions where question_id = :question_id"]
+}
+
+set object_type [km_static object_type_pretty_name $object_type_id]
+
+#Decide which html tags to offer on the basis of the abstract_data_types
+switch $abstract_data_type {
+
+ "text" {
+ set tags {shorttext textarea textarea_with_refs}
+ set pretty_tags {"Short Text" "Textarea" "Textarea with Library/Web Reference Buttons"}
+ if [empty_string_p $presentation_type] { set presentation_type "shorttext" }
+ }
+
+ "integer" {
+ set tags {shorttext}
+ set pretty_tags {"Short Text"}
+ if [empty_string_p $presentation_type] { set presentation_type "shorttext" }
+ }
+
+ "option" - "other_category" -
+ "category" {
+ set tags {select selectmultiple checkbox radio}
+ set pretty_tags {"Select" "Select Multiple" "Checkbox" "Radio Buttons"}
+ if [empty_string_p $presentation_type] { set presentation_type "select" }
+ }
+ "date" {
+ set tags {custom select}
+ set pretty_tags {"Custom" "Select"}
+ set default_date [km_default_date $question_id]
+ util_unlist $default_date year_value month_value day_value
+ if [empty_string_p $presentation_type] { set presentation_type "custom" }
+ }
+ "nephew_object" {
+ set tags {custom application}
+ set pretty_tags {"Standard List of Objects" "List of Objects with Button for Application Form on Target Object Type Page"}
+ if [empty_string_p $presentation_type] { set presentation_type "custom" }
+ }
+}
+
+# Some demo items
+set items [list "Products" "Sales" "Marketing" "Supply Chain"]
+
+# Show the demo tags for selection
+
+template::multirow create presentation_type_tags radio_row abstract_data_type tag items
+
+foreach tag $tags {
+ set pretty_tag [lindex $pretty_tags [lsearch $tags $tag]]
+ if ![string compare $tag $presentation_type] {
+ set check_string "checked"
+ } else {
+ set check_string ""
+ }
+ set radio_row "$pretty_tag"
+
+ template::multirow append presentation_type_tags $radio_row $abstract_data_type $tag $items
+}
+
+
+set title "Presentation Type for $pretty_question"
+
+set form_vars [export_form_vars object_type_id question_id]
+set count_tags [llength $tags]
+
+set_context_bar_data [list "view-questions?object_type_id=$object_type_id" "$object_type Questions"] $title
+
+ad_return_template
+
+
+
Index: openacs-4/contrib/obsolete-packages/library/www/admin/choose-questions.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/admin/choose-questions.adp,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/admin/choose-questions.adp 2 Jul 2003 12:19:44 -0000 1.1
@@ -0,0 +1,33 @@
+
+@title;noquote@
+
+
+
+
+ @form_vars;noquote@
+
+
+ Check the questions below that should be contained in the new composite question.
+ Please note that selecting a mandatory question will automatically make this composite question mandatory.
+
Make
+this the default branch."
+ }
+} else {
+
+ set attributes ""
+ set this_branch_answer ""
+ set branch_operator "="
+ set title "New Branch"
+ set message "To create a branch, define an answer to $pretty_name that will
+ lead to the following question."
+ set link ""
+}
+
+
+# Get the branch answers for category and option types so that we
+# only offer the user a choice of branch answers that have not yet
+# already been mapped
+
+set branch_answers [snd [transpose [tail [km_get_branches -question_attributes_p 1 -branch_id $branch_id $question_id $object_type_id]]]]
+
+
+set form_vars [export_form_vars question_id object_type_id]
+
+switch $abstract_data_type {
+ "category" - "other_category" {
+ # Get the categories for this question
+ set categories [km_get_child_categories $question_id]
+
+ set values {}
+ set items {}
+ foreach item $categories {
+ set value [fst $item]
+ set item [snd $item]
+
+ if { [lsearch $branch_answers $value] == -1 || $this_branch_answer == $value } {
+ lappend values $value
+ lappend items $item
+ }
+ }
+ if [null_p $values] {
+ ad_return_complaint 1 "There are no answers available for a new branch."
+ return
+ }
+ }
+ "option" {
+ # Get the answer options for this question
+ set options [km_get_answer_options $question_id]
+
+ foreach item $options {
+ set value [fst $item]
+ set item [snd $item]
+
+ if { [lsearch $branch_answers $value] < 0 || $this_branch_answer == $value } {
+ lappend values $value
+ lappend items $item
+ }
+ }
+ if [null_p $values] {
+ ad_return_complaint 1 "There are no answers available for a new branch."
+ return
+ }
+ }
+ "integer" {
+ set values_list [list == < >]
+ set items_list [list Equals {Less Than} {Greater Than}]
+ }
+ "default" {
+ #Can't deal with any other abstract_data_types here
+ ad_returnredirect "view-questions?[export_url_vars object_type_id]"
+ }
+}
+
+# Get a list of questions that exist for this object_type
+# that are not already in a branch of this object_type.
+
+set root_question_id [km_get_root_branch $question_id $object_type_id]
+if ![empty_string_p $root_question_id] {
+ set question_list [km_branch_questions -branch_id $branch_id -root_question_id $root_question_id -composite_children_p 0 $object_type_id]
+} else {
+ set question_list [km_branch_questions -branch_id $branch_id -root_question_id $question_id -composite_children_p 0 $object_type_id]
+}
+
+set branch_ids [list $branch_id]
+set key [fst $question_list]
+set question_list [tail $question_list]
+
+template::multirow create questions pretty_name short_explanation question_state abstract_data_type presentation_type checkmark checked_string question_id url_vars
+
+foreach question $question_list {
+ set pretty_name [lindex $question [lsearch $key pretty_name]]
+
+ # Cut the entry explanation a bit smaller.
+ set short_explanation [km_shorten_question [lindex $question [lsearch $key entry_explanation]]]
+
+ set question_id [lindex $question [lsearch $key "question_id"]]
+ set mandatory_p [ad_decode [lindex $question [lsearch $key mandatory_p]] t 1 0]
+ set this_abstract_data_type [km_pretty_adt [lindex $question [lsearch $key "abstract_data_type"]]]
+ set presentation_type [km_pretty_tag [lindex $question [lsearch $key "presentation_type"]]]
+ set question_state [lindex $question [lsearch $key "question_state"]]
+
+ if { $mandatory_p } {
+ set checkmark ""
+ } else {
+ set checkmark " "
+ }
+ if { [lsearch $branch_ids $question_id] >= 0 } {
+ set checked_string "checked"
+ } else {
+ set checked_string ""
+ }
+
+ set url_vars [export_url_vars object_type_id question_id]
+ template::multirow append questions $pretty_name $short_explanation $question_state \
+ $this_abstract_data_type $presentation_type $checkmark $checked_string $question_id $url_vars
+}
+
+set_context_bar_data \
+ [list "." "Knowledge Library"] \
+ [list "view-questions?object_type_id=$object_type_id" "All Questions"] \
+ [list "view-branches?[export_url_vars question_id object_type_id]" "All Branches"] "$title for $pretty_name"
+
+set object_type_name [db_string view_branches_20 "select pretty_name
+ from sn_object_types
+ where object_type_id=:object_type_id"]
+set_context_bar_data [list "view-questions?object_type_id=$object_type_id" "$object_type_name Questions"] [list "view-branches?question_id=$orig_question_id&object_type_id=$object_type_id" "Navigational Branches for $orig_pretty_name"] $title
+ad_return_template
Index: openacs-4/contrib/obsolete-packages/library/www/admin/edit-category.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/admin/edit-category.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/admin/edit-category.tcl 2 Jul 2003 12:19:44 -0000 1.1
@@ -0,0 +1,24 @@
+# /www/admin/library/edit-category.tcl
+#
+# A routing page used by view-questions.tcl. Depending on whether a
+# question has a category associated with it or not, it redirects to
+# /admin/categories or choose-category.tcl.
+#
+# $Id: edit-category.tcl,v 1.1 2003/07/02 12:19:44 peterm Exp $
+
+ad_page_variables {
+ question_id
+ object_type_id
+}
+
+db_1row edit_category_10 "
+select q.category_id, category
+from sn_questions q, old_categories c
+where question_id=:question_id
+and c.category_id(+) = q.category_id"
+
+if ![empty_string_p $category_id] {
+ ad_returnredirect "/admin/categories/one?[export_url_vars category_id]"
+} else {
+ ad_returnredirect "choose-category?[export_url_vars question_id object_type_id]"
+}
Index: openacs-4/contrib/obsolete-packages/library/www/admin/edit-object-type-2.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/admin/edit-object-type-2.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/admin/edit-object-type-2.tcl 2 Jul 2003 12:19:44 -0000 1.1
@@ -0,0 +1,124 @@
+ad_page_contract {
+ /packages/library/www/admin/edit-object-type-2.tcl
+
+ @author Carsten Clasohm (carsten@arsdigita.com)
+ @author Dirk Gomez (dirk@arsdigita.com)
+
+ @cvs-id $Id: edit-object-type-2.tcl,v 1.1 2003/07/02 12:19:44 peterm Exp $
+} {
+ pretty_name
+ pretty_plural
+ browse_p:oneof(0|1)
+ public_p:oneof(0|1)
+ create_p:oneof(0|1)
+ archive_p:oneof(0|1)
+ copy_p:oneof(0|1)
+ sweeper:oneof(none|outdated|expired)
+ sweeper_action:oneof(private|archive)
+ sweeper_warning_time:integer
+ sweeper_outdated_time:naturalnum
+ object_type_id:integer
+ default_age_filter:integer
+ {short_name:trim ""}
+ {graphic ""}
+ {warned_p 0}
+}
+csrf::authenticate
+
+set i 0
+if {[empty_string_p $pretty_name]} {
+ append complaint "
Please enter a presentation name."
+ incr i
+}
+
+if {[empty_string_p $pretty_plural]} {
+ append complaint "
Please enter a plural form of the presentation name."
+ incr i
+}
+
+if {[empty_string_p $sweeper_warning_time]} {
+ set sweeper_warning_time 0
+}
+
+if {![empty_string_p $short_name]} {
+ set context_id [ad_conn package_id]
+ if [db_0or1row get_short_name {
+ select 1 from sn_object_types
+ where context_id=:context_id
+ and short_name=:short_name
+ and rownum=1
+ and not object_type_id=:object_type_id }] {
+ append complaint "
Short name: $short_name is already used in this library instance."
+ incr i
+ }
+}
+
+if {[empty_string_p $short_name]} {
+ set short_name [db_null]
+}
+
+if { $i } {
+ ad_return_complaint $i $complaint
+ return
+}
+
+if { $public_p && $browse_p && !$warned_p } {
+ # Check if the object type has a short_description.
+ set short_description [db_list get_short_description_list {
+ select short_description
+ from sn_types_map_short_name
+ where object_type_id=:object_type_id
+ order by position}]
+
+ if {[empty_string_p $short_description]} {
+ ad_return_error "Missing short description" "
+The object type is going to be public and browsable,
+but has no assigned short description.
+Please select
+a question and click on the link Make
+this question the short description on the question's properties page."
+ return
+ }
+}
+
+set browse_p [ad_decode $browse_p 1 t f]
+set public_p [ad_decode $public_p 1 t f]
+set create_p [ad_decode $create_p 1 t f]
+set archive_p [ad_decode $archive_p 1 t f]
+set copy_p [ad_decode $copy_p 1 t f]
+
+if {$copy_p == "f" && [string equal $sweeper "archive"]} {
+ set sweeper "none"
+}
+
+# Get the uploaded graphic, if there was one
+if { [regexp {\.([a-zA-Z]+)$} $graphic match graphic_ext] } {
+ set filename "$object_type_id.$graphic_ext"
+
+ ns_cp [ns_queryget graphic.tmpfile] \
+ "[ns_info pageroot]/library-files/$filename"
+
+ set graphic_update ", graphic = :filename, graphic_p = 't'"
+} else {
+ set graphic_update ""
+}
+
+
+if { [empty_string_p $default_age_filter] } { set default_age_filter 365 }
+
+db_dml update_object_type "
+ update sn_object_types
+ set pretty_name = :pretty_name, pretty_plural = :pretty_plural, short_name = :short_name,
+ browse_p = :browse_p, public_p=:public_p, create_p = :create_p,
+ archive_p = :archive_p, copy_p = :copy_p, sweeper = :sweeper,
+ sweeper_action = :sweeper_action,
+ sweeper_warning_time = :sweeper_warning_time,
+ sweeper_outdated_time = :sweeper_outdated_time,
+ default_age_filter=:default_age_filter
+ $graphic_update
+ where object_type_id = :object_type_id"
+
+# Invalidate global cache.
+km_static -reset $object_type_id
+
+ad_returnredirect "."
Index: openacs-4/contrib/obsolete-packages/library/www/admin/edit-object-type.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/admin/edit-object-type.adp,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/admin/edit-object-type.adp 2 Jul 2003 12:19:44 -0000 1.1
@@ -0,0 +1,47 @@
+
+@title;noquote@
+
+Edit this object type by changing the fields below:
+
+
+
+@form_vars;noquote@
+
+
+
Enter a short name:
+
+
Enter a presentation name:
+
+
Enter a plural form of the presentation name:
+
+
Upload a graphic icon:
+
+
Is it possible to browse objects of this object type?
+
+
If yes, then enter the default value for the age filter (in days):
+
+
Should this object type be visible to all users?
+
+
Can the users create standalone objects of this type?
+
+
Can objects of this type be put in the archive?
+
+
Can users copy objects of this type?
+
+
Sweeper that should be used on old objects:
+
+
Action that the sweeper should perform on old objects:
+
+
Amount of days after the warning email that the action should be performed (0 for no warning email):
+
+
Amount of days after which an unchanged object is regarded as outdated:
Please enter an option for
+ this new question. This will appear in the multiple-choice list for
+ this question.
+
+
+
+
+
+
+
Index: openacs-4/contrib/obsolete-packages/library/www/admin/edit-option.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/admin/edit-option.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/admin/edit-option.tcl 2 Jul 2003 12:19:44 -0000 1.1
@@ -0,0 +1,37 @@
+ad_page_contract {
+ /packages/library/www/admin/edit-option.tcl
+
+ @author Carsten Clasohm (carsten@arsdigita.com)
+ @author Dirk Gomez (dirk@arsdigita.com)
+
+ @cvs-id $Id: edit-option.tcl,v 1.1 2003/07/02 12:19:44 peterm Exp $
+} {
+ question_id:integer
+ object_type_id:integer
+ {option_id:integer 0}
+ {invisible_p 0}
+} -properties {
+ title:onevalue
+ form_vars:onevalue
+ input_tag:onevalue
+}
+
+set pretty_type [km_static object_type_pretty_name $object_type_id]
+set graphic [km_static object_type_graphic $object_type_id]
+
+if { $option_id } {
+ set value [km_answer_option $option_id]
+} else {
+ set value ""
+}
+
+set title "Edit Option $value"
+
+set form_vars [export_form_vars object_type_id option_id question_id]
+set pretty_question [db_string view_options_10 "select pretty_name
+ from sn_questions
+ where question_id = :question_id"]
+set view_options_title "Multiple Choice Options for $pretty_question"
+
+set_context_bar_data [list "view-questions?object_type_id=$object_type_id&invisible_p=$invisible_p" "$pretty_type Questions"] [list "view-options?object_type_id=$object_type_id&question_id=$question_id" $view_options_title] $title
+ad_return_template
Index: openacs-4/contrib/obsolete-packages/library/www/admin/edit-question-2.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/admin/edit-question-2.adp,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/admin/edit-question-2.adp 2 Jul 2003 12:19:44 -0000 1.1
@@ -0,0 +1,28 @@
+
+@title@
+
+You have changed the visibility of a question. Since this affects fulltext search,
+all @pretty_type_plural@ should be reindexed. Please note that reindexing will take
+some time, and that fulltext search won't find any @pretty_type_plural@ during this
+time.
+
+
Should I reindex all @pretty_type_plural@ now? (If you press Yes, please be patient
+and don't press the button again.)
+
+
+
+
+
+
+ @form_vars;noquote@
+
+
+
+
+
+ @form_vars;noquote@
+
+
+
+
+
Index: openacs-4/contrib/obsolete-packages/library/www/admin/edit-question-2.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/admin/edit-question-2.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/admin/edit-question-2.tcl 2 Jul 2003 12:19:44 -0000 1.1
@@ -0,0 +1,267 @@
+ad_page_contract {
+
+} {
+ question_id
+ {mandatory_p 0}
+ {first_form_p 0}
+ object_type_id
+ abstract_data_type
+ {question_state "active"}
+ {order_by ""}
+ {default_value ""}
+ {pretty_name ""}
+ {entry_explanation ""}
+ {refers_to "null"}
+ {defaults_question_id "null"}
+ {max_categories "null"}
+ {browse_p ""}
+}
+csrf::authenticate
+
+#if {[doubleclick::check_all]} {
+# ns_log Notice "Going to sleep to avoid a race condition"
+# ns_sleep 10
+# ad_returnredirect "view-questions?object_type_id=$object_type_id"
+# return
+#}
+
+# First we have to set some things so that we don't have invisible mandatory questions etc.
+set link_types [list object_link content_link user_link]
+if { [lsearch $link_types $abstract_data_type] != -1 } {
+ set first_form_p 0
+}
+
+if { $question_state != "active" } {
+ set mandatory_p 0
+}
+
+set form_number $first_form_p
+set mandatory_p [ad_decode $mandatory_p 1 "t" "f"]
+
+set exists_p [db_string edit_question_2_10 "
+ select decode(count(*),0,0,1) from sn_questions
+ where question_id=:question_id"]
+
+set context_id [ad_conn package_id]
+set user_id [ad_verify_and_get_user_id]
+set creation_ip [ad_conn peeraddr]
+
+if {[empty_string_p $defaults_question_id]} { set defaults_question_id "null" }
+if {[empty_string_p $max_categories]} { set max_categories "null" }
+if {[empty_string_p $browse_p] || $browse_p} {
+ set browse_p "t"
+} else {
+ set browse_p "f"
+}
+
+if {!$exists_p} {
+ switch -exact $abstract_data_type {
+ "category" - "other_category" - "option" { set presentation_type "select" }
+ "integer" { set presentation_type "shorttext" }
+ default { set presentation_type "custom" }
+ }
+
+ set dummy [db_exec_plsql admin_edit_question_2_20 "
+ begin
+ :1 := question.insert_question (
+ v_question_id => :question_id,
+ v_pretty_name => :pretty_name,
+ v_abstract_data_type => :abstract_data_type,
+ v_order_by => :order_by,
+ v_default_value => :default_value,
+ v_entry_explanation => :entry_explanation,
+ v_creation_user => :user_id,
+ v_creation_ip => :creation_ip,
+ v_context_id => :context_id,
+ v_references_q_id => $refers_to
+ );
+ end;
+ "]
+
+} else {
+ db_exec_plsql admin_edit_question_2_30 "
+ begin
+ question.update_question (
+ v_question_id => :question_id,
+ v_pretty_name => :pretty_name,
+ v_abstract_data_type => :abstract_data_type,
+ v_order_by => :order_by,
+ v_default_value => :default_value,
+ v_entry_explanation => :entry_explanation,
+ v_modifying_user => :user_id,
+ v_modifying_ip => :creation_ip,
+ v_references_q_id => $refers_to,
+ v_def_question_id => $defaults_question_id,
+ v_max_categories => $max_categories,
+ v_browse_p => :browse_p
+ );
+ end;"
+
+ if {[db_string get_questions_browse_p { select browse_p from sn_questions where question_id = :question_id}] != $browse_p} {
+ km_flush_category_count -object_type_id $object_type_id
+ }
+}
+
+km_static -reset $question_id
+
+if {![db_0or1row edit_question_2_40 "
+ select question_state as old_state, parent_question_id, decode(branch_p,'t',1,0) as branch_p
+ from sn_question_object_type_map
+ where question_id = :question_id and object_type_id = :object_type_id"]} {
+ set old_state ""
+ set parent_question_id 0
+ set branch_p 0
+}
+
+if {[empty_string_p $parent_question_id] || $parent_question_id == [km_static km_dummy_object_id]} {
+ set parent_question_id 0
+}
+if {[empty_string_p $branch_p]} {
+ set branch_p 0
+}
+
+if { $parent_question_id && !$branch_p && $mandatory_p } {
+ # This is a mandatory child question of a composite question.
+ # Make sure that the parent question is made mandatory, too.
+
+ db_dml edit_question_2_50 "
+ update sn_question_object_type_map
+ set mandatory_p = 't'
+ where question_id = :parent_question_id
+ and object_type_id = :object_type_id"
+}
+
+if { $abstract_data_type == "composite" } {
+ # Make sure the child questions have a sensible question state.
+ # If the parent question has become invisible, all children
+ # must be invisible, too.
+ # If the parent question is made visible, we use the new
+ # question_state for its children, too.
+
+ set sql_edit_question_2_60 "
+ select question_id as child_id, question_state as child_state
+ from sn_question_object_type_map
+ where parent_question_id = :question_id
+ and object_type_id = :object_type_id"
+
+ db_foreach edit_question_2_60 $sql_edit_question_2_60 {
+ if { $question_state == "invisible" && $child_state != "invisible" } {
+ db_dml edit_question_2_70 "
+ update sn_question_object_type_map
+ set question_state = 'invisible'
+ where question_id = :child_id"
+ } elseif { $old_state == "invisible" && $question_state != "invisible" && $child_state == "invisible" } {
+ db_dml edit_question_2_80 "
+ update sn_question_object_type_map
+ set question_state = :question_state
+ where question_id = :child_id"
+ }
+ }
+}
+
+# Check if the question is the root of a branch. If it is and
+# its visibility has changed, we have to update the visibility
+# of the children, too.
+
+if {[km_root_branch_p $question_id]} {
+ set sql_edit_question_2_90 "
+ select question_id as child_id, question_state as child_state
+ from sn_question_object_type_map
+ start with parent_question_id = $question_id and object_type_id=$object_type_id
+ connect by parent_question_id = prior question_id and object_type_id=$object_type_id"
+
+ db_foreach edit_question_2_90 $sql_edit_question_2_90 {
+ if { $question_state == "invisible" && $child_state != "invisible" } {
+ db_dml edit_question_2_100 "
+ update sn_question_object_type_map
+ set question_state = 'invisible'
+ where question_id = :child_id"
+ } elseif { $old_state == "invisible" && $question_state != "invisible" && $child_state == "invisible" } {
+ db_dml edit_question_2_110 "
+ update sn_question_object_type_map
+ set question_state = '$question_state'
+ where question_id = :child_id"
+ }
+
+ }
+}
+
+# Update sn_question_object_type_map.
+if {[empty_string_p $old_state]} {
+ set max_sort_key [db_string edit_question_2_120 "
+ select max(sort_key) from sn_question_object_type_map
+ where object_type_id = :object_type_id"]
+
+ set calculcated_max_sort_key [expr $max_sort_key + 10]
+ db_dml edit_question_2_130 "
+ insert into sn_question_object_type_map
+ (object_type_id, question_id, form_number, mandatory_p, question_state, branch_p, sort_key)
+ values (:object_type_id, :question_id, :form_number, :mandatory_p,
+ :question_state, 'f', :calculcated_max_sort_key)"
+} else {
+ db_dml edit_question_2_140 "
+ update sn_question_object_type_map
+ set form_number = :form_number, mandatory_p = :mandatory_p, question_state = :question_state
+ where object_type_id = :object_type_id and question_id = :question_id"
+}
+
+
+# If a question has become invisible or visible, this affects fulltext search,
+# so ask the user if we should rebuild the Intermedia index for this
+# object type.
+
+if {![empty_string_p $old_state]} {
+ if { $old_state != $question_state &&
+ ($old_state == "invisible" || $question_state == "invisible") } {
+ if { $question_state != "invisible" } {
+ # Make sure that no two visible questions have the same sort_key.
+
+ set duplicate_p [db_string edit_question_2_150 "
+ select decode(count(*),0,0,1)
+ from sn_question_object_type_map
+ where object_type_id=:object_type_id
+ and question_id <> :question_id
+ and sort_key = (select sort_key from sn_question_object_type_map
+ where object_type_id=:object_type_id
+ and question_id=:question_id)"]
+
+ if {$duplicate_p} {
+ db_dml edit_question_2_160 "
+ update sn_question_object_type_map
+ set sort_key =
+ (select max(sort_key)+10
+ from sn_question_object_type_map
+ where object_type_id = :object_type_id)
+ where question_id=:question_id and object_type_id=:object_type_id"
+ }
+ }
+
+ set pretty_type_plural [km_static object_type_pretty_plural $object_type_id]
+ set title $pretty_name
+ set form_vars [export_form_vars object_type_id]
+ set_context_bar_data [list "view-questions?object_type_id=$object_type_id" "$pretty_name Questions"] $title
+ ad_return_template edit-question-2
+ } else {
+ set destination "view-questions"
+ ad_returnredirect "$destination?[export_url_vars question_id object_type_id abstract_data_type]"
+
+ # We don't want the template to be parsed.
+ return
+ }
+} else {
+ switch $abstract_data_type {
+ "text" { set destination "choose-presentation-type" }
+ "category" - "other_category" { set destination "choose-category" }
+ "option" { set destination "add-option" }
+ "integer" { set destination "view-questions" }
+ "composite" { set destination "choose-questions" }
+ "child_object" - "nephew_object" -
+ "object_link" { set destination "choose-object-type" }
+ "default" { set destination "view-questions" }
+ }
+ ad_returnredirect "$destination?[export_url_vars question_id object_type_id abstract_data_type]"
+
+ # We don't want the template to be parsed.
+ return
+}
+
Index: openacs-4/contrib/obsolete-packages/library/www/admin/edit-question.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/admin/edit-question.adp,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/admin/edit-question.adp 2 Jul 2003 12:19:44 -0000 1.1
@@ -0,0 +1,148 @@
+
+@title;noquote@
+
+
+
+@form_vars;noquote@
+@dc_export;noquote@
+
+
+
Enter a presentation name for this question:
+
+
Enter this question as it should appear on input forms:
+
+
+
+
Is this question mandatory for the creation of an object of this type?
+
+
+
+
+
+
Which state should this question and its answers be in?
+
+
+
+
+
+
Should this question appear on the first input form?
+
+
+
+
+
In which order should linked objects be displayed?
+
+
+
+
+
+
Refers to which question?
+
+
+
+
+
Default value:
+
+
+ Evaluation of current default value: @date_correct_output@
+
+
+ Warning: The current default value is invalid and causes a SQL error!
+
+(Please enter SQL code that can replace the x in select x from dual.
+ Examples: sysdate = the current date; sysdate+14 = 2 weeks in the future;
+ trunc(sysdate,'month') = the start of the current month)
+
+
+
+
+
Copy Default Values from linked object:
+
+
+
+
+
Maximum Number of selectable Categories:
+
+
+
+
+
Should this category question be browseable?
+
+
+
+
+
Select an abstract data type for this question:
+
+
+
+
+
+
+
+
+
+
+Note -- linking questions are not allowed to be asked first.
+
+
+
+
Note: This question is part of a branch. Therefore, you cannot change its state.
+If you want to do so, you first have to remove it from the branch tree."
+}
+
+
+set branch_p [ad_decode $branch_p 1 t f]
+set edit_p [ad_decode $edit_p 1 t f]
+set form_vars [export_form_vars question_id object_type_id abstract_data_type]
+set url_vars [export_url_vars question_id object_type_id abstract_data_type]
+set_context_bar_data [list "view-questions?object_type_id=$object_type_id" "$pretty_type Questions"] $title
+
+if {$short_id == $question_id} {
+ set is_short_p t
+ set is_part_of_short_p f
+} else {
+ set is_short_p f
+ if {[lsearch $short_id $question_id]==-1} {
+ set is_part_of_short_p f
+ } else {
+ set is_part_of_short_p t
+ }
+}
+
+if {$edit_p} {
+ if {$public_until_id == $question_id} {
+ set is_public_until_p t
+ }
+ if {$start_date_id == $question_id} {
+ set is_start_date_p t
+ }
+ if {$end_date_id == $question_id} {
+ set is_end_date_p t
+ }
+}
+
+set dc_export [doubleclick::signature_html]
+set csrf_link [csrf::link_token]
+
+ad_return_template
Index: openacs-4/contrib/obsolete-packages/library/www/admin/error.adp
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/contrib/obsolete-packages/library/www/admin/error.adp,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/contrib/obsolete-packages/library/www/admin/error.adp 2 Jul 2003 12:19:44 -0000 1.1
@@ -0,0 +1,16 @@
+
+Application Error
+
+We had
+
+ a problem
+
+ some problems
+
+ processing your entry:
+
+
This sample form shows all input questions for @pretty_type@,
+including all branch questions. The first input form shown to the user
+will not contain all of these fields.
if (@public_p@ eq 0)
+ if (@approval_p@ eq 1) and (@in_review_p@ eq 1)
+ if (@review_state@ eq library_review)
+ [Private] [In review] Make public
+ if (@review_state@ eq library_clarify)
+ [Private] [Needs clarification] Make public
+ else
+ [Private] Make public
+
+
if (@write_p@ eq 1) and (@archived_p@ eq 0):
+
if (@public_p@ eq 0)
+ if (@in_review_p@ eq 0)
+ if (@approval_p@ eq 1)
+ [Private] Propose to publish
+ else
+ [Private] Make public
+ else
+ if (@review_state@ eq library_review)
+ [Private] In review
+ if (@review_state@ eq library_clarify)
+ [Private] Review: Needs clarification
+ if (@public_p@ eq 1)
+ if (@approval_p@ eq 0)
+ [Public] Make private
+ else
+ [Public]
+
+
all other users with read permission:
+
if (@in_review_p@ eq 1)
+ [Private] [In review]
+ if (@public_p eq 1)
+ [Private]
+
+
Archive
+if (@write_p@ eq 1) or (@admin_p@ eq 1) or ( (@approval_p@ eq 1) and (@publish_p@ eq 1) ):
+
if (@archived_p@ eq 1)
+ [Archived] Remove from archive
+ if (@archive_p@ eq 1) and (@archived_p@ eq 0) and ( (@admin_p@ eq 1) or (@publish_p@ eq 1) or (@approval_p@ eq 0) or ( (@public_p@ eq 0) and (@in_review_p@ eq 0) ) )
+ Put in archive
+
+
Access control
+if (@admin_p@ eq 1) or ( (@write_p@ eq 1) and (@archived_p@ eq 0) ):
+
sn_questions: object_type_id renamed to target_object_type_id, because
+this name makes the semantics much clearer
+
+
sn_content: removed long_content, made content a clob Newsgroup
+posting to make sure that this is definitely not a performance risk:
+
+
+
+From: tkyte@us.oracle.com
+Subject: Re: clobs and possible performance issues
+To: Dirk Gomez
+Date: Sat, 14 Jul 2001 11:58:54 -0700 (PDT)
+
+In article , Dirk says...
+>
+>Hi,
+>
+>This is the current table layout:
+>
+>create table sn_content (
+> object_id
+> integer
+> constraint sn_content_object_id_fk
+> references sn_objects(object_id),
+> question_id
+> integer
+> constraint sn_content_question_id_fk
+> references sn_questions(question_id),
+> content
+> varchar(4000),
+> long_content
+> clob,
+> html_p
+> char(1)
+> constraint sn_content_html_p_ck
+> check (html_p in ('t', 'f')),
+> constraint sn_content_pk
+> primary key (object_id, question_id)
+>);
+>
+>Either content or long_content is being filled with data depending on the size
+>of content. If the content is > 4000 bytes, it is stored in the lief
+>long_content and content is set to null and vice versa.
+>
+>That has mainly historical reasons - and I would like to get rid of that.
+>
+>So retrieving content is currently done in this way (in meta pl/sql syntax):
+>
+>select content into the_content where object_id=:the_object_id and
+>question_id=:the_question_id;
+>
+>if content is null then
+>select long_content into the_contet where object_id=:the_object_id and
+>question_id=:the_question_id;
+>end if;
+>
+>Are there any performance implications when removing the content field? The
+>overall amount of queries on sn_content would get smaller, but all queries
+>would end up retrieving data from a clob or stuffing data into a clob. How do
+>queries on tables with clobs perform, mainly inserts and selects? All lookups
+>on sn_content are indexed, there are no range scans.
+>
+>cheers Dirk
+
+I'd get rid of the content column (varchar2(4000)) and just go for the clob.
+Clob data, by default, will be stored inline upto your existing 4000 bytes (you
+can control inline or out of line storage) so if the text is small, the clob
+will be stored there, if the text is large, it'll be moved out of line into the
+lob segment and stored there.
+
+You are in effect mimicking what we already do under the covers with clobs.
+
+--
+Thomas Kyte (tkyte@us.oracle.com) http://asktom.oracle.com/
+Expert one on one Oracle, programming techniques and solutions for Oracle.
+http://www.amazon.com/exec/obidos/ASIN/1861004826/
+Opinions are mine and do not necessarily reflect those of Oracle Corp
+
+
+
+
+Removed the PL/SQL function sn_object_type_view_p and replaced it with a dummy
+called km_dirks_temporary_permission_p that always return true.
+
+
+The table sn_objects holds data the knowledge objects in the system.
+
+
+The one_line_description for knowledge objects is taken with a trigger on
+sn_content- this column always holds the answer to the question that has been
+defined as the "short_description" for this object type. The column overview
+holds the long_description for the object type. The column public_until holds
+the value from sn_content that answers the question that has been defined as
+the public_until date. The public_until date holds the date on which this
+object is no longer visible in the system except for the owner and its
+group. This is a bit confusing, since you would think that that is what the
+expiration_date column should hold. In fact, the expiration_date shown when
+this object has been deleted. So,the object is deleted and visible to no one
+when the expiration_date is less than the curren date. The user_checkoff_date
+(should be called "publication_date") is the date that the user has published
+the object, i.e. made it visible to the public. public_p holds the information
+whether the object is publicly visible or not, archived_p whether the object
+is archived or not (not yet implemented). access_total and access_month are in
+this table for performance reasons: these counts are shown on almost every
+page, so we decided to store them in this table as well.
+
+
+create index sn_objects_expiration_date_ix on sn_objects (expiration_date);
+
+create index sn_objects_public_until_ix on sn_objects (public_until);
+
+create index sn_objects_checkoff_date_ix on sn_objects (user_checkoff_date);
+
+create index sn_objects_last_modified_ix on sn_objects (last_modified);
+
+create index sn_objects_new_stuff_ix on sn_objects (last_modified,
+user_checkoff_date, expiration_date, object_type_id);
+
+create index sn_objects_type_id_ix on sn_objects (object_type_id);
+
+create index sn_objects_browse_ix on sn_objects (object_type_id, context_id, expiration_date, last_modified, public_p);
+
+create index sn_objects_one_line_desc_ix on sn_objects (substr(upper(one_line_description),1,1));
+
+
+
+
Questions
+
+
The questions table holds all of the data about the questions that
+can be asked about knowledge objects.
+
+
For abstract data type category, category_id
+points to the root node of the category tree associated with this
+question. XXXTomislav
+
+For questions having the abstract data type object_object_link and
+child_object, target_object_type_id defines the object type the user
+may link to. Otherwise it has no meaning and does not map this
+question to an object type (that is in sn_question_object_type_map). The
+entry_explanation is the text that you see under the pretty_name in the
+display of a question. The column help_text is unused at this time, but can be
+used to link to a pop-up help text for any given
+question. references_question_id references the question to which an
+object-object link points to.
+
+create table sn_questions (
+ question_id
+ integer
+ constraint sn_questions_question_id_fk
+ references acs_objects (object_id)
+ constraint sn_questions_question_id_pk
+ primary key,
+ pretty_name
+ varchar(4000),
+ abstract_data_type
+ varchar(50)
+ constraint sn_questions_abstract_data_nn not null,
+ presentation_type
+ varchar(100)
+ constraint sn_questions_presentation_t_nn not null,
+ -- for all questions which display lists
+ order_by
+ varchar(100),
+ -- default for input forms
+ default_value
+ varchar(4000),
+ entry_explanation
+ varchar(4000),
+ tag_width
+ integer,
+ tag_height
+ integer,
+ help_text
+ varchar(4000),
+ -- for object_link: which type to link to
+ target_object_type_id
+ integer,
+ -- that is merged in from a change I (and Carsten ;) already did in
+ -- 7.1
+ references_question_id
+ integer
+ constraint sn_questions_referenc_qu_id_fk
+ references sn_questions(question_id),
+ -- for question of data type category
+ tree_id
+ integer
+ constraint sn_questions_tree_ref references generic_trees,
+ node_id
+ integer
+ constraint sn_questions_node_ref references sw_category_dim,
+ -- This is only used during data migration from 7.
+ category_id
+ integer,
+ -- this is only for abstract_data_type date to specify what years
+ -- should be in the select box in respect to the default date.
+ year_from
+ integer default -5,
+ year_to
+ integer default 5
+);
+
+begin
+ acs_object_type.create_type (
+ supertype => 'acs_object',
+ object_type => 'sn_question',
+ pretty_name => 'Question',
+ pretty_plural => 'Questions',
+ table_name => 'SN_QUESTIONS',
+ id_column => 'QUESTION_ID'
+ );
+end;
+/
+show errors
+
+
+
+the object name
+
+
Object Types
+
+
The table sn_object_types defines the possible types of knowledge
+objects. The column long_description defines the
+overview. public_until can point to a question of abstract data type
+date, which will determine how long the object is publically
+visible (if public_p is set). If browse_p is true, than this object
+type is browsable throughout the system. Sometimes this is not desirable, as
+in the case of child_objects. In that case, browse_p is set to false and the
+object_type will only show up in a parent-child relationship to other object
+types. The default_age_filter sets the default filter in the browse pages for
+displaying this object type. Although the user can browse objects with any
+number of different age filters, it is nice for the admins to be able to
+decide what age is most appropriate as the default.
+
+
+create table sn_object_types (
+ object_type_id
+ integer
+ constraint sn_object_types_pk
+ primary key,
+ context_id
+ constraint sn_object_types_context_id_fk
+ references apm_packages (package_id)
+ on delete cascade,
+ short_name
+ varchar(100),
+ pretty_name
+ varchar(100)
+ constraint sn_object_types_pretty_name_nn not null,
+ pretty_plural
+ varchar(100),
+ -- filename for the graphic icon. This is always
+ -- $object_type_id.extension
+ graphic
+ varchar(200),
+ graphic_p
+ char(1)
+ default 'f'
+ constraint sn_object_types_graphic_p_nn not null,
+ constraint sn_object_types_graphic_p_ck
+ check (graphic_p in ('t', 'f')),
+ deleted_p
+ char(1)
+ default 'f'
+ constraint sn_object_types_deleted_p_nn not null,
+ constraint sn_object_types_deleted_p_ck
+ check (deleted_p in ('t', 'f')),
+ browse_p
+ char(1)
+ default 't'
+ constraint sn_object_types_browse_p_nn not null,
+ constraint sn_object_types_browse_p_ck
+ check (browse_p in ('t', 'f')),
+ -- If the object type is not public, consult sn_object_type_access
+ -- to determine if a user may access this type.
+ public_p
+ char(1) default 't'
+ constraint sn_object_types_public_p_nn not null,
+ constraint sn_object_types_public_p_ck
+ check (public_p in ('t','f')),
+ -- to be able to prevent standalone objects of this object type
+ -- (meaning objects which didnt created as child or nephew)
+ -- needed this for people - demand descriptions
+ create_p
+ char(1) default 't'
+ constraint sn_object_types_create_p_nn not null,
+ constraint sn_object_types_create_p_ck
+ check (create_p in ('t','f')),
+ sort_key
+ integer,
+ -- The admin can define which question is the name, overview or
+ -- public_until date for this object type:
+ short_description
+ integer
+ constraint sn_object_typ_short_desc_id_fk
+ references sn_questions (question_id),
+ long_description
+ integer
+ constraint sn_object_type_long_desc_id_fk
+ references sn_questions (question_id),
+ public_until
+ integer
+ constraint sn_object_t_public_until_id_fk
+ references sn_questions (question_id),
+ -- that is merged in from a change I (and Carsten ;) already did in
+ -- 7.1
+ linked_question_id
+ integer
+ constraint sn_object_t_linked_quest_id_fk
+ references sn_questions(question_id),
+ default_age_filter
+ integer default 365
+);
+
+
+begin
+ acs_object_type.create_type (
+ supertype => 'acs_object',
+ object_type => 'sn_object_type',
+ pretty_name => 'Object Type',
+ pretty_plural => 'Object Types',
+ table_name => 'SN_OBJECT_TYPES',
+ id_column => 'OBJECT_TYPE_ID'
+ );
+end;
+/
+show errors
+
+-- We can only add this foreign key after creating the object_type_table.
+alter table sn_questions
+ add constraint sn_questions_object_type_id_fk
+ foreign key (target_object_type_id)
+ references sn_object_types(object_type_id);
+
+alter table sn_types_map_short_name
+ add constraint sn_types_map_object_type_id
+ foreign key (object_type_id)
+ references sn_object_types(object_type_id);
+
+
+
+
+The table sn_types_map_short_name defines the name of an object. This data has
+to be stored in another table, because it is a 1:m relationship: an object
+type can have composite short names.It has to be maps short
+
+
This defines the set of questions associated with a given object
+type. Questions can be shared among object types and grouped together
+under one parent_question_id for composite questions. We don't share questions at this point
+for any object types, but it is possible. The column form_number is something of a relic-
+if it is set to 1 then the question appears on the first form. The sort key
+sets the order of the questions outside of the branch hierarchies.Note that the system will have problems
+publishing objects if an object type has any questions that are mandatory but not visible.
+
+
+create table sn_question_object_type_map (
+ question_id
+ integer
+ constraint sn_question_otm_question_id_fk
+ references sn_questions (question_id),
+ object_type_id
+ integer
+ constraint sn_question_otm_object_t_id_fk
+ references sn_object_types (object_type_id),
+ sort_key
+ integer,
+ form_number
+ integer,
+ mandatory_p
+ char(1)
+ constraint sn_question_otm_mandatory_p_ck
+ check (mandatory_p in ('t','f')),
+ question_state
+ varchar(100)
+ constraint sn_question_otm_question_st_ck
+ check(question_state in
+ ('active','deprecated','read-only','invisible')),
+ -- used for composite and branches
+ -- -50 is the magic object from acs_magic_objects where name='km_dummy_object'. Don't change it!
+ parent_question_id
+ integer
+ default -50
+ constraint sn_question_otm_parent_q_id_nn not null
+ constraint sn_question_otm_parent_q_id_fk
+ references sn_questions (question_id),
+ -- t if this question itself is a branch, NOT if this question LEADS to branches
+ branch_p
+ char(1)
+ constraint sn_question_otm_branch_p_ck
+ check (branch_p in ('t','f')),
+ -- applies to the question as the parent node of a branch
+ branch_operator
+ varchar(4000),
+ -- the answers apply to the child nodes
+ branch_answer
+ varchar(4000),
+ -- can reference categories or sn_answer_options
+ branch_answer_foreign_key
+ integer,
+ default_branch
+ integer
+ constraint sn_question_otm_default_bra_fk
+ references sn_questions (question_id),
+ constraint sn_question_object_type_map_pk
+ primary key (question_id, object_type_id)
+);
+
+
+
Question Hierarchies (Branches and Composite)
+
+
+
+
Composite
+
+
The above table, sn_question_object_type_map, has a column
+parent_question_id. If the abstract data type of this question_id is
+composite, then the children are not branches. They should not have
+branch_p='t' and the row for the question_id that is equal to the
+parent_question_id should not have a default branch. Composite questions can
+only go one level deep- one parent and n children. No questions in a
+composite relationship should have any branch column data whatsoever.
+
+
Branches
+
+
If a question leads to branches, then it will appear as the
+parent_question_id for other rows in sn_question_object_type_map. It should
+only have abstract data types of integer, option or category. It must have a
+question_id given as default branch. This question may itself be a branch, in
+which case branch_p='t', branch_operator and
+branch_answer/branch_answer_foreign_key will also be answered, but this is not
+necessarily so. This means that the field branch_p shows if a question is
+itself a branch and not if it leads to a branch. For the cases of options
+and categories, we use the ids from sn_answer_options or sn_categories as the
+answer in the column branch_answer_foreign_key (could be eliminated by also
+storing foreign key values in the branch_answer column). Integer answers and,
+perhaps in a future version, text answers are stored in branch_answer. We
+have not implemented branches for abstract data type text for this release,
+but it's doable.
+
+
+
+
Linking
+
+
+Linking uses the site-wide linking service described somewhere else. Thise
+service supports only object-object linking though, so we had to add a table
+to the library datamodel to support linking on the question level:
+
+
This table stores the content of the one-to-one questions having abstract
+data type text for any given object. It also contains the abstract data types
+file, date and integer. The questions_id shows which question the content
+answers. If a single question has more than one answer, then that data belongs
+in the multiple-choice answers tables (sn_answer_options and
+sn_object_option_map) having the abstract data type option, mapped as a
+category in site_wide_category_map, stored as a link in sn_links (see above)
+or should be constructed as composite question having the abstract data type
+composite.
+
+
This table holds the answers to multiple choice questions. The poorly named
+"answer_option" is the simply the pretty_name multiple-choice answer, the
+option_ids are the values in the HTML selects and checkboxes.
+
+
Whenever the content of an object is changed then we store it
+here. We don't store changes in the categorization, linking or
+multiple choice questions.
+
Depending on sn_object_types.public_p, a Knowledge Object Type is
+either visible to all users with access to the Library instance, or
+only to those who have admin permission.
+
+
+
Access Control for Knowledge Objects
+
+
Depending on sn_objects.public_p, a Knowledge Object is visible for
+all users with access to the Library instance, or only for those who
+have read permission. public_p only exists for performance
+reasons. For public objects, read is granted to The Public, so a
+permission check works, although it can be skipped. For private
+objects, read as well as write can be granted to individual users and
+private user groups using the system-wide permissioning system.
+
+
+
Statistics
+
+
We group object views by month, so the following table has a count
+and date column (allowing for even more flexible grouping).
+
+
+There is no more special search handling for library. For a documentation
+of the search features see the documentation
+ of site-wide-search.
+
+
+
People Tables
+
In People information about understaffed projects (Project descriptions)
+are stored together with descriptions of open positions for these projects
+(Demand descriptions). Users can then apply for these open positions bu filling out
+an application form, saving the entered data, making changes later, attaching
+some files and finally sending the application as an email. In this table all
+text input and category selections for each application is stored together with
+the information about the creation date, the user, the project and demand.
+
In the application form are three different kinds of categories used:
+Roles/Functions of the applicant, languages spoken and the proficiency in the
+language. Therefore, three different category trees are needed. Since we don't
+use static categories, an admin has to map these three trees to the application.
+In order to do that and to distinguish between these three trees, three magic
+objects have to be created to map the category trees to. This table holds the
+object ids of these three magic objects for each library package instance.
+
+create table psn_category_trees (
+ package_id integer primary key,
+ role_magic_id constraint psn_cat_trees_role_fk
+ references acs_objects (object_id) on delete set null,
+ language_magic_id constraint psn_cat_trees_lang_fk
+ references acs_objects (object_id) on delete set null,
+ proficiency_magic_id constraint psn_cat_trees_prof_fk
+ references acs_objects (object_id) on delete set null
+);
+
+
+
This table holds all email-attachments to the application as blobs.
+
+create table psn_attachments (
+ attachment_id integer primary key,
+ application_id constraint psn_attach_appl_id_fk
+ references psn_res_applications on delete cascade,
+ title varchar2(1000),
+ mime_type varchar2(200) default 'text/plain',
+ filename varchar2(200),
+ attachment blob default empty_blob()
+);
+
+create index psn_attach_appl_id_idx on psn_attachments(application_id);
+
+create sequence psn_attachment_id_seq start with 1;
+
+
+
Creation of new object types for applications and magic tree objects.
+
+We've rebuilt the library on top of a lot of procs that deal with
+meta and object data. The procs are organized into Tcl collections that we'll
+go through in this doc. The data model is described in KM Data Model. Also see the flowchart which shows all possible
+paths within the library.
+
+
+
We have tried to write short, well-named and highly cohesive procs that
+never use upvar or uplevel. We have tried to keep site navigation
+and excursion handling on the pages. It is very difficult to figure out what
+is going on with navigation if it's buried in a proc somewhere. The idea is
+that when you look at a page, you see what variables are coming in, you see
+the procs that deal with the data machinery and display, you see how the page
+handles the navigation from the page. See below about paths to follow the
+navigation mechanism.
The procs are strictly sorted into their own
+libraries. A proc found in km-display will
+never retrieve data from oracle. A proc in km-object-data does not
+display HTML. km-categories.tcl holds procs that have to do with
+categories and some of these do display something. (these procs are part of
+'s categorization system which is part of the ACS categorization.)
+
+
+km-defs.tcl has library core-procs having to do with metadata, building
+form fields, object access
+control, checking user input and excursions (aka paths).
+
+
Abstract Data Types
+
+
text Text data stored together with a value of html_p in one row of sn_content.
+
option Multiple choice data stored in sn_object_option_map, refers to sn_answer_options
+
category Category data that maps the object to site-wide categories in site_wide_category_map
+
composite A question composed of one or more children questions which are mapped in sn_question_object_type_map.
+
date A date stored as text in sn_content but required to be a valid date.
+
integer An integer stored as text in sn_content but required to be a valid integer.
+
file An uploaded document that can be found in the document_uploads directory, the name of the file is stored in sn_content.
+
object_link Maps objects to other objects in sn_links, refers to a comment in sn_link_comments.
+
user_link Maps objects to users in sn_links, doesn't have a comment, but could.
+
child_object The answer to this question is the completed content of another object type.
+The permissions and the public/private status of this child object are exactly the same as
+for the parent object. If the parent object is public and all mandatory questions of a child object
+get answered, it will automatically get the public status. If the parent object gets deleted, so are all its child objects.
+
nephew_object The answer to this question is again the completed content of another object type.
+The permissions of uncle and nephew objects can be set seperately. To publish an uncle object,
+at least one nephew object must be published at the same time. After publishing of the uncle object,
+nephew objects can be published and unpublished seperately. If the last public nephew object of a public uncle object
+gets private, so does the uncle object. If an uncle object gets delete, so do all its nephew objects.
+This special abstract data type was needed for People 's Project and Demand descriptions.
+
+
+
+
Metadata (km-00-defs.tcl)
+
+There is one main proc responsible for getting metadata-
+km_get_questions. km_get_questions returns all visible question_ids and
+various other metadata attributes for any given object type as a keyed list of
+lists. km_get_question returns one question and is usually used to return the
+next or previous question in the question list by calling it with the
+"-next_p" or "-previous_p" options.
+
+
+The other important metadata procs are km_get_all_object_types and
+km_object_type_attributes, which return useful stuff about the object types.
+The latter is used on almost every single page in the library, since
+it returns everything we need to know to display a page for any given object
+type.
+
+
+km_static caches information about objects whose value is more or
+less static throughout the system's life time. The first time a
+particular information is being looked for, this information is being
+loaded from the database into the cache. km_static does _not_ do any
+error checking at the moment. It is also not the smartest caching
+system under the sun (not yet at least):
+
+
+
As soon as any of the supposedly mostly static information is being
+changed, the whole cache is reset.
+
Also there should be proc that loads the cache on server startup.
+
+
+
+km_conn works very much like ad_conn: it caches information on a library
+object on a per-request basis. Put everything that could be a of interest for
+an object here and retrieve it from this function. Most of the km_conn cache
+is set in km_check_object_id.
+
+
+
Building dynamic forms (km-display.tcl)
+
+
+km_get_form builds a form of questions for any object type. It takes the
+questions from km_get_questions and presents each according to its
+
+
+
Abstract data type
+
Presentation type
+
+
+
+There are various display procs that are named after the abstract data types
+that are used for them, i.e. km_user_link_field, km_option_field. Also
+important is km_get_form_field, a display proc that knows how to call procs
+that produce HTML tags from the metadata presentation types. EVERY form in
+the library that handles object data is produced by calling this
+proc. object-edit.tcl makes only one call to km_get_form to produce the
+entire form. one-question-edit.tcl also calls this proc with a question-id.
+
+
+Only small parts of the library have been templated yet, both because we were
+working under heavy timeload and because of km_get_form's complexity.
+
+
User Input
+
+
+The center proc in the family of user-input procs is km_check_input. It takes
+a list of keys, a list of values and an object type and determines if there
+has been insufficent or invalid data entered as values. It does this by
+calling km_required_questions and then compares a list of required fields for
+this object type with the keys and values.
+
+
+
Important here is the proc km_sort_form, which takes all the various
+key-value pairs coming in from a input form and assembles them into meaningful
+lists according to the abstract data type. So, for example, a question having
+abstract data type text will have a sibling variable "html_p" that is sorted
+by this procedure into a value tuple, where the first value is the text itself
+and the second is the boolean value. Mulitiple-select variables are also
+sorted into lists matched to one key. Also: km_assemble_dates. This proc
+takes n variables of the triple form var:year var:month var:day and assembles
+them to the variable var, whose value is "YY-MM-DD". (Similar to the
+date_widget but more flexible for the method of dynamic form generation
+required in this system.) var is run through the proc date_p to make sure that
+this assembled thing is really a date.
+
+
If check_input finds any reason to complain, it returns a a tuple: the
+number of complaints and the message strings. These can then be easily
+formatted to ad_return_complaint on the page.
+
+
+
Linking
+
+
+
+
Creating an object (km-object-data.tcl)
+
This is done by km_create_object.
+
+
+
Saving object data (km-object-data.tcl)
+
+The central proc in the family of procs that save object data is called
+km_save_object_data. It takes a list of keys, a list of values, a user_id and
+an object_id as arguments. It saves all data of whatever abstract data type if
+possible.
+
+
+km_save_object_data actually doesn't save any data itself, it calls procs to
+deal with the data by abstract data type.
+
+
+
+This proc only saves object data of other abstract data types for an object_id
+that already exists. (it doesn't make sense to categorize or link an object
+that doesn't exist.)
+
+
+
Retrieving object data
+
+
+In principle, data is retrieved in the same way it is saved: divided into
+abstract data types and then picked out accordingly. The proc that handles
+this is known as km_get_object_data. It only needs an object_id and it returns
+a key list of lists. Check out the form of the return lists in the proc
+itself. It returns everything you need to display this data (but this proc
+does NOT display data.) If you only want the data on a few questions or even
+just one question, then pass a list of just these questions as an optional
+argument. Otherwise it gets data for every single question that can be asked
+about this object.
+
+
+Each question supplied to km_get_object_data is looped through and answered
+according to abstract data type. The answer is retrieved by calling a proc
+that know how to get this particular type of data. Many of the other procs
+that km_get_object_data calls are also in km-object-data.tcl:
+km_get_answer_options, km_get_user_links.
+
+
+km_get_linked_objects gets all data about linked objects for a question of
+abstract data type "object_link". It is found in
+km_links.tcl. (km_get_child_objects is actually in km-links.tcl, too, since
+"child_object" a kind of link is. km_get_categories gets all category
+data for a particular question of abstract data type "categorization". It is
+found in km_categories.tcl.
+
+
+
Buttons
+
+The km8_button_panel returns datasources for the 5 buttons that appear as a
+navigation panel at the bottom of one-question-edit.tcl. They allow the user
+to go to a lot of places that can only be determined by analysing the name of
+the submit button. Accordingly, we have procs that create submit buttons of
+the style "my_submit_button_name:some_important_number".
+
+
Related to these procs is km-defs' km_button_list, which returns a list of
+all possible submit button names in .
+
+
+
Dates (km-display.tcl, km-defs.tcl)
+
+There are also some special little procs that do date stuff. For example,
+km_break_date ....breaks a date into 3 parts. Or km_empty_date_p determines if
+a date has any empty fields at all. There are some default date procs in
+km-defs.tcl.: km_default_day, km_today, km_default_year, km_default_month. The
+special proc for is km_library_date, which calculates a default date
+for beginning and ending projects.
+
+
Branches(km-branch.tcl)
+
+Branches are not abstract data types! Branches are how we call
+answer-dependent question sequences in the library. For instance, you have a
+question "Who did you vote for?". If the answer was "George W. Bush", then
+the following question might be "What reasons do you have to believe that the
+Republican party will help you personally?" If your answer was "Al Gore", then
+the following question might be "Did you vote Democratic because you were
+pleased with the present government?"
+
+
Refer to the km-library document
+to grasp the finer points of the question hierarchies for branches. The most
+important procs are km_get_root_branch, which returns the highest node of the
+branch hierarchy for given question_id. Similarly, km_root_branch_p determines
+if this is a question is at all a branch node that has children. Important
+here is the concept of "active branches". An active branch is one where all
+the questions are descendents of an answer that has been chosen higher up in
+the branch tree. If later, one answer higher up is changed, then those
+questions and answers below it are no longer considered "active" and will not
+be displayed in the interface. This is why km_active_branch_p requires the
+root_question_id of a branch AND the object_id. Each object will have its own
+specific version of the active branch path. The most critical proc is
+km_next_branch. Alter with care!!!! It takes a question_id and an answer and,
+analysing them according to the abstract data type, determines which question
+should follow. It uses the default branch if it can't determine what it should
+return, or empty, if there are no children. This proc is used when navigating
+one-question-edit.tcl form "previous" question to "next". Make sure you look
+at the km8_button_panel in km-display.tcl that predetermines the previous and
+next questions when displaying one-question-edit.tcl. And also,
+km_get_question in km-defs.tcl, which does NO branch analysis but works
+together with km_next_branch in one-question-edit-2.tcl to determine what the
+next question will be.
+
+
Access Control (km-access-procs.tcl)
+
+
In contrast to 7, the Library now uses the system-wide
+permissioning system for controlling access to the Knowledge
+Objects. Only a small part of km-access-procs.tcl is concerned with
+the actual permission checks - the large rest of the code does some
+useful things like retrieving general object information in one
+query.
+
+
km_check_object_id, km_check_object_type_id
+
+
These versatile procs should be used on all pages to which an
+object or type ID may be passed. They check if the object or type
+exists, has been deleted, is readable or writeable by the given user,
+and also can print error messages. Note that
+km_check_object_id also checks permissions for the object
+type.
+
+
Other Access Control Procs
+
+
Apart from that, there are also procs for checking if a given user
+is a library administrator, may change the owner of an object and may
+read or modify an object or object type.
+
+
+
+
Browsing (km-browse.tcl)
+
+
A couple of display procs used by browse-one-type,
+browse-one-category and the object-view family of pages can be found
+here.
+
+
The only interesting proc is km_output_object_list, which
+is used at a couple of places to output lists of objects (name,
+overview, author), possibly with Link buttons when the user is on an
+excursion. It checks the access permissions in its own way, since for
+speed reasons we have to use SQL joins and cannot use the Tcl procs
+defined in km-access.
+
+
All the stuff related to categories resides here. We use the
+standard categories from the ACS, but need some helper procs to
+deal with them.
+
+
+
+
km_category_table
+
+
When the user browses objects of one type, he can navigate through
+the associated category tree. This proc builds a subtree starting at a
+given question or category, and displays it as a HTML table. The count
+of objects below each category is passed in as a parameter.
+
+
km_get_child_categories
+
+
Returns all the categories associated with the given question as a
+list of tuples holding the category_id and the indented category
+name. This is used for data entry, where we want to display an
+indented list in a selection box.
+
+
km_get_category_counts
+
+
Counts how many objects there are for a category and its
+subcategories. The result can then be used for km_category_table.
+
+
Misc.
+
+
Mapping between objects and categories and between questions and
+category trees; procs for handling category trees (determing the root
+category, e.g.); small display procs.
+
+
+
Reuse Feedback (km-feedback.tcl)
+
+
Editing and display of general comments and reuse feedback for
+knowledge objects. Uses the site-wide service general-feedback.
+
+
User Customisation (km-users.tcl)
+
+
Procs used to display the users Workspace (saved items), and
+his own objects (with some information about their current state). This is
+also the place for hooking into ACS' system of listing user contributions and
+new stuff (km_contributions).
+
+
People: Features and Implementation
+
+ by Timo Hentschel
+December 2001
+
+
+
+
People - The Big Picture
+
+People is a community that deals with understaffed projects
+and open positions for these projects. The data about these projects
+and positions are stored in the knowledge library in the two object types
+"Project description" and "Demand description". In the past, People
+has been a TeamNet community with some changes to the knowledge library
+to reflect special requirements.
+
+
Requirements
+
+Project and Demand descriptions
+
+
The knowledge library is used for holding data for the two object types
+"Project description" and "Demand description". Demand descriptions can't
+be created without a Project description. When a Project description is
+created, the author can add an arbitrary number of Demand descriptions.
+To make a Project description public, at least one Demand description must
+exist and be made public at the same time since it doesn't make sense
+to present an understaffed project without presenting any open positions.
+After publishing of a Project, the Demands can be published an published
+seperately, but if the last public Demand gets private so does the Project.
+The permissions for the Demands can be set seperately. Each Project and each
+of its Demands has an end of publication date. If this end date is reached, the
+public Project/Demand will be made private automatically and the author will
+get an email notice. If a Project get private so do all its Demands. If the
+last public Demand of a Project gets private so does the Project itself.
+If a Project gets deleted, so do all its Demands. If the last public Demand
+of a Project gets deleted, the Project itself becomes private again.
+
+
Demand applications
+
+
Besides being able to browse Projects and Demands belonging to them, users
+can also Apply for a public Demand: They have to fill out an application
+form after being reminded that they have to make sure that their supervisor
+is aware of and complies with the application. The application can be saved
+to be completed later, in which case the list of the unfinished applications
+can be placed on the community portal. Users can attach files to the application
+that will be sent as email attachments.
+
+
Smaller features
+
+
In addition to these bigger features, People also has some smaller requirements
+also:
+
+
#10: For date input a new widget with select boxes only is needed - instead of input
+fields
+
#20: Admins should be able to group related questions with headings and seperators
+
#30: Users have to fill out an extra text input field if category "Other" is
+selected
+
#40: Users can filter the library objects based on "Duration from-to" regarding
+the start and end dates of the Projects and Demands.
+
#100: For every Demand, the name of and the link to the Project it's belonging to
+have to be displayed
+
#130: When a Demand is created, the contact field of the underlying Project is
+used as a default for the contact field of the Demand
+
+
+
Current status
+
+All requirements already got implemented except for #20, #30, #40 and #130 on the list of
+the smaller features. Also, the sweeper procedure that sets outdated public Projects
+and Demands to private still needs to be written.
+
+
Implementation
+
+Project and Demand descriptions
+
+
The relationship between Projects and Demands is something like what already
+got implemented with the abstract data type Child Object, but not quite
+the same. Therefore, a new abstract data type Nephew Object got added,
+the relationship is called an uncle-nephew relationship to express that the
+nephew's public status and permissions are not as strongly coupled to the uncle
+object than it's with parent and child objects (child objects always have
+the same permissions and public status as the parent object). On the other hand,
+this naming is somewhat misleading since the nephew object is in some way
+more dependend on its nephew objects than the parent object is on its child
+objects (an uncle object can only be made public when at least one nephew object
+is made public at the same time and the uncle object will loose the public
+status if there's no longer at least one public nephew object).
+
+
To achieve this, the code for the parent-child relationships got copied and
+slightly modified for uncle-nephew relationships. In total, the following procs
+needed to be changed or newly added:
+
+
+
+In addition to that, some user pages and some admin pages needed to be changed to support
+the new abstract data type and the People requirements for it:
+
+
User Pages:
+
+
index.tcl: check for each object type if standalone objects (i.e. Demand descriptions) of this type can be created without being linked to other objects
+
object-delete.tcl: before deleting an uncle show the user the list of all nephews which will also get deleted
+
object-delete-2.tcl: make uncle object private after deletion of the last public nephew
+
object-edit-2.tcl: Suport for 'Add new nephew' button (same as for child_object datatype)
+
object-publish.tcl: before publishing a nephew check for public uncle; before publishing an uncle, let user select which nephews to publish also
+
object-publish-2.tcl: publish a nephew with a public uncle; publish an uncle and all selected nephews
+
object-unpublish.tcl: before unpublishing last public nephew inform user that uncle will get private, too; before unpublishing an uncle inform user that all nephews will get private, too
+
object-unpublish-2.tcl: unpublish nephew and set uncle private if needed; unpublish uncle and set all nephews private
+
object-view.tcl: show toolbar for nephews (not shown for children)
+
one-question-edit.tcl: support for nephew_object datatype (same as for child_object)
+
one-question-edit-2.tcl: support for nephew_object datatype (same as for child_object)
+
questions.tcl: show nephew question with answers
+
+
+Admin Pages:
+
+
edit-question.tcl: support for nephew_object datatype (same as for child_object)
+
edit-question-2.tcl: support for nephew_object datatype (same as for child_object)
+
+
+Datamodel:
+
To specify whether users can create standalone objects of an object type - we
+won't allow users to create Demand descriptions without linked Project description:
+
+alter table sn_object_types add (
+ -- to be able to prevent standalone objects of this object type
+ -- (meaning objects which didnt created as child or nephew)
+ -- needed this for people - demand descriptions
+ create_p
+ char(1) default 't'
+ constraint sn_object_types_create_p_nn not null,
+ constraint sn_object_types_create_p_ck
+ check (create_p in ('t','f'))
+);
+
+
+
To have the hierarchy of parent-child and uncle-nephew relationships in the
+easily accessed table km_flat_object_hierarchy, the table and triggers had to be updated:
+
+alter table km_flat_object_hierarchy add (
+ -- we still have the unique (parent,child) constraint on this table
+ -- because we won't allow for two objects to be linked directly or
+ -- indirectly both as parent_child and uncle_nephew. That means that
+ -- one object tree in this hierarchy either only has parent_child links
+ -- or uncle_nephew links.
+ link_type
+ varchar2(100) default 'parent_child'
+);
+
+
+create or replace trigger km_flat_object_hier_insert_tr
+before insert on sn_links for each row
+begin
+ if :new.link_type = 'parent_child' or :new.link_type = 'uncle_nephew' then
+ insert into km_flat_object_hierarchy (object_hierarchy_id, parent, child, distance, link_type)
+ values (acs_object_id_seq.nextval, :new.object_id_a, :new.object_id_b, 1, :new.link_type);
+
+ insert into km_flat_object_hierarchy (object_hierarchy_id, parent, child, distance, link_type)
+ select acs_object_id_seq.nextval, parent, :new.object_id_b, distance+1, :new.link_type
+ from km_flat_object_hierarchy
+ where child = :new.object_id_a;
+ end if;
+end ;
+/
+show errors
+
+
+create or replace trigger km_flat_object_hier_delete_tr
+before delete on sn_links for each row
+begin
+ if :old.link_type = 'parent_child' or :old.link_type = 'uncle_nephew' then
+ delete from km_flat_object_hierarchy
+ where child = :old.object_id_b;
+ end if;
+end ;
+/
+show errors
+
+
+
Demand applications
+
+
The abstract data type nephew_object got two presentation types: Standard and
+Application Form. The latter means, that on the page of a public nephew object there
+will be button that will lead to the application form which can be found in the
+resource-application* files.
+The application form itself got implemented as a static form according to the Spec. In
+the contact data textarea all answers to registration questions are provided as
+default. Three different kind of categories are used in the application form. Since
+they didn't get implemented as static categories (static selectboxes), an admin
+has to assign category trees to the three magic application category objects that
+are created for every library instance. The data the user enters gets inserted
+into the database so that the user can come back, edit his application data and
+finally send his application - he will receive a copy. To remind the user of
+unfinished applications, a portal element showing these got added. The email
+itself has to be MIME encoded because of the files that have to be send as email
+attachments.
+
+
Tcl Procs:
+
+
km-00-defs-procs.tcl: updated km_static to support new create_p flag for object types to signal if standalone objects are alowed
+
km-admin-lib-procs.tcl: updated km_pretty_tag to support new presentation type 'application form'
+
km-psn-procs.tcl: portal_saved_applications (portal proc to show all unfinished applications of the user in a portal element)
+
+
+User Pages:
+
+
object-view.tcl: show application button in nephew if presentation type of nephew question is set to application
+
resource-application-add.tcl: show Application Policy approval page or redirect to the edit page if there's an unfinished application for this user and Demand description
resource-application-add-2.tcl: New application form with defaults for Recipient, Subject and Contact Data
+
resource-application-edit.tcl: unfinished application form with saved data
+
resource-application.adp: application form - for add and edit
+
resource-application-attach.tcl: attach files to application
+
resource-application-attach.adp: attach files to application
+
resource-application-attach-2.tcl: insert file into db and redirect to edit page
+
resource-application-save.tcl: save the entered data, delete the database entries if cancel application button got pressed and redirect either to attachment page, send page or object-view
+
resource-application-send.tcl: email preview and confirmation page
+
resource-application-send.adp: email preview and confirmation page
+
resource-application-send-2.tcl: MIME the whole email with all attachments and send them to the recipient and the user and redirect to object-view page
+
+
+Admin Pages:
+
+
choose-presentation-type.tcl: added presentation types 'standard' and 'application' for nephew questions
+
edit-object-type.tcl: added support for create_p flag of object types to signal if standalone objects are alowed
+
edit-object-type-2.tcl: added support for create_p flag of object types to signal if standalone objects are alowed
+
index.tcl: added link to management page of category trees for application form (role-tree, language-tree, language-proficiency-tree)
+
view-questions.tcl: show presentation type of nephew question
+
+
+Datamodel:
+
Table to hold most of the users data in an application:
+
In the application form are three different kinds of categories used:
+Roles/Functions of the applicant, languages spoken and the proficiency in the
+language. This table holds the object ids of the three magic objects for each
+library package instance used to map category trees to be used in the application form:
+
+create table psn_category_trees (
+ package_id integer primary key,
+ role_magic_id constraint psn_cat_trees_role_fk
+ references acs_objects (object_id) on delete set null,
+ language_magic_id constraint psn_cat_trees_lang_fk
+ references acs_objects (object_id) on delete set null,
+ proficiency_magic_id constraint psn_cat_trees_prof_fk
+ references acs_objects (object_id) on delete set null
+);
+
+
+
This table holds all email-attachments to the application as blobs:
+
+create table psn_attachments (
+ attachment_id integer primary key,
+ application_id constraint psn_attach_appl_id_fk
+ references psn_res_applications on delete cascade,
+ title varchar2(1000),
+ mime_type varchar2(200) default 'text/plain',
+ filename varchar2(200),
+ attachment blob default empty_blob()
+);
+
+create index psn_attach_appl_id_idx on psn_attachments(application_id);
+
+create sequence psn_attachment_id_seq start with 1;
+
+
+
Creation of new object types for applications and magic tree objects:
+
To support the displaying of a valid range of years in the selectboxes,
+two columns needed to be added to the table sn_questions: year_from and
+year_to describe the range of years (in respect to the year default) that
+should be displayed in the year selectbox. Admin pages and the date widget
+page dealing with the displaying of date entry fields needed to be updated to
+reflect these changes and to deal with the additional presentation type.
+
+
User Pages:
+
+
km-date-tags.tcl: updated to support new presentation_type
+
km-date-tags.adp: updated to support new presentation_type
+
+
+Admin Pages:
+
+
choose-presentation-type.tcl: added presentation type 'select' for date questions
+
view-questions.tcl: show pretty presentation type of date question
+
+
+Datamodel:
+
Added two columns to have a varying range of years in the year selectbox.
+Values are interpreted starting from the provided default.
+
+alter table sn_questions add (
+ -- this is only for abstract_data_type date to specify what years
+ -- should be in the select box in respect to the default date.
+ year_from
+ integer default -5,
+ year_to
+ integer default 5
+);
+
+
+
#30: Input field if category 'Other' is selected
+
+
This was implemented with an extra presentation type of the category
+questions 'other_category'. The content of the extra input-field is
+stored in sn_content like any other text input.
+
+
Tcl Procs:
+
+
km-00-defs-procs.tcl: support for other_category questions in km_static
+
km-admin-lib-procs.tcl: support for other_category questions
+
km-branch-procs.tcl: support for other_category questions
+
km-categories-procs.tcl: support for other_category questions
+
km-display-procs.tcl: display other_category value
+
km-object-data-procs.tcl: retrieve, save and edit other_category values
+
+
+User Pages:
+
+
km-display-question-answer.tcl: support for other_category questions
+
km-form.tcl: support for other_category questions
+
one-question-edit-2.tcl: support for other_category questions
+
questions.tcl: support for other_category questions
+
+
+Admin Pages:
+
+
choose-presentation-type.tcl: support for other_category questions
+
edit-question.tcl: support for other_category questions
+
edit-question-2.tcl: support for other_category questions
+
view-questions.tcl: support for other_category questions
+
+
+Pl/Sql Packages:
+
+
library-package-bodies.sql: Added support for other_category questions in question.insert_question
+
+
+
#40: Filtering of objects by start and end date
+
+
We added two columns to sn_object_types and added support for marking
+date questions as start_date or end_date questions in the admin pages
+(like public_until). The filter itself has been implemented in the user pages
+- browse-one-type and browse-one-category.
+
+
Datamodel:
+
+alter table sn_object_types add (
+ -- these two links to date questions have been added for
+ -- people (project start/end date):
+ start_date
+ integer
+ constraint sn_object_t_start_date_id_fk
+ references sn_questions (question_id),
+ end_date
+ integer
+ constraint sn_object_t_end_date_id_fk
+ references sn_questions (question_id)
+);
+
+
+
#70: Sweeper proc to check public status of uncle and nephew objects
+
+
That was done with just a tcl proc that gets scheduled to be run
+every night or so. Email-templates are needed since the object author
+needs to be notified if an object had to be made private. Six different
+cases had to be considered: Single objects, parent objects, child objects
+that are effected by the parent, nephew objects, uncle objects effected by
+nephews, other descendants of uncles effected by nephews.
+
+
Tcl Procs:
+
+
km-psn-procs.tcl: Actual sweeper proc
+
library-init.tcl: Schedule sweeper proc
+
+
+#100: show linked Project on Demand page
+
+
Since the relationship between Projects and Demands got implemented
+in the new abstract data type 'nephew_object' of the linking question,
+the uncle object will be shown in object-view of a nephew - the same way
+as i.e. 'Modified Date'.
+
+
User Pages:
+
+
object-view.tcl: If object is a nephew, display uncle object with
+a link
+
+
+
#130: Contact data of the Project is shown as default in Demands
+
+
To be a little bit more general with this feature, we added a column
+defaults_question_id to sn_questions which needs to be checked during editing
+of an unanswered question. The admin pages will make sure that this column
+points to a question_id of the same abstract_data_type.
+
+
Tcl Procs:
+
+
km-00-defs-procs.tcl: support for defaults_question_id
+
+
+User Pages:
+
+
km-form.tcl: support for defaults_question_id; get defaults from ancestor objects question if question haven't been answered yet
+
+
+Admin Pages:
+
+
edit-question.tcl: support for defaults_question_id; let the user select between questions of same abstract_data_type of ancestor object-types (object-types with parent-child or uncle-nephew questions to this object-type)
+
edit-question-2.tcl: support for defaults_question_id
There might be a seperate table to store the headings since adding these
+as a special abstract data type will result in special treatments in too
+many places. The downside of a seperate table will be that we'll need to
+join with this table for one-question-edit and possibly even for object-view
+which is pretty bad. Maybe there'll be a better solutuon falling from the sky.
+
+
Archive, Sweeper, Copy
+
+
Tcl Procs:
+
+
km-00-defs-procs.tcl: km_static-support for archive_p, copy_p, sweeper, sweeper_action, sweeper_warning_time, sweeper_outdated_time
+
km-access-procs.tcl: check permissions for archived objects
+
km-browse-procs.tcl: context bar, list of archived objects for browse pages
+
km-callback-procs.tcl: Support for [Archived] tag for objects
+
km-categories-procs.tcl: Support for category widget for archived objects
+
km-display-procs.tcl: Display archived objects with [Archived] tag
+
km-links-procs.tcl: Archive and unarchive objects
+
km-object-data-procs.tcl: Show list of archived objects on browse-pages, show invisible questions for archived objects
+
km-psn-procs.tcl: Sweeper for outdated/expired objects, warning sweeper for outdated/expired objects, copy object
+
km-users-procs.tcl: show copy option in toolbar
+
+
+User Pages:
+
+
browse-one-category.tcl: Let user copy objects or view the archive
+
browse-one-type.tcl: Let user copy objects or view the archive
+
comment-add.tcl: Check permissions for archived objects
+
comment-add-2.tcl: Check permissions for archived objects
+
comment-add-3.tcl: Check permissions for archived objects
+
comment-add-4.tcl: Check permissions for archived objects
+
comment-edit.tcl: Check permissions for archived objects
+
comment-edit-2.tcl: Check permissions for archived objects
+
km-display-child-object.tcl: Display archived objects with [Archived] tag
+
km-display-nephew-object.tcl: Display archived objects with [Archived] tag
+
km-linked-object-list.tcl: Display archived objects with [Archived] tag
+
index.tcl: Let user copy objects or view the archive
+
object-archive.tcl: Ask for confirmation before putting object in archive
+
object-archive-2.tcl: Put object in archive
+
object-unarchive.tcl: Ask for confirmation before removing object and selected descendants from the archive
+
object-unarchive-2.tcl: Remove objects from the archive or redirect to object-copy-2 if user wants to copy objects instead
+
object-copy.tcl: Copy object (called from index, browse-pages, one-question-edit-2, object-edit-2)
+
object-copy-2.tcl: Copy selected object list or specific object (called from object-copy, object-unarchive-2, object-view)
+
object-copy-3.tcl: Copy the objects
+
object-publish.tcl: Check permissions for archived objects
+
object-publish-2.tcl: Check permissions for archived objects
+
object-unpublish.tcl: Check permissions for archived objects
+
object-unpublish-2.tcl: Check permissions for archived objects
+
object-view.tcl: Display archived ancestor object with [Archived] tag
+
object-edit-2.tcl: Redirect to object-copy if user wants to copy objects
+
one-question-edit.tcl: Check permissions for archived objects
+
one-question-edit-2.tcl: Check permissions for archived objects, redirect to object-copy if user wants to copy objects
+
questions.tcl: Check permissions for archived objects
+
question-field-child-object.tcl: Show button to copy objects if allowed
+
question-field-nephew-object.tcl: Show button to copy objects if allowed
+
+
+Admin Pages:
+
+
create-object-type.tcl: support for new columns of sn_object_types
+
create-object-type-2.tcl: support for new columns of sn_object_types
+
edit-object-type.tcl: support for new columns of sn_object_types
+
edit-object-type-2.tcl: support for new columns of sn_object_types
+
+
+Pl/Sql Packages:
+
+
library-packages.sql: added object.copy_object to copy object
+
library-package-bodies.sql: Added support for archived_p, copy_p; added object.copy_object to copy object
+
+
+Datamodel:
+
+
+alter table sn_object_types add (
+ -- can objects of this type be archived?
+ archive_p
+ char(1)
+ default 't'
+ constraint sn_object_types_archive_p_nn not null,
+ constraint sn_object_types_archive_p_ck
+ check (archive_p in ('t', 'f')),
+ -- are you allowed to copy objects of this type?
+ copy_p
+ char(1)
+ default 't'
+ constraint sn_object_types_copy_p_nn not null,
+ constraint sn_object_types_copy_p_ck
+ check (copy_p in ('t', 'f')),
+ -- which sweeper should be checking for old objects?
+ -- outdated: objects haven't been modified for a certain time
+ -- expired: public_until date has been exceeded
+ sweeper
+ varchar(10)
+ default 'none'
+ constraint sn_object_types_sweeper_nn not null,
+ constraint sn_object_types_sweeper_ck
+ check (sweeper in ('none','outdated','expired')),
+ -- action to be performed on the objects by the sweeper
+ sweeper_action
+ varchar(10)
+ default 'private'
+ constraint sn_object_types_sw_action_nn not null,
+ constraint sn_object_types_sw_action_ck
+ check (sweeper_action in ('private','archive')),
+ -- if >0 a warning email will be sent if the object is outdated/expired
+ -- specifies the amount of days the action should be performed after
+ -- the warning email
+ sweeper_warning_time
+ integer
+ default 0
+ constraint sn_object_types_warning_nn not null,
+ -- specified the amount of days after which an unchanged objects is
+ -- regarded as outdated
+ sweeper_outdated_time
+ integer
+ default 30
+);
+
+alter table sn_objects add (
+ -- date the object got archived
+ archiving_date
+ date
+ default null,
+ -- date a warning email got sent that object is outdated
+ outdated_warning_date
+ date
+ default null,
+ -- date a warning email got sent that object is expired (public_until)
+ expired_warning_date
+ date
+ default null
+);
+
+create index sn_objects_archived_p_ix on sn_objects (archived_p);
+
+create index sn_objects_o_warning_date_ix on sn_objects (outdated_warning_date);
+
+create index sn_objects_e_warning_date_ix on sn_objects (expired_warning_date);
+
+create table sn_object_archive_reasons (
+ object_id
+ integer
+ constraint sn_object_archive_re_obj_id_fk
+ references sn_objects(object_id),
+ reason_for_archiving
+ varchar(4000),
+ archived_on
+ date default sysdate,
+ constraint sn_object_archive_reasons_pk
+ primary key (object_id, archived_on)
+);
+
+alter table saved_searches add (
+ l_i_a_p varchar2(4000)
+);
+
+create table km_sweeper (
+ user_id
+ integer
+ constraint km_sweeper_user_id_fk
+ references users,
+ package_id
+ integer
+ constraint km_sweeper_package_id_fk
+ references apm_packages,
+ object_type_id
+ integer
+ constraint km_sweeper_obj_type_id_fk
+ references sn_object_types,
+ object_id
+ integer
+ constraint km_sweeper_object_id_fk
+ references sn_objects,
+ object_name
+ varchar2(4000),
+ content
+ varchar2(4000),
+ primary key (user_id, object_id)
+);
+
+The workflow module is pretty well-documented. It contains an installation
+guide. Follow it and definitely set up graphviz, because it visualizes the
+workflow process nicely.
+
+
+If you have not set up graphviz, but want to see the graphical presentation,
+then click here.
+
+
+Don't forget the necessary email templates:
+
+
+
library_clarify
+
library_review_object
+
library_published
+
+
+
+And you have to grant access rights to the public to /workflow.
+
+
How to work with the workflow module
+
+The workflow module is quite fragile. It is pretty easy to ruin a whole
+workflow process and it is very hard to track down errors. At one point I even
+managed to deadlock a session. Hence I strictly stuck to changing one thing
+only, testing the whole workflow process and in case of success do more of the
+changes I had thought of as necessary.
+
+
+The whole workflow process is setup by running these two SQL scripts:
+
+
+
sql/oracle/library-workflow-create.sql
+
sql/oracle/library-workflow-packages.sql
+
+
+
+In case you want to recreate the library approval workflow, drop it by
+executing this script:
+
+
+
sql/oracle/library-workflow-drop.sql
+
+
+and rerun library-workflow-create and library-workflow-packages.
+
+
+Change the SQL scripts if you want to change workflow's behaviour. The web
+interface is nice, but the export function doesn't work properly.
+
+
How to change workflow's behaviour
+
+It's quite unlikely that the workflow process itself has to be changed. It's
+most certain though that you have to change a transition's context info. You
+register callback PL/SQL procedures to perform a certain job whenever a token
+passes a particular transition:
+
+
+
Enable PL/SQL proc
+
Fire PL/SQL proc
+
Assignment PL/SQL proc
+
Time PL/SQL proc
+
Deadline PL/SQL proc
+
Hold Timeout PL/SQL proc
+
Notification PL/SQL proc
+
Unassigned task PL/SQL proc
+
Access Privilege
+
+
+
+Check the sql/oracle/library-workflow-create.sql file to see which callbacks
+have been associated with which transition. It's the "insert into
+wf_context_transition_info" statements that register that information with the
+workflow module.
+
+
+Let's look into what happens when a token passes the library_review transition
+- when a knowledge item is put into the "needs to be reviewed" state:
+
+
+So if you want to change the task assignment, you either change the PL/SQL
+procedure assign_task_to_assignee, or assign another procedure to
+assignment_callback. Likewise with the fire_callback: if you want to muck
+around with the sn_objects table, then do it in review_fire.
+
+
+Exercise the same caution as with the workflow process definition itself. Work
+in small steps, test completely, roll back or commit your work etc.
+
+