moodleQuizDownloader 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ out
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in moodleQuizDownloader.gemspec
4
+ gemspec
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,4 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative '../lib/moodleQuizDownloader.rb'
3
+ include MoodleQuizDownloader
4
+ run_script(ARGV)
@@ -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,12 @@
1
+ require 'asciify'
2
+
3
+ class FileNameCreator
4
+
5
+ @@regexp = /(\w*)( (\w*))? (\w*)/
6
+ @@map = Asciify::Mapping.new(:default)
7
+
8
+ def self.fileNameFor(outputdir,name)
9
+ File.join(outputdir,name.asciify(@@map).gsub(@@regexp,"\\1\\3\\4.pdf"))
10
+ end
11
+
12
+ end
@@ -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,3 @@
1
+ module MoodleQuizDownloader
2
+ VERSION = "0.0.1"
3
+ end
@@ -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,8 @@
1
+ # Encoding: utf-8
2
+ require 'asciify'
3
+ describe "using asciify" do
4
+ it "converts umlaute" do
5
+ map = Asciify::Mapping.new(:default)
6
+ "ÄÖÜßäöü".asciify(map).should == "AeOeUessaeoeue"
7
+ end
8
+ 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