Triggers in Collector/ArcGIS Online?

16583
18
01-07-2016 07:24 AM
DawnPatrick-Brown
New Contributor II

I am trying to create a connection that will send a message/email to someone if an item is added to a Collector map that is sitting on our ArcGIS Online account. I have taken a look around, and see that there are some items you can use on servers, but I cannot find any information about this sort of thing being done with ArcGIS Online. Does anyone know whether it is possible to set up a trigger in ArcGIS Online? I am quite new to Collector and ArcGIS Online, so if you do know of something that might help, if you could explain it "for a newbie", I would really appreciate it!

Thanks 😃

18 Replies
RandyBurton
MVP Regular Contributor

I have used the REST API via python to obtain the last edit date for a feature. See thread https://community.esri.com/thread/161245 for info.  You would set up a python script to query your feature for any new updates since the script was last run, sleep for a specified period and requery.  If the script finds something, it would send an email.

DawnPatrick-Brown
New Contributor II

That sounds like it might be just the thing we need. Thanks for your help Randy!

0 Kudos
DougBrowning
MVP Frequent Contributor

I did this for a Survey123 Form by adding a field to the Hosted Feature Service database called FormEmailed and have it default to No.  I then run a script at night that uses a ArcMap layout connected to data driven pages with a definition query of FormEmailed = No (I use the Export to PDF from the ddp to get a pdf).  I use python smtp to send the email with pdf attachment.  Then I use ArcRest to set the FormEmailed = Yes.  This way I can always go back into a record and change it to No and it will send it out again.

Let me know if you want to see the code.  Getting the JSON just right is the hardest part.

Hope that helps.

AndrewMilanes
Occasional Contributor II

I would be interested in receiving that code.

0 Kudos
DougBrowning
MVP Frequent Contributor

You have no info on your profile so I have to post it here.

Note change the prt statements as that is a private library we use.  also need all the paths marked fixthis. must also install ArcRest

'''-------------------------------------------------------------------------------

Purpose:    Reads in all the form maps, creates PDFs for the forms, emails them out, then updates the FormEmailed field in the HFS.

            The HFS MUST be the first layer in the map and MUST be part of a group layer (this is how it normally comes in).

            The HFS MUST have a field called FormEmailed that is yes or no (in lowercase).

            The form map mxd MUST have a form element with the name FormName.

            The form map mxd MUST have a form element with the name PDFTitle and that should be a field from the HFS.

-------------------------------------------------------------------------------'''

import arcpy, os, string , urllib, urllib2, json, contextlib, smtplib, mimetypes, datetime, sys, time, traceback

from email.mime.multipart import MIMEMultipart

from email import encoders

from email.message import Message

from email.mime.audio import MIMEAudio

from email.mime.base import MIMEBase

from email.mime.image import MIMEImage

from email.mime.text import MIMEText

from arcrest.security import AGOLTokenSecurityHandler

from arcrest.agol import FeatureLayer

from arcrest.common.filters import LayerDefinitionFilter

# Testing flags

sendEmailsFlag = 1

markAsEmailed = 1

deleteTempPDF = 1

# login info

AGOusername = "put here"

AGOpassword = "put here"

emailSMTP = "fixthis.smtp.com"

#smtpusername = ""

#smtppassword = ""

# Temp area to store pdfs to email.  script then deletes them for cleanup.  could keep if wanted just set flag above

pdfBase = r"fixthis"

# Directory of DDP maps

mapsDir = r"fixthis"

prt("---Start of Daily Forms Email Log File---\n")

prt("Forms Email Started: " + time.asctime())

prt ("\n====================================================================================================\n")

try:

    # Run for each Form map in the Dir

    mapsList = os.listdir(mapsDir)

    for mapToUse in mapsList:

        if mapToUse.endswith(".mxd"):

            # Get map and ddp links

            mxd = arcpy.mapping.MapDocument(os.path.join(mapsDir, mapToUse))

            prt("Running map " + os.path.join(mapsDir, mapToUse))

            ddp = mxd.dataDrivenPages

            # Kick out a pdf for each record in the HFS.  Note this assumes a definition query was set for formemailed=no

            if ddp.pageCount > 0:

                for i in range(1, ddp.pageCount + 1):

                    ddp.currentPageID = i

                    row = ddp.pageRow

                    elm = arcpy.mapping.ListLayoutElements(mxd, "TEXT_ELEMENT", "FormName")

                    formName = elm[0].text

                    fixDate = row.CreationDate

                    fixedDate = str(fixDate.month) + "-" + str(fixDate.day) + "-" + str(fixDate.year)

                    # There is not always a JobName so had to make a form element called PDFTitle that is used to name forms and subject lines

                    # This gives back

                    elm2 = arcpy.mapping.ListLayoutElements(mxd, "TEXT_ELEMENT", "PDFTitle")

                    titleName = elm2[0].text

                    fieldStart = titleName.find("field") + 7

                    fieldEnd = titleName.find('"', fieldStart)

                    findField = titleName[fieldStart:fieldEnd]

                    nameToUse = row.getValue(findField)

                    if nameToUse:

                        baseName = formName + " " + nameToUse + " " + fixedDate

                    else:

                        baseName = formName + " " + "Blank Name Given" + " " + fixedDate

                    pdfName = pdfBase + "\\" + baseName + ".pdf"

                    ddp.exportToPDF(pdfName, "RANGE", str(i))

                    if sendEmailsFlag == 1:

                        # Email the pdf

                        emailfrom = row.Creator

                        # email a copy to the creator always plus the field they picked

                        # Gets mad if a null, so check for empty field

                        # Weird but the msg["To"] must be a string but the call to the smtp server must be a list

                        emailto = row.Creator

                        emailRecList = row.Creator

                        if row.EmailCopyTo:

                            emailto = row.Creator + "," + row.EmailCopyTo

                            emailRecList = emailto.split(',')

                        # this is full path to pdf to attach

                        fileToSend = pdfName

                        # this is just the name without path which becomes the actual name of the attached file

                        justfileName = baseName + ".pdf"

                        msg = MIMEMultipart()

                        msg["From"] = emailfrom

                        msg["To"] = emailto

                        msg["Subject"] = baseName + " Attached"

                        msg.preamble = "Where is this"

                        ctype, encoding = mimetypes.guess_type(fileToSend)

                        if ctype is None or encoding is not None:

                            ctype = "application/octet-stream"

                        maintype, subtype = ctype.split("/", 1)

                        fp = open(fileToSend, "rb")

                        attachment = MIMEBase(maintype, subtype)

                        attachment.set_payload(fp.read())

                        fp.close()

                        encoders.encode_base64(attachment)

                        attachment.add_header("Content-Disposition", "attachment", filename=justfileName)

                        msg.attach(attachment)

                        server = smtplib.SMTP(emailSMTP)

                        #server.starttls()

                        #server.login(smtpusername,smtppassword)   # password not needed for here

                        server.sendmail(emailfrom, emailRecList, msg.as_string())

                        server.quit()

                        prt("Sent email " + baseName + " to " + emailto)

                    # Delete the temp PDF for cleanup

                    if deleteTempPDF == 1:

                        os.remove(pdfName)

                    if markAsEmailed == 1:

                        # Update the formemailed flag to yes

                        # Get url of HFS from the layer in the map.  Assumes first layer is group of HFS then second is HFS

                        hfsLayer = arcpy.mapping.ListLayers(mxd)[1]

                        hfsURL = hfsLayer.dataSource + "/" + "updateFeatures"

                        # Get token

                        agolSH = AGOLTokenSecurityHandler(username=AGOusername,password=AGOpassword)

                        updateAttr = [{"attributes" : {"objectid": row.objectid ,"formemailed" : "yes"}}]

                        data = {'f': 'json', 'features': updateAttr, 'token' : agolSH.token}

                        encodedData = urllib.urlencode(data)

                        request = urllib2.Request(hfsURL, encodedData)

                        response = urllib2.urlopen(request)

                        readResponse = response.read()

                        jsonResponse = json.loads(readResponse)

                        if not jsonResponse['updateResults'][0]['success']:

                            prt("FormEmailed field for form " + formName + " at ObjectID " + row.objectid + " was NOT updated successfully!")

                            ScriptFailed=True

            else:

                prt( "No recrods found in the Hosted Feature Service.  There are no forms to email or not signed in to AGO.\n\n")

                ScriptFailed=True

        prt("\n")

    prt("\n" + "Daily Forms Email Complete: " + time.asctime())

    del mxd

except:

    PythonMessages("Daily Forms Email Failed")

    prt(traceback.format_exc())

    prt(arcpy.GetMessages(2))

    ScriptFailed=True

GaryBowles1
Occasional Contributor III

Doug,

I am trying to recreate what you are doing with the email of pdf from hfs data collected in survey123. When i am setting up my ddp in arcmap, i am getting empty for a value for my Data Driven Page Attribute fields instead of the data from my hfs.

Have you ran into this? Any ideas?

Thanks,

--gary

0 Kudos
DougBrowning
MVP Frequent Contributor

First make sure you are logged into AGO in ArcMap.  No red exclamation on the HFS. 

Second you must login to AGO first then add the HFS.  If you open a map with the HFS then login it will not figure out you are now connected.  This is my best guess as to your issue.

Third are you adding the filed using Insert -> Dynamic Text -> Data Driven Page Attribute

Then the text box should look like this 

<dyn type="page" property="attribute" field="UnitName" domainlookup="true"/>

You should be in layout view.

0 Kudos
GaryBowles1
Occasional Contributor III

Doug,

Everything looks the same except we are pulling our data from Portal.

I am logged into portal, added the data from File/ArcGIS Portal window.

Insert/Dynamic Text/Data Driven Page Attribute

Text box looks like this:

I am in layout view.

When I add the same data that has been copied into our SDE, everything works.

Going to have to dig into Portal and see what may be causing this to fail.

Thanks for your response I appreciate your help. If I get this figured out I will elt you know what the problem was.

--gary

Gary H. Bowles

GIS Database Administrator II | Seneca Resources

Office : 412-548-2544 | Cell Phone: 412-334-5273

0 Kudos
DougBrowning
MVP Frequent Contributor

I have only used AGO for now.  I will test if I get a chance.  Only thing I can think of is make sure Query is enabled on the HFS. 

0 Kudos