diff --git a/go-server/.env.example b/go-server/.env.example index db00d7b..773af2b 100644 --- a/go-server/.env.example +++ b/go-server/.env.example @@ -20,11 +20,24 @@ HUGGING_FACE_TOKEN="" # Token for the hugging face service # CHATGPT OPENAI Configurations OPENAI_API_KEY = "" # Secret API key -# LEMON SQUEEZY Config -LEMON_SQUEEZY_API_URL="" -LEMON_SQUEEZY_API_KEY="" -LEMON_SQUEEZY_STORE_ID="" -LEMON_SQUEEZY_WEBHOOK_PASSWORD="" +# LEMON SQUEEZY Config Global +LEMON_SQUEEZY_API_URL="https://api.lemonsqueezy.com/v1" + +# LEMON SQUEEZY Config Test +LEMON_SQUEEZY_TEST_API_KEY="" +LEMON_SQUEEZY_TEST_STORE_ID="" +LEMON_SQUEEZY_TEST_WEBHOOK_PASSWORD="" +LEMON_SQUEEZY_TEST_FREE_PLAN_DATA="" +LEMON_SQUEEZY_TEST_HOBBY_PLAN_DATA="" +LEMON_SQUEEZY_TEST_POPULAR_PLAN_DATA="" + +# LEMON SQUEEZY Config Production +LEMON_SQUEEZY_MAIN_API_KEY="" +LEMON_SQUEEZY_MAIN_STORE_ID="" +LEMON_SQUEEZY_MAIN_WEBHOOK_PASSWORD="" +LEMON_SQUEEZY_MAIN_FREE_PLAN_DATA="" +LEMON_SQUEEZY_MAIN_HOBBY_PLAN_DATA="" +LEMON_SQUEEZY_MAIN_POPULAR_PLAN_DATA="" # FIREBASE SETUP DB_KEYS_DEVELOPMENT="" diff --git a/go-server/.gitignore b/go-server/.gitignore index e1618a5..c10ab9e 100644 --- a/go-server/.gitignore +++ b/go-server/.gitignore @@ -44,4 +44,7 @@ acme.json # VEGETA tests landing.json pre_analysis.json -target.list \ No newline at end of file +target.list + +# Commands +commands \ No newline at end of file diff --git a/go-server/config/main.go b/go-server/config/main.go index 6a59f9b..874c684 100644 --- a/go-server/config/main.go +++ b/go-server/config/main.go @@ -13,6 +13,8 @@ const ( DEFAULT_PAGE_SIZE = 10 MIN_PAGE_SIZE = 1 MAX_PAGE_SIZE = 50 + ENV_DEVELOPMENT = "development" + ENV_PRODUCTION = "production" ) // use godot package to load/read the .env file and diff --git a/go-server/database/billing.go b/go-server/database/billing.go index 2a3f15f..96f2fff 100644 --- a/go-server/database/billing.go +++ b/go-server/database/billing.go @@ -1,35 +1,154 @@ package database import ( - firebase "firebase.google.com/go" + "encoding/json" + "errors" + "fmt" + "gptube/config" + "gptube/models" + + "cloud.google.com/go/firestore" "google.golang.org/api/iterator" ) -func RetrieveSubscriptions(email string) (*[]map[string]interface{}, error) { - app, err := firebase.NewApp(Ctx, nil, Sa) +func GetSubscriptionPlans() (map[models.SubscriptionPlanSlug]*models.SubscriptionPlan, error) { + envMode := config.Config("ENV_MODE") + if envMode == config.ENV_DEVELOPMENT { + return getSubscriptionPlansDevelopment() + } else if envMode == config.ENV_PRODUCTION { + return getSubscriptionPlansProduction() + } + return nil, errors.New("no valid env mode in env vars") +} + +func getSubscriptionPlansDevelopment() (map[models.SubscriptionPlanSlug]*models.SubscriptionPlan, error) { + freePlan := models.SubscriptionPlan{} + err := json.Unmarshal( + []byte(config.Config("LEMON_SQUEEZY_TEST_FREE_PLAN_DATA")), + &freePlan, + ) if err != nil { return nil, err } - client, err := app.Firestore(Ctx) + hobbyPlan := models.SubscriptionPlan{} + err = json.Unmarshal( + []byte(config.Config("LEMON_SQUEEZY_TEST_HOBBY_PLAN_DATA")), + &hobbyPlan, + ) if err != nil { return nil, err } - defer client.Close() + popularPlan := models.SubscriptionPlan{} + err = json.Unmarshal( + []byte(config.Config("LEMON_SQUEEZY_TEST_POPULAR_PLAN_DATA")), + &popularPlan, + ) + if err != nil { + return nil, err + } + + subscriptionPlans := make(map[models.SubscriptionPlanSlug]*models.SubscriptionPlan) + subscriptionPlans[models.FREE] = &freePlan + subscriptionPlans[models.HOBBY] = &hobbyPlan + subscriptionPlans[models.POPULAR] = &popularPlan + return subscriptionPlans, nil +} + +func getSubscriptionPlansProduction() (map[models.SubscriptionPlanSlug]*models.SubscriptionPlan, error) { + freePlan := models.SubscriptionPlan{} + err := json.Unmarshal( + []byte(config.Config("LEMON_SQUEEZY_MAIN_FREE_PLAN_DATA")), + &freePlan, + ) + if err != nil { + return nil, err + } + + hobbyPlan := models.SubscriptionPlan{} + err = json.Unmarshal( + []byte(config.Config("LEMON_SQUEEZY_MAIN_HOBBY_PLAN_DATA")), + &hobbyPlan, + ) + if err != nil { + return nil, err + } + + popularPlan := models.SubscriptionPlan{} + err = json.Unmarshal( + []byte(config.Config("LEMON_SQUEEZY_MAIN_POPULAR_PLAN_DATA")), + &popularPlan, + ) + if err != nil { + return nil, err + } + + subscriptionPlans := make(map[models.SubscriptionPlanSlug]*models.SubscriptionPlan) + subscriptionPlans[models.FREE] = &freePlan + subscriptionPlans[models.HOBBY] = &hobbyPlan + subscriptionPlans[models.POPULAR] = &popularPlan + return subscriptionPlans, nil +} - subscriptionsQuery := client.Collection("subscriptions").Where("user_email", "==", email) - subscriptions := subscriptionsQuery.Documents(Ctx) - results := make([]map[string]interface{}, 0) +func GetAllSubscriptions(userId string) ([]models.Subscription, error) { + client, err := GetClient() + if err != nil { + return nil, err + } + + defer client.Close() + userDoc := client.Collection(USERS_COLLECTION).Doc(userId) + iter := userDoc.Collection(SUBSCRIPTIONS_COLLECTION). + OrderBy("subscription_id", firestore.Desc).Documents(Ctx) + results := make([]models.Subscription, 0) for { - doc, err := subscriptions.Next() + doc, err := iter.Next() if err == iterator.Done { break } if err != nil { return nil, err } - results = append(results, doc.Data()) + subscription := models.Subscription{} + err = doc.DataTo(&subscription) + if err != nil { + fmt.Println(err.Error()) + return nil, err + } + results = append(results, subscription) + } + return results, nil +} + +func CreateSubscription(userId string, subscription *models.Subscription) error { + client, err := GetClient() + if err != nil { + return err + } + defer client.Close() + + userDoc := client.Collection(USERS_COLLECTION).Doc(userId) + subscriptionDoc := userDoc.Collection(SUBSCRIPTIONS_COLLECTION).Doc(subscription.SubscriptionId) + _, err = subscriptionDoc.Set(Ctx, subscription) + if err != nil { + return fmt.Errorf("error while creating subscription: %s", err) + } + return nil +} + +func UpdateSubscription(userId string, subscription *models.Subscription) error { + client, err := GetClient() + if err != nil { + return err + } + defer client.Close() + + userDoc := client.Collection(USERS_COLLECTION).Doc(userId) + subscriptionDoc := userDoc.Collection(SUBSCRIPTIONS_COLLECTION).Doc(subscription.SubscriptionId) + _, err = subscriptionDoc.Set(Ctx, subscription) + if err != nil { + return fmt.Errorf("error while creating subscription: %s", err) } - return &results, nil + return nil } diff --git a/go-server/database/main.go b/go-server/database/main.go index 718535a..3be1325 100644 --- a/go-server/database/main.go +++ b/go-server/database/main.go @@ -8,6 +8,17 @@ import ( "google.golang.org/api/option" ) +const ( + USERS_COLLECTION = "Users" + // Billing collection names + SUBSCRIPTION_PLANS_COLLECTION = "SubscriptionPlans" + SUBSCRIPTIONS_COLLECTION = "Subscriptions" + // Youtube Analyses Collections + YOUTUBE_ANALYSES_COLLECTION = "YoutubeAnalyses" + YOUTUBE_NEGATIVE_COMMENTS_COLLECTION = "NegativeComments" + YOUTUBE_VIDEOS_COLLECTION = "Videos" +) + var Ctx context.Context var Sa option.ClientOption diff --git a/go-server/docs/docs.go b/go-server/docs/docs.go index 2e1185c..cc93ee5 100644 --- a/go-server/docs/docs.go +++ b/go-server/docs/docs.go @@ -340,24 +340,894 @@ const docTemplate = `{ } } } + }, + "/billing/cancel-subscription": { + "get": { + "description": "An endpoint to cancel a subscription", + "produces": [ + "application/json" + ], + "summary": "Cancel a subscription", + "parameters": [ + { + "type": "string", + "description": "the subscription id", + "name": "subscription_id", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/fiber.Error" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/fiber.Error" + } + } + } + } + }, + "/billing/checkout": { + "get": { + "description": "An endpoint to retrieve the URL for a subscription plan sending\nthe account email as well.", + "produces": [ + "application/json" + ], + "summary": "Get the checkout URL for a subscription plan", + "parameters": [ + { + "type": "string", + "description": "the variant id of the subscription plan", + "name": "variant_id", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "the user id", + "name": "user_id", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/lemonsqueezy.ApiResponse-lemonsqueezy_CheckoutAttributes-lemonsqueezy_ApiResponseRelationshipsDiscount" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/fiber.Error" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/fiber.Error" + } + } + } + } + }, + "/billing/invoices": { + "get": { + "description": "An endpoint to retrieve the invoices from a user's subscription", + "produces": [ + "application/json" + ], + "summary": "Get the latest Invoices from a subscription", + "parameters": [ + { + "type": "string", + "description": "the subscription id", + "name": "subscription_id", + "in": "query", + "required": true + }, + { + "type": "integer", + "description": "the queried page", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "page size for the results (default: 10, max: 50)", + "name": "page_size", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseList-lemonsqueezy_SubscriptionInvoiceAttributes-lemonsqueezy_ApiResponseRelationshipsSubscriptionInvoice" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/fiber.Error" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/fiber.Error" + } + } + } + } + }, + "/billing/resume-subscription": { + "get": { + "description": "An endpoint to resume a cancelled subscription", + "produces": [ + "application/json" + ], + "summary": "Resume a subscription", + "parameters": [ + { + "type": "string", + "description": "the subscription id", + "name": "subscription_id", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/fiber.Error" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/fiber.Error" + } + } + } + } + }, + "/billing/subscription-plans": { + "get": { + "description": "An endpoint to retrieve the subscription plan offered by GPTube with its price, features, etc.", + "produces": [ + "application/json" + ], + "summary": "Get the subscription plans offered by GPTube", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.SubscriptionPlan" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/fiber.Error" + } + } + } + } + }, + "/billing/subscriptions": { + "get": { + "description": "An endpoint to retrieve all the subscriptions belonging to an account", + "produces": [ + "application/json" + ], + "summary": "Get the subscribed subscriptions of an account", + "parameters": [ + { + "type": "string", + "description": "the user id", + "name": "user_id", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Subscription" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/fiber.Error" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/fiber.Error" + } + } + } + } + }, + "/billing/update-payment-method": { + "get": { + "description": "An endpoint to retrieve the URL to update the payment method for a subscription", + "produces": [ + "application/json" + ], + "summary": "Get the update payment method URL for a subscription", + "parameters": [ + { + "type": "string", + "description": "the subscription id", + "name": "subscription_id", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/lemonsqueezy.ApiResponse-lemonsqueezy_Subscription-lemonsqueezy_ApiResponseRelationshipsSubscription" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/fiber.Error" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/fiber.Error" + } + } + } + } } }, "definitions": { "fiber.Error": { "type": "object", "properties": { - "code": { + "code": { + "type": "integer" + }, + "message": { + "type": "string" + } + } + }, + "handlers.helloApiMessage": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + }, + "lemonsqueezy.ApiResponse-lemonsqueezy_CheckoutAttributes-lemonsqueezy_ApiResponseRelationshipsDiscount": { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseData-lemonsqueezy_CheckoutAttributes-lemonsqueezy_ApiResponseRelationshipsDiscount" + }, + "jsonapi": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseJSONAPI" + }, + "links": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseSelfLink" + } + } + }, + "lemonsqueezy.ApiResponse-lemonsqueezy_Subscription-lemonsqueezy_ApiResponseRelationshipsSubscription": { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseData-lemonsqueezy_Subscription-lemonsqueezy_ApiResponseRelationshipsSubscription" + }, + "jsonapi": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseJSONAPI" + }, + "links": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseSelfLink" + } + } + }, + "lemonsqueezy.ApiResponseData-lemonsqueezy_CheckoutAttributes-lemonsqueezy_ApiResponseRelationshipsDiscount": { + "type": "object", + "properties": { + "attributes": { + "$ref": "#/definitions/lemonsqueezy.CheckoutAttributes" + }, + "id": { + "type": "string" + }, + "links": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseSelfLink" + }, + "relationships": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseRelationshipsDiscount" + }, + "type": { + "type": "string" + } + } + }, + "lemonsqueezy.ApiResponseData-lemonsqueezy_Subscription-lemonsqueezy_ApiResponseRelationshipsSubscription": { + "type": "object", + "properties": { + "attributes": { + "$ref": "#/definitions/lemonsqueezy.Subscription" + }, + "id": { + "type": "string" + }, + "links": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseSelfLink" + }, + "relationships": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseRelationshipsSubscription" + }, + "type": { + "type": "string" + } + } + }, + "lemonsqueezy.ApiResponseData-lemonsqueezy_SubscriptionInvoiceAttributes-lemonsqueezy_ApiResponseRelationshipsSubscriptionInvoice": { + "type": "object", + "properties": { + "attributes": { + "$ref": "#/definitions/lemonsqueezy.SubscriptionInvoiceAttributes" + }, + "id": { + "type": "string" + }, + "links": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseSelfLink" + }, + "relationships": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseRelationshipsSubscriptionInvoice" + }, + "type": { + "type": "string" + } + } + }, + "lemonsqueezy.ApiResponseJSONAPI": { + "type": "object", + "properties": { + "version": { + "type": "string" + } + } + }, + "lemonsqueezy.ApiResponseLink": { + "type": "object", + "properties": { + "related": { + "type": "string" + }, + "self": { + "type": "string" + } + } + }, + "lemonsqueezy.ApiResponseLinks": { + "type": "object", + "properties": { + "links": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseLink" + } + } + }, + "lemonsqueezy.ApiResponseList-lemonsqueezy_SubscriptionInvoiceAttributes-lemonsqueezy_ApiResponseRelationshipsSubscriptionInvoice": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseData-lemonsqueezy_SubscriptionInvoiceAttributes-lemonsqueezy_ApiResponseRelationshipsSubscriptionInvoice" + } + }, + "jsonapi": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseJSONAPI" + }, + "links": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseListLink" + }, + "meta": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseListMeta" + } + } + }, + "lemonsqueezy.ApiResponseListLink": { + "type": "object", + "properties": { + "first": { + "type": "string" + }, + "last": { + "type": "string" + }, + "next": { + "type": "string" + } + } + }, + "lemonsqueezy.ApiResponseListMeta": { + "type": "object", + "properties": { + "page": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseListMetaPage" + } + } + }, + "lemonsqueezy.ApiResponseListMetaPage": { + "type": "object", + "properties": { + "currentPage": { + "type": "integer" + }, + "from": { + "type": "integer" + }, + "lastPage": { + "type": "integer" + }, + "perPage": { + "type": "integer" + }, + "to": { + "type": "integer" + }, + "total": { + "type": "integer" + } + } + }, + "lemonsqueezy.ApiResponseRelationshipsDiscount": { + "type": "object", + "properties": { + "discount-redemptions": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseLinks" + }, + "store": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseLinks" + }, + "variants": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseLinks" + } + } + }, + "lemonsqueezy.ApiResponseRelationshipsSubscription": { + "type": "object", + "properties": { + "customer": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseLinks" + }, + "order": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseLinks" + }, + "order-item": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseLinks" + }, + "product": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseLinks" + }, + "store": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseLinks" + }, + "subscription-invoices": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseLinks" + }, + "subscription-items": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseLinks" + }, + "variant": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseLinks" + } + } + }, + "lemonsqueezy.ApiResponseRelationshipsSubscriptionInvoice": { + "type": "object", + "properties": { + "store": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseLinks" + }, + "subscription": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseLinks" + } + } + }, + "lemonsqueezy.ApiResponseSelfLink": { + "type": "object", + "properties": { + "self": { + "type": "string" + } + } + }, + "lemonsqueezy.BillingAddress": { + "type": "object", + "properties": { + "country": { + "type": "string" + }, + "zip": { + "type": "string" + } + } + }, + "lemonsqueezy.CheckoutAttributes": { + "type": "object", + "properties": { + "checkout_data": { + "$ref": "#/definitions/lemonsqueezy.CheckoutData" + }, + "checkout_options": { + "$ref": "#/definitions/lemonsqueezy.CheckoutOptions" + }, + "created_at": { + "type": "string" + }, + "custom_price": {}, + "expires_at": { + "type": "string" + }, + "product_options": { + "$ref": "#/definitions/lemonsqueezy.CheckoutProductOptions" + }, + "store_id": { + "type": "integer" + }, + "test_mode": { + "type": "boolean" + }, + "updated_at": { + "type": "string" + }, + "url": { + "type": "string" + }, + "variant_id": { + "type": "integer" + } + } + }, + "lemonsqueezy.CheckoutData": { + "type": "object", + "properties": { + "billing_address": { + "type": "array", + "items": { + "$ref": "#/definitions/lemonsqueezy.BillingAddress" + } + }, + "custom": { + "type": "object", + "additionalProperties": {} + }, + "discount_code": { + "type": "string" + }, + "email": { + "type": "string" + }, + "name": { + "type": "string" + }, + "tax_number": { + "type": "string" + } + } + }, + "lemonsqueezy.CheckoutOptions": { + "type": "object", + "properties": { + "button_color": { + "type": "string" + }, + "dark": { + "type": "boolean" + }, + "desc": { + "type": "boolean" + }, + "discount": { + "type": "boolean" + }, + "embed": { + "type": "boolean" + }, + "logo": { + "type": "boolean" + }, + "media": { + "type": "boolean" + }, + "subscription_preview": { + "type": "boolean" + } + } + }, + "lemonsqueezy.CheckoutProductOptions": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "enabled_variants": { + "type": "array", + "items": { + "type": "integer" + } + }, + "media": { + "type": "array", + "items": {} + }, + "name": { + "type": "string" + }, + "receipt_button_text": { + "type": "string" + }, + "receipt_link_url": { + "type": "string" + }, + "receipt_thank_you_note": { + "type": "string" + }, + "redirect_url": { + "type": "string" + } + } + }, + "lemonsqueezy.Subscription": { + "type": "object", + "properties": { + "billing_anchor": { "type": "integer" }, - "message": { + "cancelled": { + "type": "boolean" + }, + "card_brand": { + "type": "string" + }, + "card_last_four": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "customer_id": { + "type": "integer" + }, + "ends_at": { + "type": "string" + }, + "first_subscription_item": { + "$ref": "#/definitions/lemonsqueezy.SubscriptionItem" + }, + "order_id": { + "type": "integer" + }, + "order_item_id": { + "type": "integer" + }, + "pause": { + "$ref": "#/definitions/lemonsqueezy.SubscriptionPause" + }, + "product_id": { + "type": "integer" + }, + "product_name": { + "type": "string" + }, + "renews_at": { + "type": "string" + }, + "status": { + "type": "string" + }, + "status_formatted": { + "type": "string" + }, + "store_id": { + "type": "integer" + }, + "test_mode": { + "type": "boolean" + }, + "trial_ends_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "urls": { + "$ref": "#/definitions/lemonsqueezy.SubscriptionURLs" + }, + "user_email": { + "type": "string" + }, + "user_name": { + "type": "string" + }, + "variant_id": { + "type": "integer" + }, + "variant_name": { "type": "string" } } }, - "handlers.helloApiMessage": { + "lemonsqueezy.SubscriptionInvoiceAttributes": { "type": "object", "properties": { - "message": { + "billing_reason": { + "type": "string" + }, + "card_brand": { + "type": "string" + }, + "card_last_four": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "currency_rate": { + "type": "string" + }, + "discount_total": { + "type": "integer" + }, + "discount_total_formatted": { + "type": "string" + }, + "discount_total_usd": { + "type": "integer" + }, + "refunded": { + "type": "boolean" + }, + "refunded_at": { + "type": "string" + }, + "status": { + "type": "string" + }, + "status_formatted": { + "type": "string" + }, + "store_id": { + "type": "integer" + }, + "subscription_id": { + "type": "integer" + }, + "subtotal": { + "type": "integer" + }, + "subtotal_formatted": { + "type": "string" + }, + "subtotal_usd": { + "type": "integer" + }, + "tax": { + "type": "integer" + }, + "tax_formatted": { + "type": "string" + }, + "tax_usd": { + "type": "integer" + }, + "test_mode": { + "type": "boolean" + }, + "total": { + "type": "integer" + }, + "total_formatted": { + "type": "string" + }, + "total_usd": { + "type": "integer" + }, + "updated_at": { + "type": "string" + }, + "urls": { + "type": "object", + "properties": { + "invoice_url": { + "type": "string" + } + } + } + } + }, + "lemonsqueezy.SubscriptionItem": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "is_usage_based": { + "type": "boolean" + }, + "price_id": { + "type": "integer" + }, + "quantity": { + "type": "integer" + }, + "subscription_id": { + "type": "integer" + }, + "updated_at": { + "type": "string" + } + } + }, + "lemonsqueezy.SubscriptionPause": { + "type": "object", + "properties": { + "mode": { + "type": "string" + }, + "resumes_at": { + "type": "string" + } + } + }, + "lemonsqueezy.SubscriptionURLs": { + "type": "object", + "properties": { + "update_payment_method": { "type": "string" } } @@ -408,6 +1278,141 @@ const docTemplate = `{ } } }, + "models.Subscription": { + "type": "object", + "properties": { + "card_brand": { + "type": "string" + }, + "card_last_four": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "customer_id": { + "type": "integer" + }, + "ends_at": { + "type": "string" + }, + "order_id": { + "type": "integer" + }, + "product_id": { + "type": "integer" + }, + "product_name": { + "type": "string" + }, + "renews_at": { + "type": "string" + }, + "status": { + "type": "string" + }, + "status_formatted": { + "type": "string" + }, + "subscription_id": { + "description": "PK", + "type": "string" + }, + "subscription_plan_slug": { + "description": "FK SubscriptionPlan", + "allOf": [ + { + "$ref": "#/definitions/models.SubscriptionPlanSlug" + } + ] + }, + "trial_ends_at": { + "type": "string" + }, + "update_payment_method": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "user_email": { + "type": "string" + }, + "variant_id": { + "type": "integer" + } + } + }, + "models.SubscriptionPlan": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "description": { + "type": "string" + }, + "features": { + "type": "array", + "items": { + "type": "string" + } + }, + "href_monthly": { + "type": "string" + }, + "href_yearly": { + "type": "string" + }, + "id": { + "description": "PK", + "type": "string" + }, + "is_active": { + "type": "boolean" + }, + "most_popular": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "price_monthly": { + "type": "number" + }, + "price_yearly": { + "type": "number" + }, + "product_id": { + "type": "string" + }, + "slug": { + "$ref": "#/definitions/models.SubscriptionPlanSlug" + }, + "updated_at": { + "type": "string" + }, + "variants": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "models.SubscriptionPlanSlug": { + "type": "integer", + "enum": [ + 0, + 1, + 2 + ], + "x-enum-varnames": [ + "FREE", + "HOBBY", + "POPULAR" + ] + }, "models.YoutubeAnalysisLandingResults": { "type": "object", "properties": { diff --git a/go-server/docs/swagger.json b/go-server/docs/swagger.json index 22f7c6a..b7b6447 100644 --- a/go-server/docs/swagger.json +++ b/go-server/docs/swagger.json @@ -333,24 +333,894 @@ } } } + }, + "/billing/cancel-subscription": { + "get": { + "description": "An endpoint to cancel a subscription", + "produces": [ + "application/json" + ], + "summary": "Cancel a subscription", + "parameters": [ + { + "type": "string", + "description": "the subscription id", + "name": "subscription_id", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/fiber.Error" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/fiber.Error" + } + } + } + } + }, + "/billing/checkout": { + "get": { + "description": "An endpoint to retrieve the URL for a subscription plan sending\nthe account email as well.", + "produces": [ + "application/json" + ], + "summary": "Get the checkout URL for a subscription plan", + "parameters": [ + { + "type": "string", + "description": "the variant id of the subscription plan", + "name": "variant_id", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "the user id", + "name": "user_id", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/lemonsqueezy.ApiResponse-lemonsqueezy_CheckoutAttributes-lemonsqueezy_ApiResponseRelationshipsDiscount" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/fiber.Error" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/fiber.Error" + } + } + } + } + }, + "/billing/invoices": { + "get": { + "description": "An endpoint to retrieve the invoices from a user's subscription", + "produces": [ + "application/json" + ], + "summary": "Get the latest Invoices from a subscription", + "parameters": [ + { + "type": "string", + "description": "the subscription id", + "name": "subscription_id", + "in": "query", + "required": true + }, + { + "type": "integer", + "description": "the queried page", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "page size for the results (default: 10, max: 50)", + "name": "page_size", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseList-lemonsqueezy_SubscriptionInvoiceAttributes-lemonsqueezy_ApiResponseRelationshipsSubscriptionInvoice" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/fiber.Error" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/fiber.Error" + } + } + } + } + }, + "/billing/resume-subscription": { + "get": { + "description": "An endpoint to resume a cancelled subscription", + "produces": [ + "application/json" + ], + "summary": "Resume a subscription", + "parameters": [ + { + "type": "string", + "description": "the subscription id", + "name": "subscription_id", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/fiber.Error" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/fiber.Error" + } + } + } + } + }, + "/billing/subscription-plans": { + "get": { + "description": "An endpoint to retrieve the subscription plan offered by GPTube with its price, features, etc.", + "produces": [ + "application/json" + ], + "summary": "Get the subscription plans offered by GPTube", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.SubscriptionPlan" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/fiber.Error" + } + } + } + } + }, + "/billing/subscriptions": { + "get": { + "description": "An endpoint to retrieve all the subscriptions belonging to an account", + "produces": [ + "application/json" + ], + "summary": "Get the subscribed subscriptions of an account", + "parameters": [ + { + "type": "string", + "description": "the user id", + "name": "user_id", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Subscription" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/fiber.Error" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/fiber.Error" + } + } + } + } + }, + "/billing/update-payment-method": { + "get": { + "description": "An endpoint to retrieve the URL to update the payment method for a subscription", + "produces": [ + "application/json" + ], + "summary": "Get the update payment method URL for a subscription", + "parameters": [ + { + "type": "string", + "description": "the subscription id", + "name": "subscription_id", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/lemonsqueezy.ApiResponse-lemonsqueezy_Subscription-lemonsqueezy_ApiResponseRelationshipsSubscription" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/fiber.Error" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/fiber.Error" + } + } + } + } } }, "definitions": { "fiber.Error": { "type": "object", "properties": { - "code": { + "code": { + "type": "integer" + }, + "message": { + "type": "string" + } + } + }, + "handlers.helloApiMessage": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + }, + "lemonsqueezy.ApiResponse-lemonsqueezy_CheckoutAttributes-lemonsqueezy_ApiResponseRelationshipsDiscount": { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseData-lemonsqueezy_CheckoutAttributes-lemonsqueezy_ApiResponseRelationshipsDiscount" + }, + "jsonapi": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseJSONAPI" + }, + "links": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseSelfLink" + } + } + }, + "lemonsqueezy.ApiResponse-lemonsqueezy_Subscription-lemonsqueezy_ApiResponseRelationshipsSubscription": { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseData-lemonsqueezy_Subscription-lemonsqueezy_ApiResponseRelationshipsSubscription" + }, + "jsonapi": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseJSONAPI" + }, + "links": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseSelfLink" + } + } + }, + "lemonsqueezy.ApiResponseData-lemonsqueezy_CheckoutAttributes-lemonsqueezy_ApiResponseRelationshipsDiscount": { + "type": "object", + "properties": { + "attributes": { + "$ref": "#/definitions/lemonsqueezy.CheckoutAttributes" + }, + "id": { + "type": "string" + }, + "links": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseSelfLink" + }, + "relationships": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseRelationshipsDiscount" + }, + "type": { + "type": "string" + } + } + }, + "lemonsqueezy.ApiResponseData-lemonsqueezy_Subscription-lemonsqueezy_ApiResponseRelationshipsSubscription": { + "type": "object", + "properties": { + "attributes": { + "$ref": "#/definitions/lemonsqueezy.Subscription" + }, + "id": { + "type": "string" + }, + "links": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseSelfLink" + }, + "relationships": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseRelationshipsSubscription" + }, + "type": { + "type": "string" + } + } + }, + "lemonsqueezy.ApiResponseData-lemonsqueezy_SubscriptionInvoiceAttributes-lemonsqueezy_ApiResponseRelationshipsSubscriptionInvoice": { + "type": "object", + "properties": { + "attributes": { + "$ref": "#/definitions/lemonsqueezy.SubscriptionInvoiceAttributes" + }, + "id": { + "type": "string" + }, + "links": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseSelfLink" + }, + "relationships": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseRelationshipsSubscriptionInvoice" + }, + "type": { + "type": "string" + } + } + }, + "lemonsqueezy.ApiResponseJSONAPI": { + "type": "object", + "properties": { + "version": { + "type": "string" + } + } + }, + "lemonsqueezy.ApiResponseLink": { + "type": "object", + "properties": { + "related": { + "type": "string" + }, + "self": { + "type": "string" + } + } + }, + "lemonsqueezy.ApiResponseLinks": { + "type": "object", + "properties": { + "links": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseLink" + } + } + }, + "lemonsqueezy.ApiResponseList-lemonsqueezy_SubscriptionInvoiceAttributes-lemonsqueezy_ApiResponseRelationshipsSubscriptionInvoice": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseData-lemonsqueezy_SubscriptionInvoiceAttributes-lemonsqueezy_ApiResponseRelationshipsSubscriptionInvoice" + } + }, + "jsonapi": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseJSONAPI" + }, + "links": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseListLink" + }, + "meta": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseListMeta" + } + } + }, + "lemonsqueezy.ApiResponseListLink": { + "type": "object", + "properties": { + "first": { + "type": "string" + }, + "last": { + "type": "string" + }, + "next": { + "type": "string" + } + } + }, + "lemonsqueezy.ApiResponseListMeta": { + "type": "object", + "properties": { + "page": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseListMetaPage" + } + } + }, + "lemonsqueezy.ApiResponseListMetaPage": { + "type": "object", + "properties": { + "currentPage": { + "type": "integer" + }, + "from": { + "type": "integer" + }, + "lastPage": { + "type": "integer" + }, + "perPage": { + "type": "integer" + }, + "to": { + "type": "integer" + }, + "total": { + "type": "integer" + } + } + }, + "lemonsqueezy.ApiResponseRelationshipsDiscount": { + "type": "object", + "properties": { + "discount-redemptions": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseLinks" + }, + "store": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseLinks" + }, + "variants": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseLinks" + } + } + }, + "lemonsqueezy.ApiResponseRelationshipsSubscription": { + "type": "object", + "properties": { + "customer": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseLinks" + }, + "order": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseLinks" + }, + "order-item": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseLinks" + }, + "product": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseLinks" + }, + "store": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseLinks" + }, + "subscription-invoices": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseLinks" + }, + "subscription-items": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseLinks" + }, + "variant": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseLinks" + } + } + }, + "lemonsqueezy.ApiResponseRelationshipsSubscriptionInvoice": { + "type": "object", + "properties": { + "store": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseLinks" + }, + "subscription": { + "$ref": "#/definitions/lemonsqueezy.ApiResponseLinks" + } + } + }, + "lemonsqueezy.ApiResponseSelfLink": { + "type": "object", + "properties": { + "self": { + "type": "string" + } + } + }, + "lemonsqueezy.BillingAddress": { + "type": "object", + "properties": { + "country": { + "type": "string" + }, + "zip": { + "type": "string" + } + } + }, + "lemonsqueezy.CheckoutAttributes": { + "type": "object", + "properties": { + "checkout_data": { + "$ref": "#/definitions/lemonsqueezy.CheckoutData" + }, + "checkout_options": { + "$ref": "#/definitions/lemonsqueezy.CheckoutOptions" + }, + "created_at": { + "type": "string" + }, + "custom_price": {}, + "expires_at": { + "type": "string" + }, + "product_options": { + "$ref": "#/definitions/lemonsqueezy.CheckoutProductOptions" + }, + "store_id": { + "type": "integer" + }, + "test_mode": { + "type": "boolean" + }, + "updated_at": { + "type": "string" + }, + "url": { + "type": "string" + }, + "variant_id": { + "type": "integer" + } + } + }, + "lemonsqueezy.CheckoutData": { + "type": "object", + "properties": { + "billing_address": { + "type": "array", + "items": { + "$ref": "#/definitions/lemonsqueezy.BillingAddress" + } + }, + "custom": { + "type": "object", + "additionalProperties": {} + }, + "discount_code": { + "type": "string" + }, + "email": { + "type": "string" + }, + "name": { + "type": "string" + }, + "tax_number": { + "type": "string" + } + } + }, + "lemonsqueezy.CheckoutOptions": { + "type": "object", + "properties": { + "button_color": { + "type": "string" + }, + "dark": { + "type": "boolean" + }, + "desc": { + "type": "boolean" + }, + "discount": { + "type": "boolean" + }, + "embed": { + "type": "boolean" + }, + "logo": { + "type": "boolean" + }, + "media": { + "type": "boolean" + }, + "subscription_preview": { + "type": "boolean" + } + } + }, + "lemonsqueezy.CheckoutProductOptions": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "enabled_variants": { + "type": "array", + "items": { + "type": "integer" + } + }, + "media": { + "type": "array", + "items": {} + }, + "name": { + "type": "string" + }, + "receipt_button_text": { + "type": "string" + }, + "receipt_link_url": { + "type": "string" + }, + "receipt_thank_you_note": { + "type": "string" + }, + "redirect_url": { + "type": "string" + } + } + }, + "lemonsqueezy.Subscription": { + "type": "object", + "properties": { + "billing_anchor": { "type": "integer" }, - "message": { + "cancelled": { + "type": "boolean" + }, + "card_brand": { + "type": "string" + }, + "card_last_four": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "customer_id": { + "type": "integer" + }, + "ends_at": { + "type": "string" + }, + "first_subscription_item": { + "$ref": "#/definitions/lemonsqueezy.SubscriptionItem" + }, + "order_id": { + "type": "integer" + }, + "order_item_id": { + "type": "integer" + }, + "pause": { + "$ref": "#/definitions/lemonsqueezy.SubscriptionPause" + }, + "product_id": { + "type": "integer" + }, + "product_name": { + "type": "string" + }, + "renews_at": { + "type": "string" + }, + "status": { + "type": "string" + }, + "status_formatted": { + "type": "string" + }, + "store_id": { + "type": "integer" + }, + "test_mode": { + "type": "boolean" + }, + "trial_ends_at": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "urls": { + "$ref": "#/definitions/lemonsqueezy.SubscriptionURLs" + }, + "user_email": { + "type": "string" + }, + "user_name": { + "type": "string" + }, + "variant_id": { + "type": "integer" + }, + "variant_name": { "type": "string" } } }, - "handlers.helloApiMessage": { + "lemonsqueezy.SubscriptionInvoiceAttributes": { "type": "object", "properties": { - "message": { + "billing_reason": { + "type": "string" + }, + "card_brand": { + "type": "string" + }, + "card_last_four": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "currency_rate": { + "type": "string" + }, + "discount_total": { + "type": "integer" + }, + "discount_total_formatted": { + "type": "string" + }, + "discount_total_usd": { + "type": "integer" + }, + "refunded": { + "type": "boolean" + }, + "refunded_at": { + "type": "string" + }, + "status": { + "type": "string" + }, + "status_formatted": { + "type": "string" + }, + "store_id": { + "type": "integer" + }, + "subscription_id": { + "type": "integer" + }, + "subtotal": { + "type": "integer" + }, + "subtotal_formatted": { + "type": "string" + }, + "subtotal_usd": { + "type": "integer" + }, + "tax": { + "type": "integer" + }, + "tax_formatted": { + "type": "string" + }, + "tax_usd": { + "type": "integer" + }, + "test_mode": { + "type": "boolean" + }, + "total": { + "type": "integer" + }, + "total_formatted": { + "type": "string" + }, + "total_usd": { + "type": "integer" + }, + "updated_at": { + "type": "string" + }, + "urls": { + "type": "object", + "properties": { + "invoice_url": { + "type": "string" + } + } + } + } + }, + "lemonsqueezy.SubscriptionItem": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "is_usage_based": { + "type": "boolean" + }, + "price_id": { + "type": "integer" + }, + "quantity": { + "type": "integer" + }, + "subscription_id": { + "type": "integer" + }, + "updated_at": { + "type": "string" + } + } + }, + "lemonsqueezy.SubscriptionPause": { + "type": "object", + "properties": { + "mode": { + "type": "string" + }, + "resumes_at": { + "type": "string" + } + } + }, + "lemonsqueezy.SubscriptionURLs": { + "type": "object", + "properties": { + "update_payment_method": { "type": "string" } } @@ -401,6 +1271,141 @@ } } }, + "models.Subscription": { + "type": "object", + "properties": { + "card_brand": { + "type": "string" + }, + "card_last_four": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "customer_id": { + "type": "integer" + }, + "ends_at": { + "type": "string" + }, + "order_id": { + "type": "integer" + }, + "product_id": { + "type": "integer" + }, + "product_name": { + "type": "string" + }, + "renews_at": { + "type": "string" + }, + "status": { + "type": "string" + }, + "status_formatted": { + "type": "string" + }, + "subscription_id": { + "description": "PK", + "type": "string" + }, + "subscription_plan_slug": { + "description": "FK SubscriptionPlan", + "allOf": [ + { + "$ref": "#/definitions/models.SubscriptionPlanSlug" + } + ] + }, + "trial_ends_at": { + "type": "string" + }, + "update_payment_method": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "user_email": { + "type": "string" + }, + "variant_id": { + "type": "integer" + } + } + }, + "models.SubscriptionPlan": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "description": { + "type": "string" + }, + "features": { + "type": "array", + "items": { + "type": "string" + } + }, + "href_monthly": { + "type": "string" + }, + "href_yearly": { + "type": "string" + }, + "id": { + "description": "PK", + "type": "string" + }, + "is_active": { + "type": "boolean" + }, + "most_popular": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "price_monthly": { + "type": "number" + }, + "price_yearly": { + "type": "number" + }, + "product_id": { + "type": "string" + }, + "slug": { + "$ref": "#/definitions/models.SubscriptionPlanSlug" + }, + "updated_at": { + "type": "string" + }, + "variants": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "models.SubscriptionPlanSlug": { + "type": "integer", + "enum": [ + 0, + 1, + 2 + ], + "x-enum-varnames": [ + "FREE", + "HOBBY", + "POPULAR" + ] + }, "models.YoutubeAnalysisLandingResults": { "type": "object", "properties": { diff --git a/go-server/docs/swagger.yaml b/go-server/docs/swagger.yaml index e2724f6..cdcddd2 100644 --- a/go-server/docs/swagger.yaml +++ b/go-server/docs/swagger.yaml @@ -11,6 +11,394 @@ definitions: message: type: string type: object + lemonsqueezy.ApiResponse-lemonsqueezy_CheckoutAttributes-lemonsqueezy_ApiResponseRelationshipsDiscount: + properties: + data: + $ref: '#/definitions/lemonsqueezy.ApiResponseData-lemonsqueezy_CheckoutAttributes-lemonsqueezy_ApiResponseRelationshipsDiscount' + jsonapi: + $ref: '#/definitions/lemonsqueezy.ApiResponseJSONAPI' + links: + $ref: '#/definitions/lemonsqueezy.ApiResponseSelfLink' + type: object + lemonsqueezy.ApiResponse-lemonsqueezy_Subscription-lemonsqueezy_ApiResponseRelationshipsSubscription: + properties: + data: + $ref: '#/definitions/lemonsqueezy.ApiResponseData-lemonsqueezy_Subscription-lemonsqueezy_ApiResponseRelationshipsSubscription' + jsonapi: + $ref: '#/definitions/lemonsqueezy.ApiResponseJSONAPI' + links: + $ref: '#/definitions/lemonsqueezy.ApiResponseSelfLink' + type: object + lemonsqueezy.ApiResponseData-lemonsqueezy_CheckoutAttributes-lemonsqueezy_ApiResponseRelationshipsDiscount: + properties: + attributes: + $ref: '#/definitions/lemonsqueezy.CheckoutAttributes' + id: + type: string + links: + $ref: '#/definitions/lemonsqueezy.ApiResponseSelfLink' + relationships: + $ref: '#/definitions/lemonsqueezy.ApiResponseRelationshipsDiscount' + type: + type: string + type: object + lemonsqueezy.ApiResponseData-lemonsqueezy_Subscription-lemonsqueezy_ApiResponseRelationshipsSubscription: + properties: + attributes: + $ref: '#/definitions/lemonsqueezy.Subscription' + id: + type: string + links: + $ref: '#/definitions/lemonsqueezy.ApiResponseSelfLink' + relationships: + $ref: '#/definitions/lemonsqueezy.ApiResponseRelationshipsSubscription' + type: + type: string + type: object + lemonsqueezy.ApiResponseData-lemonsqueezy_SubscriptionInvoiceAttributes-lemonsqueezy_ApiResponseRelationshipsSubscriptionInvoice: + properties: + attributes: + $ref: '#/definitions/lemonsqueezy.SubscriptionInvoiceAttributes' + id: + type: string + links: + $ref: '#/definitions/lemonsqueezy.ApiResponseSelfLink' + relationships: + $ref: '#/definitions/lemonsqueezy.ApiResponseRelationshipsSubscriptionInvoice' + type: + type: string + type: object + lemonsqueezy.ApiResponseJSONAPI: + properties: + version: + type: string + type: object + lemonsqueezy.ApiResponseLink: + properties: + related: + type: string + self: + type: string + type: object + lemonsqueezy.ApiResponseLinks: + properties: + links: + $ref: '#/definitions/lemonsqueezy.ApiResponseLink' + type: object + lemonsqueezy.ApiResponseList-lemonsqueezy_SubscriptionInvoiceAttributes-lemonsqueezy_ApiResponseRelationshipsSubscriptionInvoice: + properties: + data: + items: + $ref: '#/definitions/lemonsqueezy.ApiResponseData-lemonsqueezy_SubscriptionInvoiceAttributes-lemonsqueezy_ApiResponseRelationshipsSubscriptionInvoice' + type: array + jsonapi: + $ref: '#/definitions/lemonsqueezy.ApiResponseJSONAPI' + links: + $ref: '#/definitions/lemonsqueezy.ApiResponseListLink' + meta: + $ref: '#/definitions/lemonsqueezy.ApiResponseListMeta' + type: object + lemonsqueezy.ApiResponseListLink: + properties: + first: + type: string + last: + type: string + next: + type: string + type: object + lemonsqueezy.ApiResponseListMeta: + properties: + page: + $ref: '#/definitions/lemonsqueezy.ApiResponseListMetaPage' + type: object + lemonsqueezy.ApiResponseListMetaPage: + properties: + currentPage: + type: integer + from: + type: integer + lastPage: + type: integer + perPage: + type: integer + to: + type: integer + total: + type: integer + type: object + lemonsqueezy.ApiResponseRelationshipsDiscount: + properties: + discount-redemptions: + $ref: '#/definitions/lemonsqueezy.ApiResponseLinks' + store: + $ref: '#/definitions/lemonsqueezy.ApiResponseLinks' + variants: + $ref: '#/definitions/lemonsqueezy.ApiResponseLinks' + type: object + lemonsqueezy.ApiResponseRelationshipsSubscription: + properties: + customer: + $ref: '#/definitions/lemonsqueezy.ApiResponseLinks' + order: + $ref: '#/definitions/lemonsqueezy.ApiResponseLinks' + order-item: + $ref: '#/definitions/lemonsqueezy.ApiResponseLinks' + product: + $ref: '#/definitions/lemonsqueezy.ApiResponseLinks' + store: + $ref: '#/definitions/lemonsqueezy.ApiResponseLinks' + subscription-invoices: + $ref: '#/definitions/lemonsqueezy.ApiResponseLinks' + subscription-items: + $ref: '#/definitions/lemonsqueezy.ApiResponseLinks' + variant: + $ref: '#/definitions/lemonsqueezy.ApiResponseLinks' + type: object + lemonsqueezy.ApiResponseRelationshipsSubscriptionInvoice: + properties: + store: + $ref: '#/definitions/lemonsqueezy.ApiResponseLinks' + subscription: + $ref: '#/definitions/lemonsqueezy.ApiResponseLinks' + type: object + lemonsqueezy.ApiResponseSelfLink: + properties: + self: + type: string + type: object + lemonsqueezy.BillingAddress: + properties: + country: + type: string + zip: + type: string + type: object + lemonsqueezy.CheckoutAttributes: + properties: + checkout_data: + $ref: '#/definitions/lemonsqueezy.CheckoutData' + checkout_options: + $ref: '#/definitions/lemonsqueezy.CheckoutOptions' + created_at: + type: string + custom_price: {} + expires_at: + type: string + product_options: + $ref: '#/definitions/lemonsqueezy.CheckoutProductOptions' + store_id: + type: integer + test_mode: + type: boolean + updated_at: + type: string + url: + type: string + variant_id: + type: integer + type: object + lemonsqueezy.CheckoutData: + properties: + billing_address: + items: + $ref: '#/definitions/lemonsqueezy.BillingAddress' + type: array + custom: + additionalProperties: {} + type: object + discount_code: + type: string + email: + type: string + name: + type: string + tax_number: + type: string + type: object + lemonsqueezy.CheckoutOptions: + properties: + button_color: + type: string + dark: + type: boolean + desc: + type: boolean + discount: + type: boolean + embed: + type: boolean + logo: + type: boolean + media: + type: boolean + subscription_preview: + type: boolean + type: object + lemonsqueezy.CheckoutProductOptions: + properties: + description: + type: string + enabled_variants: + items: + type: integer + type: array + media: + items: {} + type: array + name: + type: string + receipt_button_text: + type: string + receipt_link_url: + type: string + receipt_thank_you_note: + type: string + redirect_url: + type: string + type: object + lemonsqueezy.Subscription: + properties: + billing_anchor: + type: integer + cancelled: + type: boolean + card_brand: + type: string + card_last_four: + type: string + created_at: + type: string + customer_id: + type: integer + ends_at: + type: string + first_subscription_item: + $ref: '#/definitions/lemonsqueezy.SubscriptionItem' + order_id: + type: integer + order_item_id: + type: integer + pause: + $ref: '#/definitions/lemonsqueezy.SubscriptionPause' + product_id: + type: integer + product_name: + type: string + renews_at: + type: string + status: + type: string + status_formatted: + type: string + store_id: + type: integer + test_mode: + type: boolean + trial_ends_at: + type: string + updated_at: + type: string + urls: + $ref: '#/definitions/lemonsqueezy.SubscriptionURLs' + user_email: + type: string + user_name: + type: string + variant_id: + type: integer + variant_name: + type: string + type: object + lemonsqueezy.SubscriptionInvoiceAttributes: + properties: + billing_reason: + type: string + card_brand: + type: string + card_last_four: + type: string + created_at: + type: string + currency: + type: string + currency_rate: + type: string + discount_total: + type: integer + discount_total_formatted: + type: string + discount_total_usd: + type: integer + refunded: + type: boolean + refunded_at: + type: string + status: + type: string + status_formatted: + type: string + store_id: + type: integer + subscription_id: + type: integer + subtotal: + type: integer + subtotal_formatted: + type: string + subtotal_usd: + type: integer + tax: + type: integer + tax_formatted: + type: string + tax_usd: + type: integer + test_mode: + type: boolean + total: + type: integer + total_formatted: + type: string + total_usd: + type: integer + updated_at: + type: string + urls: + properties: + invoice_url: + type: string + type: object + type: object + lemonsqueezy.SubscriptionItem: + properties: + created_at: + type: string + id: + type: integer + is_usage_based: + type: boolean + price_id: + type: integer + quantity: + type: integer + subscription_id: + type: integer + updated_at: + type: string + type: object + lemonsqueezy.SubscriptionPause: + properties: + mode: + type: string + resumes_at: + type: string + type: object + lemonsqueezy.SubscriptionURLs: + properties: + update_payment_method: + type: string + type: object models.BertAIResults: properties: errors_count: @@ -41,6 +429,96 @@ definitions: success_count: type: integer type: object + models.Subscription: + properties: + card_brand: + type: string + card_last_four: + type: string + created_at: + type: string + customer_id: + type: integer + ends_at: + type: string + order_id: + type: integer + product_id: + type: integer + product_name: + type: string + renews_at: + type: string + status: + type: string + status_formatted: + type: string + subscription_id: + description: PK + type: string + subscription_plan_slug: + allOf: + - $ref: '#/definitions/models.SubscriptionPlanSlug' + description: FK SubscriptionPlan + trial_ends_at: + type: string + update_payment_method: + type: string + updated_at: + type: string + user_email: + type: string + variant_id: + type: integer + type: object + models.SubscriptionPlan: + properties: + created_at: + type: string + description: + type: string + features: + items: + type: string + type: array + href_monthly: + type: string + href_yearly: + type: string + id: + description: PK + type: string + is_active: + type: boolean + most_popular: + type: boolean + name: + type: string + price_monthly: + type: number + price_yearly: + type: number + product_id: + type: string + slug: + $ref: '#/definitions/models.SubscriptionPlanSlug' + updated_at: + type: string + variants: + items: + type: string + type: array + type: object + models.SubscriptionPlanSlug: + enum: + - 0 + - 1 + - 2 + type: integer + x-enum-varnames: + - FREE + - HOBBY + - POPULAR models.YoutubeAnalysisLandingResults: properties: bert_results: @@ -652,4 +1130,190 @@ paths: schema: $ref: '#/definitions/handlers.helloApiMessage' summary: Hello message from the billing api + /billing/cancel-subscription: + get: + description: An endpoint to cancel a subscription + parameters: + - description: the subscription id + in: query + name: subscription_id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + type: string + "400": + description: Bad Request + schema: + $ref: '#/definitions/fiber.Error' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/fiber.Error' + summary: Cancel a subscription + /billing/checkout: + get: + description: |- + An endpoint to retrieve the URL for a subscription plan sending + the account email as well. + parameters: + - description: the variant id of the subscription plan + in: query + name: variant_id + required: true + type: string + - description: the user id + in: query + name: user_id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/lemonsqueezy.ApiResponse-lemonsqueezy_CheckoutAttributes-lemonsqueezy_ApiResponseRelationshipsDiscount' + "400": + description: Bad Request + schema: + $ref: '#/definitions/fiber.Error' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/fiber.Error' + summary: Get the checkout URL for a subscription plan + /billing/invoices: + get: + description: An endpoint to retrieve the invoices from a user's subscription + parameters: + - description: the subscription id + in: query + name: subscription_id + required: true + type: string + - description: the queried page + in: query + name: page + type: integer + - description: 'page size for the results (default: 10, max: 50)' + in: query + name: page_size + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/lemonsqueezy.ApiResponseList-lemonsqueezy_SubscriptionInvoiceAttributes-lemonsqueezy_ApiResponseRelationshipsSubscriptionInvoice' + "400": + description: Bad Request + schema: + $ref: '#/definitions/fiber.Error' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/fiber.Error' + summary: Get the latest Invoices from a subscription + /billing/resume-subscription: + get: + description: An endpoint to resume a cancelled subscription + parameters: + - description: the subscription id + in: query + name: subscription_id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + type: string + "400": + description: Bad Request + schema: + $ref: '#/definitions/fiber.Error' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/fiber.Error' + summary: Resume a subscription + /billing/subscription-plans: + get: + description: An endpoint to retrieve the subscription plan offered by GPTube + with its price, features, etc. + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/models.SubscriptionPlan' + type: array + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/fiber.Error' + summary: Get the subscription plans offered by GPTube + /billing/subscriptions: + get: + description: An endpoint to retrieve all the subscriptions belonging to an account + parameters: + - description: the user id + in: query + name: user_id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/models.Subscription' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/fiber.Error' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/fiber.Error' + summary: Get the subscribed subscriptions of an account + /billing/update-payment-method: + get: + description: An endpoint to retrieve the URL to update the payment method for + a subscription + parameters: + - description: the subscription id + in: query + name: subscription_id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/lemonsqueezy.ApiResponse-lemonsqueezy_Subscription-lemonsqueezy_ApiResponseRelationshipsSubscription' + "400": + description: Bad Request + schema: + $ref: '#/definitions/fiber.Error' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/fiber.Error' + summary: Get the update payment method URL for a subscription swagger: "2.0" diff --git a/go-server/go.mod b/go-server/go.mod index a9d9e61..cd0c9eb 100644 --- a/go-server/go.mod +++ b/go-server/go.mod @@ -35,7 +35,7 @@ require ( github.com/golang/protobuf v1.5.3 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/s2a-go v0.1.7 // indirect - github.com/google/uuid v1.3.1 // indirect + github.com/google/uuid v1.4.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.2.5 // indirect github.com/googleapis/gax-go/v2 v2.12.0 // indirect github.com/josharian/intern v1.0.0 // indirect diff --git a/go-server/go.sum b/go-server/go.sum index 25495f8..05743f1 100644 --- a/go-server/go.sum +++ b/go-server/go.sum @@ -97,6 +97,8 @@ github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8 github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.2.5 h1:UR4rDjcgpgEnqpIEvkiqTYKBCKLNmlge2eVjoZfySzM= github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w= github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= diff --git a/go-server/handlers/billing.go b/go-server/handlers/billing.go index c477eed..cce5578 100644 --- a/go-server/handlers/billing.go +++ b/go-server/handlers/billing.go @@ -2,127 +2,234 @@ package handlers import ( "context" + "encoding/json" "fmt" "gptube/config" "gptube/database" "gptube/models" + "gptube/services" "gptube/utils" + "log" + "math" "net/http" + "strconv" + "strings" "time" - firebase "firebase.google.com/go" "github.com/NdoleStudio/lemonsqueezy-go" "github.com/gofiber/fiber/v2" ) -var lemonSqueezyAuthHeader = fmt.Sprintf("Bearer %s", config.Config("LEMON_SQUEEZY_API_KEY")) -var lemonClient = lemonsqueezy.New(lemonsqueezy.WithAPIKey(config.Config("LEMON_SQUEEZY_API_KEY"))) -var lemonWebhookClient = lemonsqueezy.New(lemonsqueezy.WithSigningSecret(config.Config("LEMON_SQUEEZY_WEBHOOK_PASSWORD"))) +const ( + USER_ID_META_TAG = "user_id" + SUBSCRIPTION_PLAN_SLUG_META_TAG = "subscription_plan_slug" +) -func BillingProducts(c *fiber.Ctx) error { - allVariants, _, err := lemonClient.Variants.List(context.Background()) +// @Summary Get the subscription plans offered by GPTube +// @Description An endpoint to retrieve the subscription plan offered by GPTube with its price, features, etc. +// @Produce json +// @Success 200 {array} models.SubscriptionPlan +// @Failure 500 {object} fiber.Error +// @Router /billing/subscription-plans [get] +func BillingSubscriptionPlans(c *fiber.Ctx) error { + subscriptionPlans, err := database.GetSubscriptionPlans() if err != nil { - return utils.HandleError(err, http.StatusInternalServerError, c) + return fiber.NewError(http.StatusInternalServerError, "error while retrieving subscription plans") + } + var arrSubscriptionPlans []models.SubscriptionPlan + for _, subPlan := range subscriptionPlans { + arrSubscriptionPlans = append(arrSubscriptionPlans, *subPlan) } - return c.JSON(allVariants) + return c.Status(http.StatusOK).JSON(arrSubscriptionPlans) } +// @Summary Get the checkout URL for a subscription plan +// @Description An endpoint to retrieve the URL for a subscription plan sending +// @Description the account email as well. +// @Produce json +// @Param variant_id query string true "the variant id of the subscription plan" +// @Param user_id query string true "the user id" +// @Success 200 {object} lemonsqueezy.ApiResponse[lemonsqueezy.CheckoutAttributes, lemonsqueezy.ApiResponseRelationshipsDiscount] +// @Failure 400 {object} fiber.Error +// @Failure 500 {object} fiber.Error +// @Router /billing/checkout [get] func BillingCheckout(c *fiber.Ctx) error { - variantId := c.Query("variantId", "") + variantId := strings.TrimSpace(c.Query("variant_id", "")) + userId := strings.TrimSpace(c.Query("user_id", "")) + + if variantId == "" { + return fiber.NewError(http.StatusBadRequest, "please provide a variant id") + } + if userId == "" { + return fiber.NewError(http.StatusBadRequest, "please provide a user id") + } + + subscriptionPlans, err := database.GetSubscriptionPlans() + if err != nil { + return fiber.NewError(http.StatusInternalServerError, "try again later") + } + + subscriptionPlanSlug := models.FREE + for _, subscriptionPlan := range subscriptionPlans { + for _, variant := range subscriptionPlan.Variants { + if variant == variantId { + subscriptionPlanSlug = subscriptionPlan.Slug + break + } + } + } + checkoutParams := &lemonsqueezy.CheckoutCreateParams{ - StoreID: config.Config("LEMON_SQUEEZY_STORE_ID"), + StoreID: services.LemonStoreId, VariantID: variantId, - ExpiresAt: time.Now().Add(24 * time.Hour), + ExpiresAt: time.Now().Add(24 * time.Hour), // expires in 24 hours EnabledVariants: make([]int, 0), - ButtonColor: "#D91E1E", + ButtonColor: "#81F7AC", CustomData: map[string]string{ - "message": "creating checkout", + SUBSCRIPTION_PLAN_SLUG_META_TAG: fmt.Sprint(subscriptionPlanSlug), + USER_ID_META_TAG: userId, }, } - checkout, _, err := lemonClient.Checkouts.Create(context.Background(), checkoutParams) + checkout, _, err := services.LemonClient.Checkouts.Create(context.Background(), checkoutParams) if err != nil { - return utils.HandleError(err, http.StatusInternalServerError, c) + return fiber.NewError(http.StatusInternalServerError, + "Error while trying to get the checkout URL, try again later.") } - return c.JSON(checkout) + return c.Status(http.StatusOK).JSON(checkout) } +// @Summary Get the subscribed subscriptions of an account +// @Description An endpoint to retrieve all the subscriptions belonging to an account +// @Produce json +// @Param user_id query string true "the user id" +// @Success 200 {array} models.Subscription +// @Failure 400 {object} fiber.Error +// @Failure 500 {object} fiber.Error +// @Router /billing/subscriptions [get] func BillingSubscriptions(c *fiber.Ctx) error { - userEmail := c.Query("user_email", "") - if userEmail == "" { - err := fmt.Errorf("please add the 'user_email' query param") - return utils.HandleError(err, http.StatusBadRequest, c) + userId := strings.TrimSpace(c.Query("user_id", "")) + if userId == "" { + return fiber.NewError(http.StatusBadRequest, "please add a non-empty user_id parameter") } - subscriptions, err := database.RetrieveSubscriptions(userEmail) + subscriptions, err := database.GetAllSubscriptions(userId) if err != nil { - return utils.HandleError(err, http.StatusInternalServerError, c) + return fiber.NewError(http.StatusInternalServerError, "could fetch any subscription, try again later") } - return c.JSON(fiber.Map{ - "count": len(*subscriptions), - "subscriptions": *subscriptions, - }) + return c.Status(http.StatusOK).JSON(subscriptions) } +// @Summary Get the latest Invoices from a subscription +// @Description An endpoint to retrieve the invoices from a user's subscription +// @Produce json +// @Param subscription_id query string true "the subscription id" +// @Param page query int false "the queried page" +// @Param page_size query int false "page size for the results (default: 10, max: 50)" +// @Success 200 {object} lemonsqueezy.ApiResponseList[lemonsqueezy.SubscriptionInvoiceAttributes, lemonsqueezy.ApiResponseRelationshipsSubscriptionInvoice] +// @Failure 400 {object} fiber.Error +// @Failure 500 {object} fiber.Error +// @Router /billing/invoices [get] func BillingSubscriptionInvoices(c *fiber.Ctx) error { - var body models.InvoicesRequest - if err := c.BodyParser(&body); err != nil { - return utils.HandleError(err, http.StatusInternalServerError, c) + subscriptionId := strings.TrimSpace(c.Query("subscription_id", "")) + if subscriptionId == "" { + return fiber.NewError(http.StatusBadRequest, "please provide a subscription id") + } + + page, err := strconv.Atoi(c.Query("page", fmt.Sprintf("%d", config.DEFAULT_PAGE_NUM))) + if err != nil { + return fiber.NewError(http.StatusBadRequest, "please provide a valid page number") + } + if page < config.MIN_PAGE_NUM { + return fiber.NewError(http.StatusBadRequest, "page number can not be zero or negative") + } + + pageSize, err := strconv.Atoi(c.Query("page_size", fmt.Sprintf("%d", config.DEFAULT_PAGE_SIZE))) + + if err != nil { + return fiber.NewError(http.StatusBadRequest, "please provide a valid page size number") } + if pageSize < config.MIN_PAGE_SIZE { + return fiber.NewError(http.StatusBadRequest, "page size number can not be zero or negative") + } + // Ensuring the max page size + pageSize = int(math.Min(float64(pageSize), config.MAX_PAGE_SIZE)) var invoices lemonsqueezy.SubscriptionInvoicesApiResponse agent := fiber.AcquireAgent() agent.ContentType("application/json") - agent.Set("Authorization", lemonSqueezyAuthHeader) + agent.Set("Authorization", services.LemonSqueezyAuthHeader) req := agent.Request() req.Header.SetMethod(fiber.MethodGet) req.SetRequestURI(fmt.Sprintf("%s/subscription-invoices", config.Config("LEMON_SQUEEZY_API_URL"))) agent.QueryString( fmt.Sprintf("filter[subscription_id]=%v&page[number]=%v&page[size]=%v", - body.SubscriptionId, body.Page, body.PageSize), + subscriptionId, page, pageSize), ) if err := agent.Parse(); err != nil { - return utils.HandleError(err, http.StatusInternalServerError, c) + return fiber.NewError(http.StatusInternalServerError, "couldn't fetch the the invoices please try again later") } statusCode, _, errs := agent.Struct(&invoices) if statusCode != http.StatusOK && len(errs) > 0 { - return utils.HandleError(errs[0], http.StatusInternalServerError, c) + return fiber.NewError(http.StatusInternalServerError, "couldn't fetch the the invoices please try again later") } - return c.JSON(invoices) + return c.Status(http.StatusOK).JSON(invoices) } +// @Summary Get the update payment method URL for a subscription +// @Description An endpoint to retrieve the URL to update the payment method for a subscription +// @Produce json +// @Param subscription_id query string true "the subscription id" +// @Success 200 {object} lemonsqueezy.ApiResponse[lemonsqueezy.Subscription, lemonsqueezy.ApiResponseRelationshipsSubscription] +// @Failure 400 {object} fiber.Error +// @Failure 500 {object} fiber.Error +// @Router /billing/update-payment-method [get] func BillingUpdatePaymentMethod(c *fiber.Ctx) error { - subscriptionId := c.Query("subscription_id", "") + subscriptionId := strings.TrimSpace(c.Query("subscription_id", "")) if subscriptionId == "" { - err := fmt.Errorf("please add the 'subscription_id' query param") - return utils.HandleError(err, http.StatusBadRequest, c) + return fiber.NewError(http.StatusBadRequest, "please add a non-empty 'subscription_id' query param") } - subscription, _, err := lemonClient.Subscriptions.Get(context.Background(), subscriptionId) + subscription, _, err := services.LemonClient.Subscriptions.Get(context.Background(), subscriptionId) if err != nil { - return utils.HandleError(err, http.StatusInternalServerError, c) + return fiber.NewError(http.StatusInternalServerError, + "an error while trying to retrieve the URL. Check the subscription_id exists") } - return c.JSON(subscription) + return c.Status(http.StatusOK).JSON(subscription) } +// @Summary Cancel a subscription +// @Description An endpoint to cancel a subscription +// @Produce json +// @Param subscription_id query string true "the subscription id" +// @Success 200 {string} string "OK" +// @Failure 400 {object} fiber.Error +// @Failure 500 {object} fiber.Error +// @Router /billing/cancel-subscription [get] func BillingCancelSubscription(c *fiber.Ctx) error { - subscriptionId := c.Query("subscription_id", "") + subscriptionId := strings.TrimSpace(c.Query("subscription_id", "")) if subscriptionId == "" { - err := fmt.Errorf("please add the 'subscription_id' query param") - return utils.HandleError(err, http.StatusBadRequest, c) + return fiber.NewError(http.StatusBadRequest, "please add the 'subscription_id' query param") } - _, _, err := lemonClient.Subscriptions.Cancel(context.Background(), subscriptionId) + _, _, err := services.LemonClient.Subscriptions.Cancel(context.Background(), subscriptionId) if err != nil { - return utils.HandleError(err, http.StatusInternalServerError, c) + return fiber.NewError(http.StatusInternalServerError, "could not cancel the subscription, try again later") } - return c.SendStatus(http.StatusOK) + return c.Status(http.StatusOK).SendString("OK") } +// @Summary Resume a subscription +// @Description An endpoint to resume a cancelled subscription +// @Produce json +// @Param subscription_id query string true "the subscription id" +// @Success 200 {string} string "OK" +// @Failure 400 {object} fiber.Error +// @Failure 500 {object} fiber.Error +// @Router /billing/resume-subscription [get] func BillingResumeSubscription(c *fiber.Ctx) error { - subscriptionId := c.Query("subscription_id", "") + subscriptionId := strings.TrimSpace(c.Query("subscription_id", "")) if subscriptionId == "" { - err := fmt.Errorf("please add the 'subscription_id' query param") - return utils.HandleError(err, http.StatusBadRequest, c) + return fiber.NewError(http.StatusBadRequest, "please add the 'subscription_id' query param") } subscriptionParams := &lemonsqueezy.SubscriptionUpdateParams{ ID: subscriptionId, @@ -130,117 +237,158 @@ func BillingResumeSubscription(c *fiber.Ctx) error { Cancelled: false, }, } - _, _, err := lemonClient.Subscriptions.Update(context.Background(), subscriptionParams) + _, _, err := services.LemonClient.Subscriptions.Update(context.Background(), subscriptionParams) if err != nil { - return utils.HandleError(err, http.StatusInternalServerError, c) + return fiber.NewError(http.StatusInternalServerError, "an error ocurred while resuming your subscription, try again later") } - return c.SendStatus(http.StatusOK) + return c.Status(http.StatusOK).SendString("OK") } func billingCreateSubscriptionWebhookHandler( - subscription *lemonsqueezy.WebhookRequest[lemonsqueezy.Subscription, - lemonsqueezy.ApiResponseRelationshipsSubscription]) error { - app, err := firebase.NewApp(database.Ctx, nil, database.Sa) - if err != nil { - return err + subscription *lemonsqueezy.WebhookRequest[ + lemonsqueezy.Subscription, + lemonsqueezy.ApiResponseRelationshipsSubscription, + ], +) error { + subscriptionPlanSlugMeta := subscription.Meta.CustomData[SUBSCRIPTION_PLAN_SLUG_META_TAG] + userId := subscription.Meta.CustomData[USER_ID_META_TAG].(string) + if subscriptionPlanSlugMeta == nil { + subscriptionPlanSlugMeta = fmt.Sprint(models.FREE) // by default free plan } - - client, err := app.Firestore(database.Ctx) + subscriptionPlanSlug, err := strconv.Atoi(subscriptionPlanSlugMeta.(string)) if err != nil { return err } - defer client.Close() - - newSubscriptionFirestore := models.SubscriptionFirestore{ - UserEmail: subscription.Data.Attributes.UserEmail, - SubscriptionId: subscription.Data.ID, - OrderId: subscription.Data.Attributes.OrderID, - ProductId: subscription.Data.Attributes.ProductID, - VariantId: subscription.Data.Attributes.VariantID, - CustomerId: 0, - ProductName: subscription.Data.Attributes.ProductName, - Status: subscription.Data.Attributes.Status, - StatusFormatted: subscription.Data.Attributes.StatusFormatted, - TrialEndsAt: subscription.Data.Attributes.TrialEndsAt.String(), - RenewsAt: subscription.Data.Attributes.RenewsAt.String(), - EndsAt: subscription.Data.Attributes.EndsAt.String(), - CreatedAt: subscription.Data.Attributes.CreatedAt.String(), - CardBrand: "", - CardLastFour: "", - UpdatePaymentMethod: subscription.Data.Attributes.Urls.UpdatePaymentMethod, - } - - _, err = client.Collection("subscriptions").Doc(subscription.Data.ID). - Set(database.Ctx, newSubscriptionFirestore) - if err != nil { - return fmt.Errorf("an error has occurred: %s", err) + newSubscription := models.Subscription{ + SubscriptionId: subscription.Data.ID, + SubscriptionPlanSlug: models.SubscriptionPlanSlug(subscriptionPlanSlug), + UserEmail: subscription.Data.Attributes.UserEmail, + OrderId: subscription.Data.Attributes.OrderID, + ProductId: subscription.Data.Attributes.ProductID, + VariantId: subscription.Data.Attributes.VariantID, + CustomerId: subscription.Data.Attributes.CustomerID, + ProductName: subscription.Data.Attributes.ProductName, + Status: subscription.Data.Attributes.Status, + StatusFormatted: subscription.Data.Attributes.StatusFormatted, + TrialEndsAt: subscription.Data.Attributes.TrialEndsAt, + RenewsAt: subscription.Data.Attributes.RenewsAt, + EndsAt: subscription.Data.Attributes.EndsAt, + CreatedAt: subscription.Data.Attributes.CreatedAt, + UpdatedAt: subscription.Data.Attributes.UpdatedAt, + CardBrand: subscription.Data.Attributes.CardBrand, + CardLastFour: subscription.Data.Attributes.CardLastFour, + UpdatePaymentMethod: subscription.Data.Attributes.Urls.UpdatePaymentMethod, } - return nil + fmt.Printf("[billingCreateSubscriptionWebhookHandler] creating subscription %s for user with Id %s\n", + subscription.Data.ID, userId) + + err = database.CreateSubscription(userId, &newSubscription) + return err } func billingUpdateSubscriptionWebhookHandler( subscription *lemonsqueezy.WebhookRequest[ lemonsqueezy.Subscription, - lemonsqueezy.ApiResponseRelationshipsSubscription]) error { - app, err := firebase.NewApp(database.Ctx, nil, database.Sa) - if err != nil { - return err + lemonsqueezy.ApiResponseRelationshipsSubscription, + ], +) error { + subscriptionPlanSlugMeta := subscription.Meta.CustomData[SUBSCRIPTION_PLAN_SLUG_META_TAG] + userId := subscription.Meta.CustomData[USER_ID_META_TAG].(string) + if subscriptionPlanSlugMeta == nil { + subscriptionPlanSlugMeta = fmt.Sprint(models.FREE) // by default free plan } - - client, err := app.Firestore(database.Ctx) + subscriptionPlanSlug, err := strconv.Atoi(subscriptionPlanSlugMeta.(string)) if err != nil { return err } - defer client.Close() - - fmt.Println("updating subscription") + updatedSubscription := models.Subscription{ + SubscriptionId: subscription.Data.ID, + SubscriptionPlanSlug: models.SubscriptionPlanSlug(subscriptionPlanSlug), + UserEmail: subscription.Data.Attributes.UserEmail, + OrderId: subscription.Data.Attributes.OrderID, + ProductId: subscription.Data.Attributes.ProductID, + VariantId: subscription.Data.Attributes.VariantID, + CustomerId: subscription.Data.Attributes.CustomerID, + ProductName: subscription.Data.Attributes.ProductName, + Status: subscription.Data.Attributes.Status, + StatusFormatted: subscription.Data.Attributes.StatusFormatted, + TrialEndsAt: subscription.Data.Attributes.TrialEndsAt, + RenewsAt: subscription.Data.Attributes.RenewsAt, + EndsAt: subscription.Data.Attributes.EndsAt, + CreatedAt: subscription.Data.Attributes.CreatedAt, + UpdatedAt: subscription.Data.Attributes.UpdatedAt, + CardBrand: subscription.Data.Attributes.CardBrand, + CardLastFour: subscription.Data.Attributes.CardLastFour, + UpdatePaymentMethod: subscription.Data.Attributes.Urls.UpdatePaymentMethod, + } - return nil + fmt.Printf("[billingUpdateSubscriptionWebhookHandler] updating subscription %s for user with id %s\n", + subscription.Data.ID, userId) + err = database.UpdateSubscription(userId, &updatedSubscription) + return err } func BillingSubscriptionsWebhooks(c *fiber.Ctx) error { headers := c.GetReqHeaders() signature := headers["X-Signature"] - isValidReqBody := lemonWebhookClient.Webhooks.Verify( + isValidReqBody := services.LemonWebhookClient.Webhooks.Verify( context.Background(), signature, c.Body()) if isValidReqBody { var webhookBody lemonsqueezy.WebhookRequest[lemonsqueezy.Subscription, lemonsqueezy.ApiResponseRelationshipsSubscription] if err := c.BodyParser(&webhookBody); err != nil { - c.JSON(fiber.Map{ - "error": fmt.Errorf("%v", err).Error(), - }) - return c.SendStatus(http.StatusInternalServerError) + return fiber.NewError(http.StatusInternalServerError, err.Error()) + } + + defer func() { + fmt.Printf("[BillingSubscriptionsWebhooks] event %s handled correctly\n", webhookBody.Meta.EventName) + }() + + prettyJSON, err := json.MarshalIndent(webhookBody, "", " ") + if err != nil { + return utils.HandleError(err, http.StatusInternalServerError, c) } eventHandlers := make(map[string]func( subscription *lemonsqueezy.WebhookRequest[ lemonsqueezy.Subscription, lemonsqueezy.ApiResponseRelationshipsSubscription]) error) + + switch webhookBody.Meta.EventName { + case "subscription_payment_success", + "subscription_payment_failed", + "subscription_payment_recovered", + "subscription_cancelled", + "subscription_expired": + fmt.Printf("%s\n", webhookBody.Meta.EventName) + return c.Status(http.StatusOK).JSON(fiber.Map{ + "message": fmt.Sprintf("webhook for event %s handled", webhookBody.Meta.EventName), + }) + } + + if config.Config("ENV_MODE") == config.ENV_DEVELOPMENT { + log.Printf("[BillingSubscriptionsWebhooks]\npayload body: %s\n", string(prettyJSON)) + } eventHandlers["subscription_created"] = billingCreateSubscriptionWebhookHandler eventHandlers["subscription_updated"] = billingUpdateSubscriptionWebhookHandler handler, ok := eventHandlers[webhookBody.Meta.EventName] if !ok { - utils.HandleError( - fmt.Errorf("event not registered on the webhook"), - http.StatusInternalServerError, c) + return fiber.NewError(http.StatusInternalServerError, + "event not registered on the webhook") } - - handler(&webhookBody) - - return c.JSON(fiber.Map{ + err = handler(&webhookBody) + if err != nil { + return fiber.NewError(http.StatusInternalServerError, err.Error()) + } + return c.Status(http.StatusOK).JSON(fiber.Map{ "message": "webhook received correctly", }) } - - c.Status(http.StatusInternalServerError) - return c.JSON(fiber.Map{ - "message": "error while validating the signature", - }) + return fiber.NewError(http.StatusInternalServerError, "error while validating the signature") } diff --git a/go-server/main.go b/go-server/main.go index 28a01b4..fda9d71 100644 --- a/go-server/main.go +++ b/go-server/main.go @@ -8,6 +8,7 @@ import ( "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/cors" + "github.com/gofiber/fiber/v2/middleware/recover" ) // Important!!! forget to add things like: example("param example") after a Param API definition @@ -27,6 +28,9 @@ func main() { app := fiber.New(fiber.Config{ ErrorHandler: handlers.CustomErrorHandler, }) + app.Use(recover.New(recover.Config{ + EnableStackTrace: true, + })) app.Use(cors.New()) router.SetupRoutes(app) appPort := config.Config("PORT") diff --git a/go-server/models/billing.go b/go-server/models/billing.go index 46badfc..5893991 100644 --- a/go-server/models/billing.go +++ b/go-server/models/billing.go @@ -1,26 +1,51 @@ package models -type InvoicesRequest struct { - SubscriptionId int `json:"subscriptionId"` - Page int `json:"page"` - PageSize int `json:"pageSize"` +import "time" + +type SubscriptionPlanSlug int + +const ( + FREE SubscriptionPlanSlug = iota + HOBBY + POPULAR +) + +type SubscriptionPlan struct { + Id string `json:"id" firestore:"id"` // PK + ProductId string `json:"product_id" firestore:"product_id"` + Variants []string `json:"variants" firestore:"variants"` + Slug SubscriptionPlanSlug `json:"slug" firestore:"slug"` + Name string `json:"name" firestore:"name"` + Description string `json:"description" firestore:"description"` + PriceMonthly float32 `json:"price_monthly" firestore:"price_monthly"` + PriceYearly float32 `json:"price_yearly" firestore:"price_yearly"` + HrefMonthly string `json:"href_monthly" firestore:"href_monthly"` + HrefYearly string `json:"href_yearly" firestore:"href_yearly"` + Features []string `json:"features" firestore:"features"` + MostPopular bool `json:"most_popular" firestore:"most_popular"` + IsActive bool `json:"is_active" firestore:"is_active"` + CreatedAt time.Time `json:"created_at" firestore:"created_at"` + UpdatedAt time.Time `json:"updated_at" firestore:"updated_at"` } -type SubscriptionFirestore struct { - UserEmail string `json:"user_email,omitempty" firestore:"user_email"` - SubscriptionId string `json:"subscription_id,omitempty" firestore:"subscription_id"` - OrderId int `json:"order_id,omitempty" firestore:"order_id"` - ProductId int `json:"product_id,omitempty" firestore:"product_id"` - VariantId int `json:"variant_id,omitempty" firestore:"variant_id"` - CustomerId int `json:"customer_id,omitempty" firestore:"customer_id"` - ProductName string `json:"product_name,omitempty" firestore:"product_name"` - Status string `json:"status,omitempty" firestore:"status"` - StatusFormatted string `json:"status_formatted,omitempty" firestore:"status_formatted"` - TrialEndsAt string `json:"trial_ends_at,omitempty" firestore:"trial_ends_at"` - RenewsAt string `json:"renews_at,omitempty" firestore:"renews_at"` - EndsAt string `json:"ends_at,omitempty" firestore:"ends_at"` - CreatedAt string `json:"created_at,omitempty" firestore:"created_at"` - CardBrand string `json:"card_brand,omitempty" firestore:"card_brand"` - CardLastFour string `json:"card_last_four,omitempty" firestore:"card_last_four"` - UpdatePaymentMethod string `json:"update_payment_method,omitempty" firestore:"update_payment_method"` +// This model schema will be a sub-collection of USERS_COLLECTION +type Subscription struct { + SubscriptionId string `json:"subscription_id" firestore:"subscription_id"` // PK + SubscriptionPlanSlug SubscriptionPlanSlug `json:"subscription_plan_slug" firestore:"subscription_plan_slug"` // FK SubscriptionPlan + UserEmail string `json:"user_email" firestore:"user_email"` + OrderId int `json:"order_id" firestore:"order_id"` + ProductId int `json:"product_id" firestore:"product_id"` + VariantId int `json:"variant_id" firestore:"variant_id"` + CustomerId int `json:"customer_id" firestore:"customer_id"` + ProductName string `json:"product_name" firestore:"product_name"` + Status string `json:"status" firestore:"status"` + StatusFormatted string `json:"status_formatted" firestore:"status_formatted"` + TrialEndsAt *time.Time `json:"trial_ends_at" firestore:"trial_ends_at"` + RenewsAt time.Time `json:"renews_at" firestore:"renews_at"` + EndsAt *time.Time `json:"ends_at" firestore:"ends_at"` + CreatedAt time.Time `json:"created_at" firestore:"created_at"` + UpdatedAt time.Time `json:"updated_at" firestore:"updated_at"` + CardBrand string `json:"card_brand" firestore:"card_brand"` + CardLastFour string `json:"card_last_four" firestore:"card_last_four"` + UpdatePaymentMethod string `json:"update_payment_method" firestore:"update_payment_method"` } diff --git a/go-server/models/user.go b/go-server/models/user.go new file mode 100644 index 0000000..0b15ad1 --- /dev/null +++ b/go-server/models/user.go @@ -0,0 +1,16 @@ +package models + +import "time" + +// Principal collection for every user +type User struct { + Id string `json:"id" firestore:"id"` + Name string `json:"name" firestore:"name"` + Username string `json:"username" firestore:"username"` + Email string `json:"email" firestore:"email"` + ImageURL string `json:"image_url" firestore:"image_url"` + EmailVerified time.Time `json:"email_verified" firestore:"email_verified"` + IsActive bool `json:"is_active" firestore:"is_active"` + CreatedAt time.Time `json:"created_at" firestore:"created_at"` + UpdatedAt time.Time `json:"updated_at" firestore:"updated_at"` +} diff --git a/go-server/router/main.go b/go-server/router/main.go index ef8086b..447f9b3 100644 --- a/go-server/router/main.go +++ b/go-server/router/main.go @@ -14,19 +14,28 @@ func SetupRoutes(app *fiber.App) { app.Get("/swagger/*", swagger.HandlerDefault) billing := app.Group("/billing") + // documented billing.Get("", handlers.BillingHandler) - billing.Get("/products", handlers.BillingProducts) + // documented + billing.Get("/subscription-plans", handlers.BillingSubscriptionPlans) + // documented billing.Get("/checkout", handlers.BillingCheckout) - billing.Post("/invoices", handlers.BillingSubscriptionInvoices) + // documented + billing.Get("/invoices", handlers.BillingSubscriptionInvoices) + // documented billing.Get("/subscriptions", handlers.BillingSubscriptions) + // documented billing.Get("/update-payment-method", handlers.BillingUpdatePaymentMethod) + // documented billing.Get("/cancel-subscription", handlers.BillingCancelSubscription) + // documented billing.Get("/resume-subscription", handlers.BillingResumeSubscription) // This is a special endpoint for receiving subscriptions webhooks on LemonSqueezy billing.Post("/webhooks", handlers.BillingSubscriptionsWebhooks) api := app.Group("/api") api.Get("", handlers.ApiHandler) + // documented youtubeRoutes := api.Group("/youtube") // documented youtubeRoutes.Get("/videos", handlers.YoutubeListVideosHandler) diff --git a/go-server/services/billing.go b/go-server/services/billing.go new file mode 100644 index 0000000..0a31c13 --- /dev/null +++ b/go-server/services/billing.go @@ -0,0 +1,27 @@ +package services + +import ( + "fmt" + "gptube/config" + + "github.com/NdoleStudio/lemonsqueezy-go" +) + +var LemonSqueezyAuthHeader string +var LemonClient *lemonsqueezy.Client +var LemonWebhookClient *lemonsqueezy.Client +var LemonStoreId string + +func init() { + if config.Config("ENV_MODE") == "production" { + LemonSqueezyAuthHeader = fmt.Sprintf("Bearer %s", config.Config("LEMON_SQUEEZY_MAIN_API_KEY")) + LemonClient = lemonsqueezy.New(lemonsqueezy.WithAPIKey(config.Config("LEMON_SQUEEZY_MAIN_API_KEY"))) + LemonWebhookClient = lemonsqueezy.New(lemonsqueezy.WithSigningSecret(config.Config("LEMON_SQUEEZY_MAIN_WEBHOOK_PASSWORD"))) + LemonStoreId = config.Config("LEMON_SQUEEZY_MAIN_STORE_ID") + } else { + LemonSqueezyAuthHeader = fmt.Sprintf("Bearer %s", config.Config("LEMON_SQUEEZY_TEST_API_KEY")) + LemonClient = lemonsqueezy.New(lemonsqueezy.WithAPIKey(config.Config("LEMON_SQUEEZY_TEST_API_KEY"))) + LemonWebhookClient = lemonsqueezy.New(lemonsqueezy.WithSigningSecret(config.Config("LEMON_SQUEEZY_TEST_WEBHOOK_PASSWORD"))) + LemonStoreId = config.Config("LEMON_SQUEEZY_TEST_STORE_ID") + } +} diff --git a/go-server/services/youtube.go b/go-server/services/youtube.go index c8ad8d6..d5b76b4 100644 --- a/go-server/services/youtube.go +++ b/go-server/services/youtube.go @@ -20,10 +20,12 @@ import ( "google.golang.org/api/youtube/v3" ) +const MAX_WORKERS = 200 + var Service *youtube.Service // The hole system will have a max of 200 concurrent workers -var Workers = make(chan struct{}, 200) +var Workers = make(chan struct{}, MAX_WORKERS) var commentsPerSubscription = map[string]int{ "landing": 250, diff --git a/go.work.sum b/go.work.sum index dfbcd03..827b6c7 100644 --- a/go.work.sum +++ b/go.work.sum @@ -6,4 +6,4 @@ github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XP github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= \ No newline at end of file diff --git a/gptube/gptube-api/generated-api/.openapi-generator/FILES b/gptube/gptube-api/generated-api/.openapi-generator/FILES index c683828..7861ca3 100644 --- a/gptube/gptube-api/generated-api/.openapi-generator/FILES +++ b/gptube/gptube-api/generated-api/.openapi-generator/FILES @@ -4,8 +4,38 @@ apis/index.ts index.ts models/FiberError.ts models/HandlersHelloApiMessage.ts +models/LemonsqueezyApiResponseDataLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount.ts +models/LemonsqueezyApiResponseDataLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice.ts +models/LemonsqueezyApiResponseDataLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription.ts +models/LemonsqueezyApiResponseJSONAPI.ts +models/LemonsqueezyApiResponseLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount.ts +models/LemonsqueezyApiResponseLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription.ts +models/LemonsqueezyApiResponseLink.ts +models/LemonsqueezyApiResponseLinks.ts +models/LemonsqueezyApiResponseListLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice.ts +models/LemonsqueezyApiResponseListLink.ts +models/LemonsqueezyApiResponseListMeta.ts +models/LemonsqueezyApiResponseListMetaPage.ts +models/LemonsqueezyApiResponseRelationshipsDiscount.ts +models/LemonsqueezyApiResponseRelationshipsSubscription.ts +models/LemonsqueezyApiResponseRelationshipsSubscriptionInvoice.ts +models/LemonsqueezyApiResponseSelfLink.ts +models/LemonsqueezyBillingAddress.ts +models/LemonsqueezyCheckoutAttributes.ts +models/LemonsqueezyCheckoutData.ts +models/LemonsqueezyCheckoutOptions.ts +models/LemonsqueezyCheckoutProductOptions.ts +models/LemonsqueezySubscription.ts +models/LemonsqueezySubscriptionInvoiceAttributes.ts +models/LemonsqueezySubscriptionInvoiceAttributesUrls.ts +models/LemonsqueezySubscriptionItem.ts +models/LemonsqueezySubscriptionPause.ts +models/LemonsqueezySubscriptionURLs.ts models/ModelsBertAIResults.ts models/ModelsRobertaAIResults.ts +models/ModelsSubscription.ts +models/ModelsSubscriptionPlan.ts +models/ModelsSubscriptionPlanSlug.ts models/ModelsYoutubeAnalysisLandingResults.ts models/ModelsYoutubeAnalysisResults.ts models/ModelsYoutubeAnalyzerLandingReqBody.ts diff --git a/gptube/gptube-api/generated-api/apis/DefaultApi.ts b/gptube/gptube-api/generated-api/apis/DefaultApi.ts index 0ec829e..e9ed3d0 100644 --- a/gptube/gptube-api/generated-api/apis/DefaultApi.ts +++ b/gptube/gptube-api/generated-api/apis/DefaultApi.ts @@ -17,6 +17,11 @@ import * as runtime from '../runtime'; import type { FiberError, HandlersHelloApiMessage, + LemonsqueezyApiResponseLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount, + LemonsqueezyApiResponseLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription, + LemonsqueezyApiResponseListLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice, + ModelsSubscription, + ModelsSubscriptionPlan, ModelsYoutubeAnalyzerLandingReqBody, ModelsYoutubeAnalyzerLandingRespBody, ModelsYoutubeAnalyzerReqBody, @@ -33,6 +38,16 @@ import { FiberErrorToJSON, HandlersHelloApiMessageFromJSON, HandlersHelloApiMessageToJSON, + LemonsqueezyApiResponseLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscountFromJSON, + LemonsqueezyApiResponseLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscountToJSON, + LemonsqueezyApiResponseLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscriptionFromJSON, + LemonsqueezyApiResponseLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscriptionToJSON, + LemonsqueezyApiResponseListLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoiceFromJSON, + LemonsqueezyApiResponseListLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoiceToJSON, + ModelsSubscriptionFromJSON, + ModelsSubscriptionToJSON, + ModelsSubscriptionPlanFromJSON, + ModelsSubscriptionPlanToJSON, ModelsYoutubeAnalyzerLandingReqBodyFromJSON, ModelsYoutubeAnalyzerLandingReqBodyToJSON, ModelsYoutubeAnalyzerLandingRespBodyFromJSON, @@ -85,6 +100,33 @@ export interface ApiYoutubeVideosVideoIdNegativeCommentsGetRequest { pageSize?: number; } +export interface BillingCancelSubscriptionGetRequest { + subscriptionId: string; +} + +export interface BillingCheckoutGetRequest { + variantId: string; + userId: string; +} + +export interface BillingInvoicesGetRequest { + subscriptionId: string; + page?: number; + pageSize?: number; +} + +export interface BillingResumeSubscriptionGetRequest { + subscriptionId: string; +} + +export interface BillingSubscriptionsGetRequest { + userId: string; +} + +export interface BillingUpdatePaymentMethodGetRequest { + subscriptionId: string; +} + /** * */ @@ -355,6 +397,90 @@ export class DefaultApi extends runtime.BaseAPI { return await response.value(); } + /** + * An endpoint to cancel a subscription + * Cancel a subscription + */ + async billingCancelSubscriptionGetRaw(requestParameters: BillingCancelSubscriptionGetRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise> { + if (requestParameters.subscriptionId === null || requestParameters.subscriptionId === undefined) { + throw new runtime.RequiredError('subscriptionId','Required parameter requestParameters.subscriptionId was null or undefined when calling billingCancelSubscriptionGet.'); + } + + const queryParameters: any = {}; + + if (requestParameters.subscriptionId !== undefined) { + queryParameters['subscription_id'] = requestParameters.subscriptionId; + } + + const headerParameters: runtime.HTTPHeaders = {}; + + const response = await this.request({ + path: `/billing/cancel-subscription`, + method: 'GET', + headers: headerParameters, + query: queryParameters, + }, initOverrides); + + if (this.isJsonMime(response.headers.get('content-type'))) { + return new runtime.JSONApiResponse(response); + } else { + return new runtime.TextApiResponse(response) as any; + } + } + + /** + * An endpoint to cancel a subscription + * Cancel a subscription + */ + async billingCancelSubscriptionGet(requestParameters: BillingCancelSubscriptionGetRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise { + const response = await this.billingCancelSubscriptionGetRaw(requestParameters, initOverrides); + return await response.value(); + } + + /** + * An endpoint to retrieve the URL for a subscription plan sending the account email as well. + * Get the checkout URL for a subscription plan + */ + async billingCheckoutGetRaw(requestParameters: BillingCheckoutGetRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise> { + if (requestParameters.variantId === null || requestParameters.variantId === undefined) { + throw new runtime.RequiredError('variantId','Required parameter requestParameters.variantId was null or undefined when calling billingCheckoutGet.'); + } + + if (requestParameters.userId === null || requestParameters.userId === undefined) { + throw new runtime.RequiredError('userId','Required parameter requestParameters.userId was null or undefined when calling billingCheckoutGet.'); + } + + const queryParameters: any = {}; + + if (requestParameters.variantId !== undefined) { + queryParameters['variant_id'] = requestParameters.variantId; + } + + if (requestParameters.userId !== undefined) { + queryParameters['user_id'] = requestParameters.userId; + } + + const headerParameters: runtime.HTTPHeaders = {}; + + const response = await this.request({ + path: `/billing/checkout`, + method: 'GET', + headers: headerParameters, + query: queryParameters, + }, initOverrides); + + return new runtime.JSONApiResponse(response, (jsonValue) => LemonsqueezyApiResponseLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscountFromJSON(jsonValue)); + } + + /** + * An endpoint to retrieve the URL for a subscription plan sending the account email as well. + * Get the checkout URL for a subscription plan + */ + async billingCheckoutGet(requestParameters: BillingCheckoutGetRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise { + const response = await this.billingCheckoutGetRaw(requestParameters, initOverrides); + return await response.value(); + } + /** * An endpoint used to test the billing api stability * Hello message from the billing api @@ -383,4 +509,188 @@ export class DefaultApi extends runtime.BaseAPI { return await response.value(); } + /** + * An endpoint to retrieve the invoices from a user\'s subscription + * Get the latest Invoices from a subscription + */ + async billingInvoicesGetRaw(requestParameters: BillingInvoicesGetRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise> { + if (requestParameters.subscriptionId === null || requestParameters.subscriptionId === undefined) { + throw new runtime.RequiredError('subscriptionId','Required parameter requestParameters.subscriptionId was null or undefined when calling billingInvoicesGet.'); + } + + const queryParameters: any = {}; + + if (requestParameters.subscriptionId !== undefined) { + queryParameters['subscription_id'] = requestParameters.subscriptionId; + } + + if (requestParameters.page !== undefined) { + queryParameters['page'] = requestParameters.page; + } + + if (requestParameters.pageSize !== undefined) { + queryParameters['page_size'] = requestParameters.pageSize; + } + + const headerParameters: runtime.HTTPHeaders = {}; + + const response = await this.request({ + path: `/billing/invoices`, + method: 'GET', + headers: headerParameters, + query: queryParameters, + }, initOverrides); + + return new runtime.JSONApiResponse(response, (jsonValue) => LemonsqueezyApiResponseListLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoiceFromJSON(jsonValue)); + } + + /** + * An endpoint to retrieve the invoices from a user\'s subscription + * Get the latest Invoices from a subscription + */ + async billingInvoicesGet(requestParameters: BillingInvoicesGetRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise { + const response = await this.billingInvoicesGetRaw(requestParameters, initOverrides); + return await response.value(); + } + + /** + * An endpoint to resume a cancelled subscription + * Resume a subscription + */ + async billingResumeSubscriptionGetRaw(requestParameters: BillingResumeSubscriptionGetRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise> { + if (requestParameters.subscriptionId === null || requestParameters.subscriptionId === undefined) { + throw new runtime.RequiredError('subscriptionId','Required parameter requestParameters.subscriptionId was null or undefined when calling billingResumeSubscriptionGet.'); + } + + const queryParameters: any = {}; + + if (requestParameters.subscriptionId !== undefined) { + queryParameters['subscription_id'] = requestParameters.subscriptionId; + } + + const headerParameters: runtime.HTTPHeaders = {}; + + const response = await this.request({ + path: `/billing/resume-subscription`, + method: 'GET', + headers: headerParameters, + query: queryParameters, + }, initOverrides); + + if (this.isJsonMime(response.headers.get('content-type'))) { + return new runtime.JSONApiResponse(response); + } else { + return new runtime.TextApiResponse(response) as any; + } + } + + /** + * An endpoint to resume a cancelled subscription + * Resume a subscription + */ + async billingResumeSubscriptionGet(requestParameters: BillingResumeSubscriptionGetRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise { + const response = await this.billingResumeSubscriptionGetRaw(requestParameters, initOverrides); + return await response.value(); + } + + /** + * An endpoint to retrieve the subscription plan offered by GPTube with its price, features, etc. + * Get the subscription plans offered by GPTube + */ + async billingSubscriptionPlansGetRaw(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise>> { + const queryParameters: any = {}; + + const headerParameters: runtime.HTTPHeaders = {}; + + const response = await this.request({ + path: `/billing/subscription-plans`, + method: 'GET', + headers: headerParameters, + query: queryParameters, + }, initOverrides); + + return new runtime.JSONApiResponse(response, (jsonValue) => jsonValue.map(ModelsSubscriptionPlanFromJSON)); + } + + /** + * An endpoint to retrieve the subscription plan offered by GPTube with its price, features, etc. + * Get the subscription plans offered by GPTube + */ + async billingSubscriptionPlansGet(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise> { + const response = await this.billingSubscriptionPlansGetRaw(initOverrides); + return await response.value(); + } + + /** + * An endpoint to retrieve all the subscriptions belonging to an account + * Get the subscribed subscriptions of an account + */ + async billingSubscriptionsGetRaw(requestParameters: BillingSubscriptionsGetRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise>> { + if (requestParameters.userId === null || requestParameters.userId === undefined) { + throw new runtime.RequiredError('userId','Required parameter requestParameters.userId was null or undefined when calling billingSubscriptionsGet.'); + } + + const queryParameters: any = {}; + + if (requestParameters.userId !== undefined) { + queryParameters['user_id'] = requestParameters.userId; + } + + const headerParameters: runtime.HTTPHeaders = {}; + + const response = await this.request({ + path: `/billing/subscriptions`, + method: 'GET', + headers: headerParameters, + query: queryParameters, + }, initOverrides); + + return new runtime.JSONApiResponse(response, (jsonValue) => jsonValue.map(ModelsSubscriptionFromJSON)); + } + + /** + * An endpoint to retrieve all the subscriptions belonging to an account + * Get the subscribed subscriptions of an account + */ + async billingSubscriptionsGet(requestParameters: BillingSubscriptionsGetRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise> { + const response = await this.billingSubscriptionsGetRaw(requestParameters, initOverrides); + return await response.value(); + } + + /** + * An endpoint to retrieve the URL to update the payment method for a subscription + * Get the update payment method URL for a subscription + */ + async billingUpdatePaymentMethodGetRaw(requestParameters: BillingUpdatePaymentMethodGetRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise> { + if (requestParameters.subscriptionId === null || requestParameters.subscriptionId === undefined) { + throw new runtime.RequiredError('subscriptionId','Required parameter requestParameters.subscriptionId was null or undefined when calling billingUpdatePaymentMethodGet.'); + } + + const queryParameters: any = {}; + + if (requestParameters.subscriptionId !== undefined) { + queryParameters['subscription_id'] = requestParameters.subscriptionId; + } + + const headerParameters: runtime.HTTPHeaders = {}; + + const response = await this.request({ + path: `/billing/update-payment-method`, + method: 'GET', + headers: headerParameters, + query: queryParameters, + }, initOverrides); + + return new runtime.JSONApiResponse(response, (jsonValue) => LemonsqueezyApiResponseLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscriptionFromJSON(jsonValue)); + } + + /** + * An endpoint to retrieve the URL to update the payment method for a subscription + * Get the update payment method URL for a subscription + */ + async billingUpdatePaymentMethodGet(requestParameters: BillingUpdatePaymentMethodGetRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise { + const response = await this.billingUpdatePaymentMethodGetRaw(requestParameters, initOverrides); + return await response.value(); + } + } diff --git a/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseDataLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount.ts b/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseDataLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount.ts new file mode 100644 index 0000000..1d0464f --- /dev/null +++ b/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseDataLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount.ts @@ -0,0 +1,116 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * GPTube API swagger docs + * This is the API documentation of GPTube + * + * The version of the OpenAPI document: 1.0 + * Contact: luckly083@gmail.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +import type { LemonsqueezyApiResponseRelationshipsDiscount } from './LemonsqueezyApiResponseRelationshipsDiscount'; +import { + LemonsqueezyApiResponseRelationshipsDiscountFromJSON, + LemonsqueezyApiResponseRelationshipsDiscountFromJSONTyped, + LemonsqueezyApiResponseRelationshipsDiscountToJSON, +} from './LemonsqueezyApiResponseRelationshipsDiscount'; +import type { LemonsqueezyApiResponseSelfLink } from './LemonsqueezyApiResponseSelfLink'; +import { + LemonsqueezyApiResponseSelfLinkFromJSON, + LemonsqueezyApiResponseSelfLinkFromJSONTyped, + LemonsqueezyApiResponseSelfLinkToJSON, +} from './LemonsqueezyApiResponseSelfLink'; +import type { LemonsqueezyCheckoutAttributes } from './LemonsqueezyCheckoutAttributes'; +import { + LemonsqueezyCheckoutAttributesFromJSON, + LemonsqueezyCheckoutAttributesFromJSONTyped, + LemonsqueezyCheckoutAttributesToJSON, +} from './LemonsqueezyCheckoutAttributes'; + +/** + * + * @export + * @interface LemonsqueezyApiResponseDataLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount + */ +export interface LemonsqueezyApiResponseDataLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount { + /** + * + * @type {LemonsqueezyCheckoutAttributes} + * @memberof LemonsqueezyApiResponseDataLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount + */ + attributes?: LemonsqueezyCheckoutAttributes; + /** + * + * @type {string} + * @memberof LemonsqueezyApiResponseDataLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount + */ + id?: string; + /** + * + * @type {LemonsqueezyApiResponseSelfLink} + * @memberof LemonsqueezyApiResponseDataLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount + */ + links?: LemonsqueezyApiResponseSelfLink; + /** + * + * @type {LemonsqueezyApiResponseRelationshipsDiscount} + * @memberof LemonsqueezyApiResponseDataLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount + */ + relationships?: LemonsqueezyApiResponseRelationshipsDiscount; + /** + * + * @type {string} + * @memberof LemonsqueezyApiResponseDataLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount + */ + type?: string; +} + +/** + * Check if a given object implements the LemonsqueezyApiResponseDataLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount interface. + */ +export function instanceOfLemonsqueezyApiResponseDataLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount(value: object): boolean { + let isInstance = true; + + return isInstance; +} + +export function LemonsqueezyApiResponseDataLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscountFromJSON(json: any): LemonsqueezyApiResponseDataLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount { + return LemonsqueezyApiResponseDataLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscountFromJSONTyped(json, false); +} + +export function LemonsqueezyApiResponseDataLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscountFromJSONTyped(json: any, ignoreDiscriminator: boolean): LemonsqueezyApiResponseDataLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'attributes': !exists(json, 'attributes') ? undefined : LemonsqueezyCheckoutAttributesFromJSON(json['attributes']), + 'id': !exists(json, 'id') ? undefined : json['id'], + 'links': !exists(json, 'links') ? undefined : LemonsqueezyApiResponseSelfLinkFromJSON(json['links']), + 'relationships': !exists(json, 'relationships') ? undefined : LemonsqueezyApiResponseRelationshipsDiscountFromJSON(json['relationships']), + 'type': !exists(json, 'type') ? undefined : json['type'], + }; +} + +export function LemonsqueezyApiResponseDataLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscountToJSON(value?: LemonsqueezyApiResponseDataLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'attributes': LemonsqueezyCheckoutAttributesToJSON(value.attributes), + 'id': value.id, + 'links': LemonsqueezyApiResponseSelfLinkToJSON(value.links), + 'relationships': LemonsqueezyApiResponseRelationshipsDiscountToJSON(value.relationships), + 'type': value.type, + }; +} + diff --git a/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseDataLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice.ts b/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseDataLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice.ts new file mode 100644 index 0000000..458b891 --- /dev/null +++ b/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseDataLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice.ts @@ -0,0 +1,116 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * GPTube API swagger docs + * This is the API documentation of GPTube + * + * The version of the OpenAPI document: 1.0 + * Contact: luckly083@gmail.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +import type { LemonsqueezyApiResponseRelationshipsSubscriptionInvoice } from './LemonsqueezyApiResponseRelationshipsSubscriptionInvoice'; +import { + LemonsqueezyApiResponseRelationshipsSubscriptionInvoiceFromJSON, + LemonsqueezyApiResponseRelationshipsSubscriptionInvoiceFromJSONTyped, + LemonsqueezyApiResponseRelationshipsSubscriptionInvoiceToJSON, +} from './LemonsqueezyApiResponseRelationshipsSubscriptionInvoice'; +import type { LemonsqueezyApiResponseSelfLink } from './LemonsqueezyApiResponseSelfLink'; +import { + LemonsqueezyApiResponseSelfLinkFromJSON, + LemonsqueezyApiResponseSelfLinkFromJSONTyped, + LemonsqueezyApiResponseSelfLinkToJSON, +} from './LemonsqueezyApiResponseSelfLink'; +import type { LemonsqueezySubscriptionInvoiceAttributes } from './LemonsqueezySubscriptionInvoiceAttributes'; +import { + LemonsqueezySubscriptionInvoiceAttributesFromJSON, + LemonsqueezySubscriptionInvoiceAttributesFromJSONTyped, + LemonsqueezySubscriptionInvoiceAttributesToJSON, +} from './LemonsqueezySubscriptionInvoiceAttributes'; + +/** + * + * @export + * @interface LemonsqueezyApiResponseDataLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice + */ +export interface LemonsqueezyApiResponseDataLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice { + /** + * + * @type {LemonsqueezySubscriptionInvoiceAttributes} + * @memberof LemonsqueezyApiResponseDataLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice + */ + attributes?: LemonsqueezySubscriptionInvoiceAttributes; + /** + * + * @type {string} + * @memberof LemonsqueezyApiResponseDataLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice + */ + id?: string; + /** + * + * @type {LemonsqueezyApiResponseSelfLink} + * @memberof LemonsqueezyApiResponseDataLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice + */ + links?: LemonsqueezyApiResponseSelfLink; + /** + * + * @type {LemonsqueezyApiResponseRelationshipsSubscriptionInvoice} + * @memberof LemonsqueezyApiResponseDataLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice + */ + relationships?: LemonsqueezyApiResponseRelationshipsSubscriptionInvoice; + /** + * + * @type {string} + * @memberof LemonsqueezyApiResponseDataLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice + */ + type?: string; +} + +/** + * Check if a given object implements the LemonsqueezyApiResponseDataLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice interface. + */ +export function instanceOfLemonsqueezyApiResponseDataLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice(value: object): boolean { + let isInstance = true; + + return isInstance; +} + +export function LemonsqueezyApiResponseDataLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoiceFromJSON(json: any): LemonsqueezyApiResponseDataLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice { + return LemonsqueezyApiResponseDataLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoiceFromJSONTyped(json, false); +} + +export function LemonsqueezyApiResponseDataLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoiceFromJSONTyped(json: any, ignoreDiscriminator: boolean): LemonsqueezyApiResponseDataLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'attributes': !exists(json, 'attributes') ? undefined : LemonsqueezySubscriptionInvoiceAttributesFromJSON(json['attributes']), + 'id': !exists(json, 'id') ? undefined : json['id'], + 'links': !exists(json, 'links') ? undefined : LemonsqueezyApiResponseSelfLinkFromJSON(json['links']), + 'relationships': !exists(json, 'relationships') ? undefined : LemonsqueezyApiResponseRelationshipsSubscriptionInvoiceFromJSON(json['relationships']), + 'type': !exists(json, 'type') ? undefined : json['type'], + }; +} + +export function LemonsqueezyApiResponseDataLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoiceToJSON(value?: LemonsqueezyApiResponseDataLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'attributes': LemonsqueezySubscriptionInvoiceAttributesToJSON(value.attributes), + 'id': value.id, + 'links': LemonsqueezyApiResponseSelfLinkToJSON(value.links), + 'relationships': LemonsqueezyApiResponseRelationshipsSubscriptionInvoiceToJSON(value.relationships), + 'type': value.type, + }; +} + diff --git a/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseDataLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription.ts b/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseDataLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription.ts new file mode 100644 index 0000000..3efc2e9 --- /dev/null +++ b/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseDataLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription.ts @@ -0,0 +1,116 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * GPTube API swagger docs + * This is the API documentation of GPTube + * + * The version of the OpenAPI document: 1.0 + * Contact: luckly083@gmail.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +import type { LemonsqueezyApiResponseRelationshipsSubscription } from './LemonsqueezyApiResponseRelationshipsSubscription'; +import { + LemonsqueezyApiResponseRelationshipsSubscriptionFromJSON, + LemonsqueezyApiResponseRelationshipsSubscriptionFromJSONTyped, + LemonsqueezyApiResponseRelationshipsSubscriptionToJSON, +} from './LemonsqueezyApiResponseRelationshipsSubscription'; +import type { LemonsqueezyApiResponseSelfLink } from './LemonsqueezyApiResponseSelfLink'; +import { + LemonsqueezyApiResponseSelfLinkFromJSON, + LemonsqueezyApiResponseSelfLinkFromJSONTyped, + LemonsqueezyApiResponseSelfLinkToJSON, +} from './LemonsqueezyApiResponseSelfLink'; +import type { LemonsqueezySubscription } from './LemonsqueezySubscription'; +import { + LemonsqueezySubscriptionFromJSON, + LemonsqueezySubscriptionFromJSONTyped, + LemonsqueezySubscriptionToJSON, +} from './LemonsqueezySubscription'; + +/** + * + * @export + * @interface LemonsqueezyApiResponseDataLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription + */ +export interface LemonsqueezyApiResponseDataLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription { + /** + * + * @type {LemonsqueezySubscription} + * @memberof LemonsqueezyApiResponseDataLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription + */ + attributes?: LemonsqueezySubscription; + /** + * + * @type {string} + * @memberof LemonsqueezyApiResponseDataLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription + */ + id?: string; + /** + * + * @type {LemonsqueezyApiResponseSelfLink} + * @memberof LemonsqueezyApiResponseDataLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription + */ + links?: LemonsqueezyApiResponseSelfLink; + /** + * + * @type {LemonsqueezyApiResponseRelationshipsSubscription} + * @memberof LemonsqueezyApiResponseDataLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription + */ + relationships?: LemonsqueezyApiResponseRelationshipsSubscription; + /** + * + * @type {string} + * @memberof LemonsqueezyApiResponseDataLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription + */ + type?: string; +} + +/** + * Check if a given object implements the LemonsqueezyApiResponseDataLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription interface. + */ +export function instanceOfLemonsqueezyApiResponseDataLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription(value: object): boolean { + let isInstance = true; + + return isInstance; +} + +export function LemonsqueezyApiResponseDataLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscriptionFromJSON(json: any): LemonsqueezyApiResponseDataLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription { + return LemonsqueezyApiResponseDataLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscriptionFromJSONTyped(json, false); +} + +export function LemonsqueezyApiResponseDataLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscriptionFromJSONTyped(json: any, ignoreDiscriminator: boolean): LemonsqueezyApiResponseDataLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'attributes': !exists(json, 'attributes') ? undefined : LemonsqueezySubscriptionFromJSON(json['attributes']), + 'id': !exists(json, 'id') ? undefined : json['id'], + 'links': !exists(json, 'links') ? undefined : LemonsqueezyApiResponseSelfLinkFromJSON(json['links']), + 'relationships': !exists(json, 'relationships') ? undefined : LemonsqueezyApiResponseRelationshipsSubscriptionFromJSON(json['relationships']), + 'type': !exists(json, 'type') ? undefined : json['type'], + }; +} + +export function LemonsqueezyApiResponseDataLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscriptionToJSON(value?: LemonsqueezyApiResponseDataLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'attributes': LemonsqueezySubscriptionToJSON(value.attributes), + 'id': value.id, + 'links': LemonsqueezyApiResponseSelfLinkToJSON(value.links), + 'relationships': LemonsqueezyApiResponseRelationshipsSubscriptionToJSON(value.relationships), + 'type': value.type, + }; +} + diff --git a/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseJSONAPI.ts b/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseJSONAPI.ts new file mode 100644 index 0000000..e0cc6f9 --- /dev/null +++ b/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseJSONAPI.ts @@ -0,0 +1,65 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * GPTube API swagger docs + * This is the API documentation of GPTube + * + * The version of the OpenAPI document: 1.0 + * Contact: luckly083@gmail.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +/** + * + * @export + * @interface LemonsqueezyApiResponseJSONAPI + */ +export interface LemonsqueezyApiResponseJSONAPI { + /** + * + * @type {string} + * @memberof LemonsqueezyApiResponseJSONAPI + */ + version?: string; +} + +/** + * Check if a given object implements the LemonsqueezyApiResponseJSONAPI interface. + */ +export function instanceOfLemonsqueezyApiResponseJSONAPI(value: object): boolean { + let isInstance = true; + + return isInstance; +} + +export function LemonsqueezyApiResponseJSONAPIFromJSON(json: any): LemonsqueezyApiResponseJSONAPI { + return LemonsqueezyApiResponseJSONAPIFromJSONTyped(json, false); +} + +export function LemonsqueezyApiResponseJSONAPIFromJSONTyped(json: any, ignoreDiscriminator: boolean): LemonsqueezyApiResponseJSONAPI { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'version': !exists(json, 'version') ? undefined : json['version'], + }; +} + +export function LemonsqueezyApiResponseJSONAPIToJSON(value?: LemonsqueezyApiResponseJSONAPI | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'version': value.version, + }; +} + diff --git a/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount.ts b/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount.ts new file mode 100644 index 0000000..b4f43a1 --- /dev/null +++ b/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount.ts @@ -0,0 +1,100 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * GPTube API swagger docs + * This is the API documentation of GPTube + * + * The version of the OpenAPI document: 1.0 + * Contact: luckly083@gmail.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +import type { LemonsqueezyApiResponseDataLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount } from './LemonsqueezyApiResponseDataLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount'; +import { + LemonsqueezyApiResponseDataLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscountFromJSON, + LemonsqueezyApiResponseDataLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscountFromJSONTyped, + LemonsqueezyApiResponseDataLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscountToJSON, +} from './LemonsqueezyApiResponseDataLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount'; +import type { LemonsqueezyApiResponseJSONAPI } from './LemonsqueezyApiResponseJSONAPI'; +import { + LemonsqueezyApiResponseJSONAPIFromJSON, + LemonsqueezyApiResponseJSONAPIFromJSONTyped, + LemonsqueezyApiResponseJSONAPIToJSON, +} from './LemonsqueezyApiResponseJSONAPI'; +import type { LemonsqueezyApiResponseSelfLink } from './LemonsqueezyApiResponseSelfLink'; +import { + LemonsqueezyApiResponseSelfLinkFromJSON, + LemonsqueezyApiResponseSelfLinkFromJSONTyped, + LemonsqueezyApiResponseSelfLinkToJSON, +} from './LemonsqueezyApiResponseSelfLink'; + +/** + * + * @export + * @interface LemonsqueezyApiResponseLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount + */ +export interface LemonsqueezyApiResponseLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount { + /** + * + * @type {LemonsqueezyApiResponseDataLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount} + * @memberof LemonsqueezyApiResponseLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount + */ + data?: LemonsqueezyApiResponseDataLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount; + /** + * + * @type {LemonsqueezyApiResponseJSONAPI} + * @memberof LemonsqueezyApiResponseLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount + */ + jsonapi?: LemonsqueezyApiResponseJSONAPI; + /** + * + * @type {LemonsqueezyApiResponseSelfLink} + * @memberof LemonsqueezyApiResponseLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount + */ + links?: LemonsqueezyApiResponseSelfLink; +} + +/** + * Check if a given object implements the LemonsqueezyApiResponseLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount interface. + */ +export function instanceOfLemonsqueezyApiResponseLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount(value: object): boolean { + let isInstance = true; + + return isInstance; +} + +export function LemonsqueezyApiResponseLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscountFromJSON(json: any): LemonsqueezyApiResponseLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount { + return LemonsqueezyApiResponseLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscountFromJSONTyped(json, false); +} + +export function LemonsqueezyApiResponseLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscountFromJSONTyped(json: any, ignoreDiscriminator: boolean): LemonsqueezyApiResponseLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'data': !exists(json, 'data') ? undefined : LemonsqueezyApiResponseDataLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscountFromJSON(json['data']), + 'jsonapi': !exists(json, 'jsonapi') ? undefined : LemonsqueezyApiResponseJSONAPIFromJSON(json['jsonapi']), + 'links': !exists(json, 'links') ? undefined : LemonsqueezyApiResponseSelfLinkFromJSON(json['links']), + }; +} + +export function LemonsqueezyApiResponseLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscountToJSON(value?: LemonsqueezyApiResponseLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'data': LemonsqueezyApiResponseDataLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscountToJSON(value.data), + 'jsonapi': LemonsqueezyApiResponseJSONAPIToJSON(value.jsonapi), + 'links': LemonsqueezyApiResponseSelfLinkToJSON(value.links), + }; +} + diff --git a/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription.ts b/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription.ts new file mode 100644 index 0000000..364956f --- /dev/null +++ b/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription.ts @@ -0,0 +1,100 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * GPTube API swagger docs + * This is the API documentation of GPTube + * + * The version of the OpenAPI document: 1.0 + * Contact: luckly083@gmail.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +import type { LemonsqueezyApiResponseDataLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription } from './LemonsqueezyApiResponseDataLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription'; +import { + LemonsqueezyApiResponseDataLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscriptionFromJSON, + LemonsqueezyApiResponseDataLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscriptionFromJSONTyped, + LemonsqueezyApiResponseDataLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscriptionToJSON, +} from './LemonsqueezyApiResponseDataLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription'; +import type { LemonsqueezyApiResponseJSONAPI } from './LemonsqueezyApiResponseJSONAPI'; +import { + LemonsqueezyApiResponseJSONAPIFromJSON, + LemonsqueezyApiResponseJSONAPIFromJSONTyped, + LemonsqueezyApiResponseJSONAPIToJSON, +} from './LemonsqueezyApiResponseJSONAPI'; +import type { LemonsqueezyApiResponseSelfLink } from './LemonsqueezyApiResponseSelfLink'; +import { + LemonsqueezyApiResponseSelfLinkFromJSON, + LemonsqueezyApiResponseSelfLinkFromJSONTyped, + LemonsqueezyApiResponseSelfLinkToJSON, +} from './LemonsqueezyApiResponseSelfLink'; + +/** + * + * @export + * @interface LemonsqueezyApiResponseLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription + */ +export interface LemonsqueezyApiResponseLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription { + /** + * + * @type {LemonsqueezyApiResponseDataLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription} + * @memberof LemonsqueezyApiResponseLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription + */ + data?: LemonsqueezyApiResponseDataLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription; + /** + * + * @type {LemonsqueezyApiResponseJSONAPI} + * @memberof LemonsqueezyApiResponseLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription + */ + jsonapi?: LemonsqueezyApiResponseJSONAPI; + /** + * + * @type {LemonsqueezyApiResponseSelfLink} + * @memberof LemonsqueezyApiResponseLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription + */ + links?: LemonsqueezyApiResponseSelfLink; +} + +/** + * Check if a given object implements the LemonsqueezyApiResponseLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription interface. + */ +export function instanceOfLemonsqueezyApiResponseLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription(value: object): boolean { + let isInstance = true; + + return isInstance; +} + +export function LemonsqueezyApiResponseLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscriptionFromJSON(json: any): LemonsqueezyApiResponseLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription { + return LemonsqueezyApiResponseLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscriptionFromJSONTyped(json, false); +} + +export function LemonsqueezyApiResponseLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscriptionFromJSONTyped(json: any, ignoreDiscriminator: boolean): LemonsqueezyApiResponseLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'data': !exists(json, 'data') ? undefined : LemonsqueezyApiResponseDataLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscriptionFromJSON(json['data']), + 'jsonapi': !exists(json, 'jsonapi') ? undefined : LemonsqueezyApiResponseJSONAPIFromJSON(json['jsonapi']), + 'links': !exists(json, 'links') ? undefined : LemonsqueezyApiResponseSelfLinkFromJSON(json['links']), + }; +} + +export function LemonsqueezyApiResponseLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscriptionToJSON(value?: LemonsqueezyApiResponseLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'data': LemonsqueezyApiResponseDataLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscriptionToJSON(value.data), + 'jsonapi': LemonsqueezyApiResponseJSONAPIToJSON(value.jsonapi), + 'links': LemonsqueezyApiResponseSelfLinkToJSON(value.links), + }; +} + diff --git a/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseLink.ts b/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseLink.ts new file mode 100644 index 0000000..3443703 --- /dev/null +++ b/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseLink.ts @@ -0,0 +1,73 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * GPTube API swagger docs + * This is the API documentation of GPTube + * + * The version of the OpenAPI document: 1.0 + * Contact: luckly083@gmail.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +/** + * + * @export + * @interface LemonsqueezyApiResponseLink + */ +export interface LemonsqueezyApiResponseLink { + /** + * + * @type {string} + * @memberof LemonsqueezyApiResponseLink + */ + related?: string; + /** + * + * @type {string} + * @memberof LemonsqueezyApiResponseLink + */ + self?: string; +} + +/** + * Check if a given object implements the LemonsqueezyApiResponseLink interface. + */ +export function instanceOfLemonsqueezyApiResponseLink(value: object): boolean { + let isInstance = true; + + return isInstance; +} + +export function LemonsqueezyApiResponseLinkFromJSON(json: any): LemonsqueezyApiResponseLink { + return LemonsqueezyApiResponseLinkFromJSONTyped(json, false); +} + +export function LemonsqueezyApiResponseLinkFromJSONTyped(json: any, ignoreDiscriminator: boolean): LemonsqueezyApiResponseLink { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'related': !exists(json, 'related') ? undefined : json['related'], + 'self': !exists(json, 'self') ? undefined : json['self'], + }; +} + +export function LemonsqueezyApiResponseLinkToJSON(value?: LemonsqueezyApiResponseLink | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'related': value.related, + 'self': value.self, + }; +} + diff --git a/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseLinks.ts b/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseLinks.ts new file mode 100644 index 0000000..14a29a4 --- /dev/null +++ b/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseLinks.ts @@ -0,0 +1,72 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * GPTube API swagger docs + * This is the API documentation of GPTube + * + * The version of the OpenAPI document: 1.0 + * Contact: luckly083@gmail.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +import type { LemonsqueezyApiResponseLink } from './LemonsqueezyApiResponseLink'; +import { + LemonsqueezyApiResponseLinkFromJSON, + LemonsqueezyApiResponseLinkFromJSONTyped, + LemonsqueezyApiResponseLinkToJSON, +} from './LemonsqueezyApiResponseLink'; + +/** + * + * @export + * @interface LemonsqueezyApiResponseLinks + */ +export interface LemonsqueezyApiResponseLinks { + /** + * + * @type {LemonsqueezyApiResponseLink} + * @memberof LemonsqueezyApiResponseLinks + */ + links?: LemonsqueezyApiResponseLink; +} + +/** + * Check if a given object implements the LemonsqueezyApiResponseLinks interface. + */ +export function instanceOfLemonsqueezyApiResponseLinks(value: object): boolean { + let isInstance = true; + + return isInstance; +} + +export function LemonsqueezyApiResponseLinksFromJSON(json: any): LemonsqueezyApiResponseLinks { + return LemonsqueezyApiResponseLinksFromJSONTyped(json, false); +} + +export function LemonsqueezyApiResponseLinksFromJSONTyped(json: any, ignoreDiscriminator: boolean): LemonsqueezyApiResponseLinks { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'links': !exists(json, 'links') ? undefined : LemonsqueezyApiResponseLinkFromJSON(json['links']), + }; +} + +export function LemonsqueezyApiResponseLinksToJSON(value?: LemonsqueezyApiResponseLinks | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'links': LemonsqueezyApiResponseLinkToJSON(value.links), + }; +} + diff --git a/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseListLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice.ts b/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseListLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice.ts new file mode 100644 index 0000000..53e7c5d --- /dev/null +++ b/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseListLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice.ts @@ -0,0 +1,114 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * GPTube API swagger docs + * This is the API documentation of GPTube + * + * The version of the OpenAPI document: 1.0 + * Contact: luckly083@gmail.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +import type { LemonsqueezyApiResponseDataLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice } from './LemonsqueezyApiResponseDataLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice'; +import { + LemonsqueezyApiResponseDataLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoiceFromJSON, + LemonsqueezyApiResponseDataLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoiceFromJSONTyped, + LemonsqueezyApiResponseDataLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoiceToJSON, +} from './LemonsqueezyApiResponseDataLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice'; +import type { LemonsqueezyApiResponseJSONAPI } from './LemonsqueezyApiResponseJSONAPI'; +import { + LemonsqueezyApiResponseJSONAPIFromJSON, + LemonsqueezyApiResponseJSONAPIFromJSONTyped, + LemonsqueezyApiResponseJSONAPIToJSON, +} from './LemonsqueezyApiResponseJSONAPI'; +import type { LemonsqueezyApiResponseListLink } from './LemonsqueezyApiResponseListLink'; +import { + LemonsqueezyApiResponseListLinkFromJSON, + LemonsqueezyApiResponseListLinkFromJSONTyped, + LemonsqueezyApiResponseListLinkToJSON, +} from './LemonsqueezyApiResponseListLink'; +import type { LemonsqueezyApiResponseListMeta } from './LemonsqueezyApiResponseListMeta'; +import { + LemonsqueezyApiResponseListMetaFromJSON, + LemonsqueezyApiResponseListMetaFromJSONTyped, + LemonsqueezyApiResponseListMetaToJSON, +} from './LemonsqueezyApiResponseListMeta'; + +/** + * + * @export + * @interface LemonsqueezyApiResponseListLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice + */ +export interface LemonsqueezyApiResponseListLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice { + /** + * + * @type {Array} + * @memberof LemonsqueezyApiResponseListLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice + */ + data?: Array; + /** + * + * @type {LemonsqueezyApiResponseJSONAPI} + * @memberof LemonsqueezyApiResponseListLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice + */ + jsonapi?: LemonsqueezyApiResponseJSONAPI; + /** + * + * @type {LemonsqueezyApiResponseListLink} + * @memberof LemonsqueezyApiResponseListLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice + */ + links?: LemonsqueezyApiResponseListLink; + /** + * + * @type {LemonsqueezyApiResponseListMeta} + * @memberof LemonsqueezyApiResponseListLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice + */ + meta?: LemonsqueezyApiResponseListMeta; +} + +/** + * Check if a given object implements the LemonsqueezyApiResponseListLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice interface. + */ +export function instanceOfLemonsqueezyApiResponseListLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice(value: object): boolean { + let isInstance = true; + + return isInstance; +} + +export function LemonsqueezyApiResponseListLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoiceFromJSON(json: any): LemonsqueezyApiResponseListLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice { + return LemonsqueezyApiResponseListLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoiceFromJSONTyped(json, false); +} + +export function LemonsqueezyApiResponseListLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoiceFromJSONTyped(json: any, ignoreDiscriminator: boolean): LemonsqueezyApiResponseListLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'data': !exists(json, 'data') ? undefined : ((json['data'] as Array).map(LemonsqueezyApiResponseDataLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoiceFromJSON)), + 'jsonapi': !exists(json, 'jsonapi') ? undefined : LemonsqueezyApiResponseJSONAPIFromJSON(json['jsonapi']), + 'links': !exists(json, 'links') ? undefined : LemonsqueezyApiResponseListLinkFromJSON(json['links']), + 'meta': !exists(json, 'meta') ? undefined : LemonsqueezyApiResponseListMetaFromJSON(json['meta']), + }; +} + +export function LemonsqueezyApiResponseListLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoiceToJSON(value?: LemonsqueezyApiResponseListLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'data': value.data === undefined ? undefined : ((value.data as Array).map(LemonsqueezyApiResponseDataLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoiceToJSON)), + 'jsonapi': LemonsqueezyApiResponseJSONAPIToJSON(value.jsonapi), + 'links': LemonsqueezyApiResponseListLinkToJSON(value.links), + 'meta': LemonsqueezyApiResponseListMetaToJSON(value.meta), + }; +} + diff --git a/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseListLink.ts b/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseListLink.ts new file mode 100644 index 0000000..a0358b8 --- /dev/null +++ b/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseListLink.ts @@ -0,0 +1,81 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * GPTube API swagger docs + * This is the API documentation of GPTube + * + * The version of the OpenAPI document: 1.0 + * Contact: luckly083@gmail.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +/** + * + * @export + * @interface LemonsqueezyApiResponseListLink + */ +export interface LemonsqueezyApiResponseListLink { + /** + * + * @type {string} + * @memberof LemonsqueezyApiResponseListLink + */ + first?: string; + /** + * + * @type {string} + * @memberof LemonsqueezyApiResponseListLink + */ + last?: string; + /** + * + * @type {string} + * @memberof LemonsqueezyApiResponseListLink + */ + next?: string; +} + +/** + * Check if a given object implements the LemonsqueezyApiResponseListLink interface. + */ +export function instanceOfLemonsqueezyApiResponseListLink(value: object): boolean { + let isInstance = true; + + return isInstance; +} + +export function LemonsqueezyApiResponseListLinkFromJSON(json: any): LemonsqueezyApiResponseListLink { + return LemonsqueezyApiResponseListLinkFromJSONTyped(json, false); +} + +export function LemonsqueezyApiResponseListLinkFromJSONTyped(json: any, ignoreDiscriminator: boolean): LemonsqueezyApiResponseListLink { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'first': !exists(json, 'first') ? undefined : json['first'], + 'last': !exists(json, 'last') ? undefined : json['last'], + 'next': !exists(json, 'next') ? undefined : json['next'], + }; +} + +export function LemonsqueezyApiResponseListLinkToJSON(value?: LemonsqueezyApiResponseListLink | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'first': value.first, + 'last': value.last, + 'next': value.next, + }; +} + diff --git a/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseListMeta.ts b/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseListMeta.ts new file mode 100644 index 0000000..282c120 --- /dev/null +++ b/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseListMeta.ts @@ -0,0 +1,72 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * GPTube API swagger docs + * This is the API documentation of GPTube + * + * The version of the OpenAPI document: 1.0 + * Contact: luckly083@gmail.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +import type { LemonsqueezyApiResponseListMetaPage } from './LemonsqueezyApiResponseListMetaPage'; +import { + LemonsqueezyApiResponseListMetaPageFromJSON, + LemonsqueezyApiResponseListMetaPageFromJSONTyped, + LemonsqueezyApiResponseListMetaPageToJSON, +} from './LemonsqueezyApiResponseListMetaPage'; + +/** + * + * @export + * @interface LemonsqueezyApiResponseListMeta + */ +export interface LemonsqueezyApiResponseListMeta { + /** + * + * @type {LemonsqueezyApiResponseListMetaPage} + * @memberof LemonsqueezyApiResponseListMeta + */ + page?: LemonsqueezyApiResponseListMetaPage; +} + +/** + * Check if a given object implements the LemonsqueezyApiResponseListMeta interface. + */ +export function instanceOfLemonsqueezyApiResponseListMeta(value: object): boolean { + let isInstance = true; + + return isInstance; +} + +export function LemonsqueezyApiResponseListMetaFromJSON(json: any): LemonsqueezyApiResponseListMeta { + return LemonsqueezyApiResponseListMetaFromJSONTyped(json, false); +} + +export function LemonsqueezyApiResponseListMetaFromJSONTyped(json: any, ignoreDiscriminator: boolean): LemonsqueezyApiResponseListMeta { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'page': !exists(json, 'page') ? undefined : LemonsqueezyApiResponseListMetaPageFromJSON(json['page']), + }; +} + +export function LemonsqueezyApiResponseListMetaToJSON(value?: LemonsqueezyApiResponseListMeta | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'page': LemonsqueezyApiResponseListMetaPageToJSON(value.page), + }; +} + diff --git a/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseListMetaPage.ts b/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseListMetaPage.ts new file mode 100644 index 0000000..6d694b4 --- /dev/null +++ b/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseListMetaPage.ts @@ -0,0 +1,105 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * GPTube API swagger docs + * This is the API documentation of GPTube + * + * The version of the OpenAPI document: 1.0 + * Contact: luckly083@gmail.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +/** + * + * @export + * @interface LemonsqueezyApiResponseListMetaPage + */ +export interface LemonsqueezyApiResponseListMetaPage { + /** + * + * @type {number} + * @memberof LemonsqueezyApiResponseListMetaPage + */ + currentPage?: number; + /** + * + * @type {number} + * @memberof LemonsqueezyApiResponseListMetaPage + */ + from?: number; + /** + * + * @type {number} + * @memberof LemonsqueezyApiResponseListMetaPage + */ + lastPage?: number; + /** + * + * @type {number} + * @memberof LemonsqueezyApiResponseListMetaPage + */ + perPage?: number; + /** + * + * @type {number} + * @memberof LemonsqueezyApiResponseListMetaPage + */ + to?: number; + /** + * + * @type {number} + * @memberof LemonsqueezyApiResponseListMetaPage + */ + total?: number; +} + +/** + * Check if a given object implements the LemonsqueezyApiResponseListMetaPage interface. + */ +export function instanceOfLemonsqueezyApiResponseListMetaPage(value: object): boolean { + let isInstance = true; + + return isInstance; +} + +export function LemonsqueezyApiResponseListMetaPageFromJSON(json: any): LemonsqueezyApiResponseListMetaPage { + return LemonsqueezyApiResponseListMetaPageFromJSONTyped(json, false); +} + +export function LemonsqueezyApiResponseListMetaPageFromJSONTyped(json: any, ignoreDiscriminator: boolean): LemonsqueezyApiResponseListMetaPage { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'currentPage': !exists(json, 'currentPage') ? undefined : json['currentPage'], + 'from': !exists(json, 'from') ? undefined : json['from'], + 'lastPage': !exists(json, 'lastPage') ? undefined : json['lastPage'], + 'perPage': !exists(json, 'perPage') ? undefined : json['perPage'], + 'to': !exists(json, 'to') ? undefined : json['to'], + 'total': !exists(json, 'total') ? undefined : json['total'], + }; +} + +export function LemonsqueezyApiResponseListMetaPageToJSON(value?: LemonsqueezyApiResponseListMetaPage | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'currentPage': value.currentPage, + 'from': value.from, + 'lastPage': value.lastPage, + 'perPage': value.perPage, + 'to': value.to, + 'total': value.total, + }; +} + diff --git a/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseRelationshipsDiscount.ts b/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseRelationshipsDiscount.ts new file mode 100644 index 0000000..0017e05 --- /dev/null +++ b/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseRelationshipsDiscount.ts @@ -0,0 +1,88 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * GPTube API swagger docs + * This is the API documentation of GPTube + * + * The version of the OpenAPI document: 1.0 + * Contact: luckly083@gmail.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +import type { LemonsqueezyApiResponseLinks } from './LemonsqueezyApiResponseLinks'; +import { + LemonsqueezyApiResponseLinksFromJSON, + LemonsqueezyApiResponseLinksFromJSONTyped, + LemonsqueezyApiResponseLinksToJSON, +} from './LemonsqueezyApiResponseLinks'; + +/** + * + * @export + * @interface LemonsqueezyApiResponseRelationshipsDiscount + */ +export interface LemonsqueezyApiResponseRelationshipsDiscount { + /** + * + * @type {LemonsqueezyApiResponseLinks} + * @memberof LemonsqueezyApiResponseRelationshipsDiscount + */ + discountRedemptions?: LemonsqueezyApiResponseLinks; + /** + * + * @type {LemonsqueezyApiResponseLinks} + * @memberof LemonsqueezyApiResponseRelationshipsDiscount + */ + store?: LemonsqueezyApiResponseLinks; + /** + * + * @type {LemonsqueezyApiResponseLinks} + * @memberof LemonsqueezyApiResponseRelationshipsDiscount + */ + variants?: LemonsqueezyApiResponseLinks; +} + +/** + * Check if a given object implements the LemonsqueezyApiResponseRelationshipsDiscount interface. + */ +export function instanceOfLemonsqueezyApiResponseRelationshipsDiscount(value: object): boolean { + let isInstance = true; + + return isInstance; +} + +export function LemonsqueezyApiResponseRelationshipsDiscountFromJSON(json: any): LemonsqueezyApiResponseRelationshipsDiscount { + return LemonsqueezyApiResponseRelationshipsDiscountFromJSONTyped(json, false); +} + +export function LemonsqueezyApiResponseRelationshipsDiscountFromJSONTyped(json: any, ignoreDiscriminator: boolean): LemonsqueezyApiResponseRelationshipsDiscount { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'discountRedemptions': !exists(json, 'discount-redemptions') ? undefined : LemonsqueezyApiResponseLinksFromJSON(json['discount-redemptions']), + 'store': !exists(json, 'store') ? undefined : LemonsqueezyApiResponseLinksFromJSON(json['store']), + 'variants': !exists(json, 'variants') ? undefined : LemonsqueezyApiResponseLinksFromJSON(json['variants']), + }; +} + +export function LemonsqueezyApiResponseRelationshipsDiscountToJSON(value?: LemonsqueezyApiResponseRelationshipsDiscount | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'discount-redemptions': LemonsqueezyApiResponseLinksToJSON(value.discountRedemptions), + 'store': LemonsqueezyApiResponseLinksToJSON(value.store), + 'variants': LemonsqueezyApiResponseLinksToJSON(value.variants), + }; +} + diff --git a/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseRelationshipsSubscription.ts b/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseRelationshipsSubscription.ts new file mode 100644 index 0000000..1be8020 --- /dev/null +++ b/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseRelationshipsSubscription.ts @@ -0,0 +1,128 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * GPTube API swagger docs + * This is the API documentation of GPTube + * + * The version of the OpenAPI document: 1.0 + * Contact: luckly083@gmail.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +import type { LemonsqueezyApiResponseLinks } from './LemonsqueezyApiResponseLinks'; +import { + LemonsqueezyApiResponseLinksFromJSON, + LemonsqueezyApiResponseLinksFromJSONTyped, + LemonsqueezyApiResponseLinksToJSON, +} from './LemonsqueezyApiResponseLinks'; + +/** + * + * @export + * @interface LemonsqueezyApiResponseRelationshipsSubscription + */ +export interface LemonsqueezyApiResponseRelationshipsSubscription { + /** + * + * @type {LemonsqueezyApiResponseLinks} + * @memberof LemonsqueezyApiResponseRelationshipsSubscription + */ + customer?: LemonsqueezyApiResponseLinks; + /** + * + * @type {LemonsqueezyApiResponseLinks} + * @memberof LemonsqueezyApiResponseRelationshipsSubscription + */ + order?: LemonsqueezyApiResponseLinks; + /** + * + * @type {LemonsqueezyApiResponseLinks} + * @memberof LemonsqueezyApiResponseRelationshipsSubscription + */ + orderItem?: LemonsqueezyApiResponseLinks; + /** + * + * @type {LemonsqueezyApiResponseLinks} + * @memberof LemonsqueezyApiResponseRelationshipsSubscription + */ + product?: LemonsqueezyApiResponseLinks; + /** + * + * @type {LemonsqueezyApiResponseLinks} + * @memberof LemonsqueezyApiResponseRelationshipsSubscription + */ + store?: LemonsqueezyApiResponseLinks; + /** + * + * @type {LemonsqueezyApiResponseLinks} + * @memberof LemonsqueezyApiResponseRelationshipsSubscription + */ + subscriptionInvoices?: LemonsqueezyApiResponseLinks; + /** + * + * @type {LemonsqueezyApiResponseLinks} + * @memberof LemonsqueezyApiResponseRelationshipsSubscription + */ + subscriptionItems?: LemonsqueezyApiResponseLinks; + /** + * + * @type {LemonsqueezyApiResponseLinks} + * @memberof LemonsqueezyApiResponseRelationshipsSubscription + */ + variant?: LemonsqueezyApiResponseLinks; +} + +/** + * Check if a given object implements the LemonsqueezyApiResponseRelationshipsSubscription interface. + */ +export function instanceOfLemonsqueezyApiResponseRelationshipsSubscription(value: object): boolean { + let isInstance = true; + + return isInstance; +} + +export function LemonsqueezyApiResponseRelationshipsSubscriptionFromJSON(json: any): LemonsqueezyApiResponseRelationshipsSubscription { + return LemonsqueezyApiResponseRelationshipsSubscriptionFromJSONTyped(json, false); +} + +export function LemonsqueezyApiResponseRelationshipsSubscriptionFromJSONTyped(json: any, ignoreDiscriminator: boolean): LemonsqueezyApiResponseRelationshipsSubscription { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'customer': !exists(json, 'customer') ? undefined : LemonsqueezyApiResponseLinksFromJSON(json['customer']), + 'order': !exists(json, 'order') ? undefined : LemonsqueezyApiResponseLinksFromJSON(json['order']), + 'orderItem': !exists(json, 'order-item') ? undefined : LemonsqueezyApiResponseLinksFromJSON(json['order-item']), + 'product': !exists(json, 'product') ? undefined : LemonsqueezyApiResponseLinksFromJSON(json['product']), + 'store': !exists(json, 'store') ? undefined : LemonsqueezyApiResponseLinksFromJSON(json['store']), + 'subscriptionInvoices': !exists(json, 'subscription-invoices') ? undefined : LemonsqueezyApiResponseLinksFromJSON(json['subscription-invoices']), + 'subscriptionItems': !exists(json, 'subscription-items') ? undefined : LemonsqueezyApiResponseLinksFromJSON(json['subscription-items']), + 'variant': !exists(json, 'variant') ? undefined : LemonsqueezyApiResponseLinksFromJSON(json['variant']), + }; +} + +export function LemonsqueezyApiResponseRelationshipsSubscriptionToJSON(value?: LemonsqueezyApiResponseRelationshipsSubscription | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'customer': LemonsqueezyApiResponseLinksToJSON(value.customer), + 'order': LemonsqueezyApiResponseLinksToJSON(value.order), + 'order-item': LemonsqueezyApiResponseLinksToJSON(value.orderItem), + 'product': LemonsqueezyApiResponseLinksToJSON(value.product), + 'store': LemonsqueezyApiResponseLinksToJSON(value.store), + 'subscription-invoices': LemonsqueezyApiResponseLinksToJSON(value.subscriptionInvoices), + 'subscription-items': LemonsqueezyApiResponseLinksToJSON(value.subscriptionItems), + 'variant': LemonsqueezyApiResponseLinksToJSON(value.variant), + }; +} + diff --git a/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseRelationshipsSubscriptionInvoice.ts b/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseRelationshipsSubscriptionInvoice.ts new file mode 100644 index 0000000..69365df --- /dev/null +++ b/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseRelationshipsSubscriptionInvoice.ts @@ -0,0 +1,80 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * GPTube API swagger docs + * This is the API documentation of GPTube + * + * The version of the OpenAPI document: 1.0 + * Contact: luckly083@gmail.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +import type { LemonsqueezyApiResponseLinks } from './LemonsqueezyApiResponseLinks'; +import { + LemonsqueezyApiResponseLinksFromJSON, + LemonsqueezyApiResponseLinksFromJSONTyped, + LemonsqueezyApiResponseLinksToJSON, +} from './LemonsqueezyApiResponseLinks'; + +/** + * + * @export + * @interface LemonsqueezyApiResponseRelationshipsSubscriptionInvoice + */ +export interface LemonsqueezyApiResponseRelationshipsSubscriptionInvoice { + /** + * + * @type {LemonsqueezyApiResponseLinks} + * @memberof LemonsqueezyApiResponseRelationshipsSubscriptionInvoice + */ + store?: LemonsqueezyApiResponseLinks; + /** + * + * @type {LemonsqueezyApiResponseLinks} + * @memberof LemonsqueezyApiResponseRelationshipsSubscriptionInvoice + */ + subscription?: LemonsqueezyApiResponseLinks; +} + +/** + * Check if a given object implements the LemonsqueezyApiResponseRelationshipsSubscriptionInvoice interface. + */ +export function instanceOfLemonsqueezyApiResponseRelationshipsSubscriptionInvoice(value: object): boolean { + let isInstance = true; + + return isInstance; +} + +export function LemonsqueezyApiResponseRelationshipsSubscriptionInvoiceFromJSON(json: any): LemonsqueezyApiResponseRelationshipsSubscriptionInvoice { + return LemonsqueezyApiResponseRelationshipsSubscriptionInvoiceFromJSONTyped(json, false); +} + +export function LemonsqueezyApiResponseRelationshipsSubscriptionInvoiceFromJSONTyped(json: any, ignoreDiscriminator: boolean): LemonsqueezyApiResponseRelationshipsSubscriptionInvoice { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'store': !exists(json, 'store') ? undefined : LemonsqueezyApiResponseLinksFromJSON(json['store']), + 'subscription': !exists(json, 'subscription') ? undefined : LemonsqueezyApiResponseLinksFromJSON(json['subscription']), + }; +} + +export function LemonsqueezyApiResponseRelationshipsSubscriptionInvoiceToJSON(value?: LemonsqueezyApiResponseRelationshipsSubscriptionInvoice | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'store': LemonsqueezyApiResponseLinksToJSON(value.store), + 'subscription': LemonsqueezyApiResponseLinksToJSON(value.subscription), + }; +} + diff --git a/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseSelfLink.ts b/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseSelfLink.ts new file mode 100644 index 0000000..7232584 --- /dev/null +++ b/gptube/gptube-api/generated-api/models/LemonsqueezyApiResponseSelfLink.ts @@ -0,0 +1,65 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * GPTube API swagger docs + * This is the API documentation of GPTube + * + * The version of the OpenAPI document: 1.0 + * Contact: luckly083@gmail.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +/** + * + * @export + * @interface LemonsqueezyApiResponseSelfLink + */ +export interface LemonsqueezyApiResponseSelfLink { + /** + * + * @type {string} + * @memberof LemonsqueezyApiResponseSelfLink + */ + self?: string; +} + +/** + * Check if a given object implements the LemonsqueezyApiResponseSelfLink interface. + */ +export function instanceOfLemonsqueezyApiResponseSelfLink(value: object): boolean { + let isInstance = true; + + return isInstance; +} + +export function LemonsqueezyApiResponseSelfLinkFromJSON(json: any): LemonsqueezyApiResponseSelfLink { + return LemonsqueezyApiResponseSelfLinkFromJSONTyped(json, false); +} + +export function LemonsqueezyApiResponseSelfLinkFromJSONTyped(json: any, ignoreDiscriminator: boolean): LemonsqueezyApiResponseSelfLink { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'self': !exists(json, 'self') ? undefined : json['self'], + }; +} + +export function LemonsqueezyApiResponseSelfLinkToJSON(value?: LemonsqueezyApiResponseSelfLink | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'self': value.self, + }; +} + diff --git a/gptube/gptube-api/generated-api/models/LemonsqueezyBillingAddress.ts b/gptube/gptube-api/generated-api/models/LemonsqueezyBillingAddress.ts new file mode 100644 index 0000000..f226331 --- /dev/null +++ b/gptube/gptube-api/generated-api/models/LemonsqueezyBillingAddress.ts @@ -0,0 +1,73 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * GPTube API swagger docs + * This is the API documentation of GPTube + * + * The version of the OpenAPI document: 1.0 + * Contact: luckly083@gmail.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +/** + * + * @export + * @interface LemonsqueezyBillingAddress + */ +export interface LemonsqueezyBillingAddress { + /** + * + * @type {string} + * @memberof LemonsqueezyBillingAddress + */ + country?: string; + /** + * + * @type {string} + * @memberof LemonsqueezyBillingAddress + */ + zip?: string; +} + +/** + * Check if a given object implements the LemonsqueezyBillingAddress interface. + */ +export function instanceOfLemonsqueezyBillingAddress(value: object): boolean { + let isInstance = true; + + return isInstance; +} + +export function LemonsqueezyBillingAddressFromJSON(json: any): LemonsqueezyBillingAddress { + return LemonsqueezyBillingAddressFromJSONTyped(json, false); +} + +export function LemonsqueezyBillingAddressFromJSONTyped(json: any, ignoreDiscriminator: boolean): LemonsqueezyBillingAddress { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'country': !exists(json, 'country') ? undefined : json['country'], + 'zip': !exists(json, 'zip') ? undefined : json['zip'], + }; +} + +export function LemonsqueezyBillingAddressToJSON(value?: LemonsqueezyBillingAddress | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'country': value.country, + 'zip': value.zip, + }; +} + diff --git a/gptube/gptube-api/generated-api/models/LemonsqueezyCheckoutAttributes.ts b/gptube/gptube-api/generated-api/models/LemonsqueezyCheckoutAttributes.ts new file mode 100644 index 0000000..711fb97 --- /dev/null +++ b/gptube/gptube-api/generated-api/models/LemonsqueezyCheckoutAttributes.ts @@ -0,0 +1,164 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * GPTube API swagger docs + * This is the API documentation of GPTube + * + * The version of the OpenAPI document: 1.0 + * Contact: luckly083@gmail.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +import type { LemonsqueezyCheckoutData } from './LemonsqueezyCheckoutData'; +import { + LemonsqueezyCheckoutDataFromJSON, + LemonsqueezyCheckoutDataFromJSONTyped, + LemonsqueezyCheckoutDataToJSON, +} from './LemonsqueezyCheckoutData'; +import type { LemonsqueezyCheckoutOptions } from './LemonsqueezyCheckoutOptions'; +import { + LemonsqueezyCheckoutOptionsFromJSON, + LemonsqueezyCheckoutOptionsFromJSONTyped, + LemonsqueezyCheckoutOptionsToJSON, +} from './LemonsqueezyCheckoutOptions'; +import type { LemonsqueezyCheckoutProductOptions } from './LemonsqueezyCheckoutProductOptions'; +import { + LemonsqueezyCheckoutProductOptionsFromJSON, + LemonsqueezyCheckoutProductOptionsFromJSONTyped, + LemonsqueezyCheckoutProductOptionsToJSON, +} from './LemonsqueezyCheckoutProductOptions'; + +/** + * + * @export + * @interface LemonsqueezyCheckoutAttributes + */ +export interface LemonsqueezyCheckoutAttributes { + /** + * + * @type {LemonsqueezyCheckoutData} + * @memberof LemonsqueezyCheckoutAttributes + */ + checkoutData?: LemonsqueezyCheckoutData; + /** + * + * @type {LemonsqueezyCheckoutOptions} + * @memberof LemonsqueezyCheckoutAttributes + */ + checkoutOptions?: LemonsqueezyCheckoutOptions; + /** + * + * @type {string} + * @memberof LemonsqueezyCheckoutAttributes + */ + createdAt?: string; + /** + * + * @type {object} + * @memberof LemonsqueezyCheckoutAttributes + */ + customPrice?: object; + /** + * + * @type {string} + * @memberof LemonsqueezyCheckoutAttributes + */ + expiresAt?: string; + /** + * + * @type {LemonsqueezyCheckoutProductOptions} + * @memberof LemonsqueezyCheckoutAttributes + */ + productOptions?: LemonsqueezyCheckoutProductOptions; + /** + * + * @type {number} + * @memberof LemonsqueezyCheckoutAttributes + */ + storeId?: number; + /** + * + * @type {boolean} + * @memberof LemonsqueezyCheckoutAttributes + */ + testMode?: boolean; + /** + * + * @type {string} + * @memberof LemonsqueezyCheckoutAttributes + */ + updatedAt?: string; + /** + * + * @type {string} + * @memberof LemonsqueezyCheckoutAttributes + */ + url?: string; + /** + * + * @type {number} + * @memberof LemonsqueezyCheckoutAttributes + */ + variantId?: number; +} + +/** + * Check if a given object implements the LemonsqueezyCheckoutAttributes interface. + */ +export function instanceOfLemonsqueezyCheckoutAttributes(value: object): boolean { + let isInstance = true; + + return isInstance; +} + +export function LemonsqueezyCheckoutAttributesFromJSON(json: any): LemonsqueezyCheckoutAttributes { + return LemonsqueezyCheckoutAttributesFromJSONTyped(json, false); +} + +export function LemonsqueezyCheckoutAttributesFromJSONTyped(json: any, ignoreDiscriminator: boolean): LemonsqueezyCheckoutAttributes { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'checkoutData': !exists(json, 'checkout_data') ? undefined : LemonsqueezyCheckoutDataFromJSON(json['checkout_data']), + 'checkoutOptions': !exists(json, 'checkout_options') ? undefined : LemonsqueezyCheckoutOptionsFromJSON(json['checkout_options']), + 'createdAt': !exists(json, 'created_at') ? undefined : json['created_at'], + 'customPrice': !exists(json, 'custom_price') ? undefined : json['custom_price'], + 'expiresAt': !exists(json, 'expires_at') ? undefined : json['expires_at'], + 'productOptions': !exists(json, 'product_options') ? undefined : LemonsqueezyCheckoutProductOptionsFromJSON(json['product_options']), + 'storeId': !exists(json, 'store_id') ? undefined : json['store_id'], + 'testMode': !exists(json, 'test_mode') ? undefined : json['test_mode'], + 'updatedAt': !exists(json, 'updated_at') ? undefined : json['updated_at'], + 'url': !exists(json, 'url') ? undefined : json['url'], + 'variantId': !exists(json, 'variant_id') ? undefined : json['variant_id'], + }; +} + +export function LemonsqueezyCheckoutAttributesToJSON(value?: LemonsqueezyCheckoutAttributes | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'checkout_data': LemonsqueezyCheckoutDataToJSON(value.checkoutData), + 'checkout_options': LemonsqueezyCheckoutOptionsToJSON(value.checkoutOptions), + 'created_at': value.createdAt, + 'custom_price': value.customPrice, + 'expires_at': value.expiresAt, + 'product_options': LemonsqueezyCheckoutProductOptionsToJSON(value.productOptions), + 'store_id': value.storeId, + 'test_mode': value.testMode, + 'updated_at': value.updatedAt, + 'url': value.url, + 'variant_id': value.variantId, + }; +} + diff --git a/gptube/gptube-api/generated-api/models/LemonsqueezyCheckoutData.ts b/gptube/gptube-api/generated-api/models/LemonsqueezyCheckoutData.ts new file mode 100644 index 0000000..23026f5 --- /dev/null +++ b/gptube/gptube-api/generated-api/models/LemonsqueezyCheckoutData.ts @@ -0,0 +1,112 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * GPTube API swagger docs + * This is the API documentation of GPTube + * + * The version of the OpenAPI document: 1.0 + * Contact: luckly083@gmail.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +import type { LemonsqueezyBillingAddress } from './LemonsqueezyBillingAddress'; +import { + LemonsqueezyBillingAddressFromJSON, + LemonsqueezyBillingAddressFromJSONTyped, + LemonsqueezyBillingAddressToJSON, +} from './LemonsqueezyBillingAddress'; + +/** + * + * @export + * @interface LemonsqueezyCheckoutData + */ +export interface LemonsqueezyCheckoutData { + /** + * + * @type {Array} + * @memberof LemonsqueezyCheckoutData + */ + billingAddress?: Array; + /** + * + * @type {{ [key: string]: object; }} + * @memberof LemonsqueezyCheckoutData + */ + custom?: { [key: string]: object; }; + /** + * + * @type {string} + * @memberof LemonsqueezyCheckoutData + */ + discountCode?: string; + /** + * + * @type {string} + * @memberof LemonsqueezyCheckoutData + */ + email?: string; + /** + * + * @type {string} + * @memberof LemonsqueezyCheckoutData + */ + name?: string; + /** + * + * @type {string} + * @memberof LemonsqueezyCheckoutData + */ + taxNumber?: string; +} + +/** + * Check if a given object implements the LemonsqueezyCheckoutData interface. + */ +export function instanceOfLemonsqueezyCheckoutData(value: object): boolean { + let isInstance = true; + + return isInstance; +} + +export function LemonsqueezyCheckoutDataFromJSON(json: any): LemonsqueezyCheckoutData { + return LemonsqueezyCheckoutDataFromJSONTyped(json, false); +} + +export function LemonsqueezyCheckoutDataFromJSONTyped(json: any, ignoreDiscriminator: boolean): LemonsqueezyCheckoutData { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'billingAddress': !exists(json, 'billing_address') ? undefined : ((json['billing_address'] as Array).map(LemonsqueezyBillingAddressFromJSON)), + 'custom': !exists(json, 'custom') ? undefined : json['custom'], + 'discountCode': !exists(json, 'discount_code') ? undefined : json['discount_code'], + 'email': !exists(json, 'email') ? undefined : json['email'], + 'name': !exists(json, 'name') ? undefined : json['name'], + 'taxNumber': !exists(json, 'tax_number') ? undefined : json['tax_number'], + }; +} + +export function LemonsqueezyCheckoutDataToJSON(value?: LemonsqueezyCheckoutData | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'billing_address': value.billingAddress === undefined ? undefined : ((value.billingAddress as Array).map(LemonsqueezyBillingAddressToJSON)), + 'custom': value.custom, + 'discount_code': value.discountCode, + 'email': value.email, + 'name': value.name, + 'tax_number': value.taxNumber, + }; +} + diff --git a/gptube/gptube-api/generated-api/models/LemonsqueezyCheckoutOptions.ts b/gptube/gptube-api/generated-api/models/LemonsqueezyCheckoutOptions.ts new file mode 100644 index 0000000..5d0df77 --- /dev/null +++ b/gptube/gptube-api/generated-api/models/LemonsqueezyCheckoutOptions.ts @@ -0,0 +1,121 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * GPTube API swagger docs + * This is the API documentation of GPTube + * + * The version of the OpenAPI document: 1.0 + * Contact: luckly083@gmail.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +/** + * + * @export + * @interface LemonsqueezyCheckoutOptions + */ +export interface LemonsqueezyCheckoutOptions { + /** + * + * @type {string} + * @memberof LemonsqueezyCheckoutOptions + */ + buttonColor?: string; + /** + * + * @type {boolean} + * @memberof LemonsqueezyCheckoutOptions + */ + dark?: boolean; + /** + * + * @type {boolean} + * @memberof LemonsqueezyCheckoutOptions + */ + desc?: boolean; + /** + * + * @type {boolean} + * @memberof LemonsqueezyCheckoutOptions + */ + discount?: boolean; + /** + * + * @type {boolean} + * @memberof LemonsqueezyCheckoutOptions + */ + embed?: boolean; + /** + * + * @type {boolean} + * @memberof LemonsqueezyCheckoutOptions + */ + logo?: boolean; + /** + * + * @type {boolean} + * @memberof LemonsqueezyCheckoutOptions + */ + media?: boolean; + /** + * + * @type {boolean} + * @memberof LemonsqueezyCheckoutOptions + */ + subscriptionPreview?: boolean; +} + +/** + * Check if a given object implements the LemonsqueezyCheckoutOptions interface. + */ +export function instanceOfLemonsqueezyCheckoutOptions(value: object): boolean { + let isInstance = true; + + return isInstance; +} + +export function LemonsqueezyCheckoutOptionsFromJSON(json: any): LemonsqueezyCheckoutOptions { + return LemonsqueezyCheckoutOptionsFromJSONTyped(json, false); +} + +export function LemonsqueezyCheckoutOptionsFromJSONTyped(json: any, ignoreDiscriminator: boolean): LemonsqueezyCheckoutOptions { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'buttonColor': !exists(json, 'button_color') ? undefined : json['button_color'], + 'dark': !exists(json, 'dark') ? undefined : json['dark'], + 'desc': !exists(json, 'desc') ? undefined : json['desc'], + 'discount': !exists(json, 'discount') ? undefined : json['discount'], + 'embed': !exists(json, 'embed') ? undefined : json['embed'], + 'logo': !exists(json, 'logo') ? undefined : json['logo'], + 'media': !exists(json, 'media') ? undefined : json['media'], + 'subscriptionPreview': !exists(json, 'subscription_preview') ? undefined : json['subscription_preview'], + }; +} + +export function LemonsqueezyCheckoutOptionsToJSON(value?: LemonsqueezyCheckoutOptions | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'button_color': value.buttonColor, + 'dark': value.dark, + 'desc': value.desc, + 'discount': value.discount, + 'embed': value.embed, + 'logo': value.logo, + 'media': value.media, + 'subscription_preview': value.subscriptionPreview, + }; +} + diff --git a/gptube/gptube-api/generated-api/models/LemonsqueezyCheckoutProductOptions.ts b/gptube/gptube-api/generated-api/models/LemonsqueezyCheckoutProductOptions.ts new file mode 100644 index 0000000..e94fcf9 --- /dev/null +++ b/gptube/gptube-api/generated-api/models/LemonsqueezyCheckoutProductOptions.ts @@ -0,0 +1,121 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * GPTube API swagger docs + * This is the API documentation of GPTube + * + * The version of the OpenAPI document: 1.0 + * Contact: luckly083@gmail.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +/** + * + * @export + * @interface LemonsqueezyCheckoutProductOptions + */ +export interface LemonsqueezyCheckoutProductOptions { + /** + * + * @type {string} + * @memberof LemonsqueezyCheckoutProductOptions + */ + description?: string; + /** + * + * @type {Array} + * @memberof LemonsqueezyCheckoutProductOptions + */ + enabledVariants?: Array; + /** + * + * @type {Array} + * @memberof LemonsqueezyCheckoutProductOptions + */ + media?: Array; + /** + * + * @type {string} + * @memberof LemonsqueezyCheckoutProductOptions + */ + name?: string; + /** + * + * @type {string} + * @memberof LemonsqueezyCheckoutProductOptions + */ + receiptButtonText?: string; + /** + * + * @type {string} + * @memberof LemonsqueezyCheckoutProductOptions + */ + receiptLinkUrl?: string; + /** + * + * @type {string} + * @memberof LemonsqueezyCheckoutProductOptions + */ + receiptThankYouNote?: string; + /** + * + * @type {string} + * @memberof LemonsqueezyCheckoutProductOptions + */ + redirectUrl?: string; +} + +/** + * Check if a given object implements the LemonsqueezyCheckoutProductOptions interface. + */ +export function instanceOfLemonsqueezyCheckoutProductOptions(value: object): boolean { + let isInstance = true; + + return isInstance; +} + +export function LemonsqueezyCheckoutProductOptionsFromJSON(json: any): LemonsqueezyCheckoutProductOptions { + return LemonsqueezyCheckoutProductOptionsFromJSONTyped(json, false); +} + +export function LemonsqueezyCheckoutProductOptionsFromJSONTyped(json: any, ignoreDiscriminator: boolean): LemonsqueezyCheckoutProductOptions { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'description': !exists(json, 'description') ? undefined : json['description'], + 'enabledVariants': !exists(json, 'enabled_variants') ? undefined : json['enabled_variants'], + 'media': !exists(json, 'media') ? undefined : json['media'], + 'name': !exists(json, 'name') ? undefined : json['name'], + 'receiptButtonText': !exists(json, 'receipt_button_text') ? undefined : json['receipt_button_text'], + 'receiptLinkUrl': !exists(json, 'receipt_link_url') ? undefined : json['receipt_link_url'], + 'receiptThankYouNote': !exists(json, 'receipt_thank_you_note') ? undefined : json['receipt_thank_you_note'], + 'redirectUrl': !exists(json, 'redirect_url') ? undefined : json['redirect_url'], + }; +} + +export function LemonsqueezyCheckoutProductOptionsToJSON(value?: LemonsqueezyCheckoutProductOptions | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'description': value.description, + 'enabled_variants': value.enabledVariants, + 'media': value.media, + 'name': value.name, + 'receipt_button_text': value.receiptButtonText, + 'receipt_link_url': value.receiptLinkUrl, + 'receipt_thank_you_note': value.receiptThankYouNote, + 'redirect_url': value.redirectUrl, + }; +} + diff --git a/gptube/gptube-api/generated-api/models/LemonsqueezySubscription.ts b/gptube/gptube-api/generated-api/models/LemonsqueezySubscription.ts new file mode 100644 index 0000000..3c6cdf2 --- /dev/null +++ b/gptube/gptube-api/generated-api/models/LemonsqueezySubscription.ts @@ -0,0 +1,276 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * GPTube API swagger docs + * This is the API documentation of GPTube + * + * The version of the OpenAPI document: 1.0 + * Contact: luckly083@gmail.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +import type { LemonsqueezySubscriptionItem } from './LemonsqueezySubscriptionItem'; +import { + LemonsqueezySubscriptionItemFromJSON, + LemonsqueezySubscriptionItemFromJSONTyped, + LemonsqueezySubscriptionItemToJSON, +} from './LemonsqueezySubscriptionItem'; +import type { LemonsqueezySubscriptionPause } from './LemonsqueezySubscriptionPause'; +import { + LemonsqueezySubscriptionPauseFromJSON, + LemonsqueezySubscriptionPauseFromJSONTyped, + LemonsqueezySubscriptionPauseToJSON, +} from './LemonsqueezySubscriptionPause'; +import type { LemonsqueezySubscriptionURLs } from './LemonsqueezySubscriptionURLs'; +import { + LemonsqueezySubscriptionURLsFromJSON, + LemonsqueezySubscriptionURLsFromJSONTyped, + LemonsqueezySubscriptionURLsToJSON, +} from './LemonsqueezySubscriptionURLs'; + +/** + * + * @export + * @interface LemonsqueezySubscription + */ +export interface LemonsqueezySubscription { + /** + * + * @type {number} + * @memberof LemonsqueezySubscription + */ + billingAnchor?: number; + /** + * + * @type {boolean} + * @memberof LemonsqueezySubscription + */ + cancelled?: boolean; + /** + * + * @type {string} + * @memberof LemonsqueezySubscription + */ + cardBrand?: string; + /** + * + * @type {string} + * @memberof LemonsqueezySubscription + */ + cardLastFour?: string; + /** + * + * @type {string} + * @memberof LemonsqueezySubscription + */ + createdAt?: string; + /** + * + * @type {number} + * @memberof LemonsqueezySubscription + */ + customerId?: number; + /** + * + * @type {string} + * @memberof LemonsqueezySubscription + */ + endsAt?: string; + /** + * + * @type {LemonsqueezySubscriptionItem} + * @memberof LemonsqueezySubscription + */ + firstSubscriptionItem?: LemonsqueezySubscriptionItem; + /** + * + * @type {number} + * @memberof LemonsqueezySubscription + */ + orderId?: number; + /** + * + * @type {number} + * @memberof LemonsqueezySubscription + */ + orderItemId?: number; + /** + * + * @type {LemonsqueezySubscriptionPause} + * @memberof LemonsqueezySubscription + */ + pause?: LemonsqueezySubscriptionPause; + /** + * + * @type {number} + * @memberof LemonsqueezySubscription + */ + productId?: number; + /** + * + * @type {string} + * @memberof LemonsqueezySubscription + */ + productName?: string; + /** + * + * @type {string} + * @memberof LemonsqueezySubscription + */ + renewsAt?: string; + /** + * + * @type {string} + * @memberof LemonsqueezySubscription + */ + status?: string; + /** + * + * @type {string} + * @memberof LemonsqueezySubscription + */ + statusFormatted?: string; + /** + * + * @type {number} + * @memberof LemonsqueezySubscription + */ + storeId?: number; + /** + * + * @type {boolean} + * @memberof LemonsqueezySubscription + */ + testMode?: boolean; + /** + * + * @type {string} + * @memberof LemonsqueezySubscription + */ + trialEndsAt?: string; + /** + * + * @type {string} + * @memberof LemonsqueezySubscription + */ + updatedAt?: string; + /** + * + * @type {LemonsqueezySubscriptionURLs} + * @memberof LemonsqueezySubscription + */ + urls?: LemonsqueezySubscriptionURLs; + /** + * + * @type {string} + * @memberof LemonsqueezySubscription + */ + userEmail?: string; + /** + * + * @type {string} + * @memberof LemonsqueezySubscription + */ + userName?: string; + /** + * + * @type {number} + * @memberof LemonsqueezySubscription + */ + variantId?: number; + /** + * + * @type {string} + * @memberof LemonsqueezySubscription + */ + variantName?: string; +} + +/** + * Check if a given object implements the LemonsqueezySubscription interface. + */ +export function instanceOfLemonsqueezySubscription(value: object): boolean { + let isInstance = true; + + return isInstance; +} + +export function LemonsqueezySubscriptionFromJSON(json: any): LemonsqueezySubscription { + return LemonsqueezySubscriptionFromJSONTyped(json, false); +} + +export function LemonsqueezySubscriptionFromJSONTyped(json: any, ignoreDiscriminator: boolean): LemonsqueezySubscription { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'billingAnchor': !exists(json, 'billing_anchor') ? undefined : json['billing_anchor'], + 'cancelled': !exists(json, 'cancelled') ? undefined : json['cancelled'], + 'cardBrand': !exists(json, 'card_brand') ? undefined : json['card_brand'], + 'cardLastFour': !exists(json, 'card_last_four') ? undefined : json['card_last_four'], + 'createdAt': !exists(json, 'created_at') ? undefined : json['created_at'], + 'customerId': !exists(json, 'customer_id') ? undefined : json['customer_id'], + 'endsAt': !exists(json, 'ends_at') ? undefined : json['ends_at'], + 'firstSubscriptionItem': !exists(json, 'first_subscription_item') ? undefined : LemonsqueezySubscriptionItemFromJSON(json['first_subscription_item']), + 'orderId': !exists(json, 'order_id') ? undefined : json['order_id'], + 'orderItemId': !exists(json, 'order_item_id') ? undefined : json['order_item_id'], + 'pause': !exists(json, 'pause') ? undefined : LemonsqueezySubscriptionPauseFromJSON(json['pause']), + 'productId': !exists(json, 'product_id') ? undefined : json['product_id'], + 'productName': !exists(json, 'product_name') ? undefined : json['product_name'], + 'renewsAt': !exists(json, 'renews_at') ? undefined : json['renews_at'], + 'status': !exists(json, 'status') ? undefined : json['status'], + 'statusFormatted': !exists(json, 'status_formatted') ? undefined : json['status_formatted'], + 'storeId': !exists(json, 'store_id') ? undefined : json['store_id'], + 'testMode': !exists(json, 'test_mode') ? undefined : json['test_mode'], + 'trialEndsAt': !exists(json, 'trial_ends_at') ? undefined : json['trial_ends_at'], + 'updatedAt': !exists(json, 'updated_at') ? undefined : json['updated_at'], + 'urls': !exists(json, 'urls') ? undefined : LemonsqueezySubscriptionURLsFromJSON(json['urls']), + 'userEmail': !exists(json, 'user_email') ? undefined : json['user_email'], + 'userName': !exists(json, 'user_name') ? undefined : json['user_name'], + 'variantId': !exists(json, 'variant_id') ? undefined : json['variant_id'], + 'variantName': !exists(json, 'variant_name') ? undefined : json['variant_name'], + }; +} + +export function LemonsqueezySubscriptionToJSON(value?: LemonsqueezySubscription | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'billing_anchor': value.billingAnchor, + 'cancelled': value.cancelled, + 'card_brand': value.cardBrand, + 'card_last_four': value.cardLastFour, + 'created_at': value.createdAt, + 'customer_id': value.customerId, + 'ends_at': value.endsAt, + 'first_subscription_item': LemonsqueezySubscriptionItemToJSON(value.firstSubscriptionItem), + 'order_id': value.orderId, + 'order_item_id': value.orderItemId, + 'pause': LemonsqueezySubscriptionPauseToJSON(value.pause), + 'product_id': value.productId, + 'product_name': value.productName, + 'renews_at': value.renewsAt, + 'status': value.status, + 'status_formatted': value.statusFormatted, + 'store_id': value.storeId, + 'test_mode': value.testMode, + 'trial_ends_at': value.trialEndsAt, + 'updated_at': value.updatedAt, + 'urls': LemonsqueezySubscriptionURLsToJSON(value.urls), + 'user_email': value.userEmail, + 'user_name': value.userName, + 'variant_id': value.variantId, + 'variant_name': value.variantName, + }; +} + diff --git a/gptube/gptube-api/generated-api/models/LemonsqueezySubscriptionInvoiceAttributes.ts b/gptube/gptube-api/generated-api/models/LemonsqueezySubscriptionInvoiceAttributes.ts new file mode 100644 index 0000000..c7ddec5 --- /dev/null +++ b/gptube/gptube-api/generated-api/models/LemonsqueezySubscriptionInvoiceAttributes.ts @@ -0,0 +1,280 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * GPTube API swagger docs + * This is the API documentation of GPTube + * + * The version of the OpenAPI document: 1.0 + * Contact: luckly083@gmail.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +import type { LemonsqueezySubscriptionInvoiceAttributesUrls } from './LemonsqueezySubscriptionInvoiceAttributesUrls'; +import { + LemonsqueezySubscriptionInvoiceAttributesUrlsFromJSON, + LemonsqueezySubscriptionInvoiceAttributesUrlsFromJSONTyped, + LemonsqueezySubscriptionInvoiceAttributesUrlsToJSON, +} from './LemonsqueezySubscriptionInvoiceAttributesUrls'; + +/** + * + * @export + * @interface LemonsqueezySubscriptionInvoiceAttributes + */ +export interface LemonsqueezySubscriptionInvoiceAttributes { + /** + * + * @type {string} + * @memberof LemonsqueezySubscriptionInvoiceAttributes + */ + billingReason?: string; + /** + * + * @type {string} + * @memberof LemonsqueezySubscriptionInvoiceAttributes + */ + cardBrand?: string; + /** + * + * @type {string} + * @memberof LemonsqueezySubscriptionInvoiceAttributes + */ + cardLastFour?: string; + /** + * + * @type {string} + * @memberof LemonsqueezySubscriptionInvoiceAttributes + */ + createdAt?: string; + /** + * + * @type {string} + * @memberof LemonsqueezySubscriptionInvoiceAttributes + */ + currency?: string; + /** + * + * @type {string} + * @memberof LemonsqueezySubscriptionInvoiceAttributes + */ + currencyRate?: string; + /** + * + * @type {number} + * @memberof LemonsqueezySubscriptionInvoiceAttributes + */ + discountTotal?: number; + /** + * + * @type {string} + * @memberof LemonsqueezySubscriptionInvoiceAttributes + */ + discountTotalFormatted?: string; + /** + * + * @type {number} + * @memberof LemonsqueezySubscriptionInvoiceAttributes + */ + discountTotalUsd?: number; + /** + * + * @type {boolean} + * @memberof LemonsqueezySubscriptionInvoiceAttributes + */ + refunded?: boolean; + /** + * + * @type {string} + * @memberof LemonsqueezySubscriptionInvoiceAttributes + */ + refundedAt?: string; + /** + * + * @type {string} + * @memberof LemonsqueezySubscriptionInvoiceAttributes + */ + status?: string; + /** + * + * @type {string} + * @memberof LemonsqueezySubscriptionInvoiceAttributes + */ + statusFormatted?: string; + /** + * + * @type {number} + * @memberof LemonsqueezySubscriptionInvoiceAttributes + */ + storeId?: number; + /** + * + * @type {number} + * @memberof LemonsqueezySubscriptionInvoiceAttributes + */ + subscriptionId?: number; + /** + * + * @type {number} + * @memberof LemonsqueezySubscriptionInvoiceAttributes + */ + subtotal?: number; + /** + * + * @type {string} + * @memberof LemonsqueezySubscriptionInvoiceAttributes + */ + subtotalFormatted?: string; + /** + * + * @type {number} + * @memberof LemonsqueezySubscriptionInvoiceAttributes + */ + subtotalUsd?: number; + /** + * + * @type {number} + * @memberof LemonsqueezySubscriptionInvoiceAttributes + */ + tax?: number; + /** + * + * @type {string} + * @memberof LemonsqueezySubscriptionInvoiceAttributes + */ + taxFormatted?: string; + /** + * + * @type {number} + * @memberof LemonsqueezySubscriptionInvoiceAttributes + */ + taxUsd?: number; + /** + * + * @type {boolean} + * @memberof LemonsqueezySubscriptionInvoiceAttributes + */ + testMode?: boolean; + /** + * + * @type {number} + * @memberof LemonsqueezySubscriptionInvoiceAttributes + */ + total?: number; + /** + * + * @type {string} + * @memberof LemonsqueezySubscriptionInvoiceAttributes + */ + totalFormatted?: string; + /** + * + * @type {number} + * @memberof LemonsqueezySubscriptionInvoiceAttributes + */ + totalUsd?: number; + /** + * + * @type {string} + * @memberof LemonsqueezySubscriptionInvoiceAttributes + */ + updatedAt?: string; + /** + * + * @type {LemonsqueezySubscriptionInvoiceAttributesUrls} + * @memberof LemonsqueezySubscriptionInvoiceAttributes + */ + urls?: LemonsqueezySubscriptionInvoiceAttributesUrls; +} + +/** + * Check if a given object implements the LemonsqueezySubscriptionInvoiceAttributes interface. + */ +export function instanceOfLemonsqueezySubscriptionInvoiceAttributes(value: object): boolean { + let isInstance = true; + + return isInstance; +} + +export function LemonsqueezySubscriptionInvoiceAttributesFromJSON(json: any): LemonsqueezySubscriptionInvoiceAttributes { + return LemonsqueezySubscriptionInvoiceAttributesFromJSONTyped(json, false); +} + +export function LemonsqueezySubscriptionInvoiceAttributesFromJSONTyped(json: any, ignoreDiscriminator: boolean): LemonsqueezySubscriptionInvoiceAttributes { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'billingReason': !exists(json, 'billing_reason') ? undefined : json['billing_reason'], + 'cardBrand': !exists(json, 'card_brand') ? undefined : json['card_brand'], + 'cardLastFour': !exists(json, 'card_last_four') ? undefined : json['card_last_four'], + 'createdAt': !exists(json, 'created_at') ? undefined : json['created_at'], + 'currency': !exists(json, 'currency') ? undefined : json['currency'], + 'currencyRate': !exists(json, 'currency_rate') ? undefined : json['currency_rate'], + 'discountTotal': !exists(json, 'discount_total') ? undefined : json['discount_total'], + 'discountTotalFormatted': !exists(json, 'discount_total_formatted') ? undefined : json['discount_total_formatted'], + 'discountTotalUsd': !exists(json, 'discount_total_usd') ? undefined : json['discount_total_usd'], + 'refunded': !exists(json, 'refunded') ? undefined : json['refunded'], + 'refundedAt': !exists(json, 'refunded_at') ? undefined : json['refunded_at'], + 'status': !exists(json, 'status') ? undefined : json['status'], + 'statusFormatted': !exists(json, 'status_formatted') ? undefined : json['status_formatted'], + 'storeId': !exists(json, 'store_id') ? undefined : json['store_id'], + 'subscriptionId': !exists(json, 'subscription_id') ? undefined : json['subscription_id'], + 'subtotal': !exists(json, 'subtotal') ? undefined : json['subtotal'], + 'subtotalFormatted': !exists(json, 'subtotal_formatted') ? undefined : json['subtotal_formatted'], + 'subtotalUsd': !exists(json, 'subtotal_usd') ? undefined : json['subtotal_usd'], + 'tax': !exists(json, 'tax') ? undefined : json['tax'], + 'taxFormatted': !exists(json, 'tax_formatted') ? undefined : json['tax_formatted'], + 'taxUsd': !exists(json, 'tax_usd') ? undefined : json['tax_usd'], + 'testMode': !exists(json, 'test_mode') ? undefined : json['test_mode'], + 'total': !exists(json, 'total') ? undefined : json['total'], + 'totalFormatted': !exists(json, 'total_formatted') ? undefined : json['total_formatted'], + 'totalUsd': !exists(json, 'total_usd') ? undefined : json['total_usd'], + 'updatedAt': !exists(json, 'updated_at') ? undefined : json['updated_at'], + 'urls': !exists(json, 'urls') ? undefined : LemonsqueezySubscriptionInvoiceAttributesUrlsFromJSON(json['urls']), + }; +} + +export function LemonsqueezySubscriptionInvoiceAttributesToJSON(value?: LemonsqueezySubscriptionInvoiceAttributes | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'billing_reason': value.billingReason, + 'card_brand': value.cardBrand, + 'card_last_four': value.cardLastFour, + 'created_at': value.createdAt, + 'currency': value.currency, + 'currency_rate': value.currencyRate, + 'discount_total': value.discountTotal, + 'discount_total_formatted': value.discountTotalFormatted, + 'discount_total_usd': value.discountTotalUsd, + 'refunded': value.refunded, + 'refunded_at': value.refundedAt, + 'status': value.status, + 'status_formatted': value.statusFormatted, + 'store_id': value.storeId, + 'subscription_id': value.subscriptionId, + 'subtotal': value.subtotal, + 'subtotal_formatted': value.subtotalFormatted, + 'subtotal_usd': value.subtotalUsd, + 'tax': value.tax, + 'tax_formatted': value.taxFormatted, + 'tax_usd': value.taxUsd, + 'test_mode': value.testMode, + 'total': value.total, + 'total_formatted': value.totalFormatted, + 'total_usd': value.totalUsd, + 'updated_at': value.updatedAt, + 'urls': LemonsqueezySubscriptionInvoiceAttributesUrlsToJSON(value.urls), + }; +} + diff --git a/gptube/gptube-api/generated-api/models/LemonsqueezySubscriptionInvoiceAttributesUrls.ts b/gptube/gptube-api/generated-api/models/LemonsqueezySubscriptionInvoiceAttributesUrls.ts new file mode 100644 index 0000000..5b86064 --- /dev/null +++ b/gptube/gptube-api/generated-api/models/LemonsqueezySubscriptionInvoiceAttributesUrls.ts @@ -0,0 +1,65 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * GPTube API swagger docs + * This is the API documentation of GPTube + * + * The version of the OpenAPI document: 1.0 + * Contact: luckly083@gmail.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +/** + * + * @export + * @interface LemonsqueezySubscriptionInvoiceAttributesUrls + */ +export interface LemonsqueezySubscriptionInvoiceAttributesUrls { + /** + * + * @type {string} + * @memberof LemonsqueezySubscriptionInvoiceAttributesUrls + */ + invoiceUrl?: string; +} + +/** + * Check if a given object implements the LemonsqueezySubscriptionInvoiceAttributesUrls interface. + */ +export function instanceOfLemonsqueezySubscriptionInvoiceAttributesUrls(value: object): boolean { + let isInstance = true; + + return isInstance; +} + +export function LemonsqueezySubscriptionInvoiceAttributesUrlsFromJSON(json: any): LemonsqueezySubscriptionInvoiceAttributesUrls { + return LemonsqueezySubscriptionInvoiceAttributesUrlsFromJSONTyped(json, false); +} + +export function LemonsqueezySubscriptionInvoiceAttributesUrlsFromJSONTyped(json: any, ignoreDiscriminator: boolean): LemonsqueezySubscriptionInvoiceAttributesUrls { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'invoiceUrl': !exists(json, 'invoice_url') ? undefined : json['invoice_url'], + }; +} + +export function LemonsqueezySubscriptionInvoiceAttributesUrlsToJSON(value?: LemonsqueezySubscriptionInvoiceAttributesUrls | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'invoice_url': value.invoiceUrl, + }; +} + diff --git a/gptube/gptube-api/generated-api/models/LemonsqueezySubscriptionItem.ts b/gptube/gptube-api/generated-api/models/LemonsqueezySubscriptionItem.ts new file mode 100644 index 0000000..5709a11 --- /dev/null +++ b/gptube/gptube-api/generated-api/models/LemonsqueezySubscriptionItem.ts @@ -0,0 +1,113 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * GPTube API swagger docs + * This is the API documentation of GPTube + * + * The version of the OpenAPI document: 1.0 + * Contact: luckly083@gmail.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +/** + * + * @export + * @interface LemonsqueezySubscriptionItem + */ +export interface LemonsqueezySubscriptionItem { + /** + * + * @type {string} + * @memberof LemonsqueezySubscriptionItem + */ + createdAt?: string; + /** + * + * @type {number} + * @memberof LemonsqueezySubscriptionItem + */ + id?: number; + /** + * + * @type {boolean} + * @memberof LemonsqueezySubscriptionItem + */ + isUsageBased?: boolean; + /** + * + * @type {number} + * @memberof LemonsqueezySubscriptionItem + */ + priceId?: number; + /** + * + * @type {number} + * @memberof LemonsqueezySubscriptionItem + */ + quantity?: number; + /** + * + * @type {number} + * @memberof LemonsqueezySubscriptionItem + */ + subscriptionId?: number; + /** + * + * @type {string} + * @memberof LemonsqueezySubscriptionItem + */ + updatedAt?: string; +} + +/** + * Check if a given object implements the LemonsqueezySubscriptionItem interface. + */ +export function instanceOfLemonsqueezySubscriptionItem(value: object): boolean { + let isInstance = true; + + return isInstance; +} + +export function LemonsqueezySubscriptionItemFromJSON(json: any): LemonsqueezySubscriptionItem { + return LemonsqueezySubscriptionItemFromJSONTyped(json, false); +} + +export function LemonsqueezySubscriptionItemFromJSONTyped(json: any, ignoreDiscriminator: boolean): LemonsqueezySubscriptionItem { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'createdAt': !exists(json, 'created_at') ? undefined : json['created_at'], + 'id': !exists(json, 'id') ? undefined : json['id'], + 'isUsageBased': !exists(json, 'is_usage_based') ? undefined : json['is_usage_based'], + 'priceId': !exists(json, 'price_id') ? undefined : json['price_id'], + 'quantity': !exists(json, 'quantity') ? undefined : json['quantity'], + 'subscriptionId': !exists(json, 'subscription_id') ? undefined : json['subscription_id'], + 'updatedAt': !exists(json, 'updated_at') ? undefined : json['updated_at'], + }; +} + +export function LemonsqueezySubscriptionItemToJSON(value?: LemonsqueezySubscriptionItem | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'created_at': value.createdAt, + 'id': value.id, + 'is_usage_based': value.isUsageBased, + 'price_id': value.priceId, + 'quantity': value.quantity, + 'subscription_id': value.subscriptionId, + 'updated_at': value.updatedAt, + }; +} + diff --git a/gptube/gptube-api/generated-api/models/LemonsqueezySubscriptionPause.ts b/gptube/gptube-api/generated-api/models/LemonsqueezySubscriptionPause.ts new file mode 100644 index 0000000..c61b4cd --- /dev/null +++ b/gptube/gptube-api/generated-api/models/LemonsqueezySubscriptionPause.ts @@ -0,0 +1,73 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * GPTube API swagger docs + * This is the API documentation of GPTube + * + * The version of the OpenAPI document: 1.0 + * Contact: luckly083@gmail.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +/** + * + * @export + * @interface LemonsqueezySubscriptionPause + */ +export interface LemonsqueezySubscriptionPause { + /** + * + * @type {string} + * @memberof LemonsqueezySubscriptionPause + */ + mode?: string; + /** + * + * @type {string} + * @memberof LemonsqueezySubscriptionPause + */ + resumesAt?: string; +} + +/** + * Check if a given object implements the LemonsqueezySubscriptionPause interface. + */ +export function instanceOfLemonsqueezySubscriptionPause(value: object): boolean { + let isInstance = true; + + return isInstance; +} + +export function LemonsqueezySubscriptionPauseFromJSON(json: any): LemonsqueezySubscriptionPause { + return LemonsqueezySubscriptionPauseFromJSONTyped(json, false); +} + +export function LemonsqueezySubscriptionPauseFromJSONTyped(json: any, ignoreDiscriminator: boolean): LemonsqueezySubscriptionPause { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'mode': !exists(json, 'mode') ? undefined : json['mode'], + 'resumesAt': !exists(json, 'resumes_at') ? undefined : json['resumes_at'], + }; +} + +export function LemonsqueezySubscriptionPauseToJSON(value?: LemonsqueezySubscriptionPause | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'mode': value.mode, + 'resumes_at': value.resumesAt, + }; +} + diff --git a/gptube/gptube-api/generated-api/models/LemonsqueezySubscriptionURLs.ts b/gptube/gptube-api/generated-api/models/LemonsqueezySubscriptionURLs.ts new file mode 100644 index 0000000..87e7446 --- /dev/null +++ b/gptube/gptube-api/generated-api/models/LemonsqueezySubscriptionURLs.ts @@ -0,0 +1,65 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * GPTube API swagger docs + * This is the API documentation of GPTube + * + * The version of the OpenAPI document: 1.0 + * Contact: luckly083@gmail.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +/** + * + * @export + * @interface LemonsqueezySubscriptionURLs + */ +export interface LemonsqueezySubscriptionURLs { + /** + * + * @type {string} + * @memberof LemonsqueezySubscriptionURLs + */ + updatePaymentMethod?: string; +} + +/** + * Check if a given object implements the LemonsqueezySubscriptionURLs interface. + */ +export function instanceOfLemonsqueezySubscriptionURLs(value: object): boolean { + let isInstance = true; + + return isInstance; +} + +export function LemonsqueezySubscriptionURLsFromJSON(json: any): LemonsqueezySubscriptionURLs { + return LemonsqueezySubscriptionURLsFromJSONTyped(json, false); +} + +export function LemonsqueezySubscriptionURLsFromJSONTyped(json: any, ignoreDiscriminator: boolean): LemonsqueezySubscriptionURLs { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'updatePaymentMethod': !exists(json, 'update_payment_method') ? undefined : json['update_payment_method'], + }; +} + +export function LemonsqueezySubscriptionURLsToJSON(value?: LemonsqueezySubscriptionURLs | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'update_payment_method': value.updatePaymentMethod, + }; +} + diff --git a/gptube/gptube-api/generated-api/models/ModelsSubscription.ts b/gptube/gptube-api/generated-api/models/ModelsSubscription.ts new file mode 100644 index 0000000..34609ab --- /dev/null +++ b/gptube/gptube-api/generated-api/models/ModelsSubscription.ts @@ -0,0 +1,208 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * GPTube API swagger docs + * This is the API documentation of GPTube + * + * The version of the OpenAPI document: 1.0 + * Contact: luckly083@gmail.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +import type { ModelsSubscriptionPlanSlug } from './ModelsSubscriptionPlanSlug'; +import { + ModelsSubscriptionPlanSlugFromJSON, + ModelsSubscriptionPlanSlugFromJSONTyped, + ModelsSubscriptionPlanSlugToJSON, +} from './ModelsSubscriptionPlanSlug'; + +/** + * + * @export + * @interface ModelsSubscription + */ +export interface ModelsSubscription { + /** + * + * @type {string} + * @memberof ModelsSubscription + */ + cardBrand?: string; + /** + * + * @type {string} + * @memberof ModelsSubscription + */ + cardLastFour?: string; + /** + * + * @type {string} + * @memberof ModelsSubscription + */ + createdAt?: string; + /** + * + * @type {number} + * @memberof ModelsSubscription + */ + customerId?: number; + /** + * + * @type {string} + * @memberof ModelsSubscription + */ + endsAt?: string; + /** + * + * @type {number} + * @memberof ModelsSubscription + */ + orderId?: number; + /** + * + * @type {number} + * @memberof ModelsSubscription + */ + productId?: number; + /** + * + * @type {string} + * @memberof ModelsSubscription + */ + productName?: string; + /** + * + * @type {string} + * @memberof ModelsSubscription + */ + renewsAt?: string; + /** + * + * @type {string} + * @memberof ModelsSubscription + */ + status?: string; + /** + * + * @type {string} + * @memberof ModelsSubscription + */ + statusFormatted?: string; + /** + * PK + * @type {string} + * @memberof ModelsSubscription + */ + subscriptionId?: string; + /** + * + * @type {ModelsSubscriptionPlanSlug} + * @memberof ModelsSubscription + */ + subscriptionPlanSlug?: ModelsSubscriptionPlanSlug; + /** + * + * @type {string} + * @memberof ModelsSubscription + */ + trialEndsAt?: string; + /** + * + * @type {string} + * @memberof ModelsSubscription + */ + updatePaymentMethod?: string; + /** + * + * @type {string} + * @memberof ModelsSubscription + */ + updatedAt?: string; + /** + * + * @type {string} + * @memberof ModelsSubscription + */ + userEmail?: string; + /** + * + * @type {number} + * @memberof ModelsSubscription + */ + variantId?: number; +} + +/** + * Check if a given object implements the ModelsSubscription interface. + */ +export function instanceOfModelsSubscription(value: object): boolean { + let isInstance = true; + + return isInstance; +} + +export function ModelsSubscriptionFromJSON(json: any): ModelsSubscription { + return ModelsSubscriptionFromJSONTyped(json, false); +} + +export function ModelsSubscriptionFromJSONTyped(json: any, ignoreDiscriminator: boolean): ModelsSubscription { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'cardBrand': !exists(json, 'card_brand') ? undefined : json['card_brand'], + 'cardLastFour': !exists(json, 'card_last_four') ? undefined : json['card_last_four'], + 'createdAt': !exists(json, 'created_at') ? undefined : json['created_at'], + 'customerId': !exists(json, 'customer_id') ? undefined : json['customer_id'], + 'endsAt': !exists(json, 'ends_at') ? undefined : json['ends_at'], + 'orderId': !exists(json, 'order_id') ? undefined : json['order_id'], + 'productId': !exists(json, 'product_id') ? undefined : json['product_id'], + 'productName': !exists(json, 'product_name') ? undefined : json['product_name'], + 'renewsAt': !exists(json, 'renews_at') ? undefined : json['renews_at'], + 'status': !exists(json, 'status') ? undefined : json['status'], + 'statusFormatted': !exists(json, 'status_formatted') ? undefined : json['status_formatted'], + 'subscriptionId': !exists(json, 'subscription_id') ? undefined : json['subscription_id'], + 'subscriptionPlanSlug': !exists(json, 'subscription_plan_slug') ? undefined : ModelsSubscriptionPlanSlugFromJSON(json['subscription_plan_slug']), + 'trialEndsAt': !exists(json, 'trial_ends_at') ? undefined : json['trial_ends_at'], + 'updatePaymentMethod': !exists(json, 'update_payment_method') ? undefined : json['update_payment_method'], + 'updatedAt': !exists(json, 'updated_at') ? undefined : json['updated_at'], + 'userEmail': !exists(json, 'user_email') ? undefined : json['user_email'], + 'variantId': !exists(json, 'variant_id') ? undefined : json['variant_id'], + }; +} + +export function ModelsSubscriptionToJSON(value?: ModelsSubscription | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'card_brand': value.cardBrand, + 'card_last_four': value.cardLastFour, + 'created_at': value.createdAt, + 'customer_id': value.customerId, + 'ends_at': value.endsAt, + 'order_id': value.orderId, + 'product_id': value.productId, + 'product_name': value.productName, + 'renews_at': value.renewsAt, + 'status': value.status, + 'status_formatted': value.statusFormatted, + 'subscription_id': value.subscriptionId, + 'subscription_plan_slug': ModelsSubscriptionPlanSlugToJSON(value.subscriptionPlanSlug), + 'trial_ends_at': value.trialEndsAt, + 'update_payment_method': value.updatePaymentMethod, + 'updated_at': value.updatedAt, + 'user_email': value.userEmail, + 'variant_id': value.variantId, + }; +} + diff --git a/gptube/gptube-api/generated-api/models/ModelsSubscriptionPlan.ts b/gptube/gptube-api/generated-api/models/ModelsSubscriptionPlan.ts new file mode 100644 index 0000000..b1bae20 --- /dev/null +++ b/gptube/gptube-api/generated-api/models/ModelsSubscriptionPlan.ts @@ -0,0 +1,184 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * GPTube API swagger docs + * This is the API documentation of GPTube + * + * The version of the OpenAPI document: 1.0 + * Contact: luckly083@gmail.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +import type { ModelsSubscriptionPlanSlug } from './ModelsSubscriptionPlanSlug'; +import { + ModelsSubscriptionPlanSlugFromJSON, + ModelsSubscriptionPlanSlugFromJSONTyped, + ModelsSubscriptionPlanSlugToJSON, +} from './ModelsSubscriptionPlanSlug'; + +/** + * + * @export + * @interface ModelsSubscriptionPlan + */ +export interface ModelsSubscriptionPlan { + /** + * + * @type {string} + * @memberof ModelsSubscriptionPlan + */ + createdAt?: string; + /** + * + * @type {string} + * @memberof ModelsSubscriptionPlan + */ + description?: string; + /** + * + * @type {Array} + * @memberof ModelsSubscriptionPlan + */ + features?: Array; + /** + * + * @type {string} + * @memberof ModelsSubscriptionPlan + */ + hrefMonthly?: string; + /** + * + * @type {string} + * @memberof ModelsSubscriptionPlan + */ + hrefYearly?: string; + /** + * PK + * @type {string} + * @memberof ModelsSubscriptionPlan + */ + id?: string; + /** + * + * @type {boolean} + * @memberof ModelsSubscriptionPlan + */ + isActive?: boolean; + /** + * + * @type {boolean} + * @memberof ModelsSubscriptionPlan + */ + mostPopular?: boolean; + /** + * + * @type {string} + * @memberof ModelsSubscriptionPlan + */ + name?: string; + /** + * + * @type {number} + * @memberof ModelsSubscriptionPlan + */ + priceMonthly?: number; + /** + * + * @type {number} + * @memberof ModelsSubscriptionPlan + */ + priceYearly?: number; + /** + * + * @type {string} + * @memberof ModelsSubscriptionPlan + */ + productId?: string; + /** + * + * @type {ModelsSubscriptionPlanSlug} + * @memberof ModelsSubscriptionPlan + */ + slug?: ModelsSubscriptionPlanSlug; + /** + * + * @type {string} + * @memberof ModelsSubscriptionPlan + */ + updatedAt?: string; + /** + * + * @type {Array} + * @memberof ModelsSubscriptionPlan + */ + variants?: Array; +} + +/** + * Check if a given object implements the ModelsSubscriptionPlan interface. + */ +export function instanceOfModelsSubscriptionPlan(value: object): boolean { + let isInstance = true; + + return isInstance; +} + +export function ModelsSubscriptionPlanFromJSON(json: any): ModelsSubscriptionPlan { + return ModelsSubscriptionPlanFromJSONTyped(json, false); +} + +export function ModelsSubscriptionPlanFromJSONTyped(json: any, ignoreDiscriminator: boolean): ModelsSubscriptionPlan { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'createdAt': !exists(json, 'created_at') ? undefined : json['created_at'], + 'description': !exists(json, 'description') ? undefined : json['description'], + 'features': !exists(json, 'features') ? undefined : json['features'], + 'hrefMonthly': !exists(json, 'href_monthly') ? undefined : json['href_monthly'], + 'hrefYearly': !exists(json, 'href_yearly') ? undefined : json['href_yearly'], + 'id': !exists(json, 'id') ? undefined : json['id'], + 'isActive': !exists(json, 'is_active') ? undefined : json['is_active'], + 'mostPopular': !exists(json, 'most_popular') ? undefined : json['most_popular'], + 'name': !exists(json, 'name') ? undefined : json['name'], + 'priceMonthly': !exists(json, 'price_monthly') ? undefined : json['price_monthly'], + 'priceYearly': !exists(json, 'price_yearly') ? undefined : json['price_yearly'], + 'productId': !exists(json, 'product_id') ? undefined : json['product_id'], + 'slug': !exists(json, 'slug') ? undefined : ModelsSubscriptionPlanSlugFromJSON(json['slug']), + 'updatedAt': !exists(json, 'updated_at') ? undefined : json['updated_at'], + 'variants': !exists(json, 'variants') ? undefined : json['variants'], + }; +} + +export function ModelsSubscriptionPlanToJSON(value?: ModelsSubscriptionPlan | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'created_at': value.createdAt, + 'description': value.description, + 'features': value.features, + 'href_monthly': value.hrefMonthly, + 'href_yearly': value.hrefYearly, + 'id': value.id, + 'is_active': value.isActive, + 'most_popular': value.mostPopular, + 'name': value.name, + 'price_monthly': value.priceMonthly, + 'price_yearly': value.priceYearly, + 'product_id': value.productId, + 'slug': ModelsSubscriptionPlanSlugToJSON(value.slug), + 'updated_at': value.updatedAt, + 'variants': value.variants, + }; +} + diff --git a/gptube/gptube-api/generated-api/models/ModelsSubscriptionPlanSlug.ts b/gptube/gptube-api/generated-api/models/ModelsSubscriptionPlanSlug.ts new file mode 100644 index 0000000..72829e3 --- /dev/null +++ b/gptube/gptube-api/generated-api/models/ModelsSubscriptionPlanSlug.ts @@ -0,0 +1,39 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * GPTube API swagger docs + * This is the API documentation of GPTube + * + * The version of the OpenAPI document: 1.0 + * Contact: luckly083@gmail.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +/** + * + * @export + */ +export const ModelsSubscriptionPlanSlug = { + FREE: 0, + HOBBY: 1, + POPULAR: 2 +} as const; +export type ModelsSubscriptionPlanSlug = typeof ModelsSubscriptionPlanSlug[keyof typeof ModelsSubscriptionPlanSlug]; + + +export function ModelsSubscriptionPlanSlugFromJSON(json: any): ModelsSubscriptionPlanSlug { + return ModelsSubscriptionPlanSlugFromJSONTyped(json, false); +} + +export function ModelsSubscriptionPlanSlugFromJSONTyped(json: any, ignoreDiscriminator: boolean): ModelsSubscriptionPlanSlug { + return json as ModelsSubscriptionPlanSlug; +} + +export function ModelsSubscriptionPlanSlugToJSON(value?: ModelsSubscriptionPlanSlug | null): any { + return value as any; +} + diff --git a/gptube/gptube-api/generated-api/models/index.ts b/gptube/gptube-api/generated-api/models/index.ts index cb8c2dd..af6eb0e 100644 --- a/gptube/gptube-api/generated-api/models/index.ts +++ b/gptube/gptube-api/generated-api/models/index.ts @@ -2,8 +2,38 @@ /* eslint-disable */ export * from './FiberError'; export * from './HandlersHelloApiMessage'; +export * from './LemonsqueezyApiResponseDataLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount'; +export * from './LemonsqueezyApiResponseDataLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice'; +export * from './LemonsqueezyApiResponseDataLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription'; +export * from './LemonsqueezyApiResponseJSONAPI'; +export * from './LemonsqueezyApiResponseLemonsqueezyCheckoutAttributesLemonsqueezyApiResponseRelationshipsDiscount'; +export * from './LemonsqueezyApiResponseLemonsqueezySubscriptionLemonsqueezyApiResponseRelationshipsSubscription'; +export * from './LemonsqueezyApiResponseLink'; +export * from './LemonsqueezyApiResponseLinks'; +export * from './LemonsqueezyApiResponseListLemonsqueezySubscriptionInvoiceAttributesLemonsqueezyApiResponseRelationshipsSubscriptionInvoice'; +export * from './LemonsqueezyApiResponseListLink'; +export * from './LemonsqueezyApiResponseListMeta'; +export * from './LemonsqueezyApiResponseListMetaPage'; +export * from './LemonsqueezyApiResponseRelationshipsDiscount'; +export * from './LemonsqueezyApiResponseRelationshipsSubscription'; +export * from './LemonsqueezyApiResponseRelationshipsSubscriptionInvoice'; +export * from './LemonsqueezyApiResponseSelfLink'; +export * from './LemonsqueezyBillingAddress'; +export * from './LemonsqueezyCheckoutAttributes'; +export * from './LemonsqueezyCheckoutData'; +export * from './LemonsqueezyCheckoutOptions'; +export * from './LemonsqueezyCheckoutProductOptions'; +export * from './LemonsqueezySubscription'; +export * from './LemonsqueezySubscriptionInvoiceAttributes'; +export * from './LemonsqueezySubscriptionInvoiceAttributesUrls'; +export * from './LemonsqueezySubscriptionItem'; +export * from './LemonsqueezySubscriptionPause'; +export * from './LemonsqueezySubscriptionURLs'; export * from './ModelsBertAIResults'; export * from './ModelsRobertaAIResults'; +export * from './ModelsSubscription'; +export * from './ModelsSubscriptionPlan'; +export * from './ModelsSubscriptionPlanSlug'; export * from './ModelsYoutubeAnalysisLandingResults'; export * from './ModelsYoutubeAnalysisResults'; export * from './ModelsYoutubeAnalyzerLandingReqBody'; diff --git a/gptube/swagger.yaml b/gptube/swagger.yaml index e2724f6..cdcddd2 100644 --- a/gptube/swagger.yaml +++ b/gptube/swagger.yaml @@ -11,6 +11,394 @@ definitions: message: type: string type: object + lemonsqueezy.ApiResponse-lemonsqueezy_CheckoutAttributes-lemonsqueezy_ApiResponseRelationshipsDiscount: + properties: + data: + $ref: '#/definitions/lemonsqueezy.ApiResponseData-lemonsqueezy_CheckoutAttributes-lemonsqueezy_ApiResponseRelationshipsDiscount' + jsonapi: + $ref: '#/definitions/lemonsqueezy.ApiResponseJSONAPI' + links: + $ref: '#/definitions/lemonsqueezy.ApiResponseSelfLink' + type: object + lemonsqueezy.ApiResponse-lemonsqueezy_Subscription-lemonsqueezy_ApiResponseRelationshipsSubscription: + properties: + data: + $ref: '#/definitions/lemonsqueezy.ApiResponseData-lemonsqueezy_Subscription-lemonsqueezy_ApiResponseRelationshipsSubscription' + jsonapi: + $ref: '#/definitions/lemonsqueezy.ApiResponseJSONAPI' + links: + $ref: '#/definitions/lemonsqueezy.ApiResponseSelfLink' + type: object + lemonsqueezy.ApiResponseData-lemonsqueezy_CheckoutAttributes-lemonsqueezy_ApiResponseRelationshipsDiscount: + properties: + attributes: + $ref: '#/definitions/lemonsqueezy.CheckoutAttributes' + id: + type: string + links: + $ref: '#/definitions/lemonsqueezy.ApiResponseSelfLink' + relationships: + $ref: '#/definitions/lemonsqueezy.ApiResponseRelationshipsDiscount' + type: + type: string + type: object + lemonsqueezy.ApiResponseData-lemonsqueezy_Subscription-lemonsqueezy_ApiResponseRelationshipsSubscription: + properties: + attributes: + $ref: '#/definitions/lemonsqueezy.Subscription' + id: + type: string + links: + $ref: '#/definitions/lemonsqueezy.ApiResponseSelfLink' + relationships: + $ref: '#/definitions/lemonsqueezy.ApiResponseRelationshipsSubscription' + type: + type: string + type: object + lemonsqueezy.ApiResponseData-lemonsqueezy_SubscriptionInvoiceAttributes-lemonsqueezy_ApiResponseRelationshipsSubscriptionInvoice: + properties: + attributes: + $ref: '#/definitions/lemonsqueezy.SubscriptionInvoiceAttributes' + id: + type: string + links: + $ref: '#/definitions/lemonsqueezy.ApiResponseSelfLink' + relationships: + $ref: '#/definitions/lemonsqueezy.ApiResponseRelationshipsSubscriptionInvoice' + type: + type: string + type: object + lemonsqueezy.ApiResponseJSONAPI: + properties: + version: + type: string + type: object + lemonsqueezy.ApiResponseLink: + properties: + related: + type: string + self: + type: string + type: object + lemonsqueezy.ApiResponseLinks: + properties: + links: + $ref: '#/definitions/lemonsqueezy.ApiResponseLink' + type: object + lemonsqueezy.ApiResponseList-lemonsqueezy_SubscriptionInvoiceAttributes-lemonsqueezy_ApiResponseRelationshipsSubscriptionInvoice: + properties: + data: + items: + $ref: '#/definitions/lemonsqueezy.ApiResponseData-lemonsqueezy_SubscriptionInvoiceAttributes-lemonsqueezy_ApiResponseRelationshipsSubscriptionInvoice' + type: array + jsonapi: + $ref: '#/definitions/lemonsqueezy.ApiResponseJSONAPI' + links: + $ref: '#/definitions/lemonsqueezy.ApiResponseListLink' + meta: + $ref: '#/definitions/lemonsqueezy.ApiResponseListMeta' + type: object + lemonsqueezy.ApiResponseListLink: + properties: + first: + type: string + last: + type: string + next: + type: string + type: object + lemonsqueezy.ApiResponseListMeta: + properties: + page: + $ref: '#/definitions/lemonsqueezy.ApiResponseListMetaPage' + type: object + lemonsqueezy.ApiResponseListMetaPage: + properties: + currentPage: + type: integer + from: + type: integer + lastPage: + type: integer + perPage: + type: integer + to: + type: integer + total: + type: integer + type: object + lemonsqueezy.ApiResponseRelationshipsDiscount: + properties: + discount-redemptions: + $ref: '#/definitions/lemonsqueezy.ApiResponseLinks' + store: + $ref: '#/definitions/lemonsqueezy.ApiResponseLinks' + variants: + $ref: '#/definitions/lemonsqueezy.ApiResponseLinks' + type: object + lemonsqueezy.ApiResponseRelationshipsSubscription: + properties: + customer: + $ref: '#/definitions/lemonsqueezy.ApiResponseLinks' + order: + $ref: '#/definitions/lemonsqueezy.ApiResponseLinks' + order-item: + $ref: '#/definitions/lemonsqueezy.ApiResponseLinks' + product: + $ref: '#/definitions/lemonsqueezy.ApiResponseLinks' + store: + $ref: '#/definitions/lemonsqueezy.ApiResponseLinks' + subscription-invoices: + $ref: '#/definitions/lemonsqueezy.ApiResponseLinks' + subscription-items: + $ref: '#/definitions/lemonsqueezy.ApiResponseLinks' + variant: + $ref: '#/definitions/lemonsqueezy.ApiResponseLinks' + type: object + lemonsqueezy.ApiResponseRelationshipsSubscriptionInvoice: + properties: + store: + $ref: '#/definitions/lemonsqueezy.ApiResponseLinks' + subscription: + $ref: '#/definitions/lemonsqueezy.ApiResponseLinks' + type: object + lemonsqueezy.ApiResponseSelfLink: + properties: + self: + type: string + type: object + lemonsqueezy.BillingAddress: + properties: + country: + type: string + zip: + type: string + type: object + lemonsqueezy.CheckoutAttributes: + properties: + checkout_data: + $ref: '#/definitions/lemonsqueezy.CheckoutData' + checkout_options: + $ref: '#/definitions/lemonsqueezy.CheckoutOptions' + created_at: + type: string + custom_price: {} + expires_at: + type: string + product_options: + $ref: '#/definitions/lemonsqueezy.CheckoutProductOptions' + store_id: + type: integer + test_mode: + type: boolean + updated_at: + type: string + url: + type: string + variant_id: + type: integer + type: object + lemonsqueezy.CheckoutData: + properties: + billing_address: + items: + $ref: '#/definitions/lemonsqueezy.BillingAddress' + type: array + custom: + additionalProperties: {} + type: object + discount_code: + type: string + email: + type: string + name: + type: string + tax_number: + type: string + type: object + lemonsqueezy.CheckoutOptions: + properties: + button_color: + type: string + dark: + type: boolean + desc: + type: boolean + discount: + type: boolean + embed: + type: boolean + logo: + type: boolean + media: + type: boolean + subscription_preview: + type: boolean + type: object + lemonsqueezy.CheckoutProductOptions: + properties: + description: + type: string + enabled_variants: + items: + type: integer + type: array + media: + items: {} + type: array + name: + type: string + receipt_button_text: + type: string + receipt_link_url: + type: string + receipt_thank_you_note: + type: string + redirect_url: + type: string + type: object + lemonsqueezy.Subscription: + properties: + billing_anchor: + type: integer + cancelled: + type: boolean + card_brand: + type: string + card_last_four: + type: string + created_at: + type: string + customer_id: + type: integer + ends_at: + type: string + first_subscription_item: + $ref: '#/definitions/lemonsqueezy.SubscriptionItem' + order_id: + type: integer + order_item_id: + type: integer + pause: + $ref: '#/definitions/lemonsqueezy.SubscriptionPause' + product_id: + type: integer + product_name: + type: string + renews_at: + type: string + status: + type: string + status_formatted: + type: string + store_id: + type: integer + test_mode: + type: boolean + trial_ends_at: + type: string + updated_at: + type: string + urls: + $ref: '#/definitions/lemonsqueezy.SubscriptionURLs' + user_email: + type: string + user_name: + type: string + variant_id: + type: integer + variant_name: + type: string + type: object + lemonsqueezy.SubscriptionInvoiceAttributes: + properties: + billing_reason: + type: string + card_brand: + type: string + card_last_four: + type: string + created_at: + type: string + currency: + type: string + currency_rate: + type: string + discount_total: + type: integer + discount_total_formatted: + type: string + discount_total_usd: + type: integer + refunded: + type: boolean + refunded_at: + type: string + status: + type: string + status_formatted: + type: string + store_id: + type: integer + subscription_id: + type: integer + subtotal: + type: integer + subtotal_formatted: + type: string + subtotal_usd: + type: integer + tax: + type: integer + tax_formatted: + type: string + tax_usd: + type: integer + test_mode: + type: boolean + total: + type: integer + total_formatted: + type: string + total_usd: + type: integer + updated_at: + type: string + urls: + properties: + invoice_url: + type: string + type: object + type: object + lemonsqueezy.SubscriptionItem: + properties: + created_at: + type: string + id: + type: integer + is_usage_based: + type: boolean + price_id: + type: integer + quantity: + type: integer + subscription_id: + type: integer + updated_at: + type: string + type: object + lemonsqueezy.SubscriptionPause: + properties: + mode: + type: string + resumes_at: + type: string + type: object + lemonsqueezy.SubscriptionURLs: + properties: + update_payment_method: + type: string + type: object models.BertAIResults: properties: errors_count: @@ -41,6 +429,96 @@ definitions: success_count: type: integer type: object + models.Subscription: + properties: + card_brand: + type: string + card_last_four: + type: string + created_at: + type: string + customer_id: + type: integer + ends_at: + type: string + order_id: + type: integer + product_id: + type: integer + product_name: + type: string + renews_at: + type: string + status: + type: string + status_formatted: + type: string + subscription_id: + description: PK + type: string + subscription_plan_slug: + allOf: + - $ref: '#/definitions/models.SubscriptionPlanSlug' + description: FK SubscriptionPlan + trial_ends_at: + type: string + update_payment_method: + type: string + updated_at: + type: string + user_email: + type: string + variant_id: + type: integer + type: object + models.SubscriptionPlan: + properties: + created_at: + type: string + description: + type: string + features: + items: + type: string + type: array + href_monthly: + type: string + href_yearly: + type: string + id: + description: PK + type: string + is_active: + type: boolean + most_popular: + type: boolean + name: + type: string + price_monthly: + type: number + price_yearly: + type: number + product_id: + type: string + slug: + $ref: '#/definitions/models.SubscriptionPlanSlug' + updated_at: + type: string + variants: + items: + type: string + type: array + type: object + models.SubscriptionPlanSlug: + enum: + - 0 + - 1 + - 2 + type: integer + x-enum-varnames: + - FREE + - HOBBY + - POPULAR models.YoutubeAnalysisLandingResults: properties: bert_results: @@ -652,4 +1130,190 @@ paths: schema: $ref: '#/definitions/handlers.helloApiMessage' summary: Hello message from the billing api + /billing/cancel-subscription: + get: + description: An endpoint to cancel a subscription + parameters: + - description: the subscription id + in: query + name: subscription_id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + type: string + "400": + description: Bad Request + schema: + $ref: '#/definitions/fiber.Error' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/fiber.Error' + summary: Cancel a subscription + /billing/checkout: + get: + description: |- + An endpoint to retrieve the URL for a subscription plan sending + the account email as well. + parameters: + - description: the variant id of the subscription plan + in: query + name: variant_id + required: true + type: string + - description: the user id + in: query + name: user_id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/lemonsqueezy.ApiResponse-lemonsqueezy_CheckoutAttributes-lemonsqueezy_ApiResponseRelationshipsDiscount' + "400": + description: Bad Request + schema: + $ref: '#/definitions/fiber.Error' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/fiber.Error' + summary: Get the checkout URL for a subscription plan + /billing/invoices: + get: + description: An endpoint to retrieve the invoices from a user's subscription + parameters: + - description: the subscription id + in: query + name: subscription_id + required: true + type: string + - description: the queried page + in: query + name: page + type: integer + - description: 'page size for the results (default: 10, max: 50)' + in: query + name: page_size + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/lemonsqueezy.ApiResponseList-lemonsqueezy_SubscriptionInvoiceAttributes-lemonsqueezy_ApiResponseRelationshipsSubscriptionInvoice' + "400": + description: Bad Request + schema: + $ref: '#/definitions/fiber.Error' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/fiber.Error' + summary: Get the latest Invoices from a subscription + /billing/resume-subscription: + get: + description: An endpoint to resume a cancelled subscription + parameters: + - description: the subscription id + in: query + name: subscription_id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + type: string + "400": + description: Bad Request + schema: + $ref: '#/definitions/fiber.Error' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/fiber.Error' + summary: Resume a subscription + /billing/subscription-plans: + get: + description: An endpoint to retrieve the subscription plan offered by GPTube + with its price, features, etc. + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/models.SubscriptionPlan' + type: array + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/fiber.Error' + summary: Get the subscription plans offered by GPTube + /billing/subscriptions: + get: + description: An endpoint to retrieve all the subscriptions belonging to an account + parameters: + - description: the user id + in: query + name: user_id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/models.Subscription' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/fiber.Error' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/fiber.Error' + summary: Get the subscribed subscriptions of an account + /billing/update-payment-method: + get: + description: An endpoint to retrieve the URL to update the payment method for + a subscription + parameters: + - description: the subscription id + in: query + name: subscription_id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/lemonsqueezy.ApiResponse-lemonsqueezy_Subscription-lemonsqueezy_ApiResponseRelationshipsSubscription' + "400": + description: Bad Request + schema: + $ref: '#/definitions/fiber.Error' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/fiber.Error' + summary: Get the update payment method URL for a subscription swagger: "2.0" diff --git a/subscriptions-server/.vercel.json b/subscriptions-server/.vercel.json index 05d15bc..567a0f1 100644 --- a/subscriptions-server/.vercel.json +++ b/subscriptions-server/.vercel.json @@ -1,15 +1,8 @@ { - "version": 2, - "builds": [ + "rewrites": [ { - "src": "./index.js", - "use": "@vercel/node" - } - ], - "routes": [ - { - "src": "/(.*)", - "dest": "/" + "source": "/api/(.*)", + "destination": "/api" } ] } \ No newline at end of file diff --git a/subscriptions-server/README.md b/subscriptions-server/README.md index f8c06e3..bb1e12b 100644 --- a/subscriptions-server/README.md +++ b/subscriptions-server/README.md @@ -1 +1,2 @@ Provisional server to handle subscription webhooks +Update diff --git a/subscriptions-server/handlers/index.js b/subscriptions-server/handlers/index.js index 54153e5..a667d7a 100644 --- a/subscriptions-server/handlers/index.js +++ b/subscriptions-server/handlers/index.js @@ -43,6 +43,8 @@ const getSubscriptionSchema = (subscription) => { }; const subscriptionCreatedHandler = async (payload) => { + const event_type = payload["meta"]["event_name"]; + console.log(`Entry event: ${event_type}`); const subscription = payload["data"]; const data = getSubscriptionSchema(subscription); try { @@ -59,6 +61,8 @@ const subscriptionCreatedHandler = async (payload) => { }; const subscriptionUpdatedHandler = async (payload) => { + const event_type = payload["meta"]["event_name"]; + console.log(`Entry event: ${event_type}`); const subscription = payload["data"]; const data = getSubscriptionSchema(subscription); try { diff --git a/subscriptions-server/index.js b/subscriptions-server/index.js index 91a3a74..27acef0 100644 --- a/subscriptions-server/index.js +++ b/subscriptions-server/index.js @@ -1,7 +1,7 @@ require("dotenv").config({ path: ".env.development" }); const express = require("express"); -const webhook_events = require("./handlers/index.js"); -const { validateSignature } = require("./utils.js"); +const webhook_events = require("./handlers/index"); +const { validateSignature } = require("./utils"); const app = express(); const port = process.env.PORT || 8001; @@ -13,16 +13,15 @@ app.use((req, _res, next) => { next(); }); -app.get("/", (_req, res) => { +app.get("/api", (_req, res) => { return res.status(200).send("GPTUBE-subscriptions server"); }); -app.post("/billing/webhooks", async (req, res) => { +app.post("/api/billing/webhooks", async (req, res) => { try { validateSignature(req); const body = JSON.parse(req.body); const event_type = body["meta"]["event_name"]; - console.log(`Entry event: ${event_type}`); const handler = webhook_events[`${event_type}`]; handler && (await handler(body)); res.status(200).json({ message: "webhook handled" }); diff --git a/subscriptions-server/package.json b/subscriptions-server/package.json index b0ab73f..a37c020 100644 --- a/subscriptions-server/package.json +++ b/subscriptions-server/package.json @@ -5,7 +5,8 @@ "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "start": "nodemon index.js" + "run": "node api/index.js", + "start": "nodemon api/index.js" }, "keywords": [], "author": "",