NAV Navbar
json
  • Introduction
  • Configuration
  • Operation
  • Usage
  • DDP Compatibility
  • Connecting and Authenticating
  • Subscriptions
  • Collections
  • Field Types
  • Methods
  • Version Control Access
  • Web Server Configuration
  • 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": <Hansoft database name to expose via the web service>,
        "HansoftUser": <Username for a valid SDK user on the Hansoft server>,
        "HansoftPassword": <Password for 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 authentication 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 if using WebService integrations.
        "UploadMaxSizeBytes": <Maximum size of uploaded files allowed in bytes>,
        "UploadLocalRoot": <Local path to store temporary uploaded files>    
    }
    

    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.

    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 and Authenticating

    {
        "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 occurred. See the web service log.)
    4   Invalid Resource Type (User type is not allowed)
    5   MustChangePasswordNextLogon (User must change password at next login)
    6   PasswordDisabled (User cannot log in using Hansoft password)
    7   InactiveAccount (Account has been inactivated)
    

    When authorization with a username and password is successful, an authorization token is returned in the response (in the authToken field). This token is time limited (with a lifetime in seconds specified in the authTokenTimeoutSeconds field of the authenticate result) and can be used instead 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.

    To renew an authentication token, use the renew method call, which can be made after the connection is in the Authorised state.

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

    Renewal never fails and the result message includes the new authToken and timeout in seconds.

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

    When an initial connection is made, it is in the Accepted state. The client should complete a DDP handshake with the web service. When the handshake is successful, the connection transitions to the Connected state. If the handshake is not successful, the connection transitions to the Failed state and the client should disconnect.

    When in the Authorised state, the client can issue any commands they are permitted to perform to the web service.

    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 an subscription attempt fails, a DDP nosub message is returned.

    If the subscription attempt is 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 then receives updates to data covered by the subscription as the web service becomes aware of them.

    Subscription: MyWork

    The MyWork subscription covers one collection, which is also called MyWork. This collection contains one document for each task currently assigned to the user. See Collection: MyWork for more information.

    This subscription does not accept any parameters.

    Subscription: ProjectMeta

    The ProjectMeta subscription covers one collection for each project the user is in (including planning, backlog, and QA projects). These collections are named ProjectMeta_<ProjectID> and contain information about the project in the document with the $Project key and additional documents for each field that tasks in the project can have. See Collection: ProjectMeta_ for more information.

    This subscription does not accept any parameters.

    Subscription: ProjectMilestones

    The ProjectMilestones subscription covers one collection for each planning project the user is in (no collections for backlog or QA projects). These collections are named ProjectMilestones_<ProjectID> and contain one document for each milestone in the project. See See Collection: ProjectMilestones_ for more information.

    Subscription: ProjectResources

    The ProjectResources subscription covers one collection for each planning project the user is in (no collections for backlog or QA projects). These collections are named ProjectResources_<ProjectID> and contain one document for each resource or resource group in the project. See Collection: ProjectResources_ for more information.

    This subscription does not accept any parameters.

    Subscription: ProjectSprints

    The ProjectSprints subscription covers one collection for each planning project the user is in (no collections for backlog or QA projects). These collections are named ProjectSprints_<ProjectID> and contain one document for each sprint in the project. See Collection: ProjectSprints_ for more information.

    This subscription does not accept any parameters.

    Subscription: ProjectWorkflows

    The ProjectWorkflows subscription covers one collection for each planning project the user is in (no collections for backlog or QA projects). These collections are named ProjectWorkflows_<ProjectID> and contain one document for each workflow in the project. See Collection: ProjectWorkflows_ for more information.

    This subscription does not accept any parameters.

    Subscription: ResourceGroups

    The ResourceGroups subscription covers one collection (also named ResourceGroups). This collection contains one document for each resource group in the connected database. See Collection: ResourceGroups for more information.

    This subscription does not accept any parameters.

    Subscription: ServerConnectionState

    The ServerConnectionState subscription covers one collection that keeps track of the Hansoft server connection state. See Collection: ServerConnectionState for more information.

    Subscription: TaskComments

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

    The TaskComments subscription covers one collection named TaskComments_<TaskID>, which contains all comments for the specified task. The task ID for subscribing to comments is specified in the subscription parameters as the first and only argument. More than one TaskComments subscription can be created at any time. See Collection: TaskComments_ for more information.

    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> // Set to true if task was delegated to MyWork user
                <Task Fields>
            }
        }
    }
    

    A MyWork 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 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 are never localized. For custom columns, the field name used in the following format: "CC_<ColumnHash>". The value of each field in a task document represents the value of the task field in Hansoft.

    To interpret the value of a task field and find a field name to display to end users, see the ProjectMeta_ collection corresponding to the project the task is in.

    Each task document has two fields that are always present: $ID and ProjectID. $ID stores the task's database ID as a string (same value used as the key for a task document). ProjectID stores the project ID that the task is in as a string.

    The example assumes you have subscribed to MyWork and ProjectMeta.

    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 everyone is allowed to comment
                        "CanChangePriorityInToDo": <Bool> // Set to true if everyone can change priority in the To Do
                    }
                ]
            }
        }
    }
    
    {
        "ProjectMeta_<ProjectID>": {
            "$Project": <ProjectInfo>,
            "WorkRemaining": {
                "DisplayName": "Work Remaining",
                "ReadOnly": false,
                "Type": "Hours"
                "MaxDecimals": 3
                "MinValue": 0
                "MaxValue": 10000
            }
        }
    }
    

    A ProjectMeta collection contains information about the project in the document with the special key $Project.

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

    The Type field is a JSON string. See Field Types for valid values for this field and any additional fields.

    Collection: ProjectMilestones_<ProjectID>

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

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

    For example:

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

    A ProjectMilestones collection contains one document for each milestone in the specified project. 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.

    Collection: ProjectResources_<ProjectID>

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

    The Type field has one of the following numeric values:

    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 contains one document for each resource or resource group in the specified project. A ProjectResources collection only exists for planning project IDs, not for backlog or QA project IDs. Use the ProjectMeta_<ProjectID> collection for a project 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.

    Collection: ProjectSprints_<ProjectID>

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

    The Start and End fields have a DateTime value that is an EJSON date. The AllowMembersToUpdate field is set to true if all sprint members are allowed to insert, edit, and delete items in the sprint. The field is set to false if 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 contains one document for each sprint in the specified project. 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.

    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 contains one document for each workflow in the specified project. 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.

    Collection: ResourceGroups

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

    A ResourceGroups collection contains 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.

    Collection: ServerConnectionState

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

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

    Collection: TaskComments_<TaskID>

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

    The Flags field is a bit field that can contain the following flags:

    Bit     Value       Meaning
    0       1           Comment is posted and should be visible
    1       2           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 contains all comments for one task. Each comment is stored as a document. Each document has a string representation of a comment post ID as its key.

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

    See the Hansoft documentation for information about comment text format.

    Field Types

    This section describes the JSON value types for each task field type. You will find these values types in a MyWork task document for a specified field type. Unless otherwise specified, provide these value types in the SetTaskField method when setting a field.

    Field Type: AttachedDocuments

    The value consists of two fields: a string field for a main image path for the task and an array field with object file IDs and file paths to the attached documents, plus the file size in bytes. If the attachment is an image, ImageWidth and ImageHeight are set to values greater than 0. The paths can be passed to /vc/<PathToVCFile> to download the attachments. See Version Control Access for more information.

    {
        "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 with two elements: the old ID value and the new ID value. The user of the collection must 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: DateTime

    The value is an EJSON date.

    Field Type: DateTimeTime

    The value is an EJSON date.

    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 Metadata for Project 1021>
        }
    }
    

    The value is a JSON number that represents a choice ID from a predetermined list of choices. The field meta document has a field named Enum that is a JSON array that stores two elements: choice ID (JSON number) and choice name (JSON string).

    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 are set in MinValue and MaxValue. The maximum number of decimals is set in MaxDecimals. An optional field named Unit may be present, which contains a JSON string of the units the field value is in.

    The Unit field, if present, is only for display purposes. It does not have special meaning for the Unit field value.

    Field Type: Hours

    The value is a JSON number that represents a number of hours. The number may be fractional. No other 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 are set in MinValue and MaxValue. An optional field named Unit may be present, which contains a JSON string of the units the field value is in.

    The Unit field, if present, is only for display purposes. It does not have special meaning for the Unit field value.

    Field Type: LinkedTo

    The value is a JSON array of linked to entries. Each linked to entry uses the following format:

    [ <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 Metadata for Project 1021>
        }
    }
    

    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 Metadata for Project 1021>
        }
    }
    

    The value is a JSON object that contains a Value field. This field 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 project that contains the task. This is used for the Linked To Milestone / Release Tag field in Hansoft.

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

    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 Metadata for Project 1021>
        }
    }
    

    The value is a JSON array of JSON numbers. Each number represents a choice ID from a predetermined list of choices. The field meta document has a field named Enum that is a JSON array that stores two elements: choice ID (JSON number) and choice name (JSON string).

    Field Type: MultiLine

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

    Field Type: NewID

    Used in the ProjectMeta collection when a Hansoft custom field gets a new ID. The user of the collection must update the ID.

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

    Field Type: ResourceAllocations

    The value is a JSON array of resource entries. Each resource entry uses the following format:

    [ <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 Metadata for Project 1021>
        }
    }
    

    <AllocationPercent> is the allocation percentage for the resource (0-100).

    Field Type: Resources

    The value is a JSON array of resource entries. Each entry uses the following format:

    [ <ResourceEntryTypeInteger>, <ResourceIDInteger>

    1   ResourceID specifies a normal resource ID
    2   ResourceID specifies 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 Metadata for Project 1021>
        }
    }
    

    <ResourceEntryType> specifies the type of the resource.

    Field Type: String

    The value is a JSON string that 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: TimeZones

    "TimeZoneField": [
        {
            "TimeZoneStart": {
              // Period 1 tart 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 Metadata for Project 1021>
        }
    }
    

    NOTE: This field type is used to represent blocks (zones) of time on a task. It does not represent 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, which are represented in the same format as DateTimeTime fields.

    Field Type: Workflow

    The value is a JSON number and always a 32-bit signed integer. The number corresponds to a workflow document in the ProjectWorkflows collection for the project that contains the task.

    Field Type: WorkflowStatus

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

    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 responds with a DDP result message in the following format:

    {
        "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 task 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 displayed to the right.

    The type of the new value specified depends on the field type, which can be queried from the corresponding ProjectMeta collection. See Field Types for the specific JSON value format for each field type.

    After a SetTaskField method call is made, the web service attempts to make the change. If successful, the client will receive DDP messages describing the changes the method call caused followed by a DDP result message.

    Setting a single task field may result in more that a single change. This can occur when setting the WorkflowStatus column. Transitioning to another workflow stage may result in the task being reassigned to a different user.

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

    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 previously added on a task. TaskEditComment takes three parameters:

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

    An example of a DDP method call for TaskEditComment is displayed to the right.

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

    If the method call fails, the response has the Success result field set to false and an DDP error field is present.

    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 it. TaskPostComment takes three parameters:

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

    An example of a DDP method call for TaskPostComment is displayed to the right.

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

    If the method call fails, the response has the Success result field set to false and an DDP error field will be present.

    Version Control Access

    Access to files stored in the Hansoft version control system (Documents in the client) is via normal web requests instead of over the web socket. Authorization 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. After an access token is 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, which is required for all other version control URLs. To receive a version control access token, 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, 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:

    After the server processes the request, it will respond with a 200 OK status code and a JSON object that contains a results field. This field is an array with one element for each file posted, which specifies 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 numeric code from the Hansoft SDK:

    Error Code Description
    0 NewVersionOfSDKRequired - The metadata type did not exist when the 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 specified version 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 check out of the file was skipped
    17 VersionDoesNotExtist - The version does not exist
    18 NoVersionsWouldRemain - No version would remain if the current version 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 using Nginx for a web server.

    An example Nginx configuration file for web socket proxying (but NOT HTTPS) and version control file access for testing is displayed to the right.

    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;
                }
            }
    }