* VRFS-15: session crud in progress

This commit is contained in:
Seth Call 2012-10-02 19:54:29 -05:00
parent 216755d828
commit eb9f0d791c
25 changed files with 331 additions and 157 deletions

View File

@ -18,8 +18,10 @@ gem 'jam_db', :path => "#{workspace}/jam-db/target/ruby_package"
gem 'jam_ruby', :path => "#{workspace}/jam-ruby"
gem 'jampb', :path => "#{workspace}/jam-pb/target/ruby/jampb"
gem 'pg', '0.14.0'
gem 'gon'
gem 'compass-rails'
gem 'rabl' # for JSON API development
gem 'gon' # for passthrough of Ruby variables to Javascript variables
group :development, :test do
gem 'rspec-rails', '2.11.0'
@ -42,6 +44,7 @@ group :test do
gem 'guard-spork', '0.3.2'
gem 'spork', '0.9.0'
gem 'launchy', '2.1.0'
gem 'rack-test'
# gem 'rb-fsevent', '0.9.1', :require => false
# gem 'growl', '1.0.3'
end

View File

@ -141,6 +141,9 @@ GEM
pg (= 0.14.0)
thor (= 0.15.4)
polyglot (0.3.3)
rabl (0.7.2)
activesupport (>= 2.3.14)
multi_json (~> 1.0)
rack (1.4.1)
rack-cache (1.2)
rack (>= 0.4)
@ -239,6 +242,8 @@ DEPENDENCIES
launchy (= 2.1.0)
pg (= 0.14.0)
pg_migrate (= 0.1.5)
rabl
rack-test
rails (= 3.2.8)
rspec-rails (= 2.11.0)
ruby-protocol-buffers (= 1.2.2)

View File

@ -51,7 +51,7 @@
if(msg.type == LOGIN_ACK) {
// we are in... sign in to jam session
var login_jam = mf.login_jam_session(gon.jam_session_id)
var login_jam = mf.login_music_session(gon.music_session_id)
send(login_jam)
}
};

View File

@ -10,11 +10,11 @@
LOGIN = "LOGIN"
LOGIN_ACK = "LOGIN_ACK"
LOGIN_JAM_SESSION = "LOGIN_JAM_SESSION"
LOGIN_JAM_SESSION_ACK = "LOGIN_JAM_SESSION_ACK"
USER_JOINED_JAM_SESSION = "USER_JOINED_JAM_SESSION"
LEAVE_JAM_SESSION = "LEAVE_JAM_SESSION"
LEAVE_JAM_SESSION_ACK = "LEAVE_JAM_SESSION_ACK"
LOGIN_MUSIC_SESSION = "LOGIN_MUSIC_SESSION"
LOGIN_MUSIC_SESSION_ACK = "LOGIN_MUSIC_SESSION_ACK"
USER_JOINED_MUSIC_SESSION = "USER_JOINED_MUSIC_SESSION"
LEAVE_MUSIC_SESSION = "LEAVE_MUSIC_SESSION"
LEAVE_MUSIC_SESSION_ACK = "LEAVE_MUSIC_SESSION_ACK"
HEARTBEAT = "HEARTBEAT"
TEST_SESSION_MESSAGE = "TEST_SESSION_MESSAGE"
@ -42,10 +42,10 @@
return client_container(LOGIN, SERVER_TARGET, login)
}
// create a jam session login message
message_factory.login_jam_session = function(jam_session) {
login_jam_session = { jam_session : jam_session }
return client_container(LOGIN_JAM_SESSION, SERVER_TARGET, login_jam_session)
// create a music session login message
message_factory.login_music_session = function(music_session) {
login_music_session = { music_session : music_session }
return client_container(LOGIN_MUSIC_SESSION, SERVER_TARGET, login_music_session)
}
window.message_factory = message_factory

View File

@ -5,7 +5,7 @@
* <![endif]--> */
@import "compass/css3/images";
@import "common.css.scss";
@import "client/common.css.scss";
/* Gradients in IE work with filter-gradient, but mess up event handling.
* Using solid colors via background-color for now.

View File

@ -8,7 +8,7 @@
@import "compass/css3/images";
@import "compass/css3/background-size";
@import "common.css.scss";
@import "client/common.css.scss";
body {
color: $text;

View File

@ -0,0 +1,117 @@
@font-face {
font-family: 'LatoBlackItalic';
src: url('<%= asset_path('lato/Lato-BlaIta-webfont.eot') %>');
src: url('<%= asset_path('lato/Lato-BlaIta-webfont.eot?#iefix') %>') format('embedded-opentype'),
url('<%= asset_path('lato/Lato-BlaIta-webfont.woff') %>') format('woff'),
url('<%= asset_path('lato/Lato-BlaIta-webfont.ttf') %>') format('truetype'),
url('<%= asset_path('lato/Lato-BlaIta-webfont.svg#LatoBlackItalic') %>') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'LatoBlack';
src: url('<%= asset_path('lato/Lato-Bla-webfont.eot') %>');
src: url('<%= asset_path('lato/Lato-Bla-webfont.eot?#iefix') %>') format('embedded-opentype'),
url('<%= asset_path('lato/Lato-Bla-webfont.woff') %>') format('woff'),
url('<%= asset_path('lato/Lato-Bla-webfont.ttf') %>') format('truetype'),
url('<%= asset_path('lato/Lato-Bla-webfont.svg#LatoBlack') %>') format('svg');
font-weight: normal;
font-style: normal;
}
/**
@font-face {
font-family: 'LatoBoldItalic';
src: url('<%= asset_path('lato/Lato-BolIta-webfont.eot') %>');
src: url('<%= asset_path('lato/Lato-BolIta-webfont.eot?#iefix') %>') format('embedded-opentype'),
url('<%= asset_path('lato/Lato-BolIta-webfont.woff') %>') format('woff'),
url('<%= asset_path('lato/Lato-BolIta-webfont.ttf') %>') format('truetype'),
url('<%= asset_path('lato/Lato-BolIta-webfont.svg#LatoBoldItalic') %>') format('svg');
font-weight: normal;
font-style: normal;
}
*/
@font-face {
font-family: 'LatoBold';
src: url('<%= asset_path('lato/Lato-Bol-webfont.eot') %>');
src: url('<%= asset_path('lato/Lato-Bol-webfont.eot?#iefix') %>') format('embedded-opentype'),
url('<%= asset_path('lato/Lato-Bol-webfont.woff') %>') format('woff'),
url('<%= asset_path('lato/Lato-Bol-webfont.ttf') %>') format('truetype'),
url('<%= asset_path('lato/Lato-Bol-webfont.svg#LatoBold') %>') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'LatoItalic';
src: url('<%= asset_path('lato/Lato-RegIta-webfont.eot') %>');
src: url('<%= asset_path('lato/Lato-RegIta-webfont.eot?#iefix') %>') format('embedded-opentype'),
url('<%= asset_path('lato/Lato-RegIta-webfont.woff') %>') format('woff'),
url('<%= asset_path('lato/Lato-RegIta-webfont.ttf') %>') format('truetype'),
url('<%= asset_path('lato/Lato-RegIta-webfont.svg#LatoItalic') %>') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'LatoRegular';
src: url('<%= asset_path('lato/Lato-Reg-webfont.eot') %>');
src: url('<%= asset_path('lato/Lato-Reg-webfont.eot?#iefix') %>') format('embedded-opentype'),
url('<%= asset_path('lato/Lato-Reg-webfont.woff') %>') format('woff'),
url('<%= asset_path('lato/Lato-Reg-webfont.ttf') %>') format('truetype'),
url('<%= asset_path('lato/Lato-Reg-webfont.svg#LatoRegular') %>') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'LatoLightItalic';
src: url('<%= asset_path('lato/Lato-LigIta-webfont.eot') %>');
src: url('<%= asset_path('lato/Lato-LigIta-webfont.eot?#iefix') %>') format('embedded-opentype'),
url('<%= asset_path('lato/Lato-LigIta-webfont.woff') %>') format('woff'),
url('<%= asset_path('lato/Lato-LigIta-webfont.ttf') %>') format('truetype'),
url('<%= asset_path('lato/Lato-LigIta-webfont.svg#LatoLightItalic') %>') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'LatoLight';
src: url('<%= asset_path('lato/Lato-Lig-webfont.eot') %>');
src: url('<%= asset_path('lato/Lato-Lig-webfont.eot?#iefix') %>') format('embedded-opentype'),
url('<%= asset_path('lato/Lato-Lig-webfont.woff') %>') format('woff'),
url('<%= asset_path('lato/Lato-Lig-webfont.ttf') %>') format('truetype'),
url('<%= asset_path('lato/Lato-Lig-webfont.svg#LatoLight') %>') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'LatoHairlineItalic';
src: url('<%= asset_path('lato/Lato-HaiIta-webfont.eot') %>');
src: url('<%= asset_path('lato/Lato-HaiIta-webfont.eot?#iefix') %>') format('embedded-opentype'),
url('<%= asset_path('lato/Lato-HaiIta-webfont.woff') %>') format('woff'),
url('<%= asset_path('lato/Lato-HaiIta-webfont.ttf') %>') format('truetype'),
url('<%= asset_path('lato/Lato-HaiIta-webfont.svg#LatoHairlineItalic') %>') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'LatoHairline';
src: url('<%= asset_path('lato/Lato-Hai-webfont.eot') %>');
src: url('<%= asset_path('lato/Lato-Hai-webfont.eot?#iefix') %>') format('embedded-opentype'),
url('<%= asset_path('lato/Lato-Hai-webfont.woff') %>') format('woff'),
url('<%= asset_path('lato/Lato-Hai-webfont.ttf') %>') format('truetype'),
url('<%= asset_path('lato/Lato-Hai-webfont.svg#LatoHairline') %>') format('svg');
font-weight: normal;
font-style: normal;
}

View File

@ -1,47 +0,0 @@
class JamSessionsController < ApplicationController
# have to be signed in currently to see this screen
before_filter :signed_in_user
def index
@jam_sessions = JamSession.paginate(page: params[:page])
end
def show
@jam_session = JamSession.find(params[:id])
# use gon to pass variables into javascript
gon.websocket_gateway_uri = Rails.application.config.websocket_gateway_uri
gon.jam_session_id = @jam_session.id
end
def new
@jam_session = JamSession.new
end
def create
@jam_session = JamSession.new()
@jam_session.creator = current_user
@jam_session.name = params[:jam_ruby_jam_session][:name]
if @jam_session.save
flash[:success] = "Jam Session created"
redirect_to @jam_session
else
render 'new'
end
end
def edit
end
def update
end
def destroy
JamSession.find(params[:id]).destroy
flash[:success] = "Jam Session deleted."
redirect_to jam_sessions_url
end
end

View File

@ -0,0 +1,72 @@
class MusicSessionsController < ApplicationController
# have to be signed in currently to see this screen
before_filter :signed_in_user
respond_to :html, :xml, :json
def api_index
@music_sessions = MusicSession.paginate(page: params[:page])
end
def api_create
@music_session = MusicSession.new()
@music_session.creator = current_user
@music_session.description = params[:description]
@music_session.save
respond_with @music_session, responder: ApiResponder, :location => api_session_detail_url(@music_session)
end
def api_show
@music_session = MusicSession.find(params[:id])
end
def api_member_create
@music_session = MusicSession.find(params[:id])
MusicSessionClient.ip_address = params[:ip_address]
end
def index
@music_sessions = MusicSession.paginate(page: params[:page])
end
def show
# use gon to pass variables into javascript
gon.websocket_gateway_uri = Rails.application.config.websocket_gateway_uri
gon.music_session_id = @music_session.id
end
def new
@music_session = MusicSession.new
end
def create
@music_session = MusicSession.new()
@music_session.creator = current_user
@music_session.description = params[:jam_ruby_music_session][:description]
if @music_session.save
flash[:success] = "Music Session created"
redirect_to @music_session
else
render 'new'
end
end
def edit
end
def update
end
def destroy
MusicSession.find(params[:id]).destroy
flash[:success] = "Jam Session deleted."
redirect_to music_sessions_url
end
end

View File

@ -8,7 +8,7 @@ class SessionsController < ApplicationController
user = User.find_by_email(params[:session][:email])
if user && user.authenticate(params[:session][:password])
sign_in user
redirect_back_or jam_sessions_url
redirect_back_or music_sessions_url
else
flash.now[:error] = 'Invalid email/password combination'
render 'new'

View File

@ -0,0 +1,14 @@
class ApiResponder < ActionController::Responder
def to_format
case
when has_errors?
controller.response.status = :unprocessable_entity
when post?
controller.response.status = :created
end
default_render
rescue ActionView::MissingTemplate => e
api_behavior(e)
end
end

View File

@ -1,7 +0,0 @@
<li>
<%= link_to jam_session.name, jam_session %>
<% if jam_session.creator == current_user || current_user.admin %>
| <%= link_to "delete", jam_session, method: :delete,
data: { confirm: "You sure?" } %>
<% end %>
</li>

View File

@ -0,0 +1,7 @@
<li>
<%= link_to music_session.name, music_session %>
<% if music_session.creator == current_user || current_user.admin %>
| <%= link_to "delete", music_session, method: :delete,
data: { confirm: "You sure?" } %>
<% end %>
</li>

View File

@ -1,19 +0,0 @@
<% provide(:title, 'New Jam Session') %>
<h1>New Jam Session</h1>
<div class="row">
<div class="span6 offset3">
<%= form_for(@jam_session) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label :name %>
<%= f.text_field :name %>
<!-- doesn't make sense to allow private sessions until we have friend lists
<%= f.label :public %>
<%= f.check_box :public %>
-->
<%= f.submit "Create new Jam Session", class: "btn btn-large btn-primary" %>
<% end %>
</div>
</div>

View File

@ -8,7 +8,7 @@
<li><%= link_to "Home", root_path %></li>
<li><%= link_to "Help", help_path %></li>
<% if signed_in? %>
<li><%= link_to "Jam Sessions", jam_sessions_url %></li>
<li><%= link_to "Music Sessions", music_sessions_url %></li>
<li><%= link_to "Users", users_path %></li>
<li id="fat-menu" class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">

View File

@ -5,10 +5,10 @@
<!--[if IE]>
<link rel="stylesheet" type="text/css" href="css/ie.css" media="screen, projection"/>
<![endif]-->
<%= stylesheet_link_tag "common", media: "all" %>
<%= stylesheet_link_tag "ie", media: "all" %>
<%= stylesheet_link_tag "jamkazam", media: "all" %>
<%= stylesheet_link_tag "lato", media: "all" %>
<%= stylesheet_link_tag "client/common", media: "all" %>
<%= stylesheet_link_tag "client/ie", media: "all" %>
<%= stylesheet_link_tag "client/jamkazam", media: "all" %>
<%= stylesheet_link_tag "client/lato", media: "all" %>
<%= include_gon %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>

View File

@ -0,0 +1,3 @@
object @music_sessions
extends "music_sessions/api_show"

View File

@ -0,0 +1,8 @@
object @music_session
attributes :id, :description
child(:music_session_clients => :musicians) {
collection @music_sessions, :object_root => false
attributes :id, :ip_address
}

View File

@ -3,11 +3,11 @@
<%= will_paginate %>
<ul class="Jam Sessions">
<%= render @jam_sessions %>
<ul class="Music Sessions">
<%= render @music_sessions %>
</ul>
<%= link_to "Create Jam Session", new_jam_session_path,
<%= link_to "Create Music Session", new_music_session_path,
class: "btn btn-large btn-primary" %>
<%= will_paginate %>

View File

@ -0,0 +1,13 @@
<% provide(:title, 'New Jam Session') %>
<h1>New Jam Session</h1>
<div class="row">
<div class="span6 offset3">
<%= form_for(@music_session) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label :description %>
<%= f.text_field :description %>
<%= f.submit "Create new Music Session", class: "btn btn-large btn-primary" %>
<% end %>
</div>
</div>

View File

@ -1,15 +1,13 @@
<% provide(:title, "Now Playing: #{@jam_session.name}") %>
<% provide(:title, "Now Playing: #{@music_session.description}") %>
<div class="row">
<aside class="span4">
<section>
<h1>
<%= "Now Playing: #{@jam_session.name}" %>
<%= "Now Playing: #{@music_session.description}" %>
</h1>
</section>
</aside>
<div class="span8">
<h2>This Jam Session is public: <%= @jam_session.public %></h2>
<h3>Internal Session Activity</h3>
<div id="internal_session_activity">
<p>Wait a moment... </p>

View File

@ -0,0 +1,20 @@
Rabl.configure do |config|
# Commented as these are defaults
# config.cache_all_output = false
# config.cache_sources = Rails.env != 'development' # Defaults to false
# config.cache_engine = Rabl::CacheEngine.new # Defaults to Rails cache
# config.escape_all_output = false
# config.json_engine = nil # Any multi_json engines or a Class with #encode method
# config.msgpack_engine = nil # Defaults to ::MessagePack
# config.bson_engine = nil # Defaults to ::BSON
# config.plist_engine = nil # Defaults to ::Plist::Emit
config.include_json_root = false
# config.include_msgpack_root = true
# config.include_bson_root = true
# config.include_plist_root = true
# config.include_xml_root = false
# config.include_child_root = true
# config.enable_json_callbacks = false
# config.xml_options = { :dasherize => true, :skip_types => false }
# config.view_paths = []
end

View File

@ -2,11 +2,11 @@ SampleApp::Application.routes.draw do
scope :as => 'jam_ruby' do
resources :users
resources :jam_sessions
resources :music_sessions
end
resources :users
resources :jam_sessions
resources :music_sessions
resources :sessions, only: [:new, :create, :destroy]
@ -22,60 +22,9 @@ SampleApp::Application.routes.draw do
match '/client', to: 'clients#index'
# The priority is based upon order of creation:
# first created -> highest priority.
# Sample of regular route:
# match 'products/:id' => 'catalog#view'
# Keep in mind you can assign values other than :controller and :action
# Sample of named route:
# match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase
# This route can be invoked with purchase_url(:id => product.id)
# Sample resource route (maps HTTP verbs to controller actions automatically):
# resources :products
# Sample resource route with options:
# resources :products do
# member do
# get 'short'
# post 'toggle'
# end
#
# collection do
# get 'sold'
# end
# end
# Sample resource route with sub-resources:
# resources :products do
# resources :comments, :sales
# resource :seller
# end
# Sample resource route with more complex sub-resources
# resources :products do
# resources :comments
# resources :sales do
# get 'recent', :on => :collection
# end
# end
# Sample resource route within a namespace:
# namespace :admin do
# # Directs /admin/products/* to Admin::ProductsController
# # (app/controllers/admin/products_controller.rb)
# resources :products
# end
# You can have the root of your site routed with "root"
# just remember to delete public/index.html.
# root :to => 'welcome#index'
# See how all your routes lay out with "rake routes"
# This is a legacy wild controller route that's not recommended for RESTful applications.
# Note: This route will make all actions in every controller accessible via GET requests.
# match ':controller(/:action(/:id))(.:format)'
scope '/api' do
match '/sessions/:id' => 'music_sessions#api_show', :via => :get, :as => 'api_session_detail'
match '/sessions' => 'music_sessions#api_index', :via => :get
match '/sessions' => 'music_sessions#api_create', :via => :post
end
end

View File

@ -0,0 +1,38 @@
require 'spec_helper'
describe "Music Session API ", :type => :api do
include Rack::Test::Methods
subject { page }
describe "profile page" do
let(:user) { FactoryGirl.create(:user) }
before do 2
#sign_in user
post '/sessions', "session[email]" => user.email, "session[password]" => user.password
rack_mock_session.cookie_jar["remember_token"].should == user.remember_token
end
it "should list no sessions" do
get '/api/sessions.json'
last_response.body.should eql('[]')
end
it "should create session" do
# create the session
post '/api/sessions.json', '{"description" : "a session"}', "CONTENT_TYPE" => 'application/json'
last_response.status.should eql(201)
# now fetch it's data
get last_response.headers["Location"]
music_session = JSON.parse(last_response.body)
get '/api/sessions.json'
list = JSON.parse(last_response.body)
list[0]["id"].should == music_session["id"]
end
end
end