Skip to content

Commit

Permalink
Merge pull request #2 from zvercodebender/mickey
Browse files Browse the repository at this point in the history
Add new channel and message tasks
  • Loading branch information
Rick Broker authored Dec 13, 2019
2 parents 07acecd + c93ff3c commit 541b581
Show file tree
Hide file tree
Showing 28 changed files with 657 additions and 31 deletions.
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,8 @@ venv.bak/

# Java
.classpath
.project
.project

# OS/X
.DS_Store
*.xlvals
4 changes: 3 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
language: java
jdk: openjdk8
before_install:
- chmod +x gradlew
deploy:
provider: releases
api_key:
secure: KGvqBU3jlrqtmciLW0PM2Hm8XbcXbARcgQLHJpLWFPKe1fR3brRU0PVnZjxPDFEwN8ehNT4DdL8VehutvJZTELyF4xH2OMMLKKgdfBCjB6oJ3mqOBTzvKo3Vdq1JhVtL+4Uc6DASscPwRd06stC6UPGdMDMMRwROWf/VmvWRCb1tjNFM6/Vbx/JE4XESkACvDn8mopYNPRhwvQbiAJAd9tmlcBvrwLRJ7jdcoTMKDDhoCJnfarjvxIvrbTiTeb9dz81vFLA8h7pVTuoVwgomlAzKzXKA3r2Ub2zIa+3EhXbmfGKFGReG9rOJ57r7mxSCgZTP+xi3VcH35hJyHbAOhs+7aOIbxZ90G/tVknA0UtOFe9MIqVApjn3VCAuOki24xITSsDdFt5t1qpmWNGVXfO/1kXacGHcezhTM9qlMrKosKCkezkMAMzcKnwsSmZXP+IwlhgCKdbJsHrcHbBsPF1Crkav07daBUX8nTcnsHsZAYE76S9pMJi4TXyVe93zFUv+o4lM47QWrYVOeZc1zlFpzI8rlt+OF9dczRQJ78McYh0gbhDMA8GZ4nVyRfMq/N+cjWsnHSISgxEdKQBvIbPE86hgH44ckDGdbwJBY6LcDNLMJ/e6yCQ5OX5CFnUEHAuQj2nXkGq0KBTCHvB1RGL9hQCg/UyXUxjggYrRbC+o=
file: build/libs/xlr-slack-plugin-1.0.0.jar
file_glob: true
file: build/libs/*
skip_cleanup: true
on:
tags: true
Expand Down
7 changes: 7 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Copyright 2019 XEBIALABS

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
62 changes: 60 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,65 @@ The Slack notification task needs the next information:

![notification](images/notification.png)

---
## CreateChannel task
This task creates a new channel in slack

![CreateChannel](images/CreateChannel.png)

## AddUsersToChannel
This task adds a list of users based on their email addresses

![AddUsersToChannel](images/AddUsersToChannel.png)

## postMessage
This task posts a message to a slack channel based on the channel's ID

![postMessage](images/postMessage.png)

## Adding Slack App
This plugin needs a **Slack** to communicate. You can create a custom app to to by doing the following:

1. Got to [https://api.slack.com/apps](https://api.slack.com/apps) to start building your app

![YourApps](images/yourapps.png)

2. **Create a Slack App** - provide *App Name* and *Workspace*

![createaslackapp](images/createaslackapp.png)

3. **Add features and functionality** - *Incoming Webhooks* & *Permissions*

a. **Incoming Webhooks**

![incomingwebhooks](images/incomingwebhooks.png)

Keep track of the `Webhook URL`. This will be the URL for sending notifications.

b. **Permissions**

![permissions](images/permissions1.png)
![permissions](images/permissions2.png)
![permissions](images/permissions3.png)

Add **Slack Permissions** as follows:
- Access information about user's public channels `channels:read`
- Modify your private channels `channels:write`
- Post to specific channels in Slack `incomming-webhook`
- Add a bot user with the username *@<botname>* `chat:write:bot`
- Access your workspace's profile information `users:read`
- View email addresses of people on this workspace `users:read.email`

Keep track of the `OAuth Token` and **Reinstall App**

Use the `Webhook URL` and the `OAuth Token` to configure the connection in *XL Release*


---
## References:
* [Slack Rest API](https://api.slack.com/web)

* [Slack Rest API->Create Channel](https://api.slack.com/methods/channels.create)
* [Slack Rest API->Create Conversation](https://api.slack.com/methods/conversations.create)
* [Slack Rest API->Channels Invite](https://api.slack.com/methods/channels.invite)
* [Slack Rest API->Users Info](https://api.slack.com/methods/users.info)
* [Slack Rest API->Chat Post Message](https://api.slack.com/methods/chat.postMessage)
* [Slack Rest API->lookup By Email](https://api.slack.com/methods/users.lookupByEmail)
48 changes: 40 additions & 8 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,14 +1,46 @@
// Plugins to use
import org.apache.tools.ant.filters.ReplaceTokens

plugins {
id "java"
id "com.github.hierynomus.license" version "0.13.0"
id "com.github.hierynomus.license" version "0.14.0"
id "nebula.release" version "6.0.0"
id "com.xebialabs.xl.docker" version "1.1.0"
id "com.github.hierynomus.jython" version "0.8.0"
}

// License definition
license {
header rootProject.file('src/main/license/xebialabs_community.license')
strictCheck true
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'eclipse'
apply plugin: 'maven'

xlDocker {
compileImage = 'xebialabsunsupported/xlr_dev_compile'
compileVersion = '9.0'
runImage = 'xebialabsunsupported/xlr_dev_run'
runVersion = '9.0'
runPortMapping = '15516:5516'
}


if (!project.hasProperty('release.scope')) {
project.ext['release.scope'] = 'patch'
}

// Project version
version="1.0.2"
if (!project.hasProperty('release.useLastTag')) {
project.ext['release.useLastTag'] = true
}

processResources.configure {
filter ReplaceTokens, tokens: [
'project.version': version.toString(),
'project.name' : rootProject.name
]
}

license {
header rootProject.file('LICENSE.md')
excludes(["**/*.json", "**/echarts.min.js", "**/*.png"])
strictCheck false
ext.year = Calendar.getInstance().get(Calendar.YEAR)
ext.name = 'XEBIALABS'
}
Binary file modified gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
3 changes: 1 addition & 2 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#Mon May 30 12:17:38 CEST 2016
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.13-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-bin.zip
Binary file added images/AddUsersToChannel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/CreateChannel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/createaslackapp.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/incomingwebhooks.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/permissions1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/permissions2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/permissions3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/postMessage.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/yourapps.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed src/.DS_Store
Binary file not shown.
Binary file removed src/main/.DS_Store
Binary file not shown.
3 changes: 0 additions & 3 deletions src/main/license/xebialabs_community.license

This file was deleted.

129 changes: 129 additions & 0 deletions src/main/resources/slack/AddUsersToChannel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
#
# Copyright 2019 XEBIALABS
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

import json
import requests
import urllib2
import urllib

def addUserIdToChannel(server, channel, userId):
response = {'status': -1}
try:
query_args = {'channel': channel, "user": userId}
url = "%s/channels.invite" % ( server['api'] )
encoded_args = urllib.urlencode(query_args)
url = "%s?%s" % (url, encoded_args)
token = server['clientToken']
request = urllib2.Request( url )
request.add_header('Content-Type', 'application/x-www-form-urlencoded')
request.add_header('Authorization', 'Bearer %s' % token)
myResponse = urllib2.urlopen(request)
data = json.load(myResponse)
if( not data['ok'] ):
if( data['error'] == "cant_invite_self" ):
print "Oops, Invited myself"
return {'status': 0 }
if( data['error'] == "already_in_channel" ):
print "Oops, User is already in the channel"
return {'status': 0 }
if( data['error'] == "user_not_found" ):
print "Oops, User not found"
return {'status': 0 }
print "url = %s\n\n" % url
#print json.dumps(data, indent=4, sort_keys=True)
print "Error: %s " % data['error']
return {'status': 100 }
except urllib2.HTTPError as error:
print myResponse.info()
print 'HTTP %s error!' % error.code
print 'Reason: %s' % error.read()
print "url = %s" % url
return {'status': 300 }
except urllib2.URLError as error:
print myResponse.info()
print 'Network error!'
print 'Reason: %s' % error.reason
print "url = %s" % url
return {'status': 400 }
return {'status': 0 }

def getUserIdByEmail(server, userEmail):
try:
query_args = {'email': userEmail}
url = "%s/users.lookupByEmail" % ( server['api'] )
encoded_args = urllib.urlencode(query_args)
url = "%s?%s" % (url, encoded_args)
#url = "%s/users.lookupByEmail?user=%s" % (server['api'], userEmail)
token = server['clientToken']
request = urllib2.Request( url )
request.add_header('Content-Type', 'application/x-www-form-urlencoded')
request.add_header('Authorization', 'Bearer %s' % token)

myResponse = urllib2.urlopen(request)
data = json.load(myResponse)
#print json.dumps(data, indent=4, sort_keys=True)
if( not data['ok'] ):
print "url = %s\n\n" % url
print "Error: %s for userEmail %s\n" % (data['error'], userEmail)
return {'status': 100, 'userId': 0 }
except urllib2.HTTPError as error:
print myResponse.info()
print 'HTTP %s error!' % error.code
print 'Reason: %s' % error.read()
print "url = %s" % url
return {'status': 300, 'userId': 0 }
except urllib2.URLError as error:
print myResponse.info()
print 'Network error!'
print 'Reason: %s' % error.reason
print "url = %s" % url
return {'status': 400, 'userId': 0 }
return {'status': 0, 'userId': data['user']['id'] }

# Initialize variables & check parameters
response = ''
url = "%s/channels.invite" % (server['api'])
token = server['clientToken']
proxyUrl = server['proxyUrl']
if not url.strip():
print 'Error!'
print 'Server configuration url undefined\n'
sys.exit(100)
if not token.strip():
print 'Error!'
print 'Server configuration user token undefined\n'
sys.exit(100)
if not channel.strip():
print 'Error!'
print 'Parameter channel undefined\n'
sys.exit(200)

# Set up proxy
# proxyUrl format: 'http:// username:password@proxyurl:proxyport'
if proxyUrl:
proxy = urllib2.ProxyHandler({'http': proxyUrl.strip(), 'https': proxyUrl.strip()})
auth = urllib2.HTTPBasicAuthHandler()
opener = urllib2.build_opener(proxy, auth, urllib2.HTTPHandler)
urllib2.install_opener(opener)

# Call Slack Incoming WebHook
#channel = re.sub("#|@", "", channel)
for user in users:
results = getUserIdByEmail(server, user)
if ( results['status'] > 0 ):
#print "ERROR = %s " % results['error']
print "ERROR getUserIdByEmail for %s\n" % user
else:
results = addUserIdToChannel(server, channel, results['userId'])
if ( results['status'] > 0 ):
print "ERROR = %s " % results['error']
sys.exit(results['status'])

sys.exit(0)
72 changes: 72 additions & 0 deletions src/main/resources/slack/CreateChannel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#
# Copyright 2019 XEBIALABS
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

import json
import requests
import urllib2
import re

# Initialize variables & check parameters
response = ''
url = "%s/channels.create" % (server['api'])
token = server['clientToken']
proxyUrl = server['proxyUrl']
if not url.strip():
print 'Error!'
print 'Server configuration url undefined\n'
sys.exit(100)
if not token.strip():
print 'Error!'
print 'Server configuration user token undefined\n'
sys.exit(100)
if not channel.strip():
print 'Error!'
print 'Parameter channel undefined\n'
sys.exit(200)

# Set up proxy
# proxyUrl format: 'http:// username:password@proxyurl:proxyport'
if proxyUrl:
proxy = urllib2.ProxyHandler({'http': proxyUrl.strip(), 'https': proxyUrl.strip()})
auth = urllib2.HTTPBasicAuthHandler()
opener = urllib2.build_opener(proxy, auth, urllib2.HTTPHandler)
urllib2.install_opener(opener)

# Call Slack Incoming WebHook
channel = re.sub("#|@", "", channel)
url = "%s?name=%s&validate=true" % ( url, channel.strip() )
try:
request = urllib2.Request( url )
request.add_header('Content-Type', 'application/x-www-form-urlencoded')
request.add_header('Authorization', 'Bearer %s' % token)
myResponse = urllib2.urlopen(request)
data = json.load(myResponse)
if( not data['ok'] ):
print "url = %s\n\n" % url
print json.dumps(data, indent=4, sort_keys=True)
print "Error: %s " % data['error']
sys.exit(100)
channelId = data['channel']['id']
except urllib2.HTTPError as error:
print myResponse.info()
print 'HTTP %s error!' % error.code
print 'Reason: %s' % error.read()
print "url = %s" % url
sys.exit(300)
except urllib2.URLError as error:
print myResponse.info()
print 'Network error!'
print 'Reason: %s' % error.reason
print "url = %s" % url
sys.exit(400)

# Print output
print 'Slack channel %s created successfully' % channel
sys.exit(0)
Loading

0 comments on commit 541b581

Please sign in to comment.