Skip to content

Commit bc205ea

Browse files
authored
Merge pull request #29 from traPtitech/feat/owners
2 parents 43801f2 + b42fde2 commit bc205ea

File tree

4 files changed

+440
-3
lines changed

4 files changed

+440
-3
lines changed

model/ownership.go

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
package model
22

3+
import (
4+
"errors"
5+
6+
"gorm.io/gorm"
7+
)
8+
39
type Ownership struct {
410
GormModel
511
ItemID int `gorm:"type:int;not null" json:"itemId"`
@@ -9,6 +15,101 @@ type Ownership struct {
915
Transaction []Transaction `gorm:"foreignKey:ownership_id;references:id"`
1016
}
1117

18+
type OwnershipPayload struct {
19+
ItemID int `json:"itemId"`
20+
UserID string `json:"userId"`
21+
Rentalable bool `json:"rentalable"`
22+
Memo string `json:"memo"`
23+
}
24+
1225
func (Ownership) TableName() string {
1326
return "ownerships"
1427
}
28+
29+
func CreateOwnership(ownership OwnershipPayload) (Ownership, error) {
30+
o := Ownership{
31+
ItemID: ownership.ItemID,
32+
UserID: ownership.UserID,
33+
Rentalable: ownership.Rentalable,
34+
Memo: ownership.Memo,
35+
}
36+
err := db.Transaction(func(tx *gorm.DB) error {
37+
if err := tx.Create(&o).Error; err != nil {
38+
return err
39+
}
40+
41+
return nil
42+
})
43+
if err != nil {
44+
return Ownership{}, err
45+
}
46+
47+
return o, nil
48+
}
49+
50+
func UpdateOwnership(ownershipId int, ownership OwnershipPayload) (Ownership, error) {
51+
ownershipOld, err := GetOwnership(ownershipId)
52+
if err != nil {
53+
return Ownership{}, err
54+
}
55+
56+
if ownershipOld.UserID != ownership.UserID {
57+
return Ownership{}, errors.New("編集する権限がありません")
58+
}
59+
60+
o := Ownership{
61+
ItemID: ownership.ItemID,
62+
UserID: ownership.UserID,
63+
Rentalable: ownership.Rentalable,
64+
Memo: ownership.Memo,
65+
Transaction: ownershipOld.Transaction,
66+
}
67+
err = db.Transaction(func(tx *gorm.DB) error {
68+
if err := tx.Model(&Ownership{}).Where("id = ?", ownershipId).Updates(map[string]interface{}{
69+
"rentalable": o.Rentalable,
70+
"memo": o.Memo,
71+
}).Error; err != nil {
72+
return err
73+
}
74+
return nil
75+
})
76+
if err != nil {
77+
return Ownership{}, err
78+
}
79+
80+
return o, nil
81+
}
82+
83+
func DeleteOwnership(ownershipId int, userId string) error {
84+
ownershipOld, err := GetOwnership(ownershipId)
85+
if err != nil {
86+
return err
87+
}
88+
89+
if ownershipOld.UserID != userId {
90+
return errors.New("削除する権限がありません")
91+
}
92+
93+
err = db.Transaction(func(tx *gorm.DB) error {
94+
if err := tx.Where("ownership_id = ?", ownershipId).Delete(&Transaction{}).Error; err != nil {
95+
return err
96+
}
97+
if err := tx.Delete(&Ownership{}, ownershipId).Error; err != nil {
98+
return err
99+
}
100+
return nil
101+
})
102+
if err != nil {
103+
return err
104+
}
105+
106+
return nil
107+
}
108+
109+
func GetOwnership(ownershipId int) (*Ownership, error) {
110+
var o Ownership
111+
if err := db.Preload("Transaction").First(&o, ownershipId).Error; err != nil {
112+
return nil, err
113+
}
114+
return &o, nil
115+
}

model/ownership_test.go

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package model
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func TestOwnershipTableName(t *testing.T) {
10+
t.Parallel()
11+
assert.Equal(t, "ownerships", (&Ownership{}).TableName())
12+
}
13+
14+
func TestGetOwnership(t *testing.T) {
15+
PrepareTestDatabase()
16+
17+
t.Run("failure", func(t *testing.T) {
18+
t.Parallel()
19+
assert := assert.New(t)
20+
21+
res, err := GetOwnership(-1)
22+
assert.Error(err)
23+
assert.Empty(res)
24+
})
25+
26+
t.Run("success", func(t *testing.T) {
27+
t.Parallel()
28+
assert := assert.New(t)
29+
30+
res, err := GetOwnership(1)
31+
assert.NoError(err)
32+
assert.NotEmpty(res)
33+
assert.Equal(res.UserID, "s9")
34+
assert.Equal(res.ItemID, 1)
35+
assert.Equal(res.Rentalable, true)
36+
assert.Equal(res.Memo, "memo1")
37+
assert.Equal(4, len(res.Transaction))
38+
})
39+
}
40+
41+
func TestCreateOwnership(t *testing.T) {
42+
PrepareTestDatabase()
43+
44+
t.Run("success", func(t *testing.T) {
45+
assert := assert.New(t)
46+
47+
payload := OwnershipPayload{
48+
ItemID: 1,
49+
UserID: "new_user",
50+
Rentalable: true,
51+
Memo: "created by test",
52+
}
53+
created, err := CreateOwnership(payload)
54+
assert.NoError(err)
55+
assert.NotZero(created.ID)
56+
assert.Equal(payload.ItemID, created.ItemID)
57+
assert.Equal(payload.UserID, created.UserID)
58+
assert.Equal(payload.Rentalable, created.Rentalable)
59+
assert.Equal(payload.Memo, created.Memo)
60+
61+
fetched, err := GetOwnership(created.ID)
62+
assert.NoError(err)
63+
assert.Equal(created.ID, fetched.ID)
64+
assert.Equal(created.UserID, fetched.UserID)
65+
})
66+
}
67+
68+
func TestUpdateOwnership(t *testing.T) {
69+
PrepareTestDatabase()
70+
71+
t.Run("failure: not found", func(t *testing.T) {
72+
assert := assert.New(t)
73+
_, err := UpdateOwnership(-1, OwnershipPayload{})
74+
assert.Error(err)
75+
})
76+
77+
t.Run("failure: unauthorized", func(t *testing.T) {
78+
assert := assert.New(t)
79+
_, err := UpdateOwnership(1, OwnershipPayload{
80+
ItemID: 1,
81+
UserID: "different_user",
82+
Rentalable: false,
83+
Memo: "new_memo",
84+
})
85+
assert.Error(err)
86+
})
87+
88+
t.Run("success", func(t *testing.T) {
89+
assert := assert.New(t)
90+
updated, err := UpdateOwnership(1, OwnershipPayload{
91+
ItemID: 1,
92+
UserID: "s9",
93+
Rentalable: false,
94+
Memo: "updated",
95+
})
96+
assert.NoError(err)
97+
assert.Equal("s9", updated.UserID)
98+
assert.Equal(false, updated.Rentalable)
99+
assert.Equal("updated", updated.Memo)
100+
101+
fetched, err := GetOwnership(1)
102+
assert.NoError(err)
103+
assert.Equal("updated", fetched.Memo)
104+
assert.Equal(false, fetched.Rentalable)
105+
})
106+
}
107+
108+
func TestDeleteOwnership(t *testing.T) {
109+
PrepareTestDatabase()
110+
111+
t.Run("failure: not found", func(t *testing.T) {
112+
assert := assert.New(t)
113+
err := DeleteOwnership(-1, "someone")
114+
assert.Error(err)
115+
})
116+
117+
t.Run("failure: unauthorized", func(t *testing.T) {
118+
assert := assert.New(t)
119+
err := DeleteOwnership(1, "different_user")
120+
assert.Error(err)
121+
})
122+
123+
t.Run("success", func(t *testing.T) {
124+
assert := assert.New(t)
125+
err := DeleteOwnership(1, "s9")
126+
assert.NoError(err)
127+
128+
res, err := GetOwnership(1)
129+
assert.Error(err)
130+
assert.Empty(res)
131+
})
132+
}

router/owners.go

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,75 @@ package router
22

33
import (
44
"net/http"
5+
"strconv"
56

67
"github.com/labstack/echo/v4"
8+
"github.com/traPtitech/booQ-v3/model"
79
)
810

911
// PostOwners POST /items/:id/owners
1012
func PostOwners(c echo.Context) error {
11-
return echo.NewHTTPError(http.StatusNotImplemented, "Not Implemented")
13+
itemId, err := strconv.Atoi(c.Param("id"))
14+
if err != nil {
15+
return invalidRequest(c, err)
16+
}
17+
18+
owner := model.OwnershipPayload{}
19+
if err := c.Bind(&owner); err != nil {
20+
return invalidRequest(c, err)
21+
}
22+
owner.ItemID = itemId
23+
24+
res, err := model.CreateOwnership(owner)
25+
if err != nil {
26+
return internalServerError(c, err)
27+
}
28+
29+
return c.JSON(http.StatusOK, res)
1230
}
1331

1432
// PatchOwners PUT /items/:id/owners/:ownershipid
1533
func PatchOwners(c echo.Context) error {
16-
return echo.NewHTTPError(http.StatusNotImplemented, "Not Implemented")
34+
itemId, err := strconv.Atoi(c.Param("id"))
35+
if err != nil {
36+
return invalidRequest(c, err)
37+
}
38+
39+
ownershipId, err := strconv.Atoi(c.Param("ownershipid"))
40+
if err != nil {
41+
return invalidRequest(c, err)
42+
}
43+
44+
owner := model.OwnershipPayload{}
45+
if err := c.Bind(&owner); err != nil {
46+
return invalidRequest(c, err)
47+
}
48+
owner.ItemID = itemId
49+
50+
res, err := model.UpdateOwnership(ownershipId, owner)
51+
if err != nil {
52+
return internalServerError(c, err)
53+
}
54+
55+
return c.JSON(http.StatusOK, res)
1756
}
1857

1958
// DeleteOwners PUT /items/:id/owners/:ownershipid
2059
func DeleteOwners(c echo.Context) error {
21-
return echo.NewHTTPError(http.StatusNotImplemented, "Not Implemented")
60+
ownershipId, err := strconv.Atoi(c.Param("ownershipid"))
61+
if err != nil {
62+
return invalidRequest(c, err)
63+
}
64+
65+
me, err := getAuthorizedUser(c)
66+
if err != nil {
67+
return unauthorizedRequest(c, err)
68+
}
69+
70+
err = model.DeleteOwnership(ownershipId, me)
71+
if err != nil {
72+
return internalServerError(c, err)
73+
}
74+
75+
return c.NoContent(http.StatusNoContent)
2276
}

0 commit comments

Comments
 (0)