add observees page to user profile

test plan:
 * navigate to /profile/observees
 * add new observees (specifying usernames & passwords)
 * new observees should appear in the list

notes:
 - the 'Observing' tab does not appear until at least one observee has
   been added for the user (and the page is refreshed)
 - the observing user should gain Observer enrollments for courses the
   observed user is enrolled in (both present and future)

closes CNVS-13356

Change-Id: Icda0f0d256fc73bcb554523db6436457941d8b58
Reviewed-on: https://gerrit.instructure.com/37283
Reviewed-by: Ryan Shaw <ryan@instructure.com>
Reviewed-by: Jeremy Stanley <jeremy@instructure.com>
Tested-by: Jenkins <jenkins@instructure.com>
QA-Review: Clare Strong <clare@instructure.com>
Product-Review: Hilary Scharton <hilary@instructure.com>
This commit is contained in:
Mark Severson 2014-07-03 14:12:17 -06:00
parent 73969932b7
commit 8611d9ce09
13 changed files with 172 additions and 2 deletions

View File

@ -0,0 +1,13 @@
require [
'compiled/views/UserObserveesView'
'compiled/collections/UserObserveesCollection'
], (UserObserveesView, UserObserveesCollection) ->
collection = new UserObserveesCollection
collection.user_id = ENV['current_user_id']
userObservees = new UserObserveesView(collection: collection)
userObservees.render()
userObservees.$el.appendTo('#content')
collection.fetch()

View File

@ -0,0 +1,6 @@
define [
'compiled/collections/PaginatedCollection'
], (PaginatedCollection) ->
class UserObserveesCollection extends PaginatedCollection
url: -> "/api/v1/users/#{@user_id}/observees"

View File

@ -0,0 +1,8 @@
define [
'jst/UserObservee'
'Backbone'
], (template, Backbone) ->
class UserObserveeView extends Backbone.View
template: template
tagName: 'li'

View File

@ -0,0 +1,53 @@
define [
'underscore'
'i18n!observees'
'jst/UserObservees'
'compiled/views/UserObserveeView'
'compiled/views/PaginatedCollectionView'
], (_, I18n, template, itemView, PaginatedCollectionView) ->
class UserObserveesView extends PaginatedCollectionView
autoFetch: true
template: template
itemView: itemView
className: 'user-observees'
events:
'submit .add-observee-form': 'addObservee'
els: _.extend {}, PaginatedCollectionView::els,
'.add-observee-form': '$form'
initialize: ->
super
@collection.on 'beforeFetch', =>
@setLoading(true)
@collection.on 'fetch', =>
@setLoading(false)
addObservee: (ev) ->
ev.preventDefault()
observee = @$form.getFormData()
d = $.post(@collection.url(), {observee: observee})
d.done (model) =>
@collection.add([model], merge: true)
$.flashMessage(I18n.t('observee_added', 'Now observing %{user}', user: model.name))
@$form.get(0).reset()
@focusForm()
d.error (response) =>
@$form.formErrors(JSON.parse(response.responseText))
@focusForm()
focusForm: ->
field = @$form.find(":input[value='']:not(button)").first()
field = @$form.find(":input:not(button)") unless field.length
field.focus()
setLoading: (loading) ->
@$el.toggleClass('loading', loading)
@$('.observees-list-container').attr('aria-busy', if loading then 'true' else 'false')

View File

@ -136,7 +136,7 @@
#
class ProfileController < ApplicationController
before_filter :require_registered_user, :except => [:show, :settings, :communication, :communication_update]
before_filter :require_user, :only => [:settings, :communication, :communication_update]
before_filter :require_user, :only => [:settings, :communication, :communication_update, :observees]
before_filter :require_user_for_private_profile, :only => :show
before_filter :reject_student_view_student
before_filter :require_password_session, :only => [:settings, :communication, :communication_update, :update]
@ -416,4 +416,13 @@ class ProfileController < ApplicationController
require_user
end
private :require_user_for_private_profile
def observees
@user ||= @current_user
@active_tab = 'observees'
@context = @user.profile if @user == @current_user
add_crumb(@user.short_name, profile_path)
add_crumb(t('crumbs.observees', "Observing"))
end
end

View File

@ -145,11 +145,13 @@ class UserObserveesController < ApplicationController
user.user_observees.create! do |uo|
uo.user_id = observee.id
end
user.touch
end
end
def remove_observee(observee)
user.user_observees.where(user_id: observee).destroy_all
user.touch
end
def has_observee?(observee)

View File

@ -31,7 +31,7 @@ class UserProfile < ActiveRecord::Base
validates_length_of :title, :maximum => maximum_string_length, :allow_blank => true
TAB_PROFILE, TAB_COMMUNICATION_PREFERENCES, TAB_FILES, TAB_EPORTFOLIOS,
TAB_HOME, TAB_PROFILE_SETTINGS = *0..10
TAB_HOME, TAB_PROFILE_SETTINGS, TAB_OBSERVEES = *0..10
def tabs_available(user=nil, opts={})
unless @tabs
@ -60,6 +60,10 @@ class UserProfile < ActiveRecord::Base
if user && user.fake_student?
@tabs = @tabs.slice(0,2)
end
if user && user.user_observees.exists?
@tabs << { :id => TAB_OBSERVEES, :label => I18n.t('#tabs.observees', 'Observing'), :css_class => 'observees', :href => :observees_profile_path, :no_args => true }
end
end
@tabs
end

View File

@ -0,0 +1,42 @@
@import environment
.user-observees.loading
.loading-indicator
display: block
.user-observees
h2
margin-top: 0
h3
margin-top: 55px
.add-observee-form
label input
width: inherit
.observees-list-container
min-height: 38px
.observees-list
display: block
.observees-list:empty
display: none
.loading-indicator
display: none
padding: 8px 0
border-top: 1px solid transparent
border-bottom: 1px solid transparent
.observees-list
margin: 0
li
list-style: none
padding: 8px 0
border-top: 1px solid #efefef
li:last-child
border-bottom: 1px solid #efefef

View File

@ -0,0 +1 @@
{{name}}

View File

@ -0,0 +1,27 @@
<h2>{{#t '#observees.observing'}}Observing{{/t}}</h2>
<form class="add-observee-form">
<div class="row">
<div class="span2">
<label for="unique_id">
{{#t '#observees.new_observee_username'}}Username{{/t}}
<input type="text" id="unique_id" name="unique_id">
</label>
</div>
<div class="span2">
<label for="password">
{{#t '#observees.new_observee_password'}}Password{{/t}}
<input type="password" id="password" name="password">
</label>
</div>
</div>
<button type="submit" class="btn btn-primary">{{#t '#observees.add_observee_button'}}Add Student{{/t}}</button>
</form>
<h3 id="being-observed">{{#t '#observees.being_observed'}}Students Being Observed{{/t}}</h3>
<div class="observees-list-container" aria-busy="false">
<ul class="observees-list collectionViewItems" aria-labelledby="being-observed"></ul>
<div class="loading-indicator">
<img src="/images/ajax-reload-animated.gif">&nbsp;
</div>
</div>

View File

@ -0,0 +1,2 @@
<% content_for :page_title, join_title(t(:page_title, 'Students Being Observed'), @user.name) %>
<% js_bundle :user_observees %>

View File

@ -189,5 +189,7 @@ stylesheets:
- public/stylesheets/compiled/mobile_auth.css
external_tool_full_width:
- public/stylesheets/compiled/external_tools/full_width.css
user_observees:
- public/stylesheets/compiled/user_observees.css
<%= plugin_assets.anchors_yml %>

View File

@ -668,6 +668,7 @@ routes.draw do
get :communication
put :communication_update
get :settings
get :observees
end
end