github.com/uvalib/orcid-access-ws@v0.0.0-20250612130209-7d062dbabf9d/orcidaccessws/orcid/helpers.go (about) 1 package orcid 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "errors" 7 "fmt" 8 "github.com/uvalib/orcid-access-ws/orcidaccessws/api" 9 "github.com/uvalib/orcid-access-ws/orcidaccessws/config" 10 "github.com/uvalib/orcid-access-ws/orcidaccessws/logger" 11 "html" 12 "net/http" 13 "strings" 14 "text/template" 15 ) 16 17 // log the contents of an activity update request 18 func logActivityUpdateRequest(activity api.ActivityUpdate) { 19 20 if config.Configuration.Debug { 21 fmt.Println("UpdateCode:", activity.UpdateCode) 22 fmt.Println("Work Title:", activity.Work.Title) 23 fmt.Println("Work Abstract:", activity.Work.Abstract) 24 fmt.Println("PublicationDate:", activity.Work.PublicationDate) 25 fmt.Println("URL:", activity.Work.URL) 26 fmt.Println("Authors:", activity.Work.Authors) 27 fmt.Println("ResourceType:", activity.Work.ResourceType) 28 } 29 } 30 31 func makeUpdateActivityBody(activity api.ActivityUpdate) (string, error) { 32 33 t, err := template.ParseFiles("data/work-activity-template.xml") 34 if err != nil { 35 logger.Log(fmt.Sprintf("ERROR: template parse error: %s", err)) 36 return "", err 37 } 38 39 // parse the publication date 40 YYYY, MM, DD := splitDate(activity.Work.PublicationDate) 41 42 // create our template data structure 43 data := struct { 44 PutCode string 45 Title string 46 Abstract string 47 ResourceType string 48 PublicationYear string 49 PublicationMonth string 50 PublicationDay string 51 Identifier string 52 URL string 53 Authors []api.Person 54 }{ 55 activity.UpdateCode, 56 htmlEncodeString(activity.Work.Title), 57 htmlEncodeString(activity.Work.Abstract), 58 activity.Work.ResourceType, 59 YYYY, 60 MM, 61 DD, 62 idFromDoiURL(activity.Work.URL), 63 activity.Work.URL, 64 htmlEncodePersonArray(api.SortPeople(activity.Work.Authors)), 65 } 66 67 var buffer bytes.Buffer 68 err = t.Execute(&buffer, data) 69 if err != nil { 70 logger.Log(fmt.Sprintf("ERROR: template execute error: %s", err)) 71 return "", err 72 } 73 74 s := buffer.String() 75 76 if config.Configuration.Debug { 77 fmt.Printf("XML:\n%s\n", s) 78 } 79 return s, nil 80 } 81 82 // check the error response to identify an appropriate http status response 83 func mapErrorResponseToStatus(err error) int { 84 //logger.Log(fmt.Sprintf("ERROR: [%s]", err.Error())) 85 if strings.Contains(err.Error(), " timeout") { 86 return http.StatusRequestTimeout 87 } 88 89 return http.StatusInternalServerError 90 } 91 92 func checkCommonResponse(body string) (int, error) { 93 94 cr := orcidCommonResponse{} 95 err := json.Unmarshal([]byte(body), &cr) 96 if err != nil { 97 logger.Log(fmt.Sprintf("ERROR: json unmarshal: %s", err)) 98 return http.StatusInternalServerError, err 99 } 100 101 // check protocol version to ensure we know what to do with this 102 if cr.Version != publicProtocolVersion { 103 logger.Log(fmt.Sprintf("ORCID protocol version not supported. Require: %s, received: %s", publicProtocolVersion, cr.Version)) 104 return http.StatusHTTPVersionNotSupported, nil 105 } 106 107 // is there an error string 108 if cr.Error.Value != "" { 109 if strings.HasPrefix(cr.Error.Value, "Not found") == true { 110 return http.StatusNotFound, nil 111 } 112 113 // not sure, just return a general error 114 return http.StatusInternalServerError, errors.New(cr.Error.Value) 115 } 116 117 return http.StatusOK, nil 118 } 119 120 func transformDetailsResponse(person *orcidPersonResponse) *api.OrcidDetails { 121 return constructDetails(person) 122 } 123 124 //func transformSearchResponse(search orcidResults) []*api.OrcidDetails { 125 // results := make([]*api.OrcidDetails, 0) 126 // for _, e := range search.Results { 127 // od := constructDetails(&e.Profile) 128 // od.Relevancy = fmt.Sprintf("%.6f", e.Relevancy.Value) 129 // results = append(results, od) 130 // } 131 // return (results) 132 //} 133 134 func constructDetails(person *orcidPersonResponse) *api.OrcidDetails { 135 136 od := new(api.OrcidDetails) 137 138 od.Orcid = person.Name.Path 139 od.URI = fmt.Sprintf("%s/%s", config.Configuration.OrcidOauthURL, person.Name.Path) 140 od.DisplayName = person.Name.DisplayName.Value 141 od.FirstName = person.Name.GivenName.Value 142 od.LastName = person.Name.FamilyName.Value 143 od.Biography = person.Biography.Content 144 145 // od.Keywords = make([]string, 0) 146 // for _, e := range profile.Bio.Keywords.Keywords { 147 // od.Keywords = append(od.Keywords, e.Value) 148 // } 149 150 // od.ResearchUrls = make([]string, 0) 151 // for _, e := range profile.Bio.Urls.Urls { 152 // od.ResearchUrls = append(od.ResearchUrls, e.URL.Value) 153 // } 154 155 return (od) 156 } 157 158 // when including content embedded in XML, we should HTML encode it. 159 func htmlEncodePersonArray(array []api.Person) []api.Person { 160 161 encoded := make([]api.Person, len(array), len(array)) 162 for ix, value := range array { 163 164 p := api.Person{ 165 Index: value.Index, 166 FirstName: htmlEncodeString(value.FirstName), 167 LastName: htmlEncodeString(value.LastName), 168 } 169 encoded[ix] = p 170 } 171 return encoded 172 } 173 174 func htmlEncodeString(value string) string { 175 // HTML encoding 176 encoded := html.EscapeString(value) 177 178 // encode percent characters 179 encoded = strings.Replace(encoded, "%", "%25", -1) 180 return encoded 181 } 182 183 // Split a date in the form YYYY-MM-DD into its components 184 func splitDate(date string) (string, string, string) { 185 tokens := strings.Split(date, "-") 186 var YYYY, MM, DD string 187 if len(tokens) > 0 { 188 YYYY = tokens[0] 189 } 190 191 if len(tokens) > 1 { 192 MM = tokens[1] 193 } 194 195 if len(tokens) > 2 { 196 DD = tokens[2] 197 } 198 return YYYY, MM, DD 199 } 200 201 func idFromDoiURL(url string) string { 202 return strings.Replace(url, "https://doi.org/", "", -1) 203 } 204 205 // 206 // end of file 207 //