Merge branch 'feature/scheduled_sessions' of https://bitbucket.org/jamkazam/jam-cloud into feature/scheduled_sessions
This commit is contained in:
commit
88a7ba197a
|
|
@ -0,0 +1,62 @@
|
|||
-- DROP FUNCTION IF EXISTS ams_index (my_user_id VARCHAR, my_locidispid BIGINT, my_audio_latency INTEGER, poff INTEGER, plim INTEGER);
|
||||
CREATE OR REPLACE FUNCTION ams_index (my_user_id VARCHAR, my_locidispid BIGINT, my_audio_latency INTEGER)
|
||||
RETURNS VOID
|
||||
LANGUAGE plpgsql
|
||||
STRICT
|
||||
VOLATILE
|
||||
AS $$
|
||||
BEGIN
|
||||
-- output table to hold tagged music sessions with latency
|
||||
CREATE TEMPORARY TABLE ams_music_session_tmp (music_session_id VARCHAR(64) NOT NULL, tag INTEGER, latency INTEGER) ON COMMIT DROP;
|
||||
|
||||
-- populate ams_music_session_tmp as all music sessions
|
||||
INSERT INTO ams_music_session_tmp SELECT DISTINCT id, NULL::INTEGER AS tag, NULL::INTEGER AS latency
|
||||
FROM active_music_sessions;
|
||||
|
||||
-- TODO worry about active music session where my_user_id is the creator?
|
||||
-- eh, maybe, but if the music session is active and you're the creator wouldn't you already be in it?
|
||||
-- so maybe you're on another computer, so why care? plus seth is talking about auto rsvp'ing the session
|
||||
-- for you, so maybe not a problem.
|
||||
|
||||
-- tag accepted rsvp as 1
|
||||
UPDATE ams_music_session_tmp q SET tag = 1 FROM rsvp_slots s, rsvp_requests_rsvp_slots rrs, rsvp_requests r WHERE
|
||||
q.music_session_id = s.music_session_id AND
|
||||
s.id = rrs.rsvp_slot_id AND
|
||||
rrs.rsvp_request_id = r.id AND
|
||||
r.user_id = my_user_id AND
|
||||
rrs.chosen = TRUE AND
|
||||
q.tag is NULL;
|
||||
|
||||
-- tag invitation as 2
|
||||
UPDATE ams_music_session_tmp q SET tag = 2 FROM invitations i WHERE
|
||||
q.music_session_id = i.music_session_id AND
|
||||
i.receiver_id = my_user_id AND
|
||||
q.tag IS NULL;
|
||||
|
||||
-- musician access as 3
|
||||
UPDATE ams_music_session_tmp q SET tag = 3 FROM music_sessions m WHERE
|
||||
q.music_session_id = m.id AND
|
||||
m.musician_access = TRUE AND
|
||||
q.tag IS NULL;
|
||||
|
||||
-- delete anything not tagged
|
||||
DELETE FROM ams_music_session_tmp WHERE tag IS NULL;
|
||||
|
||||
-- output table to hold users involved in the ams_music_session_tmp sessions and their latency
|
||||
CREATE TEMPORARY TABLE ams_users_tmp (music_session_id VARCHAR(64) NOT NULL, user_id VARCHAR(64) NOT NULL, latency INTEGER NOT NULL) ON COMMIT DROP;
|
||||
|
||||
-- populate ams_users_tmp as all musicians in the ams_music_session_tmp sessions with audio latency and score
|
||||
INSERT INTO ams_users_tmp SELECT c.music_session_id, c.user_id, (s.score+my_audio_latency+c.last_jam_audio_latency)/2 AS latency
|
||||
FROM ams_music_session_tmp q, connections c, current_scores s WHERE
|
||||
q.music_session_id = c.music_session_id AND
|
||||
c.locidispid = s.alocidispid AND
|
||||
s.blocidispid = my_locidispid AND
|
||||
c.last_jam_audio_latency IS NOT NULL;
|
||||
|
||||
-- calculate the average latency
|
||||
UPDATE ams_music_session_tmp q SET latency = (select AVG(u.latency) FROM ams_users_tmp u WHERE
|
||||
q.music_session_id = u.music_session_id);
|
||||
|
||||
RETURN;
|
||||
END;
|
||||
$$;
|
||||
|
|
@ -314,6 +314,85 @@ module JamRuby
|
|||
return query
|
||||
end
|
||||
|
||||
# Generate a list of music sessions (that are active) filtered by genre, language, keyword, and sorted
|
||||
# (and tagged) by rsvp'd (1st), invited (2nd), and musician can join (3rd). within a group
|
||||
# tagged the same, sorted by score. date seems irrelevant as these are active sessions.
|
||||
def self.ams_index(current_user, options = {})
|
||||
client_id = options[:client_id]
|
||||
genre = options[:genre]
|
||||
lang = options[:lang]
|
||||
keyword = options[:keyword]
|
||||
offset = options[:offset]
|
||||
limit = options[:limit]
|
||||
|
||||
connection = Connection.where(user_id: current_user.id, client_id: client_id).first!
|
||||
my_locidispid = connection.locidispid
|
||||
my_audio_latency = connection.last_jam_audio_latency
|
||||
|
||||
query = MusicSession
|
||||
.select('music_sessions.*')
|
||||
|
||||
# TODO this is not really needed when ams_music_session_tmp is joined
|
||||
# unless there is something specific we need out of active_music_sessions
|
||||
query = query.joins(
|
||||
%Q{
|
||||
INNER JOIN
|
||||
active_music_sessions
|
||||
ON
|
||||
active_music_sessions.id = music_sessions.id
|
||||
}
|
||||
)
|
||||
.select('1::integer as tag, 15::integer as latency')
|
||||
|
||||
# TODO integrate ams_music_session_tmp into the processing
|
||||
# then we can join ams_music_session_tmp and not join active_music_sessions
|
||||
# query = query.joins(
|
||||
# %Q{
|
||||
# INNER JOIN
|
||||
# ams_music_session_tmp
|
||||
# ON
|
||||
# ams_music_session_tmp.music_session_id = active_music_sessions.id
|
||||
# }
|
||||
# )
|
||||
# .select('ams_music_session_tmp.tag, ams_music_session_tmp.latency')
|
||||
|
||||
query = query.order(
|
||||
%Q{
|
||||
tag, latency, music_sessions.id
|
||||
}
|
||||
)
|
||||
.group(
|
||||
%Q{
|
||||
tag, latency, music_sessions.id
|
||||
}
|
||||
)
|
||||
|
||||
if (offset)
|
||||
query = query.offset(offset)
|
||||
end
|
||||
|
||||
if (limit)
|
||||
query = query.limit(limit)
|
||||
end
|
||||
|
||||
# cleanse keyword so it is only word characters. ignore if less than 3 characters long or greater than 100
|
||||
# TODO do we want to force match of whole words only? this matches any substring...
|
||||
# TODO do we want to match more than one word in the phrase? this matches only the first word...
|
||||
|
||||
unless keyword.nil? or keyword.length < 3 or keyword.length > 100
|
||||
w = keyword.split(/\W+/)
|
||||
if w.length > 0 and w.length >= 3
|
||||
query = query.where("music_sessions.description like '%#{w[0]}%'")
|
||||
end
|
||||
end
|
||||
|
||||
query = query.where("music_sessions.genre_id = ?", genre) unless genre.nil?
|
||||
|
||||
# TODO filter by lang
|
||||
|
||||
return query
|
||||
end
|
||||
|
||||
def self.participant_create user, music_session_id, client_id, as_musician, tracks
|
||||
music_session = MusicSession.find(music_session_id)
|
||||
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ module JamRuby
|
|||
raise StateError, "Slot does not exist"
|
||||
end
|
||||
|
||||
if rsvp_slot.chosen
|
||||
if rsvp_slot.chosen && r[:accept]
|
||||
raise StateError, "The #{rsvp_slot.instrument_id} slot has already been approved for another user."
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -332,6 +332,36 @@ describe ActiveMusicSession do
|
|||
end
|
||||
end
|
||||
|
||||
describe "ams_index" do
|
||||
it "does not crash" do
|
||||
|
||||
creator = FactoryGirl.create(:user)
|
||||
creator2 = FactoryGirl.create(:user)
|
||||
|
||||
earlier_session = FactoryGirl.create(:active_music_session, :creator => creator, :description => "Earlier Session")
|
||||
c1 = FactoryGirl.create(:connection, user: creator, music_session: earlier_session, addr: 0x01020304, locidispid: 1)
|
||||
|
||||
later_session = FactoryGirl.create(:active_music_session, :creator => creator2, :description => "Later Session")
|
||||
c2 = FactoryGirl.create(:connection, user: creator2, music_session: later_session, addr: 0x21020304, locidispid: 2)
|
||||
|
||||
user = FactoryGirl.create(:user)
|
||||
c3 = FactoryGirl.create(:connection, user: user, locidispid: 3)
|
||||
|
||||
Score.createx(c1.locidispid, c1.client_id, c1.addr, c3.locidispid, c3.client_id, c3.addr, 20, nil);
|
||||
Score.createx(c2.locidispid, c2.client_id, c2.addr, c3.locidispid, c3.client_id, c3.addr, 30, nil);
|
||||
|
||||
music_sessions = ActiveMusicSession.ams_index(user, client_id: c3.client_id).take(100)
|
||||
music_sessions.should_not be_nil
|
||||
music_sessions.length.should == 2
|
||||
end
|
||||
|
||||
# todo we need more tests:
|
||||
# rsvp'd user (chosen and not chosen)
|
||||
# invited user
|
||||
# creator (who should be automatically rsvp'd)
|
||||
# musician_access and not
|
||||
end
|
||||
|
||||
|
||||
it 'uninvited users cant join approval-required sessions without invitation' do
|
||||
user1 = FactoryGirl.create(:user) # in the jam session
|
||||
|
|
|
|||
|
|
@ -83,18 +83,33 @@
|
|||
rest.getRsvpRequests(musicSessionId)
|
||||
.done(function(rsvps) {
|
||||
if (rsvps && rsvps.length > 0) {
|
||||
// should only be 1 RSVP for this session
|
||||
// should only be 1 RSVP for this session and user
|
||||
var rsvp = rsvps[0];
|
||||
if (rsvp.canceled) {
|
||||
$('.call-to-action').html('Your RSVP request to this session has been cancelled.');
|
||||
$btnAction.hide();
|
||||
}
|
||||
else {
|
||||
$('.call-to-action').html('Tell the session organizer if you can no longer join this session');
|
||||
$btnAction.html('CANCEL RSVP');
|
||||
$btnAction.click(function(e) {
|
||||
ui.launchRsvpCancelDialog(musicSessionId, rsvp.id);
|
||||
});
|
||||
var declined = true;
|
||||
if (rsvp.rsvp_requests_rsvp_slots) {
|
||||
for (var x=0; x < rsvp.rsvp_requests_rsvp_slots.length; x++) {
|
||||
if (rsvp.rsvp_requests_rsvp_slots[x].chosen) {
|
||||
declined = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (declined) {
|
||||
$('.call-to-action').html('Your RSVP request to this session has been declined.');
|
||||
$btnAction.hide();
|
||||
}
|
||||
else {
|
||||
$('.call-to-action').html('Tell the session organizer if you can no longer join this session');
|
||||
$btnAction.html('CANCEL RSVP');
|
||||
$btnAction.click(function(e) {
|
||||
ui.launchRsvpCancelDialog(musicSessionId, rsvp.id);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
// no RSVP
|
||||
|
|
|
|||
|
|
@ -60,6 +60,21 @@ class ApiMusicSessionsController < ApiController
|
|||
limit: params[:limit])
|
||||
end
|
||||
|
||||
def ams_index
|
||||
# returns a relation which will produce a list of music_sessions which are active and augmented with attributes
|
||||
# tag and latency, then sorted by tag, latency, and finally music_sessions.id (for stability). the list is
|
||||
# filtered by genre, lang, and keyword, then paged by offset and limit (those are record numbers not page numbers).
|
||||
# tag is 1 for chosen rsvp'd sessions, 2 for invited sessions, 3 for all others (musician_access). if you're the
|
||||
# creator of a session it will be treated the same as if you had rsvp'd and been accepted.
|
||||
@music_sessions = ActiveMusicSession.ams_index(current_user,
|
||||
client_id: params[:client_id],
|
||||
genre: params[:genre],
|
||||
lang: params[:lang],
|
||||
keyword: params[:keyword],
|
||||
offset: params[:offset],
|
||||
limit: params[:limit])
|
||||
end
|
||||
|
||||
def scheduled
|
||||
@music_sessions = MusicSession.scheduled(current_user)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
object @rsvp_request
|
||||
|
||||
attributes :id, :canceled, :created_at
|
||||
attributes :id, :canceled, :cancel_all, :created_at
|
||||
|
||||
child(:user => :user) {
|
||||
attributes :id, :name, :photo_url
|
||||
}
|
||||
|
||||
child(:rsvp_slots => :rsvp_slots) {
|
||||
attributes :id, :instrument_id, :proficiency_level, :music_session_id
|
||||
child(:rsvp_requests_rsvp_slots => :rsvp_requests_rsvp_slots) {
|
||||
attributes :id, :chosen
|
||||
|
||||
child(:rsvp_requests_rsvp_slots => :rsvp_requests_rsvp_slots) {
|
||||
attributes :id, :chosen
|
||||
child(:rsvp_slot => :rsvp_slot) {
|
||||
attributes :id, :instrument_id, :proficiency_level, :music_session_id
|
||||
}
|
||||
}
|
||||
|
|
@ -12,8 +12,11 @@ describe "Session Info", :js => true, :type => :feature, :capybara_feature => tr
|
|||
MusicSession.delete_all
|
||||
User.delete_all
|
||||
|
||||
@rsvp_user = FactoryGirl.create(:user)
|
||||
@rsvp_user.save
|
||||
@rsvp_approved_user = FactoryGirl.create(:user)
|
||||
@rsvp_approved_user.save
|
||||
|
||||
@rsvp_declined_user = FactoryGirl.create(:user)
|
||||
@rsvp_declined_user.save
|
||||
|
||||
@session_invitee = FactoryGirl.create(:user)
|
||||
@session_invitee.save
|
||||
|
|
@ -28,12 +31,17 @@ describe "Session Info", :js => true, :type => :feature, :capybara_feature => tr
|
|||
FactoryGirl.create(:friendship, :user => @session_invitee, :friend => @session_creator)
|
||||
FactoryGirl.create(:friendship, :user => @session_creator, :friend => @session_invitee)
|
||||
|
||||
FactoryGirl.create(:friendship, :user => @rsvp_user, :friend => @session_creator)
|
||||
FactoryGirl.create(:friendship, :user => @session_creator, :friend => @rsvp_user)
|
||||
FactoryGirl.create(:friendship, :user => @rsvp_approved_user, :friend => @session_creator)
|
||||
FactoryGirl.create(:friendship, :user => @session_creator, :friend => @rsvp_approved_user)
|
||||
|
||||
@music_session = FactoryGirl.build(:music_session, :creator => @session_creator)
|
||||
FactoryGirl.create(:friendship, :user => @rsvp_declined_user, :friend => @session_creator)
|
||||
FactoryGirl.create(:friendship, :user => @session_creator, :friend => @rsvp_declined_user)
|
||||
|
||||
@music_session = FactoryGirl.build(:music_session, :creator => @session_creator, :scheduled_start => Time.now.utc + 2.days)
|
||||
@music_session.save
|
||||
|
||||
@url = "/sessions/#{@music_session.id}/details"
|
||||
|
||||
@slot1 = FactoryGirl.build(:rsvp_slot, :music_session => @music_session, :instrument => JamRuby::Instrument.find('electric guitar'))
|
||||
@slot1.save
|
||||
|
||||
|
|
@ -43,17 +51,27 @@ describe "Session Info", :js => true, :type => :feature, :capybara_feature => tr
|
|||
@invitation = FactoryGirl.build(:invitation, :sender => @session_creator, :receiver => @session_invitee, :music_session => @music_session)
|
||||
@invitation.save
|
||||
|
||||
@invitation = FactoryGirl.build(:invitation, :sender => @session_creator, :receiver => @rsvp_user, :music_session => @music_session)
|
||||
@invitation = FactoryGirl.build(:invitation, :sender => @session_creator, :receiver => @rsvp_approved_user, :music_session => @music_session)
|
||||
@invitation.save
|
||||
|
||||
# create RSVP request
|
||||
rsvp = RsvpRequest.create({:session_id => @music_session.id, :rsvp_slots => [@slot1.id, @slot2.id], :message => "Let's Jam!"}, @rsvp_user)
|
||||
@invitation = FactoryGirl.build(:invitation, :sender => @session_creator, :receiver => @rsvp_declined_user, :music_session => @music_session)
|
||||
@invitation.save
|
||||
|
||||
# create RSVP request 1
|
||||
@rsvp1 = RsvpRequest.create({:session_id => @music_session.id, :rsvp_slots => [@slot1.id, @slot2.id], :message => "Let's Jam!"}, @rsvp_approved_user)
|
||||
|
||||
# create RSVP request 2
|
||||
@rsvp2 = RsvpRequest.create({:session_id => @music_session.id, :rsvp_slots => [@slot1.id, @slot2.id], :message => "Let's Jam!"}, @rsvp_declined_user)
|
||||
|
||||
# approve slot1
|
||||
rs1 = RsvpRequestRsvpSlot.find_by_rsvp_slot_id(@slot1.id)
|
||||
rs2 = RsvpRequestRsvpSlot.find_by_rsvp_slot_id(@slot2.id)
|
||||
RsvpRequest.update({:id => rsvp.id, :session_id => @music_session.id, :rsvp_responses => [{:request_slot_id => rs1.id, :accept => true}, {:request_slot_id => rs2.id, :accept => false}]}, @session_creator)
|
||||
rs1 = RsvpRequestRsvpSlot.find_by_rsvp_request_id_and_rsvp_slot_id(@rsvp1.id, @slot1.id)
|
||||
rs2 = RsvpRequestRsvpSlot.find_by_rsvp_request_id_and_rsvp_slot_id(@rsvp1.id, @slot2.id)
|
||||
RsvpRequest.update({:id => @rsvp1.id, :session_id => @music_session.id, :rsvp_responses => [{:request_slot_id => rs1.id, :accept => true}, {:request_slot_id => rs2.id, :accept => false}]}, @session_creator)
|
||||
|
||||
# reject slot1 and slot2
|
||||
rs1 = RsvpRequestRsvpSlot.find_by_rsvp_request_id_and_rsvp_slot_id(@rsvp2.id, @slot1.id)
|
||||
rs2 = RsvpRequestRsvpSlot.find_by_rsvp_request_id_and_rsvp_slot_id(@rsvp2.id, @slot2.id)
|
||||
RsvpRequest.update({:id => @rsvp2.id, :session_id => @music_session.id, :rsvp_responses => [{:request_slot_id => rs1.id, :accept => false}, {:request_slot_id => rs2.id, :accept => false}]}, @session_creator)
|
||||
end
|
||||
|
||||
def ensure_success(options = {})
|
||||
|
|
@ -64,7 +82,11 @@ describe "Session Info", :js => true, :type => :feature, :capybara_feature => tr
|
|||
find('div.creator-name', text: @session_creator.name)
|
||||
|
||||
# action button
|
||||
find('#btn-action') if options[:show_cta]
|
||||
if options[:show_cta]
|
||||
find('#btn-action', :text => options[:button_text])
|
||||
else
|
||||
expect {find('#btn-action')}.to raise_error(Capybara::ElementNotFound)
|
||||
end
|
||||
|
||||
# session details
|
||||
find('div.scheduled_start')
|
||||
|
|
@ -78,13 +100,13 @@ describe "Session Info", :js => true, :type => :feature, :capybara_feature => tr
|
|||
|
||||
# right sidebar - RSVPs
|
||||
find('div.rsvp-details .avatar-tiny')
|
||||
find('div.rsvp-details .rsvp-name', text: @rsvp_user.name)
|
||||
find('div.rsvp-details .rsvp-name', text: @rsvp_approved_user.name)
|
||||
find('div.rsvp-details img.instrument-icon')
|
||||
|
||||
# right sidebar - Still Needed
|
||||
find('div.still-needed', text: @slot2.instrument.id.capitalize)
|
||||
|
||||
# right sidebar - Invited
|
||||
# right sidebar - Pending Invitations
|
||||
find('div[user-id="' + @session_invitee.id + '"]')
|
||||
|
||||
# comments
|
||||
|
|
@ -92,7 +114,7 @@ describe "Session Info", :js => true, :type => :feature, :capybara_feature => tr
|
|||
end
|
||||
|
||||
def ensure_failure
|
||||
find('div.not-found', text: "SESSION NOT FOUND")
|
||||
find('strong.not-found', text: "SESSION NOT FOUND")
|
||||
end
|
||||
|
||||
describe "view" do
|
||||
|
|
@ -103,43 +125,66 @@ describe "Session Info", :js => true, :type => :feature, :capybara_feature => tr
|
|||
@music_session.save
|
||||
|
||||
# attempt to access with musician who was invited but didn't RSVP
|
||||
sign_in_poltergeist(@session_invitee)
|
||||
url = "/sessions/#{@music_session.id}/details"
|
||||
visit url
|
||||
ensure_success({:show_cta => true})
|
||||
sign_in_poltergeist(@session_invitee)
|
||||
visit @url
|
||||
ensure_success({:show_cta => true, :button_text => 'RSVP NOW!'})
|
||||
sign_out_poltergeist
|
||||
|
||||
|
||||
# attempt to access with musician who wasn't invited
|
||||
sign_in_poltergeist(@non_session_invitee)
|
||||
|
||||
visit @url
|
||||
ensure_success({:show_cta => true, :button_text => 'RSVP NOW!'})
|
||||
sign_out_poltergeist
|
||||
|
||||
# attempt to access with musician who RSVP'ed but wasn't approved
|
||||
sign_in_poltergeist(@rsvp_declined_user)
|
||||
visit @url
|
||||
ensure_success({:show_cta => false})
|
||||
sign_out_poltergeist
|
||||
|
||||
# attempt to access with musician who RSVP'ed and was approved
|
||||
sign_in_poltergeist(@rsvp_approved_user)
|
||||
visit @url
|
||||
ensure_success({:show_cta => true, :button_text => 'CANCEL RSVP'})
|
||||
sign_out_poltergeist
|
||||
|
||||
# attempt to access with session creator
|
||||
sign_in_poltergeist(@session_creator)
|
||||
|
||||
visit @url
|
||||
ensure_success({:show_cta => false})
|
||||
sign_out_poltergeist
|
||||
|
||||
|
||||
|
||||
# attempt to access with musician who RSVP'ed but wasn't approved
|
||||
|
||||
|
||||
# attempt to access with musician who RSVP'ed and was approved
|
||||
end
|
||||
|
||||
it "should render only for session invitees for sessions with closed RSVPs before session starts" do
|
||||
# attempt to access with musician who wasn't invited
|
||||
|
||||
|
||||
# attempt to access with musician who was invited but didn't RSVP
|
||||
sign_in_poltergeist(@session_invitee)
|
||||
visit @url
|
||||
ensure_success({:show_cta => true, :button_text => 'RSVP NOW!'})
|
||||
sign_out_poltergeist
|
||||
|
||||
# attempt to access with musician who wasn't invited
|
||||
sign_in_poltergeist(@non_session_invitee)
|
||||
visit @url
|
||||
ensure_failure # NON-INVITEE SHOULD NOT BE ABLE TO VIEW FOR CLOSED RSVPs
|
||||
sign_out_poltergeist
|
||||
|
||||
# attempt to access with musician who RSVP'ed but wasn't approved
|
||||
|
||||
sign_in_poltergeist(@rsvp_declined_user)
|
||||
visit @url
|
||||
ensure_success({:show_cta => false})
|
||||
sign_out_poltergeist
|
||||
|
||||
# attempt to access with musician who RSVP'ed and was approved
|
||||
sign_in_poltergeist(@rsvp_approved_user)
|
||||
visit @url
|
||||
ensure_success({:show_cta => true, :button_text => 'CANCEL RSVP'})
|
||||
sign_out_poltergeist
|
||||
|
||||
# attempt to access with session creator
|
||||
sign_in_poltergeist(@session_creator)
|
||||
visit @url
|
||||
ensure_success({:show_cta => false})
|
||||
sign_out_poltergeist
|
||||
end
|
||||
|
||||
# musician_access = false, approval_required = false
|
||||
|
|
@ -184,45 +229,13 @@ describe "Session Info", :js => true, :type => :feature, :capybara_feature => tr
|
|||
# attempt to access with musician who RSVP'ed and was approved
|
||||
end
|
||||
|
||||
it "should render all required information" do
|
||||
# access with a user who was invited but hasn't RSVPed yet
|
||||
|
||||
|
||||
# session creator
|
||||
|
||||
# date/time
|
||||
|
||||
# genre
|
||||
|
||||
# name
|
||||
|
||||
# description
|
||||
|
||||
# notation files
|
||||
|
||||
# language
|
||||
|
||||
# access
|
||||
|
||||
# legal info
|
||||
|
||||
# view comments
|
||||
|
||||
|
||||
# sidebar - Approved RSVPs
|
||||
|
||||
# sidebar - Open Slots
|
||||
|
||||
# sidebar - Pending Invitations
|
||||
end
|
||||
|
||||
it "should allow only RSVP approvals or session invitees to add comments" do
|
||||
end
|
||||
|
||||
it "should show no call to action button if user has not RSVPed and all slots are taken" do
|
||||
end
|
||||
|
||||
it "should show no call to action button if the session organizer is viewing" do
|
||||
it "should show no call to action button for session organizer" do
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue