remove unused twitter tables and no-op jobs
test plan: * edit course settings, there should not be an error * copy a course, there should not be an error Change-Id: I733bef83b69d9c513be801d3e4b25422bcd10ebd Reviewed-on: https://gerrit.instructure.com/13832 Tested-by: Jenkins <jenkins@instructure.com> Reviewed-by: Cody Cutrer <cody@instructure.com>
This commit is contained in:
parent
c508d0dab0
commit
d70945c1bd
|
@ -1,85 +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/>.
|
||||
#
|
||||
|
||||
class ShortMessagesController < ApplicationController
|
||||
before_filter :require_context
|
||||
include Twitter
|
||||
|
||||
def index
|
||||
if authorized_action(@context, @current_user, :read)
|
||||
@associations = @context.short_message_associations
|
||||
@hashtag = @context.hashtag_model rescue nil
|
||||
found = []
|
||||
@associations += @hashtag.short_message_associations if @hashtag
|
||||
@associations.map! do |a|
|
||||
res = (found.include?(a.short_message_id) || !a.short_message) ? nil : a
|
||||
found << a.short_message_id
|
||||
res
|
||||
end
|
||||
@associations = @associations.compact.sort_by{|m| m.short_message.created_at}.reverse
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
@association = @context.short_message_associations.new
|
||||
if authorized_action(@association, @current_user, :create)
|
||||
@association = @context.short_message_associations.create
|
||||
@message = ShortMessage.new(params[:short_message])
|
||||
@message.user = @current_user
|
||||
@message.save
|
||||
@association.short_message = @message
|
||||
@association.save
|
||||
# Don't add an association to the hashtags, since this will happen
|
||||
# via twitter_searcher if the twitterer wants it to be public
|
||||
send_twitter = params.delete(:send_twitter) == "1"
|
||||
respond_to do |format|
|
||||
if @association.valid? && @message.valid?
|
||||
if send_twitter && @current_user
|
||||
# begin
|
||||
res = twitter_send @message.message
|
||||
@message.service = "twitter"
|
||||
@message.service_message_id = res["id"]
|
||||
@message.service_user_name = res["user"]["screen_name"] rescue nil
|
||||
@message.save
|
||||
# rescue
|
||||
# end
|
||||
end
|
||||
format.json { render :json => @association.to_json(:include => :short_message, :permissions => {:user => @current_user, :session => session}) }
|
||||
elsif !@association.valid?
|
||||
format.json { render :json => @association.errors.to_json, :status => :bad_request }
|
||||
else
|
||||
format.json { render :json => @message.errors.to_json, :status => :bad_request }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@association = @context.short_message_associations.find_by_short_message_id(params[:id])
|
||||
if authorized_action(@association, @current_user, :delete)
|
||||
respond_to do |format|
|
||||
if @association.destroy
|
||||
format.json { render :json => @association.to_json(:include => :short_message) }
|
||||
else
|
||||
format.json { render :json => @association.errors.to_json, :status => :bad_request }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -1,20 +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 ShortMessagesHelper
|
||||
end
|
|
@ -51,7 +51,6 @@ module Context
|
|||
QuizSubmission = ::QuizSubmission
|
||||
Rubric = ::Rubric
|
||||
RubricAssociation = ::RubricAssociation
|
||||
ShortMessage = ::ShortMessage
|
||||
Submission = ::Submission
|
||||
WebConference = ::WebConference
|
||||
Wiki = ::Wiki
|
||||
|
|
|
@ -32,7 +32,6 @@ class Course < ActiveRecord::Base
|
|||
:publish_grades_immediately,
|
||||
:allow_student_wiki_edits,
|
||||
:allow_student_assignment_edits,
|
||||
:hashtag,
|
||||
:show_public_context_messages,
|
||||
:syllabus_body,
|
||||
:public_description,
|
||||
|
@ -155,8 +154,6 @@ class Course < ActiveRecord::Base
|
|||
has_many :rubric_associations, :as => :context, :include => :rubric, :dependent => :destroy
|
||||
has_many :collaborations, :as => :context, :order => 'title, created_at', :dependent => :destroy
|
||||
has_one :scribd_account, :as => :scribdable
|
||||
has_many :short_message_associations, :as => :context, :include => :short_message, :dependent => :destroy
|
||||
has_many :short_messages, :through => :short_message_associations, :dependent => :destroy
|
||||
has_many :grading_standards, :as => :context
|
||||
has_many :context_modules, :as => :context, :order => :position, :dependent => :destroy
|
||||
has_many :active_context_modules, :as => :context, :class_name => 'ContextModule', :conditions => {:workflow_state => 'active'}
|
||||
|
@ -589,7 +586,6 @@ class Course < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def assert_defaults
|
||||
Hashtag.find_or_create_by_hashtag(self.hashtag) if self.hashtag && self.hashtag != ""
|
||||
self.tab_configuration ||= [] unless self.tab_configuration == []
|
||||
self.name = nil if self.name && self.name.strip.empty?
|
||||
self.name ||= t('missing_name', "Unnamed Course")
|
||||
|
@ -773,10 +769,6 @@ class Course < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
def hashtag_model
|
||||
Hashtag.find_by_hashtag(self.hashtag) if self.hashtag
|
||||
end
|
||||
|
||||
workflow do
|
||||
state :created do
|
||||
event :claim, :transitions_to => :claimed
|
||||
|
@ -2244,7 +2236,7 @@ class Course < ActiveRecord::Base
|
|||
def self.clonable_attributes
|
||||
[ :group_weighting_scheme, :grading_standard_id, :is_public,
|
||||
:publish_grades_immediately, :allow_student_wiki_edits,
|
||||
:allow_student_assignment_edits, :hashtag, :show_public_context_messages,
|
||||
:allow_student_assignment_edits, :show_public_context_messages,
|
||||
:syllabus_body, :allow_student_forum_attachments,
|
||||
:default_wiki_editing_roles, :allow_student_organized_groups,
|
||||
:default_view, :show_all_discussion_entries, :open_enrollment,
|
||||
|
|
|
@ -54,8 +54,6 @@ class Group < ActiveRecord::Base
|
|||
has_many :web_conferences, :as => :context, :dependent => :destroy
|
||||
has_many :collaborations, :as => :context, :order => 'title, created_at', :dependent => :destroy
|
||||
has_one :scribd_account, :as => :scribdable
|
||||
has_many :short_message_associations, :as => :context, :include => :short_message, :dependent => :destroy
|
||||
has_many :short_messages, :through => :short_message_associations, :dependent => :destroy
|
||||
has_many :media_objects, :as => :context
|
||||
has_many :zip_file_imports, :as => :context
|
||||
has_many :collections, :as => :context
|
||||
|
|
|
@ -1,72 +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/>.
|
||||
#
|
||||
|
||||
class Hashtag < ActiveRecord::Base
|
||||
has_many :short_message_associations, :as => :context
|
||||
has_many :short_messages, :through => :short_message_associations
|
||||
|
||||
attr_accessible :hashtag
|
||||
|
||||
before_save :infer_defaults
|
||||
|
||||
def infer_defaults
|
||||
self.refresh_at ||= Time.now.utc
|
||||
end
|
||||
protected :infer_defaults
|
||||
|
||||
def user_contexts
|
||||
res = {}
|
||||
contexts.each do |context|
|
||||
context.users.each do |user|
|
||||
res[user.id] ||= []
|
||||
res[user.id] << context
|
||||
end
|
||||
end
|
||||
res
|
||||
end
|
||||
|
||||
def contexts
|
||||
Group.with_hashtag(self.hashtag) + Course.with_hashtag(self.hashtag)
|
||||
end
|
||||
|
||||
def add_short_message(user, result, public=false)
|
||||
message = ShortMessage.find_by_service_message_id_and_service(result["id"], 'twitter')
|
||||
user ||= UserService.find_by_service_user_name_and_service(result["from_user"], "twitter").user rescue nil
|
||||
message ||= ShortMessage.create(
|
||||
:service_message_id => result["id"],
|
||||
:service => "twitter",
|
||||
:user => user,
|
||||
:message => result["text"],
|
||||
:created_at => Time.parse(result["created_at"]),
|
||||
:service_user_name => result["from_user"]
|
||||
)
|
||||
message.is_public ||= public
|
||||
message.save
|
||||
|
||||
self.short_message_associations.find_or_create_by_short_message_id(message.id) if public
|
||||
contexts = user_contexts[user.id] if user
|
||||
contexts ||= []
|
||||
contexts.each do |context|
|
||||
context.short_message_associations.find_or_create_by_short_message_id(message.id)
|
||||
end
|
||||
end
|
||||
|
||||
named_scope :to_be_polled, lambda {
|
||||
{ :conditions => ['hashtags.refresh_at <= ?', Time.now ], :order => :refresh_at, :limit => 1 }
|
||||
}
|
||||
end
|
|
@ -1,27 +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/>.
|
||||
#
|
||||
|
||||
class ShortMessage < ActiveRecord::Base
|
||||
attr_accessible :message, :user, :author_name, :is_public, :service_message_id, :service, :service_user_name
|
||||
has_many :short_message_associations, :dependent => :destroy
|
||||
belongs_to :user
|
||||
|
||||
def author_name
|
||||
self.user ? self.user.name : self.service_user_name
|
||||
end
|
||||
end
|
|
@ -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/>.
|
||||
#
|
||||
|
||||
class ShortMessageAssociation < ActiveRecord::Base
|
||||
attr_accessible :context, :short_message
|
||||
belongs_to :short_message
|
||||
belongs_to :context, :polymorphic => true
|
||||
|
||||
|
||||
set_policy do
|
||||
given {|user, session| self.context.grants_rights?(user, session, :read)[:read] }
|
||||
can :read
|
||||
|
||||
given {|user, session| self.context.grants_right?(user, session, :participate_as_student) }
|
||||
can :read and can :create
|
||||
|
||||
given {|user, session| user && self.short_message && self.short_message.user_id == user.id }
|
||||
can :read and can :delete
|
||||
|
||||
given {|user, session| self.context.grants_rights?(user, session, :manage)[:manage] }
|
||||
can :read and can :create and can :delete
|
||||
end
|
||||
end
|
|
@ -472,10 +472,6 @@ class User < ActiveRecord::Base
|
|||
end
|
||||
protected :assign_uuid
|
||||
|
||||
def hashtag
|
||||
nil
|
||||
end
|
||||
|
||||
named_scope :with_service, lambda { |service|
|
||||
if service.is_a?(UserService)
|
||||
{:include => :user_services, :conditions => ['user_services.service = ?', service.service]}
|
||||
|
@ -919,7 +915,7 @@ class User < ActiveRecord::Base
|
|||
'calendar_events','collaborations',
|
||||
'context_module_progressions','discussion_entries','discussion_topics',
|
||||
'enrollments','group_memberships','page_comments',
|
||||
'rubric_assessments','short_messages',
|
||||
'rubric_assessments',
|
||||
'submission_comment_participants','user_services','web_conferences',
|
||||
'web_conference_participants','wiki_pages'].each do |key|
|
||||
updates[key] = "user_id"
|
||||
|
|
|
@ -50,17 +50,6 @@
|
|||
<% end %>
|
||||
<span class="course_info name"><%= @context.name %></span>
|
||||
</td>
|
||||
<% if feature_and_service_enabled?(:twitter) %>
|
||||
<td class="hashtag_form" style="<%= hidden unless @context.hashtag && @context.hashtag != "" %> vertical-align: top;"><%= f.blabel :hashtag, :en => "Hashtag" %></td>
|
||||
<td class="hashtag_form" style="<%= hidden unless @context.hashtag && @context.hashtag != "" %> width: 60%;">
|
||||
<%= f.text_field :hashtag, :class => "course_form" %>
|
||||
<span class="course_info" id="course_hashtag"><%= @context.hashtag %></span>
|
||||
<div style="font-size: 0.8em;" id="hashtag_options"><span class="course_form">
|
||||
<%= f.check_box :show_public_context_messages %>
|
||||
<%= f.label :show_public_context_messages, :en => "collect public messages for this hashtag" %>
|
||||
</span></div>
|
||||
</td>
|
||||
<% end %>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="nobr"><%= f.blabel :course_code, :en => "Course Code" %></td>
|
||||
|
@ -72,33 +61,6 @@
|
|||
<% end %>
|
||||
<span class="course_info course_code"><%= @context.course_code %></span>
|
||||
</td>
|
||||
<% if feature_and_service_enabled?(:twitter) %>
|
||||
<td colspan="2" style=" display: none; padding-left: 10px;"><span class="course_form" style="font-size: 0.8em;">
|
||||
<a href="#" class="hashtag_dialog_link help"> <%= t('links.hashtag_help', %{What's a hashtag?}) %></a>
|
||||
<div id="hashtag_dialog" style="display: none; font-size: 0.8em;">
|
||||
<%= image_tag "twitter.png", :style => "float: left; margin: 10px;" %>
|
||||
<%= mt 'help.hashtags', %{Hashtags are special phrases that let people consistently mention the same idea (like a course) on web sites like Twitter. For example, the message "I like #instructure" is using the hashtag "instructure".
|
||||
|
||||
Hashtags should consist of letters, numbers, dashes and underscores (no spaces). The hashtag should be unique, easily recognizable, and short. Short hashtags are better since sites like Twitter limit the number of letters per message.}%>
|
||||
<p><%= before_label('examples', %{Examples}) %><br/>
|
||||
<table style="margin-left: 20px;"><tr>
|
||||
<td><%= before_label('too_general_twitter_hashtag.description', %{too general}) %></td>
|
||||
<td><b> <%= t('too_general_twitter_hashtag.example', %{#biology}) %></b></td>
|
||||
</tr><tr>
|
||||
<td><%= before_label('too_long_twitter_hashtag.description', %{too long}) %></td>
|
||||
<td><b> <%= t('too_long_twitter_hashtag.example', %{#san-fransisco-university-biology-100}) %></b></td>
|
||||
</tr><tr>
|
||||
<td><%= before_label('good_twitter_hashtag.description', %{much better}) %></td>
|
||||
<td><b> <%= t('good_twitter_hashtag.example', %{#sfu-bio100}) %></b></td>
|
||||
</tr></table>
|
||||
</p>
|
||||
<div class="button-container">
|
||||
<button type="button" class="close_dialog_button button"><%= t('buttons.kthxbai', %{Cool, Thanks}) %></button>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</td>
|
||||
<% end %>
|
||||
<% if @context.sis_source_id && can_do(@context.root_account, @current_user, :read_sis) || can_do(@context.root_account, @current_user, :manage_sis) %>
|
||||
</tr><tr>
|
||||
<td><%= f.blabel :sis_source_id, :en => "SIS ID" %></td>
|
||||
|
|
|
@ -27,7 +27,7 @@ class ActiveRecord::Base
|
|||
'calendar_events' => %w(calendar_event_repeat_id for_repeat_on),
|
||||
'content_tags' => %w(sequence_position context_module_association_id),
|
||||
'course_sections' => %w(sis_cross_listed_section_id sis_cross_listed_section_sis_batch_id sticky_xlist sis_name students_can_participate_before_start_at section_organization_name long_section_code),
|
||||
'courses' => %w(section hidden_tabs sis_name sis_course_code),
|
||||
'courses' => %w(section hidden_tabs sis_name sis_course_code hashtag),
|
||||
'discussion_topics' => %w(authorization_list_id),
|
||||
'enrollment_terms' => %w(sis_data sis_name),
|
||||
'enrollments' => %w(invitation_email can_participate_before_start_at limit_priveleges_to_course_sections),
|
||||
|
|
|
@ -52,13 +52,6 @@ Delayed::Periodic.cron 'CrocodocDocument.update_process_states', '*/5 * * * *' d
|
|||
end
|
||||
end
|
||||
|
||||
Delayed::Periodic.cron 'Twitter processing', '*/15 * * * *' do
|
||||
Shard.with_each_shard do
|
||||
TwitterSearcher.process
|
||||
TwitterUserPoller.process
|
||||
end
|
||||
end
|
||||
|
||||
Delayed::Periodic.cron 'Reporting::CountsReport.process', '0 11 * * *' do
|
||||
Reporting::CountsReport.process
|
||||
end
|
||||
|
|
|
@ -268,7 +268,6 @@ ActionController::Routing::Routes.draw do |map|
|
|||
end
|
||||
|
||||
course.resources :collaborations
|
||||
course.resources :short_messages
|
||||
|
||||
course.resources :gradebook_uploads
|
||||
course.resources :rubrics
|
||||
|
@ -411,7 +410,6 @@ ActionController::Routing::Routes.draw do |map|
|
|||
add_conferences(group)
|
||||
add_media(group)
|
||||
group.resources :collaborations
|
||||
group.resources :short_messages
|
||||
group.old_calendar 'calendar', :controller => 'calendars', :action => 'show'
|
||||
group.profile 'profile', :controller => :groups, :action => 'profile', :conditions => {:method => :get}
|
||||
end
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
class DropHashtags < ActiveRecord::Migration
|
||||
tag :postdeploy
|
||||
|
||||
def self.up
|
||||
drop_table :short_message_associations
|
||||
drop_table :short_messages
|
||||
drop_table :hashtags
|
||||
remove_column :courses, :hashtag
|
||||
end
|
||||
|
||||
def self.down
|
||||
add_column :courses, :hashtag, :string
|
||||
|
||||
create_table "hashtags" do |t|
|
||||
t.string "hashtag"
|
||||
t.datetime "refresh_at"
|
||||
t.string "last_result_id"
|
||||
t.timestamps
|
||||
end
|
||||
|
||||
create_table "short_messages" do |t|
|
||||
t.string "message"
|
||||
t.integer "user_id", :limit => 8
|
||||
t.string "author_name"
|
||||
t.timestamps
|
||||
t.boolean "is_public", :default => false
|
||||
t.string "service_message_id"
|
||||
t.string "service"
|
||||
t.string "service_user_name"
|
||||
end
|
||||
|
||||
add_index "short_messages", ["user_id"]
|
||||
|
||||
create_table "short_message_associations" do |t|
|
||||
t.integer "context_id", :limit => 8
|
||||
t.string "context_type"
|
||||
t.integer "short_message_id", :limit => 8
|
||||
t.timestamps
|
||||
end
|
||||
|
||||
add_index "short_message_associations", ["context_id", "context_type"]
|
||||
add_index "short_message_associations", ["short_message_id"]
|
||||
end
|
||||
end
|
|
@ -50,7 +50,7 @@ module CC::Importer::Canvas
|
|||
return course unless doc
|
||||
course[:migration_id] = get_node_att(doc, 'course', 'identifier')
|
||||
|
||||
['title', 'course_code', 'hashtag', 'default_wiki_editing_roles',
|
||||
['title', 'course_code', 'default_wiki_editing_roles',
|
||||
'turnitin_comments', 'default_view', 'license', 'locale',
|
||||
'group_weighting_scheme', 'storage_quota', 'grading_standard_identifier_ref'].each do |string_type|
|
||||
val = get_node_val(doc, string_type)
|
||||
|
|
|
@ -1,85 +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/>.
|
||||
#
|
||||
|
||||
class TwitterSearcher
|
||||
REFRESH_INTERVAL = 30.minutes
|
||||
REFRESH_INTERVAL_EMPTY = 60.minutes
|
||||
MAX_TAGS_PER_PROCESS = 100
|
||||
|
||||
def self.process
|
||||
TwitterSearcher.new.process
|
||||
end
|
||||
|
||||
def initialize
|
||||
@logger = RAILS_DEFAULT_LOGGER
|
||||
end
|
||||
|
||||
def process
|
||||
count = 0
|
||||
while hashtag = Hashtag.to_be_polled.first and (count += 1) < MAX_TAGS_PER_PROCESS
|
||||
hashtag.refresh_at = Time.now.utc + REFRESH_INTERVAL
|
||||
hashtag.save
|
||||
|
||||
require 'net/http'
|
||||
@logger.info("hashtag found: #{hashtag} -- requesting public twitter search")
|
||||
url = "http://search.twitter.com/search.json?q=%23#{CGI::escape(hashtag.hashtag)}&rpp=25"
|
||||
url += "&since_id=#{hashtag.last_result_id}" if hashtag.last_result_id
|
||||
url = URI.parse url
|
||||
@logger.info("request url: #{url}")
|
||||
http = Net::HTTP.new(url.host, url.port)
|
||||
request = Net::HTTP::Get.new(url.path + (url.query ? ('?' + url.query) : ''))
|
||||
response = http.request(request)
|
||||
case response
|
||||
when Net::HTTPSuccess
|
||||
@logger.info('request succeeded')
|
||||
begin
|
||||
results = ActiveSupport::JSON.decode(response.body)["results"]
|
||||
@logger.info("found #{results.length} results")
|
||||
since_id = results[0]["id"] rescue nil
|
||||
results.each do |result|
|
||||
hashtag.add_short_message(nil, result, true)
|
||||
end
|
||||
hashtag.last_result_id = since_id if since_id
|
||||
hashtag.refresh_at = Time.now.utc + (results.empty? ? REFRESH_INTERVAL_EMPTY : REFRESH_INTERVAL)
|
||||
hashtag.save
|
||||
@logger.info('results successfully added')
|
||||
rescue => e
|
||||
ErrorReport.log_exception(:processing, e, {
|
||||
:message => e.to_s,
|
||||
:url => (request.url rescue "none")
|
||||
})
|
||||
@logger.info("** unexpected error: #{e.to_s}")
|
||||
@logger.info(e.backtrace)
|
||||
end
|
||||
else
|
||||
@logger.info("throttled! Retry after: #{response['Retry-After']}")
|
||||
|
||||
# TODO: This assumes that Retry-After will always be sent as delta-seconds. We should probably support HTTP-date too:
|
||||
# http://webee.technion.ac.il/labs/comnet/netcourse/CIE/RFC/2068/201.htm
|
||||
wait_time = response['Retry-After'].to_i if response['Retry-After']
|
||||
hashtag.refresh_at = Time.now.utc + wait_time
|
||||
hashtag.save
|
||||
end
|
||||
end
|
||||
|
||||
if count >= MAX_TAGS_PER_PROCESS
|
||||
@logger.info("more hashtags to process... scheduling another job")
|
||||
TwitterSearcher.send_later_engueue_args(:process, { :priority => Delayed::LOW_PRIORITY })
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,94 +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/>.
|
||||
#
|
||||
|
||||
class TwitterUserPoller
|
||||
REFRESH_INTERVAL = 30.minutes
|
||||
REFRESH_INTERVAL_EMPTY = 60.minutes
|
||||
MAX_PER_PROCESS = 100
|
||||
|
||||
include Twitter
|
||||
|
||||
def self.process
|
||||
TwitterUserPoller.new.process
|
||||
end
|
||||
|
||||
def initialize
|
||||
@logger = RAILS_DEFAULT_LOGGER
|
||||
end
|
||||
|
||||
def retrieve_tweets(service, attempt=0)
|
||||
@twitter_service = service
|
||||
twitter_list(nil, service.last_result_id)
|
||||
end
|
||||
|
||||
def process
|
||||
count = 0
|
||||
|
||||
while service = UserService.to_be_polled.for_service('twitter').first and (count += 1) < MAX_PER_PROCESS
|
||||
service.updated_at = Time.now.utc
|
||||
service.save
|
||||
|
||||
@logger.info("user found: #{service.service_user_name} retrieving tweets...")
|
||||
since_id = nil
|
||||
count = 0
|
||||
tweets = nil
|
||||
begin
|
||||
tweets = retrieve_tweets(service)
|
||||
rescue => e
|
||||
retry_after = REFRESH_INTERVAL_EMPTY
|
||||
if e.to_s =~ /Retry After (\d+)/
|
||||
retry_after = $1
|
||||
@logger.info("throttled! Retry after: #{retry_after}")
|
||||
else
|
||||
ErrorReport.log_exception(:processing, e, {
|
||||
:message => e.to_s,
|
||||
:url => (request.url rescue "none")
|
||||
})
|
||||
@logger.info("unexpected error: #{e.to_s} #{e.backtrace.join "\n"}")
|
||||
end
|
||||
retry_after = [REFRESH_INTERVAL_EMPTY, retry_after.to_i].max
|
||||
service.refresh_at = Time.now.utc + retry_after + 1.minute
|
||||
service.save
|
||||
end
|
||||
|
||||
if tweets
|
||||
@logger.info("found #{tweets.length} tweets")
|
||||
tweets.each do |tweet|
|
||||
scans = (tweet['text'] || '').scan(/#([^#\s])/)
|
||||
@logger.info("message found: #{tweet['id']} with #{scans.length} hashtags")
|
||||
scans.each do |scan|
|
||||
hash = scan[0]
|
||||
if hashtag = Hashtag.find_by_hashtag(hash)
|
||||
hashtag.add_short_message(service.user, tweet, false)
|
||||
@logger.info("added for #{hash}")
|
||||
end
|
||||
end
|
||||
since_id ||= tweet['id'] if tweet['id']
|
||||
end
|
||||
service.last_result_id = since_id if since_id
|
||||
service.refresh_at = Time.now.utc + (since_id ? REFRESH_INTERVAL : REFRESH_INTERVAL_EMPTY)
|
||||
service.save
|
||||
end
|
||||
end
|
||||
|
||||
if count >= MAX_PER_PROCESS
|
||||
@logger.info("more services to process... scheduling another job")
|
||||
TwitterUserPoller.send_later_engueue_args(:process, { :priority => Delayed::LOW_PRIORITY })
|
||||
end
|
||||
end
|
||||
end
|
|
@ -115,8 +115,6 @@ define([
|
|||
var $add_section_form = $("#add_section_form"),
|
||||
$edit_section_form = $("#edit_section_form"),
|
||||
$course_form = $("#course_form"),
|
||||
$hashtag_form = $(".hashtag_form"),
|
||||
$course_hashtag = $("#course_hashtag"),
|
||||
$enrollment_dialog = $("#enrollment_dialog"),
|
||||
$tabBar = $("#course_details_tabs"),
|
||||
// as of jqueryui 1.9, the cookie trumps the fragment :(. so we hack
|
||||
|
@ -253,23 +251,6 @@ define([
|
|||
axis: 'y'
|
||||
}).disableSelection();
|
||||
|
||||
|
||||
$(".hashtag_dialog_link").click(function(event) {
|
||||
event.preventDefault();
|
||||
$("#hashtag_dialog").dialog({
|
||||
title: I18n.t('titles.hashtag_help', "What's a Hashtag?"),
|
||||
width: 500
|
||||
});
|
||||
});
|
||||
$(".close_dialog_button").click(function() {
|
||||
$("#hashtag_dialog").dialog('close');
|
||||
});
|
||||
$("#course_hashtag").bind('blur change keyup', function() {
|
||||
var val = $(this).val() || "";
|
||||
val = val.replace(/(\s)+/g, "_").replace(/#/, "");
|
||||
$("#hashtag_options").showIf(val && val !== "");
|
||||
$(this).val(val);
|
||||
});
|
||||
$(document).fragmentChange(function(event, hash) {
|
||||
function handleFragmentType(val){
|
||||
$("#tab-users-link").click();
|
||||
|
@ -293,8 +274,6 @@ define([
|
|||
$("#course_account_id").val(ui.item.id);
|
||||
}
|
||||
});
|
||||
$hashtag_form.showIf($course_hashtag.text().length > 0);
|
||||
$course_hashtag.triggerHandler('blur');
|
||||
});
|
||||
$(".move_course_link").click(function(event) {
|
||||
event.preventDefault();
|
||||
|
@ -311,7 +290,6 @@ define([
|
|||
}).change();
|
||||
$course_form.formSubmit({
|
||||
processData: function(data) {
|
||||
data['course[hashtag]'] = (data['course[hashtag]'] || "").replace(/\s/g, "_").replace(/#/g, "");
|
||||
if(data['course[start_at]']) {
|
||||
data['course[start_at]'] += " 12:00am";
|
||||
}
|
||||
|
@ -348,7 +326,6 @@ define([
|
|||
$(this).text($.replaceTags($(this).text(), 'self_enrollment_code', course.self_enrollment_code));
|
||||
});
|
||||
}
|
||||
$(".hashtag_form").showIf($("#course_hashtag").text().length > 0);
|
||||
},
|
||||
error: function(data) {
|
||||
$(this).loadingImage('remove');
|
||||
|
@ -359,7 +336,6 @@ define([
|
|||
.find(".cancel_button")
|
||||
.click(function() {
|
||||
$course_form.removeClass('editing');
|
||||
$hashtag_form.showIf($course_hashtag.text().length > 0);
|
||||
$(".course_form_more_options").hide();
|
||||
}).end()
|
||||
.find(":text:not(.date_entry)").keycodes('esc', function() {
|
||||
|
|
|
@ -105,7 +105,6 @@ describe ContentMigration do
|
|||
@copy_from.publish_grades_immediately = false
|
||||
@copy_from.allow_student_wiki_edits = true
|
||||
@copy_from.allow_student_assignment_edits = true
|
||||
@copy_from.hashtag = 'oi'
|
||||
@copy_from.show_public_context_messages = false
|
||||
@copy_from.allow_student_forum_attachments = false
|
||||
@copy_from.default_wiki_editing_roles = 'teachers'
|
||||
|
|
Loading…
Reference in New Issue