/
api.go
158 lines (136 loc) · 5.55 KB
/
api.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package account
import (
"net/http"
"github.com/joinself/restful-client/pkg/acl"
"github.com/joinself/restful-client/pkg/log"
"github.com/joinself/restful-client/pkg/pagination"
"github.com/joinself/restful-client/pkg/response"
"github.com/labstack/echo/v4"
)
// RegisterHandlers sets up the routing of the HTTP handlers.
func RegisterHandlers(r *echo.Group, service Service, logger log.Logger) {
res := resource{service, logger}
r.GET("", res.list)
r.POST("", res.create)
r.DELETE("/:username", res.delete)
r.PUT("/:username/password", res.changePassword)
}
type resource struct {
service Service
logger log.Logger
}
// CreateAccount godoc
// @Summary Creates a new account.
// @Description Creates a new account and sends a request for public information. You must be authenticated as an admin.
// @Tags accounts
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param request body CreateAccountRequest true "query params"
// @Success 200 {object} CreateAccountResponse
// @Router /accounts [post]
func (r resource) create(c echo.Context) error {
user := acl.CurrentUser(c)
if user == nil || !user.IsAdmin() {
return c.JSON(response.DefaultNotFoundError())
}
var input CreateAccountRequest
if err := c.Bind(&input); err != nil {
r.logger.With(c.Request().Context()).Info(err)
return c.JSON(response.DefaultBadRequestError())
}
if reqErr := input.Validate(); reqErr != nil {
r.logger.With(c.Request().Context()).Info(reqErr)
return c.JSON(reqErr.Status, reqErr)
}
account, err := r.service.Create(c.Request().Context(), input)
if err != nil {
return c.JSON(response.DefaultInternalError(c, r.logger, err.Error()))
}
return c.JSON(http.StatusCreated, CreateAccountResponse{
UserName: account.UserName,
Resources: account.Resources,
RequiresPasswordChange: (account.RequiresPasswordChange == 1),
})
}
// DeleteAccount godoc
// @Summary Deletes an existing account.
// @Description Deletes an existing account and sends a request for public information and avoids incoming comms from that account. You must be authenticated as an admin.
// @Tags accounts
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param username path string true "Username of the account to delete"
// @Success 204 {string} string "No Content"
// @Failure 404 {object} response.Error "Not found - The requested resource does not exist, or you don't have permissions to access it"
// @Router /accounts/{username} [delete]
func (r resource) delete(c echo.Context) error {
user := acl.CurrentUser(c)
if user == nil || !user.IsAdmin() {
return c.JSON(response.DefaultNotFoundError())
}
err := r.service.Delete(c.Request().Context(), c.Param("username"))
if err != nil {
return c.JSON(response.DefaultNotFoundError())
}
return c.NoContent(http.StatusNoContent)
}
// ChangePassword godoc
// @Summary Changes the password for the current user.
// @Description Changes the password for the current user. You must be authenticated.
// @Tags accounts
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param username path string true "Username of the account to change the password"
// @Param request body ChangePasswordRequest true "Password change details"
// @Success 200 {string} string "No Content"
// @Failure 400 {object} response.Error "Bad request - The provided body is not valid"
// @Failure 404 {object} response.Error "Not found - The requested resource does not exist, or you don't have permissions to access it"
// @Failure 500 {object} response.Error "Internal error - There was a problem with your request"
// @Router /accounts/{username}/password [put]
func (r resource) changePassword(c echo.Context) error {
ctx := c.Request().Context()
user := acl.CurrentUser(c)
if user == nil {
return c.JSON(response.DefaultNotFoundError())
}
if user.GetName() != c.Param("username") {
r.logger.With(ctx).Info("update username not matching")
return c.JSON(response.DefaultNotFoundError())
}
var i ChangePasswordRequest
if err := c.Bind(&i); err != nil {
r.logger.With(c.Request().Context()).Info(err)
return c.JSON(response.DefaultBadRequestError())
}
if reqErr := i.Validate(); reqErr != nil {
r.logger.With(ctx).Info(reqErr.Error)
return c.JSON(reqErr.Status, reqErr)
}
err := r.service.SetPassword(ctx, c.Param("username"), i.Password, i.NewPassword)
if err != nil {
return c.JSON(response.DefaultInternalError(c, r.logger, err.Error()))
}
return c.NoContent(http.StatusOK)
}
// ListAccounts godoc
// @Summary Lists all configured accounts.
// @Description Retrieves and lists all the configured accounts for the restful client. You must be authenticated as an admin.
// @Tags accounts
// @Accept json
// @Produce json
// @Security BearerAuth
// @Success 200 {object} ExtListResponse "Successful operation"
// @Failure 404 {object} response.Error "Not found - The requested resource does not exist, or you don't have permissions to access it"
// @Router /accounts [get]
func (r resource) list(c echo.Context) error {
user := acl.CurrentUser(c)
if user == nil || !user.IsAdmin() {
return c.JSON(response.DefaultNotFoundError())
}
apps := r.service.List(c.Request().Context())
pages := pagination.NewFromRequest(c.Request(), len(apps))
pages.Items = apps
return c.JSON(http.StatusOK, pages)
}