marmoset 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+