marmoset 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. data/bin/marmoset +189 -0
  2. metadata +115 -0
data/bin/marmoset ADDED
@@ -0,0 +1,189 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'mechanize'
5
+ require 'highline/import'
6
+ require 'choice'
7
+
8
+ HighLine.track_eof = false
9
+
10
+ class MarmosetClient
11
+ class InvalidLogin < StandardError; end
12
+ class CourseNotFound < StandardError; end
13
+ class ProblemNotFound < StandardError; end
14
+
15
+ def initialize(opts)
16
+ @agent = Mechanize.new
17
+ @course_index_page = nil
18
+ @course_page = nil
19
+ @submit_page = nil
20
+
21
+ @filename = opts[:filename]
22
+ @username = opts[:username]
23
+ @password = opts[:password]
24
+ @course = opts[:course]
25
+ @problem = opts[:problem]
26
+ end
27
+
28
+ def login
29
+ @username ||= ask("Username: ")
30
+ @password ||= ask("Password: ") {|q| q.echo = '*'}
31
+
32
+ say "Logging in ..."
33
+
34
+ login_page = @agent.get 'https://marmoset.student.cs.uwaterloo.ca/'
35
+ form = login_page.forms.first
36
+
37
+ form.username = @username
38
+ form.password = @password
39
+
40
+ login_submit_page = @agent.submit form
41
+
42
+ if login_submit_page.uri.to_s.include? 'cas.uwaterloo.ca'
43
+ raise InvalidLogin
44
+ end
45
+
46
+ @course_index_page = @agent.submit login_submit_page.forms.first
47
+ rescue InvalidLogin
48
+ say 'Invalid Username/Password'
49
+ exit
50
+ end
51
+
52
+ def select_course
53
+ say "Select course ..."
54
+ login if @course_index_page.nil?
55
+
56
+ course_links = @course_index_page.links.find_all do |l|
57
+ l.href.include? 'course.jsp'
58
+ end
59
+
60
+ if @course.nil?
61
+ choose do |menu|
62
+ course_links.each do |course_link|
63
+ menu.choice(course_link.text.strip) do
64
+ @course = course_link.text.strip
65
+ @course_page = course_link.click
66
+ end
67
+ end
68
+ end
69
+ else
70
+ course_link = course_links.find do |l|
71
+ l.text.downcase.include? @course.downcase
72
+ end
73
+ raise CourseNotFound if course_link.nil?
74
+
75
+ @course_page = course_link.click
76
+ end
77
+ rescue CourseNotFound
78
+ say "Course #{@course} could not be found."
79
+ options = course_links.collect{|x| x.text.gsub(/\([^\)]+\):/,'').strip}
80
+ say "Options are: #{options.sort.join(', ')}"
81
+ exit
82
+ end
83
+
84
+ def select_problem
85
+ say "Selecting problem ..."
86
+ select_course if @course_page.nil?
87
+
88
+ problem_links = {}
89
+
90
+ @course_page.links.find_all{|l| l.href.include? 'submitProject.jsp'}.each do |view_link|
91
+ index = @course_page.links.find_index{|l| l.href == view_link.href}
92
+ named_link = @course_page.links[index-2]
93
+ problem_links[named_link.text] = view_link
94
+ end
95
+
96
+ if @problem.nil?
97
+ choose do |menu|
98
+ problem_links.each do |(name,problem_link)|
99
+ menu.choice(name.strip) do
100
+ @problem = name
101
+ @submit_page = problem_page.click
102
+ end
103
+ end
104
+ end
105
+ else
106
+ problem_link = problem_links.find{|(prob_name,link)|
107
+ prob_name.downcase.include? @problem.downcase
108
+ }
109
+ raise ProblemNotFound if problem_link.nil?
110
+
111
+ problem_link = problem_link[1]
112
+ @submit_page = problem_link.click
113
+ end
114
+ rescue ProblemNotFound
115
+ say "Problem #{@problem} could not be found in #{@course}"
116
+ say "Options are: #{problem_links.collect{|x| x[0].strip}.sort.join(', ')}"
117
+ exit
118
+ end
119
+
120
+ def submit_problem
121
+ say "Submitting ..."
122
+ select_problem if @submit_page.nil?
123
+
124
+ form = @submit_page.forms.first
125
+ @submit_page.forms.first.file_uploads.first.file_name = @filename
126
+ @submit_response_page = @agent.submit(form)
127
+ say "Assignment submitted succesfully"
128
+ rescue Mechanize::ResponseCodeError => e
129
+ say "There was a problem submitting your assignment. Submit manually"
130
+ end
131
+ end
132
+
133
+ PROGRAM_VERSION = 1.0
134
+
135
+ Choice.options do
136
+ option :username do
137
+ short '-u'
138
+ long '--username=USERNAME'
139
+ desc 'Your Quest userid, e.g. jlfwong'
140
+ default nil
141
+ end
142
+
143
+ option :password do
144
+ short '-p'
145
+ long '--password=PASSWORD'
146
+ desc 'Your Quest password. Will be prompted if not specified'
147
+ default nil
148
+ end
149
+
150
+ option :course do
151
+ short '-c'
152
+ long '--course-code=COURSECODE'
153
+ desc 'Course ID, e.g. CS241'
154
+ default nil
155
+ end
156
+
157
+ option :problem do
158
+ short '-a'
159
+ long '--assignment-problem=PROB'
160
+ desc 'Assignment problem name, e.g. A1P4'
161
+ end
162
+
163
+ option :filename, :required => true do
164
+ short '-f'
165
+ long '--infile=FILENAME'
166
+ desc 'The file to submit to marmoset'
167
+ end
168
+
169
+ option :help do
170
+ long '--help'
171
+ desc 'Show this message'
172
+ end
173
+
174
+ option :version do
175
+ short '-v'
176
+ long '--version'
177
+ desc 'Show Version'
178
+ action do
179
+ puts "#{File.basename(__FILE__)} Marmoset CLI v#{PROGRAM_VERSION}"
180
+ exit
181
+ end
182
+ end
183
+ end
184
+
185
+ client = MarmosetClient.new(Choice.choices)
186
+ client.login
187
+ client.select_course
188
+ client.select_problem
189
+ client.submit_problem
metadata ADDED
@@ -0,0 +1,115 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: marmoset
3
+ version: !ruby/object:Gem::Version
4
+ hash: 21
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 1
10
+ version: 1.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Jamie Wong
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-09-21 00:00:00 -04:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: highline
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 13
30
+ segments:
31
+ - 1
32
+ - 6
33
+ - 1
34
+ version: 1.6.1
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: mechanize
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 23
46
+ segments:
47
+ - 1
48
+ - 0
49
+ - 0
50
+ version: 1.0.0
51
+ type: :runtime
52
+ version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: choice
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ hash: 19
62
+ segments:
63
+ - 0
64
+ - 1
65
+ - 4
66
+ version: 0.1.4
67
+ type: :runtime
68
+ version_requirements: *id003
69
+ description: A utility using highline, mechanize and choice to submit to UW Marmoset from the command line
70
+ email:
71
+ - jamie.lf.wong@gmail.com
72
+ executables:
73
+ - marmoset
74
+ extensions: []
75
+
76
+ extra_rdoc_files: []
77
+
78
+ files:
79
+ - bin/marmoset
80
+ has_rdoc: true
81
+ homepage: http://github.com/phleet/MarmosetSubmit
82
+ licenses: []
83
+
84
+ post_install_message:
85
+ rdoc_options: []
86
+
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ hash: 3
95
+ segments:
96
+ - 0
97
+ version: "0"
98
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
+ none: false
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ hash: 3
104
+ segments:
105
+ - 0
106
+ version: "0"
107
+ requirements: []
108
+
109
+ rubyforge_project:
110
+ rubygems_version: 1.3.7
111
+ signing_key:
112
+ specification_version: 3
113
+ summary: Submit to UW Marmoset from the command line
114
+ test_files: []
115
+