Created
June 26, 2018 06:59
-
-
Save eojji/73ef2b6f55cd38953c1c5e767cc56777 to your computer and use it in GitHub Desktop.
Copy to team drive - review. Listing folders - 8 https://m.cafe.naver.com/eojji/311
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Web App Exec: | |
// https://script.google.com/macros/s/AKfycbxa1mBiEPGwHpVDxw6V6p1bRBWSXHm8qbIea7Kjmv9rQUyv68_Z/exec | |
function doGet(request) { | |
var output = HtmlService.createTemplateFromFile('Page').evaluate(); | |
return output.addMetaTag('viewport', 'width=device-width, initial-scale=1'); | |
} | |
function include(filename) { | |
return HtmlService.createHtmlOutputFromFile(filename) | |
.getContent(); | |
} | |
function copyDriveFile_(title, fileId, parentId) { | |
var resource = { | |
'title': title, | |
parents: [{ id: parentId }] | |
}; | |
var optionalArgs = { | |
supportsTeamDrives : true | |
}; | |
try { | |
return Drive.Files.copy(resource, fileId, optionalArgs); | |
} catch(error) { | |
return error; // error.name, error.message; | |
} | |
} | |
function createFolderSpreadsheet_(title, folderId) { | |
var ssNew, ssId, sheetFolder, sheetFiles; | |
var title = '_gfolder, ' + Date.now() + ' ' + title; | |
try { | |
ssNew = SpreadsheetApp.create(title); | |
sheetFolder = ssNew.getSheets()[0]; | |
sheetFolder.setName('folder'); | |
sheetFolder.appendRow(["row to read", 3]); | |
sheetFolder.appendRow(["title", "id", "id2", "files", "fileSize", "start", "end", "file row", "parent"]); | |
// files | |
sheetFiles = ssNew.insertSheet('files'); | |
sheetFiles.appendRow(["row to read", 3, "page token"]); | |
sheetFiles.appendRow(['title', 'id', 'mime', 'size', 'copy', 'name', 'message', 'check', 'parent']); | |
// https://developers.google.com/drive/api/v2/reference/parents/insert | |
var resource= { "id": folderId }; | |
var optionalArgs = { "supportsTeamDrives" : true }; | |
// Drive.Parents.insert(resource, fileId, optionalArgs); | |
ssId = ssNew.getId(); | |
Drive.Parents.insert(resource, ssId, optionalArgs); | |
Drive.Parents.remove(ssId, DriveApp.getRootFolder().getId()); | |
return ssNew; | |
} catch(e) { | |
console.warn('Error: %s, %s - createFolderSpreadsheet: %s', e.name, e.message, folderId); | |
} | |
} | |
function fileCopyFromInput_(file, folderId) { | |
var appMessage = {}; | |
if (! file.copyable) { | |
appMessage.url = file.alternateLink; | |
appMessage.title = file.title; | |
appMessage.message = 'The file can not be copied to My Drive.'; | |
return appMessage; | |
} | |
var aCopy = copyDriveFile_(file.title, file.id, folderId); | |
if (aCopy.id) { | |
// console.log('Title: %s, Mimetype: %s, ID: %s', aCopy.title, aCopy.mimeType, aCopy.id); | |
appMessage.url = aCopy.alternateLink; | |
appMessage.title = aCopy.title; | |
appMessage.message = 'The copy is complete. Size: ' + aCopy.fileSize; | |
} else if (aCopy.name) { | |
console.warn('An error occurred while copying. Error Name: %s, Message: %s', aCopy.name, aCopy.message); | |
appMessage.message = 'An error occurred while copying. '+aCopy.name+ ', Message: '+ aCopy.message; | |
appMessage.url = file.alternateLink; | |
appMessage.title = file.title; | |
} | |
return appMessage; | |
} | |
function getFolderByGdUrl_(url) { | |
var idx = url.lastIndexOf('google.com'); | |
if (idx < 0) { | |
var rtn = url.match(/[-\w]{15,}/); | |
if (rtn) { | |
return getDriveFileById_(rtn[0]); | |
} | |
return; | |
} | |
var decUrl = url.substr(idx+10); | |
var arr = ["/d/", "/folders/", "?id=", "&id="]; | |
for (var i=0; i<arr.length; i++) { | |
idx = decUrl.indexOf(arr[i]); | |
if (idx < 0) { | |
continue; | |
} | |
var str = decUrl.substr(idx + arr[i].length); | |
var idMatchStr = str.match(/[-\w]{15,}/); | |
if (idMatchStr) { | |
return getDriveFileById_(idMatchStr[0]); | |
} else { | |
return; | |
} | |
} | |
} | |
function setPageTokenProperty(value) { | |
PropertiesService.getUserProperties().setProperty('PAGE_TOKEN', value); | |
} | |
function getPageTokenProperty() { | |
var pageTokenProperty = PropertiesService.getUserProperties().getProperty('PAGE_TOKEN'); | |
return pageTokenProperty; | |
} | |
function deletePageTokenProperty() { | |
PropertiesService.getUserProperties().deleteProperty('PAGE_TOKEN'); | |
} | |
function doCopyFolder_(sheetFolder, folderRowNum, sheetFiles, startTime) { | |
var folderRange, folderInfo; | |
try { | |
folderRange = sheetFolder.getRange(folderRowNum, 1, 1, 9); | |
folderInfo = folderRange.getValues()[0]; | |
} catch(e) { | |
console.warn('Error: %s, %s - doCopyFolder', e.name, e.message); | |
return '-1'; | |
} | |
var title, folderId, copyFolderId, fileRowNum; | |
title = folderInfo[0]; | |
folderId = folderInfo[1]; | |
copyFolderId = folderInfo[2]; | |
fileRowNum = folderInfo[7]; | |
if (!fileRowNum || fileRowNum < 3) { | |
var pageToken; | |
var objFiles = listFilesByPageToken_(folderId, pageToken, startTime); | |
if (!objFiles) { | |
return '9'; | |
} | |
var parentId = folderInfo[8]; | |
var resp = insertFolderById_(parentId, title); | |
if (!resp || !resp.id) { | |
console.warn('Error: %s, %s - insertFolderById(parentId: %s, %s)', resp.name, resp.message, parentId, title); | |
return '-1'; | |
} | |
folderInfo[7] = sheetFiles.getLastRow() + 1; // fileRowNum | |
sheetAppendFiles_(resp.id, objFiles.files, sheetFolder, sheetFiles); | |
folderInfo[2] = resp.id; // copyFolderId | |
folderRange.setValues([folderInfo]); | |
if (objFiles.pageToken) { | |
setPageTokenProperty(folderId+','+objFiles.pageToken); | |
return '1'; | |
} | |
return copyFilesBySheet_(startTime, sheetFiles); | |
} | |
var pageTokenProperty = getPageTokenProperty(); | |
if (pageTokenProperty) { | |
var arrIdAndPageToken = pageTokenProperty.split(','); | |
if (arrIdAndPageToken[0] == folderId && arrIdAndPageToken[1]) { | |
var objFiles = listFilesByPageToken_(folderId, arrIdAndPageToken[1], startTime); | |
if (objFiles) { | |
sheetAppendFiles_(copyFolderId, objFiles.files, sheetFolder, sheetFiles); | |
if (objFiles.pageToken) { | |
setPageTokenProperty(folderId+','+objFiles.pageToken); | |
return '1'; | |
} | |
} | |
} else { | |
deletePageTokenProperty(); | |
} | |
} | |
return copyFilesBySheet_(startTime, sheetFiles); | |
} | |
function sheetAppendFiles_(parentId, data, sheetFolder, sheetFiles) { | |
if (!data || data.length < 1) { | |
return; | |
} | |
var folderData = []; | |
var newDate = new Date(); | |
// title, id | |
// id2, files, fileSize, start, end, file row, parent | |
var newFolderContents = ['', 0, 0, newDate, newDate, 0, parentId]; | |
var fileData = []; | |
// copy, name, message, check, parent | |
var newFileContents = ['', '', '', '', parentId]; | |
var len = data.length; | |
for (var i = 0; i < len; i++) { | |
// title, id, mimeType, fileSize | |
var mimeType = data[i][2]; // mimeType | |
if (mimeType == 'application/vnd.google-apps.folder') { | |
folderData.push(data[i].slice(0, 2).concat(newFolderContents)); | |
} else { | |
fileData.push(data[i].concat(newFileContents)); | |
} | |
} | |
if (folderData && folderData.length > 0) { | |
sheetFolder.getRange(sheetFolder.getLastRow() + 1, 1, folderData.length, folderData[0].length).setValues(folderData); | |
} | |
if (fileData && fileData.length > 0) { | |
sheetFiles.getRange(sheetFiles.getLastRow() + 1, 1, fileData.length, fileData[0].length).setValues(fileData); | |
} | |
} | |
function insertFolderById_(parentId, folderName) { | |
var resource= { | |
"parents": [ | |
{ | |
"id": parentId | |
} | |
], | |
"title": folderName, | |
"mimeType": "application/vnd.google-apps.folder" | |
}; | |
// https://stackoverflow.com/questions/28378738/create-a-new-blob-in-memory-using-apps-script | |
// var blob = Utilities.newBlob(folderName); | |
var optionalArgs = { | |
supportsTeamDrives : true | |
}; | |
// var folder; | |
try { | |
// https://developers.google.com/drive/v2/reference/files#resource | |
return Drive.Files.insert(resource, Utilities.newBlob(folderName), optionalArgs); | |
} catch(error) { | |
return error; | |
} | |
} | |
function triggerAfterByName(functionName, time) { | |
ScriptApp.newTrigger(functionName) | |
.timeBased().after(time).create(); | |
console.log('%s, %s, Time: %s - trigger AfterByName', Session.getEffectiveUser().getEmail(), functionName, time); | |
} | |
function setFolderSSIdProperty(value) { | |
return PropertiesService.getUserProperties().setProperty('FOLDER_SS_ID', value); | |
} | |
function getFolderSSIdProperty() { | |
return PropertiesService.getUserProperties().getProperty('FOLDER_SS_ID'); | |
} | |
function deleteFolderSSIdProperty() { | |
return PropertiesService.getUserProperties().deleteProperty('FOLDER_SS_ID'); | |
} | |
function deleteTriggerByName(name) { | |
var getPropTrigger = PropertiesService.getUserProperties().getProperty('atHour'+name); | |
if (!getPropTrigger) { | |
getPropTrigger = 'x'; | |
} | |
var triggers = ScriptApp.getProjectTriggers(); | |
for (var i = 0; i < triggers.length; i++) { | |
if (triggers[i].getHandlerFunction() == name && triggers[i].getUniqueId() != getPropTrigger) { | |
ScriptApp.deleteTrigger(triggers[i]); | |
} | |
} | |
} | |
// https://developers.google.com/drive/v2/reference/files | |
function getDriveFileById_(id) { | |
var optionalArgs = { | |
supportsTeamDrives : true | |
}; | |
try { | |
return Drive.Files.get(id, optionalArgs); | |
} catch(error) { | |
return error; // error.name, error.message; | |
} | |
} | |
function getSpreadsheetById(ssId) { | |
if (!ssId || ssId < 10) { | |
console.warn('!ssId || ssId.length < 10 - getSpreadsheetById'); | |
return; | |
} | |
try { | |
var resp = getDriveFileById_(ssId); | |
if (resp.id && !resp.labels.trashed) { | |
return SpreadsheetApp.openById(ssId); | |
} | |
} catch(e) { | |
console.warn('Error: %s, %s - DriveApp.getFileById(%s) in getSpreadsheetById', e.name, e.message, ssId); | |
} | |
} | |
/* | |
* check: 파일 복사 함수 호출의 반환값으로 다음 작업을 결정합니다. | |
* '1': 계속 진행 | |
* '-1': 프로세스 중단 | |
* '-2': after 트리거 생성 | |
* '-3': hour 트리거 생성 | |
**/ | |
function callFileCopy_(title, id, parentId) { | |
var copiedState = { | |
copy: '1', | |
link: '', // or Error name | |
message: 'Ok', | |
check: '1' | |
} | |
var resource = { | |
'title': title, | |
parents: [{ id: parentId }] | |
}; | |
var optionalArgs = { | |
supportsTeamDrives : true | |
}; | |
var resp; | |
try { | |
resp = Drive.Files.copy(resource, id, optionalArgs); | |
if (resp && resp.id) { | |
copiedState.link = resp.alternateLink; | |
return copiedState; | |
} | |
} catch(error) { | |
resp = error; // error.name, error.message; | |
} | |
copiedState.copy = '0'; // Not copy | |
var rowContents; | |
var thisFunctionName = 'Call Drive.Files.copy'; | |
var email = Session.getEffectiveUser().getEmail(); | |
if (!resp || !resp.name) { | |
console.warn('%s, Error !resp.name, Title: %s - %s', email, title, thisFunctionName); | |
copiedState.link = ''; | |
copiedState.message = ''; | |
copiedState.check = '-2'; | |
return copiedState; | |
} | |
copiedState.link = resp.name; | |
copiedState.message = resp.message; | |
console.warn('%s, Error: %s, Message: %s, Title: %s - %s', email, resp.name, resp.message, title, thisFunctionName); | |
if (resp.message.indexOf('User rate limit exceeded') >= 0) { | |
copiedState.check = '-3'; // create trigger, hour | |
} else if (resp.message.indexOf('The user has exceeded') >= 0 || | |
resp.message.indexOf('The file limit for this Team Drive') >= 0) { | |
copiedState.check = '-1'; // process kill | |
} else { | |
copiedState.check = '1'; // Skip | |
// Error Name: Exception | |
// 'Internal Error' | |
// '빈 응답' | |
} | |
return copiedState; | |
} | |
function copyFilesBySheet_(startTime, sheet) { | |
var lastRow = sheet.getLastRow(); | |
if (!lastRow || lastRow < 3) { | |
return '9'; | |
} | |
var startRow = sheet.getRange('B1').getValue(); | |
if (!startRow || startRow < 3) { | |
startRow = 3; | |
} | |
if (startRow > lastRow) { | |
return '9'; | |
} | |
var rows = lastRow - startRow + 1; | |
var fileValues = sheet.getRange(startRow, 1, rows, 9).getValues(); | |
var fileCont; | |
var valuesCopyfile = []; | |
for (var idx = 0; idx < rows; idx++) { | |
fileCont = fileValues[idx] | |
var title = fileCont[0]; | |
var id = fileCont[1]; | |
var parent = fileCont[8]; | |
var copiedState = callFileCopy_(title, id, parent); | |
var arr = [copiedState.copy]; | |
arr.push(copiedState.link); | |
arr.push(copiedState.message); | |
arr.push(copiedState.check); | |
valuesCopyfile.push(arr); | |
if (copiedState.check === '1') { | |
// console.log('copiedState.chek: %s === 1', copiedState.check); | |
} else { | |
console.log('%s Not === 1, break copyFilesBySheet, copiedState.chek', copiedState.check); | |
break; | |
} | |
if (!timeCheck(startTime, 30000)) { // needTime: 30 sec | |
break; | |
} | |
// end for var idx | |
} | |
var valuesLength = valuesCopyfile.length; | |
sheet.getRange(startRow, 5, valuesLength, valuesCopyfile[0].length).setValues(valuesCopyfile); | |
var readToRow = (copiedState.check === '1') ? (startRow + valuesLength) : (startRow + valuesLength - 1); | |
sheet.getRange('B1').setValue(readToRow); | |
if (idx >= rows) { | |
return '9'; | |
} | |
return copiedState.check; | |
} | |
function timeCheck(startTime, needTime) { | |
var nowDate = new Date(); | |
// remain = 6 min - ( now - start ) | |
var remain = 360000 - (nowDate.getTime() - startTime); | |
if (remain < needTime) { | |
return false; | |
} else { | |
return true; | |
} | |
} | |
function trigCpFolderBySheet_() { | |
var newDate = new Date(); | |
var COPY_START_TIME = newDate.getTime(); | |
// Deletes triggers | |
var thisFunctionName = 'trigCpFolderBySheet_'; | |
deleteTriggerByName(thisFunctionName); | |
var ssId = getFolderSSIdProperty(); | |
if (!ssId || ssId.length < 10) { | |
console.warn('Error getProperty(FOLDER_SS_ID), %s', thisFunctionName); | |
return; | |
} | |
var copyFolderSs = getSpreadsheetById(ssId); | |
if (!copyFolderSs) { | |
console.warn('getSpreadsheetById(%s), at %s', ssId, thisFunctionName); | |
return; | |
} | |
var sheetFolder = copyFolderSs.getSheetByName('folder'); | |
var sheetFiles = copyFolderSs.getSheetByName('files'); | |
var folderRow = sheetFolder.getRange('B1').getValue(); // row to read | |
var timeResp; | |
var title, id, id2, files, filesArrayLength, fileRow; | |
var lastRowFiles, pageTokenProperty; | |
do { | |
var resp = doCopyFolder_(sheetFolder, folderRow, sheetFiles, COPY_START_TIME); | |
if (resp === '1') { | |
if (!timeCheck(COPY_START_TIME, 120000)) { | |
console.log('timeCheck -> triggerAfter'); | |
triggerAfterByName(thisFunctionName, 1000); // trigger 기동 | |
return; | |
} | |
} | |
} while(resp === '1'); | |
} | |
function listFilesByPageToken_(folderId, pageToken, startTime) { | |
var query = '"'+ folderId +'" in parents and trashed = false'; | |
var files, resp; | |
var data = []; | |
var fileCont = []; | |
do { | |
files = Drive.Files.list({ | |
includeTeamDriveItems : true, | |
supportsTeamDrives : true, | |
q: query, | |
maxResults: 100, | |
pageToken: pageToken, | |
}); | |
if (files.items && files.items.length > 0) { | |
for (var i = 0; i < files.items.length; i++) { | |
var file = files.items[i]; | |
fileCont = [file.title]; // file.title, file.id, file.mimeType, file.fileSize | |
fileCont.push(file.id); | |
fileCont.push(file.mimeType); | |
if (!file.fileSize) { | |
fileCont.push(0); | |
} else { | |
fileCont.push(file.fileSize); | |
} | |
data.push(fileCont); | |
} | |
} | |
pageToken = files.nextPageToken; | |
} while (pageToken && timeCheck(startTime, 30000)); // needTime: 30 sec | |
if (data.length > 0) { | |
var objFiles = {}; | |
objFiles.pageToken = pageToken; | |
objFiles.files = data; | |
return objFiles; | |
} | |
} | |
function funcCopyFromInput_(argUrl, argFolder) { | |
var appMessage = {}; | |
appMessage.url = argUrl; | |
appMessage.title = argUrl; | |
if (!argUrl || argUrl.length < 15) { | |
appMessage.message = argUrl + ' is too short to be processed.'; | |
return appMessage; | |
} | |
var file = getFolderByGdUrl_(argUrl); // return Drive.Files.get(id, optionalArgs); | |
if (!file || !file.id) { | |
var appMessage = file; | |
if (appMessage && appMessage.name) { | |
console.log('Error Name: %s, Message: %s, Form Input Url: %s', appMessage.name, appMessage.message, argUrl); | |
appMessage.message = 'Error Name: '+appMessage.name+', Message: '+appMessage.message; | |
} else { | |
console.log('Error input Url Validate. URL does not have file ID. [%s]', argUrl); | |
appMessage.message = 'Error ['+argUrl+'] Validate.'; | |
} | |
return appMessage; | |
} | |
var title = file.title; | |
if (file.mimeType != 'application/vnd.google-apps.folder') { | |
return fileCopyFromInput_(file, argFolder.id); | |
} else { | |
var ss = createFolderSpreadsheet_(title, argFolder.id); | |
var sheetFolder = ss.getSheets()[0]; | |
var newDate = new Date(); | |
sheetFolder.appendRow([title, file.id, '', 0, 0, newDate, newDate, 0, argFolder.id]); | |
setFolderSSIdProperty(ss.getId()); | |
appMessage.url = ss.getUrl(); | |
appMessage.title = ss.getName(); | |
appMessage.message = 'Create Spreadsheet'; | |
// trigger 기동 | |
triggerAfterByName('trigCpFolderBySheet_', 1000); | |
return appMessage; | |
} | |
} | |
function processForm(formObject) { | |
var formFromUrl = formObject.fromFolder.trim(); | |
var formToUrl = formObject.toFolder.trim(); | |
var appMessage = {}; | |
var toFolder = getFolderByGdUrl_(formToUrl); | |
if (!toFolder || !toFolder.id) { | |
console.warn('Error Get to folder'); | |
appMessage.message = 'Error Get to folder'; | |
return JSON.stringify(appMessage); | |
} | |
var fcResp = funcCopyFromInput_(formFromUrl, toFolder); | |
if (!fcResp) { | |
appMessage.url = 'https://drive.google.com'; | |
appMessage.title = 'My Drive'; | |
appMessage.message = 'can not copy!'; | |
} else { | |
appMessage = fcResp; | |
} | |
return JSON.stringify(appMessage); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script> | |
window.addEventListener('load', function() { | |
// console.log('Page is loaded'); | |
}); | |
// Prevent forms from submitting. | |
function preventFormSubmit() { | |
var forms = document.querySelectorAll('form'); | |
for (var i = 0; i < forms.length; i++) { | |
forms[i].addEventListener('submit', function(event) { | |
event.preventDefault(); | |
}); | |
} | |
} | |
window.addEventListener('load', preventFormSubmit); | |
function handleFormSubmit(formObject) { | |
google.script.run.withSuccessHandler(updateUrl).processForm(formObject); | |
formObject.fromFolder.value = ''; | |
} | |
function updateUrl(appMessage) { | |
var json; | |
if (appMessage) { | |
json = JSON.parse(appMessage); | |
if (json.url) { | |
// var url | |
var div = document.getElementById('output'); | |
div.innerHTML = 'Link: <a href="' + json.url + '" target="_blank">'+json.title+'</a>'; | |
} | |
if (json.message) { | |
var message = document.getElementById('message'); | |
message.innerHTML = 'Message: '+json.message; | |
} | |
} | |
} | |
</script> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<base target="_top"> | |
<?!= include('Stylesheet'); ?> | |
</head> | |
<body> | |
<h1>Copy to team drive review</h1> | |
<a href="https://gfoldercopy.eojji.com/group" target="_blank">G folder copy group</a> | |
<br><br> | |
<form id="myForm" onsubmit="handleFormSubmit(this)"> | |
From: <input name="fromFolder" type="text" required /> <br> | |
To: <input name="toFolder" type="text" required /> | |
<input type="submit" value="Copy" /> | |
</form> | |
<br> | |
<div id="message">Message: </div> | |
<div id="output">Link: </div> | |
<br> | |
Create a <a href="https://gsuite.google.com/learning-center/products/drive/get-started-team-drive/">Team Drive</a>: <a href="https://goo.gl/forms/1az5A9lwcG2HpL5s2">Request Form</a> | <a href="https://hi.eojji.com/">Contact</a> | |
<br><br> | |
<a href="https://copy.gfolder.net/" target="_blank">copy.gfolder.net</a> | <a href="https://hi.eojji.com/privacy" target="_blank">Privacy Policy</a> | |
<?!= include('JavaScript'); ?> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<style> | |
p { | |
color: green; | |
} | |
</style> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment