├── .altax ├── .gitignore ├── composer.json └── config.php ├── .gitignore ├── dev ├── locale │ └── en.yml ├── js │ └── admin │ │ ├── Gulpfile.js │ │ ├── package.json │ │ ├── src │ │ ├── main.js │ │ ├── addNotifySettingsPage.js │ │ └── components │ │ │ ├── GitterSettingsModal.js │ │ │ ├── SlackSettingsModal.js │ │ │ ├── HipChatSettingsModal.js │ │ │ ├── TestConnectorsModal.js │ │ │ └── NotifySettingsPage.js │ │ └── dist │ │ └── extension.js ├── src │ ├── Interfaces │ │ └── ConnectorInterface.php │ ├── Connectors │ │ ├── Connector.php │ │ ├── HipChatConnector.php │ │ ├── GitterConnector.php │ │ └── SlackConnector.php │ ├── ApiRoutes.php │ ├── Messages │ │ ├── DiscussionWasDeletedMessage.php │ │ ├── PostWasPostedMessage.php │ │ ├── DiscussionWasStartedMessage.php │ │ ├── PostWasDeletedMessage.php │ │ ├── PostWasHiddenMessage.php │ │ └── Message.php │ ├── Extension.php │ ├── Listeners │ │ ├── AddClientAssets.php │ │ ├── PostWasHiddenListener.php │ │ ├── PostWasPostedListener.php │ │ ├── DiscussionWasDeletedListener.php │ │ ├── DiscussionWasStartedListener.php │ │ ├── PostWasDeletedListener.php │ │ └── NotificationListener.php │ └── Api │ │ └── ConnectorTest.php ├── composer.json ├── bootstrap.php ├── flarum.json └── less │ └── admin │ └── extension.less ├── dist └── flarum-notify.zip ├── composer.json ├── readme.md └── LICENSE /.altax/.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | node_modules -------------------------------------------------------------------------------- /dev/locale/en.yml: -------------------------------------------------------------------------------- 1 | slack: 2 | # hello_world: "Hello, world!" 3 | -------------------------------------------------------------------------------- /dist/flarum-notify.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moay/flarum-notify/HEAD/dist/flarum-notify.zip -------------------------------------------------------------------------------- /.altax/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": { 3 | "alchemy/zippy": "^0.2.1", 4 | "windwalker/filesystem": "^2.1" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /dev/js/admin/Gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('flarum-gulp'); 2 | 3 | gulp({ 4 | modules: { 5 | 'notify': 'src/**/*.js' 6 | } 7 | }); 8 | -------------------------------------------------------------------------------- /dev/js/admin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "devDependencies": { 4 | "gulp": "^3.8.11", 5 | "flarum-gulp": "^0.1.0" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /dev/js/admin/src/main.js: -------------------------------------------------------------------------------- 1 | import addNotifySettingsPage from 'notify/addNotifySettingsPage'; 2 | 3 | app.initializers.add('notify', app => { 4 | addNotifySettingsPage(); 5 | }); 6 | -------------------------------------------------------------------------------- /dev/src/Interfaces/ConnectorInterface.php: -------------------------------------------------------------------------------- 1 | settings = $settings; 9 | $this->setup(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "root/flarum-notify", 3 | "description": "Get notified about forum activity via Slack, Hipchat or Gitter.", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "name": "moay", 8 | "email": "mv@moay.de" 9 | } 10 | ], 11 | "require": {} 12 | } 13 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # flarum-slack 2 | 3 | Simple notifications for Flarum. Get notified about forum activities via Slack, HipChat or Gitter. 4 | 5 | ## DEPRECATED 6 | 7 | Sadly, I didn't find the time to update the repo for newer flarum versions. But manelizzard continued the work, please use [his repo](https://github.com/manelizzard/flarum-notify). 8 | -------------------------------------------------------------------------------- /dev/bootstrap.php: -------------------------------------------------------------------------------- 1 | 0.1.0-beta.2" 15 | }, 16 | "icon": { 17 | "name": "bell", 18 | "backgroundColor": "#640049", 19 | "color": "#fff" 20 | } 21 | } -------------------------------------------------------------------------------- /dev/src/ApiRoutes.php: -------------------------------------------------------------------------------- 1 | listen(RegisterApiRoutes::class, [$this, 'addRoutes']); 10 | } 11 | 12 | /** 13 | * Registeres the api routes for the extension 14 | * @param RegisterApiRoutes $event 15 | */ 16 | public function addRoutes(RegisterApiRoutes $event) 17 | { 18 | $event->get('/notify/test/{connector}', 'notify.test', 'moay\FlarumNotify\Api\ConnectorTest'); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /dev/less/admin/extension.less: -------------------------------------------------------------------------------- 1 | .NotifySettingsTable{ 2 | td{ 3 | padding:5px; 4 | 5 | &:first-child{ 6 | padding-right:20px; 7 | font-weight:700; 8 | } 9 | } 10 | } 11 | .NotifySettingsButton.rounded{ 12 | border-radius:100px; 13 | height:30px; 14 | width:30px; 15 | position:relative; 16 | 17 | .icon{ 18 | margin-left:-7px; 19 | margin-top:-1px; 20 | display:block; 21 | } 22 | 23 | &.texty{ 24 | width:auto; 25 | margin-left:5px; 26 | padding-top:5px; 27 | } 28 | } 29 | 30 | .TestConnectorsModal{ 31 | .statusMessage{ 32 | width:100%; 33 | text-align: center; 34 | font-size:16px; 35 | } 36 | } -------------------------------------------------------------------------------- /dev/src/Messages/DiscussionWasDeletedMessage.php: -------------------------------------------------------------------------------- 1 | discussion = $discussion; 9 | $this->prepareMessage(); 10 | } 11 | 12 | /** 13 | * Prepares the message which should be sent to the Connectors 14 | * @return void 15 | */ 16 | function prepareMessage(){ 17 | $this->title = 'Discussion deleted'; 18 | $this->message = 'Discussion #' . $this->discussion->id . ' ('.$this->discussion->title.') has been deleted'; 19 | $this->short = 'Discussion deleted'; 20 | $this->color = 'red'; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /dev/js/admin/src/addNotifySettingsPage.js: -------------------------------------------------------------------------------- 1 | import { extend } from 'flarum/extend'; 2 | import AdminNav from 'flarum/components/AdminNav'; 3 | import AdminLinkButton from 'flarum/components/AdminLinkButton'; 4 | 5 | import NotifySettingsPage from 'notify/components/NotifySettingsPage'; 6 | 7 | export default function() { 8 | 9 | app.routes.notify = {path: '/notify', component: NotifySettingsPage.component()}; 10 | 11 | app.extensionSettings.notify = () => m.route(app.route('notify')); 12 | 13 | extend(AdminNav.prototype, 'items', items => { 14 | items.add('notify', AdminLinkButton.component({ 15 | href: app.route('notify'), 16 | icon: 'bell', 17 | children: 'Notify', 18 | description: 'Manage your notifications to Slack, Hipchat and Gitter.' 19 | })); 20 | }); 21 | } 22 | -------------------------------------------------------------------------------- /dev/src/Extension.php: -------------------------------------------------------------------------------- 1 | subscribe('moay\FlarumNotify\Listeners\AddClientAssets'); 11 | $events->subscribe('moay\FlarumNotify\Listeners\PostWasPostedListener'); 12 | $events->subscribe('moay\FlarumNotify\Listeners\PostWasHiddenListener'); 13 | $events->subscribe('moay\FlarumNotify\Listeners\PostWasDeletedListener'); 14 | $events->subscribe('moay\FlarumNotify\Listeners\DiscussionWasStartedListener'); 15 | $events->subscribe('moay\FlarumNotify\Listeners\DiscussionWasDeletedListener'); 16 | 17 | // Add API routes 18 | $events->subscribe('moay\FlarumNotify\ApiRoutes'); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /dev/src/Messages/PostWasPostedMessage.php: -------------------------------------------------------------------------------- 1 | post = $post; 9 | $this->prepareMessage(); 10 | } 11 | 12 | 13 | /** 14 | * Prepares the message which should be sent to the Connectors 15 | * @return void 16 | */ 17 | function prepareMessage(){ 18 | $this->author = $this->post->user; 19 | $this->message = 'added a new post to discussion #' . $this->post->discussion->id . ' ('.$this->post->discussion->title.')'; 20 | $this->short = 'New post'; 21 | 22 | $this->addLinkToParse('@'.$this->author->username, app('flarum.config')['url']."/u/{$this->author->id}"); 23 | $this->addLinkToParse('discussion #'.$this->post->discussion->id, app('flarum.config')['url']."/d/{$this->post->discussion->id}"); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /dev/src/Messages/DiscussionWasStartedMessage.php: -------------------------------------------------------------------------------- 1 | discussion = $discussion; 9 | $this->prepareMessage(); 10 | } 11 | 12 | 13 | /** 14 | * Prepares the message which should be sent to the Connectors 15 | * @return void 16 | */ 17 | function prepareMessage(){ 18 | $this->author = $this->discussion->startUser; 19 | $this->message = 'started discussion #' . $this->discussion->id . ' ('.$this->discussion->title.')'; 20 | $this->short = 'New post'; 21 | $this->color = 'green'; 22 | 23 | $this->addLinkToParse('@'.$this->author->username, app('flarum.config')['url']."/u/{$this->author->id}"); 24 | $this->addLinkToParse('discussion #'.$this->discussion->id, app('flarum.config')['url']."/d/{$this->discussion->id}"); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /dev/src/Messages/PostWasDeletedMessage.php: -------------------------------------------------------------------------------- 1 | post = $post; 9 | $this->prepareMessage(); 10 | } 11 | 12 | 13 | /** 14 | * Prepares the message which should be sent to the Connectors 15 | * @return void 16 | */ 17 | function prepareMessage(){ 18 | $this->title = 'Post deleted'; 19 | $this->message = '@'.$this->post->user->username.'\'s post was deleted from discussion #' . $this->post->discussion->id . ' ('.$this->post->discussion->title.')'; 20 | $this->short = 'Post deleted'; 21 | $this->color = 'red'; 22 | 23 | $this->addLinkToParse('@'.$this->post->user->username, app('flarum.config')['url']."/u/{$this->post->user->id}"); 24 | $this->addLinkToParse('discussion #'.$this->post->discussion->id, app('flarum.config')['url']."/d/{$this->post->discussion->id}"); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /dev/src/Messages/PostWasHiddenMessage.php: -------------------------------------------------------------------------------- 1 | post = $post; 9 | $this->prepareMessage(); 10 | } 11 | 12 | 13 | /** 14 | * Prepares the message which should be sent to the Connectors 15 | * @return void 16 | */ 17 | function prepareMessage(){ 18 | $this->title = 'Post hidden'; 19 | $this->message = '@'.$this->post->user->username.'\'s post was hidden from discussion #' . $this->post->discussion->id . ' ('.$this->post->discussion->title.')'; 20 | $this->short = 'Post hidden'; 21 | $this->color = 'orange'; 22 | 23 | $this->addLinkToParse('@'.$this->post->user->username, app('flarum.config')['url']."/u/{$this->post->user->id}"); 24 | $this->addLinkToParse('discussion #'.$this->post->discussion->id, app('flarum.config')['url']."/d/{$this->post->discussion->id}"); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /dev/src/Listeners/AddClientAssets.php: -------------------------------------------------------------------------------- 1 | listen(RegisterLocales::class, [$this, 'addLocale']); 12 | $events->listen(BuildClientView::class, [$this, 'addAssets']); 13 | } 14 | 15 | public function addLocale(RegisterLocales $event) 16 | { 17 | $event->addTranslations('en', __DIR__.'/../../locale/en.yml'); 18 | } 19 | 20 | public function addAssets(BuildClientView $event) 21 | { 22 | $event->adminAssets([ 23 | __DIR__.'/../../js/admin/dist/extension.js', 24 | __DIR__.'/../../less/admin/extension.less' 25 | ]); 26 | 27 | $event->adminBootstrapper('notify/main'); 28 | 29 | $event->adminTranslations([ 30 | // 'slack.hello_world' 31 | ]); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /dev/src/Messages/Message.php: -------------------------------------------------------------------------------- 1 | linksToParse[$string] = $url; 19 | } 20 | 21 | public function getAuthor(){ 22 | return $this->author; 23 | } 24 | 25 | public function getMessage(){ 26 | return $this->message; 27 | } 28 | 29 | public function getShort(){ 30 | return $this->short; 31 | } 32 | 33 | public function getTitle(){ 34 | return $this->title; 35 | } 36 | 37 | public function getColor(){ 38 | return $this->color; 39 | } 40 | 41 | public function getLinksToParse(){ 42 | return $this->linksToParse; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 moay 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /dev/src/Listeners/PostWasHiddenListener.php: -------------------------------------------------------------------------------- 1 | listen(PostWasHidden::class, [$this, 'sendMessage']); 13 | } 14 | 15 | /** 16 | * Sends a message via all of the enable connectors 17 | * @param PostWasHidden $event 18 | * @return void 19 | */ 20 | public function sendMessage(PostWasHidden $event) 21 | { 22 | if($this->shouldTrigger($event)){ 23 | $message = new PostWasHiddenMessage($event->post); 24 | 25 | foreach($this->getConnectorsToNotify() as $connector){ 26 | $connector->send($message); 27 | } 28 | } 29 | } 30 | 31 | /** 32 | * Checks wether or not this listener should send a notification for this event 33 | * @param PostWasHidden $event 34 | * @return boolean 35 | */ 36 | public function shouldTrigger(PostWasHidden $event){ 37 | if($this->settings->get('notify.events.post_hidden') === '1'){ 38 | return true; 39 | } 40 | return false; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /dev/src/Listeners/PostWasPostedListener.php: -------------------------------------------------------------------------------- 1 | listen(PostWasPosted::class, [$this, 'sendMessage']); 13 | } 14 | 15 | /** 16 | * Sends a message via all of the enable connectors 17 | * @param PostWasPosted $event 18 | * @return void 19 | */ 20 | public function sendMessage(PostWasPosted $event) 21 | { 22 | if($this->shouldTrigger($event)){ 23 | $message = new PostWasPostedMessage($event->post); 24 | 25 | foreach($this->getConnectorsToNotify() as $connector){ 26 | $connector->send($message); 27 | } 28 | } 29 | } 30 | 31 | /** 32 | * Checks wether or not this listener should send a notification for this event 33 | * @param PostWasPosted $event 34 | * @return boolean 35 | */ 36 | public function shouldTrigger(PostWasPosted $event){ 37 | if($this->settings->get('notify.events.new_post') === '1' 38 | && $event->post->discussion->posts()->count() > 1){ 39 | return true; 40 | } 41 | return false; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /dev/src/Listeners/DiscussionWasDeletedListener.php: -------------------------------------------------------------------------------- 1 | listen(DiscussionWasDeleted::class, [$this, 'sendMessage']); 13 | } 14 | 15 | /** 16 | * Sends a message via all of the enable connectors 17 | * @param PostWasPosted $event 18 | * @return void 19 | */ 20 | public function sendMessage(DiscussionWasDeleted $event) 21 | { 22 | if($this->shouldTrigger($event)){ 23 | $message = new DiscussionWasDeletedMessage($event->discussion); 24 | 25 | foreach($this->getConnectorsToNotify() as $connector){ 26 | $connector->send($message); 27 | } 28 | } 29 | } 30 | 31 | /** 32 | * Checks wether or not this listener should send a notification for this event 33 | * @param DiscussionWasDeleted $event 34 | * @return boolean 35 | */ 36 | public function shouldTrigger(DiscussionWasDeleted $event){ 37 | if($this->settings->get('notify.events.discussion_deleted') === '1'){ 38 | return true; 39 | } 40 | return false; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /dev/src/Listeners/DiscussionWasStartedListener.php: -------------------------------------------------------------------------------- 1 | listen(DiscussionWasStarted::class, [$this, 'sendMessage']); 13 | } 14 | 15 | /** 16 | * Sends a message via all of the enable connectors 17 | * @param PostWasPosted $event 18 | * @return void 19 | */ 20 | public function sendMessage(DiscussionWasStarted $event) 21 | { 22 | if($this->shouldTrigger($event)){ 23 | $message = new DiscussionWasStartedMessage($event->discussion); 24 | 25 | foreach($this->getConnectorsToNotify() as $connector){ 26 | $connector->send($message); 27 | } 28 | } 29 | } 30 | 31 | /** 32 | * Checks wether or not this listener should send a notification for this event 33 | * @param DiscussionWasStarted $event 34 | * @return boolean 35 | */ 36 | public function shouldTrigger(DiscussionWasStarted $event){ 37 | if($this->settings->get('notify.events.new_discussion') === '1'){ 38 | return true; 39 | } 40 | return false; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /dev/src/Listeners/PostWasDeletedListener.php: -------------------------------------------------------------------------------- 1 | listen(PostWasDeleted::class, [$this, 'sendMessage']); 13 | } 14 | 15 | /** 16 | * Sends a message via all of the enable connectors 17 | * @param PostWasDeleted $event 18 | * @return void 19 | */ 20 | public function sendMessage(PostWasDeleted $event) 21 | { 22 | if($this->shouldTrigger($event)){ 23 | $message = new PostWasDeletedMessage($event->post); 24 | 25 | foreach($this->getConnectorsToNotify() as $connector){ 26 | $connector->send($message); 27 | } 28 | } 29 | } 30 | 31 | /** 32 | * Checks wether or not this listener should send a notification for this event 33 | * @param PostWasDeleted $event 34 | * @return boolean 35 | */ 36 | public function shouldTrigger(PostWasDeleted $event){ 37 | if($this->settings->get('notify.events.post_deleted') === '1' 38 | && $event->post->discussion 39 | && $event->post->discussion->posts()->count() != 0){ 40 | return true; 41 | } 42 | return false; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /dev/src/Listeners/NotificationListener.php: -------------------------------------------------------------------------------- 1 | settings = $settings; 15 | new HipChatConnector($this->settings); 16 | } 17 | 18 | /** 19 | * Returns all connectors that need to be notified 20 | * @return array The connectors 21 | */ 22 | protected function getConnectorsToNotify(){ 23 | $connectors = []; 24 | // Check for slack 25 | if($this->settings->get('notify.services.slack') && $this->settings->get('notify.slack.token') && $this->settings->get('notify.slack.channel')){ 26 | $connectors[] = new SlackConnector($this->settings); 27 | } 28 | // Check for HipChat 29 | if($this->settings->get('notify.services.hipchat') && $this->settings->get('notify.hipchat.token') && $this->settings->get('notify.hipchat.room')){ 30 | $connectors[] = new HipChatConnector($this->settings); 31 | } 32 | // Check for Gitter 33 | if($this->settings->get('notify.services.gitter') && $this->settings->get('notify.gitter.webhook')){ 34 | $connectors[] = new GitterConnector($this->settings); 35 | } 36 | return $connectors; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /dev/src/Api/ConnectorTest.php: -------------------------------------------------------------------------------- 1 | settings = $settings; 23 | $this->bus = $bus; 24 | } 25 | 26 | /** 27 | * Handles the incoming api request and serves it with a Connector test if possible 28 | * @param $request 29 | * @return JsonResponse 30 | */ 31 | public function handle($request){ 32 | switch($request->input['connector']){ 33 | case 'slack': 34 | case 'Slack': 35 | $slackInstance = new SlackConnector($this->settings); 36 | $return = ['success'=> $slackInstance->works()]; 37 | break; 38 | case 'hipchat': 39 | case 'HipChat': 40 | $hipChatInstance = new HipChatConnector($this->settings); 41 | $return = ['success'=> $hipChatInstance->works()]; 42 | break; 43 | case 'gitter': 44 | case 'Gitter': 45 | $gitterInstance = new GitterConnector($this->settings); 46 | $return = ['success'=> $gitterInstance->works()]; 47 | break; 48 | default: 49 | $return = ['success'=>false, 'msg'=>'unknown']; 50 | } 51 | return new JsonResponse($return); 52 | } 53 | 54 | } -------------------------------------------------------------------------------- /dev/js/admin/src/components/GitterSettingsModal.js: -------------------------------------------------------------------------------- 1 | import Modal from 'flarum/components/Modal'; 2 | import Button from 'flarum/components/Button'; 3 | import saveConfig from 'flarum/utils/saveConfig'; 4 | 5 | export default class GitterSettingsModal extends Modal { 6 | constructor(...args) { 7 | super(...args); 8 | 9 | this.webhook = m.prop(app.config['notify.gitter.webhook'] || ''); 10 | } 11 | 12 | className() { 13 | return 'GitterSettingsModal Modal--small'; 14 | } 15 | 16 | title() { 17 | return 'Gitter settings'; 18 | } 19 | 20 | content() { 21 | return ( 22 |
23 |
24 |
25 | 26 | 27 |
28 | 29 |

In order to get your webhook url, visit the room you want to post to on gitter.im. Click on the Settings icon > Integrations > Custom. This will create a new webhook url for you.

30 | 31 |
32 | 33 |
34 | {Button.component({ 35 | type: 'submit', 36 | className: 'Button Button--primary GitterSettingsModal-save', 37 | loading: this.loading, 38 | children: 'Save Changes' 39 | })} 40 |
41 |
42 |
43 | ); 44 | } 45 | 46 | onsubmit(e) { 47 | e.preventDefault(); 48 | 49 | this.loading = true; 50 | 51 | saveConfig({ 52 | 'notify.gitter.webhook': this.webhook() 53 | }).then( 54 | () => this.hide(), 55 | () => { 56 | this.loading = false; 57 | m.redraw(); 58 | } 59 | ); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /dev/js/admin/src/components/SlackSettingsModal.js: -------------------------------------------------------------------------------- 1 | import Modal from 'flarum/components/Modal'; 2 | import Button from 'flarum/components/Button'; 3 | import saveConfig from 'flarum/utils/saveConfig'; 4 | import Alert from 'flarum/components/Alert'; 5 | 6 | export default class SlackSettingsModal extends Modal { 7 | constructor(...args) { 8 | super(...args); 9 | 10 | this.token = m.prop(app.config['notify.slack.token'] || ''); 11 | this.channel = m.prop(app.config['notify.slack.channel'] || '#general'); 12 | } 13 | 14 | className() { 15 | return 'SlackSettingsModal Modal--small'; 16 | } 17 | 18 | title() { 19 | return 'Slack settings'; 20 | } 21 | 22 | content() { 23 | return ( 24 |
25 |
26 |
27 | 28 | 29 |
30 | 31 |
32 | 33 | 34 |
35 | 36 |

In order to obtain the token, visit api.slack.com/web.

37 | 38 |
39 | 40 |
41 | {Button.component({ 42 | type: 'submit', 43 | className: 'Button Button--primary SlackSettingsModal-save', 44 | loading: this.loading, 45 | children: 'Save Changes' 46 | })} 47 |
48 |
49 |
50 | ); 51 | } 52 | onsubmit(e) { 53 | e.preventDefault(); 54 | 55 | this.loading = true; 56 | app.alerts.dismiss(this.testResultAlert); 57 | 58 | saveConfig({ 59 | 'notify.slack.token': this.token(), 60 | 'notify.slack.channel': this.channel() 61 | }).then( 62 | () => this.hide(), 63 | () => { 64 | this.loading = false; 65 | m.redraw(); 66 | } 67 | ); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /dev/js/admin/src/components/HipChatSettingsModal.js: -------------------------------------------------------------------------------- 1 | import Modal from 'flarum/components/Modal'; 2 | import Button from 'flarum/components/Button'; 3 | import saveConfig from 'flarum/utils/saveConfig'; 4 | import Alert from 'flarum/components/Alert'; 5 | 6 | export default class HipChatSettingsModal extends Modal { 7 | constructor(...args) { 8 | super(...args); 9 | 10 | this.token = m.prop(app.config['notify.hipchat.token'] || ''); 11 | this.room = m.prop(app.config['notify.hipchat.room'] || ''); 12 | } 13 | 14 | className() { 15 | return 'HipChatSettingsModal Modal--small'; 16 | } 17 | 18 | title() { 19 | return 'HipChat settings'; 20 | } 21 | 22 | content() { 23 | return ( 24 |
25 |
26 |
27 | 28 | 29 |
30 | 31 |
32 | 33 | 34 |
35 | 36 |

To obtain the token, visit your the room settings over at hipchat.com (Login, click on `rooms` and select your the room you want to post to). Click on `Tokens` and create a new one. The label you provide for the token will be shown with each notification.

37 |

Notify does not work with self-hosted HipChat.

38 | 39 |
40 | 41 |
42 | {Button.component({ 43 | type: 'submit', 44 | className: 'Button Button--primary HipChatSettingsModal-save', 45 | loading: this.loading, 46 | children: 'Save Changes' 47 | })} 48 |
49 |
50 |
51 | ); 52 | } 53 | 54 | onsubmit(e) { 55 | e.preventDefault(); 56 | this.loading = true; 57 | 58 | app.alerts.dismiss(this.testResultAlert); 59 | saveConfig({ 60 | 'notify.hipchat.token': this.token(), 61 | 'notify.hipchat.room': this.room() 62 | }).then( 63 | () => this.hide(), 64 | () => { 65 | this.loading = false; 66 | m.redraw(); 67 | } 68 | ); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /.altax/config.php: -------------------------------------------------------------------------------- 1 | writeln('Cleaning files out.'); 18 | 19 | // Prepare dist folder 20 | if(file_exists($distfolder)){ 21 | Filesystem::delete($distfolder); 22 | Folder::create($distfolder); 23 | } 24 | $task->writeln('Copying files over.'); 25 | recursiveCopy('dev', $basepath, $distfolder); 26 | 27 | $task->writeln('Running composer'); 28 | $task->exec(function($process){ 29 | $basepath = realpath(__DIR__ . '/..'); 30 | $distfolder = Path::clean($basepath . '/dist'); 31 | $distfolder = str_replace(' ', '\ ', $distfolder); 32 | $process->runLocally("cd ".$distfolder. '/dev' ." && composer install --prefer-dist --optimize-autoloader"); 33 | $process->runLocally("cd .. && cd .."); 34 | }); 35 | 36 | Folder::move($distfolder . '/dev', $distfolder . '/notify'); 37 | 38 | $task->writeln('Zipping'); 39 | 40 | $zippy = Zippy::load(); 41 | 42 | $archive = $zippy->create('flarum-notify.zip', array( 43 | 'notify' => $distfolder . '/notify' 44 | )); 45 | 46 | $task->writeln('Deleting copied folder'); 47 | 48 | Folder::delete($distfolder . '/notify'); 49 | File::move($basepath . '/flarum-notify.zip', $distfolder . '/flarum-notify.zip'); 50 | 51 | })->description("Builds a release ready package from the current project state and stores it in /dist."); 52 | 53 | function recursiveCopy($filename, $initialfolder, $targetfolder){ 54 | $badfiles = [ 55 | 'vendor', 56 | 'node_modules', 57 | '.DS_Store', 58 | 'sftp-config.json', 59 | '.git', 60 | '.gitignore', 61 | 'build.sh' 62 | ]; 63 | 64 | foreach(Folder::items($initialfolder . '/' . $filename, false, Folder::PATH_BASENAME) as $item){ 65 | if(!in_array($item, $badfiles)){ 66 | if(is_dir($initialfolder . '/' . $filename . '/' . $item)){ 67 | recursiveCopy($item, $initialfolder . '/' . $filename, $targetfolder . '/' . $filename); 68 | } 69 | else{ 70 | File::copy($initialfolder . '/' . $filename . '/' . $item, $targetfolder . '/' . $filename . '/' . $item); 71 | } 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /dev/src/Connectors/HipChatConnector.php: -------------------------------------------------------------------------------- 1 | settings->get('notify.hipchat.token')); 19 | $client = new Client($auth); 20 | $this->api = new RoomAPI($client); 21 | $this->message = new Message(); 22 | } 23 | 24 | /** 25 | * Method which actually sends a message to Gitter 26 | * @param Message $message 27 | * @return void 28 | */ 29 | public function send($message){ 30 | $color = 'gray'; 31 | if($message->getColor() !== null){ 32 | $color = $this->parseColor($message->getColor()); 33 | } 34 | 35 | $content = $message->getMessage(); 36 | 37 | if($message->getAuthor() !== null){ 38 | $content = '@'.$message->getAuthor()->username.' '. $content; 39 | } 40 | 41 | $content = $this->parseLinksInMessage($content, $message->getLinksToParse()); 42 | 43 | $this->message->setColor($color); 44 | $this->message->setNotify(true); 45 | $this->message->setMessage($content); 46 | 47 | $this->api->sendRoomNotification($this->settings->get('notify.hipchat.room'), $this->message); 48 | } 49 | 50 | /** 51 | * Checks wether the Connector works with the current settings 52 | * @return boolean 53 | */ 54 | public function works(){ 55 | $this->message->setMessage('Flarum is able to contact this HipChat room. Great!'); 56 | $this->message->setColor('green'); 57 | try{ 58 | $this->api->sendRoomNotification($this->settings->get('notify.hipchat.room'), $this->message); 59 | } catch(RequestException $e) { 60 | return false; 61 | } 62 | return true; 63 | } 64 | 65 | /** 66 | * Parses the message's color to something HipChat understands 67 | * @param string $color 68 | * @return string string that is usable for HipChat 69 | */ 70 | protected function parseColor($color){ 71 | $retcolor = 'gray'; 72 | 73 | $colors = [ 74 | 'red' => 'red', 75 | 'orange' => 'yellow', 76 | 'green' => 'green', 77 | 'blue' => 'purple', 78 | 'special' => 'purple' 79 | ]; 80 | 81 | if(isset($colors[$color])){ 82 | $retcolor = $colors[$color]; 83 | } 84 | 85 | return $retcolor; 86 | } 87 | 88 | /** 89 | * Parses all links in the message body to make them clickable 90 | * @param string $content 91 | * @param array $linksToParse string=>link array 92 | * @return string the parsed $content 93 | */ 94 | protected function parseLinksInMessage($content, $linksToParse){ 95 | foreach($linksToParse as $search=>$link){ 96 | $content = str_replace($search, ''.$search.'', $content); 97 | } 98 | return $content; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /dev/js/admin/src/components/TestConnectorsModal.js: -------------------------------------------------------------------------------- 1 | import Modal from 'flarum/components/Modal'; 2 | import Button from 'flarum/components/Button'; 3 | import LoadingIndicator from 'flarum/lib/components/LoadingIndicator'; 4 | 5 | export default class TestConnectorsModal extends Modal { 6 | constructor(...args) { 7 | super(...args); 8 | 9 | this.slack = {}; 10 | this.slack.token = m.prop(app.config['notify.slack.token'] || ''); 11 | this.slack.channel = m.prop(app.config['notify.slack.channel'] || ''); 12 | 13 | this.hipchat = {}; 14 | this.hipchat.token = m.prop(app.config['notify.hipchat.token'] || ''); 15 | this.hipchat.room = m.prop(app.config['notify.hipchat.room'] || ''); 16 | 17 | this.gitter = {}; 18 | this.gitter.webhook = m.prop(app.config['notify.gitter.webhook'] || ''); 19 | 20 | this.testStatus = m.prop('Preparing...'); 21 | 22 | this.runConnectorTest(); 23 | } 24 | 25 | className() { 26 | return 'TestConnectorsModal Modal--small'; 27 | } 28 | 29 | title() { 30 | return 'Testing your settings'; 31 | } 32 | 33 | content() { 34 | return ( 35 |
36 |
{this.testStatus()}
37 |
38 | ); 39 | } 40 | 41 | runConnectorTest(){ 42 | switch(this.props.connector){ 43 | case 'slack': 44 | this.runSlackTest(); 45 | break; 46 | case 'hipchat': 47 | this.runHipChatTest(); 48 | break; 49 | case 'gitter': 50 | this.runGitterTest(); 51 | break; 52 | } 53 | } 54 | 55 | runSlackTest(){ 56 | if(this.slack.token() === '' || this.slack.channel() === ''){ 57 | this.testStatus('Please fill in token and channel first.'); 58 | } 59 | else{ 60 | this.testStatus('Testing...'); 61 | m.request({method: "GET", url: "/api/notify/test/slack"}) 62 | .then((response) => { 63 | if(response.success === true){ 64 | this.testStatus('Your Slack token seems to work fine. Make sure to provide an existing channel.'); 65 | } 66 | else 67 | { 68 | this.testStatus('Your Slack token is invalid.'); 69 | } 70 | }); 71 | } 72 | } 73 | 74 | runHipChatTest(){ 75 | if(this.hipchat.token() === '' || this.hipchat.room() === ''){ 76 | this.testStatus('Please fill in token and room first.'); 77 | } 78 | else{ 79 | this.testStatus('Testing...'); 80 | m.request({method: "GET", url: "/api/notify/test/hipchat"}) 81 | .then((response) => { 82 | if(response.success === true){ 83 | this.testStatus('Hipchat notifications should work. A test message has been posted to your room.'); 84 | } 85 | else 86 | { 87 | this.testStatus('Your token is invalid or the token cannot access your room.'); 88 | } 89 | }); 90 | } 91 | } 92 | 93 | runGitterTest(){ 94 | if(this.gitter.webhook() === ''){ 95 | this.testStatus('Please fill in your webhook first.'); 96 | } 97 | else{ 98 | this.testStatus('Testing...'); 99 | m.request({method: "GET", url: "/api/notify/test/gitter"}) 100 | .then((response) => { 101 | if(response.success === true){ 102 | this.testStatus('Gitter notifications should work. A test message has been posted to your room.'); 103 | } 104 | else 105 | { 106 | this.testStatus('Your webhook is invalid or Gitter could not be reached.'); 107 | } 108 | }); 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /dev/src/Connectors/GitterConnector.php: -------------------------------------------------------------------------------- 1 | client = new GuzzleClient(); 16 | $this->webhook = $this->settings->get('notify.gitter.webhook'); 17 | } 18 | 19 | /** 20 | * Checks wether the Connector works with the current settings 21 | * @return boolean 22 | */ 23 | public function works(){ 24 | $data = [ 25 | 'form_params' => [ 26 | 'message' => 'Flarum is able to contact this Gitter room. Great!' 27 | ] 28 | ]; 29 | 30 | $response = $this->postApi($data); 31 | return $response->getBody()->getContents() == 'OK'; 32 | } 33 | 34 | /** 35 | * Method which actually sends a message to Gitter 36 | * @param Message $message 37 | * @return GuzzleResponse 38 | */ 39 | public function send($message){ 40 | $level = 'normal'; 41 | if($message->getColor() !== null){ 42 | $level = $this->parseColor($message->getColor()); 43 | } 44 | 45 | 46 | // Prefix with 'Forum activity:' 47 | $content = '####Flarum activity '."\n\n"; 48 | 49 | if($message->getAuthor() !== null){ 50 | $content .= '@'.$message->getAuthor()->username.' '; 51 | } 52 | 53 | $content .= $message->getMessage(); 54 | 55 | $content = $this->parseLinksInMessage($content, $message->getLinksToParse()); 56 | 57 | // Remove # for gutter because it will tryl to convert them into issue links 58 | $content = str_replace('iscussion #', 'iscussion ', $content); 59 | 60 | $data = [ 61 | 'form_params' => [ 62 | 'message' => $content, 63 | 'level' => $level 64 | ] 65 | ]; 66 | 67 | return $this->postApi($data); 68 | } 69 | 70 | /** 71 | * Executes a GET query via requestApi 72 | */ 73 | protected function getApi($data = []){ 74 | return $this->requestApi('GET', $data); 75 | } 76 | 77 | /** 78 | * Executes a POST query via requestApi 79 | */ 80 | protected function postApi($data = []){ 81 | return $this->requestApi('POST', $data); 82 | } 83 | 84 | /** 85 | * Executes a Guzzle request 86 | * @param string $method 87 | * @param array $data 88 | * @return GuzzleResponse 89 | */ 90 | private function requestApi($method = 'GET', $data = []){ 91 | return $this->client->request($method, $this->webhook, $data); 92 | } 93 | 94 | /** 95 | * Parses the message's color to something Gitter understands 96 | * @param string $color 97 | * @return string 'error' or 'normal' 98 | */ 99 | protected function parseColor($color){ 100 | if($color == 'red' || $color == 'orange'){ 101 | return 'error'; 102 | } 103 | return 'normal'; 104 | } 105 | 106 | /** 107 | * Parses all links in the message body to make them clickable 108 | * @param string $content 109 | * @param array $linksToParse string=>link array 110 | * @return string the parsed $content 111 | */ 112 | protected function parseLinksInMessage($content, $linksToParse){ 113 | foreach($linksToParse as $search=>$link){ 114 | $content = str_replace($search, '['.$search.']('.$link.')', $content); 115 | } 116 | return $content; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /dev/src/Connectors/SlackConnector.php: -------------------------------------------------------------------------------- 1 | client = new ApiClient($this->settings->get('notify.slack.token')); 20 | } 21 | 22 | /** 23 | * Prepares a basic message payload to send to Slack 24 | * @return void 25 | */ 26 | public function prepareNotificationPayload(){ 27 | $this->payload = new ChatPostMessagePayload(); 28 | $this->payload->setChannel($this->settings->get('notify.slack.channel')); 29 | $this->payload->setIconUrl(app('flarum.config')['url'] . $this->iconLocation); 30 | $this->payload->setUsername('Flarum'); 31 | 32 | $this->attachment = new Attachment; 33 | } 34 | 35 | /** 36 | * Checks wether the Connector works with the current settings. 37 | * 38 | * TODO: Should actually be improved to really test the channel 39 | * 40 | * @return boolean 41 | */ 42 | public function works(){ 43 | $this->payload = new AuthTestPayload; 44 | $test = $this->execute(); 45 | return $test->isOk(); 46 | } 47 | 48 | 49 | /** 50 | * Method which actually sends a message to Slack 51 | * @param Message $message 52 | * @return void 53 | */ 54 | public function send($message){ 55 | $this->prepareNotificationPayload(); 56 | $this->setMessage($message->getMessage(), $message->getShort()); 57 | $this->parseLinksInMessage($message->getLinksToParse()); 58 | if($message->getAuthor() !== null){ 59 | $this->setAuthor($message->getAuthor()->username, app('flarum.config')['url']."/u/{$message->getAuthor()->id}", $message->getAuthor()->avatar_url); 60 | if($message->getAuthor()->isAdmin()) 61 | { 62 | $this->setColor('special'); 63 | } 64 | } 65 | if($message->getColor() !== null){ 66 | $this->setColor($message->getColor()); 67 | } 68 | if($message->getTitle() !== ''){ 69 | $this->setTitle($message->getTitle()); 70 | } 71 | $this->sendMessage(); 72 | } 73 | 74 | /** 75 | * Sets the message on the Slack attachment. Also sets the fallback which is going to be displayed in system notifications. 76 | * @param string $message 77 | * @param string $fallback 78 | */ 79 | protected function setMessage($message, $fallback = false){ 80 | if($fallback !== false){ 81 | $this->setFallback($fallback); 82 | } 83 | else{ 84 | $this->setFallback($message); 85 | } 86 | return $this->attachment->setText($message); 87 | } 88 | 89 | protected function setTitle($title){ 90 | $this->attachment->setTitle($title); 91 | } 92 | 93 | protected function setFallback($fallback){ 94 | $this->attachment->setFallback($fallback); 95 | } 96 | 97 | /** 98 | * Parses the message's color to a HEX value and makes the payload use it. 99 | * @param string $color 100 | * @return void 101 | */ 102 | protected function setColor($color){ 103 | $finalcolor = '777777'; 104 | 105 | $colors = [ 106 | 'red' => 'C20000', 107 | 'orange' => 'F2C200', 108 | 'green' => '713191', 109 | 'gray' => '777777', 110 | 'default' => '777777', 111 | 'blue' => '609EB3', 112 | 'special' => '609EB3' 113 | ]; 114 | 115 | if(isset($colors[$color])){ 116 | $finalcolor = $colors[$color]; 117 | } 118 | 119 | $this->attachment->setColor($finalcolor); 120 | } 121 | 122 | /** 123 | * Sets the message author 124 | * @param string $name The author name 125 | * @param string $link A link for a click on the authors name 126 | * @param string $icon Url of the author's avatar 127 | */ 128 | protected function setAuthor($name, $link = false, $icon = null){ 129 | $this->attachment->setAuthorName($name); 130 | if($link !== false){ 131 | $this->attachment->setAuthorLink($link); 132 | } 133 | if($icon !== null){ 134 | $this->attachment->setAuthorIcon($icon); 135 | } 136 | } 137 | 138 | /** 139 | * Prepares the message attachment and sends it to Slack 140 | * @return @see execute() 141 | */ 142 | protected function sendMessage(){ 143 | $this->payload->addAttachment($this->attachment); 144 | 145 | return $this->execute(); 146 | } 147 | 148 | /** 149 | * Dispatches the message and sends it to Slack 150 | * @return mixed sending response 151 | */ 152 | private function execute(){ 153 | return $this->client->send($this->payload); 154 | } 155 | 156 | 157 | /** 158 | * Parses all links in the message body to make them clickable. Sets the message body afterwards 159 | * @param string $content 160 | * @param array $linksToParse string=>link array 161 | * @return string the parsed $content 162 | */ 163 | protected function parseLinksInMessage($linksToParse){ 164 | $message = $this->attachment->getText(); 165 | foreach($linksToParse as $search=>$link){ 166 | $message = str_replace($search, '<'.$link.'|'.$search.'>', $message); 167 | } 168 | $this->setMessage($message); 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /dev/js/admin/src/components/NotifySettingsPage.js: -------------------------------------------------------------------------------- 1 | import Component from 'flarum/Component'; 2 | import Button from 'flarum/components/Button'; 3 | import Switch from 'flarum/components/Switch'; 4 | import saveConfig from 'flarum/utils/saveConfig'; 5 | import Alert from 'flarum/components/Alert'; 6 | 7 | import SlackSettingsModal from 'notify/components/SlackSettingsModal'; 8 | import HipChatSettingsModal from 'notify/components/HipChatSettingsModal'; 9 | import GitterSettingsModal from 'notify/components/GitterSettingsModal'; 10 | import TestConnectorsModal from 'notify/components/TestConnectorsModal'; 11 | 12 | export default class NotifySettingsPage extends Component { 13 | constructor(...args) { 14 | super(...args); 15 | this.services = {}; 16 | this.services.slack = m.prop(app.config['notify.services.slack'] === '1'); 17 | this.services.hipchat = m.prop(app.config['notify.services.hipchat'] === '1'); 18 | this.services.gitter = m.prop(app.config['notify.services.gitter'] === '1'); 19 | 20 | this.events = {}; 21 | this.events.new_post = m.prop(app.config['notify.events.new_post'] === '1'); 22 | this.events.new_discussion = m.prop(app.config['notify.events.new_discussion'] === '1'); 23 | this.events.post_hidden = m.prop(app.config['notify.events.post_hidden'] === '1'); 24 | this.events.post_deleted = m.prop(app.config['notify.events.post_deleted'] === '1'); 25 | this.events.discussion_deleted = m.prop(app.config['notify.events.discussion_deleted'] === '1'); 26 | } 27 | 28 | view(){ 29 | return ( 30 |
31 |
32 |

Notification services

33 |
34 |
35 |
36 | Choose which services should be notified when there is something to notify you about. 37 |
38 | 39 | 40 | 47 | 61 | 62 | 63 | 70 | 84 | 85 | 86 | 93 | 107 | 108 |
41 | {Switch.component({ 42 | state: this.services.gitter(), 43 | children: 'Gitter', 44 | onchange: this.services.gitter 45 | })} 46 | 48 | {Button.component({ 49 | className: 'Button NotifySettingsButton rounded', 50 | icon: 'cog', 51 | type: 'button', 52 | onclick: () => app.modal.show(new GitterSettingsModal()) 53 | })} 54 | {Button.component({ 55 | className: 'Button NotifySettingsButton rounded texty', 56 | children: 'Test', 57 | type: 'button', 58 | onclick: () => app.modal.show(new TestConnectorsModal({'connector':'gitter'})) 59 | })} 60 |
64 | {Switch.component({ 65 | state: this.services.hipchat(), 66 | children: 'HipChat', 67 | onchange: this.services.hipchat 68 | })} 69 | 71 | {Button.component({ 72 | className: 'Button NotifySettingsButton rounded', 73 | icon: 'cog', 74 | type: 'button', 75 | onclick: () => app.modal.show(new HipChatSettingsModal()) 76 | })} 77 | {Button.component({ 78 | className: 'Button NotifySettingsButton rounded texty', 79 | children: 'Test', 80 | type: 'button', 81 | onclick: () => app.modal.show(new TestConnectorsModal({'connector':'hipchat'})) 82 | })} 83 |
87 | {Switch.component({ 88 | state: this.services.slack(), 89 | children: 'Slack', 90 | onchange: this.services.slack 91 | })} 92 | 94 | {Button.component({ 95 | className: 'Button NotifySettingsButton rounded', 96 | icon: 'cog', 97 | type: 'button', 98 | onclick: () => app.modal.show(new SlackSettingsModal()) 99 | })} 100 | {Button.component({ 101 | className: 'Button NotifySettingsButton rounded texty', 102 | children: 'Test', 103 | type: 'button', 104 | onclick: () => app.modal.show(new TestConnectorsModal({'connector':'slack'})) 105 | })} 106 |
109 |
110 |
111 |
112 |

Notification events

113 |
114 |
115 |
116 | Choose which events should trigger a notification. Send notifications, when 117 |
118 | 119 | 120 | 127 | 128 | 129 | 136 | 137 | 138 | 145 | 146 | 147 | 154 | 155 | 156 | 163 | 164 |
121 | {Switch.component({ 122 | state: this.events.new_discussion(), 123 | children: 'a new discussion was started', 124 | onchange: this.events.new_discussion 125 | })} 126 |
130 | {Switch.component({ 131 | state: this.events.discussion_deleted(), 132 | children: 'a discussion was deleted', 133 | onchange: this.events.discussion_deleted 134 | })} 135 |
139 | {Switch.component({ 140 | state: this.events.new_post(), 141 | children: 'a new post was posted', 142 | onchange: this.events.new_post 143 | })} 144 |
148 | {Switch.component({ 149 | state: this.events.post_hidden(), 150 | children: 'a post was hidden', 151 | onchange: this.events.post_hidden 152 | })} 153 |
157 | {Switch.component({ 158 | state: this.events.post_deleted(), 159 | children: 'a post was deleted', 160 | onchange: this.events.post_deleted 161 | })} 162 |
165 |
166 |
167 |

168 | {Button.component({ 169 | className: 'Button Button--primary', 170 | children: 'Save changes', 171 | loading: this.loading 172 | })} 173 |

174 |
175 |
176 |
177 | ); 178 | } 179 | 180 | onsubmit(e) { 181 | e.preventDefault(); 182 | 183 | this.loading = true; 184 | app.alerts.dismiss(this.successAlert); 185 | 186 | saveConfig({ 187 | 'notify.services.slack' : this.services.slack(), 188 | 'notify.services.hipchat' : this.services.hipchat(), 189 | 'notify.services.gitter' : this.services.gitter(), 190 | 'notify.events.new_post' : this.events.new_post(), 191 | 'notify.events.new_discussion' : this.events.new_discussion(), 192 | 'notify.events.post_hidden' : this.events.post_hidden(), 193 | 'notify.events.post_deleted' : this.events.post_deleted(), 194 | 'notify.events.discussion_deleted' : this.events.discussion_deleted() 195 | }) 196 | .finally(() => { 197 | this.loading = false; 198 | m.redraw(); 199 | } 200 | ); 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /dev/js/admin/dist/extension.js: -------------------------------------------------------------------------------- 1 | System.register('notify/addNotifySettingsPage', ['flarum/extend', 'flarum/components/AdminNav', 'flarum/components/AdminLinkButton', 'notify/components/NotifySettingsPage'], function (_export) { 2 | 'use strict'; 3 | 4 | var extend, AdminNav, AdminLinkButton, NotifySettingsPage; 5 | return { 6 | setters: [function (_flarumExtend) { 7 | extend = _flarumExtend.extend; 8 | }, function (_flarumComponentsAdminNav) { 9 | AdminNav = _flarumComponentsAdminNav['default']; 10 | }, function (_flarumComponentsAdminLinkButton) { 11 | AdminLinkButton = _flarumComponentsAdminLinkButton['default']; 12 | }, function (_notifyComponentsNotifySettingsPage) { 13 | NotifySettingsPage = _notifyComponentsNotifySettingsPage['default']; 14 | }], 15 | execute: function () { 16 | _export('default', function () { 17 | 18 | app.routes.notify = { path: '/notify', component: NotifySettingsPage.component() }; 19 | 20 | app.extensionSettings.notify = function () { 21 | return m.route(app.route('notify')); 22 | }; 23 | 24 | extend(AdminNav.prototype, 'items', function (items) { 25 | items.add('notify', AdminLinkButton.component({ 26 | href: app.route('notify'), 27 | icon: 'bell', 28 | children: 'Notify', 29 | description: 'Manage your notifications to Slack, Hipchat and Gitter.' 30 | })); 31 | }); 32 | }); 33 | } 34 | }; 35 | });;System.register('notify/main', ['notify/addNotifySettingsPage'], function (_export) { 36 | 'use strict'; 37 | 38 | var addNotifySettingsPage; 39 | return { 40 | setters: [function (_notifyAddNotifySettingsPage) { 41 | addNotifySettingsPage = _notifyAddNotifySettingsPage['default']; 42 | }], 43 | execute: function () { 44 | 45 | app.initializers.add('notify', function (app) { 46 | addNotifySettingsPage(); 47 | }); 48 | } 49 | }; 50 | });;System.register('notify/components/GitterSettingsModal', ['flarum/components/Modal', 'flarum/components/Button', 'flarum/utils/saveConfig'], function (_export) { 51 | 'use strict'; 52 | 53 | var Modal, Button, saveConfig, GitterSettingsModal; 54 | 55 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); 56 | 57 | var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; 58 | 59 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 60 | 61 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 62 | 63 | return { 64 | setters: [function (_flarumComponentsModal) { 65 | Modal = _flarumComponentsModal['default']; 66 | }, function (_flarumComponentsButton) { 67 | Button = _flarumComponentsButton['default']; 68 | }, function (_flarumUtilsSaveConfig) { 69 | saveConfig = _flarumUtilsSaveConfig['default']; 70 | }], 71 | execute: function () { 72 | GitterSettingsModal = (function (_Modal) { 73 | _inherits(GitterSettingsModal, _Modal); 74 | 75 | function GitterSettingsModal() { 76 | _classCallCheck(this, GitterSettingsModal); 77 | 78 | for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { 79 | args[_key] = arguments[_key]; 80 | } 81 | 82 | _get(Object.getPrototypeOf(GitterSettingsModal.prototype), 'constructor', this).apply(this, args); 83 | 84 | this.webhook = m.prop(app.config['notify.gitter.webhook'] || ''); 85 | } 86 | 87 | _createClass(GitterSettingsModal, [{ 88 | key: 'className', 89 | value: function className() { 90 | return 'GitterSettingsModal Modal--small'; 91 | } 92 | }, { 93 | key: 'title', 94 | value: function title() { 95 | return 'Gitter settings'; 96 | } 97 | }, { 98 | key: 'content', 99 | value: function content() { 100 | return m( 101 | 'div', 102 | { className: 'Modal-body' }, 103 | m( 104 | 'div', 105 | { className: 'Form' }, 106 | m( 107 | 'div', 108 | { className: 'Form-group' }, 109 | m( 110 | 'label', 111 | null, 112 | 'Gitter webhook' 113 | ), 114 | m('input', { className: 'FormControl', value: this.webhook(), oninput: m.withAttr('value', this.webhook) }) 115 | ), 116 | m( 117 | 'p', 118 | null, 119 | 'In order to get your webhook url, visit the room you want to post to on ', 120 | m( 121 | 'a', 122 | { href: 'https://gitter.im', target: '_new' }, 123 | 'gitter.im' 124 | ), 125 | '. Click on the ', 126 | m( 127 | 'i', 128 | null, 129 | 'Settings icon' 130 | ), 131 | ' > ', 132 | m( 133 | 'i', 134 | null, 135 | 'Integrations' 136 | ), 137 | ' > ', 138 | m( 139 | 'i', 140 | null, 141 | 'Custom' 142 | ), 143 | '. This will create a new webhook url for you.' 144 | ), 145 | m('hr', null), 146 | m( 147 | 'div', 148 | { className: 'Form-group' }, 149 | Button.component({ 150 | type: 'submit', 151 | className: 'Button Button--primary GitterSettingsModal-save', 152 | loading: this.loading, 153 | children: 'Save Changes' 154 | }) 155 | ) 156 | ) 157 | ); 158 | } 159 | }, { 160 | key: 'onsubmit', 161 | value: function onsubmit(e) { 162 | var _this = this; 163 | 164 | e.preventDefault(); 165 | 166 | this.loading = true; 167 | 168 | saveConfig({ 169 | 'notify.gitter.webhook': this.webhook() 170 | }).then(function () { 171 | return _this.hide(); 172 | }, function () { 173 | _this.loading = false; 174 | m.redraw(); 175 | }); 176 | } 177 | }]); 178 | 179 | return GitterSettingsModal; 180 | })(Modal); 181 | 182 | _export('default', GitterSettingsModal); 183 | } 184 | }; 185 | });;System.register('notify/components/HipChatSettingsModal', ['flarum/components/Modal', 'flarum/components/Button', 'flarum/utils/saveConfig', 'flarum/components/Alert'], function (_export) { 186 | 'use strict'; 187 | 188 | var Modal, Button, saveConfig, Alert, HipChatSettingsModal; 189 | 190 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); 191 | 192 | var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; 193 | 194 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 195 | 196 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 197 | 198 | return { 199 | setters: [function (_flarumComponentsModal) { 200 | Modal = _flarumComponentsModal['default']; 201 | }, function (_flarumComponentsButton) { 202 | Button = _flarumComponentsButton['default']; 203 | }, function (_flarumUtilsSaveConfig) { 204 | saveConfig = _flarumUtilsSaveConfig['default']; 205 | }, function (_flarumComponentsAlert) { 206 | Alert = _flarumComponentsAlert['default']; 207 | }], 208 | execute: function () { 209 | HipChatSettingsModal = (function (_Modal) { 210 | _inherits(HipChatSettingsModal, _Modal); 211 | 212 | function HipChatSettingsModal() { 213 | _classCallCheck(this, HipChatSettingsModal); 214 | 215 | for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { 216 | args[_key] = arguments[_key]; 217 | } 218 | 219 | _get(Object.getPrototypeOf(HipChatSettingsModal.prototype), 'constructor', this).apply(this, args); 220 | 221 | this.token = m.prop(app.config['notify.hipchat.token'] || ''); 222 | this.room = m.prop(app.config['notify.hipchat.room'] || ''); 223 | } 224 | 225 | _createClass(HipChatSettingsModal, [{ 226 | key: 'className', 227 | value: function className() { 228 | return 'HipChatSettingsModal Modal--small'; 229 | } 230 | }, { 231 | key: 'title', 232 | value: function title() { 233 | return 'HipChat settings'; 234 | } 235 | }, { 236 | key: 'content', 237 | value: function content() { 238 | return m( 239 | 'div', 240 | { className: 'Modal-body' }, 241 | m( 242 | 'div', 243 | { className: 'Form' }, 244 | m( 245 | 'div', 246 | { className: 'Form-group' }, 247 | m( 248 | 'label', 249 | null, 250 | 'HipChat token' 251 | ), 252 | m('input', { className: 'FormControl', value: this.token(), oninput: m.withAttr('value', this.token) }) 253 | ), 254 | m( 255 | 'div', 256 | { className: 'Form-group' }, 257 | m( 258 | 'label', 259 | null, 260 | 'Room to post to (name or id)' 261 | ), 262 | m('input', { className: 'FormControl', value: this.room(), oninput: m.withAttr('value', this.room) }) 263 | ), 264 | m( 265 | 'p', 266 | null, 267 | 'To obtain the token, visit your the room settings over at hipchat.com (Login, click on `rooms` and select your the room you want to post to). Click on `Tokens` and create a new one. The label you provide for the token will be shown with each notification.' 268 | ), 269 | m( 270 | 'p', 271 | null, 272 | 'Notify does not work with self-hosted HipChat.' 273 | ), 274 | m('hr', null), 275 | m( 276 | 'div', 277 | { className: 'Form-group' }, 278 | Button.component({ 279 | type: 'submit', 280 | className: 'Button Button--primary HipChatSettingsModal-save', 281 | loading: this.loading, 282 | children: 'Save Changes' 283 | }) 284 | ) 285 | ) 286 | ); 287 | } 288 | }, { 289 | key: 'onsubmit', 290 | value: function onsubmit(e) { 291 | var _this = this; 292 | 293 | e.preventDefault(); 294 | this.loading = true; 295 | 296 | app.alerts.dismiss(this.testResultAlert); 297 | saveConfig({ 298 | 'notify.hipchat.token': this.token(), 299 | 'notify.hipchat.room': this.room() 300 | }).then(function () { 301 | return _this.hide(); 302 | }, function () { 303 | _this.loading = false; 304 | m.redraw(); 305 | }); 306 | } 307 | }]); 308 | 309 | return HipChatSettingsModal; 310 | })(Modal); 311 | 312 | _export('default', HipChatSettingsModal); 313 | } 314 | }; 315 | });;System.register('notify/components/NotifySettingsPage', ['flarum/Component', 'flarum/components/Button', 'flarum/components/Switch', 'flarum/utils/saveConfig', 'flarum/components/Alert', 'notify/components/SlackSettingsModal', 'notify/components/HipChatSettingsModal', 'notify/components/GitterSettingsModal', 'notify/components/TestConnectorsModal'], function (_export) { 316 | 'use strict'; 317 | 318 | var Component, Button, Switch, saveConfig, Alert, SlackSettingsModal, HipChatSettingsModal, GitterSettingsModal, TestConnectorsModal, NotifySettingsPage; 319 | 320 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); 321 | 322 | var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; 323 | 324 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 325 | 326 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 327 | 328 | return { 329 | setters: [function (_flarumComponent) { 330 | Component = _flarumComponent['default']; 331 | }, function (_flarumComponentsButton) { 332 | Button = _flarumComponentsButton['default']; 333 | }, function (_flarumComponentsSwitch) { 334 | Switch = _flarumComponentsSwitch['default']; 335 | }, function (_flarumUtilsSaveConfig) { 336 | saveConfig = _flarumUtilsSaveConfig['default']; 337 | }, function (_flarumComponentsAlert) { 338 | Alert = _flarumComponentsAlert['default']; 339 | }, function (_notifyComponentsSlackSettingsModal) { 340 | SlackSettingsModal = _notifyComponentsSlackSettingsModal['default']; 341 | }, function (_notifyComponentsHipChatSettingsModal) { 342 | HipChatSettingsModal = _notifyComponentsHipChatSettingsModal['default']; 343 | }, function (_notifyComponentsGitterSettingsModal) { 344 | GitterSettingsModal = _notifyComponentsGitterSettingsModal['default']; 345 | }, function (_notifyComponentsTestConnectorsModal) { 346 | TestConnectorsModal = _notifyComponentsTestConnectorsModal['default']; 347 | }], 348 | execute: function () { 349 | NotifySettingsPage = (function (_Component) { 350 | _inherits(NotifySettingsPage, _Component); 351 | 352 | function NotifySettingsPage() { 353 | _classCallCheck(this, NotifySettingsPage); 354 | 355 | for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { 356 | args[_key] = arguments[_key]; 357 | } 358 | 359 | _get(Object.getPrototypeOf(NotifySettingsPage.prototype), 'constructor', this).apply(this, args); 360 | this.services = {}; 361 | this.services.slack = m.prop(app.config['notify.services.slack'] === '1'); 362 | this.services.hipchat = m.prop(app.config['notify.services.hipchat'] === '1'); 363 | this.services.gitter = m.prop(app.config['notify.services.gitter'] === '1'); 364 | 365 | this.events = {}; 366 | this.events.new_post = m.prop(app.config['notify.events.new_post'] === '1'); 367 | this.events.new_discussion = m.prop(app.config['notify.events.new_discussion'] === '1'); 368 | this.events.post_hidden = m.prop(app.config['notify.events.post_hidden'] === '1'); 369 | this.events.post_deleted = m.prop(app.config['notify.events.post_deleted'] === '1'); 370 | this.events.discussion_deleted = m.prop(app.config['notify.events.discussion_deleted'] === '1'); 371 | } 372 | 373 | _createClass(NotifySettingsPage, [{ 374 | key: 'view', 375 | value: function view() { 376 | return m( 377 | 'div', 378 | { className: 'NotifySettingsPage' }, 379 | m( 380 | 'div', 381 | { className: 'container' }, 382 | m( 383 | 'h2', 384 | null, 385 | 'Notification services' 386 | ), 387 | m( 388 | 'form', 389 | { onsubmit: this.onsubmit.bind(this) }, 390 | m( 391 | 'fieldset', 392 | { className: 'NotifySettingsPage-services' }, 393 | m( 394 | 'div', 395 | { className: 'helpText' }, 396 | 'Choose which services should be notified when there is something to notify you about.' 397 | ), 398 | m( 399 | 'table', 400 | { className: 'NotifySettingsTable' }, 401 | m( 402 | 'tr', 403 | null, 404 | m( 405 | 'td', 406 | null, 407 | Switch.component({ 408 | state: this.services.gitter(), 409 | children: 'Gitter', 410 | onchange: this.services.gitter 411 | }) 412 | ), 413 | m( 414 | 'td', 415 | null, 416 | Button.component({ 417 | className: 'Button NotifySettingsButton rounded', 418 | icon: 'cog', 419 | type: 'button', 420 | onclick: function onclick() { 421 | return app.modal.show(new GitterSettingsModal()); 422 | } 423 | }), 424 | Button.component({ 425 | className: 'Button NotifySettingsButton rounded texty', 426 | children: 'Test', 427 | type: 'button', 428 | onclick: function onclick() { 429 | return app.modal.show(new TestConnectorsModal({ 'connector': 'gitter' })); 430 | } 431 | }) 432 | ) 433 | ), 434 | m( 435 | 'tr', 436 | null, 437 | m( 438 | 'td', 439 | null, 440 | Switch.component({ 441 | state: this.services.hipchat(), 442 | children: 'HipChat', 443 | onchange: this.services.hipchat 444 | }) 445 | ), 446 | m( 447 | 'td', 448 | null, 449 | Button.component({ 450 | className: 'Button NotifySettingsButton rounded', 451 | icon: 'cog', 452 | type: 'button', 453 | onclick: function onclick() { 454 | return app.modal.show(new HipChatSettingsModal()); 455 | } 456 | }), 457 | Button.component({ 458 | className: 'Button NotifySettingsButton rounded texty', 459 | children: 'Test', 460 | type: 'button', 461 | onclick: function onclick() { 462 | return app.modal.show(new TestConnectorsModal({ 'connector': 'hipchat' })); 463 | } 464 | }) 465 | ) 466 | ), 467 | m( 468 | 'tr', 469 | null, 470 | m( 471 | 'td', 472 | null, 473 | Switch.component({ 474 | state: this.services.slack(), 475 | children: 'Slack', 476 | onchange: this.services.slack 477 | }) 478 | ), 479 | m( 480 | 'td', 481 | null, 482 | Button.component({ 483 | className: 'Button NotifySettingsButton rounded', 484 | icon: 'cog', 485 | type: 'button', 486 | onclick: function onclick() { 487 | return app.modal.show(new SlackSettingsModal()); 488 | } 489 | }), 490 | Button.component({ 491 | className: 'Button NotifySettingsButton rounded texty', 492 | children: 'Test', 493 | type: 'button', 494 | onclick: function onclick() { 495 | return app.modal.show(new TestConnectorsModal({ 'connector': 'slack' })); 496 | } 497 | }) 498 | ) 499 | ) 500 | ) 501 | ) 502 | ), 503 | m('hr', null), 504 | m( 505 | 'h2', 506 | null, 507 | 'Notification events' 508 | ), 509 | m( 510 | 'form', 511 | { onsubmit: this.onsubmit.bind(this) }, 512 | m( 513 | 'fieldset', 514 | { className: 'NotifySettingsPage-events' }, 515 | m( 516 | 'div', 517 | { className: 'helpText' }, 518 | 'Choose which events should trigger a notification. Send notifications, when' 519 | ), 520 | m( 521 | 'table', 522 | { className: 'NotifySettingsTable' }, 523 | m( 524 | 'tr', 525 | null, 526 | m( 527 | 'td', 528 | null, 529 | Switch.component({ 530 | state: this.events.new_discussion(), 531 | children: 'a new discussion was started', 532 | onchange: this.events.new_discussion 533 | }) 534 | ) 535 | ), 536 | m( 537 | 'tr', 538 | null, 539 | m( 540 | 'td', 541 | null, 542 | Switch.component({ 543 | state: this.events.discussion_deleted(), 544 | children: 'a discussion was deleted', 545 | onchange: this.events.discussion_deleted 546 | }) 547 | ) 548 | ), 549 | m( 550 | 'tr', 551 | null, 552 | m( 553 | 'td', 554 | null, 555 | Switch.component({ 556 | state: this.events.new_post(), 557 | children: 'a new post was posted', 558 | onchange: this.events.new_post 559 | }) 560 | ) 561 | ), 562 | m( 563 | 'tr', 564 | null, 565 | m( 566 | 'td', 567 | null, 568 | Switch.component({ 569 | state: this.events.post_hidden(), 570 | children: 'a post was hidden', 571 | onchange: this.events.post_hidden 572 | }) 573 | ) 574 | ), 575 | m( 576 | 'tr', 577 | null, 578 | m( 579 | 'td', 580 | null, 581 | Switch.component({ 582 | state: this.events.post_deleted(), 583 | children: 'a post was deleted', 584 | onchange: this.events.post_deleted 585 | }) 586 | ) 587 | ) 588 | ) 589 | ), 590 | m('hr', null), 591 | m( 592 | 'p', 593 | null, 594 | Button.component({ 595 | className: 'Button Button--primary', 596 | children: 'Save changes', 597 | loading: this.loading 598 | }) 599 | ) 600 | ) 601 | ) 602 | ); 603 | } 604 | }, { 605 | key: 'onsubmit', 606 | value: function onsubmit(e) { 607 | var _this = this; 608 | 609 | e.preventDefault(); 610 | 611 | this.loading = true; 612 | app.alerts.dismiss(this.successAlert); 613 | 614 | saveConfig({ 615 | 'notify.services.slack': this.services.slack(), 616 | 'notify.services.hipchat': this.services.hipchat(), 617 | 'notify.services.gitter': this.services.gitter(), 618 | 'notify.events.new_post': this.events.new_post(), 619 | 'notify.events.new_discussion': this.events.new_discussion(), 620 | 'notify.events.post_hidden': this.events.post_hidden(), 621 | 'notify.events.post_deleted': this.events.post_deleted(), 622 | 'notify.events.discussion_deleted': this.events.discussion_deleted() 623 | })['finally'](function () { 624 | _this.loading = false; 625 | m.redraw(); 626 | }); 627 | } 628 | }]); 629 | 630 | return NotifySettingsPage; 631 | })(Component); 632 | 633 | _export('default', NotifySettingsPage); 634 | } 635 | }; 636 | });;System.register('notify/components/SlackSettingsModal', ['flarum/components/Modal', 'flarum/components/Button', 'flarum/utils/saveConfig', 'flarum/components/Alert'], function (_export) { 637 | 'use strict'; 638 | 639 | var Modal, Button, saveConfig, Alert, SlackSettingsModal; 640 | 641 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); 642 | 643 | var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; 644 | 645 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 646 | 647 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 648 | 649 | return { 650 | setters: [function (_flarumComponentsModal) { 651 | Modal = _flarumComponentsModal['default']; 652 | }, function (_flarumComponentsButton) { 653 | Button = _flarumComponentsButton['default']; 654 | }, function (_flarumUtilsSaveConfig) { 655 | saveConfig = _flarumUtilsSaveConfig['default']; 656 | }, function (_flarumComponentsAlert) { 657 | Alert = _flarumComponentsAlert['default']; 658 | }], 659 | execute: function () { 660 | SlackSettingsModal = (function (_Modal) { 661 | _inherits(SlackSettingsModal, _Modal); 662 | 663 | function SlackSettingsModal() { 664 | _classCallCheck(this, SlackSettingsModal); 665 | 666 | for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { 667 | args[_key] = arguments[_key]; 668 | } 669 | 670 | _get(Object.getPrototypeOf(SlackSettingsModal.prototype), 'constructor', this).apply(this, args); 671 | 672 | this.token = m.prop(app.config['notify.slack.token'] || ''); 673 | this.channel = m.prop(app.config['notify.slack.channel'] || '#general'); 674 | } 675 | 676 | _createClass(SlackSettingsModal, [{ 677 | key: 'className', 678 | value: function className() { 679 | return 'SlackSettingsModal Modal--small'; 680 | } 681 | }, { 682 | key: 'title', 683 | value: function title() { 684 | return 'Slack settings'; 685 | } 686 | }, { 687 | key: 'content', 688 | value: function content() { 689 | return m( 690 | 'div', 691 | { className: 'Modal-body' }, 692 | m( 693 | 'div', 694 | { className: 'Form' }, 695 | m( 696 | 'div', 697 | { className: 'Form-group' }, 698 | m( 699 | 'label', 700 | null, 701 | 'Slack token' 702 | ), 703 | m('input', { className: 'FormControl', value: this.token(), oninput: m.withAttr('value', this.token) }) 704 | ), 705 | m( 706 | 'div', 707 | { className: 'Form-group' }, 708 | m( 709 | 'label', 710 | null, 711 | 'Channel to post to' 712 | ), 713 | m('input', { className: 'FormControl', value: this.channel(), oninput: m.withAttr('value', this.channel) }) 714 | ), 715 | m( 716 | 'p', 717 | null, 718 | 'In order to obtain the token, visit ', 719 | m( 720 | 'a', 721 | { href: 'https://api.slack.com/web', target: '_new' }, 722 | 'api.slack.com/web' 723 | ), 724 | '.' 725 | ), 726 | m('hr', null), 727 | m( 728 | 'div', 729 | { className: 'Form-group' }, 730 | Button.component({ 731 | type: 'submit', 732 | className: 'Button Button--primary SlackSettingsModal-save', 733 | loading: this.loading, 734 | children: 'Save Changes' 735 | }) 736 | ) 737 | ) 738 | ); 739 | } 740 | }, { 741 | key: 'onsubmit', 742 | value: function onsubmit(e) { 743 | var _this = this; 744 | 745 | e.preventDefault(); 746 | 747 | this.loading = true; 748 | app.alerts.dismiss(this.testResultAlert); 749 | 750 | saveConfig({ 751 | 'notify.slack.token': this.token(), 752 | 'notify.slack.channel': this.channel() 753 | }).then(function () { 754 | return _this.hide(); 755 | }, function () { 756 | _this.loading = false; 757 | m.redraw(); 758 | }); 759 | } 760 | }]); 761 | 762 | return SlackSettingsModal; 763 | })(Modal); 764 | 765 | _export('default', SlackSettingsModal); 766 | } 767 | }; 768 | });;System.register('notify/components/TestConnectorsModal', ['flarum/components/Modal', 'flarum/components/Button', 'flarum/lib/components/LoadingIndicator'], function (_export) { 769 | 'use strict'; 770 | 771 | var Modal, Button, LoadingIndicator, TestConnectorsModal; 772 | 773 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); 774 | 775 | var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; 776 | 777 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 778 | 779 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 780 | 781 | return { 782 | setters: [function (_flarumComponentsModal) { 783 | Modal = _flarumComponentsModal['default']; 784 | }, function (_flarumComponentsButton) { 785 | Button = _flarumComponentsButton['default']; 786 | }, function (_flarumLibComponentsLoadingIndicator) { 787 | LoadingIndicator = _flarumLibComponentsLoadingIndicator['default']; 788 | }], 789 | execute: function () { 790 | TestConnectorsModal = (function (_Modal) { 791 | _inherits(TestConnectorsModal, _Modal); 792 | 793 | function TestConnectorsModal() { 794 | _classCallCheck(this, TestConnectorsModal); 795 | 796 | for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { 797 | args[_key] = arguments[_key]; 798 | } 799 | 800 | _get(Object.getPrototypeOf(TestConnectorsModal.prototype), 'constructor', this).apply(this, args); 801 | 802 | this.slack = {}; 803 | this.slack.token = m.prop(app.config['notify.slack.token'] || ''); 804 | this.slack.channel = m.prop(app.config['notify.slack.channel'] || ''); 805 | 806 | this.hipchat = {}; 807 | this.hipchat.token = m.prop(app.config['notify.hipchat.token'] || ''); 808 | this.hipchat.room = m.prop(app.config['notify.hipchat.room'] || ''); 809 | 810 | this.gitter = {}; 811 | this.gitter.webhook = m.prop(app.config['notify.gitter.webhook'] || ''); 812 | 813 | this.testStatus = m.prop('Preparing...'); 814 | 815 | this.runConnectorTest(); 816 | } 817 | 818 | _createClass(TestConnectorsModal, [{ 819 | key: 'className', 820 | value: function className() { 821 | return 'TestConnectorsModal Modal--small'; 822 | } 823 | }, { 824 | key: 'title', 825 | value: function title() { 826 | return 'Testing your settings'; 827 | } 828 | }, { 829 | key: 'content', 830 | value: function content() { 831 | return m( 832 | 'div', 833 | { className: 'Modal-body' }, 834 | m( 835 | 'div', 836 | { className: 'statusMessage' }, 837 | this.testStatus() 838 | ) 839 | ); 840 | } 841 | }, { 842 | key: 'runConnectorTest', 843 | value: function runConnectorTest() { 844 | switch (this.props.connector) { 845 | case 'slack': 846 | this.runSlackTest(); 847 | break; 848 | case 'hipchat': 849 | this.runHipChatTest(); 850 | break; 851 | case 'gitter': 852 | this.runGitterTest(); 853 | break; 854 | } 855 | } 856 | }, { 857 | key: 'runSlackTest', 858 | value: function runSlackTest() { 859 | var _this = this; 860 | 861 | if (this.slack.token() === '' || this.slack.channel() === '') { 862 | this.testStatus('Please fill in token and channel first.'); 863 | } else { 864 | this.testStatus('Testing...'); 865 | m.request({ method: "GET", url: "/api/notify/test/slack" }).then(function (response) { 866 | if (response.success === true) { 867 | _this.testStatus('Your Slack token seems to work fine. Make sure to provide an existing channel.'); 868 | } else { 869 | _this.testStatus('Your Slack token is invalid.'); 870 | } 871 | }); 872 | } 873 | } 874 | }, { 875 | key: 'runHipChatTest', 876 | value: function runHipChatTest() { 877 | var _this2 = this; 878 | 879 | if (this.hipchat.token() === '' || this.hipchat.room() === '') { 880 | this.testStatus('Please fill in token and room first.'); 881 | } else { 882 | this.testStatus('Testing...'); 883 | m.request({ method: "GET", url: "/api/notify/test/hipchat" }).then(function (response) { 884 | if (response.success === true) { 885 | _this2.testStatus('Hipchat notifications should work. A test message has been posted to your room.'); 886 | } else { 887 | _this2.testStatus('Your token is invalid or the token cannot access your room.'); 888 | } 889 | }); 890 | } 891 | } 892 | }, { 893 | key: 'runGitterTest', 894 | value: function runGitterTest() { 895 | var _this3 = this; 896 | 897 | if (this.gitter.webhook() === '') { 898 | this.testStatus('Please fill in your webhook first.'); 899 | } else { 900 | this.testStatus('Testing...'); 901 | m.request({ method: "GET", url: "/api/notify/test/gitter" }).then(function (response) { 902 | if (response.success === true) { 903 | _this3.testStatus('Gitter notifications should work. A test message has been posted to your room.'); 904 | } else { 905 | _this3.testStatus('Your webhook is invalid or Gitter could not be reached.'); 906 | } 907 | }); 908 | } 909 | } 910 | }]); 911 | 912 | return TestConnectorsModal; 913 | })(Modal); 914 | 915 | _export('default', TestConnectorsModal); 916 | } 917 | }; 918 | }); --------------------------------------------------------------------------------