Remove Google Docs plugin
Google drive relevant code has been moved to the gems/google_drive Actually test google drive with mocked api responses cleaned up lots of code Fixes PLAT-1301 Test Plan: *** You'll need to use 2 separate google accounts to fully test *** ** Its helpful to have multiple chrome profiles so you dont have to log in and ** out a bunch https://support.google.com/chrome/answer/2364824?hl=en BEFORE SWITCHING TO THIS PATCH SET - Make sure you have some google doc collaborations - Directions for creating one are below - Disable your google docs plugin Switch to the patch set Enable google drive. (if not already) - You should be able to paste in a client_secrets.json - Update Redirect URI to point to your local instance (The URI should exist in the JSON) As an admin/teacher - Goto `profile/settings` and add the google drive user service - Your email should be displayed with the service - Goto Collaborations - Make sure existing collaborations still work - Click "Start new collaboration" - give it a nice name (Created by admin) - select your student - click start collaborating - You should be redirected to the new doc in google - create another collaboration without the student (Created by admin, no users) - Create an assignment with Submission Type: Online Online Entry Options: File Uploads - Make sure your student has access to the course/assignment - Goto Account settings -> Users - Click View User Groups in the top right - create a new group set with a group in it - add yourself and your student to the group - Goto the Group's Collaborations (Courses & Groups -> [group name] -> Collaborations) - Click "Start new collaboration" - give it a nice name (Created by admin for group) - select your student - click start collaborating - You should be redirected to the new doc in google As a student - Goto `profile/settings` and add the google drive user service - Your email should be displayed with the service - Goto the assignment - Submit the assignment - You should have a "Google Doc" tab - Choose a document and submit it - After it submitted, click download on the right side just to make sure its correct - Goto Collaborations - Make sure existing collaborations still work - make sure the "created by admin" collaboration works - make sure you can't see "Created by admin, no users" - Click "Start new collaboration" - give it a nice name (created by a student) - click start collaborating - You should be redirected to the new doc in google - Switch to your admin/teacher and make sure they can't access it - Edit the collaboration add the teacher, click Save - Switch to your admin/teacher and make sure they can access it - Goto `profile/settings` and REMOVE the google drive user service - Go back to collaborations - You should be forced to add the google service in order to use a collaboration - Goto the Group's Collaborations (Courses & Groups -> [group name] -> Collaborations) - Make sure you can access "Created by admin for group" - Click "Start new collaboration" - select your admin/teacher - click start collaborating - You should be redirected to the new doc in google - make sure your admin can access it to As a site admin - Disable Google Drive - Then with your student - Make sure you can still do file upload submissions on the assignment - Collaborations should no longer show up (unless you have etherpad enabled) - Google drive should no longer show up in your profile settings as a registered service Change-Id: I4dfaff6f5262743c044aadd12266fd0bd85a60e1 Reviewed-on: https://gerrit.instructure.com/69078 Reviewed-by: Andrew Butterfield <abutterfield@instructure.com> Tested-by: Jenkins QA-Review: August Thornton <august@instructure.com> Product-Review: Brad Horrocks <bhorrocks@instructure.com>
This commit is contained in:
parent
3da893f521
commit
3fee901ac0
|
@ -128,7 +128,6 @@ gem 'canvas_text_helper', path: 'gems/canvas_text_helper'
|
|||
gem 'canvas_time', path: 'gems/canvas_time'
|
||||
gem 'canvas_unzip', path: 'gems/canvas_unzip'
|
||||
gem 'csv_diff', path: 'gems/csv_diff'
|
||||
gem 'google_docs', path: 'gems/google_docs'
|
||||
gem 'google_drive', path: 'gems/google_drive'
|
||||
gem 'html_text_helper', path: 'gems/html_text_helper'
|
||||
gem 'incoming_mail_processor', path: 'gems/incoming_mail_processor'
|
||||
|
|
|
@ -1504,8 +1504,6 @@ class ApplicationController < ActionController::Base
|
|||
!!LinkedIn::Connection.config
|
||||
elsif feature == :diigo
|
||||
!!Diigo::Connection.config
|
||||
elsif feature == :google_docs
|
||||
!!GoogleDocs::Connection.config
|
||||
elsif feature == :google_drive
|
||||
Canvas::Plugin.find(:google_drive).try(:enabled?)
|
||||
elsif feature == :etherpad
|
||||
|
@ -1957,29 +1955,13 @@ class ApplicationController < ActionController::Base
|
|||
end
|
||||
end
|
||||
|
||||
def google_docs_connection
|
||||
## @real_current_user first ensures that a masquerading user never sees the
|
||||
## masqueradee's files, but in general you may want to block access to google
|
||||
## docs for masqueraders earlier in the request
|
||||
if logged_in_user
|
||||
service_token, service_secret = Rails.cache.fetch(['google_docs_tokens', logged_in_user].cache_key) do
|
||||
service = logged_in_user.user_services.where(service: "google_docs").first
|
||||
service && [service.token, service.secret]
|
||||
end
|
||||
raise GoogleDocs::NoTokenError unless service_token && service_secret
|
||||
google_docs = GoogleDocs::Connection.new(service_token, service_secret)
|
||||
else
|
||||
google_docs = GoogleDocs::Connection.new(session[:oauth_gdocs_access_token_token], session[:oauth_gdocs_access_token_secret])
|
||||
end
|
||||
google_docs
|
||||
end
|
||||
|
||||
def self.google_drive_timeout
|
||||
Setting.get('google_drive_timeout', 30).to_i
|
||||
end
|
||||
|
||||
def google_drive_connection
|
||||
return unless Canvas::Plugin.find(:google_drive).try(:settings)
|
||||
return @google_drive_connection if @google_drive_connection
|
||||
|
||||
## @real_current_user first ensures that a masquerading user never sees the
|
||||
## masqueradee's files, but in general you may want to block access to google
|
||||
## docs for masqueraders earlier in the request
|
||||
|
@ -1993,24 +1975,7 @@ class ApplicationController < ActionController::Base
|
|||
access_token = session[:oauth_gdrive_access_token]
|
||||
end
|
||||
|
||||
GoogleDocs::DriveConnection.new(refresh_token, access_token, ApplicationController.google_drive_timeout) if refresh_token && access_token
|
||||
end
|
||||
|
||||
def google_service_connection
|
||||
google_drive_connection || google_docs_connection
|
||||
end
|
||||
|
||||
def google_drive_user_client
|
||||
if logged_in_user
|
||||
refresh_token, access_token = Rails.cache.fetch(['google_drive_tokens', logged_in_user].cache_key) do
|
||||
service = logged_in_user.user_services.where(service: "google_drive").first
|
||||
service && [service.token, service.access_token]
|
||||
end
|
||||
else
|
||||
refresh_token = session[:oauth_gdrive_refresh_token]
|
||||
access_token = session[:oauth_gdrive_access_token]
|
||||
end
|
||||
google_drive_client(refresh_token, access_token)
|
||||
@google_drive_connection = GoogleDrive::Connection.new(refresh_token, access_token, ApplicationController.google_drive_timeout)
|
||||
end
|
||||
|
||||
def google_drive_client(refresh_token=nil, access_token=nil)
|
||||
|
@ -2023,6 +1988,9 @@ class ApplicationController < ActionController::Base
|
|||
GoogleDrive::Client.create(client_secrets, refresh_token, access_token)
|
||||
end
|
||||
|
||||
def user_has_google_drive
|
||||
@user_has_google_drive ||= google_drive_connection.authorized?
|
||||
end
|
||||
|
||||
def twitter_connection
|
||||
if @current_user
|
||||
|
|
|
@ -128,16 +128,8 @@ class AssignmentsController < ApplicationController
|
|||
@current_student_submissions = @assignment.submissions.where("submissions.submission_type IS NOT NULL").where(:user_id => visible_student_ids).to_a
|
||||
end
|
||||
|
||||
begin
|
||||
google_docs = google_service_connection
|
||||
@google_service = google_docs.service_type
|
||||
@google_docs_token = google_service_connection.verify_access_token && google_docs.retrieve_access_token rescue false
|
||||
rescue GoogleDocs::NoTokenError
|
||||
# Just fail I guess.
|
||||
end
|
||||
|
||||
@google_drive_upgrade = !!(logged_in_user && Canvas::Plugin.find(:google_drive).try(:settings) &&
|
||||
(!logged_in_user.user_services.where(service: 'google_drive').first || !(google_docs.verify_access_token rescue false)))
|
||||
# this will set @user_has_google_drive
|
||||
user_has_google_drive
|
||||
|
||||
add_crumb(@assignment.title, polymorphic_url([@context, @assignment]))
|
||||
|
||||
|
@ -185,8 +177,10 @@ class AssignmentsController < ApplicationController
|
|||
if assignment.allow_google_docs_submission? && @real_current_user.blank?
|
||||
docs = {}
|
||||
begin
|
||||
docs = google_service_connection.list_with_extension_filter(assignment.allowed_extensions)
|
||||
rescue GoogleDocs::NoTokenError => e
|
||||
docs = google_drive_connection.list_with_extension_filter(assignment.allowed_extensions)
|
||||
rescue GoogleDrive::NoTokenError => e
|
||||
Canvas::Errors.capture_exception(:oauth, e)
|
||||
rescue Google::APIClient::AuthorizationError => e
|
||||
Canvas::Errors.capture_exception(:oauth, e)
|
||||
rescue ArgumentError => e
|
||||
Canvas::Errors.capture_exception(:oauth, e)
|
||||
|
|
|
@ -68,20 +68,8 @@ class CollaborationsController < ApplicationController
|
|||
@collaborations = @context.collaborations.active
|
||||
log_asset_access([ "collaborations", @context ], "collaborations", "other")
|
||||
|
||||
safe_token_valid = lambda do |service|
|
||||
begin
|
||||
self.send(service).verify_access_token
|
||||
rescue => e
|
||||
Canvas::Errors.capture(e, { source: 'rescue nil' })
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
@google_drive_upgrade = logged_in_user && Canvas::Plugin.find(:google_drive).try(:settings) &&
|
||||
(!logged_in_user.user_services.where(service: 'google_drive').first ||
|
||||
!safe_token_valid.call(:google_drive_connection))
|
||||
|
||||
@google_docs_authorized = !@google_drive_upgrade && safe_token_valid.call(:google_service_connection)
|
||||
# this will set @user_has_google_drive
|
||||
user_has_google_drive
|
||||
|
||||
@sunsetting_etherpad = EtherpadCollaboration.config.try(:[], :domain) == "etherpad.instructure.com/p"
|
||||
@has_etherpad_collaborations = @collaborations.any? {|c| c.collaboration_type == 'EtherPad'}
|
||||
|
@ -108,7 +96,7 @@ class CollaborationsController < ApplicationController
|
|||
flash[:error] = t 'errors.cannot_load_collaboration', "Cannot load collaboration"
|
||||
redirect_to named_context_url(@context, :context_collaborations_url)
|
||||
end
|
||||
rescue GoogleDocs::DriveConnectionException => drive_exception
|
||||
rescue GoogleDrive::ConnectionException => drive_exception
|
||||
Canvas::Errors.capture(drive_exception)
|
||||
flash[:error] = t 'errors.cannot_load_collaboration', "Cannot load collaboration"
|
||||
redirect_to named_context_url(@context, :context_collaborations_url)
|
||||
|
@ -163,7 +151,7 @@ class CollaborationsController < ApplicationController
|
|||
format.json { render :json => @collaboration.errors, :status => :bad_request }
|
||||
end
|
||||
end
|
||||
rescue GoogleDocs::DriveConnectionException => error
|
||||
rescue GoogleDrive::ConnectionException => error
|
||||
Rails.logger.warn error
|
||||
flash[:error] = t 'errors.update_failed', "Collaboration update failed" # generic failure message
|
||||
if error.message.include?('File not found')
|
||||
|
|
|
@ -495,10 +495,9 @@ class SubmissionsController < ApplicationController
|
|||
|
||||
def submit_google_doc(document_id)
|
||||
# fetch document from google
|
||||
google_docs = google_service_connection
|
||||
|
||||
# since google drive can have many different export types, we need to send along our preferred extensions
|
||||
document_response, display_name, file_extension = google_docs.download(document_id, @assignment.allowed_extensions)
|
||||
document_response, display_name, file_extension, content_type = google_drive_connection.download(document_id,
|
||||
@assignment.allowed_extensions)
|
||||
|
||||
# error handling
|
||||
unless document_response.try(:is_a?, Net::HTTPOK) || document_response.status == 200
|
||||
|
@ -525,7 +524,7 @@ class SubmissionsController < ApplicationController
|
|||
end
|
||||
|
||||
@attachment = @assignment.attachments.new(
|
||||
uploaded_data: Rack::Test::UploadedFile.new(path, document_response.content_type, true),
|
||||
uploaded_data: Rack::Test::UploadedFile.new(path, content_type, true),
|
||||
display_name: display_name, user: @current_user
|
||||
)
|
||||
@attachment.save!
|
||||
|
|
|
@ -213,19 +213,7 @@ class UsersController < ApplicationController
|
|||
return redirect_to(user_profile_url(@current_user))
|
||||
end
|
||||
return_to_url = params[:return_to] || user_profile_url(@current_user)
|
||||
if params[:service] == "google_docs"
|
||||
request_token = GoogleDocs::Connection.request_token(oauth_success_url(:service => 'google_docs'))
|
||||
OauthRequest.create(
|
||||
:service => 'google_docs',
|
||||
:token => request_token.token,
|
||||
:secret => request_token.secret,
|
||||
:user_secret => CanvasSlug.generate(nil, 16),
|
||||
:return_url => return_to_url,
|
||||
:user => @real_current_user || @current_user,
|
||||
:original_host_with_port => request.host_with_port
|
||||
)
|
||||
redirect_to request_token.authorize_url
|
||||
elsif params[:service] == "google_drive"
|
||||
if params[:service] == "google_drive"
|
||||
redirect_uri = oauth_success_url(:service => 'google_drive')
|
||||
session[:oauth_gdrive_nonce] = SecureRandom.hex
|
||||
state = Canvas::Security.create_jwt(redirect_uri: redirect_uri, return_to_url: return_to_url, nonce: session[:oauth_gdrive_nonce])
|
||||
|
@ -273,7 +261,12 @@ class UsersController < ApplicationController
|
|||
client = google_drive_client
|
||||
client.authorization.code = params[:code]
|
||||
client.authorization.fetch_access_token!
|
||||
drive = client.discovered_api('drive', 'v2')
|
||||
|
||||
# we should look into consolidating this and connection.rb
|
||||
drive = Rails.cache.fetch(['google_drive_v2'].cache_key) do
|
||||
client.discovered_api('drive', 'v2')
|
||||
end
|
||||
|
||||
result = client.execute!(:api_method => drive.about.get)
|
||||
|
||||
if result.status == 200
|
||||
|
@ -318,32 +311,7 @@ class UsersController < ApplicationController
|
|||
url = url_for request.parameters.merge(:host => oauth_request.original_host_with_port, :only_path => false)
|
||||
redirect_to url
|
||||
else
|
||||
if params[:service] == "google_docs"
|
||||
begin
|
||||
access_token = GoogleDocs::Connection.get_access_token(oauth_request.token, oauth_request.secret, params[:oauth_verifier])
|
||||
google_docs = GoogleDocs::Connection.new(oauth_request.token, oauth_request.secret)
|
||||
service_user_id, service_user_name = google_docs.get_service_user_info access_token
|
||||
if oauth_request.user
|
||||
UserService.register(
|
||||
:service => "google_docs",
|
||||
:access_token => access_token,
|
||||
:user => oauth_request.user,
|
||||
:service_domain => "google.com",
|
||||
:service_user_id => service_user_id,
|
||||
:service_user_name => service_user_name
|
||||
)
|
||||
oauth_request.destroy
|
||||
else
|
||||
session[:oauth_gdocs_access_token_token] = access_token.token
|
||||
session[:oauth_gdocs_access_token_secret] = access_token.secret
|
||||
end
|
||||
|
||||
flash[:notice] = t('google_docs_added', "Google Docs access authorized!")
|
||||
rescue => e
|
||||
Canvas::Errors.capture_exception(:oauth, e)
|
||||
flash[:error] = t('google_docs_fail', "Google Docs authorization failed. Please try again")
|
||||
end
|
||||
elsif params[:service] == "linked_in"
|
||||
if params[:service] == "linked_in"
|
||||
begin
|
||||
linkedin_connection = LinkedIn::Connection.new
|
||||
token = session.delete(:oauth_linked_in_request_token_token)
|
||||
|
@ -967,8 +935,8 @@ class UsersController < ApplicationController
|
|||
|
||||
def delete_user_service
|
||||
deleted = @current_user.user_services.find(params[:id]).destroy
|
||||
if deleted.service == "google_docs"
|
||||
Rails.cache.delete(['google_docs_tokens', @current_user].cache_key)
|
||||
if deleted.service == "google_drive"
|
||||
Rails.cache.delete(['google_drive_tokens', @current_user].cache_key)
|
||||
end
|
||||
render :json => {:deleted => true}
|
||||
end
|
||||
|
|
|
@ -150,7 +150,17 @@ class Collaboration < ActiveRecord::Base
|
|||
# Returns an array of type hashes w/ 'name' and 'type' keys.
|
||||
def self.collaboration_types
|
||||
Canvas::Plugin.all_for_tag(:collaborations).select(&:enabled?).map do |plugin|
|
||||
HashWithIndifferentAccess.new({ 'name' => plugin.name, 'type' => plugin.id })
|
||||
# google_drive is really a google_docs_collaboration
|
||||
# eventually this will go away. baby steps...
|
||||
if plugin.id == 'google_drive'
|
||||
type = 'google_docs'
|
||||
name = 'Google Docs'
|
||||
else
|
||||
type = plugin.id
|
||||
name = plugin.name
|
||||
end
|
||||
|
||||
HashWithIndifferentAccess.new({ 'name' => name, 'type' => type })
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -219,7 +229,7 @@ class Collaboration < ActiveRecord::Base
|
|||
#
|
||||
# Returns a title string.
|
||||
def title
|
||||
read_attribute(:title) || self.parse_data.title
|
||||
read_attribute(:title) || self.parse_data["title"]
|
||||
rescue NoMethodError
|
||||
t('#collaboration.default_title', 'Unnamed Collaboration')
|
||||
end
|
||||
|
|
|
@ -16,10 +16,7 @@
|
|||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
require 'atom'
|
||||
|
||||
class GoogleDocsCollaboration < Collaboration
|
||||
GOOGLE_DOC_SERVICE = "google.com"
|
||||
GOOGLE_DRIVE_SERVICE = "drive.google.com"
|
||||
|
||||
def style_class
|
||||
|
@ -34,7 +31,7 @@ class GoogleDocsCollaboration < Collaboration
|
|||
if self.document_id && self.user
|
||||
# google docs expected an object
|
||||
# drive just wants an id
|
||||
doc = is_google_drive ? self.document_id : GoogleDocs::Entry.new(self.data)
|
||||
doc = self.document_id
|
||||
google_adapter_for_user.delete_doc(doc)
|
||||
end
|
||||
end
|
||||
|
@ -47,16 +44,10 @@ class GoogleDocsCollaboration < Collaboration
|
|||
|
||||
result = google_adapter_for_user.create_doc(name)
|
||||
if result
|
||||
if is_google_drive
|
||||
self.document_id = result.data.id
|
||||
self.data = result.data.to_json
|
||||
self.document_id = result.data.id
|
||||
self.data = result.data.to_json
|
||||
|
||||
self.url = result.data.alternateLink
|
||||
else
|
||||
self.document_id = result.document_id
|
||||
self.data = result.entry.to_xml
|
||||
self.url = result.alternate_url.to_s
|
||||
end
|
||||
self.url = result.data.alternateLink
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -75,7 +66,7 @@ class GoogleDocsCollaboration < Collaboration
|
|||
if collaborator.authorized_service_user_id != service_user_id
|
||||
google_adapter_for_user.acl_remove(self.document_id, [collaborator.authorized_service_user_id]) if collaborator.authorized_service_user_id
|
||||
|
||||
user_param = is_google_drive ? service_user_id : user
|
||||
user_param = service_user_id
|
||||
google_adapter_for_user.acl_add(self.document_id, [user_param])
|
||||
collaborator.update_attributes(:authorized_service_user_id => service_user_id)
|
||||
end
|
||||
|
@ -86,10 +77,8 @@ class GoogleDocsCollaboration < Collaboration
|
|||
end
|
||||
|
||||
def remove_users_from_document(users_to_remove)
|
||||
if is_google_drive
|
||||
users_to_remove = users_to_remove.map do |user|
|
||||
user_service = google_user_service(user, GOOGLE_DRIVE_SERVICE) and user_service.service_user_id
|
||||
end
|
||||
users_to_remove = users_to_remove.map do |user|
|
||||
user_service = google_user_service(user, GOOGLE_DRIVE_SERVICE) and user_service.service_user_id
|
||||
end
|
||||
|
||||
google_adapter_for_user.acl_remove(self.document_id, users_to_remove) if self.document_id
|
||||
|
@ -103,24 +92,20 @@ class GoogleDocsCollaboration < Collaboration
|
|||
nil
|
||||
end
|
||||
|
||||
if is_google_drive
|
||||
user_ids = new_users.map do |user|
|
||||
google_user_service(user, GOOGLE_DRIVE_SERVICE).service_user_id rescue nil
|
||||
end.compact
|
||||
else
|
||||
user_ids = new_users
|
||||
end
|
||||
user_ids = new_users.map do |user|
|
||||
google_user_service(user, GOOGLE_DRIVE_SERVICE).service_user_id rescue nil
|
||||
end.compact
|
||||
|
||||
google_adapter_for_user.acl_add(self.document_id, user_ids, domain)
|
||||
end
|
||||
end
|
||||
|
||||
def parse_data
|
||||
@entry_data ||= Atom::Entry.load_entry(self.data)
|
||||
@entry_data ||= JSON.parse(self.data)
|
||||
end
|
||||
|
||||
def self.config
|
||||
GoogleDocs::Connection.config
|
||||
GoogleDrive::Connection.config
|
||||
end
|
||||
|
||||
# Internal: Update collaborators with the given groups.
|
||||
|
@ -142,43 +127,25 @@ class GoogleDocsCollaboration < Collaboration
|
|||
|
||||
private
|
||||
|
||||
##
|
||||
# Check to see if this collaboration can use google drive
|
||||
def is_google_drive(user=self.user)
|
||||
return unless Canvas::Plugin.find(:google_drive).try(:settings)
|
||||
@google_drive ||= {}
|
||||
@google_drive[user.id] ||= !!google_user_service(user, GOOGLE_DRIVE_SERVICE)
|
||||
end
|
||||
|
||||
def google_user_service(user, service_domain=GOOGLE_DOC_SERVICE)
|
||||
def google_user_service(user, service_domain=GOOGLE_DRIVE_SERVICE)
|
||||
google_services = user.user_services.where(service_domain: service_domain).to_a
|
||||
google_services.find{|s| s.service_user_id}
|
||||
end
|
||||
|
||||
def google_docs_for_user
|
||||
service_token, service_secret = Rails.cache.fetch(['google_docs_tokens', self.user].cache_key) do
|
||||
service = self.user.user_services.where(service: "google_docs").first
|
||||
service && [service.token, service.secret]
|
||||
end
|
||||
raise GoogleDocs::NoTokenError unless service_token && service_secret
|
||||
GoogleDocs::Connection.new(service_token, service_secret)
|
||||
end
|
||||
|
||||
def google_drive_for_user
|
||||
refresh_token, access_token = Rails.cache.fetch(['google_drive_tokens', self.user].cache_key) do
|
||||
service = self.user.user_services.where(service: "google_drive").first
|
||||
service && [service.token, service.secret]
|
||||
end
|
||||
raise GoogleDocs::NoTokenError unless refresh_token && access_token
|
||||
GoogleDocs::DriveConnection.new(refresh_token, access_token, ApplicationController.google_drive_timeout)
|
||||
raise GoogleDrive::NoTokenError unless refresh_token && access_token
|
||||
GoogleDrive::Connection.new(refresh_token, access_token, ApplicationController.google_drive_timeout)
|
||||
end
|
||||
|
||||
def google_adapter_for_user
|
||||
return google_drive_for_user if is_google_drive
|
||||
google_docs_for_user
|
||||
google_drive_for_user
|
||||
end
|
||||
|
||||
def google_adapter_user_service(user)
|
||||
google_user_service(user, GOOGLE_DRIVE_SERVICE) || google_user_service(user)
|
||||
google_user_service(user)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
class UserService < ActiveRecord::Base
|
||||
include Workflow
|
||||
|
||||
|
||||
belongs_to :user
|
||||
attr_accessor :password
|
||||
attr_accessible :user, :service, :protocol, :token, :secret, :service_user_url, :service_user_id, :service_user_name, :service_domain, :visible
|
||||
|
@ -29,11 +29,11 @@ class UserService < ActiveRecord::Base
|
|||
after_save :assert_relations
|
||||
after_save :touch_user
|
||||
after_destroy :remove_related_channels
|
||||
|
||||
|
||||
def should_have_communication_channel?
|
||||
[CommunicationChannel::TYPE_TWITTER, CommunicationChannel::TYPE_YO].include?(service) && self.user
|
||||
end
|
||||
|
||||
|
||||
def assert_relations
|
||||
if should_have_communication_channel?
|
||||
cc = self.user.communication_channels.where(path_type: service).first_or_initialize
|
||||
|
@ -47,7 +47,7 @@ class UserService < ActiveRecord::Base
|
|||
end
|
||||
true
|
||||
end
|
||||
|
||||
|
||||
def remove_related_channels
|
||||
# should this include twitter?
|
||||
if [CommunicationChannel::TYPE_YO].include?(self.service) && self.user
|
||||
|
@ -56,25 +56,25 @@ class UserService < ActiveRecord::Base
|
|||
end
|
||||
true
|
||||
end
|
||||
|
||||
|
||||
def assert_communication_channel
|
||||
# why is twitter getting special treatment?
|
||||
self.touch if should_have_communication_channel? && !self.user.communication_channels.where(path_type: CommunicationChannel::TYPE_TWITTER).first
|
||||
end
|
||||
|
||||
|
||||
def infer_defaults
|
||||
self.refresh_at ||= Time.now.utc
|
||||
end
|
||||
protected :infer_defaults
|
||||
|
||||
|
||||
workflow do
|
||||
state :active do
|
||||
event :failed_request, :transitions_to => :failed
|
||||
end
|
||||
|
||||
|
||||
state :failed
|
||||
end
|
||||
|
||||
|
||||
scope :of_type, lambda { |type| where(:type => type.to_s) }
|
||||
|
||||
scope :to_be_polled, -> { where("refresh_at<", Time.now.utc).order(:refresh_at).limit(1) }
|
||||
|
@ -84,20 +84,20 @@ class UserService < ActiveRecord::Base
|
|||
where(:service => service.to_s)
|
||||
}
|
||||
scope :visible, -> { where("visible") }
|
||||
|
||||
|
||||
def service_name
|
||||
self.service.titleize rescue ""
|
||||
end
|
||||
|
||||
|
||||
def password=(password)
|
||||
self.crypted_password, self.password_salt = Canvas::Security.encrypt_password(password, 'instructure_user_service')
|
||||
end
|
||||
|
||||
|
||||
def decrypted_password
|
||||
return nil unless self.password_salt && self.crypted_password
|
||||
Canvas::Security.decrypt_password(self.crypted_password, self.password_salt, 'instructure_user_service')
|
||||
end
|
||||
|
||||
|
||||
def self.register(opts={})
|
||||
raise "User required" unless opts[:user]
|
||||
token = opts[:access_token] ? opts[:access_token].token : opts[:token]
|
||||
|
@ -117,7 +117,7 @@ class UserService < ActiveRecord::Base
|
|||
user_service.save!
|
||||
user_service
|
||||
end
|
||||
|
||||
|
||||
def self.register_from_params(user, params={})
|
||||
opts = {}
|
||||
opts[:user] = user
|
||||
|
@ -153,19 +153,17 @@ class UserService < ActiveRecord::Base
|
|||
end
|
||||
register(opts)
|
||||
end
|
||||
|
||||
|
||||
def has_profile_link?
|
||||
service != 'google_docs'
|
||||
true
|
||||
end
|
||||
|
||||
|
||||
def has_readable_user_name?
|
||||
service == 'google_docs'
|
||||
service == 'google_drive'
|
||||
end
|
||||
|
||||
|
||||
def self.sort_position(type)
|
||||
case type
|
||||
when 'google_docs'
|
||||
1
|
||||
when 'google_drive'
|
||||
2
|
||||
when 'skype'
|
||||
|
@ -184,11 +182,9 @@ class UserService < ActiveRecord::Base
|
|||
999
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def self.short_description(type)
|
||||
case type
|
||||
when 'google_docs'
|
||||
t '#user_service.descriptions.google_docs', 'Students can use Google Docs to collaborate on group projects. Google Docs allows for real-time collaborative editing of documents, spreadsheets and presentations.'
|
||||
when 'google_drive'
|
||||
t '#user_service.descriptions.google_drive', 'Students can use Google Drive to collaborate on group projects. Google Drive allows for real-time collaborative editing of documents, spreadsheets and presentations.'
|
||||
when 'google_calendar'
|
||||
|
@ -209,11 +205,9 @@ class UserService < ActiveRecord::Base
|
|||
''
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def self.registration_url(type)
|
||||
case type
|
||||
when 'google_docs'
|
||||
'http://docs.google.com'
|
||||
when 'google_drive'
|
||||
'https://www.google.com/drive/'
|
||||
when 'google_calendar'
|
||||
|
@ -234,11 +228,9 @@ class UserService < ActiveRecord::Base
|
|||
nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def service_user_link
|
||||
case service
|
||||
when 'google_docs'
|
||||
'http://docs.google.com'
|
||||
when 'google_drive'
|
||||
'https://myaccount.google.com/?pli=1'
|
||||
when 'google_calendar'
|
||||
|
@ -259,15 +251,15 @@ class UserService < ActiveRecord::Base
|
|||
'http://www.instructure.com'
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def self.configured_services
|
||||
[:google_docs, :google_drive, :twitter, :yo, :linked_in, :diigo]
|
||||
[:google_drive, :twitter, :yo, :linked_in, :diigo]
|
||||
end
|
||||
|
||||
|
||||
def self.configured_service?(service)
|
||||
configured_services.include?((service || "").to_sym)
|
||||
end
|
||||
|
||||
|
||||
def self.service_type(type)
|
||||
if type == 'google_docs' || type == 'google_drive'
|
||||
'DocumentService'
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
show_google_docs = @assignment.allow_google_docs_submission? &&
|
||||
@real_current_user.blank? &&
|
||||
@domain_root_account &&
|
||||
feature_and_service_enabled?(:google_docs)
|
||||
feature_and_service_enabled?(:google_drive)
|
||||
-%>
|
||||
<%
|
||||
js_bundle :submit_assignment
|
||||
|
@ -204,7 +204,7 @@
|
|||
}
|
||||
</style>
|
||||
<% if show_google_docs %>
|
||||
<% if @google_docs_token and not @google_drive_upgrade%>
|
||||
<% if @user_has_google_drive %>
|
||||
<% if @domain_root_account.feature_enabled?(:google_docs_domain_restriction) &&
|
||||
@domain_root_account.settings[:google_docs_domain] &&
|
||||
!@current_user.gmail.match(%r{@#{@domain_root_account.settings[:google_docs_domain]}$}) %>
|
||||
|
@ -268,20 +268,13 @@
|
|||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% elsif @google_drive_upgrade %>
|
||||
<% else %>
|
||||
<div id="submit_google_doc_form">
|
||||
<%= t 'messages.google_drives_auth_required', "Before you can submit assignments directly from Google Drive you need to authorize Canvas to access your Google Drive account:" %>
|
||||
<div style="font-size: 1.1em; text-align: center; margin: 10px;">
|
||||
<a class="btn" href="<%= oauth_url(:service => :google_drive, :return_to => (request.url + "#submit_google_doc_form")) %>"><%= t 'links.authorize_google_drive', "Authorize Google Drive Access" %></a>
|
||||
</div>
|
||||
</div>
|
||||
<% else %>
|
||||
<div id="submit_google_doc_form">
|
||||
<%= t 'messages.google_docs_auth_required', "Before you can submit assignments directly from Google Docs you need to authorize Canvas to access your Google Docs account:" %>
|
||||
<div style="font-size: 1.1em; text-align: center; margin: 10px;">
|
||||
<a class="btn" href="<%= oauth_url(:service => :google_docs, :return_to => (request.url + "#submit_google_doc_form")) %>"><%= t 'links.authorize_google_docs', "Authorize Google Docs Access" %></a>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<% Collaboration.collaboration_types.each do |collab_type| %>
|
||||
<% next if collab_type['type'] == 'etherpad' && @sunsetting_etherpad %>
|
||||
<% if collab_type['type'] == 'google_docs' %>
|
||||
<% if @domain_root_account && feature_and_service_enabled?(:google_docs) %>
|
||||
<% if @domain_root_account && feature_and_service_enabled?(:google_drive) %>
|
||||
<option value="<%= collab_type['name'] %>"><%= collab_type['name'] %></option>
|
||||
<% end %>
|
||||
<% elsif (Collaboration.collaboration_class(collab_type['type'].titleize.gsub(/\s/, "")).config rescue false) %>
|
||||
|
@ -20,7 +20,7 @@
|
|||
<% end %>
|
||||
</select>
|
||||
</td>
|
||||
</tr><tr id="google_docs_description" style="display: none;" class="collaboration_type <%= 'unauthorized' unless @google_docs_authorized%>">
|
||||
</tr><tr id="google_docs_description" style="display: none;" class="collaboration_type <%= 'unauthorized' unless @user_has_google_drive %>">
|
||||
<td colspan="2" style="padding: 5px 20px 10px">
|
||||
<%= image_tag "google_docs_icon.png", :style => "float: right; margin-left: 15px;" %>
|
||||
<%= mt 'descriptions.google_docs', "Google Docs is a great place to collaborate on a group project. It's like Microsoft Word, but lets you work together with others on the same file at the same time without having to email it around. \n \n**Warning**: you (and all your collaborators) will need a Google account in order to participate in any Google Docs collaborations." %>
|
||||
|
@ -57,20 +57,14 @@ HEREDOC
|
|||
</div>
|
||||
</div>
|
||||
<div id="collaborate_authorize_google_docs" class="collaboration_authorization" style="display: none; margin: 20px;">
|
||||
<% if @google_drive_upgrade %>
|
||||
<% if !@user_has_google_drive %>
|
||||
<%= t '#instructions.authorize_google_drive', "Before you can collaborate on documents, you need to authorize Canvas
|
||||
to access your Google Drive account:" %>
|
||||
<div class="button-container">
|
||||
<a class="btn button-default-action" href="<%= oauth_url(:service => :google_drive, :return_to => (request.url + "#add_collaboration")) %>"><%= t '#buttons.authorize_google_drive', "Authorize Google Drive Access" %></a>
|
||||
<button type="button" class="btn button-secondary cancel_button"><%= t '#buttons.cancel', "Cancel" %></button>
|
||||
</div>
|
||||
<% else %>
|
||||
<%= t '#instructions.authorize_google_docs', "Before you can collaborate on documents, you need to authorize Canvas
|
||||
to access your Google Docs account:" %>
|
||||
<div class="button-container">
|
||||
<a class="btn button-default-action" href="<%= oauth_url(:service => :google_docs, :return_to => (request.url + "#add_collaboration")) %>"><%= t '#buttons.authorize_google_docs', "Authorize Google Docs Access" %></a>
|
||||
<button type="button" class="btn button-secondary cancel_button"><%= t '#buttons.cancel', "Cancel" %></button>
|
||||
</div>
|
||||
|
||||
<% end %>
|
||||
</div>
|
||||
</td>
|
||||
|
|
|
@ -56,7 +56,7 @@ HEREDOC
|
|||
<div id="collaborations">
|
||||
<% @collaborations.each do |collaboration| %>
|
||||
<% if can_do(collaboration, @current_user, :read) %>
|
||||
<% if !collaboration.is_a?(GoogleDocsCollaboration) || (collaboration.is_a?(GoogleDocsCollaboration) && !@google_drive_upgrade) %>
|
||||
<% if !collaboration.is_a?(GoogleDocsCollaboration) || (collaboration.is_a?(GoogleDocsCollaboration) && @user_has_google_drive) %>
|
||||
<div class="collaboration <%= collaboration.style_class %> collaboration_<%= collaboration.id %>" data-id="<%= collaboration.id %>">
|
||||
<div class="collaboration-header clearfix">
|
||||
<h2>
|
||||
|
@ -81,7 +81,7 @@ HEREDOC
|
|||
:at => datetime_string(collaboration.created_at) %>
|
||||
</small>
|
||||
</div>
|
||||
<% elsif @google_drive_upgrade %>
|
||||
<% elsif !@user_has_google_drive %>
|
||||
<div class="collaboration <%= collaboration.style_class %> collaboration_<%= collaboration.id %>" data-id="<%= collaboration.id %>">
|
||||
<h3><%= collaboration.title %></h3>
|
||||
<div style="margin-bottom: 5px;" class="description">
|
||||
|
|
|
@ -229,6 +229,9 @@ TEXT
|
|||
<% if service.has_profile_link? %>
|
||||
<a href="<%= service.service_user_link %>">
|
||||
<%= t('links.view_your_profile', "view your profile") %>
|
||||
<% if service.has_readable_user_name? %>
|
||||
<span><%= service.service_user_name %></span>
|
||||
<% end %>
|
||||
</a>
|
||||
<% elsif service.has_readable_user_name? %>
|
||||
<span><%= service.service_user_name %></span>
|
||||
|
@ -252,26 +255,8 @@ TEXT
|
|||
<%= before_label(:other_services, "Click any service below to register") %>
|
||||
<% services = @user.user_services.map{|s| s.service} %>
|
||||
<ul id="unregistered_services" class="unstyled_list">
|
||||
<li id="unregistered_service_google_docs" class="service" style="<%= hidden if !feature_and_service_enabled?(:google_docs) || services.include?("google_docs") %>">
|
||||
<a href="#" class="btn btn-small"><%= image_tag "google_docs_icon.png" %> <%= t('links.google_docs', "Google Docs") %></a>
|
||||
<div style="display: none; text-align: left;" class="content" title="<%= t('titles.authorize_google_docs', "Authorize Google Docs") %>" id="unregistered_service_google_docs_dialog">
|
||||
<div>
|
||||
<%= image_tag "google_docs.png", :style => "float: left; padding-right: 5px;" %>
|
||||
<div style="font-size: 1.2em; font-weight: bold;"><%= t('headers.google_docs_access', "Google Docs Access") %></div>
|
||||
<%= t(:google_docs_description, <<-TEXT)
|
||||
Once you authorize us to see your Google Docs you'll be able to submit your assignments
|
||||
directly from Google Docs, and create and share documents with members of your classes.
|
||||
TEXT
|
||||
%>
|
||||
<div class="clear"></div>
|
||||
</div>
|
||||
<div style="text-align: center; margin-top: 10px;">
|
||||
<a class="btn" href="<%= oauth_url(:service => "google_docs", :return_to => settings_profile_url) %>"><%= t('buttons.authorize_google_docs', "Authorize Google Docs Access") %></a>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li id="unregistered_service_google_drive" class="service" style="<%= hidden if !feature_enabled?(:google_drive) || !feature_and_service_enabled?(:google_docs) || services.include?("google_drive") %>">
|
||||
<li id="unregistered_service_google_drive" class="service" style="<%= hidden if !feature_and_service_enabled?(:google_drive) || services.include?("google_drive") %>">
|
||||
<a href="#" class="btn btn-small"><%= image_tag "google_drive_icon.png" %> <%= t('links.google_drive', "Google Drive") %></a>
|
||||
<div style="display: none; text-align: left;" class="content" title="<%= t('titles.authorize_google_drive', "Authorize Google Drive") %>" id="unregistered_service_google_drive_dialog">
|
||||
<div>
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
|
||||
GoogleDocs::DriveConnection.config = Proc.new do
|
||||
settings = Canvas::Plugin.find(:google_drive).try(:settings)
|
||||
if settings
|
||||
settings = settings.dup
|
||||
settings[:client_secret] = settings[:client_secret_dec]
|
||||
end
|
||||
settings || ConfigFile.load('google_drive')
|
||||
end
|
||||
|
||||
GoogleDocs::Connection.config = Proc.new do
|
||||
Canvas::Plugin.find(:google_docs).try(:settings) || ConfigFile.load('google_docs')
|
||||
end
|
||||
|
||||
GoogleDocs::Entry.extension_looker_upper = ScribdMimeType
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
GoogleDrive::Connection.config = proc do
|
||||
settings = Canvas::Plugin.find(:google_drive).try(:settings)
|
||||
if settings
|
||||
settings = settings.dup
|
||||
settings[:client_secret] = settings[:client_secret_dec]
|
||||
end
|
||||
settings || ConfigFile.load('google_drive')
|
||||
end
|
|
@ -1,4 +0,0 @@
|
|||
source 'https://rubygems.org'
|
||||
|
||||
# Specify your gem's dependencies in google_docs.gemspec
|
||||
gemspec
|
|
@ -1,25 +0,0 @@
|
|||
# coding: utf-8
|
||||
lib = File.expand_path('../lib', __FILE__)
|
||||
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
||||
|
||||
Gem::Specification.new do |spec|
|
||||
spec.name = "google_docs"
|
||||
spec.version = "1.0.0"
|
||||
spec.authors = ["Ken Romney"]
|
||||
spec.email = ["kromney@instructure.com"]
|
||||
spec.summary = %q{Google Docs}
|
||||
|
||||
spec.files = Dir.glob("{lib,spec}/**/*") + %w(test.sh)
|
||||
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
||||
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
||||
spec.require_paths = ["lib"]
|
||||
|
||||
spec.add_dependency "ratom-nokogiri", "0.10.4"
|
||||
spec.add_dependency "oauth-instructure", "0.4.10"
|
||||
|
||||
spec.add_development_dependency "bundler", "~> 1.5"
|
||||
spec.add_development_dependency "rake"
|
||||
spec.add_development_dependency "rspec", "2.99.0"
|
||||
spec.add_development_dependency "mocha"
|
||||
spec.add_development_dependency "timecop"
|
||||
end
|
|
@ -1,13 +0,0 @@
|
|||
require "atom"
|
||||
require "oauth"
|
||||
require 'uri'
|
||||
|
||||
module GoogleDocs
|
||||
require "google_docs/connection"
|
||||
require "google_docs/drive_connection"
|
||||
require "google_docs/drive_entry"
|
||||
require "google_docs/drive_folder"
|
||||
require "google_docs/entry"
|
||||
require "google_docs/folder"
|
||||
require "google_docs/no_token_error"
|
||||
end
|
|
@ -1,362 +0,0 @@
|
|||
#
|
||||
# Copyright (C) 2011 Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
require 'atom'
|
||||
require 'oauth'
|
||||
|
||||
# See Google Docs API documentation here:
|
||||
# http://code.google.com/apis/documents/docs/2.0/developers_guide_protocol.html
|
||||
module GoogleDocs
|
||||
class Connection
|
||||
def initialize(oauth_gdocs_access_token, oauth_gdocs_access_token_secret)
|
||||
@oauth_gdocs_access_token = oauth_gdocs_access_token
|
||||
@oauth_gdocs_access_token_secret = oauth_gdocs_access_token_secret
|
||||
end
|
||||
|
||||
def retrieve_access_token
|
||||
consumer = GoogleDocs::Connection.consumer
|
||||
return nil unless consumer
|
||||
@access_token ||= OAuth::AccessToken.new(consumer, @oauth_gdocs_access_token, @oauth_gdocs_access_token_secret)
|
||||
end
|
||||
|
||||
def service_type
|
||||
:google_docs
|
||||
end
|
||||
|
||||
def get_service_user_info(access_token=retrieve_access_token)
|
||||
doc = create_doc("Temp Doc: #{Time.now.strftime("%d %b %Y, %I:%M %p")}", access_token)
|
||||
delete_doc(doc, access_token)
|
||||
service_user_id = doc.entry.authors[0].email rescue nil
|
||||
service_user_name = doc.entry.authors[0].email rescue nil
|
||||
return service_user_id, service_user_name
|
||||
end
|
||||
|
||||
def self.get_access_token(token, secret, oauth_verifier)
|
||||
consumer = GoogleDocs::Connection.consumer
|
||||
request_token = OAuth::RequestToken.new(consumer,
|
||||
token,
|
||||
secret)
|
||||
request_token.get_access_token(:oauth_verifier => oauth_verifier)
|
||||
end
|
||||
|
||||
def self.request_token(oauth_callback)
|
||||
consumer = GoogleDocs::Connection.consumer
|
||||
consumer.get_request_token({:oauth_callback => oauth_callback}, {:scope => "https://docs.google.com/feeds/ https://spreadsheets.google.com/feeds/"})
|
||||
end
|
||||
|
||||
|
||||
def download(document_id, not_supported=nil)
|
||||
access_token = retrieve_access_token
|
||||
entry = fetch_list(access_token).entries.map { |e| GoogleDocs::Entry.new(e) }.find { |e| e.document_id == document_id }
|
||||
if entry
|
||||
response = fetch_entry(access_token, entry)
|
||||
|
||||
# some new google spreadsheets will not download as plain 'xls', so
|
||||
# retry the download as 'xlsx'
|
||||
if response.is_a?(Net::HTTPBadRequest) && entry.extension == 'xls'
|
||||
entry.reset_extension_as_xlsx
|
||||
response = fetch_entry(access_token, entry)
|
||||
end
|
||||
|
||||
[response, entry.display_name, entry.extension]
|
||||
else
|
||||
[nil, nil, nil]
|
||||
end
|
||||
end
|
||||
|
||||
def fetch_entry(access_token, entry)
|
||||
response = access_token.get(entry.download_url)
|
||||
response = access_token.get(response['Location']) if response.is_a?(Net::HTTPFound)
|
||||
response
|
||||
end
|
||||
|
||||
def fetch_list(access_token)
|
||||
response = access_token.get('https://docs.google.com/feeds/documents/private/full')
|
||||
Atom::Feed.load_feed(response.body)
|
||||
end
|
||||
|
||||
private :fetch_list
|
||||
|
||||
def folderize_list(docs)
|
||||
root = Folder.new('/')
|
||||
folders = {nil => root}
|
||||
|
||||
docs.entries.each do |entry|
|
||||
entry = GoogleDocs::Entry.new(entry)
|
||||
if !folders.has_key?(entry.folder)
|
||||
folder = Folder.new(entry.folder)
|
||||
root.add_folder folder
|
||||
folders[entry.folder] = folder
|
||||
else
|
||||
folder = folders[entry.folder]
|
||||
end
|
||||
folder.add_file entry
|
||||
end
|
||||
|
||||
return root
|
||||
end
|
||||
|
||||
private :folderize_list
|
||||
|
||||
def list(access_token=nil)
|
||||
access_token ||= retrieve_access_token
|
||||
folderize_list(fetch_list(access_token))
|
||||
end
|
||||
|
||||
private :list
|
||||
|
||||
def list_with_extension_filter(extensions, access_token=nil)
|
||||
access_token ||= retrieve_access_token
|
||||
docs = list(access_token)
|
||||
if extensions && extensions.length > 0
|
||||
docs = docs.select { |e| extensions.include?(e.extension) }
|
||||
end
|
||||
docs
|
||||
end
|
||||
|
||||
def self.consumer(key = nil, secret = nil)
|
||||
if key.nil? || secret.nil?
|
||||
return nil if GoogleDocs::Connection.config.nil?
|
||||
key ||= GoogleDocs::Connection.config['api_key']
|
||||
secret ||= GoogleDocs::Connection.config['secret_key']
|
||||
end
|
||||
|
||||
require 'oauth'
|
||||
require 'oauth/consumer'
|
||||
|
||||
OAuth::Consumer.new(key, secret, {
|
||||
:site => 'https://www.google.com',
|
||||
:request_token_path => '/accounts/OAuthGetRequestToken',
|
||||
:access_token_path => '/accounts/OAuthGetAccessToken',
|
||||
:authorize_path => '/accounts/OAuthAuthorizeToken',
|
||||
:signature_method => 'HMAC-SHA1'
|
||||
})
|
||||
end
|
||||
|
||||
class Google
|
||||
class Google::Batch
|
||||
class Google::Batch::Operation
|
||||
attr_accessor :type
|
||||
|
||||
def initialize(operation_type="insert")
|
||||
self.type = operation_type
|
||||
end
|
||||
|
||||
def to_xml(builder, *_opts)
|
||||
builder['batch'].operation(type: type)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Google::GAcl
|
||||
class Google::GAcl::Role
|
||||
attr_accessor :role
|
||||
|
||||
def initialize()
|
||||
self.role = "writer"
|
||||
end
|
||||
|
||||
def to_xml(builder, *_opts)
|
||||
builder['gAcl'].role(value: role)
|
||||
end
|
||||
end
|
||||
|
||||
class Google::GAcl::Scope
|
||||
attr_accessor :type, :value
|
||||
|
||||
def initialize(email)
|
||||
self.type = "user"
|
||||
self.value = email
|
||||
end
|
||||
|
||||
def to_xml(builder, *_opts)
|
||||
builder['gAcl'].scope(type: type, value: value)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Entry < Atom::Entry
|
||||
namespace Atom::NAMESPACE
|
||||
element "id"
|
||||
element "batch:id"
|
||||
element "batch:operation", :class => Google::Batch::Operation
|
||||
element "gAcl:role", :class => Google::GAcl::Role
|
||||
element "gAcl:scope", :class => Google::GAcl::Scope
|
||||
elements :categories
|
||||
add_extension_namespace :batch, 'http://schemas.google.com/gdata/batch'
|
||||
add_extension_namespace :gAcl, 'http://schemas.google.com/acl/2007'
|
||||
end
|
||||
class Feed < Atom::Feed
|
||||
namespace Atom::NAMESPACE
|
||||
elements :entries
|
||||
elements :categories
|
||||
|
||||
add_extension_namespace :batch, 'http://schemas.google.com/gdata/batch'
|
||||
add_extension_namespace :gAcl, 'http://schemas.google.com/acl/2007'
|
||||
end
|
||||
|
||||
def create_doc(name, access_token=retrieve_access_token)
|
||||
url = "https://docs.google.com/feeds/documents/private/full"
|
||||
entry = Atom::Entry.new do |entry|
|
||||
entry.title = name
|
||||
entry.categories << Atom::Category.new do |category|
|
||||
category.scheme = "http://schemas.google.com/g/2005#kind"
|
||||
category.term = "http://schemas.google.com/docs/2007#document"
|
||||
category.label = "document"
|
||||
end
|
||||
end
|
||||
xml = entry.to_xml.to_s
|
||||
begin
|
||||
response = access_token.post(url, xml, {'Content-Type' => 'application/atom+xml'})
|
||||
rescue => e
|
||||
raise "Unable to post to Google API #{url}:\n#{xml}" +
|
||||
"\n\n(" + e.to_s + ")\n"
|
||||
end
|
||||
begin
|
||||
GoogleDocs::Entry.new(Atom::Entry.load_entry(response.body))
|
||||
rescue => e
|
||||
raise "Unable to load GoogleDocEntry from response: \n" + response.body +
|
||||
"\n\n(" + e.to_s + ")\n"
|
||||
end
|
||||
end
|
||||
|
||||
def delete_doc(entry, access_token = retrieve_access_token)
|
||||
access_token.delete(entry.edit_url, {'GData-Version' => '2', 'If-Match' => '*'})
|
||||
end
|
||||
|
||||
def acl_remove(document_id, users)
|
||||
access_token = retrieve_access_token
|
||||
url = "https://docs.google.com/feeds/acl/private/full/#{document_id}/batch"
|
||||
|
||||
Struct.new('UserStruct', :id, :gmail, :google_docs_address)
|
||||
users.each_with_index do |user, idx|
|
||||
if user.is_a? String
|
||||
users[idx] = Struct::UserStruct.new(user, user)
|
||||
end
|
||||
end
|
||||
|
||||
request_feed = Feed.new do |feed|
|
||||
feed.categories << Atom::Category.new { |category|
|
||||
category.scheme = "http://schemas.google.com/g/2005#kind"
|
||||
category.term = "http://schemas.google.com/acl/2007#accessRule"
|
||||
}
|
||||
users.each do |user|
|
||||
next unless user_identifier = user.google_docs_address || user.gmail
|
||||
|
||||
feed.entries << Entry.new do |entry|
|
||||
entry.id = "https://docs.google.com/feeds/acl/private/full/#{CGI.escape(document_id)}/user%3A#{CGI.escape(user_identifier)}"
|
||||
entry.batch_operation = Google::Batch::Operation.new('delete')
|
||||
entry.gAcl_role = Google::GAcl::Role.new
|
||||
entry.gAcl_scope = Google::GAcl::Scope.new(user_identifier)
|
||||
end
|
||||
end
|
||||
end
|
||||
response = access_token.post(url, request_feed.to_xml.to_s, {'Content-Type' => 'application/atom+xml'})
|
||||
feed = Atom::Feed.load_feed(response.body)
|
||||
res = []
|
||||
|
||||
feed.entries.each do |entry|
|
||||
user = users.to_a.find { |u| u.id == entry['http://schemas.google.com/gdata/batch', 'id'][0].to_i }
|
||||
res << user if user
|
||||
end
|
||||
|
||||
res
|
||||
end
|
||||
|
||||
|
||||
# Public: Add users to a Google Doc ACL list.
|
||||
#
|
||||
# document_id - The id of the Google Doc to add users to.
|
||||
# users - An array of user objects.
|
||||
# domain - The string domain to restrict additions to (e.g. "example.com").
|
||||
# Accounts not on this domain will be ignored.
|
||||
#
|
||||
# Returns nothing.
|
||||
def acl_add(document_id, users, domain = nil)
|
||||
access_token = retrieve_access_token
|
||||
url = "https://docs.google.com/feeds/acl/private/full/#{document_id}/batch"
|
||||
domain_regex = domain ? %r{@#{domain}$} : /./
|
||||
allowed_users = []
|
||||
|
||||
user_added = false
|
||||
request_feed = Feed.new do |feed|
|
||||
feed.categories << Atom::Category.new do |category|
|
||||
category.scheme = "http://schemas.google.com/g/2005#kind"
|
||||
category.term = "http://schemas.google.com/acl/2007#accessRule"
|
||||
end
|
||||
|
||||
allowed_users = users.select do |user|
|
||||
address = user.google_docs_address || user.gmail
|
||||
address ? address.match(domain_regex) : nil
|
||||
end
|
||||
|
||||
allowed_users.each do |user|
|
||||
user_added = true
|
||||
feed.entries << user_feed_entry(user)
|
||||
end
|
||||
end
|
||||
|
||||
return unless user_added
|
||||
|
||||
post_response = access_token.post(url, request_feed.to_xml.to_s, {'Content-Type' => 'application/atom+xml'})
|
||||
feed = Atom::Feed.load_feed(post_response.body)
|
||||
feed.entries.inject([]) do |response, entry|
|
||||
user = allowed_users.find do |u|
|
||||
u.id == entry['http://schemas.google.com/gdata/batch', 'id'][0].to_i
|
||||
end
|
||||
response << user if user
|
||||
response
|
||||
end
|
||||
end
|
||||
|
||||
def user_feed_entry(user)
|
||||
Entry.new do |entry|
|
||||
entry.batch_id = user.id
|
||||
entry.batch_operation = Google::Batch::Operation.new
|
||||
entry.gAcl_role = Google::GAcl::Role.new
|
||||
entry.gAcl_scope = Google::GAcl::Scope.new(user.google_docs_address || user.gmail)
|
||||
end
|
||||
end
|
||||
|
||||
private :user_feed_entry
|
||||
|
||||
def verify_access_token
|
||||
access_token = retrieve_access_token
|
||||
access_token.head("https://www.google.com/accounts/AuthSubTokenInfo").is_a? Net::HTTPSuccess
|
||||
end
|
||||
|
||||
def self.config_check(settings)
|
||||
consumer = GoogleDocs::Connection.consumer(settings[:api_key], settings[:secret_key])
|
||||
token = consumer.get_request_token({}, {:scope => "https://docs.google.com/feeds/"}) rescue nil
|
||||
token ? nil : "Configuration check failed, please check your settings"
|
||||
end
|
||||
|
||||
def self.config=(config)
|
||||
if !config.is_a?(Proc)
|
||||
raise "Config must be a Proc"
|
||||
end
|
||||
@config = config
|
||||
end
|
||||
|
||||
def self.config
|
||||
@config.call()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
module GoogleDocs
|
||||
class DriveFolder
|
||||
attr_reader :name, :folders, :files
|
||||
|
||||
def initialize(name, folders=[], files=[])
|
||||
@name = name
|
||||
@folders, @files = folders, files
|
||||
end
|
||||
|
||||
def add_file(file)
|
||||
@files << file
|
||||
end
|
||||
|
||||
def add_folder(folder)
|
||||
@folders << folder
|
||||
end
|
||||
|
||||
def select(&block)
|
||||
DriveFolder.new(@name,
|
||||
@folders.map { |f| f.select(&block) }.select { |f| !f.files.empty? },
|
||||
@files.select(&block))
|
||||
end
|
||||
|
||||
def map(&block)
|
||||
@folders.map { |f| f.map(&block) }.flatten +
|
||||
@files.map(&block)
|
||||
end
|
||||
|
||||
def flatten
|
||||
@folders.flatten + @files
|
||||
end
|
||||
|
||||
def to_hash
|
||||
{
|
||||
:name => @name,
|
||||
:folders => @folders.map { |sf| sf.to_hash },
|
||||
:files => @files.map { |f| f.to_hash }
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,112 +0,0 @@
|
|||
#
|
||||
# Copyright (C) 2011 Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
require 'atom'
|
||||
|
||||
module GoogleDocs
|
||||
class Entry
|
||||
def self.extension_looker_upper
|
||||
@extension_looker_upper
|
||||
end
|
||||
|
||||
def self.extension_looker_upper=(extension_looker_upper)
|
||||
@extension_looker_upper=extension_looker_upper
|
||||
end
|
||||
|
||||
attr_reader :document_id, :folder, :entry
|
||||
|
||||
def initialize(entry)
|
||||
if entry.is_a?(String)
|
||||
@entry = Atom::Entry.load_entry(entry)
|
||||
else
|
||||
@entry = entry
|
||||
end
|
||||
set_document_id_from @entry
|
||||
@folder = @entry.categories.find { |c| c.scheme.match(/\Ahttp:\/\/schemas.google.com\/docs\/2007\/folders/) }.label rescue nil
|
||||
end
|
||||
|
||||
def alternate_url
|
||||
link = @entry.links.find { |link| link.rel == "alternate" && link.type == "text/html" }
|
||||
link || "http://docs.google.com"
|
||||
end
|
||||
|
||||
def edit_url
|
||||
"https://docs.google.com/feeds/documents/private/full/#{@document_id}"
|
||||
end
|
||||
|
||||
def content_type
|
||||
@entry.content && @entry.content.type
|
||||
end
|
||||
|
||||
def extension
|
||||
if @extension.nil?
|
||||
# first, try and chose and extension by content-types we can scribd
|
||||
if !content_type.nil? && !content_type.strip.empty? && self.class.extension_looker_upper && mimetype = self.class.extension_looker_upper.find_by_name(content_type)
|
||||
@extension = mimetype.extension
|
||||
end
|
||||
# second, look at the document id itself for any clues
|
||||
if !@document_id.nil? && !@document_id.strip.empty?
|
||||
@extension ||= case @document_id
|
||||
when /\Aspreadsheet/ then
|
||||
"xls"
|
||||
when /\Apresentation/ then
|
||||
"ppt"
|
||||
when /\Adocument/ then
|
||||
"doc"
|
||||
end
|
||||
end
|
||||
# finally, just declare it unknown
|
||||
@extension ||= "unknown"
|
||||
end
|
||||
@extension == "unknown" ? nil : @extension
|
||||
end
|
||||
|
||||
def display_name
|
||||
@entry.title || "google_doc.#{extension}"
|
||||
end
|
||||
|
||||
def download_url
|
||||
url = @entry.content.src
|
||||
if url && (parsed_url = (URI.parse(url) rescue nil)) && (ext = extension)
|
||||
parsed_url.query = [parsed_url.query, "exportFormat=#{ext}", "format=#{ext}"].compact.join("&")
|
||||
url = parsed_url.to_s
|
||||
end
|
||||
url
|
||||
end
|
||||
|
||||
def to_hash
|
||||
{
|
||||
"name" => display_name,
|
||||
"document_id" => @document_id,
|
||||
"extension" => extension,
|
||||
"alternate_url" => alternate_url
|
||||
}
|
||||
end
|
||||
|
||||
def reset_extension_as_xlsx
|
||||
@extension = 'xlsx'
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_document_id_from(entry)
|
||||
doc_id = entry.simple_extensions["{http://schemas.google.com/g/2005,resourceId}"]
|
||||
@document_id = doc_id.first.to_s
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,10 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:batch="http://schemas.google.com/gdata/batch" xmlns:gAcl="http://schemas.google.com/acl/2007">
|
||||
<entry>
|
||||
<batch:id>192</batch:id>
|
||||
<batch:operation type="insert"/>
|
||||
<gAcl:role value="writer"/>
|
||||
<gAcl:scope type="user" value="u_id"/>
|
||||
</entry>
|
||||
<category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/acl/2007#accessRule"/>
|
||||
</feed>
|
|
@ -1,4 +0,0 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<entry xmlns='http://www.w3.org/2005/Atom' xmlns:gd='http://schemas.google.com/g/2005'>
|
||||
<gd:resourceId />
|
||||
</entry>
|
|
@ -1,5 +0,0 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<entry xmlns='http://www.w3.org/2005/Atom' xmlns:gd='http://schemas.google.com/g/2005'>
|
||||
<gd:resourceId>document:deadbeef</gd:resourceId>
|
||||
<content type='application/pdf' src='http://some-url/blah' />
|
||||
</entry>
|
|
@ -1,5 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<entry xmlns="http://www.w3.org/2005/Atom">
|
||||
<title>test document</title>
|
||||
<category label="document" scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/docs/2007#document"/>
|
||||
</entry>
|
|
@ -1 +0,0 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?><entry xmlns='http://www.w3.org/2005/Atom' xmlns:docs='http://schemas.google.com/docs/2007' xmlns:batch='http://schemas.google.com/gdata/batch' xmlns:gd='http://schemas.google.com/g/2005'><id>https://docs.google.com/feeds/documents/private/full/document%3A1HJoN38KHlnu32B5z_THgchnTMUbj7dgs8P-Twrm38cA</id><published>2011-10-31T22:23:06.375Z</published><updated>2011-10-31T22:23:06.993Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/docs/2007#document' label='document'/><category scheme='http://schemas.google.com/g/2005/labels' term='http://schemas.google.com/g/2005/labels#viewed' label='viewed'/><title type='text'>test document</title><content type='text/html' src='https://docs.google.com/feeds/download/documents/export/Export?id=1HJoN38KHlnu32B5z_THgchnTMUbj7dgs8P-Twrm38cA'/><link rel='alternate' type='text/html' href='https://docs.google.com/document/d/1HJoN38KHlnu32B5z_THgchnTMUbj7dgs8P-Twrm38cA/edit?hl=en_US'/><link rel='self' type='application/atom+xml' href='https://docs.google.com/feeds/documents/private/full/document%3A1HJoN38KHlnu32B5z_THgchnTMUbj7dgs8P-Twrm38cA'/><link rel='edit' type='application/atom+xml' href='https://docs.google.com/feeds/documents/private/full/document%3A1HJoN38KHlnu32B5z_THgchnTMUbj7dgs8P-Twrm38cA/gug1bunq'/><link rel='edit-media' type='text/html' href='https://docs.google.com/feeds/media/private/full/document%3A1HJoN38KHlnu32B5z_THgchnTMUbj7dgs8P-Twrm38cA/gug1bunq'/><author><name>instructure.test.2011</name><email>instructure.test.2011@gmail.com</email></author><gd:resourceId>document:1HJoN38KHlnu32B5z_THgchnTMUbj7dgs8P-Twrm38cA</gd:resourceId><gd:lastModifiedBy><name>instructure.test.2011</name><email>instructure.test.2011@gmail.com</email></gd:lastModifiedBy><gd:lastViewed>2011-10-31T22:23:06.652Z</gd:lastViewed><gd:quotaBytesUsed>0</gd:quotaBytesUsed><docs:writersCanInvite value='true'/><gd:feedLink rel='http://schemas.google.com/acl/2007#accessControlList' href='https://docs.google.com/feeds/acl/private/full/document%3A1HJoN38KHlnu32B5z_THgchnTMUbj7dgs8P-Twrm38cA'/></entry>
|
|
@ -1,5 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<entry xmlns="http://www.w3.org/2005/Atom">
|
||||
<title>Temp Doc: 07 Apr 2014, 08:32 AM</title>
|
||||
<category label="document" scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/docs/2007#document"/>
|
||||
</entry>
|
|
@ -1,94 +0,0 @@
|
|||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<feed xmlns='http://www.w3.org/2005/Atom'
|
||||
xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/'
|
||||
xmlns:docs='http://schemas.google.com/docs/2007'
|
||||
xmlns:batch='http://schemas.google.com/gdata/batch'
|
||||
xmlns:gd='http://schemas.google.com/g/2005'>
|
||||
<id>https://docs.google.com/feeds/documents/private/full</id>
|
||||
<updated>2013-01-29T23:11:36.156Z</updated>
|
||||
<category scheme='http://schemas.google.com/g/2005#kind'
|
||||
term='http://schemas.google.com/docs/2007#item' label='item' />
|
||||
<title type='text'>Available Documents -
|
||||
don@sterlingcooperdraperpryce.com</title>
|
||||
<link rel='alternate' type='text/html'
|
||||
href='https://docs.google.com' />
|
||||
<link rel='http://schemas.google.com/g/2005#feed'
|
||||
type='application/atom+xml'
|
||||
href='https://docs.google.com/feeds/documents/private/full' />
|
||||
<link rel='http://schemas.google.com/g/2005#post'
|
||||
type='application/atom+xml'
|
||||
href='https://docs.google.com/feeds/documents/private/full' />
|
||||
<link rel='http://schemas.google.com/g/2005#batch'
|
||||
type='application/atom+xml'
|
||||
href='https://docs.google.com/feeds/documents/private/full/batch' />
|
||||
<link rel='self' type='application/atom+xml'
|
||||
href='https://docs.google.com/feeds/documents/private/full' />
|
||||
<author>
|
||||
<name>don draper</name>
|
||||
<email>don@sterlingcooperdraperpryce.com</email>
|
||||
</author>
|
||||
<openSearch:totalResults>1</openSearch:totalResults>
|
||||
<openSearch:startIndex>1</openSearch:startIndex>
|
||||
<entry>
|
||||
<id>
|
||||
https://docs.google.com/feeds/documents/private/full/spreadsheet%12345</id>
|
||||
<published>2012-09-05T15:21:42.872Z</published>
|
||||
<updated>2013-01-29T21:56:31.800Z</updated>
|
||||
<category scheme='http://schemas.google.com/g/2005/labels'
|
||||
term='http://schemas.google.com/g/2005/labels#viewed'
|
||||
label='viewed' />
|
||||
<category scheme='http://schemas.google.com/g/2005#kind'
|
||||
term='http://schemas.google.com/docs/2007#spreadsheet'
|
||||
label='spreadsheet' />
|
||||
<category scheme='http://schemas.google.com/g/2005/labels'
|
||||
term='http://schemas.google.com/g/2005/labels#modified-by-me'
|
||||
label='modified-by-me' />
|
||||
<category scheme='http://schemas.google.com/g/2005/labels'
|
||||
term='http://schemas.google.com/g/2005/labels#shared'
|
||||
label='shared' />
|
||||
<title type='text'>Lucky Strike Campaign</title>
|
||||
<content type='text/html'
|
||||
src='https://docs.google.com/feeds/download/spreadsheets/Export?key=12345' />
|
||||
<link rel='alternate' type='text/html'
|
||||
href='https://docs.google.com/a/instructure.com/spreadsheet/ccc?key=12345' />
|
||||
<link rel='http://schemas.google.com/docs/2007#embed'
|
||||
type='text/html'
|
||||
href='https://docs.google.com/a/instructure.com/spreadsheet/ccc?key=12345&output=html&chrome=false&widget=true' />
|
||||
<link rel='http://schemas.google.com/docs/2007#icon'
|
||||
type='image/png'
|
||||
href='https://ssl.gstatic.com/docs/doclist/images/icon_11_spreadsheet_list.png' />
|
||||
<link rel='http://schemas.google.com/spreadsheets/2006#worksheetsfeed'
|
||||
type='application/atom+xml'
|
||||
href='https://spreadsheets.google.com/feeds/worksheets/12345/private/full' />
|
||||
<link rel='http://schemas.google.com/spreadsheets/2006#tablesfeed'
|
||||
type='application/atom+xml'
|
||||
href='https://spreadsheets.google.com/feeds/12345/tables' />
|
||||
<link rel='self' type='application/atom+xml'
|
||||
href='https://docs.google.com/feeds/documents/private/full/spreadsheet%12345' />
|
||||
<link rel='edit' type='application/atom+xml'
|
||||
href='https://docs.google.com/feeds/documents/private/full/spreadsheet%12345/hcjl6593' />
|
||||
<link rel='edit-media' type='text/html'
|
||||
href='https://docs.google.com/feeds/media/private/full/spreadsheet%12345/hcjl6593' />
|
||||
<author>
|
||||
<name>don draper</name>
|
||||
<email>don@sterlingcooperdraperpryce.com</email>
|
||||
</author>
|
||||
<gd:resourceId>
|
||||
spreadsheet:12345</gd:resourceId>
|
||||
<docs:isShareable value='true' />
|
||||
<docs:modifiedByMeDate>
|
||||
2012-09-13T21:09:04.878Z</docs:modifiedByMeDate>
|
||||
<docs:sharedWithMeDate>
|
||||
2012-09-05T15:46:27.146Z</docs:sharedWithMeDate>
|
||||
<gd:lastModifiedBy>
|
||||
<name>peggy olson</name>
|
||||
<email>peggy@sterlingcooperdraperpryce.com</email>
|
||||
</gd:lastModifiedBy>
|
||||
<gd:lastViewed>2012-09-13T21:08:09.688Z</gd:lastViewed>
|
||||
<gd:quotaBytesUsed>0</gd:quotaBytesUsed>
|
||||
<docs:writersCanInvite value='true' />
|
||||
<docs:hasForm value='false' />
|
||||
<gd:feedLink rel='http://schemas.google.com/acl/2007#accessControlList'
|
||||
href='https://docs.google.com/feeds/acl/private/full/spreadsheet%12345' />
|
||||
</entry>
|
||||
</feed>
|
|
@ -1 +0,0 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:docs='http://schemas.google.com/docs/2007' xmlns:batch='http://schemas.google.com/gdata/batch' xmlns:gd='http://schemas.google.com/g/2005'><id>https://docs.google.com/feeds/documents/private/full</id><updated>2011-10-31T22:23:05.864Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/docs/2007#item' label='item'/><title type='text'>Available Documents - instructure.test.2011@gmail.com</title><link rel='alternate' type='text/html' href='http://docs.google.com'/><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='https://docs.google.com/feeds/documents/private/full'/><link rel='http://schemas.google.com/g/2005#post' type='application/atom+xml' href='https://docs.google.com/feeds/documents/private/full'/><link rel='http://schemas.google.com/g/2005#batch' type='application/atom+xml' href='https://docs.google.com/feeds/documents/private/full/batch'/><link rel='self' type='application/atom+xml' href='https://docs.google.com/feeds/documents/private/full'/><author><name>instructure.test.2011</name><email>instructure.test.2011@gmail.com</email></author><openSearch:totalResults>0</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex></feed>
|
File diff suppressed because one or more lines are too long
|
@ -1 +0,0 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:docs='http://schemas.google.com/docs/2007' xmlns:batch='http://schemas.google.com/gdata/batch' xmlns:gd='http://schemas.google.com/g/2005'><id>https://docs.google.com/feeds/documents/private/full</id><updated>2011-10-31T22:23:07.920Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/docs/2007#item' label='item'/><title type='text'>Available Documents - instructure.test.2011@gmail.com</title><link rel='alternate' type='text/html' href='http://docs.google.com'/><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='https://docs.google.com/feeds/documents/private/full'/><link rel='http://schemas.google.com/g/2005#post' type='application/atom+xml' href='https://docs.google.com/feeds/documents/private/full'/><link rel='http://schemas.google.com/g/2005#batch' type='application/atom+xml' href='https://docs.google.com/feeds/documents/private/full/batch'/><link rel='self' type='application/atom+xml' href='https://docs.google.com/feeds/documents/private/full'/><author><name>instructure.test.2011</name><email>instructure.test.2011@gmail.com</email></author><openSearch:totalResults>1</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><entry><id>https://docs.google.com/feeds/documents/private/full/document%3A1HJoN38KHlnu32B5z_THgchnTMUbj7dgs8P-Twrm38cA</id><published>2011-10-31T22:23:06.375Z</published><updated>2011-10-31T22:23:06.993Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/docs/2007#document' label='document'/><category scheme='http://schemas.google.com/g/2005/labels' term='http://schemas.google.com/g/2005/labels#viewed' label='viewed'/><title type='text'>test document</title><content type='text/html' src='https://docs.google.com/feeds/download/documents/export/Export?id=1HJoN38KHlnu32B5z_THgchnTMUbj7dgs8P-Twrm38cA'/><link rel='alternate' type='text/html' href='https://docs.google.com/document/d/1HJoN38KHlnu32B5z_THgchnTMUbj7dgs8P-Twrm38cA/edit?hl=en_US'/><link rel='self' type='application/atom+xml' href='https://docs.google.com/feeds/documents/private/full/document%3A1HJoN38KHlnu32B5z_THgchnTMUbj7dgs8P-Twrm38cA'/><link rel='edit' type='application/atom+xml' href='https://docs.google.com/feeds/documents/private/full/document%3A1HJoN38KHlnu32B5z_THgchnTMUbj7dgs8P-Twrm38cA/gug1buow'/><link rel='edit-media' type='text/html' href='https://docs.google.com/feeds/media/private/full/document%3A1HJoN38KHlnu32B5z_THgchnTMUbj7dgs8P-Twrm38cA/gug1buow'/><author><name>instructure.test.2011</name><email>instructure.test.2011@gmail.com</email></author><gd:resourceId>document:1HJoN38KHlnu32B5z_THgchnTMUbj7dgs8P-Twrm38cA</gd:resourceId><gd:lastModifiedBy><name>instructure.test.2011</name><email>instructure.test.2011@gmail.com</email></gd:lastModifiedBy><gd:lastViewed>2011-10-31T22:23:07.015Z</gd:lastViewed><gd:quotaBytesUsed>0</gd:quotaBytesUsed><docs:writersCanInvite value='true'/><gd:feedLink rel='http://schemas.google.com/acl/2007#accessControlList' href='https://docs.google.com/feeds/acl/private/full/document%3A1HJoN38KHlnu32B5z_THgchnTMUbj7dgs8P-Twrm38cA'/></entry></feed>
|
|
@ -1,5 +0,0 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<entry xmlns='http://www.w3.org/2005/Atom' xmlns:gd='http://schemas.google.com/g/2005'>
|
||||
<content type='application/pdf' src='http://some-url/blah' />
|
||||
<gd:resourceId />
|
||||
</entry>
|
|
@ -1,10 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:batch="http://schemas.google.com/gdata/batch" xmlns:gAcl="http://schemas.google.com/acl/2007">
|
||||
<entry>
|
||||
<id>https://docs.google.com/feeds/acl/private/full/document%3A1HJoN38KHlnu32B5z_THgchnTMUbj7dgs8P-Twrm38cA/user%3Auser%40example.com</id>
|
||||
<batch:operation type="delete"/>
|
||||
<gAcl:role value="writer"/>
|
||||
<gAcl:scope type="user" value="user@example.com"/>
|
||||
</entry>
|
||||
<category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/acl/2007#accessRule"/>
|
||||
</feed>
|
|
@ -1,14 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<atom:feed xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:gAcl="http://schemas.google.com/acl/2007" xmlns:batch="http://schemas.google.com/gdata/batch">
|
||||
<atom:id>https://docs.google.com/feeds/acl/private/full/document%3A10RabxaKMMU9aSvzfGyvmSvzwQpBPhRnl-zJvCVioJVs/batch/1362693661345</atom:id>
|
||||
<atom:updated>2013-03-07T22:01:02.114Z</atom:updated>
|
||||
<atom:title type="text">Batch Feed</atom:title>
|
||||
<atom:entry>
|
||||
<atom:id>https://docs.google.com/feeds/acl/private/full/document%3A10RabxaKMMU9aSvzfGyvmSvzwQpBPhRnl-zJvCVioJVs/user%3Auser%40example.com</atom:id>
|
||||
<atom:updated>2013-03-07T22:01:02.114Z</atom:updated>
|
||||
<atom:title type="text">Deleted</atom:title>
|
||||
<atom:content type="text">Deleted</atom:content>
|
||||
<batch:status code="200" reason="Success"/>
|
||||
<batch:operation type="delete"/>
|
||||
</atom:entry>
|
||||
</atom:feed>
|
|
@ -1,10 +0,0 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<feed xmlns='http://www.w3.org/2005/Atom' xmlns:batch='http://schemas.google.com/gdata/batch' xmlns:gAcl='http://schemas.google.com/acl/2007'>
|
||||
<entry xmlns:batch='http://schemas.google.com/gdata/batch' xmlns:gAcl='http://schemas.google.com/acl/2007'>
|
||||
<id>https://docs.google.com/feeds/acl/private/full/document%3A1HJoN38KHlnu32B5z_THgchnTMUbj7dgs8P-Twrm38cA/user%3Auser%40example.com</id>
|
||||
<batch:operation type='delete'/>
|
||||
<gAcl:role value='writer'/>
|
||||
<gAcl:scope type='user' value='user@example.com'/>
|
||||
</entry>
|
||||
<category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/acl/2007#accessRule'/>
|
||||
</feed>
|
|
@ -1,4 +0,0 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<entry xmlns='http://www.w3.org/2005/Atom' xmlns:gd='http://schemas.google.com/g/2005'>
|
||||
<gd:resourceId>spreadsheet:deadbeef</gd:resourceId>
|
||||
</entry>
|
|
@ -1,5 +0,0 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<entry xmlns='http://www.w3.org/2005/Atom' xmlns:gd='http://schemas.google.com/g/2005'>
|
||||
<content type='unknown' src='http://some-url/blah' />
|
||||
<gd:resourceId />
|
||||
</entry>
|
|
@ -1,4 +0,0 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<entry xmlns='http://www.w3.org/2005/Atom' xmlns:gd='http://schemas.google.com/g/2005'>
|
||||
<gd:resourceId>unknown:deadbeef</gd:resourceId>
|
||||
</entry>
|
|
@ -1,393 +0,0 @@
|
|||
#
|
||||
# Copyright (C) 2011-2014 Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
DOCS_FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures/google_docs/'
|
||||
|
||||
def load_fixture(filename)
|
||||
File.read(DOCS_FIXTURES_PATH + filename)
|
||||
end
|
||||
|
||||
describe GoogleDocs::Connection do
|
||||
let(:xml_schema_id) { 'https://docs.google.com/feeds/documents/private/full' }
|
||||
|
||||
let(:xml_doc_list_empty) { load_fixture("doc_list_empty.xml") }
|
||||
let(:xml_doc_list_one) { load_fixture("doc_list_one.xml") }
|
||||
let(:xml_doc_list_many) { load_fixture("doc_list_many.xml") }
|
||||
let(:xml_create_doc_request) { load_fixture("create_doc_request.xml") }
|
||||
let(:xml_create_temp_doc_request) { load_fixture("create_temp_doc_request.xml") }
|
||||
let(:xml_create_doc_response) { load_fixture("create_doc_response.xml") }
|
||||
let(:xml_remove_doc_request) { load_fixture("remove_doc_request.xml") }
|
||||
let(:xml_remove_doc_response) { load_fixture("remove_doc_response.xml") }
|
||||
let(:xml_add_user_acl) { load_fixture("add_user_acl.xml") }
|
||||
let(:token) { "token" }
|
||||
let(:secret) { "secret" }
|
||||
|
||||
before do
|
||||
config = {
|
||||
"api_key" => "key",
|
||||
"secret_key" => "secret",
|
||||
}
|
||||
GoogleDocs::Connection.config = Proc.new do
|
||||
config
|
||||
end
|
||||
end
|
||||
|
||||
describe "#retrieve_access_token" do
|
||||
it "should not error out if the google plugin is not configured" do
|
||||
GoogleDocs::Connection.config = Proc.new do
|
||||
nil
|
||||
end
|
||||
google_docs = GoogleDocs::Connection.new(token, secret)
|
||||
google_docs.retrieve_access_token.should be_nil
|
||||
end
|
||||
|
||||
it "news up an OAuth::AccessToken" do
|
||||
access_token = mock_access_token
|
||||
|
||||
google_docs = GoogleDocs::Connection.new(token, secret)
|
||||
google_docs.retrieve_access_token.should == access_token
|
||||
end
|
||||
end
|
||||
|
||||
describe "#get_service_user_info" do
|
||||
it "returns service user id and name" do
|
||||
known_time = Time.new(2014, 4, 7, 8, 32)
|
||||
|
||||
Timecop.freeze(known_time) do
|
||||
prepare_mock_post(xml_schema_id, xml_create_temp_doc_request, xml_create_doc_response)
|
||||
|
||||
google_docs = GoogleDocs::Connection.new(token, secret)
|
||||
|
||||
prepare_mock_delete("#{xml_schema_id}/document:1HJoN38KHlnu32B5z_THgchnTMUbj7dgs8P-Twrm38cA")
|
||||
|
||||
user_service_id, user_service_name = google_docs.get_service_user_info google_docs.retrieve_access_token
|
||||
user_service_id.should == "instructure.test.2011@gmail.com"
|
||||
user_service_name.should == "instructure.test.2011@gmail.com"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe ".get_access_token" do
|
||||
it "returns the access token" do
|
||||
mock_consumer = mock_consumer()
|
||||
mock_request_token = mock()
|
||||
OAuth::RequestToken.expects(:new).with(mock_consumer, token, secret).returns(mock_request_token)
|
||||
mock_access_token = mock()
|
||||
mock_request_token.expects(:get_access_token).with(oauth_verifier: "oauth-verifier").returns(mock_access_token)
|
||||
|
||||
access_token = GoogleDocs::Connection.get_access_token(token, secret, "oauth-verifier")
|
||||
|
||||
access_token.should == mock_access_token
|
||||
end
|
||||
end
|
||||
|
||||
describe ".request_token" do
|
||||
it "returns a request token" do
|
||||
consumer = mock_consumer
|
||||
mock_request_token = mock()
|
||||
consumer.expects(:get_request_token).with({:oauth_callback => "http://callback.example.com"}, {:scope => "https://docs.google.com/feeds/ https://spreadsheets.google.com/feeds/"}).returns(mock_request_token)
|
||||
request_token = GoogleDocs::Connection.request_token("http://callback.example.com")
|
||||
request_token.should == mock_request_token
|
||||
end
|
||||
end
|
||||
|
||||
describe "#list_with_extension_filter" do
|
||||
context "with an empty list" do
|
||||
before do
|
||||
prepare_mock_get xml_doc_list_empty
|
||||
@google_docs = GoogleDocs::Connection.new(token, secret)
|
||||
end
|
||||
it "handles an empty list" do
|
||||
document_id_list = @google_docs.list_with_extension_filter(nil).files.map(&:document_id)
|
||||
document_id_list.should == []
|
||||
end
|
||||
it "handles an empty list with extensions" do
|
||||
document_id_list = @google_docs.list_with_extension_filter(["jpg"]).files.map(&:document_id)
|
||||
document_id_list.should == []
|
||||
end
|
||||
end
|
||||
|
||||
context "with a single document" do
|
||||
before do
|
||||
@google_docs = GoogleDocs::Connection.new(token, secret)
|
||||
end
|
||||
it "and nil filter" do
|
||||
prepare_mock_get xml_doc_list_one
|
||||
list = @google_docs.list_with_extension_filter(nil)
|
||||
document_id_list = list.files.map(&:document_id)
|
||||
document_id_list.should == ["document:1HJoN38KHlnu32B5z_THgchnTMUbj7dgs8P-Twrm38cA"]
|
||||
end
|
||||
it "and an empty filter" do
|
||||
prepare_mock_get xml_doc_list_one
|
||||
list = @google_docs.list_with_extension_filter([])
|
||||
document_id_list = list.files.map(&:document_id)
|
||||
document_id_list.should == ["document:1HJoN38KHlnu32B5z_THgchnTMUbj7dgs8P-Twrm38cA"]
|
||||
end
|
||||
|
||||
it "returns matches" do
|
||||
prepare_mock_get xml_doc_list_one
|
||||
list = @google_docs.list_with_extension_filter(['doc'])
|
||||
document_id_list = list.files.map(&:document_id)
|
||||
document_id_list.should == ["document:1HJoN38KHlnu32B5z_THgchnTMUbj7dgs8P-Twrm38cA"]
|
||||
end
|
||||
|
||||
it "rejects non matching documents" do
|
||||
prepare_mock_get xml_doc_list_one
|
||||
list = @google_docs.list_with_extension_filter(['xls'])
|
||||
document_id_list = list.files.map(&:document_id)
|
||||
document_id_list.should == []
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "with multiple documents" do
|
||||
before do
|
||||
@google_docs = GoogleDocs::Connection.new(token, secret)
|
||||
end
|
||||
it "returns filesystem view of results" do
|
||||
prepare_mock_get xml_doc_list_many
|
||||
root_folder = @google_docs.list_with_extension_filter(nil)
|
||||
|
||||
root_folder.should be_a(GoogleDocs::Folder)
|
||||
root_folder.name.should == '/'
|
||||
root_folder.folders.size.should == 1
|
||||
root_folder.folders.map { |f| f.name }.should == ["Good Stuff"]
|
||||
root_folder.folders.first.files.size.should == 1
|
||||
root_folder.folders.first.files.map(&:display_name).should == ["2012 Employee Review Form"]
|
||||
root_folder.files.size.should == 10
|
||||
end
|
||||
|
||||
it "rejects non matches" do
|
||||
prepare_mock_get xml_doc_list_many
|
||||
root_folder = @google_docs.list_with_extension_filter(['ppt', 'doc'])
|
||||
root_folder.files.size.should == 6
|
||||
document_id_list = root_folder.files.map(&:document_id)
|
||||
document_id_list.should == ["document:15OmhdkR46iZnjFycN8__s6jVKcemzAxAGiFkr6UFxgw", "document:10jp_7QYXSN90iC6iKj_JieUiE72AuJOzLhfEvs0VGrU", "document:135mk8IhGEusw3-nG-GCHNefnlhzW8wH35ytT3EiytLo", "document:1Ohs0PlPbVsDVB0J-nJM7cSC6kvDnz8xRwH70xor4-W4", "document:1dMP-0Cr8xiuBVo86TBikxdv8uM4MOaN5ssYmNMx_xUc", "document:1yzywXxOorojl6mm0RQpgdwsX9B0K0IIn-efXhrVZVFI"]
|
||||
end
|
||||
it "accepts any of the extensions" do
|
||||
prepare_mock_get xml_doc_list_many
|
||||
list = @google_docs.list_with_extension_filter(['xls', 'doc'])
|
||||
document_id_list = list.files.map(&:document_id)
|
||||
document_id_list.should == ["spreadsheet:0AiN8C_VHrPxkdEF6YmQyc3p2Qm02ODhJWGJnUmJYY2c", "spreadsheet:0AqsakWbfzwqRdDN1RDhNQ1hDWXpiVXNKN3VMb2Zlamc", "spreadsheet:0AsOXCUtn3LUxdEh6RC1KZEhoMXNqSHczeDdsc3VyYUE", "document:15OmhdkR46iZnjFycN8__s6jVKcemzAxAGiFkr6UFxgw", "document:10jp_7QYXSN90iC6iKj_JieUiE72AuJOzLhfEvs0VGrU", "document:135mk8IhGEusw3-nG-GCHNefnlhzW8wH35ytT3EiytLo", "document:1Ohs0PlPbVsDVB0J-nJM7cSC6kvDnz8xRwH70xor4-W4", "document:1dMP-0Cr8xiuBVo86TBikxdv8uM4MOaN5ssYmNMx_xUc", "spreadsheet:0AsZU1aOHX2kSdGhQVG9CWWdWcTdVZVdBMXh6V0xlVUE", "document:1yzywXxOorojl6mm0RQpgdwsX9B0K0IIn-efXhrVZVFI"]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#download" do
|
||||
it "pulls the document out that matches the provided id" do
|
||||
doc_id = 'spreadsheet:0AiN8C_VHrPxkdEF6YmQyc3p2Qm02ODhJWGJnUmJYY2c'
|
||||
access_token = mock_access_token
|
||||
document_response = mock()
|
||||
|
||||
access_token.expects(:get).returns(document_response)
|
||||
response = mock()
|
||||
response.expects(:body).returns(xml_doc_list_many)
|
||||
access_token.expects(:get).with(xml_schema_id).returns(response)
|
||||
|
||||
google_docs = GoogleDocs::Connection.new(token, secret)
|
||||
doc_array = google_docs.download(doc_id)
|
||||
doc_array[0].should == document_response
|
||||
doc_array[1].should == 'Sprint Teams'
|
||||
doc_array[2].should == 'xls'
|
||||
end
|
||||
|
||||
it "follows redirects" do
|
||||
doc_id = 'spreadsheet:0AiN8C_VHrPxkdEF6YmQyc3p2Qm02ODhJWGJnUmJYY2c'
|
||||
access_token = mock_access_token
|
||||
document_response = mock()
|
||||
|
||||
redirect = Net::HTTPFound.new(1.0, 302, "FOUND")
|
||||
redirect['Location'] = 'http://example.com/1234'
|
||||
access_token.expects(:get).returns(redirect)
|
||||
access_token.expects(:get).with('http://example.com/1234').returns(document_response)
|
||||
|
||||
response = mock()
|
||||
response.expects(:body).returns(xml_doc_list_many)
|
||||
access_token.expects(:get).with(xml_schema_id).returns(response)
|
||||
|
||||
google_docs = GoogleDocs::Connection.new(token, secret)
|
||||
doc_array = google_docs.download(doc_id)
|
||||
doc_array[0].should == document_response
|
||||
doc_array[1].should == 'Sprint Teams'
|
||||
doc_array[2].should == 'xls'
|
||||
end
|
||||
|
||||
it "handles nonexistant entry" do
|
||||
doc_id = 'spreadsheet:WRONG'
|
||||
access_token = mock_access_token
|
||||
response = mock()
|
||||
response.expects(:body).returns(xml_doc_list_many)
|
||||
access_token.expects(:get).with(xml_schema_id).returns(response)
|
||||
|
||||
google_docs = GoogleDocs::Connection.new(token, secret)
|
||||
doc_array = google_docs.download(doc_id)
|
||||
doc_array.should == [nil, nil, nil]
|
||||
end
|
||||
|
||||
it "attempts as 'xlsx' if 'xls' fails" do
|
||||
doc_id = 'spreadsheet:0AiN8C_VHrPxkdEF6YmQyc3p2Qm02ODhJWGJnUmJYY2c'
|
||||
src = 'https://docs.google.com/feeds/download/spreadsheets/Export?key=0AiN8C_VHrPxkdEF6YmQyc3p2Qm02ODhJWGJnUmJYY2c'
|
||||
xls_src = [src, "exportFormat=xls", "format=xls"].join('&')
|
||||
xlsx_src = [src, "exportFormat=xlsx", "format=xlsx"].join('&')
|
||||
|
||||
access_token = mock_access_token
|
||||
|
||||
document_response = mock()
|
||||
access_token.expects(:get).with(xlsx_src).returns(document_response)
|
||||
bad_req = Net::HTTPBadRequest.new(1.0, 400, "Bad Request")
|
||||
access_token.expects(:get).with(xls_src).returns(bad_req)
|
||||
|
||||
fetch_list_response = mock()
|
||||
fetch_list_response.expects(:body).returns(xml_doc_list_many)
|
||||
access_token.expects(:get).with(xml_schema_id).returns(fetch_list_response)
|
||||
|
||||
google_docs = GoogleDocs::Connection.new(token, secret)
|
||||
doc_array = google_docs.download(doc_id)
|
||||
doc_array[0].should == document_response
|
||||
doc_array[1].should == 'Sprint Teams'
|
||||
doc_array[2].should == 'xlsx'
|
||||
end
|
||||
end
|
||||
|
||||
describe "#create_doc" do
|
||||
it "can be created" do
|
||||
prepare_mock_post(xml_schema_id, xml_create_doc_request, xml_create_doc_response)
|
||||
|
||||
google_docs = GoogleDocs::Connection.new(token, secret)
|
||||
|
||||
new_document = google_docs.create_doc "test document", google_docs.retrieve_access_token
|
||||
new_document.document_id.should == 'document:1HJoN38KHlnu32B5z_THgchnTMUbj7dgs8P-Twrm38cA'
|
||||
new_document.extension.should == 'doc'
|
||||
new_document.display_name.should == 'test document'
|
||||
new_document.download_url.should include('id=1HJoN38KHlnu32B5z_THgchnTMUbj7dgs8P-Twrm38cA')
|
||||
new_document.alternate_url.should be_a(Atom::Link)
|
||||
new_document.alternate_url.href.should == 'https://docs.google.com/document/d/1HJoN38KHlnu32B5z_THgchnTMUbj7dgs8P-Twrm38cA/edit?hl=en_US'
|
||||
end
|
||||
end
|
||||
|
||||
describe "#delete_doc" do
|
||||
it "can be deleted" do
|
||||
prepare_mock_post(xml_schema_id, xml_create_doc_request, xml_create_doc_response)
|
||||
|
||||
google_docs = GoogleDocs::Connection.new(token, secret)
|
||||
new_document = google_docs.create_doc("test document", google_docs.retrieve_access_token)
|
||||
|
||||
prepare_mock_delete "#{xml_schema_id}/document:1HJoN38KHlnu32B5z_THgchnTMUbj7dgs8P-Twrm38cA"
|
||||
google_docs.delete_doc new_document
|
||||
end
|
||||
end
|
||||
|
||||
describe "#acl_remove" do
|
||||
it "can be removed" do
|
||||
prepare_mock_post('https://docs.google.com/feeds/acl/private/full/document:1HJoN38KHlnu32B5z_THgchnTMUbj7dgs8P-Twrm38cA/batch', xml_remove_doc_request, xml_remove_doc_response)
|
||||
|
||||
google_docs = GoogleDocs::Connection.new(token, secret)
|
||||
result = google_docs.acl_remove 'document:1HJoN38KHlnu32B5z_THgchnTMUbj7dgs8P-Twrm38cA', ['user@example.com']
|
||||
result.should == []
|
||||
end
|
||||
end
|
||||
|
||||
describe "#acl_add" do
|
||||
let(:doc_response) { mock }
|
||||
let(:doc_id) { "12345" }
|
||||
let(:url) { "https://docs.google.com/feeds/acl/private/full/#{doc_id}/batch" }
|
||||
|
||||
it "should add users to a document" do
|
||||
prepare_mock_post(url, xml_add_user_acl, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<feed xmlns=\"http://www.w3.org/2005/Atom\"/>\n")
|
||||
|
||||
google_docs = GoogleDocs::Connection.new(token, secret)
|
||||
mock_user = mock()
|
||||
mock_user.stubs(:id).returns(192)
|
||||
mock_user.stubs(:google_docs_address).returns('u_id')
|
||||
|
||||
google_docs.acl_add('12345', [mock_user], nil)
|
||||
end
|
||||
|
||||
it "should optionally filter by domain" do
|
||||
access_token = mock_access_token
|
||||
access_token.expects(:post).never
|
||||
|
||||
google_docs = GoogleDocs::Connection.new(token, secret)
|
||||
mock_user = mock()
|
||||
mock_user.stubs(:id).returns(192)
|
||||
mock_user.stubs(:google_docs_address).returns('u_id')
|
||||
|
||||
google_docs.acl_add('12345', [mock_user], 'does-not-match.com')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------
|
||||
# Helper methods for this spec
|
||||
# ----------------------------
|
||||
|
||||
def google_doc_settings
|
||||
{
|
||||
'test_user_token' => 'u_token',
|
||||
'test_user_secret' => 'u_secret',
|
||||
'test_user_id' => 'u_id',
|
||||
'test_user_name' => 'u_name',
|
||||
'api_key' => 'key',
|
||||
'secret_key' => 'secret'
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
def mock_consumer
|
||||
consumer = mock()
|
||||
OAuth::Consumer.expects(:new).at_least_once.with(
|
||||
GoogleDocs::Connection.config["api_key"],
|
||||
GoogleDocs::Connection.config["secret_key"], {
|
||||
:signature_method => 'HMAC-SHA1',
|
||||
:request_token_path => '/accounts/OAuthGetRequestToken',
|
||||
:site => 'https://www.google.com',
|
||||
:authorize_path => '/accounts/OAuthAuthorizeToken',
|
||||
:access_token_path => '/accounts/OAuthGetAccessToken'}).returns(consumer)
|
||||
return consumer
|
||||
end
|
||||
|
||||
def mock_access_token
|
||||
return @access_token if @access_token
|
||||
@access_token = mock()
|
||||
OAuth::AccessToken.expects(:new).at_least_once.with(mock_consumer(),
|
||||
"token",
|
||||
"secret").returns(@access_token)
|
||||
return @access_token
|
||||
end
|
||||
|
||||
def prepare_mock_get(response_xml)
|
||||
response = mock()
|
||||
mock_access_token.expects(:get).with(xml_schema_id).returns(response)
|
||||
response.expects(:body).returns(response_xml)
|
||||
end
|
||||
|
||||
def prepare_mock_post(url, request_xml, response_xml)
|
||||
response = mock()
|
||||
headers = {'Content-Type' => 'application/atom+xml'}
|
||||
mock_access_token.expects(:post).
|
||||
with(url, request_xml, headers).returns(response)
|
||||
response.expects(:body).returns(response_xml)
|
||||
end
|
||||
|
||||
def prepare_mock_delete(xml_schema_id)
|
||||
headers = {'GData-Version' => '2', 'If-Match' => '*'}
|
||||
mock_access_token.expects(:delete).with(xml_schema_id, headers).returns(mock())
|
||||
end
|
||||
end
|
|
@ -1,82 +0,0 @@
|
|||
#
|
||||
# Copyright (C) 2011-2014 Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
require 'spec_helper'
|
||||
|
||||
DOCS_FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures/google_docs/'
|
||||
|
||||
def load_fixture(filename)
|
||||
File.read(DOCS_FIXTURES_PATH + filename)
|
||||
end
|
||||
|
||||
describe GoogleDocs::Entry do
|
||||
let(:entry_feed) { load_fixture("create_doc_response.xml") }
|
||||
|
||||
describe "#extension" do
|
||||
context "with an extension looker upper" do
|
||||
before do
|
||||
extension_looker_upper = mock
|
||||
extension_mock = mock
|
||||
extension_looker_upper.expects(:find_by_name).with('text/html').returns(extension_mock)
|
||||
extension_mock.expects(:extension).returns("whatever")
|
||||
GoogleDocs::Entry.extension_looker_upper = extension_looker_upper
|
||||
end
|
||||
|
||||
after do
|
||||
GoogleDocs::Entry.extension_looker_upper = nil
|
||||
end
|
||||
|
||||
it "checks the extension_looker_upper first" do
|
||||
entry = GoogleDocs::Entry.new(entry_feed)
|
||||
entry.extension.should == "whatever"
|
||||
end
|
||||
end
|
||||
|
||||
it "is 'doc' when document id matches 'document'" do
|
||||
entry = GoogleDocs::Entry.new(entry_feed)
|
||||
entry.extension.should == "doc"
|
||||
end
|
||||
|
||||
it "can be reset/forced to 'xlsx'" do
|
||||
entry = GoogleDocs::Entry.new(entry_feed)
|
||||
entry.extension.should == "doc"
|
||||
entry.reset_extension_as_xlsx
|
||||
entry.extension.should == "xlsx"
|
||||
end
|
||||
end
|
||||
|
||||
describe '#download_url' do
|
||||
it 'should add exportFormat and format parameters when applicable' do
|
||||
entry = GoogleDocs::Entry.new(entry_feed)
|
||||
entry.stubs(:extension).returns("xls")
|
||||
|
||||
url = URI.parse(entry.download_url)
|
||||
|
||||
url.scheme.should == "https"
|
||||
url.host.should == "docs.google.com"
|
||||
url.path.should == "/feeds/download/documents/export/Export"
|
||||
|
||||
params = url.query.split("&")
|
||||
params.should include("id=1HJoN38KHlnu32B5z_THgchnTMUbj7dgs8P-Twrm38cA")
|
||||
params.should include("exportFormat=xls")
|
||||
params.should include("format=xls")
|
||||
|
||||
entry.stubs(:extension).returns(nil)
|
||||
entry.download_url.should == "https://docs.google.com/feeds/download/documents/export/Export?id=1HJoN38KHlnu32B5z_THgchnTMUbj7dgs8P-Twrm38cA"
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,66 +0,0 @@
|
|||
#
|
||||
# Copyright (C) 2011-2014 Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe GoogleDocs::Folder do
|
||||
class MockFile < Struct.new(:name); end
|
||||
|
||||
let(:folder) do
|
||||
folder1 = GoogleDocs::Folder.new(
|
||||
"one",
|
||||
[],
|
||||
[
|
||||
MockFile.new("one-1"),
|
||||
MockFile.new("one-2"),
|
||||
MockFile.new("one-3")
|
||||
]
|
||||
)
|
||||
|
||||
folder2 = GoogleDocs::Folder.new(
|
||||
"two",
|
||||
[],
|
||||
[
|
||||
MockFile.new("two-1"),
|
||||
MockFile.new("two-2")
|
||||
]
|
||||
)
|
||||
|
||||
GoogleDocs::Folder.new(
|
||||
"root",
|
||||
[
|
||||
folder1,
|
||||
folder2
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
it "can map files" do
|
||||
names = folder.map{ |f| f.name }
|
||||
names.should == ['one-1', 'one-2', 'one-3', 'two-1', 'two-2']
|
||||
end
|
||||
|
||||
it "can select files" do
|
||||
tree = folder.select{ |f| f.name =~ /one-[12]/ }
|
||||
tree.name.should == 'root'
|
||||
tree.folders.size.should == 1
|
||||
tree.folders.first.name.should == 'one'
|
||||
tree.folders.first.files.size.should == 2
|
||||
tree.folders.first.files.map{ |f| f.name }.should == ['one-1', 'one-2']
|
||||
end
|
||||
end
|
|
@ -1,14 +0,0 @@
|
|||
require 'google_docs'
|
||||
require 'mocha'
|
||||
require 'timecop'
|
||||
|
||||
RSpec.configure do |config|
|
||||
config.treat_symbols_as_metadata_keys_with_true_values = true
|
||||
config.run_all_when_everything_filtered = true
|
||||
config.filter_run :focus
|
||||
|
||||
config.order = 'random'
|
||||
|
||||
config.mock_framework = :mocha
|
||||
|
||||
end
|
|
@ -1,6 +0,0 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
rm -f Gemfile.lock
|
||||
bundle check || bundle install
|
||||
bundle exec rspec spec
|
|
@ -14,10 +14,14 @@ Gem::Specification.new do |spec|
|
|||
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
||||
spec.require_paths = ["lib"]
|
||||
|
||||
spec.add_dependency "rails", ">= 3.2", "< 4.2"
|
||||
spec.add_runtime_dependency "google-api-client", "0.8.2"
|
||||
|
||||
spec.add_development_dependency "bundler", "~> 1.7"
|
||||
spec.add_development_dependency "rake"
|
||||
spec.add_development_dependency "rspec", "3.2.0"
|
||||
spec.add_development_dependency "byebug"
|
||||
spec.add_development_dependency "mocha"
|
||||
spec.add_development_dependency "timecop"
|
||||
spec.add_development_dependency "webmock"
|
||||
end
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
require 'active_support'
|
||||
require 'google/api_client'
|
||||
|
||||
module GoogleDrive
|
||||
require 'google_drive/no_token_error'
|
||||
require 'google_drive/connection_exception'
|
||||
|
||||
require 'google_drive/client'
|
||||
end
|
||||
require 'google_drive/connection'
|
||||
require 'google_drive/entry'
|
||||
require 'google_drive/folder'
|
||||
end
|
|
@ -20,7 +20,6 @@ module GoogleDrive
|
|||
client
|
||||
end
|
||||
|
||||
|
||||
def self.auth_uri(client, state, login=nil)
|
||||
auth_client = client.authorization
|
||||
auth_client.update!
|
||||
|
@ -32,8 +31,6 @@ module GoogleDrive
|
|||
}
|
||||
|
||||
request_data[:login_hint] = login if login
|
||||
|
||||
|
||||
auth_client.authorization_uri(request_data).to_s
|
||||
end
|
||||
end
|
||||
|
|
|
@ -16,13 +16,10 @@
|
|||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# See Google Docs API documentation here:
|
||||
# http://code.google.com/apis/documents/docs/2.0/developers_guide_protocol.html
|
||||
module GoogleDocs
|
||||
class DriveConnectionException < RuntimeError
|
||||
end
|
||||
|
||||
class DriveConnection
|
||||
# See Google Drive API documentation here:
|
||||
# https://developers.google.com/drive/v2/web/about-sdk
|
||||
module GoogleDrive
|
||||
class Connection
|
||||
def initialize(refresh_token, access_token, timeout = nil)
|
||||
@refresh_token = refresh_token
|
||||
@access_token = access_token
|
||||
|
@ -40,7 +37,7 @@ module GoogleDocs
|
|||
def with_timeout_protection
|
||||
Timeout.timeout(@timeout || 30) { yield }
|
||||
rescue Timeout::Error
|
||||
raise DriveConnectionException, "Google Drive connection timed out"
|
||||
raise ConnectionException, 'Google Drive connection timed out'
|
||||
end
|
||||
|
||||
def client_execute(options)
|
||||
|
@ -62,23 +59,19 @@ module GoogleDocs
|
|||
)
|
||||
|
||||
file = response.data.to_hash
|
||||
entry = GoogleDocs::DriveEntry.new(file, extensions)
|
||||
entry = GoogleDrive::Entry.new(file, extensions)
|
||||
result = client_execute(:uri => entry.download_url)
|
||||
if result.status == 200
|
||||
|
||||
# hack to make it seem like the old object
|
||||
result.define_singleton_method(:content_type) do
|
||||
result.headers['Content-Type'].sub(/; charset=[^;]+/, '')
|
||||
end
|
||||
file_name = file['title']
|
||||
name_extension = file_name[/\.([a-z]+$)/, 1]
|
||||
file_extension = name_extension || file_extension_from_header(result.headers, entry)
|
||||
|
||||
# file_name should contain the file_extension
|
||||
file_name += ".#{file_extension}" unless name_extension
|
||||
[result, file_name, file_extension]
|
||||
content_type = result.headers['Content-Type'].sub(/; charset=[^;]+/, '')
|
||||
[result, file_name, file_extension, content_type]
|
||||
else
|
||||
raise DriveConnectionException, result.error_message
|
||||
raise ConnectionException, result.error_message
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -103,7 +96,7 @@ module GoogleDocs
|
|||
if result.status == 200
|
||||
result
|
||||
else
|
||||
raise DriveConnectionException, result.error_message
|
||||
raise ConnectionException, result.error_message
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -113,21 +106,23 @@ module GoogleDocs
|
|||
:api_method => drive.files.delete,
|
||||
:parameters => { :fileId => normalize_document_id(document_id) })
|
||||
if result.error? && !result.error_message.include?('File not found')
|
||||
raise DriveConnectionException, result.error_message
|
||||
raise ConnectionException, result.error_message
|
||||
end
|
||||
end
|
||||
|
||||
def acl_remove(document_id, users)
|
||||
force_token_update
|
||||
users.each do |user_id|
|
||||
next if user_id.blank? || /@/.match(user_id) # google drive ids are numeric, google docs are emails. if it is a google doc email just skip it
|
||||
# google drive ids are numeric, google docs are emails. if it is a google doc email just skip it
|
||||
# this is needed for legacy purposes
|
||||
next if user_id.blank? || /@/.match(user_id)
|
||||
result = client_execute(
|
||||
:api_method => drive.permissions.delete,
|
||||
:parameters => {
|
||||
:fileId => normalize_document_id(document_id),
|
||||
:permissionId => user_id })
|
||||
if result.error? && !result.error_message.starts_with?("Permission not found")
|
||||
raise DriveConnectionException, result.error_message
|
||||
raise ConnectionException, result.error_message
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -155,18 +150,20 @@ module GoogleDocs
|
|||
:parameters => { :fileId => normalize_document_id(document_id) }
|
||||
)
|
||||
if result.error?
|
||||
raise DriveConnectionException, result.error_message
|
||||
raise ConnectionException, result.error_message
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def verify_access_token
|
||||
def authorized?
|
||||
force_token_update
|
||||
client_execute(:api_method => drive.about.get).status == 200
|
||||
rescue ConnectionException, NoTokenError, Google::APIClient::AuthorizationError
|
||||
false
|
||||
end
|
||||
|
||||
def self.config_check(_settings)
|
||||
raise DriveConnectionException("No config check")
|
||||
raise ConnectionException("No config check")
|
||||
end
|
||||
|
||||
def self.config=(config)
|
||||
|
@ -196,20 +193,21 @@ module GoogleDocs
|
|||
end
|
||||
|
||||
def folderize_list(documents, extensions)
|
||||
root = GoogleDocs::DriveFolder.new('/')
|
||||
root = GoogleDrive::Folder.new('/')
|
||||
folders = {nil => root}
|
||||
|
||||
documents['items'].each do |doc_entry|
|
||||
next unless doc_entry['downloadUrl'] || doc_entry['exportLinks']
|
||||
entry = GoogleDocs::DriveEntry.new(doc_entry, extensions)
|
||||
if folders.has_key?(entry.folder)
|
||||
entry = GoogleDrive::Entry.new(doc_entry, extensions)
|
||||
if folders.key?(entry.folder)
|
||||
folder = folders[entry.folder]
|
||||
else
|
||||
folder = GoogleDocs::DriveFolder.new(get_folder_name_by_id(documents['items'], entry.folder))
|
||||
folder = GoogleDrive::Folder.new(get_folder_name_by_id(documents['items'], entry.folder))
|
||||
root.add_folder folder
|
||||
folders[entry.folder] = folder
|
||||
end
|
||||
folder.add_file(entry) unless doc_entry['mimeType'] && doc_entry['mimeType'] == 'application/vnd.google-apps.folder'
|
||||
is_folder = doc_entry['mimeType'] && doc_entry['mimeType'] == 'application/vnd.google-apps.folder'
|
||||
folder.add_file(entry) unless is_folder
|
||||
end
|
||||
|
||||
if extensions && extensions.length > 0
|
||||
|
@ -227,26 +225,23 @@ module GoogleDocs
|
|||
end
|
||||
|
||||
def api_client
|
||||
return nil if GoogleDocs::DriveConnection.config.nil?
|
||||
@api_client ||= GoogleDrive::Client.create(GoogleDocs::DriveConnection.config, @refresh_token, @access_token)
|
||||
end
|
||||
|
||||
# override for specs because GoogleDrive is in a sibling project
|
||||
# and not an actual declared dependency of this gem. That's
|
||||
# probably a design mistake that should be corrected
|
||||
def set_api_client(client)
|
||||
@api_client = client
|
||||
raise ConnectionException, "GoogleDrive is not configured" if GoogleDrive::Connection.config.nil?
|
||||
raise NoTokenError unless @refresh_token && @access_token
|
||||
@api_client ||= GoogleDrive::Client.create(GoogleDrive::Connection.config, @refresh_token, @access_token)
|
||||
end
|
||||
|
||||
def drive
|
||||
api_client.discovered_api('drive', 'v2')
|
||||
@drive ||= Rails.cache.fetch('google_drive_v2') do
|
||||
api_client.discovered_api('drive', 'v2')
|
||||
end
|
||||
end
|
||||
|
||||
def file_extension_from_header(headers, entry)
|
||||
file_extension = entry.extension && !entry.extension.empty? && entry.extension || 'unknown'
|
||||
|
||||
if headers['content-disposition'] && headers['content-disposition'].match(/filename=[\"\']?[^;\"\'\.]+\.(?<file_extension>[^;\"\']+)[\"\']?/)
|
||||
file_extension = Regexp.last_match[:file_extension]
|
||||
if headers['content-disposition'] &&
|
||||
headers['content-disposition'].match(/filename=[\"\']?[^;\"\'\.]+\.(?<file_extension>[^;\"\']+)[\"\']?/)
|
||||
file_extension = Regexp.last_match[:file_extension]
|
||||
end
|
||||
|
||||
file_extension
|
|
@ -0,0 +1,4 @@
|
|||
module GoogleDrive
|
||||
class ConnectionException < RuntimeError
|
||||
end
|
||||
end
|
|
@ -15,8 +15,8 @@
|
|||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
module GoogleDocs
|
||||
class DriveEntry
|
||||
module GoogleDrive
|
||||
class Entry
|
||||
|
||||
attr_reader :document_id, :folder, :entry
|
||||
|
||||
|
@ -25,7 +25,7 @@ module GoogleDocs
|
|||
@document_id = @entry['id']
|
||||
@preferred_extensions = preferred_extensions
|
||||
parent = @entry['parents'].length > 0 ? @entry['parents'][0] : nil
|
||||
@folder = (parent == nil || parent['isRoot'] ? nil : parent['id'])
|
||||
@folder = (parent.nil? || parent['isRoot'] ? nil : parent['id'])
|
||||
end
|
||||
|
||||
def alternate_url
|
||||
|
@ -37,7 +37,7 @@ module GoogleDocs
|
|||
end
|
||||
|
||||
def extension
|
||||
get_file_data[:ext]
|
||||
file_data[:ext]
|
||||
end
|
||||
|
||||
def display_name
|
||||
|
@ -45,7 +45,7 @@ module GoogleDocs
|
|||
end
|
||||
|
||||
def download_url
|
||||
get_file_data[:url]
|
||||
file_data[:url]
|
||||
end
|
||||
|
||||
def to_hash
|
||||
|
@ -58,7 +58,7 @@ module GoogleDocs
|
|||
end
|
||||
|
||||
private
|
||||
def get_file_data()
|
||||
def file_data
|
||||
# First we check export links for our preferred formats
|
||||
# then we fail over to the file properties
|
||||
if @entry['exportLinks']
|
||||
|
@ -66,10 +66,10 @@ module GoogleDocs
|
|||
end
|
||||
|
||||
# we'll have to find the url and extensions some other place
|
||||
extension ||= @entry['fileExtension'] if @entry.has_key? 'fileExtension'
|
||||
extension ||= @entry['fileExtension'] if @entry.key? 'fileExtension'
|
||||
extension ||= 'none'
|
||||
|
||||
url ||= @entry['downloadUrl'] if @entry.has_key? 'downloadUrl'
|
||||
url ||= @entry['downloadUrl'] if @entry.key? 'downloadUrl'
|
||||
|
||||
{
|
||||
url: url,
|
||||
|
@ -78,10 +78,29 @@ module GoogleDocs
|
|||
end
|
||||
|
||||
def preferred_export_link(preferred_extensions=nil)
|
||||
preferred_urls = preferred_mime_types.map do |mime_type|
|
||||
next unless @entry['exportLinks'][mime_type]
|
||||
|
||||
current_url = @entry['exportLinks'][mime_type]
|
||||
current_extension = /([a-z]+)$/.match(current_url).to_s
|
||||
has_preferred_extension = preferred_extensions && preferred_extensions.include?(current_extension)
|
||||
|
||||
# our extension is in the preferred list or we have no preferences
|
||||
[current_url, current_extension] if has_preferred_extension || !preferred_extensions
|
||||
end
|
||||
|
||||
url, extension = preferred_urls.find{ |i| i}
|
||||
|
||||
# if we dont have any "preferred extension" just return the default.
|
||||
# they will be filtered out by the folderize method
|
||||
return preferred_export_link if url.nil? && preferred_extensions
|
||||
[url, extension]
|
||||
end
|
||||
|
||||
def preferred_mime_types
|
||||
# Order is important
|
||||
# we return the first matching mime type
|
||||
preferred_mime_types = %w{
|
||||
%w{
|
||||
application/vnd.openxmlformats-officedocument.wordprocessingml.document
|
||||
application/vnd.oasis.opendocument.text
|
||||
application/vnd.openxmlformats-officedocument.presentationml.presentation
|
||||
|
@ -90,22 +109,6 @@ module GoogleDocs
|
|||
application/pdf
|
||||
application/zip
|
||||
}
|
||||
|
||||
url, extension = preferred_mime_types.map do |mime_type|
|
||||
next unless @entry['exportLinks'][mime_type]
|
||||
|
||||
current_url = @entry['exportLinks'][mime_type]
|
||||
current_extension = /([a-z]+)$/.match(current_url).to_s
|
||||
|
||||
# our extension is in the preferred list or we have no preferences
|
||||
[current_url, current_extension] if (preferred_extensions && preferred_extensions.include?(current_extension)) || !preferred_extensions
|
||||
end.find{|i|i}
|
||||
|
||||
# if we dont have any "preferred extension" just return the default.
|
||||
# they will be filtered out by the folderize method
|
||||
return preferred_export_link if url == nil && preferred_extensions
|
||||
[url, extension]
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,10 +1,9 @@
|
|||
module GoogleDocs
|
||||
module GoogleDrive
|
||||
class Folder
|
||||
attr_reader :name, :folders, :files
|
||||
|
||||
def initialize(name, folders=[], files=[])
|
||||
@name = name
|
||||
# File objects are GoogleDocEntry objects
|
||||
@folders, @files = folders, files
|
||||
end
|
||||
|
||||
|
@ -27,11 +26,15 @@ module GoogleDocs
|
|||
@files.map(&block)
|
||||
end
|
||||
|
||||
def flatten
|
||||
@folders.flatten + @files
|
||||
end
|
||||
|
||||
def to_hash
|
||||
{
|
||||
"name" => @name,
|
||||
"folders" => @folders.map { |sf| sf.to_hash },
|
||||
"files" => @files.map { |f| f.to_hash }
|
||||
:name => @name,
|
||||
:folders => @folders.map(&:to_hash),
|
||||
:files => @files.map(&:to_hash)
|
||||
}
|
||||
end
|
||||
end
|
|
@ -1,4 +1,4 @@
|
|||
module GoogleDocs
|
||||
module GoogleDrive
|
||||
class NoTokenError < StandardError
|
||||
def initialize
|
||||
super("User does not have a valid Google Docs token")
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,86 @@
|
|||
{
|
||||
"kind": "drive#file",
|
||||
"id": "**file_id**",
|
||||
"etag": "\"amKkzAMv_fUBF0Cxt1a1WaLm5Nk/MTQ1MDM3NTY4NDYwMg\"",
|
||||
"selfLink": "https://www.googleapis.com/drive/v2/files/**file_id**",
|
||||
"alternateLink": "https://docs.google.com/a/instructure.com/document/d/**file_id**/edit?usp=drivesdk",
|
||||
"embedLink": "https://docs.google.com/a/instructure.com/document/d/**file_id**/preview",
|
||||
"iconLink": "https://ssl.gstatic.com/docs/doclist/images/icon_11_document_list.png",
|
||||
"title": "Biology 100 Collaboration",
|
||||
"mimeType": "application/vnd.google-apps.document",
|
||||
"labels": {
|
||||
"starred": false,
|
||||
"hidden": false,
|
||||
"trashed": false,
|
||||
"restricted": false,
|
||||
"viewed": true
|
||||
},
|
||||
"createdDate": "2015-12-17T18:08:04.602Z",
|
||||
"modifiedDate": "2015-12-17T18:08:04.602Z",
|
||||
"modifiedByMeDate": "2015-12-17T18:08:04.602Z",
|
||||
"lastViewedByMeDate": "2015-12-17T18:08:04.602Z",
|
||||
"markedViewedByMeDate": "1970-01-01T00:00:00.000Z",
|
||||
"version": "15483",
|
||||
"parents": [
|
||||
{
|
||||
"kind": "drive#parentReference",
|
||||
"id": "0ADvGR2OPwneAUk9PVA",
|
||||
"selfLink": "https://www.googleapis.com/drive/v2/files/**file_id**/parents/0ADvGR2OPwneAUk9PVA",
|
||||
"parentLink": "https://www.googleapis.com/drive/v2/files/0ADvGR2OPwneAUk9PVA",
|
||||
"isRoot": true
|
||||
}
|
||||
],
|
||||
"exportLinks": {
|
||||
"application/rtf": "https://docs.google.com/feeds/download/documents/export/Export?id=**file_id**&exportFormat=rtf",
|
||||
"application/vnd.oasis.opendocument.text": "https://docs.google.com/feeds/download/documents/export/Export?id=**file_id**&exportFormat=odt",
|
||||
"text/html": "https://docs.google.com/feeds/download/documents/export/Export?id=**file_id**&exportFormat=html",
|
||||
"application/pdf": "https://docs.google.com/feeds/download/documents/export/Export?id=**file_id**&exportFormat=pdf",
|
||||
"application/zip": "https://docs.google.com/feeds/download/documents/export/Export?id=**file_id**&exportFormat=zip",
|
||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": "https://docs.google.com/feeds/download/documents/export/Export?id=**file_id**&exportFormat=docx",
|
||||
"text/plain": "https://docs.google.com/feeds/download/documents/export/Export?id=**file_id**&exportFormat=txt"
|
||||
},
|
||||
"userPermission": {
|
||||
"kind": "drive#permission",
|
||||
"etag": "\"amKkzAMv_fUBF0Cxt1a1WaLm5Nk/y4y5UF9JzlFDfWgHoG5-AJ5lCDM\"",
|
||||
"id": "me",
|
||||
"selfLink": "https://www.googleapis.com/drive/v2/files/**file_id**/permissions/me",
|
||||
"role": "owner",
|
||||
"type": "user"
|
||||
},
|
||||
"quotaBytesUsed": "0",
|
||||
"ownerNames": [
|
||||
"Montgomery Montgomery"
|
||||
],
|
||||
"owners": [
|
||||
{
|
||||
"kind": "drive#user",
|
||||
"displayName": "Montgomery Montgomery",
|
||||
"picture": {
|
||||
"url": "https://lh6.googleusercontent.com/-x0Cip_5Wrw0/AAAAAAAAAAI/AAAAAAAAAGM/**********/s64/photo.jpg"
|
||||
},
|
||||
"isAuthenticatedUser": true,
|
||||
"permissionId": "0024957*******0999547",
|
||||
"emailAddress": "montgomery@nowhere.com"
|
||||
}
|
||||
],
|
||||
"lastModifyingUserName": "Montgomery Montgomery",
|
||||
"lastModifyingUser": {
|
||||
"kind": "drive#user",
|
||||
"displayName": "Montgomery Montgomery",
|
||||
"picture": {
|
||||
"url": "https://lh6.googleusercontent.com/-x0Cip_5Wrw0/AAAAAAAAAAI/AAAAAAAAAGM/**********/s64/photo.jpg"
|
||||
},
|
||||
"isAuthenticatedUser": true,
|
||||
"permissionId": "0024957*******0999547",
|
||||
"emailAddress": "montgomery@nowhere.com"
|
||||
},
|
||||
"editable": true,
|
||||
"copyable": true,
|
||||
"writersCanShare": true,
|
||||
"shared": false,
|
||||
"explicitlyTrashed": false,
|
||||
"appDataContents": false,
|
||||
"spaces": [
|
||||
"drive"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
{
|
||||
"kind": "drive#fileList",
|
||||
"etag": "\"XTBboRWlttiWhZ_feOHVV3sFYJs/NldWXgcoxpDGqwSjdu9I3zgzcmU\"",
|
||||
"selfLink": "https://www.googleapis.com/drive/v2/files?q=trashed%3Dfalse",
|
||||
"nextPageToken": "fake_token",
|
||||
"nextLink": "https://www.googleapis.com/drive/v2/files?pageToken=fake_token&q=trashed%3Dfalse",
|
||||
"items": [
|
||||
{
|
||||
"kind": "drive#file",
|
||||
"id": "1p0*******************MYS-kJYhmhvfw8",
|
||||
"etag": "\"XTBboRWlttiWhZ_feOHVV3sFYJs/MTQ1MjcyMTI4NDUwOA\"",
|
||||
"selfLink": "https://www.googleapis.com/drive/v2/files/1p0*******************MYS-kJYhmhvfw8",
|
||||
"alternateLink": "https://docs.google.com/a/instructure.com/spreadsheets/d/1p0*******************MYS-kJYhmhvfw8/edit?usp=drivesdk",
|
||||
"embedLink": "https://docs.google.com/a/instructure.com/spreadsheets/d/1p0*******************MYS-kJYhmhvfw8/htmlembed",
|
||||
"openWithLinks": {
|
||||
"1083656409722": "https://docs.google.com/a/instructure.com/spreadsheets/d/1p0*******************MYS-kJYhmhvfw8/edit?usp=drive_web"
|
||||
},
|
||||
"defaultOpenWithLink": "https://docs.google.com/a/instructure.com/spreadsheets/d/1p0*******************MYS-kJYhmhvfw8/edit?usp=drive_web",
|
||||
"iconLink": "https://ssl.gstatic.com/docs/doclist/images/icon_11_spreadsheet_list.png",
|
||||
"thumbnailLink": "https://docs.google.com/a/instructure.com/feeds/vt?gd=true&id=1p0*******************MYS-kJYhmhvfw8&v=0&s=AMedNn****************MCMDEc&sz=s220",
|
||||
"title": "Top Secret Documents",
|
||||
"mimeType": "application/vnd.google-apps.spreadsheet",
|
||||
"labels": {
|
||||
"starred": false,
|
||||
"hidden": false,
|
||||
"trashed": false,
|
||||
"restricted": false,
|
||||
"viewed": true
|
||||
},
|
||||
"createdDate": "2014-07-07T20:11:17.079Z",
|
||||
"modifiedDate": "2016-01-13T21:41:24.508Z",
|
||||
"modifiedByMeDate": "2015-01-16T21:20:07.945Z",
|
||||
"lastViewedByMeDate": "2015-01-16T21:20:07.945Z",
|
||||
"markedViewedByMeDate": "1970-01-01T00:00:00.000Z",
|
||||
"version": "459452",
|
||||
"parents": [],
|
||||
"exportLinks": {
|
||||
"text/csv": "https://docs.google.com/spreadsheets/export?id=1p0*******************MYS-kJYhmhvfw8&exportFormat=csv",
|
||||
"application/x-vnd.oasis.opendocument.spreadsheet": "https://docs.google.com/spreadsheets/export?id=1p0*******************MYS-kJYhmhvfw8&exportFormat=ods",
|
||||
"application/zip": "https://docs.google.com/spreadsheets/export?id=1p0*******************MYS-kJYhmhvfw8&exportFormat=zip",
|
||||
"application/pdf": "https://docs.google.com/spreadsheets/export?id=1p0*******************MYS-kJYhmhvfw8&exportFormat=pdf",
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "https://docs.google.com/spreadsheets/export?id=1p0*******************MYS-kJYhmhvfw8&exportFormat=xlsx"
|
||||
},
|
||||
"userPermission": {
|
||||
"kind": "drive#permission",
|
||||
"etag": "\"XTBboRWlttiWhZ_feOHVV3sFYJs/fAeh6NlrWb23aHSXwPR-vOdwE0o\"",
|
||||
"id": "me",
|
||||
"selfLink": "https://www.googleapis.com/drive/v2/files/1p0*******************MYS-kJYhmhvfw8/permissions/me",
|
||||
"role": "writer",
|
||||
"type": "user"
|
||||
},
|
||||
"quotaBytesUsed": "0",
|
||||
"ownerNames": [
|
||||
"Montgomery Montgomery"
|
||||
],
|
||||
"owners": [
|
||||
{
|
||||
"kind": "drive#user",
|
||||
"displayName": "Montgomery Montgomery",
|
||||
"picture": {
|
||||
"url": "https://lh6.googleusercontent.com/-x0Cip_5Wrw0/AAAAAAAAAAI/AAAAAAAAAGM/**********/s64/photo.jpg"
|
||||
},
|
||||
"isAuthenticatedUser": false,
|
||||
"permissionId": "0024957*******0999547",
|
||||
"emailAddress": "montgomery@nowhere.com"
|
||||
}
|
||||
],
|
||||
"lastModifyingUserName": "Frank Frank",
|
||||
"lastModifyingUser": {
|
||||
"kind": "drive#user",
|
||||
"displayName": "Frank Frank",
|
||||
"isAuthenticatedUser": false,
|
||||
"permissionId": "0701907*******5319074",
|
||||
"emailAddress": "frank@nowhere.com"
|
||||
},
|
||||
"editable": true,
|
||||
"copyable": true,
|
||||
"writersCanShare": true,
|
||||
"shared": true,
|
||||
"explicitlyTrashed": false,
|
||||
"appDataContents": false,
|
||||
"spaces": [
|
||||
"drive"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -18,130 +18,73 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
describe GoogleDocs::DriveConnection do
|
||||
describe GoogleDrive::Connection do
|
||||
|
||||
let(:token) { "token" }
|
||||
let(:secret) { "secret" }
|
||||
|
||||
fake_client = Class.new do
|
||||
attr_reader :token
|
||||
attr_writer :responses
|
||||
attr_accessor :inputs
|
||||
|
||||
def initialize(input=nil)
|
||||
@input = input
|
||||
@calls = 0
|
||||
@token = 0
|
||||
@responses = []
|
||||
end
|
||||
|
||||
def insert
|
||||
self
|
||||
end
|
||||
|
||||
def request_schema
|
||||
self.class
|
||||
end
|
||||
|
||||
def discovered_api(_endpoint, _version)
|
||||
self
|
||||
end
|
||||
|
||||
def files
|
||||
self
|
||||
end
|
||||
|
||||
def authorization
|
||||
self
|
||||
end
|
||||
|
||||
def update_token!
|
||||
@token += 1
|
||||
end
|
||||
|
||||
def get
|
||||
"/api_method"
|
||||
end
|
||||
|
||||
def list
|
||||
"/api_method"
|
||||
end
|
||||
|
||||
def execute!(*args)
|
||||
@inputs = args
|
||||
response = @responses[@calls]
|
||||
@calls += 1
|
||||
response
|
||||
end
|
||||
|
||||
def execute(*args)
|
||||
execute!(*args)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
before do
|
||||
config = {
|
||||
"api_key" => "key",
|
||||
"secret_key" => "secret",
|
||||
}
|
||||
GoogleDocs::DriveConnection.config = proc do
|
||||
GoogleDrive::Connection.config = proc do
|
||||
config
|
||||
end
|
||||
end
|
||||
|
||||
describe "#file_extension from headers" do
|
||||
it "should pull the file extension from the response header" do
|
||||
google_docs = GoogleDocs::DriveConnection.new(token, secret)
|
||||
google_docs = GoogleDrive::Connection.new(token, secret)
|
||||
|
||||
headers = {
|
||||
'content-disposition' => 'attachment;filename="Testing.docx"'
|
||||
}
|
||||
|
||||
entry = stub('DriveEntry', extension: "not")
|
||||
file_extension = google_docs.send(:file_extension_from_header, headers, entry)
|
||||
entry = stub('Entry', extension: "not")
|
||||
file_extension = google_docs.send(:file_extension_from_header, headers, entry)
|
||||
|
||||
expect(file_extension).to eq("docx")
|
||||
end
|
||||
|
||||
it "should pull the file extension from the entry if its not in the response header" do
|
||||
google_docs = GoogleDocs::DriveConnection.new(token, secret)
|
||||
google_docs = GoogleDrive::Connection.new(token, secret)
|
||||
|
||||
headers = {
|
||||
'content-disposition' => 'attachment"'
|
||||
}
|
||||
|
||||
entry = stub('DriveEntry', extension: "not")
|
||||
file_extension = google_docs.send(:file_extension_from_header, headers, entry)
|
||||
entry = stub('Entry', extension: "not")
|
||||
file_extension = google_docs.send(:file_extension_from_header, headers, entry)
|
||||
expect(file_extension).to eq("not")
|
||||
end
|
||||
|
||||
it "should use unknown as a last resort file extension" do
|
||||
google_docs = GoogleDocs::DriveConnection.new(token, secret)
|
||||
google_docs = GoogleDrive::Connection.new(token, secret)
|
||||
|
||||
headers = {
|
||||
'content-disposition' => 'attachment"'
|
||||
}
|
||||
|
||||
entry = stub('DriveEntry', extension: "")
|
||||
file_extension = google_docs.send(:file_extension_from_header, headers, entry)
|
||||
entry = stub('Entry', extension: "")
|
||||
file_extension = google_docs.send(:file_extension_from_header, headers, entry)
|
||||
expect(file_extension).to eq("unknown")
|
||||
end
|
||||
|
||||
it "should use unknown as file extension when extension is nil" do
|
||||
google_docs = GoogleDocs::DriveConnection.new(token, secret)
|
||||
google_docs = GoogleDrive::Connection.new(token, secret)
|
||||
|
||||
headers = {}
|
||||
entry = stub('DriveEntry', extension: nil)
|
||||
entry = stub('Entry', extension: nil)
|
||||
|
||||
file_extension = google_docs.send(:file_extension_from_header, headers, entry)
|
||||
file_extension = google_docs.send(:file_extension_from_header, headers, entry)
|
||||
expect(file_extension).to eq("unknown")
|
||||
end
|
||||
end
|
||||
|
||||
describe "#normalize_document_id" do
|
||||
it "should remove prefixes" do
|
||||
google_docs = GoogleDocs::DriveConnection.new(token, secret)
|
||||
google_docs = GoogleDrive::Connection.new(token, secret)
|
||||
|
||||
spreadsheet_id = google_docs.send(:normalize_document_id, "spreadsheet:awesome-spreadsheet-id")
|
||||
expect(spreadsheet_id).to eq("awesome-spreadsheet-id")
|
||||
|
@ -151,8 +94,7 @@ describe GoogleDocs::DriveConnection do
|
|||
end
|
||||
|
||||
it "shouldnt do anything to normalized ids" do
|
||||
google_docs = GoogleDocs::DriveConnection.new(token, secret)
|
||||
|
||||
google_docs = GoogleDrive::Connection.new(token, secret)
|
||||
|
||||
spreadsheet_id = google_docs.send(:normalize_document_id, "awesome-spreadsheet-id")
|
||||
expect(spreadsheet_id).to eq("awesome-spreadsheet-id")
|
||||
|
@ -163,49 +105,58 @@ describe GoogleDocs::DriveConnection do
|
|||
end
|
||||
|
||||
describe "API interaction" do
|
||||
let(:connection){ GoogleDocs::DriveConnection.new(token, secret) }
|
||||
let(:client){ fake_client.new }
|
||||
let(:connection){ GoogleDrive::Connection.new(token, secret) }
|
||||
|
||||
before do
|
||||
connection.send(:set_api_client, client)
|
||||
stub_request(:get, "https://www.googleapis.com/discovery/v1/apis/drive/v2/rest").
|
||||
to_return(
|
||||
:status => 200,
|
||||
:body => load_fixture('discovered_api.json'),
|
||||
:headers => {'Content-Type' => 'application/json'}
|
||||
)
|
||||
end
|
||||
|
||||
describe "#list_with_extension_filter" do
|
||||
before do
|
||||
client.responses = [
|
||||
stub(status: 200, data: { "items" => [] })
|
||||
]
|
||||
end
|
||||
|
||||
it "should submit `trashed = false` parameter" do
|
||||
stub_request(
|
||||
:get, "https://www.googleapis.com/drive/v2/files?maxResults=0&q=trashed=false"
|
||||
).to_return(
|
||||
:status => 200, :body => load_fixture('list.json'), :headers => {'Content-Type' => 'application/json'}
|
||||
)
|
||||
|
||||
connection.list_with_extension_filter('.txt')
|
||||
expect(client.inputs.last[:parameters][:q]).to eql 'trashed=false'
|
||||
expect(WebMock).to have_requested(:get,
|
||||
"https://www.googleapis.com/drive/v2/files?maxResults=0&q=trashed=false")
|
||||
end
|
||||
end
|
||||
|
||||
describe "#download" do
|
||||
before do
|
||||
client.responses = [
|
||||
stub(status: 200, data:
|
||||
{
|
||||
'parents' => [],
|
||||
'title' => "SomeFile.txt"
|
||||
}
|
||||
),
|
||||
stub(status: 200, data: {})
|
||||
]
|
||||
end
|
||||
|
||||
it "requests a download from the api client" do
|
||||
stub_request(
|
||||
:get, "https://www.googleapis.com/drive/v2/files/42"
|
||||
).to_return(
|
||||
:status => 200, :body => load_fixture('file_data.json'), :headers => {'Content-Type' => 'application/json'}
|
||||
)
|
||||
|
||||
stub_request(
|
||||
:get, "https://docs.google.com/feeds/download/documents/export/Export?exportFormat=docx&id=**file_id**"
|
||||
).to_return(
|
||||
:status => 200, :body => "",
|
||||
:headers => {
|
||||
'Content-Type' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
|
||||
}
|
||||
)
|
||||
|
||||
output = connection.download("42", nil)
|
||||
expect(output[1]).to eq("SomeFile.txt")
|
||||
expect(output[2]).to eq("txt")
|
||||
expect(output[1]).to eq("Biology 100 Collaboration.docx")
|
||||
expect(output[2]).to eq("docx")
|
||||
end
|
||||
|
||||
it "wraps a timeout in a drive connection exception" do
|
||||
|
||||
Timeout.stubs(:timeout).raises(Timeout::Error)
|
||||
expect{ connection.download("42", nil) }.to(
|
||||
raise_error(GoogleDocs::DriveConnectionException) do |e|
|
||||
raise_error(GoogleDrive::ConnectionException) do |e|
|
||||
expect(e.message).to eq("Google Drive connection timed out")
|
||||
end
|
||||
)
|
||||
|
@ -213,26 +164,40 @@ describe GoogleDocs::DriveConnection do
|
|||
end
|
||||
|
||||
describe "#create_doc" do
|
||||
|
||||
before do
|
||||
client.responses = [
|
||||
stub(status: 200, data: {})
|
||||
]
|
||||
end
|
||||
|
||||
it "forces a new refresh token" do
|
||||
connection.create_doc("DocName")
|
||||
expect(client.token).to eq(1)
|
||||
end
|
||||
|
||||
it "wraps a timeout in a drive connection exception" do
|
||||
|
||||
Timeout.stubs(:timeout).raises(Timeout::Error)
|
||||
expect{ connection.create_doc("Docname") }.to(
|
||||
raise_error(GoogleDocs::DriveConnectionException) do |e|
|
||||
raise_error(GoogleDrive::ConnectionException) do |e|
|
||||
expect(e.message).to eq("Google Drive connection timed out")
|
||||
end
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#authorized?" do
|
||||
it "returns false when there ConnectionException" do
|
||||
|
||||
GoogleDrive::Connection.config = GoogleDrive::Connection.config = proc do
|
||||
nil
|
||||
end
|
||||
|
||||
expect(connection.authorized?).to be false
|
||||
end
|
||||
|
||||
it "returns false when there NoTokenError" do
|
||||
my_connection = GoogleDrive::Connection.new(nil, nil)
|
||||
|
||||
expect(my_connection.authorized?).to be false
|
||||
end
|
||||
|
||||
it "returns false when there NoTokenError" do
|
||||
|
||||
stub_request(:get, "https://www.googleapis.com/drive/v2/about").
|
||||
to_return(:status => 200, :body => "", :headers => {})
|
||||
|
||||
expect(connection.authorized?).to be true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,5 +1,8 @@
|
|||
require 'google_drive'
|
||||
require 'byebug'
|
||||
require 'mocha'
|
||||
require 'timecop'
|
||||
require 'webmock/rspec'
|
||||
|
||||
DRIVE_FIXTURES_PATH = File.dirname(__FILE__) + '/fixtures/google_drive/'
|
||||
|
||||
|
@ -7,11 +10,19 @@ def load_fixture(filename)
|
|||
File.read(DRIVE_FIXTURES_PATH + filename)
|
||||
end
|
||||
|
||||
|
||||
WebMock.disable_net_connect!(allow_localhost: true)
|
||||
RSpec.configure do |config|
|
||||
config.treat_symbols_as_metadata_keys_with_true_values = true
|
||||
config.run_all_when_everything_filtered = true
|
||||
config.filter_run :focus
|
||||
|
||||
config.order = 'random'
|
||||
config.mock_framework = :mocha
|
||||
end
|
||||
|
||||
|
||||
module Rails
|
||||
def self.cache
|
||||
@cache ||= ActiveSupport::Cache::MemoryStore.new
|
||||
end
|
||||
end
|
|
@ -6,16 +6,11 @@ module AccountServices
|
|||
|
||||
def self.allowable_services
|
||||
AllowedServicesHash.new.merge({
|
||||
:google_docs => {
|
||||
:name => I18n.t("Google Docs"),
|
||||
:description => "",
|
||||
:expose_to_ui => :service,
|
||||
:expose_to_ui_proc => proc { !!GoogleDocs::Connection.config }
|
||||
},
|
||||
:google_drive => {
|
||||
:name => I18n.t("Google Drive"),
|
||||
:description => "",
|
||||
:expose_to_ui => false
|
||||
:expose_to_ui => :service,
|
||||
:expose_to_ui_proc => proc { !!GoogleDrive::Connection.config }
|
||||
},
|
||||
:google_docs_previews => {
|
||||
:name => I18n.t("Google Docs Preview"),
|
||||
|
|
|
@ -80,26 +80,18 @@ Canvas::Plugin.register('etherpad', :collaborations, {
|
|||
:settings_partial => 'plugins/etherpad_settings',
|
||||
:validator => 'EtherpadValidator'
|
||||
})
|
||||
Canvas::Plugin.register('google_docs', :collaborations, {
|
||||
:name => lambda{ t :name, 'Google Docs' },
|
||||
:description => lambda{ t :description, 'Google Docs document sharing' },
|
||||
:website => 'http://docs.google.com',
|
||||
:author => 'Instructure',
|
||||
:author_website => 'http://www.instructure.com',
|
||||
:version => '1.0.0',
|
||||
:settings_partial => 'plugins/google_docs_settings',
|
||||
:validator => 'GoogleDocsValidator'
|
||||
})
|
||||
Canvas::Plugin.register('google_drive', nil,
|
||||
name: -> { t :name, 'Google Drive' },
|
||||
description: -> { t :description, 'Google Drive file sharing' },
|
||||
website: 'http://drive.google.com',
|
||||
author: 'Instructure',
|
||||
author_website: 'http://www.instructure.com',
|
||||
version: '1.0.0',
|
||||
settings_partial: 'plugins/google_drive_settings',
|
||||
validator: 'GoogleDriveValidator',
|
||||
encrypted_settings: [:client_secret]
|
||||
Canvas::Plugin.register('google_drive', :collaborations,
|
||||
{
|
||||
name: -> { t :name, 'Google Drive' },
|
||||
description: -> { t :description, 'Google Drive file sharing' },
|
||||
website: 'http://drive.google.com',
|
||||
author: 'Instructure',
|
||||
author_website: 'http://www.instructure.com',
|
||||
version: '1.0.0',
|
||||
settings_partial: 'plugins/google_drive_settings',
|
||||
validator: 'GoogleDriveValidator',
|
||||
encrypted_settings: [:client_secret]
|
||||
}
|
||||
)
|
||||
Canvas::Plugin.register('kaltura', nil, {
|
||||
:name => lambda{ t :name, 'Kaltura' },
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
#
|
||||
# Copyright (C) 2011 Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
module Canvas::Plugins::Validators::GoogleDocsValidator
|
||||
def self.validate(settings, plugin_setting)
|
||||
if settings.map(&:last).all?(&:blank?)
|
||||
{}
|
||||
else
|
||||
if settings.map(&:last).any?(&:blank?)
|
||||
plugin_setting.errors.add(:base, I18n.t('canvas.plugins.errors.all_fields_required', 'All fields are required'))
|
||||
false
|
||||
else
|
||||
res = GoogleDocs::Connection.config_check(settings)
|
||||
if res
|
||||
plugin_setting.errors.add(:base, res)
|
||||
false
|
||||
else
|
||||
settings.slice(:api_key, :secret_key)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -52,80 +52,6 @@ describe ApplicationController do
|
|||
end
|
||||
end
|
||||
|
||||
describe "#google_docs_connection" do
|
||||
it "uses @real_current_user first" do
|
||||
mock_real_current_user = mock()
|
||||
mock_current_user = mock()
|
||||
controller.instance_variable_set(:@real_current_user, mock_real_current_user)
|
||||
controller.instance_variable_set(:@current_user, mock_current_user)
|
||||
session[:oauth_gdocs_access_token_token] = "session_token"
|
||||
session[:oauth_gdocs_access_token_secret] = "sesion_secret"
|
||||
|
||||
Rails.cache.expects(:fetch).with(['google_docs_tokens', mock_real_current_user].cache_key).returns(["real_current_user_token", "real_current_user_secret"])
|
||||
|
||||
GoogleDocs::Connection.expects(:new).with("real_current_user_token", "real_current_user_secret")
|
||||
|
||||
controller.send(:google_docs_connection)
|
||||
end
|
||||
|
||||
it "uses @current_user second" do
|
||||
mock_current_user = mock()
|
||||
controller.instance_variable_set(:@real_current_user, nil)
|
||||
controller.instance_variable_set(:@current_user, mock_current_user)
|
||||
session[:oauth_gdocs_access_token_token] = "session_token"
|
||||
session[:oauth_gdocs_access_token_secret] = "sesion_secret"
|
||||
|
||||
Rails.cache.expects(:fetch).with(['google_docs_tokens', mock_current_user].cache_key).returns(["current_user_token", "current_user_secret"])
|
||||
|
||||
GoogleDocs::Connection.expects(:new).with("current_user_token", "current_user_secret")
|
||||
|
||||
controller.send(:google_docs_connection)
|
||||
end
|
||||
|
||||
it "queries user services if token isn't in the cache" do
|
||||
mock_current_user = mock()
|
||||
controller.instance_variable_set(:@real_current_user, nil)
|
||||
controller.instance_variable_set(:@current_user, mock_current_user)
|
||||
session[:oauth_gdocs_access_token_token] = "session_token"
|
||||
session[:oauth_gdocs_access_token_secret] = "sesion_secret"
|
||||
|
||||
mock_user_services = mock("mock_user_services")
|
||||
mock_current_user.expects(:user_services).returns(mock_user_services)
|
||||
mock_user_services.expects(:where).with(service: "google_docs").returns(stub(first: mock(token: "user_service_token", secret: "user_service_secret")))
|
||||
|
||||
GoogleDocs::Connection.expects(:new).with("user_service_token", "user_service_secret")
|
||||
|
||||
controller.send(:google_docs_connection)
|
||||
end
|
||||
|
||||
it "uses the session values if no users are set" do
|
||||
controller.instance_variable_set(:@real_current_user, nil)
|
||||
controller.instance_variable_set(:@current_user, nil)
|
||||
session[:oauth_gdocs_access_token_token] = "session_token"
|
||||
session[:oauth_gdocs_access_token_secret] = "sesion_secret"
|
||||
|
||||
GoogleDocs::Connection.expects(:new).with("session_token", "sesion_secret")
|
||||
|
||||
controller.send(:google_docs_connection)
|
||||
end
|
||||
|
||||
it "raises a NoTokenError when the user exists but does not have a user service" do
|
||||
mock_current_user = mock()
|
||||
controller.instance_variable_set(:@real_current_user, nil)
|
||||
controller.instance_variable_set(:@current_user, mock_current_user)
|
||||
session[:oauth_gdocs_access_token_token] = "session_token"
|
||||
session[:oauth_gdocs_access_token_secret] = "sesion_secret"
|
||||
|
||||
mock_user_services = mock("mock_user_services")
|
||||
mock_current_user.expects(:user_services).returns(mock_user_services)
|
||||
mock_user_services.expects(:where).with(service: "google_docs").returns(stub(first: nil))
|
||||
|
||||
expect {
|
||||
controller.send(:google_docs_connection)
|
||||
}.to raise_error(GoogleDocs::NoTokenError)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#google_drive_connection" do
|
||||
before :each do
|
||||
settings_mock = mock()
|
||||
|
@ -143,7 +69,7 @@ describe ApplicationController do
|
|||
|
||||
Rails.cache.expects(:fetch).with(['google_drive_tokens', mock_real_current_user].cache_key).returns(["real_current_user_token", "real_current_user_secret"])
|
||||
|
||||
GoogleDocs::DriveConnection.expects(:new).with("real_current_user_token", "real_current_user_secret", 30)
|
||||
GoogleDrive::Connection.expects(:new).with("real_current_user_token", "real_current_user_secret", 30)
|
||||
|
||||
controller.send(:google_drive_connection)
|
||||
end
|
||||
|
@ -157,7 +83,7 @@ describe ApplicationController do
|
|||
|
||||
Rails.cache.expects(:fetch).with(['google_drive_tokens', mock_current_user].cache_key).returns(["current_user_token", "current_user_secret"])
|
||||
|
||||
GoogleDocs::DriveConnection.expects(:new).with("current_user_token", "current_user_secret", 30)
|
||||
GoogleDrive::Connection.expects(:new).with("current_user_token", "current_user_secret", 30)
|
||||
controller.send(:google_drive_connection)
|
||||
end
|
||||
|
||||
|
@ -172,7 +98,7 @@ describe ApplicationController do
|
|||
mock_current_user.expects(:user_services).returns(mock_user_services)
|
||||
mock_user_services.expects(:where).with(service: "google_drive").returns(stub(first: mock(token: "user_service_token", secret: "user_service_secret")))
|
||||
|
||||
GoogleDocs::DriveConnection.expects(:new).with("user_service_token", "user_service_secret", 30)
|
||||
GoogleDrive::Connection.expects(:new).with("user_service_token", "user_service_secret", 30)
|
||||
controller.send(:google_drive_connection)
|
||||
end
|
||||
|
||||
|
@ -182,75 +108,12 @@ describe ApplicationController do
|
|||
session[:oauth_gdrive_refresh_token] = "session_token"
|
||||
session[:oauth_gdrive_access_token] = "sesion_secret"
|
||||
|
||||
GoogleDocs::DriveConnection.expects(:new).with("session_token", "sesion_secret", 30)
|
||||
GoogleDrive::Connection.expects(:new).with("session_token", "sesion_secret", 30)
|
||||
|
||||
controller.send(:google_drive_connection)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#google_drive_user_client" do
|
||||
before :each do
|
||||
settings_mock = mock()
|
||||
settings_mock.stubs(:settings).returns({})
|
||||
Canvas::Plugin.stubs(:find).returns(settings_mock)
|
||||
|
||||
end
|
||||
|
||||
let(:empty_client_secrets) do
|
||||
{
|
||||
client_id: nil,
|
||||
client_secret: nil,
|
||||
redirect_uri: nil
|
||||
}.with_indifferent_access
|
||||
end
|
||||
|
||||
it "uses @real_current_user first" do
|
||||
mock_real_current_user = mock()
|
||||
mock_current_user = mock()
|
||||
controller.instance_variable_set(:@real_current_user, mock_real_current_user)
|
||||
controller.instance_variable_set(:@current_user, mock_current_user)
|
||||
|
||||
Rails.cache.expects(:fetch).with(['google_drive_tokens', mock_real_current_user].cache_key).returns(["real_current_user_refresh_token", "real_current_user_access_token"])
|
||||
GoogleDrive::Client.expects(:create).with(empty_client_secrets,"real_current_user_refresh_token", "real_current_user_access_token")
|
||||
controller.send(:google_drive_user_client)
|
||||
end
|
||||
|
||||
it "uses @current_user second" do
|
||||
mock_current_user = mock()
|
||||
controller.instance_variable_set(:@real_current_user, nil)
|
||||
controller.instance_variable_set(:@current_user, mock_current_user)
|
||||
Rails.cache.expects(:fetch).with(['google_drive_tokens', mock_current_user].cache_key).returns(["current_user_refresh_token", "current_user_access_token"])
|
||||
GoogleDrive::Client.expects(:create).with(empty_client_secrets,"current_user_refresh_token", "current_user_access_token")
|
||||
controller.send(:google_drive_user_client)
|
||||
end
|
||||
|
||||
it "queries user services if token isn't in the cache" do
|
||||
mock_current_user = mock()
|
||||
controller.instance_variable_set(:@real_current_user, nil)
|
||||
controller.instance_variable_set(:@current_user, mock_current_user)
|
||||
|
||||
mock_user_services = mock("mock_user_services")
|
||||
mock_current_user.expects(:user_services).returns(mock_user_services)
|
||||
service_mock = mock('service')
|
||||
service_mock.stubs(first: mock(token: "user_refresh_token", access_token: "user_access_token"))
|
||||
mock_user_services.expects(:where).with(service: "google_drive").returns(service_mock)
|
||||
|
||||
GoogleDrive::Client.expects(:create).with(empty_client_secrets, "user_refresh_token", "user_access_token")
|
||||
|
||||
controller.send(:google_drive_user_client)
|
||||
end
|
||||
|
||||
it "uses the session values if no users are set" do
|
||||
controller.instance_variable_set(:@real_current_user, nil)
|
||||
controller.instance_variable_set(:@current_user, nil)
|
||||
session[:oauth_gdrive_access_token] = "access_token"
|
||||
session[:oauth_gdrive_refresh_token] = "refresh_token"
|
||||
|
||||
GoogleDrive::Client.expects(:create).with(empty_client_secrets, "refresh_token", "access_token")
|
||||
controller.send(:google_drive_user_client)
|
||||
end
|
||||
end
|
||||
|
||||
describe "js_env" do
|
||||
before do
|
||||
controller.stubs(:api_request?).returns(false)
|
||||
|
|
|
@ -184,30 +184,20 @@ describe AssignmentsController do
|
|||
assert_require_login
|
||||
end
|
||||
|
||||
it 'should not error out when google docs is not configured' do
|
||||
GoogleDocs::Connection.stubs(:config).returns nil
|
||||
user_session(@student)
|
||||
a = @course.assignments.create(:title => "some assignment")
|
||||
get 'show', :course_id => @course.id, :id => a.id
|
||||
GoogleDocs::Connection.unstub(:config)
|
||||
end
|
||||
|
||||
it 'should force users to use google drive if available' do
|
||||
it 'should set user_has_google_drive' do
|
||||
user_session(@student)
|
||||
a = @course.assignments.create(:title => "some assignment")
|
||||
plugin = Canvas::Plugin.find(:google_drive)
|
||||
plugin_setting = PluginSetting.find_by_name(plugin.id) || PluginSetting.new(:name => plugin.id, :settings => plugin.default_settings)
|
||||
plugin_setting.posted_settings = {}
|
||||
plugin_setting.save!
|
||||
google_docs_mock = mock('google_docs')
|
||||
google_docs_mock.stubs(:verify_access_token).returns(true)
|
||||
google_docs_mock.stubs(:service_type).returns(nil)
|
||||
google_docs_mock.stubs(:retrieve_access_token).returns(nil)
|
||||
controller.stubs(:google_service_connection).returns(google_docs_mock)
|
||||
google_drive_mock = mock('google_drive')
|
||||
google_drive_mock.stubs(:authorized?).returns(true)
|
||||
controller.stubs(:google_drive_connection).returns(google_drive_mock)
|
||||
get 'show', :course_id => @course.id, :id => a.id
|
||||
|
||||
expect(response).to be_success
|
||||
expect(assigns(:google_drive_upgrade)).to be_truthy
|
||||
expect(assigns(:user_has_google_drive)).to be true
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -366,7 +356,7 @@ describe AssignmentsController do
|
|||
user_session(@teacher)
|
||||
connection = stub()
|
||||
connection.stubs(:list_with_extension_filter).raises(ArgumentError)
|
||||
controller.stubs(:google_service_connection).returns(connection)
|
||||
controller.stubs(:google_drive_connection).returns(connection)
|
||||
Assignment.any_instance.stubs(:allow_google_docs_submission?).returns(true)
|
||||
Canvas::Errors.expects(:capture_exception)
|
||||
params = {course_id: @course.id, id: @assignment.id, format: 'json' }
|
||||
|
|
|
@ -42,34 +42,22 @@ describe CollaborationsController do
|
|||
|
||||
it "should assign variables" do
|
||||
user_session(@student)
|
||||
controller.stubs(:google_docs_connection).returns(mock(verify_access_token:true))
|
||||
controller.stubs(:google_drive_connection).returns(mock(authorized?:true))
|
||||
|
||||
get 'index', :course_id => @course.id
|
||||
|
||||
expect(response).to be_success
|
||||
expect(assigns(:google_docs_authorized)).to eq true
|
||||
expect(assigns(:user_has_google_drive)).to eq true
|
||||
end
|
||||
|
||||
it "should handle users without google authorized" do
|
||||
user_session(@student)
|
||||
controller.stubs(:google_docs_connection).returns(mock(verify_access_token:false))
|
||||
controller.stubs(:google_drive_connection).returns(mock(authorized?:false))
|
||||
|
||||
get 'index', :course_id => @course.id
|
||||
|
||||
expect(response).to be_success
|
||||
expect(assigns(:google_docs_authorized)).to eq false
|
||||
end
|
||||
|
||||
it "should assign variables when verify raises" do
|
||||
user_session(@student)
|
||||
google_docs_connection_mock = mock()
|
||||
google_docs_connection_mock.expects(:verify_access_token).raises("Error")
|
||||
controller.stubs(:google_docs_connection).returns(google_docs_connection_mock)
|
||||
|
||||
get 'index', :course_id => @course.id
|
||||
|
||||
expect(response).to be_success
|
||||
expect(assigns(:google_docs_authorized)).to eq false
|
||||
expect(assigns(:user_has_google_drive)).to eq false
|
||||
end
|
||||
|
||||
it 'handles users that need to upgrade to google_drive' do
|
||||
|
@ -81,8 +69,7 @@ describe CollaborationsController do
|
|||
get 'index', :course_id => @course.id
|
||||
|
||||
expect(response).to be_success
|
||||
expect(assigns(:google_docs_authorized)).to be_falsey
|
||||
expect(assigns(:google_drive_upgrade)).to be_truthy
|
||||
expect(assigns(:user_has_google_drive)).to be false
|
||||
end
|
||||
|
||||
it "should not allow the student view student to access collaborations" do
|
||||
|
@ -101,7 +88,7 @@ describe CollaborationsController do
|
|||
group = gc.groups.create!(:context => @course)
|
||||
group.add_user(@student, 'accepted')
|
||||
|
||||
#controller.stubs(:google_docs_connection).returns(mock(verify_access_token:false))
|
||||
#controller.stubs(:google_docs_connection).returns(mock(authorized?:false))
|
||||
|
||||
get 'index', :group_id => group.id
|
||||
expect(response).to be_success
|
||||
|
|
|
@ -197,14 +197,35 @@ describe SubmissionsController do
|
|||
end
|
||||
|
||||
it "should not send a comment to the entire group by default" do
|
||||
post 'create', :course_id => @course.id, :assignment_id => @assignment.id, :submission => {:submission_type => 'online_text_entry', :body => 'blah', :comment => "some comment"}
|
||||
post(
|
||||
'create',
|
||||
:course_id => @course.id,
|
||||
:assignment_id => @assignment.id,
|
||||
:submission => {
|
||||
:submission_type => 'online_text_entry',
|
||||
:body => 'blah',
|
||||
:comment => "some comment"
|
||||
}
|
||||
)
|
||||
|
||||
subs = @assignment.submissions
|
||||
expect(subs.size).to eq 2
|
||||
expect(subs.to_a.sum{ |s| s.submission_comments.size }).to eql 1
|
||||
end
|
||||
|
||||
it "should send a comment to the entire group if requested" do
|
||||
post 'create', :course_id => @course.id, :assignment_id => @assignment.id, :submission => {:submission_type => 'online_text_entry', :body => 'blah', :comment => "some comment", :group_comment => '1'}
|
||||
post(
|
||||
'create',
|
||||
:course_id => @course.id,
|
||||
:assignment_id => @assignment.id,
|
||||
:submission => {
|
||||
:submission_type => 'online_text_entry',
|
||||
:body => 'blah',
|
||||
:comment => "some comment",
|
||||
:group_comment => '1'
|
||||
}
|
||||
)
|
||||
|
||||
subs = @assignment.submissions
|
||||
expect(subs.size).to eq 2
|
||||
expect(subs.to_a.sum{ |s| s.submission_comments.size }).to eql 2
|
||||
|
@ -226,12 +247,13 @@ describe SubmissionsController do
|
|||
flag.save!
|
||||
mock_user_service = mock()
|
||||
@user.stubs(:user_services).returns(mock_user_service)
|
||||
mock_user_service.expects(:where).with(service: "google_docs").returns(stub(first: mock(token: "token", secret: "secret")))
|
||||
mock_user_service.expects(:where).with(service: "google_drive").
|
||||
returns(stub(first: mock(token: "token", secret: "secret")))
|
||||
end
|
||||
|
||||
it "should not save if domain restriction prevents it" do
|
||||
google_docs = mock
|
||||
GoogleDocs::Connection.expects(:new).returns(google_docs)
|
||||
GoogleDrive::Connection.expects(:new).returns(google_docs)
|
||||
|
||||
google_docs.expects(:download).returns([Net::HTTPOK.new(200, {}, ''), 'title', 'pdf'])
|
||||
post(:create, course_id: @course.id, assignment_id: @assignment.id,
|
||||
|
@ -338,7 +360,8 @@ describe SubmissionsController do
|
|||
|
||||
it "should allow setting 'student_entered_grade'" do
|
||||
course_with_student_logged_in(:active_all => true)
|
||||
@assignment = @course.assignments.create!(:title => "some assignment", :submission_types => "online_url,online_upload")
|
||||
@assignment = @course.assignments.create!(:title => "some assignment",
|
||||
:submission_types => "online_url,online_upload")
|
||||
@submission = @assignment.submit_homework(@user)
|
||||
put 'update', {
|
||||
:course_id => @course.id,
|
||||
|
@ -353,7 +376,8 @@ describe SubmissionsController do
|
|||
|
||||
it "should round 'student_entered_grade'" do
|
||||
course_with_student_logged_in(:active_all => true)
|
||||
@assignment = @course.assignments.create!(:title => "some assignment", :submission_types => "online_url,online_upload")
|
||||
@assignment = @course.assignments.create!(:title => "some assignment",
|
||||
:submission_types => "online_url,online_upload")
|
||||
@submission = @assignment.submit_homework(@user)
|
||||
put 'update', {
|
||||
:course_id => @course.id,
|
||||
|
|
|
@ -1352,26 +1352,6 @@ describe UsersController do
|
|||
end
|
||||
end
|
||||
|
||||
describe "oauth_success" do
|
||||
it "should use the access token to get user info" do
|
||||
|
||||
user_with_pseudonym
|
||||
admin = @user
|
||||
user_session(admin)
|
||||
|
||||
mock_oauth_request = stub(token: 'token', secret: 'secret', original_host_with_port: 'test.host', user: @user, return_url: '/')
|
||||
OauthRequest.expects(:where).with(token: 'token', service: 'google_docs').returns(stub(first: mock_oauth_request))
|
||||
|
||||
mock_access_token = stub(token: '123', secret: 'abc')
|
||||
GoogleDocs::Connection.expects(:get_access_token).with('token', 'secret', 'oauth_verifier').returns(mock_access_token)
|
||||
mock_google_docs = stub()
|
||||
GoogleDocs::Connection.expects(:new).with('token', 'secret').returns(mock_google_docs)
|
||||
mock_google_docs.expects(:get_service_user_info).with(mock_access_token)
|
||||
|
||||
get 'oauth_success', {oauth_token: 'token', service: 'google_docs', oauth_verifier: 'oauth_verifier'}, {host_with_port: 'test.host'}
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET media_download' do
|
||||
let(:kaltura_client) do
|
||||
kaltura_client = mock('CanvasKaltura::ClientV3').responds_like_instance_of(CanvasKaltura::ClientV3)
|
||||
|
|
|
@ -32,25 +32,6 @@ def valid_collaboration_attributes
|
|||
:context => @course || course_model,
|
||||
:url => "value for url",
|
||||
:title => "My Collaboration",
|
||||
:data => %{<?xml version="1.0" encoding="UTF-8"?>
|
||||
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:ns1="http://schemas.google.com/g/2005" xmlns:ns2="http://schemas.google.com/docs/2007">
|
||||
<title>Biology 100 Collaboration</title>
|
||||
<id>http://docs.google.com/feeds/documents/private/full/document%3Adc3pjs4r_3hhc6fvcc</id>
|
||||
<updated>2009-05-28T23:12:49Z</updated>
|
||||
<published>2009-05-28T23:12:49Z</published>
|
||||
<link href="http://docs.google.com/Doc?id=dc3pjs4r_3hhc6fvcc" rel="alternate" type="tex/html"/>
|
||||
<link href="http://docs.google.com/feeds/documents/private/full/document%3Adc3pjs4r_3hhc6fvcc" rel="self" type="application/atom+xml"/>
|
||||
<link href="http://docs.google.com/feeds/documents/private/full/document%3Adc3pjs4r_3hhc6fvcc/fva2z1b2" rel="edit" type="application/atom+xml"/>
|
||||
<link href="http://docs.google.com/feeds/media/private/full/document%3Adc3pjs4r_3hhc6fvcc/fva2z1b2" rel="edit-media" type="text/html"/>
|
||||
<author>
|
||||
<name>davidlamontrichards</name>
|
||||
<email>davidlamontrichards@gmail.com</email>
|
||||
</author>
|
||||
<category label="document" scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/docs/2007#document"/>
|
||||
<content/>
|
||||
<ns1:lastModifiedBy><name xmlns="http://www.w3.org/2005/Atom">davidlamontrichards</name><email xmlns="http://www.w3.org/2005/Atom">davidlamontrichards@gmail.com</email></ns1:lastModifiedBy>
|
||||
<ns1:feedLink/>
|
||||
<ns1:resourceId>document:dc3pjs4r_3hhc6fvcc</ns1:resourceId>n <ns2:writersCanInvite/>
|
||||
</entry>}
|
||||
:data => File.read('gems/google_drive/spec/fixtures/google_drive/file_data.json')
|
||||
}
|
||||
end
|
||||
|
|
|
@ -27,11 +27,11 @@ describe CollaborationsController, type: :request do
|
|||
course_with_teacher_logged_in :active_all => true, :name => "teacher 1"
|
||||
|
||||
UserService.register(
|
||||
:service => "google_docs",
|
||||
:service => "google_drive",
|
||||
:token => "token",
|
||||
:secret => "secret",
|
||||
:user => @user,
|
||||
:service_domain => "google.com",
|
||||
:service_domain => "drive.google.com",
|
||||
:service_user_id => "service_user_id",
|
||||
:service_user_name => "service_user_name"
|
||||
)
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
||||
|
||||
%w{ Twitter GoogleDocs LinkedIn }.each do |integration|
|
||||
%w{ Twitter LinkedIn }.each do |integration|
|
||||
describe integration do
|
||||
before do
|
||||
course_with_student_logged_in(:active_all => true)
|
||||
|
@ -28,8 +28,6 @@ describe integration do
|
|||
UsersController.any_instance.expects(:feature_and_service_enabled?).with(integration.underscore).returns(true)
|
||||
if integration == "LinkedIn"
|
||||
LinkedIn::Connection.expects(:config).at_least_once.returns({})
|
||||
elsif integration == "GoogleDocs"
|
||||
GoogleDocs::Connection.expects(:config).at_least_once.returns({})
|
||||
elsif integration == "Twitter"
|
||||
Twitter::Connection.expects(:config).at_least_once.returns({})
|
||||
else
|
||||
|
@ -97,9 +95,7 @@ describe integration do
|
|||
|
||||
# mock up the response from the 3rd party service, so we don't actually contact it
|
||||
OAuth::Consumer.any_instance.expects(:token_request).with(anything, anything, anything, has_entry(:oauth_verifier, "test_verifier"), anything).returns({:oauth_token => "test_token", :oauth_token_secret => "test_secret"})
|
||||
if integration == "GoogleDocs"
|
||||
GoogleDocs::Connection.any_instance.expects(:get_service_user_info).returns(["test_user_id", "test_user_name"])
|
||||
elsif integration == "LinkedIn"
|
||||
if integration == "LinkedIn"
|
||||
LinkedIn::Connection.any_instance.expects(:get_service_user_info).with(instance_of(OAuth::AccessToken)).returns(["test_user_id", "test_user_name"])
|
||||
elsif integration == "Twitter"
|
||||
Twitter::Connection.any_instance.expects(:get_service_user).returns(["test_user_id", "test_user_name"])
|
||||
|
@ -126,9 +122,7 @@ describe integration do
|
|||
OAuth::Consumer.any_instance.expects(:token_request).with(anything, anything, anything, has_entry(:oauth_verifier, "test_verifier"), anything).returns({:oauth_token => "test_token", :oauth_token_secret => "test_secret"})
|
||||
|
||||
# pretend that somehow we think we got a valid auth token, but we actually didn't
|
||||
if integration == "GoogleDocs"
|
||||
GoogleDocs::Connection.any_instance.expects(:get_service_user_info).raises(RuntimeError, "Third-party service totally like, failed")
|
||||
elsif integration == "LinkedIn"
|
||||
if integration == "LinkedIn"
|
||||
LinkedIn::Connection.any_instance.expects(:get_service_user_info).with(instance_of(OAuth::AccessToken)).raises(RuntimeError, "Third-party service totally like, failed")
|
||||
elsif integration == "Twitter"
|
||||
Twitter::Connection.any_instance.expects(:get_service_user).raises(RuntimeError, "Third-party service totally like, failed")
|
||||
|
|
|
@ -251,9 +251,17 @@ describe Account do
|
|||
end
|
||||
|
||||
it "should not wipe out services that are substrings of each other" do
|
||||
|
||||
AccountServices.register_service(
|
||||
:google_docs_prev,
|
||||
{
|
||||
:name => "My google docs prev", :description => "", :expose_to_ui => :service, :default => true
|
||||
}
|
||||
)
|
||||
|
||||
@a.disable_service('google_docs_previews')
|
||||
@a.disable_service('google_docs')
|
||||
expect(@a.allowed_services).to eq '-google_docs_previews,-google_docs'
|
||||
@a.disable_service('google_docs_prev')
|
||||
expect(@a.allowed_services).to eq '-google_docs_previews,-google_docs_prev'
|
||||
end
|
||||
|
||||
describe "services_exposed_to_ui_hash" do
|
||||
|
|
|
@ -27,7 +27,7 @@ describe Collaboration do
|
|||
|
||||
it "should allow google docs collaborations" do
|
||||
expect(Collaboration.collaboration_class('GoogleDocs')).to eql(nil)
|
||||
plugin_setting = PluginSetting.new(:name => "google_docs", :settings => {})
|
||||
plugin_setting = PluginSetting.new(:name => "google_drive", :settings => {})
|
||||
plugin_setting.save!
|
||||
expect(Collaboration.collaboration_class('GoogleDocs')).to eql(GoogleDocsCollaboration)
|
||||
plugin_setting.disabled = true
|
||||
|
@ -55,10 +55,9 @@ describe Collaboration do
|
|||
google_docs_collaboration_model
|
||||
end
|
||||
|
||||
it "should be able to parse the data stored as an Atom entry" do
|
||||
it "should be able to parse the data stored as JSON" do
|
||||
ae = @collaboration.parse_data
|
||||
expect(ae).to be_is_a(Atom::Entry)
|
||||
expect(ae.title).to eql('Biology 100 Collaboration')
|
||||
expect(ae['title']).to eql('Biology 100 Collaboration')
|
||||
end
|
||||
|
||||
it "should be able to get the title from the data" do
|
||||
|
|
|
@ -25,14 +25,11 @@ describe GoogleDocsCollaboration do
|
|||
google_docs_collaboration = GoogleDocsCollaboration.new
|
||||
google_docs_collaboration.title = "title"
|
||||
google_docs_collaboration.user = user
|
||||
google_doc_connection = stub(retrieve_access_token: "asdf123")
|
||||
|
||||
Canvas::Plugin.stubs(:find).with(:google_drive).returns(nil)
|
||||
GoogleDocs::Connection.expects(:new).returns(google_doc_connection)
|
||||
file = stub(document_id: 1, entry: stub(to_xml: "<xml></xml>"), alternate_url: "http://google.com")
|
||||
google_doc_connection.expects(:create_doc).with("title").returns(file)
|
||||
google_drive_connection = stub(retrieve_access_token: "asdf123")
|
||||
GoogleDrive::Connection.expects(:new).returns(google_drive_connection)
|
||||
file = stub(data: stub(id: 1, to_json: "{id: 1}", alternateLink: "http://google.com"))
|
||||
google_drive_connection.expects(:create_doc).with("title").returns(file)
|
||||
Rails.cache.expects(:fetch).returns(["token", "secret"])
|
||||
|
||||
google_docs_collaboration.initialize_document
|
||||
end
|
||||
end
|
||||
|
|
|
@ -140,10 +140,6 @@ describe UserService do
|
|||
end
|
||||
|
||||
context "service type disambiguation" do
|
||||
it "should know that google_docs means 'DocumentService" do
|
||||
expect(UserService.service_type('google_docs')).to eql('DocumentService')
|
||||
end
|
||||
|
||||
it "should know that google_drive means 'DocumentService" do
|
||||
expect(UserService.service_type('google_drive')).to eql('DocumentService')
|
||||
end
|
||||
|
|
|
@ -12,7 +12,7 @@ describe "assignments" do
|
|||
end
|
||||
|
||||
it "should not show google docs tab for masquerading admin" do
|
||||
PluginSetting.create!(:name => 'google_docs', :settings => {})
|
||||
PluginSetting.create!(:name => 'google_drive', :settings => {})
|
||||
get "/users/#{@student.id}/masquerade"
|
||||
expect_new_page_load { f('.masquerade_button').click }
|
||||
|
||||
|
|
|
@ -206,10 +206,9 @@ describe "assignments" do
|
|||
end
|
||||
|
||||
context "google drive" do
|
||||
before(:each) do
|
||||
PluginSetting.create!(:name => 'google_docs', :settings => {})
|
||||
before do
|
||||
PluginSetting.create!(:name => 'google_drive', :settings => {})
|
||||
set_up_google_docs()
|
||||
setup_google_drive()
|
||||
end
|
||||
|
||||
it "should have a google doc tab if google docs is enabled", priority: "1", test_id: 161884 do
|
||||
|
@ -224,16 +223,16 @@ describe "assignments" do
|
|||
context "select file or folder" do
|
||||
before(:each) do
|
||||
# mock out function calls
|
||||
google_service_connection = mock()
|
||||
google_service_connection.stubs(:service_type).returns('google_drive')
|
||||
google_service_connection.stubs(:retrieve_access_token).returns('access_token')
|
||||
google_service_connection.stubs(:verify_access_token).returns(true)
|
||||
google_drive_connection = mock()
|
||||
google_drive_connection.stubs(:service_type).returns('google_drive')
|
||||
google_drive_connection.stubs(:retrieve_access_token).returns('access_token')
|
||||
google_drive_connection.stubs(:authorized?).returns(true)
|
||||
|
||||
# mock files to show up from "google drive"
|
||||
file_list = create_file_list
|
||||
google_service_connection.stubs(:list_with_extension_filter).returns(file_list)
|
||||
google_drive_connection.stubs(:list_with_extension_filter).returns(file_list)
|
||||
|
||||
ApplicationController.any_instance.stubs(:google_service_connection).returns(google_service_connection)
|
||||
ApplicationController.any_instance.stubs(:google_drive_connection).returns(google_drive_connection)
|
||||
|
||||
# create assignment
|
||||
@assignment.update_attributes(:submission_types => 'online_upload')
|
||||
|
@ -261,11 +260,11 @@ describe "assignments" do
|
|||
|
||||
it "forces users to authenticate", priority: "1", test_id: 161892 do
|
||||
# stub out google drive
|
||||
google_service_connection = mock()
|
||||
google_service_connection.stubs(:service_type).returns('google_drive')
|
||||
google_service_connection.stubs(:retrieve_access_token).returns(nil)
|
||||
google_service_connection.stubs(:verify_access_token).returns(nil)
|
||||
ApplicationController.any_instance.stubs(:google_service_connection).returns(google_service_connection)
|
||||
google_drive_connection = mock()
|
||||
google_drive_connection.stubs(:service_type).returns('google_drive')
|
||||
google_drive_connection.stubs(:retrieve_access_token).returns(nil)
|
||||
google_drive_connection.stubs(:authorized?).returns(nil)
|
||||
ApplicationController.any_instance.stubs(:google_drive_connection).returns(google_drive_connection)
|
||||
|
||||
@assignment.update_attributes(:submission_types => 'online_upload')
|
||||
get "/courses/#{@course.id}/assignments/#{@assignment.id}"
|
||||
|
|
|
@ -16,7 +16,7 @@ describe "collaborations" do
|
|||
context "#{title} collaboration" do
|
||||
before(:each) do
|
||||
course_with_student_logged_in
|
||||
set_up_google_docs
|
||||
setup_google_drive
|
||||
end
|
||||
|
||||
it 'should display the new collaboration form if there are no existing collaborations', priority: "1", test_id: 162354 do
|
||||
|
|
|
@ -16,7 +16,7 @@ describe "collaborations" do
|
|||
context "#{title} collaboration" do
|
||||
before(:each) do
|
||||
course_with_teacher_logged_in
|
||||
set_up_google_docs
|
||||
setup_google_drive
|
||||
end
|
||||
|
||||
it 'should display the new collaboration form if there are no existing collaborations', priority: "1", test_id: 132521 do
|
||||
|
|
|
@ -16,7 +16,7 @@ describe "collaborations" do
|
|||
context "#{title} collaboration" do
|
||||
before(:each) do
|
||||
course_with_student_logged_in
|
||||
set_up_google_docs
|
||||
setup_google_drive
|
||||
end
|
||||
|
||||
it 'should be editable', priority: "1", test_id: 158504 do
|
||||
|
@ -39,7 +39,7 @@ describe "collaborations" do
|
|||
context "Google Docs collaborations with google docs not having access" do
|
||||
before(:each) do
|
||||
course_with_teacher_logged_in
|
||||
set_up_google_docs(false)
|
||||
setup_google_drive(false, false)
|
||||
end
|
||||
|
||||
it 'should not be editable if google drive does not have access to your account', priority: "1", test_id: 162363 do
|
||||
|
|
|
@ -16,7 +16,7 @@ describe "collaborations" do
|
|||
context "#{title} collaboration" do
|
||||
before(:each) do
|
||||
course_with_teacher_logged_in
|
||||
set_up_google_docs
|
||||
setup_google_drive
|
||||
end
|
||||
|
||||
it 'should be editable', priority: "1", test_id: 138612 do
|
||||
|
@ -39,7 +39,7 @@ describe "collaborations" do
|
|||
context "Google Docs collaborations with google docs not having access" do
|
||||
before(:each) do
|
||||
course_with_teacher_logged_in
|
||||
set_up_google_docs(false)
|
||||
setup_google_drive(false, false)
|
||||
end
|
||||
|
||||
it 'should not be editable if google drive does not have access to your account', priority: "1", test_id: 160259 do
|
||||
|
|
|
@ -64,34 +64,6 @@ describe "default plugins" do
|
|||
expect(settings[:name]).to eq 'asdf'
|
||||
end
|
||||
|
||||
it "should allow configuring google docs plugin" do
|
||||
settings = Canvas::Plugin.find(:google_docs).try(:settings)
|
||||
expect(settings).to be_nil
|
||||
|
||||
GoogleDocs::Connection.stubs(:config_check).returns("Bad check")
|
||||
get "/plugins/google_docs"
|
||||
|
||||
multiple_accounts_select
|
||||
f("#plugin_setting_disabled").click
|
||||
wait_for_ajaximations
|
||||
f("#settings_api_key").send_keys("asdf")
|
||||
f("#settings_secret_key").send_keys("asdf")
|
||||
submit_form('#new_plugin_setting')
|
||||
|
||||
assert_flash_error_message /There was an error/
|
||||
|
||||
GoogleDocs::Connection.stubs(:config_check).returns(nil)
|
||||
submit_form('#new_plugin_setting')
|
||||
wait_for_ajax_requests
|
||||
|
||||
assert_flash_notice_message /successfully updated/
|
||||
|
||||
settings = Canvas::Plugin.find(:google_docs).try(:settings)
|
||||
expect(settings).not_to be_nil
|
||||
expect(settings[:api_key]).to eq 'asdf'
|
||||
expect(settings[:secret_key]).to eq 'asdf'
|
||||
end
|
||||
|
||||
it "should allow configuring linked in plugin" do
|
||||
settings = Canvas::Plugin.find(:linked_in).try(:settings)
|
||||
expect(settings).to be_nil
|
||||
|
|
|
@ -306,9 +306,8 @@ describe "groups" do
|
|||
#-------------------------------------------------------------------------------------------------------------------
|
||||
describe "collaborations page" do
|
||||
before(:each) do
|
||||
set_up_google_docs
|
||||
unless PluginSetting.where(name: 'google_docs').exists?
|
||||
PluginSetting.create!(name: 'google_docs', settings: {})
|
||||
setup_google_drive
|
||||
unless PluginSetting.where(name: 'google_drive').exists?
|
||||
PluginSetting.create!(name: 'google_drive', settings: {})
|
||||
end
|
||||
end
|
||||
|
|
|
@ -48,15 +48,15 @@ module CollaborationsCommon
|
|||
# title - The title of the new collaboration (default: "New collaboration").
|
||||
#
|
||||
# Returns a boolean.
|
||||
def create_collaboration!(type, title = 'New collaboration')
|
||||
unless PluginSetting.where(:name => type).exists?
|
||||
PluginSetting.create!(:name => type, :settings => {})
|
||||
PluginSetting.create!(:name => 'google_drive', :settings => {}) if type == "google_docs"
|
||||
end
|
||||
# PluginSetting.where(:name => type).destroy_all
|
||||
# PluginSetting.where(:name => 'google_drive').destroy_all
|
||||
def create_collaboration!(collaboration_type, title = 'New collaboration')
|
||||
|
||||
name = Collaboration.collaboration_types.detect{|t| t[:type] == type}[:name]
|
||||
plugin_type = collaboration_type
|
||||
plugin_type = 'google_drive' if plugin_type == 'google_docs'
|
||||
unless PluginSetting.where(:name => plugin_type).exists?
|
||||
PluginSetting.create!(:name => plugin_type, :settings => {})
|
||||
end
|
||||
|
||||
name = Collaboration.collaboration_types.detect{|t| t[:type] == collaboration_type}[:name]
|
||||
|
||||
@collaboration = Collaboration.typed_collaboration_instance(name)
|
||||
@collaboration.context = @course
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
module CollaborationsSpecsCommon
|
||||
def new_collaborations_form(type)
|
||||
|
||||
def ensure_plugin(type)
|
||||
type = 'google_drive' if type == 'google_docs'
|
||||
PluginSetting.create!(:name => type, :settings => {})
|
||||
end
|
||||
|
||||
def new_collaborations_form(type)
|
||||
ensure_plugin(type)
|
||||
validate_collaborations
|
||||
end
|
||||
|
||||
|
@ -45,7 +51,7 @@ module CollaborationsSpecsCommon
|
|||
end
|
||||
|
||||
def display_available_collaborators(type)
|
||||
PluginSetting.create!(:name => type, :settings => {})
|
||||
ensure_plugin(type)
|
||||
|
||||
student_in_course(:course => @course)
|
||||
@student.update_attribute(:name, 'Don Draper')
|
||||
|
@ -56,7 +62,7 @@ module CollaborationsSpecsCommon
|
|||
end
|
||||
|
||||
def select_collaborators(type)
|
||||
PluginSetting.create!(:name => type, :settings => {})
|
||||
ensure_plugin(type)
|
||||
|
||||
student_in_course(:course => @course)
|
||||
@student.update_attribute(:name, 'Don Draper')
|
||||
|
@ -93,7 +99,7 @@ module CollaborationsSpecsCommon
|
|||
end
|
||||
|
||||
def deselect_collaborators(type)
|
||||
PluginSetting.create!(:name => type, :settings => {})
|
||||
ensure_plugin(type)
|
||||
|
||||
student_in_course(:course => @course)
|
||||
@student.update_attribute(:name, 'Don Draper')
|
||||
|
@ -106,7 +112,7 @@ module CollaborationsSpecsCommon
|
|||
end
|
||||
|
||||
def select_collaborators_and_look_for_start(type)
|
||||
PluginSetting.create!(:name => type, :settings => {})
|
||||
ensure_plugin(type)
|
||||
|
||||
collaboration_name = "StreetsOfRage"
|
||||
manually_create_collaboration(collaboration_name)
|
||||
|
@ -138,7 +144,7 @@ module CollaborationsSpecsCommon
|
|||
end
|
||||
|
||||
def display_new_form_if_none_exist(type)
|
||||
PluginSetting.create!(:name => type, :settings => {})
|
||||
ensure_plugin(type)
|
||||
validate_collaborations(%W{/courses/#{@course.id}/collaborations
|
||||
/courses/#{@course.id}/collaborations#add_collaboration}, true)
|
||||
end
|
||||
|
@ -157,7 +163,7 @@ module CollaborationsSpecsCommon
|
|||
end
|
||||
|
||||
def not_display_new_form_when_penultimate_collaboration_is_deleted(type, title)
|
||||
PluginSetting.create!(:name => type, :settings => {})
|
||||
ensure_plugin(type)
|
||||
|
||||
@collaboration1 = Collaboration.typed_collaboration_instance(title)
|
||||
@collaboration1.context = @course
|
||||
|
|
|
@ -1,23 +1,20 @@
|
|||
module GoogleDriveCommon
|
||||
def set_up_google_docs(setupDrive = true)
|
||||
def setup_google_drive(add_user_service=true, authorized=true)
|
||||
|
||||
|
||||
UserService.register(
|
||||
:service => "google_docs",
|
||||
:service => "google_drive",
|
||||
:token => "token",
|
||||
:secret => "secret",
|
||||
:user => @user,
|
||||
:service_domain => "google.com",
|
||||
:service_domain => "drive.google.com",
|
||||
:service_user_id => "service_user_id",
|
||||
:service_user_name => "service_user_name"
|
||||
)
|
||||
|
||||
GoogleDocs::Connection.any_instance.
|
||||
stubs(:verify_access_token).
|
||||
returns(true)
|
||||
|
||||
# GoogleDocs::Connection.any_instance.
|
||||
# stubs(:list).
|
||||
# returns(nil)
|
||||
) if add_user_service
|
||||
|
||||
GoogleDrive::Connection.any_instance.
|
||||
stubs(:authorized?).
|
||||
returns(authorized)
|
||||
|
||||
GoogleDocsCollaboration.any_instance.
|
||||
stubs(:initialize_document).
|
||||
|
@ -27,24 +24,5 @@ module GoogleDriveCommon
|
|||
stubs(:delete_document).
|
||||
returns(nil)
|
||||
|
||||
if setupDrive == true
|
||||
set_up_drive_connection
|
||||
end
|
||||
end
|
||||
|
||||
def set_up_drive_connection
|
||||
UserService.register(
|
||||
:service => "google_drive",
|
||||
:token => "token",
|
||||
:secret => "secret",
|
||||
:user => @user,
|
||||
:service_domain => "drive.google.com",
|
||||
:service_user_id => "service_user_id",
|
||||
:service_user_name => "service_user_name"
|
||||
)
|
||||
|
||||
GoogleDocs::DriveConnection.any_instance.
|
||||
stubs(:verify_access_token).
|
||||
returns(true)
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue