Select to view content in your preferred language

Add storymap to existing collection programmatically using python api

519
7
Jump to solution
02-12-2024 02:47 PM
Labels (2)
atmosfairy
New Contributor II

Hi All,

I have created a python tool that allows multiple users to create a storymap based on a template. I have manually grouped these together to create a collection. However, I would like to implement an instruction that will programatically add the newly created storymap to the collection. 

I have inspected the collection and all I can see is a dictionary of a single Collection-UI node. Is there a way to do this noting that I am using arcgis 2.2.0?

** UPDATE - I can access the json file and can see I need to add another resourceId node defining type  and specifying the item id of the portal item. So my question now is: how do I add a resourceId node to the json file?

0 Kudos
2 Solutions

Accepted Solutions
ThePreatorian
Esri Contributor

Hi @atmosfairy  You have made a lot of progress. 

Unfortunately the python API does not currently support StoryMap Collections. But that will be fixed with the April 2.3.0 release.

You are on the right track. We will need to update the json file for the collection programmatically. And possibly do a few things to the Collection metadata depending on your use case. I just have a couple questions in order to understand the workflow better:
1. Are you creating a brand new Collections, or planning to add to an existing Collection?
2. Do you plan to verify the Collection after running your script before publishing the changes?

In the end you will probably need to use a combination of the the following methods/packages to get this working:

ResourceManager.add  (esri python api)
Item.update (esri python api)
json (built in python package)

View solution in original post

ThePreatorian
Esri Contributor

We always recommend QA on items generated programmatically.
Here is some code to get you started. Updating the itemKeywords will be important in order to point your story to the newly created draft. You might need to modify as needed 

#Get collection Item
target_collection = Item(itemid="COLLECTION_ITEM_ID")
target_collection_json = draft_data = draft_data = 
#This draft will be modified with new information
draft_data = target_collection.resources.get("published_data.json", try_json=True)
#Generate a new draft_filename
draft_file_name = f"draft_{unix_timestamp}.json"
#Get the node that will get the new items
root_id = draft_data['root']
ui_child_id = draft_data['nodes']['root_id']['children'][0]
collention_ui_node = draft_data['nodes']['ui_child_id']

for storyID in storymap_list:
  #generate new resourceID
  generated_resource_id = f"r-{uuid4()[:6]}"
  #Add StoryMap Id as new Item
  draft_data['resources'][generated_resource_id] = {
   "type": "portal-item",
   "data": {
   "itemId": storyID
   }
  }
  #Update Itemrefs
 collection_ui_node['data'['items'].append({"resourceId":generated_resource_id})

#Remove existing Keywords
keywords = target_collection.typeKeywords
if 'smstatuspublished'in keywords:
 keywords.pop('smstatuspublished')
if 'smstatusunpublishedchanges' in keywords:
 keywords.pop('smstatusunpublishedchanges')

#Append Editor App, unpublished and Draft pointer keyword
keywords.append('smeditorapp:python')
keywords.append('unpublished')
keywords.append(f'smdraftresourceid:{draft_file_name}.json')

#update keywords on the item
target_collection.update(item_properties={"typeKeywords":keywords})
#add the new Draft as a resource
target_collection.resources.add(file_name=draft_file_name, text=json.dumps(data, indent=4))

  
  

  
 

 

View solution in original post

7 Replies
ThePreatorian
Esri Contributor

Hi @atmosfairy  You have made a lot of progress. 

Unfortunately the python API does not currently support StoryMap Collections. But that will be fixed with the April 2.3.0 release.

You are on the right track. We will need to update the json file for the collection programmatically. And possibly do a few things to the Collection metadata depending on your use case. I just have a couple questions in order to understand the workflow better:
1. Are you creating a brand new Collections, or planning to add to an existing Collection?
2. Do you plan to verify the Collection after running your script before publishing the changes?

In the end you will probably need to use a combination of the the following methods/packages to get this working:

ResourceManager.add  (esri python api)
Item.update (esri python api)
json (built in python package)

atmosfairy
New Contributor II

Hi @ThePreatorian,

In 99% of cases, I will be adding new storymaps to an existing collection; however, there may be the need to create a new collection from time-to-time.

Haven't thought about verifying the Collection after running script, but before publishing changes - is this the recommended workflow?

And thanks for getting back to me - good to know that this functionality is just around the corner

0 Kudos
ThePreatorian
Esri Contributor

We always recommend QA on items generated programmatically.
Here is some code to get you started. Updating the itemKeywords will be important in order to point your story to the newly created draft. You might need to modify as needed 

#Get collection Item
target_collection = Item(itemid="COLLECTION_ITEM_ID")
target_collection_json = draft_data = draft_data = 
#This draft will be modified with new information
draft_data = target_collection.resources.get("published_data.json", try_json=True)
#Generate a new draft_filename
draft_file_name = f"draft_{unix_timestamp}.json"
#Get the node that will get the new items
root_id = draft_data['root']
ui_child_id = draft_data['nodes']['root_id']['children'][0]
collention_ui_node = draft_data['nodes']['ui_child_id']

for storyID in storymap_list:
  #generate new resourceID
  generated_resource_id = f"r-{uuid4()[:6]}"
  #Add StoryMap Id as new Item
  draft_data['resources'][generated_resource_id] = {
   "type": "portal-item",
   "data": {
   "itemId": storyID
   }
  }
  #Update Itemrefs
 collection_ui_node['data'['items'].append({"resourceId":generated_resource_id})

#Remove existing Keywords
keywords = target_collection.typeKeywords
if 'smstatuspublished'in keywords:
 keywords.pop('smstatuspublished')
if 'smstatusunpublishedchanges' in keywords:
 keywords.pop('smstatusunpublishedchanges')

#Append Editor App, unpublished and Draft pointer keyword
keywords.append('smeditorapp:python')
keywords.append('unpublished')
keywords.append(f'smdraftresourceid:{draft_file_name}.json')

#update keywords on the item
target_collection.update(item_properties={"typeKeywords":keywords})
#add the new Draft as a resource
target_collection.resources.add(file_name=draft_file_name, text=json.dumps(data, indent=4))

  
  

  
 

 

atmosfairy
New Contributor II

Love that! Thanks @ThePreatorian. Will get back to you if I have any further questions.

0 Kudos
ThePreatorian
Esri Contributor

Noticed A couple of naming/syntax issues with the previous code. Cleaned up a bit here:

#Get collection Item
target_collection = Item(itemid="COLLECTION_ITEM_ID")
#This draft will be modified with new information
draft_data = target_collection.resources.get("published_data.json", try_json=True)
#Generate a new draft_filename
draft_file_name = f"draft_{unix_timestamp}.json"
#Get the node that will get the new items
root_id = draft_data['root']
ui_child_id = draft_data['nodes']['root_id']['children'][0]
collention_ui_node = draft_data['nodes']['ui_child_id']

for storyID in storymap_list:
  #generate new resourceID
  generated_resource_id = f"r-{uuid4()[:6]}"
  #Add StoryMap Id as new Item
  draft_data['resources'][generated_resource_id] = {
   "type": "portal-item",
   "data": {
   "itemId": storyID
   }
  }
  #Update Itemrefs
 collection_ui_node['data'['items'].append({"resourceId":generated_resource_id})

#Remove existing Keywords
keywords = target_collection.typeKeywords
if 'smstatuspublished'in keywords:
 keywords.pop('smstatuspublished')
if 'smstatusunpublishedchanges' in keywords:
 keywords.pop('smstatusunpublishedchanges')

#Append Editor App, unpublished and Draft pointer keyword
keywords.append('smeditorapp:python')
keywords.append('unpublished')
keywords.append(f'smdraftresourceid:{draft_file_name}.json')

#update keywords on the item
target_collection.update(item_properties={"typeKeywords":keywords})
#add the new Draft as a resource
target_collection.resources.add(file_name=draft_file_name, text=json.dumps(draft_data, indent=4))
PeterKnoop
MVP Regular Contributor

@ThePreatorian that is helpful advice to QA programmatically created content. Do you know where one can find a definition of the StoryMap model to check against, such as what keywords are required, optional, etc.?

0 Kudos
ThePreatorian
Esri Contributor

At this time, we have not published developer documentation for ArcGIS StoryMaps. However, you can use the StoryMap , Briefing , and Collection classes in the Python API to create ArcGIS StoryMap items. These classes manage keywords, and we do not recommend editing them manually. If you need to query keywords for your scripts, you can use the {Class}._item.typeKeywords property. 

Please note the above advice of manually manipulating everything is only applicable until Python v2.3.0 is released around April 2024. After that release, Collections and Briefings will be supported in the API, so the recommended way to manipulate the Collection would be to use the class-specific methods.

If you have any further questions or need more information, feel free to ask!