기본 콘텐츠로 건너뛰기

Google sheet(+Google apps script) 만으로 손쉽게 슬랙 생일축하 봇 만들기. Slack Birthday message bot via Googlesheet(+Google apps script)

안녕하세요. 

제가 비전공자이기 때문에 비전공자도 가능한 방법입니다.


저희 회사는 Birthdaybot 이라는 Slack app을 사용해왔는데, 최근에 아래와 같이 free plan limit 이 끝났다는 메시지를 받게 되었습니다.. 흑..

20%할인을 해준다고 하지만.. 인당 0.99 달러~ 1.99 달러를 지불하고 사용하느니 직접 만들어봐야겠다고 생각해서 도전했습니다. (이 블로그를 참고했는데 오류나는 코드를 일부 수정하고 기능을 추가했습니다. Chavo님 감사합니다!!)




먼저 결과물은 이렇게 됩니다. 저희 회사는 기본언어가 영어라 영어로 했지만 한글로 바꾸시면 됩니다! 



자 그럼, 멤버의 생일이 되면 특정 슬랙 채널에 메시지를 작성하면서 생일자를 부르면서 축하해는데, 

이 때 생일 축하 메시지도 고정되어 있는게 아니라 여러개를 등록해서 랜덤하게 출력하는 봇을 만들어 볼게요.


전체적인 진행 순서는 아래와 같습니다.

1. 슬랙 incoming webhook 페이지에 가서 (https://slack.com/apps/A0F7XDUAZ-incoming-webhooks)

2. 알림이 가길 원하는 채널 선택 후 추가, webhook URL을 복사

3. 구글 시트에서 apps-script 코드를 추가

4. 트리거 설정하면 끝!



1번부터 차례대로 해봅시다. https://slack.com/apps/A0F7XDUAZ-incoming-webhooks 에 방문하면 로그인을 해야합니다. 로그인 후 Add to Slack을 누릅니다.



2. 그 다음,  적절한 채널 명을 지정하고 add incoming webhooks integration 버튼을 누릅니다.



그리고 빨간글씨의 URL을 복사해서 잘 어디 메모장 같은 곳에 둡니다.


아래로 스크롤해서 내리면 봇의 이름과 아이콘을 지정할 수 있습니다. 원하는 봇 이름과 아이콘으로 바꿔주세요!



3. 구글시트로 갑니다. 구글시트 양식의 형태는 이렇게 해줍니다. 브라우저에서 구글시트의 URL주소를 잘 보시면 d/ 부터 다음 / 까지가 구글시트의 id값인데 복사해서 잘 둡니다.



여기서 잠깐!

  SlackUID가 뭔가 싶으실거예요!. 결과물에서 보실 수 있듯 저는 생일자를 슬랙에서 @이름 으로 어싸인해서 알리고, 그 스레드에 누군가가 축하메시지를 남겼을 때 생일자가 볼 수 있게 하기 위해서 이렇게 구성했습니다만, 필요없으신 분은 그냥 이름으로만 하셔도 됩니다. 저처럼 Slack UID를 써서 알림을 주고싶은 경우에는 이 글 끝에서 추가로 방법 알려드릴게요!

구글시트 상단 메뉴 Extentions > Apps Script 를 누르면 새창이 뜹니다.

Code.gs 부분에 아래 코드를 추가합니다.

// 구글 스프레드시트 ID 설정
const spreadsheetId = "복사해뒀던 구글스프레드시트 ID를 넣어주세요";

// Slack에 메시지를 보낼 Webhook URL 설정
const webhookURL = "복사해뒀던 webhook URL을 넣어주세요.";

// 스프레드시트에서 생일 정보를 읽어올 범위 설정. 구글시트 탭 이름을 수정해주시고 범위도 A1:B열이 아니라면
// 수정해주세요!
const range = SpreadsheetApp.openById(spreadsheetId).getRange("시트이름!A1:B");

// 날짜가 유효한지 검증하는 함수
function isValidDate(d) {
if (Object.prototype.toString.call(d) !== "[object Date]")
return false;
return !isNaN(d.getTime());
}

// 생일 정보를 맵 형태로 가져오는 함수
function getBirthdayMap() {
const birthdayMap = {}

const rowNum = range.getNumRows();
for (let i = 2; i <= rowNum; i++) {
const nameCell = range.getCell(i, 1);
if (nameCell.isBlank()) {
break;
}

const date = range.getCell(i, 2).getValue();

if (isValidDate(date)) {
const dateKey = date.toLocaleDateString(undefined, {
month: "2-digit",
day: "2-digit"
});

if (birthdayMap[dateKey]) {
birthdayMap[dateKey].push(i)
} else {
birthdayMap[dateKey] = [i];
}
}
}

return birthdayMap;
}

// Slack에 메시지를 보내는 함수
function sendMessageToSlack(today, birthdayMembers) {
const todayDateKey = Utilities.formatDate(today, "KST", "yyyy-MM-dd");

let text = "";

// 축하 메시지 목록 (문구를 수정하고, 여러개를 추가하셔도 됩니다!! 각 행 사이의 ','가 필수이고 // 마지막 항목에는 ','를 넣지 않습니다.)
let congrats_msg_list = [
"🎉 Happy Birthday! Today is all about you!",
"🎈 Wishing you all the happiness on your special day!",
"🍰 Another year older, another year wiser! Happy Birthday!",
"🎁 Celebrate big! It's your special day!",
"I’ve got a big favor to ask ... Drop what you’re doing and celebrate with us! Happy Birthday! It’s a special day for an awesome person! 🥳🥳🥳"
];

// 랜덤 메시지 선택
let randomIndex = Math.floor(Math.random() * congrats_msg_list.length);
let randomCongratsMsg = congrats_msg_list[randomIndex];

if (birthdayMembers)
text = birthdayMembers.reduce((acc, rowNum) => acc + "<@" + range.getCell(rowNum, 1).getValue().toString() + "> ", "");
else
return;

// Slack 메시지 포맷 설정, 랜덤 메시지 적용
const message = {
"attachments": [
{
"color": "#2eb8",
"fields": [
{
"title": `${randomCongratsMsg} (${todayDateKey})`,
"value": `${text}\n\n 🎉🎉🎉`,
"short": false
}
]
}
]
};

var options = {
'method': 'post',
'contentType': 'application/json',
'payload': JSON.stringify(message)
};

// Webhook을 통해 Slack에 메시지 전송
UrlFetchApp.fetch(webhookURL, options);
}

// 오늘 생일인 사람들에게 메시지를 보내는 함수
function sendBirthdayMessage() {
const birthdayMap = getBirthdayMap();

const today = new Date();

const todayDateKey = Utilities.formatDate(today, "KST", "MM/dd");

const birthdayMembers = birthdayMap[todayDateKey];

sendMessageToSlack(today, birthdayMembers);
Logger.log("Today's Date: " + today);
Logger.log("Birthday Members: " + birthdayMembers);
}


그 다음 위에 디스켓 모양버튼을 눌러 저장합니다.

좌측 슬라이드 메뉴에서 Triggers 를 누르고 아래와 같이 설정한 뒤 Save 버튼을 누릅니다.


권한승인을 위해 로그인을 하라고 하는 경우 제가 참고한 블로거분 글 처럼 Advanced > Go To ExampleOfSendBirthdayMessage (unsafe) 를 클릭해서 마저 권한을 얻습니다.

잘 작동하는지를 테스트 하려면,  Select type of time base trigger 부분을 specitic time 으로 하고 1분 뒤로 지정해서 확인하면 좋습니다.




(Optional)

슬랙에 가입되어있는 이메일 주소를 구글시트에 적어놓으면, 이를 기반으로 SlackUID를 찾아서 같은 구글시트에 정기적으로 입력되도록 할 수 있습니다.

저의 경우엔 Zapier 보다 가격이 저렴하고 무료로도 사용이 가능한 Make 라는 서비스를 이용했습니다.

 전체적으로는 일단 아래와 같이 시나리오가 구성됩니다.

(구글시트와 슬랙 모듈을 추가할 때 최초 시도시에는 구글과 슬랙 계정 로그인 및 권한부여를 해줘야 합니다.)


먼저 구글시트로 다시 돌아가서, 위에서 제시한 구글시트 템플릿 기준 A열에 email을 넣어주세요. 이러면 Google Apps Script에서 지정했던 열도 추가로 수정해주셔야 합니다! 

 


그 다음 Make에서 Google sheets - Get Range Values 모듈을 추가하고, 


한글로 설명해놓은 각 항목에 적절한 값을 넣어주세요. Range 는 email 주소가 들어있는 A2:A로 할게요.

Slack - Search for User 모듈을 추가하고,  녹색 A열을 선택해줍니다.




다음으로 Google sheet - Update a Row 모듈을 추가해서 아래와 같이 구성합니다.


다음으로는 아래 Tools 에서 ignore 모듈도 하나 추가합니다.

(이건 에러가 발생했을 때 무시하는 용도인데, 안전을 위해서 추가하는겁니다. ㅎㅎ)




ignore 모듈과 Slack 모듈 사이 줄(?) 을 클릭하면 filter 를 설정할 수 있는데 무시하는 조건을 아래처럼 "슬랙에서 에러가 발생해서 에러메시지가  있는 경우" 로 설정해주시면 됩니다.




마지막으로,

 Google sheet - Get Range Values 모듈에 시계모양을 클릭하면 어떻게 이 시나리오를 실행할지에 대해서 설정할 수 있는데,  저는 구글시트+Google Apps Script로 슬랙 알림메시지가 발송되는 트리거를 9AM~10AM으로 설정 했기에 그 전에 SlackUID를 모두 정기적으로 업데이트 할 수 있도록 매 평일 아침 8시 50분으로 설정했습니다.




테스트를 해보려면 하단의 Run once 를 누르면됩니다.

그리고 마지막 단계! 시나리오를 On 으로 바꿔주면 끝!





댓글

이 블로그의 인기 게시물

#1 (진행 중)아두이노 뇌파센서 헤드셋 만들기(Arduino EEG brain wave headset for psychological test) 만들어 뇌파 읽기

 15년 겨울쯤엔가 TED에서 흥미로운 동영상을 봤다. 뇌파를 통해 컴퓨터 안의 객체를 조종하는 모습을 시연하는 것이었다. 뇌파로 이런 것들이 가능하다는 것이 놀라웠다. 나는 심리학도가 아닌가. 뇌파가 더 정확한 심리검사를 만들 수 있는 도구가 될 수 있다는 생각이 들었다.  예를들어 검사문항(디지털 검사)이 100개짜리 라면 핵심 문항들(각 10번 단위)을 체크할 때마다 심경의 변화, 뇌파변화를 센서(객관적)도 기록하고 디지털검사(주관적)로도 기록해서 함께 데이터화 한다면 더 정확한 심경을 읽어 낼 수 있지 않을까? 라는 생각이었다. 2011년 대학원 다닐 때 컴공과 학부생들 겨울방학 특강으로 Objective-C를 무려1개월간 청강했고, C언어를 무려 2개월동안 학원에 다니면서 공부한 사람이기에 ! -_-;;;; 할 수 있을 것이다............  우선 뇌파센서를 구매해야겠지.  알리 익스프레스에서 구매한 EEG 뇌파센서 kit.  2개를 구매했다.비싸군 ㅠㅠ 배송이 한달정도 걸렸다. 학창시절 라디오 만들기인가..실과시간에 도전해본 납땜 이후로는 처음 해보는 납땜이어서 고생좀 했다. 뇌파를 측정해서 hex 코드로 컴퓨터로 읽어들일 수 있는 상태다. 읽어들인 hex값들을 10진수로 변환하고 유의미한 그래프로 그리거나 데이터화 하는 것이 필요 해 보이지만 아직 받은 값을 10진수로 변환하는 방법을 모르겠다. ㅠㅠ 소스코드는 그냥 단순히 hex값으로 읽어오는것이다보니.. 별거 없다;; 나중에 10진수로 변환하여 읽어들이고 자료화 하는 단계가 필요한 것 같은데 차근차근 진행 해 봐야겠다. 준비물 :  1. HM-08 블루투스 모듈 ($5.30) 2. 아두이노 나노 호환품 ($1.89) 3. direct nerosky e eg  brain sensor kit ($50.05) 4. 기타 빵판과

#1 (완료) 아두이노 음주 측정기(Alcohol tester with Arduino)

음주운전을 하지 않는 가장 좋은방법은 대리운전 비용 1만원~1.2만원이 아깝지 않으면서 대리운전 전화번호를 누를 수 있는 정도의 취함 상태인 것 같다. 그래서 생각해본 아이디어가 아예 법적으로 차량에 의무적으로 장치를 설치하도록 하는데 이 장치는 차에 시동을 걸기 전 음주측정을 해야하고 정상 수치내에 있을때만 시동이 걸리는 장치!  물론 조수석에 앉을 누군가가 음주운전을 돕기 위해 대신불어준다면 안되겠지만..ㅠㅠ 아침 출근을 위해 정말 급하게 가글을 하고 나와 출근하려 시동을 걸었는데..가글액에 섞인 알코올 성분때문에 지각을 하는 경우도 생길 수 있겠다만.. 그래도 한번 만들어 보자. 어차피 내게는 차량과 연동할 기술적 지식이 아직 없으므로! 하하하하 06.13 진행 중이나 아직 정리가 안됨 07.01 에 05.28 진행 내용 추가 실제 경찰들 처럼 더더더~ 멘트로 몰입감+정확성(3회 불어서 나온수치의 평균을 활용하는 벙법)을 높일 수 있도록 개선하였다. -_-; Ready 상태. 이후 3,2,1 카운트 후 blow! 그리고 수치를 반복하여 깜빡이며 한다. 이하 소스코드 #include <LiquidCrystal.h> // initialize the library with the numbers of the interface pins LiquidCrystal lcd(12, 11, 5, 4, 3, 2); void setup() {   // set up the LCD's number of columns and rows:   lcd.begin(16, 2); } void loop() { lcd.setCursor(1, 0); //라인1로 커서 위치   lcd.print("Ready...");   delay(4000); lcd.clear();   // set the cursor to column 0, line 1   // (note: line 1 is t

(완료) Cron의 crontab 명령으로 Python code를 스케쥴대로 실행하기(Run python code by fixed interval with using Cron)

(완료)1# Python 으로 지출관리 사이트에서 모든지출 데이터 xlsx 파일 뽑아내고 Zapier로 구글시트에 업데이트하기 (Using Python, crawling and exporting company wide expenses data with Xlsx file. Update a Google sheet from this Xlsx file with Zapier.) (완료) 2# Python 으로 지출관리 사이트에서 모든지출 데이터 xlsx 파일 뽑아내고 Zapier로 구글시트에 업데이트하기 (Using Python, crawling and exporting company wide expenses data with Xlsx file. Update a Google sheet from this Xlsx file with Zapier.) 위 포스팅 내용 대로, 1. python을 통해 selenium 모듈로 crawling을 해서 xlsx 파일을 이메일로 받고 2. xlsx 파일은 Zapier 라는 노코드 툴에서 Email parser by Zapier 와 2개의 Zap 으로 처리해서 구글시트에 업데이트를 했다. 하지만 계속 실시간 데이터를 유지하는게 필요하다.  그럼 이제  추가적으로 이제 이걸 딜레이 시간 을 포함해서 정기적으로 실행되도록 해보자. 딜레이가 Zapier에서 10분 나머지 작업이 진행되는데 2분 정도로 총 12분 걸리는 것으로 확인을 했다.  그리고 나의 경우엔 월요일부터 금요일까지, 아침 7시 30분 부터 저녁 6시 00분까지 30분 간격으로 업데이트 되도록 하겠다.   딜레이를 고려한다면 매 시 48,18분에 python 코드가 돌아가면 얼추 정각에 완료되는 거군! 그러기 위해서는 cron 이라는 리눅스 스케줄러를 사용하려고 한다. 1. terminal 을 열고 sudo apt install cron 으로 crontab을 설치 2. crontab -e 명령어로 VI편집기 오픈 3. i 를 눌러서 insert mode로 전환 4. 아래 명령어