Skip to content

Commit

Permalink
wp api
Browse files Browse the repository at this point in the history
  • Loading branch information
benorloff committed Mar 22, 2024
1 parent 91c8623 commit 94fd6e5
Show file tree
Hide file tree
Showing 8 changed files with 495 additions and 20 deletions.
214 changes: 202 additions & 12 deletions app/(platform)/(dashboard)/ai/page.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,218 @@
"use client"

import { SiteInfo } from "@/components/ai/site-info";
import { DashboardTitle } from "@/components/dashboard-title"
import { SiteSelect } from "@/components/sites/site-select";
import { Button } from "@/components/ui/button";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage
} from "@/components/ui/form"
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { db } from "@/lib/db";
import { WpApiEndpoint, wpGet } from "@/lib/wordpress";
import { auth } from "@clerk/nextjs";
import { zodResolver } from "@hookform/resolvers/zod";
import { set } from "lodash";
import { EyeIcon } from "lucide-react";
import { useState } from "react";
import { useForm } from "react-hook-form";
import { z } from "zod";

const httpRegex = /^(http|https):/
const completeUrlRegex = /^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_+.~#?&/=]*)$/

const AIPage = async () => {
const { userId } = auth();
const FormSchema = z.object({
url: z
.string()
.max(255)
.transform((val, ctx) => {
let completeUrl = val;
if (!httpRegex.test(completeUrl)) {
completeUrl = `https://${completeUrl}`;
}
if (!completeUrlRegex.test(completeUrl)) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "Please enter a valid URL",
});

const sites = await db.site.findMany({
where: {
members: {
some: {
userId: userId!,
}
return z.NEVER;
}
},
include: {
members: true
return completeUrl;
}),
username: z.string({
required_error: "Username is required",
}),
appPassword: z.string({
required_error: "App password is required",
}),
})

const AIPage = () => {
// const { userId } = auth();

// const sites = await db.site.findMany({
// where: {
// members: {
// some: {
// userId: userId!,
// }
// }
// },
// include: {
// members: true
// }
// })

const [credentials, setCredentials] = useState<z.infer<typeof FormSchema>>()
const [wpPages, setWpPages] = useState<any>({data: [], headers: []})
const [wpPosts, setWpPosts] = useState<any>({data: [], headers: []})
const [wpCategories, setWpCategories] = useState<any>({data: [], headers: []})
const [wpPlugins, setWpPlugins] = useState<any>({data: [], headers: []})
const [headers, setHeaders] = useState<any>({})

// For testing purposes only
const form = useForm<z.infer<typeof FormSchema>>({
resolver: zodResolver(FormSchema),
defaultValues: {
url: "demozone.flywheelsites.com",
username: "test",
appPassword: "PQaG iA4n bmZT zTVi IZB6 sj4R",
}
})

const onSubmit = (values: z.infer<typeof FormSchema>) => {
setCredentials(values);
// SiteInfo(values).then((res) => {setData(res.data), setHeaders(res.headers)});
wpGet({
url: values.url,
pretty: true,
username: values.username,
password: values.appPassword,
endpoint: "pages",
}).then((res) =>
setWpPages({data: res.data, headers: res.headers})
);
wpGet({
url: values.url,
pretty: true,
username: values.username,
password: values.appPassword,
endpoint: "posts",
}).then((res) =>
setWpPosts({data: res.data, headers: res.headers})
);
wpGet({
url: values.url,
pretty: true,
username: values.username,
password: values.appPassword,
endpoint: "plugins",
}).then((res) =>
setWpPlugins({data: res.data, headers: res.headers})
);
console.log(wpPages, "<-- wpPages state")
console.log(wpPosts, "<-- wpPosts state")
form.reset();
}

return(
<>
<DashboardTitle />
<SiteSelect sites={sites} />
{/* <SiteSelect sites={sites} /> */}
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="w-full space-y-4">
<FormField
control={form.control}
name="url"
render={({ field }) => (
<FormItem>
<FormLabel>URL</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="username"
render={({ field }) => (
<FormItem>
<FormLabel>Username</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="appPassword"
render={({ field }) => (
<FormItem>
<FormLabel>Application Password</FormLabel>
<FormControl>
<Input type="password" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit">Submit</Button>
{(credentials?.url && credentials?.username && credentials?.appPassword) && (<p>Access Granted</p>)}
</form>
</Form>
{/* {(credentials?.url && credentials?.username && credentials?.appPassword) && (
<SiteInfo {...credentials} />
)} */}
<div className="text-2xl py-4">Pages</div>
{wpPages.headers.length > 0 && (<p>Total Pages: {wpPages.headers.find((header) => header[0] === 'x-wp-total')[1]}</p>)}
{wpPages.data.length > 0 && (
wpPages.data.map((page: object) => (
<div key={page.id} className="py-4">
<p>Title: {page.title.rendered}</p>
<p>Date: {new Date(page.date).toLocaleString()}</p>
<p>URL: {page.link}</p>
<Button>Select</Button>
</div>

))
)}
<div className="text-2xl py-4">Posts</div>
{wpPosts.headers.length > 0 && (<p>Total Posts: {wpPosts.headers.find((header) => header[0] === 'x-wp-total')[1]}</p>)}
{wpPosts.data.length > 0 && (
wpPosts.data.map((post: object) => (
<div key={post.id} className="py-4">
<p>Title: {post.title.rendered}</p>
<p>Date: {new Date(post.date).toLocaleString()}</p>
<p>URL: {post.link}</p>
<Button>Select</Button>
</div>

))
)}
<div className="text-2xl py-4">Plugins</div>
{wpPlugins.data.length > 0 && (
wpPlugins.data.map((plugin: object) => (
<div key={plugin.plugin_uri} className="py-4">
<p>Name: {plugin.name}</p>
<p>Status: {plugin.status}</p>
<p>URI: {plugin.plugin_uri}</p>
<Button>Select</Button>
</div>

))
)}

</>
)
};
Expand Down
8 changes: 4 additions & 4 deletions app/(platform)/(dashboard)/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,15 @@ const DashboardPage = async () => {
where: {
orgId: orgId!,
},
take: 10,
orderBy: {
createdAt: "desc",
},
take: 5,
});

console.log(await checkSubscription(), "<-- checkSubscription result")

return (
<>
<div className="text-3xl mb-8">{greeting}</div>
<h3 className="text-2xl mb-4">Recently Active Sites</h3>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{sites.map((site) => (
<Card key={site.id} className="flex flex-grow flex-col justify-between">
Expand Down
27 changes: 27 additions & 0 deletions components/ai/site-info.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"use server"

interface SiteAccessValues {
url: string,
username: string,
appPassword: string,
}

export const SiteInfo = async (values: SiteAccessValues) => {

console.log(values, "<-- values from SiteInfo")
const wpApiHost = `${values.url}/wp-json/wp/v2`
console.log(wpApiHost, "<-- wpApiHost")

// WP API Pages Endpoint
const response = await fetch(`${wpApiHost}/pages`, {
headers: {
"Content-Type": "application/json",
"Authorization": `Basic ${btoa(`${values.username}:${values.appPassword}`)}`
}
})

const data = await response.json();
const headers = response.headers;

return { data, headers };
}
12 changes: 10 additions & 2 deletions components/stripe-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Loader2 } from "lucide-react";
import { toast } from "sonner";

import { StripeSession } from "@/actions/create-stripe-session/schema";
import { cn } from "@/lib/utils";

interface StripeButtonProps {
customerId?: string;
Expand Down Expand Up @@ -39,10 +40,17 @@ export const StripeButton = ({
<Button
onClick={onClick}
disabled={isLoading}
className="relative"
>
<span
className={cn(
isLoading ? "opacity-0" : "opacity-100",
)}
>
{label}
</span>
{isLoading
? <Loader2 className="mr-2 h-4 w-4 animate-spin" />
: <>{label}</>
&& <Loader2 className="absolute mx-auto h-4 w-4 animate-spin" />
}
</Button>

Expand Down
5 changes: 5 additions & 0 deletions lib/anthropic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import Anthropic from '@anthropic-ai/sdk';

export const anthropic = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY!,
});
64 changes: 64 additions & 0 deletions lib/wordpress.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,35 @@
"use server"

export type WpApiEndpoint =
"posts"
| "categories"
| "tags"
| "pages"
| "comments"
| "taxonomies"
| "media"
| "users"
| "types"
| "statuses"
| "settings"
| "themes"
| "search"
| "block-types"
| "blocks"
| "block-renderer"
| "block-directory/search"
| "plugins";


export interface WpApiRequest {
url: string,
pretty: boolean,
username: string,
password: string,
endpoint: WpApiEndpoint,
resourceId?: number,
}

export const siteIsWordPress = async (url: string) => {
console.log("siteIsWordPress", url)

Expand All @@ -24,4 +54,38 @@ export const siteIsWordPress = async (url: string) => {

// Return the result as a boolean
return data!!;
}

export const wpGet = async ({
url,
pretty,
username,
password,
endpoint,
resourceId,
}: WpApiRequest) => {

let data;
let headers;

let urlPath = `${url}${pretty ? '/wp-json' : '/?rest_route='}/wp/v2/${endpoint}/${resourceId ? `/${resourceId}` : ""}`
console.log(urlPath, "<-- urlPath")

try {
const response = await fetch(urlPath, {
headers: {
"Content-Type": "application/json",
"Authorization": `Basic ${btoa(`${username}:${password}`)}`
},
cache: "no-cache",
})
data = await response.json();
headers = response.headers;
} catch (error) {
console.error(error);
return {
error: "An error occurred while fetching data from the WordPress API",
}
}
return { data, headers };
}
Loading

0 comments on commit 94fd6e5

Please sign in to comment.