sakai-info 0.4.6 → 0.5.0
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.
- 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
|