Added PUT /account/{id}/fields
This commit is contained in:
parent
227132413a
commit
880a384f35
|
@ -34,12 +34,12 @@ func (d Db) AccountCreate(input AccountCreateInput) (CreatedAccount, error) {
|
|||
|
||||
_, err := d.DbPool.Exec(context.Background(), accountFieldsSQL, newFieldID, input.ID, field.Name, field.Values)
|
||||
if err != nil {
|
||||
if strings.HasPrefix(err.Error(), "ERROR: duplicate key") {
|
||||
d.Log.Error("Database error when trying to account field", "err", err.Error())
|
||||
}
|
||||
//if strings.HasPrefix(err.Error(), "ERROR: duplicate key") {
|
||||
d.Log.Error("Database error when trying to add account field", "err", err.Error(), "accountID", input.ID, "fieldName", field.Name, "fieldvalues", field.Values)
|
||||
// }
|
||||
}
|
||||
|
||||
d.Log.Debug("Added account field", "accountId", input.ID, "fieldName", field.Name, "fieldValues", field.Values)
|
||||
d.Log.Debug("Added account field", "accountID", input.ID, "fieldName", field.Name, "fieldValues", field.Values)
|
||||
}
|
||||
|
||||
return CreatedAccount{
|
||||
|
@ -129,3 +129,51 @@ func (d Db) AccountGet(accountID string, APIKey string, Name string) (Account, e
|
|||
|
||||
return account, nil
|
||||
}
|
||||
|
||||
func (d Db) AccountUpdateFields(accountID string, fields []AccountCreateInputFields) (Account, error) {
|
||||
// Begin database transaction
|
||||
conn, err := d.DbPool.Acquire(context.Background())
|
||||
if err != nil {
|
||||
d.Log.Error("Could not acquire database connection", "err", err.Error(), "accountID", accountID)
|
||||
return Account{}, err
|
||||
}
|
||||
|
||||
tx, err := conn.Begin(context.Background())
|
||||
if err != nil {
|
||||
d.Log.Error("Could not begin database transaction", "err", err.Error(), "accountID", accountID)
|
||||
return Account{}, err
|
||||
}
|
||||
|
||||
// Rollback is safe to call even if the tx is already closed, so if
|
||||
// the tx commits successfully, this is a no-op
|
||||
defer tx.Rollback(context.Background())
|
||||
|
||||
_, err = tx.Exec(context.Background(), "DELETE FROM \"accountsFields\" WHERE \"accountId\" = $1;", accountID)
|
||||
if err != nil {
|
||||
d.Log.Error("Could not delete previous fields", "err", err.Error(), "accountID", accountID)
|
||||
return Account{}, err
|
||||
}
|
||||
|
||||
accountFieldsSQL := "INSERT INTO \"accountsFields\" (id, \"accountId\", name, value) VALUES($1,$2,$3,$4);"
|
||||
for _, field := range fields {
|
||||
newFieldID, err := uuid.NewRandom()
|
||||
if err != nil {
|
||||
d.Log.Fatal("Could not create new Uuid", "err", err.Error())
|
||||
}
|
||||
|
||||
_, err = tx.Exec(context.Background(), accountFieldsSQL, newFieldID, accountID, field.Name, field.Values)
|
||||
if err != nil {
|
||||
d.Log.Error("Database error when trying to add account field", "err", err.Error(), "accountID", accountID, "fieldName", field.Name, "fieldvalues", field.Values)
|
||||
}
|
||||
|
||||
d.Log.Debug("Added account field", "accountID", accountID, "fieldName", field.Name, "fieldValues", field.Values)
|
||||
}
|
||||
|
||||
err = tx.Commit(context.Background())
|
||||
if err != nil {
|
||||
d.Log.Error("Database error when tying to commit", "err", err.Error())
|
||||
return Account{}, err
|
||||
}
|
||||
|
||||
return d.AccountGet(accountID, "", "")
|
||||
}
|
||||
|
|
|
@ -119,7 +119,7 @@ var doc = `{
|
|||
},
|
||||
"/account/:id": {
|
||||
"delete": {
|
||||
"description": "Requires Authorization-header with role \"admin\".\nExample: Authorization: bearer xxx\nWhere \"xxx\" is a valid JWT token",
|
||||
"description": "Requires Authorization-header with role \"admin\" or a matching account id\nExample: Authorization: bearer xxx\nWhere \"xxx\" is a valid JWT token",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
|
@ -171,6 +171,15 @@ var doc = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/handlers.ResJSONError"
|
||||
}
|
||||
}
|
||||
},
|
||||
"415": {
|
||||
"description": "Unsupported Media Type",
|
||||
"schema": {
|
||||
|
@ -258,6 +267,86 @@ var doc = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"/account/{id}/fields": {
|
||||
"put": {
|
||||
"description": "Requires Authorization-header with role \"admin\".\nExample: Authorization: bearer xxx\nWhere \"xxx\" is a valid JWT token",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"summary": "Update account fields",
|
||||
"operationId": "account-update-fields",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Fields array with objects to be written to database",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/db.AccountCreateInputFields"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/db.Account"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/handlers.ResJSONError"
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/handlers.ResJSONError"
|
||||
}
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "Forbidden",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/handlers.ResJSONError"
|
||||
}
|
||||
}
|
||||
},
|
||||
"415": {
|
||||
"description": "Unsupported Media Type",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/handlers.ResJSONError"
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/handlers.ResJSONError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/api-key": {
|
||||
"post": {
|
||||
"description": "Authenticate account by API Key",
|
||||
|
|
|
@ -103,7 +103,7 @@
|
|||
},
|
||||
"/account/:id": {
|
||||
"delete": {
|
||||
"description": "Requires Authorization-header with role \"admin\".\nExample: Authorization: bearer xxx\nWhere \"xxx\" is a valid JWT token",
|
||||
"description": "Requires Authorization-header with role \"admin\" or a matching account id\nExample: Authorization: bearer xxx\nWhere \"xxx\" is a valid JWT token",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
|
@ -155,6 +155,15 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/handlers.ResJSONError"
|
||||
}
|
||||
}
|
||||
},
|
||||
"415": {
|
||||
"description": "Unsupported Media Type",
|
||||
"schema": {
|
||||
|
@ -242,6 +251,86 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/account/{id}/fields": {
|
||||
"put": {
|
||||
"description": "Requires Authorization-header with role \"admin\".\nExample: Authorization: bearer xxx\nWhere \"xxx\" is a valid JWT token",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"summary": "Update account fields",
|
||||
"operationId": "account-update-fields",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Fields array with objects to be written to database",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/db.AccountCreateInputFields"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/db.Account"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/handlers.ResJSONError"
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/handlers.ResJSONError"
|
||||
}
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "Forbidden",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/handlers.ResJSONError"
|
||||
}
|
||||
}
|
||||
},
|
||||
"415": {
|
||||
"description": "Unsupported Media Type",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/handlers.ResJSONError"
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/handlers.ResJSONError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/api-key": {
|
||||
"post": {
|
||||
"description": "Authenticate account by API Key",
|
||||
|
|
|
@ -142,7 +142,7 @@ paths:
|
|||
consumes:
|
||||
- application/json
|
||||
description: |-
|
||||
Requires Authorization-header with role "admin".
|
||||
Requires Authorization-header with role "admin" or a matching account id
|
||||
Example: Authorization: bearer xxx
|
||||
Where "xxx" is a valid JWT token
|
||||
operationId: account-del
|
||||
|
@ -177,6 +177,12 @@ paths:
|
|||
items:
|
||||
$ref: '#/definitions/handlers.ResJSONError'
|
||||
type: array
|
||||
"404":
|
||||
description: Not Found
|
||||
schema:
|
||||
items:
|
||||
$ref: '#/definitions/handlers.ResJSONError'
|
||||
type: array
|
||||
"415":
|
||||
description: Unsupported Media Type
|
||||
schema:
|
||||
|
@ -237,6 +243,62 @@ paths:
|
|||
$ref: '#/definitions/handlers.ResJSONError'
|
||||
type: array
|
||||
summary: Get account by id
|
||||
/account/{id}/fields:
|
||||
put:
|
||||
consumes:
|
||||
- application/json
|
||||
description: |-
|
||||
Requires Authorization-header with role "admin".
|
||||
Example: Authorization: bearer xxx
|
||||
Where "xxx" is a valid JWT token
|
||||
operationId: account-update-fields
|
||||
parameters:
|
||||
- description: Fields array with objects to be written to database
|
||||
in: body
|
||||
name: body
|
||||
required: true
|
||||
schema:
|
||||
items:
|
||||
$ref: '#/definitions/db.AccountCreateInputFields'
|
||||
type: array
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/db.Account'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
items:
|
||||
$ref: '#/definitions/handlers.ResJSONError'
|
||||
type: array
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
items:
|
||||
$ref: '#/definitions/handlers.ResJSONError'
|
||||
type: array
|
||||
"403":
|
||||
description: Forbidden
|
||||
schema:
|
||||
items:
|
||||
$ref: '#/definitions/handlers.ResJSONError'
|
||||
type: array
|
||||
"415":
|
||||
description: Unsupported Media Type
|
||||
schema:
|
||||
items:
|
||||
$ref: '#/definitions/handlers.ResJSONError'
|
||||
type: array
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
items:
|
||||
$ref: '#/definitions/handlers.ResJSONError'
|
||||
type: array
|
||||
summary: Update account fields
|
||||
/auth/api-key:
|
||||
post:
|
||||
consumes:
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
|
||||
// AccountDel godoc
|
||||
// @Summary Delete an account
|
||||
// @Description Requires Authorization-header with role "admin".
|
||||
// @Description Requires Authorization-header with role "admin" or a matching account id
|
||||
// @Description Example: Authorization: bearer xxx
|
||||
// @Description Where "xxx" is a valid JWT token
|
||||
// @ID account-del
|
||||
|
|
52
src/handlers/put.go
Normal file
52
src/handlers/put.go
Normal file
|
@ -0,0 +1,52 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/google/uuid"
|
||||
"gitlab.larvit.se/power-plan/auth/src/db"
|
||||
)
|
||||
|
||||
// AccountUpdateFields godoc
|
||||
// @Summary Update account fields
|
||||
// @Description Requires Authorization-header with role "admin".
|
||||
// @Description Example: Authorization: bearer xxx
|
||||
// @Description Where "xxx" is a valid JWT token
|
||||
// @ID account-update-fields
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param body body []db.AccountCreateInputFields true "Fields array with objects to be written to database"
|
||||
// @Success 200 {object} db.Account
|
||||
// @Failure 400 {object} []ResJSONError
|
||||
// @Failure 401 {object} []ResJSONError
|
||||
// @Failure 403 {object} []ResJSONError
|
||||
// @Failure 415 {object} []ResJSONError
|
||||
// @Failure 500 {object} []ResJSONError
|
||||
// @Router /account/{id}/fields [put]
|
||||
func (h Handlers) AccountUpdateFields(c *fiber.Ctx) error {
|
||||
accountID := c.Params("accountID")
|
||||
|
||||
_, uuidErr := uuid.Parse(accountID)
|
||||
if uuidErr != nil {
|
||||
return c.Status(400).JSON([]ResJSONError{{Error: "Invalid uuid format"}})
|
||||
}
|
||||
|
||||
authErr := h.RequireAdminRole(c)
|
||||
if authErr != nil {
|
||||
return c.Status(403).JSON([]ResJSONError{{Error: authErr.Error()}})
|
||||
}
|
||||
|
||||
fieldsInput := new([]db.AccountCreateInputFields)
|
||||
|
||||
if err := c.BodyParser(fieldsInput); err != nil {
|
||||
return c.Status(400).JSON([]ResJSONError{
|
||||
{Error: err.Error()},
|
||||
})
|
||||
}
|
||||
|
||||
updatedAccount, err := h.Db.AccountUpdateFields(accountID, *fieldsInput)
|
||||
if err != nil {
|
||||
return c.Status(500).JSON([]ResJSONError{{Error: "Internal server error"}})
|
||||
}
|
||||
|
||||
return c.Status(200).JSON(updatedAccount)
|
||||
}
|
|
@ -97,6 +97,8 @@ func main() {
|
|||
app.Post("/auth/api-key", handlers.AccountAuthAPIKey)
|
||||
app.Post("/auth/password", handlers.AccountAuthPassword)
|
||||
app.Post("/renew-token", handlers.RenewToken)
|
||||
app.Put("/account/:accountID/fields", handlers.AccountUpdateFields)
|
||||
// app.Put("")
|
||||
|
||||
log.Info("Trying to start web server", "WEB_BIND_HOST", os.Getenv("WEB_BIND_HOST"))
|
||||
|
||||
|
|
|
@ -110,6 +110,32 @@ test('test-cases/01basic.js: Auth by username and password', async t => {
|
|||
t.equal(userJWT.accountName, userName, 'The verified account name should match the created user');
|
||||
});
|
||||
|
||||
test('test-cases/01basic.js: PUT /account/{id}/fields', async t => {
|
||||
const res = await got.put(`${process.env.AUTH_URL}/account/${user.id}/fields`, {
|
||||
headers: { 'Authorization': `bearer ${adminJWTString}`},
|
||||
json: [
|
||||
{
|
||||
name: 'foo',
|
||||
values: ['bar'],
|
||||
},
|
||||
{
|
||||
name: 'role',
|
||||
values: ['tomte'],
|
||||
}
|
||||
],
|
||||
responseType: 'json',
|
||||
});
|
||||
|
||||
t.equal(user.id, res.body.id, 'The responded account id should be the same as the old one');
|
||||
t.equal(Object.keys(res.body.fields).length, 2, 'There should only be two fields in total');
|
||||
t.equal(JSON.stringify(res.body.fields.foo), '["bar"]', 'The foo field should have values ["bar"]');
|
||||
t.equal(JSON.stringify(res.body.fields.role), '["tomte"]', 'The role field should have values ["tomte"]');
|
||||
|
||||
// Overload the previous user
|
||||
user.fields = res.body.fields;
|
||||
user.name = res.body.name;
|
||||
});
|
||||
|
||||
test('test-cases/01basic.js: Remove an account', async t => {
|
||||
try {
|
||||
// Random uuid that should not exist in the db. The chance of this existing is... small
|
||||
|
|
Loading…
Reference in New Issue
Block a user