Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: column description – backend #4331

Merged
merged 8 commits into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 42 additions & 33 deletions server/api.postman_collection.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"info": {
"_postman_id": "45d5f690-f459-4371-a09f-8aff874591f2",
"_postman_id": "42d60e2e-95bb-4336-8893-afed92d835c3",
"name": "scrumlr.io",
"description": "This is the documentation for the REST API server of the application [scrumlr.io](https://scrumlr.io). You get in touch with us and send an email to [[email protected]](https://[email protected]). The software is [MIT licensed](https://opensource.org/licenses/MIT) so do whatever you want with it. If you want to checkout the progress of our development and take a peek into our backlog you can checkout our [GitHub repository](https://github.com/inovex/scrumlr.io). By the way, this already the third iteration of our server and we're still working on the interface and on further improvements. Since the API is mainly intended for our web client we won't start with API versions at the moment so breaking changes may be incoming. Once it got stable we'll maybe start with that.\n\nIf you're using the postman collection in order to explore the different resources you should also checkout the variables of the collection. Anytime you'll create new resources (e.g. your login or a board) variables will be stored and used for subsequent calls on other resources.\n\nAccess to protected resources will be authorized if a bearer token is sent or it is included in the `jwt` Cookie, which will be automatically set upon login.\n\n## Getting started\n\nLet's try to explain the basic flow of how a new board can will be created and someone tries to join the board as a participant.\n\nFirst you can check whether you are already logged in by a `GET` request on `/user`. See the _User_ section for more information.\n\n1. A user signs into the application (see _Login_ section)\n2. The user creates a new board (`POST` on `/boards`, checkout _Boards_ section)\n3. Another logged in user tries to join the board (`POST` on `/boards/{id}/participants`, checkout _Participants_ section)\n 1. If the boards access policy is set to `PUBLIC` the participant will be added to the board and afterwards all resources will be available\n 2. If the board requires a passphrase and the access policy is set to `BY_PASSPHRASE` a client error will be reported until the user sends the correct passphrase within the payload of the request\n 3. If the boards access policy is set to `BY_INVITE` a session request will be created instead and the user will be redirected to the new resource. The board owner now needs to accept or reject the request until the user can continue\n\nThese are just the basic steps of how sessions can be created. You can also have a look into the section _Realtime_ to see how you can open websockets and listen to live updates on the data.",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
"_exporter_id": "32837949"
"_exporter_id": "32423964"
},
"item": [
{
Expand Down Expand Up @@ -1392,7 +1392,7 @@
" pm.expect(response.code).to.be.equal(201);",
" });",
" ",
" res = response.json();",
" const res = response.json();",
" pm.test(\"PreRequestScript – Check id is included\", function () {",
" var id = res.id;",
" pm.expect(id).to.exist;",
Expand Down Expand Up @@ -2207,7 +2207,7 @@
" pm.expect(response.code).to.be.equal(200);",
" });",
" ",
" res = response.json();",
" const res = response.json();",
" pm.test(\"PreRequestScript – Check id\", function () {",
" var id = res.id;",
" pm.expect(id).to.exist;",
Expand Down Expand Up @@ -2589,26 +2589,29 @@
"listen": "test",
"script": {
"exec": [
"pm.test(\"Successful POST request\", function () {\r",
"const res = pm.response.json();\r",
"\r",
"pm.test(\"Successful POST request\", () => {\r",
" pm.expect(pm.response).to.have.status(201);\r",
"});\r",
"\r",
"pm.test(\"Check id is included\", function () {\r",
" var id = pm.response.json().id;\r",
"pm.test(\"Check id is included\", () => {\r",
" pm.expect(res.id).to.exist;\r",
" pm.expect(res.id).to.be.not.empty;\r",
" pm.collectionVariables.set(\"column_id\", res.id);\r",
"})\r",
"\r",
" pm.expect(id).to.exist;\r",
" pm.expect(id).to.be.not.empty;\r",
" pm.collectionVariables.set(\"column_id\", id);\r",
"pm.test(\"Check column name to be right\", () => {\r",
" pm.expect(res.name).to.equal(\"My new column\");\r",
"})\r",
"\r",
"pm.test(\"Check column name to be right\", function () {\r",
" var name = pm.response.json().name;\r",
" pm.expect(name).to.equal(\"My new column\");\r",
"pm.test(\"Check if column is correctly not visible\", () => {\r",
" pm.expect(res.visible).to.eql(false);\r",
"})\r",
"\r",
"pm.test(\"Check if column is correctly not visible\", function () {\r",
" var visible = pm.response.json().visible;\r",
" pm.expect(visible).to.eql(false);\r",
"pm.test(\"Check if description is saved\", () => {\r",
" pm.expect(res.description).to.exist;\r",
" pm.expect(res.description).to.equal(\"The column description\");\r",
"})"
],
"type": "text/javascript",
Expand All @@ -2621,7 +2624,7 @@
"header": [],
"body": {
"mode": "raw",
"raw": "{\r\n \"name\": \"My new column\",\r\n \"visible\": false,\r\n \"color\": \"backlog-blue\",\r\n \"index\": 1\r\n}",
"raw": "{\r\n \"name\": \"My new column\",\r\n \"description\": \"The column description\",\r\n \"visible\": false,\r\n \"color\": \"backlog-blue\",\r\n \"index\": 1\r\n}",
"options": {
"raw": {
"language": "json"
Expand Down Expand Up @@ -2692,7 +2695,7 @@
}
],
"cookie": [],
"body": "{\n \"id\": \"fecb346a-9d9e-43ca-b873-8fcb09f2b0c3\",\n \"name\": \"My new column\",\n \"color\": \"lean-lilac\",\n \"visible\": false,\n \"index\": 1\n}"
"body": "{\n \"id\": \"fecb346a-9d9e-43ca-b873-8fcb09f2b0c3\",\n \"name\": \"My new column\",\n \"description\": \"The column description\",\n \"color\": \"lean-lilac\",\n \"visible\": false,\n \"index\": 1\n}"
}
]
},
Expand All @@ -2703,18 +2706,20 @@
"listen": "test",
"script": {
"exec": [
"const res = pm.response.json();",
"",
"pm.test(\"Successful GET request\", function () {",
" pm.expect(pm.response).to.have.status(200);",
"});",
"",
"pm.test(\"Check length of coumns array\", function () {",
" var res = pm.response.json();",
" pm.expect(res).to.be.an(\"array\");",
" pm.expect(res.length).to.be.equal(3);",
"})",
""
],
"type": "text/javascript"
"type": "text/javascript",
"packages": {}
}
}
],
Expand Down Expand Up @@ -2771,7 +2776,7 @@
}
],
"cookie": [],
"body": "[\n {\n \"id\": \"526d5efb-281d-4f4f-b308-6537e6727381\",\n \"name\": \"Lean coffee\",\n \"color\": \"backlog-blue\",\n \"visible\": true,\n \"index\": 0\n },\n {\n \"id\": \"fecb346a-9d9e-43ca-b873-8fcb09f2b0c3\",\n \"name\": \"My new column\",\n \"color\": \"lean-lilac\",\n \"visible\": false,\n \"index\": 1\n },\n {\n \"id\": \"70cb04ee-b46e-4176-940c-cdf06cadef07\",\n \"name\": \"Actions\",\n \"color\": \"planning-pink\",\n \"visible\": false,\n \"index\": 2\n }\n]"
"body": "[\n {\n \"id\": \"526d5efb-281d-4f4f-b308-6537e6727381\",\n \"name\": \"Lean coffee\",\n \"description\": \"The column description\",\n \"color\": \"backlog-blue\",\n \"visible\": true,\n \"index\": 0\n },\n {\n \"id\": \"fecb346a-9d9e-43ca-b873-8fcb09f2b0c3\",\n \"name\": \"My new column\",\n \"description\": \"\",\n \"color\": \"lean-lilac\",\n \"visible\": false,\n \"index\": 1\n },\n {\n \"id\": \"70cb04ee-b46e-4176-940c-cdf06cadef07\",\n \"name\": \"Actions\",\n \"description\": \"\",\n \"color\": \"planning-pink\",\n \"visible\": false,\n \"index\": 2\n }\n]"
}
]
},
Expand All @@ -2782,20 +2787,22 @@
"listen": "test",
"script": {
"exec": [
"pm.test(\"Successful GET request\", function () {",
"const res = pm.response.json();",
"",
"pm.test(\"Successful GET request\", () => {",
" pm.expect(pm.response).to.have.status(200);",
"});",
"",
"pm.test(\"Check column\", function () {",
" var res = pm.response.json();",
"",
"pm.test(\"Check column\", () => {",
" pm.expect(res.id).to.equal(pm.collectionVariables.get(\"column_id\"));",
" pm.expect(res.name).to.equal(\"My new column\");",
" pm.expect(res.description).to.equal(\"The column description\");",
" pm.expect(res.visible).to.eql(false);",
" pm.expect(res.index).to.equal(1);",
"})"
],
"type": "text/javascript"
"type": "text/javascript",
"packages": {}
}
}
],
Expand Down Expand Up @@ -2854,7 +2861,7 @@
}
],
"cookie": [],
"body": "{\n \"id\": \"fecb346a-9d9e-43ca-b873-8fcb09f2b0c3\",\n \"name\": \"My new column\",\n \"color\": \"lean-lilac\",\n \"visible\": false,\n \"index\": 1\n}"
"body": "{\n \"id\": \"fecb346a-9d9e-43ca-b873-8fcb09f2b0c3\",\n \"name\": \"My new column\",\n \"description\": \"The column description\",\n \"color\": \"lean-lilac\",\n \"visible\": false,\n \"index\": 1\n}"
}
]
},
Expand All @@ -2865,20 +2872,22 @@
"listen": "test",
"script": {
"exec": [
"const res = pm.response.json();",
"",
"pm.test(\"Successful PUT request\", function () {",
" pm.expect(pm.response).to.have.status(200);",
"});",
"",
"pm.test(\"Check updated values\", function () {",
" var res = pm.response.json();",
"",
" pm.expect(res.name).to.equal(\"Updated column name\");",
" pm.expect(res.description).to.equal(\"The updated column description\");",
" pm.expect(res.color).to.equal(\"online-orange\");",
" pm.expect(res.visible).to.equal(true);",
" pm.expect(res.index).to.equal(0);",
"})"
],
"type": "text/javascript"
"type": "text/javascript",
"packages": {}
}
}
],
Expand All @@ -2887,7 +2896,7 @@
"header": [],
"body": {
"mode": "raw",
"raw": "{\r\n \"name\": \"Updated column name\",\r\n \"color\": \"online-orange\",\r\n \"visible\": true,\r\n \"index\": 0\r\n}",
"raw": "{\r\n \"name\": \"Updated column name\",\r\n \"description\": \"The updated column description\",\r\n \"color\": \"online-orange\",\r\n \"visible\": true,\r\n \"index\": 0\r\n}",
"options": {
"raw": {
"language": "json"
Expand Down Expand Up @@ -2955,7 +2964,7 @@
}
],
"cookie": [],
"body": "{\n \"id\": \"fecb346a-9d9e-43ca-b873-8fcb09f2b0c3\",\n \"name\": \"Updated column name\",\n \"color\": \"online-orange\",\n \"visible\": true,\n \"index\": 0\n}"
"body": "{\n \"id\": \"fecb346a-9d9e-43ca-b873-8fcb09f2b0c3\",\n \"description\": \"The updated column description\",\n \"name\": \"Updated column name\",\n \"color\": \"online-orange\",\n \"visible\": true,\n \"index\": 0\n}"
}
]
},
Expand Down Expand Up @@ -3583,7 +3592,7 @@
" });",
" ",
" pm.test(\"PreRequestScript – safe note to delete\", function () {",
" res = response.json();",
" const res = response.json();",
" pm.expect(res.id).to.exist;",
" pm.collectionVariables.set(\"note_to_delete_id\", res.id); ",
" })",
Expand Down
13 changes: 12 additions & 1 deletion server/src/common/dto/columns.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package dto

import (
"github.com/google/uuid"
"net/http"

"github.com/google/uuid"
"scrumlr.io/server/database"
"scrumlr.io/server/database/types"
)
Expand All @@ -16,6 +17,9 @@ type Column struct {
// The column name.
Name string `json:"name"`

// The column description.
Description string `json:"description"`

// The column color.
Color types.Color `json:"color"`

Expand All @@ -29,6 +33,7 @@ type Column struct {
func (c *Column) From(column database.Column) *Column {
c.ID = column.ID
c.Name = column.Name
c.Description = column.Description
c.Color = column.Color
c.Visible = column.Visible
c.Index = column.Index
Expand Down Expand Up @@ -57,6 +62,9 @@ type ColumnRequest struct {
// The column name to set.
Name string `json:"name"`

// The column description to set.
Description string `json:"description"`

// The column color to set.
Color types.Color `json:"color"`

Expand All @@ -78,6 +86,9 @@ type ColumnUpdateRequest struct {
// The column name to set.
Name string `json:"name"`

// The column description to set.
Description string `json:"description"`

// The column color to set.
Color types.Color `json:"color"`

Expand Down
3 changes: 3 additions & 0 deletions server/src/database/columns.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type Column struct {
ID uuid.UUID
Board uuid.UUID
Name string
Description string
Color types.Color
Visible bool
Index int
Expand All @@ -28,6 +29,7 @@ type ColumnInsert struct {
bun.BaseModel `bun:"table:columns"`
Board uuid.UUID
Name string
Description string
Color types.Color
Visible *bool
Index *int
Expand All @@ -39,6 +41,7 @@ type ColumnUpdate struct {
ID uuid.UUID
Board uuid.UUID
Name string
Description string
Color types.Color
Visible bool
Index int
Expand Down
18 changes: 17 additions & 1 deletion server/src/database/columns_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package database

import (
"testing"

"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"scrumlr.io/server/database/types"
"testing"
)

var boardForColumnsTest uuid.UUID
Expand Down Expand Up @@ -49,6 +50,7 @@ func TestRunnerForColumns(t *testing.T) {
t.Run("Update=4", testMoveLastColumnOnFirstIndex)
t.Run("Update=5", testMoveFirstColumnOnSecondIndex)
t.Run("Update=6", testMoveSecondColumnOnFirstIndex)
t.Run("Update=7", testUpdateDescription)
}

func testGetColumn(t *testing.T) {
Expand Down Expand Up @@ -337,3 +339,17 @@ func verifyOrder(t *testing.T, ids ...uuid.UUID) {
assert.Equal(t, index, value.Index)
}
}

func testUpdateDescription(t *testing.T) {
column, err := testDb.UpdateColumn(ColumnUpdate{
ID: firstColumn.ID,
Board: boardForColumnsTest,
Name: "FirstColumn",
Description: "Updated Column Description",
Color: types.ColorBacklogBlue,
Visible: true,
Index: 0,
})
assert.Nil(t, err)
assert.Equal(t, "Updated Column Description", column.Description)
}
BenedictHomuth marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE IF EXISTS columns DROP COLUMN IF EXISTS "description";
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE IF EXISTS columns ADD COLUMN "description" VARCHAR(128) DEFAULT '';
4 changes: 2 additions & 2 deletions server/src/services/boards/columns.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (
)

func (s *BoardService) CreateColumn(_ context.Context, body dto.ColumnRequest) (*dto.Column, error) {
column, err := s.database.CreateColumn(database.ColumnInsert{Board: body.Board, Name: body.Name, Color: body.Color, Visible: body.Visible, Index: body.Index})
column, err := s.database.CreateColumn(database.ColumnInsert{Board: body.Board, Name: body.Name, Description: body.Description, Color: body.Color, Visible: body.Visible, Index: body.Index})
if err != nil {
logger.Get().Errorw("unable to create column", "err", err)
return nil, err
Expand All @@ -36,7 +36,7 @@ func (s *BoardService) DeleteColumn(_ context.Context, board, column, user uuid.
}

func (s *BoardService) UpdateColumn(_ context.Context, body dto.ColumnUpdateRequest) (*dto.Column, error) {
column, err := s.database.UpdateColumn(database.ColumnUpdate{ID: body.ID, Board: body.Board, Name: body.Name, Color: body.Color, Visible: body.Visible, Index: body.Index})
column, err := s.database.UpdateColumn(database.ColumnUpdate{ID: body.ID, Board: body.Board, Name: body.Name, Description: body.Description, Color: body.Color, Visible: body.Visible, Index: body.Index})
if err != nil {
logger.Get().Errorw("unable to update column", "err", err)
return nil, err
Expand Down
Loading