diff --git a/README.md b/README.md index fec3a04..057c018 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,22 @@ A Golang wrapper for some common [Cvent SOAP API](https://developers.cvent.com/d ## Thanks to gosoap [gosoap](https://github.com/tiaguinho/gosoap) gave this wrapper a big head start. There was a lot of hacking on gosoap to make it work with Cvent's API, so you will find it forked and included with `gocvent`. +## Build your own Definitions +This package includes Golang Structures for the out-of-the-box versions of Contacts, Events, Registrations and Users CvObjects in the [`definitions/`](definitions/) directory. If you want to work with other CvObjects and/or use custom fields on these structures, you will need to build your own `struct`s using `cvent.StructGen("filePath", "CvObject")`, then use the resulting `struct`s in your Cvent API retrieve calls, e.g. + +```go +var objectDef objDefs.EventRetrieveResult +err := cvent.Retrieve("Event", v, &objectDef) +if err != nil { + fmt.Printf("TestRetrieveEvent err from cvent.Retrieve: %s", err) +} +fmt.Printf("Event Title: %s\n", objectDef.CvObject.EventTitle) +``` + ## Check out the Tests Demonstrations of each of the implemented Cvent API methods has at least one corresponding test in [gocvent_test.go](gocvent_test.go). Current implementation includes: * [Login](https://developers.cvent.com/documentation/soap-api/call-definitions/authentication/login/) * [DescribeCvObject](https://developers.cvent.com/documentation/soap-api/call-definitions/object-metadata-calls/describecvobject/) * [DescribeGlobal](https://developers.cvent.com/documentation/soap-api/call-definitions/object-metadata-calls/describeglobal/) * [Search](https://developers.cvent.com/documentation/soap-api/call-definitions/search-and-retrieve/search/) (only _AndSearch_ style filtering is currently implemented, see [CvSearchObject](https://developers.cvent.com/documentation/soap-api/object-definitions/cvsearchobject/) and [`gosoap/encode.go`](gosoap/encode.go#L76)) +* [Retrieve](https://developers.cvent.com/documentation/soap-api/call-definitions/search-and-retrieve/retrieve/) (gocvent only supports retrieval of one record at a time, which is different than the Cvent's function which would support several. Pull requests welcomed.) diff --git a/definitions.go b/definitions.go index 6a50bff..98c8d9f 100644 --- a/definitions.go +++ b/definitions.go @@ -10,6 +10,15 @@ type CventAPI struct { soap *gosoap.Client } +// CvObject is a generic result of a Retrieve call, so this is mostly just metadata fields +type CvObject struct { + Type string `xml:"type,attr"` + ID string `xml:"Id,attr"` + CreatedBy string `xml:"CreatedBy,attr"` + CreatedDate string `xml:"CreatedDate,attr"` + LastModifiedDate string `xml:"LastModifiedDate,attr"` +} + // AnswerDetail looks and smells a lot like LookUpDetail IMO type AnswerDetail struct { AnswerText string `xml:"AnswerText,attr"` @@ -116,6 +125,16 @@ type LookUpDetail struct { Value string `xml:"Value,attr"` } +// RetrieveResponse wrapper for RetrieveResult +type RetrieveResponse struct { + RetrieveResult RetrieveResult +} + +// RetrieveResult contains information about the records returned by a Retrieve API Call +type RetrieveResult struct { + CvObject CvObject `xml:"CvObject"` +} + // SearchResponse wrapper for SearchResult type SearchResponse struct { SearchResult SearchResult diff --git a/definitions/Contact.go b/definitions/Contact.go new file mode 100644 index 0000000..cc4cfcc --- /dev/null +++ b/definitions/Contact.go @@ -0,0 +1,82 @@ +package gocvent + +// ContactRetrieveResult defines the result wrapper +type ContactRetrieveResult struct { + CvObject Contact `xml:"RetrieveResult>CvObject"` +} + +// Contact defines the CvObject +type Contact struct { + Active bool `xml:"Active,attr"` + ActivityId string `xml:"ActivityId,attr"` + CCEmailAddress string `xml:"CCEmailAddress,attr"` + Company string `xml:"Company,attr"` + ContactType string `xml:"ContactType,attr"` + ContactTypeCode string `xml:"ContactTypeCode,attr"` + CreatedBy string `xml:"CreatedBy,attr"` + CreatedDate string `xml:"CreatedDate,attr"` + DateOfBirth string `xml:"DateOfBirth,attr"` + Designation string `xml:"Designation,attr"` + EmailAddress string `xml:"EmailAddress,attr"` + EmailAddressStatus string `xml:"EmailAddressStatus,attr"` + ExcludedFromEmail bool `xml:"ExcludedFromEmail,attr"` + ExpirationDate string `xml:"ExpirationDate,attr"` + FacebookURL string `xml:"FacebookURL,attr"` + FirstName string `xml:"FirstName,attr"` + Gender string `xml:"Gender,attr"` + HomeAddress1 string `xml:"HomeAddress1,attr"` + HomeAddress2 string `xml:"HomeAddress2,attr"` + HomeAddress3 string `xml:"HomeAddress3,attr"` + HomeCity string `xml:"HomeCity,attr"` + HomeCountry string `xml:"HomeCountry,attr"` + HomeCountryCode string `xml:"HomeCountryCode,attr"` + HomeFax string `xml:"HomeFax,attr"` + HomePhone string `xml:"HomePhone,attr"` + HomePostalCode string `xml:"HomePostalCode,attr"` + HomeState string `xml:"HomeState,attr"` + HomeStateCode string `xml:"HomeStateCode,attr"` + Id string `xml:"Id,attr"` + ImageURL string `xml:"ImageURL,attr"` + IsCreatedViaTestReg bool `xml:"IsCreatedViaTestReg,attr"` + IsObfuscated bool `xml:"IsObfuscated,attr"` + JoinDate string `xml:"JoinDate,attr"` + LastModifiedBy string `xml:"LastModifiedBy,attr"` + LastModifiedDate string `xml:"LastModifiedDate,attr"` + LastName string `xml:"LastName,attr"` + LastOptOutBy string `xml:"LastOptOutBy,attr"` + LastOptOutDate string `xml:"LastOptOutDate,attr"` + LastRenewalDate string `xml:"LastRenewalDate,attr"` + LinkedInURL string `xml:"LinkedInURL,attr"` + LogDate string `xml:"LogDate,attr"` + LogReason string `xml:"LogReason,attr"` + LogResponse string `xml:"LogResponse,attr"` + MembershipCode string `xml:"MembershipCode,attr"` + MiddleName string `xml:"MiddleName,attr"` + MobilePhone string `xml:"MobilePhone,attr"` + NationalIdentificationNumber string `xml:"NationalIdentificationNumber,attr"` + Nickname string `xml:"Nickname,attr"` + OptedIn bool `xml:"OptedIn,attr"` + Pager string `xml:"Pager,attr"` + ParentContactId string `xml:"ParentContactId,attr"` + PassportCountry string `xml:"PassportCountry,attr"` + PassportCountryCode string `xml:"PassportCountryCode,attr"` + PassportNumber string `xml:"PassportNumber,attr"` + PrimaryAddress string `xml:"PrimaryAddress,attr"` + Salutation string `xml:"Salutation,attr"` + SMTPCode string `xml:"SMTPCode,attr"` + SocialSecurityNumber string `xml:"SocialSecurityNumber,attr"` + SourceId string `xml:"SourceId,attr"` + Title string `xml:"Title,attr"` + TwitterURL string `xml:"TwitterURL,attr"` + WorkAddress1 string `xml:"WorkAddress1,attr"` + WorkAddress2 string `xml:"WorkAddress2,attr"` + WorkAddress3 string `xml:"WorkAddress3,attr"` + WorkCity string `xml:"WorkCity,attr"` + WorkCountry string `xml:"WorkCountry,attr"` + WorkCountryCode string `xml:"WorkCountryCode,attr"` + WorkFax string `xml:"WorkFax,attr"` + WorkPhone string `xml:"WorkPhone,attr"` + WorkPostalCode string `xml:"WorkPostalCode,attr"` + WorkState string `xml:"WorkState,attr"` + WorkStateCode string `xml:"WorkStateCode,attr"` +} diff --git a/definitions/Event.go b/definitions/Event.go new file mode 100644 index 0000000..ec843fa --- /dev/null +++ b/definitions/Event.go @@ -0,0 +1,70 @@ +package gocvent + +// EventRetrieveResult defines the result wrapper +type EventRetrieveResult struct { + CvObject Event `xml:"RetrieveResult>CvObject"` +} + +// Event defines the CvObject +type Event struct { + ArchiveDate string `xml:"ArchiveDate,attr"` + Capacity string `xml:"Capacity,attr"` + Category string `xml:"Category,attr"` + City string `xml:"City,attr"` + ClosedBy string `xml:"ClosedBy,attr"` + Country string `xml:"Country,attr"` + CountryCode string `xml:"CountryCode,attr"` + CreatedBy string `xml:"CreatedBy,attr"` + Currency string `xml:"Currency,attr"` + EventCalendarAlternateURL string `xml:"EventCalendarAlternateURL,attr"` + EventCalendarCompletedURL string `xml:"EventCalendarCompletedURL,attr"` + EventCalendarLinkText string `xml:"EventCalendarLinkText,attr"` + EventCode string `xml:"EventCode,attr"` + EventDescription string `xml:"EventDescription,attr"` + EventEndDate string `xml:"EventEndDate,attr"` + EventLaunchDate string `xml:"EventLaunchDate,attr"` + EventStartDate string `xml:"EventStartDate,attr"` + EventStatus string `xml:"EventStatus,attr"` + EventTitle string `xml:"EventTitle,attr"` + ExternalAuthentication bool `xml:"ExternalAuthentication,attr"` + Hidden bool `xml:"Hidden,attr"` + Id string `xml:"Id,attr"` + InternalNote string `xml:"InternalNote,attr"` + LastModifiedDate string `xml:"LastModifiedDate,attr"` + Location string `xml:"Location,attr"` + MeetingRequestId string `xml:"MeetingRequestId,attr"` + MerchantAccount string `xml:"MerchantAccount,attr"` + MerchantAccountId string `xml:"MerchantAccountId,attr"` + PhoneNumber string `xml:"PhoneNumber,attr"` + PlannerCompany string `xml:"PlannerCompany,attr"` + PlannerEmailAddress string `xml:"PlannerEmailAddress,attr"` + PlannerFirstName string `xml:"PlannerFirstName,attr"` + PlannerLastName string `xml:"PlannerLastName,attr"` + PlannerPrefix string `xml:"PlannerPrefix,attr"` + PlannerTitle string `xml:"PlannerTitle,attr"` + PlanningStatus string `xml:"PlanningStatus,attr"` + PostalCode string `xml:"PostalCode,attr"` + RSVPbyDate string `xml:"RSVPbyDate,attr"` + StakeholderAddress1 string `xml:"StakeholderAddress1,attr"` + StakeholderAddress2 string `xml:"StakeholderAddress2,attr"` + StakeholderAddress3 string `xml:"StakeholderAddress3,attr"` + StakeholderCity string `xml:"StakeholderCity,attr"` + StakeholderCompany string `xml:"StakeholderCompany,attr"` + StakeholderCountryCode string `xml:"StakeholderCountryCode,attr"` + StakeholderEmailAddress string `xml:"StakeholderEmailAddress,attr"` + StakeholderFirstName string `xml:"StakeholderFirstName,attr"` + StakeholderHomePhone string `xml:"StakeholderHomePhone,attr"` + StakeholderLastName string `xml:"StakeholderLastName,attr"` + StakeholderMobilePhone string `xml:"StakeholderMobilePhone,attr"` + StakeholderPostalCode string `xml:"StakeholderPostalCode,attr"` + StakeholderStateCode string `xml:"StakeholderStateCode,attr"` + StakeholderTitle string `xml:"StakeholderTitle,attr"` + StakeholderWorkFax string `xml:"StakeholderWorkFax,attr"` + StakeholderWorkPhone string `xml:"StakeholderWorkPhone,attr"` + State string `xml:"State,attr"` + StateCode string `xml:"StateCode,attr"` + StreetAddress1 string `xml:"StreetAddress1,attr"` + StreetAddress2 string `xml:"StreetAddress2,attr"` + StreetAddress3 string `xml:"StreetAddress3,attr"` + Timezone string `xml:"Timezone,attr"` +} diff --git a/definitions/Registration.go b/definitions/Registration.go new file mode 100644 index 0000000..1fc4087 --- /dev/null +++ b/definitions/Registration.go @@ -0,0 +1,45 @@ +package gocvent + +// RegistrationRetrieveResult defines the result wrapper +type RegistrationRetrieveResult struct { + CvObject Registration `xml:"RetrieveResult>CvObject"` +} + +// Registration defines the CvObject +type Registration struct { + CancelledDate string `xml:"CancelledDate,attr"` + CCEmailAddress string `xml:"CCEmailAddress,attr"` + Company string `xml:"Company,attr"` + ConfirmationNumber string `xml:"ConfirmationNumber,attr"` + ContactId string `xml:"ContactId,attr"` + Credit string `xml:"Credit,attr"` + EmailAddress string `xml:"EmailAddress,attr"` + EventCode string `xml:"EventCode,attr"` + EventId string `xml:"EventId,attr"` + EventStartDate string `xml:"EventStartDate,attr"` + EventTitle string `xml:"EventTitle,attr"` + FirstName string `xml:"FirstName,attr"` + GroupId string `xml:"GroupId,attr"` + GroupLeader bool `xml:"GroupLeader,attr"` + Id string `xml:"Id,attr"` + InternalNote string `xml:"InternalNote,attr"` + InvitedBy string `xml:"InvitedBy,attr"` + InviteeId string `xml:"InviteeId,attr"` + IsTestRegistrant bool `xml:"IsTestRegistrant,attr"` + LastModifiedDate string `xml:"LastModifiedDate,attr"` + LastName string `xml:"LastName,attr"` + ModifiedBy string `xml:"ModifiedBy,attr"` + OriginalResponseDate string `xml:"OriginalResponseDate,attr"` + Participant bool `xml:"Participant,attr"` + ReferenceId string `xml:"ReferenceId,attr"` + RegistrationDate string `xml:"RegistrationDate,attr"` + RegistrationType string `xml:"RegistrationType,attr"` + RegistrationTypeCode string `xml:"RegistrationTypeCode,attr"` + ResponseMethod string `xml:"ResponseMethod,attr"` + SourceId string `xml:"SourceId,attr"` + Status string `xml:"Status,attr"` + TargetedListId string `xml:"TargetedListId,attr"` + TargetedListName string `xml:"TargetedListName,attr"` + Title string `xml:"Title,attr"` + WorkPhone string `xml:"WorkPhone,attr"` +} diff --git a/definitions/User.go b/definitions/User.go new file mode 100644 index 0000000..2879ce3 --- /dev/null +++ b/definitions/User.go @@ -0,0 +1,51 @@ +package gocvent + +// UserRetrieveResult defines the result wrapper +type UserRetrieveResult struct { + CvObject User `xml:"RetrieveResult>CvObject"` +} + +// User defines the CvObject +type User struct { + Active bool `xml:"Active,attr"` + Address1 string `xml:"Address1,attr"` + Address2 string `xml:"Address2,attr"` + Address3 string `xml:"Address3,attr"` + AllEventVisibility bool `xml:"AllEventVisibility,attr"` + AllRFPVisibility bool `xml:"AllRFPVisibility,attr"` + AllSurveyVisibility bool `xml:"AllSurveyVisibility,attr"` + ChangePasswordOnLogin bool `xml:"ChangePasswordOnLogin,attr"` + City string `xml:"City,attr"` + Company string `xml:"Company,attr"` + Country string `xml:"Country,attr"` + CountryCode string `xml:"CountryCode,attr"` + CreatedBy string `xml:"CreatedBy,attr"` + CreatedDate string `xml:"CreatedDate,attr"` + DefaultContactGroupId string `xml:"DefaultContactGroupId,attr"` + Email string `xml:"Email,attr"` + FederatedId string `xml:"FederatedId,attr"` + FirstName string `xml:"FirstName,attr"` + HomeFax string `xml:"HomeFax,attr"` + HomePhone string `xml:"HomePhone,attr"` + Id string `xml:"Id,attr"` + LastLoginDate string `xml:"LastLoginDate,attr"` + LastModifiedBy string `xml:"LastModifiedBy,attr"` + LastModifiedDate string `xml:"LastModifiedDate,attr"` + LastName string `xml:"LastName,attr"` + MobilePhone string `xml:"MobilePhone,attr"` + Pager string `xml:"Pager,attr"` + Password string `xml:"Password,attr"` + Passwordstrong string `xml:"Password (strong),attr"` + PasswordSalt string `xml:"Password Salt,attr"` + PostalCode string `xml:"PostalCode,attr"` + Prefix string `xml:"Prefix,attr"` + State string `xml:"State,attr"` + StateCode string `xml:"StateCode,attr"` + Title string `xml:"Title,attr"` + Username string `xml:"Username,attr"` + UserRole string `xml:"UserRole,attr"` + UserRoleId string `xml:"UserRoleId,attr"` + UserType string `xml:"UserType,attr"` + WorkFax string `xml:"WorkFax,attr"` + WorkPhone string `xml:"WorkPhone,attr"` +} diff --git a/gocvent.go b/gocvent.go index 329d6c5..1984e33 100644 --- a/gocvent.go +++ b/gocvent.go @@ -2,6 +2,9 @@ package gocvent import ( "errors" + "io/ioutil" + "os/exec" + "strings" "github.com/matthewpoer/gocvent/gosoap" ) @@ -89,6 +92,25 @@ func (c *CventAPI) DescribeGlobal() (DescribeGlobalResult, error) { return r.DescribeGlobalResult, nil } +// Retrieve is used to get a single Cvent Object +func (c *CventAPI) Retrieve(ObjectType string, ID string, objectDef interface{}) error { + + params := gosoap.Params{} + params["ObjectType"] = ObjectType + params["Ids"] = ID + + err := c.soap.Call("Retrieve", params) + if err != nil { + return errors.New("CventAPI.Retrieve Soap Retrieve Failure: " + err.Error()) + } + + err = c.soap.Unmarshal(&objectDef) + if err != nil { + return errors.New("CventAPI.Retrieve received SOAP Fault: " + err.Error()) + } + return nil +} + // Search is used to Search any Cvent Object using an optional set of filters func (c *CventAPI) Search(ObjectType string, Filters []Filter) (SearchResult, error) { var r SearchResponse @@ -110,3 +132,80 @@ func (c *CventAPI) Search(ObjectType string, Filters []Filter) (SearchResult, er } return r.SearchResult, nil } + +// StructGen is used to generate a Golang struct based on the fields in a CvObject +func (c *CventAPI) StructGen(filePath string, objectType string) error { + + // get fields and info. about the CvObject + var objectList = make([]string, 1) + objectList[0] = objectType + r, err := c.DescribeCvObject(objectList) + if err != nil { + return err + } + foundObjectType := false + for _, CvObjectMetadata := range r { + if CvObjectMetadata.Name == objectType { + foundObjectType = true + } + } + if !foundObjectType { + return errors.New("DescribeCvObject failure") + } + + output := "package gocvent\n" + output += "// " + objectType + "RetrieveResult defines the result wrapper\n" + output += "type " + objectType + "RetrieveResult struct {\n" + output += "CvObject " + objectType + " `xml:\"RetrieveResult>CvObject\"`\n" + output += "}\n" + output += "// " + objectType + " defines the CvObject\n" + output += "type " + objectType + " struct {\n" + + for _, CvObjectMetadata := range r { + if CvObjectMetadata.Name == objectType { + for _, objectField := range CvObjectMetadata.Fields { + + // ignore anything that isn't on the object we're tracking + if objectField.ObjectLocation != "/"+objectType { + continue + } + + dataType := "string" + if objectField.DataType == "Boolean" { + dataType = "bool" + } + if objectField.DataType == "Date Time" { + dataType = "string" // @todo should be whatever golang likes to call datetime + } + + xmlFieldName := strings.TrimSpace(objectField.Name) // drop leading/trailing spaces + structFieldname := strings.Replace(xmlFieldName, " ", "", -1) // don't allow spaces in field name + structFieldname = strings.Replace(structFieldname, "(", "", -1) // don't allow parens in field name + structFieldname = strings.Replace(structFieldname, ")", "", -1) // don't allow parens in field name + + output += "\t" + structFieldname + " " + + dataType + + " `xml:\"" + xmlFieldName + ",attr\"` " + + "\n" + } + } + } + + output += "}\n" + + fileName := filePath + "/" + objectType + ".go" + data := []byte(output) + err = ioutil.WriteFile(fileName, data, 0644) + if err != nil { + return err + } + + // run gofmt on the new definitions file + cmd := exec.Command("gofmt", "-w", fileName) + err = cmd.Run() + if err != nil { + return err + } + + return nil +} diff --git a/gocvent_test.go b/gocvent_test.go index efbe687..8bec381 100644 --- a/gocvent_test.go +++ b/gocvent_test.go @@ -4,6 +4,7 @@ import ( "os" "testing" + objDefs "github.com/matthewpoer/gocvent/definitions" log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" @@ -146,6 +147,7 @@ func TestDescribeCvObjectSingleBadObject(t *testing.T) { objectList[0] = "SomeFakeObjectName" r, err := cvent.DescribeCvObject(objectList) + // skip the conventional err != nil check. This test is expecting a failure. assert.NotEmpty(t, err) assert.Zero(t, len(r)) } @@ -168,6 +170,87 @@ func TestDescribeGlobal(t *testing.T) { assert.NotEmpty(t, r.MaxRecordSet) } +func TestRetrieveEvent(t *testing.T) { + cvent, success, err := genericAuth() + if err != nil || !success { + t.Errorf("TestRetrieveEvent fails because authorization or invocation failed") + return + } + + // get a list of Events, there should always be a few to work with + searchRes, err := cvent.Search("Event", []Filter{}) + if err != nil { + log.Printf("TestRetrieveEvent err from cvent.Search: %s", err) + } + assert.Nil(t, err) + assert.Greater(t, len(searchRes.Ids), 0) + + // No need to test against all events, 3 should be plenty + if len(searchRes.Ids) > 3 { + searchRes.Ids = searchRes.Ids[:3] + } + + // attempt to retrieve basic data about each User + for _, v := range searchRes.Ids { + var objectDef objDefs.EventRetrieveResult + err := cvent.Retrieve("Event", v, &objectDef) + if err != nil { + log.Printf("TestRetrieveEvent err from cvent.Retrieve: %s", err) + } + + assert.Nil(t, err) + assert.NotNil(t, objectDef.CvObject.Capacity) + assert.NotEmpty(t, objectDef.CvObject.Capacity) + assert.NotNil(t, objectDef.CvObject.Currency) + assert.NotEmpty(t, objectDef.CvObject.Currency) + assert.NotNil(t, objectDef.CvObject.EventStatus) + assert.NotEmpty(t, objectDef.CvObject.EventStatus) + assert.NotNil(t, objectDef.CvObject.EventTitle) + assert.NotEmpty(t, objectDef.CvObject.EventTitle) + assert.NotNil(t, objectDef.CvObject.Id) + assert.NotEmpty(t, objectDef.CvObject.Id) + } + +} + +func TestRetrieveUser(t *testing.T) { + cvent, success, err := genericAuth() + if err != nil || !success { + t.Errorf("TestRetrieveUser fails because authorization or invocation failed") + return + } + + // get a list of users, there should always be a few users to work with + searchRes, err := cvent.Search("User", []Filter{}) + if err != nil { + log.Printf("TestRetrieveUser err from cvent.Search: %s", err) + } + assert.Nil(t, err) + assert.Greater(t, len(searchRes.Ids), 0) + + // No need to test against all users, 3 should be plenty + if len(searchRes.Ids) > 3 { + searchRes.Ids = searchRes.Ids[:3] + } + + // attempt to retrieve basic data about each User + for _, v := range searchRes.Ids { + var objectDef objDefs.UserRetrieveResult + err := cvent.Retrieve("User", v, &objectDef) + if err != nil { + log.Printf("TestRetrieveUser err from cvent.Retrieve: %s", err) + } + assert.Nil(t, err) + assert.NotNil(t, objectDef.CvObject.Email) + assert.NotEmpty(t, objectDef.CvObject.Email) + assert.NotNil(t, objectDef.CvObject.Id) + assert.NotEmpty(t, objectDef.CvObject.Id) + assert.NotNil(t, objectDef.CvObject.LastName) + assert.NotEmpty(t, objectDef.CvObject.LastName) + } + +} + func TestSearchNoFilter(t *testing.T) { cvent, success, err := genericAuth() if err != nil || !success { @@ -228,3 +311,24 @@ func TestSearchWithFilters(t *testing.T) { assert.Greater(t, len(r.Ids), 0) assert.Greater(t, len(r.Ids), numberOfSmiths) } + +func TestStructGen(t *testing.T) { + cvent, success, err := genericAuth() + if err != nil || !success { + t.Errorf("TestStructGen fails because authorization or invocation failed") + return + } + assert.Nil(t, err) + + err = cvent.StructGen("definitions", "Contact") + assert.Nil(t, err) + + err = cvent.StructGen("definitions", "Event") + assert.Nil(t, err) + + err = cvent.StructGen("definitions", "Registration") + assert.Nil(t, err) + + err = cvent.StructGen("definitions", "User") + assert.Nil(t, err) +} diff --git a/gosoap/encode.go b/gosoap/encode.go index 38d4d0e..bebc04d 100644 --- a/gosoap/encode.go +++ b/gosoap/encode.go @@ -89,6 +89,29 @@ func recursiveEncode(hm interface{}) { recursiveEncode(v.MapIndex(key).Interface()) } else if key.String() == "Filter" { recursiveEncode(v.MapIndex(key).Interface()) + } else if key.String() == "Ids" { + IDs := xml.StartElement{ + Name: xml.Name{ + Space: "", + Local: "Ids", + }, + Attr: []xml.Attr{ + {Name: xml.Name{Space: "", Local: "xmlns"}, Value: "http://schemas.cvent.com/api/2006-11"}, + }, + } + ID := xml.StartElement{ + Name: xml.Name{ + Space: "", + Local: "Id", + }, + } + + tokens = append(tokens, IDs) + tokens = append(tokens, ID) + tokens = append(tokens, xml.CharData(fmt.Sprintf("%s", v.MapIndex(key)))) + tokens = append(tokens, xml.EndElement{Name: ID.Name}) + tokens = append(tokens, xml.EndElement{Name: IDs.Name}) + } else { t = xml.StartElement{ Name: xml.Name{ diff --git a/samples/RetrieveResponse.xml b/samples/RetrieveResponse.xml new file mode 100644 index 0000000..f925f1b --- /dev/null +++ b/samples/RetrieveResponse.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file