feat(enakgame): filter play history by game and status
GET /customer/enakgame/sessions takes optional game_id and status, so a game reloaded mid-play finds the session it was running (status=STARTED) instead of starting a new one and charging EnakCoin again. An invalid game_id or status is refused. integration-enakgame.md §4.4 now describes recovery after a reload: keep the session_id in sessionStorage, continue a STARTED session before expires_at, and call complete again for a COMPLETED one to get the full answer, prize included. The mobile guide and RFC §11 mention the filters. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
b5d2cd491a
commit
52e8fe11c6
@@ -30,7 +30,8 @@ Alasan di balik aturannya ada di [`rfc-enakgame.md`](./rfc-enakgame.md) dan
|
|||||||
selalu `reward_total` dari backend.
|
selalu `reward_total` dari backend.
|
||||||
3. **Satu tap "Main" = satu `Idempotency-Key`.** Retry memakai key yang sama.
|
3. **Satu tap "Main" = satu `Idempotency-Key`.** Retry memakai key yang sama.
|
||||||
4. **Token customer adalah rahasia.** Hanya diterima lewat bridge, disimpan di memori,
|
4. **Token customer adalah rahasia.** Hanya diterima lewat bridge, disimpan di memori,
|
||||||
tidak pernah ditaruh di URL, `localStorage`, cookie, log, atau analytics.
|
tidak pernah ditaruh di URL, `localStorage`, `sessionStorage`, cookie, log, atau
|
||||||
|
analytics. (`session_id` boleh disimpan di `sessionStorage`, §4.4.)
|
||||||
5. **Semua jumlah bilangan bulat.** Tidak ada pecahan EnakCoin.
|
5. **Semua jumlah bilangan bulat.** Tidak ada pecahan EnakCoin.
|
||||||
6. **Main game tidak butuh PIN.**
|
6. **Main game tidak butuh PIN.**
|
||||||
|
|
||||||
@@ -94,7 +95,8 @@ tunggu `token`, lalu ulangi request yang sama.
|
|||||||
## 4. Alur satu kali main
|
## 4. Alur satu kali main
|
||||||
|
|
||||||
```
|
```
|
||||||
init ─► GET /customer/enakgame/games ─► tampilkan biaya (dan roda, untuk spin)
|
init ─► cek session yang masih berjalan (§4.4)
|
||||||
|
─► GET /customer/enakgame/games ─► tampilkan biaya (dan roda, untuk spin)
|
||||||
─► tap Main ─► POST /customer/enakgame/sessions (EnakCoin dipotong)
|
─► tap Main ─► POST /customer/enakgame/sessions (EnakCoin dipotong)
|
||||||
─► permainan berjalan (batas waktu: expires_at)
|
─► permainan berjalan (batas waktu: expires_at)
|
||||||
─► POST /customer/enakgame/sessions/:id/complete (server menghitung hadiah)
|
─► POST /customer/enakgame/sessions/:id/complete (server menghitung hadiah)
|
||||||
@@ -227,9 +229,13 @@ sepakati daftarnya dengan tim backoffice.
|
|||||||
| `310` | `score` bukan bilangan bulat atau `outcome` bukan string | Bug di game |
|
| `310` | `score` bukan bilangan bulat atau `outcome` bukan string | Bug di game |
|
||||||
| `404` | Session tidak ada / milik customer lain | Pesan umum |
|
| `404` | Session tidak ada / milik customer lain | Pesan umum |
|
||||||
|
|
||||||
### 4.4 Cek status — `GET /customer/enakgame/sessions/:id`
|
### 4.4 Pemulihan setelah reload
|
||||||
|
|
||||||
Untuk memulihkan keadaan, mis. game dimuat ulang saat session masih berjalan:
|
Webview bisa memuat ulang halaman game (aplikasi ke background, memori habis, crash)
|
||||||
|
saat customer sedang main. EnakCoin sudah terpotong, jadi game wajib menemukan lagi
|
||||||
|
session-nya. Dua endpoint dipakai:
|
||||||
|
|
||||||
|
**Satu session** — `GET /customer/enakgame/sessions/:id`
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
@@ -238,8 +244,35 @@ Untuk memulihkan keadaan, mis. game dimuat ulang saat session masih berjalan:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`status`: `STARTED`, `COMPLETED`, `REFUNDED`, atau `EXPIRED`. Riwayat main customer ada
|
`status`: `STARTED`, `COMPLETED`, `REFUNDED`, atau `EXPIRED`. Response ini tidak memuat
|
||||||
di `GET /customer/enakgame/sessions?page=1&limit=20` (dipakai aplikasi, bukan game).
|
`prize` atau rincian hadiah; untuk itu kirim ulang complete (lihat di bawah).
|
||||||
|
|
||||||
|
**Mencari session** — `GET /customer/enakgame/sessions?game_id=8a1f…&status=STARTED&limit=1`
|
||||||
|
|
||||||
|
Bentuk item sama dengan di atas, dibungkus `data` + `pagination`, terbaru di atas.
|
||||||
|
Semua query opsional: `game_id`, `status` (`STARTED`, `COMPLETED`, `REFUNDED`,
|
||||||
|
`EXPIRED`), `page`, `limit`. `status` atau `game_id` yang tidak valid ditolak `304`.
|
||||||
|
|
||||||
|
**Alurnya, setiap kali menerima `init`:**
|
||||||
|
|
||||||
|
1. Simpan `session_id` di **`sessionStorage`** setiap kali start berhasil, dan hapus
|
||||||
|
setelah hasilnya ditampilkan. `session_id` bukan rahasia; token tetap hanya di
|
||||||
|
memori (§1).
|
||||||
|
2. Bila ada `session_id` tersimpan, panggil `GET /sessions/:id`. Bila tidak ada (mis.
|
||||||
|
webview dibuka ulang dari awal), panggil
|
||||||
|
`GET /sessions?game_id=<game_id>&status=STARTED&limit=1`.
|
||||||
|
3. Tindak lanjuti sesuai status:
|
||||||
|
|
||||||
|
| Keadaan | Yang dilakukan game |
|
||||||
|
|---|---|
|
||||||
|
| `STARTED`, sekarang sebelum `expires_at` | **Lanjutkan** session itu: jangan start baru (EnakCoin akan terpotong lagi). Spin: langsung kirim complete `{}` dan tampilkan hasilnya. Game lain: progres main hilang, jadi mulai ulang permainan di session yang sama dengan timer sampai `expires_at`, lalu kirim complete |
|
||||||
|
| `STARTED`, `expires_at` sudah lewat | Anggap selesai. Server mengubahnya menjadi `EXPIRED` (atau merefund bila complete sebelumnya gagal karena error server) dalam ±1 menit. Tampilkan "Waktu bermain habis", lalu customer boleh start baru |
|
||||||
|
| `COMPLETED` | Hasil sudah dihitung tapi mungkin belum ditampilkan. Kirim ulang `POST /sessions/:id/complete` dengan body apa saja (`{}`): server mengembalikan jawaban yang sama persis, termasuk `prize`, tanpa hadiah dobel. Tampilkan hasilnya |
|
||||||
|
| `REFUNDED` | "EnakCoin kamu dikembalikan." |
|
||||||
|
| `EXPIRED` | "Waktu bermain habis." |
|
||||||
|
| Tidak ada session | Tampilkan layar awal seperti biasa |
|
||||||
|
|
||||||
|
Riwayat main lengkap (tanpa filter) dipakai aplikasi customer, bukan game.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -289,6 +322,7 @@ saja.
|
|||||||
|
|
||||||
- [ ] Bridge sesuai kontrak §2 yang sudah disepakati dengan tim aplikasi.
|
- [ ] Bridge sesuai kontrak §2 yang sudah disepakati dengan tim aplikasi.
|
||||||
- [ ] Token hanya di memori; tidak ada di URL, storage, log, atau analytics.
|
- [ ] Token hanya di memori; tidak ada di URL, storage, log, atau analytics.
|
||||||
|
- [ ] Pemulihan setelah reload (§4.4): session `STARTED` dilanjutkan, bukan start baru; `COMPLETED` ditampilkan lewat complete ulang.
|
||||||
- [ ] Biaya main dan label event tampil sebelum main.
|
- [ ] Biaya main dan label event tampil sebelum main.
|
||||||
- [ ] Satu `Idempotency-Key` per tap Main, dipakai ulang saat retry.
|
- [ ] Satu `Idempotency-Key` per tap Main, dipakai ulang saat retry.
|
||||||
- [ ] Complete hanya mengirim `score` / `outcome` / `data`, tidak pernah hadiah.
|
- [ ] Complete hanya mengirim `score` / `outcome` / `data`, tidak pernah hadiah.
|
||||||
|
|||||||
@@ -616,6 +616,9 @@ kembali", lalu tutup. Tidak perlu mengirim pesan ke game.
|
|||||||
|
|
||||||
### 8.4 Riwayat main — `GET /customer/enakgame/sessions?page=1&limit=20`
|
### 8.4 Riwayat main — `GET /customer/enakgame/sessions?page=1&limit=20`
|
||||||
|
|
||||||
|
Query opsional `game_id` (riwayat satu game) dan `status` (`STARTED`, `COMPLETED`,
|
||||||
|
`REFUNDED`, `EXPIRED`) untuk filter atau tab.
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"data": [
|
"data": [
|
||||||
|
|||||||
@@ -842,7 +842,7 @@ tambahkan snapshot harian, bukan cache yang di-invalidate.
|
|||||||
| `POST` | `/sessions` | §7.1. Wajib `Idempotency-Key` |
|
| `POST` | `/sessions` | §7.1. Wajib `Idempotency-Key` |
|
||||||
| `POST` | `/sessions/:id/complete` | §7.2. Idempotent tanpa header |
|
| `POST` | `/sessions/:id/complete` | §7.2. Idempotent tanpa header |
|
||||||
| `GET` | `/sessions/:id` | Status dan hasil |
|
| `GET` | `/sessions/:id` | Status dan hasil |
|
||||||
| `GET` | `/sessions` | Riwayat main |
|
| `GET` | `/sessions` | Riwayat main; filter opsional `game_id`, `status` (dipakai game untuk menemukan session `STARTED` setelah reload) |
|
||||||
|
|
||||||
Prefix `/enakgame` dipakai karena `/customer/games` sudah dipakai alur spin lama.
|
Prefix `/enakgame` dipakai karena `/customer/games` sudah dipakai alur spin lama.
|
||||||
|
|
||||||
|
|||||||
@@ -50,16 +50,18 @@ func (h *EnakGameCustomerHandler) StartSession(c *gin.Context) {
|
|||||||
util.HandleResponse(c.Writer, c.Request, h.service.StartSession(c.Request.Context(), customerID, &req, idempotencyKey(c)), method)
|
util.HandleResponse(c.Writer, c.Request, h.service.StartSession(c.Request.Context(), customerID, &req, idempotencyKey(c)), method)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListSessions is GET /customer/enakgame/sessions?page=&limit=.
|
// ListSessions is GET /customer/enakgame/sessions?game_id=&status=&page=&limit=.
|
||||||
func (h *EnakGameCustomerHandler) ListSessions(c *gin.Context) {
|
func (h *EnakGameCustomerHandler) ListSessions(c *gin.Context) {
|
||||||
const method = "EnakGameCustomerHandler::ListSessions"
|
const method = "EnakGameCustomerHandler::ListSessions"
|
||||||
customerID, ok := customerIDFromGin(c, method)
|
customerID, ok := customerIDFromGin(c, method)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
page, _ := strconv.Atoi(c.Query("page"))
|
var q models.GameSessionListQuery
|
||||||
limit, _ := strconv.Atoi(c.Query("limit"))
|
if !bindQuery(c, &q, method) {
|
||||||
util.HandleResponse(c.Writer, c.Request, h.service.ListSessions(c.Request.Context(), customerID, page, limit), method)
|
return
|
||||||
|
}
|
||||||
|
util.HandleResponse(c.Writer, c.Request, h.service.ListSessions(c.Request.Context(), customerID, q), method)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSession is GET /customer/enakgame/sessions/:id.
|
// GetSession is GET /customer/enakgame/sessions/:id.
|
||||||
|
|||||||
@@ -189,6 +189,16 @@ type CustomerGameSession struct {
|
|||||||
RefundReason *string `json:"refund_reason"`
|
RefundReason *string `json:"refund_reason"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GameSessionListQuery filters a customer's play history. The game client uses
|
||||||
|
// game_id with status=STARTED to find the play it was running before a reload.
|
||||||
|
type GameSessionListQuery struct {
|
||||||
|
GameID string `form:"game_id"`
|
||||||
|
// STARTED, COMPLETED, REFUNDED or EXPIRED; empty for all.
|
||||||
|
Status string `form:"status"`
|
||||||
|
Page int `form:"page"`
|
||||||
|
Limit int `form:"limit"`
|
||||||
|
}
|
||||||
|
|
||||||
// GameSessionCompleteInput is what the client reports at the end of a play (§7.2): data
|
// GameSessionCompleteInput is what the client reports at the end of a play (§7.2): data
|
||||||
// only. Anything else it sends, a reward amount above all, is ignored (P1).
|
// only. Anything else it sends, a reward amount above all, is ignored (P1).
|
||||||
type GameSessionCompleteInput struct {
|
type GameSessionCompleteInput struct {
|
||||||
|
|||||||
@@ -675,12 +675,34 @@ func TestGameSession_CustomerReads(t *testing.T) {
|
|||||||
_, err = e.sessions.GetSession(ctx, e.bob, started.SessionID)
|
_, err = e.sessions.GetSession(ctx, e.bob, started.SessionID)
|
||||||
assert.ErrorIs(t, err, repository.ErrGameSessionNotFound, "another customer's session")
|
assert.ErrorIs(t, err, repository.ErrGameSessionNotFound, "another customer's session")
|
||||||
|
|
||||||
page, err := e.sessions.ListSessions(ctx, e.alice, 1, 10)
|
page, err := e.sessions.ListSessions(ctx, e.alice, models.GameSessionListQuery{Page: 1, Limit: 10})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.EqualValues(t, 1, page.Pagination.Total)
|
assert.EqualValues(t, 1, page.Pagination.Total)
|
||||||
page, err = e.sessions.ListSessions(ctx, e.bob, 1, 10)
|
page, err = e.sessions.ListSessions(ctx, e.bob, models.GameSessionListQuery{Page: 1, Limit: 10})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Empty(t, page.Data)
|
assert.Empty(t, page.Data)
|
||||||
|
|
||||||
|
// After a reload, the game finds the play it was running by game and status.
|
||||||
|
other := e.playableGame(e.orgA, "other", 1)
|
||||||
|
otherStarted, err := e.sessions.Start(ctx, e.alice, other.ID, "k2")
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, err = e.sessions.Complete(ctx, e.alice, otherStarted.SessionID, models.GameSessionCompleteInput{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
running, err := e.sessions.ListSessions(ctx, e.alice, models.GameSessionListQuery{GameID: game.ID.String(), Status: "started"})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, running.Data, 1)
|
||||||
|
assert.Equal(t, started.SessionID, running.Data[0].ID)
|
||||||
|
running, err = e.sessions.ListSessions(ctx, e.alice, models.GameSessionListQuery{GameID: other.ID.String(), Status: constants.GameSessionStatusStarted})
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Empty(t, running.Data, "the other game's play is completed")
|
||||||
|
all, err := e.sessions.ListSessions(ctx, e.alice, models.GameSessionListQuery{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 2, all.Pagination.Total)
|
||||||
|
|
||||||
|
_, err = e.sessions.ListSessions(ctx, e.alice, models.GameSessionListQuery{Status: "PLAYING"})
|
||||||
|
assert.ErrorIs(t, err, ErrGameSessionRejected)
|
||||||
|
_, err = e.sessions.ListSessions(ctx, e.alice, models.GameSessionListQuery{GameID: "runner"})
|
||||||
|
assert.ErrorIs(t, err, ErrGameSessionRejected)
|
||||||
}
|
}
|
||||||
|
|
||||||
// gameWith makes an ACTIVE game of org A with the given result rules and an active
|
// gameWith makes an ACTIVE game of org A with the given result rules and an active
|
||||||
|
|||||||
@@ -419,10 +419,26 @@ func (p *GameSessionProcessor) ListGames(ctx context.Context, customerID uuid.UU
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListSessions returns a page of the customer's sessions, newest first.
|
// ListSessions returns a page of the customer's sessions, newest first, of one game
|
||||||
func (p *GameSessionProcessor) ListSessions(ctx context.Context, customerID uuid.UUID, page, limit int) (*models.PaginatedResponse[models.CustomerGameSession], error) {
|
// or status when asked.
|
||||||
page, limit = enakGamePage(page, limit)
|
func (p *GameSessionProcessor) ListSessions(ctx context.Context, customerID uuid.UUID, q models.GameSessionListQuery) (*models.PaginatedResponse[models.CustomerGameSession], error) {
|
||||||
sessions, total, err := p.sessions.ListCustomerSessions(ctx, customerID, (page-1)*limit, limit)
|
page, limit := enakGamePage(q.Page, q.Limit)
|
||||||
|
filter := repository.CustomerSessionFilter{CustomerID: customerID, Offset: (page - 1) * limit, Limit: limit}
|
||||||
|
if s := strings.TrimSpace(q.GameID); s != "" {
|
||||||
|
id, err := uuid.Parse(s)
|
||||||
|
if err != nil {
|
||||||
|
return nil, gameSessionRejected("game_id must be a UUID")
|
||||||
|
}
|
||||||
|
filter.GameID = &id
|
||||||
|
}
|
||||||
|
switch status := strings.ToUpper(strings.TrimSpace(q.Status)); status {
|
||||||
|
case "", constants.GameSessionStatusStarted, constants.GameSessionStatusCompleted,
|
||||||
|
constants.GameSessionStatusRefunded, constants.GameSessionStatusExpired:
|
||||||
|
filter.Status = status
|
||||||
|
default:
|
||||||
|
return nil, gameSessionRejected("status must be STARTED, COMPLETED, REFUNDED or EXPIRED")
|
||||||
|
}
|
||||||
|
sessions, total, err := p.sessions.ListCustomerSessions(ctx, filter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -287,7 +287,7 @@ func TestGameSessionRepository_ReadsAndMoves(t *testing.T) {
|
|||||||
assert.True(t, got.Flagged)
|
assert.True(t, got.Flagged)
|
||||||
assert.NotNil(t, got.CompletionFailedAt)
|
assert.NotNil(t, got.CompletionFailedAt)
|
||||||
|
|
||||||
sessions, total, err := f.sessions.ListCustomerSessions(ctx, f.customer, 0, 1)
|
sessions, total, err := f.sessions.ListCustomerSessions(ctx, CustomerSessionFilter{CustomerID: f.customer, Limit: 1})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.EqualValues(t, 2, total)
|
assert.EqualValues(t, 2, total)
|
||||||
assert.Len(t, sessions, 1)
|
assert.Len(t, sessions, 1)
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ type GameSessionRepository interface {
|
|||||||
GetSessionBySpendTransaction(ctx context.Context, spendTransactionID uuid.UUID) (*entities.GameSession, error)
|
GetSessionBySpendTransaction(ctx context.Context, spendTransactionID uuid.UUID) (*entities.GameSession, error)
|
||||||
// ListCustomerSessions returns a page of a customer's sessions, newest first, and
|
// ListCustomerSessions returns a page of a customer's sessions, newest first, and
|
||||||
// the total.
|
// the total.
|
||||||
ListCustomerSessions(ctx context.Context, customerID uuid.UUID, offset, limit int) ([]entities.GameSession, int64, error)
|
ListCustomerSessions(ctx context.Context, filter CustomerSessionFilter) ([]entities.GameSession, int64, error)
|
||||||
|
|
||||||
CompleteSession(ctx context.Context, id uuid.UUID, completion GameSessionCompletion) (bool, error)
|
CompleteSession(ctx context.Context, id uuid.UUID, completion GameSessionCompletion) (bool, error)
|
||||||
RefundSession(ctx context.Context, id, refundTransactionID uuid.UUID, reason string, endedAt time.Time) (bool, error)
|
RefundSession(ctx context.Context, id, refundTransactionID uuid.UUID, reason string, endedAt time.Time) (bool, error)
|
||||||
@@ -116,8 +116,26 @@ func (r *gameSessionRepository) GetSessionBySpendTransaction(ctx context.Context
|
|||||||
return r.first(DBFromContext(ctx, r.db).WithContext(ctx).Where("spend_transaction_id = ?", spendTransactionID))
|
return r.first(DBFromContext(ctx, r.db).WithContext(ctx).Where("spend_transaction_id = ?", spendTransactionID))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *gameSessionRepository) ListCustomerSessions(ctx context.Context, customerID uuid.UUID, offset, limit int) ([]entities.GameSession, int64, error) {
|
// CustomerSessionFilter selects a customer's sessions.
|
||||||
q := DBFromContext(ctx, r.db).WithContext(ctx).Model(&entities.GameSession{}).Where("customer_id = ?", customerID)
|
type CustomerSessionFilter struct {
|
||||||
|
CustomerID uuid.UUID
|
||||||
|
// Nil for every game.
|
||||||
|
GameID *uuid.UUID
|
||||||
|
// Empty for every status.
|
||||||
|
Status string
|
||||||
|
Offset int
|
||||||
|
Limit int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *gameSessionRepository) ListCustomerSessions(ctx context.Context, filter CustomerSessionFilter) ([]entities.GameSession, int64, error) {
|
||||||
|
q := DBFromContext(ctx, r.db).WithContext(ctx).Model(&entities.GameSession{}).Where("customer_id = ?", filter.CustomerID)
|
||||||
|
if filter.GameID != nil {
|
||||||
|
q = q.Where("game_id = ?", *filter.GameID)
|
||||||
|
}
|
||||||
|
if filter.Status != "" {
|
||||||
|
q = q.Where("status = ?", filter.Status)
|
||||||
|
}
|
||||||
|
offset, limit := filter.Offset, filter.Limit
|
||||||
var total int64
|
var total int64
|
||||||
if err := q.Count(&total).Error; err != nil {
|
if err := q.Count(&total).Error; err != nil {
|
||||||
return nil, 0, fmt.Errorf("failed to count game sessions: %w", err)
|
return nil, 0, fmt.Errorf("failed to count game sessions: %w", err)
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ type EnakGameCustomerService interface {
|
|||||||
ListGames(ctx context.Context, customerID uuid.UUID) *contract.Response
|
ListGames(ctx context.Context, customerID uuid.UUID) *contract.Response
|
||||||
StartSession(ctx context.Context, customerID uuid.UUID, req *contract.StartGameSessionRequest, idempotencyKey string) *contract.Response
|
StartSession(ctx context.Context, customerID uuid.UUID, req *contract.StartGameSessionRequest, idempotencyKey string) *contract.Response
|
||||||
CompleteSession(ctx context.Context, customerID, sessionID uuid.UUID, in models.GameSessionCompleteInput) *contract.Response
|
CompleteSession(ctx context.Context, customerID, sessionID uuid.UUID, in models.GameSessionCompleteInput) *contract.Response
|
||||||
ListSessions(ctx context.Context, customerID uuid.UUID, page, limit int) *contract.Response
|
ListSessions(ctx context.Context, customerID uuid.UUID, q models.GameSessionListQuery) *contract.Response
|
||||||
GetSession(ctx context.Context, customerID, sessionID uuid.UUID) *contract.Response
|
GetSession(ctx context.Context, customerID, sessionID uuid.UUID) *contract.Response
|
||||||
|
|
||||||
ListVouchers(ctx context.Context, customerID uuid.UUID) *contract.Response
|
ListVouchers(ctx context.Context, customerID uuid.UUID) *contract.Response
|
||||||
@@ -371,8 +371,8 @@ func (s *EnakGameCustomerServiceImpl) CompleteSession(ctx context.Context, custo
|
|||||||
return respond(ctx, completion, err)
|
return respond(ctx, completion, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *EnakGameCustomerServiceImpl) ListSessions(ctx context.Context, customerID uuid.UUID, page, limit int) *contract.Response {
|
func (s *EnakGameCustomerServiceImpl) ListSessions(ctx context.Context, customerID uuid.UUID, q models.GameSessionListQuery) *contract.Response {
|
||||||
sessions, err := s.sessions.ListSessions(ctx, customerID, page, limit)
|
sessions, err := s.sessions.ListSessions(ctx, customerID, q)
|
||||||
return respond(ctx, sessions, err)
|
return respond(ctx, sessions, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user