cbb2133991
Users get Remnawave subscription via /config or inline button; TRIAL_USER_DAYS and panel lookup by Telegram ID. Co-authored-by: Cursor <cursoragent@cursor.com>
165 lines
4.1 KiB
Go
165 lines
4.1 KiB
Go
package remnawave
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"time"
|
|
)
|
|
|
|
type CreateUserInput struct {
|
|
Username string
|
|
ExpireAt time.Time
|
|
TelegramID *int64
|
|
ExternalSquadUUID *string
|
|
ActiveInternalSquads []string
|
|
TrafficLimitBytes *int64
|
|
Description string
|
|
}
|
|
|
|
type PanelUser struct {
|
|
UUID string
|
|
Username string
|
|
ShortUUID string
|
|
Status string
|
|
ExpireAt time.Time
|
|
SubscriptionURL string
|
|
}
|
|
|
|
func (c *Client) GetUserByUsername(ctx context.Context, username string) (*PanelUser, error) {
|
|
path := fmt.Sprintf("/api/users/by-username/%s", username)
|
|
resp, body, err := c.get(ctx, path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if resp.StatusCode == http.StatusNotFound {
|
|
return nil, nil
|
|
}
|
|
if resp.StatusCode != http.StatusOK {
|
|
return nil, apiError(resp.StatusCode, body)
|
|
}
|
|
return parsePanelUser(body), nil
|
|
}
|
|
|
|
func (c *Client) GetUserByTelegramID(ctx context.Context, telegramID int64) (*PanelUser, error) {
|
|
path := fmt.Sprintf("/api/users/by-telegram-id/%d", telegramID)
|
|
resp, body, err := c.get(ctx, path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if resp.StatusCode == http.StatusNotFound {
|
|
return nil, nil
|
|
}
|
|
if resp.StatusCode != http.StatusOK {
|
|
return nil, apiError(resp.StatusCode, body)
|
|
}
|
|
u := parsePanelUser(body)
|
|
if u == nil || u.UUID == "" {
|
|
return nil, nil
|
|
}
|
|
return u, nil
|
|
}
|
|
|
|
func (c *Client) CreateUser(ctx context.Context, in CreateUserInput) (*PanelUser, error) {
|
|
payload := map[string]any{
|
|
"username": in.Username,
|
|
"expireAt": in.ExpireAt.UTC().Format(time.RFC3339Nano),
|
|
"status": "ACTIVE",
|
|
}
|
|
if in.TelegramID != nil {
|
|
payload["telegramId"] = *in.TelegramID
|
|
}
|
|
if in.ExternalSquadUUID != nil && *in.ExternalSquadUUID != "" {
|
|
payload["externalSquadUuid"] = *in.ExternalSquadUUID
|
|
}
|
|
if len(in.ActiveInternalSquads) > 0 {
|
|
payload["activeInternalSquads"] = in.ActiveInternalSquads
|
|
}
|
|
if in.TrafficLimitBytes != nil {
|
|
payload["trafficLimitBytes"] = *in.TrafficLimitBytes
|
|
}
|
|
if in.Description != "" {
|
|
payload["description"] = in.Description
|
|
}
|
|
|
|
resp, body, err := c.post(ctx, "/api/users", payload)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
|
|
return nil, apiError(resp.StatusCode, body)
|
|
}
|
|
return parsePanelUser(body), nil
|
|
}
|
|
|
|
type AssignSquadsInput struct {
|
|
UUID string
|
|
Username string
|
|
ExternalSquadUUID *string
|
|
ActiveInternalSquads []string
|
|
}
|
|
|
|
func (c *Client) AssignSquads(ctx context.Context, in AssignSquadsInput) (*PanelUser, error) {
|
|
if in.UUID == "" && in.Username == "" {
|
|
return nil, fmt.Errorf("нужен uuid или username")
|
|
}
|
|
payload := map[string]any{}
|
|
if in.UUID != "" {
|
|
payload["uuid"] = in.UUID
|
|
} else {
|
|
payload["username"] = in.Username
|
|
}
|
|
if in.ExternalSquadUUID != nil {
|
|
payload["externalSquadUuid"] = in.ExternalSquadUUID
|
|
}
|
|
if in.ActiveInternalSquads != nil {
|
|
payload["activeInternalSquads"] = in.ActiveInternalSquads
|
|
}
|
|
|
|
resp, body, err := c.patch(ctx, "/api/users", payload)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if resp.StatusCode != http.StatusOK {
|
|
return nil, apiError(resp.StatusCode, body)
|
|
}
|
|
return parsePanelUser(body), nil
|
|
}
|
|
|
|
func parsePanelUser(body []byte) *PanelUser {
|
|
var wrap struct {
|
|
Response map[string]json.RawMessage `json:"response"`
|
|
}
|
|
if json.Unmarshal(body, &wrap) != nil || wrap.Response == nil {
|
|
return nil
|
|
}
|
|
u := &PanelUser{}
|
|
if raw, ok := wrap.Response["uuid"]; ok {
|
|
_ = json.Unmarshal(raw, &u.UUID)
|
|
}
|
|
if raw, ok := wrap.Response["username"]; ok {
|
|
_ = json.Unmarshal(raw, &u.Username)
|
|
}
|
|
if raw, ok := wrap.Response["shortUuid"]; ok {
|
|
_ = json.Unmarshal(raw, &u.ShortUUID)
|
|
}
|
|
if raw, ok := wrap.Response["status"]; ok {
|
|
_ = json.Unmarshal(raw, &u.Status)
|
|
}
|
|
if raw, ok := wrap.Response["expireAt"]; ok {
|
|
var s string
|
|
if json.Unmarshal(raw, &s) == nil {
|
|
if t, err := time.Parse(time.RFC3339Nano, s); err == nil {
|
|
u.ExpireAt = t
|
|
} else if t, err := time.Parse(time.RFC3339, s); err == nil {
|
|
u.ExpireAt = t
|
|
}
|
|
}
|
|
}
|
|
if raw, ok := wrap.Response["subscriptionUrl"]; ok {
|
|
_ = json.Unmarshal(raw, &u.SubscriptionURL)
|
|
}
|
|
return u
|
|
}
|