que-web 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -0
- data/README.md +6 -0
- data/docker/Dockerfile +22 -0
- data/docker/Gemfile +5 -0
- data/docker/Gemfile.lock +28 -0
- data/docker/config.ru +10 -0
- data/examples/rack/Gemfile.lock +2 -0
- data/examples/rack/config.ru +9 -1
- data/lib/que/web.rb +42 -1
- data/que-web.gemspec +2 -1
- data/web/public/js/{vendor/jquery.js → jquery.min.js} +0 -0
- data/web/public/js/jquery.timeago.min.js +17 -0
- data/web/public/styles/application.css +4 -0
- data/web/views/_flash.erb +3 -0
- data/web/views/failing.erb +4 -2
- data/web/views/layout.erb +12 -3
- data/web/views/running.erb +1 -1
- data/web/views/scheduled.erb +2 -2
- data/web/views/show.erb +1 -1
- metadata +24 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 472d12b5889358f528fe9de93f81177f72512635
|
4
|
+
data.tar.gz: 16c433810179716c6f9be25fb32a15b0496c3c48
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 05b564a90c42a676e7b4fc297d1fa2965bf930315809df2faa9b88e733a94e505a2aa3f1eb75fce07c0f7bf3ffe41895f704bb89f00549ff5da093c14d64c2c3
|
7
|
+
data.tar.gz: 6048a2d8a906e3fd0f881e917ea2cdf2532ffca7e8c0df1a1c79d66275b5032d21de1467aa5b385667b34ac550dc4d6fecf962f7d2394c9f40a2a6c259dd3251
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
### 0.3.0 - 2014-11-24
|
2
|
+
#### Added:
|
3
|
+
- Dockerfile #1
|
4
|
+
- Show errors in list view #7
|
5
|
+
- Relative "x minutes from now" dates for all visible dates #3
|
6
|
+
- Display flash messages on delete or run immediate actions (only if session available) #6
|
7
|
+
- CHANGELOG file
|
8
|
+
|
9
|
+
#### Fixed:
|
10
|
+
- Large argument lists now wrap in list view #8
|
11
|
+
|
12
|
+
#### Security:
|
13
|
+
- Use Erubis to escape html by default #9
|
14
|
+
|
15
|
+
|
16
|
+
### 0.2.2 - 2014-11-14
|
17
|
+
#### Added:
|
18
|
+
- Working dashboard
|
19
|
+
- List running, scheduled, and failing jobs
|
20
|
+
- Delete jobs
|
21
|
+
- Run jobs immediately
|
22
|
+
- Show job details
|
data/README.md
CHANGED
@@ -38,3 +38,9 @@ Or in Rails `config/routes.rb`
|
|
38
38
|
require "que/web"
|
39
39
|
mount Que::Web => "/que"
|
40
40
|
```
|
41
|
+
|
42
|
+
If you want to use Docker, run:
|
43
|
+
```
|
44
|
+
docker run -e DATABASE_URL=postgres://username:password@hostname/db_name -p 3002:8080 joevandyk/que-web
|
45
|
+
```
|
46
|
+
Or use docker/Dockerfile to build your own container.
|
data/docker/Dockerfile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# There's an image at joevandyk/que-web.
|
2
|
+
# Run like:
|
3
|
+
# docker run -e DATABASE_URL=postgres://username:password@hostname/db_name -p 3002:8080 joevandyk/que-web
|
4
|
+
|
5
|
+
FROM dockerfile/ruby
|
6
|
+
|
7
|
+
# Define working directory.
|
8
|
+
WORKDIR /app
|
9
|
+
|
10
|
+
EXPOSE 8080
|
11
|
+
|
12
|
+
# Define default command.
|
13
|
+
CMD bundle exec puma -e production -p 8080 /app/config.ru
|
14
|
+
|
15
|
+
RUN apt-get update && \
|
16
|
+
apt-get install libpq-dev -y && \
|
17
|
+
rm -rf /var/cache/apt/* /var/lib/apt/lists/*
|
18
|
+
|
19
|
+
|
20
|
+
ADD . /app
|
21
|
+
RUN bundle install
|
22
|
+
|
data/docker/Gemfile
ADDED
data/docker/Gemfile.lock
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
pg (0.17.1)
|
5
|
+
puma (2.9.2)
|
6
|
+
rack (>= 1.1, < 2.0)
|
7
|
+
que (0.8.2)
|
8
|
+
que-web (0.2.2)
|
9
|
+
que (~> 0.8)
|
10
|
+
sinatra
|
11
|
+
rack (1.5.2)
|
12
|
+
rack-protection (1.5.3)
|
13
|
+
rack
|
14
|
+
sequel (4.16.0)
|
15
|
+
sinatra (1.4.5)
|
16
|
+
rack (~> 1.4)
|
17
|
+
rack-protection (~> 1.4)
|
18
|
+
tilt (~> 1.3, >= 1.3.4)
|
19
|
+
tilt (1.4.1)
|
20
|
+
|
21
|
+
PLATFORMS
|
22
|
+
ruby
|
23
|
+
|
24
|
+
DEPENDENCIES
|
25
|
+
pg
|
26
|
+
puma
|
27
|
+
que-web
|
28
|
+
sequel
|
data/docker/config.ru
ADDED
data/examples/rack/Gemfile.lock
CHANGED
data/examples/rack/config.ru
CHANGED
@@ -2,6 +2,7 @@ require File.expand_path('../boot', __FILE__)
|
|
2
2
|
require 'que/web'
|
3
3
|
|
4
4
|
map '/que' do
|
5
|
+
use Rack::Session::Cookie, :secret => 'insecure', :key => 'que.examples.rack'
|
5
6
|
run Que::Web
|
6
7
|
end
|
7
8
|
|
@@ -14,7 +15,14 @@ end
|
|
14
15
|
|
15
16
|
map '/fail' do
|
16
17
|
run lambda { |env|
|
17
|
-
FailJob.enqueue 'arg1', {name: 'fail', age: 20}
|
18
|
+
FailJob.enqueue 'arg1', {name: 'fail', age: 20, numbers: [10]*50}
|
19
|
+
[200, {}, ['Failing job queued']]
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
map '/xss' do
|
24
|
+
run lambda { |env|
|
25
|
+
FailJob.enqueue '<script>alert("xss")</script>', {name: '<script>alert("xss")', age: 20, numbers: [10]*50}
|
18
26
|
[200, {}, ['Failing job queued']]
|
19
27
|
}
|
20
28
|
end
|
data/lib/que/web.rb
CHANGED
@@ -1,14 +1,17 @@
|
|
1
1
|
require "sinatra"
|
2
|
+
require "erubis"
|
2
3
|
|
3
4
|
module Que
|
4
5
|
class Web < Sinatra::Base
|
5
6
|
PAGE_SIZE = 10
|
7
|
+
FLASH_KEY = 'que.web.flash'.freeze
|
6
8
|
|
7
9
|
use Rack::MethodOverride
|
8
10
|
|
9
11
|
set :root, File.expand_path("../../../web", __FILE__)
|
10
12
|
set :public_folder, proc { "#{root}/public" }
|
11
13
|
set :views, proc { File.expand_path("views", root) }
|
14
|
+
set :erb, :escape_html => true
|
12
15
|
|
13
16
|
get "/" do
|
14
17
|
stats = Que.execute SQL[:dashboard_stats]
|
@@ -58,9 +61,12 @@ module Que
|
|
58
61
|
put "/jobs/:id" do |id|
|
59
62
|
job_id = id.to_i
|
60
63
|
if job_id > 0
|
61
|
-
|
64
|
+
run_at = Time.now
|
65
|
+
Que.execute SQL[:reschedule_job], [job_id, run_at]
|
66
|
+
set_flash "info", "Job #{job_id} rescheduled for #{run_at}"
|
62
67
|
end
|
63
68
|
|
69
|
+
|
64
70
|
redirect request.referrer, 303
|
65
71
|
end
|
66
72
|
|
@@ -68,6 +74,7 @@ module Que
|
|
68
74
|
job_id = id.to_i
|
69
75
|
if job_id > 0
|
70
76
|
Que.execute SQL[:delete_job], [job_id]
|
77
|
+
set_flash "warning", "Job #{job_id} deleted"
|
71
78
|
end
|
72
79
|
|
73
80
|
redirect request.referrer, 303
|
@@ -78,6 +85,8 @@ module Que
|
|
78
85
|
Pager.new(page, PAGE_SIZE, record_count)
|
79
86
|
end
|
80
87
|
|
88
|
+
after { session['flash'] = {} if @sweep_flash }
|
89
|
+
|
81
90
|
helpers do
|
82
91
|
def root_path
|
83
92
|
"#{env['SCRIPT_NAME']}/"
|
@@ -88,6 +97,38 @@ module Que
|
|
88
97
|
"active"
|
89
98
|
end
|
90
99
|
end
|
100
|
+
|
101
|
+
def format_args(job)
|
102
|
+
truncate job.args.map(&:inspect).join(', ')
|
103
|
+
end
|
104
|
+
|
105
|
+
def format_error(job)
|
106
|
+
return unless job.last_error
|
107
|
+
line = job.last_error.lines.first
|
108
|
+
truncate line, 30
|
109
|
+
end
|
110
|
+
|
111
|
+
def relative_time(time)
|
112
|
+
%{<time class="timeago" datetime="#{time.utc.iso8601}">#{time.utc}</time>}
|
113
|
+
end
|
114
|
+
|
115
|
+
def truncate(str, len=200)
|
116
|
+
if str.length > len
|
117
|
+
str[0..len] + '...'
|
118
|
+
else
|
119
|
+
str
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def flash
|
124
|
+
@sweep_flash = true
|
125
|
+
session[FLASH_KEY] ||= {}
|
126
|
+
end
|
127
|
+
|
128
|
+
def set_flash(level, val)
|
129
|
+
hash = session[FLASH_KEY] ||= {}
|
130
|
+
hash[level] = val
|
131
|
+
end
|
91
132
|
end
|
92
133
|
end
|
93
134
|
end
|
data/que-web.gemspec
CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "que-web"
|
7
|
-
spec.version = "0.
|
7
|
+
spec.version = "0.3.0"
|
8
8
|
spec.authors = ["Jason Staten"]
|
9
9
|
spec.email = ["jstaten07@gmail.com"]
|
10
10
|
spec.summary = %q{A web interface for the que queue}
|
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
|
|
19
19
|
|
20
20
|
spec.add_dependency "que", "~> 0.8"
|
21
21
|
spec.add_dependency "sinatra"
|
22
|
+
spec.add_dependency "erubis"
|
22
23
|
|
23
24
|
spec.add_development_dependency "bundler", "~> 1.6"
|
24
25
|
spec.add_development_dependency "rake", "~> 10.0"
|
File without changes
|
@@ -0,0 +1,17 @@
|
|
1
|
+
/**
|
2
|
+
* Timeago is a jQuery plugin that makes it easy to support automatically
|
3
|
+
* updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago").
|
4
|
+
*
|
5
|
+
* @name timeago
|
6
|
+
* @version 1.4.1
|
7
|
+
* @requires jQuery v1.2.3+
|
8
|
+
* @author Ryan McGeary
|
9
|
+
* @license MIT License - http://www.opensource.org/licenses/mit-license.php
|
10
|
+
*
|
11
|
+
* For usage and examples, visit:
|
12
|
+
* http://timeago.yarp.com/
|
13
|
+
*
|
14
|
+
* Copyright (c) 2008-2013, Ryan McGeary (ryan -[at]- mcgeary [*dot*] org)
|
15
|
+
*/
|
16
|
+
|
17
|
+
!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a(jQuery)}(function(a){function d(){var c=e(this),d=b.settings;return isNaN(c.datetime)||(0==d.cutoff||Math.abs(g(c.datetime))<d.cutoff)&&a(this).text(f(c.datetime)),this}function e(c){if(c=a(c),!c.data("timeago")){c.data("timeago",{datetime:b.datetime(c)});var d=a.trim(c.text());b.settings.localeTitle?c.attr("title",c.data("timeago").datetime.toLocaleString()):!(d.length>0)||b.isTime(c)&&c.attr("title")||c.attr("title",d)}return c.data("timeago")}function f(a){return b.inWords(g(a))}function g(a){return(new Date).getTime()-a.getTime()}a.timeago=function(b){return b instanceof Date?f(b):"string"==typeof b?f(a.timeago.parse(b)):"number"==typeof b?f(new Date(b)):f(a.timeago.datetime(b))};var b=a.timeago;a.extend(a.timeago,{settings:{refreshMillis:6e4,allowPast:!0,allowFuture:!1,localeTitle:!1,cutoff:0,strings:{prefixAgo:null,prefixFromNow:null,suffixAgo:"ago",suffixFromNow:"from now",inPast:"any moment now",seconds:"less than a minute",minute:"about a minute",minutes:"%d minutes",hour:"about an hour",hours:"about %d hours",day:"a day",days:"%d days",month:"about a month",months:"%d months",year:"about a year",years:"%d years",wordSeparator:" ",numbers:[]}},inWords:function(b){function k(d,e){var f=a.isFunction(d)?d(e,b):d,g=c.numbers&&c.numbers[e]||e;return f.replace(/%d/i,g)}if(!this.settings.allowPast&&!this.settings.allowFuture)throw"timeago allowPast and allowFuture settings can not both be set to false.";var c=this.settings.strings,d=c.prefixAgo,e=c.suffixAgo;if(this.settings.allowFuture&&0>b&&(d=c.prefixFromNow,e=c.suffixFromNow),!this.settings.allowPast&&b>=0)return this.settings.strings.inPast;var f=Math.abs(b)/1e3,g=f/60,h=g/60,i=h/24,j=i/365,l=45>f&&k(c.seconds,Math.round(f))||90>f&&k(c.minute,1)||45>g&&k(c.minutes,Math.round(g))||90>g&&k(c.hour,1)||24>h&&k(c.hours,Math.round(h))||42>h&&k(c.day,1)||30>i&&k(c.days,Math.round(i))||45>i&&k(c.month,1)||365>i&&k(c.months,Math.round(i/30))||1.5>j&&k(c.year,1)||k(c.years,Math.round(j)),m=c.wordSeparator||"";return void 0===c.wordSeparator&&(m=" "),a.trim([d,l,e].join(m))},parse:function(b){var c=a.trim(b);return c=c.replace(/\.\d+/,""),c=c.replace(/-/,"/").replace(/-/,"/"),c=c.replace(/T/," ").replace(/Z/," UTC"),c=c.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2"),c=c.replace(/([\+\-]\d\d)$/," $100"),new Date(c)},datetime:function(c){var d=b.isTime(c)?a(c).attr("datetime"):a(c).attr("title");return b.parse(d)},isTime:function(b){return"time"===a(b).get(0).tagName.toLowerCase()}});var c={init:function(){var c=a.proxy(d,this);c();var e=b.settings;e.refreshMillis>0&&(this._timeagoInterval=setInterval(c,e.refreshMillis))},update:function(c){var e=b.parse(c);a(this).data("timeago",{datetime:e}),b.settings.localeTitle&&a(this).attr("title",e.toLocaleString()),d.apply(this)},updateFromDOM:function(){a(this).data("timeago",{datetime:b.parse(b.isTime(this)?a(this).attr("datetime"):a(this).attr("title"))}),d.apply(this)},dispose:function(){this._timeagoInterval&&(window.clearInterval(this._timeagoInterval),this._timeagoInterval=null)}};a.fn.timeago=function(a,b){var d=a?c[a]:c.init;if(!d)throw new Error("Unknown function name '"+a+"' for timeago");return this.each(function(){d.call(this,b)}),this},document.createElement("abbr"),document.createElement("time")});
|
data/web/views/failing.erb
CHANGED
@@ -13,6 +13,7 @@
|
|
13
13
|
<th>Job</th>
|
14
14
|
<th>Queue</th>
|
15
15
|
<th>Args</th>
|
16
|
+
<th>Error</th>
|
16
17
|
<th></th>
|
17
18
|
<th></th>
|
18
19
|
</tr>
|
@@ -20,11 +21,12 @@
|
|
20
21
|
<tbody>
|
21
22
|
<% @list.page_jobs.each do |job| %>
|
22
23
|
<tr>
|
23
|
-
<td><a href="<%= to "jobs/#{job.job_id}" %>"
|
24
|
+
<td><a href="<%= to "jobs/#{job.job_id}" %>"><%== relative_time job.run_at %></a></td>
|
24
25
|
<td><%= job.error_count %></td>
|
25
26
|
<td><%= job.job_class %></td>
|
26
27
|
<td><%= job.queue %></td>
|
27
|
-
<td><pre><%= job
|
28
|
+
<td><pre><%= format_args job %></pre></td>
|
29
|
+
<td><%= format_error job %></pre></td>
|
28
30
|
<td>
|
29
31
|
<form action="<%= to "jobs/#{job.job_id}" %>" method="post">
|
30
32
|
<input type="hidden" name="_method" value="put" />
|
data/web/views/layout.erb
CHANGED
@@ -7,8 +7,17 @@
|
|
7
7
|
<link rel="stylesheet" href="<%= root_path %>styles/font-awesome.min.css" />
|
8
8
|
<link rel="stylesheet" href="<%= root_path %>styles/application.css" />
|
9
9
|
<body>
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
<%== erb :_navbar %>
|
11
|
+
<%== erb :_flash %>
|
12
|
+
<%== yield %>
|
13
|
+
<%== erb :_footer %>
|
14
|
+
<script src="<%= root_path %>js/jquery.min.js"></script>
|
15
|
+
<script src="<%= root_path %>js/jquery.timeago.min.js"></script>
|
16
|
+
<script>
|
17
|
+
(function($){
|
18
|
+
$.timeago.settings.allowFuture = true;
|
19
|
+
$(".timeago").timeago();
|
20
|
+
}(jQuery));
|
21
|
+
</script>
|
13
22
|
</body>
|
14
23
|
</html>
|
data/web/views/running.erb
CHANGED
@@ -17,7 +17,7 @@
|
|
17
17
|
<tbody>
|
18
18
|
<% @list.page_jobs.each do |job| %>
|
19
19
|
<tr>
|
20
|
-
<td
|
20
|
+
<td><%== relative_time job.pg_state_changed_at %></td>
|
21
21
|
<td><%= job.job_class %></td>
|
22
22
|
<td><%= job.queue %></td>
|
23
23
|
<td><pre><%= job.args.map(&:inspect).join(', ') %></pre></td>
|
data/web/views/scheduled.erb
CHANGED
@@ -19,10 +19,10 @@
|
|
19
19
|
<tbody>
|
20
20
|
<% @list.page_jobs.each do |job| %>
|
21
21
|
<tr>
|
22
|
-
<td><a href="<%= to "jobs/#{job.job_id}" %>"
|
22
|
+
<td><a href="<%= to "jobs/#{job.job_id}" %>"><%== relative_time job.run_at %></a></td>
|
23
23
|
<td><%= job.job_class %></td>
|
24
24
|
<td><%= job.queue %></td>
|
25
|
-
<td><pre><%= job
|
25
|
+
<td><pre><%= format_args job %></pre></td>
|
26
26
|
<td>
|
27
27
|
<form action="<%= to "jobs/#{job.job_id}" %>" method="post">
|
28
28
|
<input type="hidden" name="_method" value="put" />
|
data/web/views/show.erb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: que-web
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jason Staten
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-11-
|
11
|
+
date: 2014-11-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: que
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: erubis
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: bundler
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -89,11 +103,16 @@ extra_rdoc_files: []
|
|
89
103
|
files:
|
90
104
|
- ".gitignore"
|
91
105
|
- ".travis.yml"
|
106
|
+
- CHANGELOG.md
|
92
107
|
- Gemfile
|
93
108
|
- LICENSE.txt
|
94
109
|
- README.md
|
95
110
|
- Rakefile
|
96
111
|
- doc/queweb.png
|
112
|
+
- docker/Dockerfile
|
113
|
+
- docker/Gemfile
|
114
|
+
- docker/Gemfile.lock
|
115
|
+
- docker/config.ru
|
97
116
|
- examples/rack/Gemfile
|
98
117
|
- examples/rack/Gemfile.lock
|
99
118
|
- examples/rack/boot.rb
|
@@ -117,15 +136,17 @@ files:
|
|
117
136
|
- web/public/fonts/fontawesome-webfont.ttf
|
118
137
|
- web/public/fonts/fontawesome-webfont.woff
|
119
138
|
- web/public/js/foundation.min.js
|
139
|
+
- web/public/js/jquery.min.js
|
140
|
+
- web/public/js/jquery.timeago.min.js
|
120
141
|
- web/public/js/vendor/fastclick.js
|
121
142
|
- web/public/js/vendor/jquery.cookie.js
|
122
|
-
- web/public/js/vendor/jquery.js
|
123
143
|
- web/public/js/vendor/modernizr.js
|
124
144
|
- web/public/js/vendor/placeholder.js
|
125
145
|
- web/public/styles/application.css
|
126
146
|
- web/public/styles/font-awesome.min.css
|
127
147
|
- web/public/styles/foundation.min.css
|
128
148
|
- web/public/styles/normalize.css
|
149
|
+
- web/views/_flash.erb
|
129
150
|
- web/views/_footer.erb
|
130
151
|
- web/views/_navbar.erb
|
131
152
|
- web/views/_pager.erb
|