NAV Navbar
json

Introduction

The Hansoft web service provides access to a subset of data from the Hansoft server and operations via a WebSocket connection using the DDP protocol.

The following information can help you understand how the web service works and provides detailed information and examples.

For additional help, contact support@hansoft.com.

Configuration

Config file structure

{
    "ListenAddress": <Hostname or IP address to listen for incoming connections on>,
    "ListenPort": <Port number to listen for incoming connections on>,
    "FastCGIListenAddress": <Hostname or IP address to listen for incoming FastCGI connections on>,
    "FastCGIListenPort": <Port number to listen for incoming FastCGI connections on>,
    "HansoftHost": <Hostname or IP address of the Hansoft server to connect to>,
    "HansoftPort": <Port number of the Hansoft server to connect to>,
    "HansoftDatabase": <The name of the database to expose via the web service>,
    "HansoftUser": <Username of a valid SDK user on the Hansoft server to use>,
    "HansoftPassword": <Password of the specified SDK user>,
    "HansoftRetryTimer": <Retry timeout in seconds if the SDK connection fails>,
    "HansoftAuthenticationTimer": <Timeout in seconds for authentication requests>,
    "VersionControlLocalRoot": <Local path to the location to sync version control files to>,
    "AuthTokenTimeoutMinutes": <Number of minutes auth tokens are valid for>,
    "AccessTokenTimeoutMinutes": <Number of minutes access tokens are valid for>,
    "SharedSecret": <Secret key phrase used to generate key for signing tokens>,
    "IntegrationsDDPAuthenticationToken": <Secret key used to authenticate integrations>, // Required iff using WebService integrations.
    "UploadMaxSizeBytes": <Maximum size of uploaded files allowed, in bytes>,
    "UploadLocalRoot": <Local path to a location where tempoary uploaded files can be stored>    
}

The web service is configured using a JSON configuration file named HansoftWebServiceConfig.json. This file is read from the WebService startup directory.

In the config file, you can configure how the web service listens for incoming web sockets connections and the Hansoft server and database it should connect to.

Example config file:

{
    "ListenAddress": "localhost",
    "ListenPort": 8086,
    "FastCGIListenAddress": "localhost",
    "FastCGIListenPort": 8087,
    "HansoftHost": "localhost",
    "HansoftPort": 50256,
    "HansoftDatabase": "Test1",
    "HansoftUser": "WebService",
    "HansoftPassword": "hpmsdk",
    "HansoftRetryTimer": 10.0,
    "HansoftAuthenticationTimer": 20.0,
    "VersionControlLocalRoot": "/var/hpmwebservice/versioncontrol/",
    "AuthTokenTimeoutMinutes": 30,
    "AccessTokenTimeoutMinutes": 30,
    "SharedSecret": "SECRETSECRET",
    "UploadLocalRoot": "/var/hpmwebservice/uploadtemp/"
}

Operation

The web service connects and authorizes to the Hansoft server specified in the config file.

A log file named HansoftWebService.log is located in the Log directory in the WebService startup directory. It a good source of information for troubleshooting if issues occur with the web service. When the web service restarts, the existing log file is renamed with the current timestamp and a new log file is created.

After the web service connects and authorizes with the Hansoft server, it starts listening for incoming WebSocket connections on the specified address and port.

Note: The web service does not implement HTTPS for incoming WebSocket connections. The web service should be behind a web server that provides HTTPS connections for general access and forwards data to the web service. In a production environment, the nginx web server performs well. In development environments, a simple node.js application can be used.

Usage

The web service exposes access to a limited set of data and tasks via the DDP protocol over a WebSocket connection.

You should be familiar with WebSockets and the DDP protocol if you are developing applications that use the web service.

When accessing the web service from a JavaScript-based application (either in a browser or via node.js), we recommend using a DDP client library such as ddp.js (https://github.com/mondora/ddp.js/).

If you are familiar with REST-based web APIs, make sure you understand the key differences and advantages offered by the DDP & WebSockets API used by the web service:

DDP Compatibility

The web service follows the DDP protocol described in https://github.com/meteor/meteor/blob/devel/packages/ddp/DDP.md with one exception:

DDP removed messages are used to remove documents from a collection. If a removed message is received without an id field, the entire collection specified in the collection field should be removed from the client.

The web service expects to receive and sends one DDP message per text payload WebSocket packet. This is not specified in the DDP specification, but is a common requirement of third-party DDP libraries.

Connecting & Authentication

{
    "msg": "method",
    "method": "authenticate",
    "params": [ <UsernameString>, <PasswordString> ],
    "id": <ClientSpecificMethodID>
}

Connections to the web service move through a number of states during normal operation:

When in the Connected state, the client should start the authorization process by issuing an authenticate method call.

Receiving this method call by the web service transitions the connection to the Authorising state. While in this state, no additonal operations are allowed by the client.

The web service then attempts to authenticate the user against the Hansoft server. When authentication completes (either success or failure), the web service sends a result message to the client.

If authentication is successful, the web service responds with:

{
    "msg": "result",
    "id": <ClientSpecificMethodID>,
    "result": {
        "success": true,
        "authResult": 0,
        "authToken": <AuthTokenString>,
        "authTokenTimeoutSeconds": <AuthTokenTimeoutInSeconds>
        "authResourceID": <AuthenticatedResourceID>
    }
}

The connection transitions to the Authorised state.

If authentication fails, the web service responds with:

{
    "msg": "result",
    "id": <ClientSpecificMethodID>,
    "result": {
        "success": false,
        "authResult" <1 | 2 | 3 | 4 | 5 | 6 | 7>
    },
    "error": {
        "error": <Brief Description String>
        "reason": // OPTIONAL
        "message": // OPTIONAL
    }
}

The connection transitions back to the Connected state. The client can attempt to authorize again.

When authentication fails, the authResult field in the result data is one of the following integers:

1   Invalid Credentials ( Username or password was invalid )
2   Time Out ( Authentication took too long )
3   Error ( An unknown error occured, the web service log should be consulted )
4   Invalid Resource Type ( User type is not allowed )
5   MustChangePasswordNextLogon ( User must change password next logon )
6   PasswordDisabled ( User cannot login using Hansoft password )
7   InactiveAccount ( Account has been inactivated )

Upon a successful authorization with a username and password an authorization token will be returned in the response (in the authToken field). This authorization token is a time limited token ( with a lifetime in seconds specified in the authTokenTimeoutSeconds field of the authenticate result ) that that can be used in place of a username and password when authorizing again:

{
    "msg": "method",
    "method": "authenticate",
    "params": [ <AuthToken> ],
    "id": <ClientSpecificMethodID>
}

This allows for applications to reconnect to the web service without requesting credentials from a user if the connection is dropped. Note that a connection authorized via an authorization token behaves identically to a connection authorized using a username and password - no state is preserved from the login that generated the authorization token.

The amount of time an authorization token is valid for is set in the web service config file using the AuthTokenTimeoutMinutes parameter.

If you want to renew an authentication token you can do so via the renew method call, which can be made once the connection is in the Authorised state.

{
    "msg": "method",
    "method": "renew",
    "params": [],
    "id": "ClientSpecifiedMethodID"
}

Renewal will never fail and the result message will include the new authToken and the authToken timeout in seconds.

{
    "msg": "result",
    "id": <ClientSpecifiedMethodIDString>,
    "result": {
        "success": true,
        "authToken": <NewAuthToken>,
        "authTokenTimeoutSeconds": <AuthTokenTimeoutInSeconds>
    }
}

When a connection is first made it is in the Accepted state. The client should now complete a DDP handshake with the web service. Upon successful completion of this handshake the connection transitions to the Connected state. If the handshake was unsuccessful the connection transitions to the Failed state and the client should disconnect.

Once in the Authorised state the client is free to issue any commands to the web service that they are permitted to do.

Subscriptions

{
    "msg": "sub",
    "id": <ClientChosenSubIDString>,
    "name": <SubscriptionNameString>,
    "params": <ArrayOfParams> // OPTIONAL
}
{
    "msg": "nosub",
    "id": <ClientChosenSubIDString>,
    "error": <ErrorObject> // OPTIONAL
}
{
    "msg": "ready",
    "subs": [ <ClientChosenSubIDString> ]
}

Subscriptions are made using a standard DDP subscribe message.

If the subscription attempt failed a DDP nosub message will be returned.

If the subscription attempt was successful the client will receive updates (added, changed, removed DDP messages) for the current state of data covered by the subscription followed by a DDP ready message.

The client will then receive updates to data covered by the subscription as the web service becomes aware of them.

Subscription: MyWork

The MyWork subscription subscribes to the tasks currently assigned to the user. See the Collection: MyWork section for more information.

This subscription does not accept any parameters.

Subscription: Tasks

The Tasks subscription subscribes to a single task in a project, as well as all related child documents - for example, assigned users, project columns and milestones.

This subscription requires the Task ID as a parameter.

Subscription: ProjectResources

The ProjectResources subscription covers one collection for the project specified. These collections are named ProjectResources_<ProjectID> and contain one document for each resource or resource group in the project. See the Collection: ProjectResources_ section for more information.

This subscription requires the Project ID as a parameter. You can optionally specify a Sprint ID to limit to resources assigned to that sprint.

Subscription: ProjectMilestones

The ProjectMilestones subscription covers one collection for the project specified. These collections will be named ProjectMilestones_<ProjectID> and contain one document for each milestone in the project. See Collection: ProjectMilestones_<ProjectID> below.

This subscription requires the Project ID as a parameter.

Subscription: TaskComments

{
    "msg": "sub",
    "id": <ClientChosenSubIDString>,
    "name": "TaskComments",
    "params": [ <TaskIDString> ]
}

A TaskComments subscription covers one collection named TaskComments_<TaskID> containing all the comments for the task specified. The ID of the task to subscribe to comments for is specified in the subscription parameters as the first and only argument. More than one TaskComments subscriptions can be created at any one time.

See Collection: TaskComments_<TaskID> below.

Subscription: Dashboards

The Dashboards subscription subscribes to the dashboards shared to the user. This subscription has no parameters.

Subscription: ChartResultSet

The ChartResultSet subscription subscribes to the latest result set for a chart. This subscription requires the ChartID as a parameter.

Subscription: ServerConnectionState

ServerConnectionState is one collection that keeps track of the Hansoft server connection state. See Collection: ServerConnectionState.

Collections

Collection: MyWork

{
    "MyWork": {
        <TaskIDKey>: {
            "$ID": <TaskIDString>,
            "$ProjectID": <ProjectIDString>,
            "URL": <Hansoft URL>,
            "CommittedToProjectID": <CommittedToProjectIDString> // OPTIONAL. If this task is committed to the planning view, this field is set to the project ID of the main project.
            "LinkedToPipeline": <Bool> // Set to true if task was created though a pipeline
            "IsDelegatedTo": <IsDelegatedToBool> // true if task was delegated to MyWork user, false otherwise.
            <Task Fields>
        }
    }
}

This collection contains one document for each task currently assigned to the user.

The key of each document is the string representation of the task database ID.

Each field of a task document represents a task field in Hansoft. The key of each field is referred to as a task field name. These names are strings that are used to identify a task field and make it easier for developers to locate the task fields they are interested in. They are not designed to be displayed to end users and as such are never localized. For custom columns the field name used is of the format "CC_<ColumnHash>". The value of each field in a task document represents the value of that task field in Hansoft.

To interpret the value of a task field and find an end user displayable name of a field the ProjectMeta_<ProjectID> collection corresponding to the project the task is a member of should be consulted.

Each task document has two fields that are always present: $ID and ProjectID, $ID holds the tasks database ID as a string (the same value that is used as the key for a task document) and ProjectID holds a string of the ID of the project the task is a member of.

For example, assuming you have subscribed to MyWork:

Collection: ProjectMeta_<ProjectID>

{
    "ProjectMeta_<ProjectID>": {
        "$Project": {
            "Name": <ProjectNameString>,
            "SortName": <ProjectSortNameString>,
            "Type": <"Planning" or "Backlog" or "QA">,
            "Backlog": <BacklogProjectIDString>, // Only for non-backlog projects
            "QA": <QAProjectIDString>, // Only for non-qa projects
            "Planning": <PlanningProjectIDString> // Only for non-planning projects
            "Settings": [
                {
                    "EverybodyCanComment": <Bool> // Set to true if everybody is allowed to comment, false otherwise
                    "CanChangePriorityInToDo": <Bool> // Set to true if everybody can change priority in todo, false otherwise
                }
            ]
        }
    }
}
{
    "ProjectMeta_<ProjectID>": {
        "$Project": <ProjectInfo>,
        "WorkRemaining": {
            "DisplayName": "Work Remaining",
            "ReadOnly": false,
            "Type": "Hours"
            "MaxDecimals": 3
            "MinValue": 0
            "MaxValue": 10000
        }
    }
}

A ProjectMeta collections holds information on the project itself in the document with the special key $Project, in the shown format.

Each remaining document in a ProjectMeta collection will represent a task field that tasks in that project can have. These documents are referred to as field meta documents. The document ids will be the task field name and the contents of the document will specify the display name of the field ( in the DisplayName field, for user display ), the read only status of the field ( in the ReadOnly field), the type of the field ( in the Type field, for interpretation ) and optionally additional information depending on the type. AccessByMainManagersAndDelegatedUsers is available on custom fields and if set to true, data in the task field can only be edited by main managers and users that have delegation rights.

The Type field is a JSON string and valid values of it and any additional fields that may be present are described in the Field Types section of this document.

Collection: ProjectResources_<ProjectID>

{
    "ProjectResources_<ProjectID>": {
        <ResourceIDString>: {
            "Name": <ResourceNameString>,
            "SortName": <ResourceSortNameString>, // OPTIONAL
            "Type": <ResourceTypeInteger>
        }
    }
}

The Type field will have a numeric value that will be one of:

1   Resource is a normal user
2   Resource is a SDK user
3   Resource is a ghost user 
4   Resource is a QA user

For example:

{
    "ProjectResources_1023": {
        "84": {
            "Name": "Dougal Langley",
            "Type": 1
        },
        "85": {
            "Name": "Percy Woodrow",
            "Type": 1
        },
        "85": {
            "Name": "SDKUser",
            "Type": 2
        }
    }
}

A ProjectResources collection holds one document for each resource or resource group that is a member of the specified project. Note that a ProjectResources collection only exists for planning project IDs, not for backlog or QA project IDs. The ProjectMeta_<ProjectID> collection for a project can be used to find the planning project ID for a backlog or QA project.

Each document has a string representation of a resource ID as its key. Its contents follows the shown format

Collection: ProjectSprints_<ProjectID>

{
    "ProjectSprints_<ProjectID>": {
        <SprintIDString>: {
            "Name": <SprintNameString>,
            "Start": <SprintStartDateTime>, 
            "End": <SprintEndDateTime>,
            "AllowMembersToUpdate": <AllowMembersToUpdateBool>
            "Resources": [ 
                {
                    "ID": <ResourceIDNumber> // See ProjectResources_ collection
                }
            ],
        }
    }
}

The Start and End fields will have a DateTime value that will be an EJSON date. The AllowMembersToUpdate field will be set to true if all sprint members are allowed to insert, edit and delete items in the sprint and if set to false only main managers and delegated users can update items.

For example:

{
    "ProjectSprints_2046": {
        "102": {
            "Name": "Sprint 1 2018-10-10 - 2018-10-23",
            "Start": {"$date": 1539129600000},
            "End": {"$date": 1540252800000},
            "AllowMembersToUpdate": true,
            "Resources": [ {"ID": 12}, {"ID": 14} ]
        },
        "204": {
            "Name": "Sprint 2 2018-10-24 - 2018-11-06",
            "Start": {"$date": 1540339200000},
            "End": {"$date": 1541462400000},
            "AllowMembersToUpdate": true,
            "Resources": [ {"ID": 12}, {"ID": 14} ]
        },
        "308": {
            "Name": "Sprint 3 2018-11-07 - 2018-11-20",
            "Start": {"$date": 1541548800000},
            "End": {"$date": 1542672000000},
            "AllowMembersToUpdate": false,
            "Resources": [ {"ID": 12}, {"ID": 14} ]
        }
    }
}

A ProjectSprints collection holds one document for each sprint in the specified project. Note that a ProjectSprints collection only exists for planning project IDs, not for backlog or QA project IDs.

Each document has a string representation of a sprint ID as its key. Its contents follows the shown format

Collection: ProjectMilestones_<ProjectID>

{
    "ProjectMilestones_<ProjectID>": {
        <MilestoneIDString>: {
            "Name": <MilestoneNameString>,
            "Date": <MilestoneDateTime>, 
        }
    }
}

The Date field is a DateTime value that will be an EJSON date.

For example:

{
    "ProjectSprints_2046": {
        "402": {
            "Name": "Release 1",
            "Date": {"$date": 1539129600000},
        },
        "404": {
            "Name": "Release 2",
            "Date": {"$date": 1540339200000},
        }
    }
}

A ProjectMilestones collection holds one document for each milestone in the specified project. Note that a ProjectMilestones collection only exists for planning project IDs, not for backlog or QA project IDs.

Each document has a string representation of a milestone ID as its key. Its contents follows the shown format

Collection: ProjectWorkflows_<ProjectID>

{
    "ProjectWorkflows_<ProjectID>": {
        <WorkflowIDString>: {
            "Name": <WorkflowNameString>,
            "HideItemStatus": <HideItemStatusBool> // Set to true if item status should be hidden when item status and workflow status are displayed as a pair
            "WorkflowObjects": [
                {
                    "ID": <WorkflowStatusIDNumber>,
                    "Name": <WorkflowStatusNameString>,
                    "Icon": <WorkflowStatusIconNumber>, // OPTIONAL
                    "CannotSetNotAssigned": <CannotSetNotAssignedWhenAssigningToSomeoneInThisStatusBool>, // OPTIONAL
                    "HideInToDoList": <DoNotShowInToDoListWhenItemIsInThisStatusBool>, // OPTIONAL
                    "ConnectedStatuses": [ // OPTIONAL
                        {
                            "ConnectedToID": <ConnectedWorkflowStatusIDNumber>
                                "RequiredFields": [ // OPTIONAL mandatory data fields
                                    {
                                         "FieldID": <TaskFieldIDNameString>
                                    }
                                ]
                        }
                    ],
                    "StatusToWorkflowStatuses": [ // OPTIONAL when status changes to FromID go to workflow status ToID
                        {
                            "StatusID": <StatusIDNumber>,
                            "StatusName": <StatusNameString>,
                            "WorkflowStatusID": <WorkflowStatusIDNumber>,
                            "WorkflowStatusName": <WorkflowStatusNameString>
                        }
                    ]
                }
            ]
        }
    }
}

For example:

{
    "ProjectWorkflows_2046": {
        "0": {
            "Name": "Bug workflow",
            "HideItemStatus": false,
            "WorkflowObjects": [
                {
                    "ID": 2,
                    "Name": "New",
                    "Icon": 3,
                    "CannotSetNotAssigned": false,
                    "HideInToDoList": false,
                    "ConnectedStatuses": [
                        {
                            "ConnectedToID": 3,
                            "RequiredFields": [
                                {
                                    "FieldID": "BugPriority"
                                }
                            ]
                        }
                    ],
                    "StatusToWorkflowStatuses": [
                        {
                            "StatusID": 0,
                            "StatusName": "Completed",
                            "WorkflowStatusID": 9,
                            "WorkflowStatusName": "Resolved"
                        }
                    ]
                },
                {
                    "ID": 3,
                    "Name": "Assigned",
                    "Icon": 7,
                    "CannotSetNotAssigned": true,
                    "ConnectedStatuses": [
                        {
                            "ConnectedToID": 5
                        }
                    ],
                    "StatusToWorkflowStatuses": [
                        {
                            "StatusID": 0,
                            "StatusName": "Completed",
                            "WorkflowStatusID": 9,
                            "WorkflowStatusName": "Resolved"
                        }
                    ]
                }
            ]
        }
    }
}

A ProjectWorkflows collection holds one document for each workflow in the specified project. Note that a ProjectWorkflows collection only exists for planning project IDs, not for backlog or QA project IDs.

Each document has a string representation of a workflow ID as its key. Its contents follows the shown format

Collection: TaskComments_<TaskID>

{
    "PostedBy": <NameOfResourceString>,
    "PostedByID": <ResourceIDString>,
    "PostedAt": < EJSON date >,
    "ParentID: <ParentPostIDString>,
    "Flags": <FlagsNumber>,
    "Text": <CommentTextInHansoftFormat>
}

The Flags field is a bitfield that may contain the following flags:

Bit     Value       Meaning
0       1           The comment is posted and should be visible.
1       2           The comment is currently being edited by a resource.
"TaskComments_<TaskID>": {
    "12": {
        "PostedBy": "Geralt Barnacle",
        "PostedByID": "120",
        "PostedAt": {"$date": 1519051982000},
        "ParentID": "-1",
        "Text": "I tried this today with no luck. I will try again tomorrow."
    }
}

A TaskComments collection holds all comments for one task. Each comment is stored as a document with the post ID of the comment as a string as the key.

Each comment document has the following format shown here.

A parent ID of -1 indicates that the comment is not a reply.

Consult the Hansoft documentation for information on the Hansoft comment text format.

Collection: ResourceGroups

{
    "ResourceGroups": {
        <ResourceGroupIDString>: {
            "Name": <ResourceGroupNameString>,
            "SortName": <ResourceGroupSortNameString> // OPTIONAL
        }
    }
}

A ResourceGroups collection holds one document for each resource group in the connected Hansoft database.

Each document has a string representation of a resource group ID as its key. Its contents follows the shown format

Collection: Dashboards

{
    "Dashboards": {
        <DashboardIDString>: {
            "createdBy": "Administrator",
                "createdByUserId": 1,
                "layout": "twoColumns",
                "layoutColumns": [{
                    charts: [{ id: 100, name: "ChartA", { id: 101, name: "ChartB" } }]
                    }, {
                            charts: [],
            }],
                        "name": "Dashboard A",
                        "theme": "",
        }
    }
}

A Dashboards collection holds one document for each dashboard in the connected Hansoft database. Each document has a string representation of a dashboard ID as its key.

Collection: ChartResultSets

{
    "ChartResultSets": {
        <ChartIDString>: {
                "dataLabels": "value",
                "datasets": [ ... ],
                    "dimensions": [ ... ],
                        "grouping": "none",
                        "labels": [ ... ],
                "legend": "visible",
            "measures": [ ... ],
                        "orientation", "horizontal",
                "theme": "",
                        "type": "bar",
        }
    }
}

A ChartResultSets collection holds one document for each chart result set subscribed to. Each document has a string representation of a chart ID as its key. The contents vary depending on the chart type. The format is broadly compatible with chart.js.

Collection: ServerConnectionState

{
    "ServerConnectionState": {
        "": {
            active": <ConnectedBool>,
        }
    }
}

A ServerConnectionState collection holds one pseudo document for the Hansoft server connection state.

Field Types

This section describes the JSON value types for each task field type. These JSON value types are what you can expect for find in a MyWork task document for a field of the given type. These JSON value types are also, unless otherwise specified, what you should provide the method SetTaskField with when setting a field of the given type.

Field Type: String

The value is a JSON string and is expected to be displayed on one line. No other meta document fields are present.

Field Type: StringList

The value is a JSON array of strings. No other meta document fields are present.

Field Type: MultiLine

The value is a JSON string and is expected to be displayed as multiple lines of text. No other field meta document fields are present.

The value is a JSON string that is a URL and is expected to be displayed as a clickable link. No other meta document fields are present.

Field Type: Integer

"IntegerField": {
    "DisplayName": "Integer Field",
    "ReadOnly": false,
    "AccessByMainManagersAndDelegatedUsers": false,
    "Type": "Integer",
    "Unit": "days"
    "MinValue": -2147483648
    "MaxValue": 2147483647
}

The value is a JSON number, and always a 32 bit signed integer, limits in MinValue and MaxValue. An optional field named Unit may be present that contains a JSON string of the units this field value is in.

The Unit field, if present, is only for display purposes. Hansoft or the web service assign no special meaning to the value of the Unit field.

Field Type: Float

"FloatField": {
    "DisplayName": "Float Field",
    "ReadOnly": false,
    "AccessByMainManagersAndDelegatedUsers": false,
    "Type": "Float",
    "Unit": "kg"
    "MaxDecimals": 3
    "MinValue": -1000000000
    "MaxValue": 1000000000
}

The value is a JSON number and always a 32 bit floating point value, limits in MinValue and MaxValue and max number of decimals in MaxDecimals. An optional field named Unit may be present that contains a JSON string of the units this field value is in.

The Unit field, if present, is only for display purposes. Hansoft or the web service assign no special meaning to the value of the Unit field.

Field Type: DateTime

The value is an EJSON Date.

Field Type: DateTimeTime

The value is an EJSON Date.

Field Type: Workflow

The value is a JSON number, and always a 32 bit signed integer. This number corresponds to a workflow document in the ProjectWorkflows collection for the container project of the task.

Field Type: WorkflowStatus

The value is a JSON number, and always a 32 bit signed integer. This number corresponds to a workflow object ID in the workflow document for the workflow set on the task in the ProjectWorkflows collection for the container project of the task.

Field Type: Enum


{
    "MyWork": {
        "86": {
            "$ID": "86",
            "$ProjectID": "1021",
            "URL": "hansoft://mymachine;My_Database;59152447/Task/86?ID=2",
            "Status": 1,
            <Other Task Fields>
        }
    },
    "ProjectMeta_1021": {
        "Status": {
            "DisplayName": "Completion Status",
            "ReadOnly": false,
            "Type": "Enum",
            "Enum": [
                        [ 0, "Not Done" ]
                    ,   [ 1, "In Progress" ]
                    ,   [ 2, "Done" ]
            ]
        },
        <Other Field Meta Data for Project 1021>
    }
}

The value is a JSON number that represents a choice ID from a predetermined list of choices. The field meta document will have a field named Enum that is a JSON array whose elements are a choice ID ( a JSON number) and a choice name (a JSON string) stored in a two element array.

Field Type: MultiEnum

{
    "MyWork": {
        "86": {
            "$ID": "86",
            "$ProjectID": "1021",
            "URL": "hansoft://mymachine;My_Database;59152447/Task/86?ID=2",
            "MultipleChoice": {
                "Value": [ 0, 2 ],
            },
            <Other Task Fields>
        }
    },
    "ProjectMeta_1021": {
        "MultipleChoice": {
            "DisplayName": "Multiple Choice",
            "ReadOnly": false,
            "AccessByMainManagersAndDelegatedUsers": false,
            "Type": "MultiEnum",
            "Enum": [
                    [ 0, "Apples" ]
                ,   [ 1, "Oranges" ]
                ,   [ 2, "Pears" ]
            ]
        },
        <Other Field Meta Data for Project 1021>
    }
}

The value is a JSON array of JSON numbers, each of which represent a choice ID from a predetermined list of choices. The field meta document will have a field named Enum that is a JSON array whose elements are a choice ID ( a JSON number) and a choice name (a JSON string) stored in a two element array.

Field Type: MilestoneMultiEnum

{
    "MyWork": {
        "86": {
            "$ID": "86",
            "$ProjectID": "1021",
            "URL": "hansoft://mymachine;My_Database;59152447/Task/86?ID=2",
            "LinkedToMilestone": {
                "Value": [ 0, 1 ]
            },
            <Other Task Fields>
        }
    },
    "ProjectMeta_1021": {
        "LinkedToMilestone": {
            "DisplayName": "Linked To Milestone",
            "ReadOnly": false,
            "Type": "MilestoneMultiEnum"
        },
        <Other Field Meta Data for Project 1021>
    }
}

The value is a JSON object containing a Value field that is a JSON array of numbers that each represent a milestone ID. This number corresponds to a milestone object ID in the milestone document for the milestones set on the task in the ProjectMilestones collection for the container project of the task. This is used for the Linked To Milestone / Release Tag Hansoft field.

When using the SetTaskField method to change the value of an MilestoneMultiEnum field a different format is used from the one above. In this case the value just needs to be and array of the integer choice IDs.

Field Type: Hours

The value is a JSON number that represents a ( potentially fractional ) number of hours. No other meta document fields are present.

Field Type: TimeZones

"TimeZoneField": [
    {
        "TimeZoneStart": {
          // Period 1 Start Time:
          < EJSON date >
        },
        "TimeZoneEnd": {
          // Period 1 End Time:
          < EJSON date >
        }
    },
    {
        "TimeZoneStart": {
          // Period 2 Start Time:
          < EJSON date >
        },
        "TimeZoneEnd": {
          // Period 2 End Time:
          < EJSON date >
    },
]
{
    "MyWork": {
        "86": {
            "$ID": "86",
            "$ProjectID": "1021",
            "URL": "hansoft://mymachine;My_Database;59152447/Task/86?ID=2",
            "TimeZones": [
                { "TimeZoneStart": {"$date": 1518652800000}, "TimeZoneEnd": {"$date": 1518739200000} }
            ],
            <Other Task Fields>
        }
    },
    "ProjectMeta_1021": {
        "TimeZones": {
            "DisplayName": "Time",
            "ReadOnly": true,
            "Type": "TimeZones"
        },
        <Other Field Meta Data for Project 1021>
    }
}

NOTE: This field type is used to represent blocks (zones) of time on a task. It is not regarding time zones such as GMT or UTC.

The value is a JSON array of periods of time represented as a two element array of start and end times represented in the same format as DateTimeTime fields.

Field Type: Resources

The value is a JSON array of resource entries where each resource entry is of the form:

[ <ResourceEntryTypeInteger>, <ResourceIDInteger>

1   ResourceID specifies a normal resource ID
2   ResourceID specified a resource group ID
3   The resource entry represents all project members, ResourceID is ignored.
{
    "MyWork": {
        "86": {
            "$ID": "86",
            "$ProjectID": "1021",
            "URL": "hansoft://mymachine;My_Database;59152447/Task/86?ID=2",
            "CC_123844": [
                [ 1, 23 ],
                [ 1, 28 ],
            ],
            <Other Task Fields>
        }
    },
    "ProjectMeta_1021": {
        "CC_123844": {
            "DisplayName": "Custom Resource List",
            "ReadOnly": false,
            "AccessByMainManagersAndDelegatedUsers": false,
            "Type": "Resources"
        },
        <Other Field Meta Data for Project 1021>
    }
}

where <ResourceEntryType> will specify the type of the resource and be one of the one shown.

Field Type: ResourceAllocations

The value is a JSON array of resource entries where each resource entry is of the form:

[ <ResourceIDInteger>, <AllocationPercent> ]

1   ResourceID specifies a normal resource ID
2   ResourceID specified a resource group ID
3   The resource entry represents all project members, ResourceID is ignored.
{
    "MyWork": {
        "86": {
            "$ID": "86",
            "$ProjectID": "1021",
            "URL": "hansoft://mymachine;My_Database;59152447/Task/86?ID=2",
            "ResourceAllocation": [
                [ 23, 100 ],
                [ 28, 100 ],
            ],
            <Other Task Fields>
        }
    },
    "ProjectMeta_1021": {
        "ResourceAllocation": {
            "DisplayName": "Assigned to",
            "ReadOnly": false,
            "Type": "ResourcesAllocation"
        },
        <Other Field Meta Data for Project 1021>
    }
}

where <AllocationPercent> is the allocation percent, 0-100, of the resource.

Field Type: LinkedTo

The value is a JSON array of linked to entries where each linked to entry is of the form:

[ <LinkedToIDInteger>, <LinkedToDescriptionString>, <LinkedToHansoftURLString> ]

{
    "MyWork": {
        "86": {
            "$ID": "86",
            "$ProjectID": "1021",
            "URL": "hansoft://mymachine;My_Database;59152447/Task/86?ID=2"
            "LinkedTo": [
                [ 1551, "My first task", "hansoft://mymachine;My_Database;59152447/Task/1550" ],
                [ 1553, "My second task", "hansoft://mymachine;My_Database;59152447/Task/1552" ],
            ],
            <Other Task Fields>
        }
    },
    "ProjectMeta_1021": {
        "LinkedTo": {
            "DisplayName": "Linked to item",
            "ReadOnly": false,
            "Type": "LinkedTo"
        },
        <Other Field Meta Data for Project 1021>
    }
}

Field Type: AttachedDocuments

The value consistst of two fields, a string field for a possible main image path for the task and an array field with an object file IDs and file paths to the attached documents as well as the file size in bytes. If the attachment is an image, ImageWidth and ImageHeight will be set to values greater than 0. The paths can be passed to /vc/<PathToVCFile> (described in the Version Control Access section) to download the attachments.

{
    "MyWork": {
        "86": {
            "$ID": "86",
            "$ProjectID": "1021",
            "URL": "hansoft://mymachine;My_Database;59152447/Task/86?ID=2"
            "AttachedDocuments": {
                "MainImage": "Projects/MyProject/Attachments/General_545/Arrow.png",
                "AttachedDocuments": [
                    "FileID": 130,
                    "FilePath": "Projects/MyProject/Attachments/General_545/Arrow.png",
                    "Size": 13198
                    "ImageWidth": 361,
                    "ImageHeight": 256
                ]
            },
            <Other Task Fields>
        }
    },
}

Field Type: ChangedColumns

Used when a Hansoft custom field gets a new ID, e.g. due to a name change. The value is a JSON array of custom field changes represented as a two element array of the old ID value and the new ID value. It is up to the user of the collection to update the ID.

"ChangedColumns": [
    {
        "OldID": {
          // Old custom field value
          < OldFieldIDString >
        },
        "NewID": {
          // New custom field value
          < NewFieldIDString >
        }
    },
]
{
    "MyWork": {
        "86": {
            "ChangedColumns": [
                { "OldID": "CC_2311583649", "NewID": "CC_3267738323" }
            ],
        }
    },
}

Field Type: NewID

Used in the ProjectMeta collection when a Hansoft custom field gets a new ID. It is up to the user of the collection to update the ID.

{
    "ProjectMeta_1021": {
        "CC_2311583649": {
            "NewID": "CC_3267738323",
        },
    }
}

Methods

Methods are the only way for clients to request changes to be made to the Hansoft server.

NOTE: The optional randomSeed field of DDP method calls is never used or required by the web service.

Method: SetTaskField

{
    "msg": "method",
    "method": "SetTaskField",
    "params": [ "86", "Description", "Task Two" ],
    "id": "ClientSpecifiedMethodID"
}
{
    "msg": "result",
    "id": <ClientSpecifiedMethodIDString>,
    "result": {
        "success": true,
    }
}

If a SetTaskField method call fails the web service will respond with a DDP result message of the form:

{
    "msg": "result",
    "id": <ClientSpecificMethodIDString>,
    "result": {
        "success": false,
    },
    "error": {
        "error": <ErrorString>,
        "reason": <ReasonString>, // OPTIONAL
        "message": <MessageString> // OPTIONAL
    }
}

or:

{
    "msg": "result",
    "id": <ClientSpecificMethodIDString>,
    "result": {
        "success": false,
        "RequiredFieldsMissing": <ArrayOfTaskFieldNameStrings>
    }   
}

The SetTaskField method is used to change the value of a tasks field. Any task that the user has permission to edit can be modified ( currently this is limited to tasks currently assigned to the user ). The SetTaskField method takes three parameters:

[ <TaskIDString>, <TaskFieldNameString>, <NewValue> ]

An example of a DDP method call for SetTaskField is shown here.

The type of the new value specified depends on the type of the field being set ( which can be queried from the corresponding ProjectMeta collection). Consult the Field Types section of this document for the specific JSON value format for each field type.

Once a SetTaskField method call has been made the web service will attempt to perform the change. If successful the client will receive DDP messages describing the changes the method call caused followed by a DDP result message of the form shown.

Note that setting a single task field may result in more than just that single change being made. This is true in the case of setting the WorkflowStatus column as transitioning to another workflow stage may result in the task being reassigned to a different user.

In the second form RequiredFieldsMissing contains a list of task field names that must have values set before the SetTaskField method will be allowed. This is used for WorkflowStatus fields when a workflow has been configured to require specific fields be set.

Method: TaskPostComment

{
    "msg": "method",
    "method": "TaskPostComment ",
    "params": [ "86", -1, "My comment" ],
    "id": "ClientSpecifiedMethodID"
}
{
    "msg": "result",
    "id": <ClientSpecifiedMethodIDString>,
    "result": {
        "success": true,
    }
}
{
    "msg": "result",
    "id": <ClientSpecificMethodIDString>,
    "result": {
        "success": false,
    },
    "error": {
        "error": <ErrorString>,
        "reason": <ReasonString>, // OPTIONAL
        "message": <MessageString> // OPTIONAL
    }
}

The TaskPostComment method is used to post a new comment on a task. Any task the user has permission to access can have a comment posted on. TaskPostComment takes three parameters:

[ <TaskIDString>, <ParentPostIDOrMinusOneString>, <CommentTextString> ]

An example of a DDP method call for TaskPostComment is shown here.

A successful TaskPostComment method call will result in a DDP result message with the Success result field set to true.

If the method call failed the response will have the Success result field set to false and an DDP error field will be present.

Method: TaskEditComment

{
    "msg": "method",
    "method": "TaskEditComment ",
    "params": [ "86", 12, "My updated comment" ],
    "id": "ClientSpecifiedMethodID"
}
{
    "msg": "result",
    "id": <ClientSpecifiedMethodIDString>,
    "result": {
        "success": true
    }
}
{
    "msg": "result",
    "id": <ClientSpecificMethodIDString>,
    "result": {
        "success": false,
    },
    "error": {
        "error": <ErrorString>,
        "reason": <ReasonString>, // OPTIONAL
        "message": <MessageString> // OPTIONAL
    }
}

The TaskEditComment method is used to edit a comment the user has previously made on a task. TaskEditComment takes three parameters:

[ <TaskIDString>, <PostIDString>, <CommentTextString> ]

An example of a DDP method call for TaskEditComment is shown here.

A successful TaskEditComment method call will result in a DDP result message with the Success result field set to true.

If the method call failed the response will have the Success result field set to false and an DDP error field will be present.

Method: CreateBug

{
    "msg": "method",
    "method": "CreateBug ",
    "params": [ { "ProjectID": 11389, "Fields": { "WorkRemaining": 4, "Description": "My bug", "DetailedDescription": "Hello" } } ],
    "id": "ClientSpecifiedMethodID"
}
{
    "msg": "result",
    "id": <ClientSpecifiedMethodIDString>,
    "result": {
        "success": true,
        "createdTaskId": 1,
    }
}
{
    "msg": "result",
    "id": <ClientSpecificMethodIDString>,
    "result": {
        "success": false,
    },
    "error": {
        "error": <ErrorString>,
        "reason": <ReasonString>, // OPTIONAL
        "message": <MessageString> // OPTIONAL
    }
}

The CreateBug method creates a bug in a QA project. CreateBug has one object with two arguments, a ProjectID field and a Fields field:

[ { "ProjectID":<ProjectIDString>, "Fields": { <TaskFieldNameString1>, <NewValue1>, ..., <TaskFieldNameStringN>, <NewValueN> } } ]

If no workflow and workflow status is provided, the default workflow and first workflow status of that workflow will be used.

An example of a DDP method call for CreateBug is shown here.

The type of the new value specified depends on the type of the field being set ( which can be queried from the corresponding ProjectMeta collection). Consult the Field Types section of this document for the specific JSON value format for each field type.

Once a CreateBug method call has been made the web service will attempt to create a bug in the QA project of the specified project. If successful the client will receive DDP messages describing the changes the method call caused followed by a DDP result message of the form shown.

Version Control Access

Access to files stored in the Hansoft version control system (Documents in the client) is via normal web requests rather than over the web socket. Authorization to to access version control files is controlled by access tokens. A version control access token can be acquired via the /requestaccess URL as described below. Once an access token has been acquired it must be provided when making requests to download or upload version control files. This is done by providing the acquired access token in a cookie named 'hsaccess' when making requests to /vc/<PathToVCFile> or /upload.

/requestaccess

​ This URL is used to request a version control access token that is required for all other version control URLs. To receive a version control access token you make a GET request to this URL with your authorization token stored in a cookie named 'hsauth'

/vc/<PathToVCFile>

​ This provides read access to files in version control via GET requests. For example to read the file Global/Info.txt stored in Hansoft documents you can make a HTTP GET request to https://<WebServiceProxy>/vc/Global/Info.txt.

/upload

​ This provides write access to files in version control via Multi-Part POST requests (multipart/form-data). A number of fields are expected for a request to be successful:

Once the server has processed the request it will respond with a 200 OK status code and a JSON object containing a single field results that is an array with one element for each file POSTed specifying the result of the add operation.

{
    'results': [
        { // One entry for each file POSTed
            'file': '<FilePath>',
            'result': 'succeeded' or 'alreadyExists' or 'error',
            'error': <ErrorCode>, // Only if 'result' = 'error',
            'customError': '<CustomErrorText>' // Only if 'result' = 'error'
        }
    ]
}

The 'error' field in the file result entries is a numerical code take from the Hansoft SDK:

Error Code Description
0 NewVersionOfSDKRequired - The meta data type did not exist when this SDK was created. Upgrade to a newer version of the SDK to be able to use this format.
1 Success - The operation completed successfully.
2 Other - An unspecified error occurred.
3 InternalError - An internal error occurred.
4 FileAlreadyExists - The file already exists.
5 Checksum - The file failed checksum check.
6 DiskFull - The disk is full.
7 FileDoesNotExist - The file does not exist.
8 InvalidVersion - The version specified was invalid.
9 FileAlreadyCheckedOut - The file was already checked out.
10 AccessDenied - Access to the file was denied.
11 FileDoesNotExistLocal - The file does not exist locally.
12 FileAlreadyCheckedOutByYou - The file is already checked out by you.
13 CouldNotWriteFileLocal - The file could not be written locally.
14 FileDeleted - The file is deleted.
15 FileNotDeleted - The file is not deleted
16 CheckedOutSkipped - The checkout of the file was skipped.
17 VersionDoesNotExtist - The version does not exist.
18 NoVersionsWouldRemain - No version would remain if the current was deleted.
19 FileIsAlreadyVersion - The file is already the version specified.
20 CouldNotReadFileLocal - The file could not be read locally.
21 Success_FileUnchanged - The operation completed successfully, but the file was unchanged and no operation was performed.
22 FileAreadyDeleted - The file was already deleted.

Web Server Configuration

The Hansoft web service is not designed to be made directly accessible to clients. A web server should be used in front of the web service for two main reasons:

Security: The web server can be used to provide HTTPS connections to the web service.

Functionality: Access to files stored in Hansoft's internal version control via HTTP requires the use of a compatible web server.

We recommend Nginx as a suitable web server. It's carefully crafted architecture is an ideal front end of the Hansoft web service.

An example Nginx configuration file that is configured for web socket proxying (but NOT HTTPS) and version control file access for testing is shown below.

daemon off;
pid <PIDFilePath>;
worker_processes 1;
events {
    worker_connections  4096;
}
http {
    # Websocket proxying
        map $http_upgrade $connection_upgrade {
            default upgrade;
            '' close;
        }

        upstream websocket {
            server <HPMWebServiceIPAddress>:<HPMWebServiceWSPort>;
        }

        server {
            listen 8088;
            location / {
                proxy_pass http://websocket;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection $connection_upgrade;
            }
        }

    # Version control file serving
        server {
            listen 8085;

            location /versioncontrol/ {
                include ./fastcgi.conf; #or whatever you named it
                fastcgi_pass  <HPMWebServiceIPAddress>:<HPMWebServiceFastCGIPort>;
            }

            location /vcaccess {
                internal;
                # Where the VC files are downloaded to:
                alias X:/Deploy/HPMWebService/VersionControl;
            }
        }
}