Merged master to re-converge after merge of PR #983

Ian Blenke 9 anos atrás
pai
commit
7b952fa8ac
105 arquivos alterados com 1586 adições e 761 exclusões
  1. 12 2
      .env.example
  2. 1 0
      .gitignore
  3. 8 2
      Capfile
  4. 7 4
      Gemfile
  5. 33 10
      Gemfile.lock
  6. 1 1
      Guardfile
  7. 40 3
      Procfile
  8. 15 3
      README.md
  9. 16 0
      app/assets/javascripts/pages/agent-edit-page.js.coffee
  10. 5 0
      app/assets/stylesheets/application.css.scss.erb
  11. 2 2
      app/concerns/markdown_class_attributes.rb
  12. 6 1
      app/controllers/agents_controller.rb
  13. 9 0
      app/controllers/jobs_controller.rb
  14. 1 0
      app/models/agents/adioso_agent.rb
  15. 1 2
      app/models/agents/basecamp_agent.rb
  16. 1 1
      app/models/agents/change_detector_agent.rb
  17. 1 1
      app/models/agents/commander_agent.rb
  18. 1 1
      app/models/agents/data_output_agent.rb
  19. 1 1
      app/models/agents/de_duplication_agent.rb
  20. 2 2
      app/models/agents/dropbox_file_url_agent.rb
  21. 2 1
      app/models/agents/dropbox_watch_agent.rb
  22. 1 1
      app/models/agents/email_agent.rb
  23. 1 1
      app/models/agents/email_digest_agent.rb
  24. 1 1
      app/models/agents/event_formatting_agent.rb
  25. 3 1
      app/models/agents/ftpsite_agent.rb
  26. 2 1
      app/models/agents/google_calendar_publish_agent.rb
  27. 2 1
      app/models/agents/growl_agent.rb
  28. 2 1
      app/models/agents/hipchat_agent.rb
  29. 2 1
      app/models/agents/human_task_agent.rb
  30. 21 59
      app/models/agents/imap_folder_agent.rb
  31. 2 1
      app/models/agents/jabber_agent.rb
  32. 1 1
      app/models/agents/java_script_agent.rb
  33. 5 4
      app/models/agents/jira_agent.rb
  34. 1 1
      app/models/agents/manual_event_agent.rb
  35. 2 1
      app/models/agents/mqtt_agent.rb
  36. 2 0
      app/models/agents/pdf_info_agent.rb
  37. 2 4
      app/models/agents/peak_detector_agent.rb
  38. 5 2
      app/models/agents/post_agent.rb
  39. 4 2
      app/models/agents/public_transport_agent.rb
  40. 1 1
      app/models/agents/pushover_agent.rb
  41. 1 1
      app/models/agents/rss_agent.rb
  42. 1 1
      app/models/agents/scheduler_agent.rb
  43. 2 3
      app/models/agents/sentiment_agent.rb
  44. 1 1
      app/models/agents/shell_command_agent.rb
  45. 8 11
      app/models/agents/slack_agent.rb
  46. 3 1
      app/models/agents/stubhub_agent.rb
  47. 3 1
      app/models/agents/translation_agent.rb
  48. 1 1
      app/models/agents/trigger_agent.rb
  49. 2 2
      app/models/agents/tumblr_publish_agent.rb
  50. 2 1
      app/models/agents/twilio_agent.rb
  51. 2 1
      app/models/agents/twitter_publish_agent.rb
  52. 3 2
      app/models/agents/twitter_stream_agent.rb
  53. 10 2
      app/models/agents/twitter_user_agent.rb
  54. 6 9
      app/models/agents/user_location_agent.rb
  55. 2 1
      app/models/agents/weather_agent.rb
  56. 14 14
      app/models/agents/webhook_agent.rb
  57. 1 1
      app/models/agents/website_agent.rb
  58. 4 3
      app/models/agents/weibo_publish_agent.rb
  59. 2 1
      app/models/agents/weibo_user_agent.rb
  60. 4 2
      app/models/agents/witai_agent.rb
  61. 3 4
      app/models/agents/wunderlist_agent.rb
  62. 1 1
      app/views/agents/_form.html.erb
  63. 4 0
      app/views/jobs/index.html.erb
  64. 2 1
      app/views/scenarios/show.html.erb
  65. 0 4
      bin/rails
  66. 0 4
      bin/rake
  67. 0 4
      bin/rspec
  68. 0 15
      bin/spring
  69. 54 0
      config/deploy.rb
  70. 1 0
      config/deploy/production.rb
  71. 5 2
      config/environments/development.rb
  72. 5 0
      config/routes.rb
  73. 9 9
      deployment/site-cookbooks/huginn_production/files/default/unicorn.rb
  74. 0 3
      deployment/.chef/knife.rb
  75. 0 11
      deployment/Cheffile
  76. 0 71
      deployment/Cheffile.lock
  77. 0 40
      deployment/Vagrantfile
  78. 20 0
      deployment/logrotate/huginn
  79. 70 0
      deployment/nginx/huginn
  80. 119 0
      deployment/nginx/huginn-ssl
  81. 0 30
      deployment/roles/huginn_development.json
  82. 0 30
      deployment/roles/huginn_production.json
  83. 0 78
      deployment/site-cookbooks/huginn_development/recipes/default.rb
  84. 0 2
      deployment/site-cookbooks/huginn_production/files/default/Procfile
  85. 0 109
      deployment/site-cookbooks/huginn_production/files/default/env.example
  86. 0 36
      deployment/site-cookbooks/huginn_production/files/default/nginx.conf
  87. 0 111
      deployment/site-cookbooks/huginn_production/recipes/default.rb
  88. 20 0
      doc/README.md
  89. 0 0
      doc/configuration/dotenv.md
  90. 0 0
      doc/configuration/procfile.md
  91. 44 0
      doc/docker/install.md
  92. 144 0
      doc/heroku/install.md
  93. 9 0
      doc/heroku/update.md
  94. 6 0
      doc/manual/README.md
  95. 47 0
      doc/manual/capistrano.md
  96. 401 0
      doc/manual/installation.md
  97. 68 0
      doc/manual/requirements.md
  98. 92 0
      doc/manual/update.md
  99. 1 1
      docker/README.md
  100. 1 1
      docker/scripts/setup
  101. 94 0
      lib/tasks/production.rake
  102. 26 10
      spec/controllers/agents_controller_spec.rb
  103. 16 3
      spec/controllers/jobs_controller_spec.rb
  104. 25 1
      spec/models/agents/post_agent_spec.rb
  105. 2 0
      spec/models/agents/twitter_user_agent_spec.rb

+ 12 - 2
.env.example

@@ -57,7 +57,7 @@ SKIP_INVITATION_CODE=false
57 57
 # Outgoing email settings.  To use Gmail or Google Apps, put your Google Apps domain or gmail.com
58 58
 # as the SMTP_DOMAIN and your Gmail username and password as the SMTP_USER_NAME and SMTP_PASSWORD.
59 59
 #
60
-# PLEASE NOTE: In order to enable emails locally (e.g., when not in the production Rails environment),
60
+# PLEASE NOTE: In order to enable sending real emails via SMTP locally (e.g., when not in the production Rails environment),
61 61
 # you must also set SEND_EMAIL_IN_DEVELOPMENT to true below.
62 62
 #
63 63
 # If you have trouble with port 587 on Gmail, you can also try setting
@@ -71,7 +71,8 @@ SMTP_PORT=587
71 71
 SMTP_AUTHENTICATION=plain
72 72
 SMTP_ENABLE_STARTTLS_AUTO=true
73 73
 
74
-# Send emails when running in the development Rails environment.
74
+# Set to true to send real emails via SMTP when running in the development Rails environment.
75
+# Set to false to have emails intercepted in development and displayed at http://localhost:3000/letter_opener
75 76
 SEND_EMAIL_IN_DEVELOPMENT=false
76 77
 
77 78
 # The address from which system emails will appear to be sent.
@@ -174,3 +175,12 @@ DELAYED_JOB_MAX_RUNTIME=2
174 175
 
175 176
 # Amount of seconds for delayed_job to sleep before checking for new jobs
176 177
 DELAYED_JOB_SLEEP_DELAY=10
178
+
179
+###############################################################
180
+# Capistrano deployment, read the documentation:              #
181
+# https://github.com/cantino/huginn/doc/manual/capistrano.md  #
182
+###############################################################
183
+
184
+#CAPISTRANO_DEPLOY_SERVER=
185
+#CAPISTRANO_DEPLOY_USER=
186
+#CAPISTRANO_DEPLOY_REPO_URL=

+ 1 - 0
.gitignore

@@ -25,3 +25,4 @@ deployment/cookbooks
25 25
 .ruby-gemset
26 26
 .ruby-version
27 27
 manifest.yml
28
+config/unicorn.rb

+ 8 - 2
Capfile

@@ -1,2 +1,8 @@
1
-load 'deploy'
2
-load 'config/deploy'
1
+# Load DSL and set up stages
2
+require 'capistrano/setup'
3
+# Include default deployment tasks
4
+require 'capistrano/deploy'
5
+
6
+require 'capistrano/bundler'
7
+require 'capistrano/rails/assets'
8
+require 'capistrano/rails/migrations'

+ 7 - 4
Gemfile

@@ -99,8 +99,13 @@ group :development do
99 99
   gem 'binding_of_caller'
100 100
   gem 'quiet_assets'
101 101
   gem 'guard'
102
-  gem 'guard-livereload'
102
+  gem 'guard-livereload', '~> 2.2'
103 103
   gem 'guard-rspec'
104
+  gem 'letter_opener_web'
105
+
106
+  gem 'capistrano', '~> 3.4.0'
107
+  gem 'capistrano-rails', '~> 1.1'
108
+  gem 'capistrano-bundler', '~> 1.1.4'
104 109
 
105 110
   group :test do
106 111
     gem 'coveralls', require: false
@@ -112,8 +117,6 @@ group :development do
112 117
     gem 'rspec-rails', '~> 3.1'
113 118
     gem 'rspec-html-matchers', '~> 0.7'
114 119
     gem 'shoulda-matchers'
115
-    gem 'spring', '~> 1.3.0'
116
-    gem 'spring-commands-rspec'
117 120
     gem 'vcr'
118 121
     gem 'webmock', '~> 1.17.4', require: false
119 122
   end
@@ -121,6 +124,7 @@ end
121 124
 
122 125
 group :production do
123 126
   gem 'rack', '> 1.5.0'
127
+  gem 'unicorn', '~> 4.9.0'
124 128
 end
125 129
 
126 130
 # Platform requirements.
@@ -146,6 +150,5 @@ end
146 150
 
147 151
 on_heroku do
148 152
   gem 'pg'
149
-  gem 'unicorn'
150 153
   gem 'rails_12factor', group: :production
151 154
 end

+ 33 - 10
Gemfile.lock

@@ -84,6 +84,16 @@ GEM
84 84
       rails (>= 3.1)
85 85
     buftok (0.2.0)
86 86
     builder (3.2.2)
87
+    capistrano (3.4.0)
88
+      i18n
89
+      rake (>= 10.0.0)
90
+      sshkit (~> 1.3)
91
+    capistrano-bundler (1.1.4)
92
+      capistrano (~> 3.1)
93
+      sshkit (~> 1.2)
94
+    capistrano-rails (1.1.3)
95
+      capistrano (~> 3.1)
96
+      capistrano-bundler (~> 1.1)
87 97
     celluloid (0.16.0)
88 98
       timers (~> 4.0.0)
89 99
     chronic (0.10.2)
@@ -95,6 +105,7 @@ GEM
95 105
       coffee-script-source
96 106
       execjs
97 107
     coffee-script-source (1.9.1)
108
+    colorize (0.7.7)
98 109
     cookiejar (0.3.2)
99 110
     coveralls (0.7.1)
100 111
       multi_json (~> 1.3)
@@ -230,10 +241,16 @@ GEM
230 241
     kaminari (0.16.1)
231 242
       actionpack (>= 3.0.0)
232 243
       activesupport (>= 3.0.0)
233
-    kgio (2.9.2)
244
+    kgio (2.9.3)
234 245
     kramdown (1.3.3)
235 246
     launchy (2.4.2)
236 247
       addressable (~> 2.3)
248
+    letter_opener (1.4.1)
249
+      launchy (~> 2.2)
250
+    letter_opener_web (1.3.0)
251
+      actionmailer (>= 3.2)
252
+      letter_opener (~> 1.0)
253
+      railties (>= 3.2)
237 254
     libv8 (3.16.14.7)
238 255
     liquid (3.0.6)
239 256
     listen (2.7.9)
@@ -261,6 +278,9 @@ GEM
261 278
     mysql2 (0.3.16)
262 279
     naught (1.0.0)
263 280
     net-ftp-list (3.2.8)
281
+    net-scp (1.2.1)
282
+      net-ssh (>= 2.6.5)
283
+    net-ssh (2.9.2)
264 284
     netrc (0.10.3)
265 285
     nokogiri (1.6.6.2)
266 286
       mini_portile (~> 0.6.0)
@@ -413,15 +433,16 @@ GEM
413 433
     slop (3.6.0)
414 434
     spectrum-rails (1.3.4)
415 435
       railties (>= 3.1)
416
-    spring (1.3.6)
417
-    spring-commands-rspec (1.0.4)
418
-      spring (>= 0.9.1)
419 436
     sprockets (3.2.0)
420 437
       rack (~> 1.0)
421 438
     sprockets-rails (2.3.1)
422 439
       actionpack (>= 3.0)
423 440
       activesupport (>= 3.0)
424 441
       sprockets (>= 2.8, < 4.0)
442
+    sshkit (1.7.1)
443
+      colorize (>= 0.7.0)
444
+      net-scp (>= 1.1.2)
445
+      net-ssh (>= 2.8.0)
425 446
     string-scrub (0.0.5)
426 447
     systemu (2.6.4)
427 448
     term-ansicolor (1.3.0)
@@ -469,7 +490,7 @@ GEM
469 490
     unf (0.1.4)
470 491
       unf_ext
471 492
     unf_ext (0.0.7.1)
472
-    unicorn (4.8.3)
493
+    unicorn (4.9.0)
473 494
       kgio (~> 2.6)
474 495
       rack
475 496
       raindrops (~> 0.7)
@@ -497,6 +518,9 @@ DEPENDENCIES
497 518
   binding_of_caller
498 519
   bootstrap-kaminari-views (~> 0.0.3)
499 520
   bundler (>= 1.5.0)
521
+  capistrano (~> 3.4.0)
522
+  capistrano-bundler (~> 1.1.4)
523
+  capistrano-rails (~> 1.1)
500 524
   coffee-rails (~> 4.1.0)
501 525
   coveralls
502 526
   daemons (~> 1.1.9)
@@ -518,7 +542,7 @@ DEPENDENCIES
518 542
   geokit-rails (~> 2.0.1)
519 543
   google-api-client
520 544
   guard
521
-  guard-livereload
545
+  guard-livereload (~> 2.2)
522 546
   guard-rspec
523 547
   haversine
524 548
   hipchat (~> 1.2.0)
@@ -529,6 +553,7 @@ DEPENDENCIES
529 553
   jsonpath (~> 0.5.6)
530 554
   kaminari (~> 0.16.1)
531 555
   kramdown (~> 1.3.3)
556
+  letter_opener_web
532 557
   liquid (~> 3.0.3)
533 558
   mini_magick
534 559
   mqtt
@@ -562,8 +587,6 @@ DEPENDENCIES
562 587
   shoulda-matchers
563 588
   slack-notifier (~> 1.0.0)
564 589
   spectrum-rails
565
-  spring (~> 1.3.0)
566
-  spring-commands-rspec
567 590
   string-scrub
568 591
   therubyracer (~> 0.12.2)
569 592
   tumblr_client
@@ -574,7 +597,7 @@ DEPENDENCIES
574 597
   tzinfo (>= 1.2.0)
575 598
   tzinfo-data
576 599
   uglifier (>= 1.3.0)
577
-  unicorn
600
+  unicorn (~> 4.9.0)
578 601
   vcr
579 602
   webmock (~> 1.17.4)
580 603
   weibo_2!
@@ -582,4 +605,4 @@ DEPENDENCIES
582 605
   xmpp4r (~> 0.5.6)
583 606
 
584 607
 BUNDLED WITH
585
-   1.10.5
608
+   1.10.6

+ 1 - 1
Guardfile

@@ -8,7 +8,7 @@ guard 'livereload' do
8 8
   watch(%r{(app|vendor)(/assets/\w+/(.+\.(css|js|html|png|jpg))).*}) { |m| "/assets/#{m[3]}" }
9 9
 end
10 10
 
11
-guard :rspec, cmd: 'bundle exec spring rspec' do
11
+guard :rspec, cmd: 'bundle exec rspec' do
12 12
   watch(%r{^spec/.+_spec\.rb$})
13 13
   watch(%r{^lib/(.+)\.rb$})     { |m| "spec/lib/#{m[1]}_spec.rb" }
14 14
   watch('spec/spec_helper.rb')  { "spec" }

+ 40 - 3
Procfile

@@ -1,13 +1,50 @@
1
+###############################
2
+#         DEVELOPMENT         #
3
+###############################
4
+
1 5
 # Procfile for development using the new threaded worker (scheduler, twitter stream and delayed job)
2 6
 web: bundle exec rails server -b0.0.0.0
3 7
 jobs: bundle exec rails runner bin/threaded.rb
4 8
 
5
-# Possible Profile configuration for production:
6
-# web: bundle exec unicorn -c config/unicorn/production.rb
9
+# Old version with separate processes (use this if you have issues with the threaded version)
10
+# web: bundle exec rails server
11
+# schedule: bundle exec rails runner bin/schedule.rb
12
+# twitter: bundle exec rails runner bin/twitter_stream.rb
13
+# dj: bundle exec script/delayed_job run
14
+
15
+###############################
16
+#         PRODUCTION          #
17
+###############################
18
+
19
+# You need to copy or link config/unicorn.rb.example to config/unicorn.rb for both production versions.
20
+# Have a look at the deployment guides, if you want to set up huginn on your server:
21
+# https://github.com/cantino/huginn/doc
22
+
23
+# Using the threaded worker (consumes less RAM but can run slower)
24
+# web: bundle exec unicorn -c config/unicorn.rb
7 25
 # jobs: bundle exec rails runner bin/threaded.rb
8 26
 
9 27
 # Old version with separate processes (use this if you have issues with the threaded version)
10
-# web: bundle exec rails server -b0.0.0.0
28
+# web: bundle exec unicorn -c config/unicorn.rb
11 29
 # schedule: bundle exec rails runner bin/schedule.rb
12 30
 # twitter: bundle exec rails runner bin/twitter_stream.rb
13 31
 # dj: bundle exec script/delayed_job run
32
+
33
+###############################
34
+# Multiple DelayedJob workers #
35
+###############################
36
+# Per default Huginn can just run one agent at a time. Using a lot of agents or calling slow
37
+# external services frequently might require more DelayedJob workers (an indicator for this is
38
+# a backlog in your 'Job Management' page).
39
+# Every uncommented line starts an additional DelayedJob worker. This works for development, production
40
+# and for the threaded and separate worker processes. Keep in mind one worker needs about 300MB of RAM.
41
+#
42
+#dj2: bundle exec script/delayed_job -i 2 run
43
+#dj3: bundle exec script/delayed_job -i 3 run
44
+#dj4: bundle exec script/delayed_job -i 4 run
45
+#dj5: bundle exec script/delayed_job -i 5 run
46
+#dj6: bundle exec script/delayed_job -i 6 run
47
+#dj7: bundle exec script/delayed_job -i 7 run
48
+#dj8: bundle exec script/delayed_job -i 8 run
49
+#dj9: bundle exec script/delayed_job -i 9 run
50
+#dj10: bundle exec script/delayed_job -i 10 run

+ 15 - 3
README.md

@@ -53,7 +53,11 @@ And now, some example screenshots.  Below them are instructions to get you start
53 53
 
54 54
 ## Getting Started
55 55
 
56
-### Quick Start
56
+### Docker
57
+
58
+The quickest and easiest way to check out Huginn is to use the offical Docker image. Have a look at the [documentation](./doc/docker/install.md).
59
+
60
+### Local Installation
57 61
 
58 62
 If you just want to play around, you can simply fork this repository, then perform the following steps:
59 63
 
@@ -66,7 +70,9 @@ If you just want to play around, you can simply fork this repository, then perfo
66 70
 * Read the [wiki][wiki] for usage examples and to get started making new Agents.
67 71
 * Periodically run `git fetch upstream` and then `git checkout master && git merge upstream/master` to merge in the newest version of Huginn.
68 72
 
69
-Note: by default, emails are not sent in the `development` Rails environment, which is what you just setup.  If you'd like to enable emails when playing with Huginn locally, set `SEND_EMAIL_IN_DEVELOPMENT` to `true` in your `.env` file.
73
+Note: By default, emails are intercepted in the `development` Rails environment, which is what you just setup.  You can view 
74
+them at [http://localhost:3000/letter_opener](http://localhost:3000/letter_opener). If you'd like to send real emails via SMTP when playing 
75
+with Huginn locally, set `SEND_EMAIL_IN_DEVELOPMENT` to `true` in your `.env` file.
70 76
 
71 77
 If you need more detailed instructions, see the [Novice setup guide][novice-setup-guide].
72 78
 
@@ -80,12 +86,18 @@ All agents have specs! Test all specs with `bundle exec rspec`, or test a specif
80 86
 
81 87
 ## Deployment
82 88
 
83
-Try Huginn on Heroku: [![Deploy](https://www.herokucdn.com/deploy/button.png)](https://heroku.com/deploy) (Takes a few minutes to setup.  Be sure to click 'View it' after launch!)
89
+### Heroku
90
+
91
+Try Huginn on Heroku: [![Deploy](https://www.herokucdn.com/deploy/button.png)](https://heroku.com/deploy) (Takes a few minutes to setup. Read the [documentation](./doc/heroku/install.md) while you are waiting and be sure to click 'View it' after launch!)
84 92
 
85 93
 Huginn works on the free version of Heroku [with limitations](https://github.com/cantino/huginn/wiki/Run-Huginn-for-free-on-Heroku). For non-experimental use, we recommend Heroku's cheapest paid plan or our Docker container.
86 94
 
87 95
 Please see [the Huginn Wiki](https://github.com/cantino/huginn/wiki#deploying-huginn) for detailed deployment strategies for different providers.
88 96
 
97
+### Manual installation on any server
98
+
99
+Have a look at the [installation guide](./doc/manual/README.md).
100
+
89 101
 ### Optional Setup
90 102
 
91 103
 #### Setup for private development

+ 16 - 0
app/assets/javascripts/pages/agent-edit-page.js.coffee

@@ -16,6 +16,17 @@ class @AgentEditPage
16 16
     if $("#agent_type").length
17 17
       $("#agent_type").on "change", => @handleTypeChange(false)
18 18
       @handleTypeChange(true)
19
+
20
+      # Update the dropdown to match agent description as well as agent name
21
+      $('#agent_type').select2
22
+        width: 'resolve'
23
+        formatResult: formatAgentForSelect
24
+        escapeMarkup: (m) ->
25
+          m
26
+        matcher: (term, text, opt) ->
27
+          description = opt.attr('title')
28
+          text.toUpperCase().indexOf(term.toUpperCase()) >= 0 or description.toUpperCase().indexOf(term.toUpperCase()) >= 0
29
+
19 30
     else
20 31
       @enableDryRunButton()
21 32
       @buildAce()
@@ -177,5 +188,10 @@ class @AgentEditPage
177 188
     @updateFromEditors()
178 189
     Utils.handleDryRunButton(e.target)
179 190
 
191
+  formatAgentForSelect = (agent) ->
192
+    originalOption = agent.element
193
+    description = agent.element[0].title
194
+    '<strong>' + agent.text + '</strong><br/>' + description
195
+
180 196
 $ ->
181 197
   Utils.registerPage(AgentEditPage, forPathsMatching: /^agents/)

+ 5 - 0
app/assets/stylesheets/application.css.scss.erb

@@ -304,3 +304,8 @@ $service-colors:      #55acee     #8fc857     #444444     #2c4762     #007EE5
304 304
 .label-service {
305 305
   @include services;
306 306
 }
307
+
308
+.select2-highlighted a {
309
+  color: yellow;
310
+  text-decoration: underline;
311
+}

+ 2 - 2
app/concerns/markdown_class_attributes.rb

@@ -11,7 +11,7 @@ module MarkdownClassAttributes
11 11
 
12 12
           def #{attribute}
13 13
             if self.class.#{attribute}.is_a?(Proc)
14
-              Utils.unindent(self.instance_eval(&self.class.#{attribute}) || "No #{attribute} has been set.").tap {|i| p i}
14
+              Utils.unindent(self.instance_eval(&self.class.#{attribute}) || "No #{attribute} has been set.")
15 15
             else
16 16
               Utils.unindent(self.class.#{attribute} || "No #{attribute} has been set.")
17 17
             end
@@ -29,4 +29,4 @@ module MarkdownClassAttributes
29 29
       end
30 30
     end
31 31
   end
32
-end
32
+end

+ 6 - 1
app/controllers/agents_controller.rb

@@ -148,6 +148,9 @@ class AgentsController < ApplicationController
148 148
     else
149 149
       @agent = agents.build
150 150
     end
151
+
152
+    @agent.scenario_ids = [params[:scenario_id]] if params[:scenario_id] && current_user.scenarios.find_by(id: params[:scenario_id])
153
+
151 154
     initialize_presenter
152 155
 
153 156
     respond_to do |format|
@@ -236,8 +239,10 @@ class AgentsController < ApplicationController
236 239
     when "show"
237 240
       if @agent && !@agent.destroyed?
238 241
         path = agent_path(@agent)
242
+      else
243
+        path = agents_path
239 244
       end
240
-    when /\A#{Regexp::escape scenarios_path}\/\d+\Z/, agents_path
245
+    when /\A#{Regexp::escape scenarios_path}\/\d+\z/, agents_path
241 246
       path = ret
242 247
     end
243 248
 

+ 9 - 0
app/controllers/jobs_controller.rb

@@ -48,6 +48,15 @@ class JobsController < ApplicationController
48 48
     end
49 49
   end
50 50
 
51
+  def destroy_all
52
+    Delayed::Job.where(locked_at: nil).delete_all
53
+
54
+    respond_to do |format|
55
+      format.html { redirect_to jobs_path, notice: "All jobs removed." }
56
+      format.json { render json: '', status: :ok }
57
+    end
58
+  end
59
+
51 60
   private
52 61
 
53 62
   def running?

+ 1 - 0
app/models/agents/adioso_agent.rb

@@ -6,6 +6,7 @@ module Agents
6 6
 
7 7
     description <<-MD
8 8
   		The Adioso Agent will tell you the minimum airline prices between a pair of cities, and within a certain period of time.
9
+
9 10
       The currency is USD. Please make sure that the difference between `start_date` and `end_date` is less than 150 days. You will need to contact [Adioso](http://adioso.com/)
10 11
   		for a `username` and `password`.
11 12
     MD

+ 1 - 2
app/models/agents/basecamp_agent.rb

@@ -7,10 +7,9 @@ module Agents
7 7
     cannot_receive_events!
8 8
 
9 9
     description <<-MD
10
-      The BasecampAgent checks a Basecamp project for new Events
10
+      The Basecamp Agent checks a Basecamp project for new Events
11 11
 
12 12
       To be able to use this Agent you need to authenticate with 37signals in the [Services](/services) section first.
13
-
14 13
     MD
15 14
 
16 15
     event_description <<-MD

+ 1 - 1
app/models/agents/change_detector_agent.rb

@@ -3,7 +3,7 @@ module Agents
3 3
     cannot_be_scheduled!
4 4
 
5 5
     description <<-MD
6
-      The ChangeDetectorAgent receives a stream of events and emits a new event when a property of the received event changes.
6
+      The Change Detector Agent receives a stream of events and emits a new event when a property of the received event changes.
7 7
 
8 8
       `property` specifies the property to be watched.
9 9
 

+ 1 - 1
app/models/agents/commander_agent.rb

@@ -5,7 +5,7 @@ module Agents
5 5
     cannot_create_events!
6 6
 
7 7
     description <<-MD
8
-      This agent is triggered by schedule or an incoming event and commands other agents ("targets") to run, disable, configure, or enable themselves.
8
+      The Commander Agent is triggered by schedule or an incoming event, and commands other agents ("targets") to run, disable, configure, or enable themselves.
9 9
 
10 10
       # Action types
11 11
 

+ 1 - 1
app/models/agents/data_output_agent.rb

@@ -4,7 +4,7 @@ module Agents
4 4
 
5 5
     description  do
6 6
       <<-MD
7
-        The Agent outputs received events as either RSS or JSON.  Use it to output a public or private stream of Huginn data.
7
+        The Data Output Agent outputs received events as either RSS or JSON.  Use it to output a public or private stream of Huginn data.
8 8
 
9 9
         This Agent will output data at:
10 10
 

+ 1 - 1
app/models/agents/de_duplication_agent.rb

@@ -4,7 +4,7 @@ module Agents
4 4
     cannot_be_scheduled!
5 5
 
6 6
     description <<-MD
7
-      The DeDuplicationAgent receives a stream of events and remits the event if it is not a duplicate.
7
+      The De-duplication Agent receives a stream of events and remits the event if it is not a duplicate.
8 8
 
9 9
       `property` the value that should be used to determine the uniqueness of the event (empty to use the whole payload)
10 10
 

+ 2 - 2
app/models/agents/dropbox_file_url_agent.rb

@@ -5,9 +5,9 @@ module Agents
5 5
     cannot_be_scheduled!
6 6
 
7 7
     description <<-MD
8
+      The Dropbox File Url Agent is used to work with Dropbox. It takes a file path (or multiple file paths) and emits events with [temporary links](https://www.dropbox.com/developers/core/docs#media).
9
+
8 10
       #{'## Include the `dropbox-api` and `omniauth-dropbox` gems in your `Gemfile` and set `DROPBOX_OAUTH_KEY` and `DROPBOX_OAUTH_SECRET` in your environment to use Dropbox Agents.' if dependencies_missing?}
9
-      The _DropboxFileUrlAgent_ is used to work with Dropbox. It takes a file path (or multiple files paths) and emits
10
-      events with [temporary links](https://www.dropbox.com/developers/core/docs#media).
11 11
 
12 12
       The incoming event payload needs to have a `paths` key, with a comma-separated list of files you want the URL for. For example:
13 13
 

+ 2 - 1
app/models/agents/dropbox_watch_agent.rb

@@ -6,8 +6,9 @@ module Agents
6 6
     default_schedule "every_1m"
7 7
 
8 8
     description <<-MD
9
+      The Dropbox Watch Agent watches the given `dir_to_watch` and emits events with the detected changes.
10
+      
9 11
       #{'## Include the `dropbox-api` and `omniauth-dropbox` gems in your `Gemfile` and set `DROPBOX_OAUTH_KEY` and `DROPBOX_OAUTH_SECRET` in your environment to use Dropbox Agents.' if dependencies_missing?}
10
-      The _DropboxWatchAgent_ watches the given `dir_to_watch` and emits events with the detected changes.
11 12
     MD
12 13
 
13 14
     event_description <<-MD

+ 1 - 1
app/models/agents/email_agent.rb

@@ -6,7 +6,7 @@ module Agents
6 6
     cannot_create_events!
7 7
 
8 8
     description <<-MD
9
-      The EmailAgent sends any events it receives via email immediately.
9
+      The Email Agent sends any events it receives via email immediately.
10 10
 
11 11
       You can specify the email's subject line by providing a `subject` option, which can contain Liquid formatting.  E.g.,
12 12
       you could provide `"Huginn email"` to set a simple subject, or `{{subject}}` to use the `subject` key from the incoming Event.

+ 1 - 1
app/models/agents/email_digest_agent.rb

@@ -7,7 +7,7 @@ module Agents
7 7
     cannot_create_events!
8 8
 
9 9
     description <<-MD
10
-      The EmailDigestAgent collects any Events sent to it and sends them all via email when scheduled.
10
+      The Email Digest Agent collects any Events sent to it and sends them all via email when scheduled.
11 11
 
12 12
       By default, the will have a `subject` and an optional `headline` before listing the Events.  If the Events'
13 13
       payloads contain a `message`, that will be highlighted, otherwise everything in

+ 1 - 1
app/models/agents/event_formatting_agent.rb

@@ -3,7 +3,7 @@ module Agents
3 3
     cannot_be_scheduled!
4 4
 
5 5
     description <<-MD
6
-      An Event Formatting Agent allows you to format incoming Events, adding new fields as needed.
6
+      The Event Formatting Agent allows you to format incoming Events, adding new fields as needed.
7 7
 
8 8
       For example, here is a possible Event:
9 9
 

+ 3 - 1
app/models/agents/ftpsite_agent.rb

@@ -9,8 +9,10 @@ module Agents
9 9
     gem_dependency_check { defined?(Net::FTP) && defined?(Net::FTP::List) }
10 10
 
11 11
     description <<-MD
12
+      The FTP Site Agent checks an FTP site and creates Events based on newly uploaded files in a directory.
13
+
12 14
       #{'## Include `net-ftp-list` in your Gemfile to use this Agent!' if dependencies_missing?}
13
-      The FtpsiteAgent checks a FTP site and creates Events based on newly uploaded files in a directory.
15
+
14 16
 
15 17
       Specify a `url` that represents a directory of an FTP site to watch, and a list of `patterns` to match against file names.
16 18
 

+ 2 - 1
app/models/agents/google_calendar_publish_agent.rb

@@ -7,8 +7,9 @@ module Agents
7 7
     gem_dependency_check { defined?(Google) && defined?(Google::APIClient) }
8 8
 
9 9
     description <<-MD
10
+      The Google Calendar Publish Agent creates events on your Google Calendar.
11
+
10 12
       #{'## Include `google-api-client` in your Gemfile to use this Agent!' if dependencies_missing?}
11
-      The GoogleCalendarPublishAgent creates events on your google calendar.
12 13
 
13 14
       This agent relies on service accounts, rather than oauth.
14 15
 

+ 2 - 1
app/models/agents/growl_agent.rb

@@ -8,8 +8,9 @@ module Agents
8 8
     gem_dependency_check { defined?(Growl) }
9 9
 
10 10
     description <<-MD
11
+      The Growl Agent sends any events it receives to a Growl GNTP server immediately.
12
+
11 13
       #{'## Include `ruby-growl` in your Gemfile to use this Agent!' if dependencies_missing?}
12
-      The GrowlAgent sends any events it receives to a Growl GNTP server immediately.
13 14
       
14 15
       It is assumed that events have a `message` or `text` key, which will hold the body of the growl notification, and a `subject` key, which will have the headline of the Growl notification. You can use Event Formatting Agent if your event does not provide these keys.
15 16
 

+ 2 - 1
app/models/agents/hipchat_agent.rb

@@ -8,8 +8,9 @@ module Agents
8 8
     gem_dependency_check { defined?(HipChat) }
9 9
 
10 10
     description <<-MD
11
+      The Hipchat Agent sends messages to a Hipchat Room
12
+
11 13
       #{'## Include `hipchat` in your Gemfile to use this Agent!' if dependencies_missing?}
12
-      The HipchatAgent sends messages to a Hipchat Room
13 14
 
14 15
       To authenticate you need to set the `auth_token`, you can get one at your Hipchat Group Admin page which you can find here:
15 16
 

+ 2 - 1
app/models/agents/human_task_agent.rb

@@ -5,8 +5,9 @@ module Agents
5 5
     gem_dependency_check { defined?(RTurk) }
6 6
 
7 7
     description <<-MD
8
+      The Human Task Agent is used to create Human Intelligence Tasks (HITs) on Mechanical Turk.
9
+
8 10
       #{'## Include `rturk` in your Gemfile to use this Agent!' if dependencies_missing?}
9
-      You can use a HumanTaskAgent to create Human Intelligence Tasks (HITs) on Mechanical Turk.
10 11
 
11 12
       HITs can be created in response to events, or on a schedule.  Set `trigger_on` to either `schedule` or `event`.
12 13
 

+ 21 - 59
app/models/agents/imap_folder_agent.rb

@@ -11,90 +11,52 @@ module Agents
11 11
     default_schedule "every_30m"
12 12
 
13 13
     description <<-MD
14
+      The Imap Folder Agent checks an IMAP server in specified folders and creates Events based on new mails found since the last run. In the first visit to a folder, this agent only checks for the initial status and does not create events.
14 15
 
15
-      The ImapFolderAgent checks an IMAP server in specified folders
16
-      and creates Events based on new mails found since the last run.
17
-      In the first visit to a folder, this agent only checks for the
18
-      initial status and does not create events.
19
-
20
-      Specify an IMAP server to connect with `host`, and set `ssl` to
21
-      true if the server supports IMAP over SSL.  Specify `port` if
22
-      you need to connect to a port other than standard (143 or 993
23
-      depending on the `ssl` value).
16
+      Specify an IMAP server to connect with `host`, and set `ssl` to true if the server supports IMAP over SSL.  Specify `port` if you need to connect to a port other than standard (143 or 993 depending on the `ssl` value).
24 17
 
25 18
       Specify login credentials in `username` and `password`.
26 19
 
27 20
       List the names of folders to check in `folders`.
28 21
 
29
-      To narrow mails by conditions, build a `conditions` hash with
30
-      the following keys:
31
-
32
-      - "subject"
33
-      - "body"
34
-
35
-          Specify a regular expression to match against the decoded
36
-          subject/body of each mail.
22
+      To narrow mails by conditions, build a `conditions` hash with the following keys:
37 23
 
38
-          Use the `(?i)` directive for case-insensitive search.  For
39
-          example, a pattern `(?i)alert` will match "alert", "Alert"
40
-          or "ALERT".  You can also make only a part of a pattern to
41
-          work case-insensitively: `Re: (?i:alert)` will match either
42
-          "Re: Alert" or "Re: alert", but not "RE: alert".
24
+      - `subject`
25
+      - `body`
26
+          Specify a regular expression to match against the decoded subject/body of each mail.
43 27
 
44
-          When a mail has multiple non-attachment text parts, they are
45
-          prioritized according to the `mime_types` option (which see
46
-          below) and the first part that matches a "body" pattern, if
47
-          specified, will be chosen as the "body" value in a created
48
-          event.
28
+          Use the `(?i)` directive for case-insensitive search.  For example, a pattern `(?i)alert` will match "alert", "Alert"or "ALERT".  You can also make only a part of a pattern to work case-insensitively: `Re: (?i:alert)` will match either "Re: Alert" or "Re: alert", but not "RE: alert".
49 29
 
50
-          Named captures will appear in the "matches" hash in a
51
-          created event.
30
+          When a mail has multiple non-attachment text parts, they are prioritized according to the `mime_types` option (which see below) and the first part that matches a "body" pattern, if specified, will be chosen as the "body" value in a created event.
52 31
 
53
-      - "from", "to", "cc"
32
+          Named captures will appear in the "matches" hash in a created event.
54 33
 
55
-          Specify a shell glob pattern string that is matched against
56
-          mail addresses extracted from the corresponding header
57
-          values of each mail.
34
+      - `from`, `to`, `cc`
35
+          Specify a shell glob pattern string that is matched against mail addresses extracted from the corresponding header values of each mail.
58 36
 
59 37
           Patterns match addresses in case insensitive manner.
60 38
 
61
-          Multiple pattern strings can be specified in an array, in
62
-          which case a mail is selected if any of the patterns
63
-          matches. (i.e. patterns are OR'd)
39
+          Multiple pattern strings can be specified in an array, in which case a mail is selected if any of the patterns matches. (i.e. patterns are OR'd)
64 40
 
65
-      - "mime_types"
41
+      - `mime_types`
42
+          Specify an array of MIME types to tell which non-attachment part of a mail among its text/* parts should be used as mail body.  The default value is `['text/plain', 'text/enriched', 'text/html']`.
66 43
 
67
-          Specify an array of MIME types to tell which non-attachment
68
-          part of a mail among its text/* parts should be used as mail
69
-          body.  The default value is `['text/plain', 'text/enriched',
70
-          'text/html']`.
71
-
72
-      - "is_unread"
73
-
74
-          Setting this to true or false means only mails that is
75
-          marked as unread or read respectively, are selected.
44
+      - `is_unread`
45
+          Setting this to true or false means only mails that is marked as unread or read respectively, are selected.
76 46
 
77 47
           If this key is unspecified or set to null, it is ignored.
78 48
 
79
-      - "has_attachment"
80
-
81
-          Setting this to true or false means only mails that does or does
82
-          not have an attachment are selected.
49
+      - `has_attachment`
50
+      
51
+          Setting this to true or false means only mails that does or does not have an attachment are selected.
83 52
 
84 53
           If this key is unspecified or set to null, it is ignored.
85 54
 
86 55
       Set `mark_as_read` to true to mark found mails as read.
87 56
 
88
-      Each agent instance memorizes the highest UID of mails that are
89
-      found in the last run for each watched folder, so even if you
90
-      change a set of conditions so that it matches mails that are
91
-      missed previously, or if you alter the flag status of already
92
-      found mails, they will not show up as new events.
57
+      Each agent instance memorizes the highest UID of mails that are found in the last run for each watched folder, so even if you change a set of conditions so that it matches mails that are missed previously, or if you alter the flag status of already found mails, they will not show up as new events.
93 58
 
94
-      Also, in order to avoid duplicated notification it keeps a list
95
-      of Message-Id's of 100 most recent mails, so if multiple mails
96
-      of the same Message-Id are found, you will only see one event
97
-      out of them.
59
+      Also, in order to avoid duplicated notification it keeps a list of Message-Id's of 100 most recent mails, so if multiple mails of the same Message-Id are found, you will only see one event out of them.
98 60
     MD
99 61
 
100 62
     event_description <<-MD

+ 2 - 1
app/models/agents/jabber_agent.rb

@@ -6,8 +6,9 @@ module Agents
6 6
     gem_dependency_check { defined?(Jabber) }
7 7
 
8 8
     description <<-MD
9
+      The Jabber Agent will send any events it receives to your Jabber/XMPP IM account.
10
+
9 11
       #{'## Include `xmpp4r` in your Gemfile to use this Agent!' if dependencies_missing?}
10
-      The JabberAgent will send any events it receives to your Jabber/XMPP IM account.
11 12
 
12 13
       Specify the `jabber_server` and `jabber_port` for your Jabber server.
13 14
 

+ 1 - 1
app/models/agents/java_script_agent.rb

@@ -10,7 +10,7 @@ module Agents
10 10
     default_schedule "never"
11 11
 
12 12
     description <<-MD
13
-      This Agent allows you to write code in JavaScript that can create and receive events.  If other Agents aren't meeting your needs, try this one!
13
+      The JavaScript Agent allows you to write code in JavaScript that can create and receive events.  If other Agents aren't meeting your needs, try this one!
14 14
 
15 15
       You can put code in the `code` option, or put your code in a Credential and reference it from `code` with `credential:<name>` (recommended).
16 16
 

+ 5 - 4
app/models/agents/jira_agent.rb

@@ -11,12 +11,13 @@ module Agents
11 11
     description <<-MD
12 12
       The Jira Agent subscribes to Jira issue updates.
13 13
 
14
-      `jira_url` specifies the full URL of the jira installation, including https://
15
-      `jql` is an optional Jira Query Language-based filter to limit the flow of events. See [JQL Docs](https://confluence.atlassian.com/display/JIRA/Advanced+Searching) for details. 
16
-      `username` and `password` are optional, and may need to be specified if your Jira instance is read-protected
17
-      `timeout` is an optional parameter that specifies how long the request processing may take in minutes.
14
+      - `jira_url` specifies the full URL of the jira installation, including https://
15
+      - `jql` is an optional Jira Query Language-based filter to limit the flow of events. See [JQL Docs](https://confluence.atlassian.com/display/JIRA/Advanced+Searching) for details. 
16
+      - `username` and `password` are optional, and may need to be specified if your Jira instance is read-protected
17
+      - `timeout` is an optional parameter that specifies how long the request processing may take in minutes.
18 18
 
19 19
       The agent does periodic queries and emits the events containing the updated issues in JSON format.
20
+
20 21
       NOTE: upon the first execution, the agent will fetch everything available by the JQL query. So if it's not desirable, limit the `jql` query by date.
21 22
     MD
22 23
 

+ 1 - 1
app/models/agents/manual_event_agent.rb

@@ -4,7 +4,7 @@ module Agents
4 4
     cannot_receive_events!
5 5
 
6 6
     description <<-MD
7
-      Use this Agent to manually create Events for testing or other purposes.
7
+      The Manual Event Agent is used to manually create Events for testing or other purposes.
8 8
     MD
9 9
 
10 10
     event_description "User determined"

+ 2 - 1
app/models/agents/mqtt_agent.rb

@@ -6,8 +6,9 @@ module Agents
6 6
     gem_dependency_check { defined?(MQTT) }
7 7
 
8 8
     description <<-MD
9
+      The MQTT Agent allows both publication and subscription to an MQTT topic.
10
+
9 11
       #{'## Include `mqtt` in your Gemfile to use this Agent!' if dependencies_missing?}
10
-      The MQTT agent allows both publication and subscription to an MQTT topic.
11 12
 
12 13
       MQTT is a generic transport protocol for machine to machine communication.
13 14
 

+ 2 - 0
app/models/agents/pdf_info_agent.rb

@@ -9,6 +9,8 @@ module Agents
9 9
     cannot_be_scheduled!
10 10
 
11 11
     description <<-MD
12
+      The PDF Info Agent returns the metadata contained within a given PDF file, using HyPDF.
13
+
12 14
       #{'## Include the `hypdf` gem in your `Gemfile` to use PDFInfo Agents.' if dependencies_missing?}
13 15
 
14 16
       In order for this agent to work, you need to have [HyPDF](https://devcenter.heroku.com/articles/hypdf) running and configured.

+ 2 - 4
app/models/agents/peak_detector_agent.rb

@@ -5,15 +5,13 @@ module Agents
5 5
     cannot_be_scheduled!
6 6
 
7 7
     description <<-MD
8
-      Use a PeakDetectorAgent to watch for peaks in an event stream.  When a peak is detected, the resulting Event will have a payload message of `message`.  You can include extractions in the message, for example: `I saw a bar of: {{foo.bar}}`, have a look at the [Wiki](https://github.com/cantino/huginn/wiki/Formatting-Events-using-Liquid) for details.
8
+      The Peak Detector Agent will watch for peaks in an event stream.  When a peak is detected, the resulting Event will have a payload message of `message`.  You can include extractions in the message, for example: `I saw a bar of: {{foo.bar}}`, have a look at the [Wiki](https://github.com/cantino/huginn/wiki/Formatting-Events-using-Liquid) for details.
9 9
 
10 10
       The `value_path` value is a [JSONPaths](http://goessner.net/articles/JsonPath/) to the value of interest.  `group_by_path` is a hash path that will be used to group values, if present.
11 11
 
12 12
       Set `expected_receive_period_in_days` to the maximum amount of time that you'd expect to pass between Events being received by this Agent.
13 13
 
14
-      You may set `window_duration_in_days` to change the default memory window length of `14` days,
15
-      `min_peak_spacing_in_days` to change the default minimum peak spacing of `2` days (peaks closer together will be ignored), and
16
-      `std_multiple` to change the default standard deviation threshold multiple of `3`.
14
+      You may set `window_duration_in_days` to change the default memory window length of `14` days, `min_peak_spacing_in_days` to change the default minimum peak spacing of `2` days (peaks closer together will be ignored), and `std_multiple` to change the default standard deviation threshold multiple of `3`.
17 15
     MD
18 16
 
19 17
     event_description <<-MD

+ 5 - 2
app/models/agents/post_agent.rb

@@ -7,13 +7,13 @@ module Agents
7 7
     default_schedule "never"
8 8
 
9 9
     description <<-MD
10
-      A PostAgent receives events from other agents (or runs periodically), merges those events with the [Liquid-interpolated](https://github.com/cantino/huginn/wiki/Formatting-Events-using-Liquid) contents of `payload`, and sends the results as POST (or GET) requests to a specified url.  To skip merging in the incoming event, but still send the interpolated payload, set `no_merge` to `true`.
10
+      A Post Agent receives events from other agents (or runs periodically), merges those events with the [Liquid-interpolated](https://github.com/cantino/huginn/wiki/Formatting-Events-using-Liquid) contents of `payload`, and sends the results as POST (or GET) requests to a specified url.  To skip merging in the incoming event, but still send the interpolated payload, set `no_merge` to `true`.
11 11
 
12 12
       The `post_url` field must specify where you would like to send requests. Please include the URI scheme (`http` or `https`).
13 13
 
14 14
       The `method` used can be any of `get`, `post`, `put`, `patch`, and `delete`.
15 15
 
16
-      By default, non-GETs will be sent with form encoding (`application/x-www-form-urlencoded`).  Change `content_type` to `json` to send JSON instead.
16
+      By default, non-GETs will be sent with form encoding (`application/x-www-form-urlencoded`).  Change `content_type` to `json` to send JSON instead.  Change `content_type` to `xml` to send XML, where the name of the root element may be specified using `xml_root`, defaulting to `post`.
17 17
 
18 18
       Other Options:
19 19
 
@@ -102,6 +102,9 @@ module Agents
102 102
         when 'json'
103 103
           headers['Content-Type'] = 'application/json; charset=utf-8'
104 104
           body = data.to_json
105
+        when 'xml'
106
+          headers['Content-Type'] = 'text/xml; charset=utf-8'
107
+          body = data.to_xml(root: (interpolated(payload)[:xml_root] || 'post'))
105 108
         else
106 109
           body = data
107 110
         end

+ 4 - 2
app/models/agents/public_transport_agent.rb

@@ -7,13 +7,15 @@ module Agents
7 7
     default_schedule "every_2m"
8 8
 
9 9
     description <<-MD
10
+      The Public Transport Request Agent generates Events based on NextBus GPS transit predictions.
11
+
10 12
       Specify the following user settings:
11 13
 
12
-      * stops (array)
13 14
       * agency (string)
15
+      * stops (array)
14 16
       * alert_window_in_minutes (integer)
15 17
 
16
-      This Agent generates Events based on NextBus GPS transit predictions.  First, select an agency by visiting [http://www.nextbus.com/predictor/agencySelector.jsp](http://www.nextbus.com/predictor/agencySelector.jsp) and finding your transit system.  Once you find it, copy the part of the URL after `?a=`.  For example, for the San Francisco MUNI system, you would end up on [http://www.nextbus.com/predictor/stopSelector.jsp?a=**sf-muni**](http://www.nextbus.com/predictor/stopSelector.jsp?a=sf-muni) and copy "sf-muni".  Put that into this Agent's agency setting.
18
+      First, select an agency by visiting [http://www.nextbus.com/predictor/agencySelector.jsp](http://www.nextbus.com/predictor/agencySelector.jsp) and finding your transit system.  Once you find it, copy the part of the URL after `?a=`.  For example, for the San Francisco MUNI system, you would end up on [http://www.nextbus.com/predictor/stopSelector.jsp?a=**sf-muni**](http://www.nextbus.com/predictor/stopSelector.jsp?a=sf-muni) and copy "sf-muni".  Put that into this Agent's agency setting.
17 19
 
18 20
       Next, find the stop tags that you care about.  To find the tags for the sf-muni system, for the N route, visit this URL:
19 21
       [http://webservices.nextbus.com/service/publicXMLFeed?command=routeConfig&a=sf-muni&r=**N**](http://webservices.nextbus.com/service/publicXMLFeed?command=routeConfig&a=sf-muni&r=N)

+ 1 - 1
app/models/agents/pushover_agent.rb

@@ -6,7 +6,7 @@ module Agents
6 6
     API_URL = 'https://api.pushover.net/1/messages.json'
7 7
 
8 8
     description <<-MD
9
-      The PushoverAgent receives and collects events and sends them via push notification to a user/group.
9
+      The Pushover Agent receives and collects events and sends them via push notification to a user/group.
10 10
 
11 11
       **You need a Pushover API Token:** [https://pushover.net/apps/build](https://pushover.net/apps/build)
12 12
 

+ 1 - 1
app/models/agents/rss_agent.rb

@@ -13,7 +13,7 @@ module Agents
13 13
 
14 14
     description do
15 15
       <<-MD
16
-        This Agent consumes RSS feeds and emits events when they change.
16
+        The RSS Agent consumes RSS feeds and emits events when they change.
17 17
 
18 18
         This Agent is fairly simple, using [feed-normalizer](https://github.com/aasmith/feed-normalizer) as a base.  For complex feeds
19 19
         with additional field types, we recommend using a WebsiteAgent.  See [this example](https://github.com/cantino/huginn/wiki/Agent-configuration-examples#itunes-trailers).

+ 1 - 1
app/models/agents/scheduler_agent.rb

@@ -13,7 +13,7 @@ module Agents
13 13
     cattr_reader :second_precision_enabled
14 14
 
15 15
     description <<-MD
16
-      This agent periodically takes an action on target Agents according to a user-defined schedule.
16
+      The Scheduler Agent periodically takes an action on target Agents according to a user-defined schedule.
17 17
 
18 18
       # Action types
19 19
 

+ 2 - 3
app/models/agents/sentiment_agent.rb

@@ -7,10 +7,9 @@ module Agents
7 7
     cannot_be_scheduled!
8 8
 
9 9
     description <<-MD
10
-      The SentimentAgent generates `good-bad` (psychological valence or happiness index), `active-passive` (arousal),
11
-      and  `strong-weak` (dominance) score. It will output a value between 1 and 9. It will only work on English content.
10
+      The Sentiment Agent generates `good-bad` (psychological valence or happiness index), `active-passive` (arousal), and  `strong-weak` (dominance) score. It will output a value between 1 and 9. It will only work on English content.
12 11
 
13
-      Make sure the content this agent is analyzing have sufficient length to get respectable results.
12
+      Make sure the content this agent is analyzing is of sufficient length to get respectable results.
14 13
 
15 14
       Provide a JSONPath in `content` field where content is residing and set `expected_receive_period_in_days` to the maximum number of days you would allow to be passed between events being received by this agent.
16 15
     MD

+ 1 - 1
app/models/agents/shell_command_agent.rb

@@ -9,7 +9,7 @@ module Agents
9 9
     end
10 10
 
11 11
     description <<-MD
12
-      The ShellCommandAgent can execute commands on your local system, returning the output.
12
+      The Shell Command Agent will execute commands on your local system, returning the output.
13 13
 
14 14
       `command` specifies the command to be executed, and `path` will tell ShellCommandAgent in what directory to run this command.
15 15
 

+ 8 - 11
app/models/agents/slack_agent.rb

@@ -8,22 +8,19 @@ module Agents
8 8
     gem_dependency_check { defined?(Slack) }
9 9
 
10 10
     description <<-MD
11
+      The Slack Agent lets you receive events and send notifications to [Slack](https://slack.com/).
12
+
11 13
       #{'## Include `slack-notifier` in your Gemfile to use this Agent!' if dependencies_missing?}
12
-      The SlackAgent lets you receive events and send notifications to [Slack](https://slack.com/).
13 14
 
14
-      To get started, you will first need to setup an incoming webhook.
15
-      Go to, <code>https://<em>your_team_name</em>.slack.com/services/new/incoming-webhook</code>,
16
-      choose a default channel and add the integration.
15
+      To get started, you will first need to configure an incoming webhook.
16
+      
17
+      - Go to `https://my.slack.com/services/new/incoming-webhook`, choose a default channel and add the integration.
17 18
 
18
-      Your webhook URL will look like: <code>https://hooks.slack.com/services/<em>random1</em>/<em>random2</em>/<em>token</em></code>
19
+      Your webhook URL will look like: `https://hooks.slack.com/services/some/random/characters`
19 20
 
20
-      Once the webhook has been setup it can be used to post to other channels or ping team members.
21
-      To send a private message to team-mate, assign his username as `@username` to the channel option.
22
-      To communicate with a different webhook on slack, assign your custom webhook name to the webhook option.
23
-      Messages can also be formatted using [Liquid](https://github.com/cantino/huginn/wiki/Formatting-Events-using-Liquid).
21
+      Once the webhook has been configured, it can be used to post to other channels or direct to team members. To send a private message to team member, use their @username as the channel. Messages can be formatted using [Liquid](https://github.com/cantino/huginn/wiki/Formatting-Events-using-Liquid).
24 22
 
25
-      Finally, you can set a custom icon for this webhook in `icon`, either as [emoji](http://unicodey.com/emoji-data/table.htm) or an URL to an image.
26
-      Leaving this field blank will use the default icon for a webhook.
23
+      Finally, you can set a custom icon for this webhook in `icon`, either as [emoji](http://www.emoji-cheat-sheet.com) or an URL to an image. Leaving this field blank will use the default icon for a webhook.
27 24
     MD
28 25
 
29 26
     def default_options

+ 3 - 1
app/models/agents/stubhub_agent.rb

@@ -3,7 +3,9 @@ module Agents
3 3
     cannot_receive_events!
4 4
 
5 5
     description <<-MD
6
-      This StubHubAgent creates an event for a given StubHub Event. It can be used to track how many tickets are available for the event and the minimum and maximum price. All that is required is that you paste in the url from the actual event, e.g. http://www.stubhub.com/outside-lands-music-festival-tickets/outside-lands-music-festival-3-day-pass-san-francisco-golden-gate-park-polo-fields-8-8-2014-9020701/
6
+      The StubHub Agent creates an event for a given StubHub Event.
7
+
8
+      It can be used to track how many tickets are available for the event and the minimum and maximum price. All that is required is that you paste in the url from the actual event, e.g. http://www.stubhub.com/outside-lands-music-festival-tickets/outside-lands-music-festival-3-day-pass-san-francisco-golden-gate-park-polo-fields-8-8-2014-9020701/
7 9
     MD
8 10
 
9 11
     event_description <<-MD

+ 3 - 1
app/models/agents/translation_agent.rb

@@ -3,8 +3,10 @@ module Agents
3 3
     cannot_be_scheduled!
4 4
 
5 5
     description <<-MD
6
-      You can use Translation Agent to translate text between natural languages.
6
+      The Translation Agent will attempt to translate text between natural languages.
7
+
7 8
       Services are provided using Microsoft Translator. You can [sign up](https://datamarket.azure.com/dataset/bing/microsofttranslator) and [register your application](https://datamarket.azure.com/developer/applications/register) to get `client_id` and `client_secret` which are required to use this agent.
9
+      
8 10
       `to` must be filled with a [translator language code](http://msdn.microsoft.com/en-us/library/hh456380.aspx).
9 11
 
10 12
       Specify what you would like to translate in `content` field, you can use [Liquid](https://github.com/cantino/huginn/wiki/Formatting-Events-using-Liquid) specify which part of the payload you want to translate.

+ 1 - 1
app/models/agents/trigger_agent.rb

@@ -5,7 +5,7 @@ module Agents
5 5
     VALID_COMPARISON_TYPES = %w[regex !regex field<value field<=value field==value field!=value field>=value field>value]
6 6
 
7 7
     description <<-MD
8
-      Use a TriggerAgent to watch for a specific value in an Event payload.
8
+      The Trigger Agent will watch for a specific value in an Event payload.
9 9
 
10 10
       The `rules` array contains hashes of `path`, `value`, and `type`.  The `path` value is a dotted path through a hash in [JSONPaths](http://goessner.net/articles/JsonPath/) syntax.
11 11
 

+ 2 - 2
app/models/agents/tumblr_publish_agent.rb

@@ -7,9 +7,9 @@ module Agents
7 7
     cannot_be_scheduled!
8 8
 
9 9
     description <<-MD
10
-      #{'## Include `tumblr_client` and `omniauth-tumblr` in your Gemfile to use this Agent!' if dependencies_missing?}
10
+      The Tumblr Publish Agent publishes Tumblr posts from the events it receives.
11 11
 
12
-      The TumblrPublishAgent publishes Tumblr posts from the events it receives.
12
+      #{'## Include `tumblr_client` and `omniauth-tumblr` in your Gemfile to use this Agent!' if dependencies_missing?}
13 13
 
14 14
       To be able to use this Agent you need to authenticate with Tumblr in the [Services](/services) section first.
15 15
 

+ 2 - 1
app/models/agents/twilio_agent.rb

@@ -8,8 +8,9 @@ module Agents
8 8
     gem_dependency_check { defined?(Twilio) }
9 9
 
10 10
     description <<-MD
11
+      The Twilio Agent receives and collects events and sends them via text message (up to 160 characters) or gives you a call when scheduled.
12
+
11 13
       #{'## Include `twilio-ruby` in your Gemfile to use this Agent!' if dependencies_missing?}
12
-      The TwilioAgent receives and collects events and sends them via text message (up to 160 characters) or gives you a call when scheduled.
13 14
 
14 15
       It is assumed that events have a `message`, `text`, or `sms` key, the value of which is sent as the content of the text message/call. You can use the EventFormattingAgent if your event does not provide these keys.
15 16
 

+ 2 - 1
app/models/agents/twitter_publish_agent.rb

@@ -5,8 +5,9 @@ module Agents
5 5
     cannot_be_scheduled!
6 6
 
7 7
     description <<-MD
8
+      The Twitter Publish Agent publishes tweets from the events it receives.
9
+
8 10
       #{twitter_dependencies_missing if dependencies_missing?}
9
-      The TwitterPublishAgent publishes tweets from the events it receives.
10 11
 
11 12
       To be able to use this Agent you need to authenticate with Twitter in the [Services](/services) section first.
12 13
 

+ 3 - 2
app/models/agents/twitter_stream_agent.rb

@@ -5,8 +5,9 @@ module Agents
5 5
     cannot_receive_events!
6 6
 
7 7
     description <<-MD
8
+      The Twitter Stream Agent follows the Twitter stream in real time, watching for certain keywords, or filters, that you provide.
9
+
8 10
       #{twitter_dependencies_missing if dependencies_missing?}
9
-      The TwitterStreamAgent follows the Twitter stream in real time, watching for certain keywords, or filters, that you provide.
10 11
 
11 12
       To follow the Twitter stream, provide an array of `filters`.  Multiple words in a filter must all show up in a tweet, but are independent of order.
12 13
       If you provide an array instead of a filter, the first entry will be considered primary and any additional values will be treated as aliases.
@@ -122,4 +123,4 @@ module Agents
122 123
       end
123 124
     end
124 125
   end
125
-end
126
+end

+ 10 - 2
app/models/agents/twitter_user_agent.rb

@@ -5,14 +5,17 @@ module Agents
5 5
     cannot_receive_events!
6 6
 
7 7
     description <<-MD
8
+      The Twitter User Agent follows the timeline of a specified Twitter user.
9
+
8 10
       #{twitter_dependencies_missing if dependencies_missing?}
9
-      The TwitterUserAgent follows the timeline of a specified Twitter user.
10 11
 
11 12
       To be able to use this Agent you need to authenticate with Twitter in the [Services](/services) section first.
12 13
 
13 14
       You must also provide the `username` of the Twitter user to monitor.
14 15
 
15 16
       Set `include_retweets` to `false` to not include retweets (default: `true`)
17
+      
18
+      Set `exclude_replies` to `true` to exclude replies (default: `false`)
16 19
 
17 20
       Set `expected_update_period_in_days` to the maximum amount of time that you'd expect to pass between Events being created by this Agent.
18 21
 
@@ -53,6 +56,7 @@ module Agents
53 56
       {
54 57
         'username' => 'tectonic',
55 58
         'include_retweets' => 'true',
59
+        'exclude_replies' => 'false',
56 60
         'expected_update_period_in_days' => '2'
57 61
       }
58 62
     end
@@ -81,10 +85,14 @@ module Agents
81 85
     def include_retweets?
82 86
       interpolated[:include_retweets] != "false"
83 87
     end
88
+    
89
+    def exclude_replies?
90
+      boolify(interpolated[:exclude_replies]) || false
91
+    end
84 92
 
85 93
     def check
86 94
       since_id = memory['since_id'] || nil
87
-      opts = {:count => 200, :include_rts => include_retweets?, :exclude_replies => false, :include_entities => true, :contributor_details => true}
95
+      opts = {:count => 200, :include_rts => include_retweets?, :exclude_replies => exclude_replies?, :include_entities => true, :contributor_details => true}
88 96
       opts.merge! :since_id => since_id unless since_id.nil?
89 97
 
90 98
       # http://rdoc.info/gems/twitter/Twitter/REST/Timelines#user_timeline-instance_method

+ 6 - 9
app/models/agents/user_location_agent.rb

@@ -6,18 +6,15 @@ module Agents
6 6
 
7 7
     gem_dependency_check { defined?(Haversine) }
8 8
 
9
-    description do
10
-      <<-MD
11
-        #{'## Include `haversine` in your Gemfile to use this Agent!' if dependencies_missing?}
12
-        The UserLocationAgent creates events based on WebHook POSTS that contain a `latitude` and `longitude`.  You can use the [POSTLocation](https://github.com/cantino/post_location) or [PostGPS](https://github.com/chriseidhof/PostGPS) iOS app to post your location.
9
+    description do <<-MD
10
+      The User Location Agent creates events based on WebHook POSTS that contain a `latitude` and `longitude`.  You can use the [POSTLocation](https://github.com/cantino/post_location) or [PostGPS](https://github.com/chriseidhof/PostGPS) iOS app to post your location to `https://#{ENV['DOMAIN']}/users/#{user.id}/update_location/:secret` where `:secret` is specified in your options.
13 11
 
12
+      #{'## Include `haversine` in your Gemfile to use this Agent!' if dependencies_missing?}
14 13
 
15
-        Your POST path will be `https://#{ENV['DOMAIN']}/users/#{user.id}/update_location/:secret` where `:secret` is specified in your options.
14
+      If you want to only keep more precise locations, set `max_accuracy` to the upper bound, in meters. The default name for this field is `accuracy`, but you can change this by setting a value for `accuracy_field`.
16 15
 
17
-        If you want to only keep more precise locations, set `max_accuracy` to the upper bound, in meters. The default name for this field is `accuracy`, but you can change this by setting a value for `accuracy_field`.
18
-
19
-        If you want to require a certain distance traveled, set `min_distance` to the minimum distance, in meters. Note that GPS readings and the measurement itself aren't exact, so don't rely on this for precision filtering.
20
-      MD
16
+      If you want to require a certain distance traveled, set `min_distance` to the minimum distance, in meters. Note that GPS readings and the measurement itself aren't exact, so don't rely on this for precision filtering.
17
+    MD
21 18
     end
22 19
 
23 20
     event_description <<-MD

+ 2 - 1
app/models/agents/weather_agent.rb

@@ -8,8 +8,9 @@ module Agents
8 8
     gem_dependency_check { defined?(Wunderground) && defined?(ForecastIO) }
9 9
 
10 10
     description <<-MD
11
+      The Weather Agent creates an event for the day's weather at a given `location`.
12
+
11 13
       #{'## Include `forecast_io` and `wunderground` in your Gemfile to use this Agent!' if dependencies_missing?}
12
-      The WeatherAgent creates an event for the day's weather at a given `location`.
13 14
 
14 15
       You also must select `which_day` you would like to get the weather for where the number 0 is for today and 1 is for tomorrow and so on. Weather is only returned for 1 week at a time.
15 16
 

+ 14 - 14
app/models/agents/webhook_agent.rb

@@ -3,23 +3,23 @@ module Agents
3 3
     cannot_be_scheduled!
4 4
     cannot_receive_events!
5 5
 
6
-    description  do
7
-        <<-MD
8
-        Use this Agent to create events by receiving webhooks from any source.
6
+    description do <<-MD
7
+      The Webhook Agent will create events by receiving webhooks from any source. In order to create events with this agent, make a POST request to:
9 8
 
10
-        In order to create events with this agent, make a POST request to:
11
-        ```
12
-           https://#{ENV['DOMAIN']}/users/#{user.id}/web_requests/#{id || '<id>'}/:secret
13
-        ``` where `:secret` is specified in your options.
9
+      ```
10
+         https://#{ENV['DOMAIN']}/users/#{user.id}/web_requests/#{id || ':id'}/#{options['secret'] || ':secret'}
11
+      ```
14 12
 
15
-        Options:
13
+      #{'The placeholder symbols above will be replaced by their values once the agent is saved.' unless id}
16 14
 
17
-          * `secret` - A token that the host will provide for authentication.
18
-          * `expected_receive_period_in_days` - How often you expect to receive
19
-            events this way. Used to determine if the agent is working.
20
-          * `payload_path` - JSONPath of the attribute in the POST body to be
21
-            used as the Event payload.  If `payload_path` points to an array,
22
-            Events will be created for each element.
15
+      Options:
16
+
17
+        * `secret` - A token that the host will provide for authentication.
18
+        * `expected_receive_period_in_days` - How often you expect to receive
19
+          events this way. Used to determine if the agent is working.
20
+        * `payload_path` - JSONPath of the attribute in the POST body to be
21
+          used as the Event payload.  If `payload_path` points to an array,
22
+          Events will be created for each element.
23 23
       MD
24 24
     end
25 25
 

+ 1 - 1
app/models/agents/website_agent.rb

@@ -14,7 +14,7 @@ module Agents
14 14
     UNIQUENESS_FACTOR = 3
15 15
 
16 16
     description <<-MD
17
-      The WebsiteAgent scrapes a website, XML document, or JSON feed and creates Events based on the results.
17
+      The Website Agent scrapes a website, XML document, or JSON feed and creates Events based on the results.
18 18
 
19 19
       Specify a `url` and select a `mode` for when to create Events based on the scraped data, either `all` or `on_change`.
20 20
 

+ 4 - 3
app/models/agents/weibo_publish_agent.rb

@@ -7,12 +7,13 @@ module Agents
7 7
     cannot_be_scheduled!
8 8
 
9 9
     description <<-MD
10
+      The Weibo Publish Agent publishes tweets from the events it receives.
11
+
10 12
       #{'## Include `weibo_2` in your Gemfile to use this Agent!' if dependencies_missing?}
11
-      The WeiboPublishAgent publishes tweets from the events it receives.
12 13
 
13
-      You must first set up a Weibo app and generate an `acess_token` for the user to send statuses as.
14
+      You must first set up a Weibo app and generate an `access_token` for the user that will be used for posting status updates.
14 15
 
15
-      Include that in options, along with the `app_key` and `app_secret` for your Weibo app. It's useful to also include the Weibo user id of the person to publish as.
16
+      You'll use that `access_token`, along with the `app_key` and `app_secret` for your Weibo app. You must also include the Weibo User ID (as `uid`) of the person to publish as.
16 17
 
17 18
       You must also specify a `message_path` parameter: a [JSONPaths](http://goessner.net/articles/JsonPath/) to the value to tweet.
18 19
 

+ 2 - 1
app/models/agents/weibo_user_agent.rb

@@ -7,8 +7,9 @@ module Agents
7 7
     cannot_receive_events!
8 8
 
9 9
     description <<-MD
10
+      The Weibo User Agent follows the timeline of a specified Weibo user. It uses this endpoint: http://open.weibo.com/wiki/2/statuses/user_timeline/en
11
+
10 12
       #{'## Include `weibo_2` in your Gemfile to use this Agent!' if dependencies_missing?}
11
-      The WeiboUserAgent follows the timeline of a specified Weibo user. It uses this endpoint: http://open.weibo.com/wiki/2/statuses/user_timeline/en
12 13
 
13 14
       You must first set up a Weibo app and generate an `acess_token` to authenticate with. Provide that, along with the `app_key` and `app_secret` for your Weibo app in the options.
14 15
 

+ 4 - 2
app/models/agents/witai_agent.rb

@@ -3,9 +3,11 @@ module Agents
3 3
     cannot_be_scheduled!
4 4
 
5 5
     description <<-MD
6
+      The `wit.ai` agent receives events, sends a text query to your `wit.ai` instance and generates outcome events.
6 7
 
7
-    `wit.ai` agent receives events, sends text query to your `wit.ai` instance and generates outcome events. Fill in `Server Access Token` of your `wit.ai` instance. Use [Liquid](https://github.com/cantino/huginn/wiki/Formatting-Events-using-Liquid) to fill query field.
8
-    `expected_receive_period_in_days` is the expected number of days by which agent should receive events. It helps in determining if the agent is working.
8
+      Fill in `Server Access Token` of your `wit.ai` instance. Use [Liquid](https://github.com/cantino/huginn/wiki/Formatting-Events-using-Liquid) to fill query field.
9
+      
10
+      `expected_receive_period_in_days` is the expected number of days by which agent should receive events. It helps in determining if the agent is working.
9 11
     MD
10 12
 
11 13
     event_description <<-MD

+ 3 - 4
app/models/agents/wunderlist_agent.rb

@@ -9,12 +9,11 @@ module Agents
9 9
     gem_dependency_check { Devise.omniauth_providers.include?(:wunderlist) }
10 10
 
11 11
     description <<-MD
12
-      #{'## Include the `omniauth-wunderlist` gem in your `Gemfile` and set `WUNDERLIST_OAUTH_KEY` and `WUNDERLIST_OAUTH_SECRET` in your environment to use this Agent' if dependencies_missing?}
12
+      The WunderlistAgent creates new Wunderlist tasks based on the incoming event.
13 13
 
14
-      The WunderlistAgent creates new new tasks based on the incoming event.
14
+      #{'## Include the `omniauth-wunderlist` gem in your `Gemfile` and set `WUNDERLIST_OAUTH_KEY` and `WUNDERLIST_OAUTH_SECRET` in your environment to use this Agent' if dependencies_missing?}
15 15
 
16 16
       To be able to use this Agent you need to authenticate with Wunderlist in the [Services](/services) section first.
17
-
18 17
     MD
19 18
 
20 19
     def default_options
@@ -77,4 +76,4 @@ module Agents
77 76
                     'X-Client-ID' => ENV["WUNDERLIST_OAUTH_KEY"] }}
78 77
     end
79 78
   end
80
-end
79
+end

+ 1 - 1
app/views/agents/_form.html.erb

@@ -23,7 +23,7 @@
23 23
           <% if @agent.new_record? %>
24 24
             <div class="form-group type-select">
25 25
               <%= f.label :type %>
26
-              <%= f.select :type, options_for_select([['Select an Agent Type', 'Agent']] + Agent.types.map(&:to_s).sort.map {|type| [type.gsub(/^.*::/, ''), type] }, @agent.type), {}, :class => 'select2 form-control' %>
26
+              <%= f.select :type, options_for_select([['Select an Agent Type', 'Agent', {title: ''}]] + Agent.types.map {|type| [type.name.gsub(/^.*::/, '').underscore.humanize.titleize, type, {title: h(Agent.build_for_type(type.name,current_user,{}).html_description.lines.first.strip)}] }, @agent.type), {}, :class => 'form-control' %>
27 27
             </div>
28 28
           <% end %>
29 29
         </div>

+ 4 - 0
app/views/jobs/index.html.erb

@@ -79,6 +79,10 @@
79 79
         <%= link_to destroy_failed_jobs_path, class: "btn btn-default", method: :delete do %>
80 80
           <span class="glyphicon glyphicon-trash"></span> Remove failed jobs
81 81
         <% end %>
82
+
83
+        <%= link_to destroy_all_jobs_path, class: "btn btn-default", method: :delete, data: { confirm: "Are you sure you want to delete ALL pending jobs for all Huginn users?" } do %>
84
+          <span class="glyphicon glyphicon-remove"></span> Remove all jobs
85
+        <% end %>
82 86
       </div>
83 87
     </div>
84 88
   </div>

+ 2 - 1
app/views/scenarios/show.html.erb

@@ -16,10 +16,11 @@
16 16
 
17 17
       <div class="btn-group">
18 18
         <%= link_to icon_tag('glyphicon-chevron-left') + ' Back', scenarios_path, class: "btn btn-default" %>
19
+        <%= link_to icon_tag('glyphicon-plus') + ' New Agent', new_agent_path(scenario_id: @scenario.id), class: "btn btn-default" %>
19 20
         <%= link_to icon_tag('glyphicon-random') + ' View Diagram', scenario_diagram_path(@scenario), class: "btn btn-default" %>
20 21
         <%= link_to icon_tag('glyphicon-edit') + ' Edit', edit_scenario_path(@scenario), class: "btn btn-default" %>
21 22
         <% if @scenario.source_url.present? %>
22
-          <%= link_to icon_tag('glyphicon-plus') + ' Update', new_scenario_imports_path(url: @scenario.source_url), class: "btn btn-default" %>
23
+          <%= link_to icon_tag('glyphicon-refresh') + ' Update', new_scenario_imports_path(url: @scenario.source_url), class: "btn btn-default" %>
23 24
         <% end %>
24 25
         <%= link_to icon_tag('glyphicon-share-alt') + ' Share', share_scenario_path(@scenario), class: "btn btn-default" %>
25 26
         <%= link_to icon_tag('glyphicon-trash') + ' Delete', scenario_path(@scenario), method: :delete, data: { confirm: "This will remove the '#{@scenario.name}' Scenerio from all Agents and delete it.  Are you sure?" }, class: "btn btn-default" %>

+ 0 - 4
bin/rails

@@ -1,8 +1,4 @@
1 1
 #!/usr/bin/env ruby
2
-begin
3
-  load File.expand_path("../spring", __FILE__)
4
-rescue LoadError
5
-end
6 2
 APP_PATH = File.expand_path('../../config/application',  __FILE__)
7 3
 require_relative '../config/boot'
8 4
 require 'rails/commands'

+ 0 - 4
bin/rake

@@ -1,8 +1,4 @@
1 1
 #!/usr/bin/env ruby
2
-begin
3
-  load File.expand_path("../spring", __FILE__)
4
-rescue LoadError
5
-end
6 2
 require_relative '../config/boot'
7 3
 require 'rake'
8 4
 Rake.application.run

+ 0 - 4
bin/rspec

@@ -1,7 +1,3 @@
1 1
 #!/usr/bin/env ruby
2
-begin
3
-  load File.expand_path("../spring", __FILE__)
4
-rescue LoadError
5
-end
6 2
 require 'bundler/setup'
7 3
 load Gem.bin_path('rspec-core', 'rspec')

+ 0 - 15
bin/spring

@@ -1,15 +0,0 @@
1
-#!/usr/bin/env ruby
2
-
3
-# This file loads spring without using Bundler, in order to be fast.
4
-# It gets overwritten when you run the `spring binstub` command.
5
-
6
-unless defined?(Spring)
7
-  require "rubygems"
8
-  require "bundler"
9
-
10
-  if match = Bundler.default_lockfile.read.match(/^GEM$.*?^    (?:  )*spring \((.*?)\)$.*?^$/m)
11
-    Gem.paths = { "GEM_PATH" => Bundler.bundle_path.to_s }
12
-    gem "spring", match[1]
13
-    require "spring/binstub"
14
-  end
15
-end

+ 54 - 0
config/deploy.rb

@@ -0,0 +1,54 @@
1
+require 'dotenv'
2
+Dotenv.load
3
+
4
+# config valid only for current version of Capistrano
5
+lock '3.4.0'
6
+
7
+set :application, 'huginn'
8
+set :repo_url, ENV['CAPISTRANO_DEPLOY_REPO_URL'] || 'https://github.com/cantino/huginn.git'
9
+
10
+# Default branch is :master
11
+set :branch, ENV['BRANCH'] || 'master'
12
+
13
+set :deploy_to, '/home/huginn'
14
+
15
+# Set to :debug for verbose ouput
16
+set :log_level, :info
17
+
18
+# Default value for :linked_files is []
19
+set :linked_files, fetch(:linked_files, []).push('.env', 'Procfile', 'config/unicorn.rb')
20
+
21
+# Default value for linked_dirs is []
22
+set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle')
23
+
24
+# Default value for keep_releases is 5
25
+# set :keep_releases, 5
26
+
27
+set :bundle_jobs, 4
28
+
29
+set :conditionally_migrate, true # Defaults to false. If true, it's skip migration if files in db/migrate not modified
30
+
31
+task :deploy => [:production]
32
+
33
+namespace :deploy do
34
+  after 'check:make_linked_dirs', :migrate_to_cap do
35
+    on roles(:all) do
36
+      # Try to migrate from the manual installation to capistrano directory structure
37
+      next if test('[ -L ~/huginn ]')
38
+      fetch(:linked_files).each do |f|
39
+        if !test("[ -f ~/shared/#{f} ] ") && test("[ -f ~/huginn/#{f} ]")
40
+          execute("cp ~/huginn/#{f} ~/shared/#{f}")
41
+        end
42
+      end
43
+      execute('mv ~/huginn ~/huginn.manual')
44
+      execute('ln -s ~/current ~/huginn')
45
+    end
46
+  end
47
+  after :publishing, :restart do
48
+    on roles(:all) do
49
+      within release_path do
50
+        execute :rake, 'production:restart'
51
+      end
52
+    end
53
+  end
54
+end

+ 1 - 0
config/deploy/production.rb

@@ -0,0 +1 @@
1
+server ENV['CAPISTRANO_DEPLOY_SERVER'], user: ENV['CAPISTRANO_DEPLOY_USER'] || 'huginn', roles: %w{app db web}

+ 5 - 2
config/environments/development.rb

@@ -39,8 +39,11 @@ Huginn::Application.configure do
39 39
 
40 40
   config.action_mailer.default_url_options = { :host => ENV['DOMAIN'] }
41 41
   config.action_mailer.asset_host = ENV['DOMAIN']
42
-  config.action_mailer.perform_deliveries = ENV['SEND_EMAIL_IN_DEVELOPMENT'] == 'true'
43 42
   config.action_mailer.raise_delivery_errors = true
44
-  config.action_mailer.delivery_method = :smtp
43
+  if ENV['SEND_EMAIL_IN_DEVELOPMENT'] == 'true'
44
+    config.action_mailer.delivery_method = :smtp
45
+  else
46
+    config.action_mailer.delivery_method = :letter_opener_web
47
+  end
45 48
   # smtp_settings moved to config/initializers/action_mailer.rb
46 49
 end

+ 5 - 0
config/routes.rb

@@ -62,6 +62,7 @@ Huginn::Application.routes.draw do
62 62
     end
63 63
     collection do
64 64
       delete :destroy_failed
65
+      delete :destroy_all
65 66
     end
66 67
   end
67 68
 
@@ -74,6 +75,10 @@ Huginn::Application.routes.draw do
74 75
   devise_for :users,
75 76
              controllers: { omniauth_callbacks: 'omniauth_callbacks' },
76 77
              sign_out_via: [:post, :delete]
78
+  
79
+  if Rails.env.development?
80
+    mount LetterOpenerWeb::Engine, at: "/letter_opener"
81
+  end
77 82
 
78 83
   get "/about" => "home#about"
79 84
   root :to => "home#index"

+ 9 - 9
deployment/site-cookbooks/huginn_production/files/default/unicorn.rb

@@ -1,24 +1,25 @@
1
-app_path = "/home/huginn/current"
1
+wd = File.expand_path(File.join(File.dirname(__FILE__), '..'))
2
+
3
+app_path = wd
2 4
 
3 5
 worker_processes 2
4 6
 preload_app true
5 7
 timeout 180
6
-listen '/home/huginn/shared/tmp/sockets/unicorn.sock'
8
+listen "#{wd}/tmp/sockets/unicorn.socket"
7 9
 
8 10
 working_directory app_path
9 11
 
10 12
 rails_env = ENV['RAILS_ENV'] || 'production'
11 13
 
12 14
 # Log everything to one file
13
-stderr_path "log/unicorn_out.log"
14
-stdout_path "log/unicorn_err.log"
15
+stderr_path "log/unicorn.log"
16
+stdout_path "log/unicorn.log"
15 17
 
16 18
 # Set master PID location
17
-pid '/home/huginn/shared/tmp/pids/unicorn.pid'
19
+pid "#{wd}/tmp/pids/unicorn.pid"
18 20
 
19 21
 before_fork do |server, worker|
20
-  defined?(ActiveRecord::Base) and
21
-    ActiveRecord::Base.connection.disconnect!
22
+  ActiveRecord::Base.connection.disconnect!
22 23
   old_pid = "#{server.config[:pid]}.oldbin"
23 24
   if File.exist?(old_pid) && server.pid != old_pid
24 25
     begin
@@ -30,6 +31,5 @@ before_fork do |server, worker|
30 31
 end
31 32
 
32 33
 after_fork do |server, worker|
33
-  defined?(ActiveRecord::Base) and
34
-    ActiveRecord::Base.establish_connection
34
+  ActiveRecord::Base.establish_connection
35 35
 end

+ 0 - 3
deployment/.chef/knife.rb

@@ -1,3 +0,0 @@
1
-cookbook_path ["cookbooks", "site-cookbooks"]
2
-role_path     "roles"
3
-data_bag_path "data_bags"

+ 0 - 11
deployment/Cheffile

@@ -1,11 +0,0 @@
1
-#!/usr/bin/env ruby
2
-#^syntax detection
3
-
4
-site 'http://community.opscode.com/api/v1'
5
-
6
-cookbook 'ark'
7
-cookbook 'runit'
8
-cookbook 'git', :git => 'git://github.com/opscode-cookbooks/git.git'
9
-cookbook 'nginx', :git => 'git://github.com/opscode-cookbooks/nginx.git'
10
-cookbook 'mysql', :git => 'git://github.com/opscode-cookbooks/mysql.git'
11
-cookbook 'nodejs', :git => 'git://github.com/redguide/nodejs.git'

+ 0 - 71
deployment/Cheffile.lock

@@ -1,71 +0,0 @@
1
-SITE
2
-  remote: http://community.opscode.com/api/v1
3
-  specs:
4
-    apt (2.4.0)
5
-    bluepill (2.3.1)
6
-      rsyslog (>= 0.0.0)
7
-    build-essential (2.0.2)
8
-    chef_handler (1.1.6)
9
-    dmg (2.2.0)
10
-    ohai (2.0.0)
11
-    rsyslog (1.12.2)
12
-    runit (1.5.10)
13
-      build-essential (>= 0.0.0)
14
-      yum (~> 3.0)
15
-      yum-epel (>= 0.0.0)
16
-    windows (1.31.0)
17
-      chef_handler (>= 0.0.0)
18
-    yum (3.2.0)
19
-    yum-epel (0.3.6)
20
-      yum (~> 3.0)
21
-
22
-GIT
23
-  remote: git://github.com/redguide/nodejs.git
24
-  ref: master
25
-  sha: 91d8d11f189d13815d56af5700168e1cad88ae7f
26
-  specs:
27
-    nodejs (1.3.0)
28
-      apt (>= 0.0.0)
29
-      build-essential (>= 0.0.0)
30
-      yum-epel (>= 0.0.0)
31
-
32
-GIT
33
-  remote: git://github.com/opscode-cookbooks/git.git
34
-  ref: master
35
-  sha: b1bca76aaf3a3a2131744f17f6e5087e22fa3c40
36
-  specs:
37
-    git (4.0.3)
38
-      build-essential (>= 0.0.0)
39
-      dmg (>= 0.0.0)
40
-      runit (>= 1.0)
41
-      windows (>= 0.0.0)
42
-      yum (~> 3.0)
43
-      yum-epel (>= 0.0.0)
44
-
45
-GIT
46
-  remote: git://github.com/opscode-cookbooks/mysql.git
47
-  ref: master
48
-  sha: 4b70e99730ab4a7ce6c1dd7a35654a764fb6e0fe
49
-  specs:
50
-    mysql (5.2.13)
51
-
52
-GIT
53
-  remote: git://github.com/opscode-cookbooks/nginx.git
54
-  ref: master
55
-  sha: 45588ee2a5c7144a0ef2a5992e7f273542236d27
56
-  specs:
57
-    nginx (2.7.3)
58
-      apt (~> 2.2)
59
-      bluepill (~> 2.3)
60
-      build-essential (~> 2.0)
61
-      ohai (~> 2.0)
62
-      runit (~> 1.2)
63
-      yum-epel (~> 0.3)
64
-
65
-DEPENDENCIES
66
-  git (>= 0)
67
-  mysql (>= 0)
68
-  nginx (>= 0)
69
-  nodejs (>= 0)
70
-  runit (>= 0)
71
-

+ 0 - 40
deployment/Vagrantfile

@@ -1,40 +0,0 @@
1
-# -*- mode: ruby -*-
2
-# vi: set ft=ruby :
3
-
4
-Vagrant.configure("2") do |config|
5
-  config.omnibus.chef_version = :latest
6
-
7
-  config.vm.provision :chef_solo do |chef|
8
-    chef.roles_path = "roles"
9
-    chef.cookbooks_path = ["cookbooks", "site-cookbooks"]
10
-    chef.add_role("huginn_development")
11
-    # chef.add_role("huginn_production")
12
-  end
13
-
14
-  config.vm.provider :virtualbox do |vb, override|
15
-    #vb.memory = 1024
16
-    #vb.cpus = 4
17
-    override.vm.box = "hashicorp/precise64"
18
-    override.vm.network :forwarded_port, host: 3000, guest: 3000
19
-  end
20
-
21
-  config.vm.provider :parallels do |prl, override|
22
-    override.vm.box = "parallels/ubuntu-12.04"
23
-  end
24
-
25
-  config.vm.provider :aws do |aws, override|
26
-    aws.ami = ENV['AWS_AMI'] || "ami-828675f5"
27
-    aws.region = ENV['AWS_REGION'] || "eu-west-1"
28
-    aws.instance_type = "t1.micro"
29
-
30
-    override.vm.box = "dummy"
31
-    override.vm.box_url = "https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box"
32
-    override.ssh.private_key_path = ENV["AWS_SSH_PRIVKEY"]
33
-    override.ssh.username = ENV['AWS_SSH_USER'] || "ubuntu"
34
-
35
-    aws.access_key_id = ENV["AWS_ACCESS_KEY_ID"]
36
-    aws.secret_access_key = ENV["AWS_SECRET_ACCESS_KEY"]
37
-    aws.keypair_name = ENV["AWS_KEYPAIR_NAME"]
38
-    aws.security_groups = [ ENV["AWS_SECURITY_GROUP"] ]
39
-  end
40
-end

+ 20 - 0
deployment/logrotate/huginn

@@ -0,0 +1,20 @@
1
+/home/huginn/huginn/log/*.log {
2
+  daily
3
+  missingok
4
+  rotate 180
5
+  # must use with delaycompress below
6
+  compress
7
+  dateext
8
+
9
+  # this is important if using "compress" since we need to call
10
+  # the "lastaction" script below before compressing:
11
+  delaycompress
12
+
13
+  # note the lack of the evil "copytruncate" option in this
14
+  # config.  Unicorn supports the USR1 signal and we send it
15
+  # as our "lastaction" action:
16
+  lastaction
17
+    pid=/home/huginn/huginn/tmp/pids/unicorn.pid
18
+    test -s $pid && kill -USR1 "$(cat $pid)"
19
+  endscript
20
+}

+ 70 - 0
deployment/nginx/huginn

@@ -0,0 +1,70 @@
1
+## Huginn
2
+##
3
+## Lines starting with two hashes (##) are comments with information.
4
+## Lines starting with one hash (#) are configuration parameters that can be uncommented.
5
+##
6
+###################################
7
+##         configuration         ##
8
+###################################
9
+##
10
+## See installation.md#using-https for additional HTTPS configuration details.
11
+
12
+upstream huginn {
13
+  server unix:/home/huginn/huginn/tmp/sockets/unicorn.socket fail_timeout=0;
14
+}
15
+
16
+## Normal HTTP host
17
+server {
18
+  listen 0.0.0.0:80 default_server;
19
+  listen [::]:80 ipv6only=on default_server;
20
+  server_name YOUR_SERVER_FQDN; ## Replace this with something like huginn.example.com
21
+  server_tokens off; ## Don't show the nginx version number, a security best practice
22
+  root /home/huginn/huginn/public;
23
+
24
+  ## Increase this if you want to upload large attachments
25
+  client_max_body_size 20m;
26
+
27
+  ## Individual nginx logs for this Huginn vhost
28
+  access_log  /var/log/nginx/huginn_access.log;
29
+  error_log   /var/log/nginx/huginn_error.log;
30
+
31
+  location / {
32
+    ## Serve static files from defined root folder.
33
+    ## @huginn is a named location for the upstream fallback, see below.
34
+    try_files $uri $uri/index.html $uri.html @huginn;
35
+  }
36
+
37
+  ## If a file, which is not found in the root folder is requested,
38
+  ## then the proxy passes the request to the upsteam (huginn unicorn).
39
+  location @huginn {
40
+    ## If you use HTTPS make sure you disable gzip compression
41
+    ## to be safe against BREACH attack.
42
+    # gzip off;
43
+
44
+    proxy_read_timeout      300;
45
+    proxy_connect_timeout   300;
46
+    proxy_redirect          off;
47
+
48
+    proxy_set_header    Host                $http_host;
49
+    proxy_set_header    X-Real-IP           $remote_addr;
50
+    proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;
51
+    proxy_set_header    X-Forwarded-Proto   $scheme;
52
+    proxy_set_header    X-Frame-Options     SAMEORIGIN;
53
+
54
+    proxy_pass http://huginn;
55
+  }
56
+
57
+  ## Enable gzip compression as per rails guide:
58
+  ## http://guides.rubyonrails.org/asset_pipeline.html#gzip-compression
59
+  ## WARNING: If you are using relative urls remove the block below
60
+  ## See config/application.rb under "Relative url support" for the list of
61
+  ## other files that need to be changed for relative url support
62
+  location ~ ^/(assets)/ {
63
+    root /home/huginn/huginn/public;
64
+    gzip_static on; # to serve pre-gzipped version
65
+    expires max;
66
+    add_header Cache-Control public;
67
+  }
68
+
69
+  error_page 502 /502.html;
70
+}

+ 119 - 0
deployment/nginx/huginn-ssl

@@ -0,0 +1,119 @@
1
+## Huginn
2
+##
3
+## Modified from nginx http version
4
+## Modified from http://blog.phusion.nl/2012/04/21/tutorial-setting-up-gitlab-on-debian-6/
5
+## Modified from https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
6
+## Modified from https://github.com/gitlabhq/gitlabhq/blob/master/lib/support/nginx/gitlab-ssl
7
+##
8
+## Lines starting with two hashes (##) are comments with information.
9
+## Lines starting with one hash (#) are configuration parameters that can be uncommented.
10
+##
11
+###################################
12
+##         configuration         ##
13
+###################################
14
+##
15
+## See installation.md#using-https for additional HTTPS configuration details.
16
+
17
+upstream huginn {
18
+  server unix:/home/huginn/huginn/tmp/sockets/unicorn.socket fail_timeout=0;
19
+}
20
+
21
+## Redirects all HTTP traffic to the HTTPS host
22
+server {
23
+  listen 0.0.0.0:80;
24
+  listen [::]:80 ipv6only=on default_server;
25
+  server_name YOUR_SERVER_FQDN; ## Replace this with something like huginn.example.com
26
+  server_tokens off; ## Don't show the nginx version number, a security best practice
27
+  return 301 https://$server_name$request_uri;
28
+  access_log  /var/log/nginx/huginn_access.log;
29
+  error_log   /var/log/nginx/huginn_error.log;
30
+}
31
+
32
+
33
+## HTTPS host
34
+server {
35
+  listen 0.0.0.0:443 ssl;
36
+  listen [::]:443 ipv6only=on ssl default_server;
37
+  server_name YOUR_SERVER_FQDN; ## Replace this with something like huginn.example.com
38
+  server_tokens off; ## Don't show the nginx version number, a security best practice
39
+  root /home/git/huginn/public;
40
+
41
+  ## Increase this if you want to upload large attachments
42
+  ## Or if you want to accept large git objects over http
43
+  client_max_body_size 20m;
44
+
45
+  ## Strong SSL Security
46
+  ## https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html & https://cipherli.st/
47
+  ssl on;
48
+  ssl_certificate /etc/nginx/ssl/huginn.crt;
49
+  ssl_certificate_key /etc/nginx/ssl/huginn.key;
50
+
51
+  ssl_ciphers 'ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4';
52
+  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
53
+  ssl_prefer_server_ciphers on;
54
+  ssl_session_cache shared:SSL:10m;
55
+  ssl_session_timeout 5m;
56
+
57
+  ## See app/controllers/application_controller.rb for headers set
58
+
59
+  ## [Optional] If your certficate has OCSP, enable OCSP stapling to reduce the overhead and latency of running SSL.
60
+  ## Replace with your ssl_trusted_certificate. For more info see:
61
+  ## - https://medium.com/devops-programming/4445f4862461
62
+  ## - https://www.ruby-forum.com/topic/4419319
63
+  ## - https://www.digitalocean.com/community/tutorials/how-to-configure-ocsp-stapling-on-apache-and-nginx
64
+  # ssl_stapling on;
65
+  # ssl_stapling_verify on;
66
+  # ssl_trusted_certificate /etc/nginx/ssl/stapling.trusted.crt;
67
+  # resolver 208.67.222.222 208.67.222.220 valid=300s; # Can change to your DNS resolver if desired
68
+  # resolver_timeout 5s;
69
+
70
+  ## [Optional] Generate a stronger DHE parameter:
71
+  ##   sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096
72
+  ##
73
+  # ssl_dhparam /etc/ssl/certs/dhparam.pem;
74
+
75
+  ## Individual nginx logs for this huginn vhost
76
+  access_log  /var/log/nginx/huginn_access.log;
77
+  error_log   /var/log/nginx/huginn_error.log;
78
+
79
+  location / {
80
+    ## Serve static files from defined root folder.
81
+    ## @huginn is a named location for the upstream fallback, see below.
82
+    try_files $uri $uri/index.html $uri.html @huginn;
83
+  }
84
+
85
+  ## If a file, which is not found in the root folder is requested,
86
+  ## then the proxy passes the request to the upsteam (huginn unicorn).
87
+  location @huginn {
88
+    ## If you use HTTPS make sure you disable gzip compression
89
+    ## to be safe against BREACH attack.
90
+    gzip off;
91
+
92
+    proxy_read_timeout      300;
93
+    proxy_connect_timeout   300;
94
+    proxy_redirect          off;
95
+
96
+    proxy_set_header    Host                $http_host;
97
+    proxy_set_header    X-Real-IP           $remote_addr;
98
+    proxy_set_header    X-Forwarded-Ssl     on;
99
+    proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;
100
+    proxy_set_header    X-Forwarded-Proto   $scheme;
101
+    proxy_set_header    X-Frame-Options     SAMEORIGIN;
102
+
103
+    proxy_pass http://huginn;
104
+  }
105
+
106
+  ## Enable gzip compression as per rails guide:
107
+  ## http://guides.rubyonrails.org/asset_pipeline.html#gzip-compression
108
+  ## WARNING: If you are using relative urls remove the block below
109
+  ## See config/application.rb under "Relative url support" for the list of
110
+  ## other files that need to be changed for relative url support
111
+  location ~ ^/(assets)/ {
112
+    root /home/huginn/huginn/public;
113
+    gzip_static on; # to serve pre-gzipped version
114
+    expires max;
115
+    add_header Cache-Control public;
116
+  }
117
+
118
+  error_page 502 /502.html;
119
+}

+ 0 - 30
deployment/roles/huginn_development.json

@@ -1,30 +0,0 @@
1
-{
2
-
3
-"name" : "huginn_development",
4
-
5
-"chef_type" : "role",
6
-
7
-"json_class" : "Chef::Role",
8
-
9
-"description" : "Huginn Development Environment",
10
-
11
-"default_attributes" : {
12
-    "mysql" : {
13
-      "server_root_password" : "",
14
-      "server_repl_password" : "",
15
-      "server_debian_password" : ""
16
-    },
17
-    "nginx" : {
18
-       "init_style" : "upstart"
19
-    }
20
-},
21
-
22
-"run_list":[
23
-             "recipe[git]",
24
-             "recipe[apt]",
25
-             "recipe[mysql::server]",
26
-             "recipe[mysql::client]",
27
-             "recipe[nodejs::nodejs_from_binary]",
28
-             "recipe[huginn_development]"
29
-           ]
30
-}

+ 0 - 30
deployment/roles/huginn_production.json

@@ -1,30 +0,0 @@
1
-{
2
-
3
-"name" : "huginn_production",
4
-
5
-"chef_type" : "role",
6
-
7
-"json_class" : "Chef::Role",
8
-
9
-"description" : "Huginn Production Environment",
10
-
11
-"default_attributes" : {
12
-  "mysql": {
13
-    "server_root_password": "password",
14
-    "server_repl_password": "",
15
-    "server_debian_password": ""
16
-  },
17
-    "nginx" : {
18
-       "init_style" : "upstart"
19
-    }
20
-},
21
-
22
-"run_list":[
23
-             "recipe[git]",
24
-             "recipe[apt]",
25
-             "recipe[mysql::server]",
26
-             "recipe[nodejs::nodejs_from_binary]",
27
-             "recipe[nginx]",
28
-             "recipe[huginn_production]"
29
-           ]
30
-}

+ 0 - 78
deployment/site-cookbooks/huginn_development/recipes/default.rb

@@ -1,78 +0,0 @@
1
-include_recipe 'apt'
2
-include_recipe 'build-essential'
3
-
4
-user "huginn" do
5
-  action :create
6
-  system true
7
-  home "/home/huginn"
8
-  password "$6$ZwO6b.6tij$SMa8UIwtESGDxB37NwHsct.gJfXWmmflNbH.oypwJ9y0KkzMkCdw7D14iK7GX9C4CWSEcpGOFUow7p01rQFu5."
9
-  supports :manage_home => true
10
-  gid "sudo"
11
-  shell "/bin/bash"
12
-end
13
-
14
-group "huginn" do
15
-  members ["huginn"]
16
-  action :create
17
-end
18
-
19
-%w("ruby1.9.1" "ruby1.9.1-dev" "libxslt-dev" "libxml2-dev" "curl" "libmysqlclient-dev" "libffi-dev" "libssl-dev").each do |pkg|
20
-  package pkg do
21
-    action :install
22
-  end
23
-end
24
-
25
-bash "Setting default ruby and gem versions to 1.9" do
26
-  code <<-EOH
27
-    if [ $(readlink /usr/bin/ruby) != "ruby1.9.1" ]
28
-    then
29
-      update-alternatives --set ruby /usr/bin/ruby1.9.1
30
-    fi
31
-
32
-    if [ $(readlink /usr/bin/gem) != "gem1.9.1" ]
33
-    then
34
-      update-alternatives --set gem /usr/bin/gem1.9.1
35
-    fi
36
-  EOH
37
-end
38
-
39
-git "/home/huginn/huginn" do
40
-  repository 'git://github.com/cantino/huginn.git'
41
-  reference 'master'
42
-  action :sync
43
-  user "huginn"
44
-end
45
-
46
-gem_package("rake")
47
-gem_package("bundle")
48
-
49
-bash "Setting huginn user with NOPASSWD option" do
50
-  cwd "/etc/sudoers.d"
51
-  code <<-EOH
52
-    touch huginn
53
-    chmod 0440 huginn
54
-    echo "huginn ALL=(ALL) NOPASSWD:ALL" >> huginn
55
-    EOH
56
-end
57
-
58
-bash "huginn dependencies" do
59
-  user "huginn"
60
-  cwd "/home/huginn/huginn"
61
-  code <<-EOH
62
-    export LANG="en_US.UTF-8"
63
-    export LC_ALL="en_US.UTF-8"
64
-    sudo bundle install
65
-    sed s/REPLACE_ME_NOW\!/$(sudo bundle exec rake secret)/ .env.example > .env
66
-    sudo bundle exec rake db:create
67
-    sudo bundle exec rake db:migrate
68
-    sudo bundle exec rake db:seed
69
-    EOH
70
-end
71
-
72
-bash "huginn has been installed and will start in a minute" do
73
-  user "huginn"
74
-  cwd "/home/huginn/huginn"
75
-  code <<-EOH
76
-    sudo nohup foreman start &
77
-    EOH
78
-end

+ 0 - 2
deployment/site-cookbooks/huginn_production/files/default/Procfile

@@ -1,2 +0,0 @@
1
-web: sudo bundle exec unicorn_rails -c config/unicorn.rb -E production
2
-jobs: sudo RAILS_ENV=production bundle exec rails runner bin/threaded.rb

+ 0 - 109
deployment/site-cookbooks/huginn_production/files/default/env.example

@@ -1,109 +0,0 @@
1
-# ==== Required configuration settings for Huginn ====
2
-
3
-# Replace the following with the output from "rake secret"
4
-APP_SECRET_TOKEN=REPLACE_ME_NOW!
5
-
6
-# This is the domain where your Huginn instance will be running. The default should work
7
-# for development, but it needs to be changed to your Huginn domain when you deploy to a
8
-# production environment (e.g., yourdomain.com, possibly including a port).
9
-#DOMAIN=localhost:3000
10
-
11
-############################
12
-#      Database Setup      #
13
-############################
14
-
15
-DATABASE_ADAPTER=mysql2
16
-DATABASE_ENCODING=utf8
17
-DATABASE_RECONNECT=true
18
-DATABASE_NAME=huginn_production
19
-DATABASE_POOL=5
20
-DATABASE_USERNAME=root
21
-DATABASE_PASSWORD=password
22
-#DATABASE_HOST=your-domain-here.com
23
-#DATABASE_PORT=3306
24
-#DATABASE_SOCKET=/tmp/mysql.sock
25
-
26
-# ==== Additional required production settings ====
27
-
28
-# Configure Rails environment.  This should only be needed in production and may cause errors in development.
29
-RAILS_ENV=production
30
-
31
-# Should Rails force all requests to use SSL?
32
-FORCE_SSL=false
33
-
34
-############################
35
-#     Allowing Signups     #
36
-############################
37
-
38
-# This invitation code will be required for users to signup with your Huginn installation.
39
-# You can see its use in user.rb.  PLEASE CHANGE THIS!
40
-INVITATION_CODE=try-huginn
41
-
42
-# If you don't want to require users to have an invitation code, set this to true
43
-SKIP_INVITATION_CODE=false
44
-
45
-#############################
46
-#    Email Configuration    #
47
-#############################
48
-
49
-# Outgoing email settings.  To use Gmail or Google Apps, put your Google Apps domain or gmail.com
50
-# as the SMTP_DOMAIN and your Gmail username and password as the SMTP_USER_NAME and SMTP_PASSWORD.
51
-# 
52
-# PLEASE NOTE: In order to enable emails locally (e.g., when not in the production Rails environment),
53
-# you must also set SEND_EMAIL_IN_DEVELOPMENT to true below.
54
-
55
-SMTP_DOMAIN=your-domain-here.com
56
-SMTP_USER_NAME=you@gmail.com
57
-SMTP_PASSWORD=somepassword
58
-SMTP_SERVER=smtp.gmail.com
59
-SMTP_PORT=587
60
-SMTP_AUTHENTICATION=plain
61
-SMTP_ENABLE_STARTTLS_AUTO=true
62
-
63
-# Send emails when running in the development Rails environment.
64
-SEND_EMAIL_IN_DEVELOPMENT=false
65
-
66
-# The address from which system emails will appear to be sent.
67
-EMAIL_FROM_ADDRESS=from_address@gmail.com
68
-
69
-###########################
70
-#      Agent Logging      #
71
-###########################
72
-
73
-# Number of lines of log messages to keep per Agent
74
-AGENT_LOG_LENGTH=200
75
-
76
-#############################
77
-#  AWS and Mechanical Turk  #
78
-#############################
79
-
80
-# AWS Credentials for MTurk
81
-AWS_ACCESS_KEY_ID=YOUR-AWS-ACCESS-KEY-ID
82
-AWS_ACCESS_KEY=YOUR-AWS-ACCESS-KEY
83
-
84
-# Set AWS_SANDBOX to true if you're developing Huginn code.
85
-AWS_SANDBOX=false
86
-
87
-########################
88
-#   Various Settings   #
89
-########################
90
-
91
-# Specify the HTTP backend library for Faraday, used in WebsiteAgent.
92
-# You can change this depending on the performance and stability you
93
-# need for your service.  Any choice other than "typhoeus",
94
-# "net_http", or "em_http" should require you to bundle a corresponding
95
-# gem via Gemfile.
96
-FARADAY_HTTP_BACKEND=typhoeus
97
-
98
-# Allow JSONPath eval expresions. i.e., $..price[?(@ < 20)]
99
-# You should not allow this on a shared Huginn box because it is not secure.
100
-ALLOW_JSONPATH_EVAL=false
101
-
102
-# Enable this setting to allow insecure Agents like the ShellCommandAgent.  Only do this
103
-# when you trust everyone using your Huginn installation.
104
-ENABLE_INSECURE_AGENTS=false
105
-
106
-# Use Graphviz for generating diagrams instead of using Google Chart
107
-# Tools.  Specify a dot(1) command path built with SVG support
108
-# enabled.
109
-#USE_GRAPHVIZ_DOT=dot

+ 0 - 36
deployment/site-cookbooks/huginn_production/files/default/nginx.conf

@@ -1,36 +0,0 @@
1
-#worker_process 2;
2
-user huginn huginn;
3
-
4
-events {
5
-  worker_connections 1024;
6
-  accept_mutex on;
7
-}
8
-
9
-http {
10
-  types_hash_max_size 2048;
11
-  include    mime.types;
12
-
13
-  upstream huginn_server {
14
-    server unix:/home/huginn/shared/tmp/sockets/unicorn.sock;
15
-  }
16
-
17
-  server {
18
-    listen 80;
19
-    server_name _;
20
-    keepalive_timeout 5;
21
-    root /home/huginn/current/public;
22
-    try_files $uri/index.html $uri.html $uri @app;
23
-    error_page 500 502 503 504 /500.html;
24
-    location = /500.html {
25
-      root /home/huginn/current/public;
26
-    }
27
-    location @app {
28
-      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
29
-      proxy_set_header X-Forwarded-Proto $scheme;
30
-      proxy_set_header Host $http_host;
31
-      proxy_redirect off;
32
-      proxy_pass http://huginn_server;
33
-    }
34
-}
35
-}
36
-

+ 0 - 111
deployment/site-cookbooks/huginn_production/recipes/default.rb

@@ -1,111 +0,0 @@
1
-include_recipe 'apt'
2
-include_recipe 'build-essential'
3
-
4
-user "huginn" do
5
-  system true
6
-  home "/home/huginn"
7
-  password "$6$ZwO6b.6tij$SMa8UIwtESGDxB37NwHsct.gJfXWmmflNbH.oypwJ9y0KkzMkCdw7D14iK7GX9C4CWSEcpGOFUow7p01rQFu5."
8
-  supports :manage_home => true
9
-  shell "/bin/bash"
10
-  gid "sudo"
11
-end
12
-
13
-group "huginn" do
14
-  members ["huginn"]
15
-end
16
-
17
-%w("ruby1.9.1" "ruby1.9.1-dev" "libxslt-dev" "libxml2-dev" "curl" "libmysqlclient-dev" "libffi-dev" "libssl-dev").each do |pkg|
18
-  package("#{pkg}")
19
-end
20
-
21
-bash "Setting default ruby and gem versions to 1.9" do
22
-  code <<-EOH
23
-    if [ $(readlink /usr/bin/ruby) != "ruby1.9.1" ]
24
-    then
25
-      update-alternatives --set ruby /usr/bin/ruby1.9.1
26
-    fi
27
-
28
-    if [ $(readlink /usr/bin/gem) != "gem1.9.1" ]
29
-    then
30
-      update-alternatives --set gem /usr/bin/gem1.9.1
31
-    fi
32
-  EOH
33
-end
34
-
35
-gem_package("rake")
36
-gem_package("bundle")
37
-
38
-service "nginx" do
39
-  supports :restart => true, :start => true, :stop => true, :reload => true
40
-  action :nothing
41
-end
42
-
43
-bash "Setting huginn user with NOPASSWD option" do
44
-  cwd "/etc/sudoers.d"
45
-  code <<-EOH
46
-    touch huginn && chmod 0440 huginn 
47
-    echo "huginn ALL=(ALL) NOPASSWD:ALL" >> huginn
48
-  EOH
49
-end
50
-
51
-deploy "/home/huginn" do
52
-  repo "https://github.com/cantino/huginn.git"
53
-  branch "master"
54
-  user "huginn"
55
-  group "huginn"
56
-  environment "RAILS_ENV" => "production"
57
-  keep_releases 5
58
-  create_dirs_before_symlink []
59
-  symlinks "log" => "log"
60
-  symlink_before_migrate({})
61
-  rollback_on_error true
62
-  notifies :enable, "service[nginx]"
63
-  notifies :start, "service[nginx]"
64
-  before_symlink do
65
-    %w(config log tmp).each do |dir|
66
-      directory "/home/huginn/shared/#{dir}" do
67
-      owner "huginn"
68
-      group "huginn"
69
-      recursive true
70
-      end
71
-    end
72
-    directory("/home/huginn/shared/tmp/pids")
73
-    directory("/home/huginn/shared/tmp/sockets")
74
-    %w(Procfile unicorn.rb nginx.conf).each do |file|
75
-      cookbook_file "/home/huginn/shared/config/#{file}" do
76
-      owner "huginn"
77
-      action :create_if_missing
78
-      end
79
-    end
80
-    cookbook_file "home/huginn/shared/config/.env" do
81
-    source "env.example"
82
-    mode "666"
83
-    owner "huginn"
84
-    action :create_if_missing
85
-    end
86
-  end
87
-  before_restart do
88
-    bash "huginn dependencies" do
89
-      cwd "/home/huginn/current"
90
-      user "huginn"
91
-      group "huginn"
92
-      code <<-EOH
93
-      export LANG="en_US.UTF-8"
94
-      export LC_ALL="en_US.UTF-8"
95
-      ln -nfs /home/huginn/shared/config/Procfile ./Procfile
96
-      ln -nfs /home/huginn/shared/config/.env ./.env
97
-      ln -nfs /home/huginn/shared/config/unicorn.rb ./config/unicorn.rb
98
-      sudo cp /home/huginn/shared/config/nginx.conf /etc/nginx/
99
-      echo 'gem "unicorn", :group => :production' >> Gemfile
100
-      sudo bundle install --without=development --without=test
101
-      sed -i s/REPLACE_ME_NOW\!/$(sudo bundle exec rake secret)/ /home/huginn/shared/config/.env
102
-      sudo RAILS_ENV=production bundle exec rake db:create
103
-      sudo RAILS_ENV=production bundle exec rake db:migrate
104
-      sudo RAILS_ENV=production bundle exec rake db:seed
105
-      sudo RAILS_ENV=production bundle exec rake assets:precompile
106
-      sudo foreman export upstart /etc/init -a huginn -u huginn -l log
107
-      sudo start huginn
108
-      EOH
109
-    end
110
-  end
111
-end

+ 20 - 0
doc/README.md

@@ -0,0 +1,20 @@
1
+# Documentation
2
+
3
+## Installation and upgrading
4
+
5
+### Docker (not recommended for production)
6
+
7
+- [Check out Huginn with Docker](docker/install.md) Run a local Huginn installation using Docker
8
+
9
+### Manual installation
10
+
11
+Manual installation instructions which will guide through the steps to install Huginn on any Ubuntu 12.04/14.04 or Debian 6/7 server.
12
+
13
+- [Install](manual/README.md) Requirements, directory structures and installation from source.
14
+- [Update](manual/update.md) Update your installation.
15
+- Deploy updates via [Capistrano](manual/capistrano.md).
16
+
17
+### Heroku
18
+
19
+- [Deploy to Heroku](heroku/install.md)
20
+- [Update](heroku/update.md) an existing Heroku deployment

deployment/nodes/.gitignore → doc/configuration/dotenv.md


+ 0 - 0
doc/configuration/procfile.md


+ 44 - 0
doc/docker/install.md

@@ -0,0 +1,44 @@
1
+## Why run Huginn with docker
2
+
3
+You can play with or deploy Huginn inside of [docker](http://www.docker.io/).
4
+
5
+Getting Huginn up and running using docker is quick and painless once you have docker installed. The docker container is suitable for production and evaluation. Huginn uses environmental variables for configuration, so rather than having a .env file, the Docker container expects variables to be passed into the launch command.
6
+
7
+## Running the Container
8
+
9
+### Quick start to check out Huginn
10
+
11
+#### OSX GUI using Kitematic
12
+
13
+1. Download and install [Kitematic](https://www.docker.com/docker-kitematic)
14
+* Start Kitematic and search for `cantino/huginn`
15
+* Click `create` and wait for the container to be downloaded and booted
16
+* Click on the link icon next to 'WEB PREVIEW'
17
+* Log in to your Huginn instance using the username `admin` and password `password`
18
+
19
+#### OSX/Windows/Linux using docker machine
20
+
21
+1. Download [docker machine](https://docs.docker.com/machine/#installation) for your OS
22
+* Follow the installation instructions untill you can successfully run `docker ps`
23
+* Get the the IP of the VM running docker by running `docker-machine ls`
24
+* Start your Huginn container using `docker run -it -p 3000:3000 cantino/huginn`
25
+* Open Huginn in the browser [http://docker-machine ip:3000](http://<docker-machine ip>:3000)
26
+* Log in to your Huginn instance using the username `admin` and password `password`
27
+
28
+#### Linux
29
+
30
+1. Install docker using the [install instructions](https://docs.docker.com/installation/)
31
+* Start your Huginn container using `docker run -it -p 3000:3000 cantino/huginn`
32
+* Open Huginn in the browser [http://localhost:3000](http://localhost:3000)
33
+* Log in to your Huginn instance using the username `admin` and password `password`
34
+
35
+## Configuration and linking to a database container
36
+
37
+Follow the [instructions on the docker hub registry](https://registry.hub.docker.com/u/cantino/huginn/) on how to configure Huginn using environment variables and linking the container to an external MySQL or PostgreSQL database.
38
+
39
+### Other options:
40
+
41
+Other Docker options:
42
+
43
+* If you don't want to use the official repo, see also: https://registry.hub.docker.com/u/andrewcurioso/huginn/
44
+* If you'd like to run Huginn's web process and job worker process in separate containers, another option is https://github.com/hackedu/huginn-docker. It also uses Unicorn as the web server and serves precompiled assets.

+ 144 - 0
doc/heroku/install.md

@@ -0,0 +1,144 @@
1
+## Deploy to Heroku
2
+
3
+### Important things to keep in mind on the free plan
4
+
5
+* Heroku's [free plan](https://www.heroku.com/pricing) limits total runtime per day to 18 hours. This means that Huginn must sleep some of the time, and so recurring tasks will only run if their recurrence frequency fits within the free plan's awake time, which is 30 minutes. Therefore, we recommend that you only use the every 1 minute, every 2 minute, and every 5 minute Agent scheduling options.
6
+* When setting up Pingdom, set the `Check interval` to '60 minutes' so that your Huginn instance is up half the time.
7
+* Heroku's free Postgres plan limits the number of database rows that you can have to 10,000, so you should be sure to set a low event retention schedule for your agents.
8
+* The `setup_heroku` command points Heroku at a special Procfile (`deployment/heroku/Procfile.heroku`) that is designed to be run on only one Heroku web worker.  If you want to run multiple workers, change the Heroku config variable `PROCFILE_PATH` with `heroku config:set PROCFILE_PATH=./Procfile` and switch back to the standard Huginn Procfile configuration.
9
+
10
+### Instructions
11
+
12
+* Install the [Heroku Toolbelt](https://toolbelt.heroku.com/) and then run `heroku login`
13
+* Go into your huginn directory and run `bundle`
14
+* Now, run the magic setup wizard: `bin/setup_heroku`
15
+* That's it!
16
+* If you make changes, you can re-run `bin/setup_heroku`, or just do `git push heroku master`.
17
+* Signup for a free [Pingdom](https://www.pingdom.com/free/) account and have it ping your Huginn URL on Heroku once an hour.
18
+
19
+### Using your own mail server
20
+
21
+```bash
22
+# Outgoing email settings.  To use Gmail or Google Apps, put your Google Apps domain or gmail.com
23
+# as the SMTP_DOMAIN and your Gmail username and password as the SMTP_USER_NAME and SMTP_PASSWORD.
24
+heroku config:set SMTP_DOMAIN=your-domain-here.com
25
+heroku config:set SMTP_USER_NAME=you@gmail.com
26
+heroku config:set SMTP_PASSWORD=somepassword
27
+heroku config:set SMTP_SERVER=smtp.gmail.com
28
+
29
+# The address from which system emails will appear to be sent.
30
+heroku config:set EMAIL_FROM_ADDRESS=you@gmail.com
31
+```
32
+
33
+### Backing up your data
34
+
35
+See: https://devcenter.heroku.com/articles/heroku-postgres-import-export
36
+
37
+### Example output from `bin/setup_heroku`
38
+
39
+```
40
+~/projects/oss/huginn (master)$ bin/setup_heroku 
41
+
42
+Welcome andrew@example.com!  It looks like you're logged into Heroku.
43
+
44
+It looks like you don't have a Heroku app set up yet for this repo.
45
+You can either exit now and run 'heroku create', or I can do it for you.
46
+Would you like me to create a Heroku app for you now in this repo? (y/n) y
47
+Creating radiant-forest-1519... done, stack is cedar
48
+http://radiant-forest-1519.herokuapp.com/ | git@heroku.com:radiant-forest-1519.git
49
+Git remote heroku added
50
+Your Heroku app name is radiant-forest-1519.  Is this correct? (y/n) y
51
+Setting up APP_SECRET_TOKEN...
52
+Setting BUILDPACK_URL to https://github.com/ddollar/heroku-buildpack-multi.git
53
+BUILDPACK_URL: https://github.com/ddollar/heroku-buildpack-multi.git
54
+Setting PROCFILE_PATH to deployment/heroku/Procfile.heroku
55
+PROCFILE_PATH: deployment/heroku/Procfile.heroku
56
+Setting ON_HEROKU to true
57
+Setting FORCE_SSL to true
58
+Setting DOMAIN to radiant-forest-1519.herokuapp.com
59
+
60
+You need to set an invitation code for your Huginn instance.  If you plan to share this instance, you will
61
+tell this code to anyone who you'd like to invite.  If you won't share it, then just set this to something
62
+that people will not guess.
63
+What code would you like to use? 
64
+What code would you like to use? something-secret
65
+Setting INVITATION_CODE to something-secret
66
+
67
+Okay, let's setup outgoing email settings.  The simplest solution is to use the free sendgrid Heroku addon.
68
+If you'd like to use your own server, or your Gmail account, please see .env.example and set
69
+SMTP_DOMAIN, SMTP_USER_NAME, SMTP_PASSWORD, and SMTP_SERVER with 'heroku config:set'.
70
+Should I enable the free sendgrid addon? (y/n) y
71
+Use `heroku addons:docs sendgrid` to view documentation.
72
+SMTP_SERVER: smtp.sendgrid.net
73
+SMTP_DOMAIN: heroku.com
74
+SMTP_USER_NAME: app27830035@heroku.com
75
+SMTP_PASSWORD: sflajgz0
76
+What email address would you like email to appear to be sent from? andrew@example.com
77
+Setting EMAIL_FROM_ADDRESS to andrew@example.com
78
+EMAIL_FROM_ADDRESS: andrew@example.com
79
+
80
+Should I push your current branch (master) to heroku? (y/n) y
81
+This may take a moment...
82
+Initializing repository, done.
83
+
84
+-----> Fetching custom git buildpack... done
85
+-----> Multipack app detected
86
+=====> Downloading Buildpack: https://github.com/cantino/heroku-selectable-procfile.git
87
+=====> Detected Framework: Selectable Procfile
88
+-----> Using deployment/heroku/Procfile.heroku as Procfile
89
+=====> Downloading Buildpack: https://github.com/heroku/heroku-buildpack-ruby.git
90
+=====> Detected Framework: Ruby
91
+-----> Compiling Ruby/Rails
92
+-----> Using Ruby version: ruby-2.0.0
93
+-----> Installing dependencies using 1.6.3
94
+       Running: bundle install --without development:test --path vendor/bundle --binstubs vendor/bundle/bin -j4 --deployment
95
+       Fetching source index from https://rubygems.org/
96
+       Fetching git://github.com/cantino/twitter-stream.git
97
+       Installing i18n 0.6.9
98
+       Installing rake 10.3.2
99
+       Installing minitest 5.3.5
100
+       [...gems are installed...]
101
+       Your bundle is complete!
102
+       Gems in the groups development and test were not installed.
103
+       It was installed into ./vendor/bundle
104
+       Post-install message from httparty:
105
+       When you HTTParty, you must party hard!
106
+       Post-install message from rufus-scheduler:
107
+       Bundle completed (133.85s)
108
+       Cleaning up the bundler cache.
109
+-----> Preparing app for Rails asset pipeline
110
+       Running: rake assets:precompile
111
+       I, [2014-07-26T20:36:06.069156 #5939]  INFO -- : Writing /tmp/build_7b0d30bd-3c35-46dc-b73d-b5f05754d340/public/assets/select2x2-ec4bf2b76c97838b357413d72a2f69cf.png [...]
112
+       Asset precompilation completed (42.28s)
113
+       Cleaning assets
114
+       Running: rake assets:clean
115
+
116
+Using release configuration from last framework (Ruby).
117
+-----> Discovering process types
118
+       Procfile declares types     -> web
119
+       Default types for Multipack -> console, rake, worker
120
+
121
+-----> Compressing... done, 45.1MB
122
+-----> Launching... done, v19
123
+       http://radiant-forest-1519.herokuapp.com/ deployed to Heroku
124
+
125
+To git@heroku.com:radiant-forest-1519.git
126
+ * [new branch]      master -> master
127
+Running database migrations...
128
+Running `rake db:migrate` attached to terminal... up, run.3341
129
+
130
+[...migrations run...]
131
+
132
+I can make an admin user on your new Huginn instance and setup some example Agents.
133
+Should I create a new admin user and some example Agents? (y/n) y
134
+
135
+Okay, what is your email address? andrew@example.com
136
+And what username would you like to login as? andrew
137
+Finally, what password would you like to use? 
138
+Just a moment...
139
+
140
+
141
+Okay, you should be all set!  Visit https://radiant-forest-1519.herokuapp.com and login as 'andrew' with your password.
142
+
143
+Done!
144
+```

+ 9 - 0
doc/heroku/update.md

@@ -0,0 +1,9 @@
1
+## Update an existing Heroku deployment
2
+
3
+Once you've run `bin/setup_heroku`, you should have 'cantino/huginn' as a remote in git.  (Check with `git remote -v`.)  Now, you can update your Heroku installation with the following commands:
4
+
5
+```sh
6
+git fetch origin
7
+git merge origin/master
8
+git push -f heroku master # note: this will wipe out any code changes that only exist on Heroku!
9
+```

+ 6 - 0
doc/manual/README.md

@@ -0,0 +1,6 @@
1
+# Manual Installation
2
+
3
+- [Requirements](requirements.md) Software and hardware requirements to run the Huginn installation
4
+- [Install](installation.md) Installation guide for Ubundu/Debian
5
+- [Update](update.md) Update an existing Huginn installation
6
+- Deploy updates via [Capistrano](capistrano.md)

+ 47 - 0
doc/manual/capistrano.md

@@ -0,0 +1,47 @@
1
+# Deploy updates via Capistrano
2
+
3
+After you followed the [manual installation guide](installation.md) it is simple to push updates to your huginn instance using capistrano.
4
+
5
+### 1. Ensure you have SSH access to your server via the huginn user
6
+
7
+Either set a password for the huginn user or add your public SSH key:
8
+
9
+    # Set password
10
+    sudo passwd huginn
11
+
12
+    # Or add a SSH key
13
+    sudo -u huginn -H mkdir -p /home/huginn/.ssh
14
+    sudo -u huginn -H editor /home/huginn/.ssh/authorized_keys
15
+    sudo -u huginn -H chmod -R 700 /home/huginn/.ssh
16
+
17
+### 2. Configure Capistrano on your local machine
18
+
19
+Add Capistrano configuration to you local `.env`:
20
+
21
+    CAPISTRANO_DEPLOY_SERVER=<IP or FQDN of your server>
22
+    CAPISTRANO_DEPLOY_USER=huginn
23
+    CAPISTRANO_DEPLOY_REPO_URL=https://github.com/cantino/huginn.git
24
+
25
+
26
+### 3. Run Capistrano
27
+
28
+You can now run Capistrano and update your server:
29
+
30
+    cap production deploy
31
+
32
+If you want to deploy a different branch, pass it as environment variable:
33
+
34
+    cap production deploy BRANCH=awesome-feature
35
+
36
+### Changes to remote .env and Procfile
37
+
38
+If you want to change the `.env`, `Procfile` or `config/unicorn.rb` of your installation you still need to do it on your server, do not forget to export the init scripts after your are done:
39
+
40
+    cd /home/huginn/huginn
41
+    # Whichever you want to change
42
+    sudo -u huginn -H editor Procfile
43
+    sudo -u huginn -H editor .env
44
+    sudo -u huginn -H editor config/unicorn.rb
45
+    # Export init scripts and restart huginn
46
+    sudo rake production:export
47
+

+ 401 - 0
doc/manual/installation.md

@@ -0,0 +1,401 @@
1
+# Installation from source
2
+
3
+
4
+## Important Notes
5
+
6
+This guide is long because it covers many cases and includes all commands you need.
7
+
8
+This installation guide was created for and tested on **Debian/Ubuntu** operating systems. Please read [doc/install/requirements.md](./requirements.md) for hardware and operating system requirements.
9
+
10
+This is the official installation guide to set up a production server. To set up a **development installation** or for many other installation options please see [the getting started section of the readme](https://github.com/cantino/huginn#getting-started).
11
+
12
+The following steps have been known to work. Please **use caution when you deviate** from this guide. Make sure you don't violate any assumptions Huginn makes about its environment. For example many people run into permission problems because they change the location of directories or run services as the wrong user.
13
+
14
+If you find a bug/error in this guide please **submit a pull request**.
15
+
16
+If not stated otherwise all commands should be run as user with sudo permissions or as root.
17
+
18
+When having problems during the installation please check the [troubleshooting](#troubleshooting) section.
19
+
20
+## Overview
21
+
22
+The Huginn installation consists of setting up the following components:
23
+
24
+1. Packages / Dependencies
25
+1. Ruby
26
+1. System Users
27
+1. Database
28
+1. Huginn
29
+1. Nginx
30
+
31
+## 1. Packages / Dependencies
32
+
33
+`sudo` is not installed on Debian by default. Make sure your system is
34
+up-to-date and install it.
35
+
36
+    # run as root!
37
+    apt-get update -y
38
+    apt-get upgrade -y
39
+    apt-get install sudo -y
40
+
41
+**Note:** During this installation some files will need to be edited manually. If you are familiar with vim set it as default editor with the commands below. If you are not familiar with vim please skip this and keep using the default editor.
42
+
43
+    # Install vim and set as default editor
44
+    sudo apt-get install -y vim
45
+    sudo update-alternatives --set editor /usr/bin/vim.basic
46
+
47
+Import node.js repository (can be skipped on Ubuntu and Debian Jessie):
48
+
49
+    curl -sL https://deb.nodesource.com/setup_0.12 | sudo bash -
50
+
51
+Install the required packages (needed to compile Ruby and native extensions to Ruby gems):
52
+
53
+    sudo apt-get install -y runit build-essential git zlib1g-dev libyaml-dev libssl-dev libgdbm-dev libreadline-dev libncurses5-dev libffi-dev curl openssh-server checkinstall libxml2-dev libxslt-dev libcurl4-openssl-dev libicu-dev logrotate python-docutils pkg-config cmake nodejs graphviz
54
+
55
+
56
+## 2. Ruby
57
+
58
+
59
+The use of Ruby version managers such as [RVM](http://rvm.io/), [rbenv](https://github.com/sstephenson/rbenv) or [chruby](https://github.com/postmodern/chruby) with Huginn in production frequently leads to hard-to-diagnose problems. Version managers are not supported and we strongly advise everyone to follow the instructions below to use a system Ruby.
60
+
61
+Remove the old Ruby versions if present:
62
+
63
+    sudo apt-get remove -y ruby1.8 ruby1.9
64
+
65
+Download Ruby and compile it:
66
+
67
+    mkdir /tmp/ruby && cd /tmp/ruby
68
+    curl -L --progress http://cache.ruby-lang.org/pub/ruby/2.2/ruby-2.2.3.tar.bz2 | tar xj
69
+    cd ruby-2.2.3
70
+    ./configure --disable-install-rdoc
71
+    make -j`nproc`
72
+    sudo make install
73
+
74
+Install the bundler and foreman gems:
75
+
76
+    sudo gem install bundler foreman --no-ri --no-rdoc
77
+
78
+## 3. System Users
79
+
80
+Create a user for Huginn:
81
+
82
+    sudo adduser --disabled-login --gecos 'Huginn' huginn
83
+
84
+## 4. Database
85
+
86
+Install the database packages
87
+
88
+    sudo apt-get install -y mysql-server mysql-client libmysqlclient-dev
89
+
90
+    # Pick a MySQL root password (can be anything), type it and press enter,
91
+    # retype the MySQL root password and press enter
92
+
93
+Check the installed MySQL version (remeber if its >= 5.5.3 for the `.env` configuration done later):
94
+
95
+    mysql --version
96
+
97
+Secure your installation
98
+
99
+    sudo mysql_secure_installation
100
+
101
+Login to MySQL
102
+
103
+    mysql -u root -p
104
+
105
+    # Type the MySQL root password
106
+
107
+Create a user for Huginn do not type the `mysql>`, this is part of the prompt. Change `$password` in the command below to a real password you pick
108
+
109
+    mysql> CREATE USER 'huginn'@'localhost' IDENTIFIED BY '$password';
110
+
111
+Ensure you can use the InnoDB engine which is necessary to support long indexes
112
+
113
+    mysql> SET storage_engine=INNODB;
114
+
115
+    # If this fails, check your MySQL config files (e.g. `/etc/mysql/*.cnf`, `/etc/mysql/conf.d/*`)
116
+    # for the setting "innodb = off"
117
+
118
+Grant the Huginn user necessary permissions on the database
119
+
120
+    mysql> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, LOCK TABLES ON `huginn_production`.* TO 'huginn'@'localhost';
121
+
122
+Quit the database session
123
+
124
+    mysql> \q
125
+
126
+Try connecting to the new database with the new user
127
+
128
+    sudo -u huginn -H mysql -u huginn -p -D huginn_production
129
+
130
+    # Type the password you replaced $password with earlier
131
+
132
+You should now see `ERROR 1049 (42000): Unknown database 'huginn_production'` which is fine because we will create the database later.
133
+
134
+You are done installing the database and can go back to the rest of the installation.
135
+
136
+
137
+## 6. Huginn
138
+
139
+### Clone the Source
140
+
141
+    # We'll install Huginn into the home directory of the user "huginn"
142
+    cd /home/huginn
143
+
144
+    # Clone Huginn repository
145
+    sudo -u huginn -H git clone https://github.com/cantino/huginn.git -b master huginn
146
+
147
+    # Go to Huginn installation folder
148
+    cd /home/huginn/huginn
149
+
150
+    # Copy the example Huginn config
151
+    sudo -u huginn -H cp .env.example .env
152
+
153
+    # Create the log/, tmp/pids/ and tmp/sockets/ directories
154
+    sudo -u huginn mkdir -p log tmp/pids tmp/sockets
155
+
156
+    # Make sure Huginn can write to the log/ and tmp/ directories
157
+    sudo chown -R huginn log/ tmp/
158
+    sudo chmod -R u+rwX,go-w log/ tmp/
159
+
160
+    # Make sure permissions are set correctly
161
+    sudo chmod -R u+rwX,go-w log/
162
+    sudo chmod -R u+rwX tmp/
163
+    sudo -u huginn -H chmod o-rwx .env
164
+
165
+    # Copy the example Unicorn config
166
+    sudo -u huginn -H cp config/unicorn.rb.example config/unicorn.rb
167
+
168
+### Install Gems
169
+
170
+**Note:** As of bundler 1.5.2, you can invoke `bundle install -jN` (where `N` the number of your processor cores) and enjoy parallel gem installation with measurable difference in completion time (~60% faster). Check the number of your cores with `nproc`. For more information check this [post](http://robots.thoughtbot.com/parallel-gem-installing-using-bundler). First make sure you have bundler >= 1.5.2 (run `bundle -v`) as it addresses some [issues](https://devcenter.heroku.com/changelog-items/411) that were [fixed](https://github.com/bundler/bundler/pull/2817) in 1.5.2.
171
+
172
+    sudo -u huginn -H bundle install --deployment --without development test
173
+
174
+
175
+### Configure it
176
+
177
+    # Update Huginn config file and follow the instructions
178
+    sudo -u huginn -H editor .env
179
+
180
+If you are using a local MySQL server the database configuration should look like this (use the password of the huginn MySQL user you created earlier):
181
+
182
+    DATABASE_ADAPTER=mysql2
183
+    DATABASE_RECONNECT=true
184
+    DATABASE_NAME=huginn_production
185
+    DATABASE_POOL=20
186
+    DATABASE_USERNAME=huginn
187
+    DATABASE_PASSWORD='$password'
188
+    #DATABASE_HOST=your-domain-here.com
189
+    #DATABASE_PORT=3306
190
+    #DATABASE_SOCKET=/tmp/mysql.sock
191
+
192
+    DATABASE_ENCODING=utf8
193
+    # MySQL only: If you are running a MySQL server >=5.5.3, you should
194
+    # set DATABASE_ENCODING to utf8mb4 instead of utf8 so that the
195
+    # database can hold 4-byte UTF-8 characters like emoji.
196
+    #DATABASE_ENCODING=utf8mb4
197
+
198
+**Important**: Uncomment the RAILS_ENV setting to run Huginn in the production rails environment
199
+
200
+    RAILS_ENV=production
201
+
202
+Change the Unicorn config if needed, the [requirements.md](./requirements.md#unicorn-workers) has a section explaining the suggested amount of unicorn workers:
203
+
204
+    # Increase the amount of workers if you expect to have a high load instance.
205
+    # 2 are enough for most use cases, if the server has less then 2GB of RAM
206
+    # decrease the worker amount to 1
207
+    sudo -u huginn -H editor config/unicorn.rb
208
+
209
+
210
+**Important Note:** Make sure to edit both `.env` and `unicorn.rb` to match your setup.
211
+
212
+**Note:** If you want to use HTTPS, which is what we recommend, see [Using HTTPS](#using-https) for the additional steps.
213
+
214
+
215
+### Initialize Database
216
+
217
+    # Create the database
218
+    sudo -u huginn -H bundle exec rake db:create RAILS_ENV=production
219
+
220
+    # Migrate to the latest version
221
+    sudo -u huginn -H bundle exec rake db:migrate RAILS_ENV=production
222
+
223
+    # Create admin user and example agents
224
+    sudo -u huginn -H bundle exec rake db:seed RAILS_ENV=production
225
+
226
+When done you see `See the Huginn Wiki for more Agent examples!  https://github.com/cantino/huginn/wiki`
227
+
228
+**Note:** This will create an initial user, you can set the username and password by supplying it in environmental variables `SEED_USERNAME` and `SEED_PASSWORD` as seen below. If you don't set the password (and it is set to the default one) please wait with exposing Huginn to the public internet until the installation is done and you've logged into the server and changed your password.
229
+
230
+    sudo -u huginn -H bundle exec rake db:seed RAILS_ENV=production SEED_USERNAME=admin SEED_PASSWORD=yourpassword
231
+
232
+### Compile Assets
233
+
234
+    sudo -u huginn -H bundle exec rake assets:precompile RAILS_ENV=production
235
+
236
+### Install Init Script
237
+
238
+Huginn uses [foreman](http://ddollar.github.io/foreman/) to generate the init scripts based on a `Procfile`
239
+
240
+Edit the `Procfile` and choose one of the suggested versions for production
241
+
242
+    sudo -u huginn -H editor Procfile
243
+
244
+Export the init scripts:
245
+
246
+    sudo rake production:export
247
+
248
+**Note:** You have to re-export the init script every time you change the configuration in `.env` or your `Procfile`!
249
+
250
+### Setup Logrotate
251
+
252
+    sudo cp deployment/logrotate/huginn /etc/logrotate.d/huginn
253
+
254
+
255
+### Ensure Your Huginn Instance Is Running
256
+
257
+    sudo rake production:status
258
+
259
+## 7. Nginx
260
+
261
+**Note:** Nginx is the officially supported web server for Huginn. If you cannot or do not want to use Nginx as your web server, the wiki has a page on how to configure [apache](https://github.com/cantino/huginn/wiki/Apache-Huginn-configuration).
262
+
263
+### Installation
264
+
265
+    sudo apt-get install -y nginx
266
+
267
+### Site Configuration
268
+
269
+Copy the example site config:
270
+
271
+    sudo cp deployment/nginx/huginn /etc/nginx/sites-available/huginn
272
+    sudo ln -s /etc/nginx/sites-available/huginn /etc/nginx/sites-enabled/huginn
273
+
274
+Make sure to edit the config file to match your setup, if you are running multiple nginx sites remove the `default_server` argument from the `listen` directives:
275
+
276
+    # Change YOUR_SERVER_FQDN to the fully-qualified
277
+    # domain name of your host serving Huginn.
278
+    sudo editor /etc/nginx/sites-available/huginn
279
+
280
+Remove the default nginx site, **if huginn is the only enabled nginx site**:
281
+
282
+    sudo rm /etc/nginx/sites-enabled/default
283
+
284
+**Note:** If you want to use HTTPS, which is what we recommend, replace the `huginn` Nginx config with `huginn-ssl`. See [Using HTTPS](#using-https) for HTTPS configuration details.
285
+
286
+### Test Configuration
287
+
288
+Validate your `huginn` or `huginn-ssl` Nginx config file with the following command:
289
+
290
+    sudo nginx -t
291
+
292
+You should receive `syntax is okay` and `test is successful` messages. If you receive errors check your `huginn` or `huginn-ssl` Nginx config file for typos, etc. as indicated in the error message given.
293
+
294
+### Restart
295
+
296
+    sudo service nginx restart
297
+
298
+# Done!
299
+
300
+### Initial Login
301
+
302
+Visit YOUR_SERVER in your web browser for your first Huginn login. The setup has created a default admin account for you. You can use it to log in:
303
+
304
+    admin
305
+    password
306
+
307
+
308
+**Enjoy!** :sparkles: :star: :fireworks:
309
+
310
+You can use `cd /home/huginn/huginn && sudo rake production:start` and `cd /home/huginn/huginn && sudo rake production:stop` to start and stop Huginn.
311
+
312
+Be sure to read the section about how to [update](./update.md) your Huginn installation as well! You can also use [Capistrano](./capistrano.md) to keep your installation up to date.
313
+
314
+**Note:** We also recommend applying standard security practices to your server, including installing a firewall ([ufw](https://wiki.ubuntu.com/UncomplicatedFirewall) is good on Ubuntu and also available for Debian).
315
+
316
+## Advanced Setup Tips
317
+
318
+### Using HTTPS
319
+
320
+To use Huginn with HTTPS:
321
+
322
+1. In `.env`:
323
+    1. Set the `FORCE_SSL` option to `true`.
324
+1. Use the `huginn-ssl` Nginx example config instead of the `huginn` config:
325
+    1. `sudo cp deployment/nginx/huginn-ssl /etc/nginx/sites-available/huginn`
326
+    1. Update `YOUR_SERVER_FQDN`.
327
+    1. Update `ssl_certificate` and `ssl_certificate_key`.
328
+    1. Review the configuration file and consider applying other security and performance enhancing features.
329
+
330
+Restart Nginx, export the init script and restart Huginn:
331
+
332
+```
333
+cd /home/huginn/huginn
334
+sudo service nginx restart
335
+sudo rake production:export
336
+```
337
+
338
+Using a self-signed certificate is discouraged, but if you must use it follow the normal directions. Then generate the certificate:
339
+
340
+```
341
+sudo mkdir -p /etc/nginx/ssl/
342
+cd /etc/nginx/ssl/
343
+sudo openssl req -newkey rsa:2048 -x509 -nodes -days 3560 -out huginn.crt -keyout huginn.key
344
+sudo chmod o-r huginn.key
345
+```
346
+
347
+## Troubleshooting
348
+
349
+If something went wrong during the installation please make sure you followed the instructions and did not miss a step.
350
+
351
+When your Huginn instance still is not working first run the self check:
352
+
353
+    cd /home/huginn/huginn
354
+    sudo rake production:check
355
+
356
+We are sorry when you are still having issues, now please check the various log files for error messages:
357
+
358
+#### Nginx error log `/var/log/nginx/huginn_error.log`
359
+
360
+This file should be empty, it is the first place to look because `nginx` is the first application handling the request your are sending to Huginn.
361
+
362
+Common problems:
363
+
364
+* `connect() to unix:/home/huginn/huginn/tmp/sockets/unicorn.socket failed`: The Unicorn application server is not running, ensure you uncommented one of the example configuration below the `PRODUCTION` label in your [Profile](#install-init-script) and the unicorn config file (`/home/huginn/huginn/config/unicorn.rb`) exists.
365
+* `138 open() "/home/huginn/huginn/public/..." failed (13: Permission denied)`: The `/home/huginn/huginn/public` directory needs to be readable by the nginx user (which is per default `www-data`)
366
+
367
+
368
+#### Unicorn log `/home/huginn/huginn/log/unicorn.log`
369
+
370
+Should only contain HTTP request log entries like: `10.0.2.2 - - [18/Aug/2015:21:15:12 +0000] "GET / HTTP/1.0" 200 - 0.0110`
371
+
372
+If you see ruby exception backtraces or other error messages the problem could be one of the following:
373
+
374
+* The configuration file `/home/huginn/huginn/config/unicorn.rb` does not exist
375
+* Gem dependencies where not [installed](#install-gems)
376
+
377
+#### Rails Application log `/home/huginn/huginn/log/production.log`
378
+
379
+This file is pretty verbose, you want to look at it if you are getting the `We're sorry, but something went wrong.` error message when using Huginn. This is an example backtrace that can help you or other huginn developers locate the issue:
380
+
381
+```
382
+NoMethodError (undefined method `name' for nil:NilClass):
383
+  app/controllers/jobs_controller.rb:6:in `index'
384
+  config/initializers/silence_worker_status_logger.rb:5:in `call_with_silence_worker_status'
385
+```
386
+
387
+#### Runit/Background Worker logs `/home/huginn/huginn/log/*/current`
388
+
389
+Those files will contain error messages or backtraces if one of your agent is not performing as they should. The easiest way to debug an Agent is to watch all your log files for changes and trigger the agent to run via the Huginn web interface.
390
+
391
+The log file location depends your `Procfile` configuration, this command will give you a list of the available logs:
392
+
393
+    ls -al /home/huginn/huginn/log/*/current
394
+
395
+When you want to monitor the background processes you can easily watch all the files for changes:
396
+
397
+    tail -f /home/huginn/huginn/log/*/current
398
+
399
+### Still having problems? :crying_cat_face:
400
+
401
+You probably found an error message or exception backtrace you could not resolve. Please create a new [issue](https://github.com/cantino/huginn/issues) and include as much information as you could gather about the problem your are experiencing.

+ 68 - 0
doc/manual/requirements.md

@@ -0,0 +1,68 @@
1
+# Requirements
2
+
3
+## Operating Systems
4
+
5
+### Supported Unix distributions by this guide
6
+
7
+- Ubuntu (14.04 and 12.04)
8
+- Debian (Jessie and Wheezy)
9
+
10
+### Unsupported Unix distributions
11
+
12
+- CentOS
13
+- Red Hat Enterprise Linux
14
+- OS X
15
+- Arch Linux
16
+- Fedora
17
+- Gentoo
18
+- FreeBSD
19
+
20
+On the above unsupported distributions is still possible to install Huginn, and many people do. Follow the [installation guide](./installation.md) and substitute the `apt` commands with the corresponding package manager commands of your distribution.
21
+
22
+### Non-Unix operating systems such as Windows
23
+
24
+Huginn is developed for Unix operating systems.
25
+Huginn does **not** run on Windows and we have no plans of supporting it in the near future.
26
+Please consider using a virtual machine to run Huginn on Windows.
27
+
28
+## Ruby versions
29
+
30
+Huginn requires Ruby (MRI) 2.0, 2.1 or 2.2
31
+You will have to use the standard MRI implementation of Ruby.
32
+We love [JRuby](http://jruby.org/) and [Rubinius](http://rubini.us/) but Huginn needs several Gems that have native extensions.
33
+
34
+## Hardware requirements
35
+
36
+### CPU
37
+
38
+- _single core_ setups will work but depending on the amount of Huginn Agents and users it will run a bit slower since the application server and background jobs can not run simultaneously
39
+- _dual core_ setups are the **recommended** system/vps and will work well for a decent amount of Agents
40
+- 3+ cores can be needed when running multiple DelayedJob workers
41
+
42
+### Memory
43
+
44
+You need at least 0.5GB of physical and 0.5GB of addressable memory (swap) to install and use Huginn with the default configuration!
45
+With less memory you need to manually adjust the `Gemfile` and Huginn can respond with internal server errors when accessing the web interface.
46
+
47
+- 256MB RAM + 0.5GB of swap is the absolute minimum but we strongly **advise against** this amount of memory. See the Wiki page about running Huginn on [systems with low memory](https://github.com/cantino/huginn/wiki/Running-Huginn-on-minimal-systems-with-low-RAM-&-CPU-e.g.-Raspberry-Pi)
48
+- 0.5GB RAM + 0.5GB swap will work relatively well with SSD drives, but can feel a bit slow due to swapping
49
+- 1GB RAM + 1GB swap will work with two unicorn workers and the threaded background worker
50
+- **2GB RAM** is the **recommended** memory size, it will support 2 unicorn workers and both the threaded and the old separate workers
51
+- for each 300MB of additional RAM you can run one extra DelayedJob worker
52
+
53
+## Unicorn Workers
54
+
55
+It's possible to increase the amount of unicorn workers and this will usually help for to reduce the response time of the applications and increase the ability to handle parallel requests.
56
+
57
+For most instances we recommend using: CPU cores = unicorn workers.
58
+
59
+If you have a 512MB machine we recommend to configure only one Unicorn worker and use the threaded background worker to prevent excessive swapping.
60
+
61
+
62
+## DelayedJob Workers
63
+
64
+A DelayedJob worker is a separate process which runs your Huginn Agents. It fetches Websites, polls external services for updates, etc. Depending on the amount of Agents and the check frequency of those you might need to run more than one worker (like it is done in the threaded setup).
65
+
66
+Estimating the amount of workers needed is easy. One worker can perform just one check at a time.  
67
+If you have 60 Agents checking websites every minute which take about 1 second to respond, one worker is fine.  
68
+If you need more Agents or are dealing with slow/unreliable websites/services, you should consider running additional workers.

+ 92 - 0
doc/manual/update.md

@@ -0,0 +1,92 @@
1
+# Update
2
+
3
+You can also use [Capistrano](./capistrano.md) to keep your installation up to date.
4
+
5
+### 0. Ensure depencies are up to date
6
+
7
+```
8
+cd /home/huginn/huginn
9
+sudo rake production:check
10
+```
11
+
12
+### 1. Stop server
13
+
14
+```
15
+sudo rake production:stop
16
+```
17
+
18
+### 2. Store the current version
19
+
20
+```
21
+export OLD_VERSION=`git rev-parse HEAD`
22
+```
23
+
24
+### 3. Update the code
25
+
26
+Back up changed files
27
+
28
+```
29
+sudo -u huginn -H cp Procfile Procfile.bak
30
+```
31
+
32
+Get the new code
33
+```
34
+sudo -u huginn -H git fetch --all
35
+sudo -u huginn -H git checkout -- db/schema.rb Procfile
36
+sudo -u huginn -H git checkout master
37
+sudo -u huginn -H git pull
38
+```
39
+
40
+Restore backed up files
41
+
42
+```
43
+sudo -u huginn -H cp Procfile.bak Procfile
44
+```
45
+
46
+### 4. Install gems, migrate and precompile assets
47
+
48
+```
49
+cd /home/huginn/huginn
50
+
51
+sudo -u huginn -H bundle install --deployment --without development test
52
+
53
+# Run database migrations
54
+sudo -u huginn -H bundle exec rake db:migrate RAILS_ENV=production
55
+
56
+# Clean up assets and cache
57
+sudo -u huginn -H bundle exec rake assets:clean assets:precompile tmp:cache:clear RAILS_ENV=production
58
+
59
+```
60
+
61
+### 5. Update the Procfile
62
+
63
+Check for changes made to the default `Procfile`
64
+```
65
+sudo -u huginn -H git diff $OLD_VERSION..master Procfile
66
+```
67
+
68
+Update your `Procfile` if the default options of the version you are using changed
69
+```
70
+sudo -u huginn -H editor Procfile
71
+```
72
+
73
+### 6. Update the .env file
74
+
75
+Check for changes made to the example `.env`
76
+```
77
+sudo -u huginn -H git diff $OLD_VERSION..master .env.example
78
+```
79
+
80
+Update your `.env` with new options or changed defaults
81
+```
82
+sudo -u huginn -H editor .env
83
+```
84
+
85
+
86
+### 7. Export init script and start Huginn
87
+
88
+```
89
+# Export the init script
90
+sudo rake production:export
91
+```
92
+

+ 1 - 1
docker/README.md

@@ -68,7 +68,7 @@ To link to another mysql container, for example:
68 68
 To link to another container named 'postgres':
69 69
 
70 70
     docker run --rm --name huginn \
71
-        --link postgres:postgresql \
71
+        --link postgres \
72 72
         -p 3000:3000 \
73 73
         -e "HUGINN_DATABASE_USERNAME=huginn" \
74 74
         -e "HUGINN_DATABASE_PASSWORD=pass@word" \

+ 1 - 1
docker/scripts/setup

@@ -29,7 +29,7 @@ if [ -d "/scripts/cache" ]; then
29 29
   mv /scripts/cache vendor/
30 30
   chown -R huginn:huginn vendor/cache
31 31
 fi
32
-sudo -u huginn -H bundle install --deployment --without development test
32
+sudo -u huginn -H bundle install --deployment --without test
33 33
 
34 34
 # silence setlocale message (THANKS DEBIAN!)
35 35
 cat > /etc/default/locale <<EOF

+ 94 - 0
lib/tasks/production.rake

@@ -0,0 +1,94 @@
1
+def failed; "[ \033[31mFAIL\033[0m ]"; end
2
+def ok;     "[  \033[32mOK\033[0m  ]"; end
3
+
4
+def run_as_root
5
+  return true if ENV['USER'] == 'root'
6
+  puts "#{failed} Please run this command as root or with sudo\n\n"
7
+  exit -1
8
+end
9
+
10
+def runit_installed
11
+  return true unless `which sv` && $?.to_i != 0
12
+  puts "#{failed} Please install runit: \n\nsudo apt-get install runit\n\n"
13
+  exit -1
14
+end
15
+
16
+def remove_upstart_config
17
+  return true unless File.exists?('/etc/init/huginn.conf')
18
+  puts "#{failed} Please stop huginn and remove the huginn upstart init scripts:\n\n"
19
+  puts "sudo stop huginn"
20
+  puts "sudo rm /etc/init/huginn*\n\n"
21
+  exit -1
22
+end
23
+
24
+namespace :production do
25
+  task :check do |t|
26
+    remove_upstart_config
27
+    runit_installed
28
+    puts "#{ok} Everything is fine" if t.application.top_level_tasks.include? 'production:check'
29
+  end
30
+
31
+  task :stop => :check do
32
+    puts "Stopping huginn ..."
33
+    run_sv('stop')
34
+  end
35
+
36
+  task :start => :check do
37
+    puts "Startig huginn ..."
38
+    run_sv('start')
39
+  end
40
+
41
+  task :status => :check do
42
+    run_sv('status')
43
+  end
44
+
45
+  task :restart => :check do
46
+    puts "Restarting huginn ..."
47
+    run_sv('restart')
48
+  end
49
+
50
+  task :export => :check do
51
+    run_as_root
52
+    Rake::Task['production:stop'].execute
53
+    puts "Exporting new services ..."
54
+    run('rm -rf /etc/service/huginn*')
55
+    run('foreman export runit -a huginn -l /home/huginn/huginn/log /etc/service')
56
+    services = Dir.glob('/etc/service/huginn*')
57
+    while services.length > 0
58
+      services.each do |p|
59
+        supervise = File.join(p, 'supervise')
60
+        next if !Dir.exists?(supervise)
61
+        run("chown -R huginn:huginn #{p}")
62
+        services.delete(p)
63
+      end
64
+      sleep 0.1
65
+    end
66
+  end
67
+end
68
+
69
+def run_sv(command)
70
+  Dir.glob('/etc/service/huginn*').each do |p|
71
+    with_retries do
72
+      run("sv #{command} #{File.basename(p)}")
73
+    end
74
+  end
75
+end
76
+
77
+def run(cmd, verbose=false)
78
+  output = `#{cmd}`
79
+  if $?.to_i != 0
80
+    raise "'#{cmd}' exited with a non-zero return value: #{output}"
81
+  end
82
+  puts output if verbose && output.strip != ''
83
+  output
84
+end
85
+
86
+def with_retries(&block)
87
+  tries ||= 5
88
+  output = block.call
89
+rescue StandardError => e
90
+  retry unless (tries -= 1).zero?
91
+  raise e
92
+else
93
+  puts output
94
+end

+ 26 - 10
spec/controllers/agents_controller_spec.rb

@@ -87,19 +87,35 @@ describe AgentsController do
87 87
     end
88 88
   end
89 89
 
90
-  describe "GET new with :id" do
91
-    it "opens a clone of a given Agent" do
92
-      sign_in users(:bob)
93
-      get :new, :id => agents(:bob_website_agent).to_param
94
-      expect(assigns(:agent).attributes).to eq(users(:bob).agents.build_clone(agents(:bob_website_agent)).attributes)
90
+  describe "GET new" do
91
+    describe "with :id" do
92
+      it "opens a clone of a given Agent" do
93
+        sign_in users(:bob)
94
+        get :new, :id => agents(:bob_website_agent).to_param
95
+        expect(assigns(:agent).attributes).to eq(users(:bob).agents.build_clone(agents(:bob_website_agent)).attributes)
96
+      end
97
+
98
+      it "only allows the current user to clone his own Agent" do
99
+        sign_in users(:bob)
100
+
101
+        expect {
102
+          get :new, :id => agents(:jane_website_agent).to_param
103
+        }.to raise_error(ActiveRecord::RecordNotFound)
104
+      end
95 105
     end
96 106
 
97
-    it "only allows the current user to clone his own Agent" do
98
-      sign_in users(:bob)
107
+    describe "with a scenario_id" do
108
+      it 'populates the assigned agent with the scenario' do
109
+        sign_in users(:bob)
110
+        get :new, :scenario_id => scenarios(:bob_weather).id
111
+        expect(assigns(:agent).scenario_ids).to eq([scenarios(:bob_weather).id])
112
+      end
99 113
 
100
-      expect {
101
-        get :new, :id => agents(:jane_website_agent).to_param
102
-      }.to raise_error(ActiveRecord::RecordNotFound)
114
+      it "does not see other user's scenarios" do
115
+        sign_in users(:bob)
116
+        get :new, :scenario_id => scenarios(:jane_weather).id
117
+        expect(assigns(:agent).scenario_ids).to eq([])
118
+      end
103 119
     end
104 120
   end
105 121
 

+ 16 - 3
spec/controllers/jobs_controller_spec.rb

@@ -1,7 +1,6 @@
1 1
 require 'spec_helper'
2 2
 
3 3
 describe JobsController do
4
-
5 4
   describe "GET index" do
6 5
     before do
7 6
       async_handler_yaml =
@@ -71,12 +70,26 @@ describe JobsController do
71 70
     before do
72 71
       @failed = Delayed::Job.create(failed_at: Time.now - 1.minute)
73 72
       @running = Delayed::Job.create(locked_at: Time.now, locked_by: 'test')
73
+      @pending = Delayed::Job.create
74 74
       sign_in users(:jane)
75 75
     end
76 76
 
77 77
     it "just destroy failed jobs" do
78
-      expect { delete :destroy_failed, id: @failed.id }.to change(Delayed::Job, :count).by(-1)
79
-      expect { delete :destroy_failed, id: @running.id }.to change(Delayed::Job, :count).by(0)
78
+      expect { delete :destroy_failed }.to change(Delayed::Job, :count).by(-1)
79
+    end
80
+  end
81
+
82
+  describe "DELETE destroy_all" do
83
+    before do
84
+      @failed = Delayed::Job.create(failed_at: Time.now - 1.minute)
85
+      @running = Delayed::Job.create(locked_at: Time.now, locked_by: 'test')
86
+      @pending = Delayed::Job.create
87
+      sign_in users(:jane)
88
+    end
89
+
90
+    it "destroys all jobs" do
91
+      expect { delete :destroy_all }.to change(Delayed::Job, :count).by(-2)
92
+      expect(Delayed::Job.find(@running.id)).to be
80 93
     end
81 94
   end
82 95
 end

+ 25 - 1
spec/models/agents/post_agent_spec.rb

@@ -38,11 +38,14 @@ describe Agents::PostAgent do
38 38
       when :get, :delete
39 39
         req.data = request.uri.query
40 40
       else
41
-        case request.headers['Content-Type'][/\A[^;\s]+/]
41
+        content_type = request.headers['Content-Type'][/\A[^;\s]+/]
42
+        case content_type
42 43
         when 'application/x-www-form-urlencoded'
43 44
           req.data = request.body
44 45
         when 'application/json'
45 46
           req.data = ActiveSupport::JSON.decode(request.body)
47
+        when 'text/xml'
48
+          req.data = Hash.from_xml(request.body)
46 49
         else
47 50
           raise "unexpected Content-Type: #{content_type}"
48 51
         end
@@ -152,6 +155,27 @@ describe Agents::PostAgent do
152 155
       expect(@sent_requests[:post][0].data).to eq(@checker.options['payload'])
153 156
     end
154 157
 
158
+    it "sends options['payload'] as XML as a POST request" do
159
+      @checker.options['content_type'] = 'xml'
160
+      expect {
161
+        @checker.check
162
+      }.to change { @sent_requests[:post].length }.by(1)
163
+
164
+      expect(@sent_requests[:post][0].data.keys).to eq([ 'post' ])
165
+      expect(@sent_requests[:post][0].data['post']).to eq(@checker.options['payload'])
166
+    end
167
+
168
+    it "sends options['payload'] as XML with custom root element name, as a POST request" do
169
+      @checker.options['content_type'] = 'xml'
170
+      @checker.options['xml_root'] = 'foobar'
171
+      expect {
172
+        @checker.check
173
+      }.to change { @sent_requests[:post].length }.by(1)
174
+
175
+      expect(@sent_requests[:post][0].data.keys).to eq([ 'foobar' ])
176
+      expect(@sent_requests[:post][0].data['foobar']).to eq(@checker.options['payload'])
177
+    end
178
+
155 179
     it "sends options['payload'] as a GET request" do
156 180
       @checker.options['method'] = 'get'
157 181
       expect {

+ 2 - 0
spec/models/agents/twitter_user_agent_spec.rb

@@ -7,6 +7,8 @@ describe Agents::TwitterUserAgent do
7 7
 
8 8
     @opts = {
9 9
       :username => "tectonic",
10
+      :include_retweets => "true",
11
+      :exclude_replies => "false",
10 12
       :expected_update_period_in_days => "2",
11 13
       :starting_at => "Jan 01 00:00:01 +0000 2000",
12 14
       :consumer_key => "---",