ALwrity + Wordpress + Wix + GSC integration
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
/** Google Search Console API client for ALwrity frontend. */
|
||||
|
||||
import { apiClient } from './client';
|
||||
import { useAuth } from '@clerk/clerk-react';
|
||||
|
||||
export interface GSCSite {
|
||||
siteUrl: string;
|
||||
@@ -76,11 +75,9 @@ class GSCAPI {
|
||||
* Get Google Search Console OAuth authorization URL
|
||||
*/
|
||||
async getAuthUrl(): Promise<{ auth_url: string }> {
|
||||
console.log('GSC API: Getting OAuth authorization URL');
|
||||
try {
|
||||
const client = await this.getAuthenticatedClient();
|
||||
const response = await client.get(`${this.baseUrl}/auth/url`);
|
||||
console.log('GSC API: OAuth URL retrieved successfully');
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('GSC API: Error getting OAuth URL:', error);
|
||||
@@ -92,13 +89,11 @@ class GSCAPI {
|
||||
* Handle OAuth callback (typically called from popup)
|
||||
*/
|
||||
async handleCallback(code: string, state: string): Promise<{ success: boolean; message: string }> {
|
||||
console.log('GSC API: Handling OAuth callback');
|
||||
try {
|
||||
const client = await this.getAuthenticatedClient();
|
||||
const response = await client.get(`${this.baseUrl}/callback`, {
|
||||
params: { code, state }
|
||||
});
|
||||
console.log('GSC API: OAuth callback handled successfully');
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('GSC API: Error handling OAuth callback:', error);
|
||||
@@ -110,11 +105,9 @@ class GSCAPI {
|
||||
* Get user's Google Search Console sites
|
||||
*/
|
||||
async getSites(): Promise<{ sites: GSCSite[] }> {
|
||||
console.log('GSC API: Getting user sites');
|
||||
try {
|
||||
const client = await this.getAuthenticatedClient();
|
||||
const response = await client.get(`${this.baseUrl}/sites`);
|
||||
console.log(`GSC API: Retrieved ${response.data.sites.length} sites`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('GSC API: Error getting sites:', error);
|
||||
@@ -126,11 +119,9 @@ class GSCAPI {
|
||||
* Get search analytics data
|
||||
*/
|
||||
async getAnalytics(request: GSCAnalyticsRequest): Promise<GSCAnalyticsResponse> {
|
||||
console.log('GSC API: Getting analytics data for site:', request.site_url);
|
||||
try {
|
||||
const client = await this.getAuthenticatedClient();
|
||||
const response = await client.post(`${this.baseUrl}/analytics`, request);
|
||||
console.log('GSC API: Analytics data retrieved successfully');
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('GSC API: Error getting analytics:', error);
|
||||
@@ -142,11 +133,9 @@ class GSCAPI {
|
||||
* Get sitemaps for a specific site
|
||||
*/
|
||||
async getSitemaps(siteUrl: string): Promise<{ sitemaps: GSCSitemap[] }> {
|
||||
console.log('GSC API: Getting sitemaps for site:', siteUrl);
|
||||
try {
|
||||
const client = await this.getAuthenticatedClient();
|
||||
const response = await client.get(`${this.baseUrl}/sitemaps/${encodeURIComponent(siteUrl)}`);
|
||||
console.log(`GSC API: Retrieved ${response.data.sitemaps.length} sitemaps`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('GSC API: Error getting sitemaps:', error);
|
||||
@@ -158,11 +147,9 @@ class GSCAPI {
|
||||
* Get GSC connection status
|
||||
*/
|
||||
async getStatus(): Promise<GSCStatusResponse> {
|
||||
console.log('GSC API: Getting connection status');
|
||||
try {
|
||||
const client = await this.getAuthenticatedClient();
|
||||
const response = await client.get(`${this.baseUrl}/status`);
|
||||
console.log('GSC API: Status retrieved, connected:', response.data.connected);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('GSC API: Error getting status:', error);
|
||||
@@ -170,15 +157,27 @@ class GSCAPI {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear incomplete GSC credentials
|
||||
*/
|
||||
async clearIncomplete(): Promise<{ success: boolean; message: string }> {
|
||||
try {
|
||||
const client = await this.getAuthenticatedClient();
|
||||
const response = await client.post(`${this.baseUrl}/clear-incomplete`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('GSC API: Error clearing incomplete credentials:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect GSC account
|
||||
*/
|
||||
async disconnect(): Promise<{ success: boolean; message: string }> {
|
||||
console.log('GSC API: Disconnecting GSC account');
|
||||
try {
|
||||
const client = await this.getAuthenticatedClient();
|
||||
const response = await client.delete(`${this.baseUrl}/disconnect`);
|
||||
console.log('GSC API: Account disconnected successfully');
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('GSC API: Error disconnecting account:', error);
|
||||
@@ -190,10 +189,8 @@ class GSCAPI {
|
||||
* Health check
|
||||
*/
|
||||
async healthCheck(): Promise<{ status: string; service: string; timestamp: string }> {
|
||||
console.log('GSC API: Performing health check');
|
||||
try {
|
||||
const response = await apiClient.get(`${this.baseUrl}/health`);
|
||||
console.log('GSC API: Health check passed');
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('GSC API: Health check failed:', error);
|
||||
|
||||
158
frontend/src/api/personaApi.ts
Normal file
158
frontend/src/api/personaApi.ts
Normal file
@@ -0,0 +1,158 @@
|
||||
/**
|
||||
* Persona API Client
|
||||
* Handles communication with the persona generation backend services.
|
||||
*/
|
||||
|
||||
import { apiClient } from './client';
|
||||
|
||||
export interface PersonaGenerationRequest {
|
||||
onboarding_data: {
|
||||
websiteAnalysis?: any;
|
||||
competitorResearch?: any;
|
||||
sitemapAnalysis?: any;
|
||||
businessData?: any;
|
||||
};
|
||||
selected_platforms: string[];
|
||||
user_preferences?: any;
|
||||
}
|
||||
|
||||
export interface PersonaGenerationResponse {
|
||||
success: boolean;
|
||||
core_persona?: any;
|
||||
platform_personas?: Record<string, any>;
|
||||
quality_metrics?: any;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface PersonaQualityRequest {
|
||||
core_persona: any;
|
||||
platform_personas: Record<string, any>;
|
||||
user_feedback?: any;
|
||||
}
|
||||
|
||||
export interface PersonaQualityResponse {
|
||||
success: boolean;
|
||||
quality_metrics?: any;
|
||||
recommendations?: string[];
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface PersonaOptions {
|
||||
success: boolean;
|
||||
available_platforms: Array<{
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
}>;
|
||||
persona_types: string[];
|
||||
quality_metrics: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate AI writing personas using the sophisticated persona system.
|
||||
*/
|
||||
export const generateWritingPersonas = async (
|
||||
request: PersonaGenerationRequest
|
||||
): Promise<PersonaGenerationResponse> => {
|
||||
try {
|
||||
const response = await apiClient.post('/api/onboarding/step4/generate-personas', request);
|
||||
return response.data;
|
||||
} catch (error: any) {
|
||||
console.error('Error generating personas:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error.response?.data?.detail || error.message || 'Failed to generate personas'
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Assess the quality of generated personas.
|
||||
*/
|
||||
export const assessPersonaQuality = async (
|
||||
request: PersonaQualityRequest
|
||||
): Promise<PersonaQualityResponse> => {
|
||||
try {
|
||||
const response = await apiClient.post('/api/onboarding/step4/assess-quality', request);
|
||||
return response.data;
|
||||
} catch (error: any) {
|
||||
console.error('Error assessing persona quality:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error.response?.data?.detail || error.message || 'Failed to assess persona quality'
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Regenerate persona with different parameters.
|
||||
*/
|
||||
export const regeneratePersona = async (
|
||||
request: PersonaGenerationRequest
|
||||
): Promise<PersonaGenerationResponse> => {
|
||||
try {
|
||||
const response = await apiClient.post('/api/onboarding/step4/regenerate-persona', request);
|
||||
return response.data;
|
||||
} catch (error: any) {
|
||||
console.error('Error regenerating persona:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error.response?.data?.detail || error.message || 'Failed to regenerate persona'
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get available options for persona generation.
|
||||
*/
|
||||
export const getPersonaGenerationOptions = async (): Promise<PersonaOptions> => {
|
||||
try {
|
||||
const response = await apiClient.get('/api/onboarding/step4/persona-options');
|
||||
return response.data;
|
||||
} catch (error: any) {
|
||||
console.error('Error getting persona options:', error);
|
||||
return {
|
||||
success: false,
|
||||
available_platforms: [],
|
||||
persona_types: [],
|
||||
quality_metrics: []
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Utility function to prepare onboarding data for persona generation.
|
||||
*/
|
||||
export const prepareOnboardingData = (stepData: any) => {
|
||||
return {
|
||||
websiteAnalysis: stepData?.analysis || null,
|
||||
competitorResearch: {
|
||||
competitors: stepData?.competitors || [],
|
||||
researchSummary: stepData?.researchSummary || null,
|
||||
socialMediaAccounts: stepData?.socialMediaAccounts || {}
|
||||
},
|
||||
sitemapAnalysis: stepData?.sitemapAnalysis || null,
|
||||
businessData: stepData?.businessData || null
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Utility function to validate persona generation request.
|
||||
*/
|
||||
export const validatePersonaRequest = (request: PersonaGenerationRequest): string[] => {
|
||||
const errors: string[] = [];
|
||||
|
||||
if (!request.onboarding_data) {
|
||||
errors.push('Onboarding data is required');
|
||||
}
|
||||
|
||||
if (!request.selected_platforms || request.selected_platforms.length === 0) {
|
||||
errors.push('At least one platform must be selected');
|
||||
}
|
||||
|
||||
if (request.selected_platforms && request.selected_platforms.length > 5) {
|
||||
errors.push('Maximum 5 platforms can be selected');
|
||||
}
|
||||
|
||||
return errors;
|
||||
};
|
||||
83
frontend/src/api/wix.ts
Normal file
83
frontend/src/api/wix.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* Wix API Client
|
||||
* Handles Wix connection status and operations
|
||||
*/
|
||||
|
||||
import { apiClient } from './client';
|
||||
|
||||
export interface WixStatus {
|
||||
connected: boolean;
|
||||
sites: Array<{
|
||||
id: string;
|
||||
blog_url: string;
|
||||
blog_id: string;
|
||||
created_at: string;
|
||||
scope: string;
|
||||
}>;
|
||||
total_sites: number;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
class WixAPI {
|
||||
private baseUrl = '/api/wix';
|
||||
private getAuthToken: (() => Promise<string | null>) | null = null;
|
||||
|
||||
/**
|
||||
* Set the auth token getter function
|
||||
*/
|
||||
setAuthTokenGetter(getToken: () => Promise<string | null>) {
|
||||
this.getAuthToken = getToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get authenticated API client with auth token
|
||||
*/
|
||||
private async getAuthenticatedClient() {
|
||||
const token = this.getAuthToken ? await this.getAuthToken() : null;
|
||||
|
||||
if (!token) {
|
||||
throw new Error('No authentication token available');
|
||||
}
|
||||
|
||||
return apiClient.create({
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Wix connection status
|
||||
*/
|
||||
async getStatus(): Promise<WixStatus> {
|
||||
try {
|
||||
const client = await this.getAuthenticatedClient();
|
||||
const response = await client.get(`${this.baseUrl}/status`);
|
||||
return response.data;
|
||||
} catch (error: any) {
|
||||
console.error('Wix API: Error getting status:', error);
|
||||
return {
|
||||
connected: false,
|
||||
sites: [],
|
||||
total_sites: 0,
|
||||
error: error.response?.data?.detail || error.message
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Health check for Wix service
|
||||
*/
|
||||
async healthCheck(): Promise<boolean> {
|
||||
try {
|
||||
const client = await this.getAuthenticatedClient();
|
||||
await client.get(`${this.baseUrl}/connection/status`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Wix API: Health check failed:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const wixAPI = new WixAPI();
|
||||
276
frontend/src/api/wordpress.ts
Normal file
276
frontend/src/api/wordpress.ts
Normal file
@@ -0,0 +1,276 @@
|
||||
/**
|
||||
* WordPress API client for ALwrity frontend.
|
||||
* Handles WordPress site connections, content publishing, and management.
|
||||
*/
|
||||
|
||||
import { apiClient } from './client';
|
||||
|
||||
export interface WordPressSite {
|
||||
id: number;
|
||||
site_url: string;
|
||||
site_name: string;
|
||||
username: string;
|
||||
is_active: boolean;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export interface WordPressSiteRequest {
|
||||
site_url: string;
|
||||
site_name: string;
|
||||
username: string;
|
||||
app_password: string;
|
||||
}
|
||||
|
||||
export interface WordPressPublishRequest {
|
||||
site_id: number;
|
||||
title: string;
|
||||
content: string;
|
||||
excerpt?: string;
|
||||
featured_image_path?: string;
|
||||
categories?: string[];
|
||||
tags?: string[];
|
||||
status?: 'draft' | 'publish' | 'private';
|
||||
meta_description?: string;
|
||||
}
|
||||
|
||||
export interface WordPressPublishResponse {
|
||||
success: boolean;
|
||||
post_id?: number;
|
||||
post_url?: string;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface WordPressPost {
|
||||
id: number;
|
||||
wp_post_id: number;
|
||||
title: string;
|
||||
status: string;
|
||||
published_at?: string;
|
||||
created_at: string;
|
||||
site_name: string;
|
||||
site_url: string;
|
||||
}
|
||||
|
||||
export interface WordPressStatusResponse {
|
||||
connected: boolean;
|
||||
sites?: WordPressSite[];
|
||||
total_sites: number;
|
||||
}
|
||||
|
||||
export interface WordPressHealthResponse {
|
||||
status: string;
|
||||
service: string;
|
||||
timestamp: string;
|
||||
version: string;
|
||||
}
|
||||
|
||||
class WordPressAPI {
|
||||
private baseUrl = '/wordpress';
|
||||
private getAuthToken: (() => Promise<string | null>) | null = null;
|
||||
|
||||
/**
|
||||
* Set authentication token getter
|
||||
*/
|
||||
setAuthTokenGetter(getter: () => Promise<string | null>) {
|
||||
this.getAuthToken = getter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get authenticated client with token
|
||||
*/
|
||||
private async getAuthenticatedClient() {
|
||||
if (this.getAuthToken) {
|
||||
const token = await this.getAuthToken();
|
||||
if (token) {
|
||||
// Create a new client instance with the auth header
|
||||
return apiClient.create({
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return apiClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get WordPress connection status
|
||||
*/
|
||||
async getStatus(): Promise<WordPressStatusResponse> {
|
||||
try {
|
||||
const client = await this.getAuthenticatedClient();
|
||||
const response = await client.get(`${this.baseUrl}/status`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('WordPress API: Error getting status:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new WordPress site connection
|
||||
*/
|
||||
async addSite(siteData: WordPressSiteRequest): Promise<WordPressSite> {
|
||||
try {
|
||||
const client = await this.getAuthenticatedClient();
|
||||
const response = await client.post(`${this.baseUrl}/sites`, siteData);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('WordPress API: Error adding site:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all WordPress sites for the current user
|
||||
*/
|
||||
async getSites(): Promise<WordPressSite[]> {
|
||||
try {
|
||||
const client = await this.getAuthenticatedClient();
|
||||
const response = await client.get(`${this.baseUrl}/sites`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('WordPress API: Error getting sites:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect a WordPress site
|
||||
*/
|
||||
async disconnectSite(siteId: number): Promise<{ success: boolean; message: string }> {
|
||||
try {
|
||||
const client = await this.getAuthenticatedClient();
|
||||
const response = await client.delete(`${this.baseUrl}/sites/${siteId}`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('WordPress API: Error disconnecting site:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish content to WordPress
|
||||
*/
|
||||
async publishContent(publishData: WordPressPublishRequest): Promise<WordPressPublishResponse> {
|
||||
try {
|
||||
const client = await this.getAuthenticatedClient();
|
||||
const response = await client.post(`${this.baseUrl}/publish`, publishData);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('WordPress API: Error publishing content:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get published posts from WordPress sites
|
||||
*/
|
||||
async getPosts(siteId?: number): Promise<WordPressPost[]> {
|
||||
try {
|
||||
const client = await this.getAuthenticatedClient();
|
||||
const params = siteId ? { site_id: siteId } : {};
|
||||
const response = await client.get(`${this.baseUrl}/posts`, { params });
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('WordPress API: Error getting posts:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update post status (draft/publish/private)
|
||||
*/
|
||||
async updatePostStatus(postId: number, status: string): Promise<{ success: boolean; message: string }> {
|
||||
try {
|
||||
const client = await this.getAuthenticatedClient();
|
||||
const response = await client.put(`${this.baseUrl}/posts/${postId}/status`, null, {
|
||||
params: { status }
|
||||
});
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('WordPress API: Error updating post status:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a WordPress post
|
||||
*/
|
||||
async deletePost(postId: number, force: boolean = false): Promise<{ success: boolean; message: string }> {
|
||||
try {
|
||||
const client = await this.getAuthenticatedClient();
|
||||
const response = await client.delete(`${this.baseUrl}/posts/${postId}`, {
|
||||
params: { force }
|
||||
});
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('WordPress API: Error deleting post:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test WordPress site connection
|
||||
*/
|
||||
async testConnection(siteData: WordPressSiteRequest): Promise<boolean> {
|
||||
try {
|
||||
// This would typically be a separate endpoint for testing connections
|
||||
// For now, we'll try to add the site and see if it succeeds
|
||||
await this.addSite(siteData);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('WordPress API: Connection test failed:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Health check
|
||||
*/
|
||||
async healthCheck(): Promise<WordPressHealthResponse> {
|
||||
try {
|
||||
const response = await apiClient.get(`${this.baseUrl}/health`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('WordPress API: Health check failed:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate WordPress site URL
|
||||
*/
|
||||
validateSiteUrl(url: string): boolean {
|
||||
try {
|
||||
// Remove protocol if present
|
||||
const cleanUrl = url.replace(/^https?:\/\//, '');
|
||||
|
||||
// Basic URL validation
|
||||
const urlPattern = /^[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]*\.([a-zA-Z]{2,}|[a-zA-Z]{2,}\.[a-zA-Z]{2,})$/;
|
||||
|
||||
return urlPattern.test(cleanUrl) || cleanUrl.includes('localhost') || cleanUrl.includes('127.0.0.1');
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format WordPress site URL
|
||||
*/
|
||||
formatSiteUrl(url: string): string {
|
||||
if (!url) return '';
|
||||
|
||||
// Add protocol if missing
|
||||
if (!url.startsWith('http://') && !url.startsWith('https://')) {
|
||||
return `https://${url}`;
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
// Export singleton instance
|
||||
export const wordpressAPI = new WordPressAPI();
|
||||
export default wordpressAPI;
|
||||
113
frontend/src/api/wordpressOAuth.ts
Normal file
113
frontend/src/api/wordpressOAuth.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* WordPress OAuth2 API client for ALwrity frontend.
|
||||
* Handles WordPress.com OAuth2 authentication flow.
|
||||
*/
|
||||
|
||||
import { apiClient } from './client';
|
||||
|
||||
export interface WordPressOAuthResponse {
|
||||
auth_url: string;
|
||||
state: string;
|
||||
}
|
||||
|
||||
export interface WordPressOAuthStatus {
|
||||
connected: boolean;
|
||||
sites: WordPressOAuthSite[];
|
||||
total_sites: number;
|
||||
}
|
||||
|
||||
export interface WordPressOAuthSite {
|
||||
id: number;
|
||||
blog_id: string;
|
||||
blog_url: string;
|
||||
scope: string;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
class WordPressOAuthAPI {
|
||||
private baseUrl = '/wp';
|
||||
private getAuthToken: (() => Promise<string | null>) | null = null;
|
||||
|
||||
/**
|
||||
* Set authentication token getter
|
||||
*/
|
||||
setAuthTokenGetter(getter: () => Promise<string | null>) {
|
||||
this.getAuthToken = getter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get authenticated client with token
|
||||
*/
|
||||
private async getAuthenticatedClient() {
|
||||
const token = this.getAuthToken ? await this.getAuthToken() : null;
|
||||
|
||||
if (!token) {
|
||||
throw new Error('No authentication token available');
|
||||
}
|
||||
|
||||
return apiClient.create({
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get WordPress OAuth2 authorization URL
|
||||
*/
|
||||
async getAuthUrl(): Promise<WordPressOAuthResponse> {
|
||||
try {
|
||||
const client = await this.getAuthenticatedClient();
|
||||
const response = await client.get(`${this.baseUrl}/auth/url`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('WordPress OAuth API: Error getting auth URL:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get WordPress OAuth connection status
|
||||
*/
|
||||
async getStatus(): Promise<WordPressOAuthStatus> {
|
||||
try {
|
||||
const client = await this.getAuthenticatedClient();
|
||||
const response = await client.get(`${this.baseUrl}/status`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('WordPress OAuth API: Error getting status:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect a WordPress site
|
||||
*/
|
||||
async disconnectSite(tokenId: number): Promise<{ success: boolean; message: string }> {
|
||||
try {
|
||||
const client = await this.getAuthenticatedClient();
|
||||
const response = await client.delete(`${this.baseUrl}/disconnect/${tokenId}`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('WordPress OAuth API: Error disconnecting site:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Health check
|
||||
*/
|
||||
async healthCheck(): Promise<{ status: string; service: string; timestamp: string; version: string }> {
|
||||
try {
|
||||
const response = await apiClient.get(`${this.baseUrl}/health`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('WordPress OAuth API: Health check failed:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Export singleton instance
|
||||
export const wordpressOAuthAPI = new WordPressOAuthAPI();
|
||||
export default wordpressOAuthAPI;
|
||||
Reference in New Issue
Block a user