markciecior / ConnectPyse

ConnectWise (Manage) REST API client written in Python 3.x
MIT License
21 stars 8 forks source link

Support for customFields or configuration questions #26

Open djBirdman opened 2 years ago

djBirdman commented 2 years ago

I'm wondering if there is support for custom fields, or in particular for what I'm working on right now configuration questions?

If I'm understanding things correctly, these are both presented as lists of dictionaries, compared to things like company and site that are presenting as a dictionary and where the "sub-attributes" are used. For example printing out custom fields shows: customFields: [{'id': 7, 'caption': 'Link', 'type': 'Hyperlink', 'entryMethod': 'EntryField', 'numberOfDecimals': 0, 'value': 'https://www.example.net/1234}] ... and configuration questions similarly as: questions: [{'answerId': 1014, 'questionId': 502, 'question': 'What is the IP address?', 'answer': '192.168.1.66', 'sequenceNumber': 1.0, 'numberOfDecimals': 0, 'fieldType': 'IPAddress', 'requiredFlag': False}]

I thought it might work with something along the lines of: configurationsApi.update_configuration(configId, 'customFields/id=7', 'https://www.example.net/1235') ...or configurationsApi.update_configuration(configId, 'questions/questionId=502', '192.168.1.65')

NB: I have tested the update method with sub-attributes and it works perfectly - in case this is useful for others or worth documenting: configurationsApi.update_configuration(configId, 'site/id', 1078) Also useful in the main readme might be how multiple conditions can be used e.g. configurationsApi.conditions = f'type/id=100 AND name contains "{searchString}"' (also noting that the CW API expects search strings to be enclosed with double quotes)

emichaud commented 2 years ago

Hey @djBirdman, I know this question has been out here for a bit, but wanted to check in to see if you still have the issue and if you could clarify better what you're looking for, not 100% sure from reading your original note.

djBirdman commented 2 years ago

In terms of the issue I was trying to solve, we got around it by using the built-in 'ipAddress' field and working out a way to use a custom Hosted API pod in the configurations page rather than a hyperlink in a custom field.

What we are looking for is supporting custom fields in any part of ConnectWise, or specifically questions fields under configurations. (I've lumped them together, because they are both lists of dictionaries)

i.e. just like I can get all configurations for a company if I know the company ID

configurationsApi.conditions = 'company/id=21489'
configs = configurationsApi.get_configurations()

we'd like to be able to do the same for custom fields or questions, e.g. for routers where we record the external IP address in a question, it might look like

configurationsApi.conditions = 'questions/questionId=482/answer=12.34.56.78'
configs = configurationsApi.get_configurations()

Similarly, for setting fields where we would use

configurationsApi.update_configuration(configId, 'macAddress', 'AA:BB:CC:DD:EE:FF')

we might update with

configurationsApi.update_configuration(configId, 'questions/questionId=482/answer', '87.65.43.21')

For reference, this is how things look when we print() a returned configuration

id: 840
name: Router One
...
company: {'id': 21489, 'identifier': 'CompanyName', 'name': 'Company Name', ... }
...
questions: [{'answerId': 1966, 'questionId': 482, 'question': 'What is the external IP address?', 'answer': '12.34.56.78', 'sequenceNumber': 1.0, 'numberOfDecimals': 0, 'fieldType': 'IPAddress', 'requiredFlag': False}, { ... }]
...
markciecior commented 2 years ago

Since connectpyse is a very light wrapper around the Manage REST API, anything that the REST API supports should be workable using connectpyse. This is true of configuration questions and custom fields. Most of this is based on what I pulled from the official Manage docs here.

The questions dict is a top-level attribute of configurations, and the individual questions can be queried using the childConditions path parameter.

Given a configuration item with the following question:

"questions": [
            {
                "answerId": 20868,
                "questionId": 441,
                "question": "LAN IP Address:",
                "answer": "10.8.0.15",
                "sequenceNumber": 10.00,
                "numberOfDecimals": 0,
                "fieldType": "Text",
                "requiredFlag": false
            }
]

You can query for this config item using this URL: GET {{baseUrl}}/company/configurations?conditions=company/id=12345&childConditions=questions/questionId=441 AND questions/answer = "10.8.0.15"

I don't have an interpreter in front of me, but I believe the above can be done with connectpyse like this:

configurationsApi.childConditions = 'questions/questionId=441 AND questions/answer = "10.8.0.15"'
configs = configurationsApi.get_configurations()

The same should hold true for custom fields (using the customFieldConditions parameter), though I haven't had a reason to use it myself just yet.

djBirdman commented 2 years ago

Ah, thanks for that - I had missed the query string parameters section of that CW docs page when reading previously.

I've tested connectpyse and it needs to be childconditions or customfieldconditions, e.g.

configurationsApi.childconditions = 'questions/questionId=441 AND questions/answer = "10.8.0.15"'
configs = configurationsApi.get_configurations()

(My python fu isn't strong, but interestingly there are no errors when using the camel case name. The API definitely ignores it though)

I need to do further testing for updating custom fields/questions, but if I understand the 'Patch' section in the CW docs then we would need to update the object locally and then update the whole object via API, i.e. for configurations using replace_configuration

djBirdman commented 1 year ago

Right, it's been too long, but finally got around to looking into this...and confirming that can successfully update questions and custom fields.

The CW API states that when updating fields "When working with custom fields, you must pass the entire array of custom fields.", and the same holds for questions under configuration. (The method below works for customFields, except of course updating 'value' instead of 'answer')

To update the question on an answer, copy the questions array locally, update the answer field in that copy and pass the array as the value in update_configuration()

configs = configurationsApi.get_configurations()
for c in configs:
    updateConfigId = c.id
    questionsArray = c.questions
    questionsArray[3]['answer'] = '10.8.0.15'
    configurationsApi.update_configuration(updateConfigId, 'questions', questionsArray)