faculty note support in new inbox
also pull in course/group user so we can use it in the future Change-Id: I34c2aea2fea9b56c988d4903fb2fcf32d96d4f10 Reviewed-on: https://gerrit.instructure.com/5190 Reviewed-by: Jon Jensen <jon@instructure.com> Tested-by: Hudson <hudson@instructure.com>
This commit is contained in:
parent
b77558c281
commit
274f8880ad
|
@ -20,6 +20,8 @@ class TokenInput
|
|||
@tokens.html('')
|
||||
@change?(@token_values())
|
||||
|
||||
@added = @options.added
|
||||
|
||||
@placeholder = $('<span />')
|
||||
@placeholder.text(@options.placeholder)
|
||||
@placeholder.appendTo(@fake_input) if @options.placeholder
|
||||
|
@ -95,6 +97,7 @@ class TokenInput
|
|||
@tokens.append($token)
|
||||
@val('') unless data?.no_clear
|
||||
@placeholder.hide()
|
||||
@added?(data.data) if data
|
||||
@change?(@token_values())
|
||||
@selector?.reposition()
|
||||
|
||||
|
@ -393,7 +396,7 @@ class TokenSelector
|
|||
state = !@input.has_token(value: id) unless state?
|
||||
if state
|
||||
@selection.addClass('on') if @selection_toggleable()
|
||||
@input.add_token value: id, text: @selection.find('b').text(), no_clear: true
|
||||
@input.add_token value: id, text: @selection.find('b').text(), no_clear: true, data: @selection.data('user_data')
|
||||
else
|
||||
@selection.removeClass('on')
|
||||
@input.remove_token value: id
|
||||
|
@ -538,6 +541,7 @@ I18n.scoped 'conversations', (I18n) ->
|
|||
$form.attr action: $selected_conversation.find('a.details_link').attr('add_url')
|
||||
|
||||
reset_message_form()
|
||||
$form.find('#user_note_info').showIf($selected_conversation?.hasClass('private')).find('input').attr('checked', false)
|
||||
$form.show().find(':input:visible:first').focus()
|
||||
|
||||
reset_message_form = ->
|
||||
|
@ -594,7 +598,7 @@ I18n.scoped 'conversations', (I18n) ->
|
|||
$selected_conversation.scrollIntoView()
|
||||
else
|
||||
if params and params.user_id and params.user_name
|
||||
$('#recipients').data('token_input').add_token value: params.user_id, text: params.user_name
|
||||
$('#recipients').data('token_input').add_token value: params.user_id, text: params.user_name, data: {id: params.user_id, name: params.user_name, can_add_notes: params.can_add_notes}
|
||||
$('#from_conversation_id').val(params.from_conversation_id)
|
||||
return
|
||||
|
||||
|
@ -603,7 +607,7 @@ I18n.scoped 'conversations', (I18n) ->
|
|||
|
||||
completion = (data) ->
|
||||
return unless is_selected($c)
|
||||
for user in data.participants when !MessageInbox.user_cache[user.id]
|
||||
for user in data.participants when !MessageInbox.user_cache[user.id]?.avatar
|
||||
MessageInbox.user_cache[user.id] = user
|
||||
user.html_name = html_name_for_user(user)
|
||||
$messages.show()
|
||||
|
@ -634,8 +638,8 @@ I18n.scoped 'conversations', (I18n) ->
|
|||
$form.loadingImage('remove')
|
||||
|
||||
MessageInbox.shared_contexts_for_user = (user, limit=2) ->
|
||||
shared_contexts = (course.name for course_id in user.course_ids when course = @contexts.courses[course_id]).
|
||||
concat(group.name for group_id in user.group_ids when group = @contexts.groups[group_id])
|
||||
shared_contexts = (course.name for course_id, roles of user.common_courses when course = @contexts.courses[course_id]).
|
||||
concat(group.name for group_id, roles of user.common_groups when group = @contexts.groups[group_id])
|
||||
shared_contexts.sort (a, b) ->
|
||||
a = a.toLowerCase()
|
||||
b = b.toLowerCase()
|
||||
|
@ -651,6 +655,12 @@ I18n.scoped 'conversations', (I18n) ->
|
|||
shared_contexts = MessageInbox.shared_contexts_for_user(user)
|
||||
$.htmlEscape(user.name) + if shared_contexts.length then " <em>" + $.htmlEscape(shared_contexts) + "</em>" else ''
|
||||
|
||||
can_add_notes_for = (user) ->
|
||||
return true if user.can_add_notes
|
||||
for course_id, roles of user.common_courses
|
||||
return true if 'StudentEnrollment' in roles and (MessageInbox.can_add_notes or MessageInbox.contexts.courses[course_id]?.can_add_notes)
|
||||
false
|
||||
|
||||
build_message = (data) ->
|
||||
$message = $("#message_blank").clone(true).attr('id', 'message_' + data.id)
|
||||
$message.data('id', data.id)
|
||||
|
@ -1287,6 +1297,11 @@ I18n.scoped 'conversations', (I18n) ->
|
|||
|
||||
$('.recipients').tokenInput
|
||||
placeholder: I18n.t('recipient_field_placeholder', "Enter a name, course, or group")
|
||||
added: (data) ->
|
||||
unless data.id and "#{data.id}".match(/^(course|group)_/)
|
||||
data = $.extend({}, data)
|
||||
delete data.avatar # since it's the wrong size and possibly a blank image
|
||||
MessageInbox.user_cache[data.id] ?= data
|
||||
selector:
|
||||
messages: {no_results: I18n.t('no_results', 'No results found')}
|
||||
populator: ($node, data, options={}) ->
|
||||
|
@ -1297,10 +1312,11 @@ I18n.scoped 'conversations', (I18n) ->
|
|||
$b = $('<b />')
|
||||
$b.text(data.name)
|
||||
$span = $('<span />')
|
||||
$span.text(MessageInbox.shared_contexts_for_user(data)) if data.course_ids?
|
||||
$span.text(MessageInbox.shared_contexts_for_user(data)) if data.common_courses?
|
||||
$node.append($b, $span)
|
||||
$node.attr('title', data.name)
|
||||
$node.data('id', data.id)
|
||||
$node.data('user_data', data)
|
||||
$node.addClass(if data.type then data.type else 'user')
|
||||
if options.level > 0
|
||||
$node.prepend('<a class="toggle"><i></i></a>')
|
||||
|
@ -1322,9 +1338,11 @@ I18n.scoped 'conversations', (I18n) ->
|
|||
if tokens.length > 1 or tokens[0]?.match(/^(course|group)_/)
|
||||
$form.find('#group_conversation').attr('checked', true) if !$form.find('#group_conversation_info').is(':visible')
|
||||
$form.find('#group_conversation_info').show()
|
||||
$form.find('#user_note_info').hide()
|
||||
else
|
||||
$form.find('#group_conversation').attr('checked', true)
|
||||
$form.find('#group_conversation_info').hide()
|
||||
$form.find('#user_note_info').showIf((user = MessageInbox.user_cache[tokens[0]]) and can_add_notes_for(user))
|
||||
|
||||
$(window).resize inbox_resize
|
||||
setTimeout inbox_resize
|
||||
|
|
|
@ -84,7 +84,6 @@ class ConversationsController < ApplicationController
|
|||
recipients = Array(recipients)
|
||||
@conversation = @current_user.initiate_conversation(recipients)
|
||||
@message = create_message_on_conversation(@conversation, !batch_private_messages)
|
||||
@message.generate_user_note if params[:user_note]
|
||||
@conversation
|
||||
end
|
||||
if batch_private_messages
|
||||
|
@ -245,16 +244,20 @@ class ConversationsController < ApplicationController
|
|||
def load_all_contexts
|
||||
@contexts = {:courses => {}, :groups => {}}
|
||||
@current_user.concluded_courses.each do |course|
|
||||
@contexts[:courses][course.id] = {:id => course.id, :name => course.name, :type => :course, :active => course.recently_ended? }
|
||||
@contexts[:courses][course.id] = {:id => course.id, :name => course.name, :type => :course, :active => course.recently_ended?, :can_add_notes => can_add_notes_to?(course) }
|
||||
end
|
||||
@current_user.courses.each do |course|
|
||||
@contexts[:courses][course.id] = {:id => course.id, :name => course.name, :type => :course, :active => true }
|
||||
@contexts[:courses][course.id] = {:id => course.id, :name => course.name, :type => :course, :active => true, :can_add_notes => can_add_notes_to?(course) }
|
||||
end
|
||||
@current_user.groups.each do |group|
|
||||
@contexts[:groups][group.id] = {:id => group.id, :name => group.name, :type => :group, :active => group.active? }
|
||||
end
|
||||
end
|
||||
|
||||
def can_add_notes_to?(course)
|
||||
course.enable_user_notes && course.grants_right?(@current_user, nil, :manage_user_notes)
|
||||
end
|
||||
|
||||
def matching_contexts(search, exclude = [])
|
||||
avatar_url = avatar_url_for_group(true)
|
||||
@contexts.values.map(&:values).flatten.
|
||||
|
@ -311,13 +314,13 @@ class ConversationsController < ApplicationController
|
|||
end
|
||||
|
||||
def jsonify_users(users, blank_avatar_fallback = false)
|
||||
ids_present = users.first.respond_to?(:common_course_ids)
|
||||
ids_present = users.first.respond_to?(:common_courses)
|
||||
users.map { |user|
|
||||
{:id => user.id,
|
||||
:name => user.short_name,
|
||||
:avatar => avatar_url_for_user(user, blank_avatar_fallback),
|
||||
:course_ids => ids_present ? user.common_course_ids : [],
|
||||
:group_ids => ids_present ? user.common_group_ids : []
|
||||
:common_courses => ids_present ? user.common_courses : [],
|
||||
:common_groups => ids_present ? user.common_groups : []
|
||||
}
|
||||
}
|
||||
end
|
||||
|
|
|
@ -201,6 +201,12 @@ module ApplicationHelper
|
|||
end
|
||||
@context_url_lookup[lookup] = res
|
||||
end
|
||||
|
||||
def message_user_path(user)
|
||||
params = {:user_id => user.id, :user_name => user.short_name}
|
||||
params[:can_add_notes] = true if user.grants_right?(@current_user, :create_user_notes)
|
||||
conversations_path + "#/conversations?" + params.to_query.gsub('+', '%20')
|
||||
end
|
||||
|
||||
def hidden(include_style=false)
|
||||
include_style ? "style='display:none;'" : "display: none;"
|
||||
|
|
|
@ -8,7 +8,7 @@ module ConversationsHelper
|
|||
|
||||
def formatted_contexts(contexts)
|
||||
if contexts.is_a? User
|
||||
contexts = {:courses => contexts.common_course_ids, :groups => contexts.common_group_ids}
|
||||
contexts = {:courses => contexts.common_courses.keys, :groups => contexts.common_groups.keys}
|
||||
end
|
||||
"<em>#{ERB::Util.h(context_names(contexts).to_sentence)}</em>".html_safe
|
||||
end
|
||||
|
@ -23,8 +23,8 @@ module ConversationsHelper
|
|||
|
||||
# get up to two contexts that are shared by >= 50% of the audience
|
||||
contexts = audience.inject({}) { |hash, user|
|
||||
user.common_course_ids.each { |id| (hash[[:courses, id]] ||= []) << user.id }
|
||||
user.common_group_ids.each { |id| (hash[[:groups, id]] ||= []) << user.id }
|
||||
user.common_courses.each { |id, roles| (hash[[:courses, id]] ||= []) << user.id }
|
||||
user.common_groups.each { |id, roles| (hash[[:groups, id]] ||= []) << user.id }
|
||||
hash
|
||||
}.
|
||||
sort_by{ |c| - c.last.size}.
|
||||
|
|
|
@ -27,12 +27,12 @@ class Conversation < ActiveRecord::Base
|
|||
has_many :participants,
|
||||
:through => :conversation_participants,
|
||||
:source => :user,
|
||||
:select => User::MESSAGEABLE_USER_COLUMN_SQL + ", NULL AS common_course_ids, NULL AS common_group_ids",
|
||||
:select => User::MESSAGEABLE_USER_COLUMN_SQL + ", NULL AS common_courses, NULL AS common_groups",
|
||||
:order => 'last_authored_at IS NULL, last_authored_at DESC, LOWER(COALESCE(short_name, name))'
|
||||
has_many :subscribed_participants,
|
||||
:through => :subscribed_conversation_participants,
|
||||
:source => :user,
|
||||
:select => User::MESSAGEABLE_USER_COLUMN_SQL + ", NULL AS common_course_ids, NULL AS common_group_ids",
|
||||
:select => User::MESSAGEABLE_USER_COLUMN_SQL + ", NULL AS common_courses, NULL AS common_groups",
|
||||
:order => 'last_authored_at IS NULL, last_authored_at DESC, LOWER(COALESCE(short_name, name))'
|
||||
has_many :attachments, :through => :conversation_messages
|
||||
|
||||
|
|
|
@ -97,7 +97,7 @@ class ConversationParticipant < ActiveRecord::Base
|
|||
}.map{ |m|
|
||||
m.forwarded_messages.map(&:author_id)
|
||||
}.flatten.uniq - [self.user_id]
|
||||
participants |= User.find(:all, :select => User::MESSAGEABLE_USER_COLUMN_SQL + ", NULL AS common_course_ids, NULL AS common_group_ids", :conditions => {:id => user_ids})
|
||||
participants |= User.find(:all, :select => User::MESSAGEABLE_USER_COLUMN_SQL + ", NULL AS common_courses, NULL AS common_groups", :conditions => {:id => user_ids})
|
||||
end
|
||||
return participants unless include_context_info
|
||||
# we do this to find out the contexts they share with the user
|
||||
|
@ -105,8 +105,8 @@ class ConversationParticipant < ActiveRecord::Base
|
|||
context_info[user.id] = user
|
||||
}
|
||||
participants.each { |user|
|
||||
user.common_course_ids = context_info[user.id].common_course_ids
|
||||
user.common_group_ids = context_info[user.id].common_group_ids
|
||||
user.common_courses = context_info[user.id].common_courses
|
||||
user.common_groups = context_info[user.id].common_groups
|
||||
}
|
||||
end
|
||||
|
||||
|
|
|
@ -128,8 +128,10 @@ class Enrollment < ActiveRecord::Base
|
|||
:conditions => "courses.workflow_state = 'aborted' or courses.workflow_state = 'completed' or enrollments.workflow_state = 'rejected' or enrollments.workflow_state = 'completed'"
|
||||
|
||||
|
||||
ENROLLMENT_RANK = ['TeacherEnrollment','TaEnrollment','DesignerEnrollment','StudentEnrollment','ObserverEnrollment']
|
||||
ENROLLMENT_RANK_SQL = ENROLLMENT_RANK.size.times.inject('CASE '){|s, i| s << "WHEN type = '#{ENROLLMENT_RANK[i]}' THEN #{i} "} << 'END'
|
||||
def self.highest_enrollment_type(type, type2)
|
||||
res = ['TeacherEnrollment','TaEnrollment','DesignerEnrollment','StudentEnrollment','ObserverEnrollment'].find{|t| t == type || t == type2}
|
||||
res = ENROLLMENT_RANK.find{|t| t == type || t == type2}
|
||||
res ||= type || type2
|
||||
res
|
||||
end
|
||||
|
|
|
@ -1632,8 +1632,8 @@ class User < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
MESSAGEABLE_USER_COLUMNS = ['id', 'short_name', 'name', 'avatar_image_url', 'avatar_image_source']
|
||||
MESSAGEABLE_USER_COLUMN_SQL = "users." + (MESSAGEABLE_USER_COLUMNS.join(", users."))
|
||||
MESSAGEABLE_USER_COLUMNS = ['id', 'short_name', 'name', 'avatar_image_url', 'avatar_image_source'].map{|col|"users.#{col}"}
|
||||
MESSAGEABLE_USER_COLUMN_SQL = MESSAGEABLE_USER_COLUMNS.join(", ")
|
||||
def messageable_users(options = {})
|
||||
hash = enrollment_visibility
|
||||
full_course_ids = hash[:full_course_ids]
|
||||
|
@ -1684,25 +1684,37 @@ class User < ActiveRecord::Base
|
|||
course_sql << "(course_section_id IN (#{section_ids.join(',')}))" if section_ids.present?
|
||||
course_sql << "(course_id IN (#{restricted_course_hash.keys.join(',')}) AND (enrollments.type = 'TeacherEnrollment' OR enrollments.type = 'TaEnrollment' OR enrollments.user_id IN (#{([self.id] + restricted_course_hash.values.flatten.uniq).join(',')})))" if restricted_course_hash.present?
|
||||
user_sql << <<-SQL if course_sql.present?
|
||||
SELECT #{MESSAGEABLE_USER_COLUMN_SQL}, course_id, null AS group_id
|
||||
SELECT #{MESSAGEABLE_USER_COLUMN_SQL}, course_id, NULL AS group_id, #{connection.func(:group_concat, :'enrollments.type', ':')} AS roles
|
||||
FROM users, enrollments, courses
|
||||
WHERE (#{course_sql.join(' OR ')}) AND users.id = user_id AND courses.id = course_id
|
||||
AND (#{self.class.reflections[:current_and_invited_enrollments].options[:conditions]}
|
||||
OR #{self.class.reflections[:concluded_enrollments].options[:conditions]}
|
||||
)
|
||||
AND #{user_condition_sql}
|
||||
GROUP BY #{connection.group_by(*(MESSAGEABLE_USER_COLUMNS + [:course_id]))}
|
||||
SQL
|
||||
|
||||
user_sql << <<-SQL if group_ids.present?
|
||||
SELECT #{MESSAGEABLE_USER_COLUMN_SQL}, null AS course_id, group_id
|
||||
SELECT #{MESSAGEABLE_USER_COLUMN_SQL}, NULL AS course_id, group_id, NULL AS roles
|
||||
FROM users, group_memberships
|
||||
WHERE group_id IN (#{group_ids.join(',')}) AND users.id = user_id
|
||||
AND group_memberships.workflow_state <> 'deleted'
|
||||
AND #{user_condition_sql}
|
||||
SQL
|
||||
|
||||
# if this is an account admin who doesn't have any courses/groups in common
|
||||
# with the user, we want to know the user's highest current enrollment type
|
||||
highest_enrollment_sql = <<-SQL
|
||||
SELECT type
|
||||
FROM enrollments, courses
|
||||
WHERE
|
||||
user_id = users.id AND courses.id = course_id
|
||||
AND #{self.class.reflections[:current_and_invited_enrollments].options[:conditions]}
|
||||
ORDER BY #{Enrollment::ENROLLMENT_RANK_SQL}
|
||||
LIMIT 1
|
||||
SQL
|
||||
user_sql << <<-SQL if account_ids.present?
|
||||
SELECT #{MESSAGEABLE_USER_COLUMN_SQL}, null AS course_id, null AS group_id
|
||||
SELECT #{MESSAGEABLE_USER_COLUMN_SQL}, 0 AS course_id, NULL AS group_id, (#{highest_enrollment_sql}) AS roles
|
||||
FROM users, user_account_associations
|
||||
WHERE user_account_associations.account_id IN (#{account_ids.join(',')})
|
||||
AND user_account_associations.user_id = users.id
|
||||
|
@ -1715,7 +1727,7 @@ class User < ActiveRecord::Base
|
|||
# conversation with that user)
|
||||
if options[:conversation_id].present?
|
||||
user_sql << <<-SQL
|
||||
SELECT #{MESSAGEABLE_USER_COLUMN_SQL}, null AS course_id, null AS group_id
|
||||
SELECT #{MESSAGEABLE_USER_COLUMN_SQL}, NULL AS course_id, NULL AS group_id, NULL AS roles
|
||||
FROM users, conversation_participants
|
||||
WHERE #{user_condition_sql}
|
||||
AND conversation_participants.user_id = users.id
|
||||
|
@ -1723,7 +1735,7 @@ class User < ActiveRecord::Base
|
|||
SQL
|
||||
elsif options[:no_check_context]
|
||||
user_sql << <<-SQL
|
||||
SELECT #{MESSAGEABLE_USER_COLUMN_SQL}, null AS course_id, null AS group_id
|
||||
SELECT #{MESSAGEABLE_USER_COLUMN_SQL}, NULL AS course_id, NULL AS group_id, NULL AS roles
|
||||
FROM users
|
||||
WHERE #{user_condition_sql}
|
||||
SQL
|
||||
|
@ -1733,10 +1745,12 @@ class User < ActiveRecord::Base
|
|||
# if none of our potential sources was included, we're done
|
||||
return [] if user_sql.empty?
|
||||
|
||||
concat_sql = connection.adapter_name =~ /postgres/i ? :"course_id::text || ':' || roles::text" : :"course_id || ':' || roles"
|
||||
|
||||
users = User.find_by_sql(<<-SQL)
|
||||
SELECT #{MESSAGEABLE_USER_COLUMN_SQL},
|
||||
#{connection.func(:group_concat, :course_id)} AS common_course_ids,
|
||||
#{connection.func(:group_concat, :group_id)} AS common_group_ids
|
||||
#{connection.func(:group_concat, concat_sql)} AS common_courses,
|
||||
#{connection.func(:group_concat, :group_id)} AS common_groups
|
||||
FROM (
|
||||
#{user_sql.join(' UNION ')}
|
||||
) users
|
||||
|
@ -1746,8 +1760,16 @@ class User < ActiveRecord::Base
|
|||
#{options[:limit] ? "LIMIT #{options[:limit].to_i}" : ""}
|
||||
SQL
|
||||
users.each do |user|
|
||||
user.common_course_ids = user.common_course_ids.to_s.split(",").map(&:to_i)
|
||||
user.common_group_ids = user.common_group_ids.to_s.split(",").map(&:to_i)
|
||||
user.common_courses = user.common_courses.to_s.split(",").inject({}){ |hash, info|
|
||||
roles = info.split(/:/)
|
||||
hash[roles.shift.to_i] = roles
|
||||
hash
|
||||
}
|
||||
user.common_groups = user.common_groups.to_s.split(",").inject({}){ |hash, info|
|
||||
roles = info.split(/:/)
|
||||
hash[roles.shift.to_i] = ['Member']
|
||||
hash
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<a class="button button-sidebar button-sidebar-wide" href="<%= context_url(@context, :controller => :gradebooks, :action => :grade_summary, :id => @user.id) %>"><%= image_tag "grading_icon.png" %> <%= t 'links.user_grades', "Grades for %{user}", :user => context_user_name(@context, @user) %></a>
|
||||
<% end %>
|
||||
<% if can_do(@context, @current_user, :send_messages) %>
|
||||
<a class="button button-sidebar-wide" href="<%= conversations_path %>#/conversations?<%= {:user_id => @user.id, :user_name => @user.short_name}.to_query.gsub('+', '%20') %>"><%= image_tag "email.png" %> <%= t 'links.message_user', "Message %{user}", :user => context_user_name(@context, @user) %></a>
|
||||
<a class="button button-sidebar-wide" href="<%= message_user_path(@user) %>"><%= image_tag "email.png" %> <%= t 'links.message_user', "Message %{user}", :user => context_user_name(@context, @user) %></a>
|
||||
<% end %>
|
||||
<% if @domain_root_account.enable_user_notes and can_do(@user, @current_user, :read_user_notes) %>
|
||||
<a href="<%= user_user_notes_path(@user) %>" class="button button-sidebar-wide"> <%= t 'links.faculty_journal', "Faculty Journal for %{user}", :user => context_user_name(@context, @user) %></a>
|
||||
|
|
|
@ -65,8 +65,9 @@
|
|||
</ul>
|
||||
<table>
|
||||
<tr id="recipient_info"><th><%= label_tag :recipients, :to, :en => "To", :before => true %></th><td><%= text_field_tag :recipients, nil, :finder_url => conversations_find_recipients_url, :class => "recipients" %></td></tr>
|
||||
<tr id="group_conversation_info"><th></th><td><%= check_box_tag :group_conversation %> <%= label_tag :group_conversation, :en => "This is a group conversation. Participants will see all messages" %></td></tr>
|
||||
<tr><th><%= label_tag :body, :message, :en => "Message", :before => true %></th><td><%= text_area_tag :body %></td></tr>
|
||||
<tr id="group_conversation_info"><th></th><td><%= check_box_tag :group_conversation %> <%= label_tag :group_conversation, :en => "This is a group conversation. Participants will see all messages" %></td></tr>
|
||||
<tr id="user_note_info"><th></th><td><%= check_box_tag :user_note, "1", false, :id => :add_to_faculty_journal %> <%= label_tag :add_to_faculty_journal, :en => "Add as a Faculty Journal entry" %></td></tr>
|
||||
<tr>
|
||||
<th> </th>
|
||||
<td>
|
||||
|
@ -221,6 +222,7 @@
|
|||
MessageInbox.initial_conversations_count = <%= @conversations_count %>;
|
||||
MessageInbox.scope = <%= raw @scope.to_json %>;
|
||||
MessageInbox.label_scope = <%= raw @label.to_json %>;
|
||||
MessageInbox.can_add_notes = <%= raw @current_user.associated_accounts.any?{|a| a.enable_user_notes && a.grants_right?(@current_user, nil, :manage_students) } %>;
|
||||
<% unless @current_user.watched_conversations_intro? %>
|
||||
$.conversationsIntroSlideshow()
|
||||
<% end %>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<a class="button button-sidebar button-sidebar-wide" href="<%= context_url(@context, :context_student_grades_url, @user.id) %>"><%= image_tag "grading_icon.png" %> <%= t('links.grades', "Grades for %{user}", :user => context_user_name(@context, @user)) %></a>
|
||||
<% end %>
|
||||
<% if can_do(@context, @current_user, :send_messages) %>
|
||||
<a class="button button-sidebar button-sidebar-wide" href="<%= conversations_url %>#/conversations?user_id=<%= @user.id %>&user_name=<%= URI.escape(@user.short_name) %>"><%= image_tag "email.png" %> <%= t('links.message_user', "Message %{user}", :user => context_user_name(@context, @user)) %></a>
|
||||
<a class="button button-sidebar button-sidebar-wide" href="<%= message_user_path(@user) %>"><%= image_tag "email.png" %> <%= t('links.message_user', "Message %{user}", :user => context_user_name(@context, @user)) %></a>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
|
|
@ -75,7 +75,7 @@
|
|||
</td>
|
||||
<% if course.user_is_teacher?(@current_user) %>
|
||||
<td>
|
||||
<a href="<%= inbox_url %>#reply<%= {'context_code' => course.asset_string, 'recipients' => student[:enrollment].user_id.to_s}.to_json %>" class="message_student_link" title="<%= t 'message_student', 'Message this student' %>"><%= image_tag "email.png" %></a>
|
||||
<a href="<%= message_user_path(student[:enrollment].user) %>" class="message_student_link" title="<%= t 'message_student', 'Message this student' %>"><%= image_tag "email.png" %></a>
|
||||
</td>
|
||||
<% end %>
|
||||
</tr>
|
||||
|
|
|
@ -444,12 +444,17 @@ class ActiveRecord::ConnectionAdapters::AbstractAdapter
|
|||
# for functions that differ from one adapter to the next, use the following
|
||||
# method (overriding as needed in non-standard adapters), e.g.
|
||||
#
|
||||
# connection.func(:group_concat, :name) ->
|
||||
# group_concat(name) (default)
|
||||
# string_agg(name::text, ',') (postgres)
|
||||
# connection.func(:group_concat, :name, '|') ->
|
||||
# group_concat(name, '|') (default)
|
||||
# group_concat(name SEPARATOR '|') (mysql)
|
||||
# string_agg(name::text, '|') (postgres)
|
||||
|
||||
def func(name, *args)
|
||||
"#{name}(#{args.map{ |arg| arg.is_a?(Symbol) ? arg : quote_value(arg) }.join(', ')})"
|
||||
"#{name}(#{args.map{ |arg| func_arg_esc(arg) }.join(', ')})"
|
||||
end
|
||||
|
||||
def func_arg_esc(arg)
|
||||
arg.is_a?(Symbol) ? arg : quote(arg)
|
||||
end
|
||||
|
||||
def group_by(*columns)
|
||||
|
@ -457,12 +462,24 @@ class ActiveRecord::ConnectionAdapters::AbstractAdapter
|
|||
end
|
||||
end
|
||||
|
||||
if defined?(ActiveRecord::ConnectionAdapters::MySQLAdapter)
|
||||
ActiveRecord::ConnectionAdapters::MySQLAdapter.class_eval do
|
||||
def func(name, *args)
|
||||
case name
|
||||
when :group_concat
|
||||
"group_concat(#{func_arg_esc(args.first)} SEPARATOR #{quote(args[1] || ',')})"
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if defined?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
|
||||
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.class_eval do
|
||||
def func(name, *args)
|
||||
case name
|
||||
when :group_concat
|
||||
"string_agg(#{args.first}::text, ',')"
|
||||
"string_agg((#{func_arg_esc(args.first)})::text, #{quote(args[1] || ',')})"
|
||||
else
|
||||
super
|
||||
end
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
this.tokens.html('');
|
||||
return typeof this.change === "function" ? this.change(this.token_values()) : void 0;
|
||||
}, this));
|
||||
this.added = this.options.added;
|
||||
this.placeholder = $('<span />');
|
||||
this.placeholder.text(this.options.placeholder);
|
||||
if (this.options.placeholder) {
|
||||
|
@ -104,6 +105,11 @@
|
|||
this.val('');
|
||||
}
|
||||
this.placeholder.hide();
|
||||
if (data) {
|
||||
if (typeof this.added === "function") {
|
||||
this.added(data.data);
|
||||
}
|
||||
}
|
||||
if (typeof this.change === "function") {
|
||||
this.change(this.token_values());
|
||||
}
|
||||
|
@ -534,7 +540,8 @@
|
|||
return this.input.add_token({
|
||||
value: id,
|
||||
text: this.selection.find('b').text(),
|
||||
no_clear: true
|
||||
no_clear: true,
|
||||
data: this.selection.data('user_data')
|
||||
});
|
||||
} else {
|
||||
this.selection.removeClass('on');
|
||||
|
@ -710,7 +717,7 @@
|
|||
}
|
||||
};
|
||||
I18n.scoped('conversations', function(I18n) {
|
||||
var add_conversation, build_attachment, build_media_object, build_message, build_submission, build_submission_comment, close_menus, html_name_for_user, inbox_action, inbox_action_url_for, inbox_resize, is_selected, open_conversation_menu, open_menu, parse_query_string, remove_conversation, reposition_conversation, reset_message_form, select_conversation, select_unloaded_conversation, set_conversation_state, set_hash, set_last_label, show_message_form, toggle_message_actions, update_conversation;
|
||||
var add_conversation, build_attachment, build_media_object, build_message, build_submission, build_submission_comment, can_add_notes_for, close_menus, html_name_for_user, inbox_action, inbox_action_url_for, inbox_resize, is_selected, open_conversation_menu, open_menu, parse_query_string, remove_conversation, reposition_conversation, reset_message_form, select_conversation, select_unloaded_conversation, set_conversation_state, set_hash, set_last_label, show_message_form, toggle_message_actions, update_conversation;
|
||||
show_message_form = function() {
|
||||
var newMessage;
|
||||
newMessage = !($selected_conversation != null);
|
||||
|
@ -733,6 +740,7 @@
|
|||
});
|
||||
}
|
||||
reset_message_form();
|
||||
$form.find('#user_note_info').showIf($selected_conversation != null ? $selected_conversation.hasClass('private') : void 0).find('input').attr('checked', false);
|
||||
return $form.show().find(':input:visible:first').focus();
|
||||
};
|
||||
reset_message_form = function() {
|
||||
|
@ -812,7 +820,12 @@
|
|||
if (params && params.user_id && params.user_name) {
|
||||
$('#recipients').data('token_input').add_token({
|
||||
value: params.user_id,
|
||||
text: params.user_name
|
||||
text: params.user_name,
|
||||
data: {
|
||||
id: params.user_id,
|
||||
name: params.user_name,
|
||||
can_add_notes: params.can_add_notes
|
||||
}
|
||||
});
|
||||
$('#from_conversation_id').val(params.from_conversation_id);
|
||||
}
|
||||
|
@ -821,14 +834,14 @@
|
|||
$form.loadingImage();
|
||||
$c = $selected_conversation;
|
||||
completion = function(data) {
|
||||
var i, j, message, submission, user, _i, _len, _ref;
|
||||
var i, j, message, submission, user, _i, _len, _ref, _ref2;
|
||||
if (!is_selected($c)) {
|
||||
return;
|
||||
}
|
||||
_ref = data.participants;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
user = _ref[_i];
|
||||
if (!MessageInbox.user_cache[user.id]) {
|
||||
if (!((_ref2 = MessageInbox.user_cache[user.id]) != null ? _ref2.avatar : void 0)) {
|
||||
MessageInbox.user_cache[user.id] = user;
|
||||
user.html_name = html_name_for_user(user);
|
||||
}
|
||||
|
@ -863,27 +876,27 @@
|
|||
}
|
||||
};
|
||||
MessageInbox.shared_contexts_for_user = function(user, limit) {
|
||||
var course, course_id, group, group_id, shared_contexts;
|
||||
var course, course_id, group, group_id, roles, shared_contexts;
|
||||
if (limit == null) {
|
||||
limit = 2;
|
||||
}
|
||||
shared_contexts = ((function() {
|
||||
var _i, _len, _ref, _results;
|
||||
_ref = user.course_ids;
|
||||
var _ref, _results;
|
||||
_ref = user.common_courses;
|
||||
_results = [];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
course_id = _ref[_i];
|
||||
for (course_id in _ref) {
|
||||
roles = _ref[course_id];
|
||||
if (course = this.contexts.courses[course_id]) {
|
||||
_results.push(course.name);
|
||||
}
|
||||
}
|
||||
return _results;
|
||||
}).call(this)).concat((function() {
|
||||
var _i, _len, _ref, _results;
|
||||
_ref = user.group_ids;
|
||||
var _ref, _results;
|
||||
_ref = user.common_groups;
|
||||
_results = [];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
group_id = _ref[_i];
|
||||
for (group_id in _ref) {
|
||||
roles = _ref[group_id];
|
||||
if (group = this.contexts.groups[group_id]) {
|
||||
_results.push(group.name);
|
||||
}
|
||||
|
@ -907,6 +920,20 @@
|
|||
shared_contexts = MessageInbox.shared_contexts_for_user(user);
|
||||
return $.htmlEscape(user.name) + (shared_contexts.length ? " <em>" + $.htmlEscape(shared_contexts) + "</em>" : '');
|
||||
};
|
||||
can_add_notes_for = function(user) {
|
||||
var course_id, roles, _ref, _ref2;
|
||||
if (user.can_add_notes) {
|
||||
return true;
|
||||
}
|
||||
_ref = user.common_courses;
|
||||
for (course_id in _ref) {
|
||||
roles = _ref[course_id];
|
||||
if (__indexOf.call(roles, 'StudentEnrollment') >= 0 && (MessageInbox.can_add_notes || ((_ref2 = MessageInbox.contexts.courses[course_id]) != null ? _ref2.can_add_notes : void 0))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
build_message = function(data) {
|
||||
var $attachment_blank, $media_object_blank, $message, $pm_action, $ul, attachment, avatar, pm_url, submessage, user, user_name, _i, _j, _len, _len2, _ref, _ref2, _ref3, _ref4, _ref5, _ref6;
|
||||
$message = $("#message_blank").clone(true).attr('id', 'message_' + data.id);
|
||||
|
@ -1791,6 +1818,14 @@
|
|||
$('#no_messages').showIf(!$conversation_list.find('li').length);
|
||||
$('.recipients').tokenInput({
|
||||
placeholder: I18n.t('recipient_field_placeholder', "Enter a name, course, or group"),
|
||||
added: function(data) {
|
||||
var _base, _name, _ref3;
|
||||
if (!(data.id && ("" + data.id).match(/^(course|group)_/))) {
|
||||
data = $.extend({}, data);
|
||||
delete data.avatar;
|
||||
return (_ref3 = (_base = MessageInbox.user_cache)[_name = data.id]) != null ? _ref3 : _base[_name] = data;
|
||||
}
|
||||
},
|
||||
selector: {
|
||||
messages: {
|
||||
no_results: I18n.t('no_results', 'No results found')
|
||||
|
@ -1808,12 +1843,13 @@
|
|||
$b = $('<b />');
|
||||
$b.text(data.name);
|
||||
$span = $('<span />');
|
||||
if (data.course_ids != null) {
|
||||
if (data.common_courses != null) {
|
||||
$span.text(MessageInbox.shared_contexts_for_user(data));
|
||||
}
|
||||
$node.append($b, $span);
|
||||
$node.attr('title', data.name);
|
||||
$node.data('id', data.id);
|
||||
$node.data('user_data', data);
|
||||
$node.addClass(data.type ? data.type : 'user');
|
||||
if (options.level > 0) {
|
||||
$node.prepend('<a class="toggle"><i></i></a>');
|
||||
|
@ -1840,15 +1876,17 @@
|
|||
token_input = $('#recipients').data('token_input');
|
||||
token_input.fake_input.css('width', '100%');
|
||||
token_input.change = function(tokens) {
|
||||
var _ref3;
|
||||
var user, _ref3;
|
||||
if (tokens.length > 1 || ((_ref3 = tokens[0]) != null ? _ref3.match(/^(course|group)_/) : void 0)) {
|
||||
if (!$form.find('#group_conversation_info').is(':visible')) {
|
||||
$form.find('#group_conversation').attr('checked', true);
|
||||
}
|
||||
return $form.find('#group_conversation_info').show();
|
||||
$form.find('#group_conversation_info').show();
|
||||
return $form.find('#user_note_info').hide();
|
||||
} else {
|
||||
$form.find('#group_conversation').attr('checked', true);
|
||||
return $form.find('#group_conversation_info').hide();
|
||||
$form.find('#group_conversation_info').hide();
|
||||
return $form.find('#user_note_info').showIf((user = MessageInbox.user_cache[tokens[0]]) && can_add_notes_for(user));
|
||||
}
|
||||
};
|
||||
$(window).resize(inbox_resize);
|
||||
|
|
Loading…
Reference in New Issue