github.com/mhlo/force@v0.22.28-0.20150915022417-6d05ecfb0b47/metadata2.go (about) 1 package main 2 3 /*import ( 4 "archive/zip" 5 "bitbucket.org/pkg/inflect" 6 "bufio" 7 "bytes" 8 "encoding/base64" 9 "encoding/xml" 10 "errors" 11 "fmt" 12 "io/ioutil" 13 "os" 14 "path/filepath" 15 "reflect" 16 "strconv" 17 "strings" 18 "time" 19 )*/ 20 /* 21 type ForceConnectedApps []ForceConnectedApp 22 23 type ForceConnectedApp struct { 24 Name string `xml:"fullName"` 25 Id string `xml:"id"` 26 Type string `xml:"type"` 27 } 28 29 type ComponentFailure struct { 30 Changed bool `xml:"changed"` 31 Created bool `xml:"created"` 32 Deleted bool `xml:"deleted"` 33 FileName string `xml:"fileName"` 34 FullName string `xml:"fullName"` 35 LineNumber int `xml:"lineNumber"` 36 Problem string `xml:"problem"` 37 ProblemType string `xml:"problemType"` 38 Success bool `xml:"success"` 39 } 40 41 type ComponentSuccess struct { 42 Changed bool `xml:"changed"` 43 Created bool `xml:"created"` 44 Deleted bool `xml:"deleted"` 45 FileName string `xml:"fileName"` 46 FullName string `xml:"fullName"` 47 Id string `xml:"id"` 48 Success bool `xml:"success"` 49 } 50 51 type RunTestResult struct { 52 NumberOfFailures int `xml:"numFailures"` 53 NumberOfTestsRun int `xml:"numTestsRun"` 54 TotalTime int `xml:"totalTime"` 55 } 56 57 type ComponentDetails struct { 58 ComponentSuccesses []ComponentSuccess `xml:"componentSuccesses"` 59 ComponentFailures []ComponentFailure `xml:"componentFailures"` 60 } 61 62 type ForceCheckDeploymentStatusResult struct { 63 CheckOnly bool `xml:"checkOnly"` 64 CompletedDate time.Time `xml:"completedDate"` 65 CreatedDate time.Time `xml:"createdDate"` 66 Details ComponentDetails `xml:"details"` 67 Done bool `xml:"done"` 68 Id string `xml:"id"` 69 NumberComponentErrors int `xml:"numberComponentErrors"` 70 NumberComponentsDeployed int `xml:"numberComponentsDeployed"` 71 NumberComponentsTotal int `xml:"numberComponentsTotal"` 72 NumberTestErrors int `xml:"numberTestErrors"` 73 NumberTestsCompleted int `xml:"numberTestsCompleted"` 74 NumberTestsTotal int `xml:"numberTestsTotal"` 75 RollbackOnError bool `xml:"rollbackOnError"` 76 Status string `xml:"status"` 77 Success bool `xml:"success"` 78 } 79 80 type ForceMetadataDeployProblem struct { 81 Changed bool `xml:"changed"` 82 Created bool `xml:"created"` 83 Deleted bool `xml:"deleted"` 84 Filename string `xml:"fileName"` 85 Name string `xml:"fullName"` 86 Problem string `xml:"problem"` 87 ProblemType string `xml:"problemType"` 88 Success bool `xml:"success"` 89 } 90 91 type ForceMetadataQueryElement struct { 92 Name string 93 Members []string 94 } 95 96 type ForceMetadataQuery []ForceMetadataQueryElement 97 98 type ForceMetadataFiles map[string][]byte 99 100 type ForceMetadata struct { 101 ApiVersion string 102 Force *Force 103 } 104 105 type ForceDeployOptions struct { 106 AllowMissingFiles bool `xml:"allowMissingFiles"` 107 AutoUpdatePackage bool `xml:"autoUpdatePackage"` 108 CheckOnly bool `xml:"checkOnly"` 109 IgnoreWarnings bool `xml:"ignoreWarnings"` 110 PerformRetrieve bool `xml:"performRetrieve"` 111 PurgeOnDelete bool `xml:"purgeOnDelete"` 112 RollbackOnError bool `xml:"rollbackOnError"` 113 RunAllTests bool `xml:"runAllTests"` 114 runTests []string `xml:"runTests"` 115 SinglePackage bool `xml:"singlePackage"` 116 } 117 */ 118 /* These structs define which options are available and which are 119 required for the various field types you can create. Reflection 120 is used to leverage these structs in validating options when creating 121 a custom field. 122 */ 123 /* 124 type GeolocationFieldRequired struct { 125 DisplayLocationInDecimal bool `xml:"displayLocationInDecimal"` 126 Scale int `xml:"scale"` 127 } 128 129 type GeolocationField struct { 130 DsiplayLocationInDecimal bool `xml:"displayLocationInDecimal"` 131 Required bool `xml:"required"` 132 Scale int `xml:"scale"` 133 Description string `xml:"description"` 134 HelpText string `xml:"helpText"` 135 } 136 137 type AutoNumberFieldRequired struct { 138 StartingNumber int `xml:"startingNumber"` 139 DisplayFormat string `xml:"displayFormat"` 140 } 141 142 type AutoNumberField struct { 143 StartingNumber int `xml:"startingNumber"` 144 DisplayFormat string `xml:"displayFormat"` 145 Description string `xml:"description"` 146 HelpText string `xml:"helpText"` 147 ExternalId bool `xml:"externalId"` 148 } 149 150 type FloatFieldRequired struct { 151 Precision int `xml:"precision"` 152 Scale int `xml:"scale"` 153 } 154 155 type FloatField struct { 156 Description string `xml:"description"` 157 HelpText string `xml:"helpText"` 158 Unique bool `xml:"unique"` 159 ExternalId bool `xml:"externalId"` 160 DefaultValue uint `xml:"defaultValue"` 161 Precision int `xml:"precision"` 162 Scale int `xml:"scale"` 163 Formula string `xml:"formula"` 164 FormulaTreatBlanksAs string `xml:"formulaTreatBlanksAs"` 165 } 166 167 type NumberFieldRequired struct { 168 Precision int `xml:"precision"` 169 Scale int `xml:"scale"` 170 } 171 172 type NumberField struct { 173 Description string `xml:"description"` 174 HelpText string `xml:"helpText"` 175 Unique bool `xml:"unique"` 176 ExternalId bool `xml:"externalId"` 177 DefaultValue uint `xml:"defaultValue"` 178 Formula string `xml:"formula"` 179 FormulaTreatBlanksAs string `xml:"formulaTreatBlanksAs"` 180 Precision int `xml:"precision"` 181 Scale int `xml:"scale"` 182 } 183 184 type DatetimeFieldRequired struct { 185 } 186 187 type DatetimeField struct { 188 Description string `xml:"description"` 189 HelpText string `xml:"helpText"` 190 DefaultValue time.Time `xml:"defaultValue"` 191 Required bool `xml:"required"` 192 Formula string `xml:"formula"` 193 FormulaTreatBlanksAs string `xml:"formulaTreatBlanksAs"` 194 } 195 196 type PicklistValue struct { 197 FullName string `xml:"fullName"` 198 Default bool `xml:"default"` 199 } 200 201 type PicklistFieldRequired struct { 202 Picklist []PicklistValue `xml:"picklist>picklistValues"` 203 } 204 205 type PicklistField struct { 206 Picklist []PicklistValue `xml:"picklist>picklistValues"` 207 } 208 209 type BoolFieldRequired struct { 210 DefaultValue bool `xml:"defaultValue"` 211 } 212 213 type BoolField struct { 214 Description string `xml:"description"` 215 HelpText string `xml:"helpText"` 216 DefaultValue bool `xml:"defaultValue"` 217 Formula string `xml:"formula"` 218 FormulaTreatBlanksAs string `xml:"formulaTreatBlanksAs"` 219 } 220 221 type DescribeMetadataObject struct { 222 ChildXmlNames []string `xml:"childXmlNames"` 223 DirectoryName string `xml:"directoryName"` 224 InFolder bool `xml:"inFolder"` 225 MetaFile bool `xml:"metaFile"` 226 Suffix string `xml:"suffix"` 227 XmlName string `xml:"xmlName"` 228 } 229 230 type MetadataDescribeResult struct { 231 NamespacePrefix string `xml:"organizationNamespace"` 232 PartialSaveAllowed bool `xml:"partialSaveAllowed"` 233 TestRequired bool `xml:"testRequired"` 234 MetadataObjects []DescribeMetadataObject `xml:"metadataObjects"` 235 } 236 237 type MetadataDescribeValueTypeResult struct { 238 ValueTypeFields []MetadataValueTypeField `xml:"result"` 239 } 240 241 type MetadataValueTypeField struct { 242 //Fields MetadataValueTypeField 243 ForeignKeyDomain string 244 IsForeignKey bool 245 IsNameField bool 246 MinOccurs int 247 Name string 248 SoapType string 249 } 250 251 type MDFileProperties struct { 252 CreatedById string `xml:"createdById"` 253 CreateByName string `xml:"createdByName"` 254 CreateDate time.Time `xml:"createdDate"` 255 FileName string `xml:"fileName"` 256 FullName string `xml:"fullName"` 257 Id string `xml:"id"` 258 LastModifiedById string `xml:"lastModifiedById"` 259 LastModifiedByName string `xml:"lastModifiedByName"` 260 LastModifedByDate time.Time `xml:"lastModifiedByDate"` 261 ManageableState string `xml:"manageableState"` 262 NamespacePrefix string `xml:"namespacePrefix"` 263 Type string `xml:"type"` 264 } 265 266 type ListMetadataResponse struct { 267 Result []MDFileProperties `xml:"result"` 268 } 269 270 type EncryptedFieldRequired struct { 271 Length int `xml:"length"` 272 MaskType string `xml:"maskType"` 273 MaskChar string `xml:"maskChar"` 274 } 275 276 type EncryptedField struct { 277 Label string `xml:"label"` 278 Name string `xml:"fullName"` 279 Required bool `xml:"required"` 280 Length int `xml:"length"` 281 Description string `xml:"description"` 282 HelpText string `xml:"helpText"` 283 MaskType string `xml:"maskType"` 284 MaskChar string `xml:"maskChar"` 285 } 286 287 type StringFieldRequired struct { 288 Length int `xml:"length"` 289 } 290 291 type StringField struct { 292 Label string `xml:"label"` 293 Name string `xml:"fullName"` 294 Required bool `xml:"required"` 295 Length int `xml:"length"` 296 Description string `xml:"description"` 297 HelpText string `xml:"helpText"` 298 Unique bool `xml:"unique"` 299 CaseSensitive bool `xml:"caseSensitive"` 300 ExternalId bool `xml:"externalId"` 301 DefaultValue string `xml:"defaultValue"` 302 Formula string `xml:"formula"` 303 FormulaTreatBlanksAs string `xml:"formulaTreatBlanksAs"` 304 } 305 306 type PhoneFieldRequired struct { 307 } 308 309 type PhoneField struct { 310 Label string `xml:"label"` 311 Name string `xml:"fullName"` 312 Required bool `xml:"required"` 313 Description string `xml:"description"` 314 HelpText string `xml:"helpText"` 315 DefaultValue string `xml:"defaultValue"` 316 } 317 318 type EmailFieldRequired struct { 319 } 320 321 type TextAreaFieldRequired struct { 322 } 323 324 type TextAreaField struct { 325 Label string `xml:"label"` 326 Name string `xml:"fullName"` 327 Required bool `xml:"required"` 328 Description string `xml:"description"` 329 HelpText string `xml:"helpText"` 330 DefaultValue string `xml:"defaultValue"` 331 } 332 333 type LongTextAreaFieldRequired struct { 334 Length int `xml:"length"` 335 VisibleLines int `xml:"visibleLines"` 336 } 337 338 type LongTextAreaField struct { 339 Label string `xml:"label"` 340 Name string `xml:"fullName"` 341 Required bool `xml:"required"` 342 Description string `xml:"description"` 343 HelpText string `xml:"helpText"` 344 DefaultValue string `xml:"defaultValue"` 345 Length int `xml:"length"` 346 VisibleLines int `xml:"visibleLines"` 347 } 348 349 type RichTextAreaFieldRequired struct { 350 Length int `xml:"length"` 351 VisibleLines int `xml:"visibleLines"` 352 } 353 354 type RichTextAreaField struct { 355 Label string `xml:"label"` 356 Name string `xml:"fullName"` 357 Required bool `xml:"required"` 358 Description string `xml:"description"` 359 HelpText string `xml:"helpText"` 360 Length int `xml:"length"` 361 VisibleLines int `xml:"visibleLines"` 362 } 363 364 type LookupFieldRequired struct{} 365 366 type LookupField struct { 367 ReferenceTo string `xml:"referenceTo"` 368 RelationshipLabel string `xml:"relationshipLabel"` 369 RelationshipName string `xml:"relationshipName"` 370 } 371 372 type MasterDetailRequired struct{} 373 374 type MasterDetail struct { 375 ReferenceTo string `xml:"referenceTo"` 376 RelationshipLabel string `xml:"relationshipLabel"` 377 RelationshipName string `xml:"relationshipName"` 378 } 379 380 type MetaData struct { 381 FullName string 382 } 383 384 type MetaDataWithContent struct { 385 MetaData 386 Content []byte 387 } 388 389 type CustomField struct { 390 MetaData 391 CaseSensitive bool 392 DefaultValue bool 393 DeleteConstraint DeleteConstraint 394 Deprecated bool 395 Description string 396 DisplayFormat string 397 DisplayLocationInDecimal bool 398 Encrypted bool 399 ExternalDeveloperName string 400 ExternalId bool 401 Formula string 402 FormulaTreatBlankAs TreatBlankAs 403 Indexed bool 404 InlineHelperText string 405 IsFilteringDisabled bool 406 IsNameField bool 407 IsSortingDisabled bool 408 ReparentableMasterDetail bool 409 Label string 410 Length int 411 LookupFilter LookupFilter 412 MaskChar EncryptedFieldMaskChar 413 MaskType EncryptedFieldMaskType 414 Picklist Picklist 415 PopulateExistingRows bool 416 Precision int 417 ReferenceTargetField string 418 ReferenceTo string 419 RelationshipLabel string 420 RelationshipName string 421 RelationshipOrder int 422 Required bool 423 Scale int 424 StartingNumber int 425 StripMarkup bool 426 SummarizedField string 427 SummaryFilterItems []FilterItem 428 SummaryForeignKey string 429 SummaryOperations SummaryOperations 430 TrackFeedHistory bool 431 TrackHistory bool 432 TrackTrending bool 433 TrueValueIndexed bool 434 Type FieldType 435 Unique bool 436 VisibleLines int 437 WriteRequiresMasterRead bool 438 } 439 440 type EncryptedFieldMaskChar int 441 const ( 442 Asterisk EncryptedFieldMaskChar = 1 + iota 443 X 444 ) 445 var encryptedFieldMaskChars = [...]string { 446 "asterisk", 447 "X", 448 } 449 func (efm EncryptedFieldMaskChar) String() string { return encryptedFieldMaskChars[efm - 1] } 450 451 type EncryptedFieldMaskType int 452 const ( 453 All EncryptedFieldMaskType = 1 + iota 454 CreditCard 455 Ssn 456 LastFour 457 Sin 458 Nino 459 ) 460 var encryptedFieldMaskTypes = [...]string { 461 "all", 462 "creditCard", 463 "ssn", 464 "lastFour", 465 "sin", 466 "nino", 467 } 468 func (efmt EncryptedFieldMaskType) String() string { return encryptedFieldMaskTypes[efmt - 1] } 469 470 type DeleteConstraint int 471 const ( 472 SetNull DeleteConstraint = 1 + iota 473 Restrict 474 Cascade 475 ) 476 var deleteConstraints = [...]string { 477 "SetNull", 478 "Restrict", 479 "Cascade", 480 } 481 func (dc DeleteConstraint) String() string { return deleteConstraints[dc - 1] } 482 483 type TreatBlankAs int 484 const ( 485 BlankAsBlank TreatBlankAs = 1 + iota 486 BlankAsZero 487 ) 488 var treatBlankAs = [...]string { 489 "BlankAsBlank", 490 "BlankAsZero", 491 } 492 func (tba TreatBlankAs) String() string { return treatBlankAs[tba - 1] } 493 494 type FilterOperation int 495 const ( 496 Equals FilterOperation = 1 + iota 497 NotEqual 498 LessThan 499 GreaterThan 500 LessOrEqual 501 GreaterOrEqual 502 Contains 503 NotContain 504 StartsWith 505 Includes 506 Excludes 507 Within 508 ) 509 var filterOperations = [...]string { 510 "equals", 511 "notEqual", 512 "lessThan", 513 "greaterThan", 514 "lessOrEqual", 515 "greaterOrEqual", 516 "contains", 517 "notContain", 518 "startsWith", 519 "includes", 520 "excludes", 521 "within", 522 } 523 func (fo FilterOperation) String() string { return filterOperations[fo - 1] } 524 525 type PickList struct { 526 ControllingField string 527 PicklistValues []PicklistValue 528 Sorted bool 529 } 530 531 type FilterItem struct { 532 Field string 533 Operation FilterOperation 534 Value string 535 ValueField string 536 } 537 538 type LookupFilter struct { 539 Active bool 540 BooleanFilter string 541 Description string 542 ErrorMessage string 543 FilterItems []FilterItem 544 InfoMessage string 545 IsOptional bool 546 } 547 548 549 // Example of how to use Go's reflection 550 // Print the attributes of a Data Model 551 func getAttributes(m interface{}) map[string]reflect.StructField { 552 typ := reflect.TypeOf(m) 553 // if a pointer to a struct is passed, get the type of the dereferenced object 554 if typ.Kind() == reflect.Ptr { 555 typ = typ.Elem() 556 } 557 558 // create an attribute data structure as a map of types keyed by a string. 559 attrs := make(map[string]reflect.StructField) 560 // Only structs are supported so return an empty result if the passed object 561 // isn't a struct 562 if typ.Kind() != reflect.Struct { 563 fmt.Printf("%v type can't have attributes inspected\n", typ.Kind()) 564 return attrs 565 } 566 567 // loop through the struct's fields and set the map 568 for i := 0; i < typ.NumField(); i++ { 569 p := typ.Field(i) 570 if !p.Anonymous { 571 attrs[strings.ToLower(p.Name)] = p 572 } 573 } 574 575 return attrs 576 } 577 578 func ValidateOptionsAndDefaults(typ string, fields map[string]reflect.StructField, requiredDefaults reflect.Value, options map[string]string) (newOptions map[string]string, err error) { 579 newOptions = make(map[string]string) 580 // validate optional attributes 581 for name, value := range options { 582 fmt.Printf("%-v", fields) 583 field, ok := fields[strings.ToLower(name)] 584 if !ok { 585 ErrorAndExit(fmt.Sprintf("validation error: %s:%s is not a valid option for field type %s", name, value, typ)) 586 } else { 587 newOptions[field.Tag.Get("xml")] = options[name] 588 } 589 } 590 591 // validate required attributes 592 s := requiredDefaults 593 tod := s.Type() 594 for i := 0; i < s.NumField(); i++ { 595 _, ok := options[strings.ToLower(tod.Field(i).Name)] 596 if !ok { 597 switch s.Field(i).Type().Name() { 598 case "int": 599 newOptions[tod.Field(i).Tag.Get("xml")] = strconv.Itoa(s.Field(i).Interface().(int)) 600 break 601 case "bool": 602 if typ == "bool" { 603 if _, ok = options["formula"]; ok { 604 if tod.Field(i).Tag.Get("xml") == "defaultValue" { 605 break 606 } 607 } 608 } //else { 609 newOptions[tod.Field(i).Tag.Get("xml")] = strconv.FormatBool(s.Field(i).Interface().(bool)) 610 //} 611 break 612 case "string": 613 newOptions[tod.Field(i).Tag.Get("xml")] = s.Field(i).Interface().(string) 614 break 615 } 616 } else { 617 newOptions[tod.Field(i).Tag.Get("xml")] = options[strings.ToLower(tod.Field(i).Name)] 618 } 619 } 620 return newOptions, err 621 } 622 623 func (fm *ForceMetadata) ValidateFieldOptions(typ string, options map[string]string) (newOptions map[string]string, err error) { 624 625 newOptions = make(map[string]string) 626 var attrs map[string]reflect.StructField 627 var s reflect.Value 628 629 switch typ { 630 case "picklist": 631 attrs = getAttributes(&PicklistField{}) 632 s = reflect.ValueOf(&PicklistFieldRequired{}).Elem() 633 case "phone": 634 attrs = getAttributes(&PhoneField{}) 635 s = reflect.ValueOf(&PhoneFieldRequired{}).Elem() 636 break 637 case "email", "url": 638 attrs = getAttributes(&StringField{}) 639 s = reflect.ValueOf(&EmailFieldRequired{}).Elem() 640 break 641 case "encryptedtext": 642 attrs = getAttributes(&EncryptedField{}) 643 s = reflect.ValueOf(&EncryptedFieldRequired{175, "all", "asterisk"}).Elem() 644 break 645 case "string", "text": 646 attrs = getAttributes(&StringField{}) 647 if _, ok := options["formula"]; ok { 648 s = reflect.ValueOf(&StringFieldRequired{}).Elem() 649 } else { 650 s = reflect.ValueOf(&StringFieldRequired{255}).Elem() 651 } 652 break 653 case "textarea": 654 attrs = getAttributes(&TextAreaField{}) 655 s = reflect.ValueOf(&TextAreaFieldRequired{}).Elem() 656 break 657 case "longtextarea": 658 attrs = getAttributes(&LongTextAreaField{}) 659 s = reflect.ValueOf(&LongTextAreaFieldRequired{32768, 5}).Elem() 660 break 661 case "richtextarea": 662 attrs = getAttributes(&RichTextAreaField{}) 663 s = reflect.ValueOf(&RichTextAreaFieldRequired{32768, 5}).Elem() 664 break 665 case "bool", "boolean", "checkbox": 666 attrs = getAttributes(&BoolField{}) 667 if _, ok := options["formula"]; ok { 668 s = reflect.ValueOf(&BoolFieldRequired{}).Elem() 669 } else { 670 s = reflect.ValueOf(&BoolFieldRequired{false}).Elem() 671 } 672 break 673 case "datetime", "date": 674 attrs = getAttributes(&DatetimeField{}) 675 s = reflect.ValueOf(&DatetimeFieldRequired{}).Elem() 676 break 677 case "float", "double", "percent", "currency": 678 attrs = getAttributes(&FloatField{}) 679 s = reflect.ValueOf(&FloatFieldRequired{16, 2}).Elem() 680 break 681 case "number", "int": 682 attrs = getAttributes(&NumberField{}) 683 s = reflect.ValueOf(&NumberFieldRequired{18, 0}).Elem() 684 break 685 case "autonumber": 686 attrs = getAttributes(&AutoNumberField{}) 687 s = reflect.ValueOf(&AutoNumberFieldRequired{0, "AN-{00000}"}).Elem() 688 break 689 case "geolocation": 690 attrs = getAttributes(&GeolocationField{}) 691 s = reflect.ValueOf(&GeolocationFieldRequired{true, 5}).Elem() 692 break 693 case "lookup": 694 attrs = getAttributes(&LookupField{}) 695 s = reflect.ValueOf(&LookupFieldRequired{}).Elem() 696 break 697 case "masterdetail": 698 attrs = getAttributes(&MasterDetail{}) 699 s = reflect.ValueOf(&MasterDetailRequired{}).Elem() 700 break 701 default: 702 //ErrorAndExit(fmt.Sprintf("Field type %s is not implemented.", typ)) 703 break 704 } 705 706 fmt.Println("Attrs: ", s) 707 newOptions, err = ValidateOptionsAndDefaults(typ, attrs, s, options) 708 709 return newOptions, nil 710 } 711 712 func NewForceMetadata(force *Force) (fm *ForceMetadata) { 713 fm = &ForceMetadata{ApiVersion: apiVersionNumber, Force: force} 714 return 715 } 716 */