Skip to content

Commit 734c09b

Browse files
fait la créations / editions / supprétion de fichier
rend le bouton edi
1 parent b9a9433 commit 734c09b

3 files changed

Lines changed: 306 additions & 169 deletions

File tree

src/app/(app)/projects/[id]/actions.ts

Lines changed: 74 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -545,8 +545,8 @@ async function updateReadmeOnGithub(octokit: Octokit, owner: string, repo: strin
545545
} catch (error: any) {
546546
if (error.status === 404 && !existingSha) {
547547
console.log(`[updateReadmeOnGithub] README.md not found for ${owner}/${repo}, creating it.`);
548-
const paramsForCreation = { ...paramsForUpdate }; // Re-create params for creation
549-
delete paramsForCreation.sha; // Ensure SHA is not in creation params
548+
const paramsForCreation = { ...paramsForUpdate };
549+
delete paramsForCreation.sha;
550550
try {
551551
await octokit.rest.repos.createOrUpdateFileContents(paramsForCreation);
552552
console.log(`[updateReadmeOnGithub] README.md created successfully on GitHub for ${owner}/${repo} after initial 404.`);
@@ -609,7 +609,7 @@ export async function saveProjectReadmeAction(prevState: SaveProjectReadmeFormSt
609609
repo,
610610
path: 'README.md',
611611
});
612-
// @ts-ignore // Octokit types can be tricky with union types for content
612+
// @ts-ignore
613613
if ('sha' in readmeData && readmeData.type === 'file') {
614614
// @ts-ignore
615615
existingSha = readmeData.sha;
@@ -712,7 +712,7 @@ export async function toggleProjectVisibilityAction(prevState: ToggleProjectVisi
712712
if (oauthToken?.accessToken) {
713713
const octokit = new Octokit({ auth: oauthToken.accessToken });
714714
const repoParts = updatedProjectInDb.githubRepoName.split('/');
715-
if (repoParts.length !== 2 || !repoParts[0] || !repoParts[1]) { // Added check for empty parts
715+
if (repoParts.length !== 2 || !repoParts[0] || !repoParts[1]) {
716716
console.error(`[toggleProjectVisibilityAction] Invalid githubRepoName format: ${updatedProjectInDb.githubRepoName}`);
717717
return { error: `Project visibility updated in FlowUp, but GitHub repo name format is invalid.`, project: updatedProjectInDb };
718718
}
@@ -1169,7 +1169,7 @@ export async function linkProjectToGithubAction(
11691169

11701170
let createdRepo;
11711171
try {
1172-
console.log(`Attempting to create repository '${repoSlug}' for authenticated user (OAuth). Private: ${repoIsPrivate}`);
1172+
console.log(`Attempting to create repository '${repoSlug}' for authenticated user. Private: ${repoIsPrivate}`);
11731173
createdRepo = await octokit.rest.repos.createForAuthenticatedUser({
11741174
name: repoSlug,
11751175
private: repoIsPrivate,
@@ -1326,6 +1326,74 @@ export async function getFileContentAction(
13261326
}
13271327
}
13281328

1329+
1330+
export async function saveFileContentAction(
1331+
projectUuid: string,
1332+
filePath: string,
1333+
content: string,
1334+
sha: string,
1335+
commitMessage?: string
1336+
): Promise<{ success: boolean; newSha?: string; error?: string }> {
1337+
const session = await auth();
1338+
if (!session?.user?.uuid) {
1339+
return { success: false, error: "Authentication required." };
1340+
}
1341+
1342+
const project = await dbGetProjectByUuid(projectUuid);
1343+
if (!project || !project.githubRepoName) {
1344+
return { success: false, error: "Project not found or not linked to GitHub." };
1345+
}
1346+
1347+
const oauthToken = await dbGetUserGithubOAuthToken(session.user.uuid);
1348+
if (!oauthToken || !oauthToken.accessToken) {
1349+
return { success: false, error: "GitHub account not linked or token missing." };
1350+
}
1351+
1352+
const [owner, repo] = project.githubRepoName.split('/');
1353+
if (!owner || !repo) {
1354+
return { success: false, error: "Invalid GitHub repository name format." };
1355+
}
1356+
1357+
const octokit = new Octokit({ auth: oauthToken.accessToken });
1358+
1359+
try {
1360+
const response = await octokit.rest.repos.createOrUpdateFileContents({
1361+
owner,
1362+
repo,
1363+
path: filePath,
1364+
message: commitMessage || `Update ${filePath} via FlowUp`,
1365+
content: Buffer.from(content).toString('base64'),
1366+
sha,
1367+
committer: { // Optional: use user's GitHub details if available
1368+
name: session.user.name || 'FlowUp User',
1369+
email: session.user.email || 'user@flowup.app',
1370+
},
1371+
author: {
1372+
name: session.user.name || 'FlowUp User',
1373+
email: session.user.email || 'user@flowup.app',
1374+
}
1375+
});
1376+
1377+
if (response.status === 200 || response.status === 201) { // 200 for update, 201 for create
1378+
return { success: true, newSha: response.data.content?.sha };
1379+
} else {
1380+
return { success: false, error: `GitHub API returned status ${response.status}` };
1381+
}
1382+
} catch (error: any) {
1383+
console.error(`[saveFileContentAction] Error saving file ${filePath}:`, error.status, error.message, error.response?.data);
1384+
let userMessage = `Failed to save file: ${error.message || 'Unknown error'}`;
1385+
if (error.status === 409) { // Conflict, SHA mismatch
1386+
userMessage = "File has been modified since you opened it. Please refresh and try again.";
1387+
} else if (error.status === 403) {
1388+
userMessage = "Permission denied. Ensure you have write access to this repository.";
1389+
} else if (error.status === 404) {
1390+
userMessage = "File not found. It might have been deleted or moved.";
1391+
}
1392+
return { success: false, error: userMessage };
1393+
}
1394+
}
1395+
1396+
13291397
// Placeholder for future GitHub App related auth, if needed
13301398
// export async function fetchUserGithubAccessDetailsAction(): Promise<{
13311399
// installation: UserGithubInstallation | null;
@@ -1345,3 +1413,4 @@ export async function getFileContentAction(
13451413
// }
13461414

13471415

1416+

0 commit comments

Comments
 (0)