Skip to content

Commit

Permalink
Merge branch 'main' into sidebar-accordion-scroll
Browse files Browse the repository at this point in the history
  • Loading branch information
devsargam authored Dec 3, 2024
2 parents 4915961 + 49837ea commit 70116f2
Show file tree
Hide file tree
Showing 50 changed files with 1,645 additions and 161 deletions.
17 changes: 17 additions & 0 deletions .github/workflows/cd_prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,23 @@ jobs:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2

# Set up Kubernetes CLI and configure access
- name: Set up kubectl
uses: azure/setup-kubectl@v1
with:
version: 'latest'

- name: Set KUBECONFIG environment variable
run: mkdir $HOME/.kube && echo $KUBE_POSTGRES_CONFIG | base64 -d > $HOME/.kube/config
env:
KUBE_POSTGRES_CONFIG: ${{ secrets.KUBE_POSTGRES_CONFIG }}

# Proxy the database (use kubectl port-forward or other mechanisms)
- name: Proxy Database using Kubernetes
run: |
kubectl port-forward svc/postgres 5432:5432 -n postgres &
sleep 5
- name: Build and push
uses: docker/build-push-action@v4
with:
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
"@radix-ui/react-separator": "^1.1.0",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-switch": "^1.1.0",
"@radix-ui/react-tooltip": "^1.0.7",
"@radix-ui/react-tooltip": "^1.1.2",
"@tabler/icons-react": "^3.14.0",
"@types/bcrypt": "^5.0.2",
"@types/jsonwebtoken": "^9.0.5",
Expand Down
2 changes: 1 addition & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
-- CreateTable
CREATE TABLE "BountySubmission" (
"id" TEXT NOT NULL,
"prLink" TEXT NOT NULL,
"paymentMethod" TEXT NOT NULL,
"status" TEXT NOT NULL DEFAULT 'pending',
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"amount" DOUBLE PRECISION NOT NULL DEFAULT 0,
"userId" TEXT NOT NULL,

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

-- CreateIndex
CREATE UNIQUE INDEX "BountySubmission_userId_prLink_key" ON "BountySubmission"("userId", "prLink");

-- AddForeignKey
ALTER TABLE "BountySubmission" ADD CONSTRAINT "BountySubmission_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-- AlterTable
ALTER TABLE "User" ADD COLUMN "appxAuthToken" TEXT;

-- AlterTable
ALTER TABLE "VideoMetadata" ADD COLUMN "appxVideoId" TEXT;
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "VideoMetadata" ADD COLUMN "appxVideoJSON" JSONB;
33 changes: 25 additions & 8 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ model NotionMetadata {
model VideoMetadata {
id Int @id @default(autoincrement())
contentId Int
appxVideoId String?
appxVideoJSON Json?
video_1080p_mp4_1 String? // Link to 1080p mp4 quality video variant 1
video_1080p_mp4_2 String? // Link to 1080p mp4 quality video variant 2
video_1080p_mp4_3 String? // Link to 1080p mp4 quality video variant 3
Expand Down Expand Up @@ -138,28 +140,30 @@ model Session {
}

model User {
id String @id @default(cuid())
id String @id @default(cuid())
name String?
email String? @unique
email String? @unique
token String?
sessions Session[]
purchases UserPurchases[]
videoProgress VideoProgress[]
comments Comment[]
votes Vote[]
discordConnect DiscordConnect?
disableDrm Boolean @default(false)
bunnyProxyEnabled Boolean @default(false)
disableDrm Boolean @default(false)
bunnyProxyEnabled Boolean @default(false)
bookmarks Bookmark[]
password String?
appxUserId String?
appxUsername String?
appxAuthToken String?
questions Question[]
answers Answer[]
certificate Certificate[]
upiIds UpiId[] @relation("UserUpiIds")
solanaAddresses SolanaAddress[] @relation("UserSolanaAddresses")
githubUser GitHubLink? @relation("UserGithub")
upiIds UpiId[] @relation("UserUpiIds")
solanaAddresses SolanaAddress[] @relation("UserSolanaAddresses")
githubUser GitHubLink? @relation("UserGithub")
bounties BountySubmission[]
}

model GitHubLink {
Expand Down Expand Up @@ -322,6 +326,20 @@ model Event {
updatedAt DateTime @updatedAt
}

model BountySubmission {
id String @id @default(uuid())
prLink String
paymentMethod String
status String @default("pending")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
amount Float @default(0)
userId String
user User @relation(fields: [userId], references: [id])
@@unique([userId, prLink])
}

enum VoteType {
UPVOTE
DOWNVOTE
Expand All @@ -343,4 +361,3 @@ enum MigrationStatus {
MIGRATED
MIGRATION_ERROR
}

109 changes: 109 additions & 0 deletions src/actions/bounty/adminActions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
'use server';
import prisma from '@/db';
import { getServerSession } from 'next-auth';
import { authOptions } from '@/lib/auth';
import { ROLES } from '../types';

export type Bounty = {
id: string;
prLink: string;
paymentMethod: string;
status: string;
createdAt: Date;
updatedAt: Date;
amount: number;
userId: string;
user: {
id: string;
name: string | null;
};
};

type BountyResponse = {
bounties?: Bounty[];
totalINRBounties?: number;
totalSOLBounties?: number;
error?: string;
};

export async function getBounties(): Promise<BountyResponse> {
const session = await getServerSession(authOptions);

if (!session || !session.user || session.user.role !== ROLES.ADMIN) {
return { error: 'Unauthorized or insufficient permissions' };
}

try {
const bounties = await prisma.bountySubmission.findMany({
select: {
id: true,
prLink: true,
paymentMethod: true,
status: true,
createdAt: true,
updatedAt: true,
amount: true,
userId: true,
user: {
select: {
id: true,
name: true,
},
},
},
});

let totalINRBounties = 0;
let totalSOLBounties = 0;

bounties.forEach((bounty) => {
if (bounty.paymentMethod.includes('@')) {
totalINRBounties += bounty.amount || 0;
} else {
totalSOLBounties += bounty.amount || 0;
}
});

return { bounties, totalINRBounties, totalSOLBounties };
} catch (e) {
return { error: 'An error occurred while approving the bounty.' };
}
}

export async function deleteBounty(bountyId: string) {
const session = await getServerSession(authOptions);

if (!session || !session.user || session.user.role !== ROLES.ADMIN) {
return { error: 'Unauthorized or insufficient permissions' };
}
try {
const deleteBounty = await prisma.bountySubmission.delete({
where: { id: bountyId },
});
return { success: !!deleteBounty };
} catch (e) {
return { error: 'An error occurred while approving the bounty.' };
}
}

export async function confirmBounty(bountyId: string, amount: number) {
const session = await getServerSession(authOptions);

if (!session || !session.user || session.user.role !== ROLES.ADMIN) {
return { error: 'Unauthorized or insufficient permissions' };
}

try {
const updatedBounty = await prisma.bountySubmission.update({
where: { id: bountyId },
data: { status: 'confirmed', amount },
});

if (updatedBounty) {
return { success: true };
}
return { error: 'Failed to update bounty.' };
} catch (e) {
return { error: 'An error occurred while approving the bounty.' };
}
}
2 changes: 2 additions & 0 deletions src/actions/bounty/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './userActions';
export * from './adminActions';
11 changes: 11 additions & 0 deletions src/actions/bounty/schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { z } from 'zod';

export const bountySubmissionSchema = z.object({
prLink: z.string().url({ message: 'Invalid GitHub PR link' }),
paymentMethod: z.string(),
});

export const adminApprovalSchema = z.object({
bountyId: z.string(),
status: z.enum(['approved', 'rejected']),
});
9 changes: 9 additions & 0 deletions src/actions/bounty/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export interface BountySubmissionData {
prLink: string;
paymentMethod: string;
}

export interface AdminApprovalData {
bountyId: string;
status: 'approved' | 'rejected';
}
61 changes: 61 additions & 0 deletions src/actions/bounty/userActions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
'use server';
import prisma from '@/db';
import { bountySubmissionSchema } from './schema';
import { BountySubmissionData } from './types';
import { getServerSession } from 'next-auth';
import { authOptions } from '@/lib/auth';
import { createSafeAction } from '@/lib/create-safe-action';
import { Prisma } from '@prisma/client';

async function submitBountyHandler(data: BountySubmissionData) {
try {
const session = await getServerSession(authOptions);

if (!session || !session.user) {
return { error: 'User not authenticated' };
}

const bountySubmission = await prisma.bountySubmission.create({
data: {
prLink: data.prLink,
paymentMethod: data.paymentMethod,
userId: session.user.id,
},
});
return { data: bountySubmission };
} catch (error: any) {
if (error instanceof Prisma.PrismaClientKnownRequestError) {
if (error.code === 'P2002') {
return {
error: 'PR already submitted. Try a different one.',
};
}
}
return { error: 'Failed to submit bounty!' };
}
}

export async function getUserBounties() {
try {
const session = await getServerSession(authOptions);

if (!session || !session.user) {
throw new Error('User not authenticated');
}

const bounties = await prisma.bountySubmission.findMany({
where: { userId: session.user.id },
include: { user: true },
});

return bounties;
} catch (error) {
console.error('Error retrieving user bounties:', error);
throw error;
}
}

export const submitBounty = createSafeAction(
bountySubmissionSchema,
submitBountyHandler,
);
1 change: 0 additions & 1 deletion src/actions/payoutMethods/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import { createSafeAction } from '@/lib/create-safe-action';
const addUpiHandler = async (
data: InputTypeCreateUpi,
): Promise<ReturnTypeCreateUpi> => {
console.log(data);
const session = await getServerSession(authOptions);

if (!session || !session.user.id) {
Expand Down
Loading

0 comments on commit 70116f2

Please sign in to comment.