|
12 | 12 | // IMPORTANT: These must be configured in your Google Cloud project. |
13 | 13 | // See README.md for details. |
14 | 14 | const GDRIVE_API_KEY = ''; // Placeholder - might not be needed for AppData folder access |
15 | | -const GDRIVE_SCOPES = 'https://www.googleapis.com/auth/drive.appdata'; |
| 15 | +const GDRIVE_SCOPES = 'https://www.googleapis.com/auth/drive.file'; |
| 16 | +const APP_FOLDER_NAME = 'FeatherNote'; |
16 | 17 |
|
17 | 18 | let gapiInited = false; |
18 | 19 | let gisInited = false; |
19 | 20 | let tokenClient; |
20 | 21 | let accessToken = null; |
21 | 22 | let REMOTE_GOOGLEDRIVE_FILES = []; |
| 23 | +let appFolderId = null; |
22 | 24 |
|
23 | 25 | // --- Initialization Functions --- |
24 | 26 |
|
@@ -158,16 +160,57 @@ async function callDriveApi(apiCall) { |
158 | 160 | } |
159 | 161 |
|
160 | 162 | /** |
161 | | - * Lists all files in the appDataFolder. |
| 163 | + * Ensures the 'FeatherNote' folder exists in the user's Drive. |
| 164 | + * @returns {Promise<string>} The ID of the folder. |
| 165 | + */ |
| 166 | +async function ensureAppFolder() { |
| 167 | + if (appFolderId) return appFolderId; |
| 168 | + |
| 169 | + try { |
| 170 | + // 1. Search for the folder |
| 171 | + const response = await gapi.client.drive.files.list({ |
| 172 | + q: `mimeType = 'application/vnd.google-apps.folder' and name = '${APP_FOLDER_NAME}' and trashed = false`, |
| 173 | + fields: 'files(id, name)', |
| 174 | + spaces: 'drive', |
| 175 | + }); |
| 176 | + |
| 177 | + if (response.result.files && response.result.files.length > 0) { |
| 178 | + appFolderId = response.result.files[0].id; |
| 179 | + return appFolderId; |
| 180 | + } |
| 181 | + |
| 182 | + // 2. If not found, create it |
| 183 | + const fileMetadata = { |
| 184 | + 'name': APP_FOLDER_NAME, |
| 185 | + 'mimeType': 'application/vnd.google-apps.folder' |
| 186 | + }; |
| 187 | + |
| 188 | + const createResponse = await gapi.client.drive.files.create({ |
| 189 | + resource: fileMetadata, |
| 190 | + fields: 'id' |
| 191 | + }); |
| 192 | + |
| 193 | + appFolderId = createResponse.result.id; |
| 194 | + return appFolderId; |
| 195 | + |
| 196 | + } catch (err) { |
| 197 | + console.error("Error finding/creating app folder:", err); |
| 198 | + throw err; |
| 199 | + } |
| 200 | +} |
| 201 | + |
| 202 | +/** |
| 203 | + * Lists all files in the App Folder (FeatherNote). |
162 | 204 | * @returns {Promise<Array>} A promise that resolves with a list of file metadata. |
163 | 205 | */ |
164 | 206 | async function listAllFilesFromGoogleDrive() { |
165 | 207 | try { |
| 208 | + const folderId = await ensureAppFolder(); |
166 | 209 | let files = []; |
167 | 210 | let pageToken = null; |
168 | 211 | do { |
169 | 212 | const response = await gapi.client.drive.files.list({ |
170 | | - spaces: 'appDataFolder', |
| 213 | + q: `'${folderId}' in parents and trashed = false`, |
171 | 214 | fields: 'nextPageToken, files(id, name, modifiedTime)', |
172 | 215 | pageSize: 100, |
173 | 216 | pageToken: pageToken, |
@@ -206,6 +249,7 @@ window.signOutFromGoogleDrive = function() { |
206 | 249 | google.accounts.oauth2.revoke(accessToken, () => { |
207 | 250 | console.log('Access token revoked.'); |
208 | 251 | accessToken = null; |
| 252 | + appFolderId = null; |
209 | 253 |
|
210 | 254 | const app = Alpine.$data(document.querySelector('#main-app')); |
211 | 255 | if (app.gdriveStore) { |
@@ -297,7 +341,14 @@ window.uploadNoteToGoogleDrive = async function(note, remoteMeta = null) { |
297 | 341 | if (found) { |
298 | 342 | existingFileId = found.id; |
299 | 343 | } else { |
300 | | - metadata.parents = ['appDataFolder']; |
| 344 | + // New file: Ensure parent folder exists and set it |
| 345 | + try { |
| 346 | + const folderId = await ensureAppFolder(); |
| 347 | + metadata.parents = [folderId]; |
| 348 | + } catch (e) { |
| 349 | + console.error("Could not get parent folder:", e); |
| 350 | + return; |
| 351 | + } |
301 | 352 | } |
302 | 353 | } |
303 | 354 |
|
|
0 commit comments