[Google app script] ๊ตฌ๊ธ€ ์Šคํ”„๋ ˆ๋“œ์‹œํŠธ๋ฅผ PDF๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ Slack ์ฑ„๋„์— ์ „์†กํ•˜๊ธฐ
๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๋””์ง€ํ„ธ ๊ฟ€ํŒ

[Google app script] ๊ตฌ๊ธ€ ์Šคํ”„๋ ˆ๋“œ์‹œํŠธ๋ฅผ PDF๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ Slack ์ฑ„๋„์— ์ „์†กํ•˜๊ธฐ

by ์ผ์ƒ์„ ๊ณต์œ ํ•ฉ๋‹ˆ๋‹ค 2022. 2. 21.

์ง€๋‚œ ๋ฒˆ์—” ์‹œ๊ฐ„์ด ์—†์–ด์„œ slack file upload๋ฅผ ๊ตฌํ˜„ํ•˜์ง€ ๋ชปํ–ˆ๋Š”๋ฐ ์ฐจ๋ถ„ํžˆ ํ•˜๋‹ˆ๊นŒ ๊ธˆ๋ฐฉ ํ•˜๊ฒŒ๋˜์—ˆ๋‹ค. ๋˜ํ•œ ๊ตฌ๊ธ€์—๋Š” ์ •๋ณด๊ฐ€ ๋งŽ์•„์„œ ๋„์›€์ด ๋งŽ์ด ๋˜์—ˆ๋‹ค. ์—ญ์‹œ ์ง€์‹์„ ์„œ์น˜ํ•˜๋Š”๋ฐ๋Š” ๊ตฌ๊ธ€๋งŒํ•œ๊ฒŒ ์—†๋Š” ๊ฒƒ ๊ฐ™๋‹ค.

๊ตฌ๊ธ€ ์Šคํ”„๋ ˆ๋“œ์‹œํŠธ PDF๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ๋ฉ”์ผ ๋ณด๋‚ด๊ธฐ

 

[google spreadsheet & app script] PDF ์ฒจ๋ถ€ํ•˜์—ฌ ๋ฉ”์ผ ๋ณด๋‚ด๊ธฐ

์Šคํ”„๋ ˆ๋“œ์‹œํŠธ์— ์ฃผ๊ธฐ์ ์œผ๋กœ ๋น„์Šทํ•œ ํ˜•ํƒœ์˜ ๋ณด๊ณ ์„œ๋‚˜ ๋ฆฌํฌํŠธ๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ๊ณต์œ ํ•  ์ผ์ด ์ƒ๊ธด๋‹ค. ํ•ด๋‹น ์†Œ์Šค๋Š” ์Šคํ”„๋ ˆ๋“œ์‹œํŠธ๋ฅผ PDF๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ๋ฉ”์ผ์— ์ฒจ๋ถ€ํŒŒ์ผ๋กœ ์ „๋‹ฌํ•œ๋‹ค. ์ถ”๊ฐ€์ ์œผ๋กœ ๋ฉ”์ผ ๋ณธ๋ฌธ์€

odaily.tistory.com


๊ตฌ๊ธ€ ์Šคํ”„๋ ˆ๋“œ์‹œํŠธ๋ฅผ PDF๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ๋ฐ”๋กœ Slack ์ฑ„๋„์— ์ „์†กํ•˜๊ธฐ

๋งํฌ : https://api.slack.com/methods/files.upload

function sendSlackFile() {
  /** ๊ตฌ๊ธ€ ์Šคํ”„๋ ˆ๋“œ์‹œํŠธ pdf ๋ณ€ํ™˜*/
  var theurl = '์ง€๋‚œ๋ฒˆ์— ์Šคํ”„๋ ˆ๋“œ ์‹œํŠธ pdf๋กœ ๋ณ€ํ™˜ํ•œ ๊ธ€ ์ฐพ์•„๋ณด๊ธฐ!'

  var token = ScriptApp.getOAuthToken();
  var docurl = UrlFetchApp.fetch(theurl, { headers: { 'Authorization': 'Bearer ' + token } });

 /** ์Šฌ๋ž™ fileupload */
  var metadata = {
    token: "slack API ํ† ํฐ",
    channels: "์ฑ„๋„ ID",
    filename: "ํŒŒ์ผ์ด๋ฆ„.ํ™•์žฅ์ž",
    title: "ํŒŒ์ผ์ œ๋ชฉ",
  };

  var url = "https://slack.com/api/files.upload";
  var boundary = "xxxxxxxxxx";
  var data = "";
  for (var i in metadata) {
    data += "--" + boundary + "\r\n";
    data += "Content-Disposition: form-data; name=\"" + i + "\"; \r\n\r\n" + metadata[i] + "\r\n";
  }
  data += "--" + boundary + "\r\n";
  
  /** value1 */
  data += "Content-Disposition: form-data; name=\"file\"; filename=\""+"ํŒŒ์ผ์ด๋ฆ„"+"\"\r\n";
  data += "Content-Type:application/ํŒŒ์ผํ™•์žฅ์ž\r\n\r\n";
  
  /** value2 , file ์‚ฌ์ด์ฆˆ ๋งŒํผ */
  var payload = Utilities.newBlob(data).getBytes()
    .concat(docurl.getBlob().getBytes())
    .concat(Utilities.newBlob("\r\n--" + boundary + "--").getBytes());
   var options = {
    method : "post",
    contentType : "multipart/form-data; boundary=" + boundary,
    payload : payload,
    muteHttpExceptions: true,
  };
  
  var res = UrlFetchApp.fetch(url, options).getContentText();

  Logger.log(res);
}

#์†Œ์Šค ํ•ด์„ํ•˜๊ธฐ

  • ์Šคํ”„๋ ˆ๋“œ์‹œํŠธ๋„ ํ•œ๋ฒˆ pdf๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ UrlFetchApp์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค. UrlFetchApp : ๋ฆฌ์†Œ์Šค๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ  ์ธํ„ฐ๋„ท์„ ํ†ตํ•ด ๋‹ค๋ฅธ ํ˜ธ์ŠคํŠธ์™€ ํ†ต์‹ ํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๋‹ค.
 /** ๊ตฌ๊ธ€ ์Šคํ”„๋ ˆ๋“œ์‹œํŠธ pdf ๋ณ€ํ™˜*/
  var theurl = '์ง€๋‚œ๋ฒˆ์— ์Šคํ”„๋ ˆ๋“œ ์‹œํŠธ pdf๋กœ ๋ณ€ํ™˜ํ•œ ๊ธ€ ์ฐพ์•„๋ณด๊ธฐ!'

  var token = ScriptApp.getOAuthToken();
  var docurl = UrlFetchApp.fetch(theurl, { headers: { 'Authorization': 'Bearer ' + token } });
  • slack์— my app์œผ๋กœ ๋“ค์–ด๊ฐ€๋ฉด api token์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ์Šฌ๋ž™ ์ฑ„๋„ ID ๋ณด๋Š” ๋ฐฉ๋ฒ•์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค. 

  • ์ž‘์„ฑํ•œ ์†Œ์Šค์ฝ”๋“œ ์˜ˆ์‹œ์ด๋‹ค.
/** ์Šฌ๋ž™ fileupload */
  var metadata = {
    token: "slack API ํ† ํฐ",
    channels: "์ฑ„๋„ ID",
    filename: "ํŒŒ์ผ์ด๋ฆ„.ํ™•์žฅ์ž",
    title: "ํŒŒ์ผ์ œ๋ชฉ",
  };

  var url = "https://slack.com/api/files.upload";
  var boundary = "xxxxxxxxxx";
  var data = "";
  for (var i in metadata) {
    data += "--" + boundary + "\r\n";
    data += "Content-Disposition: form-data; name=\"" + i + "\"; \r\n\r\n" + metadata[i] + "\r\n";
  }
  data += "--" + boundary + "\r\n";
  
  /** value1 */
  data += "Content-Disposition: form-data; name=\"file\"; filename=\""+"ํŒŒ์ผ์ด๋ฆ„"+"\"\r\n";
  data += "Content-Type:application/ํŒŒ์ผํ™•์žฅ์ž\r\n\r\n";
  
  /** value2 , file ์‚ฌ์ด์ฆˆ ๋งŒํผ */
  var payload = Utilities.newBlob(data).getBytes()
    .concat(docurl.getBlob().getBytes())
    .concat(Utilities.newBlob("\r\n--" + boundary + "--").getBytes());
   var options = {
    method : "post",
    contentType : "multipart/form-data; boundary=" + boundary,
    payload : payload,
    muteHttpExceptions: true,
  };

 

ํ•œ์‹œ๊ฐ„ ์•ˆ์— ์ž‘์—…์„ ํ•ด๋‚ด์„œ ์ •๋ง ๋‹คํ–‰์ด์˜€๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค. ๊ถ๊ธˆํ•˜์‹  ์‚ฌํ•ญ์€ ๋Œ“๊ธ€๋กœ ๋‚จ๊ฒจ์ฃผ์‹œ๋ฉด ๋‹ต๋ณ€์„ ๋‹ฌ๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด ๋‹ค์Œ์—” ๋…ธ์…˜ ์—ฐ๋™์„ ๊ฐ€์ง€๊ณ  ์˜ฌ ์˜ˆ์ •์ž…๋‹ˆ๋‹ค. 

 

๋Œ“๊ธ€