This commit is contained in:
alma 2025-04-21 11:26:40 +02:00
parent 8783f195fa
commit 8ab7ddc7b0
2 changed files with 79 additions and 60 deletions

View File

@ -39,14 +39,16 @@ declare module "next-auth" {
interface JWT {
sub?: string;
accessToken: string;
refreshToken: string;
accessTokenExpires: number;
role: string[];
username: string;
first_name: string;
last_name: string;
accessToken?: string;
refreshToken?: string;
accessTokenExpires?: number;
role?: string[];
username?: string;
first_name?: string;
last_name?: string;
error?: string;
email?: string | null;
name?: string | null;
}
}
@ -140,31 +142,13 @@ export const authOptions: NextAuthOptions = {
},
callbacks: {
async jwt({ token, account, profile }) {
console.log('JWT callback start:', {
hasAccount: !!account,
hasProfile: !!profile,
token
});
if (account && profile) {
const keycloakProfile = profile as KeycloakProfile;
console.log('JWT callback profile:', {
rawRoles: keycloakProfile.roles,
realmAccess: keycloakProfile.realm_access,
profile: keycloakProfile
});
// Get roles from realm_access
const roles = keycloakProfile.realm_access?.roles || [];
console.log('JWT callback raw roles:', roles);
// Clean up roles by removing ROLE_ prefix and converting to lowercase
const cleanRoles = roles.map((role: string) =>
role.replace(/^ROLE_/, '').toLowerCase()
);
console.log('JWT callback cleaned roles:', cleanRoles);
token.accessToken = account.access_token ?? '';
token.refreshToken = account.refresh_token ?? '';
token.accessTokenExpires = account.expires_at ?? 0;
@ -173,27 +157,14 @@ export const authOptions: NextAuthOptions = {
token.username = keycloakProfile.preferred_username ?? '';
token.first_name = keycloakProfile.given_name ?? '';
token.last_name = keycloakProfile.family_name ?? '';
console.log('JWT callback final token:', {
tokenRoles: token.role,
token
});
} else if (token.accessToken) {
// Decode the token to get roles
try {
const decoded = jwtDecode<DecodedToken>(token.accessToken);
console.log('Decoded token:', decoded);
if (decoded.realm_access?.roles) {
const roles = decoded.realm_access.roles;
console.log('Decoded token roles:', roles);
// Clean up roles by removing ROLE_ prefix and converting to lowercase
const cleanRoles = roles.map((role: string) =>
role.replace(/^ROLE_/, '').toLowerCase()
);
console.log('Decoded token cleaned roles:', cleanRoles);
token.role = cleanRoles;
}
} catch (error) {
@ -212,17 +183,7 @@ export const authOptions: NextAuthOptions = {
throw new Error(token.error);
}
console.log('Session callback token:', {
tokenRoles: token.role,
tokenSub: token.sub,
tokenUsername: token.username,
token
});
// Ensure we have an array of roles
const userRoles = Array.isArray(token.role) ? token.role : [];
console.log('Session callback userRoles:', userRoles);
session.user = {
id: token.sub ?? '',
email: token.email ?? null,
@ -235,11 +196,6 @@ export const authOptions: NextAuthOptions = {
};
session.accessToken = token.accessToken;
console.log('Session callback final session:', {
userRoles: session.user.role,
session
});
return session;
}
},

View File

@ -31,6 +31,20 @@ interface ContactFile {
lastmod: string;
}
interface Contact {
id: string;
name: string;
email: string;
phone: string;
address: string;
notes: string;
tags: string[];
created_at: string;
updated_at: string;
user_id: string;
vcard: string;
}
export default function Navigation({ nextcloudFolders, onFolderSelect }: NavigationProps) {
const [searchQuery, setSearchQuery] = useState('');
const [expandedContacts, setExpandedContacts] = useState(false);
@ -65,7 +79,8 @@ export default function Navigation({ nextcloudFolders, onFolderSelect }: Navigat
const response = await fetch('/api/nextcloud/files?folder=Contacts');
if (response.ok) {
const files = await response.json();
console.log('Received files:', files); // Debug log
// Only log the number of files received, not their contents
console.log(`Received ${files.length} files from Nextcloud`);
// Filter for VCF files and map to ContactFile interface
const vcfFiles = files
.filter((file: any) => file.basename.endsWith('.vcf'))
@ -75,7 +90,8 @@ export default function Navigation({ nextcloudFolders, onFolderSelect }: Navigat
basename: file.basename,
lastmod: file.lastmod
}));
console.log('Processed VCF files:', vcfFiles); // Debug log
// Only log the number of VCF files processed
console.log(`Processed ${vcfFiles.length} VCF files`);
setContactFiles(vcfFiles);
}
} catch (error) {
@ -92,10 +108,58 @@ export default function Navigation({ nextcloudFolders, onFolderSelect }: Navigat
}
}, [expandedContacts]);
// Debug log for contactFiles state
useEffect(() => {
console.log('Current contactFiles state:', contactFiles);
}, [contactFiles]);
const handleVcfFile = async (file: File) => {
try {
const text = await file.text();
const vcards = text.split('END:VCARD').filter(vcard => vcard.trim());
const processedContacts = vcards.map(vcard => {
const lines = vcard.split('\n');
const contact: Contact = {
id: crypto.randomUUID(),
name: '',
email: '',
phone: '',
address: '',
notes: '',
tags: [],
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
user_id: '',
vcard: vcard + 'END:VCARD'
};
lines.forEach(line => {
if (line.startsWith('FN:')) {
contact.name = line.substring(3);
} else if (line.startsWith('EMAIL;')) {
contact.email = line.split(':')[1];
} else if (line.startsWith('TEL;')) {
contact.phone = line.split(':')[1];
} else if (line.startsWith('ADR;')) {
contact.address = line.split(':')[1];
}
});
return contact;
});
// Only log the number of contacts processed, not their details
console.log(`Processed ${processedContacts.length} contacts from VCF file`);
// Convert Contact objects to ContactFile objects
const contactFiles: ContactFile[] = processedContacts.map(contact => ({
id: contact.id,
filename: `${contact.name}.vcf`,
basename: contact.name,
lastmod: new Date().toISOString()
}));
setContactFiles(prev => [...prev, ...contactFiles]);
} catch (error) {
console.error('Error processing VCF file:', error);
}
};
return (
<div className="flex flex-col h-full bg-carnet-sidebar">
@ -164,7 +228,6 @@ export default function Navigation({ nextcloudFolders, onFolderSelect }: Navigat
<div className="px-3 py-2 text-sm text-carnet-text-muted">Aucun contact</div>
) : (
contactFiles.map((file) => {
console.log('Rendering contact file:', file); // Debug log
return (
<button
key={file.id}