You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

266 line
6.2KB

  1. package main
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "io/ioutil"
  7. "log"
  8. "net/http"
  9. "strings"
  10. )
  11. //abstract CRUD operation for espoCRM Entity
  12. func crmCreateEntity(entityType string, jsonB []byte) (entity interface{}, err error) {
  13. url := CRMConfig.apiURL(entityType)
  14. jsonStr, err := postRAW(jsonB, url, crmBuildCommonAPIHeader())
  15. if err != nil {
  16. entity, _ = crmRescueDuplicateCreate(err, entityType)
  17. return
  18. }
  19. return crmJSON2Entity(entityType, jsonStr)
  20. }
  21. func crmUpdateEntity(entityType string, id string, jsonB []byte) (entity interface{}, err error) {
  22. url := CRMConfig.apiEntityURL(entityType, id)
  23. jsonStr, err := patchRAW(jsonB, url, crmBuildCommonAPIHeader())
  24. if err != nil {
  25. log.Println(err)
  26. return
  27. }
  28. return crmJSON2Entity(entityType, jsonStr)
  29. }
  30. func crmReplaceEntity(entityType string, id string, jsonB []byte) (entity interface{}, err error) {
  31. url := CRMConfig.apiEntityURL(entityType, id)
  32. jsonStr, err := putRAW(jsonB, url, crmBuildCommonAPIHeader())
  33. if err != nil {
  34. log.Println(err)
  35. return
  36. }
  37. return crmJSON2Entity(entityType, jsonStr)
  38. }
  39. func crmDeleteEntity(entityType string, id string) (deleted bool, err error) {
  40. url := CRMConfig.apiEntityURL(entityType, id)
  41. resp, err := deleteRAW(url, crmBuildCommonAPIHeader())
  42. if err != nil {
  43. log.Println(err)
  44. return
  45. }
  46. deleted = strings.ToLower(resp) == "true"
  47. return
  48. }
  49. //give an id, return json
  50. func crmGetEntity(entityType string, id string) (entity interface{}, err error) {
  51. url := CRMConfig.apiEntityURL(entityType, id)
  52. jsonStr, err := getRAW(url, crmBuildCommonAPIHeader())
  53. if err != nil {
  54. log.Println(err)
  55. return
  56. }
  57. return crmJSON2Entity(entityType, jsonStr)
  58. }
  59. func crmBuildCommonAPIHeader() (headers map[string]string) {
  60. headers = map[string]string{}
  61. headers["Authorization"] = crmAuthHeader()
  62. headers["Accept"] = "application/json"
  63. headers["Content-Type"] = "application/json"
  64. return headers
  65. }
  66. //given a json string, convert it to Typed structure
  67. func crmJSON2Entity(entityType string, data string) (r interface{}, err error) {
  68. switch entityType {
  69. case "Lead":
  70. e := crmdLead{}
  71. err = json.Unmarshal([]byte(data), &e)
  72. r = e
  73. case "Account":
  74. //r = crmdAccount{}
  75. case "Location":
  76. e := crmdLocation{}
  77. err = json.Unmarshal([]byte(data), &e)
  78. r = e
  79. case "Contact":
  80. e := crmdContact{}
  81. err = json.Unmarshal([]byte(data), &e)
  82. r = e
  83. default:
  84. log.Fatalf("crmJSON2Entity: Unknown EntityType %s", entityType)
  85. }
  86. if err != nil {
  87. log.Println(err)
  88. }
  89. return
  90. }
  91. func crmRescueDuplicateCreate(e error, entityType string) (entity interface{}, success bool) {
  92. if !isErrIndicateDuplicate(e) {
  93. return
  94. }
  95. entity, err := e.(errorHTTPResponse).XStatusReason().Data2Entity(entityType)
  96. success = err == nil
  97. return
  98. }
  99. func isErrIndicateDuplicate(e error) (yes bool) {
  100. err, isOurError := e.(errorHTTPResponse)
  101. if !isOurError {
  102. return
  103. }
  104. reason := err.XStatusReason()
  105. yes = strings.ToLower(reason.Reason) == "duplicate"
  106. return
  107. }
  108. type crmdSearchFilter struct {
  109. Attribute string
  110. CompareMethod string //startWith, equals, contains, endsWith, like, isNull, isNotNull , notEquals
  111. ExpectValue string
  112. }
  113. type crmdSearchResult struct {
  114. Total int `json:"total"`
  115. List *json.RawMessage `json:"list"`
  116. }
  117. func crmSearchEntity(entityType string, filters []crmdSearchFilter) (result crmdSearchResult, err error) {
  118. url := CRMConfig.apiURL(entityType)
  119. req, err := http.NewRequest("GET", url, nil)
  120. if err != nil {
  121. log.Println("crmGetRecord: cannot form good http Request")
  122. log.Print(err)
  123. return
  124. }
  125. //auth header
  126. req.Header.Set("Authorization", crmAuthHeader())
  127. req.Header.Set("Accept", "application/json, text/javascript, */*; q=0.01")
  128. req.Header.Set("Content-Type", "application/json")
  129. //query string
  130. q := req.URL.Query()
  131. q.Add("maxSize", "20")
  132. q.Add("maxSize", "0")
  133. q.Add("sortBy", "createdAt")
  134. q.Add("asc", "false")
  135. for k, v := range filters {
  136. switch v.CompareMethod {
  137. case "startWith", "equals", "contains", "endsWith", "like", "notEquals":
  138. q.Add(fmt.Sprintf("where[%d][type]", k), v.CompareMethod)
  139. q.Add(fmt.Sprintf("where[%d][attribute]", k), v.Attribute)
  140. q.Add(fmt.Sprintf("where[%d][value]", k), v.ExpectValue)
  141. case "isNull", "isNotNull":
  142. q.Add(fmt.Sprintf("where[%d][type]", k), v.CompareMethod)
  143. q.Add(fmt.Sprintf("where[%d][attribute]", k), v.Attribute)
  144. default:
  145. log.Printf("Unknown Compare Method %s", v.CompareMethod)
  146. }
  147. }
  148. req.URL.RawQuery = q.Encode()
  149. //debugDumpHTTPRequest(req)
  150. client := &http.Client{}
  151. r, err := client.Do(req)
  152. //debugDumpHTTPResponse(r)
  153. if err != nil {
  154. return
  155. }
  156. defer r.Body.Close()
  157. jsonB, err := ioutil.ReadAll(r.Body)
  158. if err != nil {
  159. return
  160. }
  161. err = json.Unmarshal(jsonB, &result)
  162. return
  163. }
  164. func crmFindEntityByID(entityType string, id string) (entity interface{}, err error) {
  165. id = strings.TrimSpace(id)
  166. if id == "" {
  167. err = errors.New("empty ID not accepted")
  168. return
  169. }
  170. total, list, err := crmFindEntityByAttr(entityType, "id", id)
  171. if total > 1 {
  172. log.Printf("ERROR: more than one(%d) %s associated with %s", total, entityType, id)
  173. }
  174. if err != nil {
  175. return
  176. }
  177. switch entityType {
  178. case "Lead":
  179. e, ok := list.([]crmdLead)
  180. if (!ok) || (len(e) != total) {
  181. return
  182. }
  183. entity = e[0]
  184. case "Livecast":
  185. e, ok := list.([]crmdLiveCast)
  186. if (!ok) || (len(e) != total) {
  187. return
  188. }
  189. entity = e[0]
  190. case "Meeting":
  191. e, ok := list.([]crmdMeeting)
  192. if (!ok) || (len(e) != total) {
  193. return
  194. }
  195. entity = e[0]
  196. default:
  197. err = errors.New("unknown entity type " + entityType)
  198. }
  199. return
  200. }
  201. func crmFindEntityByAttr(entityType, attribute, value string) (total int, list interface{}, err error) {
  202. filters := []crmdSearchFilter{
  203. {attribute, "equals", value},
  204. }
  205. cs, err := crmSearchEntity(entityType, filters)
  206. if err != nil || cs.Total < 1 {
  207. return
  208. }
  209. return cs.toEntityList(entityType)
  210. }
  211. func (m crmdSearchResult) toEntityList(entityType string) (total int, list interface{}, err error) {
  212. total = m.Total
  213. switch entityType {
  214. case "Lead":
  215. e := []crmdLead{}
  216. err = json.Unmarshal(*m.List, &e)
  217. list = e
  218. case "Livecast":
  219. e := []crmdLiveCast{}
  220. err = json.Unmarshal(*m.List, &e)
  221. list = e
  222. case "Meeting":
  223. e := []crmdMeeting{}
  224. err = json.Unmarshal(*m.List, &e)
  225. list = e
  226. default:
  227. err = errors.New("unknown entity type " + entityType)
  228. }
  229. return
  230. }