chore: Linter rule for properly formatted api errors (#2123)

* chore: Linter rule for properly formatted api errors
* Add omitempty to 'Detail' field
This commit is contained in:
Steven Masley 2022-06-07 09:33:06 -05:00 committed by GitHub
parent 3f1e885d21
commit af401e3fe1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 351 additions and 302 deletions

View File

@ -123,6 +123,7 @@ func New(options *Options) *API {
)
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
httpapi.Write(w, http.StatusOK, httpapi.Response{
//nolint:gocritic
Message: "👋",
})
})

View File

@ -23,7 +23,7 @@ func (api *API) logReportCSPViolations(rw http.ResponseWriter, r *http.Request)
if err != nil {
api.Logger.Warn(ctx, "csp violation", slog.Error(err))
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: "Failed to read body, invalid json",
Message: "Failed to read body, invalid json.",
Detail: err.Error(),
})
return

View File

@ -32,7 +32,7 @@ func (api *API) postFile(rw http.ResponseWriter, r *http.Request) {
case "application/x-tar":
default:
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: fmt.Sprintf("Unsupported content type header %q", contentType),
Message: fmt.Sprintf("Unsupported content type header %q.", contentType),
})
return
}
@ -41,7 +41,7 @@ func (api *API) postFile(rw http.ResponseWriter, r *http.Request) {
data, err := io.ReadAll(r.Body)
if err != nil {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: "Failed to read file from request",
Message: "Failed to read file from request.",
Detail: err.Error(),
})
return
@ -65,7 +65,7 @@ func (api *API) postFile(rw http.ResponseWriter, r *http.Request) {
})
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error saving file",
Message: "Internal error saving file.",
Detail: err.Error(),
})
return
@ -80,7 +80,7 @@ func (api *API) fileByHash(rw http.ResponseWriter, r *http.Request) {
hash := chi.URLParam(r, "hash")
if hash == "" {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: "File hash must be provided in url",
Message: "File hash must be provided in url.",
})
return
}
@ -91,7 +91,7 @@ func (api *API) fileByHash(rw http.ResponseWriter, r *http.Request) {
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching file",
Message: "Internal error fetching file.",
Detail: err.Error(),
})
return

View File

@ -21,7 +21,7 @@ func (api *API) regenerateGitSSHKey(rw http.ResponseWriter, r *http.Request) {
privateKey, publicKey, err := gitsshkey.Generate(api.SSHKeygenAlgorithm)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error generating a new SSH keypair",
Message: "Internal error generating a new SSH keypair.",
Detail: err.Error(),
})
return
@ -35,7 +35,7 @@ func (api *API) regenerateGitSSHKey(rw http.ResponseWriter, r *http.Request) {
})
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error updating user's git SSH key",
Message: "Internal error updating user's git SSH key.",
Detail: err.Error(),
})
return
@ -44,7 +44,7 @@ func (api *API) regenerateGitSSHKey(rw http.ResponseWriter, r *http.Request) {
newKey, err := api.Database.GetGitSSHKey(r.Context(), user.ID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching user's git SSH key",
Message: "Internal error fetching user's git SSH key.",
Detail: err.Error(),
})
return
@ -69,7 +69,7 @@ func (api *API) gitSSHKey(rw http.ResponseWriter, r *http.Request) {
gitSSHKey, err := api.Database.GetGitSSHKey(r.Context(), user.ID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching user's SSH key",
Message: "Internal error fetching user's SSH key.",
Detail: err.Error(),
})
return
@ -89,7 +89,7 @@ func (api *API) agentGitSSHKey(rw http.ResponseWriter, r *http.Request) {
resource, err := api.Database.GetWorkspaceResourceByID(r.Context(), agent.ResourceID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching workspace resource",
Message: "Internal error fetching workspace resource.",
Detail: err.Error(),
})
return
@ -98,7 +98,7 @@ func (api *API) agentGitSSHKey(rw http.ResponseWriter, r *http.Request) {
job, err := api.Database.GetWorkspaceBuildByJobID(r.Context(), resource.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching workspace build",
Message: "Internal error fetching workspace build.",
Detail: err.Error(),
})
return
@ -107,7 +107,7 @@ func (api *API) agentGitSSHKey(rw http.ResponseWriter, r *http.Request) {
workspace, err := api.Database.GetWorkspaceByID(r.Context(), job.WorkspaceID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching workspace",
Message: "Internal error fetching workspace.",
Detail: err.Error(),
})
return
@ -116,7 +116,7 @@ func (api *API) agentGitSSHKey(rw http.ResponseWriter, r *http.Request) {
gitSSHKey, err := api.Database.GetGitSSHKey(r.Context(), workspace.OwnerID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching git SSH key",
Message: "Internal error fetching git SSH key.",
Detail: err.Error(),
})
return

View File

@ -63,7 +63,7 @@ type Response struct {
// err.Error() text.
// - "database: too many open connections"
// - "stat: too many open files"
Detail string `json:"detail"`
Detail string `json:"detail,omitempty"`
// Validations are form field-specific friendly error messages. They will be
// shown on a form field in the UI. These can also be used to add additional
// context if there is a set of errors in the primary 'Message'.
@ -78,7 +78,7 @@ type Error struct {
func Forbidden(rw http.ResponseWriter) {
Write(rw, http.StatusForbidden, Response{
Message: "Forbidden",
Message: "Forbidden.",
})
}
@ -107,7 +107,7 @@ func Read(rw http.ResponseWriter, r *http.Request, value interface{}) bool {
err := json.NewDecoder(r.Body).Decode(value)
if err != nil {
Write(rw, http.StatusBadRequest, Response{
Message: "Request body must be valid JSON",
Message: "Request body must be valid JSON.",
Detail: err.Error(),
})
return false
@ -123,14 +123,14 @@ func Read(rw http.ResponseWriter, r *http.Request, value interface{}) bool {
})
}
Write(rw, http.StatusBadRequest, Response{
Message: "Validation failed",
Message: "Validation failed.",
Validations: apiErrors,
})
return false
}
if err != nil {
Write(rw, http.StatusInternalServerError, Response{
Message: "Internal error validating request body payload",
Message: "Internal error validating request body payload.",
Detail: err.Error(),
})
return false

View File

@ -20,7 +20,7 @@ func TestWrite(t *testing.T) {
t.Parallel()
rw := httptest.NewRecorder()
httpapi.Write(rw, http.StatusOK, httpapi.Response{
Message: "wow",
Message: "Wow.",
})
var m map[string]interface{}
err := json.NewDecoder(rw.Body).Decode(&m)

View File

@ -65,7 +65,7 @@ func ExtractAPIKey(db database.Store, oauth *OAuth2Configs) func(http.Handler) h
}
if cookieValue == "" {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: fmt.Sprintf("Cookie %q or query parameter must be provided", SessionTokenKey),
Message: fmt.Sprintf("Cookie %q or query parameter must be provided.", SessionTokenKey),
})
return
}
@ -73,7 +73,7 @@ func ExtractAPIKey(db database.Store, oauth *OAuth2Configs) func(http.Handler) h
// APIKeys are formatted: ID-SECRET
if len(parts) != 2 {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: fmt.Sprintf("Invalid %q cookie API key format", SessionTokenKey),
Message: fmt.Sprintf("Invalid %q cookie API key format.", SessionTokenKey),
})
return
}
@ -82,13 +82,13 @@ func ExtractAPIKey(db database.Store, oauth *OAuth2Configs) func(http.Handler) h
// Ensuring key lengths are valid.
if len(keyID) != 10 {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: fmt.Sprintf("Invalid %q cookie API key id", SessionTokenKey),
Message: fmt.Sprintf("Invalid %q cookie API key id.", SessionTokenKey),
})
return
}
if len(keySecret) != 22 {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: fmt.Sprintf("Invalid %q cookie API key secret", SessionTokenKey),
Message: fmt.Sprintf("Invalid %q cookie API key secret.", SessionTokenKey),
})
return
}
@ -96,12 +96,12 @@ func ExtractAPIKey(db database.Store, oauth *OAuth2Configs) func(http.Handler) h
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: "API key is invalid",
Message: "API key is invalid.",
})
return
}
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching API key by id",
Message: "Internal error fetching API key by id.",
Detail: err.Error(),
})
return
@ -111,7 +111,7 @@ func ExtractAPIKey(db database.Store, oauth *OAuth2Configs) func(http.Handler) h
// Checking to see if the secret is valid.
if subtle.ConstantTimeCompare(key.HashedSecret, hashed[:]) != 1 {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: "API key secret is invalid",
Message: "API key secret is invalid.",
})
return
}
@ -128,7 +128,7 @@ func ExtractAPIKey(db database.Store, oauth *OAuth2Configs) func(http.Handler) h
oauthConfig = oauth.Github
default:
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("Unexpected authentication type %q", key.LoginType),
Message: fmt.Sprintf("Unexpected authentication type %q.", key.LoginType),
})
return
}
@ -140,7 +140,7 @@ func ExtractAPIKey(db database.Store, oauth *OAuth2Configs) func(http.Handler) h
}).Token()
if err != nil {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: "Could not refresh expired Oauth token",
Message: "Could not refresh expired Oauth token.",
Detail: err.Error(),
})
return
@ -156,7 +156,7 @@ func ExtractAPIKey(db database.Store, oauth *OAuth2Configs) func(http.Handler) h
// Checking if the key is expired.
if key.ExpiresAt.Before(now) {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: fmt.Sprintf("API key expired at %q", key.ExpiresAt.String()),
Message: fmt.Sprintf("API key expired at %q.", key.ExpiresAt.String()),
})
return
}
@ -184,7 +184,7 @@ func ExtractAPIKey(db database.Store, oauth *OAuth2Configs) func(http.Handler) h
})
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("API key couldn't update: %s", err.Error()),
Message: fmt.Sprintf("API key couldn't update: %s.", err.Error()),
})
return
}
@ -196,7 +196,7 @@ func ExtractAPIKey(db database.Store, oauth *OAuth2Configs) func(http.Handler) h
roles, err := db.GetAuthorizationUserRoles(r.Context(), key.UserID)
if err != nil {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: "Internal error fetching user's roles",
Message: "Internal error fetching user's roles.",
Detail: err.Error(),
})
return

View File

@ -32,7 +32,7 @@ func TestAPIKey(t *testing.T) {
successHandler := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
// Only called if the API key passes through the handler.
httpapi.Write(rw, http.StatusOK, httpapi.Response{
Message: "it worked!",
Message: "It worked!",
})
})
@ -203,7 +203,7 @@ func TestAPIKey(t *testing.T) {
// Checks that it exists on the context!
_ = httpmw.APIKey(r)
httpapi.Write(rw, http.StatusOK, httpapi.Response{
Message: "it worked!",
Message: "It worked!",
})
})).ServeHTTP(rw, r)
res := rw.Result()
@ -241,7 +241,7 @@ func TestAPIKey(t *testing.T) {
// Checks that it exists on the context!
_ = httpmw.APIKey(r)
httpapi.Write(rw, http.StatusOK, httpapi.Response{
Message: "it worked!",
Message: "It worked!",
})
})).ServeHTTP(rw, r)
res := rw.Result()

View File

@ -15,7 +15,7 @@ func parseUUID(rw http.ResponseWriter, r *http.Request, param string) (uuid.UUID
rawID := chi.URLParam(r, param)
if rawID == "" {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: "Missing UUID in URL",
Message: "Missing UUID in URL.",
// Url params mean nothing to a user
Detail: fmt.Sprintf("%q URL param missing", param),
})
@ -25,7 +25,7 @@ func parseUUID(rw http.ResponseWriter, r *http.Request, param string) (uuid.UUID
parsed, err := uuid.Parse(rawID)
if err != nil {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: fmt.Sprintf("Invalid UUID %q", param),
Message: fmt.Sprintf("Invalid UUID %q.", param),
Detail: err.Error(),
})
return uuid.UUID{}, false

View File

@ -63,7 +63,7 @@ func ExtractOAuth2(config OAuth2Config) func(http.Handler) http.Handler {
state, err := cryptorand.String(32)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error generating state string",
Message: "Internal error generating state string.",
Detail: err.Error(),
})
return
@ -92,7 +92,7 @@ func ExtractOAuth2(config OAuth2Config) func(http.Handler) http.Handler {
if state == "" {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: "State must be provided",
Message: "State must be provided.",
})
return
}
@ -100,13 +100,13 @@ func ExtractOAuth2(config OAuth2Config) func(http.Handler) http.Handler {
stateCookie, err := r.Cookie(oauth2StateCookieName)
if err != nil {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: fmt.Sprintf("Cookie %q must be provided", oauth2StateCookieName),
Message: fmt.Sprintf("Cookie %q must be provided.", oauth2StateCookieName),
})
return
}
if stateCookie.Value != state {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: "State mismatched",
Message: "State mismatched.",
})
return
}
@ -120,7 +120,7 @@ func ExtractOAuth2(config OAuth2Config) func(http.Handler) http.Handler {
oauthToken, err := config.Exchange(r.Context(), code)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error exchanging Oauth code",
Message: "Internal error exchanging Oauth code.",
Detail: err.Error(),
})
return

View File

@ -46,13 +46,13 @@ func ExtractOrganizationParam(db database.Store) func(http.Handler) http.Handler
organization, err := db.GetOrganizationByID(r.Context(), orgID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: fmt.Sprintf("Organization %q does not exist", orgID),
Message: fmt.Sprintf("Organization %q does not exist.", orgID),
})
return
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching organization",
Message: "Internal error fetching organization.",
Detail: err.Error(),
})
return
@ -77,13 +77,13 @@ func ExtractOrganizationMemberParam(db database.Store) func(http.Handler) http.H
})
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusForbidden, httpapi.Response{
Message: "Not a member of the organization",
Message: "Not a member of the organization.",
})
return
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching organization member",
Message: "Internal error fetching organization member.",
Detail: err.Error(),
})
return

View File

@ -35,12 +35,12 @@ func ExtractTemplateParam(db database.Store) func(http.Handler) http.Handler {
template, err := db.GetTemplateByID(r.Context(), templateID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: fmt.Sprintf("Template %q does not exist", templateID),
Message: fmt.Sprintf("Template %q does not exist.", templateID),
})
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching template",
Message: "Internal error fetching template.",
Detail: err.Error(),
})
return
@ -48,7 +48,7 @@ func ExtractTemplateParam(db database.Store) func(http.Handler) http.Handler {
if template.Deleted {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: fmt.Sprintf("Template %q does not exist", templateID),
Message: fmt.Sprintf("Template %q does not exist.", templateID),
})
return
}

View File

@ -35,13 +35,13 @@ func ExtractTemplateVersionParam(db database.Store) func(http.Handler) http.Hand
templateVersion, err := db.GetTemplateVersionByID(r.Context(), templateVersionID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: fmt.Sprintf("Template version %q does not exist", templateVersionID),
Message: fmt.Sprintf("Template version %q does not exist.", templateVersionID),
})
return
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching template version",
Message: "Internal error fetching template version.",
Detail: err.Error(),
})
return

View File

@ -17,7 +17,7 @@ const (
// userErrorMessage is a constant so that no information about the state
// of the queried user can be gained. We return the same error if the user
// does not exist, or if the input is just garbage.
userErrorMessage = "\"user\" must be an existing uuid or username"
userErrorMessage = "\"user\" must be an existing uuid or username."
)
// UserParam returns the user from the ExtractUserParam handler.
@ -40,7 +40,7 @@ func ExtractUserParam(db database.Store) func(http.Handler) http.Handler {
userQuery := chi.URLParam(r, "user")
if userQuery == "" {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: "\"user\" must be provided",
Message: "\"user\" must be provided.",
})
return
}
@ -49,7 +49,7 @@ func ExtractUserParam(db database.Store) func(http.Handler) http.Handler {
user, err = db.GetUserByID(r.Context(), APIKey(r).UserID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching user",
Message: "Internal error fetching user.",
Detail: err.Error(),
})
return

View File

@ -31,14 +31,14 @@ func ExtractWorkspaceAgent(db database.Store) func(http.Handler) http.Handler {
cookie, err := r.Cookie(SessionTokenKey)
if err != nil {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: fmt.Sprintf("Cookie %q must be provided", SessionTokenKey),
Message: fmt.Sprintf("Cookie %q must be provided.", SessionTokenKey),
})
return
}
token, err := uuid.Parse(cookie.Value)
if err != nil {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: fmt.Sprintf("Parse token %q: %s", cookie.Value, err),
Message: fmt.Sprintf("Parse token %q: %s.", cookie.Value, err),
})
return
}
@ -46,14 +46,14 @@ func ExtractWorkspaceAgent(db database.Store) func(http.Handler) http.Handler {
if errors.Is(err, sql.ErrNoRows) {
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: "Agent token is invalid",
Message: "Agent token is invalid.",
})
return
}
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching workspace agent",
Message: "Internal error fetching workspace agent.",
Detail: err.Error(),
})
return

View File

@ -32,13 +32,13 @@ func ExtractWorkspaceAgentParam(db database.Store) func(http.Handler) http.Handl
agent, err := db.GetWorkspaceAgentByID(r.Context(), agentUUID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: "Agent doesn't exist with that id",
Message: "Agent doesn't exist with that id.",
})
return
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching workspace agent",
Message: "Internal error fetching workspace agent.",
Detail: err.Error(),
})
return
@ -46,7 +46,7 @@ func ExtractWorkspaceAgentParam(db database.Store) func(http.Handler) http.Handl
resource, err := db.GetWorkspaceResourceByID(r.Context(), agent.ResourceID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching workspace resource",
Message: "Internal error fetching workspace resource.",
Detail: err.Error(),
})
return
@ -55,7 +55,7 @@ func ExtractWorkspaceAgentParam(db database.Store) func(http.Handler) http.Handl
job, err := db.GetProvisionerJobByID(r.Context(), resource.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching provisioner job",
Message: "Internal error fetching provisioner job.",
Detail: err.Error(),
})
return
@ -69,7 +69,7 @@ func ExtractWorkspaceAgentParam(db database.Store) func(http.Handler) http.Handl
build, err := db.GetWorkspaceBuildByJobID(r.Context(), job.ID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching workspace build",
Message: "Internal error fetching workspace build.",
Detail: err.Error(),
})
return
@ -77,7 +77,7 @@ func ExtractWorkspaceAgentParam(db database.Store) func(http.Handler) http.Handl
workspace, err := db.GetWorkspaceByID(r.Context(), build.WorkspaceID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching workspace",
Message: "Internal error fetching workspace.",
Detail: err.Error(),
})
return
@ -86,7 +86,7 @@ func ExtractWorkspaceAgentParam(db database.Store) func(http.Handler) http.Handl
apiKey := APIKey(r)
if apiKey.UserID != workspace.OwnerID {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: "Getting non-personal agents isn't supported",
Message: "Getting non-personal agents isn't supported.",
})
return
}

View File

@ -35,13 +35,13 @@ func ExtractWorkspaceBuildParam(db database.Store) func(http.Handler) http.Handl
workspaceBuild, err := db.GetWorkspaceBuildByID(r.Context(), workspaceBuildID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: fmt.Sprintf("Workspace build %q does not exist", workspaceBuildID),
Message: fmt.Sprintf("Workspace build %q does not exist.", workspaceBuildID),
})
return
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching workspace build",
Message: "Internal error fetching workspace build.",
Detail: err.Error(),
})
return

View File

@ -33,13 +33,13 @@ func ExtractWorkspaceParam(db database.Store) func(http.Handler) http.Handler {
workspace, err := db.GetWorkspaceByID(r.Context(), workspaceID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: fmt.Sprintf("Workspace %q does not exist", workspaceID),
Message: fmt.Sprintf("Workspace %q does not exist.", workspaceID),
})
return
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching workspace",
Message: "Internal error fetching workspace.",
Detail: err.Error(),
})
return

View File

@ -34,13 +34,13 @@ func ExtractWorkspaceResourceParam(db database.Store) func(http.Handler) http.Ha
resource, err := db.GetWorkspaceResourceByID(r.Context(), resourceUUID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: "Resource doesn't exist with that id",
Message: "Resource doesn't exist with that id.",
})
return
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching provisioner resource",
Message: "Internal error fetching provisioner resource.",
Detail: err.Error(),
})
return
@ -49,7 +49,7 @@ func ExtractWorkspaceResourceParam(db database.Store) func(http.Handler) http.Ha
job, err := db.GetProvisionerJobByID(r.Context(), resource.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error provisioner job",
Message: "Internal error provisioner job.",
Detail: err.Error(),
})
return
@ -63,7 +63,7 @@ func ExtractWorkspaceResourceParam(db database.Store) func(http.Handler) http.Ha
build, err := db.GetWorkspaceBuildByJobID(r.Context(), job.ID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error workspace build",
Message: "Internal error workspace build.",
Detail: err.Error(),
})
return

View File

@ -45,13 +45,13 @@ func (api *API) postOrganizations(rw http.ResponseWriter, r *http.Request) {
_, err := api.Database.GetOrganizationByName(r.Context(), req.Name)
if err == nil {
httpapi.Write(rw, http.StatusConflict, httpapi.Response{
Message: "Organization already exists with that name",
Message: "Organization already exists with that name.",
})
return
}
if !errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("Internal error fetching organization %q", req.Name),
Message: fmt.Sprintf("Internal error fetching organization %q.", req.Name),
Detail: err.Error(),
})
return
@ -84,7 +84,7 @@ func (api *API) postOrganizations(rw http.ResponseWriter, r *http.Request) {
})
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error inserting organization member",
Message: "Internal error inserting organization member.",
Detail: err.Error(),
})
return

View File

@ -24,7 +24,7 @@ func parsePagination(w http.ResponseWriter, r *http.Request) (p codersdk.Paginat
afterID, err = uuid.Parse(r.URL.Query().Get("after_id"))
if err != nil {
httpapi.Write(w, http.StatusBadRequest, httpapi.Response{
Message: "Query param 'after_id' must be a valid UUID",
Message: "Query param 'after_id' must be a valid UUID.",
Validations: []httpapi.Error{
{Field: "after_id", Detail: err.Error()},
},
@ -36,7 +36,7 @@ func parsePagination(w http.ResponseWriter, r *http.Request) (p codersdk.Paginat
limit, err = strconv.Atoi(s)
if err != nil {
httpapi.Write(w, http.StatusBadRequest, httpapi.Response{
Message: "Query param 'limit' must be a valid integer",
Message: "Query param 'limit' must be a valid integer.",
Validations: []httpapi.Error{
{Field: "limit", Detail: err.Error()},
},
@ -48,7 +48,7 @@ func parsePagination(w http.ResponseWriter, r *http.Request) (p codersdk.Paginat
offset, err = strconv.Atoi(s)
if err != nil {
httpapi.Write(w, http.StatusBadRequest, httpapi.Response{
Message: "Query param 'offset' must be a valid integer",
Message: "Query param 'offset' must be a valid integer.",
Validations: []httpapi.Error{
{Field: "offset", Detail: err.Error()},
},

View File

@ -41,13 +41,13 @@ func (api *API) postParameter(rw http.ResponseWriter, r *http.Request) {
})
if err == nil {
httpapi.Write(rw, http.StatusConflict, httpapi.Response{
Message: fmt.Sprintf("Parameter already exists in scope %q and name %q", scope, createRequest.Name),
Message: fmt.Sprintf("Parameter already exists in scope %q and name %q.", scope, createRequest.Name),
})
return
}
if !errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching parameter",
Message: "Internal error fetching parameter.",
Detail: err.Error(),
})
return
@ -66,7 +66,7 @@ func (api *API) postParameter(rw http.ResponseWriter, r *http.Request) {
})
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error inserting parameter",
Message: "Internal error inserting parameter.",
Detail: err.Error(),
})
return
@ -98,7 +98,7 @@ func (api *API) parameters(rw http.ResponseWriter, r *http.Request) {
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching parameter scope values",
Message: "Internal error fetching parameter scope values.",
Detail: err.Error(),
})
return
@ -133,14 +133,14 @@ func (api *API) deleteParameter(rw http.ResponseWriter, r *http.Request) {
})
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: fmt.Sprintf("No parameter found at the provided scope with name %q", name),
Message: fmt.Sprintf("No parameter found at the provided scope with name %q.", name),
Detail: err.Error(),
})
return
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching parameter",
Message: "Internal error fetching parameter.",
Detail: err.Error(),
})
return
@ -148,13 +148,13 @@ func (api *API) deleteParameter(rw http.ResponseWriter, r *http.Request) {
err = api.Database.DeleteParameterValueByID(r.Context(), parameterValue.ID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error deleting parameter",
Message: "Internal error deleting parameter.",
Detail: err.Error(),
})
return
}
httpapi.Write(rw, http.StatusOK, httpapi.Response{
Message: "parameter deleted",
Message: "Parameter deleted.",
})
}
@ -243,7 +243,7 @@ func readScopeAndID(rw http.ResponseWriter, r *http.Request) (database.Parameter
scope = database.ParameterScopeWorkspace
default:
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: fmt.Sprintf("Invalid scope %q", scope),
Message: fmt.Sprintf("Invalid scope %q.", scope),
Validations: []httpapi.Error{
{Field: "scope", Detail: "invalid scope"},
},
@ -255,7 +255,7 @@ func readScopeAndID(rw http.ResponseWriter, r *http.Request) (database.Parameter
uid, err := uuid.Parse(id)
if err != nil {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: fmt.Sprintf("Invalid UUID %q", id),
Message: fmt.Sprintf("Invalid UUID %q.", id),
Detail: err.Error(),
Validations: []httpapi.Error{
{Field: "id", Detail: "Invalid UUID"},

View File

@ -38,7 +38,7 @@ func (api *API) provisionerDaemons(rw http.ResponseWriter, r *http.Request) {
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching provisioner daemons",
Message: "Internal error fetching provisioner daemons.",
Detail: err.Error(),
})
return

View File

@ -32,7 +32,7 @@ func (api *API) provisionerJobLogs(rw http.ResponseWriter, r *http.Request, job
beforeRaw := r.URL.Query().Get("before")
if beforeRaw != "" && follow {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: "Query param \"before\" cannot be used with \"follow\"",
Message: "Query param \"before\" cannot be used with \"follow\".",
})
return
}
@ -43,7 +43,7 @@ func (api *API) provisionerJobLogs(rw http.ResponseWriter, r *http.Request, job
afterMS, err := strconv.ParseInt(afterRaw, 10, 64)
if err != nil {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: "Query param \"after\" must be an integer",
Message: "Query param \"after\" must be an integer.",
Validations: []httpapi.Error{
{Field: "after", Detail: "Must be an integer"},
},
@ -62,7 +62,7 @@ func (api *API) provisionerJobLogs(rw http.ResponseWriter, r *http.Request, job
beforeMS, err := strconv.ParseInt(beforeRaw, 10, 64)
if err != nil {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: "Query param \"before\" must be an integer",
Message: "Query param \"before\" must be an integer.",
Validations: []httpapi.Error{
{Field: "before", Detail: "Must be an integer"},
},
@ -85,7 +85,7 @@ func (api *API) provisionerJobLogs(rw http.ResponseWriter, r *http.Request, job
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching provisioner logs",
Message: "Internal error fetching provisioner logs.",
Detail: err.Error(),
})
return
@ -119,7 +119,7 @@ func (api *API) provisionerJobLogs(rw http.ResponseWriter, r *http.Request, job
})
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error watching provisioner logs",
Message: "Internal error watching provisioner logs.",
Detail: err.Error(),
})
return
@ -136,7 +136,7 @@ func (api *API) provisionerJobLogs(rw http.ResponseWriter, r *http.Request, job
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching provisioner logs",
Message: "Internal error fetching provisioner logs.",
Detail: err.Error(),
})
return
@ -200,7 +200,7 @@ func (api *API) provisionerJobResources(rw http.ResponseWriter, r *http.Request,
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching job resources",
Message: "Internal error fetching job resources.",
Detail: err.Error(),
})
return
@ -215,7 +215,7 @@ func (api *API) provisionerJobResources(rw http.ResponseWriter, r *http.Request,
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching workspace agent",
Message: "Internal error fetching workspace agent.",
Detail: err.Error(),
})
return
@ -230,7 +230,8 @@ func (api *API) provisionerJobResources(rw http.ResponseWriter, r *http.Request,
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get workspace apps: %s", err),
Message: "Internal error fetching workspace applications.",
Detail: err.Error(),
})
return
}
@ -252,7 +253,7 @@ func (api *API) provisionerJobResources(rw http.ResponseWriter, r *http.Request,
apiAgent, err := convertWorkspaceAgent(agent, convertApps(dbApps), api.AgentConnectionUpdateFrequency)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error reading job agent",
Message: "Internal error reading job agent.",
Detail: err.Error(),
})
return

View File

@ -61,7 +61,7 @@ func (api *API) checkPermissions(rw http.ResponseWriter, r *http.Request) {
for k, v := range params.Checks {
if v.Object.ResourceType == "" {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: fmt.Sprintf("Object's \"resource_type\" field must be defined for key %q", k),
Message: fmt.Sprintf("Object's \"resource_type\" field must be defined for key %q.", k),
})
return
}

View File

@ -34,7 +34,7 @@ func (api *API) template(rw http.ResponseWriter, r *http.Request) {
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching workspace count",
Message: "Internal error fetching workspace count.",
Detail: err.Error(),
})
return
@ -66,7 +66,7 @@ func (api *API) deleteTemplate(rw http.ResponseWriter, r *http.Request) {
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching workspaces by template id",
Message: "Internal error fetching workspaces by template id.",
Detail: err.Error(),
})
return
@ -83,7 +83,7 @@ func (api *API) deleteTemplate(rw http.ResponseWriter, r *http.Request) {
})
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error deleting template",
Message: "Internal error deleting template.",
Detail: err.Error(),
})
return
@ -110,7 +110,7 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
})
if err == nil {
httpapi.Write(rw, http.StatusConflict, httpapi.Response{
Message: fmt.Sprintf("Template with name %q already exists", createTemplate.Name),
Message: fmt.Sprintf("Template with name %q already exists.", createTemplate.Name),
Validations: []httpapi.Error{{
Field: "name",
Detail: "This value is already in use and should be unique.",
@ -120,7 +120,7 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
}
if !errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching template by name",
Message: "Internal error fetching template by name.",
Detail: err.Error(),
})
return
@ -128,7 +128,7 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
templateVersion, err := api.Database.GetTemplateVersionByID(r.Context(), createTemplate.VersionID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: fmt.Sprintf("Template version %q does not exist", createTemplate.VersionID),
Message: fmt.Sprintf("Template version %q does not exist.", createTemplate.VersionID),
Validations: []httpapi.Error{
{Field: "template_version_id", Detail: "Template version does not exist"},
},
@ -137,7 +137,7 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching template version",
Message: "Internal error fetching template version.",
Detail: err.Error(),
})
return
@ -145,7 +145,7 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
importJob, err := api.Database.GetProvisionerJobByID(r.Context(), templateVersion.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching provisioner job",
Message: "Internal error fetching provisioner job.",
Detail: err.Error(),
})
return
@ -213,7 +213,7 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
})
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error inserting template",
Message: "Internal error inserting template.",
Detail: err.Error(),
})
return
@ -232,7 +232,7 @@ func (api *API) templatesByOrganization(rw http.ResponseWriter, r *http.Request)
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching templates in organization",
Message: "Internal error fetching templates in organization.",
Detail: err.Error(),
})
return
@ -252,7 +252,7 @@ func (api *API) templatesByOrganization(rw http.ResponseWriter, r *http.Request)
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching workspace counts",
Message: "Internal error fetching workspace counts.",
Detail: err.Error(),
})
return
@ -271,13 +271,13 @@ func (api *API) templateByOrganizationAndName(rw http.ResponseWriter, r *http.Re
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: fmt.Sprintf("No template found by name %q in the %q organization", templateName, organization.Name),
Message: fmt.Sprintf("No template found by name %q in the %q organization.", templateName, organization.Name),
})
return
}
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching template",
Message: "Internal error fetching template.",
Detail: err.Error(),
})
return
@ -293,7 +293,7 @@ func (api *API) templateByOrganizationAndName(rw http.ResponseWriter, r *http.Re
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching workspace counts",
Message: "Internal error fetching workspace counts.",
Detail: err.Error(),
})
return

View File

@ -29,7 +29,7 @@ func (api *API) templateVersion(rw http.ResponseWriter, r *http.Request) {
job, err := api.Database.GetProvisionerJobByID(r.Context(), templateVersion.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching provisioner job",
Message: "Internal error fetching provisioner job.",
Detail: err.Error(),
})
return
@ -47,7 +47,7 @@ func (api *API) patchCancelTemplateVersion(rw http.ResponseWriter, r *http.Reque
job, err := api.Database.GetProvisionerJobByID(r.Context(), templateVersion.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching provisioner job",
Message: "Internal error fetching provisioner job.",
Detail: err.Error(),
})
return
@ -73,7 +73,7 @@ func (api *API) patchCancelTemplateVersion(rw http.ResponseWriter, r *http.Reque
})
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error updating provisioner job",
Message: "Internal error updating provisioner job.",
Detail: err.Error(),
})
return
@ -92,7 +92,7 @@ func (api *API) templateVersionSchema(rw http.ResponseWriter, r *http.Request) {
job, err := api.Database.GetProvisionerJobByID(r.Context(), templateVersion.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching provisioner job",
Message: "Internal error fetching provisioner job.",
Detail: err.Error(),
})
return
@ -109,7 +109,7 @@ func (api *API) templateVersionSchema(rw http.ResponseWriter, r *http.Request) {
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error listing parameter schemas",
Message: "Internal error listing parameter schemas.",
Detail: err.Error(),
})
return
@ -119,7 +119,7 @@ func (api *API) templateVersionSchema(rw http.ResponseWriter, r *http.Request) {
apiSchema, err := convertParameterSchema(schema)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("Internal error converting schema %s", schema.Name),
Message: fmt.Sprintf("Internal error converting schema %s.", schema.Name),
Detail: err.Error(),
})
return
@ -139,7 +139,7 @@ func (api *API) templateVersionParameters(rw http.ResponseWriter, r *http.Reques
job, err := api.Database.GetProvisionerJobByID(r.Context(), templateVersion.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching provisioner job",
Message: "Internal error fetching provisioner job.",
Detail: err.Error(),
})
return
@ -160,7 +160,7 @@ func (api *API) templateVersionParameters(rw http.ResponseWriter, r *http.Reques
})
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error computing values",
Message: "Internal error computing values.",
Detail: err.Error(),
})
return
@ -193,7 +193,7 @@ func (api *API) postTemplateVersionDryRun(rw http.ResponseWriter, r *http.Reques
job, err := api.Database.GetProvisionerJobByID(r.Context(), templateVersion.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error updating provisioner job",
Message: "Internal error updating provisioner job.",
Detail: err.Error(),
})
return
@ -228,7 +228,7 @@ func (api *API) postTemplateVersionDryRun(rw http.ResponseWriter, r *http.Reques
})
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error unmarshalling provisioner job",
Message: "Internal error unmarshalling provisioner job.",
Detail: err.Error(),
})
return
@ -250,7 +250,7 @@ func (api *API) postTemplateVersionDryRun(rw http.ResponseWriter, r *http.Reques
})
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error inserting provisioner job",
Message: "Internal error inserting provisioner job.",
Detail: err.Error(),
})
return
@ -300,13 +300,13 @@ func (api *API) patchTemplateVersionDryRunCancel(rw http.ResponseWriter, r *http
if job.CompletedAt.Valid {
httpapi.Write(rw, http.StatusPreconditionFailed, httpapi.Response{
Message: "Job has already completed",
Message: "Job has already completed.",
})
return
}
if job.CanceledAt.Valid {
httpapi.Write(rw, http.StatusPreconditionFailed, httpapi.Response{
Message: "Job has already been marked as canceled",
Message: "Job has already been marked as canceled.",
})
return
}
@ -320,14 +320,14 @@ func (api *API) patchTemplateVersionDryRunCancel(rw http.ResponseWriter, r *http
})
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error updating provisioner job",
Message: "Internal error updating provisioner job.",
Detail: err.Error(),
})
return
}
httpapi.Write(rw, http.StatusOK, httpapi.Response{
Message: "Job has been marked as canceled",
Message: "Job has been marked as canceled.",
})
}
@ -343,7 +343,7 @@ func (api *API) fetchTemplateVersionDryRunJob(rw http.ResponseWriter, r *http.Re
jobUUID, err := uuid.Parse(jobID)
if err != nil {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: fmt.Sprintf("Job ID %q must be a valid UUID", jobID),
Message: fmt.Sprintf("Job ID %q must be a valid UUID.", jobID),
Detail: err.Error(),
})
return database.ProvisionerJob{}, false
@ -356,7 +356,7 @@ func (api *API) fetchTemplateVersionDryRunJob(rw http.ResponseWriter, r *http.Re
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching provisioner job",
Message: "Internal error fetching provisioner job.",
Detail: err.Error(),
})
return database.ProvisionerJob{}, false
@ -376,7 +376,7 @@ func (api *API) fetchTemplateVersionDryRunJob(rw http.ResponseWriter, r *http.Re
err = json.Unmarshal(job.Input, &input)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error unmarshaling job metadata",
Message: "Internal error unmarshaling job metadata.",
Detail: err.Error(),
})
return database.ProvisionerJob{}, false
@ -409,12 +409,12 @@ func (api *API) templateVersionsByTemplate(rw http.ResponseWriter, r *http.Reque
_, err := store.GetTemplateVersionByID(r.Context(), paginationParams.AfterID)
if err != nil && xerrors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: fmt.Sprintf("Record at \"after_id\" (%q) does not exists", paginationParams.AfterID.String()),
Message: fmt.Sprintf("Record at \"after_id\" (%q) does not exists.", paginationParams.AfterID.String()),
})
return err
} else if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching template version at after_id",
Message: "Internal error fetching template version at after_id.",
Detail: err.Error(),
})
return err
@ -433,7 +433,7 @@ func (api *API) templateVersionsByTemplate(rw http.ResponseWriter, r *http.Reque
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching template versions",
Message: "Internal error fetching template versions.",
Detail: err.Error(),
})
return err
@ -446,7 +446,7 @@ func (api *API) templateVersionsByTemplate(rw http.ResponseWriter, r *http.Reque
jobs, err := store.GetProvisionerJobsByIDs(r.Context(), jobIDs)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching provisioner job",
Message: "Internal error fetching provisioner job.",
Detail: err.Error(),
})
return err
@ -460,7 +460,7 @@ func (api *API) templateVersionsByTemplate(rw http.ResponseWriter, r *http.Reque
job, exists := jobByID[version.JobID.String()]
if !exists {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("Job %q doesn't exist for version %q", version.JobID, version.ID),
Message: fmt.Sprintf("Job %q doesn't exist for version %q.", version.JobID, version.ID),
})
return err
}
@ -492,13 +492,13 @@ func (api *API) templateVersionByName(rw http.ResponseWriter, r *http.Request) {
})
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: fmt.Sprintf("No template version found by name %q", templateVersionName),
Message: fmt.Sprintf("No template version found by name %q.", templateVersionName),
})
return
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching template version",
Message: "Internal error fetching template version.",
Detail: err.Error(),
})
return
@ -506,7 +506,7 @@ func (api *API) templateVersionByName(rw http.ResponseWriter, r *http.Request) {
job, err := api.Database.GetProvisionerJobByID(r.Context(), templateVersion.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching provisioner job",
Message: "Internal error fetching provisioner job.",
Detail: err.Error(),
})
return
@ -528,13 +528,13 @@ func (api *API) patchActiveTemplateVersion(rw http.ResponseWriter, r *http.Reque
version, err := api.Database.GetTemplateVersionByID(r.Context(), req.ID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: "Template version not found",
Message: "Template version not found.",
})
return
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching template version",
Message: "Internal error fetching template version.",
Detail: err.Error(),
})
return
@ -551,7 +551,7 @@ func (api *API) patchActiveTemplateVersion(rw http.ResponseWriter, r *http.Reque
})
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error updating active template version",
Message: "Internal error updating active template version.",
Detail: err.Error(),
})
return
@ -574,13 +574,13 @@ func (api *API) postTemplateVersionsByOrganization(rw http.ResponseWriter, r *ht
_, err := api.Database.GetTemplateByID(r.Context(), req.TemplateID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: "Template does not exist",
Message: "Template does not exist.",
})
return
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching template",
Message: "Internal error fetching template.",
Detail: err.Error(),
})
return
@ -590,13 +590,13 @@ func (api *API) postTemplateVersionsByOrganization(rw http.ResponseWriter, r *ht
file, err := api.Database.GetFileByHash(r.Context(), req.StorageSource)
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: "File not found",
Message: "File not found.",
})
return
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching file",
Message: "Internal error fetching file.",
Detail: err.Error(),
})
return
@ -695,7 +695,7 @@ func (api *API) templateVersionResources(rw http.ResponseWriter, r *http.Request
job, err := api.Database.GetProvisionerJobByID(r.Context(), templateVersion.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching provisioner job",
Message: "Internal error fetching provisioner job.",
Detail: err.Error(),
})
return
@ -716,7 +716,7 @@ func (api *API) templateVersionLogs(rw http.ResponseWriter, r *http.Request) {
job, err := api.Database.GetProvisionerJobByID(r.Context(), templateVersion.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching provisioner job",
Message: "Internal error fetching provisioner job.",
Detail: err.Error(),
})
return

View File

@ -42,7 +42,7 @@ func (api *API) userOAuth2Github(rw http.ResponseWriter, r *http.Request) {
memberships, err := api.GithubOAuth2Config.ListOrganizationMemberships(r.Context(), oauthClient)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching authenticated Github user organizations",
Message: "Internal error fetching authenticated Github user organizations.",
Detail: err.Error(),
})
return
@ -67,7 +67,7 @@ func (api *API) userOAuth2Github(rw http.ResponseWriter, r *http.Request) {
emails, err := api.GithubOAuth2Config.ListEmails(r.Context(), oauthClient)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching personal Github user",
Message: "Internal error fetching personal Github user.",
Detail: err.Error(),
})
return
@ -88,7 +88,7 @@ func (api *API) userOAuth2Github(rw http.ResponseWriter, r *http.Request) {
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("Internal error fetching user by email %q", *email.Email),
Message: fmt.Sprintf("Internal error fetching user by email %q.", *email.Email),
Detail: err.Error(),
})
return
@ -122,7 +122,7 @@ func (api *API) userOAuth2Github(rw http.ResponseWriter, r *http.Request) {
ghUser, err := api.GithubOAuth2Config.AuthenticatedUser(r.Context(), oauthClient)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching authenticated Github user",
Message: "Internal error fetching authenticated Github user.",
Detail: err.Error(),
})
return
@ -148,7 +148,7 @@ func (api *API) userOAuth2Github(rw http.ResponseWriter, r *http.Request) {
})
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error creating user",
Message: "Internal error creating user.",
Detail: err.Error(),
})
return

View File

@ -30,7 +30,7 @@ func (api *API) firstUser(rw http.ResponseWriter, r *http.Request) {
userCount, err := api.Database.GetUserCount(r.Context())
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching user count",
Message: "Internal error fetching user count.",
Detail: err.Error(),
})
return
@ -59,7 +59,7 @@ func (api *API) postFirstUser(rw http.ResponseWriter, r *http.Request) {
userCount, err := api.Database.GetUserCount(r.Context())
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching user count",
Message: "Internal error fetching user count.",
Detail: err.Error(),
})
return
@ -68,7 +68,7 @@ func (api *API) postFirstUser(rw http.ResponseWriter, r *http.Request) {
// If a user already exists, the initial admin user no longer can be created.
if userCount != 0 {
httpapi.Write(rw, http.StatusConflict, httpapi.Response{
Message: "The initial user has already been created",
Message: "The initial user has already been created.",
})
return
}
@ -80,7 +80,7 @@ func (api *API) postFirstUser(rw http.ResponseWriter, r *http.Request) {
})
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error creating user",
Message: "Internal error creating user.",
Detail: err.Error(),
})
return
@ -96,7 +96,7 @@ func (api *API) postFirstUser(rw http.ResponseWriter, r *http.Request) {
})
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error updating user's roles",
Message: "Internal error updating user's roles.",
Detail: err.Error(),
})
return
@ -124,7 +124,7 @@ func (api *API) users(rw http.ResponseWriter, r *http.Request) {
statuses = append(statuses, database.UserStatus(filter))
default:
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: fmt.Sprintf("%q is not a valid user status", filter),
Message: fmt.Sprintf("%q is not a valid user status.", filter),
Validations: []httpapi.Error{
{Field: "status", Detail: "invalid status"},
},
@ -157,7 +157,7 @@ func (api *API) users(rw http.ResponseWriter, r *http.Request) {
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching users",
Message: "Internal error fetching users.",
Detail: err.Error(),
})
return
@ -173,7 +173,7 @@ func (api *API) users(rw http.ResponseWriter, r *http.Request) {
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching user's organizations",
Message: "Internal error fetching user's organizations.",
Detail: err.Error(),
})
return
@ -213,13 +213,13 @@ func (api *API) postUser(rw http.ResponseWriter, r *http.Request) {
})
if err == nil {
httpapi.Write(rw, http.StatusConflict, httpapi.Response{
Message: "User already exists",
Message: "User already exists.",
})
return
}
if !errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching user",
Message: "Internal error fetching user.",
Detail: err.Error(),
})
return
@ -228,13 +228,13 @@ func (api *API) postUser(rw http.ResponseWriter, r *http.Request) {
_, err = api.Database.GetOrganizationByID(r.Context(), createUser.OrganizationID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: fmt.Sprintf("Organization does not exist with the provided id %q", createUser.OrganizationID),
Message: fmt.Sprintf("Organization does not exist with the provided id %q.", createUser.OrganizationID),
})
return
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching organization",
Message: "Internal error fetching organization.",
Detail: err.Error(),
})
return
@ -243,7 +243,7 @@ func (api *API) postUser(rw http.ResponseWriter, r *http.Request) {
user, _, err := api.createUser(r.Context(), createUser)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error creating user",
Message: "Internal error creating user.",
Detail: err.Error(),
})
return
@ -264,7 +264,7 @@ func (api *API) userByName(rw http.ResponseWriter, r *http.Request) {
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching user's organizations",
Message: "Internal error fetching user's organizations.",
Detail: err.Error(),
})
return
@ -298,14 +298,14 @@ func (api *API) putUserProfile(rw http.ResponseWriter, r *http.Request) {
})
}
httpapi.Write(rw, http.StatusConflict, httpapi.Response{
Message: "User already exists",
Message: "User already exists.",
Validations: responseErrors,
})
return
}
if !errors.Is(err, sql.ErrNoRows) && isDifferentUser {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching user",
Message: "Internal error fetching user.",
Detail: err.Error(),
})
return
@ -320,7 +320,7 @@ func (api *API) putUserProfile(rw http.ResponseWriter, r *http.Request) {
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error updating user",
Message: "Internal error updating user.",
Detail: err.Error(),
})
return
@ -329,7 +329,7 @@ func (api *API) putUserProfile(rw http.ResponseWriter, r *http.Request) {
organizationIDs, err := userOrganizationIDs(r.Context(), api, user)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching user's organizations",
Message: "Internal error fetching user's organizations.",
Detail: err.Error(),
})
return
@ -349,7 +349,7 @@ func (api *API) putUserStatus(status database.UserStatus) func(rw http.ResponseW
if status == database.UserStatusSuspended && user.ID == apiKey.UserID {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: "You cannot suspend yourself",
Message: "You cannot suspend yourself.",
})
return
}
@ -362,7 +362,7 @@ func (api *API) putUserStatus(status database.UserStatus) func(rw http.ResponseW
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("Internal error updating user's status to %q", status),
Message: fmt.Sprintf("Internal error updating user's status to %q.", status),
Detail: err.Error(),
})
return
@ -371,7 +371,7 @@ func (api *API) putUserStatus(status database.UserStatus) func(rw http.ResponseW
organizations, err := userOrganizationIDs(r.Context(), api, user)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching user's organizations",
Message: "Internal error fetching user's organizations.",
Detail: err.Error(),
})
return
@ -399,7 +399,7 @@ func (api *API) putUserPassword(rw http.ResponseWriter, r *http.Request) {
err := userpassword.Validate(params.Password)
if err != nil {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: "Invalid password",
Message: "Invalid password.",
Validations: []httpapi.Error{
{
Field: "password",
@ -417,14 +417,14 @@ func (api *API) putUserPassword(rw http.ResponseWriter, r *http.Request) {
ok, err := userpassword.Compare(string(user.HashedPassword), params.OldPassword)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error with passwords",
Message: "Internal error with passwords.",
Detail: err.Error(),
})
return
}
if !ok {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: "Old password is incorrect",
Message: "Old password is incorrect.",
Validations: []httpapi.Error{
{
Field: "old_password",
@ -439,7 +439,7 @@ func (api *API) putUserPassword(rw http.ResponseWriter, r *http.Request) {
hashedPassword, err := userpassword.Hash(params.Password)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error hashing new password",
Message: "Internal error hashing new password.",
Detail: err.Error(),
})
return
@ -450,7 +450,7 @@ func (api *API) putUserPassword(rw http.ResponseWriter, r *http.Request) {
})
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error updating user's password",
Message: "Internal error updating user's password.",
Detail: err.Error(),
})
return
@ -475,7 +475,7 @@ func (api *API) userRoles(rw http.ResponseWriter, r *http.Request) {
memberships, err := api.Database.GetOrganizationMembershipsByUserID(r.Context(), user.ID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching user's organization memberships",
Message: "Internal error fetching user's organization memberships.",
Detail: err.Error(),
})
return
@ -542,7 +542,7 @@ func (api *API) putUserRoles(rw http.ResponseWriter, r *http.Request) {
organizationIDs, err := userOrganizationIDs(r.Context(), api, user)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching user's organizations",
Message: "Internal error fetching user's organizations.",
Detail: err.Error(),
})
return
@ -583,7 +583,7 @@ func (api *API) organizationsByUser(rw http.ResponseWriter, r *http.Request) {
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching user's organizations",
Message: "Internal error fetching user's organizations.",
Detail: err.Error(),
})
return
@ -636,7 +636,7 @@ func (api *API) postLogin(rw http.ResponseWriter, r *http.Request) {
})
if err != nil && !xerrors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error",
Message: "Internal error.",
})
return
}
@ -645,7 +645,7 @@ func (api *API) postLogin(rw http.ResponseWriter, r *http.Request) {
equal, err := userpassword.Compare(string(user.HashedPassword), loginWithPassword.Password)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error",
Message: "Internal error.",
})
}
if !equal {
@ -719,7 +719,7 @@ func (api *API) postLogout(rw http.ResponseWriter, r *http.Request) {
err := api.Database.DeleteAPIKeyByID(r.Context(), apiKey.ID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error deleting API key",
Message: "Internal error deleting API key.",
Detail: err.Error(),
})
return
@ -749,7 +749,7 @@ func (api *API) createAPIKey(rw http.ResponseWriter, r *http.Request, params dat
keyID, keySecret, err := generateAPIKeyIDSecret()
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error generating API key",
Message: "Internal error generating API key.",
Detail: err.Error(),
})
return "", false
@ -782,7 +782,7 @@ func (api *API) createAPIKey(rw http.ResponseWriter, r *http.Request, params dat
})
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error inserting API key",
Message: "Internal error inserting API key.",
Detail: err.Error(),
})
return "", false

View File

@ -34,14 +34,15 @@ func (api *API) workspaceAgent(rw http.ResponseWriter, r *http.Request) {
dbApps, err := api.Database.GetWorkspaceAppsByAgentID(r.Context(), workspaceAgent.ID)
if err != nil && !xerrors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get workspace agent apps: %s", err),
Message: "Internal error fetching workspace agent applications.",
Detail: err.Error(),
})
return
}
apiAgent, err := convertWorkspaceAgent(workspaceAgent, convertApps(dbApps), api.AgentConnectionUpdateFrequency)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error reading workspace agent",
Message: "Internal error reading workspace agent.",
Detail: err.Error(),
})
return
@ -60,14 +61,14 @@ func (api *API) workspaceAgentDial(rw http.ResponseWriter, r *http.Request) {
apiAgent, err := convertWorkspaceAgent(workspaceAgent, nil, api.AgentConnectionUpdateFrequency)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error reading workspace agent",
Message: "Internal error reading workspace agent.",
Detail: err.Error(),
})
return
}
if apiAgent.Status != codersdk.WorkspaceAgentConnected {
httpapi.Write(rw, http.StatusPreconditionFailed, httpapi.Response{
Message: fmt.Sprintf("Agent isn't connected! Status: %s", apiAgent.Status),
Message: fmt.Sprintf("Agent isn't connected! Status: %s.", apiAgent.Status),
})
return
}
@ -75,7 +76,7 @@ func (api *API) workspaceAgentDial(rw http.ResponseWriter, r *http.Request) {
conn, err := websocket.Accept(rw, r, nil)
if err != nil {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: "Failed to accept websocket",
Message: "Failed to accept websocket.",
Detail: err.Error(),
})
return
@ -107,7 +108,7 @@ func (api *API) workspaceAgentMetadata(rw http.ResponseWriter, r *http.Request)
apiAgent, err := convertWorkspaceAgent(workspaceAgent, nil, api.AgentConnectionUpdateFrequency)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error reading workspace agent",
Message: "Internal error reading workspace agent.",
Detail: err.Error(),
})
return
@ -115,7 +116,7 @@ func (api *API) workspaceAgentMetadata(rw http.ResponseWriter, r *http.Request)
resource, err := api.Database.GetWorkspaceResourceByID(r.Context(), workspaceAgent.ResourceID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching workspace resources",
Message: "Internal error fetching workspace resources.",
Detail: err.Error(),
})
return
@ -123,7 +124,7 @@ func (api *API) workspaceAgentMetadata(rw http.ResponseWriter, r *http.Request)
build, err := api.Database.GetWorkspaceBuildByJobID(r.Context(), resource.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching workspace build",
Message: "Internal error fetching workspace build.",
Detail: err.Error(),
})
return
@ -131,7 +132,7 @@ func (api *API) workspaceAgentMetadata(rw http.ResponseWriter, r *http.Request)
workspace, err := api.Database.GetWorkspaceByID(r.Context(), build.WorkspaceID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching workspace",
Message: "Internal error fetching workspace.",
Detail: err.Error(),
})
return
@ -139,7 +140,7 @@ func (api *API) workspaceAgentMetadata(rw http.ResponseWriter, r *http.Request)
owner, err := api.Database.GetUserByID(r.Context(), workspace.OwnerID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching workspace owner",
Message: "Internal error fetching workspace owner.",
Detail: err.Error(),
})
return
@ -163,7 +164,7 @@ func (api *API) workspaceAgentListen(rw http.ResponseWriter, r *http.Request) {
resource, err := api.Database.GetWorkspaceResourceByID(r.Context(), workspaceAgent.ResourceID)
if err != nil {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: "Failed to accept websocket",
Message: "Failed to accept websocket.",
Detail: err.Error(),
})
return
@ -172,7 +173,8 @@ func (api *API) workspaceAgentListen(rw http.ResponseWriter, r *http.Request) {
build, err := api.Database.GetWorkspaceBuildByJobID(r.Context(), resource.JobID)
if err != nil {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: fmt.Sprintf("get workspace build job: %s", err),
Message: "Internal error fetching workspace build job.",
Detail: err.Error(),
})
return
}
@ -196,7 +198,8 @@ func (api *API) workspaceAgentListen(rw http.ResponseWriter, r *http.Request) {
slog.F("agent", workspaceAgent),
)
httpapi.Write(rw, http.StatusForbidden, httpapi.Response{
Message: fmt.Sprintf("ensure latest build: %s", err),
Message: "Agent trying to connect from non-latest build.",
Detail: err.Error(),
})
return
}
@ -206,7 +209,8 @@ func (api *API) workspaceAgentListen(rw http.ResponseWriter, r *http.Request) {
})
if err != nil {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: fmt.Sprintf("accept websocket: %s", err),
Message: "Failed to accept websocket.",
Detail: err.Error(),
})
return
}
@ -319,7 +323,7 @@ func (api *API) workspaceAgentTurn(rw http.ResponseWriter, r *http.Request) {
host, port, err := net.SplitHostPort(r.RemoteAddr)
if err != nil {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: "Invalid remote address",
Message: "Invalid remote address.",
Detail: err.Error(),
})
return
@ -339,7 +343,7 @@ func (api *API) workspaceAgentTurn(rw http.ResponseWriter, r *http.Request) {
})
if err != nil {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: "Failed to accept websocket",
Message: "Failed to accept websocket.",
Detail: err.Error(),
})
return
@ -368,7 +372,7 @@ func (api *API) workspaceAgentPTY(rw http.ResponseWriter, r *http.Request) {
apiAgent, err := convertWorkspaceAgent(workspaceAgent, nil, api.AgentConnectionUpdateFrequency)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error reading workspace agent",
Message: "Internal error reading workspace agent.",
Detail: err.Error(),
})
return
@ -383,7 +387,7 @@ func (api *API) workspaceAgentPTY(rw http.ResponseWriter, r *http.Request) {
reconnect, err := uuid.Parse(r.URL.Query().Get("reconnect"))
if err != nil {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: "Query param 'reconnect' must be a valid UUID",
Message: "Query param 'reconnect' must be a valid UUID.",
Validations: []httpapi.Error{
{Field: "reconnect", Detail: "invalid UUID"},
},
@ -404,7 +408,7 @@ func (api *API) workspaceAgentPTY(rw http.ResponseWriter, r *http.Request) {
})
if err != nil {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: "Failed to accept websocket",
Message: "Failed to accept websocket.",
Detail: err.Error(),
})
return

View File

@ -33,13 +33,14 @@ func (api *API) workspaceAppsProxyPath(rw http.ResponseWriter, r *http.Request)
})
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: "workspace not found",
Message: "Workspace not found.",
})
return
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get workspace: %s", err),
Message: "Internal error fetching workspace.",
Detail: err.Error(),
})
return
}
@ -50,7 +51,8 @@ func (api *API) workspaceAppsProxyPath(rw http.ResponseWriter, r *http.Request)
build, err := api.Database.GetLatestWorkspaceBuildByWorkspaceID(r.Context(), workspace.ID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get workspace build: %s", err),
Message: "Internal error fetching workspace build.",
Detail: err.Error(),
})
return
}
@ -58,7 +60,8 @@ func (api *API) workspaceAppsProxyPath(rw http.ResponseWriter, r *http.Request)
resources, err := api.Database.GetWorkspaceResourcesByJobID(r.Context(), build.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get workspace resources: %s", err),
Message: "Internal error fetching workspace resources.",
Detail: err.Error(),
})
return
}
@ -69,13 +72,14 @@ func (api *API) workspaceAppsProxyPath(rw http.ResponseWriter, r *http.Request)
agents, err := api.Database.GetWorkspaceAgentsByResourceIDs(r.Context(), resourceIDs)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get workspace agents: %s", err),
Message: "Internal error fetching workspace agents.",
Detail: err.Error(),
})
return
}
if len(agents) == 0 {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: "no agents exist",
Message: "No agents exist.",
})
}
@ -95,19 +99,20 @@ func (api *API) workspaceAppsProxyPath(rw http.ResponseWriter, r *http.Request)
})
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: "application not found",
Message: "Application not found.",
})
return
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get workspace app: %s", err),
Message: "Internal error fetching workspace application.",
Detail: err.Error(),
})
return
}
if !app.Url.Valid {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: fmt.Sprintf("application does not have a url: %s", err),
Message: fmt.Sprintf("Application %s does not have a url.", app.Name),
})
return
}
@ -115,7 +120,8 @@ func (api *API) workspaceAppsProxyPath(rw http.ResponseWriter, r *http.Request)
appURL, err := url.Parse(app.Url.String)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("parse app url: %s", err),
Message: fmt.Sprintf("App url %q must be a valid url.", app.Url.String),
Detail: err.Error(),
})
return
}
@ -155,7 +161,8 @@ func (api *API) workspaceAppsProxyPath(rw http.ResponseWriter, r *http.Request)
conn, release, err := api.workspaceAgentCache.Acquire(r, agent.ID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("dial workspace agent: %s", err),
Message: "Failed to dial workspace agent.",
Detail: err.Error(),
})
return
}

View File

@ -31,7 +31,7 @@ func (api *API) workspaceBuild(rw http.ResponseWriter, r *http.Request) {
job, err := api.Database.GetProvisionerJobByID(r.Context(), workspaceBuild.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching provisioner job",
Message: "Internal error fetching provisioner job.",
Detail: err.Error(),
})
return
@ -72,12 +72,12 @@ func (api *API) workspaceBuilds(rw http.ResponseWriter, r *http.Request) {
_, err := store.GetWorkspaceBuildByID(r.Context(), paginationParams.AfterID)
if err != nil && xerrors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: fmt.Sprintf("Record at \"after_id\" (%q) does not exist", paginationParams.AfterID.String()),
Message: fmt.Sprintf("Record at \"after_id\" (%q) does not exist.", paginationParams.AfterID.String()),
})
return err
} else if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching workspace build at \"after_id\"",
Message: "Internal error fetching workspace build at \"after_id\".",
Detail: err.Error(),
})
return err
@ -96,7 +96,7 @@ func (api *API) workspaceBuilds(rw http.ResponseWriter, r *http.Request) {
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching workspace build",
Message: "Internal error fetching workspace build.",
Detail: err.Error(),
})
return err
@ -118,7 +118,7 @@ func (api *API) workspaceBuilds(rw http.ResponseWriter, r *http.Request) {
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching provisioner jobs",
Message: "Internal error fetching provisioner jobs.",
Detail: err.Error(),
})
return
@ -142,7 +142,7 @@ func (api *API) workspaceBuilds(rw http.ResponseWriter, r *http.Request) {
job, exists := jobByID[build.JobID.String()]
if !exists {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("Job %q doesn't exist for build %q", build.JobID, build.ID),
Message: fmt.Sprintf("Job %q doesn't exist for build %q.", build.JobID, build.ID),
})
return
}
@ -166,13 +166,13 @@ func (api *API) workspaceBuildByName(rw http.ResponseWriter, r *http.Request) {
})
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: fmt.Sprintf("No workspace build found by name %q", workspaceBuildName),
Message: fmt.Sprintf("No workspace build found by name %q.", workspaceBuildName),
})
return
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching workspace build by name",
Message: "Internal error fetching workspace build by name.",
Detail: err.Error(),
})
return
@ -180,7 +180,7 @@ func (api *API) workspaceBuildByName(rw http.ResponseWriter, r *http.Request) {
job, err := api.Database.GetProvisionerJobByID(r.Context(), workspaceBuild.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching provisioner job",
Message: "Internal error fetching provisioner job.",
Detail: err.Error(),
})
return
@ -214,7 +214,7 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) {
action = rbac.ActionUpdate
default:
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("Transition %q not supported", createBuild.Transition),
Message: fmt.Sprintf("Transition %q not supported.", createBuild.Transition),
})
return
}
@ -227,7 +227,7 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) {
latestBuild, err := api.Database.GetLatestWorkspaceBuildByWorkspaceID(r.Context(), workspace.ID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching the latest workspace build",
Message: "Internal error fetching the latest workspace build.",
Detail: err.Error(),
})
return
@ -237,7 +237,7 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) {
templateVersion, err := api.Database.GetTemplateVersionByID(r.Context(), createBuild.TemplateVersionID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: "Template version not found",
Message: "Template version not found.",
Validations: []httpapi.Error{{
Field: "template_version_id",
Detail: "template version not found",
@ -247,7 +247,7 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) {
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching template version",
Message: "Internal error fetching template version.",
Detail: err.Error(),
})
return
@ -255,7 +255,7 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) {
templateVersionJob, err := api.Database.GetProvisionerJobByID(r.Context(), templateVersion.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching provisioner job",
Message: "Internal error fetching provisioner job.",
Detail: err.Error(),
})
return
@ -282,7 +282,7 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) {
template, err := api.Database.GetTemplateByID(r.Context(), templateVersion.TemplateID.UUID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching template job",
Message: "Internal error fetching template job.",
Detail: err.Error(),
})
return
@ -295,7 +295,7 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) {
priorJob, err := api.Database.GetProvisionerJobByID(r.Context(), priorHistory.JobID)
if err == nil && convertProvisionerJob(priorJob).Status.Active() {
httpapi.Write(rw, http.StatusConflict, httpapi.Response{
Message: "A workspace build is already active",
Message: "A workspace build is already active.",
})
return
}
@ -303,7 +303,7 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) {
priorBuildNum = priorHistory.BuildNumber
} else if !errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching prior workspace build",
Message: "Internal error fetching prior workspace build.",
Detail: err.Error(),
})
return
@ -362,7 +362,7 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) {
})
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error inserting workspace build",
Message: "Internal error inserting workspace build.",
Detail: err.Error(),
})
return
@ -386,7 +386,7 @@ func (api *API) patchCancelWorkspaceBuild(rw http.ResponseWriter, r *http.Reques
workspace, err := api.Database.GetWorkspaceByID(r.Context(), workspaceBuild.WorkspaceID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "No workspace exists for this job",
Message: "No workspace exists for this job.",
})
return
}
@ -399,7 +399,7 @@ func (api *API) patchCancelWorkspaceBuild(rw http.ResponseWriter, r *http.Reques
job, err := api.Database.GetProvisionerJobByID(r.Context(), workspaceBuild.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching provisioner job",
Message: "Internal error fetching provisioner job.",
Detail: err.Error(),
})
return
@ -425,7 +425,7 @@ func (api *API) patchCancelWorkspaceBuild(rw http.ResponseWriter, r *http.Reques
})
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error updating provisioner job",
Message: "Internal error updating provisioner job.",
Detail: err.Error(),
})
return
@ -440,7 +440,7 @@ func (api *API) workspaceBuildResources(rw http.ResponseWriter, r *http.Request)
workspace, err := api.Database.GetWorkspaceByID(r.Context(), workspaceBuild.WorkspaceID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "No workspace exists for this job",
Message: "No workspace exists for this job.",
})
return
}
@ -453,7 +453,7 @@ func (api *API) workspaceBuildResources(rw http.ResponseWriter, r *http.Request)
job, err := api.Database.GetProvisionerJobByID(r.Context(), workspaceBuild.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching provisioner job",
Message: "Internal error fetching provisioner job.",
Detail: err.Error(),
})
return
@ -466,7 +466,7 @@ func (api *API) workspaceBuildLogs(rw http.ResponseWriter, r *http.Request) {
workspace, err := api.Database.GetWorkspaceByID(r.Context(), workspaceBuild.WorkspaceID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "No workspace exists for this job",
Message: "No workspace exists for this job.",
})
return
}
@ -479,7 +479,7 @@ func (api *API) workspaceBuildLogs(rw http.ResponseWriter, r *http.Request) {
job, err := api.Database.GetProvisionerJobByID(r.Context(), workspaceBuild.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching provisioner job",
Message: "Internal error fetching provisioner job.",
Detail: err.Error(),
})
return
@ -492,7 +492,7 @@ func (api *API) workspaceBuildState(rw http.ResponseWriter, r *http.Request) {
workspace, err := api.Database.GetWorkspaceByID(r.Context(), workspaceBuild.WorkspaceID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "No workspace exists for this job",
Message: "No workspace exists for this job.",
})
return
}

View File

@ -26,7 +26,7 @@ func (api *API) postWorkspaceAuthAzureInstanceIdentity(rw http.ResponseWriter, r
instanceID, err := azureidentity.Validate(r.Context(), req.Signature, api.AzureCertificates)
if err != nil {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: "Invalid Azure identity",
Message: "Invalid Azure identity.",
Detail: err.Error(),
})
return
@ -45,7 +45,7 @@ func (api *API) postWorkspaceAuthAWSInstanceIdentity(rw http.ResponseWriter, r *
identity, err := awsidentity.Validate(req.Signature, req.Document, api.AWSCertificates)
if err != nil {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: "Invalid AWS identity",
Message: "Invalid AWS identity.",
Detail: err.Error(),
})
return
@ -66,7 +66,7 @@ func (api *API) postWorkspaceAuthGoogleInstanceIdentity(rw http.ResponseWriter,
payload, err := api.GoogleTokenValidator.Validate(r.Context(), req.JSONWebToken, "")
if err != nil {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: "Invalid GCP identity",
Message: "Invalid GCP identity.",
Detail: err.Error(),
})
return
@ -81,7 +81,7 @@ func (api *API) postWorkspaceAuthGoogleInstanceIdentity(rw http.ResponseWriter,
err = mapstructure.Decode(payload.Claims, &claims)
if err != nil {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: "Error decoding JWT claims",
Message: "Error decoding JWT claims.",
Detail: err.Error(),
})
return
@ -93,13 +93,13 @@ func (api *API) handleAuthInstanceID(rw http.ResponseWriter, r *http.Request, in
agent, err := api.Database.GetWorkspaceAgentByInstanceID(r.Context(), instanceID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: fmt.Sprintf("Instance with id %q not found", instanceID),
Message: fmt.Sprintf("Instance with id %q not found.", instanceID),
})
return
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching provisioner job agent",
Message: "Internal error fetching provisioner job agent.",
Detail: err.Error(),
})
return
@ -107,7 +107,7 @@ func (api *API) handleAuthInstanceID(rw http.ResponseWriter, r *http.Request, in
resource, err := api.Database.GetWorkspaceResourceByID(r.Context(), agent.ResourceID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching provisioner job resource",
Message: "Internal error fetching provisioner job resource.",
Detail: err.Error(),
})
return
@ -115,14 +115,14 @@ func (api *API) handleAuthInstanceID(rw http.ResponseWriter, r *http.Request, in
job, err := api.Database.GetProvisionerJobByID(r.Context(), resource.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching provisioner job",
Message: "Internal error fetching provisioner job.",
Detail: err.Error(),
})
return
}
if job.Type != database.ProvisionerJobTypeWorkspaceBuild {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: fmt.Sprintf("%q jobs cannot be authenticated", job.Type),
Message: fmt.Sprintf("%q jobs cannot be authenticated.", job.Type),
})
return
}
@ -130,7 +130,7 @@ func (api *API) handleAuthInstanceID(rw http.ResponseWriter, r *http.Request, in
err = json.Unmarshal(job.Input, &jobData)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error extracting job data",
Message: "Internal error extracting job data.",
Detail: err.Error(),
})
return
@ -138,7 +138,7 @@ func (api *API) handleAuthInstanceID(rw http.ResponseWriter, r *http.Request, in
resourceHistory, err := api.Database.GetWorkspaceBuildByID(r.Context(), jobData.WorkspaceBuildID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching workspace build",
Message: "Internal error fetching workspace build.",
Detail: err.Error(),
})
return
@ -149,14 +149,14 @@ func (api *API) handleAuthInstanceID(rw http.ResponseWriter, r *http.Request, in
latestHistory, err := api.Database.GetLatestWorkspaceBuildByWorkspaceID(r.Context(), resourceHistory.WorkspaceID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching the latest workspace build",
Message: "Internal error fetching the latest workspace build.",
Detail: err.Error(),
})
return
}
if latestHistory.ID != resourceHistory.ID {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: fmt.Sprintf("Resource found for id %q, but isn't registered on the latest history", instanceID),
Message: fmt.Sprintf("Resource found for id %q, but isn't registered on the latest history.", instanceID),
})
return
}

View File

@ -3,7 +3,6 @@ package coderd
import (
"database/sql"
"errors"
"fmt"
"net/http"
"github.com/google/uuid"
@ -26,7 +25,7 @@ func (api *API) workspaceResource(rw http.ResponseWriter, r *http.Request) {
job, err := api.Database.GetProvisionerJobByID(r.Context(), workspaceBuild.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching provisioner job",
Message: "Internal error fetching provisioner job.",
Detail: err.Error(),
})
return
@ -43,7 +42,7 @@ func (api *API) workspaceResource(rw http.ResponseWriter, r *http.Request) {
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching provisioner job agents",
Message: "Internal error fetching provisioner job agents.",
Detail: err.Error(),
})
return
@ -55,7 +54,8 @@ func (api *API) workspaceResource(rw http.ResponseWriter, r *http.Request) {
apps, err := api.Database.GetWorkspaceAppsByAgentIDs(r.Context(), agentIDs)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get workspace apps: %s", err),
Message: "Internal error fetching workspace agent applications.",
Detail: err.Error(),
})
return
}
@ -71,7 +71,7 @@ func (api *API) workspaceResource(rw http.ResponseWriter, r *http.Request) {
convertedAgent, err := convertWorkspaceAgent(agent, convertApps(dbApps), api.AgentConnectionUpdateFrequency)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error reading workspace agent",
Message: "Internal error reading workspace agent.",
Detail: err.Error(),
})
return

View File

@ -46,7 +46,7 @@ func (api *API) workspace(rw http.ResponseWriter, r *http.Request) {
showDeleted, err = strconv.ParseBool(deletedStr)
if err != nil {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: fmt.Sprintf("Invalid boolean value %q for \"deleted\" query param", deletedStr),
Message: fmt.Sprintf("Invalid boolean value %q for \"deleted\" query param.", deletedStr),
Validations: []httpapi.Error{
{Field: "deleted", Detail: "Must be a valid boolean"},
},
@ -56,7 +56,7 @@ func (api *API) workspace(rw http.ResponseWriter, r *http.Request) {
}
if workspace.Deleted && !showDeleted {
httpapi.Write(rw, http.StatusGone, httpapi.Response{
Message: fmt.Sprintf("Workspace %q was deleted, you can view this workspace by specifying '?deleted=true' and trying again", workspace.ID.String()),
Message: fmt.Sprintf("Workspace %q was deleted, you can view this workspace by specifying '?deleted=true' and trying again.", workspace.ID.String()),
})
return
}
@ -64,7 +64,7 @@ func (api *API) workspace(rw http.ResponseWriter, r *http.Request) {
build, err := api.Database.GetLatestWorkspaceBuildByWorkspaceID(r.Context(), workspace.ID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching workspace build",
Message: "Internal error fetching workspace build.",
Detail: err.Error(),
})
return
@ -90,7 +90,7 @@ func (api *API) workspace(rw http.ResponseWriter, r *http.Request) {
err = group.Wait()
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching resource",
Message: "Internal error fetching resource.",
Detail: err.Error(),
})
return
@ -141,7 +141,7 @@ func (api *API) workspaces(rw http.ResponseWriter, r *http.Request) {
workspaces, err := api.Database.GetWorkspacesWithFilter(r.Context(), filter)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching workspaces",
Message: "Internal error fetching workspaces.",
Detail: err.Error(),
})
return
@ -153,7 +153,8 @@ func (api *API) workspaces(rw http.ResponseWriter, r *http.Request) {
apiWorkspaces, err := convertWorkspaces(r.Context(), api.Database, workspaces)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("convert workspaces: %s", err),
Message: "Internal error reading workspace.",
Detail: err.Error(),
})
return
}
@ -175,7 +176,7 @@ func (api *API) workspaceByOwnerAndName(rw http.ResponseWriter, r *http.Request)
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching workspace by name",
Message: "Internal error fetching workspace by name.",
Detail: err.Error(),
})
return
@ -187,7 +188,7 @@ func (api *API) workspaceByOwnerAndName(rw http.ResponseWriter, r *http.Request)
build, err := api.Database.GetLatestWorkspaceBuildByWorkspaceID(r.Context(), workspace.ID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching workspace build",
Message: "Internal error fetching workspace build.",
Detail: err.Error(),
})
return
@ -195,7 +196,7 @@ func (api *API) workspaceByOwnerAndName(rw http.ResponseWriter, r *http.Request)
job, err := api.Database.GetProvisionerJobByID(r.Context(), build.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching provisioner job",
Message: "Internal error fetching provisioner job.",
Detail: err.Error(),
})
return
@ -203,7 +204,7 @@ func (api *API) workspaceByOwnerAndName(rw http.ResponseWriter, r *http.Request)
template, err := api.Database.GetTemplateByID(r.Context(), workspace.TemplateID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching template",
Message: "Internal error fetching template.",
Detail: err.Error(),
})
return
@ -229,7 +230,7 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req
template, err := api.Database.GetTemplateByID(r.Context(), createWorkspace.TemplateID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: fmt.Sprintf("Template %q doesn't exist", createWorkspace.TemplateID.String()),
Message: fmt.Sprintf("Template %q doesn't exist.", createWorkspace.TemplateID.String()),
Validations: []httpapi.Error{{
Field: "template_id",
Detail: "template not found",
@ -239,7 +240,7 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching template",
Message: "Internal error fetching template.",
Detail: err.Error(),
})
return
@ -247,7 +248,7 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req
if organization.ID != template.OrganizationID {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: fmt.Sprintf("Template is not in organization %q", organization.Name),
Message: fmt.Sprintf("Template is not in organization %q.", organization.Name),
})
return
}
@ -257,13 +258,13 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req
})
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: "You aren't allowed to access templates in that organization",
Message: "You aren't allowed to access templates in that organization.",
})
return
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching organization member",
Message: "Internal error fetching organization member.",
Detail: err.Error(),
})
return
@ -272,7 +273,7 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req
dbAutostartSchedule, err := validWorkspaceSchedule(createWorkspace.AutostartSchedule, time.Duration(template.MinAutostartInterval))
if err != nil {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: "Invalid Autostart Schedule",
Message: "Invalid Autostart Schedule.",
Validations: []httpapi.Error{{Field: "schedule", Detail: err.Error()}},
})
return
@ -281,7 +282,7 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req
dbTTL, err := validWorkspaceTTLMillis(createWorkspace.TTLMillis, time.Duration(template.MaxTtl))
if err != nil {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: "Invalid Workspace TTL",
Message: "Invalid Workspace TTL.",
Validations: []httpapi.Error{{Field: "ttl_ms", Detail: err.Error()}},
})
return
@ -301,14 +302,14 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req
template, err := api.Database.GetTemplateByID(r.Context(), workspace.TemplateID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("Find template for conflicting workspace name %q", createWorkspace.Name),
Message: fmt.Sprintf("Find template for conflicting workspace name %q.", createWorkspace.Name),
Detail: err.Error(),
})
return
}
// The template is fetched for clarity to the user on where the conflicting name may be.
httpapi.Write(rw, http.StatusConflict, httpapi.Response{
Message: fmt.Sprintf("Workspace %q already exists in the %q template", createWorkspace.Name, template.Name),
Message: fmt.Sprintf("Workspace %q already exists in the %q template.", createWorkspace.Name, template.Name),
Validations: []httpapi.Error{{
Field: "name",
Detail: "this value is already in use and should be unique",
@ -318,7 +319,7 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req
}
if !errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("Internal error fetching workspace by name %q", createWorkspace.Name),
Message: fmt.Sprintf("Internal error fetching workspace by name %q.", createWorkspace.Name),
Detail: err.Error(),
})
return
@ -327,7 +328,7 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req
templateVersion, err := api.Database.GetTemplateVersionByID(r.Context(), template.ActiveVersionID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching template version",
Message: "Internal error fetching template version.",
Detail: err.Error(),
})
return
@ -335,7 +336,7 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req
templateVersionJob, err := api.Database.GetProvisionerJobByID(r.Context(), templateVersion.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching template version job",
Message: "Internal error fetching template version job.",
Detail: err.Error(),
})
return
@ -437,7 +438,7 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req
})
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error creating workspace",
Message: "Internal error creating workspace.",
Detail: err.Error(),
})
return
@ -445,7 +446,7 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req
user, err := api.Database.GetUserByID(r.Context(), apiKey.UserID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error fetching user",
Message: "Internal error fetching user.",
Detail: err.Error(),
})
return
@ -470,7 +471,7 @@ func (api *API) putWorkspaceAutostart(rw http.ResponseWriter, r *http.Request) {
if err != nil {
api.Logger.Error(r.Context(), "fetch workspace template", slog.F("workspace_id", workspace.ID), slog.F("template_id", workspace.TemplateID), slog.Error(err))
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Error fetching workspace template",
Message: "Error fetching workspace template.",
})
return
}
@ -478,7 +479,7 @@ func (api *API) putWorkspaceAutostart(rw http.ResponseWriter, r *http.Request) {
dbSched, err := validWorkspaceSchedule(req.Schedule, time.Duration(template.MinAutostartInterval))
if err != nil {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: "Invalid autostart schedule",
Message: "Invalid autostart schedule.",
Validations: []httpapi.Error{{Field: "schedule", Detail: err.Error()}},
})
return
@ -490,7 +491,7 @@ func (api *API) putWorkspaceAutostart(rw http.ResponseWriter, r *http.Request) {
})
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error updating workspace autostart schedule",
Message: "Internal error updating workspace autostart schedule.",
Detail: err.Error(),
})
return
@ -520,7 +521,7 @@ func (api *API) putWorkspaceTTL(rw http.ResponseWriter, r *http.Request) {
dbTTL, err := validWorkspaceTTLMillis(req.TTLMillis, time.Duration(template.MaxTtl))
if err != nil {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: "Invalid workspace TTL",
Message: "Invalid workspace TTL.",
Detail: err.Error(),
Validations: []httpapi.Error{
{
@ -538,7 +539,7 @@ func (api *API) putWorkspaceTTL(rw http.ResponseWriter, r *http.Request) {
})
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Internal error updating workspace TTL",
Message: "Internal error updating workspace TTL.",
Detail: err.Error(),
})
return
@ -564,20 +565,20 @@ func (api *API) putExtendWorkspace(rw http.ResponseWriter, r *http.Request) {
build, err := s.GetLatestWorkspaceBuildByWorkspaceID(r.Context(), workspace.ID)
if err != nil {
code = http.StatusInternalServerError
resp.Message = "workspace not found"
resp.Message = "Workspace not found."
return xerrors.Errorf("get latest workspace build: %w", err)
}
if build.Transition != database.WorkspaceTransitionStart {
code = http.StatusConflict
resp.Message = "workspace must be started, current status: " + string(build.Transition)
resp.Message = "Workspace must be started, current status: " + string(build.Transition)
return xerrors.Errorf("workspace must be started, current status: %s", build.Transition)
}
newDeadline := req.Deadline.UTC()
if err := validWorkspaceDeadline(build.Deadline, newDeadline); err != nil {
code = http.StatusBadRequest
resp.Message = "bad extend workspace request"
resp.Message = "Bad extend workspace request."
resp.Validations = append(resp.Validations, httpapi.Error{Field: "deadline", Detail: err.Error()})
return err
}
@ -589,10 +590,10 @@ func (api *API) putExtendWorkspace(rw http.ResponseWriter, r *http.Request) {
Deadline: newDeadline,
}); err != nil {
code = http.StatusInternalServerError
resp.Message = "failed to extend workspace deadline"
resp.Message = "Failed to extend workspace deadline."
return xerrors.Errorf("update workspace build: %w", err)
}
resp.Message = "deadline updated to " + newDeadline.Format(time.RFC3339)
resp.Message = "Deadline updated to " + newDeadline.Format(time.RFC3339) + "."
return nil
})
@ -651,7 +652,7 @@ func (api *API) watchWorkspace(rw http.ResponseWriter, r *http.Request) {
workspace, err := api.Database.GetWorkspaceByID(r.Context(), workspace.ID)
if err != nil {
_ = wsjson.Write(ctx, c, httpapi.Response{
Message: "Internal error fetching workspace",
Message: "Internal error fetching workspace.",
Detail: err.Error(),
})
return
@ -659,7 +660,7 @@ func (api *API) watchWorkspace(rw http.ResponseWriter, r *http.Request) {
build, err := api.Database.GetLatestWorkspaceBuildByWorkspaceID(r.Context(), workspace.ID)
if err != nil {
_ = wsjson.Write(ctx, c, httpapi.Response{
Message: "Internal error fetching workspace build",
Message: "Internal error fetching workspace build.",
Detail: err.Error(),
})
return
@ -685,7 +686,7 @@ func (api *API) watchWorkspace(rw http.ResponseWriter, r *http.Request) {
err = group.Wait()
if err != nil {
_ = wsjson.Write(ctx, c, httpapi.Response{
Message: "Internal error fetching resource",
Message: "Internal error fetching resource.",
Detail: err.Error(),
})
return

View File

@ -603,7 +603,7 @@ func TestWorkspaceUpdateAutostart(t *testing.T) {
require.IsType(t, err, &codersdk.Error{}, "expected codersdk.Error")
coderSDKErr, _ := err.(*codersdk.Error) //nolint:errorlint
require.Equal(t, coderSDKErr.StatusCode(), 404, "expected status code 404")
require.Equal(t, fmt.Sprintf("Workspace %q does not exist", wsid), coderSDKErr.Message, "unexpected response code")
require.Equal(t, fmt.Sprintf("Workspace %q does not exist.", wsid), coderSDKErr.Message, "unexpected response code")
})
}
@ -704,7 +704,7 @@ func TestWorkspaceUpdateTTL(t *testing.T) {
require.IsType(t, err, &codersdk.Error{}, "expected codersdk.Error")
coderSDKErr, _ := err.(*codersdk.Error) //nolint:errorlint
require.Equal(t, coderSDKErr.StatusCode(), 404, "expected status code 404")
require.Equal(t, fmt.Sprintf("Workspace %q does not exist", wsid), coderSDKErr.Message, "unexpected response code")
require.Equal(t, fmt.Sprintf("Workspace %q does not exist.", wsid), coderSDKErr.Message, "unexpected response code")
})
}

View File

@ -115,3 +115,38 @@ func InTx(m dsl.Matcher) {
`).Where(m["x"].Text != m["y"].Text).
At(m["f"]).Report("Pass the tx database into the '$f' function inside the closure. Use '$y' over $x'")
}
// HttpAPIErrorMessage intends to enforce constructing proper sentences as
// error messages for the api. A proper sentence includes proper capitalization
// and ends with punctuation.
// There are ways around the linter, but this should work in the common cases.
func HttpAPIErrorMessage(m dsl.Matcher) {
m.Import("github.com/coder/coder/coderd/httpapi")
isNotProperError := func(v dsl.Var) bool {
return v.Type.Is("string") &&
// Either starts with a lowercase, or ends without punctuation.
// The reason I don't check for NOT ^[A-Z].*[.!?]$ is because there
// are some exceptions. Any string starting with a formatting
// directive (%s) for example is exempt.
(m["m"].Text.Matches(`^"[a-z].*`) ||
m["m"].Text.Matches(`.*[^.!?]"$`))
}
m.Match(`
httpapi.Write($_, $s, httpapi.Response{
$*_,
Message: $m,
$*_,
})
`, `
httpapi.Write($_, $s, httpapi.Response{
$*_,
Message: fmt.$f($m, $*_),
$*_,
})
`,
).Where(isNotProperError(m["m"])).
At(m["m"]).
Report("Field \"Message\" should be a proper sentence with a capitalized first letter and ending in punctuation. $m")
}