concerto_hardware 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|