return user display info for collection items
This standardizes the "user display" sub-object returned by the discussions api, and returns that same data for each collection item. test plan: make api calls to return collection items, verify the user sub-object is present and contains the expected user data. Change-Id: Ie5b1468816ffbf27a005044effbc49082bdf679b Reviewed-on: https://gerrit.instructure.com/11276 Tested-by: Jenkins <jenkins@instructure.com> Reviewed-by: Simon Williams <simon@instructure.com>
This commit is contained in:
parent
9be4a8edea
commit
06b10f6a34
|
@ -35,9 +35,8 @@
|
|||
#
|
||||
# /api/v1/collection_items/<id>/discussion_topics/self/view
|
||||
#
|
||||
# A Collection Item object looks like:
|
||||
# @object Collection Item
|
||||
#
|
||||
# !!!javascript
|
||||
# {
|
||||
# // The ID of the collection item.
|
||||
# id: 7,
|
||||
|
@ -45,9 +44,6 @@
|
|||
# // The ID of the collection that this item belongs to.
|
||||
# collection_id: 2,
|
||||
#
|
||||
# // The ID of the user that created the collection item.
|
||||
# user_id: 37,
|
||||
#
|
||||
# // The type of the item.
|
||||
# // Currently defined types are: "url", "image", "audio", and "video".
|
||||
# //
|
||||
|
@ -115,6 +111,21 @@
|
|||
#
|
||||
# // The timestamp of when the item was posted by the user
|
||||
# created_at: "2012-05-30T17:45:25Z",
|
||||
#
|
||||
# // Information on the user that created the collection item.
|
||||
# user : {
|
||||
# // The ID of the user.
|
||||
# id: 37,
|
||||
#
|
||||
# // The display name of the user.
|
||||
# display_name: "John Doe",
|
||||
#
|
||||
# // The URL of the user's avatar image, or a fallback image if the user has not given one.
|
||||
# avatar_image_url: "http://...",
|
||||
#
|
||||
# // The URL to the HTML page in Canvas of this user's public profile.
|
||||
# html_url: "http://<canvas>/users/37"
|
||||
# },
|
||||
# }
|
||||
class CollectionItemsController < ApplicationController
|
||||
before_filter :require_collection, :only => [:index, :create]
|
||||
|
@ -132,29 +143,11 @@ class CollectionItemsController < ApplicationController
|
|||
# curl https://<canvas>/api/v1/collections/<collection_id>/items \
|
||||
# -H 'Authorization: Bearer <token>'
|
||||
#
|
||||
# @example_response
|
||||
# [
|
||||
# {
|
||||
# id: 7,
|
||||
# collection_id: 2,
|
||||
# item_type: "url",
|
||||
# link_url: "https://example.com/some/path",
|
||||
# post_count: 2,
|
||||
# upvote_count: 3,
|
||||
# upvoted_by_user: false,
|
||||
# root_item_id: 3,
|
||||
# image_url: "https://<canvas>/files/item_image.png",
|
||||
# title: "my title",
|
||||
# description: "some block of plain text",
|
||||
# user_comment: nil,
|
||||
# url: "https://<canvas>/api/v1/collections/items/7"
|
||||
# created_at: "2012-05-30T17:45:25Z",
|
||||
# }
|
||||
# ]
|
||||
# @returns [Collection Item]
|
||||
def index
|
||||
pagination_route = api_v1_collection_items_list_url(@collection)
|
||||
if authorized_action(@collection, @current_user, :read)
|
||||
@items = Api.paginate(@collection.collection_items.active.newest_first, self, pagination_route)
|
||||
@items = Api.paginate(@collection.collection_items.active.newest_first.scoped(:include => :user), self, pagination_route)
|
||||
render :json => collection_items_json(@items, @current_user, session)
|
||||
end
|
||||
end
|
||||
|
@ -169,23 +162,7 @@ class CollectionItemsController < ApplicationController
|
|||
# curl https://<canvas>/api/v1/collections/items/<item_id> \
|
||||
# -H 'Authorization: Bearer <token>'
|
||||
#
|
||||
# @example_response
|
||||
# {
|
||||
# id: 7,
|
||||
# collection_id: 2,
|
||||
# item_type: "url",
|
||||
# link_url: "https://example.com/some/path",
|
||||
# post_count: 2,
|
||||
# upvote_count: 3,
|
||||
# upvoted_by_user: false,
|
||||
# root_item_id: 3,
|
||||
# image_url: "https://<canvas>/files/item_image.png",
|
||||
# title: "my title",
|
||||
# description: "some block of plain text",
|
||||
# user_comment: nil,
|
||||
# url: "https://<canvas>/api/v1/collections/items/7"
|
||||
# created_at: "2012-05-30T17:45:25Z",
|
||||
# }
|
||||
# @returns Collection Item
|
||||
def show
|
||||
find_item_and_collection
|
||||
if authorized_action(@item, @current_user, :read)
|
||||
|
@ -237,6 +214,7 @@ class CollectionItemsController < ApplicationController
|
|||
# -F user_comment="clone of some other item" \
|
||||
# -H 'Authorization: Bearer <token>'
|
||||
#
|
||||
# @returns Collection Item
|
||||
def create
|
||||
@item = @collection.collection_items.new(:user => @current_user)
|
||||
if authorized_action(@item, @current_user, :create)
|
||||
|
@ -271,6 +249,7 @@ class CollectionItemsController < ApplicationController
|
|||
# -F user_comment='edited comment' \
|
||||
# -H 'Authorization: Bearer <token>'
|
||||
#
|
||||
# @returns Collection Item
|
||||
def update
|
||||
find_item_and_collection
|
||||
if authorized_action(@item, @current_user, :update)
|
||||
|
@ -293,6 +272,8 @@ class CollectionItemsController < ApplicationController
|
|||
# curl https://<canvas>/api/v1/collections/items/<item_id> \
|
||||
# -X DELETE \
|
||||
# -H 'Authorization: Bearer <token>'
|
||||
#
|
||||
# @returns Collection Item
|
||||
def destroy
|
||||
find_item_and_collection
|
||||
if authorized_action(@item, @current_user, :delete)
|
||||
|
@ -384,7 +365,7 @@ class CollectionItemsController < ApplicationController
|
|||
end
|
||||
|
||||
def find_item_and_collection
|
||||
@item = CollectionItem.active.find(params[:item_id])
|
||||
@item = CollectionItem.active.find(params[:item_id], :include => :user)
|
||||
@collection = @item.active_collection
|
||||
end
|
||||
|
||||
|
|
|
@ -32,9 +32,7 @@
|
|||
# Group collections can only be created, updated, or deleted by group
|
||||
# moderators.
|
||||
#
|
||||
# A Collection object looks like:
|
||||
#
|
||||
# !!!javascript
|
||||
# @object Collection
|
||||
# {
|
||||
# // The ID of the collection.
|
||||
# id: 5,
|
||||
|
@ -69,21 +67,7 @@ class CollectionsController < ApplicationController
|
|||
# curl -H 'Authorization: Bearer <token>' \
|
||||
# https://<canvas>/api/v1/users/self/collections
|
||||
#
|
||||
# @example_response
|
||||
# [
|
||||
# {
|
||||
# id: 1,
|
||||
# name: "My Collection",
|
||||
# visibility: "public",
|
||||
# followed_by_user: false
|
||||
# },
|
||||
# {
|
||||
# id: 2,
|
||||
# name: "My Personal Collection",
|
||||
# visibility: "private",
|
||||
# followed_by_user: true
|
||||
# }
|
||||
# ]
|
||||
# @returns [Collection]
|
||||
def index
|
||||
collection_route = polymorphic_url([:api_v1, @context, :collections])
|
||||
scope = @context.collections.active.newest_first
|
||||
|
@ -111,13 +95,7 @@ class CollectionsController < ApplicationController
|
|||
# curl -H 'Authorization: Bearer <token>' \
|
||||
# https://<canvas>/api/v1/collections/<collection_id>
|
||||
#
|
||||
# @example_response
|
||||
# {
|
||||
# id: 1,
|
||||
# name: "My Collection",
|
||||
# visibility: "public",
|
||||
# followed_by_user: false
|
||||
# }
|
||||
# @returns Collection
|
||||
def show
|
||||
@collection = find_collection
|
||||
if authorized_action(@collection, @current_user, :read)
|
||||
|
@ -139,13 +117,7 @@ class CollectionsController < ApplicationController
|
|||
# -F visibility=public \
|
||||
# https://<canvas>/api/v1/users/self/collections
|
||||
#
|
||||
# @example_response
|
||||
# {
|
||||
# id: 1,
|
||||
# name: "My Collection",
|
||||
# visibility: "public",
|
||||
# followed_by_user: false
|
||||
# }
|
||||
# @returns Collection
|
||||
def create
|
||||
@collection = @context.collections.new(params.slice(*SETTABLE_ATTRIBUTES))
|
||||
if authorized_action(@collection, @current_user, :create)
|
||||
|
@ -174,13 +146,7 @@ class CollectionsController < ApplicationController
|
|||
# -F name='My Edited Collection' \
|
||||
# https://<canvas>/api/v1/collections/<collection_id>
|
||||
#
|
||||
# @example_response
|
||||
# {
|
||||
# id: 1,
|
||||
# name: "My Edited Collection",
|
||||
# visibility: "public",
|
||||
# followed_by_user: false
|
||||
# }
|
||||
# @returns Collection
|
||||
def update
|
||||
@collection = find_collection
|
||||
if authorized_action(@collection, @current_user, :update)
|
||||
|
@ -202,13 +168,7 @@ class CollectionsController < ApplicationController
|
|||
# -X DELETE \
|
||||
# https://<canvas>/api/v1/collections/<collection_id>
|
||||
#
|
||||
# @example_response
|
||||
# {
|
||||
# id: 1,
|
||||
# name: "My Collection",
|
||||
# visibility: "public",
|
||||
# followed_by_user: false
|
||||
# }
|
||||
# @returns Collection
|
||||
def destroy
|
||||
@collection = find_collection
|
||||
if authorized_action(@collection, @current_user, :delete)
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
# API for accessing and participating in discussion topics in groups and courses.
|
||||
class DiscussionTopicsApiController < ApplicationController
|
||||
include Api::V1::DiscussionTopics
|
||||
include Api::V1::User
|
||||
|
||||
before_filter :require_context
|
||||
before_filter :require_topic
|
||||
|
@ -75,8 +76,8 @@ class DiscussionTopicsApiController < ApplicationController
|
|||
# {
|
||||
# "unread_entries": [1,3,4],
|
||||
# "participants": [
|
||||
# { "id": 10, "display_name": "user 1", "avatar_url": "https://..." },
|
||||
# { "id": 11, "display_name": "user 2", "avatar_url": "https://..." }
|
||||
# { "id": 10, "display_name": "user 1", "avatar_image_url": "https://...", "html_url": "https://..." },
|
||||
# { "id": 11, "display_name": "user 2", "avatar_image_url": "https://...", "html_url": "https://..." }
|
||||
# ],
|
||||
# "view": [
|
||||
# { "id": 1, "user_id": 10, "parent_id": null, "message": "...html text...", "replies": [
|
||||
|
@ -92,8 +93,7 @@ class DiscussionTopicsApiController < ApplicationController
|
|||
|
||||
if structure
|
||||
participant_info = User.find(participant_ids).map do |user|
|
||||
participant_url = @context.is_a?(CollectionItem) ? user_url(user) : polymorphic_url([@context, user])
|
||||
{ :id => user.id, :display_name => user.short_name, :avatar_image_url => avatar_image_url(User.avatar_key(user.id)), :html_url => participant_url }
|
||||
user_display_json(user, @context.is_a_context? && @context)
|
||||
end
|
||||
unread_entries = entry_ids - DiscussionEntryParticipant.read_entry_ids(entry_ids, @current_user)
|
||||
# as an optimization, the view structure is pre-serialized as a json
|
||||
|
|
|
@ -53,6 +53,7 @@ def init
|
|||
|
||||
options[:page_title] = "Canvas LMS REST API Documentation"
|
||||
|
||||
build_json_objects_map
|
||||
generate_assets
|
||||
serialize_index
|
||||
serialize_static_pages
|
||||
|
@ -136,3 +137,20 @@ def serialize_static_pages
|
|||
options.delete(:file)
|
||||
end
|
||||
end
|
||||
|
||||
def build_json_objects_map
|
||||
obj_map = {}
|
||||
resource_obj_list = {}
|
||||
options[:resources].each do |r,cs|
|
||||
cs.each do |controller|
|
||||
controller.tags(:object).each do |obj|
|
||||
name, json = obj.text.split(%r{\n+}, 2).map(&:strip)
|
||||
obj_map[name] = topicize r
|
||||
resource_obj_list[r] ||= []
|
||||
resource_obj_list[r] << [name, json]
|
||||
end
|
||||
end
|
||||
end
|
||||
options[:json_objects_map] = obj_map
|
||||
options[:json_objects] = resource_obj_list
|
||||
end
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
SyntaxHighlighter.defaults['gutter'] = false;
|
||||
SyntaxHighlighter.defaults['toolbar'] = false;
|
||||
SyntaxHighlighter.defaults['auto-links'] = false;
|
||||
$('.example_response pre.example.code').addClass('brush: js');
|
||||
$('#content pre.code.javascript code').each(function(i, el) {
|
||||
$(el).parent().addClass('brush: js');
|
||||
$(el).replaceWith(el.innerHTML);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<h4>Example Response:</h4>
|
||||
<% object.tags(:example_response).each do |tag| %>
|
||||
<h4><%= htmlify_line(tag.name) %></h4>
|
||||
<pre class="example code"><%= html_syntax_highlight(tag.text, :plain) %></pre>
|
||||
<pre class="example code brush:js"><%= html_syntax_highlight(tag.text, :plain) %></pre>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
<% if @is_list %>
|
||||
Returns a list of
|
||||
<% else %>
|
||||
Returns a
|
||||
<% end %>
|
||||
<a href='<%= @resource_name %>.html#<%= @object_name %>'><%= @is_list ? @object_name.pluralize : @object_name %></a>
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
def init
|
||||
super
|
||||
sections :argument, :request_field, :response_field, :example_request, :example_response
|
||||
sections :argument, :request_field, :response_field, :example_request, :example_response, :returns
|
||||
end
|
||||
|
||||
def request_field
|
||||
|
@ -33,6 +33,22 @@ def argument
|
|||
generic_tag :argument, :no_types => false, :label => "Request Parameters"
|
||||
end
|
||||
|
||||
def returns
|
||||
return unless object.has_tag?(:returns)
|
||||
response_info = object.tag(:returns)
|
||||
case response_info.text
|
||||
when %r{\[(.*)\]}
|
||||
@object_name = $1.strip
|
||||
@is_list = true
|
||||
else
|
||||
@object_name = response_info.text.strip
|
||||
@is_list = false
|
||||
end
|
||||
@resource_name = options[:json_objects_map][@object_name]
|
||||
return unless @resource_name
|
||||
erb(:returns)
|
||||
end
|
||||
|
||||
def generic_tag(name, opts = {})
|
||||
return unless object.has_tag?(name)
|
||||
@no_names = true if opts[:no_names]
|
||||
|
|
|
@ -36,5 +36,6 @@ end
|
|||
def topic_doc
|
||||
@docstring = options[:controllers].map { |c| c.docstring }.join("\n\n")
|
||||
def @object.source_type; nil; end
|
||||
htmlify(@docstring.strip, :markdown)
|
||||
@json_objects = options[:json_objects][@resource] || []
|
||||
erb(:topic_doc)
|
||||
end
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<%= htmlify(@docstring.strip, :markdown) %>
|
||||
|
||||
<% @json_objects.each do |name, json| %>
|
||||
<div class='object_definition'>
|
||||
<h3><a name="<%= name %>">A <%= name %> object looks like:</a></h3>
|
||||
|
||||
<pre class="example code brush:js">
|
||||
<%= html_syntax_highlight(json, :plain) %>
|
||||
</pre>
|
||||
</div>
|
||||
<% end %>
|
|
@ -18,13 +18,14 @@
|
|||
|
||||
module Api::V1::Collection
|
||||
include Api::V1::Json
|
||||
include Api::V1::User
|
||||
|
||||
API_COLLECTION_JSON_OPTS = {
|
||||
:only => %w(id name visibility),
|
||||
}
|
||||
|
||||
API_COLLECTION_ITEM_JSON_OPTS = {
|
||||
:only => %w(id collection_id user_id user_comment created_at),
|
||||
:only => %w(id collection_id user_comment created_at),
|
||||
}
|
||||
|
||||
API_COLLECTION_ITEM_DATA_JSON_OPTS = {
|
||||
|
@ -54,6 +55,7 @@ module Api::V1::Collection
|
|||
|
||||
items.map do |item|
|
||||
hash = api_json(item, current_user, session, API_COLLECTION_ITEM_JSON_OPTS)
|
||||
hash['user'] = user_display_json(item.user)
|
||||
hash['url'] = api_v1_collection_item_url(item)
|
||||
item_data = item.collection_item_data
|
||||
hash['image_pending'] = item_data.image_pending
|
||||
|
|
|
@ -52,6 +52,22 @@ module Api::V1::User
|
|||
end
|
||||
end
|
||||
|
||||
# this mini-object is used for secondary user responses, when we just want to
|
||||
# provide enough information to display a user.
|
||||
# for instance, discussion entries return this json as a sub-object.
|
||||
#
|
||||
# if parent_context is given, the html_url will be scoped to that context, so:
|
||||
# /courses/X/users/Y
|
||||
# otherwise it'll just be:
|
||||
# /users/Y
|
||||
# keep in mind the latter form is only accessible if the user has a public profile
|
||||
# (or if the api caller is an admin)
|
||||
def user_display_json(user, parent_context = nil)
|
||||
return {} unless user
|
||||
participant_url = parent_context ? polymorphic_url([parent_context, user]) : user_url(user)
|
||||
{ :id => user.id, :display_name => user.short_name, :avatar_image_url => avatar_image_url(User.avatar_key(user.id)), :html_url => participant_url }
|
||||
end
|
||||
|
||||
# optimization hint, currently user only needs to pull pseudonyms from the db
|
||||
# if a site admin is making the request or they can manage_students
|
||||
def user_json_is_admin?(context = @context, current_user = @current_user)
|
||||
|
|
|
@ -36,6 +36,8 @@ YARD::Tags::Library.define_tag("API example request", :example_request)
|
|||
YARD::Tags::Library.define_tag("API example response", :example_response)
|
||||
YARD::Tags::Library.define_tag("API subtopic", :subtopic)
|
||||
YARD::Tags::Library.define_tag("API resource is Beta", :beta)
|
||||
YARD::Tags::Library.define_tag("API Object Definition", :object)
|
||||
YARD::Tags::Library.define_tag("API Return Type", :returns)
|
||||
|
||||
module YARD::Templates::Helpers
|
||||
module BaseHelper
|
||||
|
|
|
@ -169,7 +169,12 @@ describe "Collections API", :type => :integration do
|
|||
{
|
||||
'id' => item.id,
|
||||
'collection_id' => item.collection_id,
|
||||
'user_id' => item.user_id,
|
||||
'user' => {
|
||||
'id' => item.user.id,
|
||||
'display_name' => item.user.short_name,
|
||||
'avatar_image_url' => "http://www.example.com/images/users/#{User.avatar_key(item.user.id)}",
|
||||
'html_url' => (item.user == @user) ? "http://www.example.com/profile" : "http://www.example.com/users/#{item.user.id}",
|
||||
},
|
||||
'item_type' => item.collection_item_data.item_type,
|
||||
'link_url' => item.collection_item_data.link_url,
|
||||
'post_count' => item.collection_item_data.post_count,
|
||||
|
|
|
@ -374,7 +374,12 @@ describe UsersController, :type => :integration do
|
|||
'collection_item' => {
|
||||
'id' => @item.id,
|
||||
'collection_id' => @item.collection_id,
|
||||
'user_id' => @item.user_id,
|
||||
'user' => {
|
||||
'id' => @item.user.id,
|
||||
'display_name' => @item.user.short_name,
|
||||
'avatar_image_url' => "http://www.example.com/images/users/#{User.avatar_key(@item.user.id)}",
|
||||
'html_url' => (@item.user == @user) ? "http://www.example.com/profile" : "http://www.example.com/users/#{@item.user.id}",
|
||||
},
|
||||
'item_type' => @item.collection_item_data.item_type,
|
||||
'link_url' => @item.collection_item_data.link_url,
|
||||
'post_count' => @item.collection_item_data.post_count,
|
||||
|
|
Loading…
Reference in New Issue