Class: Oncourse::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/oncourse/client.rb

Overview

<user_id>

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(username, password, request_rate = 1) ⇒ Client

create new mechanize object and go through login steps



21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/oncourse/client.rb', line 21

def initialize(username,password,request_rate=1)
  @request_rate = request_rate
  @mech = Mechanize.new()
   = @mech.get(URLS[:main])
   = .forms.first
  .Username = username
  .Password = password.strip
  home_page = .submit
  script_tag = home_page.parser.search("script").select{|s| s.text.index('user_id')}.first
  raise "Login failed, script_tag not present." unless script_tag
  @user_id = /\"user_id\":\"([0-9]+)\"/.match(script_tag.text).captures.first
  raise "Login failed, unable to find user_id" unless @user_id
end

Instance Attribute Details

#lesson_treeObject

Returns the value of attribute lesson_tree.



18
19
20
# File 'lib/oncourse/client.rb', line 18

def lesson_tree
  @lesson_tree
end

#mechObject

Returns the value of attribute mech.



18
19
20
# File 'lib/oncourse/client.rb', line 18

def mech
  @mech
end

#request_rateObject

Returns the value of attribute request_rate.



18
19
20
# File 'lib/oncourse/client.rb', line 18

def request_rate
  @request_rate
end

#user_idObject

Returns the value of attribute user_id.



18
19
20
# File 'lib/oncourse/client.rb', line 18

def user_id
  @user_id
end

#weeksObject

Returns the value of attribute weeks.



18
19
20
# File 'lib/oncourse/client.rb', line 18

def weeks
  @weeks
end

Instance Method Details

#fix_malformed_json(malformed_json) ⇒ Object

oncourse produces a lot of malformed json. It seems to strip the quotes off strings on deeply nested objects. Not sure what they’re doing wrong, since I don’t think the problem is with ext3



146
147
148
# File 'lib/oncourse/client.rb', line 146

def fix_malformed_json(malformed_json)
  return malformed_json.gsub(/([a-z][a-zA-Z0-9_]+):(?!\s)/, '"\1":')
end


199
200
201
202
203
204
205
206
207
208
209
# File 'lib/oncourse/client.rb', line 199

def link_standard(standard_id, date, period)
  response = @mech.post(URLS[:link_standards], {
    objectType: "L",
    id: standard_id,
    date: date.strftime("%m/%d/%Y"),
    period: period,
    link: true
  })

  return JSON.parse(response.content)
end

#post_lesson(lesson, homework, date, period) ⇒ Object

This method will absolutely overwrite anything that occupies this place in the lesson plan. To play it safe, one should call read_lesson and store that response somewhere before using post lesson. This way there is a backup of previous work. Oncourse does not appear to keep a revision history on lesson plans.



228
229
230
231
232
233
234
235
236
237
# File 'lib/oncourse/client.rb', line 228

def post_lesson(lesson, homework, date, period)
  response = @mech.post(URLS[:post_lesson], {
    userId: @user_id,
    date: date.strftime("%m/%d/%Y"),
    period: period,
    notes: lesson,
    homework: homework
  })
  return response
end

#rate_pauseObject



90
91
92
# File 'lib/oncourse/client.rb', line 90

def rate_pause
  sleep((1 + rand(0.1)) * @request_rate)
end

#read_lesson(date, period) ⇒ Object

method to read one lesson through the json interface This is required before posting a lesson since it’s the only way to get the homework field that I’ve found. If you post an empty homework field, any previous homework entry will be lost



122
123
124
125
126
127
128
129
# File 'lib/oncourse/client.rb', line 122

def read_lesson(date, period)
  response = @mech.post(URLS[:read_lesson], {
    userId: @user_id,
    date: date.strftime("%m/%d/%Y"),
    period: period
  })
  return JSON.parse(response.content)["ReturnValue"]
end

#read_lesson_standard_filters(set_id, subject) ⇒ Object

reads filters that must be applied after selecting first child group



172
173
174
175
176
# File 'lib/oncourse/client.rb', line 172

def read_lesson_standard_filters(set_id, subject)
  response = @mech.post(URLS[:lesson_standard_filters], {setId: set_id, subject: subject})

  return JSON.parse(response.content)
end

#read_lesson_standards_tree(set_id, subject, grade, year) ⇒ Object

Reads a full list of standards for a given SetID, subject, grade, and year



179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/oncourse/client.rb', line 179

def read_lesson_standards_tree(set_id, subject, grade, year)
  response = @mech.post(URLS[:lesson_standards_tree], {
    userId: @user_id,
    setId: set_id,
    subject: subject,
    yearName: year,
    searchText1: "",
    searchOperator: "",
    searchText2: "",
    powerSetID: "",
    mapID: "",
    grade: grade,
    showOnlyPowerSet: false,
    activityDate: Date.today.strftime("%m/%d/%Y"), # seems arbitrary
    activityPeriod: 1 # arbitrary
  })

  return JSON.parse(response.content)
end

#read_lesson_treeObject



131
132
133
134
135
136
137
138
139
140
141
# File 'lib/oncourse/client.rb', line 131

def read_lesson_tree()
  return @lesson_tree if @lesson_tree
  response = @mech.post(URLS[:lesson_tree], {userId: @user_id})

  # oncourse returns invalid JSON, using this ugly regex for now.
  fixed_json = fix_malformed_json(response.content)

  @lesson_tree = JSON.parse(fixed_json)

  return @lesson_tree
end

#read_planner(start_date, num_weeks) ⇒ Object

read lesson planner for current user starting at start_Date: start_date and going each week up to num_weeks



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/oncourse/client.rb', line 37

def read_planner(start_date, num_weeks)
  @weeks = []
  start = start_date
  cell_ids = 0
  itr = 0
  num_weeks.times do
    start += itr * 7
    week = {start: start.strftime("%Y%m%d")}
    week[:columns] = []

    # a get request to this set_planner url sets the current viewed planner
    @mech.get(URLS[:set_planner], {date: week[:start], user_id: @user_id, template:'N'})
    rate_pause()

    planner_frame = @mech.get(URLS[:get_planner])

    # parse out column headers
    columns = planner_frame.parser.search("tr.sheetRowHeader th:not(.sheetRow1stCell)").each_with_index.map{|cell, idx| {label: cell.text.strip, period: idx + 1}}

    # parse out each cell, ids give date and period.
    # Period corresponds to column number.
    # .lessonPreview classes contain the markup and content created by ext3's text editor
    # that teachers use to input lessons.
    cells = planner_frame.parser.search(".sheetCell")
    cells = cells.map do |cell|
      cell_hash = {
        date: cell['id'][0...-2],
        period: cell['id'][-2..-1].to_i,
        html: cell.search('.lessonPreview').first.inner_html
      }
      flag_element = cell.search('.sheetCellIcons img[src="/images/icons/flag_blue.png"]').first
      if(flag_element)
        match = /showStandard\(\'([0-9]+)\'\)/.match(flag_element['onclick'])
        if(match && match.captures.first)
          cell_hash[:standards_id] = match.captures.first
        end
      end
      cell_hash
    end
    columns.each do |column|
      column[:cells] = cells.select{|cell| cell[:period] == column[:period]}
    end

    week[:columns] = columns

    @weeks << week
    itr += 1
    rate_pause()
  end

  return @weeks
end

#read_planner_standardsObject



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/oncourse/client.rb', line 94

def read_planner_standards()
  raise "planner weeks empty" if !@weeks || @weeks.length == 0
  keys = ["id", "header_name", "detail_name"]
  @weeks.each do |week|
    week[:columns].each do |column|
      column[:cells].each do |cell|
        next unless cell[:standards_id]

        json_response = @mech.post(URLS[:lesson_standards], {
          id: cell[:standards_id]
        })

        cell[:standards] = JSON.parse(json_response.content).map{|f| f.reject{|k,v| !keys.include?(k)}}
        rate_pause()
      end
    end
  end
  return @weeks
end

#read_standard_areas(set_id) ⇒ Object

reads first child group of standards



165
166
167
168
169
# File 'lib/oncourse/client.rb', line 165

def read_standard_areas(set_id)
  response = @mech.post(URLS[:standard_areas], {setId: set_id})

  return JSON.parse(fix_malformed_json(response.content))
end

#read_standard_groupsObject

read parent groups for standards



151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/oncourse/client.rb', line 151

def read_standard_groups()
  read_lesson_tree unless @lesson_tree

  #have to traverse a big json tree here
  standards_branch = @lesson_tree.find{|branch| branch["text"] == "Standards"}
  return standards_branch["children"].map do |child|
    {
      label: child["text"],
      set_id: child["xconfig"]["setId"]
    }
  end
end

#save_planner(filename) ⇒ Object



114
115
116
# File 'lib/oncourse/client.rb', line 114

def save_planner(filename)
  File.open(filename, "w") { |f| f.puts JSON.pretty_generate(@weeks)}
end


211
212
213
214
215
216
217
218
219
220
221
# File 'lib/oncourse/client.rb', line 211

def unlink_standard(standard_id, date, period)
  response = @mech.post(URLS[:link_standards], {
    objectType: "L",
    id: standard_id,
    date: date.strftime("%m/%d/%Y"),
    period: period,
    link: false
  })

  return JSON.parse(response.content)
end