sakai-info 0.4.6 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +18 -0
- data/LICENSE +5 -0
- data/README.md +2 -2
- data/ROADMAP.md +30 -5
- data/bin/sin +20 -18
- data/lib/sakai-info.rb +5 -104
- data/lib/sakai-info/cache.rb +23 -0
- data/lib/sakai-info/cli.rb +4 -34
- data/lib/sakai-info/cli/help.rb +96 -39
- data/lib/sakai-info/cli/lookup.rb +96 -0
- data/lib/sakai-info/cli/query.rb +58 -0
- data/lib/sakai-info/cli/special.rb +32 -0
- data/lib/sakai-info/content.rb +44 -1
- data/lib/sakai-info/exceptions.rb +27 -0
- data/lib/sakai-info/hacks.rb +49 -0
- data/lib/sakai-info/quiz.rb +115 -25
- data/lib/sakai-info/util.rb +50 -0
- data/lib/sakai-info/version.rb +1 -1
- metadata +9 -2
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,23 @@
|
|
1
1
|
# sakai-info Change History #
|
2
2
|
|
3
|
+
### 0.5.0 ###
|
4
|
+
|
5
|
+
*Released 2012-06-21*
|
6
|
+
|
7
|
+
* Added --full-children and --all options for content
|
8
|
+
* Refactored rake tasks into one directory
|
9
|
+
* Added a barebones proof-of-concept-only query mode
|
10
|
+
* Removed quiz, quiz-section, and quiz-item types due to ID overlap risk
|
11
|
+
* Added new special modes to intercept calls for these removed object types
|
12
|
+
* Added published-quiz and pending-quiz types
|
13
|
+
* Added published-quiz-section and pending-quiz-section types
|
14
|
+
* Added published-quiz-item and pending-quiz-item types
|
15
|
+
* Added --texts record listing to published-quiz-item and pending-quiz-item
|
16
|
+
* Added --items record listing to quiz
|
17
|
+
* Better summaries for items in quiz-sections and quizzes
|
18
|
+
* Added a number of command line object type shortcuts
|
19
|
+
* Added random test fixture generation for user objects
|
20
|
+
|
3
21
|
### 0.4.6 ###
|
4
22
|
|
5
23
|
*Released 2012-05-19*
|
data/LICENSE
CHANGED
@@ -6,3 +6,8 @@ domain. This applies worldwide.
|
|
6
6
|
I grant any entity the right to use this work for any purpose, without
|
7
7
|
any conditions, unless such conditions are required by law.
|
8
8
|
|
9
|
+
If you require a fuller legal statement, please refer to the Creative
|
10
|
+
Commons Zero license:
|
11
|
+
|
12
|
+
http://creativecommons.org/publicdomain/zero/1.0/
|
13
|
+
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# sakai-info #
|
2
2
|
|
3
|
-
last updated: 2012-
|
3
|
+
last updated: 2012-06-21
|
4
4
|
author: David Adams (daveadams@gmail.com)
|
5
5
|
github url: https://github.com/daveadams/sakai-info
|
6
6
|
|
@@ -24,7 +24,7 @@ Use `rake` to test and build the gem:
|
|
24
24
|
$ rake gem:build
|
25
25
|
|
26
26
|
The resulting gem will be saved to the working directory as
|
27
|
-
`sakai-info-0.
|
27
|
+
`sakai-info-0.5.0.gem`.
|
28
28
|
|
29
29
|
Cleanup built gems using:
|
30
30
|
|
data/ROADMAP.md
CHANGED
@@ -1,18 +1,43 @@
|
|
1
1
|
# sakai-info Roadmap #
|
2
2
|
|
3
|
-
*Last updated 2012-
|
3
|
+
*Last updated 2012-06-21*
|
4
4
|
|
5
|
-
### 0.5.
|
5
|
+
### 0.5.1 ###
|
6
|
+
|
7
|
+
* Test fixture generation for sites
|
8
|
+
* Text fixture loading into sqlite for sites and users
|
9
|
+
* Field restrictions for lookups
|
10
|
+
* Simple queries by name/title for user/site
|
11
|
+
* More details for quizzes including access control data
|
12
|
+
|
13
|
+
### 0.5.2 ###
|
14
|
+
|
15
|
+
* Test fixture generation for quizzes
|
16
|
+
* Better date formatting all around
|
17
|
+
* More query functionality
|
18
|
+
* Proof-of-concept sin shell
|
19
|
+
* Chat channel/message support
|
20
|
+
|
21
|
+
### 0.5.3 ###
|
22
|
+
|
23
|
+
* RDS schema creation and data loading for MySQL and Oracle testing
|
24
|
+
* More query and shell functionality
|
25
|
+
|
26
|
+
### 0.5.4 ###
|
27
|
+
|
28
|
+
* Barebones web interface - HTML, JSON, and YAML
|
29
|
+
* More query and shell functionality
|
30
|
+
|
31
|
+
### 0.5.5 ###
|
6
32
|
|
7
|
-
* Sqlite test infrastructure for a few basic objects
|
8
|
-
* Deeper query functionality and field specification
|
9
|
-
* Simple web query interface - HTML, JSON, and YAML
|
10
33
|
* Global cache instead of per-class
|
34
|
+
* More query, web, and shell functionality
|
11
35
|
|
12
36
|
### 0.6.x ###
|
13
37
|
|
14
38
|
* Test fixtures and basic unit tests for all represented objects
|
15
39
|
* RDoc coverage for every class
|
40
|
+
* More focus on other library usage besides ad hoc CLI/web queries
|
16
41
|
|
17
42
|
### 0.7.x ###
|
18
43
|
|
data/bin/sin
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
# sakai-info library
|
6
6
|
#
|
7
7
|
# Created 2012-02-15 daveadams@gmail.com
|
8
|
-
# Last updated 2012-
|
8
|
+
# Last updated 2012-05-23 daveadams@gmail.com
|
9
9
|
#
|
10
10
|
# https://github.com/daveadams/sakai-info
|
11
11
|
#
|
@@ -104,11 +104,16 @@ when "test" then
|
|
104
104
|
exit
|
105
105
|
end
|
106
106
|
|
107
|
+
when "query" then
|
108
|
+
mode = args.shift
|
109
|
+
|
107
110
|
else
|
108
|
-
# test to see if it's an accepted
|
109
|
-
if CLI::
|
110
|
-
mode =
|
111
|
-
|
111
|
+
# test to see if it's an accepted lookup mode
|
112
|
+
if CLI::LookupModes.keys.include? args[0]
|
113
|
+
mode = "lookup"
|
114
|
+
|
115
|
+
elsif CLI::SpecialModes.keys.include? args[0]
|
116
|
+
mode = "special"
|
112
117
|
|
113
118
|
else
|
114
119
|
STDERR.puts "ERROR: Command '#{args[0]}' was not recognized."
|
@@ -136,18 +141,15 @@ if not db_name.nil?
|
|
136
141
|
DB.default_database = db_name
|
137
142
|
end
|
138
143
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
rescue ObjectNotFoundException
|
150
|
-
STDERR.puts "ERROR: Could not find #{mode} with an ID of '#{id}'"
|
151
|
-
exit 1
|
144
|
+
case mode
|
145
|
+
when "query"
|
146
|
+
CLI::Query.process(args, flags)
|
147
|
+
|
148
|
+
when "lookup"
|
149
|
+
CLI::Lookup.process(args, flags)
|
150
|
+
|
151
|
+
when "special"
|
152
|
+
CLI::Special.process(args, flags)
|
153
|
+
|
152
154
|
end
|
153
155
|
|
data/lib/sakai-info.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
# Base library file
|
3
3
|
#
|
4
4
|
# Created 2012-02-15 daveadams@gmail.com
|
5
|
-
# Last updated 2012-05-
|
5
|
+
# Last updated 2012-05-20 daveadams@gmail.com
|
6
6
|
#
|
7
7
|
# https://github.com/daveadams/sakai-info
|
8
8
|
#
|
@@ -17,109 +17,10 @@ require 'sequel'
|
|
17
17
|
require 'logger'
|
18
18
|
|
19
19
|
require 'sakai-info/version'
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
class SakaiException < Exception; end
|
25
|
-
|
26
|
-
# exception to be raised when an object of a certain type cannot be found
|
27
|
-
class ObjectNotFoundException < SakaiException
|
28
|
-
def initialize(classname, identifier)
|
29
|
-
@classname = classname
|
30
|
-
@identifier = identifier
|
31
|
-
|
32
|
-
super("Could not find a #{@classname} object for '#{@identifier}'")
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
class Util
|
37
|
-
# misc support functions
|
38
|
-
FILESIZE_LABELS = ["bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]
|
39
|
-
def self.format_filesize(i_size)
|
40
|
-
size = i_size.to_f
|
41
|
-
negative = false
|
42
|
-
|
43
|
-
if size < 0
|
44
|
-
negative = true
|
45
|
-
size = -size
|
46
|
-
end
|
47
|
-
|
48
|
-
label = 0
|
49
|
-
(FILESIZE_LABELS.size - 1).times do
|
50
|
-
if size >= 1024.0
|
51
|
-
size = size / 1024.0
|
52
|
-
label += 1
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
if size >= 100.0 or label == 0
|
57
|
-
"#{negative ? "-" : ""}#{size.to_i.to_s} #{FILESIZE_LABELS[label]}"
|
58
|
-
else
|
59
|
-
"#{negative ? "-" : ""}#{sprintf("%.1f", size)} #{FILESIZE_LABELS[label]}"
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def self.format_entity_date(raw)
|
64
|
-
if raw =~ /^(....)(..)(..)(..)(..)(..).*$/
|
65
|
-
# I believe these are usually in UTC
|
66
|
-
Time.utc($1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i).getlocal
|
67
|
-
else
|
68
|
-
raw
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
# cache control
|
74
|
-
class Cache
|
75
|
-
def self.clear_all
|
76
|
-
SakaiObject.descendants.select { |klass|
|
77
|
-
klass.methods.include? :clear_cache
|
78
|
-
}.each { |klass|
|
79
|
-
klass.clear_cache
|
80
|
-
}
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
######################################################################
|
86
|
-
# extensions to other objects
|
87
|
-
class String
|
88
|
-
def is_uuid?
|
89
|
-
self =~ /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
# terrible hack to work around mysql case issues
|
94
|
-
# essentially, if the hash key asked for is a symbol and its value is
|
95
|
-
# nil, then try again with the uppercased version of the symbol
|
96
|
-
# this might cause problems in weird cases with other hashes, this is
|
97
|
-
# definitely not a sustainable fix.
|
98
|
-
# TODO: patch Sequel for case-insensitive/-fixed identifiers
|
99
|
-
class Hash
|
100
|
-
alias :original_brackets :[]
|
101
|
-
|
102
|
-
def [](key)
|
103
|
-
if not (value = original_brackets(key)).nil?
|
104
|
-
return value
|
105
|
-
else
|
106
|
-
if key.is_a? Symbol
|
107
|
-
return original_brackets(key.to_s.upcase.to_sym)
|
108
|
-
else
|
109
|
-
return nil
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
# alias .to_s on Blob class to match OCI8 blob class's read method
|
116
|
-
module Sequel
|
117
|
-
module SQL
|
118
|
-
class Blob
|
119
|
-
alias :read :to_s
|
120
|
-
end
|
121
|
-
end
|
122
|
-
end
|
20
|
+
require 'sakai-info/exceptions'
|
21
|
+
require 'sakai-info/hacks'
|
22
|
+
require 'sakai-info/util'
|
23
|
+
require 'sakai-info/cache'
|
123
24
|
|
124
25
|
# baseline db connectivity
|
125
26
|
require 'sakai-info/database'
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# cache.rb
|
2
|
+
# Cache control
|
3
|
+
#
|
4
|
+
# Created 2012-05-20 daveadams@gmail.com
|
5
|
+
# Last updated 2012-05-20 daveadams@gmail.com
|
6
|
+
#
|
7
|
+
# https://github.com/daveadams/sakai-info
|
8
|
+
#
|
9
|
+
# This software is public domain.
|
10
|
+
#
|
11
|
+
|
12
|
+
module SakaiInfo
|
13
|
+
# cache control
|
14
|
+
class Cache
|
15
|
+
def self.clear_all
|
16
|
+
SakaiObject.descendants.select { |klass|
|
17
|
+
klass.methods.include? :clear_cache
|
18
|
+
}.each { |klass|
|
19
|
+
klass.clear_cache
|
20
|
+
}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/sakai-info/cli.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
# - sakai-info command line tool support
|
3
3
|
#
|
4
4
|
# Created 2012-02-19 daveadams@gmail.com
|
5
|
-
# Last updated 2012-
|
5
|
+
# Last updated 2012-06-21 daveadams@gmail.com
|
6
6
|
#
|
7
7
|
# https://github.com/daveadams/sakai-info
|
8
8
|
#
|
@@ -10,40 +10,10 @@
|
|
10
10
|
#
|
11
11
|
|
12
12
|
require 'sakai-info/cli/help'
|
13
|
+
require 'sakai-info/cli/lookup'
|
14
|
+
require 'sakai-info/cli/query'
|
15
|
+
require 'sakai-info/cli/special'
|
13
16
|
|
14
17
|
# it's faster to run single-threaded
|
15
18
|
Sequel.single_threaded = true
|
16
19
|
|
17
|
-
module SakaiInfo
|
18
|
-
class CLI
|
19
|
-
ObjectModes = {
|
20
|
-
"site" => Site,
|
21
|
-
"page" => Page,
|
22
|
-
"tool" => Tool,
|
23
|
-
"user" => User,
|
24
|
-
"group" => Group,
|
25
|
-
"quiz" => Quiz,
|
26
|
-
"quiz-section" => QuizSection,
|
27
|
-
"quiz-item" => QuizItem,
|
28
|
-
"quiz-attempt" => QuizAttempt,
|
29
|
-
"quiz-attempt-item" => QuizAttemptItem,
|
30
|
-
"quiz-attempt-item-attachment" => QuizAttemptItemAttachment,
|
31
|
-
"qpool" => QuestionPool,
|
32
|
-
"question-pool" => QuestionPool,
|
33
|
-
"assignment" => Assignment,
|
34
|
-
"assignment-submission" => AssignmentSubmission,
|
35
|
-
"forum" => Forum,
|
36
|
-
"forum-thread" => ForumThread,
|
37
|
-
"forum-post" => ForumPost,
|
38
|
-
"content" => Content,
|
39
|
-
"announcement" => Announcement,
|
40
|
-
"announcement-channel" => AnnouncementChannel,
|
41
|
-
"gradebook" => Gradebook,
|
42
|
-
"gradebook-item" => GradebookItem,
|
43
|
-
"role" => AuthzRole,
|
44
|
-
"function" => AuthzFunction,
|
45
|
-
"realm" => AuthzRealm,
|
46
|
-
}
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
data/lib/sakai-info/cli/help.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
# - sin command line help
|
3
3
|
#
|
4
4
|
# Created 2012-02-19 daveadams@gmail.com
|
5
|
-
# Last updated 2012-
|
5
|
+
# Last updated 2012-06-21 daveadams@gmail.com
|
6
6
|
#
|
7
7
|
# https://github.com/daveadams/sakai-info
|
8
8
|
#
|
@@ -10,26 +10,42 @@
|
|
10
10
|
#
|
11
11
|
|
12
12
|
module SakaiInfo
|
13
|
-
|
13
|
+
module CLI
|
14
14
|
class Help
|
15
15
|
STRINGS = {
|
16
16
|
:default => <<EOF,
|
17
|
-
Sakai
|
18
|
-
|
17
|
+
Sakai INfo: sin #{VERSION}
|
18
|
+
|
19
|
+
LOOKUP MODE
|
20
|
+
Lookup details about a particular object and its child objects.
|
21
|
+
|
22
|
+
Usage: sin <object-type> [<id>] [<options>]
|
23
|
+
|
24
|
+
Supported object types:
|
25
|
+
user, group, site, page, tool, pending-quiz, published-quiz,
|
26
|
+
pending-quiz-section, published-quiz-section, pending-quiz-item,
|
27
|
+
published-quiz-item, quiz-attempt, quiz-attempt-item,
|
28
|
+
quiz-attempt-item-attachment, question-pool, assignment,
|
29
|
+
assignment-submission, forum, forum-thread, forum-post, content,
|
30
|
+
announcement, announcement-channel, gradebook, gradebook-item,
|
31
|
+
role, function, realm
|
32
|
+
|
33
|
+
QUERY MODE
|
34
|
+
Query particular fields from certain objects given certain conditions.
|
35
|
+
|
36
|
+
Usage: sin query <object-type> [<options>]
|
19
37
|
|
20
|
-
|
21
|
-
user, group, site, page, tool, quiz, quiz-section, quiz-item, quiz-attempt,
|
22
|
-
quiz-attempt-item, quiz-attempt-item-attachment, question-pool, assignment,
|
23
|
-
assignment-submission, forum, forum-thread, forum-post, content,
|
24
|
-
announcement, announcement-channel, gradebook, gradebook-item, role,
|
25
|
-
function, realm
|
38
|
+
Use "sin help query" for more details.
|
26
39
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
40
|
+
OTHER COMMANDS
|
41
|
+
Usage: sin <command>
|
42
|
+
|
43
|
+
Available commands:
|
44
|
+
test Tests configured database connections
|
45
|
+
help Prints general help
|
46
|
+
version Prints version
|
47
|
+
help <command> Prints help about a particular command
|
48
|
+
help options Prints help about additional options
|
33
49
|
EOF
|
34
50
|
|
35
51
|
"options" => <<EOF,
|
@@ -151,45 +167,78 @@ sin tool
|
|
151
167
|
Prints information about the tool ID specified.
|
152
168
|
EOF
|
153
169
|
|
154
|
-
"quiz" => <<EOF,
|
155
|
-
sin quiz
|
170
|
+
"pending-quiz" => <<EOF,
|
171
|
+
sin pending-quiz
|
156
172
|
|
157
|
-
Usage: sin quiz <id> [<options>]
|
173
|
+
Usage: sin pending-quiz <id> [<options>]
|
158
174
|
|
159
|
-
Prints information about the quiz ID specified.
|
160
|
-
|
161
|
-
include additional information:
|
175
|
+
Prints information about the pending quiz ID specified. Additional options
|
176
|
+
may be passed to include additional information:
|
162
177
|
|
163
178
|
--sections Print section summary list
|
164
|
-
--
|
179
|
+
--items Print summary of items on the quiz
|
165
180
|
--mod Print creation/modification info
|
181
|
+
EOF
|
166
182
|
|
167
|
-
|
183
|
+
"published-quiz" => <<EOF,
|
184
|
+
sin published-quiz
|
185
|
+
|
186
|
+
Usage: sin published-quiz <id> [<options>]
|
187
|
+
|
188
|
+
Prints information about the published quiz ID specified. Additional options
|
189
|
+
may be passed to include additional information:
|
190
|
+
|
191
|
+
--sections Print section summary list
|
168
192
|
--items Print summary of items on the quiz
|
193
|
+
--attempts Print summary of user quiz attempts
|
194
|
+
--mod Print creation/modification info
|
169
195
|
EOF
|
170
196
|
|
171
|
-
"quiz-section" => <<EOF,
|
172
|
-
sin quiz-section
|
197
|
+
"pending-quiz-section" => <<EOF,
|
198
|
+
sin pending-quiz-section
|
173
199
|
|
174
|
-
Usage: sin quiz-section <id> [<options>]
|
200
|
+
Usage: sin pending-quiz-section <id> [<options>]
|
175
201
|
|
176
|
-
Prints information about the quiz section ID specified.
|
177
|
-
|
178
|
-
passed to include additional information:
|
202
|
+
Prints information about the pending quiz section ID specified. Additional
|
203
|
+
options may be passed to include additional information:
|
179
204
|
|
180
205
|
--items Print summary of items in the section
|
181
206
|
--mod Print creation/modification info
|
182
207
|
EOF
|
183
208
|
|
184
|
-
"quiz-
|
185
|
-
sin quiz-
|
209
|
+
"published-quiz-section" => <<EOF,
|
210
|
+
sin published-quiz-section
|
186
211
|
|
187
|
-
Usage: sin quiz-
|
212
|
+
Usage: sin published-quiz-section <id> [<options>]
|
188
213
|
|
189
|
-
Prints information about the quiz
|
190
|
-
|
191
|
-
passed to include additional information:
|
214
|
+
Prints information about the published quiz section ID specified. Additional
|
215
|
+
options may be passed to include additional information:
|
192
216
|
|
217
|
+
--items Print summary of items in the section
|
218
|
+
--mod Print creation/modification info
|
219
|
+
EOF
|
220
|
+
|
221
|
+
"pending-quiz-item" => <<EOF,
|
222
|
+
sin pending-quiz-item
|
223
|
+
|
224
|
+
Usage: sin pending-quiz-item <id> [<options>]
|
225
|
+
|
226
|
+
Prints information about the pending quiz item ID specified. Additional
|
227
|
+
options may be passed to include additional information:
|
228
|
+
|
229
|
+
--texts List associated pending-quiz-item-text records
|
230
|
+
--mod Print creation/modification info
|
231
|
+
EOF
|
232
|
+
|
233
|
+
"published-quiz-item" => <<EOF,
|
234
|
+
sin published-quiz-item
|
235
|
+
|
236
|
+
Usage: sin published-quiz-item <id> [<options>]
|
237
|
+
|
238
|
+
Prints information about the published quiz item ID specified. Additional
|
239
|
+
options may be passed to include additional information:
|
240
|
+
|
241
|
+
--texts List associated quiz-item-text records
|
193
242
|
--mod Print creation/modification info
|
194
243
|
EOF
|
195
244
|
|
@@ -311,9 +360,10 @@ sin content
|
|
311
360
|
Prints information about the content resource or collection ID specified.
|
312
361
|
Additional options may be passed to include additional information:
|
313
362
|
|
314
|
-
--properties
|
315
|
-
--children
|
316
|
-
--
|
363
|
+
--properties Print all properties
|
364
|
+
--children Recursively print collection children
|
365
|
+
--full-children Print children with full IDs and file paths
|
366
|
+
--mod Print creation/modification info
|
317
367
|
EOF
|
318
368
|
"announcement" => <<EOF,
|
319
369
|
sin announcement
|
@@ -378,6 +428,13 @@ sin realm
|
|
378
428
|
--roles List roles associated with this realm
|
379
429
|
--users List users in this realm
|
380
430
|
--mod Print creation/modification info
|
431
|
+
EOF
|
432
|
+
"query" => <<EOF,
|
433
|
+
sin query
|
434
|
+
|
435
|
+
Usage: sin query <object-type> [<options>]
|
436
|
+
|
437
|
+
Query mode is only being tested at present.
|
381
438
|
EOF
|
382
439
|
}
|
383
440
|
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# lookup.rb
|
2
|
+
# class for handling the default command line mode
|
3
|
+
#
|
4
|
+
# Created 2012-05-23 daveadams@gmail.com
|
5
|
+
# Last updated 2012-06-21 daveadams@gmail.com
|
6
|
+
#
|
7
|
+
# https://github.com/daveadams/sakai-info
|
8
|
+
#
|
9
|
+
# This software is public domain.
|
10
|
+
#
|
11
|
+
|
12
|
+
module SakaiInfo
|
13
|
+
module CLI
|
14
|
+
class Lookup
|
15
|
+
def self.process(args, flags)
|
16
|
+
object_type = args.shift
|
17
|
+
id = args.shift
|
18
|
+
|
19
|
+
if flags.include? "--all"
|
20
|
+
serials = CLI::LookupModes[object_type].all_serializations
|
21
|
+
elsif
|
22
|
+
flags.include? "--dbrow-only"
|
23
|
+
serials = [:dbrow_only]
|
24
|
+
else
|
25
|
+
serials = [:default] + flags.collect{|flag|flag.gsub(/^--/,'').gsub("-","_").to_sym}
|
26
|
+
end
|
27
|
+
begin
|
28
|
+
puts CLI::LookupModes[object_type].find(id).to_yaml(serials)
|
29
|
+
rescue ObjectNotFoundException
|
30
|
+
STDERR.puts "ERROR: Could not find #{object_type} with an ID of '#{id}'"
|
31
|
+
exit 1
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
LookupModes = {
|
37
|
+
"site" => Site,
|
38
|
+
"page" => Page,
|
39
|
+
"tool" => Tool,
|
40
|
+
"user" => User,
|
41
|
+
"group" => Group,
|
42
|
+
"pq" => PublishedQuiz,
|
43
|
+
"pubquiz" => PublishedQuiz,
|
44
|
+
"published-quiz" => PublishedQuiz,
|
45
|
+
"nq" => PendingQuiz,
|
46
|
+
"penquiz" => PendingQuiz,
|
47
|
+
"pending-quiz" => PendingQuiz,
|
48
|
+
"pqs" => PublishedQuizSection,
|
49
|
+
"pubqs" => PublishedQuizSection,
|
50
|
+
"published-quiz-section" => PublishedQuizSection,
|
51
|
+
"nqs" => PendingQuizSection,
|
52
|
+
"penqs" => PendingQuizSection,
|
53
|
+
"pending-quiz-section" => PendingQuizSection,
|
54
|
+
"pqi" => PublishedQuizItem,
|
55
|
+
"pubqi" => PublishedQuizItem,
|
56
|
+
"published-quiz-item" => PublishedQuizItem,
|
57
|
+
"nqi" => PendingQuizItem,
|
58
|
+
"penqi" => PendingQuizItem,
|
59
|
+
"pending-quiz-item" => PendingQuizItem,
|
60
|
+
"qa" => QuizAttempt,
|
61
|
+
"quiz-attempt" => QuizAttempt,
|
62
|
+
"qai" => QuizAttemptItem,
|
63
|
+
"quiz-attempt-item" => QuizAttemptItem,
|
64
|
+
"qaia" => QuizAttemptItemAttachment,
|
65
|
+
"quiz-attempt-item-attachment" => QuizAttemptItemAttachment,
|
66
|
+
"qp" => QuestionPool,
|
67
|
+
"qpool" => QuestionPool,
|
68
|
+
"question-pool" => QuestionPool,
|
69
|
+
"a" => Assignment,
|
70
|
+
"assignment" => Assignment,
|
71
|
+
"as" => AssignmentSubmission,
|
72
|
+
"asub" => AssignmentSubmission,
|
73
|
+
"assignment-submission" => AssignmentSubmission,
|
74
|
+
"forum" => Forum,
|
75
|
+
"ft" => ForumThread,
|
76
|
+
"forum-thread" => ForumThread,
|
77
|
+
"fp" => ForumPost,
|
78
|
+
"forum-post" => ForumPost,
|
79
|
+
"content" => Content,
|
80
|
+
"ann" => Announcement,
|
81
|
+
"announcement" => Announcement,
|
82
|
+
"annchan" => AnnouncementChannel,
|
83
|
+
"announcement-channel" => AnnouncementChannel,
|
84
|
+
"gb" => Gradebook,
|
85
|
+
"gradebook" => Gradebook,
|
86
|
+
"gbi" => GradebookItem,
|
87
|
+
"gradebook-item" => GradebookItem,
|
88
|
+
"role" => AuthzRole,
|
89
|
+
"fn" => AuthzFunction,
|
90
|
+
"func" => AuthzFunction,
|
91
|
+
"function" => AuthzFunction,
|
92
|
+
"realm" => AuthzRealm,
|
93
|
+
}
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# query.rb
|
2
|
+
# class for handling "query" command line mode
|
3
|
+
#
|
4
|
+
# Created 2012-05-23 daveadams@gmail.com
|
5
|
+
# Last updated 2012-06-21 daveadams@gmail.com
|
6
|
+
#
|
7
|
+
# https://github.com/daveadams/sakai-info
|
8
|
+
#
|
9
|
+
# This software is public domain.
|
10
|
+
#
|
11
|
+
|
12
|
+
module SakaiInfo
|
13
|
+
module CLI
|
14
|
+
class Query
|
15
|
+
def self.process(args, flags)
|
16
|
+
# TODO: expand query functionality from proof of concept
|
17
|
+
object_type = args.shift
|
18
|
+
fields = []
|
19
|
+
site_id = nil
|
20
|
+
|
21
|
+
if object_type == "quiz"
|
22
|
+
flags.each do |flag|
|
23
|
+
case flag
|
24
|
+
when /^--fields=/
|
25
|
+
fields = flag.split("=")[1].split(",")
|
26
|
+
when /^--site=/
|
27
|
+
site_id = flag.split("=")[1]
|
28
|
+
else
|
29
|
+
STDERR.puts "ERROR: Unrecognized query flag"
|
30
|
+
exit 1
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
if site_id.nil?
|
35
|
+
STDERR.puts "ERROR: No site ID was provided"
|
36
|
+
exit 1
|
37
|
+
end
|
38
|
+
|
39
|
+
puts PublishedQuiz.find_ids_by_site_id(site_id)
|
40
|
+
|
41
|
+
elsif object_type == "userid" or object_type == "user_id" or object_type == "uid"
|
42
|
+
id = args.shift
|
43
|
+
begin
|
44
|
+
user = User.find(id)
|
45
|
+
puts user.id
|
46
|
+
rescue ObjectNotFoundException => e
|
47
|
+
STDERR.puts "ERROR: #{e}"
|
48
|
+
exit 1
|
49
|
+
end
|
50
|
+
|
51
|
+
else
|
52
|
+
STDERR.puts "ERROR: Unrecognized object type"
|
53
|
+
exit 1
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# special.rb
|
2
|
+
# class for handling the special command line modes
|
3
|
+
#
|
4
|
+
# Created 2012-06-21 daveadams@gmail.com
|
5
|
+
# Last updated 2012-06-21 daveadams@gmail.com
|
6
|
+
#
|
7
|
+
# https://github.com/daveadams/sakai-info
|
8
|
+
#
|
9
|
+
# This software is public domain. See LICENSE.
|
10
|
+
#
|
11
|
+
|
12
|
+
module SakaiInfo
|
13
|
+
module CLI
|
14
|
+
class Special
|
15
|
+
def self.process(args, flags)
|
16
|
+
mode = args.shift
|
17
|
+
|
18
|
+
STDERR.puts "WARNING:"
|
19
|
+
STDERR.puts " Looking up items of type '#{mode}' can return ambiguous results."
|
20
|
+
STDERR.puts " Please use #{SpecialModes[mode]} types instead."
|
21
|
+
exit 1
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
SpecialModes = {
|
26
|
+
"quiz" => "'published-quiz' or 'pending-quiz'",
|
27
|
+
"quiz-section" => "'published-quiz-section' or 'pending-quiz-section'",
|
28
|
+
"quiz-item" => "'published-quiz-item' or 'pending-quiz-item'",
|
29
|
+
}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
data/lib/sakai-info/content.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
# SakaiInfo::Content library
|
3
3
|
#
|
4
4
|
# Created 2012-02-17 daveadams@gmail.com
|
5
|
-
# Last updated 2012-05-
|
5
|
+
# Last updated 2012-05-20 daveadams@gmail.com
|
6
6
|
#
|
7
7
|
# https://github.com/daveadams/sakai-info
|
8
8
|
#
|
@@ -140,6 +140,16 @@ module SakaiInfo
|
|
140
140
|
self.binary_entity
|
141
141
|
self.original_mod_details_serialization
|
142
142
|
end
|
143
|
+
|
144
|
+
def self.all_serializations
|
145
|
+
[
|
146
|
+
:default,
|
147
|
+
:children,
|
148
|
+
:realm,
|
149
|
+
:properties,
|
150
|
+
:mod
|
151
|
+
]
|
152
|
+
end
|
143
153
|
end
|
144
154
|
|
145
155
|
class ContentResource < Content
|
@@ -218,6 +228,14 @@ module SakaiInfo
|
|
218
228
|
"size" => self.size_on_disk,
|
219
229
|
}
|
220
230
|
end
|
231
|
+
|
232
|
+
def detailed_summary_serialization
|
233
|
+
{
|
234
|
+
"id" => self.id,
|
235
|
+
"size" => self.size_on_disk,
|
236
|
+
"file_path" => self.file_path,
|
237
|
+
}
|
238
|
+
end
|
221
239
|
end
|
222
240
|
|
223
241
|
class ContentCollection < Content
|
@@ -319,6 +337,13 @@ module SakaiInfo
|
|
319
337
|
}
|
320
338
|
end
|
321
339
|
|
340
|
+
def detailed_summary_serialization
|
341
|
+
{
|
342
|
+
"id" => self.id,
|
343
|
+
"size_on_disk" => self.size_on_disk,
|
344
|
+
}
|
345
|
+
end
|
346
|
+
|
322
347
|
def children_serialization
|
323
348
|
result = {
|
324
349
|
"collections" => self.children["collections"].collect { |cc|
|
@@ -337,6 +362,24 @@ module SakaiInfo
|
|
337
362
|
result
|
338
363
|
end
|
339
364
|
|
365
|
+
def full_children_serialization
|
366
|
+
result = {
|
367
|
+
"collections" => self.children["collections"].collect { |cc|
|
368
|
+
cc.serialize(:detailed_summary, :full_children)
|
369
|
+
},
|
370
|
+
"resources" => self.children["resources"].collect { |cr|
|
371
|
+
cr.serialize(:detailed_summary)
|
372
|
+
}
|
373
|
+
}
|
374
|
+
if result["collections"] == []
|
375
|
+
result.delete("collections")
|
376
|
+
end
|
377
|
+
if result["resources"] == []
|
378
|
+
result.delete("resources")
|
379
|
+
end
|
380
|
+
result
|
381
|
+
end
|
382
|
+
|
340
383
|
def self.query_by_parent(parent_id)
|
341
384
|
DB.connect[:content_collection].where(:in_collection => parent_id)
|
342
385
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# exceptions.rb
|
2
|
+
# Special exception definitions
|
3
|
+
#
|
4
|
+
# Created 2012-05-20 daveadams@gmail.com
|
5
|
+
# Last updated 2012-05-20 daveadams@gmail.com
|
6
|
+
#
|
7
|
+
# https://github.com/daveadams/sakai-info
|
8
|
+
#
|
9
|
+
# This software is public domain.
|
10
|
+
#
|
11
|
+
|
12
|
+
module SakaiInfo
|
13
|
+
# base exception class for distinguishing SakaiInfo exceptions
|
14
|
+
# from Ruby exceptions
|
15
|
+
class SakaiException < Exception; end
|
16
|
+
|
17
|
+
# exception to be raised when an object of a certain type cannot be found
|
18
|
+
class ObjectNotFoundException < SakaiException
|
19
|
+
def initialize(classname, identifier)
|
20
|
+
@classname = classname
|
21
|
+
@identifier = identifier
|
22
|
+
|
23
|
+
super("Could not find a #{@classname} object for '#{@identifier}'")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# hacks.rb
|
2
|
+
# Hacks necessary to work around problems in external libraries
|
3
|
+
#
|
4
|
+
# Created 2012-05-20 daveadams@gmail.com
|
5
|
+
# Last updated 2012-05-20 daveadams@gmail.com
|
6
|
+
#
|
7
|
+
# https://github.com/daveadams/sakai-info
|
8
|
+
#
|
9
|
+
# This software is public domain.
|
10
|
+
#
|
11
|
+
|
12
|
+
######################################################################
|
13
|
+
# extensions to other objects
|
14
|
+
class String
|
15
|
+
def is_uuid?
|
16
|
+
self =~ /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# terrible hack to work around mysql case issues
|
21
|
+
# essentially, if the hash key asked for is a symbol and its value is
|
22
|
+
# nil, then try again with the uppercased version of the symbol
|
23
|
+
# this might cause problems in weird cases with other hashes, this is
|
24
|
+
# definitely not a sustainable fix.
|
25
|
+
# TODO: patch Sequel for case-insensitive/-fixed identifiers
|
26
|
+
class Hash
|
27
|
+
alias :original_brackets :[]
|
28
|
+
|
29
|
+
def [](key)
|
30
|
+
if not (value = original_brackets(key)).nil?
|
31
|
+
return value
|
32
|
+
else
|
33
|
+
if key.is_a? Symbol
|
34
|
+
return original_brackets(key.to_s.upcase.to_sym)
|
35
|
+
else
|
36
|
+
return nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# alias .to_s on Blob class to match OCI8 blob class's read method
|
43
|
+
module Sequel
|
44
|
+
module SQL
|
45
|
+
class Blob
|
46
|
+
alias :read :to_s
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/sakai-info/quiz.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
# SakaiInfo::Quiz library
|
3
3
|
#
|
4
4
|
# Created 2012-02-17 daveadams@gmail.com
|
5
|
-
# Last updated 2012-
|
5
|
+
# Last updated 2012-06-21 daveadams@gmail.com
|
6
6
|
#
|
7
7
|
# https://github.com/daveadams/sakai-info
|
8
8
|
#
|
@@ -113,11 +113,19 @@ module SakaiInfo
|
|
113
113
|
end
|
114
114
|
|
115
115
|
def section_count
|
116
|
-
@section_count ||=
|
116
|
+
@section_count ||= self.section_class.count_by_quiz_id(@id)
|
117
117
|
end
|
118
118
|
|
119
119
|
def sections
|
120
|
-
@sections ||=
|
120
|
+
@sections ||= self.section_class.find_by_quiz_id(@id)
|
121
|
+
end
|
122
|
+
|
123
|
+
def item_count
|
124
|
+
@item_count ||= self.item_class.count_by_quiz_id(self.id)
|
125
|
+
end
|
126
|
+
|
127
|
+
def items
|
128
|
+
@items ||= self.item_class.find_by_quiz_id(self.id)
|
121
129
|
end
|
122
130
|
|
123
131
|
def default_serialization
|
@@ -128,6 +136,7 @@ module SakaiInfo
|
|
128
136
|
"status" => self.status,
|
129
137
|
"type" => self.quiz_type,
|
130
138
|
"section_count" => self.section_count,
|
139
|
+
"item_count" => self.item_count,
|
131
140
|
"attempt_count" => nil
|
132
141
|
}
|
133
142
|
if not self.site.nil?
|
@@ -169,8 +178,18 @@ module SakaiInfo
|
|
169
178
|
}
|
170
179
|
end
|
171
180
|
|
181
|
+
def items_serialization
|
182
|
+
{
|
183
|
+
"items" => self.items.collect { |i| i.serialize(:quiz_summary) }
|
184
|
+
}
|
185
|
+
end
|
186
|
+
|
172
187
|
def self.all_serializations
|
173
|
-
[
|
188
|
+
[
|
189
|
+
:default,
|
190
|
+
:sections,
|
191
|
+
:items,
|
192
|
+
]
|
174
193
|
end
|
175
194
|
end
|
176
195
|
|
@@ -202,21 +221,30 @@ module SakaiInfo
|
|
202
221
|
end
|
203
222
|
|
204
223
|
def self.find_by_site_id(site_id)
|
205
|
-
|
206
|
-
PendingQuiz.query_by_site_id(site_id).all.each do |row|
|
224
|
+
PendingQuiz.query_by_site_id(site_id).all.collect do |row|
|
207
225
|
@@cache[row[:id]] = PendingQuiz.new(row, site_id)
|
208
|
-
results << @@cache[row[:id]]
|
209
226
|
end
|
210
|
-
results
|
211
227
|
end
|
212
228
|
|
213
229
|
def self.count_by_site_id(site_id)
|
214
230
|
PendingQuiz.query_by_site_id(site_id).count
|
215
231
|
end
|
216
232
|
|
233
|
+
def self.find_ids_by_site_id(site_id)
|
234
|
+
PendingQuiz.query_by_site_id(site_id).select(:id).all.collect { |row| row[:id] }
|
235
|
+
end
|
236
|
+
|
217
237
|
def quiz_type
|
218
238
|
"pending"
|
219
239
|
end
|
240
|
+
|
241
|
+
def section_class
|
242
|
+
PendingQuizSection
|
243
|
+
end
|
244
|
+
|
245
|
+
def item_class
|
246
|
+
PendingQuizItem
|
247
|
+
end
|
220
248
|
end
|
221
249
|
|
222
250
|
class PublishedQuiz < Quiz
|
@@ -248,22 +276,31 @@ module SakaiInfo
|
|
248
276
|
end
|
249
277
|
|
250
278
|
def self.find_by_site_id(site_id)
|
251
|
-
|
252
|
-
PublishedQuiz.query_by_site_id(site_id).all.each do |row|
|
279
|
+
PublishedQuiz.query_by_site_id(site_id).all.collect do |row|
|
253
280
|
@@cache[row[:id]] = PublishedQuiz.new(row, site_id)
|
254
|
-
results << @@cache[row[:id]]
|
255
281
|
end
|
256
|
-
results
|
257
282
|
end
|
258
283
|
|
259
284
|
def self.count_by_site_id(site_id)
|
260
285
|
PublishedQuiz.query_by_site_id(site_id).count
|
261
286
|
end
|
262
287
|
|
288
|
+
def self.find_ids_by_site_id(site_id)
|
289
|
+
PublishedQuiz.query_by_site_id(site_id).select(:id).all.collect { |row| row[:id] }
|
290
|
+
end
|
291
|
+
|
263
292
|
def quiz_type
|
264
293
|
"published"
|
265
294
|
end
|
266
295
|
|
296
|
+
def section_class
|
297
|
+
PublishedQuizSection
|
298
|
+
end
|
299
|
+
|
300
|
+
def item_class
|
301
|
+
PublishedQuizItem
|
302
|
+
end
|
303
|
+
|
267
304
|
def attempt_count
|
268
305
|
@attempt_count ||= QuizAttempt.count_by_quiz_id(self.id)
|
269
306
|
end
|
@@ -279,7 +316,12 @@ module SakaiInfo
|
|
279
316
|
end
|
280
317
|
|
281
318
|
def self.all_serializations
|
282
|
-
[
|
319
|
+
[
|
320
|
+
:default,
|
321
|
+
:sections,
|
322
|
+
:items,
|
323
|
+
:attempts,
|
324
|
+
]
|
283
325
|
end
|
284
326
|
end
|
285
327
|
|
@@ -335,12 +377,7 @@ module SakaiInfo
|
|
335
377
|
end
|
336
378
|
|
337
379
|
def self.find_by_quiz_id(quiz_id)
|
338
|
-
section_class =
|
339
|
-
PendingQuizSection
|
340
|
-
else
|
341
|
-
PublishedQuizSection
|
342
|
-
end
|
343
|
-
|
380
|
+
section_class = Quiz.find(quiz_id).section_class
|
344
381
|
QuizSection.query_by_quiz_id(quiz_id).all.collect do |row|
|
345
382
|
section_class.new(row)
|
346
383
|
end
|
@@ -355,11 +392,11 @@ module SakaiInfo
|
|
355
392
|
end
|
356
393
|
|
357
394
|
def item_count
|
358
|
-
@item_count ||= QuizItem.count_by_section_id(
|
395
|
+
@item_count ||= QuizItem.count_by_section_id(self.id)
|
359
396
|
end
|
360
397
|
|
361
398
|
def items
|
362
|
-
@items ||= QuizItem.find_by_section_id(
|
399
|
+
@items ||= QuizItem.find_by_section_id(self.id)
|
363
400
|
end
|
364
401
|
|
365
402
|
def default_serialization
|
@@ -393,7 +430,7 @@ module SakaiInfo
|
|
393
430
|
|
394
431
|
def items_serialization
|
395
432
|
{
|
396
|
-
"items" => self.items.collect{|i|i.serialize(:
|
433
|
+
"items" => self.items.collect{|i|i.serialize(:section_summary)}
|
397
434
|
}
|
398
435
|
end
|
399
436
|
|
@@ -534,15 +571,35 @@ module SakaiInfo
|
|
534
571
|
|
535
572
|
def self.find_by_quiz_id(quiz_id)
|
536
573
|
item_class = QuizItem.class_for_type(Quiz.find(quiz_id).quiz_type)
|
537
|
-
QuizItem.query_by_quiz_id(quiz_id).all.collect do |row|
|
574
|
+
QuizItem.query_by_quiz_id(quiz_id).order(:sequence).all.collect do |row|
|
538
575
|
item_class.new(row)
|
539
|
-
end
|
576
|
+
end.sort { |a,b| if a.section.sequence == b.section.sequence
|
577
|
+
a.sequence <=> b.sequence
|
578
|
+
else
|
579
|
+
a.section.sequence <=> b.section.sequence
|
580
|
+
end }
|
540
581
|
end
|
541
582
|
|
542
583
|
def item_type
|
543
584
|
nil
|
544
585
|
end
|
545
586
|
|
587
|
+
def itemtext_table
|
588
|
+
nil
|
589
|
+
end
|
590
|
+
|
591
|
+
def texts
|
592
|
+
if self.itemtext_table.nil?
|
593
|
+
return []
|
594
|
+
end
|
595
|
+
|
596
|
+
DB.connect[self.itemtext_table].
|
597
|
+
select(:text).
|
598
|
+
where(:itemid => self.id).
|
599
|
+
order(:sequence).all.
|
600
|
+
collect { |row| row[:text].read }
|
601
|
+
end
|
602
|
+
|
546
603
|
def default_serialization
|
547
604
|
{
|
548
605
|
"id" => self.id,
|
@@ -562,8 +619,33 @@ module SakaiInfo
|
|
562
619
|
}
|
563
620
|
end
|
564
621
|
|
622
|
+
def quiz_summary_serialization
|
623
|
+
{
|
624
|
+
"id" => self.id,
|
625
|
+
"section" => self.section.sequence,
|
626
|
+
"sequence" => self.sequence,
|
627
|
+
}
|
628
|
+
end
|
629
|
+
|
630
|
+
def section_summary_serialization
|
631
|
+
{
|
632
|
+
"id" => self.id,
|
633
|
+
"sequence" => self.sequence,
|
634
|
+
}
|
635
|
+
end
|
636
|
+
|
637
|
+
def texts_serialization
|
638
|
+
{
|
639
|
+
"texts" => self.texts
|
640
|
+
}
|
641
|
+
end
|
642
|
+
|
565
643
|
def self.all_serializations
|
566
|
-
[
|
644
|
+
[
|
645
|
+
:default,
|
646
|
+
:mod,
|
647
|
+
:texts
|
648
|
+
]
|
567
649
|
end
|
568
650
|
end
|
569
651
|
|
@@ -589,6 +671,10 @@ module SakaiInfo
|
|
589
671
|
def item_type
|
590
672
|
"pending"
|
591
673
|
end
|
674
|
+
|
675
|
+
def itemtext_table
|
676
|
+
:sam_itemtext_t
|
677
|
+
end
|
592
678
|
end
|
593
679
|
|
594
680
|
class PublishedQuizItem < QuizItem
|
@@ -613,6 +699,10 @@ module SakaiInfo
|
|
613
699
|
def item_type
|
614
700
|
"published"
|
615
701
|
end
|
702
|
+
|
703
|
+
def itemtext_table
|
704
|
+
:sam_publisheditemtext_t
|
705
|
+
end
|
616
706
|
end
|
617
707
|
|
618
708
|
# class QuizItemAttachment < SakaiObject
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# util.rb
|
2
|
+
# Utility methods
|
3
|
+
#
|
4
|
+
# Created 2012-05-20 daveadams@gmail.com
|
5
|
+
# Last updated 2012-05-20 daveadams@gmail.com
|
6
|
+
#
|
7
|
+
# https://github.com/daveadams/sakai-info
|
8
|
+
#
|
9
|
+
# This software is public domain.
|
10
|
+
#
|
11
|
+
|
12
|
+
module SakaiInfo
|
13
|
+
class Util
|
14
|
+
# misc support functions
|
15
|
+
FILESIZE_LABELS = ["bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]
|
16
|
+
def self.format_filesize(i_size)
|
17
|
+
size = i_size.to_f
|
18
|
+
negative = false
|
19
|
+
|
20
|
+
if size < 0
|
21
|
+
negative = true
|
22
|
+
size = -size
|
23
|
+
end
|
24
|
+
|
25
|
+
label = 0
|
26
|
+
(FILESIZE_LABELS.size - 1).times do
|
27
|
+
if size >= 1024.0
|
28
|
+
size = size / 1024.0
|
29
|
+
label += 1
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
if size >= 100.0 or label == 0
|
34
|
+
"#{negative ? "-" : ""}#{size.to_i.to_s} #{FILESIZE_LABELS[label]}"
|
35
|
+
else
|
36
|
+
"#{negative ? "-" : ""}#{sprintf("%.1f", size)} #{FILESIZE_LABELS[label]}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.format_entity_date(raw)
|
41
|
+
if raw =~ /^(....)(..)(..)(..)(..)(..).*$/
|
42
|
+
# I believe these are usually in UTC
|
43
|
+
Time.utc($1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i).getlocal
|
44
|
+
else
|
45
|
+
raw
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
data/lib/sakai-info/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sakai-info
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-06-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: sequel
|
@@ -52,10 +52,16 @@ extensions: []
|
|
52
52
|
extra_rdoc_files: []
|
53
53
|
files:
|
54
54
|
- lib/sakai-info.rb
|
55
|
+
- lib/sakai-info/util.rb
|
55
56
|
- lib/sakai-info/group.rb
|
56
57
|
- lib/sakai-info/tool.rb
|
57
58
|
- lib/sakai-info/cli/help.rb
|
59
|
+
- lib/sakai-info/cli/query.rb
|
60
|
+
- lib/sakai-info/cli/special.rb
|
61
|
+
- lib/sakai-info/cli/lookup.rb
|
58
62
|
- lib/sakai-info/site.rb
|
63
|
+
- lib/sakai-info/cache.rb
|
64
|
+
- lib/sakai-info/exceptions.rb
|
59
65
|
- lib/sakai-info/assignment.rb
|
60
66
|
- lib/sakai-info/authz.rb
|
61
67
|
- lib/sakai-info/gradebook.rb
|
@@ -64,6 +70,7 @@ files:
|
|
64
70
|
- lib/sakai-info/sakai_object.rb
|
65
71
|
- lib/sakai-info/quiz.rb
|
66
72
|
- lib/sakai-info/user.rb
|
73
|
+
- lib/sakai-info/hacks.rb
|
67
74
|
- lib/sakai-info/version.rb
|
68
75
|
- lib/sakai-info/announcement.rb
|
69
76
|
- lib/sakai-info/database.rb
|