Skip to content

Commit 6884b80

Browse files
authored
Merge pull request #1420 from traPtitech/hotfix/delete_playlog
playlogを削除できるようにする
2 parents e73a1c1 + a456b21 commit 6884b80

File tree

10 files changed

+911
-453
lines changed

10 files changed

+911
-453
lines changed

docs/openapi/v2.yaml

Lines changed: 279 additions & 246 deletions
Large diffs are not rendered by default.

src/handler/v2/game_play_log.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,3 +211,20 @@ func (gpl *GamePlayLog) GetEditionPlayStats(c echo.Context, editionIDPath openap
211211

212212
return c.JSON(http.StatusOK, res)
213213
}
214+
215+
func (gpl *GamePlayLog) DeleteGamePlayLog(c echo.Context, editionIDPath openapi.EditionIDInPath, gameIDPath openapi.GameIDInPath, playLogIDPath openapi.PlayLogIDInPath) error {
216+
editionID := values.NewLauncherVersionIDFromUUID(editionIDPath)
217+
gameID := values.NewGameIDFromUUID(gameIDPath)
218+
playLogID := values.GamePlayLogIDFromUUID(playLogIDPath)
219+
220+
err := gpl.gamePlayLogService.DeleteGamePlayLog(c.Request().Context(), editionID, gameID, playLogID)
221+
if errors.Is(err, service.ErrInvalidPlayLogID) {
222+
return echo.NewHTTPError(http.StatusNotFound, "play log not found")
223+
}
224+
if err != nil {
225+
log.Printf("error: failed to delete game play log: %v\n", err)
226+
return echo.NewHTTPError(http.StatusInternalServerError, "failed to delete game play log")
227+
}
228+
229+
return c.NoContent(http.StatusOK)
230+
}

src/handler/v2/game_play_log_test.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -773,3 +773,70 @@ func TestGetGamePlayStats(t *testing.T) {
773773
})
774774
}
775775
}
776+
777+
func TestDeleteGamePlayLog(t *testing.T) {
778+
t.Parallel()
779+
780+
ctrl := gomock.NewController(t)
781+
782+
testCases := map[string]struct {
783+
editionID values.LauncherVersionID
784+
gameID values.GameID
785+
playLogID values.GamePlayLogID
786+
DeleteGamePlayLogErr error
787+
isError bool
788+
statusCode int
789+
}{
790+
"正常系": {
791+
editionID: values.NewLauncherVersionID(),
792+
gameID: values.NewGameID(),
793+
playLogID: values.NewGamePlayLogID(),
794+
statusCode: http.StatusOK,
795+
},
796+
"ErrInvalidPlayLogIDなので404": {
797+
editionID: values.NewLauncherVersionID(),
798+
gameID: values.NewGameID(),
799+
playLogID: values.NewGamePlayLogID(),
800+
DeleteGamePlayLogErr: service.ErrInvalidPlayLogID,
801+
isError: true,
802+
statusCode: http.StatusNotFound,
803+
},
804+
"その他のエラーなので500": {
805+
editionID: values.NewLauncherVersionID(),
806+
gameID: values.NewGameID(),
807+
playLogID: values.NewGamePlayLogID(),
808+
DeleteGamePlayLogErr: assert.AnError,
809+
isError: true,
810+
statusCode: http.StatusInternalServerError,
811+
},
812+
}
813+
814+
for name, testCase := range testCases {
815+
t.Run(name, func(t *testing.T) {
816+
t.Parallel()
817+
818+
serviceMock := mock.NewMockGamePlayLogV2(ctrl)
819+
h := NewGamePlayLog(serviceMock)
820+
821+
serviceMock.EXPECT().
822+
DeleteGamePlayLog(gomock.Any(), testCase.editionID, testCase.gameID, testCase.playLogID).
823+
Return(testCase.DeleteGamePlayLogErr)
824+
825+
url := fmt.Sprintf("/editions/%s/games/%s/plays/%s",
826+
uuid.UUID(testCase.editionID).String(), uuid.UUID(testCase.gameID).String(), uuid.UUID(testCase.playLogID).String())
827+
c, _, rec := setupTestRequest(t, http.MethodDelete, url, nil)
828+
829+
err := h.DeleteGamePlayLog(c, openapi.EditionIDInPath(testCase.editionID), openapi.GameIDInPath(testCase.gameID), openapi.PlayLogIDInPath(testCase.playLogID))
830+
831+
if testCase.isError {
832+
var httpError *echo.HTTPError
833+
assert.ErrorAs(t, err, &httpError)
834+
assert.Equal(t, testCase.statusCode, httpError.Code)
835+
return
836+
}
837+
838+
assert.NoError(t, err)
839+
assert.Equal(t, testCase.statusCode, rec.Code)
840+
})
841+
}
842+
}

src/handler/v2/openapi/openapi.gen.go

Lines changed: 247 additions & 207 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/repository/gorm2/v2_game_play_log.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,3 +355,21 @@ func (g *GamePlayLogV2) GetEditionPlayStats(ctx context.Context, editionID value
355355
hourlyStats,
356356
), nil
357357
}
358+
359+
func (g *GamePlayLogV2) DeleteGamePlayLog(ctx context.Context, playLogID values.GamePlayLogID) error {
360+
db, err := g.db.getDB(ctx)
361+
if err != nil {
362+
return fmt.Errorf("get db: %w", err)
363+
}
364+
365+
result := db.Unscoped().
366+
Delete(&schema.GamePlayLogTable{}, "id = ?", uuid.UUID(playLogID))
367+
if result.RowsAffected == 0 {
368+
return repository.ErrNoRecordDeleted
369+
}
370+
if result.Error != nil {
371+
return fmt.Errorf("delete game play log: %w", result.Error)
372+
}
373+
374+
return nil
375+
}

src/repository/gorm2/v2_game_play_log_test.go

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1466,3 +1466,123 @@ func TestGetEditionPlayStats(t *testing.T) {
14661466
})
14671467
}
14681468
}
1469+
1470+
func TestDeleteGamePlayLog(t *testing.T) {
1471+
t.Parallel()
1472+
1473+
ctx := t.Context()
1474+
db, err := testDB.getDB(ctx)
1475+
require.NoError(t, err)
1476+
1477+
playLogID := values.NewGamePlayLogID()
1478+
1479+
game1 := &schema.GameTable2{
1480+
ID: uuid.New(),
1481+
Name: "Test Game for DeleteGamePlayLog",
1482+
Description: "description",
1483+
VisibilityTypeID: 1,
1484+
CreatedAt: time.Now(),
1485+
LatestVersionUpdatedAt: time.Now(),
1486+
}
1487+
gameImage1 := &schema.GameImageTable2{
1488+
ID: uuid.New(),
1489+
GameID: game1.ID,
1490+
ImageTypeID: 1,
1491+
CreatedAt: time.Now(),
1492+
}
1493+
gameVideo1 := &schema.GameVideoTable2{
1494+
ID: uuid.New(),
1495+
GameID: game1.ID,
1496+
VideoTypeID: 1,
1497+
CreatedAt: time.Now(),
1498+
}
1499+
gameVersion1 := &schema.GameVersionTable2{
1500+
ID: uuid.New(),
1501+
GameID: game1.ID,
1502+
GameImageID: gameImage1.ID,
1503+
GameVideoID: gameVideo1.ID,
1504+
Name: "v1.0",
1505+
Description: "First version",
1506+
CreatedAt: time.Now(),
1507+
}
1508+
edition1 := &schema.EditionTable{
1509+
ID: uuid.New(),
1510+
Name: "Edition for DeleteGamePlayLog",
1511+
CreatedAt: time.Now(),
1512+
}
1513+
require.NoError(t, db.Create(game1).Error)
1514+
t.Cleanup(func() { require.NoError(t, testDB.db.Session(&gorm.Session{}).Unscoped().Delete(game1).Error) })
1515+
require.NoError(t, db.Create(gameImage1).Error)
1516+
t.Cleanup(func() { require.NoError(t, testDB.db.Session(&gorm.Session{}).Unscoped().Delete(gameImage1).Error) })
1517+
require.NoError(t, db.Create(gameVideo1).Error)
1518+
t.Cleanup(func() { require.NoError(t, testDB.db.Session(&gorm.Session{}).Unscoped().Delete(gameVideo1).Error) })
1519+
require.NoError(t, db.Create(gameVersion1).Error)
1520+
t.Cleanup(func() { require.NoError(t, testDB.db.Session(&gorm.Session{}).Unscoped().Delete(gameVersion1).Error) })
1521+
require.NoError(t, db.Create(edition1).Error)
1522+
t.Cleanup(func() { require.NoError(t, testDB.db.Session(&gorm.Session{}).Unscoped().Delete(edition1).Error) })
1523+
1524+
playLog1 := &schema.GamePlayLogTable{
1525+
ID: playLogID.UUID(),
1526+
EditionID: edition1.ID,
1527+
GameID: game1.ID,
1528+
GameVersionID: gameVersion1.ID,
1529+
StartTime: time.Now().Add(-10 * time.Minute),
1530+
EndTime: sql.NullTime{Time: time.Now(), Valid: true},
1531+
CreatedAt: time.Now(),
1532+
UpdatedAt: time.Now(),
1533+
}
1534+
1535+
testCases := map[string]struct {
1536+
playLogID values.GamePlayLogID
1537+
beforePlayLogs []*schema.GamePlayLogTable
1538+
afterPlayLogs []*schema.GamePlayLogTable
1539+
err error
1540+
}{
1541+
"正しく削除できる": {
1542+
playLogID: playLogID,
1543+
beforePlayLogs: []*schema.GamePlayLogTable{playLog1},
1544+
afterPlayLogs: []*schema.GamePlayLogTable{},
1545+
},
1546+
"存在しないIDを指定した場合ErrNoRecordDeletedが返る": {
1547+
playLogID: values.NewGamePlayLogID(),
1548+
beforePlayLogs: []*schema.GamePlayLogTable{playLog1},
1549+
afterPlayLogs: []*schema.GamePlayLogTable{playLog1},
1550+
err: repository.ErrNoRecordDeleted,
1551+
},
1552+
}
1553+
1554+
for name, testCase := range testCases {
1555+
t.Run(name, func(t *testing.T) {
1556+
1557+
err := db.Create(testCase.beforePlayLogs).Error
1558+
require.NoError(t, err)
1559+
1560+
t.Cleanup(func() {
1561+
err := db.Unscoped().Delete(testCase.beforePlayLogs).Error
1562+
require.NoError(t, err)
1563+
})
1564+
1565+
gamePlayLogRepository := NewGamePlayLogV2(testDB)
1566+
1567+
err = gamePlayLogRepository.DeleteGamePlayLog(t.Context(), testCase.playLogID)
1568+
1569+
if testCase.err != nil {
1570+
assert.ErrorIs(t, err, testCase.err)
1571+
return
1572+
}
1573+
1574+
assert.NoError(t, err)
1575+
1576+
var resultAfterPlayLogs []*schema.GamePlayLogTable
1577+
beforePlayLogIDs := make([]uuid.UUID, len(testCase.beforePlayLogs))
1578+
for i, log := range testCase.beforePlayLogs {
1579+
beforePlayLogIDs[i] = log.ID
1580+
}
1581+
err = db.Where("id IN ?", beforePlayLogIDs).Find(&resultAfterPlayLogs).Error
1582+
require.NoError(t, err)
1583+
1584+
assert.Equal(t, testCase.afterPlayLogs, resultAfterPlayLogs)
1585+
1586+
})
1587+
}
1588+
}

src/repository/v2_game_play_log.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,8 @@ type GamePlayLogV2 interface {
3535
// 統計データが存在しない場合でも空の統計を返すようにする。エラーは発生しない
3636
// editionNameも含めて返すため、editionsテーブルとのJOINが必要
3737
GetEditionPlayStats(ctx context.Context, editionID values.LauncherVersionID, start, end time.Time) (*domain.EditionPlayStats, error)
38+
// DeleteGamePlayLog
39+
// 指定されたプレイログを削除する。
40+
// 条件に当てはまるプレイログが存在しない場合、ErrNoRecordDeletedを返す。
41+
DeleteGamePlayLog(ctx context.Context, playLogID values.GamePlayLogID) error
3842
}

src/service/v2/game_play_log.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,3 +169,35 @@ func (g *GamePlayLog) GetEditionPlayStats(ctx context.Context, editionID values.
169169

170170
return stats, nil
171171
}
172+
173+
func (g *GamePlayLog) DeleteGamePlayLog(ctx context.Context, editionID values.LauncherVersionID, gameID values.GameID, playLogID values.GamePlayLogID) error {
174+
err := g.db.Transaction(ctx, nil, func(ctx context.Context) error {
175+
playLog, err := g.gamePlayLogRepository.GetGamePlayLog(ctx, playLogID)
176+
if errors.Is(err, repository.ErrRecordNotFound) {
177+
return service.ErrInvalidPlayLogID
178+
}
179+
if err != nil {
180+
return fmt.Errorf("get game play log: %w", err)
181+
}
182+
183+
if playLog.GetEditionID() != editionID || playLog.GetGameID() != gameID {
184+
return service.ErrInvalidPlayLogID
185+
}
186+
187+
err = g.gamePlayLogRepository.DeleteGamePlayLog(ctx, playLogID)
188+
if errors.Is(err, repository.ErrNoRecordDeleted) {
189+
return service.ErrInvalidPlayLogID
190+
}
191+
if err != nil {
192+
return fmt.Errorf("delete game play log: %w", err)
193+
}
194+
195+
return nil
196+
})
197+
198+
if err != nil {
199+
return err
200+
}
201+
202+
return nil
203+
}

0 commit comments

Comments
 (0)