Skip to content

Commit

Permalink
Added all Youtube OAuth
Browse files Browse the repository at this point in the history
  • Loading branch information
anoopkarnik committed Jul 18, 2024
1 parent 4fe6a6d commit d5708f5
Show file tree
Hide file tree
Showing 12 changed files with 207 additions and 39 deletions.
22 changes: 22 additions & 0 deletions apps/dashboard-app/actions/connections/youtube-connections.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
'use server'

import { createYoutube, getYoutubeByAccessToken, getYoutubeByUserId } from '@repo/prisma-db/repo/youtube'
import { get } from 'http'


export const onYoutubeConnection = async ({access_token, refresh_token, scopes, userId}: any) => {
if(access_token){
console.log('access_token in actions', access_token)
const connected = await getYoutubeByAccessToken(access_token)
console.log('connected', connected)
if (!connected){
const youtube = await createYoutube({access_token, refresh_token, scopes, userId})
}
}

}

export const getYoutubeConnection = async (userId: string) => {
const connection = await getYoutubeByUserId(userId)
return connection
}
22 changes: 17 additions & 5 deletions apps/dashboard-app/app/(dashboard)/connections/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { useSearchParams } from 'next/navigation'
import ConnectionClient from '../../../components/ConnectionClient'
import { onOpenAIConnection } from '../../../actions/connections/openai-connections'
import { ConnectionsContext } from '../../../providers/connections-provider'
import { onYoutubeConnection } from '../../../actions/connections/youtube-connections'

type Props = {
searchParams?: { [key: string]: string | undefined }
Expand All @@ -17,11 +18,14 @@ const Connections = () => {

const params = useSearchParams();
const access_token = params.get('access_token')
const refresh_token = params.get('refresh_token')
const scopes = params.get('scopes')
const workspace_name = params.get('workspace_name')
const workspace_icon = params.get('workspace_icon')
const workspace_id = params.get('workspace_id')
const database_id = params.get('database_id')
const apiKey = params.get('apiKey')
const type = params.get('type')
const session = useSession()
const user = session?.data?.user
const userId = user?.id
Expand All @@ -31,10 +35,18 @@ const Connections = () => {

useEffect(() =>{
const onUserConnection = async () =>{
// @ts-ignore
await onNotionConnection({access_token,workspace_id,workspace_icon,workspace_name,database_id,userId})
// @ts-ignore
await onOpenAIConnection({apiKey,userId})
if (type === 'Notion'){
// @ts-ignore
await onNotionConnection({access_token,workspace_id,workspace_icon,workspace_name,database_id,userId})
}
if (type === 'OpenAI'){
// @ts-ignore
await onOpenAIConnection({apiKey,userId})
}
if (type === 'Youtube'){
// @ts-ignore
await onYoutubeConnection({access_token,refresh_token,scopes,userId})
}
const user_info = await getUserInfo(userId || '')
const newConnections: Record<string, boolean> = {}
user_info?.connections.forEach((connection: any) => {
Expand All @@ -43,7 +55,7 @@ const Connections = () => {
setConnections(newConnections)
}
onUserConnection()
},[access_token,workspace_id,workspace_icon,workspace_name,database_id,apiKey,userId])
},[access_token,refresh_token, scopes, workspace_id,workspace_icon,workspace_name,database_id,apiKey,userId,type])

return (
<div className='m-6'>
Expand Down
5 changes: 3 additions & 2 deletions apps/dashboard-app/app/api/callback/notion/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,14 @@ export async function GET(req: NextRequest) {
: '';

console.log(`Number of databases connected: ${databasesPages?.results?.length}`);
const type = 'Notion';


return NextResponse.redirect(
`${process.env.NEXT_PUBLIC_URL}/dashboard/connections?access_token=${response.data.access_token}&workspace_name=${response.data.workspace_name}&workspace_icon=${response.data.workspace_icon}&workspace_id=${response.data.workspace_id}&database_id=${databaseId}`
`${process.env.NEXT_PUBLIC_URL}/connections?access_token=${response.data.access_token}&workspace_name=${response.data.workspace_name}&workspace_icon=${response.data.workspace_icon}&workspace_id=${response.data.workspace_id}&database_id=${databaseId}&type=${type}`
);
}
}

return NextResponse.redirect(`${process.env.NEXT_PUBLIC_URL}/dashboard/connections`);
return NextResponse.redirect(`${process.env.NEXT_PUBLIC_URL}/connections`);
}
3 changes: 2 additions & 1 deletion apps/dashboard-app/app/api/callback/openai/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { NextRequest, NextResponse } from 'next/server';

export async function GET(req: NextRequest) {
const apiKey = req.nextUrl.searchParams.get('apiKey');
const type = 'OpenAI';
if (apiKey) {
return NextResponse.redirect(`${process.env.NEXT_PUBLIC_URL}/dashboard/connections?apiKey=${apiKey}`);
return NextResponse.redirect(`${process.env.NEXT_PUBLIC_URL}/dashboard/connections?apiKey=${apiKey}&type=${type}`);
}
return NextResponse.redirect(`${process.env.NEXT_PUBLIC_URL}/dashboard/connections`);
}
33 changes: 17 additions & 16 deletions apps/dashboard-app/app/api/callback/youtube/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,23 @@ import axios from 'axios';
import { NextRequest, NextResponse } from 'next/server';
import { google } from 'googleapis';

const oauth2Client = new google.auth.OAuth2(
process.env.NEXT_PUBLIC_YOUTUBE_CLIENT_ID,
process.env.NEXT_PUBLIC_YOUTUBE_CLIENT_SECRET,
process.env.NEXT_PUBLIC_YOUTUBE_REDIRECT_URI
);
export async function GET(req: NextRequest) {

// generate a url that asks permissions for Blogger and Google Calendar scopes
const scopes = [
'https://www.googleapis.com/auth/blogger',
'https://www.googleapis.com/auth/calendar'
];
const oauth2Client = new google.auth.OAuth2(
process.env.NEXT_PUBLIC_YOUTUBE_CLIENT_ID,
process.env.NEXT_PUBLIC_YOUTUBE_CLIENT_SECRET,
process.env.NEXT_PUBLIC_YOUTUBE_REDIRECT_URI
);

const code = req.nextUrl.searchParams.get('code');
const response = await oauth2Client.getToken(code as string);
const type = 'Youtube';
if (response){
return NextResponse.redirect(
`${process.env.NEXT_PUBLIC_URL}/connections?access_token=${response.tokens.access_token}&refresh_token=${response.tokens.refresh_token}&scopes=${response.tokens.scope}&type=${type}`
);
}

const url = oauth2Client.generateAuthUrl({
// 'online' (default) or 'offline' (gets refresh_token)
access_type: 'offline',

// If you only need one scope you can pass it as a string
scope: scopes
});
return NextResponse.redirect(`${process.env.NEXT_PUBLIC_URL}/connections`);
}
30 changes: 30 additions & 0 deletions apps/dashboard-app/app/api/oauth/youtube/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import axios from 'axios';
import { NextRequest, NextResponse } from 'next/server';
import { google } from 'googleapis';


export async function GET(req: NextRequest) {

const oauth2Client = new google.auth.OAuth2(
process.env.NEXT_PUBLIC_YOUTUBE_CLIENT_ID,
process.env.NEXT_PUBLIC_YOUTUBE_CLIENT_SECRET,
process.env.NEXT_PUBLIC_YOUTUBE_REDIRECT_URI
);

// generate a url that asks permissions for Blogger and Google Calendar scopes
const scopes = [
'https://www.googleapis.com/auth/youtube',
'https://www.googleapis.com/auth/youtube.force-ssl',
'https://www.googleapis.com/auth/youtube.readonly',
'https://www.googleapis.com/auth/youtube.upload',
];

const url = oauth2Client.generateAuthUrl({
// 'online' (default) or 'offline' (gets refresh_token)
access_type: 'offline',

// If you only need one scope you can pass it as a string
scope: scopes
});
return NextResponse.redirect(url);
}
4 changes: 2 additions & 2 deletions apps/dashboard-app/components/ConnectionClient.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ const ConnectionClient = ({description,type,icon,title,connected,formElements,pu
setOauthUrl(process.env.NEXT_PUBLIC_NOTION_OAUTH_URL as string)
}
else if (type === 'Youtube'){
setCallbackUrl('')
setOauthUrl(process.env.NEXT_PUBLIC_YOUTUBE_REDIRECT_URI as string)
setCallbackUrl(process.env.NEXT_PUBLIC_URL+'/api/callback/youtube')
setOauthUrl(process.env.NEXT_PUBLIC_YOUTUBE_OAUTH_URL as string)
}
},[type])

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
-- AlterTable
ALTER TABLE "connection_schema"."Connections" ADD COLUMN "youtubeId" TEXT;

-- CreateTable
CREATE TABLE "connection_schema"."Youtube" (
"id" TEXT NOT NULL,
"accessToken" TEXT NOT NULL,
"refreshToken" TEXT NOT NULL,
"scope" TEXT NOT NULL,
"userId" TEXT NOT NULL,

CONSTRAINT "Youtube_pkey" PRIMARY KEY ("id")
);

-- CreateIndex
CREATE UNIQUE INDEX "Youtube_accessToken_key" ON "connection_schema"."Youtube"("accessToken");

-- CreateIndex
CREATE UNIQUE INDEX "Youtube_refreshToken_key" ON "connection_schema"."Youtube"("refreshToken");

-- AddForeignKey
ALTER TABLE "connection_schema"."Youtube" ADD CONSTRAINT "Youtube_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user_schema"."User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "connection_schema"."Connections" ADD CONSTRAINT "Connections_youtubeId_fkey" FOREIGN KEY ("youtubeId") REFERENCES "connection_schema"."Youtube"("id") ON DELETE SET NULL ON UPDATE CASCADE;
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
Warnings:
- You are about to drop the column `scope` on the `Youtube` table. All the data in the column will be lost.
- Added the required column `scopes` to the `Youtube` table without a default value. This is not possible if the table is not empty.
*/
-- AlterTable
ALTER TABLE "connection_schema"."Youtube" DROP COLUMN "scope",
ADD COLUMN "scopes" TEXT NOT NULL;
14 changes: 14 additions & 0 deletions packages/prisma-db/prisma/schema/connection.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,27 @@ model OpenAI {
@@schema("connection_schema")
}

model Youtube {
id String @id @default(uuid())
accessToken String? @unique
refreshToken String? @unique
scopes String?
connections Connections[]
User User @relation(fields: [userId], references: [id])
userId String
@@schema("connection_schema")
}

model Connections {
id String @id @default(uuid())
type String @unique
Notion Notion? @relation(fields: [notionId], references: [id])
notionId String?
OpenAI OpenAI? @relation(fields: [openaiId], references: [id])
openaiId String?
Youtube Youtube? @relation(fields: [youtubeId], references: [id])
youtubeId String?
User User? @relation(fields: [userId], references: [id])
userId String?
Expand Down
27 changes: 14 additions & 13 deletions packages/prisma-db/prisma/schema/user.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ model User {
accounts Account[]
sessions Session[]
password String?
Notion Notion[]
OpenAI OpenAI[]
connections Connections[]
workflows Workflows[]
nodes Node[]
Notion Notion[]
OpenAI OpenAI[]
Youtube Youtube[]
connections Connections[]
workflows Workflows[]
nodes Node[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
Expand All @@ -33,8 +34,8 @@ model Account {
id_token String?
session_state String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
Expand All @@ -48,17 +49,17 @@ model Session {
expires DateTime
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@schema("user_schema")
}

model VerificationToken {
id String @id @default(cuid())
email String
token String @unique
expires DateTime
token String @unique
expires DateTime
@@unique([email,token])
@@schema("user_schema")
Expand All @@ -67,8 +68,8 @@ model VerificationToken {
model ResetPasswordToken {
id String @id @default(cuid())
email String
token String @unique
expires DateTime
token String @unique
expires DateTime
@@unique([email,token])
@@schema("user_schema")
Expand Down
51 changes: 51 additions & 0 deletions packages/prisma-db/src/youtube.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import db from './index'

export const createYoutube = async ({access_token,refresh_token,scopes,userId}:any) =>{
const youtube = await db.youtube.create({
data:{
userId: userId,
accessToken: access_token,
refreshToken: refresh_token,
scopes: scopes,
connections: {
create: {
userId: userId,
type: "Youtube"
}
}
}
})
return youtube
}

export const getYoutubeByAccessToken = async (access_token: string) => {
if(access_token){
try {
const connected = await db.youtube.findUnique({
where:{
accessToken: access_token,
},
include:{
connections: {
select: {
type: true
}
}
}
})
return connected;
} catch (error) {
return null
}
}
return null
}

export const getYoutubeByUserId = async (userId: string) => {
const connection = await db.youtube.findFirst({
where:{
userId
}
})
return connection
}

0 comments on commit d5708f5

Please sign in to comment.