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  //