feat: Upgrade to Next.js 16.1 & React 19.2, migrate to Supabase SSR with async client handling
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
'use server';
|
||||
|
||||
import { createServerComponentClient } from '@supabase/auth-helpers-nextjs';
|
||||
import { cookies } from 'next/headers';
|
||||
import { createClient } from '@/lib/supabase/server';
|
||||
import { checkIsAdmin } from './track-api-usage';
|
||||
import { addCredits, getUserCredits } from './credit-service';
|
||||
import { AdminCreditUpdateSchema, AdminSettingsSchema } from '@/types/whisky';
|
||||
|
||||
interface UserWithCredits {
|
||||
id: string;
|
||||
@@ -23,7 +23,7 @@ interface UserWithCredits {
|
||||
*/
|
||||
export async function getAllUsersWithCredits(): Promise<UserWithCredits[]> {
|
||||
try {
|
||||
const supabase = createServerComponentClient({ cookies });
|
||||
const supabase = await createClient();
|
||||
|
||||
// Check if current user is admin
|
||||
const { data: { user } } = await supabase.auth.getUser();
|
||||
@@ -97,7 +97,8 @@ export async function updateUserCredits(
|
||||
reason: string
|
||||
): Promise<{ success: boolean; error?: string }> {
|
||||
try {
|
||||
const supabase = createServerComponentClient({ cookies });
|
||||
const validated = AdminCreditUpdateSchema.parse({ userId, newBalance, reason });
|
||||
const supabase = await createClient();
|
||||
|
||||
// Check if current user is admin
|
||||
const { data: { user } } = await supabase.auth.getUser();
|
||||
@@ -107,20 +108,20 @@ export async function updateUserCredits(
|
||||
if (!isAdmin) return { success: false, error: 'Not authorized' };
|
||||
|
||||
// Get current credits
|
||||
const currentCredits = await getUserCredits(userId);
|
||||
const currentCredits = await getUserCredits(validated.userId);
|
||||
if (!currentCredits) {
|
||||
return { success: false, error: 'User credits not found' };
|
||||
}
|
||||
|
||||
const difference = newBalance - currentCredits.balance;
|
||||
const difference = validated.newBalance - currentCredits.balance;
|
||||
|
||||
// Use addCredits which handles the transaction logging
|
||||
const result = await addCredits(userId, difference, reason, user.id);
|
||||
const result = await addCredits(validated.userId, difference, validated.reason, user.id);
|
||||
|
||||
return result;
|
||||
} catch (err) {
|
||||
console.error('Error in updateUserCredits:', err);
|
||||
return { success: false, error: 'Failed to update credits' };
|
||||
return { success: false, error: err instanceof Error ? err.message : 'Failed to update credits' };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,7 +133,8 @@ export async function setUserDailyLimit(
|
||||
dailyLimit: number | null
|
||||
): Promise<{ success: boolean; error?: string }> {
|
||||
try {
|
||||
const supabase = createServerComponentClient({ cookies });
|
||||
const validated = AdminSettingsSchema.parse({ userId, dailyLimit });
|
||||
const supabase = await createClient();
|
||||
|
||||
// Check if current user is admin
|
||||
const { data: { user } } = await supabase.auth.getUser();
|
||||
@@ -143,8 +145,8 @@ export async function setUserDailyLimit(
|
||||
|
||||
const { error } = await supabase
|
||||
.from('user_credits')
|
||||
.update({ daily_limit: dailyLimit })
|
||||
.eq('user_id', userId);
|
||||
.update({ daily_limit: validated.dailyLimit })
|
||||
.eq('user_id', validated.userId);
|
||||
|
||||
if (error) {
|
||||
console.error('Error setting daily limit:', error);
|
||||
@@ -154,7 +156,7 @@ export async function setUserDailyLimit(
|
||||
return { success: true };
|
||||
} catch (err) {
|
||||
console.error('Error in setUserDailyLimit:', err);
|
||||
return { success: false, error: 'Failed to set daily limit' };
|
||||
return { success: false, error: err instanceof Error ? err.message : 'Failed to set daily limit' };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,7 +169,8 @@ export async function setUserApiCosts(
|
||||
geminiAiCost: number
|
||||
): Promise<{ success: boolean; error?: string }> {
|
||||
try {
|
||||
const supabase = createServerComponentClient({ cookies });
|
||||
const validated = AdminSettingsSchema.parse({ userId, googleSearchCost, geminiAiCost });
|
||||
const supabase = await createClient();
|
||||
|
||||
// Check if current user is admin
|
||||
const { data: { user } } = await supabase.auth.getUser();
|
||||
@@ -179,10 +182,10 @@ export async function setUserApiCosts(
|
||||
const { error } = await supabase
|
||||
.from('user_credits')
|
||||
.update({
|
||||
google_search_cost: googleSearchCost,
|
||||
gemini_ai_cost: geminiAiCost
|
||||
google_search_cost: validated.googleSearchCost,
|
||||
gemini_ai_cost: validated.geminiAiCost
|
||||
})
|
||||
.eq('user_id', userId);
|
||||
.eq('user_id', validated.userId);
|
||||
|
||||
if (error) {
|
||||
console.error('Error setting API costs:', error);
|
||||
@@ -192,7 +195,7 @@ export async function setUserApiCosts(
|
||||
return { success: true };
|
||||
} catch (err) {
|
||||
console.error('Error in setUserApiCosts:', err);
|
||||
return { success: false, error: 'Failed to set API costs' };
|
||||
return { success: false, error: err instanceof Error ? err.message : 'Failed to set API costs' };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,7 +208,7 @@ export async function bulkAddCredits(
|
||||
reason: string
|
||||
): Promise<{ success: boolean; processed: number; failed: number; error?: string }> {
|
||||
try {
|
||||
const supabase = createServerComponentClient({ cookies });
|
||||
const supabase = await createClient();
|
||||
|
||||
// Check if current user is admin
|
||||
const { data: { user } } = await supabase.auth.getUser();
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
import { getNebiusClient } from '@/lib/ai-client';
|
||||
import { SYSTEM_INSTRUCTION as GEMINI_SYSTEM_INSTRUCTION } from '@/lib/gemini';
|
||||
import { BottleMetadataSchema, AnalysisResponse, BottleMetadata } from '@/types/whisky';
|
||||
import { createServerActionClient } from '@supabase/auth-helpers-nextjs';
|
||||
import { cookies } from 'next/headers';
|
||||
import { createClient } from '@/lib/supabase/server';
|
||||
import { createHash } from 'crypto';
|
||||
import { trackApiUsage } from './track-api-usage';
|
||||
import { checkCreditBalance, deductCredits } from './credit-service';
|
||||
@@ -16,7 +15,7 @@ export async function analyzeBottleNebius(base64Image: string, tags?: string[],
|
||||
|
||||
let supabase;
|
||||
try {
|
||||
supabase = createServerActionClient({ cookies });
|
||||
supabase = await createClient();
|
||||
console.log('[analyzeBottleNebius] Initialized Supabase client');
|
||||
const { data: { session } } = await supabase.auth.getSession();
|
||||
if (!session || !session.user) {
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
|
||||
import { geminiModel, SYSTEM_INSTRUCTION } from '@/lib/gemini';
|
||||
import { BottleMetadataSchema, AnalysisResponse } from '@/types/whisky';
|
||||
import { createServerActionClient } from '@supabase/auth-helpers-nextjs';
|
||||
import { cookies } from 'next/headers';
|
||||
import { createClient } from '@/lib/supabase/server';
|
||||
import { createHash } from 'crypto';
|
||||
import { trackApiUsage } from './track-api-usage';
|
||||
import { checkCreditBalance, deductCredits } from './credit-service';
|
||||
@@ -16,7 +15,7 @@ export async function analyzeBottle(base64Image: string, tags?: string[], locale
|
||||
let supabase; // Declare supabase outside try block for error tracking access
|
||||
try {
|
||||
// Initialize Supabase client inside the try block
|
||||
supabase = createServerActionClient({ cookies });
|
||||
supabase = await createClient();
|
||||
console.log('[analyzeBottle] Initialized Supabase client');
|
||||
|
||||
// ... (auth and credit check remain same) ...
|
||||
|
||||
53
src/services/buddy.ts
Normal file
53
src/services/buddy.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
'use server';
|
||||
|
||||
import { createClient } from '@/lib/supabase/server';
|
||||
import { BuddySchema, BuddyData } from '@/types/whisky';
|
||||
|
||||
export async function addBuddy(rawData: BuddyData) {
|
||||
const supabase = await createClient();
|
||||
|
||||
try {
|
||||
const { name } = BuddySchema.parse(rawData);
|
||||
const { data: { session } } = await supabase.auth.getSession();
|
||||
if (!session) throw new Error('Nicht autorisiert');
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from('buddies')
|
||||
.insert([{ name, user_id: session.user.id }])
|
||||
.select()
|
||||
.single();
|
||||
|
||||
if (error) throw error;
|
||||
return { success: true, data };
|
||||
} catch (error) {
|
||||
console.error('Add Buddy Error:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Fehler beim Hinzufügen des Buddies',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteBuddy(id: string) {
|
||||
const supabase = await createClient();
|
||||
|
||||
try {
|
||||
const { data: { session } } = await supabase.auth.getSession();
|
||||
if (!session) throw new Error('Nicht autorisiert');
|
||||
|
||||
const { error } = await supabase
|
||||
.from('buddies')
|
||||
.delete()
|
||||
.eq('id', id)
|
||||
.eq('user_id', session.user.id);
|
||||
|
||||
if (error) throw error;
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('Delete Buddy Error:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Fehler beim Löschen des Buddies',
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
'use server';
|
||||
|
||||
import { createServerComponentClient } from '@supabase/auth-helpers-nextjs';
|
||||
import { cookies } from 'next/headers';
|
||||
import { createClient } from '@/lib/supabase/server';
|
||||
|
||||
import { checkIsAdmin } from './track-api-usage';
|
||||
|
||||
@@ -34,7 +33,7 @@ interface CreditTransaction {
|
||||
*/
|
||||
export async function getUserCredits(userId: string): Promise<UserCredits | null> {
|
||||
try {
|
||||
const supabase = createServerComponentClient({ cookies });
|
||||
const supabase = await createClient();
|
||||
|
||||
// Security check: Only self or admin can view credits
|
||||
const { data: { user: currentUser } } = await supabase.auth.getUser();
|
||||
@@ -137,7 +136,7 @@ export async function deductCredits(
|
||||
reason?: string
|
||||
): Promise<{ success: boolean; newBalance?: number; error?: string }> {
|
||||
try {
|
||||
const supabase = createServerComponentClient({ cookies });
|
||||
const supabase = await createClient();
|
||||
|
||||
// Get current credits
|
||||
const credits = await getUserCredits(userId);
|
||||
@@ -218,7 +217,7 @@ export async function addCredits(
|
||||
adminId?: string
|
||||
): Promise<{ success: boolean; newBalance?: number; error?: string }> {
|
||||
try {
|
||||
const supabase = createServerComponentClient({ cookies });
|
||||
const supabase = await createClient();
|
||||
|
||||
// Security check
|
||||
const { data: { user: currentUser } } = await supabase.auth.getUser();
|
||||
@@ -284,7 +283,7 @@ export async function getCreditTransactions(
|
||||
limit: number = 50
|
||||
): Promise<CreditTransaction[]> {
|
||||
try {
|
||||
const supabase = createServerComponentClient({ cookies });
|
||||
const supabase = await createClient();
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from('credit_transactions')
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
'use server';
|
||||
|
||||
import { createServerActionClient } from '@supabase/auth-helpers-nextjs';
|
||||
import { cookies } from 'next/headers';
|
||||
import { createClient } from '@/lib/supabase/server';
|
||||
import { revalidatePath } from 'next/cache';
|
||||
|
||||
export async function deleteBottle(bottleId: string) {
|
||||
const supabase = createServerActionClient({ cookies });
|
||||
const supabase = await createClient();
|
||||
|
||||
try {
|
||||
const { data: { session } } = await supabase.auth.getSession();
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
'use server';
|
||||
|
||||
import { createServerActionClient } from '@supabase/auth-helpers-nextjs';
|
||||
import { cookies } from 'next/headers';
|
||||
import { createClient } from '@/lib/supabase/server';
|
||||
import { revalidatePath } from 'next/cache';
|
||||
|
||||
export async function deleteSession(sessionId: string) {
|
||||
const supabase = createServerActionClient({ cookies });
|
||||
const supabase = await createClient();
|
||||
|
||||
try {
|
||||
const { data: { session } } = await supabase.auth.getSession();
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
'use server';
|
||||
|
||||
import { createServerActionClient } from '@supabase/auth-helpers-nextjs';
|
||||
import { cookies } from 'next/headers';
|
||||
import { createClient } from '@/lib/supabase/server';
|
||||
import { revalidatePath } from 'next/cache';
|
||||
|
||||
export async function deleteTasting(tastingId: string, bottleId: string) {
|
||||
const supabase = createServerActionClient({ cookies });
|
||||
const supabase = await createClient();
|
||||
|
||||
try {
|
||||
const { data: { session } } = await supabase.auth.getSession();
|
||||
|
||||
@@ -2,22 +2,17 @@
|
||||
|
||||
import { trackApiUsage, checkDailyLimit } from './track-api-usage';
|
||||
import { checkCreditBalance, deductCredits } from './credit-service';
|
||||
import { createServerComponentClient } from '@supabase/auth-helpers-nextjs';
|
||||
import { cookies } from 'next/headers';
|
||||
import { createClient } from '@/lib/supabase/server';
|
||||
|
||||
import { DiscoveryDataSchema, DiscoveryData } from '@/types/whisky';
|
||||
|
||||
/**
|
||||
* Service to discover a Whiskybase ID for a given bottle.
|
||||
* Uses Google Custom Search JSON API to search Google and extracts the ID from the first result.
|
||||
*/
|
||||
export async function discoverWhiskybaseId(bottle: {
|
||||
name: string;
|
||||
distillery?: string;
|
||||
abv?: number;
|
||||
age?: number;
|
||||
distilled_at?: string;
|
||||
bottled_at?: string;
|
||||
batch_info?: string;
|
||||
}) {
|
||||
export async function discoverWhiskybaseId(rawBottle: DiscoveryData) {
|
||||
// Validate input
|
||||
const bottle = DiscoveryDataSchema.parse(rawBottle);
|
||||
// Both Gemini and Custom Search often use the same API key if created via AI Studio
|
||||
const apiKey = process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY;
|
||||
const cx = '37e905eb03fd14e0f'; // Provided by user
|
||||
@@ -30,7 +25,7 @@ export async function discoverWhiskybaseId(bottle: {
|
||||
}
|
||||
|
||||
// Get current user for tracking
|
||||
const supabase = createServerComponentClient({ cookies });
|
||||
const supabase = await createClient();
|
||||
const { data: { user } } = await supabase.auth.getUser();
|
||||
|
||||
if (!user) {
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
'use server';
|
||||
|
||||
import { createServerActionClient } from '@supabase/auth-helpers-nextjs';
|
||||
import { cookies } from 'next/headers';
|
||||
import { createClient } from '@/lib/supabase/server';
|
||||
import { BottleMetadata } from '@/types/whisky';
|
||||
|
||||
export async function findMatchingBottle(metadata: BottleMetadata) {
|
||||
const supabase = createServerActionClient({ cookies });
|
||||
const supabase = await createClient();
|
||||
|
||||
try {
|
||||
const { data: { session } } = await supabase.auth.getSession();
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
'use server';
|
||||
|
||||
import { createServerActionClient } from '@supabase/auth-helpers-nextjs';
|
||||
import { cookies } from 'next/headers';
|
||||
import { BottleMetadata } from '@/types/whisky';
|
||||
import { createClient } from '@/lib/supabase/server';
|
||||
import { BottleMetadataSchema } from '@/types/whisky';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
export async function saveBottle(
|
||||
metadata: BottleMetadata,
|
||||
rawMetadata: any,
|
||||
base64Image: string | null,
|
||||
_ignoredUserId: string, // Keeping for signature compatibility
|
||||
preUploadedUrl?: string
|
||||
) {
|
||||
const supabase = createServerActionClient({ cookies });
|
||||
const supabase = await createClient();
|
||||
|
||||
try {
|
||||
const metadata = BottleMetadataSchema.parse(rawMetadata);
|
||||
const { data: { session } } = await supabase.auth.getSession();
|
||||
if (!session) {
|
||||
throw new Error('Nicht autorisiert oder Session abgelaufen.');
|
||||
|
||||
@@ -1,25 +1,16 @@
|
||||
'use server';
|
||||
|
||||
import { createServerActionClient } from '@supabase/auth-helpers-nextjs';
|
||||
import { cookies } from 'next/headers';
|
||||
import { createClient } from '@/lib/supabase/server';
|
||||
import { revalidatePath } from 'next/cache';
|
||||
import { validateSession } from './validate-session';
|
||||
|
||||
export async function saveTasting(data: {
|
||||
bottle_id: string;
|
||||
session_id?: string;
|
||||
rating: number;
|
||||
nose_notes?: string;
|
||||
palate_notes?: string;
|
||||
finish_notes?: string;
|
||||
is_sample?: boolean;
|
||||
buddy_ids?: string[];
|
||||
tag_ids?: string[];
|
||||
tasted_at?: string;
|
||||
}) {
|
||||
const supabase = createServerActionClient({ cookies });
|
||||
import { TastingNoteSchema, TastingNoteData } from '@/types/whisky';
|
||||
|
||||
export async function saveTasting(rawData: TastingNoteData) {
|
||||
const supabase = await createClient();
|
||||
|
||||
try {
|
||||
const data = TastingNoteSchema.parse(rawData);
|
||||
const { data: { session } } = await supabase.auth.getSession();
|
||||
if (!session) throw new Error('Nicht autorisiert');
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
'use server';
|
||||
|
||||
import { createServerComponentClient } from '@supabase/auth-helpers-nextjs';
|
||||
import { cookies } from 'next/headers';
|
||||
import { createClient } from '@/lib/supabase/server';
|
||||
import { checkIsAdmin } from './track-api-usage';
|
||||
import { addCredits } from './credit-service';
|
||||
|
||||
@@ -32,7 +31,7 @@ export interface UserSubscription {
|
||||
export async function getAllPlans(): Promise<SubscriptionPlan[]> {
|
||||
try {
|
||||
console.log('[getAllPlans] Starting...');
|
||||
const supabase = createServerComponentClient({ cookies });
|
||||
const supabase = await createClient();
|
||||
|
||||
// RLS policy will handle admin check
|
||||
const { data, error } = await supabase
|
||||
@@ -61,7 +60,7 @@ export async function getAllPlans(): Promise<SubscriptionPlan[]> {
|
||||
*/
|
||||
export async function getActivePlans(): Promise<SubscriptionPlan[]> {
|
||||
try {
|
||||
const supabase = createServerComponentClient({ cookies });
|
||||
const supabase = await createClient();
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from('subscription_plans')
|
||||
@@ -86,7 +85,7 @@ export async function getActivePlans(): Promise<SubscriptionPlan[]> {
|
||||
*/
|
||||
export async function createPlan(plan: Omit<SubscriptionPlan, 'id' | 'created_at' | 'updated_at'>): Promise<{ success: boolean; error?: string; plan?: SubscriptionPlan }> {
|
||||
try {
|
||||
const supabase = createServerComponentClient({ cookies });
|
||||
const supabase = await createClient();
|
||||
|
||||
// Check if current user is admin
|
||||
const { data: { user } } = await supabase.auth.getUser();
|
||||
@@ -118,7 +117,7 @@ export async function createPlan(plan: Omit<SubscriptionPlan, 'id' | 'created_at
|
||||
*/
|
||||
export async function updatePlan(planId: string, updates: Partial<SubscriptionPlan>): Promise<{ success: boolean; error?: string }> {
|
||||
try {
|
||||
const supabase = createServerComponentClient({ cookies });
|
||||
const supabase = await createClient();
|
||||
|
||||
// Check if current user is admin
|
||||
const { data: { user } } = await supabase.auth.getUser();
|
||||
@@ -149,7 +148,7 @@ export async function updatePlan(planId: string, updates: Partial<SubscriptionPl
|
||||
*/
|
||||
export async function deletePlan(planId: string): Promise<{ success: boolean; error?: string }> {
|
||||
try {
|
||||
const supabase = createServerComponentClient({ cookies });
|
||||
const supabase = await createClient();
|
||||
|
||||
// Check if current user is admin
|
||||
const { data: { user } } = await supabase.auth.getUser();
|
||||
@@ -180,7 +179,7 @@ export async function deletePlan(planId: string): Promise<{ success: boolean; er
|
||||
*/
|
||||
export async function getUserSubscription(userId: string): Promise<{ subscription: UserSubscription | null; plan: SubscriptionPlan | null }> {
|
||||
try {
|
||||
const supabase = createServerComponentClient({ cookies });
|
||||
const supabase = await createClient();
|
||||
|
||||
const { data: subscription, error: subError } = await supabase
|
||||
.from('user_subscriptions')
|
||||
@@ -218,7 +217,7 @@ export async function getUserSubscription(userId: string): Promise<{ subscriptio
|
||||
*/
|
||||
export async function setUserPlan(userId: string, planId: string): Promise<{ success: boolean; error?: string }> {
|
||||
try {
|
||||
const supabase = createServerComponentClient({ cookies });
|
||||
const supabase = await createClient();
|
||||
|
||||
// Check if current user is admin
|
||||
const { data: { user } } = await supabase.auth.getUser();
|
||||
@@ -253,7 +252,7 @@ export async function setUserPlan(userId: string, planId: string): Promise<{ suc
|
||||
*/
|
||||
export async function grantMonthlyCredits(): Promise<{ success: boolean; processed: number; failed: number; error?: string }> {
|
||||
try {
|
||||
const supabase = createServerComponentClient({ cookies });
|
||||
const supabase = await createClient();
|
||||
|
||||
// Check if current user is admin
|
||||
const { data: { user } } = await supabase.auth.getUser();
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
'use server';
|
||||
|
||||
import { createServerActionClient } from '@supabase/auth-helpers-nextjs';
|
||||
import { cookies } from 'next/headers';
|
||||
import { createClient } from '@/lib/supabase/server';
|
||||
|
||||
import { TagSchema, TagData } from '@/types/whisky';
|
||||
|
||||
export type TagCategory = 'nose' | 'taste' | 'finish' | 'texture';
|
||||
|
||||
@@ -19,7 +20,7 @@ export interface Tag {
|
||||
*/
|
||||
export async function getTagsByCategory(category: TagCategory): Promise<Tag[]> {
|
||||
try {
|
||||
const supabase = createServerActionClient({ cookies });
|
||||
const supabase = await createClient();
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from('tags')
|
||||
@@ -45,7 +46,7 @@ export async function getTagsByCategory(category: TagCategory): Promise<Tag[]> {
|
||||
*/
|
||||
export async function getAllSystemTags(): Promise<Tag[]> {
|
||||
try {
|
||||
const supabase = createServerActionClient({ cookies });
|
||||
const supabase = await createClient();
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from('tags')
|
||||
@@ -68,10 +69,11 @@ export async function getAllSystemTags(): Promise<Tag[]> {
|
||||
/**
|
||||
* Create a custom user tag
|
||||
*/
|
||||
export async function createCustomTag(name: string, category: TagCategory): Promise<{ success: boolean; tag?: Tag; error?: string }> {
|
||||
const supabase = createServerActionClient({ cookies });
|
||||
export async function createCustomTag(rawName: string, rawCategory: TagCategory): Promise<{ success: boolean; tag?: Tag; error?: string }> {
|
||||
const supabase = await createClient();
|
||||
|
||||
try {
|
||||
const { name, category } = TagSchema.parse({ name: rawName, category: rawCategory });
|
||||
const { data: { session } } = await supabase.auth.getSession();
|
||||
if (!session) throw new Error('Nicht autorisiert');
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
'use server';
|
||||
|
||||
import { createServerComponentClient } from '@supabase/auth-helpers-nextjs';
|
||||
import { cookies } from 'next/headers';
|
||||
import { createClient } from '@/lib/supabase/server';
|
||||
|
||||
interface TrackApiUsageParams {
|
||||
userId: string;
|
||||
@@ -33,7 +32,7 @@ const GOOGLE_SEARCH_DAILY_LIMIT = 80;
|
||||
*/
|
||||
export async function trackApiUsage(params: TrackApiUsageParams): Promise<{ success: boolean; error?: string }> {
|
||||
try {
|
||||
const supabase = createServerComponentClient({ cookies });
|
||||
const supabase = await createClient();
|
||||
|
||||
// Security check: Ensure user is only tracking their own usage
|
||||
const { data: { user } } = await supabase.auth.getUser();
|
||||
@@ -69,7 +68,7 @@ export async function trackApiUsage(params: TrackApiUsageParams): Promise<{ succ
|
||||
*/
|
||||
export async function checkDailyLimit(apiType: 'google_search' | 'gemini_ai'): Promise<DailyLimitCheck> {
|
||||
try {
|
||||
const supabase = createServerComponentClient({ cookies });
|
||||
const supabase = await createClient();
|
||||
|
||||
// Only enforce limit for Google Search
|
||||
if (apiType !== 'google_search') {
|
||||
@@ -114,7 +113,7 @@ export async function checkDailyLimit(apiType: 'google_search' | 'gemini_ai'): P
|
||||
*/
|
||||
export async function getUserApiStats(userId: string): Promise<ApiStats | null> {
|
||||
try {
|
||||
const supabase = createServerComponentClient({ cookies });
|
||||
const supabase = await createClient();
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from('api_usage')
|
||||
@@ -152,7 +151,7 @@ export async function getUserApiStats(userId: string): Promise<ApiStats | null>
|
||||
*/
|
||||
export async function getGlobalApiStats(): Promise<ApiStats | null> {
|
||||
try {
|
||||
const supabase = createServerComponentClient({ cookies });
|
||||
const supabase = await createClient();
|
||||
|
||||
// Check if user is admin
|
||||
const { data: { user } } = await supabase.auth.getUser();
|
||||
@@ -197,7 +196,7 @@ export async function getGlobalApiStats(): Promise<ApiStats | null> {
|
||||
export async function checkIsAdmin(userId: string): Promise<boolean> {
|
||||
try {
|
||||
console.log('[checkIsAdmin] Checking admin status for user:', userId);
|
||||
const supabase = createServerComponentClient({ cookies });
|
||||
const supabase = await createClient();
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from('admin_users')
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
'use server';
|
||||
|
||||
import { createServerActionClient } from '@supabase/auth-helpers-nextjs';
|
||||
import { cookies } from 'next/headers';
|
||||
import { createClient } from '@/lib/supabase/server';
|
||||
import { revalidatePath } from 'next/cache';
|
||||
|
||||
export async function updateBottleStatus(bottleId: string, status: 'sealed' | 'open' | 'sampled' | 'empty') {
|
||||
const supabase = createServerActionClient({ cookies });
|
||||
const supabase = await createClient();
|
||||
|
||||
try {
|
||||
const { data: { session } } = await supabase.auth.getSession();
|
||||
|
||||
@@ -1,24 +1,15 @@
|
||||
'use server';
|
||||
|
||||
import { createServerActionClient } from '@supabase/auth-helpers-nextjs';
|
||||
import { cookies } from 'next/headers';
|
||||
import { createClient } from '@/lib/supabase/server';
|
||||
import { revalidatePath } from 'next/cache';
|
||||
|
||||
export async function updateBottle(bottleId: string, data: {
|
||||
name?: string;
|
||||
distillery?: string;
|
||||
category?: string;
|
||||
abv?: number;
|
||||
age?: number;
|
||||
whiskybase_id?: string;
|
||||
purchase_price?: number;
|
||||
distilled_at?: string;
|
||||
bottled_at?: string;
|
||||
batch_info?: string;
|
||||
}) {
|
||||
const supabase = createServerActionClient({ cookies });
|
||||
import { UpdateBottleSchema, UpdateBottleData } from '@/types/whisky';
|
||||
|
||||
export async function updateBottle(bottleId: string, rawData: UpdateBottleData) {
|
||||
const supabase = await createClient();
|
||||
|
||||
try {
|
||||
const data = UpdateBottleSchema.parse(rawData);
|
||||
const { data: { session } } = await supabase.auth.getSession();
|
||||
if (!session) throw new Error('Nicht autorisiert');
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
'use server';
|
||||
|
||||
import { createServerActionClient } from '@supabase/auth-helpers-nextjs';
|
||||
import { cookies } from 'next/headers';
|
||||
import { createClient } from '@/lib/supabase/server';
|
||||
|
||||
/**
|
||||
* Validates if a session is still "active" based on its age.
|
||||
@@ -10,7 +9,7 @@ import { cookies } from 'next/headers';
|
||||
export async function validateSession(sessionId: string | null): Promise<boolean> {
|
||||
if (!sessionId) return false;
|
||||
|
||||
const supabase = createServerActionClient({ cookies });
|
||||
const supabase = await createClient();
|
||||
|
||||
try {
|
||||
const { data: session, error } = await supabase
|
||||
|
||||
Reference in New Issue
Block a user