student_progress 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4d9dea94b9cd8654f0adc44aee02f20d47c2960550c225cdca11b83c83485d03
4
- data.tar.gz: d81aeaf2c9d5724ccb1f42ddc42b0c0fdd74716e734d580d9268c052b6f30ae0
3
+ metadata.gz: 429b3f920a6cba30aa9acc9f355dc9d9c68e1e2f1dc429b356645ccc0fcf4da3
4
+ data.tar.gz: 30097be3a7e0c598b58a52a04074499df3eeb49d243e099f8f04fc54de4d127c
5
5
  SHA512:
6
- metadata.gz: c52570801505fd77e3d6a3be41d9496f9307a538e811daa56c9f60a330e391ae6ce4872e2bd001bb2b13478130d496347217de541390f9b63f0081863327474a
7
- data.tar.gz: ee0dd4fc7f72210c1112405dc8f0d675236e04b7bf4637906c746e6a1cde7ed575cf38f86b3606289c6715679e0da681e599fdc93e6304a10eec957712cabf3e
6
+ metadata.gz: 46dd020fb09416d02df9a3d5ad11b92a8677da10a60a0d72d8f8173eb86f7b75268cbf8116344ae62977b12310d535b567136bbf467ced87d4161690a527b020
7
+ data.tar.gz: 65f7b13ade40d3a4ef3d4b159e34ed3efda6790162c8bea7a20c78f3859201e96a919bac16a04f9b6046dd784d2e063946d72d56141c74c4f91a1d18ab4733e6
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- student_progress (0.1.2)
4
+ student_progress (0.2.0)
5
5
  json
6
6
  nokogiri
7
7
  poltergeist
@@ -40,7 +40,7 @@ GEM
40
40
  method_source (~> 0.9.0)
41
41
  public_suffix (3.0.2)
42
42
  rack (2.0.5)
43
- rack-test (1.0.0)
43
+ rack-test (1.1.0)
44
44
  rack (>= 1.0, < 3)
45
45
  rake (10.5.0)
46
46
  rspec (3.7.0)
@@ -64,6 +64,29 @@ unless DB.table_exists? :students
64
64
  end
65
65
  end
66
66
 
67
+ unless DB.table_exists? :completed_lessons
68
+ DB.create_table :completed_lessons do
69
+ primary_key :id
70
+ Integer :lesson_id
71
+ end
72
+ end
73
+
74
+ unless DB[:completed_lessons].columns.include?(:date)
75
+ DB.add_column :completed_lessons, :date, :date
76
+ end
77
+
78
+ unless DB[:cohorts].columns.include?(:periscope_url)
79
+ DB.add_column :cohorts, :periscope_url, :string
80
+ end
81
+
82
+ unless DB[:completed_lessons].columns.include?(:student_id)
83
+ DB.add_column :completed_lessons, :student_id, :integer
84
+ end
85
+
86
+ unless DB[:student_reports].columns.include?(:current_topic_status)
87
+ DB.add_column :student_reports, :current_topic_status, :string
88
+ end
89
+
67
90
  require_relative "./student_progress/version"
68
91
  require_relative "./student_progress/cli"
69
92
  require_relative "./student_progress/student"
@@ -74,6 +97,8 @@ require_relative "./student_progress/topic"
74
97
  require_relative "./student_progress/unit"
75
98
  require_relative "./student_progress/student_report"
76
99
  require_relative "./student_progress/progress_report"
100
+ require_relative "./student_progress/progress_importer"
101
+ require_relative "./student_progress/completed_lesson"
77
102
 
78
103
 
79
104
  # module StudentProgress
@@ -1,7 +1,7 @@
1
1
  class StudentProgress::CLI
2
2
  def call
3
3
  puts "Hello from CLI"
4
- prompt_for_login
4
+ prompt_for_login
5
5
  StudentProgress::Scraper.scrape_lessons
6
6
  main_menu
7
7
  goodbye
@@ -14,7 +14,10 @@ class StudentProgress::CLI
14
14
  puts "\n"
15
15
  print "Password: "
16
16
  password = STDIN.noecho(&:gets).chomp
17
- StudentProgress::Scraper.login_user(email, password)
17
+ unless StudentProgress::Scraper.login_user(email, password)
18
+ prompt_for_login
19
+ end
20
+ true
18
21
  end
19
22
 
20
23
  def main_menu
@@ -48,7 +51,7 @@ class StudentProgress::CLI
48
51
 
49
52
  def list_choices
50
53
  puts "Choose an option below by number"
51
- puts "1. Select Cohort"
54
+ puts "1. Manage Cohorts"
52
55
  puts "2. Add Cohort"
53
56
  puts "3. Set goal for the week"
54
57
  puts "4. To view a list of past reports"
@@ -72,11 +75,86 @@ class StudentProgress::CLI
72
75
  puts "Whoops! Didn't understand that input"
73
76
  end
74
77
  end
75
- display_students
78
+ show_options_for_cohort
79
+ end
80
+
81
+ def show_options_for_cohort
82
+ puts "What would you like to do with the cohort?"
83
+ puts "1. Create Progress Report"
84
+ puts "2. Add a member(s) to the cohort"
85
+ puts "3. Remove a member from the cohort"
86
+ puts "4. Add a periscope URL to scrape progress from"
87
+ puts "5. Delete this cohort"
88
+ puts "type 'back' to return to the main menu or 'exit' to exit the CLI"
89
+ @input = gets.strip.downcase
90
+ return if ["back", "exit"].include?(@input)
91
+ case @input.to_i
92
+ when 1
93
+ display_students
94
+ when 2
95
+ add_students_to_cohort_view
96
+ when 3
97
+ remove_students_from_cohort_view
98
+ when 4
99
+ add_periscope_link_for_cohort_data
100
+ when 5
101
+ delete_this_cohort_view
102
+ else
103
+ puts "Whoops! didn't understand that input"
104
+ show_options_for_cohort
105
+ end
106
+ end
107
+
108
+ def add_students_to_cohort_view
109
+ puts "Enter the github usernames of the students you'd like to add as a comma separated list"
110
+ @input = gets.strip
111
+ return if ["back", "exit"].include?(@input.downcase)
112
+ usernames = @input.chomp.split(',').map(&:strip)
113
+ @selected_cohort.add_students(usernames)
114
+ puts "Just added #{usernames.count} students to your cohort"
115
+ puts "#{@selected_cohort.name} now has #{@selected_cohort.students.count} students"
116
+ show_options_for_cohort
76
117
  end
77
118
 
78
- def prompt_for_cohort_by_number
119
+ def remove_students_from_cohort_view
120
+ puts "Enter the github usernames of the students you'd like to remove as a comma separated list"
121
+ puts "Current usernames:"
122
+ puts @selected_cohort.students.collect{|s| s.github_username}.join(', ')
123
+ @input = gets.strip
124
+ return if ["back", "exit"].include?(@input.downcase)
125
+ usernames = @input.chomp.split(',').map(&:strip)
126
+ removed = @selected_cohort.remove_students(usernames)
127
+ puts "Just removed #{removed} students from the cohort"
128
+ puts "#{@selected_cohort.name} now has #{@selected_cohort.students.count} students"
129
+ show_options_for_cohort
130
+ end
131
+
132
+ def add_periscope_link_for_cohort_data
133
+ puts "Paste in the link to the periscope doc you'd like to use to import Cohort progress"
134
+ @input = gets.strip
135
+ @selected_cohort.periscope_url = @input
136
+ @selected_cohort.save
137
+ puts "Successfully added the periscope url to #{@selected_cohort.name}"
138
+ end
79
139
 
140
+ def delete_this_cohort_view
141
+ puts "Are you sure you want to delete the #{@selected_cohort.name} cohort?"
142
+ puts "type 'yes' to confirm or 'no' to go back to the cohort menu"
143
+ puts "You can also type 'back' to return to the main menu, or 'exit' to exit the CLI"
144
+ @input = gets.strip
145
+ return if ["back", "exit"].include?(@input.downcase)
146
+ case @input.downcase
147
+ when 'yes'
148
+ @selected_cohort.delete_and_unassign_students
149
+ @selected_cohort = nil
150
+ puts "cohort successfully deleted"
151
+ list_choices
152
+ when 'no'
153
+ show_options_for_cohort
154
+ else
155
+ puts "Whoops! Didn't understand that."
156
+ delete_this_cohort_view
157
+ end
80
158
  end
81
159
 
82
160
  def prompt_for_cohort_name
@@ -88,7 +166,7 @@ class StudentProgress::CLI
88
166
 
89
167
  def prompt_for_usernames
90
168
  puts "Please enter the GitHub usernames for the students you'd like info about (separated by commas)"
91
- usernames = gets.chomp.split(',').map(&:strip)
169
+ usernames = gets.chomp.split(',').map(&:strip).map(&:downcase)
92
170
  puts "Hang on a sec, adding #{usernames.count} students"
93
171
  @new_cohort.add_students(usernames)
94
172
  puts "All done!"
@@ -139,10 +217,11 @@ class StudentProgress::CLI
139
217
  output << "Students should #{@goal[:goal]} by the end of the week"
140
218
  output << "To do that, they'll have completed #{@goal[:lessons]} lessons and #{@goal[:labs]} labs"
141
219
  end
142
- headers = ['Student Name', 'Current Lab', 'Lessons', 'Labs']
220
+ headers = ['Student Name', 'Current Lab', 'Current Topic', 'Lessons', 'Labs']
143
221
  report = @selected_cohort.progress_reports.last
144
222
  rows = report.student_reports.collect.with_index(1) do |student_report|
145
- [student_report.student_name, student_report.current_lab, student_report.lessons_complete, student_report.labs_complete]
223
+ student_report.generate_current_topic_status
224
+ [student_report.student_name, student_report.current_lab, student_report.current_topic_status, student_report.lessons_complete, student_report.labs_complete]
146
225
  end
147
226
  table = Terminal::Table.new headings: headers, rows: rows
148
227
  output << table
@@ -3,10 +3,34 @@ class StudentProgress::Cohort < Sequel::Model
3
3
  one_to_many :progress_reports
4
4
  def add_students(usernames)
5
5
  usernames.each do |username|
6
- student = StudentProgress::Student.find_or_create(github_username: username)
7
- student.cohort_id = self.id
6
+ student = StudentProgress::Student.find_or_create(github_username: username.downcase)
7
+ self.add_student(student)
8
8
  student.save
9
9
  end
10
+ self.save
11
+ end
12
+
13
+ def remove_students(usernames)
14
+ removed = 0
15
+ usernames.each do |username|
16
+ student = self.students_dataset.first(github_username: username.downcase)
17
+ if student
18
+ self.remove_student(student)
19
+ removed += 1
20
+ else
21
+ puts "Student with github username: #{username} not found."
22
+ end
23
+ end
24
+ self.save
25
+ removed
26
+ end
27
+
28
+ def delete_and_unassign_students
29
+ students.each do |student|
30
+ student.cohort_id = nil
31
+ student.save
32
+ end
33
+ self.delete
10
34
  end
11
35
 
12
36
  def run_progress_report
@@ -0,0 +1,3 @@
1
+ class StudentProgress::CompletedLesson < Sequel::Model
2
+ many_to_one :student
3
+ end
@@ -53,6 +53,12 @@ class StudentProgress::Lesson
53
53
  lesson ? lesson.unit.title : "couldn't find that lesson"
54
54
  end
55
55
 
56
+ def self.topic_from_lesson_title(lesson_title)
57
+ lesson = @@all.find{ |l| l.title.strip == lesson_title.strip}
58
+ binding.pry unless lesson
59
+ lesson ? lesson.unit.topic : "couldn't find that lesson"
60
+ end
61
+
56
62
  def self.progress_when_unit_complete(unit_title)
57
63
  lessons = 0
58
64
  labs = 0
@@ -0,0 +1,42 @@
1
+ class StudentProgress::ProgressImporter
2
+ require 'csv'
3
+ require 'open-uri'
4
+
5
+ def self.import(url)
6
+ options = { headers: true, header_converters: :symbol }
7
+
8
+
9
+ csv_file = open(url)
10
+ content = File.new(csv_file)
11
+ CSV.foreach(content, options, &method(:create_and_associate_progress))
12
+
13
+ nil
14
+ end
15
+
16
+ def self.create_and_associate_progress(row)
17
+ # Example Row:
18
+ #<CSV::Row
19
+ # first_name:"Brennan"
20
+ # last_name:"Fulmer"
21
+ # deprecated_github_username:"BrennanFulmer"
22
+ # curriculum_id:"31648"
23
+ # completed_at:"2018-07-26 19:12:46.353279"
24
+ # track_id:"31303"
25
+ # title:"Rails Static Request"
26
+ # >
27
+ student = StudentProgress::Student.first(github_username: row[:deprecated_github_username].downcase)
28
+ lesson = StudentProgress::Lesson.find_by_id(row[:curriculum_id].to_i)
29
+ if student && lesson
30
+ if completed = StudentProgress::CompletedLesson.first(student_id: student.id, lesson_id: lesson.id)
31
+ return
32
+ else
33
+ completed = StudentProgress::CompletedLesson.create(student_id: student.id, lesson_id: lesson.id)
34
+ completed.date = row[:completed_at]
35
+ completed.save
36
+ end
37
+ else
38
+ binding.pry
39
+ end
40
+
41
+ end
42
+ end
@@ -1,5 +1,6 @@
1
1
  class StudentProgress::ProgressReport < Sequel::Model
2
2
  one_to_many :student_reports
3
+ many_to_one :cohort
3
4
 
4
5
  def on_track(labs_goal, cohort=nil)
5
6
  result = {}
@@ -14,4 +15,10 @@ class StudentProgress::ProgressReport < Sequel::Model
14
15
  end
15
16
  result
16
17
  end
18
+
19
+ def import_progress_from_periscope
20
+ if self.cohort.periscope_url
21
+ StudentProgress::ProgressImporter.import(self.cohort.periscope_url)
22
+ end
23
+ end
17
24
  end
@@ -9,7 +9,7 @@ class StudentProgress::Scraper
9
9
  end.each.with_index(1) do |username, index|
10
10
  @@session.visit("https://learn.co/#{username}")
11
11
  student = StudentProgress::Student.find_or_create(
12
- github_username: username
12
+ github_username: username.downcase
13
13
  )
14
14
  student.first_name = @@session.first('.media-block__content--fill').text.split("\n").first.split(' ').first
15
15
  student.last_name = @@session.first('.media-block__content--fill').text.split("\n").first.split(' ').slice(1)
@@ -22,9 +22,11 @@ class StudentProgress::Scraper
22
22
  student_id: student.id,
23
23
  progress_report_id: report.id
24
24
  )
25
-
26
25
  print "#{index}.."
27
26
  end
27
+ if cohort.periscope_url
28
+ StudentProgress::ProgressImporter.import(cohort.periscope_url)
29
+ end
28
30
  puts "Done!"
29
31
  end
30
32
 
@@ -37,6 +39,13 @@ class StudentProgress::Scraper
37
39
  puts "Signing in now..."
38
40
  sleep 0.5
39
41
  @@session.click_button "Sign in"
42
+ if @@session.current_path == "/account_check/failure" || @@session.current_path == "/"
43
+ puts "Invalid email or password"
44
+ puts "\n"
45
+ false
46
+ else
47
+ true
48
+ end
40
49
  end
41
50
 
42
51
  def self.scrape_lessons
@@ -1,6 +1,7 @@
1
1
  class StudentProgress::Student < Sequel::Model
2
2
  many_to_one :cohort
3
3
  one_to_many :student_reports
4
+ one_to_many :completed_lessons
4
5
 
5
6
  def current_lab
6
7
  student_reports.last.current_lab
@@ -5,4 +5,14 @@ class StudentProgress::StudentReport < Sequel::Model
5
5
  def student_name
6
6
  self.student && self.student.full_name
7
7
  end
8
+
9
+ def generate_current_topic_status
10
+ topic = StudentProgress::Lesson.topic_from_lesson_title(student.current_lab)
11
+ ratio = (topic.lessons.map(&:id) & student.completed_lessons.map(&:lesson_id)).length/topic.lessons.count.to_f
12
+ percent = (ratio*100).round(2)
13
+ status = student.cohort.periscope_url ? "#{topic.title}: #{percent}% complete" : "to track this, add perisocpe url to cohort"
14
+ self.current_topic_status = status
15
+ self.save
16
+ status
17
+ end
8
18
  end
@@ -1,3 +1,3 @@
1
1
  module StudentProgress
2
- VERSION = "0.1.2"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: student_progress
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dakota Martinez
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-07-21 00:00:00.000000000 Z
11
+ date: 2018-07-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -187,7 +187,9 @@ files:
187
187
  - lib/student_progress.rb
188
188
  - lib/student_progress/cli.rb
189
189
  - lib/student_progress/cohort.rb
190
+ - lib/student_progress/completed_lesson.rb
190
191
  - lib/student_progress/lesson.rb
192
+ - lib/student_progress/progress_importer.rb
191
193
  - lib/student_progress/progress_report.rb
192
194
  - lib/student_progress/scraper.rb
193
195
  - lib/student_progress/student.rb