Merge branch 'develop' of bitbucket.org:jamkazam/jam-cloud into develop
This commit is contained in:
commit
e7b8d05f6d
|
|
@ -126,6 +126,8 @@ module JamAdmin
|
|||
config.twitter_app_secret = ENV['TWITTER_APP_SECRET'] || 'Azcy3QqfzYzn2fsojFPYXcn72yfwa0vG6wWDrZ3KT8'
|
||||
|
||||
config.ffmpeg_path = ENV['FFMPEG_PATH'] || (File.exist?('/usr/local/bin/ffmpeg') ? '/usr/local/bin/ffmpeg' : '/usr/bin/ffmpeg')
|
||||
config.normalize_ogg_path = ENV['NORMALIZE_OGG_PATH'] || (File.exist?('/usr/local/bin/normalize-ogg') ? '/usr/local/bin/normalize-ogg' : '/usr/bin/normalize-ogg')
|
||||
config.normalize_mp3_path = ENV['NORMALIZE_MP3_PATH'] || (File.exist?('/usr/local/bin/normalize-mp3') ? '/usr/local/bin/normalize-mp3' : '/usr/bin/normalize-mp3')
|
||||
|
||||
config.max_audio_downloads = 100
|
||||
|
||||
|
|
|
|||
|
|
@ -481,6 +481,7 @@ message RecordingMasterMixComplete {
|
|||
optional string msg = 3;
|
||||
optional string notification_id = 4;
|
||||
optional string created_at = 5;
|
||||
optional string claimed_recording_id = 6;
|
||||
}
|
||||
|
||||
message DownloadAvailable {
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ require "jam_ruby/constants/validation_messages"
|
|||
require "jam_ruby/errors/permission_error"
|
||||
require "jam_ruby/errors/state_error"
|
||||
require "jam_ruby/errors/jam_argument_error"
|
||||
require "jam_ruby/errors/conflict_error"
|
||||
require "jam_ruby/lib/app_config"
|
||||
require "jam_ruby/lib/s3_manager_mixin"
|
||||
require "jam_ruby/lib/module_overrides"
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
<br/>
|
||||
<br/>
|
||||
<p>
|
||||
This email was received because someone left feedback at <a style="color: #588C98;" href="http://www.jamkazam.com/corp/contact">http://www.jamkazam.com/corp/contact</a>
|
||||
This email was received because someone left feedback at <a href="http://www.jamkazam.com/corp/contact">http://www.jamkazam.com/corp/contact</a>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<% provide(:title, "You've been invited to JamKazam by #{@sender.name}!") %>
|
||||
<% provide(:photo_url, @sender.resolved_photo_url) %>
|
||||
|
||||
To signup, please go to the <a style="color: #588C98;" href="<%= @signup_url %>">create account</a> page.
|
||||
To signup, please go to the <a href="<%= @signup_url %>">create account</a> page.
|
||||
|
||||
<% content_for :note do %>
|
||||
<% if @note %>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
<% provide(:title, 'Welcome to the JamKazam Beta!') %>
|
||||
|
||||
To signup, please go to the <a style="color: #588C98;" href="<%= @signup_url %>">create account</a> page.
|
||||
To signup, please go to the <a href="<%= @signup_url %>">create account</a> page.
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
</p>
|
||||
|
||||
<p>
|
||||
<a style="color: #588C98;" href="https://jamkazam.desk.com/">https://jamkazam.desk.com</a>
|
||||
<a href="https://jamkazam.desk.com/">https://jamkazam.desk.com</a>
|
||||
</p>
|
||||
|
||||
<p>-- Team JamKazam
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@
|
|||
</p>
|
||||
|
||||
<p>
|
||||
<a style="color: #588C98;" href="http://www.jamkazam.com/downloads">Go to Download Page</a>
|
||||
<a href="http://www.jamkazam.com/downloads">Go to Download Page</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a style="color: #588C98;" href="https://jamkazam.desk.com">Go to Support Center</a>
|
||||
<a href="https://jamkazam.desk.com">Go to Support Center</a>
|
||||
</p>
|
||||
|
||||
<p>-- Team JamKazam
|
||||
|
|
|
|||
|
|
@ -6,13 +6,13 @@
|
|||
<p>We noticed that you have not yet successfully set up your audio gear and passed the JamKazam latency and input/output audio gear tests. This means that you cannot yet play in online sessions with other musicians. If you are having trouble with this step, please click the link below for a knowledge base article that can help you get past this hurdle. If the test says your audio gear is not fast enough, or if your audio quality sounds poor, or if you are just confused, it’s very likely the tips in this article will help you get things set up and optimized so you can start playing online.
|
||||
</p>
|
||||
|
||||
<p><a style="color: #588C98;" href="http://bit.ly/1i4Uul4">http://bit.ly/1i4Uul4</a>
|
||||
<p><a href="http://bit.ly/1i4Uul4">http://bit.ly/1i4Uul4</a>
|
||||
</p>
|
||||
|
||||
<p>And if this knowledge base article does not get you fixed up, please visit our JamKazam support center at the link below, and post a request for assistance so that we can help you get up and running:
|
||||
</p>
|
||||
|
||||
<p><a style="color: #588C98;" href="https://jamkazam.desk.com">https://jamkazam.desk.com</a>
|
||||
<p><a href="https://jamkazam.desk.com">https://jamkazam.desk.com</a>
|
||||
</p>
|
||||
|
||||
<p>-- Team JamKazam
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
It’s still very early in our company’s development, so we don’t have zillions of users online on our service yet. If you click Find Session, you will often not find a good session to join, both due to the number of musicians online at any given time, and also because you won’t see private sessions where groups of musicians don’t want to be interrupted in their sessions.
|
||||
</p>
|
||||
|
||||
<p>If you are having trouble getting into sessions, we’d suggest you click the Musicians tile on the home screen of the app or the website: <a style="color: #588C98;" href="http://www.jamkazam.com/client#/musicians">Go To Musicians Page</a>
|
||||
<p>If you are having trouble getting into sessions, we’d suggest you click the Musicians tile on the home screen of the app or the website: <a href="http://www.jamkazam.com/client#/musicians">Go To Musicians Page</a>
|
||||
</p>
|
||||
|
||||
<p>This will display the JamKazam musicians sorted by latency to you - in other words, you can see which musicians have good network connections to you. Any musicians with green and yellow latency scores have good enough connections to support a play session with you. We recommend that read the profiles of these musicians to find others with shared musical interests and good network connections to you, and then use the Message button to say hi and see if they are interested in playing with you. If they are, use the Connect button to “friend” them on JamKazam, and use the Message button to set up a time to meet online for a session.
|
||||
|
|
@ -24,7 +24,7 @@ One of the best ways to connect and play with others is to invite your friends f
|
|||
If you are having audio quality problems or other issues when you get into a session, please click the link below to visit our support center, and check the knowledge base articles under the Troubleshooting header to find solutions. And if that doesn’t work, please post a request for assistance in the support center so that we can help you get up and running:
|
||||
</p>
|
||||
|
||||
<p><a style="color: #588C98;" href="https://jamkazam.desk.com">https://jamkazam.desk.com</a>
|
||||
<p><a href="https://jamkazam.desk.com">https://jamkazam.desk.com</a>
|
||||
</p>
|
||||
|
||||
<p>-- Team JamKazam
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
</p>
|
||||
|
||||
<p>Find Other Musicians on JamKazam<br />
|
||||
To find and connect with other musicians who are already on JamKazam, we’d suggest you click the Musicians tile on the home screen of the app or the website: <a style="color: #588C98;" href="http://www.jamkazam.com/client#/musicians">Go To Musicians Page</a>
|
||||
To find and connect with other musicians who are already on JamKazam, we’d suggest you click the Musicians tile on the home screen of the app or the website: <a href="http://www.jamkazam.com/client#/musicians">Go To Musicians Page</a>
|
||||
</p>
|
||||
|
||||
<p>This will display the JamKazam musicians sorted by latency to you - in other words, you can see which musicians have good network connections to you. Any musicians with green and yellow latency scores have good enough connections to support a play session with you. We recommend that you read the profiles of these musicians to find others with shared musical interests and good network connections to you, and then use the Message button to say hi and see if they are interested in playing with you. If they are, use the Connect button to “friend” them on JamKazam, and use the Message button to set up a time to meet online for a session.
|
||||
|
|
@ -20,7 +20,7 @@ One of the best ways to connect and play with others is to invite your friends f
|
|||
<p>If you have any trouble, please visit our support center at the link below any time to get help:
|
||||
</p>
|
||||
|
||||
<p><a style="color: #588C98;" href="https://jamkazam.desk.com/">https://jamkazam.desk.com</a>
|
||||
<p><a href="https://jamkazam.desk.com/">https://jamkazam.desk.com</a>
|
||||
</p>
|
||||
|
||||
<p>-- Team JamKazam
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
<p>If you have any trouble, please visit our support center at the link below any time to get help:
|
||||
</p>
|
||||
|
||||
<p><a style="color: #588C98;" href="https://jamkazam.desk.com">https://jamkazam.desk.com</a>
|
||||
<p><a href="https://jamkazam.desk.com">https://jamkazam.desk.com</a>
|
||||
</p>
|
||||
|
||||
<p>-- Team JamKazam
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
<p>If you are having audio quality problems or other issues when you get into a session, please click the link below to visit our support center, and check the knowledge base articles under the Troubleshooting header to find solutions. And if that doesn’t work, please post a request for assistance in the support center so that we can help you get up and running:
|
||||
</p>
|
||||
|
||||
<p><a style="color: #588C98;" href="https://jamkazam.desk.com">https://jamkazam.desk.com</a>
|
||||
<p><a href="https://jamkazam.desk.com">https://jamkazam.desk.com</a>
|
||||
</p>
|
||||
|
||||
<p>We really want you to be successful and have fun with this new way of playing music with others, so please reach out and let us help you!
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
<% provide(:title, 'New Band Session') %>
|
||||
|
||||
<p><%= @body %> <a style="color: #588C98;" href="<%= @session_url %>">Listen in.</a></p>
|
||||
<p><%= @body %> <a href="<%= @session_url %>">Listen in.</a></p>
|
||||
|
|
@ -2,4 +2,4 @@
|
|||
|
||||
<p>Welcome to JamKazam, <%= @user.first_name %>!</p>
|
||||
|
||||
<p>To confirm this email address, please go to the <a style="color: #588C98;" href="<%= @signup_confirm_url %>">signup confirmation page</a>.</p>
|
||||
<p>To confirm this email address, please go to the <a href="<%= @signup_confirm_url %>">signup confirmation page</a>.</p>
|
||||
|
|
|
|||
|
|
@ -2,4 +2,4 @@
|
|||
|
||||
<p><%= @body %></p>
|
||||
|
||||
<p>To accept this friend request, <a style="color: #588C98;" href="<%= @url %>">click here</a>.</p>
|
||||
<p>To accept this friend request, <a href="<%= @url %>">click here</a>.</p>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
<% provide(:title, 'Musician in Session') %>
|
||||
|
||||
<p><%= @body %> <a style="color: #588C98;" href="<%= @session_url %>">Listen in.</a></p>
|
||||
<p><%= @body %> <a href="<%= @session_url %>">Listen in.</a></p>
|
||||
|
|
@ -24,7 +24,7 @@ Hi <%= @user.first_name %>,
|
|||
<% end %>
|
||||
</table>
|
||||
</p>
|
||||
<p>There are currently <%= @new_musicians.size%> musicians on JamKazam with low enough latency Internet connections to you to support a good online session. To see ALL the JamKazam musicians with whom you may want to connect and play, view our Musicians page at: <a style="color: #588C98;" href="http://www.jamkazam.com/client#/musicians">http://www.jamkazam.com/client#/musicians</a>.
|
||||
<p>There are currently <%= @new_musicians.size%> musicians on JamKazam with low enough latency Internet connections to you to support a good online session. To see ALL the JamKazam musicians with whom you may want to connect and play, view our Musicians page at: <a href="http://www.jamkazam.com/client#/musicians">http://www.jamkazam.com/client#/musicians</a>.
|
||||
</p>
|
||||
|
||||
<p>Best Regards,</p>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
<% provide(:title, 'JamKazam Password Reset') %>
|
||||
|
||||
Visit this link so that you can change your JamKazam password: <a style="color: #588C98;" href="<%= @password_reset_url %>">reset password</a>.
|
||||
Visit this link so that you can change your JamKazam password: <a href="<%= @password_reset_url %>">reset password</a>.
|
||||
|
|
@ -2,4 +2,4 @@
|
|||
|
||||
<p><%= @body %></p>
|
||||
|
||||
<p><a style="color: #588C98;" href="<%= @session_url %>">View Session Details</a></p>
|
||||
<p><a href="<%= @session_url %>">View Session Details</a></p>
|
||||
|
|
@ -7,5 +7,5 @@
|
|||
<p><%= @session_name %></p>
|
||||
<p><%= @session_date %></p>
|
||||
|
||||
<p><a style="color: #588C98;" href="<%= @session_url %>">View Session Details</a></p>
|
||||
<p><a href="<%= @session_url %>">View Session Details</a></p>
|
||||
<% end %>
|
||||
|
|
@ -68,7 +68,7 @@
|
|||
<td><%= sess.genre.description %></td>
|
||||
<td>
|
||||
<%= sess.name %><br/>
|
||||
<a style="color: #588C98;" href="<%= "http://www.jamkazam.com/sessions/#{sess.id}/details" %>">Details</a>
|
||||
<a href="<%= "http://www.jamkazam.com/sessions/#{sess.id}/details" %>">Details</a>
|
||||
</td>
|
||||
<td><%= sess.description %></td>
|
||||
<td style="text-align:center">
|
||||
|
|
@ -86,7 +86,7 @@
|
|||
</tbody>
|
||||
</table>
|
||||
|
||||
<p>To see ALL the scheduled sessions that you might be interested in joining, view our <a style="color: #588C98;" href="http://www.jamkazam.com/client#/findSession">Find Session page</a>.</p>
|
||||
<p>To see ALL the scheduled sessions that you might be interested in joining, view our <a href="http://www.jamkazam.com/client#/findSession">Find Session page</a>.</p>
|
||||
|
||||
<p>Best Regards,</p>
|
||||
|
||||
|
|
|
|||
|
|
@ -7,4 +7,4 @@
|
|||
<%= @session_date %>
|
||||
</p>
|
||||
|
||||
<p><a style="color: #588C98;" href="<%= @session_url %>">View Session Details</a></p>
|
||||
<p><a href="<%= @session_url %>">View Session Details</a></p>
|
||||
|
|
@ -7,4 +7,4 @@
|
|||
<%= @session_date %>
|
||||
</p>
|
||||
|
||||
<p><a style="color: #588C98;" href="<%= @session_url %>">View Session Details</a></p>
|
||||
<p><a href="<%= @session_url %>">View Session Details</a></p>
|
||||
|
|
@ -7,4 +7,4 @@
|
|||
<%= @session_date %>
|
||||
</p>
|
||||
|
||||
<p><a style="color: #588C98;" href="<%= @session_url %>">View Session Details</a></p>
|
||||
<p><a href="<%= @session_url %>">View Session Details</a></p>
|
||||
|
|
@ -7,4 +7,4 @@
|
|||
<%= @session_date %>
|
||||
</p>
|
||||
|
||||
<p><a style="color: #588C98;" href="<%= @session_url %>">View Session Details</a></p>
|
||||
<p><a href="<%= @session_url %>">View Session Details</a></p>
|
||||
|
|
@ -7,4 +7,4 @@
|
|||
<%= @session_date %>
|
||||
</p>
|
||||
|
||||
<p><a style="color: #588C98;" href="<%= @session_url %>">View Session Details</a></p>
|
||||
<p><a href="<%= @session_url %>">View Session Details</a></p>
|
||||
|
|
@ -7,4 +7,4 @@
|
|||
<%= @session_date %>
|
||||
</p>
|
||||
|
||||
<p><a style="color: #588C98;" href="<%= @session_url %>">View Session Details</a></p>
|
||||
<p><a href="<%= @session_url %>">View Session Details</a></p>
|
||||
|
|
@ -7,4 +7,4 @@
|
|||
<%= @session_date %>
|
||||
</p>
|
||||
|
||||
<p><a style="color: #588C98;" href="<%= @session_url %>">View Session Details</a></p>
|
||||
<p><a href="<%= @session_url %>">View Session Details</a></p>
|
||||
|
|
@ -4,5 +4,5 @@
|
|||
<% content_for :note do %>
|
||||
<%= @note %>
|
||||
|
||||
<p>To reply to this message, <a style="color: #588C98;" href="<%= @url %>">click here</a>.</p>
|
||||
<p>To reply to this message, <a href="<%= @url %>">click here</a>.</p>
|
||||
<% end %>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
<% provide(:title, 'Please Confirm New JamKazam Email') %>
|
||||
|
||||
Please click the following link to confirm your change in email: <a style="color: #588C98;" href="<%= @user.update_email_confirmation_url %>">confirm email</a>.
|
||||
Please click the following link to confirm your change in email: <a href="<%= @user.update_email_confirmation_url %>">confirm email</a>.
|
||||
|
|
@ -11,31 +11,31 @@
|
|||
<p>
|
||||
Getting Started Video<br/>
|
||||
We recommend watching this video before you jump into the service just to get oriented. It will really help you hit the ground running:
|
||||
<a style="color: #588C98;" href="https://www.youtube.com/watch?v=VexH4834o9I">https://www.youtube.com/watch?v=VexH4834o9I</a>
|
||||
<a href="https://www.youtube.com/watch?v=VexH4834o9I">https://www.youtube.com/watch?v=VexH4834o9I</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Other Great Tutorial Videos<br />
|
||||
There are several other very great videos that will help you understand how to find and connect with other musicians on the service, create your own sessions or find and join other musicians’ sessions, play in sessions, record and share your performances, and even live broadcast your sessions to family, friends, and fans. Check these helpful videos out here:
|
||||
<a style="color: #588C98;" href="https://jamkazam.desk.com/customer/portal/articles/1304097-tutorial-videos">https://jamkazam.desk.com/customer/portal/articles/1304097-tutorial-videos</a>
|
||||
<a href="https://jamkazam.desk.com/customer/portal/articles/1304097-tutorial-videos">https://jamkazam.desk.com/customer/portal/articles/1304097-tutorial-videos</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Knowledge Base Articles<br />
|
||||
You can find Getting Started knowledge base articles on things like frequently asked questions (FAQ), minimum system requirements for your Windows or Mac computer, how to troubleshoot audio problems in sessions, and more here:
|
||||
<a style="color: #588C98;" href="https://jamkazam.desk.com/customer/portal/topics/564807-getting-started/articles">https://jamkazam.desk.com/customer/portal/topics/564807-getting-started/articles</a>
|
||||
<a href="https://jamkazam.desk.com/customer/portal/topics/564807-getting-started/articles">https://jamkazam.desk.com/customer/portal/topics/564807-getting-started/articles</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
JamKazam Support Portal<br />
|
||||
If you run into trouble and need help, please reach out to us. We will be glad to do everything we can to get you up and running. You can find our support portal here:
|
||||
<a style="color: #588C98;" href="https://jamkazam.desk.com/">https://jamkazam.desk.com/</a>
|
||||
<a href="https://jamkazam.desk.com/">https://jamkazam.desk.com/</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
JamKazam Community Forum<br />
|
||||
And if you just want to chat, share tips and war stories, and hang out with fellow JamKazamers, you can visit our community forum here:
|
||||
<a style="color: #588C98;" href="http://forums.jamkazam.com/">http://forums.jamkazam.com/</a>
|
||||
<a href="http://forums.jamkazam.com/">http://forums.jamkazam.com/</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@
|
|||
margin-bottom:0px;
|
||||
line-height:140%;
|
||||
}
|
||||
a {
|
||||
color: #ffcc00 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
|
@ -48,7 +51,7 @@
|
|||
|
||||
<!-- CALL OUT BOX -->
|
||||
</font></p>
|
||||
<p style="margin-top:0px"><font size="2" color="#7FACBA" face="Arial, Helvetica, sans-serif">This email was sent to you because you have an account at <a style="color: #588C98;" href="http://www.jamkazam.com">JamKazam</a>.
|
||||
<p style="margin-top:0px"><font size="2" color="#7FACBA" face="Arial, Helvetica, sans-serif">This email was sent to you because you have an account at <a href="http://www.jamkazam.com">JamKazam</a>.
|
||||
</td></tr></table>
|
||||
|
||||
</td>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@
|
|||
margin-bottom:0px;
|
||||
line-height:140%;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #ffcc00 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
|
@ -37,7 +39,7 @@
|
|||
<td align="left">
|
||||
|
||||
<!-- CALL OUT BOX -->
|
||||
<p style="margin-top:0px"><font size="2" color="#7FACBA" face="Arial, Helvetica, sans-serif">This email was sent to you because you have an account at <a style="color: #588C98;" href="http://www.jamkazam.com">JamKazam</a>. Click <a style="color: #588C98;" href="http://www.jamkazam.com/client#/account/profile">here to unsubscribe</a> and update your profile settings.
|
||||
<p style="margin-top:0px"><font size="2" color="#7FACBA" face="Arial, Helvetica, sans-serif">This email was sent to you because you have an account at <a href="http://www.jamkazam.com">JamKazam</a>. Click <a href="http://www.jamkazam.com/client#/account/profile">here to unsubscribe</a> and update your profile settings.
|
||||
</font></p>
|
||||
</td></tr></table>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
module JamRuby
|
||||
class ConflictError < Exception
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -27,6 +27,10 @@ module JamRuby
|
|||
"#{base_url}/findSession"
|
||||
end
|
||||
|
||||
def self.session(session)
|
||||
"#{base_url}/session/#{session.id}"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.base_url
|
||||
|
|
|
|||
|
|
@ -712,9 +712,10 @@ module JamRuby
|
|||
)
|
||||
end
|
||||
|
||||
def recording_master_mix_complete(receiver_id, recording_id, band_id, msg, notification_id, created_at)
|
||||
def recording_master_mix_complete(receiver_id, recording_id, claimed_recording_id, band_id, msg, notification_id, created_at)
|
||||
recording_master_mix_complete = Jampb::RecordingMasterMixComplete.new(
|
||||
:recording_id => recording_id,
|
||||
:claimed_recording_id => claimed_recording_id,
|
||||
:band_id => band_id,
|
||||
:msg => msg,
|
||||
:notification_id => notification_id,
|
||||
|
|
|
|||
|
|
@ -724,7 +724,7 @@ module JamRuby
|
|||
|
||||
query = query.offset(offset)
|
||||
query = query.limit(limit)
|
||||
query = query.where("music_sessions.create_type IS NULL OR music_sessions.create_type != ?", MusicSession::CREATE_TYPE_QUICK_START)
|
||||
query = query.where("music_sessions.create_type IS NULL OR (music_sessions.create_type != ? AND music_sessions.create_type != ?)", MusicSession::CREATE_TYPE_QUICK_START, MusicSession::CREATE_TYPE_IMMEDIATE)
|
||||
query = query.where("music_sessions.genre_id = ?", genre) unless genre.blank?
|
||||
query = query.where('music_sessions.language = ?', lang) unless lang.blank?
|
||||
query = query.where("(description_tsv @@ to_tsquery('jamenglish', ?))", ActiveRecord::Base.connection.quote(keyword) + ':*') unless keyword.blank?
|
||||
|
|
|
|||
|
|
@ -1147,6 +1147,7 @@ module JamRuby
|
|||
msg = @@message_factory.recording_master_mix_complete(
|
||||
claimed_recording.user_id,
|
||||
recording.id,
|
||||
claimed_recording.id,
|
||||
notification.band_id,
|
||||
notification_msg,
|
||||
notification.id,
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ module JamRuby
|
|||
|
||||
# authorize the user attempting to respond to the RSVP request
|
||||
if music_session.creator.id != user.id
|
||||
raise PermissionError, "Only the session organizer can accept or decline and RSVP request."
|
||||
raise PermissionError, "Only the session organizer can accept or decline an RSVP request."
|
||||
end
|
||||
|
||||
rsvp_request = RsvpRequest.find_by_id(rsvp_request_id)
|
||||
|
|
@ -181,8 +181,35 @@ module JamRuby
|
|||
raise StateError, "Slot does not exist"
|
||||
end
|
||||
|
||||
# slot has already been accepted
|
||||
if rsvp_slot.chosen && r[:accept]
|
||||
raise StateError, "All RSVP slots for the #{rsvp_slot.instrument_id} have been already approved."
|
||||
# get the instrument and skill level for this slot and see if there are others available
|
||||
# and auto-reassign the request_slot to the open rsvp_slot
|
||||
open_slots = music_session.open_slots
|
||||
|
||||
# don't worry about matching proficiency if the user RSVPed to "Any Skill Level"
|
||||
if rsvp_slot.proficiency_level == 0
|
||||
open_slots = open_slots.select { |slot| slot.instrument_id == rsvp_slot.instrument_id }
|
||||
else
|
||||
open_slots = open_slots.select { |slot| slot.instrument_id == rsvp_slot.instrument_id && slot.proficiency_level == rsvp_slot.proficiency_level }
|
||||
end
|
||||
|
||||
# (1) another available slot exists matching this instrument and proficiency
|
||||
unless open_slots.blank?
|
||||
rsvp_slot = open_slots.first
|
||||
request_slot.rsvp_slot_id = rsvp_slot.id # this links the RsvpRequestRsvpSlot to the available open slot matching this instrument and proficiency level
|
||||
|
||||
# (2) no identical slots available => create a new one on the fly
|
||||
else
|
||||
new_slot = RsvpSlot.new
|
||||
new_slot.instrument_id = rsvp_slot.instrument_id
|
||||
new_slot.proficiency_level = rsvp_slot.proficiency_level
|
||||
new_slot.music_session_id = rsvp_slot.music_session_id
|
||||
new_slot.is_unstructured_rsvp = rsvp_slot.is_unstructured_rsvp
|
||||
new_slot.save!
|
||||
|
||||
request_slot.rsvp_slot_id = new_slot.id # saved below on line 218
|
||||
end
|
||||
end
|
||||
|
||||
if r[:accept]
|
||||
|
|
|
|||
|
|
@ -322,7 +322,7 @@ module JamRuby
|
|||
|
||||
raise "no output ogg file after mix" unless File.exist? @output_ogg_filename
|
||||
|
||||
ffmpeg_cmd = "#{APP_CONFIG.ffmpeg_path} -i \"#{@output_ogg_filename}\" -ab 128k -metadata JamRecordingId=#{@manifest[:recording_id]} -metadata JamMixId=#{@mix_id} -metadata JamType=Mix \"#{@output_mp3_filename}\""
|
||||
ffmpeg_cmd = "#{APP_CONFIG.ffmpeg_path} -i \"#{@output_ogg_filename}\" -ab 192k -metadata JamRecordingId=#{@manifest[:recording_id]} -metadata JamMixId=#{@mix_id} -metadata JamType=Mix \"#{@output_mp3_filename}\""
|
||||
|
||||
system(ffmpeg_cmd)
|
||||
|
||||
|
|
@ -335,6 +335,30 @@ module JamRuby
|
|||
end
|
||||
|
||||
raise "no output mp3 file after conversion" unless File.exist? @output_mp3_filename
|
||||
|
||||
# time to normalize both mp3 and ogg files
|
||||
|
||||
normalize_ogg_cmd = "#{APP_CONFIG.normalize_ogg_path} --bitrate 128 -i \"#{@output_ogg_filename}\""
|
||||
system(normalize_ogg_cmd)
|
||||
unless $? == 0
|
||||
@error_reason = 'normalize-ogg-failed'
|
||||
@error_detail = $?.to_s
|
||||
error_msg = "normalize-ogg failed status=#{$?} error_reason=#{@error_reason} error_detail=#{@error_detail}"
|
||||
@@log.info(error_msg)
|
||||
raise error_msg
|
||||
end
|
||||
raise "no output ogg file after normalization" unless File.exist? @output_ogg_filename
|
||||
|
||||
normalize_mp3_cmd = "#{APP_CONFIG.normalize_mp3_path} --bitrate 128 -i \"#{@output_mp3_filename}\""
|
||||
system(normalize_mp3_cmd)
|
||||
unless $? == 0
|
||||
@error_reason = 'normalize-mp3-failed'
|
||||
@error_detail = $?.to_s
|
||||
error_msg = "normalize-mp3 failed status=#{$?} error_reason=#{@error_reason} error_detail=#{@error_detail}"
|
||||
@@log.info(error_msg)
|
||||
raise error_msg
|
||||
end
|
||||
raise "no output mp3 file after conversion" unless File.exist? @output_mp3_filename
|
||||
end
|
||||
|
||||
def symbolize_keys(obj)
|
||||
|
|
|
|||
|
|
@ -228,7 +228,47 @@ describe RsvpRequest do
|
|||
n.description.should == NotificationTypes::SCHEDULED_SESSION_RSVP_APPROVED
|
||||
end
|
||||
|
||||
it "should not allow approval of RSVP for a slot that has already been approved" do
|
||||
it "should allow approval of multiple RSVPs to same slot ID when multiple slots exist for same instrument and proficiency level" do
|
||||
@music_session.open_rsvps = true
|
||||
@music_session.save!
|
||||
|
||||
@slot2.delete
|
||||
|
||||
slot2 = FactoryGirl.build(:rsvp_slot, :music_session => @music_session, :instrument => JamRuby::Instrument.find('electric guitar'))
|
||||
slot2.save!
|
||||
|
||||
rsvp1 = RsvpRequest.create({:session_id => @music_session.id, :rsvp_slots => [@slot1.id], :message => "Let's Jam!"}, @session_invitee)
|
||||
rsvp2 = RsvpRequest.create({:session_id => @music_session.id, :rsvp_slots => [@slot1.id], :message => "Let's Jam!"}, @non_session_invitee)
|
||||
|
||||
rs1 = RsvpRequestRsvpSlot.find_by_rsvp_request_id(rsvp1.id)
|
||||
rs1.rsvp_slot_id.should == @slot1.id
|
||||
|
||||
# approve RSVP 1
|
||||
RsvpRequest.update({:id => rsvp1.id, :session_id => @music_session.id, :rsvp_responses => [{:request_slot_id => rs1.id, :accept => true}]}, @session_creator)
|
||||
|
||||
# ensure slot ID didn't change
|
||||
rs1 = RsvpRequestRsvpSlot.find_by_rsvp_request_id(rsvp1.id)
|
||||
rs1.rsvp_slot_id.should == @slot1.id
|
||||
|
||||
# check before approving
|
||||
rs2 = RsvpRequestRsvpSlot.find_by_rsvp_request_id(rsvp2.id)
|
||||
rs2.rsvp_slot_id.should == @slot1.id
|
||||
|
||||
# approve RSVP 2 (same slot ID, but slot2 is same instrument + proficiency level)
|
||||
RsvpRequest.update({:id => rsvp2.id, :session_id => @music_session.id, :rsvp_responses => [{:request_slot_id => rs2.id, :accept => true}]}, @session_creator)
|
||||
|
||||
# should have linked the RsvpRequestRsvpSlot record to the second slot
|
||||
rs2 = RsvpRequestRsvpSlot.find_by_rsvp_request_id(rsvp2.id)
|
||||
rs2.rsvp_slot_id.should == slot2.id
|
||||
|
||||
slots = RsvpSlot.where("music_session_id = ?", @music_session.id)
|
||||
slots.count.should == 2
|
||||
|
||||
request_slots = RsvpRequestRsvpSlot.where("chosen=true")
|
||||
request_slots.count.should == 2
|
||||
end
|
||||
|
||||
it "should create a new slot for an RSVP for a slot that has already been approved" do
|
||||
rsvp = RsvpRequest.create({:session_id => @music_session.id, :rsvp_slots => [@slot1.id, @slot2.id], :message => "Let's Jam!"}, @session_invitee)
|
||||
|
||||
# approve
|
||||
|
|
@ -239,7 +279,10 @@ describe RsvpRequest do
|
|||
# approve again
|
||||
rs1 = RsvpRequestRsvpSlot.find_by_rsvp_slot_id(@slot1.id)
|
||||
rs2 = RsvpRequestRsvpSlot.find_by_rsvp_slot_id(@slot2.id)
|
||||
expect {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 => true}]}, @session_creator)}.to raise_error(StateError)
|
||||
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 => true}]}, @session_creator)
|
||||
|
||||
slots = RsvpSlot.where("music_session_id = ?", @music_session.id)
|
||||
slots.count.should == 4
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,14 @@ def app_config
|
|||
ENV['FFMPEG_PATH'] || '/usr/local/bin/ffmpeg'
|
||||
end
|
||||
|
||||
def normalize_ogg_path
|
||||
ENV['NORMALIZE_OGG_PATH'] || '/usr/local/bin/normalize-ogg'
|
||||
end
|
||||
|
||||
def normalize_mp3_path
|
||||
ENV['NORMALIZE_MP3_PATH'] || '/usr/local/bin/normalize-mp3'
|
||||
end
|
||||
|
||||
def icecast_reload_cmd
|
||||
'true' # as in, /bin/true
|
||||
end
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@
|
|||
|
||||
function beforeShow(data) {
|
||||
sessionId = data.id;
|
||||
console.log("sessionId=%o", sessionId);
|
||||
loadSessionData();
|
||||
}
|
||||
|
||||
|
|
@ -41,8 +40,7 @@
|
|||
function inviteMusicians(e) {
|
||||
e.preventDefault();
|
||||
|
||||
friendInput = inviteMusiciansUtil.inviteSessionUpdate('#update-session-invite-musicians',
|
||||
sessionId);
|
||||
friendInput = inviteMusiciansUtil.inviteSessionUpdate('#update-session-invite-musicians', sessionId);
|
||||
inviteMusiciansUtil.loadFriends();
|
||||
$(friendInput).show();
|
||||
// invitationDialog.showEmailDialog();
|
||||
|
|
@ -85,12 +83,55 @@
|
|||
e.preventDefault();
|
||||
|
||||
var rsvpId = $(e.target).attr('request-id');
|
||||
var userName = $(e.target).attr('user-name');
|
||||
var instrumentIds = $(e.target).attr('data-instrument-text');
|
||||
var params = buildRsvpRequestActionParams(rsvpId, true);
|
||||
|
||||
// first check if any open slots exist for these instruments
|
||||
rest.getOpenSessionSlots(sessionData.id, true)
|
||||
.done(function(openSlots) {
|
||||
if (openSlots) {
|
||||
if (openSlots.length === 0) {
|
||||
ui.launchRsvpCreateSlotDialog(sessionData.id, instrumentIds.split('|'), userName);
|
||||
}
|
||||
else {
|
||||
var arrInstrumentIds = instrumentIds.split('|');
|
||||
var openSlotInstrumentIds = [];
|
||||
var unavailableSlotInstrumentIds = [];
|
||||
|
||||
// ensure each instrument in the user's list is available in the open slots list
|
||||
$.each(openSlots, function(index, slot) {
|
||||
openSlotInstrumentIds.push(slot.instrument_id);
|
||||
});
|
||||
|
||||
// build list of instrument IDs in the RSVP request for which there are no open slots
|
||||
for (var i=0; i < arrInstrumentIds.length; i++) {
|
||||
if ($.inArray(arrInstrumentIds[i], openSlotInstrumentIds) === -1) {
|
||||
unavailableSlotInstrumentIds.push(arrInstrumentIds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (unavailableSlotInstrumentIds.length > 0) {
|
||||
ui.launchRsvpCreateSlotDialog(sessionData.id, unavailableSlotInstrumentIds, userName, function() {
|
||||
approve(rsvpId, params);
|
||||
});
|
||||
}
|
||||
else {
|
||||
approve(rsvpId, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
ui.launchRsvpCreateSlotDialog(sessionData.id, instrumentIds.split('|'), userName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function approve(rsvpId, params) {
|
||||
rest.updateRsvpRequest(rsvpId, params)
|
||||
.done(refreshSessionDetail)
|
||||
.fail(function(jqXHR, textStatus, errorMessage) {
|
||||
if (jqXHR.status === 400) {
|
||||
if (jqXHR.status === 409) {
|
||||
app.notify(
|
||||
{
|
||||
title: "Unable to Approve RSVP",
|
||||
|
|
@ -284,11 +325,14 @@
|
|||
var latencyHtml = "";
|
||||
$.each(sessionData.pending_rsvp_requests, function(index, pending_rsvp_request) {
|
||||
if (pending_rsvp_request.user_id != context.JK.currentUserId) {
|
||||
var instrumentDesc = [];
|
||||
|
||||
if ("instrument_list" in pending_rsvp_request && pending_rsvp_request.instrument_list != null) {
|
||||
$.each(pending_rsvp_request.instrument_list, function (index, instrument) {
|
||||
var instrumentId = instrument == null ? null : instrument.id;
|
||||
var inst = context.JK.getInstrumentIcon24(instrumentId);
|
||||
instrumentLogoHtml += '<img title="' + instrumentId + '" hoveraction="instrument" data-instrument-id="' + instrumentId + '" src="' + inst + '" width="24" height="24" /> ';
|
||||
instrumentDesc.push(instrumentId);
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -304,7 +348,7 @@
|
|||
$templateAccountPendingRsvp.html(),
|
||||
{user_id: pending_rsvp_request.user_id, avatar_url: avatar_url,
|
||||
user_name: pending_rsvp_request.user.name, instruments: instrumentLogoHtml,
|
||||
latency: latencyHtml, request_id: pending_rsvp_request.id},
|
||||
latency: latencyHtml, request_id: pending_rsvp_request.id, instrument_text: instrumentDesc.join('|')},
|
||||
{variable: 'data'}
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@
|
|||
var rest = context.JK.Rest();
|
||||
var sessionId = null;
|
||||
var sessionData = null;
|
||||
var $screen = null;
|
||||
var $screen = $("#account-session-properties");
|
||||
var $inputFiles = $screen.find('#session-select-files');
|
||||
var $selectedFilenames = $screen.find('#selected-filenames');
|
||||
var $propertiesBody = null;
|
||||
var $languageList = null;
|
||||
var $recurringModeList = null;
|
||||
|
|
@ -62,10 +64,11 @@
|
|||
|
||||
function events() {
|
||||
$startTimeList.on('change', toggleStartTime);
|
||||
$btnSelectFiles.on('click', toggleSelectFiles);
|
||||
$dateTimeTBD.on('ifChanged', toggleDateTBD);
|
||||
$screen.find("#session-update").on('click', updateSessionProperties);
|
||||
$screen.find('#session-prop-select-files').on('change', changeSelectedFiles);
|
||||
|
||||
$inputFiles.on('change', changeSelectedFiles);
|
||||
$btnSelectFiles.on('click', toggleSelectFiles);
|
||||
}
|
||||
|
||||
function toggleStartTime() {
|
||||
|
|
@ -252,7 +255,8 @@
|
|||
// }
|
||||
}
|
||||
data.recurring_mode = $recurringModeList.val();
|
||||
data.music_notations = sessionData.music_notations;
|
||||
data.music_notations = JSON.stringify(sessionData.music_notations);
|
||||
console.log("data.music_notations=%o", data.music_notations);
|
||||
data.timezone = $timezoneList.val();
|
||||
data.open_rsvps = $screen.find("#open-rsvp")[0].checked;
|
||||
|
||||
|
|
@ -306,6 +310,7 @@
|
|||
function uploadNotations(notations) {
|
||||
var formData = new FormData();
|
||||
var maxExceeded = false;
|
||||
|
||||
$.each(notations, function(i, file) {
|
||||
var max = 10 * 1024 * 1024;
|
||||
if(file.size > max) {
|
||||
|
|
@ -326,6 +331,7 @@
|
|||
}
|
||||
|
||||
formData.append('client_id', app.clientId);
|
||||
//formData.append('session_id', sessionId);
|
||||
$btnSelectFiles.text('UPLOADING...').data('uploading', true)
|
||||
$uploadSpinner.show();
|
||||
return rest.uploadMusicNotations(formData)
|
||||
|
|
@ -362,7 +368,6 @@
|
|||
}
|
||||
|
||||
function changeSelectedFiles() {
|
||||
var $inputFiles = $screen.find('#session-prop-select-files');
|
||||
var fileNames = [];
|
||||
var files = $inputFiles.get(0).files;
|
||||
var error = false;
|
||||
|
|
@ -400,7 +405,7 @@
|
|||
}
|
||||
|
||||
event.preventDefault();
|
||||
$('#session-select-files').trigger('click');
|
||||
$inputFiles.trigger('click');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -457,9 +462,10 @@
|
|||
$fansAccess.val(sessionData.fans_access_value);
|
||||
$screen.find('#session-policy').val(sessionData.legal_policy);
|
||||
|
||||
$selectedFilenames.empty();
|
||||
context._.each(sessionData.music_notations, function(notation) {
|
||||
var $link = $('<a href="/music_notations/' + notation.id + '">').text(notation.file_name);
|
||||
var $text = $('<span>').text($link);
|
||||
var $link = notation.viewable ? $('<a href="' + notation.file_url + '" rel="external">').html(notation.file_name) : '#';
|
||||
var $text = $('<span>').html($link);
|
||||
var $file = $('<li>').append($text);
|
||||
$musicNotations.append($file);
|
||||
})
|
||||
|
|
@ -473,7 +479,6 @@
|
|||
|
||||
app.bindScreen('account/sessionProperties', screenBindings);
|
||||
|
||||
$screen = $(".account-session-properties");
|
||||
$propertiesBody = $screen.find("#account-session-properties-div");
|
||||
$recurringModeList = $screen.find("#recurring-mode-prop-list");
|
||||
$languageList = $screen.find("#session-prop-lang-list");
|
||||
|
|
@ -485,7 +490,7 @@
|
|||
$musicianAccess = $screen.find("#session-prop-musician-access");
|
||||
$fansAccess = $screen.find("#session-prop-fans-access");
|
||||
$musicNotations = $screen.find("#selected-filenames");
|
||||
$btnSelectFiles = $screen.find("#select-notation-files");
|
||||
$btnSelectFiles = $screen.find(".btn-select-files");
|
||||
$uploadSpinner = $screen.find(".upload-spinner");
|
||||
$dateTimeTBD = $screen.find("#date_time_tbd");
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
}
|
||||
|
||||
function showDialog() {
|
||||
return app.layout.showDialog('rsvp-cancel-dialog');
|
||||
return app.layout.showDialog(dialogId);
|
||||
}
|
||||
|
||||
function events() {
|
||||
|
|
@ -99,7 +99,7 @@
|
|||
|
||||
$dialog = $('[layout-id="' + dialogId + '"]');
|
||||
|
||||
$("#rsvp-cancel-dialog").iCheck({
|
||||
$dialog.iCheck({
|
||||
checkboxClass: 'icheckbox_minimal',
|
||||
radioClass: 'iradio_minimal',
|
||||
inheritClass: true
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
(function(context,$) {
|
||||
|
||||
"use strict";
|
||||
context.JK = context.JK || {};
|
||||
context.JK.RsvpCreateSlotDialog = function(app, sessionId, instrumentIds, rsvpRequesterName, createSlotsCallback) {
|
||||
var EVENTS = context.JK.EVENTS;
|
||||
var logger = context.JK.logger;
|
||||
var rest = context.JK.Rest();
|
||||
var $dialog = null;
|
||||
var dialogId = 'rsvp-create-slot-dialog';
|
||||
var $btnSave = null;
|
||||
|
||||
function beforeShow(data) {
|
||||
}
|
||||
|
||||
function afterShow(data) {
|
||||
var instructions = "All RSVP slots for the instruments below have already been filled. Would you like to open up a new RSVP slot for " + rsvpRequesterName + " so that they can join your session too?";
|
||||
var instruments = instrumentIds.join("<br/>");
|
||||
|
||||
$('.instructions', $dialog).html(instructions);
|
||||
$('.instruments', $dialog).html(instruments);
|
||||
}
|
||||
|
||||
function afterHide() {
|
||||
}
|
||||
|
||||
function showDialog() {
|
||||
return app.layout.showDialog(dialogId);
|
||||
}
|
||||
|
||||
function events() {
|
||||
$btnSave.unbind('click');
|
||||
$btnSave.click(function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
if (createSlotsCallback) {
|
||||
createSlotsCallback();
|
||||
app.layout.closeDialog(dialogId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
|
||||
var dialogBindings = {
|
||||
'beforeShow' : beforeShow,
|
||||
'afterShow' : afterShow,
|
||||
'afterHide': afterHide
|
||||
};
|
||||
|
||||
app.bindDialog(dialogId, dialogBindings);
|
||||
|
||||
$dialog = $('[layout-id="' + dialogId + '"]');
|
||||
$btnSave = $dialog.find('.btnSave');
|
||||
|
||||
events();
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
this.showDialog = showDialog;
|
||||
}
|
||||
|
||||
return this;
|
||||
})(window,jQuery);
|
||||
|
|
@ -30,17 +30,14 @@
|
|||
|
||||
var hasOpenSlots = response.open_slots && response.open_slots.length > 0;
|
||||
|
||||
|
||||
if (response['is_unstructured_rsvp?']) {
|
||||
var checkedState = hasOpenSlots ? '' : 'checked="checked"'
|
||||
$('.rsvp-instruments', $dialog).append('<input type="checkbox" ' + checkedState + ' value="unstructured"/>Play Any Instrument You Like<br/>');
|
||||
$('.rsvp-instruments', $dialog).append('<input type="checkbox" ' + checkedState + ' value="unstructured"/><span>Play Any Instrument You Like</span><br/>');
|
||||
}
|
||||
|
||||
if (hasOpenSlots) {
|
||||
$.each(response.open_slots, function(index, val) {
|
||||
var instrument = val.instrument_id;
|
||||
|
||||
$('.rsvp-instruments', $dialog).append('<input type="checkbox" value="' + val.id + '"/>' + val.description + " (" + val.proficiency_desc + ")<br/>");
|
||||
$('.rsvp-instruments', $dialog).append('<input type="checkbox" data-instrument-id="' + val.instrument_id + '" value="' + val.id + '"/><span>' + val.description + " (" + val.proficiency_desc + ")</span><br/>");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -60,18 +57,28 @@
|
|||
$btnSubmit.click(function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var error = false;
|
||||
var slotIds = [];
|
||||
var selectedSlots = [];
|
||||
$("input:checked", '.rsvp-instruments').each(function(index) {
|
||||
var selection = $(this).attr('data-instrument-id');
|
||||
|
||||
if ($.inArray(selection, selectedSlots) > -1) {
|
||||
$('.error', $dialog).html('You have selected the same instrument twice.').show();
|
||||
error = true;
|
||||
return;
|
||||
}
|
||||
selectedSlots.push(selection);
|
||||
slotIds.push($(this).val());
|
||||
});
|
||||
|
||||
if (error) return;
|
||||
|
||||
if (slotIds.length === 0) {
|
||||
$('.error', $dialog).show();
|
||||
$('.error', $dialog).html('You must select at least 1 instrument.').show();
|
||||
return;
|
||||
}
|
||||
|
||||
var error = false;
|
||||
|
||||
// TODO: show spinner??
|
||||
rest.submitRsvpRequest(sessionId, slotIds)
|
||||
.done(function(response) {
|
||||
|
|
@ -83,8 +90,7 @@
|
|||
})
|
||||
.fail(function(xhr, textStatus, errorMessage) {
|
||||
error = true;
|
||||
$('.error', $dialog).html("Unexpected error occurred while saving message (" + xhr.status + ")");
|
||||
$('.error', $dialog).show();
|
||||
$('.error', $dialog).html("Unexpected error occurred while saving message (" + xhr.status + ")").show();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
var $selectedFilenames = $screen.find('#selected-filenames');
|
||||
var $uploadSpinner = $screen.find('.upload-spinner');
|
||||
var $selectedFilenames = $('#settings-selected-filenames');
|
||||
var $inputFiles = $('#settings-select-files');
|
||||
var $inputFiles = $screen.find('#session-select-files');
|
||||
var $btnSelectFiles = $screen.find('.btn-select-files');
|
||||
var rest = new JK.Rest();
|
||||
var sessionId;
|
||||
|
|
@ -116,37 +116,7 @@
|
|||
rest.updateSession($('#session-settings-id').val(), data).done(settingsSaved);
|
||||
}
|
||||
|
||||
function changeSettingsSelectedFiles() {
|
||||
var fileNames = [];
|
||||
var files = $inputFiles.get(0).files;
|
||||
var error = false;
|
||||
for (var i = 0; i < files.length; ++i) {
|
||||
var name = files.item(i).name;
|
||||
var ext = name.split('.').pop().toLowerCase();
|
||||
if ($.inArray(ext, ["pdf", "png", "jpg", "jpeg", "gif", "xml", "mxl", "txt"]) == -1) {
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
fileNames.push(name);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
app.notifyAlert("Error", "We're sorry, but you can only upload images (.png .jpg .jpeg .gif), text (.txt), PDFs (.pdf), and XML files (.xml .mxl).");
|
||||
$inputFiles.replaceWith($inputFiles.clone(true));
|
||||
}
|
||||
else {
|
||||
// upload as soon as user picks their files.
|
||||
uploadSettingsNotations($inputFiles.get(0).files)
|
||||
.done(function() {
|
||||
context._.each(fileNames, function(fileName) {
|
||||
var $text = $('<span>').text(fileName);
|
||||
$selectedFilenames.append($text);
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function uploadSettingsNotations(notations) {
|
||||
function uploadNotations(notations) {
|
||||
|
||||
var formData = new FormData();
|
||||
var maxExceeded = false;
|
||||
|
|
@ -205,14 +175,44 @@
|
|||
});
|
||||
}
|
||||
|
||||
function toggleSettingsSelectFiles(event) {
|
||||
function changeSelectedFiles() {
|
||||
var fileNames = [];
|
||||
var files = $inputFiles.get(0).files;
|
||||
var error = false;
|
||||
for (var i = 0; i < files.length; ++i) {
|
||||
var name = files.item(i).name;
|
||||
var ext = name.split('.').pop().toLowerCase();
|
||||
if ($.inArray(ext, ["pdf", "png", "jpg", "jpeg", "gif", "xml", "mxl", "txt"]) == -1) {
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
fileNames.push(name);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
app.notifyAlert("Error", "We're sorry, but you can only upload images (.png .jpg .jpeg .gif), text (.txt), PDFs (.pdf), and XML files (.xml .mxl).");
|
||||
$inputFiles.replaceWith($inputFiles.clone(true));
|
||||
}
|
||||
else {
|
||||
// upload as soon as user picks their files.
|
||||
uploadNotations($inputFiles.get(0).files)
|
||||
.done(function() {
|
||||
context._.each(fileNames, function(fileName) {
|
||||
var $text = $('<span>').text(fileName);
|
||||
$selectedFilenames.append($text);
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function toggleSelectFiles(event) {
|
||||
if($btnSelectFiles.data('uploading')) {
|
||||
logger.debug("ignoring click of SELECT FILES... while uploading")
|
||||
return false;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
$('#settings-select-files').trigger('click');
|
||||
$inputFiles.trigger('click');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -225,8 +225,8 @@
|
|||
function events() {
|
||||
$('#session-settings-dialog-submit').on('click', saveSettings);
|
||||
|
||||
$inputFiles.on('change', changeSettingsSelectedFiles);
|
||||
$btnSelectFiles.on('click', toggleSettingsSelectFiles);
|
||||
$inputFiles.on('change', changeSelectedFiles);
|
||||
$btnSelectFiles.on('click', toggleSelectFiles);
|
||||
}
|
||||
|
||||
this.initialize = function() {
|
||||
|
|
|
|||
|
|
@ -88,8 +88,11 @@
|
|||
|
||||
var fullScore = null;
|
||||
|
||||
if (response.internet_score) {
|
||||
fullScore = response.last_jam_audio_latency + calculateAudioLatency(response.my_audio_latency) + calculateAudioLatency(response.internet_score);
|
||||
if (response.internet_score && response.internet_score.length > 0) {
|
||||
if (response.internet_score[0].score && !isNaN(response.internet_score[0].score)) {
|
||||
var internetScore = parseInt(response.internet_score[0].score);
|
||||
fullScore = (response.internet_score + calculateAudioLatency(response.my_audio_latency) + calculateAudioLatency(response.last_jam_audio_latency)) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
// latency badge template needs these 2 properties
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
var notificationBatchSize = 20;
|
||||
var currentNotificationPage = 0;
|
||||
var didLoadAllNotifications = false, isLoading = false;
|
||||
var ui = new context.JK.UIHelper(JK.app);
|
||||
|
||||
function isNotificationsPanelVisible() {
|
||||
return $contents.is(':visible')
|
||||
|
|
@ -422,7 +423,7 @@
|
|||
var $action_btn = $notification.find($btnNotificationAction);
|
||||
$action_btn.text('SESSION DETAILS');
|
||||
$action_btn.click(function() {
|
||||
context.JK.popExternalLink('/sessions/' + payload.session_id + '/details');
|
||||
openSessionInfoWebPage({"session_id": payload.session_id});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -843,10 +844,12 @@
|
|||
}, [{
|
||||
id: "btn-more-info",
|
||||
text: "MORE INFO",
|
||||
"layout-action": "close",
|
||||
href: JK.root_url + "/sessions/" + payload.session_id + "/details",
|
||||
rel: "external",
|
||||
"class": "button-orange"
|
||||
"class": "button-orange",
|
||||
callback: openSessionInfoWebPage,
|
||||
callback_args: {
|
||||
"session_id": payload.session_id
|
||||
}
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
|
@ -865,10 +868,12 @@
|
|||
"icon_url": context.JK.resolveAvatarUrl(payload.photo_url)
|
||||
}, [{
|
||||
id: "btn-manage-rsvp",
|
||||
text: "Manage RSVP",
|
||||
"layout-action": "close",
|
||||
href: "/client#/account/sessionDetail/" + payload.session_id,
|
||||
"class": "button-orange"
|
||||
text: "MANAGE RSVP",
|
||||
"class": "button-orange",
|
||||
callback: navigateToSessionDetails,
|
||||
callback_args: {
|
||||
"session_id": payload.session_id
|
||||
}
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
|
@ -886,11 +891,14 @@
|
|||
"icon_url": context.JK.resolveAvatarUrl(payload.photo_url)
|
||||
}, [{
|
||||
id: "btn-session-details",
|
||||
text: "Session Details",
|
||||
text: "SESSION DETAILS",
|
||||
"layout-action": "close",
|
||||
href: JK.root_url + "/sessions/" + payload.session_id + "/details",
|
||||
rel: "external",
|
||||
"class": "button-orange"
|
||||
"class": "button-orange",
|
||||
callback: openSessionInfoWebPage,
|
||||
callback_args: {
|
||||
"session_id": payload.session_id
|
||||
}
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
|
@ -908,11 +916,13 @@
|
|||
"icon_url": context.JK.resolveAvatarUrl(payload.photo_url)
|
||||
}, [{
|
||||
id: "btn-session-details",
|
||||
text: "Session Details",
|
||||
"layout-action": "close",
|
||||
href: JK.root_url + "/sessions/" + payload.session_id + "/details",
|
||||
text: "SESSION DETAILS",
|
||||
rel: "external",
|
||||
"class": "button-orange"
|
||||
"class": "button-orange",
|
||||
callback: openSessionInfoWebPage,
|
||||
callback_args: {
|
||||
"session_id": payload.session_id
|
||||
}
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
|
@ -930,11 +940,13 @@
|
|||
"icon_url": context.JK.resolveAvatarUrl(payload.photo_url)
|
||||
}, [{
|
||||
id: "btn-session-details",
|
||||
text: "Session Details",
|
||||
"layout-action": "close",
|
||||
href: JK.root_url + "/sessions/" + payload.session_id + "/details",
|
||||
text: "SESSION DETAILS",
|
||||
rel: "external",
|
||||
"class": "button-orange"
|
||||
"class": "button-orange",
|
||||
callback: openSessionInfoWebPage,
|
||||
callback_args: {
|
||||
"session_id": payload.session_id
|
||||
}
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
|
@ -952,11 +964,13 @@
|
|||
"icon_url": context.JK.resolveAvatarUrl(payload.photo_url)
|
||||
}, [{
|
||||
id: "btn-session-details",
|
||||
text: "Session Details",
|
||||
"layout-action": "close",
|
||||
href: JK.root_url + "/sessions/" + payload.session_id + "/details",
|
||||
text: "SESSION DETAILS",
|
||||
rel: "external",
|
||||
"class": "button-orange"
|
||||
"class": "button-orange",
|
||||
callback: openSessionInfoWebPage,
|
||||
callback_args: {
|
||||
"session_id": payload.session_id
|
||||
}
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
|
@ -974,11 +988,13 @@
|
|||
"icon_url": context.JK.resolveAvatarUrl(payload.photo_url)
|
||||
}, [{
|
||||
id: "btn-session-details",
|
||||
text: "Session Details",
|
||||
"layout-action": "close",
|
||||
href: JK.root_url + "/sessions/" + payload.session_id + "/details",
|
||||
text: "SESSION DETAILS",
|
||||
rel: "external",
|
||||
"class": "button-orange"
|
||||
"class": "button-orange",
|
||||
callback: openSessionInfoWebPage,
|
||||
callback_args: {
|
||||
"session_id": payload.session_id
|
||||
}
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
|
@ -996,11 +1012,13 @@
|
|||
"icon_url": context.JK.resolveAvatarUrl(payload.photo_url)
|
||||
}, [{
|
||||
id: "btn-session-details",
|
||||
text: "Session Details",
|
||||
"layout-action": "close",
|
||||
href: JK.root_url + "/sessions/" + payload.session_id + "/details",
|
||||
text: "SESSION DETAILS",
|
||||
rel: "external",
|
||||
"class": "button-orange"
|
||||
"class": "button-orange",
|
||||
callback: openSessionInfoWebPage,
|
||||
callback_args: {
|
||||
"session_id": payload.session_id
|
||||
}
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
|
@ -1019,11 +1037,13 @@
|
|||
"icon_url": context.JK.resolveAvatarUrl(payload.photo_url)
|
||||
}, [{
|
||||
id: "btn-session-details",
|
||||
text: "Session Details",
|
||||
"layout-action": "close",
|
||||
href: JK.root_url + "/sessions/" + payload.session_id + "/details",
|
||||
text: "SESSION DETAILS",
|
||||
rel: "external",
|
||||
"class": "button-orange"
|
||||
"class": "button-orange",
|
||||
callback: openSessionInfoWebPage,
|
||||
callback_args: {
|
||||
"session_id": payload.session_id
|
||||
}
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
|
@ -1101,7 +1121,7 @@
|
|||
"class": "button-orange",
|
||||
callback: shareRecording,
|
||||
callback_args: {
|
||||
"recording_id": payload.recording_id
|
||||
"claimed_recording_id": payload.claimed_recording_id
|
||||
}
|
||||
}]
|
||||
);
|
||||
|
|
@ -1109,7 +1129,9 @@
|
|||
}
|
||||
|
||||
function shareRecording(args) {
|
||||
var recordingId = args.recording_id;
|
||||
var claimedRecordingId = args.claimed_recording_id;
|
||||
|
||||
ui.launchShareDialog(claimedRecordingId, 'recording');
|
||||
}
|
||||
|
||||
function registerBandInvitation() {
|
||||
|
|
@ -1231,6 +1253,14 @@
|
|||
context.JK.popExternalLink('/recordings/' + args.recording_id);
|
||||
}
|
||||
|
||||
function navigateToSessionDetails(args) {
|
||||
context.location = '/client#/account/sessionDetail/' + args.session_id;
|
||||
}
|
||||
|
||||
function openSessionInfoWebPage(args) {
|
||||
context.JK.popExternalLink('/sessions/' + args.session_id + '/details');
|
||||
}
|
||||
|
||||
function deleteNotificationHandler(evt) {
|
||||
evt.stopPropagation();
|
||||
var notificationId = $(this).attr('notification-id');
|
||||
|
|
|
|||
|
|
@ -84,17 +84,25 @@ class RecordingUtils
|
|||
mixStateClass = 'discarded'
|
||||
mixState = 'discarded'
|
||||
else
|
||||
mixStateMsg = 'STILL UPLOADING'
|
||||
mixStateClass = 'still-uploading'
|
||||
mixState = 'still-uploading'
|
||||
|
||||
return {
|
||||
if mix.fake and mix.discarded
|
||||
mixStateMsg = 'DISCARDED'
|
||||
mixStateClass = 'discarded'
|
||||
mixState = 'discarded'
|
||||
else
|
||||
mixStateMsg = 'STILL UPLOADING'
|
||||
mixStateClass = 'still-uploading'
|
||||
mixState = 'still-uploading'
|
||||
|
||||
result = {
|
||||
mixStateMsg: mixStateMsg,
|
||||
mixStateClass: mixStateClass,
|
||||
mixState: mixState,
|
||||
isError: mixState == 'error'
|
||||
}
|
||||
|
||||
result
|
||||
|
||||
onMixHover: () ->
|
||||
$mix = $(this).closest('.mix')
|
||||
mixStateInfo = $mix.data('mix-state')
|
||||
|
|
@ -114,7 +122,10 @@ class RecordingUtils
|
|||
serverInfo = $mix.data('server-info')
|
||||
|
||||
# lie if this is a virtualized mix (i.e., mix is created after recording is made)
|
||||
mixState = 'still-uploading' if !serverInfo? or serverInfo.fake
|
||||
if !serverInfo?
|
||||
mixState = 'still-uploading'
|
||||
else if serverInfo.fake
|
||||
mixState = if serverInfo.discarded then 'discarded' else 'still-uploading'
|
||||
|
||||
summary = ''
|
||||
if mixState == 'still-uploading'
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
var friendInput = null;
|
||||
|
||||
// Main layout
|
||||
var $screen = null;
|
||||
var $screen = $('#create-session-layout');
|
||||
var $wizardSteps = null;
|
||||
var $currentWizardStep = null;
|
||||
var step = 0;
|
||||
|
|
@ -42,6 +42,7 @@
|
|||
var $languageList = null;
|
||||
var $sessionPlusMusiciansLabel = null;
|
||||
var $editScheduledSessions = null;
|
||||
var $inputFiles = $screen.find('#session-select-files');
|
||||
var $btnSelectFiles = null;
|
||||
var $selectedFilenames = null;
|
||||
var $uploadSpinner = null;
|
||||
|
|
@ -1032,7 +1033,6 @@
|
|||
}
|
||||
|
||||
function changeSelectedFiles() {
|
||||
var $inputFiles = $('#session-step-2 #session-select-files');
|
||||
var fileNames = [];
|
||||
var files = $inputFiles.get(0).files;
|
||||
var error = false;
|
||||
|
|
@ -1070,7 +1070,7 @@
|
|||
}
|
||||
|
||||
event.preventDefault();
|
||||
$('#session-select-files').trigger('click');
|
||||
$inputFiles.trigger('click');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1186,8 +1186,6 @@
|
|||
function events() {
|
||||
$createTypes.on("ifChanged", toggleCreateType);
|
||||
$startTimeList.on('change', function() { toggleStartTime(); });
|
||||
$btnSelectFiles.on('click', toggleSelectFiles);
|
||||
$('#session-step-2 #session-select-files').on('change', changeSelectedFiles);
|
||||
$policyTypes.on("ifChanged", togglePolicyTypeChanged);
|
||||
$('#session-step-4 #session-musician-access').on('change', toggleMusicianAccessTypes);
|
||||
$('#session-step-4 #session-fans-access').on('change', toggleFanAccessTypes);
|
||||
|
|
@ -1205,6 +1203,9 @@
|
|||
});
|
||||
|
||||
$(friendInput).focus(function() { $(this).val(''); })
|
||||
|
||||
$inputFiles.on('change', changeSelectedFiles);
|
||||
$btnSelectFiles.on('click', toggleSelectFiles);
|
||||
}
|
||||
|
||||
function initialize(invitationDialogInstance, friendSelectorDialog, instrumentSelectorInstance, instrumentRSVPSelectorInstance) {
|
||||
|
|
@ -1221,7 +1222,6 @@
|
|||
var screenBindings = {'beforeShow': beforeShow, 'afterShow': afterShow};
|
||||
app.bindScreen('createSession', screenBindings);
|
||||
|
||||
$screen = $('#create-session-layout');
|
||||
$wizardSteps = $screen.find('.create-session-wizard');
|
||||
$templateSteps = $('#template-session-steps');
|
||||
$templateButtons = $('#template-session-buttons');
|
||||
|
|
|
|||
|
|
@ -371,6 +371,14 @@
|
|||
if(response["errors"] && response["errors"]["tracks"] && response["errors"]["tracks"][0] == "Please select at least one track") {
|
||||
app.notifyAlert("No Inputs Configured", $('<span>You will need to reconfigure your audio device.</span>'));
|
||||
}
|
||||
else if(response["errors"] && response["errors"]["music_session"] && response["errors"]["music_session"][0] == ["is currently recording"]) {
|
||||
promptLeave = false;
|
||||
context.window.location = "/client#/findSession";
|
||||
app.notify( { title: "Unable to Join Session", text: "The session is currently recording." }, null, true);
|
||||
}
|
||||
else {
|
||||
app.notifyServerError(xhr, 'Unable to Join Session');
|
||||
}
|
||||
}
|
||||
else {
|
||||
app.notifyServerError(xhr, 'Unable to Join Session');
|
||||
|
|
@ -396,7 +404,12 @@
|
|||
if(screenActive) {
|
||||
// this path is possible if FTUE is invoked on session page, and they cancel
|
||||
sessionModel.leaveCurrentSession()
|
||||
.fail(app.ajaxError);
|
||||
.fail(function(jqXHR) {
|
||||
if(jqXHR.status != 404) {
|
||||
logger.debug("leave session failed");
|
||||
app.ajaxError(arguments)
|
||||
}
|
||||
});
|
||||
}
|
||||
screenActive = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -184,10 +184,10 @@
|
|||
leaveSessionRest(currentSessionId)
|
||||
.done(function() {
|
||||
sessionChanged();
|
||||
deferred.resolve(arguments);
|
||||
deferred.resolve(arguments[0], arguments[1], arguments[2]);
|
||||
})
|
||||
.fail(function() {
|
||||
deferred.reject(arguments);
|
||||
deferred.reject(arguments[0], arguments[1], arguments[2]);
|
||||
});
|
||||
|
||||
// 'unregister' for callbacks
|
||||
|
|
|
|||
|
|
@ -133,6 +133,11 @@
|
|||
rest.getSession(sessionId)
|
||||
.done(function(response) {
|
||||
session = response;
|
||||
if(session && session.recording) {
|
||||
context.JK.app.notify( { title: "Unable to Join Session", text: "The session is currently recording." }, null, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if ("invitations" in session) {
|
||||
var invitation;
|
||||
// user has invitations for this session
|
||||
|
|
|
|||
|
|
@ -220,6 +220,7 @@ context.JK.SyncViewer = class SyncViewer
|
|||
updateTrackState: ($track) =>
|
||||
clientInfo = $track.data('client-info')
|
||||
serverInfo = $track.data('server-info')
|
||||
myTrack = serverInfo.user.id == context.JK.currentUserId
|
||||
|
||||
# determine client state
|
||||
clientStateMsg = 'UNKNOWN'
|
||||
|
|
@ -246,7 +247,7 @@ context.JK.SyncViewer = class SyncViewer
|
|||
clientStateClass = 'missing'
|
||||
clientState = @clientStates.missing
|
||||
else
|
||||
clientStateClass = 'DISCARDED'
|
||||
clientStateMsg = 'DISCARDED'
|
||||
clientStateClass = 'discarded'
|
||||
clientState = @clientStates.discarded
|
||||
|
||||
|
|
@ -261,7 +262,7 @@ context.JK.SyncViewer = class SyncViewer
|
|||
uploadStateClass = 'error'
|
||||
uploadState = @uploadStates.too_many_upload_failures
|
||||
else
|
||||
if serverInfo.user.id == context.JK.currentUserId
|
||||
if myTrack
|
||||
if clientInfo?
|
||||
if clientInfo.local_state == 'HQ'
|
||||
uploadStateMsg = 'PENDING UPLOAD'
|
||||
|
|
@ -282,7 +283,7 @@ context.JK.SyncViewer = class SyncViewer
|
|||
else
|
||||
uploadStateMsg = 'UPLOADED'
|
||||
uploadStateClass = 'uploaded'
|
||||
if serverInfo.user.id == context.JK.currentUserId
|
||||
if myTrack
|
||||
uploadState = @uploadStates.me_uploaded
|
||||
else
|
||||
uploadState = @uploadStates.them_uploaded
|
||||
|
|
@ -301,6 +302,30 @@ context.JK.SyncViewer = class SyncViewer
|
|||
$uploadStateMsg.text(uploadStateMsg)
|
||||
$uploadStateProgress.css('width', '0')
|
||||
|
||||
# this allows us to make styling decisions based on the combination of both client and upload state.
|
||||
$track.addClass("clientState-#{clientStateClass}").addClass("uploadState-#{uploadStateClass}")
|
||||
|
||||
$clientRetry = $clientState.find('.retry')
|
||||
$uploadRetry = $uploadState.find('.retry')
|
||||
|
||||
if gon.isNativeClient
|
||||
# handle client state
|
||||
|
||||
# only show RETRY button if you have a SQ or if it's missing, and it's been uploaded already
|
||||
if (clientState == @clientStates.sq or clientState == @clientStates.missing) and (uploadState == @uploadStates.me_uploaded or uploadState == @uploadStates.them_uploaded)
|
||||
$clientRetry.show()
|
||||
else
|
||||
$clientRetry.hide()
|
||||
|
||||
# only show RETRY button if you have the HQ track, it's your track, and the server doesn't yet have it
|
||||
if myTrack and @clientStates.hq and (uploadState == @uploadStates.error or uploadState == @uploadStates.me_upload_soon)
|
||||
$uploadRetry.show()
|
||||
else
|
||||
$uploadRetry.hide()
|
||||
else
|
||||
$clientRetry.hide()
|
||||
$uploadRetry.hide()
|
||||
|
||||
associateClientInfo: (recording) =>
|
||||
for clientInfo in recording.local_tracks
|
||||
$track = @list.find(".recorded-track[data-recording-id='#{recording.recording_id}'][data-client-track-id='#{clientInfo.client_track_id}']")
|
||||
|
|
@ -485,7 +510,14 @@ context.JK.SyncViewer = class SyncViewer
|
|||
recordingInfo = null
|
||||
if userSync == 'fake'
|
||||
recordingInfo = arguments[1]
|
||||
userSync = { recording_id: recordingInfo.id, duration: recordingInfo.duration, fake:true }
|
||||
# sift through the recorded_tracks in here; if they are marked discarded, then we can also mark this one discarded too
|
||||
discarded = true
|
||||
for claim in recordingInfo.claimed_recordings
|
||||
if claim.user_id == context.JK.currentUserId
|
||||
discarded = false
|
||||
break
|
||||
|
||||
userSync = { recording_id: recordingInfo.id, duration: recordingInfo.duration, fake:true, discarded: discarded }
|
||||
$mix = $(context._.template(@templateMix.html(), userSync, {variable: 'data'}))
|
||||
else
|
||||
$mix = $(context._.template(@templateMix.html(), userSync, {variable: 'data'}))
|
||||
|
|
@ -504,14 +536,16 @@ context.JK.SyncViewer = class SyncViewer
|
|||
$track.data('sync-viewer', this)
|
||||
$clientState = $track.find('.client-state')
|
||||
$uploadState = $track.find('.upload-state')
|
||||
$clientState.find('.retry').click(this.retryDownloadRecordedTrack)
|
||||
$uploadState.find('.retry').click(this.retryUploadRecordedTrack)
|
||||
$clientStateRetry = $clientState.find('.retry')
|
||||
$clientStateRetry.click(this.retryDownloadRecordedTrack)
|
||||
$uploadStateRetry = $uploadState.find('.retry')
|
||||
$uploadStateRetry.click(this.retryUploadRecordedTrack)
|
||||
context.JK.bindHoverEvents($track)
|
||||
context.JK.bindInstrumentHover($track, {positions:['top'], shrinkToFit: true});
|
||||
context.JK.hoverBubble($clientState, this.onHoverOfStateIndicator, {width:'450px', closeWhenOthersOpen: true, positions:['left']})
|
||||
context.JK.hoverBubble($uploadState, this.onHoverOfStateIndicator, {width:'450px', closeWhenOthersOpen: true, positions:['right']})
|
||||
$clientState.addClass('is-native-client') if context.jamClient.IsNativeClient()
|
||||
$uploadState.addClass('is-native-client') if context.jamClient.IsNativeClient()
|
||||
$clientState.addClass('is-native-client') if gon.isNativeClient
|
||||
$uploadState.addClass('is-native-client') if gon.isNativeClient
|
||||
$track
|
||||
|
||||
createStreamMix: (userSync) =>
|
||||
|
|
@ -523,8 +557,8 @@ context.JK.SyncViewer = class SyncViewer
|
|||
$uploadState.find('.retry').click(this.retryUploadRecordedTrack)
|
||||
context.JK.hoverBubble($clientState, this.onStreamMixHover, {width:'450px', closeWhenOthersOpen: true, positions:['left']})
|
||||
context.JK.hoverBubble($uploadState, this.onStreamMixHover, {width:'450px', closeWhenOthersOpen: true, positions:['right']})
|
||||
$clientState.addClass('is-native-client') if context.jamClient.IsNativeClient()
|
||||
$uploadState.addClass('is-native-client') if context.jamClient.IsNativeClient()
|
||||
$clientState.addClass('is-native-client') if gon.isNativeClient
|
||||
$uploadState.addClass('is-native-client') if gon.isNativeClient
|
||||
$track
|
||||
|
||||
exportRecording: (e) =>
|
||||
|
|
|
|||
|
|
@ -47,12 +47,19 @@
|
|||
return rsvpDialog.showDialog();
|
||||
}
|
||||
|
||||
function launchRsvpCreateSlotDialog(sessionId, instrumentIds, rsvpRequesterName, createSlotsCallback) {
|
||||
var rsvpDialog = new JK.RsvpCreateSlotDialog(JK.app, sessionId, instrumentIds, rsvpRequesterName, createSlotsCallback);
|
||||
rsvpDialog.initialize();
|
||||
return rsvpDialog.showDialog();
|
||||
}
|
||||
|
||||
this.addSessionLike = addSessionLike;
|
||||
this.addRecordingLike = addRecordingLike;
|
||||
this.launchCommentDialog = launchCommentDialog;
|
||||
this.launchShareDialog = launchShareDialog;
|
||||
this.launchRsvpSubmitDialog = launchRsvpSubmitDialog;
|
||||
this.launchRsvpCancelDialog = launchRsvpCancelDialog;
|
||||
this.launchRsvpCreateSlotDialog = launchRsvpCreateSlotDialog;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@
|
|||
|
||||
function togglePlay() {
|
||||
if(playing) {
|
||||
$status.text('SESSION IN PROGRESS');
|
||||
$status.text('LIVE SESSION IN PROGRESS');
|
||||
stopPlay();
|
||||
}
|
||||
else {
|
||||
|
|
|
|||
|
|
@ -452,6 +452,25 @@
|
|||
.action-bar {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
#selected-filenames {
|
||||
margin-top:10px;
|
||||
font-size:12px;
|
||||
|
||||
margin-left: 5px;
|
||||
li {
|
||||
margin-bottom:1px;
|
||||
white-space:nowrap;
|
||||
line-height:14px;
|
||||
}
|
||||
|
||||
li span {
|
||||
white-space:nowrap;
|
||||
text-overflow:ellipsis;
|
||||
overflow:hidden;
|
||||
display:block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** account sessions */
|
||||
|
|
|
|||
|
|
@ -180,6 +180,7 @@ $fair: #cc9900;
|
|||
|
||||
|
||||
@mixin client-state-box {
|
||||
|
||||
.client-state {
|
||||
position:relative;
|
||||
text-align:center;
|
||||
|
|
@ -193,7 +194,6 @@ $fair: #cc9900;
|
|||
|
||||
&.error {
|
||||
background-color: $error;
|
||||
&.is-native-client { .retry { display:inline-block; } }
|
||||
}
|
||||
|
||||
&.hq {
|
||||
|
|
@ -202,12 +202,10 @@ $fair: #cc9900;
|
|||
|
||||
&.sq {
|
||||
background-color: $good;
|
||||
&.is-native-client { .retry { display:inline-block; } }
|
||||
}
|
||||
|
||||
&.missing {
|
||||
background-color: $error;
|
||||
&.is-native-client { .retry { display:inline-block; } }
|
||||
}
|
||||
|
||||
&.discarded {
|
||||
|
|
@ -240,7 +238,6 @@ $fair: #cc9900;
|
|||
|
||||
&.error {
|
||||
background-color: $error;
|
||||
&.is-native-client { .retry { display:inline-block; } }
|
||||
}
|
||||
|
||||
&.missing {
|
||||
|
|
@ -249,7 +246,6 @@ $fair: #cc9900;
|
|||
|
||||
&.upload-soon {
|
||||
background-color: $fair;
|
||||
&.is-native-client { .retry { display:inline-block; } }
|
||||
}
|
||||
|
||||
&.uploaded {
|
||||
|
|
@ -278,7 +274,7 @@ $fair: #cc9900;
|
|||
color:white;
|
||||
|
||||
&.still-uploading { background-color: $fair; }
|
||||
&.discard {background-color: $unknown; }
|
||||
&.discarded {background-color: $unknown; }
|
||||
&.unknown { background-color: $unknown; }
|
||||
&.error { background-color: $error; }
|
||||
&.mixed { background-color: $good; }
|
||||
|
|
|
|||
|
|
@ -16,6 +16,10 @@ class ApiController < ApplicationController
|
|||
@exception = exception
|
||||
render "errors/permission_error", :status => 403
|
||||
end
|
||||
rescue_from 'JamRuby::ConflictError' do |exception|
|
||||
@exception = exception
|
||||
render "errors/conflict_error", :status => 409
|
||||
end
|
||||
rescue_from 'ActiveRecord::RecordNotFound' do |exception|
|
||||
@@log.debug(exception)
|
||||
render :json => { :errors => { :resource => ["record not found"] } }, :status => 404
|
||||
|
|
|
|||
|
|
@ -212,13 +212,16 @@ class ApiMusicSessionsController < ApiController
|
|||
@music_session.band = (params[:band] ? Band.find(params[:band]) : nil) if params.include? :band
|
||||
@music_session.save
|
||||
|
||||
params[:music_notations].each do |notation_id|
|
||||
notation = MusicNotation.find(notation_id)
|
||||
notation.music_session = ms
|
||||
notation.save
|
||||
if params.include? :music_notations
|
||||
notations = JSON.parse(params[:music_notations])
|
||||
notations.each do |n|
|
||||
notation = MusicNotation.find(n["id"])
|
||||
notation.music_session = @music_session
|
||||
notation.save
|
||||
|
||||
ms.music_notations << notation
|
||||
end if params.include? :music_notations
|
||||
@music_session.music_notations << notation
|
||||
end
|
||||
end
|
||||
|
||||
if @music_session.errors.any?
|
||||
response.status = :unprocessable_entity
|
||||
|
|
|
|||
|
|
@ -75,11 +75,11 @@ module FeedsHelper
|
|||
end
|
||||
|
||||
def recording_artist_name(recording)
|
||||
(recording.band.nil? ? nil : recording.band.name) || recording.candidate_claimed_recording.user.name
|
||||
(recording.band.nil? ? nil : recording.band.name) || recording.owner.name
|
||||
end
|
||||
|
||||
def recording_artist_id(recording)
|
||||
(recording.band.nil? ? nil : recording.band.id) || recording.candidate_claimed_recording.user.id
|
||||
(recording.band.nil? ? nil : recording.band.id) || recording.owner.id
|
||||
end
|
||||
|
||||
def recording_artist_hoveraction(recording)
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@
|
|||
{{data.latency}}
|
||||
%td.rsvp-buttons
|
||||
%a{href: "/client#/profile/{{data.user_id}}", class: 'button-orange left', 'user-id' => "{{data.user_id}}"} PROFILE
|
||||
%a{href: "#", class: 'button-orange left approveRsvpRequest', 'user-id' => "{{data.user_id}}", 'request-id' => "{{data.request_id}}"} APPROVE
|
||||
%a{href: "#", class: 'button-orange left approveRsvpRequest', 'data-instrument-text' => "{{data.instrument_text}}", 'user-id' => "{{data.user_id}}", 'request-id' => "{{data.request_id}}", 'user-name' => "{{data.user_name}}"} APPROVE
|
||||
%a{href: "#", class: 'button-orange left declineRsvpRequest', 'user-id' => "{{data.user_id}}", 'request-id' => "{{data.request_id}}"} DECLINE
|
||||
.clearall
|
||||
.clearall
|
||||
|
|
|
|||
|
|
@ -98,12 +98,12 @@
|
|||
Notation Files:
|
||||
.right-column
|
||||
.spinner-small.upload-spinner
|
||||
.selected-files-section
|
||||
%ul#selected-filenames
|
||||
.select-files-section
|
||||
%a{href: "#", class: "button-orange btn-select-files", id: "select-notation-files"} SELECT FILES...
|
||||
%input{type: "file", class: "hidden", id: "session-prop-select-files", value: "Select Files...",
|
||||
%a.button-orange.btn-select-files SELECT FILES...
|
||||
%input{type: "file", class: "hidden", id: "session-select-files", value: "Select Files...",
|
||||
accept: ".pdf, .png, .jpg, .jpeg, .gif, .xml, .mxl, .txt", multiple: "true"}
|
||||
.selected-files-section
|
||||
%ul#selected-filenames
|
||||
.clearall
|
||||
.clearall
|
||||
.clearall
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@
|
|||
%div{:id => "settings-selected-filenames"}
|
||||
.right.ib.mb10
|
||||
%a.button-orange.btn-select-files SELECT FILES...
|
||||
%input.hidden{:type => "file", :id => "settings-select-files", :value => "Select Files...", :accept => ".pdf, .png, .jpg, .jpeg, .gif, .xml, .mxl, .txt"}
|
||||
%input.hidden{:type => "file", :id => "session-select-files", :value => "Select Files...", :accept => ".pdf, .png, .jpg, .jpeg, .gif, .xml, .mxl, .txt"}
|
||||
.spinner-small.upload-spinner
|
||||
|
||||
.clearall.right.mt10
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
= render 'dialogs/commentDialog'
|
||||
= render 'dialogs/rsvpSubmitDialog'
|
||||
= render 'dialogs/rsvpCancelDialog'
|
||||
= render 'dialogs/rsvpCreateSlotDialog'
|
||||
= render 'dialogs/sessionCancelDialog'
|
||||
= render 'dialogs/signinDialog'
|
||||
= render 'dialogs/signupDialog'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
.dialog.dialog-overlay-sm layout='dialog' layout-id='rsvp-create-slot-dialog' id='rsvp-create-slot-dialog'
|
||||
.content-head
|
||||
= image_tag "content/icon_alert.png", {:width => 24, :height => 24, :class => 'content-icon' }
|
||||
h1 RSVP Slot Already Filled
|
||||
|
||||
.dialog-inner
|
||||
div.instructions
|
||||
br
|
||||
div.instruments
|
||||
.buttons
|
||||
.right
|
||||
a.button-grey class='btnCancel' layout-action='cancel' NO
|
||||
a.button-orange class='btnSave' YES
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
.schedule-recurrence
|
||||
.part
|
||||
.slot-instructions Check the box(es) next to the track(s) you want to play in the session:
|
||||
.error{:style => 'display:none'} You must select at least 1 instrument.
|
||||
.error{:style => 'display:none'}
|
||||
.rsvp-instruments
|
||||
|
||||
.comment-instructions Enter a message to the other musicians in the session (optional):
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
object @exception
|
||||
|
||||
attributes :message
|
||||
|
||||
node "type" do
|
||||
"ConflictError"
|
||||
end
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
<% end %>
|
||||
|
||||
<div class="recordings-page">
|
||||
<% if @claimed_recording.is_public %>
|
||||
<% if @claimed_recording.is_public || @claimed_recording.recording.has_access?(current_user) %>
|
||||
<div class="landing-band">
|
||||
<% unless @claimed_recording.recording.band.blank? %>
|
||||
<div class="landing-avatar">
|
||||
|
|
@ -97,7 +97,7 @@
|
|||
<% end %>
|
||||
</div>
|
||||
|
||||
<% if @claimed_recording.is_public %>
|
||||
<% if @claimed_recording.is_public || @claimed_recording.recording.has_access?(current_user) %>
|
||||
<% if signed_in? %>
|
||||
<% unless @claimed_recording.recording.band.nil? %>
|
||||
<%= render :partial => "shared/landing_sidebar", :locals => {:user => @claimed_recording.recording.band, :recent_history => @claimed_recording.recording.band.recent_history} %>
|
||||
|
|
|
|||
|
|
@ -178,6 +178,8 @@ if defined?(Bundler)
|
|||
|
||||
config.audiomixer_path = "/var/lib/audiomixer/audiomixer/audiomixerapp"
|
||||
config.ffmpeg_path = ENV['FFMPEG_PATH'] || (File.exist?('/usr/local/bin/ffmpeg') ? '/usr/local/bin/ffmpeg' : '/usr/bin/ffmpeg')
|
||||
config.normalize_ogg_path = ENV['NORMALIZE_OGG_PATH'] || (File.exist?('/usr/local/bin/normalize-ogg') ? '/usr/local/bin/normalize-ogg' : '/usr/bin/normalize-ogg')
|
||||
config.normalize_mp3_path = ENV['NORMALIZE_MP3_PATH'] || (File.exist?('/usr/local/bin/normalize-mp3') ? '/usr/local/bin/normalize-mp3' : '/usr/bin/normalize-mp3')
|
||||
|
||||
# if it looks like linux, use init.d script; otherwise use kill
|
||||
config.icecast_reload_cmd = ENV['ICECAST_RELOAD_CMD'] || (File.exist?('/usr/local/bin/icecast2') ? "bash -l -c #{Shellwords.escape("sudo /etc/init.d/icecast2 reload")}" : "bash -l -c #{Shellwords.escape("kill -1 `ps -f | grep /usr/local/bin/icecast | grep -v grep | awk \'{print $2}\'`")}")
|
||||
|
|
|
|||
|
|
@ -11,6 +11,26 @@ describe "Music Session", :js => true, :type => :feature, :capybara_feature => t
|
|||
|
||||
subject { page }
|
||||
|
||||
describe "recorded session" do
|
||||
|
||||
before(:each) do
|
||||
ActiveMusicSession.delete_all
|
||||
MusicSession.delete_all
|
||||
end
|
||||
|
||||
let(:searcher) { FactoryGirl.create(:user) }
|
||||
let(:creator) { FactoryGirl.create(:user) }
|
||||
let(:conn) { FactoryGirl.create(:connection, :user => creator) }
|
||||
let(:description) {'hot recordings in here'}
|
||||
let(:session) {FactoryGirl.create(:active_music_session, creator:creator, description: description)}
|
||||
let(:recording) {FactoryGirl.create(:recording, music_session: session, owner: creator)}
|
||||
|
||||
it "won't let user join" do
|
||||
recording.touch
|
||||
join_session(searcher, description:'hot recordings in here', no_verify:true)
|
||||
find('#notification p').text('The session is currently recording.')
|
||||
end
|
||||
end
|
||||
|
||||
context "last person" do
|
||||
before(:each) do
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe "Landing", :js => true, :type => :feature, :capybara_feature => true do
|
||||
describe "Landing" do
|
||||
|
||||
let (:user) { FactoryGirl.create(:user) }
|
||||
|
||||
|
|
@ -10,41 +10,70 @@ describe "Landing", :js => true, :type => :feature, :capybara_feature => true do
|
|||
Recording.delete_all
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
MusicSession.delete_all
|
||||
sign_in_poltergeist(user)
|
||||
end
|
||||
|
||||
let (:claimed_recording) { FactoryGirl.create(:claimed_recording) }
|
||||
let (:recording) { claimed_recording.recording }
|
||||
|
||||
it "should render comments" do
|
||||
describe "no js required" do
|
||||
|
||||
recording = ClaimedRecording.first
|
||||
comment = "test comment"
|
||||
timestamp = "less than a minute ago"
|
||||
url = "/recordings/#{claimed_recording.id}"
|
||||
visit url
|
||||
it "shows private recording to someone who was in the session" do
|
||||
# make the session hidden
|
||||
claimed_recording.is_public = false
|
||||
claimed_recording.save!
|
||||
|
||||
fill_in "txtRecordingComment", with: comment
|
||||
find('#btnPostComment').trigger(:click)
|
||||
visit "/recordings/#{claimed_recording.id}"
|
||||
|
||||
# (1) Test a user creating a comment and ensure it displays.
|
||||
# and verify that after we visit the page, we can see the name of it
|
||||
find('strong', text: 'RECORDING NOT FOUND')
|
||||
|
||||
# comment body
|
||||
find('div.comment-text', text: comment)
|
||||
# log in the user who was a part of the session
|
||||
sign_in(claimed_recording.user)
|
||||
|
||||
# timestamp
|
||||
find('div.comment-timestamp', text: timestamp)
|
||||
visit "/recordings/#{claimed_recording.id}"
|
||||
|
||||
# (2) Test a user visiting a landing page with an existing comment.
|
||||
# and verify that after we visit the page, we can see the name of it
|
||||
find('h2', text: claimed_recording.name)
|
||||
end
|
||||
end
|
||||
|
||||
# re-visit page to reload from database
|
||||
visit url
|
||||
|
||||
# comment body
|
||||
find('div.comment-text', text: comment)
|
||||
describe "js required", :js => true, :type => :feature, :capybara_feature => true do
|
||||
|
||||
# timestamp
|
||||
find('div.comment-timestamp', text: timestamp)
|
||||
before(:each) do
|
||||
MusicSession.delete_all
|
||||
sign_in_poltergeist(user)
|
||||
end
|
||||
|
||||
|
||||
it "should render comments" do
|
||||
|
||||
recording = ClaimedRecording.first
|
||||
comment = "test comment"
|
||||
timestamp = "less than a minute ago"
|
||||
url = "/recordings/#{claimed_recording.id}"
|
||||
visit url
|
||||
|
||||
fill_in "txtRecordingComment", with: comment
|
||||
find('#btnPostComment').trigger(:click)
|
||||
|
||||
# (1) Test a user creating a comment and ensure it displays.
|
||||
|
||||
# comment body
|
||||
find('div.comment-text', text: comment)
|
||||
|
||||
# timestamp
|
||||
find('div.comment-timestamp', text: timestamp)
|
||||
|
||||
# (2) Test a user visiting a landing page with an existing comment.
|
||||
|
||||
# re-visit page to reload from database
|
||||
visit url
|
||||
|
||||
# comment body
|
||||
find('div.comment-text', text: comment)
|
||||
|
||||
# timestamp
|
||||
find('div.comment-timestamp', text: timestamp)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -417,9 +417,11 @@ def join_session(joiner, options)
|
|||
# verify the session description is seen by second client
|
||||
expect(page).to have_text(description)
|
||||
find('.join-link').trigger(:click)
|
||||
find('#btn-accept-terms').trigger(:click)
|
||||
expect(page).to have_selector('h2', text: 'my tracks')
|
||||
find('#session-screen .session-mytracks .session-track')
|
||||
unless options[:no_verify]
|
||||
find('#btn-accept-terms').trigger(:click)
|
||||
expect(page).to have_selector('h2', text: 'my tracks')
|
||||
find('#session-screen .session-mytracks .session-track')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ module JamWebsockets
|
|||
@router.periodical_check_connections
|
||||
|
||||
EventMachine::PeriodicTimer.new(2) do
|
||||
sane_logging { @router.periodical_check_connections }
|
||||
safety_net { sane_logging { @router.periodical_check_connections } }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -89,7 +89,7 @@ module JamWebsockets
|
|||
@router.periodical_check_clients
|
||||
|
||||
EventMachine::PeriodicTimer.new(30) do
|
||||
sane_logging { @router.periodical_check_clients }
|
||||
safety_net { sane_logging { @router.periodical_check_clients } }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -98,16 +98,29 @@ module JamWebsockets
|
|||
@router.periodical_flag_connections
|
||||
|
||||
EventMachine::PeriodicTimer.new(2) do
|
||||
sane_logging { @router.periodical_flag_connections }
|
||||
safety_net { sane_logging { @router.periodical_flag_connections } }
|
||||
end
|
||||
end
|
||||
|
||||
def start_stats_dump
|
||||
EventMachine::PeriodicTimer.new(60) do
|
||||
@router.periodical_stats_dump
|
||||
safety_net { @router.periodical_stats_dump }
|
||||
end
|
||||
end
|
||||
|
||||
# this was added for this reason: https://jamkazam.atlassian.net/browse/VRFS-2425
|
||||
# if an unhandled exception occurs in PeriodicTimer, it just kills all future timers; doesn't kill the app.
|
||||
# not really what you want.
|
||||
|
||||
# so, we signal to Bugsnag, so we know really bad stuff is happening, but we also move
|
||||
def safety_net(&blk)
|
||||
begin
|
||||
blk.call
|
||||
rescue => e
|
||||
Bugsnag.notify(e)
|
||||
@log.error("unhandled exception in EM Timer #{e}")
|
||||
end
|
||||
end
|
||||
def sane_logging(&blk)
|
||||
# used around repeated transactions that cause too much ActiveRecord::Base logging
|
||||
# example is handling heartbeats
|
||||
|
|
|
|||
Loading…
Reference in New Issue