Initial import into Gitea

This commit is contained in:
Grae Jones
2026-03-14 13:50:09 -07:00
parent 8e7e03702e
commit 34c1f09e01
154 changed files with 17666 additions and 1548 deletions

View File

@@ -0,0 +1,205 @@
using System.Text.Json.Serialization;
namespace MetaApi.Models;
#region Campaign Payloads
/// <summary>
/// Create a Meta campaign.
/// Meta hierarchy: Campaign → Ad Set → Ad
/// With Advantage+ (v25.0+), this uses the unified campaign API.
/// </summary>
public sealed class CreateCampaignPayload
{
public string Name { get; set; } = string.Empty;
public MetaObjective Objective { get; set; } = MetaObjective.Conversions;
/// <summary>
/// Campaign spending limit in account currency (in cents).
/// Null = no campaign spending limit.
/// </summary>
public long? SpendCapCents { get; set; }
/// <summary>
/// Special ad categories required by Meta for housing, employment, credit, etc.
/// Empty = none (most campaigns).
/// </summary>
public List<string> SpecialAdCategories { get; set; } = new();
public MetaCampaignStatus Status { get; set; } = MetaCampaignStatus.Paused;
}
public sealed class GetCampaignPayload
{
public string CampaignId { get; set; } = string.Empty;
}
public sealed class UpdateCampaignPayload
{
public string CampaignId { get; set; } = string.Empty;
public string? Name { get; set; }
public MetaCampaignStatus? Status { get; set; }
public long? SpendCapCents { get; set; }
}
public sealed class ListCampaignsPayload
{
public MetaCampaignStatus? StatusFilter { get; set; }
public int Limit { get; set; } = 50;
public string? After { get; set; } // Cursor-based pagination
}
#endregion
#region Ad Set Payloads
/// <summary>
/// Create a Meta Ad Set (equivalent to Google Ad Group).
/// Ad Sets define targeting, budget, schedule, and bid strategy.
/// </summary>
public sealed class CreateAdSetPayload
{
public string CampaignId { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
/// <summary>Daily budget in account currency cents.</summary>
public long DailyBudgetCents { get; set; }
/// <summary>Lifetime budget in cents (alternative to daily). Null = use daily.</summary>
public long? LifetimeBudgetCents { get; set; }
public string? StartTime { get; set; } // ISO 8601
public string? EndTime { get; set; } // ISO 8601
public MetaBillingEvent BillingEvent { get; set; } = MetaBillingEvent.Impressions;
public MetaOptimizationGoal OptimizationGoal { get; set; } = MetaOptimizationGoal.LinkClicks;
/// <summary>Target CPA bid amount in cents (for CPA bidding).</summary>
public long? BidAmountCents { get; set; }
public MetaCampaignStatus Status { get; set; } = MetaCampaignStatus.Paused;
}
#endregion
#region Ad Account Payloads
/// <summary>
/// Create a new ad account under USIM's Business Manager.
/// Requires Advanced Access to business_management permission.
/// </summary>
public sealed class CreateAdAccountPayload
{
/// <summary>Display name for the new ad account.</summary>
public string Name { get; set; } = string.Empty;
/// <summary>Currency code (e.g. "USD"). ISO 4217.</summary>
public string Currency { get; set; } = "USD";
/// <summary>Timezone (IANA format, e.g. "America/Los_Angeles"). Numeric TZ ID also accepted.</summary>
public int TimezoneId { get; set; } = 1; // Default: America/Los_Angeles
/// <summary>End advertiser name/business for the account.</summary>
public string? EndAdvertiser { get; set; }
/// <summary>Media agency managing the account.</summary>
public string? MediaAgency { get; set; }
/// <summary>Partner (USIM).</summary>
public string? Partner { get; set; }
}
#endregion
#region Insights Payloads
/// <summary>
/// Retrieve campaign performance metrics (Meta Insights API).
/// </summary>
public sealed class CampaignInsightsPayload
{
public string CampaignId { get; set; } = string.Empty;
public string? DatePreset { get; set; } // e.g., "last_7d", "last_30d", "this_month"
public string? StartDate { get; set; } // YYYY-MM-DD (time_range)
public string? EndDate { get; set; } // YYYY-MM-DD (time_range)
public string Level { get; set; } = "campaign"; // campaign, adset, ad
}
public sealed class AccountInsightsPayload
{
public string? DatePreset { get; set; }
public string? StartDate { get; set; }
public string? EndDate { get; set; }
}
#endregion
#region Enums
/// <summary>
/// Meta campaign objectives.
/// As of API v25.0, Meta is consolidating to Outcome-Driven Ad Experiences (ODAX).
/// These map to the Advantage+ unified campaign objectives.
/// </summary>
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum MetaObjective
{
/// <summary>OUTCOME_AWARENESS - Brand awareness and reach</summary>
Awareness = 0,
/// <summary>OUTCOME_TRAFFIC - Drive traffic to a destination</summary>
Traffic = 1,
/// <summary>OUTCOME_ENGAGEMENT - Get more engagement (likes, comments, shares)</summary>
Engagement = 2,
/// <summary>OUTCOME_LEADS - Generate leads</summary>
Leads = 3,
/// <summary>OUTCOME_APP_PROMOTION - Drive app installs</summary>
AppPromotion = 4,
/// <summary>OUTCOME_SALES - Drive conversions/sales</summary>
Conversions = 5
}
/// <summary>
/// Meta campaign/ad set status values.
/// </summary>
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum MetaCampaignStatus
{
Active = 0,
Paused = 1,
Deleted = 2,
Archived = 3
}
/// <summary>
/// Meta billing events for ad sets.
/// </summary>
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum MetaBillingEvent
{
Impressions = 0,
LinkClicks = 1,
ThruPlay = 2
}
/// <summary>
/// Meta optimization goals for ad sets.
/// </summary>
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum MetaOptimizationGoal
{
None = 0,
LinkClicks = 1,
Impressions = 2,
Reach = 3,
LandingPageViews = 4,
LeadGeneration = 5,
Conversions = 6,
Value = 7
}
#endregion

View File

@@ -0,0 +1,96 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace MetaApi.Models;
/// <summary>
/// Request from Gateway to MetaApi.
/// Identical contract to GoogleApi.Models.ProviderRequest for Gateway compatibility.
/// </summary>
public sealed class ProviderRequest
{
/// <summary>
/// Operation to execute (e.g., "Ping", "CreateCampaign", "GetCampaignInsights")
/// </summary>
public string Operation { get; set; } = string.Empty;
/// <summary>
/// Tenant/account ID - maps to Meta ad account ID (act_XXXXXXX).
/// Populated by Gateway from tbAdAccount.accExternalAccountId where accNetwork='meta'.
/// </summary>
public string? TenantId { get; set; }
/// <summary>
/// Login customer ID - maps to Meta Business Manager ID.
/// In Meta's agency model, the BM owns and manages client ad accounts.
/// Populated by Gateway from tbAdAccount.accLoginAccountId.
/// </summary>
public string? LoginCustomerId { get; set; }
/// <summary>
/// Correlation ID for request tracing
/// </summary>
public string? RequestId { get; set; }
/// <summary>
/// Operation-specific payload
/// </summary>
public JsonElement? Payload { get; set; }
/// <summary>
/// Deserialize payload to strongly-typed object
/// </summary>
public T GetPayload<T>() where T : new()
{
if (Payload == null || Payload.Value.ValueKind == JsonValueKind.Null || Payload.Value.ValueKind == JsonValueKind.Undefined)
return new T();
try
{
return JsonSerializer.Deserialize<T>(Payload.Value.GetRawText(), JsonOptions.Default) ?? new T();
}
catch
{
return new T();
}
}
}
/// <summary>
/// Response from MetaApi to Gateway.
/// Identical contract to GoogleApi.Models.ProviderResponse.
/// </summary>
public sealed class ProviderResponse
{
public bool Ok { get; set; }
public string? RequestId { get; set; }
public object? Data { get; set; }
public ProviderError? Error { get; set; }
public static ProviderResponse Success(string? requestId, object? data = null)
=> new() { Ok = true, RequestId = requestId, Data = data };
public static ProviderResponse Fail(string? requestId, string code, string message, object? detail = null)
=> new()
{
Ok = false,
RequestId = requestId,
Error = new ProviderError { Code = code, Message = message, Detail = detail }
};
}
public sealed class ProviderError
{
public string Code { get; set; } = "ERROR";
public string Message { get; set; } = "Unknown error";
public object? Detail { get; set; }
}
internal static class JsonOptions
{
public static readonly JsonSerializerOptions Default = new(JsonSerializerDefaults.Web)
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
}