Content Script: Retrive information
Nodes¶
Getting Content Server nodes¶
All the objects stored on OpentText Content Server are referred as nodes in Content Script.
The base interface representing a node is the CSNode interface. CSNode is the base interface for most of the Content Script API objects.
Almost all the Content Script API Objects inherit from CSNodeImpl which is the base-class implementing the CSNode interface. As said a node represents an object on Content Server.
Different Objects correspond to different implementation of the CSNode interface (e.g. Folders(SubType=0) are implemented by CSFolderImpl, Documents(SubType=144) correspond to CSDocumentImpl).
A CSNode (more generally speaking any Content Script API Object) features:
- Properties: this is information specific to the Content Server object (e.g. name, subtype, size, creation date) and may vary for each CSNode implementation. In order to be recognized as properties the CSNode fields must be decoretad with the
@ContentScriptAPIField
; - API Methdos: these are the APIs used to manipulate and retrieve information associated with objects;
- Features: these are additional features that are not strictly related to objects (their are not object's properties) but depend on external factors: the way Content Server is configured (which modules are available, how are they configuration), on object's configuration, on the user's permissions on the objects, on the context in which the features are accessed etc.
The Content Script API service you are going to use the most for retriving nodes is the docman{:style="color:red"} service.
docman{:style="color:red"} features several methods that allows you to retrive a node given:
- its unique numeric identifier;
- its path
- its name and the container in which is located;
- its nickname;
- etc..
The Base API also features a asCSNode{:style="color:#e7853c;font-size:bold;"} method that serves as a shortcut for the above mentioned use cases.
Performances-tip: Lazy loading
In order to optimize performances, Content Scripts lazy-loads information from OTCS 'database, which means that such information is not available until firstly accessed. docman{:style="color:red"} APIs allow you to specify which information you want to load beforehand. Retriving the minimum amount of information necessary is tipically done using the APIs ending with the Fast suffix and is to be consider a best practice and might have a significant impact over your's application performances.
1 2 3 4 5 |
|
1 2 3 4 |
|
Getting a node given its ID¶
def node = docman.getNode(2000, //NodeID (on most of the environments 2000 identifies the Enterprise Workspace)
true, //'true' if Reference information shall be loaded
true, //'true' if Reservation information shall be loaeded
true, //'true' if Versions information shall be loaeded
true, //-true- if Current Version shall be loaeded
true, //'true' if Node's features shall be loaeded
true, //'true' if Metadata shall be loaeded
true, //'true' if Permissions information shall be loaeded
)
node = docman.getNode(2000) //this is a shortcut for docman.getNode(2000, true, true, false, false, true, true, true) (loads the node without its versions)
node = docman.getNodeFast(2000) //this is a shortcut for docman.getNode(2000, false, false, false, false, false, false, false) (loads just the base node's information)
node = asCSNode(id:2000) //this is a shortcut for docman.getNode(2000)
node = asCSNode(2000)//this is a shortcut for asCSNode(id:2000)
Get a list of nodes given their IDs¶
docman.getNodesFastWith(
[2000L, 2006L], // List of nodes IDs
["GIF", "promotedCmds", "defaultLink", "size", "tableName"], // List of additional features to retrive
params, //Current request parameters
true, //'true' if Versions information shall be loaeded
true, //'true' if Node's features shall be loaeded
true //'true' if Permissions information shall be loaeded
)
docman.getNodesFast(2000L, 2006L) //this is a shortcut for docman.getNodesFastWith([2000L,2006L], [], [:], false, false, false)
docman.getNodes(2000L, 2006L) //this is a shortcut for docman.getNodesFastWith([2000L, 2006L], [], [:], true, true, true)
Get Volumes¶
The most common volumes can be easily accessed using a dedicated API featured by the docman service. If an API is not available a volume can be retrieved using a simple SQL query based on its subtype. Volumes come in handy when you want to retrieve a node by its path.
docman.getEnterpriseWS() //Enterprise Workspace
docman.getPersonalWS() //Personal Workspace
docman.getCategoryWS() //Category Workspace
docman.getContentScriptVolume() //Content Script Volume
/*
161 -- Workflow Volume
198 -- Classification Volume
211 -- Reports Volume
233 -- Database Lookups
236 -- Database Connections
274 -- Best Bets
405 -- Recycle Bin
541 -- Content Server Templates
862 -- Connected Workspaces
863 -- Workspace Types
*/
def node = docman.getNodeFast(sql.runSQLFast("""Select "DataID"
FROM DTree
Where SubType = 161""", false, false, 0
).rows[0].DataID)
Get Nodes By Path¶
def ews = docman.getEnterpriseWS()
node = docman.getNodeByPath(ews, "Training:Folder")
node = docman.getNodeByPath( "Training:Folder") //this is a shortcut for docman.getNodeByPath(docman.getEnterpriseWS(), "Training:Folder")
node = asCSNode(path:"Training:Folder")//this is a shortcut for docman.getNodeByPath("Training:Folder")
Performances-tip: Use the variable to avoid reloading the same information
In order to optimize performances, you should always assign information you know is not going to change (during your script execution) to Content Script variables so to avoid to reload them everytime they are accessed.
def ews = docman.getEnterpriseWS()
node = docman.getNodeByPath(ews, "Training:Folder")
node = docman.getNodeByPath(ews, "An:Other:Path")
node = docman.getNodeByPath( docman.getEnterpriseWS(), "Training:Folder")
node = docman.getNodeByPath( docman.getEnterpriseWS(), "An:Other:Path")
Users and Groups¶
Getting Content Server Users and Groups¶
Content Server Users and Groups are managed by the users service in the Content Script. users service operates with CSMember, CSUser and CSGroup classes. CSUser and CSGroup are the classes that are providing API to work with the Content Server Users and Groups correspondingly. CSMember is an abstract class for for CSUser and CSGroup objects. It is used in the API where both Users and Groups classes can be passed as a parameter or return as a method return value. users service provides set of methods to retrieve User or a Group:
- get current user (user who is actually executing Content Script)
- get user/group by id
- get group by name
- get user by login name
- list group members
- etc..
Get current User¶
def user = users.current // Will return CSUser object of the user that is executing the script
Get by member ID¶
CSMember member
// Pass User or Group by ID. Method will return CSUser or CSGroup class objects
//Pass ID of the Content Server User
member = users.getMemberById(1000)
out << member instanceof CSUserImpl // will display true
//Pass ID of the Content Server User
member = users.getMemberById(1001)
out << ( member instanceof CSGroupImpl ) // will return true
//Get User by ID
member = users.getUserById(1000) // will return CSUser class object
//Get group by ID
member = users.getGroupById(1001) // will return CSGroup class object
Get member by the name¶
CSMember member
//Get Member using User Login Name
member = users.getMemberByLoginName("Admin") // Will return CSUser class object
//Get Member using Group Name
member = users.getMemberByLoginName("DefaultGroup") // Will return CSGroup class object
//Get User by UserName
member = users.getUserByLoginName("Admin")
//Get Group by Name
member = users.getGroupByName("DefaultGroup")
Get members by ID¶
def members
//Get by IDs
members = users.getMembersByID(1000,1001)
//members[0] - is object of CSUser class
//members[1] - is object of CSGroup class
Permissions¶
Getting Content Server Node Permissions¶
Content Script docman service allows script developers to perform operations with the Content Server permissions model. To get get node permissions:
CSNode node = asCSNode(33561)
//Node permissions can be retrieved either
//calling CSNode getRigths() method
CSNodeRights nodeRights = node.getRights()
//or by calling docman method and passing node as an attribute
nodeRights = docman.getRights(node)
Content Server permissions model is represented as two classes CSNodeRights and CSNodeRight. CSNodeRights class contains all the permissions of the node. It's fields correspond to Content Server node permission type. ownerRight - Owner Permissions ownerGroupRight - Owner Group Permissions publicRight - Public Access Permissions ACLRights - list of Assigned permissions Every permission is an CSNodeRight object, with following fields: rightID - ID of the User/Group to whom this Right is assigned permissions - list of permissions set. Following options are possible:
1 |
|
To get node permissions:
//To get Owner Permissions
out << nodeRights.ownerRight.permissions
//To get Assignemt Permissions Users with their permissions
def assignedAccessUsers = [:]
nodeRights.ACLRights.each{ right ->
def currUser = users.getMemberById(right.rightID);
assignedAccessUsers[currUser.name] = right.permissions
}
out << assignedAccessUsers
There are set of methods to check if current user has special permissions against the node. Methods to check permission are implemented for CSNode and they are prefixed with "has" and than following permissions description:
- hasAddItemPermission()
- hasDeletePermission()
- hasDeleteVersionsPermission()
- hasEditAttributesPermission()
- hasEditPermissionsPermission()
- hasModifyPermission()
- hasReservePermission()
- hasSeeContentsPermission()
- hasSeePermission()
Sample validation:
CSNode node = asCSNode(33561)
out << node.hasDeletePermission() //will return TRUE if current user has Delete pemissions on a node
Categories¶
Getting Node Categories¶
Content Script docman service allows to performs full set of actions related to Content Server categories. Below you will find samples how to get Category definition and get Content Server node categories along with its attribute values.
def category = docman.getCategory(self.parent, "User Info") // Object of type CSCategory
def attributesMap = category.getAttributes() // Get map with Category Attributes
def firstNameAttr = category.getAttribute(attributesMap[2 as Long]) // get definition of the attribute with ID 2 CSCategoryAttribute
out << "Attribute ${firstNameAttr.getDisplayName()} has default value set to: ${firstNameAttr.values()}" // get default value for the attribue
Get value of the category attributes applied to a node:
def node = docman.getNodeByName(self.parent, "Folder With Categoty")
//Get Attribute value
def attrValue = node."User Info"."First Name" as String
out << "The current value of First Name is now ${attrValue} <br/>"
//get first attribute value
attrValue = node."User Info".Phone
out << "Get first Phone attribute value ${attrValue} <br/>"
//get all attribute values
attrValue = node."User Info".Phone as List
out << "Get all Phone attribute values ${attrValue} <br/>"
You can always export the category as a map, and later on update it from the very same map:
out << node."User Info" as Map
Classification¶
Manipulation with a node Classifications in Content Script is performed by the classification service. This sections describes how to get classifications applied to a node.
First of all if you need to check if node is classifiable:
def node = docman.getNodeByName( self.parent, "Test Folder")
//Check if Classification can be applied to the node
out << "Classification can be applied to a node: ${classification.isClassifiable(node)}"
out << "<br>"
//List classifialbe subtypes
out << "Classification can be applied to following node subtypes:"
out << "<br>"
out << classification.listClassifiebleSubTypes()
To get classifications:
def node = docman.getNodeByName( self.parent, "Test Folder")
// get node classifications
def classifications = classification.getClassifications(node)
//Will return list of classifications applied to a node
out << classifications.collect { it.name }
Executing SQL queries¶
Content Script API allows execution of SQL statements against Content Server database, without the need for creatomg a LiveReport object. sql service has a set of methods allowing developer to run SQL queries.
Not all DBMS are equal
Please keep in mind DBMS server SQL specific syntax of the queries used. Adapt provided queries to the DBMS server type in your environment.
Execute a simple SQL query¶
out << sql.runSQL("""select * from DTree where %1 and ParentID = %2 and ModifyDate > %3""", //SQL Code to be executed
true, // true if the query must be executed using a cursor
true, // true if the query must be wrapped in a transaction (required administrative privilagies)
10, // numer of records to be returned
// Below the list of optional parameters
"#FilterObject:0", // Parameters can be a LiveReport query template expression
2000, // Integers
1.year.ago).rows // Dates
// Strings
The above query is executed with three parameters, specified as %N in the SQL statement.
SQL execution methods are returning CSReportResult class object. To get query executing result rows feature should be used, as in the example above.
Another option to run SQL queis utilization of the sql.runSQLFast()
methods. Syntax for "Fast" methods is the same. These methods are faster implementation of the SQL execution script, but the compromise is that they are not ThreadSafe (i.e. not to be used in multi-threaded scripts).
Execute a SQL query with pagination¶
In some cases it is required to implement queries that return paginated data, e.g. for browsing pages. sql exposes a set of methods that allow developers to easily build such queries
The example below provides an overview of the usage of sql.runPaginatedSql()
API:
def sqlProjections = "DataID, Name"
def fromClause = "DTree dt"
def whereClause = "SubType = 0"
def pageSize = 5
def transaction = true
def runPaginatedQuery = { firstRow ->
def sqlResult = sql.runPaginatedSql(sqlProjections, fromClause, whereClause, firstRow, pageSize, "dt", "DataID", "ASC", transaction)
out << "<br>"
out << "Start row ${firstRow}"
sqlResult.rows.each { row ->
out << "<br>"
out << "Folder Name: ${row.name}. Name: ${row.dataid}"
}
}
runPaginatedQuery(1)
runPaginatedQuery(6)
Working with Forms¶
Content Server Forms and Form Templates objects can be manipulated with Content Script through the forms service API.
The most important Service API Objects returned by the aformentioned service are: CSForm, CSFormTemplate and Form
While CSForm is used to manipulate the Content Server Forms objects (e.g. changing name, applying categories and classifications, changing permissions etc...) the Form type is used to represent the data submitted (record) through the form.
Objects used in this paragraph's examples
The examples presented in this paragraph are all making use of a Form Object named HowTo Form associated to a FormTemplate object named HowTo having the following structure.
The FormTemplate object has been configured to be associated to an SQL Table named Z_HowTo.
At the time of configuration Content Server produced the following SQL DDL instructions:
create table Z_HowTo
(
VolumeID bigint not null,
DataID bigint not null,
VersionNum bigint not null,
Seq bigint null,
RowSeqNum int default 1 not null,
IterationNum int default 1 not null,
Field nvarchar(255) null,
Other_Field nvarchar(255) null
)
/
create index Z_HowTo_Index1
on Z_HowTo ( VolumeID, DataID, VersionNum, Seq )
/
create table Z_HowToSet
(
VolumeID bigint not null,
DataID bigint not null,
VersionNum bigint not null,
Seq bigint null,
SubSeq int null,
RowSeqNum int default 1 not null,
IterationNum int default 1 not null,
Field_In_Set nvarchar(255) null
)
/
create index Z_HowToSet_Index1
on Z_HowToSet ( VolumeID, DataID, VersionNum, Seq )
/
The Form object uses, as a submission mechanism, the SQL Storage option, while no revision mechanism has been associated to it.
Retrive submitted data¶
To get the Content Server Form associated submitted data you can leverage the listFormData* APIs, these APIs accept an optional filters parameter, which can be used only for Forms having SQL Table as associated submission mechanism. Filters are Maps having as keys the names of the tables you want to filter data from and as values a valid SQL where clause:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
|
def formNode = docman.getNodeByName(self.parent, "User Info Form") //returns a CSFormImpl node
def submittedData = formNode.listFormData()
In the script above formNode in CSForm object type that has API implemented to work with Content Server Forms. submittedData is a list of Form
object types that corresponds to certain record of the submitted form data.
To access fields of the form:
//List sumbitted data
//Access Form fields
submittedData.each {form ->
out << "User ${form.firstName[0]} ${form.lastName as String}. Age ${form.age as String}"
out << "<br>"
}
In the example above following form attributes are accessed:
Field Name | Normalized |
---|---|
First Name | firstName |
Last Name | lastName |
Age | age |
In scripts, form field values can be accessed using the following notation form.normalizedname.value
where normalization is performed by the Content Suite Framework.
1 2 3 4 5 6 7 8 9 10 11 |
|
Also it is possible to represent Form attributed values as a Map. This allows easy access to the form data:
out << "List Form data as a Map <br>"
//List all form Records as a Map
submittedData.each {form ->
out << "<br>"
out << "${forms.formToMap(form)}"
}
Reverse logic is kept as well, meaning Form data cat be set from a Map utilizing forms.MapToForm(Map map, Form form)