github.com/uvalib/orcid-access-ws@v0.0.0-20250612130209-7d062dbabf9d/orcidaccessws/handlers/update_activity_handler.go (about)

     1  package handlers
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  	"github.com/gorilla/mux"
     8  	"github.com/uvalib/orcid-access-ws/orcidaccessws/api"
     9  	"github.com/uvalib/orcid-access-ws/orcidaccessws/authtoken"
    10  	"github.com/uvalib/orcid-access-ws/orcidaccessws/config"
    11  	"github.com/uvalib/orcid-access-ws/orcidaccessws/dao"
    12  	"github.com/uvalib/orcid-access-ws/orcidaccessws/logger"
    13  	"github.com/uvalib/orcid-access-ws/orcidaccessws/orcid"
    14  	"io"
    15  	"io/ioutil"
    16  	"net/http"
    17  )
    18  
    19  var emptyUpdateCode = ""
    20  
    21  // UpdateActivity -- update activity handler
    22  func UpdateActivity(w http.ResponseWriter, r *http.Request) {
    23  
    24  	vars := mux.Vars(r)
    25  	id := vars["id"]
    26  	token := r.URL.Query().Get("auth")
    27  
    28  	// parameters OK?
    29  	if isEmpty(id) || isEmpty(token) {
    30  		status := http.StatusBadRequest
    31  		encodeUpdateActivityResponse(w, status, http.StatusText(status), emptyUpdateCode)
    32  		return
    33  	}
    34  
    35  	// validate the token
    36  	if authtoken.Validate(config.Configuration.SharedSecret, token) == false {
    37  		status := http.StatusForbidden
    38  		encodeUpdateActivityResponse(w, status, http.StatusText(status), emptyUpdateCode)
    39  		return
    40  	}
    41  
    42  	decoder := json.NewDecoder(r.Body)
    43  	activity := api.ActivityUpdate{}
    44  
    45  	if err := decoder.Decode(&activity); err != nil {
    46  		logger.Log(fmt.Sprintf("ERROR: decoding update activity request payload: %s", err))
    47  		status := http.StatusBadRequest
    48  		encodeUpdateActivityResponse(w, status,
    49  			fmt.Sprintf("%s (%s)", http.StatusText(status), err.Error()),
    50  			emptyUpdateCode)
    51  		return
    52  	}
    53  
    54  	defer io.Copy(ioutil.Discard, r.Body)
    55  	defer r.Body.Close()
    56  
    57  	if err := validateRequestPayload(activity); err != nil {
    58  		logger.Log(fmt.Sprintf("ERROR: invalid request payload: %s", err))
    59  		status := http.StatusBadRequest
    60  		encodeUpdateActivityResponse(w, status,
    61  			fmt.Sprintf("%s (%s)", http.StatusText(status), err.Error()),
    62  			emptyUpdateCode)
    63  		return
    64  	}
    65  
    66  	// get the users ORCID attributes
    67  	attributes, err := dao.Store.GetOrcidAttributesByCid(id)
    68  	if err != nil {
    69  		logger.Log(fmt.Sprintf("ERROR: %s", err.Error()))
    70  		status := http.StatusInternalServerError
    71  		encodeUpdateActivityResponse(w, status,
    72  			fmt.Sprintf("%s (%s)", http.StatusText(status), err.Error()),
    73  			emptyUpdateCode)
    74  		return
    75  	}
    76  
    77  	// we did not find the item, return 404
    78  	if attributes == nil || len(attributes) == 0 {
    79  		status := http.StatusNotFound
    80  		encodeUpdateActivityResponse(w, status, http.StatusText(status), emptyUpdateCode)
    81  		return
    82  	}
    83  
    84  	// verify the attributes are sufficient for our needs
    85  	if err := validateOrcidAttributes(*attributes[0]); err != nil {
    86  		logger.Log(fmt.Sprintf("ERROR: invalid ORCID attributes for cid %s: %s", id, err))
    87  		status := http.StatusBadRequest
    88  		encodeUpdateActivityResponse(w, status,
    89  			fmt.Sprintf("%s (%s)", http.StatusText(status), err.Error()),
    90  			emptyUpdateCode)
    91  		return
    92  	}
    93  
    94  	// update the activity
    95  	updateCode, status, err := orcid.UpdateOrcidActivity(attributes[0].Orcid, attributes[0].OauthAccessToken, activity)
    96  
    97  	// the token might be expired, lets try to renew it
    98  	if false { //status == http.StatusUnauthorized {
    99  		var newAccessToken = ""
   100  		var newRefreshToken = ""
   101  		// renew the access token...
   102  		newAccessToken, newRefreshToken, status, err = orcid.RenewAccessToken(attributes[0].OauthRefreshToken)
   103  		if status == http.StatusOK {
   104  			attributes[0].OauthAccessToken = newAccessToken
   105  			attributes[0].OauthRefreshToken = newRefreshToken
   106  			// save the new tokens
   107  			err = dao.Store.SetOrcidAttributesByCid(id, *attributes[0])
   108  
   109  			// if successful, retry the activity update
   110  			if err == nil {
   111  				updateCode, status, err = orcid.UpdateOrcidActivity(attributes[0].Orcid, attributes[0].OauthAccessToken, activity)
   112  			} else {
   113  				logger.Log(fmt.Sprintf("ERROR: %s", err.Error()))
   114  				status = http.StatusInternalServerError
   115  			}
   116  		}
   117  	}
   118  
   119  	// we did got an error, return it
   120  	if status != http.StatusOK {
   121  		encodeUpdateActivityResponse(w, status,
   122  			fmt.Sprintf("%s (%s)", http.StatusText(status), err), emptyUpdateCode)
   123  		return
   124  	}
   125  
   126  	encodeUpdateActivityResponse(w, status, http.StatusText(status), updateCode)
   127  }
   128  
   129  // basic validation that the required fields for the activity update request exist
   130  func validateRequestPayload(activity api.ActivityUpdate) error {
   131  
   132  	if len(activity.Work.Title) == 0 {
   133  		return errors.New("empty work title")
   134  	}
   135  
   136  	if len(activity.Work.ResourceType) == 0 {
   137  		return errors.New("empty work resource type")
   138  	}
   139  
   140  	if len(activity.Work.URL) == 0 {
   141  		return errors.New("empty work url")
   142  	}
   143  
   144  	return nil
   145  }
   146  
   147  // validation that the necessary ORCID attributes exist before we use them
   148  func validateOrcidAttributes(attributes api.OrcidAttributes) error {
   149  
   150  	if len(attributes.Orcid) == 0 {
   151  		return errors.New("blank ORCID attribute")
   152  	}
   153  
   154  	if len(attributes.OauthAccessToken) == 0 {
   155  		return errors.New("blank OAuth access token")
   156  	}
   157  
   158  	if len(attributes.OauthRefreshToken) == 0 {
   159  		return errors.New("blank OAuth refresh token")
   160  	}
   161  
   162  	return nil
   163  }
   164  
   165  //
   166  // end of file
   167  //