-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #18 from paywteam/feature/notifier
Complete implementation for fragment notifier
- Loading branch information
Showing
9 changed files
with
196 additions
and
7 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import nodeMailer, { Transporter } from 'nodemailer' | ||
import LogHelper from '@/modules/LogHelper' | ||
|
||
export default class Mailer { | ||
private static _instance: Mailer | ||
|
||
/** | ||
* Mail transporter | ||
*/ | ||
private readonly transporter: Transporter | ||
|
||
/** | ||
* Get singleton instance | ||
* | ||
* @constructor | ||
*/ | ||
public static get Instance(): Mailer { | ||
if (this._instance === undefined) { | ||
this._instance = new this() | ||
} | ||
|
||
return this._instance | ||
} | ||
|
||
/** | ||
* Private constructor for singleton pattern | ||
*/ | ||
// eslint-disable-next-line no-useless-constructor | ||
private constructor() { | ||
this.transporter = nodeMailer.createTransport({ | ||
service: process.env.MAIL_SERVICE, | ||
host: process.env.MAIL_HOST, | ||
port: parseInt(process.env.MAIL_PORT, 10), | ||
secure: true, | ||
auth: { | ||
user: process.env.MAIL_USERNAME, | ||
pass: process.env.MAIL_PASSWORD | ||
} | ||
}) | ||
} | ||
|
||
public sendMail(mailOptions: object): void { | ||
this.transporter.sendMail(mailOptions, err => { | ||
if (err) { | ||
LogHelper.Instance.log('error', 'Mailer error: ' + err.stack) | ||
} | ||
}) | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,6 @@ | ||
import BrowserHandler from '@/modules/BrowserHandler' | ||
import { UserDoc } from '@@/migrate/schemas/user' | ||
import Mailer from '@/modules/Mailer' | ||
|
||
interface Selector { | ||
name: string | ||
|
@@ -8,9 +10,16 @@ interface Selector { | |
export default class FragmentNotifier { | ||
private static readonly VIEWPORT = { width: 1280, height: 800 } | ||
|
||
// public notify(): void {} | ||
public async notify( | ||
user: UserDoc, | ||
url: string, | ||
selector: Selector | ||
): Promise<void> { | ||
const captureImg = await this.capture(url, selector) | ||
this.sendCaptureToUser(user, url, captureImg) | ||
} | ||
|
||
public async capture(url: string, selector: Selector): Promise<string> { | ||
private async capture(url: string, selector: Selector): Promise<string> { | ||
const page = await BrowserHandler.Instance.browser.newPage() | ||
await page.setViewport(FragmentNotifier.VIEWPORT) | ||
await page.goto(url, { waitUntil: 'networkidle2' }) | ||
|
@@ -20,7 +29,7 @@ export default class FragmentNotifier { | |
return null | ||
} | ||
|
||
const capture = element.screenshot({ | ||
const capture = await element.screenshot({ | ||
encoding: 'base64' | ||
}) | ||
|
||
|
@@ -29,5 +38,20 @@ export default class FragmentNotifier { | |
return capture | ||
} | ||
|
||
// public sendCaptureToUser(): void {} | ||
private sendCaptureToUser(user: UserDoc, url: string, capture: string): void { | ||
Mailer.Instance.sendMail({ | ||
from: '"webglue notifier" <[email protected]>', | ||
to: user.email, | ||
subject: 'webglue fragment 변화 알림', | ||
html: `<a href="${url}"><img src="cid:[email protected]" /></a>`, | ||
attachments: [ | ||
{ | ||
filename: 'fragment.png', | ||
content: capture, | ||
encoding: 'base64', | ||
cid: '[email protected]' // same cid value as in the html img src | ||
} | ||
] | ||
}) | ||
} | ||
} |
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import FragmentWatcher from '@/modules/webglue-api/FragmentWatcher' | ||
import FragmentNotifier from '@/modules/webglue-api/FragmentNotifier' | ||
import { UserDoc } from '@@/migrate/schemas/user' | ||
|
||
export default class EventServiceProvider { | ||
public static boot(): void { | ||
this.registerFragmentEvent() | ||
} | ||
|
||
private static registerFragmentEvent(): void { | ||
FragmentWatcher.Instance.on( | ||
FragmentWatcher.CHANGE_EVENT, | ||
( | ||
user: UserDoc, | ||
url: string, | ||
selector: { name: string; offset: number } | ||
) => { | ||
const notifier = new FragmentNotifier() | ||
notifier.notify(user, url, selector).then() | ||
} | ||
) | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import schedule from 'node-schedule' | ||
import FragmentWatcher from '@/modules/webglue-api/FragmentWatcher' | ||
|
||
export default class ScheduleServiceProvider { | ||
public static boot(): void { | ||
this.scheduleWatcher() | ||
} | ||
|
||
private static scheduleWatcher(): void { | ||
// watch fragment every 5 minutes | ||
schedule.scheduleJob('*/5 * * * *', () => { | ||
FragmentWatcher.Instance.watch().then() | ||
}) | ||
} | ||
} |
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -190,11 +190,25 @@ | |
dependencies: | ||
"@types/node" "*" | ||
|
||
"@types/node-schedule@^1.2.4": | ||
version "1.2.4" | ||
resolved "https://registry.yarnpkg.com/@types/node-schedule/-/node-schedule-1.2.4.tgz#2dce38dd7d87e77cd293113ac72f795fb9f6dfe0" | ||
integrity sha512-s8ie8rUwAtX0Si75SiKH14akE/Ofw/Hx4Exbulv4wOQJEDerI7zeOaDODr/a1UEaHN19VkmZCt9Q0rFEKrVE5g== | ||
dependencies: | ||
"@types/node" "*" | ||
|
||
"@types/node@*": | ||
version "12.12.12" | ||
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.12.tgz#529bc3e73dbb35dd9e90b0a1c83606a9d3264bdb" | ||
integrity sha512-MGuvYJrPU0HUwqF7LqvIj50RZUX23Z+m583KBygKYUZLlZ88n6w28XRNJRJgsHukLEnLz6w6SvxZoLgbr5wLqQ== | ||
|
||
"@types/nodemailer@^6.2.2": | ||
version "6.2.2" | ||
resolved "https://registry.yarnpkg.com/@types/nodemailer/-/nodemailer-6.2.2.tgz#08df85c22546e9f3f3c86e5635571c5229ab43a3" | ||
integrity sha512-vDbSSe3+bBXYgibKs8duOrH7bhAv1hMHl3Vtdr3KmXZWLfi5WtIg3X6D/+K4SMK1RbNlm5QZBQCOldST/sVjjg== | ||
dependencies: | ||
"@types/node" "*" | ||
|
||
"@types/oauth@*": | ||
version "0.9.1" | ||
resolved "https://registry.yarnpkg.com/@types/oauth/-/oauth-0.9.1.tgz#e17221e7f7936b0459ae7d006255dff61adca305" | ||
|
@@ -742,6 +756,14 @@ cors@^2.8.5: | |
object-assign "^4" | ||
vary "^1" | ||
|
||
cron-parser@^2.7.3: | ||
version "2.13.0" | ||
resolved "https://registry.yarnpkg.com/cron-parser/-/cron-parser-2.13.0.tgz#6f930bb6f2931790d2a9eec83b3ec276e27a6725" | ||
integrity sha512-UWeIpnRb0eyoWPVk+pD3TDpNx3KCFQeezO224oJIkktBrcW6RoAPOx5zIKprZGfk6vcYSmA8yQXItejSaDBhbQ== | ||
dependencies: | ||
is-nan "^1.2.1" | ||
moment-timezone "^0.5.25" | ||
|
||
cross-spawn@^6.0.5: | ||
version "6.0.5" | ||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" | ||
|
@@ -824,7 +846,7 @@ deep-is@~0.1.3: | |
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" | ||
integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= | ||
|
||
define-properties@^1.1.2, define-properties@^1.1.3: | ||
define-properties@^1.1.1, define-properties@^1.1.2, define-properties@^1.1.3: | ||
version "1.1.3" | ||
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" | ||
integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== | ||
|
@@ -1758,6 +1780,13 @@ is-glob@^4.0.0, is-glob@^4.0.1: | |
dependencies: | ||
is-extglob "^2.1.1" | ||
|
||
is-nan@^1.2.1: | ||
version "1.2.1" | ||
resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.2.1.tgz#9faf65b6fb6db24b7f5c0628475ea71f988401e2" | ||
integrity sha1-n69ltvttskt/XAYoR16nH5iEAeI= | ||
dependencies: | ||
define-properties "^1.1.1" | ||
|
||
is-promise@^2.1.0: | ||
version "2.1.0" | ||
resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" | ||
|
@@ -1960,6 +1989,11 @@ logform@^2.1.1: | |
ms "^2.1.1" | ||
triple-beam "^1.3.0" | ||
|
||
[email protected]: | ||
version "0.1.1" | ||
resolved "https://registry.yarnpkg.com/long-timeout/-/long-timeout-0.1.1.tgz#9721d788b47e0bcb5a24c2e2bee1a0da55dab514" | ||
integrity sha1-lyHXiLR+C8taJMLivuGg2lXatRQ= | ||
|
||
lru-cache@^5.1.1: | ||
version "5.1.1" | ||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" | ||
|
@@ -2048,7 +2082,14 @@ module-alias@^2.2.2: | |
resolved "https://registry.yarnpkg.com/module-alias/-/module-alias-2.2.2.tgz#151cdcecc24e25739ff0aa6e51e1c5716974c0e0" | ||
integrity sha512-A/78XjoX2EmNvppVWEhM2oGk3x4lLxnkEA4jTbaK97QKSDjkIoOsKQlfylt/d3kKKi596Qy3NP5XrXJ6fZIC9Q== | ||
|
||
moment@^2.24.0: | ||
moment-timezone@^0.5.25: | ||
version "0.5.27" | ||
resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.27.tgz#73adec8139b6fe30452e78f210f27b1f346b8877" | ||
integrity sha512-EIKQs7h5sAsjhPCqN6ggx6cEbs94GK050254TIJySD1bzoM5JTYDwAU1IoVOeTOL6Gm27kYJ51/uuvq1kIlrbw== | ||
dependencies: | ||
moment ">= 2.9.0" | ||
|
||
"moment@>= 2.9.0", moment@^2.24.0: | ||
version "2.24.0" | ||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" | ||
integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg== | ||
|
@@ -2147,6 +2188,20 @@ [email protected]: | |
resolved "https://registry.yarnpkg.com/nocache/-/nocache-2.1.0.tgz#120c9ffec43b5729b1d5de88cd71aa75a0ba491f" | ||
integrity sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q== | ||
|
||
node-schedule@^1.3.2: | ||
version "1.3.2" | ||
resolved "https://registry.yarnpkg.com/node-schedule/-/node-schedule-1.3.2.tgz#d774b383e2a6f6ade59eecc62254aea07cd758cb" | ||
integrity sha512-GIND2pHMHiReSZSvS6dpZcDH7pGPGFfWBIEud6S00Q8zEIzAs9ommdyRK1ZbQt8y1LyZsJYZgPnyi7gpU2lcdw== | ||
dependencies: | ||
cron-parser "^2.7.3" | ||
long-timeout "0.1.1" | ||
sorted-array-functions "^1.0.0" | ||
|
||
nodemailer@^6.3.1: | ||
version "6.3.1" | ||
resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.3.1.tgz#2784beebac6b9f014c424c54dbdcc5c4d1221346" | ||
integrity sha512-j0BsSyaMlyadEDEypK/F+xlne2K5m6wzPYMXS/yxKI0s7jmT1kBx6GEKRVbZmyYfKOsjkeC/TiMVDJBI/w5gMQ== | ||
|
||
normalize-package-data@^2.3.2: | ||
version "2.5.0" | ||
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" | ||
|
@@ -2777,6 +2832,11 @@ [email protected]: | |
resolved "https://registry.yarnpkg.com/sliced/-/sliced-1.0.1.tgz#0b3a662b5d04c3177b1926bea82b03f837a2ef41" | ||
integrity sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E= | ||
|
||
sorted-array-functions@^1.0.0: | ||
version "1.2.0" | ||
resolved "https://registry.yarnpkg.com/sorted-array-functions/-/sorted-array-functions-1.2.0.tgz#43265b21d6e985b7df31621b1c11cc68d8efc7c3" | ||
integrity sha512-sWpjPhIZJtqO77GN+LD8dDsDKcWZ9GCOJNqKzi1tvtjGIzwfoyuRH8S0psunmc6Z5P+qfDqztSbwYR5X/e1UTg== | ||
|
||
source-map-support@^0.5.6: | ||
version "0.5.16" | ||
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042" | ||
|