diff --git a/internal/collections/domain.go b/internal/collections/domain.go
index 5e3792245..315172987 100644
--- a/internal/collections/domain.go
+++ b/internal/collections/domain.go
@@ -71,20 +71,33 @@ type Repo interface { //nolint:interfacebloat
at time.Time,
) (collection.UserSubjectEpisodesCollection, error)
- GetPersonCollect(
+ GetPersonCollection(
ctx context.Context, userID model.UserID,
cat collection.PersonCollectCategory, targetID model.PersonID,
) (collection.UserPersonCollection, error)
- AddPersonCollect(
+ AddPersonCollection(
ctx context.Context, userID model.UserID,
cat collection.PersonCollectCategory, targetID model.PersonID,
) error
- RemovePersonCollect(
+ RemovePersonCollection(
ctx context.Context, userID model.UserID,
cat collection.PersonCollectCategory, targetID model.PersonID,
) error
+
+ CountPersonCollections(
+ ctx context.Context,
+ userID model.UserID,
+ cat collection.PersonCollectCategory,
+ ) (int64, error)
+
+ ListPersonCollection(
+ ctx context.Context,
+ userID model.UserID,
+ cat collection.PersonCollectCategory,
+ limit, offset int,
+ ) ([]collection.UserPersonCollection, error)
}
type Update struct {
diff --git a/internal/collections/infra/mysql_repo.go b/internal/collections/infra/mysql_repo.go
index 7ffb3b291..d00846704 100644
--- a/internal/collections/infra/mysql_repo.go
+++ b/internal/collections/infra/mysql_repo.go
@@ -461,7 +461,7 @@ func (r mysqlRepo) updateCollectionTime(obj *dao.SubjectCollection,
return nil
}
-func (r mysqlRepo) GetPersonCollect(
+func (r mysqlRepo) GetPersonCollection(
ctx context.Context, userID model.UserID,
cat collection.PersonCollectCategory, targetID model.PersonID,
) (collection.UserPersonCollection, error) {
@@ -484,7 +484,7 @@ func (r mysqlRepo) GetPersonCollect(
}, nil
}
-func (r mysqlRepo) AddPersonCollect(
+func (r mysqlRepo) AddPersonCollection(
ctx context.Context, userID model.UserID,
cat collection.PersonCollectCategory, targetID model.PersonID,
) error {
@@ -503,7 +503,7 @@ func (r mysqlRepo) AddPersonCollect(
return nil
}
-func (r mysqlRepo) RemovePersonCollect(
+func (r mysqlRepo) RemovePersonCollection(
ctx context.Context, userID model.UserID,
cat collection.PersonCollectCategory, targetID model.PersonID,
) error {
@@ -518,6 +518,52 @@ func (r mysqlRepo) RemovePersonCollect(
return nil
}
+func (r mysqlRepo) CountPersonCollections(
+ ctx context.Context,
+ userID model.UserID,
+ cat collection.PersonCollectCategory,
+) (int64, error) {
+ q := r.q.PersonCollect.WithContext(ctx).
+ Where(r.q.PersonCollect.UserID.Eq(userID), r.q.PersonCollect.Category.Eq(string(cat)))
+
+ c, err := q.Count()
+ if err != nil {
+ return 0, errgo.Wrap(err, "dal")
+ }
+
+ return c, nil
+}
+
+func (r mysqlRepo) ListPersonCollection(
+ ctx context.Context,
+ userID model.UserID,
+ cat collection.PersonCollectCategory,
+ limit, offset int,
+) ([]collection.UserPersonCollection, error) {
+ q := r.q.PersonCollect.WithContext(ctx).
+ Order(r.q.PersonCollect.CreatedTime.Desc()).
+ Where(r.q.PersonCollect.UserID.Eq(userID), r.q.PersonCollect.Category.Eq(string(cat))).Limit(limit).Offset(offset)
+
+ collections, err := q.Find()
+ if err != nil {
+ r.log.Error("unexpected error happened", zap.Error(err))
+ return nil, errgo.Wrap(err, "dal")
+ }
+
+ var results = make([]collection.UserPersonCollection, len(collections))
+ for i, c := range collections {
+ results[i] = collection.UserPersonCollection{
+ ID: c.ID,
+ Category: c.Category,
+ TargetID: c.TargetID,
+ UserID: c.UserID,
+ CreatedAt: time.Unix(int64(c.CreatedTime), 0),
+ }
+ }
+
+ return results, nil
+}
+
func (r mysqlRepo) UpdateEpisodeCollection(
ctx context.Context,
userID model.UserID,
diff --git a/internal/collections/infra/mysql_repo_test.go b/internal/collections/infra/mysql_repo_test.go
index 4fbd53d5b..df4b89bd8 100644
--- a/internal/collections/infra/mysql_repo_test.go
+++ b/internal/collections/infra/mysql_repo_test.go
@@ -533,7 +533,7 @@ func TestMysqlRepo_GetPersonCollect(t *testing.T) {
})
require.NoError(t, err)
- r, err := repo.GetPersonCollect(context.Background(), uid, cat, mid)
+ r, err := repo.GetPersonCollection(context.Background(), uid, cat, mid)
require.NoError(t, err)
require.Equal(t, uid, r.UserID)
require.Equal(t, mid, r.TargetID)
@@ -555,7 +555,7 @@ func TestMysqlRepo_AddPersonCollect(t *testing.T) {
require.NoError(t, err)
})
- err := repo.AddPersonCollect(context.Background(), uid, cat, mid)
+ err := repo.AddPersonCollection(context.Background(), uid, cat, mid)
require.NoError(t, err)
r, err := table.WithContext(context.TODO()).Where(table.UserID.Eq(uid)).Take()
@@ -590,9 +590,93 @@ func TestMysqlRepo_RemovePersonCollect(t *testing.T) {
require.NoError(t, err)
require.NotZero(t, r.ID)
- err = repo.RemovePersonCollect(context.Background(), uid, cat, mid)
+ err = repo.RemovePersonCollection(context.Background(), uid, cat, mid)
require.NoError(t, err)
_, err = table.WithContext(context.TODO()).Where(table.UserID.Eq(uid)).Take()
require.ErrorIs(t, err, gorm.ErrRecordNotFound)
}
+
+func TestMysqlRepo_CountPersonCollections(t *testing.T) {
+ t.Parallel()
+ test.RequireEnv(t, test.EnvMysql)
+
+ const uid model.UserID = 41000
+ const cat = "prsn"
+
+ repo, q := getRepo(t)
+ test.RunAndCleanup(t, func() {
+ _, err := q.PersonCollect.
+ WithContext(context.Background()).
+ Where(q.PersonCollect.UserID.Eq(uid)).
+ Delete()
+ require.NoError(t, err)
+ })
+
+ for i := 0; i < 5; i++ {
+ err := q.PersonCollect.
+ WithContext(context.Background()).
+ Create(&dao.PersonCollect{
+ UserID: uid,
+ TargetID: model.PersonID(i + 100),
+ Category: cat,
+ CreatedTime: uint32(time.Now().Unix()),
+ })
+ require.NoError(t, err)
+ }
+
+ count, err := repo.CountPersonCollections(context.Background(), uid, cat)
+ require.NoError(t, err)
+ require.EqualValues(t, 5, count)
+}
+
+func TestMysqlRepo_ListPersonCollection(t *testing.T) {
+ t.Parallel()
+ test.RequireEnv(t, test.EnvMysql)
+
+ const uid model.UserID = 42000
+ const cat = "prsn"
+
+ repo, q := getRepo(t)
+
+ var err error
+ test.RunAndCleanup(t, func() {
+ _, err = q.PersonCollect.
+ WithContext(context.Background()).
+ Where(q.PersonCollect.UserID.Eq(uid)).
+ Delete()
+ require.NoError(t, err)
+ })
+
+ data, err := repo.ListPersonCollection(context.Background(), uid, collection.PersonCollectCategory(cat), 5, 0)
+ require.NoError(t, err)
+ require.Len(t, data, 0)
+
+ for i := 0; i < 5; i++ {
+ err = q.PersonCollect.
+ WithContext(context.Background()).
+ Create(&dao.PersonCollect{
+ UserID: uid,
+ TargetID: model.PersonID(i + 100),
+ Category: cat,
+ CreatedTime: uint32(time.Now().Unix()),
+ })
+ require.NoError(t, err)
+ }
+
+ for i := 0; i < 2; i++ {
+ err = q.PersonCollect.
+ WithContext(context.Background()).
+ Create(&dao.PersonCollect{
+ UserID: uid,
+ TargetID: model.PersonID(i + 200),
+ Category: cat,
+ CreatedTime: uint32(time.Now().Unix()),
+ })
+ require.NoError(t, err)
+ }
+
+ data, err = repo.ListPersonCollection(context.Background(), uid, collection.PersonCollectCategory(cat), 5, 0)
+ require.NoError(t, err)
+ require.Len(t, data, 5)
+}
diff --git a/internal/mocks/CollectionRepo.go b/internal/mocks/CollectionRepo.go
index bad2d3fc4..3fbafd138 100644
--- a/internal/mocks/CollectionRepo.go
+++ b/internal/mocks/CollectionRepo.go
@@ -30,12 +30,12 @@ func (_m *CollectionRepo) EXPECT() *CollectionRepo_Expecter {
return &CollectionRepo_Expecter{mock: &_m.Mock}
}
-// AddPersonCollect provides a mock function with given fields: ctx, userID, cat, targetID
-func (_m *CollectionRepo) AddPersonCollect(ctx context.Context, userID uint32, cat collection.PersonCollectCategory, targetID uint32) error {
+// AddPersonCollection provides a mock function with given fields: ctx, userID, cat, targetID
+func (_m *CollectionRepo) AddPersonCollection(ctx context.Context, userID uint32, cat collection.PersonCollectCategory, targetID uint32) error {
ret := _m.Called(ctx, userID, cat, targetID)
if len(ret) == 0 {
- panic("no return value specified for AddPersonCollect")
+ panic("no return value specified for AddPersonCollection")
}
var r0 error
@@ -48,33 +48,91 @@ func (_m *CollectionRepo) AddPersonCollect(ctx context.Context, userID uint32, c
return r0
}
-// CollectionRepo_AddPersonCollect_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddPersonCollect'
-type CollectionRepo_AddPersonCollect_Call struct {
+// CollectionRepo_AddPersonCollection_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddPersonCollection'
+type CollectionRepo_AddPersonCollection_Call struct {
*mock.Call
}
-// AddPersonCollect is a helper method to define mock.On call
+// AddPersonCollection is a helper method to define mock.On call
// - ctx context.Context
// - userID uint32
// - cat collection.PersonCollectCategory
// - targetID uint32
-func (_e *CollectionRepo_Expecter) AddPersonCollect(ctx interface{}, userID interface{}, cat interface{}, targetID interface{}) *CollectionRepo_AddPersonCollect_Call {
- return &CollectionRepo_AddPersonCollect_Call{Call: _e.mock.On("AddPersonCollect", ctx, userID, cat, targetID)}
+func (_e *CollectionRepo_Expecter) AddPersonCollection(ctx interface{}, userID interface{}, cat interface{}, targetID interface{}) *CollectionRepo_AddPersonCollection_Call {
+ return &CollectionRepo_AddPersonCollection_Call{Call: _e.mock.On("AddPersonCollection", ctx, userID, cat, targetID)}
}
-func (_c *CollectionRepo_AddPersonCollect_Call) Run(run func(ctx context.Context, userID uint32, cat collection.PersonCollectCategory, targetID uint32)) *CollectionRepo_AddPersonCollect_Call {
+func (_c *CollectionRepo_AddPersonCollection_Call) Run(run func(ctx context.Context, userID uint32, cat collection.PersonCollectCategory, targetID uint32)) *CollectionRepo_AddPersonCollection_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(uint32), args[2].(collection.PersonCollectCategory), args[3].(uint32))
})
return _c
}
-func (_c *CollectionRepo_AddPersonCollect_Call) Return(_a0 error) *CollectionRepo_AddPersonCollect_Call {
+func (_c *CollectionRepo_AddPersonCollection_Call) Return(_a0 error) *CollectionRepo_AddPersonCollection_Call {
_c.Call.Return(_a0)
return _c
}
-func (_c *CollectionRepo_AddPersonCollect_Call) RunAndReturn(run func(context.Context, uint32, collection.PersonCollectCategory, uint32) error) *CollectionRepo_AddPersonCollect_Call {
+func (_c *CollectionRepo_AddPersonCollection_Call) RunAndReturn(run func(context.Context, uint32, collection.PersonCollectCategory, uint32) error) *CollectionRepo_AddPersonCollection_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// CountPersonCollections provides a mock function with given fields: ctx, userID, cat
+func (_m *CollectionRepo) CountPersonCollections(ctx context.Context, userID uint32, cat collection.PersonCollectCategory) (int64, error) {
+ ret := _m.Called(ctx, userID, cat)
+
+ if len(ret) == 0 {
+ panic("no return value specified for CountPersonCollections")
+ }
+
+ var r0 int64
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, uint32, collection.PersonCollectCategory) (int64, error)); ok {
+ return rf(ctx, userID, cat)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, uint32, collection.PersonCollectCategory) int64); ok {
+ r0 = rf(ctx, userID, cat)
+ } else {
+ r0 = ret.Get(0).(int64)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, uint32, collection.PersonCollectCategory) error); ok {
+ r1 = rf(ctx, userID, cat)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CollectionRepo_CountPersonCollections_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CountPersonCollections'
+type CollectionRepo_CountPersonCollections_Call struct {
+ *mock.Call
+}
+
+// CountPersonCollections is a helper method to define mock.On call
+// - ctx context.Context
+// - userID uint32
+// - cat collection.PersonCollectCategory
+func (_e *CollectionRepo_Expecter) CountPersonCollections(ctx interface{}, userID interface{}, cat interface{}) *CollectionRepo_CountPersonCollections_Call {
+ return &CollectionRepo_CountPersonCollections_Call{Call: _e.mock.On("CountPersonCollections", ctx, userID, cat)}
+}
+
+func (_c *CollectionRepo_CountPersonCollections_Call) Run(run func(ctx context.Context, userID uint32, cat collection.PersonCollectCategory)) *CollectionRepo_CountPersonCollections_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].(uint32), args[2].(collection.PersonCollectCategory))
+ })
+ return _c
+}
+
+func (_c *CollectionRepo_CountPersonCollections_Call) Return(_a0 int64, _a1 error) *CollectionRepo_CountPersonCollections_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CollectionRepo_CountPersonCollections_Call) RunAndReturn(run func(context.Context, uint32, collection.PersonCollectCategory) (int64, error)) *CollectionRepo_CountPersonCollections_Call {
_c.Call.Return(run)
return _c
}
@@ -139,12 +197,12 @@ func (_c *CollectionRepo_CountSubjectCollections_Call) RunAndReturn(run func(con
return _c
}
-// GetPersonCollect provides a mock function with given fields: ctx, userID, cat, targetID
-func (_m *CollectionRepo) GetPersonCollect(ctx context.Context, userID uint32, cat collection.PersonCollectCategory, targetID uint32) (collection.UserPersonCollection, error) {
+// GetPersonCollection provides a mock function with given fields: ctx, userID, cat, targetID
+func (_m *CollectionRepo) GetPersonCollection(ctx context.Context, userID uint32, cat collection.PersonCollectCategory, targetID uint32) (collection.UserPersonCollection, error) {
ret := _m.Called(ctx, userID, cat, targetID)
if len(ret) == 0 {
- panic("no return value specified for GetPersonCollect")
+ panic("no return value specified for GetPersonCollection")
}
var r0 collection.UserPersonCollection
@@ -167,33 +225,33 @@ func (_m *CollectionRepo) GetPersonCollect(ctx context.Context, userID uint32, c
return r0, r1
}
-// CollectionRepo_GetPersonCollect_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPersonCollect'
-type CollectionRepo_GetPersonCollect_Call struct {
+// CollectionRepo_GetPersonCollection_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPersonCollection'
+type CollectionRepo_GetPersonCollection_Call struct {
*mock.Call
}
-// GetPersonCollect is a helper method to define mock.On call
+// GetPersonCollection is a helper method to define mock.On call
// - ctx context.Context
// - userID uint32
// - cat collection.PersonCollectCategory
// - targetID uint32
-func (_e *CollectionRepo_Expecter) GetPersonCollect(ctx interface{}, userID interface{}, cat interface{}, targetID interface{}) *CollectionRepo_GetPersonCollect_Call {
- return &CollectionRepo_GetPersonCollect_Call{Call: _e.mock.On("GetPersonCollect", ctx, userID, cat, targetID)}
+func (_e *CollectionRepo_Expecter) GetPersonCollection(ctx interface{}, userID interface{}, cat interface{}, targetID interface{}) *CollectionRepo_GetPersonCollection_Call {
+ return &CollectionRepo_GetPersonCollection_Call{Call: _e.mock.On("GetPersonCollection", ctx, userID, cat, targetID)}
}
-func (_c *CollectionRepo_GetPersonCollect_Call) Run(run func(ctx context.Context, userID uint32, cat collection.PersonCollectCategory, targetID uint32)) *CollectionRepo_GetPersonCollect_Call {
+func (_c *CollectionRepo_GetPersonCollection_Call) Run(run func(ctx context.Context, userID uint32, cat collection.PersonCollectCategory, targetID uint32)) *CollectionRepo_GetPersonCollection_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(uint32), args[2].(collection.PersonCollectCategory), args[3].(uint32))
})
return _c
}
-func (_c *CollectionRepo_GetPersonCollect_Call) Return(_a0 collection.UserPersonCollection, _a1 error) *CollectionRepo_GetPersonCollect_Call {
+func (_c *CollectionRepo_GetPersonCollection_Call) Return(_a0 collection.UserPersonCollection, _a1 error) *CollectionRepo_GetPersonCollection_Call {
_c.Call.Return(_a0, _a1)
return _c
}
-func (_c *CollectionRepo_GetPersonCollect_Call) RunAndReturn(run func(context.Context, uint32, collection.PersonCollectCategory, uint32) (collection.UserPersonCollection, error)) *CollectionRepo_GetPersonCollect_Call {
+func (_c *CollectionRepo_GetPersonCollection_Call) RunAndReturn(run func(context.Context, uint32, collection.PersonCollectCategory, uint32) (collection.UserPersonCollection, error)) *CollectionRepo_GetPersonCollection_Call {
_c.Call.Return(run)
return _c
}
@@ -316,6 +374,68 @@ func (_c *CollectionRepo_GetSubjectEpisodesCollection_Call) RunAndReturn(run fun
return _c
}
+// ListPersonCollection provides a mock function with given fields: ctx, userID, cat, limit, offset
+func (_m *CollectionRepo) ListPersonCollection(ctx context.Context, userID uint32, cat collection.PersonCollectCategory, limit int, offset int) ([]collection.UserPersonCollection, error) {
+ ret := _m.Called(ctx, userID, cat, limit, offset)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ListPersonCollection")
+ }
+
+ var r0 []collection.UserPersonCollection
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, uint32, collection.PersonCollectCategory, int, int) ([]collection.UserPersonCollection, error)); ok {
+ return rf(ctx, userID, cat, limit, offset)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, uint32, collection.PersonCollectCategory, int, int) []collection.UserPersonCollection); ok {
+ r0 = rf(ctx, userID, cat, limit, offset)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]collection.UserPersonCollection)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, uint32, collection.PersonCollectCategory, int, int) error); ok {
+ r1 = rf(ctx, userID, cat, limit, offset)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CollectionRepo_ListPersonCollection_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListPersonCollection'
+type CollectionRepo_ListPersonCollection_Call struct {
+ *mock.Call
+}
+
+// ListPersonCollection is a helper method to define mock.On call
+// - ctx context.Context
+// - userID uint32
+// - cat collection.PersonCollectCategory
+// - limit int
+// - offset int
+func (_e *CollectionRepo_Expecter) ListPersonCollection(ctx interface{}, userID interface{}, cat interface{}, limit interface{}, offset interface{}) *CollectionRepo_ListPersonCollection_Call {
+ return &CollectionRepo_ListPersonCollection_Call{Call: _e.mock.On("ListPersonCollection", ctx, userID, cat, limit, offset)}
+}
+
+func (_c *CollectionRepo_ListPersonCollection_Call) Run(run func(ctx context.Context, userID uint32, cat collection.PersonCollectCategory, limit int, offset int)) *CollectionRepo_ListPersonCollection_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].(uint32), args[2].(collection.PersonCollectCategory), args[3].(int), args[4].(int))
+ })
+ return _c
+}
+
+func (_c *CollectionRepo_ListPersonCollection_Call) Return(_a0 []collection.UserPersonCollection, _a1 error) *CollectionRepo_ListPersonCollection_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CollectionRepo_ListPersonCollection_Call) RunAndReturn(run func(context.Context, uint32, collection.PersonCollectCategory, int, int) ([]collection.UserPersonCollection, error)) *CollectionRepo_ListPersonCollection_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
// ListSubjectCollection provides a mock function with given fields: ctx, userID, subjectType, collectionType, showPrivate, limit, offset
func (_m *CollectionRepo) ListSubjectCollection(ctx context.Context, userID uint32, subjectType uint8, collectionType collection.SubjectCollection, showPrivate bool, limit int, offset int) ([]collection.UserSubjectCollection, error) {
ret := _m.Called(ctx, userID, subjectType, collectionType, showPrivate, limit, offset)
@@ -380,12 +500,12 @@ func (_c *CollectionRepo_ListSubjectCollection_Call) RunAndReturn(run func(conte
return _c
}
-// RemovePersonCollect provides a mock function with given fields: ctx, userID, cat, targetID
-func (_m *CollectionRepo) RemovePersonCollect(ctx context.Context, userID uint32, cat collection.PersonCollectCategory, targetID uint32) error {
+// RemovePersonCollection provides a mock function with given fields: ctx, userID, cat, targetID
+func (_m *CollectionRepo) RemovePersonCollection(ctx context.Context, userID uint32, cat collection.PersonCollectCategory, targetID uint32) error {
ret := _m.Called(ctx, userID, cat, targetID)
if len(ret) == 0 {
- panic("no return value specified for RemovePersonCollect")
+ panic("no return value specified for RemovePersonCollection")
}
var r0 error
@@ -398,33 +518,33 @@ func (_m *CollectionRepo) RemovePersonCollect(ctx context.Context, userID uint32
return r0
}
-// CollectionRepo_RemovePersonCollect_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemovePersonCollect'
-type CollectionRepo_RemovePersonCollect_Call struct {
+// CollectionRepo_RemovePersonCollection_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemovePersonCollection'
+type CollectionRepo_RemovePersonCollection_Call struct {
*mock.Call
}
-// RemovePersonCollect is a helper method to define mock.On call
+// RemovePersonCollection is a helper method to define mock.On call
// - ctx context.Context
// - userID uint32
// - cat collection.PersonCollectCategory
// - targetID uint32
-func (_e *CollectionRepo_Expecter) RemovePersonCollect(ctx interface{}, userID interface{}, cat interface{}, targetID interface{}) *CollectionRepo_RemovePersonCollect_Call {
- return &CollectionRepo_RemovePersonCollect_Call{Call: _e.mock.On("RemovePersonCollect", ctx, userID, cat, targetID)}
+func (_e *CollectionRepo_Expecter) RemovePersonCollection(ctx interface{}, userID interface{}, cat interface{}, targetID interface{}) *CollectionRepo_RemovePersonCollection_Call {
+ return &CollectionRepo_RemovePersonCollection_Call{Call: _e.mock.On("RemovePersonCollection", ctx, userID, cat, targetID)}
}
-func (_c *CollectionRepo_RemovePersonCollect_Call) Run(run func(ctx context.Context, userID uint32, cat collection.PersonCollectCategory, targetID uint32)) *CollectionRepo_RemovePersonCollect_Call {
+func (_c *CollectionRepo_RemovePersonCollection_Call) Run(run func(ctx context.Context, userID uint32, cat collection.PersonCollectCategory, targetID uint32)) *CollectionRepo_RemovePersonCollection_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(uint32), args[2].(collection.PersonCollectCategory), args[3].(uint32))
})
return _c
}
-func (_c *CollectionRepo_RemovePersonCollect_Call) Return(_a0 error) *CollectionRepo_RemovePersonCollect_Call {
+func (_c *CollectionRepo_RemovePersonCollection_Call) Return(_a0 error) *CollectionRepo_RemovePersonCollection_Call {
_c.Call.Return(_a0)
return _c
}
-func (_c *CollectionRepo_RemovePersonCollect_Call) RunAndReturn(run func(context.Context, uint32, collection.PersonCollectCategory, uint32) error) *CollectionRepo_RemovePersonCollect_Call {
+func (_c *CollectionRepo_RemovePersonCollection_Call) RunAndReturn(run func(context.Context, uint32, collection.PersonCollectCategory, uint32) error) *CollectionRepo_RemovePersonCollection_Call {
_c.Call.Return(run)
return _c
}
diff --git a/web/handler/character/collect.go b/web/handler/character/collect.go
index fefab8933..f8d6c60b6 100644
--- a/web/handler/character/collect.go
+++ b/web/handler/character/collect.go
@@ -54,13 +54,13 @@ func (h Character) collectCharacter(c echo.Context, cid uint32, uid uint32) erro
return res.InternalError(c, err, "get character error")
}
// check if the user has collected the character
- if _, err := h.collect.GetPersonCollect(ctx, uid, collection.PersonCollectCategoryCharacter, cid); err == nil {
+ if _, err := h.collect.GetPersonCollection(ctx, uid, collection.PersonCollectCategoryCharacter, cid); err == nil {
return nil // already collected
} else if !errors.Is(err, gerr.ErrNotFound) {
return res.InternalError(c, err, "get character collect error")
}
// add the collect
- if err := h.collect.AddPersonCollect(ctx, uid, collection.PersonCollectCategoryCharacter, cid); err != nil {
+ if err := h.collect.AddPersonCollection(ctx, uid, collection.PersonCollectCategoryCharacter, cid); err != nil {
return res.InternalError(c, err, "add character collect failed")
}
return nil
@@ -76,14 +76,14 @@ func (h Character) uncollectCharacter(c echo.Context, cid uint32, uid uint32) er
return res.InternalError(c, err, "get character error")
}
// check if the user has collected the character
- if _, err := h.collect.GetPersonCollect(ctx, uid, collection.PersonCollectCategoryCharacter, cid); err != nil {
+ if _, err := h.collect.GetPersonCollection(ctx, uid, collection.PersonCollectCategoryCharacter, cid); err != nil {
if errors.Is(err, gerr.ErrNotFound) {
return res.NotFound("character not collected")
}
return res.InternalError(c, err, "get character collect error")
}
// remove the collect
- if err := h.collect.RemovePersonCollect(ctx, uid, collection.PersonCollectCategoryCharacter, cid); err != nil {
+ if err := h.collect.RemovePersonCollection(ctx, uid, collection.PersonCollectCategoryCharacter, cid); err != nil {
return res.InternalError(c, err, "remove character collect failed")
}
return nil
diff --git a/web/handler/person/collect.go b/web/handler/person/collect.go
index e3c6d0c17..d1ec9fa62 100644
--- a/web/handler/person/collect.go
+++ b/web/handler/person/collect.go
@@ -56,13 +56,13 @@ func (h Person) collectPerson(c echo.Context, pid uint32, uid uint32) error {
return res.InternalError(c, err, "get person error")
}
// check if the user has collected the person
- if _, err := h.collect.GetPersonCollect(ctx, uid, collection.PersonCollectCategoryPerson, pid); err == nil {
+ if _, err := h.collect.GetPersonCollection(ctx, uid, collection.PersonCollectCategoryPerson, pid); err == nil {
return nil // already collected
} else if !errors.Is(err, gerr.ErrNotFound) {
return res.InternalError(c, err, "get person collect error")
}
// add the collect
- if err := h.collect.AddPersonCollect(ctx, uid, collection.PersonCollectCategoryPerson, pid); err != nil {
+ if err := h.collect.AddPersonCollection(ctx, uid, collection.PersonCollectCategoryPerson, pid); err != nil {
return res.InternalError(c, err, "add person collect failed")
}
return nil
@@ -78,14 +78,14 @@ func (h Person) uncollectPerson(c echo.Context, pid uint32, uid uint32) error {
return res.InternalError(c, err, "get person error")
}
// check if the user has collected the person
- if _, err := h.collect.GetPersonCollect(ctx, uid, collection.PersonCollectCategoryPerson, pid); err != nil {
+ if _, err := h.collect.GetPersonCollection(ctx, uid, collection.PersonCollectCategoryPerson, pid); err != nil {
if errors.Is(err, gerr.ErrNotFound) {
return res.NotFound("person not collected")
}
return res.InternalError(c, err, "get person collect error")
}
// remove the collect
- if err := h.collect.RemovePersonCollect(ctx, uid, collection.PersonCollectCategoryPerson, pid); err != nil {
+ if err := h.collect.RemovePersonCollection(ctx, uid, collection.PersonCollectCategoryPerson, pid); err != nil {
return res.InternalError(c, err, "remove person collect failed")
}
return nil
diff --git a/web/handler/user/get_character_collection.go b/web/handler/user/get_character_collection.go
new file mode 100644
index 000000000..42657e601
--- /dev/null
+++ b/web/handler/user/get_character_collection.go
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: AGPL-3.0-only
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, version 3.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+// See the GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see
+
+package user
+
+import (
+ "errors"
+ "net/http"
+
+ "github.com/labstack/echo/v4"
+ "github.com/trim21/errgo"
+
+ "github.com/bangumi/server/domain/gerr"
+ "github.com/bangumi/server/internal/collections/domain/collection"
+ "github.com/bangumi/server/internal/model"
+ "github.com/bangumi/server/web/req"
+ "github.com/bangumi/server/web/res"
+)
+
+func (h User) GetCharacterCollection(c echo.Context) error {
+ username := c.Param("username")
+ if username == "" {
+ return res.BadRequest("missing require parameters `username`")
+ }
+
+ characterID, err := req.ParseID(c.Param("character_id"))
+ if err != nil {
+ return err
+ }
+
+ return h.getCharacterCollection(c, username, characterID)
+}
+
+func (h User) getCharacterCollection(c echo.Context, username string, characterID model.CharacterID) error {
+ const notFoundMessage = "character is not collected by user"
+
+ character, err := h.character.Get(c.Request().Context(), characterID)
+ if err != nil {
+ if errors.Is(err, gerr.ErrNotFound) {
+ return res.ErrNotFound
+ }
+
+ return errgo.Wrap(err, "failed to get character")
+ }
+
+ u, err := h.user.GetByName(c.Request().Context(), username)
+ if err != nil {
+ if errors.Is(err, gerr.ErrNotFound) {
+ return res.NotFound("user doesn't exist or has been removed")
+ }
+
+ return errgo.Wrap(err, "failed to get user by name")
+ }
+
+ collect, err := h.collect.GetPersonCollection(
+ c.Request().Context(),
+ u.ID,
+ collection.PersonCollectCategoryCharacter,
+ characterID,
+ )
+ if err != nil {
+ if errors.Is(err, gerr.ErrNotFound) {
+ return res.NotFound(notFoundMessage)
+ }
+
+ return errgo.Wrap(err, "failed to get user's character collection")
+ }
+
+ return c.JSON(http.StatusOK, res.ConvertModelCharacterCollection(collect, character))
+}
diff --git a/web/handler/user/get_person_collection.go b/web/handler/user/get_person_collection.go
new file mode 100644
index 000000000..1240cb8a4
--- /dev/null
+++ b/web/handler/user/get_person_collection.go
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: AGPL-3.0-only
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, version 3.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+// See the GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see
+
+package user
+
+import (
+ "errors"
+ "net/http"
+
+ "github.com/labstack/echo/v4"
+ "github.com/trim21/errgo"
+
+ "github.com/bangumi/server/domain/gerr"
+ "github.com/bangumi/server/internal/collections/domain/collection"
+ "github.com/bangumi/server/internal/model"
+ "github.com/bangumi/server/web/req"
+ "github.com/bangumi/server/web/res"
+)
+
+func (h User) GetPersonCollection(c echo.Context) error {
+ username := c.Param("username")
+ if username == "" {
+ return res.BadRequest("missing require parameters `username`")
+ }
+
+ personID, err := req.ParseID(c.Param("person_id"))
+ if err != nil {
+ return err
+ }
+
+ return h.getPersonCollection(c, username, personID)
+}
+
+func (h User) getPersonCollection(c echo.Context, username string, personID model.PersonID) error {
+ const notFoundMessage = "person is not collected by user"
+
+ person, err := h.person.Get(c.Request().Context(), personID)
+ if err != nil {
+ if errors.Is(err, gerr.ErrNotFound) {
+ return res.ErrNotFound
+ }
+
+ return errgo.Wrap(err, "failed to get person")
+ }
+
+ u, err := h.user.GetByName(c.Request().Context(), username)
+ if err != nil {
+ if errors.Is(err, gerr.ErrNotFound) {
+ return res.NotFound("user doesn't exist or has been removed")
+ }
+
+ return errgo.Wrap(err, "failed to get user by name")
+ }
+
+ collect, err := h.collect.GetPersonCollection(
+ c.Request().Context(), u.ID, collection.PersonCollectCategoryPerson, personID)
+ if err != nil {
+ if errors.Is(err, gerr.ErrNotFound) {
+ return res.NotFound(notFoundMessage)
+ }
+
+ return errgo.Wrap(err, "failed to get person collect")
+ }
+
+ return c.JSON(http.StatusOK, res.ConvertModelPersonCollection(collect, person))
+}
diff --git a/web/handler/user/list_character_collections.go b/web/handler/user/list_character_collections.go
new file mode 100644
index 000000000..70fa7a534
--- /dev/null
+++ b/web/handler/user/list_character_collections.go
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: AGPL-3.0-only
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, version 3.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+// See the GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see
+
+package user
+
+import (
+ "errors"
+ "net/http"
+
+ "github.com/labstack/echo/v4"
+ "github.com/trim21/errgo"
+
+ "github.com/bangumi/server/domain/gerr"
+ "github.com/bangumi/server/internal/collections/domain/collection"
+ "github.com/bangumi/server/internal/model"
+ "github.com/bangumi/server/internal/pkg/generic/slice"
+ "github.com/bangumi/server/internal/user"
+ "github.com/bangumi/server/web/req"
+ "github.com/bangumi/server/web/res"
+)
+
+func (h User) ListCharacterCollection(c echo.Context) error {
+ page, err := req.GetPageQuery(c, req.DefaultPageLimit, req.DefaultMaxPageLimit)
+ if err != nil {
+ return err
+ }
+
+ username := c.Param("username")
+ if username == "" {
+ return res.BadRequest("missing require parameters `username`")
+ }
+
+ u, err := h.user.GetByName(c.Request().Context(), username)
+ if err != nil {
+ if errors.Is(err, gerr.ErrNotFound) {
+ return res.NotFound("user doesn't exist or has been removed")
+ }
+
+ return errgo.Wrap(err, "user.GetByName")
+ }
+
+ return h.listCharacterCollection(c, u, page)
+}
+
+func (h User) listCharacterCollection(c echo.Context, u user.User, page req.PageQuery) error {
+ count, err := h.collect.CountPersonCollections(c.Request().Context(), u.ID, collection.PersonCollectCategoryCharacter)
+ if err != nil {
+ return errgo.Wrap(err, "failed to count user's character collections")
+ }
+
+ if count == 0 {
+ if count == 0 {
+ return c.JSON(http.StatusOK, res.Paged{Data: []int{}, Total: count, Limit: page.Limit, Offset: page.Offset})
+ }
+ }
+
+ if err = page.Check(count); err != nil {
+ return err
+ }
+
+ cols, err := h.collect.ListPersonCollection(
+ c.Request().Context(),
+ u.ID, collection.PersonCollectCategoryCharacter,
+ page.Limit, page.Offset)
+ if err != nil {
+ return errgo.Wrap(err, "failed to list user's person collections")
+ }
+
+ characterIDs := slice.Map(cols, func(item collection.UserPersonCollection) model.PersonID {
+ return item.TargetID
+ })
+
+ characterMap, err := h.character.GetByIDs(c.Request().Context(), characterIDs)
+ if err != nil {
+ return errgo.Wrap(err, "failed to get persons")
+ }
+
+ var data = make([]res.PersonCollection, 0, len(cols))
+
+ for _, col := range cols {
+ character, ok := characterMap[col.TargetID]
+ if !ok {
+ continue
+ }
+ data = append(data, res.ConvertModelCharacterCollection(col, character))
+ }
+
+ return c.JSON(http.StatusOK, res.Paged{
+ Data: data,
+ Total: count,
+ Limit: page.Limit,
+ Offset: page.Offset,
+ })
+}
diff --git a/web/handler/user/list_person_collections.go b/web/handler/user/list_person_collections.go
new file mode 100644
index 000000000..9289fe07d
--- /dev/null
+++ b/web/handler/user/list_person_collections.go
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: AGPL-3.0-only
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, version 3.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+// See the GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see
+
+package user
+
+import (
+ "errors"
+ "net/http"
+
+ "github.com/labstack/echo/v4"
+ "github.com/trim21/errgo"
+
+ "github.com/bangumi/server/domain/gerr"
+ "github.com/bangumi/server/internal/collections/domain/collection"
+ "github.com/bangumi/server/internal/model"
+ "github.com/bangumi/server/internal/pkg/generic/slice"
+ "github.com/bangumi/server/internal/user"
+ "github.com/bangumi/server/web/req"
+ "github.com/bangumi/server/web/res"
+)
+
+func (h User) ListPersonCollection(c echo.Context) error {
+ page, err := req.GetPageQuery(c, req.DefaultPageLimit, req.DefaultMaxPageLimit)
+ if err != nil {
+ return err
+ }
+
+ username := c.Param("username")
+ if username == "" {
+ return res.BadRequest("missing require parameters `username`")
+ }
+
+ u, err := h.user.GetByName(c.Request().Context(), username)
+ if err != nil {
+ if errors.Is(err, gerr.ErrNotFound) {
+ return res.NotFound("user doesn't exist or has been removed")
+ }
+
+ return errgo.Wrap(err, "user.GetByName")
+ }
+
+ return h.listPersonCollection(c, u, page)
+}
+
+func (h User) listPersonCollection(c echo.Context, u user.User, page req.PageQuery) error {
+ count, err := h.collect.CountPersonCollections(c.Request().Context(), u.ID, collection.PersonCollectCategoryPerson)
+ if err != nil {
+ return errgo.Wrap(err, "failed to count user's person collections")
+ }
+
+ if count == 0 {
+ if count == 0 {
+ return c.JSON(http.StatusOK, res.Paged{Data: []int{}, Total: count, Limit: page.Limit, Offset: page.Offset})
+ }
+ }
+
+ if err = page.Check(count); err != nil {
+ return err
+ }
+
+ cols, err := h.collect.ListPersonCollection(
+ c.Request().Context(), u.ID, collection.PersonCollectCategoryPerson,
+ page.Limit, page.Offset)
+ if err != nil {
+ return errgo.Wrap(err, "failed to list user's person collections")
+ }
+
+ personIDs := slice.Map(cols, func(item collection.UserPersonCollection) model.PersonID {
+ return item.TargetID
+ })
+
+ personMap, err := h.person.GetByIDs(c.Request().Context(), personIDs)
+ if err != nil {
+ return errgo.Wrap(err, "failed to get persons")
+ }
+
+ var data = make([]res.PersonCollection, 0, len(cols))
+
+ for _, col := range cols {
+ person, ok := personMap[col.TargetID]
+ if !ok {
+ continue
+ }
+ data = append(data, res.ConvertModelPersonCollection(col, person))
+ }
+
+ return c.JSON(http.StatusOK, res.Paged{
+ Data: data,
+ Total: count,
+ Limit: page.Limit,
+ Offset: page.Offset,
+ })
+}
diff --git a/web/handler/user/user.go b/web/handler/user/user.go
index 59236045f..a85733224 100644
--- a/web/handler/user/user.go
+++ b/web/handler/user/user.go
@@ -19,6 +19,7 @@ import (
"github.com/bangumi/server/config"
"github.com/bangumi/server/ctrl"
+ "github.com/bangumi/server/internal/character"
"github.com/bangumi/server/internal/collections"
"github.com/bangumi/server/internal/episode"
"github.com/bangumi/server/internal/person"
@@ -27,18 +28,20 @@ import (
)
type User struct {
- ctrl ctrl.Ctrl
- episode episode.Repo
- person person.Service
- collect collections.Repo
- subject subject.CachedRepo
- log *zap.Logger
- user user.Repo
- cfg config.AppConfig
+ ctrl ctrl.Ctrl
+ episode episode.Repo
+ character character.Repo
+ person person.Repo
+ collect collections.Repo
+ subject subject.CachedRepo
+ log *zap.Logger
+ user user.Repo
+ cfg config.AppConfig
}
func New(
- p person.Service,
+ person person.Repo,
+ character character.Repo,
user user.Repo,
ctrl ctrl.Ctrl,
subject subject.Repo,
@@ -47,13 +50,14 @@ func New(
log *zap.Logger,
) (User, error) {
return User{
- ctrl: ctrl,
- episode: episode,
- collect: collect,
- subject: subject,
- user: user,
- person: p,
- log: log.Named("handler.User"),
- cfg: config.AppConfig{},
+ ctrl: ctrl,
+ episode: episode,
+ collect: collect,
+ subject: subject,
+ user: user,
+ person: person,
+ character: character,
+ log: log.Named("handler.User"),
+ cfg: config.AppConfig{},
}, nil
}
diff --git a/web/res/collection.go b/web/res/collection.go
index 17eecb208..84534d55b 100644
--- a/web/res/collection.go
+++ b/web/res/collection.go
@@ -60,22 +60,24 @@ type PersonCollection struct {
CreatedAt time.Time `json:"created_at"`
}
-// func ConvertModelPersonCollection(c collection.UserPersonCollection, person PersonV0) PersonCollection {
-// return PersonCollection{
-// ID: person.ID,
-// Type: person.Type,
-// Name: person.Name,
-// Images: person.Images,
-// CreatedAt: c.CreatedAt,
-// }
-// }
+func ConvertModelPersonCollection(c collection.UserPersonCollection, person model.Person) PersonCollection {
+ img := PersonImage(person.Image)
+ return PersonCollection{
+ ID: person.ID,
+ Type: person.Type,
+ Name: person.Name,
+ Images: img,
+ CreatedAt: c.CreatedAt,
+ }
+}
-// func convertModelCharacterCollection(c collection.UserPersonCollection, character CharacterV0) PersonCollection {
-// return PersonCollection{
-// ID: character.ID,
-// Type: character.Type,
-// Name: character.Name,
-// Images: character.Images,
-// CreatedAt: c.CreatedAt,
-// }
-// }
+func ConvertModelCharacterCollection(c collection.UserPersonCollection, character model.Character) PersonCollection {
+ img := PersonImage(character.Image)
+ return PersonCollection{
+ ID: character.ID,
+ Type: character.Type,
+ Name: character.Name,
+ Images: img,
+ CreatedAt: c.CreatedAt,
+ }
+}
diff --git a/web/routes.go b/web/routes.go
index ba82adf93..b796c2df7 100644
--- a/web/routes.go
+++ b/web/routes.go
@@ -94,10 +94,10 @@ func AddRouters(
v0.PATCH("/users/-/collections/:subject_id/episodes",
userHandler.PatchEpisodeCollectionBatch, req.JSON, mw.NeedLogin)
- // v0.GET("/users/:username/collections/-/characters", userHandler.ListCharacterCollection)
- // v0.GET("/users/:username/collections/-/characters/:character_id", userHandler.GetCharacterCollection)
- // v0.GET("/users/:username/collections/-/persons", userHandler.ListPersonCollection)
- // v0.GET("/users/:username/collections/-/persons/:person_id", userHandler.GetPersonCollection)
+ v0.GET("/users/:username/collections/-/characters", userHandler.ListCharacterCollection)
+ v0.GET("/users/:username/collections/-/characters/:character_id", userHandler.GetCharacterCollection)
+ v0.GET("/users/:username/collections/-/persons", userHandler.ListPersonCollection)
+ v0.GET("/users/:username/collections/-/persons/:person_id", userHandler.GetPersonCollection)
{
i := indexHandler