github.com/decred/politeia@v1.4.0/politeiawww/client/error.go (about)

     1  // Copyright (c) 2020-2021 The Decred developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package client
     6  
     7  import (
     8  	"fmt"
     9  	"net/http"
    10  	"strings"
    11  
    12  	cmplugin "github.com/decred/politeia/politeiad/plugins/comments"
    13  	piplugin "github.com/decred/politeia/politeiad/plugins/pi"
    14  	tkplugin "github.com/decred/politeia/politeiad/plugins/ticketvote"
    15  	umplugin "github.com/decred/politeia/politeiad/plugins/usermd"
    16  	cmv1 "github.com/decred/politeia/politeiawww/api/comments/v1"
    17  	rcv1 "github.com/decred/politeia/politeiawww/api/records/v1"
    18  	tkv1 "github.com/decred/politeia/politeiawww/api/ticketvote/v1"
    19  )
    20  
    21  // ErrorReply represents the request body that is returned from politeiawww
    22  // when an error occurs. PluginID will only be populated if the error occurred
    23  // during execution of a plugin command.
    24  type ErrorReply struct {
    25  	PluginID     string
    26  	ErrorCode    int
    27  	ErrorContext string
    28  }
    29  
    30  // RespErr represents a politeiawww response error. A RespErr is returned
    31  // anytime the politeiawww response is not a 200.
    32  //
    33  // The various politeiawww APIs can have overlapping error codes. The API is
    34  // included to allow the Error() method to return the correct human readable
    35  // error message.
    36  type RespErr struct {
    37  	HTTPCode   int
    38  	API        string
    39  	ErrorReply ErrorReply
    40  }
    41  
    42  // Error satisfies the error interface.
    43  func (e RespErr) Error() string {
    44  	switch e.HTTPCode {
    45  	case http.StatusInternalServerError:
    46  		return fmt.Sprintf("500 internal server error: %v",
    47  			e.ErrorReply.ErrorCode)
    48  	case http.StatusBadRequest:
    49  		var msg string
    50  		if e.ErrorReply.PluginID == "" {
    51  			// API user error
    52  			msg = apiUserErr(e.API, e.ErrorReply)
    53  		} else {
    54  			// Plugin user error
    55  			msg = pluginUserErr(e.ErrorReply)
    56  		}
    57  		return fmt.Sprintf("%v %v", e.HTTPCode, msg)
    58  	default:
    59  		return fmt.Sprintf("%v %+v", e.HTTPCode, e.ErrorReply)
    60  	}
    61  }
    62  
    63  func apiUserErr(api string, e ErrorReply) string {
    64  	var errMsg string
    65  	switch api {
    66  	case cmv1.APIRoute:
    67  		errMsg = cmv1.ErrorCodes[cmv1.ErrorCodeT(e.ErrorCode)]
    68  	case rcv1.APIRoute:
    69  		errMsg = rcv1.ErrorCodes[rcv1.ErrorCodeT(e.ErrorCode)]
    70  	case tkv1.APIRoute:
    71  		errMsg = tkv1.ErrorCodes[tkv1.ErrorCodeT(e.ErrorCode)]
    72  	}
    73  
    74  	// Remove "/" from api string. "/records/v1" to "records v1".
    75  	s := strings.Split(api, "/")
    76  	api = strings.Join(s, " ")
    77  	api = strings.Trim(api, " ")
    78  
    79  	// Create error string
    80  	m := fmt.Sprintf("%v user error code %v", api, e.ErrorCode)
    81  	if errMsg != "" {
    82  		m += fmt.Sprintf(", %v", errMsg)
    83  	}
    84  	if e.ErrorContext != "" {
    85  		m += fmt.Sprintf(": %v", e.ErrorContext)
    86  	}
    87  	return m
    88  }
    89  
    90  func pluginUserErr(e ErrorReply) string {
    91  	var errMsg string
    92  	switch e.PluginID {
    93  	case cmplugin.PluginID:
    94  		errMsg = cmplugin.ErrorCodes[cmplugin.ErrorCodeT(e.ErrorCode)]
    95  	case piplugin.PluginID:
    96  		errMsg = piplugin.ErrorCodes[piplugin.ErrorCodeT(e.ErrorCode)]
    97  	case tkplugin.PluginID:
    98  		errMsg = tkplugin.ErrorCodes[tkplugin.ErrorCodeT(e.ErrorCode)]
    99  	case umplugin.PluginID:
   100  		errMsg = umplugin.ErrorCodes[umplugin.ErrorCodeT(e.ErrorCode)]
   101  	}
   102  	m := fmt.Sprintf("%v plugin error code %v", e.PluginID, e.ErrorCode)
   103  	if errMsg != "" {
   104  		m += fmt.Sprintf(", %v", errMsg)
   105  	}
   106  	if e.ErrorContext != "" {
   107  		m += fmt.Sprintf(": %v", e.ErrorContext)
   108  	}
   109  	return m
   110  }