├── composer.json
├── .gitignore
├── config.sample.php
├── app.json
├── .editorconfig
├── api.php
├── dist
└── css
│ └── styles.css
├── LICENSE
├── src
└── Archibald
│ ├── Api.php
│ ├── Archibald.php
│ └── Request.php
├── index.php
├── README.md
└── composer.lock
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "autoload": {
3 | "psr-4": {"Archibald\\": "src/Archibald"}
4 | },
5 | "require": {
6 | "guzzlehttp/guzzle": "~4.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor
2 | composer.phar
3 | config.php
4 | dploy.yaml
5 | TODO.md
6 | .DS_Store
7 | .DS_Store?
8 | *.sublime-*
9 | .Spotlight-V100
10 | .Trashes
11 | .ehthumbs.db
12 | Thumbs.db
13 | *.tmp
14 | .rev
15 |
--------------------------------------------------------------------------------
/config.sample.php:
--------------------------------------------------------------------------------
1 | loadConfig();
13 | $archie->setupConfigVars();
14 |
15 | /**
16 | * Return errors when there are
17 | */
18 | if ($archie->hasConfigErrors()) {
19 | $errors = $archie->getConfigErrors();
20 |
21 | foreach ($errors as $error) {
22 | echo $error . ' ';
23 | }
24 | }
25 | else {
26 | /**
27 | * Make API request when required POST vars are present
28 | */
29 | if (isset($_POST['command']) && '/archie' == $_POST['command']) {
30 | $post = $_POST;
31 | $request = new Api($post);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/dist/css/styles.css:
--------------------------------------------------------------------------------
1 | * {
2 | box-sizing: border-box;
3 | }
4 |
5 | body {
6 | font-size: 16px;
7 | font-family: Arial, Helvetica, sans-serif;
8 | line-height: 1.25;
9 | color: #555;
10 | }
11 |
12 | .container {
13 | width: 100%;
14 | max-width: 800px;
15 | margin: 0 auto;
16 | padding: 20px 0;
17 | }
18 |
19 | h1 {
20 | color: #361889;
21 | }
22 |
23 | p, img, input[type="text"] {
24 | margin-bottom: 1em;
25 | }
26 |
27 | .info {
28 | padding: 10px 20px;
29 | border-radius: 2px;
30 | width: 75%;
31 | overflow: hidden;
32 | }
33 |
34 | .info.ok {
35 | font-weight: bold;
36 | background: #47FFB5;
37 | color: #164C37;
38 | }
39 |
40 | .info.bad {
41 | background: #FFE780;
42 | }
43 |
44 | .info.bad p {
45 | font-weight: bold;
46 | }
47 |
48 | img {
49 | max-width: 100%;
50 | }
51 |
52 | input[type="text"] {
53 | width: 75%;
54 | line-height: 2;
55 | padding-left: 10px;
56 | padding-right: 10px;
57 | border: 2px solid #ccc;
58 | border-radius: 2px;
59 | font-size: 24px;
60 | color: #555;
61 | }
62 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014
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 |
--------------------------------------------------------------------------------
/src/Archibald/Api.php:
--------------------------------------------------------------------------------
1 | slashToken = SLASHCOMMAND_TOKEN;
15 |
16 | if ($request['token'] && $request['command']) {
17 | $token = $request['token'];
18 | $command = $request['command'];
19 |
20 | if ($this->isValidToken($token)) {
21 | if ($this->isValidCommand($command)) {
22 |
23 | $data = array(
24 | 'team_id' => $request['team_id'],
25 | 'channel' => $request['channel_id'],
26 | 'user_id' => $request['user_id'],
27 | 'user' => $request['user_name'],
28 | 'body' => $request['text']
29 | );
30 |
31 | $request = new Request($data);
32 | }
33 | else {
34 | echo 'Invalid Command';
35 | }
36 | }
37 | else {
38 | echo 'Invalid Slash Command Token. Please check your config!';
39 | }
40 | }
41 | else {
42 | echo 'No valid API call.';
43 | }
44 | }
45 |
46 | private function isValidToken($token)
47 | {
48 | return $token == $this->slashToken;
49 | }
50 |
51 | private function isValidCommand($command)
52 | {
53 | return $command == $this->commandName;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/index.php:
--------------------------------------------------------------------------------
1 | loadConfig();
11 | $archie->setupConfigVars();
12 |
13 | ?>
14 |
15 |
16 |
17 | Archibald
18 |
19 |
20 |
21 |
22 |
Your Archibald server is up and running
23 | hasConfigErrors()): ?>
24 |
25 |
Uh oooh! Troubles ahead…
26 |
27 | getConfigErrors();
29 | foreach ($errors as $error): ?>
30 | - = $error; ?>
31 |
32 |
33 |
34 |
35 |
I have everything I need. You’re good to go!
36 |
37 |
This is your Slash Command URL
38 |
39 |
Now head over to your Slack Integration settings and insert it into the URL field of the Slash Command Integration:
40 |

41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/src/Archibald/Archibald.php:
--------------------------------------------------------------------------------
1 | hasConfig()) {
34 | $this->configPath = DOCUMENT_ROOT . '/' . $this->configName;
35 | require_once($this->configPath);
36 | return true;
37 | }
38 |
39 | return false;
40 | }
41 |
42 | /**
43 | * Checks if the config file exists in the document root
44 | * @return boolean Returns true if file exists
45 | */
46 | private function hasConfig()
47 | {
48 | return file_exists(DOCUMENT_ROOT . '/' . $this->configName);
49 | }
50 |
51 | /**
52 | * Loops through the config variables and populates $configErrors if there
53 | * are any
54 | */
55 | public function setupConfigVars()
56 | {
57 | foreach ($this->configVars as $configVar) {
58 | $result = $this->checkConfigVar($configVar);
59 |
60 | if ($result !== true) {
61 | $this->configErrors[] = $result;
62 | }
63 | }
64 | }
65 |
66 | /**
67 | * Checks if a configuration variable is defined and not empty.
68 | * Environment variables take precedence over defined constants in config.php
69 | */
70 | private function checkConfigVar($configVar)
71 | {
72 | $check = getenv($configVar);
73 | $const = null;
74 |
75 | if ($check !== false) {
76 | if (empty($check)) {
77 | return $configVar . ' is empty. Please make sure you have properly set your configuration variables.';
78 | }
79 |
80 | return define($configVar, $check);
81 | }
82 | else if (defined($configVar)) {
83 | $const = constant($configVar);
84 |
85 | if (empty($const)) {
86 | return $configVar . ' is empty. Please make sure you have your config.php set up properly';
87 | }
88 |
89 | return true;
90 | }
91 | else {
92 | return $configVar . ' was not found. Please make sure you have it defined either in your config.php or as a Config Variable.';
93 | }
94 | }
95 |
96 | /**
97 | * @return boolean Returns true if there are errors
98 | */
99 | public function hasConfigErrors()
100 | {
101 | return $this->configErrors !== null;
102 | }
103 |
104 | /**
105 | * @return array|null
106 | */
107 | public function getConfigErrors()
108 | {
109 | return $this->configErrors;
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/src/Archibald/Request.php:
--------------------------------------------------------------------------------
1 | webhookUrl = WEBHOOK_URL;
24 |
25 | $this->body = $request['body'];
26 | $this->channel = $request['channel'];
27 | $this->user = $request['user'];
28 |
29 | $this->client = new Client();
30 |
31 | $this->parseRequestType();
32 | }
33 |
34 | public function parseRequestType()
35 | {
36 | switch ($this->body) {
37 | case 'shaq':
38 | $this->body = 'I love you!';
39 | $shaq = $this->staticRequest('shaq');
40 | break;
41 |
42 | case 'kannste':
43 | case 'kannsteschonsomachen':
44 | case 'kannstemachen':
45 | case 'kacke':
46 | $kannste = $this->staticRequest('kannste');
47 | break;
48 |
49 | case 'tags':
50 | $tags = $this->searchTags($this->body);
51 | break;
52 |
53 | case '';
54 | echo 'Please provide a tag! e.g. `/archie wow`';
55 | break;
56 |
57 | default:
58 | $search = $this->searchGif($this->body);
59 | break;
60 | }
61 | }
62 |
63 | private function staticRequest($request)
64 | {
65 | $responseBody = '';
66 |
67 | switch ($request) {
68 | case 'shaq':
69 | $responseBody = 'http://replygif.net/i/1106.gif';
70 | break;
71 | case 'kannste':
72 | $responseBody = 'http://i.imgur.com/D6iqV0b.png';
73 | break;
74 | }
75 |
76 | $this->postResponse($responseBody);
77 | }
78 |
79 | public function searchGif($requestString)
80 | {
81 | try {
82 | $response = $this->client->get(
83 | $this->requestGifs, [
84 | 'query' => [
85 | 'api-key' => $this->apiKey,
86 | 'tag' => $requestString
87 | ]
88 | ]
89 | );
90 | }
91 | catch (RequestException $e) {
92 | echo $e->getRequest();
93 | if ($e->hasResponse()) {
94 | $this->postResponse($e->getResponse());
95 | }
96 | }
97 | $responseBody = $response->getBody();
98 | $message = $this->randomGif($responseBody);
99 |
100 | if (false !== $message) {
101 | $this->postResponse($message);
102 | }
103 | else {
104 | echo 'No GIFs found with tag *' . $this->body . '*';
105 | }
106 | }
107 |
108 | public function searchTags($requestString)
109 | {
110 | try {
111 | $response = $this->client->get(
112 | $this->requestTags, [
113 | 'query' => [
114 | 'api-key' => $this->apiKey,
115 | 'reaction' => 1
116 | ]
117 | ]
118 | );
119 | }
120 | catch (RequestException $e) {
121 | echo $e->getRequest();
122 | if ($e->hasResponse()) {
123 | $this->postResponse($e->getResponse());
124 | }
125 | }
126 |
127 | $responseBody = $response->getBody();
128 | $message = $this->getTagList($responseBody);
129 | }
130 |
131 | public function randomGif($responseBody)
132 | {
133 | $gifs = json_decode($responseBody);
134 |
135 | $size = count($gifs);
136 | $randomIndex = rand(0, $size-1);
137 |
138 | if ($size < 1) {
139 | return false;
140 | }
141 | return $gifs[$randomIndex]->file;
142 | }
143 |
144 | public function getTagList($responseBody)
145 | {
146 | $tags = json_decode($responseBody);
147 |
148 | $tagList = '';
149 |
150 | foreach ($tags as $tag) {
151 | $tagList .= $tag->title . " (" . $tag->count . ")\t";
152 | }
153 |
154 | /**
155 | * The Tag List is echoed by slackbot,
156 | * so other don’t see it
157 | */
158 | echo $tagList;
159 | }
160 |
161 | public function postResponse($message)
162 | {
163 | $finalMessage = $this->user . ": <" . $message . "|" . $this->body . ">";
164 | $channel = $this->channel;
165 |
166 | $data = array(
167 | 'payload' => json_encode(array(
168 | 'username' => 'Archibald',
169 | 'icon_emoji' => ':hatched_chick:',
170 | 'channel' => $channel,
171 | 'text' => $finalMessage
172 | ))
173 | );
174 |
175 | $request = $this->client->post($this->webhookUrl, array(
176 | 'body' => $data
177 | ));
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Archibald
2 |
3 | Archibald is a Slack integration written in PHP to post tag-selected GIF replies from [replygif.net](http://replygif.net) into your current Slack channel or Direct Messages. You can either self-host it or easily set it up with the **[Heroku Deploy Button](#deploy-to-heroku)**.
4 |
5 | ## How to use Archibald
6 |
7 | 
8 |
9 | With Archibald, you can use the following commands in Slack:
10 |
11 | `/archie tags`
12 | Shows a list of all tags that can be used, together with the amount of gifs available in brackets
13 |
14 | `/archie [tag]`
15 | Use a tag to let Archibald search for a gif with that tag and randomly select one for you.
E.g: `/archie magic`
16 |
17 | `/archie shaq`
18 | You’ll love it, because he (you know who) loves you dearly!
19 |
20 | ## Get Archibald up and running
21 |
22 | You will have to take the following steps to set up and configure Archibald for your Slack team:
23 |
24 | 1. Configure Slash Command and Incoming WebHooks integrations in your Slack settings.
25 | 2. Deploy the integration with a Slash Command Token and the Incoming WebHooks URL you are given in step 1.
26 |
27 | ### Slash Command Integration
28 |
29 | Add a new **Slash Command** integration for your team.
30 |
31 | 
32 |
33 | For the Integration Settings, use the following values:
34 |
35 | | Setting | Value |
36 | |--- |--- |
37 | | Command | /archie |
38 | | URL | `http://yourOwnDomain.com/archibald/api.php` if you use your own server **or** `https://your-heroku-app-name.heroku.com/api.php` if you use Heroku Deploy Button (see below). If you don’t know the URL yet, come back later. |
39 | | Method | POST |
40 | | Autocomplete help text |  |
41 | | Descriptive Label | Archibald |
42 |
43 | You will get a token that you will have to use later to configure Archibald.
44 |
45 | 
46 |
47 | ### Incoming WebHooks Integration
48 |
49 | Now add a new **Incoming WebHooks** integration for your team.
50 |
51 | 
52 |
53 | It doesn’t matter which channel you choose for the messages to be posted to. All you need to do in the settings for the **Incoming WebHooks** integration is to copy the **Webhook URL**. You will use it when you configure Archibald. All other values of the Incoming WebHooks integration will be overwritten by Archibald.
54 |
55 | 
56 |
57 | ## Deploy to Heroku
58 |
59 | If you set up Archibald the easy way, you can use the Heroku Deploy Button:
60 |
61 | [](https://heroku.com/deploy)
62 |
63 | When you press that button, you will be redirected to Heroku, where you can set up your own app. Insert the *Token* from the **Slash Command** integration and the *Webhook URL* from the **Incoming WebHooks** integration into the respective form fields and hit *Deploy*.
64 |
65 | If you’re finished with the deployment, you can go and view the app.
66 |
67 | 
68 |
69 | Now head over to your Slack Integration settings and insert the URL you’ll be given by the app into the URL field of the **Slash Command** integration.
70 |
71 | 
72 |
73 | That’s it. You can now try out Archibald.
74 |
75 | ## Deploy to your own PHP Server
76 |
77 | ### config.php
78 |
79 | Rename `config.sample.php` to `config.php` and set the *Token* from the **Slash Command** integration as well as the *Webhook URL* from the **Incoming WebHooks** integration.
80 |
81 | ```php
82 | define('SLASHCOMMAND_TOKEN', 'Your copied Token here');
83 | define('WEBHOOK_URL', 'The copied WebHook URL here');
84 | ```
85 |
86 | ### Upload files to Webserver
87 |
88 | You need to upload all files to a webserver running PHP version 5.4.x or higher. Before you upload the files, be sure to use [Composer](https://getcomposer.org/) to also include all vendor files.
89 |
90 | ```sh
91 | composer install
92 | ```
93 |
--------------------------------------------------------------------------------
/composer.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_readme": [
3 | "This file locks the dependencies of your project to a known state",
4 | "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
5 | "This file is @generated automatically"
6 | ],
7 | "hash": "6e8ba63e698c0c932877006e794f463e",
8 | "packages": [
9 | {
10 | "name": "guzzlehttp/guzzle",
11 | "version": "4.2.3",
12 | "source": {
13 | "type": "git",
14 | "url": "https://github.com/guzzle/guzzle.git",
15 | "reference": "66fd916e9f9130bc22c51450476823391cb2f67c"
16 | },
17 | "dist": {
18 | "type": "zip",
19 | "url": "https://api.github.com/repos/guzzle/guzzle/zipball/66fd916e9f9130bc22c51450476823391cb2f67c",
20 | "reference": "66fd916e9f9130bc22c51450476823391cb2f67c",
21 | "shasum": ""
22 | },
23 | "require": {
24 | "ext-json": "*",
25 | "guzzlehttp/streams": "~2.1",
26 | "php": ">=5.4.0"
27 | },
28 | "require-dev": {
29 | "ext-curl": "*",
30 | "phpunit/phpunit": "~4.0",
31 | "psr/log": "~1.0"
32 | },
33 | "suggest": {
34 | "ext-curl": "Guzzle will use specific adapters if cURL is present"
35 | },
36 | "type": "library",
37 | "extra": {
38 | "branch-alias": {
39 | "dev-master": "4.2-dev"
40 | }
41 | },
42 | "autoload": {
43 | "psr-4": {
44 | "GuzzleHttp\\": "src/"
45 | },
46 | "files": [
47 | "src/functions.php"
48 | ]
49 | },
50 | "notification-url": "https://packagist.org/downloads/",
51 | "license": [
52 | "MIT"
53 | ],
54 | "authors": [
55 | {
56 | "name": "Michael Dowling",
57 | "email": "mtdowling@gmail.com",
58 | "homepage": "https://github.com/mtdowling"
59 | }
60 | ],
61 | "description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients",
62 | "homepage": "http://guzzlephp.org/",
63 | "keywords": [
64 | "client",
65 | "curl",
66 | "framework",
67 | "http",
68 | "http client",
69 | "rest",
70 | "web service"
71 | ],
72 | "time": "2014-10-05 19:29:14"
73 | },
74 | {
75 | "name": "guzzlehttp/streams",
76 | "version": "2.1.0",
77 | "source": {
78 | "type": "git",
79 | "url": "https://github.com/guzzle/streams.git",
80 | "reference": "f91b721d73f0e561410903b3b3c90a5d0e40b534"
81 | },
82 | "dist": {
83 | "type": "zip",
84 | "url": "https://api.github.com/repos/guzzle/streams/zipball/f91b721d73f0e561410903b3b3c90a5d0e40b534",
85 | "reference": "f91b721d73f0e561410903b3b3c90a5d0e40b534",
86 | "shasum": ""
87 | },
88 | "require": {
89 | "php": ">=5.4.0"
90 | },
91 | "require-dev": {
92 | "phpunit/phpunit": "~4.0"
93 | },
94 | "type": "library",
95 | "extra": {
96 | "branch-alias": {
97 | "dev-master": "2.0-dev"
98 | }
99 | },
100 | "autoload": {
101 | "psr-4": {
102 | "GuzzleHttp\\Stream\\": "src/"
103 | },
104 | "files": [
105 | "src/functions.php"
106 | ]
107 | },
108 | "notification-url": "https://packagist.org/downloads/",
109 | "license": [
110 | "MIT"
111 | ],
112 | "authors": [
113 | {
114 | "name": "Michael Dowling",
115 | "email": "mtdowling@gmail.com",
116 | "homepage": "https://github.com/mtdowling"
117 | }
118 | ],
119 | "description": "Provides a simple abstraction over streams of data (Guzzle 4+)",
120 | "homepage": "http://guzzlephp.org/",
121 | "keywords": [
122 | "Guzzle",
123 | "stream"
124 | ],
125 | "time": "2014-08-17 21:15:53"
126 | }
127 | ],
128 | "packages-dev": [],
129 | "aliases": [],
130 | "minimum-stability": "stable",
131 | "stability-flags": [],
132 | "prefer-stable": false,
133 | "prefer-lowest": false,
134 | "platform": [],
135 | "platform-dev": []
136 | }
137 |
--------------------------------------------------------------------------------