concerto_hardware 0.0.5
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 +7 -0
- data/LICENSE +14 -0
- data/README.rdoc +7 -0
- data/Rakefile +40 -0
- data/app/assets/images/concerto_hardware/helpicon.png +0 -0
- data/app/assets/javascripts/concerto_hardware/application.js +15 -0
- data/app/assets/javascripts/concerto_hardware/players.js +2 -0
- data/app/assets/stylesheets/concerto_hardware/application.css +13 -0
- data/app/assets/stylesheets/concerto_hardware/players.css.scss +3 -0
- data/app/assets/stylesheets/scaffolds.css.scss +56 -0
- data/app/controllers/concerto_hardware/application_controller.rb +16 -0
- data/app/controllers/concerto_hardware/players_controller.rb +116 -0
- data/app/helpers/players_helper.rb +2 -0
- data/app/models/concerto_hardware/ability.rb +42 -0
- data/app/models/concerto_hardware/player.rb +169 -0
- data/app/views/concerto_hardware/players/_form.html.erb +77 -0
- data/app/views/concerto_hardware/players/_show_body.html.erb +45 -0
- data/app/views/concerto_hardware/players/_show_header.html.erb +17 -0
- data/app/views/concerto_hardware/players/edit.html.erb +9 -0
- data/app/views/concerto_hardware/players/index.html.erb +49 -0
- data/app/views/concerto_hardware/players/new.html.erb +8 -0
- data/app/views/concerto_hardware/players/show.html.erb +8 -0
- data/app/views/concerto_hardware/screens/_screen_link.html.erb +49 -0
- data/config/locales/en.yml +29 -0
- data/config/routes.rb +21 -0
- data/db/migrate/20121220000000_create_concerto_hardware_players.rb +12 -0
- data/db/migrate/20131127201048_add_updates_to_concerto_hardware_players.rb +6 -0
- data/lib/concerto-hardware.rb +6 -0
- data/lib/concerto_hardware/engine.rb +68 -0
- data/lib/concerto_hardware/version.rb +3 -0
- data/test/fixtures/players.yml +13 -0
- data/test/functional/players_controller_test.rb +49 -0
- data/test/unit/helpers/players_helper_test.rb +4 -0
- data/test/unit/player_test.rb +7 -0
- metadata +109 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 2a8507b255441f28f56a5053cb63e0880e17d40f
|
4
|
+
data.tar.gz: 1bdd8dff01bfb754b32b7cc9e2538f573bebc030
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a67113f0fd71723c6f450a4d651de1682e35465c1bd3113f23ea12e6d45e8588a4d092f7807398ef480c81b5e9a4efbd09491fa666d20ed2acdab78398ab7f16
|
7
|
+
data.tar.gz: e5490b2f6b25587619c9760bb8ea3194a0eca5bb49de639a2b7949c74c342d4c16495a8100bdaef7fb167e0b441ee4260b299496062d2440a3218111e000f4b0
|
data/LICENSE
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
Copyright 2011 Concerto Authors
|
2
|
+
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
you may not use this file except in compliance with the License.
|
5
|
+
You may obtain a copy of the License at
|
6
|
+
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
See the License for the specific language governing permissions and
|
13
|
+
limitations under the License.
|
14
|
+
|
data/README.rdoc
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
A Rails Engine for managing Bandshell-powered Concerto hardware
|
2
|
+
|
3
|
+
To use this engine, add the following to the Concerto Gemfile:
|
4
|
+
gem 'concerto-hardware', :path => '/path/to/concerto-hardware'
|
5
|
+
|
6
|
+
To create the proper migrations, use:
|
7
|
+
rails generate concerto-hardware
|
data/Rakefile
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'rdoc/task'
|
9
|
+
rescue LoadError
|
10
|
+
require 'rdoc/rdoc'
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
RDoc::Task = Rake::RDocTask
|
13
|
+
end
|
14
|
+
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
17
|
+
rdoc.title = 'ConcertoHardware'
|
18
|
+
rdoc.options << '--line-numbers'
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
+
end
|
22
|
+
|
23
|
+
APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
|
24
|
+
load 'rails/tasks/engine.rake'
|
25
|
+
|
26
|
+
|
27
|
+
|
28
|
+
Bundler::GemHelper.install_tasks
|
29
|
+
|
30
|
+
require 'rake/testtask'
|
31
|
+
|
32
|
+
Rake::TestTask.new(:test) do |t|
|
33
|
+
t.libs << 'lib'
|
34
|
+
t.libs << 'test'
|
35
|
+
t.pattern = 'test/**/*_test.rb'
|
36
|
+
t.verbose = false
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
task :default => :test
|
Binary file
|
@@ -0,0 +1,15 @@
|
|
1
|
+
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
2
|
+
// listed below.
|
3
|
+
//
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
5
|
+
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
|
6
|
+
//
|
7
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
8
|
+
// the compiled file.
|
9
|
+
//
|
10
|
+
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
|
11
|
+
// GO AFTER THE REQUIRES BELOW.
|
12
|
+
//
|
13
|
+
//= require jquery
|
14
|
+
//= require jquery_ujs
|
15
|
+
//= require_tree .
|
@@ -0,0 +1,13 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the top of the
|
9
|
+
* compiled file, but it's generally better to create a new file per style scope.
|
10
|
+
*
|
11
|
+
*= require_self
|
12
|
+
*= require_tree .
|
13
|
+
*/
|
@@ -0,0 +1,56 @@
|
|
1
|
+
body {
|
2
|
+
background-color: #fff;
|
3
|
+
color: #333;
|
4
|
+
font-family: verdana, arial, helvetica, sans-serif;
|
5
|
+
font-size: 13px;
|
6
|
+
line-height: 18px; }
|
7
|
+
|
8
|
+
p, ol, ul, td {
|
9
|
+
font-family: verdana, arial, helvetica, sans-serif;
|
10
|
+
font-size: 13px;
|
11
|
+
line-height: 18px; }
|
12
|
+
|
13
|
+
pre {
|
14
|
+
background-color: #eee;
|
15
|
+
padding: 10px;
|
16
|
+
font-size: 11px; }
|
17
|
+
|
18
|
+
a {
|
19
|
+
color: #000;
|
20
|
+
&:visited {
|
21
|
+
color: #666; }
|
22
|
+
&:hover {
|
23
|
+
color: #fff;
|
24
|
+
background-color: #000; } }
|
25
|
+
|
26
|
+
div {
|
27
|
+
&.field, &.actions {
|
28
|
+
margin-bottom: 10px; } }
|
29
|
+
|
30
|
+
#notice {
|
31
|
+
color: green; }
|
32
|
+
|
33
|
+
.field_with_errors {
|
34
|
+
padding: 2px;
|
35
|
+
background-color: red;
|
36
|
+
display: table; }
|
37
|
+
|
38
|
+
#error_explanation {
|
39
|
+
width: 450px;
|
40
|
+
border: 2px solid red;
|
41
|
+
padding: 7px;
|
42
|
+
padding-bottom: 0;
|
43
|
+
margin-bottom: 20px;
|
44
|
+
background-color: #f0f0f0;
|
45
|
+
h2 {
|
46
|
+
text-align: left;
|
47
|
+
font-weight: bold;
|
48
|
+
padding: 5px 5px 5px 15px;
|
49
|
+
font-size: 12px;
|
50
|
+
margin: -7px;
|
51
|
+
margin-bottom: 0px;
|
52
|
+
background-color: #c00;
|
53
|
+
color: #fff; }
|
54
|
+
ul li {
|
55
|
+
font-size: 12px;
|
56
|
+
list-style: square; } }
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ConcertoHardware
|
2
|
+
# Congratulations! You've found this engine's secret sauce.
|
3
|
+
# In a regular isolated engine, the engine's ApplicationController
|
4
|
+
# inherits from ActionController::Base. We're using the the main app's
|
5
|
+
# ApplicationController, making the isolation a little less strict.
|
6
|
+
# For example, we get the layout from the main Concerto app.
|
7
|
+
# Note that links back to the main application will need to directly
|
8
|
+
# reference the main_app router.
|
9
|
+
class ApplicationController < ::ApplicationController
|
10
|
+
def current_ability
|
11
|
+
# Use the Ability class defined in this engine's namespace.
|
12
|
+
# It is designed to also include the rules from the main app.
|
13
|
+
@current_ability ||= Ability.new(current_accessor)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require_dependency "concerto_hardware/application_controller"
|
2
|
+
|
3
|
+
module ConcertoHardware
|
4
|
+
class PlayersController < ApplicationController
|
5
|
+
unloadable #marks this class for reloading in between requests
|
6
|
+
#include routes.named_routes.helpers
|
7
|
+
before_filter :screen_api
|
8
|
+
|
9
|
+
# GET /players
|
10
|
+
# GET /players.json
|
11
|
+
def index
|
12
|
+
@players = Player.all
|
13
|
+
auth!
|
14
|
+
|
15
|
+
respond_to do |format|
|
16
|
+
format.html # index.html.erb
|
17
|
+
format.json { render :json => @players }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# GET /players/1
|
22
|
+
# GET /players/1.json
|
23
|
+
# GET /players/by_screen/2(.json)
|
24
|
+
# GET /players/current(.json)
|
25
|
+
def show
|
26
|
+
if params.has_key? :screen_id
|
27
|
+
screen_id = params[:screen_id]
|
28
|
+
@player = ConcertoHardware::Player.find_by_screen_id!(screen_id)
|
29
|
+
elsif params.has_key? :id
|
30
|
+
@player = Player.find(params[:id])
|
31
|
+
else # Return data about the logged-in screen
|
32
|
+
if current_screen.nil?
|
33
|
+
raise ActiveRecord::RecordNotFound, "Couldn't find an authenticated screen."
|
34
|
+
else
|
35
|
+
@player = Player.find_by_screen_id!(current_screen.id)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
auth!
|
39
|
+
|
40
|
+
respond_to do |format|
|
41
|
+
format.html # show.html.erb
|
42
|
+
format.json { render :json => @player }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# GET /players/new
|
47
|
+
# GET /players/new.json
|
48
|
+
def new
|
49
|
+
@player = Player.new
|
50
|
+
if !params[:screen_id].nil?
|
51
|
+
# TODO: Error handling
|
52
|
+
@player.screen = Screen.find(params[:screen_id])
|
53
|
+
end
|
54
|
+
auth!
|
55
|
+
|
56
|
+
respond_to do |format|
|
57
|
+
format.html # new.html.erb
|
58
|
+
format.json { render :json => @player }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# GET /players/1/edit
|
63
|
+
def edit
|
64
|
+
@player = Player.find(params[:id])
|
65
|
+
auth!
|
66
|
+
end
|
67
|
+
|
68
|
+
# POST /players
|
69
|
+
# POST /players.json
|
70
|
+
def create
|
71
|
+
@player = Player.new(params[:player])
|
72
|
+
auth!
|
73
|
+
|
74
|
+
respond_to do |format|
|
75
|
+
if @player.save
|
76
|
+
format.html { redirect_to [hardware, @player], :notice => 'Player was successfully created.' }
|
77
|
+
format.json { render :json => @player, :status => :created, :location => @player }
|
78
|
+
else
|
79
|
+
format.html { render :action => "new" }
|
80
|
+
format.json { render :json => @player.errors, :status => :unprocessable_entity }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# PUT /players/1
|
86
|
+
# PUT /players/1.json
|
87
|
+
def update
|
88
|
+
@player = Player.find(params[:id])
|
89
|
+
auth!
|
90
|
+
|
91
|
+
respond_to do |format|
|
92
|
+
if @player.update_attributes(params[:player])
|
93
|
+
format.html { redirect_to [hardware, @player], :notice => 'Player was successfully updated.' }
|
94
|
+
format.json { head :no_content }
|
95
|
+
else
|
96
|
+
format.html { render :action => "edit" }
|
97
|
+
format.json { render :json => @player.errors, :status => :unprocessable_entity }
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# DELETE /players/1
|
103
|
+
# DELETE /players/1.json
|
104
|
+
def destroy
|
105
|
+
@player = Player.find(params[:id])
|
106
|
+
auth!
|
107
|
+
@player.destroy
|
108
|
+
|
109
|
+
respond_to do |format|
|
110
|
+
format.html { redirect_to hardware.players_url }
|
111
|
+
format.json { head :no_content }
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module ConcertoHardware
|
2
|
+
# The enigne's Ability class simply extends the existing Ability
|
3
|
+
# class for the application. We rely on the fact that it already
|
4
|
+
# includes CanCan::Ability.
|
5
|
+
class Ability < ::Ability
|
6
|
+
def initialize(accessor)
|
7
|
+
super # Get the main application's rules
|
8
|
+
# The main app will delegate to user_abilities, etc.
|
9
|
+
# Note the inherited rules give Admins rights to manage everything
|
10
|
+
end
|
11
|
+
|
12
|
+
def user_abilities(user)
|
13
|
+
super # Get the user rules from the main applications
|
14
|
+
|
15
|
+
# For debugging you may want to make all Players readable
|
16
|
+
# can :read, Player
|
17
|
+
|
18
|
+
# Let's defer to Concerto's rules for Screen Permissions.
|
19
|
+
# This will apply to both users browsing the hardware info
|
20
|
+
# as well as public screens in public instances accessing their data.
|
21
|
+
# - Right now, only admins can create players (TODO)
|
22
|
+
# - It may become desirable in the future for reading to be
|
23
|
+
# restricted or curtailed if a lot of sensitive data is stored here.
|
24
|
+
can :read, Player do |player|
|
25
|
+
!player.screen.nil? and can? :read, player.screen
|
26
|
+
end
|
27
|
+
can :update, Player do |player|
|
28
|
+
!player.screen.nil? and can? :update, player.screen
|
29
|
+
end
|
30
|
+
can :delete, Player do |player|
|
31
|
+
!player.screen.nil? and can? :delete, player.screen
|
32
|
+
end
|
33
|
+
end # user_abilities
|
34
|
+
|
35
|
+
def screen_abilities(screen)
|
36
|
+
# A logged-in screen can read its own Player information.
|
37
|
+
can :read, Player, :screen_id => screen.id
|
38
|
+
# In the future it may also need to write reporting data, so
|
39
|
+
# this will need to be expanded.
|
40
|
+
end # screen_abilities
|
41
|
+
end # class Ability
|
42
|
+
end # module ConcertoHardware
|
@@ -0,0 +1,169 @@
|
|
1
|
+
module ConcertoHardware
|
2
|
+
class Player < ActiveRecord::Base
|
3
|
+
belongs_to :screen
|
4
|
+
|
5
|
+
def self.time_accessor(*syms)
|
6
|
+
syms.each do |sym|
|
7
|
+
attr_accessor sym
|
8
|
+
composed_of sym,
|
9
|
+
:class_name => 'Time',
|
10
|
+
:mapping => [sym.to_s, "to_s"],
|
11
|
+
:constructor => Proc.new{ |item| item },
|
12
|
+
:converter => Proc.new{ |item| item }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Hack to get the multiparameter virtual attributes working
|
17
|
+
def self.create_time_zone_conversion_attribute?(name, column)
|
18
|
+
column.nil? ? true : super
|
19
|
+
end
|
20
|
+
|
21
|
+
validates_associated :screen
|
22
|
+
validates_presence_of :screen_id
|
23
|
+
validates_presence_of :screen, :message => 'must exist'
|
24
|
+
validates_uniqueness_of :screen_id
|
25
|
+
|
26
|
+
time_accessor :wkday_on_time, :wkday_off_time
|
27
|
+
time_accessor :wknd_on_time, :wknd_off_time
|
28
|
+
time_accessor :party_time
|
29
|
+
attr_accessor :wknd_disable
|
30
|
+
attr_accessor :force_off
|
31
|
+
|
32
|
+
after_initialize :default_values
|
33
|
+
after_find :retrieve_screen_on_off
|
34
|
+
before_save :process_screen_on_off
|
35
|
+
|
36
|
+
def default_values
|
37
|
+
self.screen_on_off ||= [
|
38
|
+
{
|
39
|
+
:action => "on",
|
40
|
+
:wkday => "12345", # M-F
|
41
|
+
:time_after => "07:00",
|
42
|
+
:time_before => "20:00"
|
43
|
+
},
|
44
|
+
{
|
45
|
+
:action => "on",
|
46
|
+
:wkday => "06", # Sun, Sat
|
47
|
+
:time_after => "09:00",
|
48
|
+
:time_before => "20:00"
|
49
|
+
}
|
50
|
+
].to_json
|
51
|
+
retrieve_screen_on_off #populate the virtual attributes.
|
52
|
+
end
|
53
|
+
|
54
|
+
# Take screen controls from the form and store them
|
55
|
+
# in a standard format that the player will understand.
|
56
|
+
# https://github.com/concerto/concerto-hardware/
|
57
|
+
# wiki/Player-API#screen-onoff-times
|
58
|
+
# TODO: Formatting for datetimes
|
59
|
+
# TODO: Validation
|
60
|
+
# TODO: TIMEZONES
|
61
|
+
def process_screen_on_off
|
62
|
+
ruleset = []
|
63
|
+
unless self.wkday_on_time.nil? or self.wkday_off_time.nil?
|
64
|
+
ruleset << {
|
65
|
+
:action => "on",
|
66
|
+
:wkday => "12345", # M-F
|
67
|
+
:time_after => fmt_time(wkday_on_time), # "07:00"
|
68
|
+
:time_before => fmt_time(wkday_off_time), # "23:00"
|
69
|
+
}
|
70
|
+
end
|
71
|
+
unless self.wknd_on_time.nil? or self.wknd_off_time.nil?
|
72
|
+
ruleset << {
|
73
|
+
:action => self.wknd_disable=="1" ? "off" : "on",
|
74
|
+
:wkday => "06", # Sun, Sat
|
75
|
+
:time_after => fmt_time(wknd_on_time), # "07:00"
|
76
|
+
:time_before => fmt_time(wknd_off_time), # "23:00"
|
77
|
+
}
|
78
|
+
end
|
79
|
+
if self.force_off == "1"
|
80
|
+
ruleset << {
|
81
|
+
:action => "off",
|
82
|
+
:date => Time.now.strftime("%Y-%m-%d")
|
83
|
+
}
|
84
|
+
end
|
85
|
+
if ruleset.empty? && self.screen_on_off.blank?
|
86
|
+
ruleset << {
|
87
|
+
:action => "on"
|
88
|
+
}
|
89
|
+
end
|
90
|
+
|
91
|
+
self.screen_on_off = ruleset.to_json unless ruleset.empty?
|
92
|
+
end
|
93
|
+
|
94
|
+
# This is a very limited parsing of the on/off rules
|
95
|
+
# Pretty much it will only work on rulesets created by the methods
|
96
|
+
# in this model. The format is very flexible, but this model only
|
97
|
+
# supports 3 simple rules.
|
98
|
+
def retrieve_screen_on_off
|
99
|
+
return nil if screen_on_off.blank?
|
100
|
+
|
101
|
+
ruleset = ActiveSupport::JSON.decode(self.screen_on_off)
|
102
|
+
ruleset.each do |rule|
|
103
|
+
if rule.has_key? 'action'
|
104
|
+
if rule.has_key? 'wkday' and rule['wkday']=='12345' and
|
105
|
+
rule['action']='on'
|
106
|
+
if rule.has_key? 'time_after' and rule.has_key? 'time_before'
|
107
|
+
self.wkday_on_time = Time.parse(rule['time_after'])
|
108
|
+
self.wkday_off_time = Time.parse(rule['time_before'])
|
109
|
+
end
|
110
|
+
end # weekday
|
111
|
+
if rule.has_key? 'wkday' and rule['wkday']=='06'
|
112
|
+
if rule.has_key? 'time_after' and rule.has_key? 'time_before'
|
113
|
+
self.wknd_on_time = Time.parse(rule['time_after'])
|
114
|
+
self.wknd_off_time = Time.parse(rule['time_before'])
|
115
|
+
end
|
116
|
+
self.wknd_disable = (rule['action'] != 'on')
|
117
|
+
end # weekend
|
118
|
+
if rule.has_key? 'date'
|
119
|
+
if rule['date'] == Time.now.strftime("%Y-%m-%d")
|
120
|
+
self.force_off = (rule['action'] != 'on')
|
121
|
+
end
|
122
|
+
end # force off rules
|
123
|
+
end # has an action
|
124
|
+
end # each rule
|
125
|
+
end # retrive_screen_on_off
|
126
|
+
|
127
|
+
# Relies on retrive_screen_on_off having been called at load.
|
128
|
+
def screen_on_off_valid
|
129
|
+
!(
|
130
|
+
wkday_on_time.nil? or wkday_off_time.nil? or
|
131
|
+
wknd_on_time.nil? or wknd_off_time.nil? or wknd_disable.nil?
|
132
|
+
)
|
133
|
+
end
|
134
|
+
|
135
|
+
# Returns an array of strings describing the screen's behavior.
|
136
|
+
# Relies on retrive_screen_on_off having been called at load.
|
137
|
+
def describe_screen_on_off
|
138
|
+
rules = []
|
139
|
+
if self.screen_on_off.blank?
|
140
|
+
rules << "On/off times not configured. The screen will always be on."
|
141
|
+
elsif !screen_on_off_valid
|
142
|
+
rules << "On/off rules are invalid. Edit and save the Player to fix."
|
143
|
+
else
|
144
|
+
rules << "Weekdays: on at "+fmt_time(wkday_on_time, "%l:%M%P")+", "+
|
145
|
+
"off at "+fmt_time(wkday_off_time, "%l:%M%P")+"."
|
146
|
+
if wknd_disable
|
147
|
+
rules << "Weekends: off."
|
148
|
+
else
|
149
|
+
rules << "Weekends: on at "+fmt_time(wknd_on_time, "%l:%M%P")+", "+
|
150
|
+
"off at "+fmt_time(wknd_off_time, "%l:%M%P")+"."
|
151
|
+
end
|
152
|
+
if force_off
|
153
|
+
rules << "Manual override: screen will be off until midnight tonight."
|
154
|
+
end
|
155
|
+
end
|
156
|
+
rules
|
157
|
+
end
|
158
|
+
|
159
|
+
def fmt_time(timeobj, fmt = "%H:%M")
|
160
|
+
if !timeobj.nil?
|
161
|
+
if timeobj.is_a?(String)
|
162
|
+
timeobj = Time.parse(timeobj)
|
163
|
+
end
|
164
|
+
timeobj.strftime(fmt).strip
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
end # class Player
|
169
|
+
end # module ConcertoHardware
|
@@ -0,0 +1,77 @@
|
|
1
|
+
<%= form_for(@player) do |f| %>
|
2
|
+
<%= render :partial => "layouts/errors", :object => @player %>
|
3
|
+
|
4
|
+
<fieldset>
|
5
|
+
<legend><span><%= t('.provide_details') %></span></legend>
|
6
|
+
|
7
|
+
<%= f.hidden_field :screen_id %>
|
8
|
+
|
9
|
+
<div class="clearfix">
|
10
|
+
<%= f.label :ip_address %>
|
11
|
+
<div class="input">
|
12
|
+
<%= f.text_field :ip_address %>
|
13
|
+
</div>
|
14
|
+
</div>
|
15
|
+
|
16
|
+
<div class="clearfix">
|
17
|
+
<div class="input checkbox">
|
18
|
+
<ul class="inputs-list">
|
19
|
+
<li><%= f.check_box :activated %> <%= f.label :activated %></li>
|
20
|
+
</ul>
|
21
|
+
</div>
|
22
|
+
</div>
|
23
|
+
|
24
|
+
<!-- Screen on/off times. Good luck, UI designer. -->
|
25
|
+
<div class="clearfix">
|
26
|
+
<%= f.label :wkday_on_time %>
|
27
|
+
<div class="input-prepend">
|
28
|
+
<span class="add-on"><%= t(:at) %></span>
|
29
|
+
<%= f.text_field(:wkday_on_time, :maxlength => 20, :class => "timefield input-small", :value => @player.fmt_time(@player.wkday_on_time, "%l:%M%P") || ConcertoConfig[:content_default_start_time]) %>
|
30
|
+
</div>
|
31
|
+
</div>
|
32
|
+
<div class="clearfix">
|
33
|
+
<%= f.label :wkday_off_time %>
|
34
|
+
<div class="input-prepend">
|
35
|
+
<span class="add-on"><%= t(:at) %></span>
|
36
|
+
<%= f.text_field(:wkday_off_time, :maxlength => 20, :class => "timefield input-small", :value => @player.fmt_time(@player.wkday_off_time, "%l:%M%P") || ConcertoConfig[:content_default_end_time]) %>
|
37
|
+
</div>
|
38
|
+
</div>
|
39
|
+
|
40
|
+
<div class="clearfix">
|
41
|
+
<div class="input checkbox">
|
42
|
+
<ul class="inputs-list">
|
43
|
+
<li><%= f.check_box :wknd_disable %> <%= f.label :wknd_disable %></li>
|
44
|
+
</ul>
|
45
|
+
</div>
|
46
|
+
</div>
|
47
|
+
<div class="clearfix">
|
48
|
+
<%= f.label :wknd_on_time %>
|
49
|
+
<div class="input-prepend">
|
50
|
+
<span class="add-on"><%= t(:at) %></span>
|
51
|
+
<%= f.text_field(:wknd_on_time, :maxlength => 20, :class => "timefield input-small", :value => @player.fmt_time(@player.wknd_on_time, "%l:%M%P") || ConcertoConfig[:content_default_start_time]) %>
|
52
|
+
</div>
|
53
|
+
</div>
|
54
|
+
<div class="clearfix">
|
55
|
+
<%= f.label :wknd_off_time %>
|
56
|
+
<div class="input-prepend">
|
57
|
+
<span class="add-on"><%= t(:at) %></span>
|
58
|
+
<%= f.text_field(:wknd_off_time, :maxlength => 20, :class => "timefield input-small", :value => @player.fmt_time(@player.wknd_off_time, "%l:%M%P") || ConcertoConfig[:content_default_end_time]) %>
|
59
|
+
</div>
|
60
|
+
</div>
|
61
|
+
|
62
|
+
<div class="clearfix">
|
63
|
+
<div class="input checkbox">
|
64
|
+
<ul class="inputs-list">
|
65
|
+
<li><%= f.check_box :force_off %> <%= f.label :force_off %> (temporarily turns off the screen until midnight tonight)</li>
|
66
|
+
</ul>
|
67
|
+
</div>
|
68
|
+
</div>
|
69
|
+
<p><em>All time fields should be entered in 24 hour format (HH:mm), for example 23:30 for 11:30 PM.</em></p>
|
70
|
+
</fieldset>
|
71
|
+
|
72
|
+
<div class="submit_bar actions">
|
73
|
+
<%= f.submit button_text, :class => "btn btn-primary" %>
|
74
|
+
<%= link_to t(:cancel), (@player.persisted? ? player_path : players_path), :class => "btn" %>
|
75
|
+
</div>
|
76
|
+
|
77
|
+
<% end %>
|
@@ -0,0 +1,45 @@
|
|
1
|
+
<div class="row-fluid">
|
2
|
+
<div class="span12">
|
3
|
+
<div class="default-padding">
|
4
|
+
<div class="subblock">
|
5
|
+
<div class="default-padding clearfix">
|
6
|
+
|
7
|
+
<p id="notice"><%= notice %></p>
|
8
|
+
|
9
|
+
<p>
|
10
|
+
<b>Ip address:</b>
|
11
|
+
<%= @player.ip_address %>
|
12
|
+
</p>
|
13
|
+
|
14
|
+
<p>
|
15
|
+
<b>Screen:</b>
|
16
|
+
<% if @player.screen.nil? %>
|
17
|
+
Not found
|
18
|
+
<% else %>
|
19
|
+
<% if can? :read, @player.screen %>
|
20
|
+
<%= link_to @player.screen.name, [main_app, @player.screen] %>
|
21
|
+
<% else %>
|
22
|
+
<%= @player.screen.name %>
|
23
|
+
<% end %>
|
24
|
+
<% end %>
|
25
|
+
</p>
|
26
|
+
|
27
|
+
<p>
|
28
|
+
<b>Activated:</b>
|
29
|
+
<%= @player.activated %>
|
30
|
+
</p>
|
31
|
+
|
32
|
+
<p>
|
33
|
+
<b>Screen on/off times:</b>
|
34
|
+
<ul>
|
35
|
+
<% @player.describe_screen_on_off.each do |rule| %>
|
36
|
+
<li><%=rule%></li>
|
37
|
+
<% end %>
|
38
|
+
</ul>
|
39
|
+
</p>
|
40
|
+
|
41
|
+
</div>
|
42
|
+
</div>
|
43
|
+
</div>
|
44
|
+
</div>
|
45
|
+
</div>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<div class="viewblock-header_right">
|
2
|
+
<div class="button-padding">
|
3
|
+
<% if can? :update, @player %>
|
4
|
+
<%= link_to t(:edit_model, :model => ConcertoHardware::Player.model_name.human), edit_player_path(@player), :class => "btn" %>
|
5
|
+
<% end %>
|
6
|
+
<% if can? :delete, @player %>
|
7
|
+
<%= link_to t(:destroy_model, :model => ConcertoHardware::Player.model_name.human), @player, :data => { :confirm => t(:are_you_sure_delete_model_key, :model => ConcertoHardware::Player.model_name.human, :key => @player.screen.name) }, :method => :delete, :class => "btn" %>
|
8
|
+
<% end %>
|
9
|
+
</div>
|
10
|
+
</div>
|
11
|
+
|
12
|
+
<div class="default-padding">
|
13
|
+
<h1>
|
14
|
+
<%= link_to t(:all_model, :model => ConcertoHardware::Player.model_name.human.pluralize), players_path %> >
|
15
|
+
<%= @player.screen.name + " Player" %>
|
16
|
+
</h1>
|
17
|
+
</div>
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<section class="viewblock">
|
2
|
+
<header class="viewblock-header">
|
3
|
+
<h1 class="default-padding"><%= t('.header', :screen => "#{@player.screen.name if !@player.screen.nil?}") %></h1>
|
4
|
+
</header>
|
5
|
+
<div class="viewblock-cont">
|
6
|
+
<%= render :partial => 'form', :locals => { :button_text => t(:update_model, :model => ConcertoHardware::Player.model_name.human) } %>
|
7
|
+
</div>
|
8
|
+
</section>
|
9
|
+
|
@@ -0,0 +1,49 @@
|
|
1
|
+
<section class="viewblock">
|
2
|
+
<header class="viewblock-header">
|
3
|
+
<div class="viewblock-header_right">
|
4
|
+
<div class="button-padding">
|
5
|
+
<% if can? :create, ConcertoHardware::Player %>
|
6
|
+
<%= link_to t(:new_model, :model => ConcertoHardware::Player.model_name.human), new_player_path, :class => "btn" %>
|
7
|
+
<% end %>
|
8
|
+
</div>
|
9
|
+
</div>
|
10
|
+
<h1 class="default-padding">
|
11
|
+
<%= t(:all_model, :model => ConcertoHardware::Player.model_name.human.pluralize) %>
|
12
|
+
</h1>
|
13
|
+
</header>
|
14
|
+
<div class="viewblock-cont">
|
15
|
+
<table>
|
16
|
+
<tr>
|
17
|
+
<th><%= ConcertoHardware::Player.human_attribute_name(:ip_address) %></th>
|
18
|
+
<th><%= ConcertoHardware::Player.human_attribute_name(:screen_id) %></th>
|
19
|
+
<th><%= ConcertoHardware::Player.human_attribute_name(:activated) %></th>
|
20
|
+
<th>Actions</th>
|
21
|
+
</tr>
|
22
|
+
|
23
|
+
<% @players.each do |player| %>
|
24
|
+
<tr>
|
25
|
+
<td><%= player.ip_address %></td>
|
26
|
+
<td><%= player.screen.name %></td>
|
27
|
+
<td><%= player.activated %></td>
|
28
|
+
|
29
|
+
<td>
|
30
|
+
<% if can? :read, player %>
|
31
|
+
<%= link_to t(:show, :model => ConcertoHardware::Player.model_name.human), player, :class => "btn" %>
|
32
|
+
<% end %>
|
33
|
+
<% if can? :edit, player %>
|
34
|
+
<%= link_to t(:edit, :model => ConcertoHardware::Player.model_name.human), edit_player_path(player), :class => "btn" %>
|
35
|
+
<% end %>
|
36
|
+
<% if can? :delete, player %>
|
37
|
+
<%= link_to t(:destroy, :model => ConcertoHardware::Player), player,
|
38
|
+
:data => { :confirm => t(:are_you_sure_delete_model_key, :model =>ConcertoHardware::Player.model_name.human, :key => player.screen.name) }, :method => :delete, :class => "btn" %>
|
39
|
+
<% end %>
|
40
|
+
</td>
|
41
|
+
</tr>
|
42
|
+
<% end %>
|
43
|
+
</table>
|
44
|
+
</div>
|
45
|
+
</section>
|
46
|
+
<div class="default-padding">
|
47
|
+
<%# for demo purposes: %>
|
48
|
+
Note: the poll interval is currently set to <%=ConcertoConfig[:poll_interval]%> seconds.
|
49
|
+
</div>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<section class="viewblock">
|
2
|
+
<header class="viewblock-header">
|
3
|
+
<h1 class="default-padding"><%= t('.header', :screen => "#{@player.screen.name if !@player.screen.nil?}") %></h1>
|
4
|
+
</header>
|
5
|
+
<div class="viewblock-cont">
|
6
|
+
<%= render :partial => 'form', :locals => { :button_text => t(:create_model, :model => ConcertoHardware::Player.model_name.human) } %>
|
7
|
+
</div>
|
8
|
+
</section>
|
@@ -0,0 +1,49 @@
|
|
1
|
+
<%# This partial will be read in the context of the main Concerto app. %>
|
2
|
+
<%# URL helpers require use of the 'hardware' routing helper. %>
|
3
|
+
<%# ConcertoHardware authorization rules are automatically provided. %>
|
4
|
+
|
5
|
+
<section class="viewblock">
|
6
|
+
<header class="viewblock-header">
|
7
|
+
<div class="viewblock-header_right">
|
8
|
+
<div class="button-padding">
|
9
|
+
<% if @player.nil? %>
|
10
|
+
<%= link_to 'Add Player', hardware.new_player_path(:screen_id => @screen.id), :class => "btn" %>
|
11
|
+
<% else %>
|
12
|
+
<% if can? :update, @player %>
|
13
|
+
<%= link_to 'Edit Player', hardware.edit_player_path(@player), :class => "btn" %>
|
14
|
+
<% end %>
|
15
|
+
<% end %>
|
16
|
+
</div>
|
17
|
+
</div>
|
18
|
+
|
19
|
+
<div class="default-padding">
|
20
|
+
<h1><%= t('.concerto_player') %></h1>
|
21
|
+
</div>
|
22
|
+
</header>
|
23
|
+
<div class="viewblock-cont">
|
24
|
+
<div class="default-padding">
|
25
|
+
<% if @player.nil? %>
|
26
|
+
<div class="alert alert-block alert-zero">
|
27
|
+
<p class="alert-heading"><%= t('.no_player_header') %></p>
|
28
|
+
<p><%= t('.no_player_msg') %></p>
|
29
|
+
<% if can? :update, @player %>
|
30
|
+
<%= link_to t('.add_player_msg'), hardware.new_player_path(:screen_id => @screen.id) %>
|
31
|
+
<% end %>
|
32
|
+
</div>
|
33
|
+
<% else %>
|
34
|
+
<h3><%= @screen.name + " Player" %></h3>
|
35
|
+
<p><b><%= @player.activated ? t('.activated') : t('.not_activated') %></b></p>
|
36
|
+
<br />
|
37
|
+
<% if can? :read, @player %>
|
38
|
+
<p><b>IP Address:</b> <%= @player.ip_address %></p>
|
39
|
+
<p><b>Screen On/Off Times:</b></p>
|
40
|
+
<ul>
|
41
|
+
<% @player.describe_screen_on_off.each do |rule| %>
|
42
|
+
<li><%= rule %></li>
|
43
|
+
<% end %>
|
44
|
+
</ul>
|
45
|
+
<% end %>
|
46
|
+
<% end %>
|
47
|
+
</div>
|
48
|
+
</div>
|
49
|
+
</section>
|
@@ -0,0 +1,29 @@
|
|
1
|
+
en:
|
2
|
+
activerecord:
|
3
|
+
models:
|
4
|
+
concerto_hardware/player: 'Player'
|
5
|
+
attributes:
|
6
|
+
concerto_hardware/player:
|
7
|
+
activated: 'Active'
|
8
|
+
ip_address: 'IP Address'
|
9
|
+
wkday_on_time: 'Weekday turn On time'
|
10
|
+
wkday_off_time: 'Weekday turn Off time'
|
11
|
+
wknd_disable: 'Disable on weekends'
|
12
|
+
wknd_on_time: 'Weekend turn On time'
|
13
|
+
wknd_off_time: 'Weekend turn Off time'
|
14
|
+
|
15
|
+
concerto_hardware:
|
16
|
+
players:
|
17
|
+
new:
|
18
|
+
header: 'New %{screen} Player'
|
19
|
+
edit:
|
20
|
+
header: 'Edit %{screen} Player'
|
21
|
+
|
22
|
+
screens:
|
23
|
+
screen_link:
|
24
|
+
concerto_player: "Concerto Player"
|
25
|
+
no_player_header: "No Player"
|
26
|
+
no_player_msg: "A Concerto Player has not yet been connected to this screen."
|
27
|
+
add_player_msg: "Specify a Player manually."
|
28
|
+
activated: "Activated"
|
29
|
+
not_activated: "Not Activated"
|
data/config/routes.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# The routing is configured such that it does its own routing.
|
2
|
+
# This means the central application will specifically mount
|
3
|
+
# the engine to make the routes available in a certain sub-url,
|
4
|
+
# for example one route would look like
|
5
|
+
# /hardware/players/new
|
6
|
+
ConcertoHardware::Engine.routes.draw do
|
7
|
+
# Just a test welcome page, we'll replace this with something
|
8
|
+
# more useful later.
|
9
|
+
root :to => proc { |env| [200, {}, ["Welcome to the hardware plugin!"]] }
|
10
|
+
|
11
|
+
# Since we have an isolated namespace, routes are automaticaly scoped
|
12
|
+
# to the ConcertoHardware module.
|
13
|
+
resources :players do
|
14
|
+
collection do
|
15
|
+
# Look up a player based on the screen ID.
|
16
|
+
match 'by_screen/:screen_id' => ConcertoHardware::PlayersController.action(:show)
|
17
|
+
# Show the player associated with the logged in screen.
|
18
|
+
match 'current' => ConcertoHardware::PlayersController.action(:show)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module ConcertoHardware
|
2
|
+
class Engine < ::Rails::Engine
|
3
|
+
# Isolated Namespace enforces healthy separation from the Concerto app.
|
4
|
+
# Nothing else should come before this call in this class.
|
5
|
+
isolate_namespace ConcertoHardware
|
6
|
+
|
7
|
+
# The engine name will be the name of the class
|
8
|
+
# that contains the URL helpers for our routes.
|
9
|
+
# This must come after isolate_namespace!
|
10
|
+
engine_name 'hardware'
|
11
|
+
|
12
|
+
# Define plugin information for the Concerto application to read.
|
13
|
+
# Do not modify @plugin_info outside of this static configuration block.
|
14
|
+
def plugin_info(plugin_info_class)
|
15
|
+
@plugin_info ||= plugin_info_class.new do
|
16
|
+
# Make the engine's controller accessible at /hardware
|
17
|
+
add_route("hardware", ConcertoHardware::Engine)
|
18
|
+
|
19
|
+
# Initialize configuration settings with a description and a default.
|
20
|
+
# Administrators can change the value through the Concerto dashboard.
|
21
|
+
add_config("poll_interval", "60",
|
22
|
+
:value_type => "integer",
|
23
|
+
:category => "System",
|
24
|
+
:seq_no => 999,
|
25
|
+
:description => "Client hardware polling interval in seconds")
|
26
|
+
|
27
|
+
# Some code to run at app boot
|
28
|
+
init do
|
29
|
+
Rails.logger.info "ConcertoHardware: Initialization code is running"
|
30
|
+
end
|
31
|
+
|
32
|
+
# The following hooks allow integration into the main Concerto app
|
33
|
+
# at the controller and view levels.
|
34
|
+
|
35
|
+
add_controller_hook "ScreensController", :show, :before do
|
36
|
+
@player = Player.find_by_screen_id(@screen.id)
|
37
|
+
end
|
38
|
+
|
39
|
+
add_controller_hook "ScreensController", :change, :before do
|
40
|
+
Rails.logger.info "concerto-hardware: screen change callback"
|
41
|
+
if @screen.auth_in_progress? # have a temp token to look at
|
42
|
+
if Player.where(:screen_id => @screen.id).count == 0 # No existing player
|
43
|
+
if ((@screen.temp_token.length > Screen::TEMP_TOKEN_LENGTH) and
|
44
|
+
(@screen.temp_token[Screen::TEMP_TOKEN_LENGTH].downcase == "s"))
|
45
|
+
# Okay, we have a legit player situation.
|
46
|
+
Rails.logger.info "concerto-hardware: creating Player for the new Screen!"
|
47
|
+
flash[:notice] ||= ""
|
48
|
+
player = Player.new
|
49
|
+
player.screen_id = @screen.id
|
50
|
+
player.activated = true
|
51
|
+
if player.save
|
52
|
+
Rails.logger.info " Success!"
|
53
|
+
#flash[:notice] << " A player hardware profile was automatically created!"
|
54
|
+
# TODO: User notification.
|
55
|
+
else
|
56
|
+
Rails.logger.info " Failed."
|
57
|
+
#flash[:notice] << " We could not create a player hardware profile, however."
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
add_view_hook "ScreensController", :screen_details, :partial => "concerto_hardware/screens/screen_link"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end # class Engine
|
68
|
+
end # module ConcertoHardware
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html
|
2
|
+
|
3
|
+
one:
|
4
|
+
secret: MyString
|
5
|
+
ip_address: MyString
|
6
|
+
screen_id: 1
|
7
|
+
activated: false
|
8
|
+
|
9
|
+
two:
|
10
|
+
secret: MyString
|
11
|
+
ip_address: MyString
|
12
|
+
screen_id: 1
|
13
|
+
activated: false
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class PlayersControllerTest < ActionController::TestCase
|
4
|
+
setup do
|
5
|
+
@player = players(:one)
|
6
|
+
end
|
7
|
+
|
8
|
+
test "should get index" do
|
9
|
+
get :index
|
10
|
+
assert_response :success
|
11
|
+
assert_not_nil assigns(:players)
|
12
|
+
end
|
13
|
+
|
14
|
+
test "should get new" do
|
15
|
+
get :new
|
16
|
+
assert_response :success
|
17
|
+
end
|
18
|
+
|
19
|
+
test "should create player" do
|
20
|
+
assert_difference('Player.count') do
|
21
|
+
post :create, player: @player.attributes
|
22
|
+
end
|
23
|
+
|
24
|
+
assert_redirected_to player_path(assigns(:player))
|
25
|
+
end
|
26
|
+
|
27
|
+
test "should show player" do
|
28
|
+
get :show, id: @player
|
29
|
+
assert_response :success
|
30
|
+
end
|
31
|
+
|
32
|
+
test "should get edit" do
|
33
|
+
get :edit, id: @player
|
34
|
+
assert_response :success
|
35
|
+
end
|
36
|
+
|
37
|
+
test "should update player" do
|
38
|
+
put :update, id: @player, player: @player.attributes
|
39
|
+
assert_redirected_to player_path(assigns(:player))
|
40
|
+
end
|
41
|
+
|
42
|
+
test "should destroy player" do
|
43
|
+
assert_difference('Player.count', -1) do
|
44
|
+
delete :destroy, id: @player
|
45
|
+
end
|
46
|
+
|
47
|
+
assert_redirected_to players_path
|
48
|
+
end
|
49
|
+
end
|
metadata
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: concerto_hardware
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.5
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Concerto Team
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-05-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 3.2.9
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 3.2.9
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: sqlite3
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: A Rails Engine for managing Bandshell-powered Concerto hardware
|
42
|
+
email:
|
43
|
+
- team@concerto-signage.org
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- app/assets/images/concerto_hardware/helpicon.png
|
49
|
+
- app/assets/javascripts/concerto_hardware/application.js
|
50
|
+
- app/assets/javascripts/concerto_hardware/players.js
|
51
|
+
- app/assets/stylesheets/concerto_hardware/application.css
|
52
|
+
- app/assets/stylesheets/concerto_hardware/players.css.scss
|
53
|
+
- app/assets/stylesheets/scaffolds.css.scss
|
54
|
+
- app/controllers/concerto_hardware/application_controller.rb
|
55
|
+
- app/controllers/concerto_hardware/players_controller.rb
|
56
|
+
- app/helpers/players_helper.rb
|
57
|
+
- app/models/concerto_hardware/ability.rb
|
58
|
+
- app/models/concerto_hardware/player.rb
|
59
|
+
- app/views/concerto_hardware/players/_form.html.erb
|
60
|
+
- app/views/concerto_hardware/players/_show_body.html.erb
|
61
|
+
- app/views/concerto_hardware/players/_show_header.html.erb
|
62
|
+
- app/views/concerto_hardware/players/edit.html.erb
|
63
|
+
- app/views/concerto_hardware/players/index.html.erb
|
64
|
+
- app/views/concerto_hardware/players/new.html.erb
|
65
|
+
- app/views/concerto_hardware/players/show.html.erb
|
66
|
+
- app/views/concerto_hardware/screens/_screen_link.html.erb
|
67
|
+
- config/locales/en.yml
|
68
|
+
- config/routes.rb
|
69
|
+
- db/migrate/20121220000000_create_concerto_hardware_players.rb
|
70
|
+
- db/migrate/20131127201048_add_updates_to_concerto_hardware_players.rb
|
71
|
+
- lib/concerto-hardware.rb
|
72
|
+
- lib/concerto_hardware/engine.rb
|
73
|
+
- lib/concerto_hardware/version.rb
|
74
|
+
- LICENSE
|
75
|
+
- Rakefile
|
76
|
+
- README.rdoc
|
77
|
+
- test/fixtures/players.yml
|
78
|
+
- test/functional/players_controller_test.rb
|
79
|
+
- test/unit/helpers/players_helper_test.rb
|
80
|
+
- test/unit/player_test.rb
|
81
|
+
homepage: http://concerto-signage.org
|
82
|
+
licenses:
|
83
|
+
- Apache-2.0
|
84
|
+
metadata: {}
|
85
|
+
post_install_message:
|
86
|
+
rdoc_options: []
|
87
|
+
require_paths:
|
88
|
+
- lib
|
89
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
requirements: []
|
100
|
+
rubyforge_project:
|
101
|
+
rubygems_version: 2.0.14
|
102
|
+
signing_key:
|
103
|
+
specification_version: 4
|
104
|
+
summary: A Rails Engine for managing Bandshell-powered Concerto hardware
|
105
|
+
test_files:
|
106
|
+
- test/fixtures/players.yml
|
107
|
+
- test/functional/players_controller_test.rb
|
108
|
+
- test/unit/helpers/players_helper_test.rb
|
109
|
+
- test/unit/player_test.rb
|