Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(#81): notification #82

Open
wants to merge 26 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
395fc9d
feat(#81): token 알림을 위한 scope 추가
ygnoh Apr 18, 2018
f17296f
feat(#81): notifications permission 추가
ygnoh Apr 18, 2018
90eeaab
refact(#81): frontend/backend 디렉토리 분리
ygnoh Apr 19, 2018
86ae85d
feat(#81): init backend package.json
ygnoh Apr 19, 2018
12712bc
feat(#81): .gitignore 생성 및 express 설치
ygnoh Apr 19, 2018
05f99d7
feat(#81): 서버 기초 코드 작성
ygnoh Apr 19, 2018
51b1632
feat(#81): 기초적인 webhook request 처리
ygnoh Apr 19, 2018
f55390d
feat(#81): try-catch 방어 로직 추가
ygnoh Apr 24, 2018
a8841c9
feat(#81): backend firebase 추가
ygnoh Apr 25, 2018
9bc45db
feat(#81): frontend firebase 추가
ygnoh Apr 25, 2018
50da988
feat(#81): backend firebase 초기화 성공
ygnoh Apr 25, 2018
3688386
feat(#81): gitignore에 firebase private key 추가
ygnoh Apr 25, 2018
620022b
feat(#81): npm request installed
ygnoh Apr 25, 2018
59adf52
feat(#81): backend googleapis 설치
ygnoh Apr 25, 2018
e1c7f8a
feat(#81): backend에서 불필요한 firebase 제거
ygnoh Apr 25, 2018
863df14
feat(#81): webhook 시, fcm에 request 전달
ygnoh Apr 25, 2018
02a47b3
feat(#81): frontend firebase 초기화
ygnoh Apr 25, 2018
787238d
feat(#81): popup 내 username 등록 기능 구현
ygnoh May 3, 2018
9a3c3a4
fix(#81): 누락된 list class 추가
ygnoh May 3, 2018
f0aad35
feat(#81): webpack watch 모드 추가
ygnoh May 3, 2018
882dedc
feat(#81): username 등록 시 registration id 발급
ygnoh May 3, 2018
265ef07
feat(#81): manifest CSP 허용
ygnoh May 3, 2018
4ba6e04
feat(#81): firebase util 생성
ygnoh May 3, 2018
ef12782
refact(#81): firebase 관련 const 수정
ygnoh May 3, 2018
d9a4f26
refact(#81): background.js firebase 관련 로직 제거
ygnoh May 3, 2018
31d3164
feat(#81): firebase util export
ygnoh May 3, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions backend/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
firebase-key.json
package-lock.json
.vscode/
node_modules/
25 changes: 25 additions & 0 deletions backend/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "smart-github",
"version": "1.1.0",
"description": "Chrome extension for github",
"main": "src/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/ygnoh/smart-github.git"
},
"keywords": [],
"author": "Yonggoo Noh <yonggoo.noh@gmail.com> (https://github.com/ygnoh)",
"license": "AGPL-3.0-only",
"bugs": {
"url": "https://github.com/ygnoh/smart-github/issues"
},
"homepage": "https://github.com/ygnoh/smart-github#readme",
"dependencies": {
"express": "^4.16.3",
"googleapis": "^29.0.0",
"request": "^2.85.0"
}
}
76 changes: 76 additions & 0 deletions backend/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
const express = require("express");
const request = require("request");
const {google} = require("googleapis");

const app = express();
const PORT = 3000;

let accessToken;
getAccessToken().then(token => accessToken = token);

app.post("/watch", (req, res, next) => {
let payload = "";

req.on("readable", () => {
const read = req.read();
if (!read) {
return;
}

payload += read;
});

req.on("end", () => {
try {
const {comment} = JSON.parse(payload);
const {html_url, user, body} = comment;

console.log(`${user.login}가 당신의 글(${html_url})에 댓글을 달았습니다:\n${body}`);

request.post({
url: "https://fcm.googleapis.com/v1/projects/smart-github/messages:send",
json: true,
headers: {
"Content-type": "application/json",
"Authorization": `Bearer ${accessToken}`
},
body: {
message: {
token: "", // TODO: 타겟 앱 인스턴스 등록 토큰
notification: {
body: "this is body",
title: "this is title"
}
}
}
}, function(error, incomingMessage, response) {
console.log(error);
});
} catch (e) {
console.error(e);
}
});
});

app.listen(PORT, () => console.log(`\nStart to listen on port ${PORT}.\n`));

function getAccessToken() {
return new Promise(function (resolve, reject) {
// the private key to get an access token
const key = require('../firebase-key.json');
const jwtClient = new google.auth.JWT(
key.client_email,
null,
key.private_key,
["https://www.googleapis.com/auth/firebase.messaging"],
null
);
jwtClient.authorize(function (err, tokens) {
if (err) {
reject(err);
return;
}
resolve(tokens.access_token);
});
});
}
File renamed without changes.
File renamed without changes.
4 changes: 3 additions & 1 deletion package.json → frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"description": "Chrome extension for github",
"main": "src/background.js",
"dependencies": {
"babel-runtime": "^6.26.0"
"babel-runtime": "^6.26.0",
"firebase": "^4.13.1"
},
"devDependencies": {
"babel-core": "^6.26.0",
Expand All @@ -21,6 +22,7 @@
"copy": "cp -r src/manifest.json src/popup.html src/_locales src/icons dist-dev/",
"copy-production": "cp -r src/manifest.json src/popup.html src/_locales src/icons dist/",
"build": "webpack && npm run copy",
"build-watch": "webpack --watch && npm run copy",
"build-production": "webpack --env.production && npm run copy-production",
"clean": "rm -r dist-dev/*",
"clean-production": "rm -r dist/*",
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
5 changes: 5 additions & 0 deletions src/consts/index.js → frontend/src/consts/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
const FIREBASE = {
SERVER_ID: "767779176892"
};

const MESSAGE = {
HOSTS_UPDATED: "hosts-updated",
ISSUE_TAB_LOADED: "issue-tab-loaded",
Expand All @@ -8,5 +12,6 @@ const MESSAGE = {
};

export {
FIREBASE,
MESSAGE
};
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
7 changes: 5 additions & 2 deletions src/manifest.json → frontend/src/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,14 @@
"permissions": [
"tabs",
"webNavigation",
"storage"
"storage",
"gcm"
],

"default_locale": "en",

"author": "yonggoo.noh@gmail.com",
"homepage_url": "https://github.com/ygnoh/smart-github"
"homepage_url": "https://github.com/ygnoh/smart-github",

"content_security_policy": "script-src 'self' https://www.gstatic.com/ https://*.firebaseio.com https://www.googleapis.com; object-src 'self'"
}
17 changes: 13 additions & 4 deletions src/popup.css → frontend/src/popup.css
Original file line number Diff line number Diff line change
Expand Up @@ -58,22 +58,31 @@ a {
color: #0645AD;
}

/* body container */
.sg-popup-body-container {
display: none;
}

.sg-popup-body-container.is-on {
display: block;
}

/* body */
.sg-popup-body {
font-size: 14px;
padding: 10px;
}

.sg-host-list {
.sg-body-list {
padding: 10px;
margin-left: 10px;
}

.sg-host-list li {
.sg-body-list li {
margin-bottom: 5px;
}

.sg-popup-heading {
.sg-body-header {
font-size: 16px;
font-weight: 500;
}
Expand All @@ -85,7 +94,7 @@ a {
left: 9.375%;
}

#sg-host-input {
.sg-footer-input {
font-size: 14px;
width: 150px;
height: 20px;
Expand Down
56 changes: 56 additions & 0 deletions frontend/src/popup.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="popup.bundle.css">
</head>
<body>
<div class="sg-popup">
<div class="sg-popup-header">
<img class="sg-logo-icon" src="icons/logo32.png">
<span class="sg-logo-text">Smart Github</span>
<ul class="sg-menu-items">
<li class="sg-menu-item">
<a href="https://github.com/ygnoh/smart-github/issues" target="_blank">Contribute</a>
</li>
<li class="sg-menu-item">
<a href="https://github.com/ygnoh/smart-github" target="_blank">Help</a>
</li>
</ul>
</div>
<input type="radio" id="sg-host-button" name="sg-popup-buttons" data-target=".sg-popup-host" checked>
<label for="sg-host-button">Host</label>
<input type="radio" id="sg-noti-button" name="sg-popup-buttons" data-target=".sg-popup-noti">
<label for="sg-noti-button">Noti</label>
<div class="sg-popup-body-container sg-popup-host is-on">
<div class="sg-popup-body">
<span class="sg-body-header">Your Hosts:</span>
<ul class="sg-body-list sg-host-list"></ul>
</div>
<div class="sg-popup-footer">
<form class="sg-footer-form">
<input class="sg-footer-input" type="text" placeholder="Enter a host" spellcheck="false" tabindex="1">
<button class="sg-host-save">Save</button>
<button class="sg-host-reset">Reset</button>
</form>
</div>
</div>
<div class="sg-popup-body-container sg-popup-noti">
<div class="sg-popup-body">
<span class="sg-body-header">Registered usernames:</span>
<ul class="sg-body-list sg-username-list"></ul>
</div>
<div class="sg-popup-footer">
<form class="sg-footer-form">
<input class="sg-footer-input" type="text" placeholder="Enter your username" spellcheck="false" tabindex="1">
<button class="sg-username-save">Save</button>
<button class="sg-username-reset">Reset</button>
</form>
</div>
</div>
</ul>
</div>

<script src="popup.bundle.js"></script>
</body>
</html>
61 changes: 61 additions & 0 deletions frontend/src/popup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import "./popup.css";
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이게 필요한가?

import {storage, dom} from "./utils";

storage.getHosts().then(hosts => {
const hostListContainer = dom.getHostList();

hosts.forEach(host => {
const item = document.createElement("li");
item.innerHTML = host;
hostListContainer.appendChild(item);
});
});

storage.getUsernames().then(usernames => {
const usernameListContainer = dom.getUsernameList();

usernames.forEach(username => {
const item = document.createElement("li");
item.innerHTML = username;
usernameListContainer.appendChild(item);
});
});

let prevTarget = document.querySelector(".sg-popup-host");
[].forEach.call(dom.getPopupBtns(), btn => {
btn.addEventListener("change", e => {
prevTarget.classList.remove("is-on");
const target = document.querySelector(e.target.dataset.target);
target.classList.add("is-on");
prevTarget = target;
});
});
dom.getHostSaveBtn().addEventListener("click", saveHost);
dom.getHostResetBtn().addEventListener("click", storage.resetHosts.bind(storage));
dom.getUsernameSaveBtn().addEventListener("click", saveUsername);
dom.getUsernameResetBtn().addEventListener("click", storage.resetUsernames.bind(storage));
dom.getFooterForm().addEventListener("submit", e => {
e.preventDefault();
});

function saveHost() {
const input = dom.getFooterInput();
let newHost = input.value.trim();
// 입력 받은 host에 www. 값이 있다면 제거
newHost = newHost.replace(/^www\./, "");
if (newHost === "") {
return;
}

storage.setHosts(newHost);
}

function saveUsername() {
const username = dom.getFooterInput().value.trim();

if (username === "") {
return;
}

storage.setUsername(username);
}
24 changes: 18 additions & 6 deletions src/utils/dom.js → frontend/src/utils/dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,29 @@ export default {
getHostList() {
return document.querySelector(".sg-host-list");
},
getUsernameList() {
return document.querySelector(".sg-username-list");
},
getPopupBtns() {
return document.querySelectorAll("input[type=radio][name='sg-popup-buttons']");
},
getHostSaveBtn() {
return document.getElementById("sg-host-save");
return document.querySelector(".sg-host-save");
},
getUsernameSaveBtn() {
return document.querySelector(".sg-username-save");
},
getHostResetBtn() {
return document.getElementById("sg-host-reset");
return document.querySelector(".sg-host-reset");
},
getUsernameResetBtn() {
return document.querySelector(".sg-username-reset");
},
getHostInput() {
return document.getElementById("sg-host-input");
getFooterInput() {
return document.querySelector(".is-on .sg-footer-input");
},
getHostForm() {
return document.getElementById("sg-host-form");
getFooterForm() {
return document.querySelector(".is-on .sg-footer-form");
},
removeResetTemplateBtns() {
const bottomArea = this.getIssueBottomArea();
Expand Down
File renamed without changes.
19 changes: 19 additions & 0 deletions frontend/src/utils/firebase.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {FIREBASE} from "../consts";
import * as firebase from "firebase/app";
import "firebase/database";

const config = {
apiKey: "AIzaSyD7maFJ1fc_lGPQev9Jiyse53AgtCybpJg",
authDomain: "smart-github.firebaseapp.com",
databaseURL: "https://smart-github.firebaseio.com",
projectId: "smart-github",
storageBucket: "smart-github.appspot.com",
messagingSenderId: FIREBASE.SERVER_ID
};
firebase.initializeApp(config);
const database = firebase.database();

export {
firebase,
database
};
4 changes: 3 additions & 1 deletion src/utils/index.js → frontend/src/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import fetcher from "./fetcher";
import storage from "./storage";
import urlManager from "./urlManager";
import dom from "./dom";
import firebase from "./firebase";

export {
fetcher,
storage,
urlManager,
dom
dom,
firebase
};
Loading