5 Commits

Author SHA1 Message Date
edmand46 cafc2bfc6a rename Config.APIKey to AdminKey, add search to project storage list
CI / build (push) Successful in 1m2s
2026-08-25 13:59:30 +03:00
edmand46 6e7c818f75 remove UGC surface, add CI, versioning docs
CI / build (push) Successful in 1m14s
2026-08-19 17:49:03 +03:00
edmand46 ae74fb22d3 add player data operations: update, ban/unban, delete, inventory adjust, storage
Players.Update/Ban/Unban/Delete + List search; new InventoryService.Adjust
and StorageService.Get/Upsert/Delete; IdempotencyKey on wallet adjust;
models regenerated via apigen
2026-08-13 08:47:14 +03:00
edmand46 d602a95baf Add ProjectStorageService (list/get/upsert/delete) 2026-08-12 23:58:34 +03:00
rudder 58eb477763 Per-project admin key auth, drop ProjectID; MIT license; go 1.21 2026-08-12 17:37:46 +03:00
30 changed files with 407 additions and 170 deletions
+26
View File
@@ -0,0 +1,26 @@
name: CI
on:
push:
branches: [master, main]
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.21'
- name: Build
run: go build ./...
- name: Vet
run: go vet ./...
+1
View File
@@ -0,0 +1 @@
.idea/
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Rudder
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+18 -8
View File
@@ -1,8 +1,7 @@
# liveops-go-sdk # rudder-go-sdk
Серверный Go SDK для LiveOps-платформы Rudder. Покрывает server-admin Серверный Go SDK для LiveOps-платформы Rudder. Покрывает server-admin
поверхность `/game/v1` (auth по `X-API-Key`, ключ — `GAME_ADMIN_API_KEY` поверхность `/game/v1` (auth по `X-API-Key`).
на gateway).
## Install ## Install
@@ -14,14 +13,26 @@ go env -w GOPRIVATE=hub.rudder.build/*
go get hub.rudder.build/rudder/rudder-go-sdk@latest go get hub.rudder.build/rudder/rudder-go-sdk@latest
``` ```
Требуется Go 1.25+. Токен не нужен — репозиторий публичный. Требуется Go 1.21+. Токен не нужен — репозиторий публичный.
## Версионирование
Потребители фиксируют версию по git-тегу
(`go get hub.rudder.build/rudder/rudder-go-sdk@vX.Y.Z`). Первый тег `v0.1.0`
будет создан при релизе; до него версионирования нет.
## Доступ
`AdminKey` — это per-project Admin Key: поле «Admin Key» в настройках проекта
в дашборде (app.rudder.build → проект → Settings). Ключ сам определяет
проект, отдельный project ID не нужен. Храните его только на сервере —
никогда не вшивайте в игровые клиенты.
## Usage ## Usage
```go ```go
client, err := rudder.New(rudder.Config{ client, err := rudder.New(rudder.Config{
APIKey: os.Getenv("GAME_ADMIN_API_KEY"), AdminKey: os.Getenv("RUDDER_ADMIN_KEY"),
ProjectID: "your-project-id",
}) })
if err != nil { if err != nil {
// *rudder.APIError с кодом sdk/invalid-options // *rudder.APIError с кодом sdk/invalid-options
@@ -35,7 +46,6 @@ wallet, err := client.Wallet.Adjust(ctx, playerID, rudder.AdjustWalletParameters
Reason: "compensation", Reason: "compensation",
}) })
metrics, err := client.Metrics.Get(ctx) metrics, err := client.Metrics.Get(ctx)
page, err := client.Ugc.List(ctx, rudder.ListUgcParameters{Status: "pending"})
``` ```
## Ошибки ## Ошибки
@@ -44,7 +54,7 @@ page, err := client.Ugc.List(ctx, rudder.ListUgcParameters{Status: "pending"})
var apiErr *rudder.APIError var apiErr *rudder.APIError
if errors.As(err, &apiErr) { if errors.As(err, &apiErr) {
apiErr.Status // HTTP status apiErr.Status // HTTP status
apiErr.Code // машинный код, константы в models.ErrorCode* apiErr.Code // машинный код из тела ошибки gateway
apiErr.RequestID // корреляция с логами gateway apiErr.RequestID // корреляция с логами gateway
} }
``` ```
+12 -11
View File
@@ -8,8 +8,7 @@ import (
const DefaultBaseURL = "https://api.rudder.build" const DefaultBaseURL = "https://api.rudder.build"
type Config struct { type Config struct {
APIKey string AdminKey string
ProjectID string
BaseURL string BaseURL string
Timeout time.Duration Timeout time.Duration
HTTPClient *http.Client HTTPClient *http.Client
@@ -20,15 +19,15 @@ type Client struct {
Metrics *MetricsService Metrics *MetricsService
Leaderboards *LeaderboardsService Leaderboards *LeaderboardsService
Wallet *WalletService Wallet *WalletService
Ugc *UgcService Inventory *InventoryService
Storage *StorageService
ProjectStorage *ProjectStorageService
} }
func New(config Config) (*Client, error) { func New(config Config) (*Client, error) {
if config.APIKey == "" { if config.AdminKey == "" {
return nil, &APIError{Code: ErrorCodeInvalidOptions, Message: "APIKey is required"} return nil, &APIError{Code: ErrorCodeInvalidOptions, Message: "AdminKey is required"}
}
if config.ProjectID == "" {
return nil, &APIError{Code: ErrorCodeInvalidOptions, Message: "ProjectID is required"}
} }
if config.BaseURL == "" { if config.BaseURL == "" {
@@ -43,8 +42,7 @@ func New(config Config) (*Client, error) {
transport := &transport{ transport := &transport{
baseURL: config.BaseURL, baseURL: config.BaseURL,
apiKey: config.APIKey, apiKey: config.AdminKey,
projectID: config.ProjectID,
httpClient: config.HTTPClient, httpClient: config.HTTPClient,
} }
@@ -53,6 +51,9 @@ func New(config Config) (*Client, error) {
Metrics: &MetricsService{transport: transport}, Metrics: &MetricsService{transport: transport},
Leaderboards: &LeaderboardsService{transport: transport}, Leaderboards: &LeaderboardsService{transport: transport},
Wallet: &WalletService{transport: transport}, Wallet: &WalletService{transport: transport},
Ugc: &UgcService{transport: transport}, Inventory: &InventoryService{transport: transport},
Storage: &StorageService{transport: transport},
ProjectStorage: &ProjectStorageService{transport: transport},
}, nil }, nil
} }
+1 -1
View File
@@ -1,3 +1,3 @@
module hub.rudder.build/rudder/rudder-go-sdk module hub.rudder.build/rudder/rudder-go-sdk
go 1.25.2 go 1.21
+35
View File
@@ -0,0 +1,35 @@
package rudder
import (
"context"
"net/http"
"net/url"
"hub.rudder.build/rudder/rudder-go-sdk/models"
)
type InventoryService struct {
transport *transport
}
type AdjustInventoryParameters struct {
Slug string
Amount int64
Reason string
IdempotencyKey string
}
func (s *InventoryService) Adjust(ctx context.Context, playerID string, parameters AdjustInventoryParameters) (*models.InventoryItem, error) {
body := models.AdjustPlayerInventoryItemRequest{
Slug: parameters.Slug,
Amount: parameters.Amount,
Reason: parameters.Reason,
IdempotencyKey: parameters.IdempotencyKey,
}
var response models.InventoryItem
if err := s.transport.do(ctx, http.MethodPost, "/players/"+url.PathEscape(playerID)+"/inventory/adjust", nil, body, &response); err != nil {
return nil, err
}
return &response, nil
}
@@ -0,0 +1,10 @@
// Code generated by apigen. DO NOT EDIT.
package models
type AdjustPlayerInventoryItemRequest struct {
Amount int64 `json:"amount,omitempty"`
IdempotencyKey string `json:"idempotencyKey,omitempty"`
Reason string `json:"reason,omitempty"`
Slug string `json:"slug,omitempty"`
}
+5 -4
View File
@@ -3,8 +3,9 @@
package models package models
type AdjustPlayerWalletRequest struct { type AdjustPlayerWalletRequest struct {
Amount int64 `json:"amount,omitempty"` Amount int64 `json:"amount,omitempty"`
CurrencyCode string `json:"currencyCode,omitempty"` CurrencyCode string `json:"currencyCode,omitempty"`
PlayerID string `json:"playerId,omitempty"` IdempotencyKey string `json:"idempotencyKey,omitempty"`
Reason string `json:"reason,omitempty"` PlayerID string `json:"playerId,omitempty"`
Reason string `json:"reason,omitempty"`
} }
+7
View File
@@ -0,0 +1,7 @@
// Code generated by apigen. DO NOT EDIT.
package models
type AdminGetProjectStorageResponse struct {
Item ProjectStorageItem `json:"item,omitempty"`
}
+15 -11
View File
@@ -5,15 +5,19 @@ package models
import "encoding/json" import "encoding/json"
type AdminPlayer struct { type AdminPlayer struct {
CreatedAt string `json:"createdAt,omitempty"` BanReason string `json:"banReason,omitempty"`
Data json.RawMessage `json:"data,omitempty"` BannedAt string `json:"bannedAt,omitempty"`
ID string `json:"id,omitempty"` BannedUntil string `json:"bannedUntil,omitempty"`
Language string `json:"language,omitempty"` CreatedAt string `json:"createdAt,omitempty"`
LastSeen string `json:"lastSeen,omitempty"` Data json.RawMessage `json:"data,omitempty"`
Nickname string `json:"nickname,omitempty"` DeletedAt string `json:"deletedAt,omitempty"`
PayerFlag bool `json:"payerFlag,omitempty"` ID string `json:"id,omitempty"`
ProjectID string `json:"projectId,omitempty"` Language string `json:"language,omitempty"`
Region string `json:"region,omitempty"` LastSeen string `json:"lastSeen,omitempty"`
StableID string `json:"stableId,omitempty"` Nickname string `json:"nickname,omitempty"`
UpdatedAt string `json:"updatedAt,omitempty"` PayerFlag bool `json:"payerFlag,omitempty"`
ProjectID string `json:"projectId,omitempty"`
Region string `json:"region,omitempty"`
StableID string `json:"stableId,omitempty"`
UpdatedAt string `json:"updatedAt,omitempty"`
} }
+11
View File
@@ -0,0 +1,11 @@
// Code generated by apigen. DO NOT EDIT.
package models
type AdminProjectStorageItem struct {
Data string `json:"data,omitempty"`
ExpiresAt string `json:"expiresAt,omitempty"`
ReadPermission string `json:"readPermission,omitempty"`
Type string `json:"type,omitempty"`
WritePermission string `json:"writePermission,omitempty"`
}
+9
View File
@@ -0,0 +1,9 @@
// Code generated by apigen. DO NOT EDIT.
package models
type BanPlayerRequest struct {
BannedUntil string `json:"bannedUntil,omitempty"`
IdempotencyKey string `json:"idempotencyKey,omitempty"`
Reason string `json:"reason,omitempty"`
}
+7
View File
@@ -0,0 +1,7 @@
// Code generated by apigen. DO NOT EDIT.
package models
type DeletePlayerRequest struct {
IdempotencyKey string `json:"idempotencyKey,omitempty"`
}
+8
View File
@@ -0,0 +1,8 @@
// Code generated by apigen. DO NOT EDIT.
package models
type GetProjectStorageResponse struct {
Items []ProjectStorageItem `json:"items,omitempty"`
NextCursor string `json:"nextCursor,omitempty"`
}
-8
View File
@@ -1,8 +0,0 @@
// Code generated by apigen. DO NOT EDIT.
package models
type ListUgcResponse struct {
Items []UgcSubmission `json:"items,omitempty"`
NextCursor string `json:"nextCursor,omitempty"`
}
+15
View File
@@ -0,0 +1,15 @@
// Code generated by apigen. DO NOT EDIT.
package models
type ProjectStorageItem struct {
Data string `json:"data,omitempty"`
ExpiresAt string `json:"expiresAt,omitempty"`
ID string `json:"id,omitempty"`
ReadPermission string `json:"readPermission,omitempty"`
Size int64 `json:"size,omitempty"`
Type string `json:"type,omitempty"`
UpdatedAt string `json:"updatedAt,omitempty"`
Version int64 `json:"version,omitempty"`
WritePermission string `json:"writePermission,omitempty"`
}
-9
View File
@@ -1,9 +0,0 @@
// Code generated by apigen. DO NOT EDIT.
package models
type ReviewUgcRequest struct {
ID string `json:"id,omitempty"`
ReviewedBy string `json:"reviewedBy,omitempty"`
Status string `json:"status,omitempty"`
}
-8
View File
@@ -1,8 +0,0 @@
// Code generated by apigen. DO NOT EDIT.
package models
type SubmittedBy struct {
UserID string `json:"userId,omitempty"`
Username string `json:"username,omitempty"`
}
-19
View File
@@ -1,19 +0,0 @@
// Code generated by apigen. DO NOT EDIT.
package models
import "encoding/json"
type UgcSubmission struct {
Description string `json:"description,omitempty"`
FileSize int64 `json:"fileSize,omitempty"`
FileURL string `json:"fileUrl,omitempty"`
ID string `json:"id,omitempty"`
Metadata json.RawMessage `json:"metadata,omitempty"`
Name string `json:"name,omitempty"`
ReviewedAt string `json:"reviewedAt,omitempty"`
ReviewedBy string `json:"reviewedBy,omitempty"`
Status string `json:"status,omitempty"`
SubmittedAt string `json:"submittedAt,omitempty"`
SubmittedBy SubmittedBy `json:"submittedBy,omitempty"`
}
+10
View File
@@ -0,0 +1,10 @@
// Code generated by apigen. DO NOT EDIT.
package models
import "encoding/json"
type UpdatePlayerRequest struct {
Data json.RawMessage `json:"data,omitempty"`
Nickname string `json:"nickname,omitempty"`
}
-10
View File
@@ -1,10 +0,0 @@
// Code generated by apigen. DO NOT EDIT.
package models
import "encoding/json"
type UpdateUgcMetadataRequest struct {
ID string `json:"id,omitempty"`
Metadata json.RawMessage `json:"metadata,omitempty"`
}
+8
View File
@@ -0,0 +1,8 @@
// Code generated by apigen. DO NOT EDIT.
package models
type UpsertPlayerStorageRequest struct {
Data string `json:"data,omitempty"`
ExpiresAt string `json:"expiresAt,omitempty"`
}
+7
View File
@@ -0,0 +1,7 @@
// Code generated by apigen. DO NOT EDIT.
package models
type UpsertProjectStorageRequest struct {
Items []AdminProjectStorageItem `json:"items,omitempty"`
}
+63
View File
@@ -2,9 +2,11 @@ package rudder
import ( import (
"context" "context"
"encoding/json"
"net/http" "net/http"
"net/url" "net/url"
"strconv" "strconv"
"time"
"hub.rudder.build/rudder/rudder-go-sdk/models" "hub.rudder.build/rudder/rudder-go-sdk/models"
) )
@@ -16,6 +18,7 @@ type PlayersService struct {
type ListPlayersParameters struct { type ListPlayersParameters struct {
Limit int Limit int
Offset int Offset int
Search string
} }
func (s *PlayersService) List(ctx context.Context, parameters ListPlayersParameters) (*models.ListPlayersResponse, error) { func (s *PlayersService) List(ctx context.Context, parameters ListPlayersParameters) (*models.ListPlayersResponse, error) {
@@ -26,6 +29,9 @@ func (s *PlayersService) List(ctx context.Context, parameters ListPlayersParamet
if parameters.Offset > 0 { if parameters.Offset > 0 {
query.Set("offset", strconv.Itoa(parameters.Offset)) query.Set("offset", strconv.Itoa(parameters.Offset))
} }
if parameters.Search != "" {
query.Set("search", parameters.Search)
}
var response models.ListPlayersResponse var response models.ListPlayersResponse
if err := s.transport.do(ctx, http.MethodGet, "/players/list", query, nil, &response); err != nil { if err := s.transport.do(ctx, http.MethodGet, "/players/list", query, nil, &response); err != nil {
@@ -41,3 +47,60 @@ func (s *PlayersService) Get(ctx context.Context, playerID string) (*models.Admi
} }
return &response, nil return &response, nil
} }
type UpdatePlayerParameters struct {
Nickname *string
Data json.RawMessage
}
func (s *PlayersService) Update(ctx context.Context, playerID string, parameters UpdatePlayerParameters) (*models.AdminPlayer, error) {
body := models.UpdatePlayerRequest{
Data: parameters.Data,
}
if parameters.Nickname != nil {
body.Nickname = *parameters.Nickname
}
var response models.AdminPlayer
if err := s.transport.do(ctx, http.MethodPatch, "/players/"+url.PathEscape(playerID), nil, body, &response); err != nil {
return nil, err
}
return &response, nil
}
type BanPlayerParameters struct {
Reason string
Until *time.Time
IdempotencyKey string
}
func (s *PlayersService) Ban(ctx context.Context, playerID string, parameters BanPlayerParameters) (*models.AdminPlayer, error) {
body := models.BanPlayerRequest{
Reason: parameters.Reason,
IdempotencyKey: parameters.IdempotencyKey,
}
if parameters.Until != nil {
body.BannedUntil = parameters.Until.Format(time.RFC3339)
}
var response models.AdminPlayer
if err := s.transport.do(ctx, http.MethodPost, "/players/"+url.PathEscape(playerID)+"/ban", nil, body, &response); err != nil {
return nil, err
}
return &response, nil
}
func (s *PlayersService) Unban(ctx context.Context, playerID string) (*models.AdminPlayer, error) {
var response models.AdminPlayer
if err := s.transport.do(ctx, http.MethodPost, "/players/"+url.PathEscape(playerID)+"/unban", nil, nil, &response); err != nil {
return nil, err
}
return &response, nil
}
func (s *PlayersService) Delete(ctx context.Context, playerID string, idempotencyKey string) error {
body := models.DeletePlayerRequest{
IdempotencyKey: idempotencyKey,
}
return s.transport.do(ctx, http.MethodDelete, "/players/"+url.PathEscape(playerID), nil, body, nil)
}
+62
View File
@@ -0,0 +1,62 @@
package rudder
import (
"context"
"net/http"
"net/url"
"strconv"
"hub.rudder.build/rudder/rudder-go-sdk/models"
)
type ProjectStorageService struct {
transport *transport
}
type ListProjectStorageParameters struct {
Limit int
Cursor string
Search string
}
func (s *ProjectStorageService) List(ctx context.Context, parameters ListProjectStorageParameters) (*models.GetProjectStorageResponse, error) {
query := url.Values{}
if parameters.Limit > 0 {
query.Set("limit", strconv.Itoa(parameters.Limit))
}
if parameters.Cursor != "" {
query.Set("cursor", parameters.Cursor)
}
if parameters.Search != "" {
query.Set("search", parameters.Search)
}
var response models.GetProjectStorageResponse
if err := s.transport.do(ctx, http.MethodGet, "/project-storage", query, nil, &response); err != nil {
return nil, err
}
return &response, nil
}
func (s *ProjectStorageService) Get(ctx context.Context, itemType string) (*models.ProjectStorageItem, error) {
var response models.AdminGetProjectStorageResponse
if err := s.transport.do(ctx, http.MethodGet, "/project-storage/"+url.PathEscape(itemType), nil, nil, &response); err != nil {
return nil, err
}
return &response.Item, nil
}
type UpsertProjectStorageParameters struct {
Items []models.AdminProjectStorageItem
}
func (s *ProjectStorageService) Upsert(ctx context.Context, parameters UpsertProjectStorageParameters) error {
body := models.UpsertProjectStorageRequest{
Items: parameters.Items,
}
return s.transport.do(ctx, http.MethodPut, "/project-storage", nil, body, nil)
}
func (s *ProjectStorageService) Delete(ctx context.Context, itemType string) error {
return s.transport.do(ctx, http.MethodDelete, "/project-storage/"+url.PathEscape(itemType), nil, nil, nil)
}
+46
View File
@@ -0,0 +1,46 @@
package rudder
import (
"context"
"net/http"
"net/url"
"time"
"hub.rudder.build/rudder/rudder-go-sdk/models"
)
type StorageService struct {
transport *transport
}
func (s *StorageService) Get(ctx context.Context, playerID string, storageType string) (*models.PlayerStorage, error) {
var response models.PlayerStorage
if err := s.transport.do(ctx, http.MethodGet, "/players/"+url.PathEscape(playerID)+"/storage/"+url.PathEscape(storageType), nil, nil, &response); err != nil {
return nil, err
}
return &response, nil
}
type UpsertStorageParameters struct {
Data string
ExpiresAt *time.Time
}
func (s *StorageService) Upsert(ctx context.Context, playerID string, storageType string, parameters UpsertStorageParameters) (*models.PlayerStorage, error) {
body := models.UpsertPlayerStorageRequest{
Data: parameters.Data,
}
if parameters.ExpiresAt != nil {
body.ExpiresAt = parameters.ExpiresAt.Format(time.RFC3339)
}
var response models.PlayerStorage
if err := s.transport.do(ctx, http.MethodPut, "/players/"+url.PathEscape(playerID)+"/storage/"+url.PathEscape(storageType), nil, body, &response); err != nil {
return nil, err
}
return &response, nil
}
func (s *StorageService) Delete(ctx context.Context, playerID string, storageType string) error {
return s.transport.do(ctx, http.MethodDelete, "/players/"+url.PathEscape(playerID)+"/storage/"+url.PathEscape(storageType), nil, nil, nil)
}
+1 -2
View File
@@ -14,12 +14,11 @@ import (
type transport struct { type transport struct {
baseURL string baseURL string
apiKey string apiKey string
projectID string
httpClient *http.Client httpClient *http.Client
} }
func (t *transport) do(ctx context.Context, method, path string, query url.Values, body any, out any) error { func (t *transport) do(ctx context.Context, method, path string, query url.Values, body any, out any) error {
endpoint := strings.TrimSuffix(t.baseURL, "/") + "/game/v1/projects/" + t.projectID + path endpoint := strings.TrimSuffix(t.baseURL, "/") + "/game/v1" + path
if len(query) > 0 { if len(query) > 0 {
endpoint += "?" + query.Encode() endpoint += "?" + query.Encode()
} }
-72
View File
@@ -1,72 +0,0 @@
package rudder
import (
"context"
"encoding/json"
"net/http"
"net/url"
"strconv"
"hub.rudder.build/rudder/rudder-go-sdk/models"
)
type UgcService struct {
transport *transport
}
type ListUgcParameters struct {
Status string
Limit int
Cursor string
}
func (s *UgcService) List(ctx context.Context, parameters ListUgcParameters) (*models.ListUgcResponse, error) {
query := url.Values{}
if parameters.Status != "" {
query.Set("status", parameters.Status)
}
if parameters.Limit > 0 {
query.Set("limit", strconv.Itoa(parameters.Limit))
}
if parameters.Cursor != "" {
query.Set("cursor", parameters.Cursor)
}
var response models.ListUgcResponse
if err := s.transport.do(ctx, http.MethodGet, "/ugc", query, nil, &response); err != nil {
return nil, err
}
return &response, nil
}
func (s *UgcService) UpdateMetadata(ctx context.Context, id string, metadata json.RawMessage) (*models.UgcSubmission, error) {
body := models.UpdateUgcMetadataRequest{
ID: id,
Metadata: metadata,
}
var response models.UgcSubmission
if err := s.transport.do(ctx, http.MethodPatch, "/ugc/"+url.PathEscape(id)+"/metadata", nil, body, &response); err != nil {
return nil, err
}
return &response, nil
}
type ReviewUgcParameters struct {
Status string
ReviewedBy string
}
func (s *UgcService) Review(ctx context.Context, id string, parameters ReviewUgcParameters) (*models.UgcSubmission, error) {
body := models.ReviewUgcRequest{
ID: id,
Status: parameters.Status,
ReviewedBy: parameters.ReviewedBy,
}
var response models.UgcSubmission
if err := s.transport.do(ctx, http.MethodPost, "/ugc/"+url.PathEscape(id)+"/review", nil, body, &response); err != nil {
return nil, err
}
return &response, nil
}
+9 -7
View File
@@ -13,17 +13,19 @@ type WalletService struct {
} }
type AdjustWalletParameters struct { type AdjustWalletParameters struct {
CurrencyCode string CurrencyCode string
Amount int64 Amount int64
Reason string Reason string
IdempotencyKey string
} }
func (s *WalletService) Adjust(ctx context.Context, playerID string, parameters AdjustWalletParameters) (*models.WalletDetails, error) { func (s *WalletService) Adjust(ctx context.Context, playerID string, parameters AdjustWalletParameters) (*models.WalletDetails, error) {
body := models.AdjustPlayerWalletRequest{ body := models.AdjustPlayerWalletRequest{
PlayerID: playerID, PlayerID: playerID,
CurrencyCode: parameters.CurrencyCode, CurrencyCode: parameters.CurrencyCode,
Amount: parameters.Amount, Amount: parameters.Amount,
Reason: parameters.Reason, Reason: parameters.Reason,
IdempotencyKey: parameters.IdempotencyKey,
} }
var response models.WalletDetails var response models.WalletDetails