moodleQuizDownloader 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +42 -0
- data/Rakefile +1 -0
- data/bin/moodleQuizDownloader.rb +4 -0
- data/lib/moodleQuizDownloader.rb +16 -0
- data/lib/moodleQuizDownloader/file_name_creator.rb +12 -0
- data/lib/moodleQuizDownloader/moodle_parser.rb +61 -0
- data/lib/moodleQuizDownloader/option_handler.rb +104 -0
- data/lib/moodleQuizDownloader/quiz_downloader.rb +78 -0
- data/lib/moodleQuizDownloader/version.rb +3 -0
- data/moodleQuizDownloader.gemspec +31 -0
- data/spec/api/asciify_spec.rb +8 -0
- data/spec/api/pdfkit_spec.rb +21 -0
- data/spec/fileNameCreator_spec.rb +19 -0
- data/spec/moodleparsing/exam-overview-moodle-ss2013.html +358 -0
- data/spec/moodleparsing/exam-overview.html +233 -0
- data/spec/moodleparsing/moodleparsing_spec.rb +53 -0
- data/spec/moodleparsing/review-page-nutzerbild.html +278 -0
- data/spec/moodleparsing/review-page.html +239 -0
- data/spec/option_handler_spec.rb +127 -0
- metadata +175 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a8c17d2cdd565630203b2eaacaaf27fe47fe3110
|
4
|
+
data.tar.gz: de31f285dd09c3cfd339c01a3761067169f08bbf
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5d2fa647058a7534f13518b88ab538d1a195a57090f8293b4803b4044b134e256d20a396c2ac8a85d1d130fdea9c3ca88eb64dd3ca2424966062dfd72855470f
|
7
|
+
data.tar.gz: b862718b20c6ae363765f1dae1d6ac1b97104375f87d20af8b471f46605a791f96f77fc6cae2c2f0565c5fdcfd76992820f84353fdde8cf49abe296bba71fb99
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Dr Blinken
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# MoodleQuizDownloader
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'moodleQuizDownloader'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install moodleQuizDownloader
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
for example, run
|
22
|
+
|
23
|
+
$ moodleQuizDownloader.rb -e 4711 -u drblinken -s http://moodle2.htw-berlin.de/ -p geheim --verbose
|
24
|
+
|
25
|
+
to see a list of all attempts in exam 4711 on the specified server,
|
26
|
+
and
|
27
|
+
|
28
|
+
$ moodleQuizDownloader.rb -e 4711 -u drblinken -s http://moodle2.htw-berlin.de/ -p geheim --verbose download
|
29
|
+
|
30
|
+
to download them.
|
31
|
+
|
32
|
+
to see all options:
|
33
|
+
|
34
|
+
$ moodleQuizDownloader.rb help
|
35
|
+
|
36
|
+
## Contributing
|
37
|
+
|
38
|
+
1. Fork it
|
39
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
40
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
41
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
42
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require_relative "moodleQuizDownloader/version.rb"
|
2
|
+
require_relative "moodleQuizDownloader/option_handler.rb"
|
3
|
+
require_relative "moodleQuizDownloader/quiz_downloader.rb"
|
4
|
+
|
5
|
+
module MoodleQuizDownloader
|
6
|
+
def run_script(arguments)
|
7
|
+
options = OptionHandler.new(arguments).parse
|
8
|
+
if options.usage
|
9
|
+
puts options.usage
|
10
|
+
exit
|
11
|
+
end
|
12
|
+
QuizDownloader.new.run(options)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module MoodleParser
|
2
|
+
@@user_view_regexp = Regexp.new('http://moodle2.htw-berlin.de/moodle/user/view.php')
|
3
|
+
|
4
|
+
def moodle_login_page(server)
|
5
|
+
"#{server}/moodle/login/index.php"
|
6
|
+
end
|
7
|
+
def moodle_item(server)
|
8
|
+
"#{server}/moodle/mod/quiz/view.php?id="
|
9
|
+
end
|
10
|
+
def moodle_quiz_report(server)
|
11
|
+
"#{server}/moodle/mod/quiz/report.php?mode=overview&id="
|
12
|
+
end
|
13
|
+
|
14
|
+
def login(agent,moodle_login_page,moodle_username,moodle_password)
|
15
|
+
puts "++++#{moodle_login_page}"
|
16
|
+
page = agent.get(moodle_login_page)
|
17
|
+
form = page.forms[1]
|
18
|
+
form.username = moodle_username
|
19
|
+
form.password = moodle_password
|
20
|
+
page = form.submit
|
21
|
+
end
|
22
|
+
|
23
|
+
def selectReviewLinks(page)
|
24
|
+
page.links.select do |ll|
|
25
|
+
cls = ll.attributes.attributes['class']
|
26
|
+
cls && cls.value == 'reviewlink'
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def extract_attempt_list(page)
|
31
|
+
i = 1
|
32
|
+
result_list = []
|
33
|
+
while page.at("//*[@id=\"attempts\"]/tbody/tr[#{i}]/td[3]/a[1]") do
|
34
|
+
student_name = page.at("//*[@id=\"attempts\"]/tbody/tr[#{i}]/td[3]/a[1]").text
|
35
|
+
attempt_url = page.at("//*[@id=\"attempts\"]/tbody/tr[#{i}]/td[3]/a[2]").attributes["href"].value
|
36
|
+
result_list << [student_name,attempt_url]
|
37
|
+
i += 1
|
38
|
+
end
|
39
|
+
result_list
|
40
|
+
end
|
41
|
+
|
42
|
+
def extractUserName(page)
|
43
|
+
|
44
|
+
l = page.links.select {|x| @@user_view_regexp.match(x.href)}
|
45
|
+
nutzerbild_string = "Nutzerbild "
|
46
|
+
nutzerbild = l.select{ |x| /Nutzerbild/.match(x.text)}
|
47
|
+
if nutzerbild.empty?
|
48
|
+
nutzerbild = l.select{ |x| /Picture of/.match(x.text)}
|
49
|
+
nutzerbild_string = "Picture of "
|
50
|
+
end
|
51
|
+
if nutzerbild.empty?
|
52
|
+
puts "## WARNING! ##"
|
53
|
+
puts "could not extract user name"
|
54
|
+
puts "## nutzerbild #{nutzerbild.inspect}"
|
55
|
+
puts "-- nutzerbild_string #{nutzerbild_string}"
|
56
|
+
return "Unknown Student"
|
57
|
+
end
|
58
|
+
nutzerbild.first.text.gsub(nutzerbild_string,"")
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
class OptionHandler
|
5
|
+
def valid_commands
|
6
|
+
[:list, :download, :connect]
|
7
|
+
end
|
8
|
+
attr_reader :options, :optionparser
|
9
|
+
def initialize(arguments = [])
|
10
|
+
@arguments = arguments
|
11
|
+
@options, @optionparser = parse(arguments)
|
12
|
+
end
|
13
|
+
def usage
|
14
|
+
@options.usage
|
15
|
+
end
|
16
|
+
|
17
|
+
def validate(options,optionparser)
|
18
|
+
options.usage = optionparser.help unless valid?(options)
|
19
|
+
end
|
20
|
+
def valid?(options)
|
21
|
+
options.valid &&
|
22
|
+
options.moodle_username &&
|
23
|
+
options.moodle_password &&
|
24
|
+
options.moodle_server &&
|
25
|
+
options.exam_id != 0
|
26
|
+
end
|
27
|
+
|
28
|
+
def parse(args = @arguments)
|
29
|
+
# The options specified on the command line will be collected in *options*.
|
30
|
+
# We set default values here.
|
31
|
+
options = OpenStruct.new
|
32
|
+
options.valid = true
|
33
|
+
options.verbose = false
|
34
|
+
options.moodle_username = ENV['MOODLE_USERNAME']
|
35
|
+
options.moodle_password = ENV['MOODLE_PASSWORD']
|
36
|
+
options.moodle_server = ENV['MOODLE_SERVER']
|
37
|
+
options.outputdir = "out"
|
38
|
+
options.exam_id = 0
|
39
|
+
options.command = :list
|
40
|
+
options.usage = nil
|
41
|
+
|
42
|
+
|
43
|
+
opt_parser = OptionParser.new do |opts|
|
44
|
+
opts.banner = <<DELIM
|
45
|
+
Usage: moodleQuizDownloader [options] <command>
|
46
|
+
Where <command> is one of the following: #{valid_commands.join(", ")}
|
47
|
+
DELIM
|
48
|
+
|
49
|
+
opts.separator ""
|
50
|
+
opts.separator "Specific options:"
|
51
|
+
|
52
|
+
opts.on("-e", "--exam EXAM_ID",
|
53
|
+
"The ID of the Exam to be downloaded") do | id |
|
54
|
+
options.exam_id = id
|
55
|
+
end
|
56
|
+
opts.on("-o", "--outputdir DIR",
|
57
|
+
"Output Dir (defaults to . )") do | dir |
|
58
|
+
options.outputdir = dir
|
59
|
+
end
|
60
|
+
opts.on("-u", "--user USERNAME",
|
61
|
+
"Your Moodle User Name",
|
62
|
+
"(can also be set via MOODLE_USERNAME environment variable)") do |username|
|
63
|
+
options.moodle_username = username
|
64
|
+
end
|
65
|
+
opts.on("-p", "--password PASSWORD]",
|
66
|
+
"Your Moodle Password",
|
67
|
+
"(can also be set via MOODLE_PASSWORD environment variable)") do |password|
|
68
|
+
options.moodle_password = password
|
69
|
+
end
|
70
|
+
|
71
|
+
opts.on("-s", "--server SERVER]",
|
72
|
+
"Your Moodle Server",
|
73
|
+
"(can also be set via MOODLE_SERVER environment variable)") do |server|
|
74
|
+
options.moodle_server = server
|
75
|
+
end
|
76
|
+
|
77
|
+
opts.separator ""
|
78
|
+
opts.separator "Common options:"
|
79
|
+
|
80
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
81
|
+
puts opts
|
82
|
+
exit
|
83
|
+
end
|
84
|
+
|
85
|
+
opts.on_tail("-v", "--version", "Show version") do
|
86
|
+
options.command = :version
|
87
|
+
end
|
88
|
+
opts.on("-b", "--[no-]verbose", "Run verbosely") do |v|
|
89
|
+
options.verbose = v
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
opt_parser.order(args) do | command |
|
94
|
+
command = command.to_sym
|
95
|
+
if valid_commands.include?(command)
|
96
|
+
options.command = command
|
97
|
+
else
|
98
|
+
options.valid=false
|
99
|
+
end
|
100
|
+
end
|
101
|
+
validate(options,opt_parser)
|
102
|
+
options
|
103
|
+
end # parse()
|
104
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'mechanize'
|
2
|
+
require 'pdfkit'
|
3
|
+
require 'asciify'
|
4
|
+
require "bundler/setup"
|
5
|
+
require 'fileutils'
|
6
|
+
require_relative 'file_name_creator'
|
7
|
+
|
8
|
+
require_relative 'moodle_parser'
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
class QuizDownloader
|
13
|
+
include MoodleParser
|
14
|
+
|
15
|
+
def smoketest(server)
|
16
|
+
begin
|
17
|
+
agent = Mechanize.new
|
18
|
+
page = login(agent,moodle_login_page(server),"xxx","xxx")
|
19
|
+
if page.nil?
|
20
|
+
puts "could not connect to server #{server}"
|
21
|
+
else
|
22
|
+
puts "connection to server seems to be working"
|
23
|
+
end
|
24
|
+
rescue Exception => e
|
25
|
+
puts "could not connect to server #{server}"
|
26
|
+
#puts e.message
|
27
|
+
end
|
28
|
+
end
|
29
|
+
def attemptlist(options,agent)
|
30
|
+
puts "connecting to moodle" if options.verbose
|
31
|
+
page = login(agent,moodle_login_page(options.moodle_server),options.moodle_username,options.moodle_password)
|
32
|
+
moodle_overview_url = moodle_quiz_report(options.moodle_server)+options.exam_id.to_s
|
33
|
+
puts "==== downloading overview" if options.verbose
|
34
|
+
puts moodle_overview_url if options.verbose
|
35
|
+
page = agent.get(moodle_overview_url)
|
36
|
+
#attempts = selectReviewLinks(page)
|
37
|
+
attempt_list = extract_attempt_list(page)
|
38
|
+
end
|
39
|
+
|
40
|
+
def download(attempt_list,options,agent)
|
41
|
+
FileUtils.mkdir_p(options.outputdir)
|
42
|
+
attempt_list.each do | attempt|
|
43
|
+
student_name, attempt_url = attempt
|
44
|
+
|
45
|
+
attempt_url = attempt_url+"&showall=1"
|
46
|
+
page = agent.get(attempt_url)
|
47
|
+
puts "==== downloading attempt" if options.verbose
|
48
|
+
puts attempt_url if options.verbose
|
49
|
+
#student = extractUserName(page)
|
50
|
+
student = student_name
|
51
|
+
outputfile = FileNameCreator.fileNameFor(options.outputdir,student)
|
52
|
+
puts "Loading: #{student}"
|
53
|
+
kit = PDFKit.new(page.body)
|
54
|
+
kit.to_file(outputfile)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
def run(options)
|
60
|
+
agent = Mechanize.new
|
61
|
+
case options.command
|
62
|
+
when :connect
|
63
|
+
smoketest(options.moodle_server)
|
64
|
+
when :list
|
65
|
+
attempt_list = attemptlist(options,agent)
|
66
|
+
puts "found #{attempt_list.length} attempts:"
|
67
|
+
puts attempt_list.map{|a,b| a}
|
68
|
+
when :download
|
69
|
+
attempt_list = attemptlist(options,agent)
|
70
|
+
download(attempt_list,options,agent)
|
71
|
+
else
|
72
|
+
puts "command #{options.command} not recognized"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
end
|
78
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'moodleQuizDownloader/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "moodleQuizDownloader"
|
8
|
+
spec.version = MoodleQuizDownloader::VERSION
|
9
|
+
spec.authors = ["Dr Blinken"]
|
10
|
+
spec.email = ["drblinken@gmail.com"]
|
11
|
+
spec.description = %q{Downloads Quizzes from Moodle as PDF}
|
12
|
+
spec.summary = %q{This is a little ruby command line tool that hooks to a moodle server and downloads all attempts for an exam as pdfs.}
|
13
|
+
spec.homepage = "https://github.com/drblinken/moodleQuizDownloader"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
|
22
|
+
spec.add_dependency "asciify"
|
23
|
+
spec.add_dependency "iconv" #this is a dependency of asciify
|
24
|
+
spec.add_dependency 'mechanize'
|
25
|
+
spec.add_dependency 'pdfkit'
|
26
|
+
|
27
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
28
|
+
spec.add_development_dependency "rake"
|
29
|
+
spec.add_development_dependency "rspec"
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#
|
2
|
+
# rspec to test usage of pdfkit in this script
|
3
|
+
#
|
4
|
+
# installation
|
5
|
+
# gem 'pdfkit'
|
6
|
+
# brew install wkhtmltopdf
|
7
|
+
# don't just install the gem, this didn't work as described in
|
8
|
+
# https://github.com/pdfkit/pdfkit/wiki/Installing-WKHTMLTOPDF
|
9
|
+
# https://github.com/pdfkit/pdfkit/wiki/
|
10
|
+
# http://code.google.com/p/wkhtmltopdf/
|
11
|
+
# https://github.com/pdfkit/pdfkit
|
12
|
+
require 'pdfkit'
|
13
|
+
describe 'pdfkit api' do
|
14
|
+
it "should convert a html page to pdf" do
|
15
|
+
html = '<body>Hallu</body>'
|
16
|
+
kit = PDFKit.new(html)
|
17
|
+
# >> k.to_file('simple.pdf')
|
18
|
+
pdf = kit.to_pdf
|
19
|
+
pdf.should match /^%PDF-/
|
20
|
+
end
|
21
|
+
end
|