* feat: add enterprise license activation and deactivation endpoints - Implemented `EnterpriseLicenseActivateEndpoint` and `EnterpriseLicenseDeactivateEndpoint` for managing enterprise licenses. - Updated URL routing to include new endpoints for activating and deactivating enterprise licenses. - Added necessary request handling and response structures for enterprise license operations. - Enhanced existing license management logic to accommodate enterprise-specific requirements. * feat: add enterprise plan invite and update handling - Implemented `handle_enterprise_plan_invite_case` to manage invites under the enterprise plan. - Added `handle_enterprise_plan_update_case` for role updates within the enterprise plan. - Updated `handle_cloud_payments` to incorporate new enterprise plan handling logic for invites and role updates. * feat: add enterprise license management endpoints - Introduced new endpoints for managing enterprise licenses, including `InstanceLicenseSyncEndpoint`, `EnterpriseModifySeatsEndpoint`, `EnterpriseSubscriptionPortalEndpoint`, and `EnterpriseSubscriptionProrationPreviewEndpoint`. - Updated URL routing to accommodate the new endpoints for enterprise license operations. - Enhanced the views and API interactions to support enterprise license modifications and subscription management. * feat: enhance enterprise license activation and management - Updated `EnterpriseLicenseActivateEndpoint` to allow any user to access the activation endpoint. - Introduced new airgapped activation handler for enterprise licenses, enabling file uploads and processing of activation files. - Added routes for enterprise license activation in airgapped mode, including file handling and database population. - Enhanced error handling and response structures for better user feedback during activation processes. * feat: implement instance license management features - Added new components and hooks for managing instance licenses, including activation via license key and file uploads. - Introduced `InstanceManagementStore` to handle license operations and state management. - Created UI components for license management, including forms for entering license keys and uploading license files. - Enhanced API interactions for license activation and deactivation, with improved error handling and user feedback. - Updated routing and layout for the instance management page to accommodate new features. * refactor: replace regular imports with type imports for improved clarity across multiple components * fix: admin build * refactor: update enterprise license API paths and enhance error handling - Changed API paths for enterprise license endpoints to include "instances" in the URL structure. - Improved error handling in the EnterpriseLicenseActivateEndpoint and EnterpriseLicenseDeactivateEndpoint to return more specific error messages based on response status codes. - Added logging configuration for "plane.payments" in both local and production settings. * feat: add InstanceLicenseEndpoint for retrieving current enterprise license plan - Introduced InstanceLicenseEndpoint to fetch the current enterprise license plan from the payment server. - Updated URL routing to include the new endpoint for instance licenses. - Enhanced error handling for the new endpoint to manage various response scenarios. * feat: add billing and user management pages, update sidebar menu - Introduced new routes for billing and user management in the admin dashboard. - Updated the sidebar menu to include links for the new billing and user management pages. - Refactored existing components to utilize a new PageWrapper for consistent layout across pages. - Enhanced the AI, authentication, and image pages with the new PageWrapper for improved UI consistency. * fix: adjust icon sizes * feat: enterprise license activation UI * fix: remove unnecessary shrink-0 class from header actions div in PageWrapper * fix: update error handling in enterprise license endpoints - Removed unnecessary newline in the Python API view for instance licenses. - Changed the response in the Go handler to return a success status with a message when no enterprise license exists, instead of an internal server error. * feat: enhance enterprise license management and update dependencies * refactor: simplify EnterprisePlanCard and enhance button handling - Removed unnecessary props and state management from EnterprisePlanCard. - Updated PlanCard to conditionally render the button. - Enhanced BillingActionsButton to provide tooltips for Enterprise plan users. - Adjusted limit-reached-info to reflect Enterprise plan status in seat management. * style: update modal styling for enterprise license success component * refactor: streamline enterprise license deactivation process - Removed the requirement for a license key in the Python API view. - Simplified the Go handler by eliminating unnecessary payload parsing and improved the response structure for cases with no existing enterprise license. * refactor: remove InstanceLicenseActions component and clean up related code - Deleted the InstanceLicenseActions component to streamline the enterprise license management. - Updated EnterprisePlanCard to conditionally render components based on the subscription status. - Removed unused props and functions related to trial period checks from the instance management store and types. * refactor: simplify GetEnterpriseLicenseCurrentPlan response structure - Removed unnecessary fields from the response for both existing and new enterprise licenses. - Streamlined the JSON output to focus on essential information, enhancing clarity and reducing payload size. * feat: implement seat management functionality for enterprise licenses - Added InstanceLicenseActions component to handle license synchronization and deactivation. - Introduced SeatsManagementButton for managing seat additions and removals. - Created modals and forms for adding and removing seats, including proration previews. - Updated EnterprisePlanCard to integrate new seat management features. - Enhanced instance management store with methods for updating subscription details and managing seats. * feat: enhance enterprise plan user guidance and UI updates * refactor: update instance management service usage and rename seat form components * fix: closure issues in enterprise plan card and instance management store * feat: add endpoint to remove unused seats from enterprise licenses - Introduced EnterpriseLicenseRemoveUnusedSeatsEndpoint to handle the removal of unused seats. - Updated URL routing to include the new endpoint. - Refactored user count retrieval logic to streamline seat management processes. * fix: remove duplicate workspaceSlug prop from RemoveUnusedSeatsModal in GlobalModals component * chore: change the enterprise member count * feat: enhance seat management UI and logic for subscription levels - Updated the SelectSeatsStep component to display different messages based on subscription level (workspace vs instance). - Modified the ConfirmPriceStep to reflect the subscription level in the confirmation message. - Added subscription level handling in the AddSeatsForm component. - Improved the invitation description to differentiate between Enterprise and non-Enterprise plans. - Introduced a new field for allowed total users in the TMemberInviteCheck type for Enterprise plans. - Refactored styles for better UI consistency in the NumberInputWithControls component. * feat: implement enterprise plan invite check for workspace - Added a method to check the allowed total users for inviting new members based on the enterprise plan. - Integrated the invite check into the existing endpoint response, providing clarity on user limits for enterprise workspaces. - Enhanced the logic to count current active and invited users, ensuring accurate seat management for enterprise licenses. * refactor: remove unused import in workspace invite check endpoint - Eliminated the unused import of handle_enterprise_plan_invite_case from the invite.py file, streamlining the code and improving maintainability. * fix: update enterprise plan user limit check in invitation description * fix: format --------- Co-authored-by: Prateek Shourya <[email protected]> Co-authored-by: b-saikrishnakanth <[email protected]>
662 lines
20 KiB
Go
662 lines
20 KiB
Go
package prime_api
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
)
|
|
|
|
type IPrimeMonitorApi interface {
|
|
// Getters for the api
|
|
IsAirgapped() bool
|
|
AppVersion() string
|
|
ApiHostname() string
|
|
|
|
PostServiceStatus(StatusPayload) ErrorCode
|
|
GetFeatureFlags(licenseKey string) (*FlagDataResponse, *APIError)
|
|
ActivateInstance() *APIError
|
|
DeactivateInstance() *APIError
|
|
RetrievePlans(string) (*[]Product, *APIError)
|
|
RetrievePaymentLink(RetrievePaymentLinkPayload) (*RetrievePaymentLinkResponse, *APIError)
|
|
UpdateSubcription(SeatUpdatePayload) (*SeatUpdateResponse, *APIError)
|
|
SyncWorkspace(WorkspaceSyncPayload) (*WorkspaceActivationResponse, *APIError)
|
|
DeactivateLicense(LicenseDeactivatePayload) (*WorkspaceActivationResponse, *APIError)
|
|
ActivateWorkspace(WorkspaceActivationPayload) (*WorkspaceActivationResponse, *APIError)
|
|
ActivateFreeWorkspace(WorkspaceActivationPayload) (*WorkspaceActivationResponse, *APIError)
|
|
InitializeInstance(CredentialsPayload) (SetupResponse, *APIError)
|
|
GetSubscriptionDetails(WorkspaceSubscriptionPayload) (*WorkspaceSubscriptionResponse, *APIError)
|
|
GetProrationPreview(ProrationPreviewPayload) (*ProrationPreviewResponse, *APIError)
|
|
|
|
// Enterprise License
|
|
EnterpriseLicenseActivate(EnterpriseLicenseActivatePayload) (*EnterpriseLicenseActivateResponse, *APIError)
|
|
SyncEnterpriseLicense(EnterpriseLicenseSyncPayload) (*EnterpriseLicenseActivateResponse, *APIError)
|
|
GetEnterpriseFeatureFlags(licenseKey string) (*FlagDataResponse, *APIError)
|
|
DeactivateEnterpriseLicense(LicenseDeactivatePayload) *APIError
|
|
UpdateEnterpriseLicenseSeats(UpdateEnterpriseLicenseSeatsPayload) (*SeatUpdateResponse, *APIError)
|
|
GetEnterpriseLicensePortal() (*EnterpriseLicensePortalResponse, *APIError)
|
|
GetEnterpriseLicenseProrationPreview(UpdateEnterpriseLicenseSeatsPayload) (*ProrationPreviewResponse, *APIError)
|
|
}
|
|
|
|
type LicenseDeactivatePayload struct {
|
|
WorkspaceSlug string `json:"workspace_slug"`
|
|
WorkspaceID string `json:"workspace_id"`
|
|
LicenseKey string `json:"license_key"`
|
|
}
|
|
|
|
type PrimeMonitorApi struct {
|
|
host string
|
|
instanceId string
|
|
appVersion string
|
|
client string
|
|
version string
|
|
machineSignature string
|
|
}
|
|
|
|
type CredentialsPayload struct {
|
|
ServerId string
|
|
Domain string
|
|
AppVersion string
|
|
}
|
|
|
|
type WorkspaceSubscriptionPayload struct {
|
|
WorkspaceId string `json:"workspace_id"`
|
|
LicenseKey string `json:"license_key"`
|
|
}
|
|
|
|
type WorkspaceSubscriptionResponse struct {
|
|
Product string `json:"product"`
|
|
CurrentPeriodEnd string `json:"current_period_end_date"`
|
|
SubscriptionExists bool `json:"subscription_exists"`
|
|
Url string `json:"url"`
|
|
}
|
|
|
|
type ProrationPreviewPayload struct {
|
|
WorkspaceId string `json:"workspace_id"`
|
|
Quantity int `json:"quantity"`
|
|
WorkspaceSlug string `json:"workspace_slug"`
|
|
LicenseKey string `json:"license_key"`
|
|
}
|
|
|
|
type ProrationPreviewResponse struct {
|
|
QuantityDifference int `json:"quantity_difference"`
|
|
PerSeatProrationAmount float64 `json:"per_seat_prorated_amount"`
|
|
NewQuantity int `json:"new_quantity"`
|
|
TotalProratedAmount float64 `json:"total_prorated_amount"`
|
|
CurrentQuantity int `json:"current_quantity"`
|
|
CurrentPriceAmount float64 `json:"current_price_amount"`
|
|
CurrentPriceInterval string `json:"current_price_interval"`
|
|
}
|
|
|
|
type SetupResponse struct {
|
|
Domain string `json:"domain"`
|
|
InstanceId string `json:"instance_id"`
|
|
Host string `json:"prime_host"`
|
|
Version string `json:"version"`
|
|
}
|
|
|
|
type FlagsPayload struct {
|
|
EncryptedData string `json:"encrypted_data"`
|
|
}
|
|
|
|
// Add this struct to handle the error response from the server
|
|
type ErrorResponse struct {
|
|
Message string `json:"message"`
|
|
Error string `json:"error"`
|
|
}
|
|
|
|
func NewMonitorApi(host, machineSignature, instanceId, appVersion string) IPrimeMonitorApi {
|
|
return &PrimeMonitorApi{
|
|
host: host,
|
|
instanceId: instanceId,
|
|
appVersion: appVersion,
|
|
client: "Prime-Monitor",
|
|
version: appVersion,
|
|
machineSignature: machineSignature,
|
|
}
|
|
}
|
|
|
|
// We don't need this for the normal api, but we need it for the airgapped api
|
|
func (api *PrimeMonitorApi) ApiHostname() string {
|
|
return ""
|
|
}
|
|
|
|
func (api *PrimeMonitorApi) AppVersion() string {
|
|
return api.appVersion
|
|
}
|
|
|
|
func (api *PrimeMonitorApi) IsAirgapped() bool {
|
|
return false
|
|
}
|
|
|
|
func (api *PrimeMonitorApi) SetClient(client string) {
|
|
api.client = client
|
|
}
|
|
|
|
var (
|
|
API_PREFIX = "/api/v2"
|
|
MONITOR_ENDPOINT = API_PREFIX + "/monitor/"
|
|
FEATURE_FLAGS = API_PREFIX + "/flags/"
|
|
INSTANCE_PREFIX = API_PREFIX + "/instances"
|
|
ACTIVATE_INSTANCE = INSTANCE_PREFIX + "/activate/"
|
|
DEACTIVATE_INSTANCE = INSTANCE_PREFIX + "/deactivate/"
|
|
UPGRADE_INSTANCE = INSTANCE_PREFIX + "/upgrade/"
|
|
FREE_WORKSPACE_ACTIVATE = API_PREFIX + "/licenses/initialize/"
|
|
WORKSPACE_ACTIVATE = API_PREFIX + "/licenses/activate/"
|
|
SYNC_WORKSPACE = API_PREFIX + "/licenses/sync/"
|
|
UPDATE_SUBSCRIPTION = API_PREFIX + "/modify-subscriptions/"
|
|
SETUP_ENDPOINT = API_PREFIX + "/instances/initialize/"
|
|
SUBSCRIPTION_PORTAL = API_PREFIX + "/subscription-portal/"
|
|
RETRIEVE_PLANS = API_PREFIX + "/instances/products/"
|
|
RETRIEVE_PAYMENT_LINK = API_PREFIX + "/instances/payment-link/"
|
|
DEACTIVATE_LICENSE_ENDPOINT = API_PREFIX + "/licenses/deactivate/"
|
|
PRORATION_PREVIEW = API_PREFIX + "/subscriptions/proration-preview/"
|
|
// Enterprise License
|
|
ENTERPRISE_LICENSE_ACTIVATE = API_PREFIX + "/enterprise/licenses/activate/"
|
|
SYNC_ENTERPRISE_LICENSE = API_PREFIX + "/enterprise/licenses/sync/"
|
|
DEACTIVATE_ENTERPRISE_LICENSE = API_PREFIX + "/enterprise/licenses/deactivate/"
|
|
UPDATE_ENTERPRISE_LICENSE_SEATS = API_PREFIX + "/enterprise/licenses/update-subscriptions/"
|
|
ENTERPRISE_SUBSCRIPTION_PORTAL = API_PREFIX + "/enterprise/licenses/subscription-portal/"
|
|
ENTERPRISE_PRORATION_PREVIEW = API_PREFIX + "/enterprise/licenses/subscription-proration-preview/"
|
|
)
|
|
|
|
/* ----------------------- Controller Methods ------------------------------ */
|
|
// Posts the status of the services given, to the prime server, returns error if
|
|
// hinderer, else doesn't return anything
|
|
func (api *PrimeMonitorApi) PostServiceStatus(payload StatusPayload) ErrorCode {
|
|
_, err := api.post(api.host+MONITOR_ENDPOINT, payload)
|
|
if err != nil {
|
|
return UNABLE_TO_POST_SERVICE_STATUS
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func (api *PrimeMonitorApi) DeactivateLicense(payload LicenseDeactivatePayload) (*WorkspaceActivationResponse, *APIError) {
|
|
resp, apiError := api.post(api.host+DEACTIVATE_LICENSE_ENDPOINT, payload)
|
|
if apiError != nil {
|
|
return nil, apiError
|
|
}
|
|
data := WorkspaceActivationResponse{}
|
|
|
|
if err := json.Unmarshal(resp, &data); err != nil {
|
|
return nil, &APIError{
|
|
Error: fmt.Sprintf("Error unmarshaling response: %v", err),
|
|
Success: false,
|
|
}
|
|
}
|
|
|
|
return &data, nil
|
|
}
|
|
|
|
func (api *PrimeMonitorApi) ActivateFreeWorkspace(payload WorkspaceActivationPayload) (*WorkspaceActivationResponse, *APIError) {
|
|
resp, apiError := api.post(api.host+FREE_WORKSPACE_ACTIVATE, payload)
|
|
if apiError != nil {
|
|
return nil, apiError
|
|
}
|
|
data := WorkspaceActivationResponse{}
|
|
if err := json.Unmarshal(resp, &data); err != nil {
|
|
return nil, &APIError{
|
|
Error: fmt.Sprintf("Error unmarshaling response: %v", err),
|
|
Success: false,
|
|
}
|
|
}
|
|
return &data, nil
|
|
}
|
|
|
|
// Activating a paid licensed workspace
|
|
func (api *PrimeMonitorApi) ActivateWorkspace(payload WorkspaceActivationPayload) (*WorkspaceActivationResponse, *APIError) {
|
|
resp, apiError := api.post(api.host+WORKSPACE_ACTIVATE, payload)
|
|
if apiError != nil {
|
|
return nil, apiError
|
|
}
|
|
data := WorkspaceActivationResponse{}
|
|
if err := json.Unmarshal(resp, &data); err != nil {
|
|
return nil, &APIError{
|
|
Error: fmt.Sprintf("Error unmarshaling response: %v", err),
|
|
Success: false,
|
|
}
|
|
}
|
|
return &data, nil
|
|
}
|
|
|
|
func (api *PrimeMonitorApi) GetFeatureFlags(licenseKey string) (*FlagDataResponse, *APIError) {
|
|
flagData, apiError := api.post(api.host+FEATURE_FLAGS, map[string]string{
|
|
"license_key": licenseKey,
|
|
"version": api.version,
|
|
})
|
|
if apiError != nil {
|
|
return nil, apiError
|
|
}
|
|
data := FlagDataResponse{}
|
|
if err := json.Unmarshal(flagData, &data); err != nil {
|
|
return nil, &APIError{
|
|
Error: fmt.Sprintf("Error unmarshaling response: %v", err),
|
|
Success: false,
|
|
}
|
|
}
|
|
return &data, nil
|
|
}
|
|
|
|
func (api *PrimeMonitorApi) RetrievePlans(quantity string) (*[]Product, *APIError) {
|
|
resp, apiError := api.get(api.host+RETRIEVE_PLANS, map[string]string{
|
|
"quantity": quantity,
|
|
})
|
|
if apiError != nil {
|
|
return nil, apiError
|
|
}
|
|
data := []Product{}
|
|
if err := json.Unmarshal(resp, &data); err != nil {
|
|
return nil, &APIError{
|
|
Error: fmt.Sprintf("Error unmarshaling response: %v", err),
|
|
Success: false,
|
|
}
|
|
}
|
|
return &data, nil
|
|
}
|
|
|
|
func (api *PrimeMonitorApi) RetrievePaymentLink(payload RetrievePaymentLinkPayload) (*RetrievePaymentLinkResponse, *APIError) {
|
|
resp, apiError := api.post(api.host+RETRIEVE_PAYMENT_LINK, payload)
|
|
if apiError != nil {
|
|
return nil, apiError
|
|
}
|
|
data := RetrievePaymentLinkResponse{}
|
|
if err := json.Unmarshal(resp, &data); err != nil {
|
|
return nil, &APIError{
|
|
Error: fmt.Sprintf("Error unmarshaling response: %v", err),
|
|
Success: false,
|
|
}
|
|
}
|
|
return &data, nil
|
|
}
|
|
|
|
func (api *PrimeMonitorApi) SyncWorkspace(payload WorkspaceSyncPayload) (*WorkspaceActivationResponse, *APIError) {
|
|
resp, apiError := api.post(api.host+SYNC_WORKSPACE, payload)
|
|
if apiError != nil {
|
|
return nil, apiError
|
|
}
|
|
data := WorkspaceActivationResponse{}
|
|
if err := json.Unmarshal(resp, &data); err != nil {
|
|
return nil, &APIError{
|
|
Error: fmt.Sprintf("Error unmarshaling response: %v", err),
|
|
Success: false,
|
|
}
|
|
}
|
|
return &data, nil
|
|
}
|
|
|
|
func (api *PrimeMonitorApi) ActivateInstance() *APIError {
|
|
_, apiError := api.post(api.host+ACTIVATE_INSTANCE, nil)
|
|
if apiError != nil {
|
|
return apiError
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (api *PrimeMonitorApi) DeactivateInstance() *APIError {
|
|
_, apiError := api.post(api.host+DEACTIVATE_INSTANCE, nil)
|
|
if apiError != nil {
|
|
return apiError
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (api *PrimeMonitorApi) UpgradeInstance() *APIError {
|
|
_, apiError := api.post(api.host+UPGRADE_INSTANCE, nil)
|
|
if apiError != nil {
|
|
return apiError
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (api *PrimeMonitorApi) UpdateSubcription(payload SeatUpdatePayload) (*SeatUpdateResponse, *APIError) {
|
|
resp, apiError := api.post(api.host+UPDATE_SUBSCRIPTION, payload)
|
|
if apiError != nil {
|
|
return nil, apiError
|
|
}
|
|
|
|
data := SeatUpdateResponse{}
|
|
if err := json.Unmarshal(resp, &data); err != nil {
|
|
return nil, &APIError{
|
|
Error: fmt.Sprintf("Error unmarshaling response: %v", err),
|
|
Success: false,
|
|
}
|
|
}
|
|
return &data, nil
|
|
}
|
|
|
|
func (api *PrimeMonitorApi) InitializeInstance(payload CredentialsPayload) (SetupResponse, *APIError) {
|
|
resp, apiError := api.post(api.host+SETUP_ENDPOINT, map[string]string{
|
|
"machine_signature": payload.ServerId,
|
|
"domain": payload.Domain,
|
|
"app_version": payload.AppVersion,
|
|
"deploy_platform": "KUBERNETES",
|
|
})
|
|
|
|
if apiError != nil {
|
|
return SetupResponse{}, apiError
|
|
}
|
|
|
|
setupResponse := SetupResponse{}
|
|
if err := json.Unmarshal(resp, &setupResponse); err != nil {
|
|
return SetupResponse{}, &APIError{
|
|
Error: fmt.Sprintf("Error unmarshaling response: %v", err),
|
|
Success: false,
|
|
}
|
|
}
|
|
return setupResponse, nil
|
|
}
|
|
|
|
func (api *PrimeMonitorApi) GetSubscriptionDetails(payload WorkspaceSubscriptionPayload) (*WorkspaceSubscriptionResponse, *APIError) {
|
|
resp, apiError := api.post(api.host+SUBSCRIPTION_PORTAL, payload)
|
|
if apiError != nil {
|
|
return nil, apiError
|
|
}
|
|
|
|
data := WorkspaceSubscriptionResponse{}
|
|
if err := json.Unmarshal(resp, &data); err != nil {
|
|
return nil, &APIError{
|
|
Error: fmt.Sprintf("Error unmarshaling response: %v", err),
|
|
Success: false,
|
|
}
|
|
}
|
|
return &data, nil
|
|
}
|
|
|
|
func (api *PrimeMonitorApi) GetProrationPreview(payload ProrationPreviewPayload) (*ProrationPreviewResponse, *APIError) {
|
|
// Make the request
|
|
resp, apiError := api.post(api.host+PRORATION_PREVIEW, payload)
|
|
if apiError != nil {
|
|
return nil, apiError
|
|
}
|
|
|
|
// Unmarshal the response
|
|
data := ProrationPreviewResponse{}
|
|
if err := json.Unmarshal(resp, &data); err != nil {
|
|
return nil, &APIError{
|
|
Error: fmt.Sprintf("Error unmarshaling response: %v", err),
|
|
Success: false,
|
|
}
|
|
}
|
|
// Return the response
|
|
return &data, nil
|
|
}
|
|
|
|
func (api *PrimeMonitorApi) EnterpriseLicenseActivate(payload EnterpriseLicenseActivatePayload) (*EnterpriseLicenseActivateResponse, *APIError) {
|
|
resp, apiError := api.post(api.host+ENTERPRISE_LICENSE_ACTIVATE, payload)
|
|
if apiError != nil {
|
|
return nil, apiError
|
|
}
|
|
data := EnterpriseLicenseActivateResponse{}
|
|
if err := json.Unmarshal(resp, &data); err != nil {
|
|
return nil, &APIError{
|
|
Error: fmt.Sprintf("Error unmarshaling response: %v", err),
|
|
Success: false,
|
|
}
|
|
}
|
|
return &data, nil
|
|
}
|
|
|
|
func (api *PrimeMonitorApi) SyncEnterpriseLicense(payload EnterpriseLicenseSyncPayload) (*EnterpriseLicenseActivateResponse, *APIError) {
|
|
resp, apiError := api.post(api.host+SYNC_ENTERPRISE_LICENSE, payload)
|
|
if apiError != nil {
|
|
return nil, apiError
|
|
}
|
|
data := EnterpriseLicenseActivateResponse{}
|
|
if err := json.Unmarshal(resp, &data); err != nil {
|
|
return nil, &APIError{
|
|
Error: fmt.Sprintf("Error unmarshaling response: %v", err),
|
|
Success: false,
|
|
}
|
|
}
|
|
return &data, nil
|
|
}
|
|
|
|
func (api *PrimeMonitorApi) GetEnterpriseFeatureFlags(licenseKey string) (*FlagDataResponse, *APIError) {
|
|
resp, apiError := api.post(api.host+FEATURE_FLAGS, map[string]string{
|
|
"license_key": licenseKey,
|
|
"version": api.version,
|
|
})
|
|
|
|
if apiError != nil {
|
|
return nil, apiError
|
|
}
|
|
data := FlagDataResponse{}
|
|
if err := json.Unmarshal(resp, &data); err != nil {
|
|
return nil, &APIError{
|
|
Error: fmt.Sprintf("Error unmarshaling response: %v", err),
|
|
Success: false,
|
|
}
|
|
}
|
|
return &data, nil
|
|
}
|
|
|
|
func (api *PrimeMonitorApi) DeactivateEnterpriseLicense(payload LicenseDeactivatePayload) *APIError {
|
|
_, apiError := api.post(api.host+DEACTIVATE_ENTERPRISE_LICENSE, payload)
|
|
if apiError != nil {
|
|
return apiError
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ====================== Enterprise License ==========================
|
|
|
|
func (api *PrimeMonitorApi) UpdateEnterpriseLicenseSeats(payload UpdateEnterpriseLicenseSeatsPayload) (*SeatUpdateResponse, *APIError) {
|
|
resp, apiError := api.post(api.host+UPDATE_ENTERPRISE_LICENSE_SEATS, payload)
|
|
if apiError != nil {
|
|
return nil, apiError
|
|
}
|
|
data := SeatUpdateResponse{}
|
|
if err := json.Unmarshal(resp, &data); err != nil {
|
|
return nil, &APIError{
|
|
Error: fmt.Sprintf("Error unmarshaling response: %v", err),
|
|
Success: false,
|
|
}
|
|
}
|
|
return &data, nil
|
|
}
|
|
|
|
func (api *PrimeMonitorApi) GetEnterpriseLicensePortal() (*EnterpriseLicensePortalResponse, *APIError) {
|
|
resp, apiError := api.post(api.host+ENTERPRISE_SUBSCRIPTION_PORTAL, nil)
|
|
if apiError != nil {
|
|
return nil, apiError
|
|
}
|
|
data := EnterpriseLicensePortalResponse{}
|
|
if err := json.Unmarshal(resp, &data); err != nil {
|
|
return nil, &APIError{
|
|
Error: fmt.Sprintf("Error unmarshaling response: %v", err),
|
|
Success: false,
|
|
}
|
|
}
|
|
return &data, nil
|
|
}
|
|
|
|
func (api *PrimeMonitorApi) GetEnterpriseLicenseProrationPreview(payload UpdateEnterpriseLicenseSeatsPayload) (*ProrationPreviewResponse, *APIError) {
|
|
resp, apiError := api.post(api.host+ENTERPRISE_PRORATION_PREVIEW, payload)
|
|
if apiError != nil {
|
|
return nil, apiError
|
|
}
|
|
data := ProrationPreviewResponse{}
|
|
if err := json.Unmarshal(resp, &data); err != nil {
|
|
return nil, &APIError{
|
|
Error: fmt.Sprintf("Error unmarshaling response: %v", err),
|
|
Success: false,
|
|
}
|
|
}
|
|
return &data, nil
|
|
}
|
|
|
|
// ------------------------ Helper Methods ----------------------------------
|
|
/*
|
|
prepareRequest prepares an HTTP request with the necessary headers and parameters.
|
|
|
|
Parameters:
|
|
- method: string specifying the HTTP method (e.g., "GET", "POST").
|
|
- urlStr: string specifying the URL for the request.
|
|
- body: io.Reader containing the request body.
|
|
- params: map[string]string containing the query parameters.
|
|
|
|
Returns:
|
|
- *http.Request: The prepared HTTP request.
|
|
- error: An error if any occurs during the preparation.
|
|
*/
|
|
func (api *PrimeMonitorApi) prepareRequest(method, urlStr string, body io.Reader, params map[string]string) (*http.Request, error) {
|
|
if method == "GET" && params != nil {
|
|
parsedURL, err := url.Parse(urlStr)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error parsing URL: %v", err)
|
|
}
|
|
query := parsedURL.Query()
|
|
for key, value := range params {
|
|
query.Set(key, value)
|
|
}
|
|
parsedURL.RawQuery = query.Encode()
|
|
urlStr = parsedURL.String()
|
|
}
|
|
|
|
req, err := http.NewRequest(method, urlStr, body)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error creating request: %v", err)
|
|
}
|
|
|
|
headers := map[string]string{
|
|
"X-Instance-Id": api.instanceId,
|
|
"X-Machine-Signature": api.machineSignature,
|
|
"X-Client": api.client,
|
|
"X-License-Version": api.version,
|
|
"Content-Type": "application/json",
|
|
}
|
|
|
|
for key, value := range headers {
|
|
req.Header.Add(key, value)
|
|
}
|
|
|
|
return req, nil
|
|
}
|
|
|
|
/*
|
|
doRequest executes the HTTP request and handles common response scenarios.
|
|
|
|
Parameters:
|
|
- req: *http.Request specifying the HTTP request to execute.
|
|
|
|
Returns:
|
|
- []byte: The response body.
|
|
- error: An error if any occurs during the request execution.
|
|
*/
|
|
func (api *PrimeMonitorApi) doRequest(req *http.Request) ([]byte, *APIError) {
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return nil, &APIError{
|
|
Error: fmt.Sprintf("error making request: %v", err),
|
|
Success: false,
|
|
}
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
switch {
|
|
case resp.StatusCode >= 200 && resp.StatusCode <= 227:
|
|
body, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return nil, &APIError{
|
|
Error: fmt.Sprintf("error reading response body: %v", err),
|
|
Success: false,
|
|
}
|
|
}
|
|
return body, nil
|
|
case resp.StatusCode >= 300 && resp.StatusCode <= 308:
|
|
body, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return nil, &APIError{
|
|
Error: fmt.Sprintf("error reading response body: %v", err),
|
|
Success: false,
|
|
}
|
|
}
|
|
return body, nil
|
|
case resp.StatusCode >= 400 && resp.StatusCode <= 451:
|
|
body, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return nil, &APIError{
|
|
Error: fmt.Sprintf("error reading response body: %v", err),
|
|
Success: false,
|
|
}
|
|
}
|
|
|
|
// Try to parse the error response
|
|
var errorResp ErrorResponse
|
|
if err := json.Unmarshal(body, &errorResp); err != nil {
|
|
// If we can't parse the error, return the status code
|
|
return nil, &APIError{
|
|
Error: fmt.Sprintf("unexpected status code %d", resp.StatusCode),
|
|
Success: false,
|
|
}
|
|
}
|
|
|
|
return nil, &APIError{
|
|
Error: errorResp.Error,
|
|
Success: false,
|
|
}
|
|
default:
|
|
return nil, &APIError{
|
|
Error: fmt.Sprintf("unexpected status code: %v", resp.StatusCode),
|
|
Success: false,
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
get performs a GET request.
|
|
|
|
Parameters:
|
|
- baseURL: string specifying the base URL for the request.
|
|
- params: map[string]string containing the query parameters.
|
|
|
|
Returns:
|
|
- []byte: The response body.
|
|
- error: An error if any occurs during the request.
|
|
*/
|
|
func (api *PrimeMonitorApi) get(baseURL string, params map[string]string) ([]byte, *APIError) {
|
|
req, err := api.prepareRequest("GET", baseURL, nil, params)
|
|
if err != nil {
|
|
return nil, &APIError{
|
|
Error: fmt.Sprintf("error preparing request: %v", err),
|
|
Success: false,
|
|
}
|
|
}
|
|
|
|
return api.doRequest(req)
|
|
}
|
|
|
|
/*
|
|
post performs a POST request with JSON body.
|
|
|
|
Parameters:
|
|
- baseURL: string specifying the base URL for the request.
|
|
- data: interface{} containing the data to be sent in the request body.
|
|
|
|
Returns:
|
|
- []byte: The response body.
|
|
- error: An error if any occurs during the request.
|
|
*/
|
|
func (api *PrimeMonitorApi) post(baseURL string, data interface{}) ([]byte, *APIError) {
|
|
jsonData, err := json.Marshal(data)
|
|
if err != nil {
|
|
return nil, &APIError{
|
|
Error: fmt.Sprintf("error marshaling data: %v", err),
|
|
Success: false,
|
|
}
|
|
}
|
|
|
|
req, err := api.prepareRequest("POST", baseURL, bytes.NewBuffer(jsonData), nil)
|
|
if err != nil {
|
|
return nil, &APIError{
|
|
Error: fmt.Sprintf("error preparing request: %v", err),
|
|
Success: false,
|
|
}
|
|
}
|
|
|
|
return api.doRequest(req)
|
|
}
|