sakai-info 0.3.0 → 0.3.1
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 +11 -0
- data/README.md +2 -2
- data/ROADMAP.md +17 -5
- data/bin/sakai-info +2 -2
- data/lib/sakai-info.rb +1 -1
- data/lib/sakai-info/assignment.rb +89 -86
- data/lib/sakai-info/cli.rb +6 -1
- data/lib/sakai-info/cli/help.rb +83 -7
- data/lib/sakai-info/mod_props.rb +11 -2
- data/lib/sakai-info/quiz.rb +327 -8
- data/lib/sakai-info/sakai_object.rb +9 -1
- data/lib/sakai-info/sakai_xml_entity.rb +44 -39
- data/lib/sakai-info/site.rb +3 -3
- data/lib/sakai-info/version.rb +1 -1
- metadata +4 -4
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
# sakai-info Change History #
|
2
2
|
|
3
|
+
## 0.3.1 ##
|
4
|
+
|
5
|
+
*Released 2012-02-29*
|
6
|
+
|
7
|
+
* New objects: quiz-attempt, quiz-attempt-item, quiz-attempt-item-attachment
|
8
|
+
* More new objects: assignment, assignment-submission
|
9
|
+
* SakaiXMLEntity base class supports ModProps
|
10
|
+
* New standard CL arguments: --dbrow-only and --mod-details
|
11
|
+
* First steps towards a sqlite test infrastructure: schema creation
|
12
|
+
* First steps towards better Sakai DB docs: graphviz file for quiz tables
|
13
|
+
|
3
14
|
## 0.3.0 ##
|
4
15
|
|
5
16
|
*Released 2012-02-26*
|
data/README.md
CHANGED
@@ -10,7 +10,7 @@ tool or the libraries.
|
|
10
10
|
|
11
11
|
## Meta ##
|
12
12
|
|
13
|
-
last updated: 2012-02-
|
13
|
+
last updated: 2012-02-29
|
14
14
|
author: David Adams (daveadams@gmail.com)
|
15
15
|
github url: https://github.com/daveadams/sakai-info
|
16
16
|
|
@@ -26,7 +26,7 @@ Use `rake` to test and build the gem:
|
|
26
26
|
$ rake gem:build
|
27
27
|
|
28
28
|
The resulting gem will be saved to the working directory as
|
29
|
-
`sakai-info-0.3.
|
29
|
+
`sakai-info-0.3.1.gem`.
|
30
30
|
|
31
31
|
Cleanup built gems using:
|
32
32
|
|
data/ROADMAP.md
CHANGED
@@ -1,10 +1,6 @@
|
|
1
1
|
# sakai-info Roadmap #
|
2
2
|
|
3
|
-
*Last updated 2012-02-
|
4
|
-
|
5
|
-
### 0.3.1 ###
|
6
|
-
|
7
|
-
* CLI access to assignments
|
3
|
+
*Last updated 2012-02-29*
|
8
4
|
|
9
5
|
### 0.3.2 ###
|
10
6
|
|
@@ -18,6 +14,22 @@
|
|
18
14
|
|
19
15
|
* CLI access to forums
|
20
16
|
|
17
|
+
### 0.3.5 ###
|
18
|
+
|
19
|
+
* CLI access to gradebook
|
20
|
+
|
21
|
+
### 0.3.6 ###
|
22
|
+
|
23
|
+
* CLI access to announcements
|
24
|
+
|
25
|
+
### 0.3.7 ###
|
26
|
+
|
27
|
+
* CLI access to content
|
28
|
+
|
29
|
+
### 0.3.8 ###
|
30
|
+
|
31
|
+
* CLI access to authz (realms, roles, functions)
|
32
|
+
|
21
33
|
### 0.4 ###
|
22
34
|
|
23
35
|
* Standardized abstraction for user and site to support --mod and --dbrow
|
data/bin/sakai-info
CHANGED
@@ -140,9 +140,9 @@ if flags.include? "--all"
|
|
140
140
|
serials = CLI::ObjectModes[mode].all_serializations
|
141
141
|
elsif
|
142
142
|
flags.include? "--dbrow-only"
|
143
|
-
serials = [:
|
143
|
+
serials = [:dbrow_only]
|
144
144
|
else
|
145
|
-
serials = [:default] + flags.collect{|flag|flag.gsub(/^--/,'').to_sym}
|
145
|
+
serials = [:default] + flags.collect{|flag|flag.gsub(/^--/,'').gsub("-","_").to_sym}
|
146
146
|
end
|
147
147
|
begin
|
148
148
|
puts CLI::ObjectModes[mode].find(id).to_yaml(serials)
|
data/lib/sakai-info.rb
CHANGED
@@ -73,9 +73,9 @@ end
|
|
73
73
|
require 'sakai-info/database'
|
74
74
|
|
75
75
|
# base objects
|
76
|
+
require 'sakai-info/mod_props'
|
76
77
|
require 'sakai-info/sakai_object'
|
77
78
|
require 'sakai-info/sakai_xml_entity'
|
78
|
-
require 'sakai-info/mod_props'
|
79
79
|
|
80
80
|
# sakai object classes
|
81
81
|
require 'sakai-info/user'
|
@@ -2,7 +2,7 @@
|
|
2
2
|
# SakaiInfo::Assignment library
|
3
3
|
#
|
4
4
|
# Created 2012-02-17 daveadams@gmail.com
|
5
|
-
# Last updated 2012-02-
|
5
|
+
# Last updated 2012-02-29 daveadams@gmail.com
|
6
6
|
#
|
7
7
|
# https://github.com/daveadams/sakai-info
|
8
8
|
#
|
@@ -11,46 +11,43 @@
|
|
11
11
|
|
12
12
|
module SakaiInfo
|
13
13
|
class Assignment < SakaiXMLEntity
|
14
|
-
attr_reader :
|
14
|
+
attr_reader :dbrow, :site_id
|
15
15
|
|
16
16
|
@@cache = {}
|
17
17
|
def self.find(id)
|
18
18
|
if @@cache[id].nil?
|
19
19
|
xml = ""
|
20
|
-
row = DB.connect[:
|
20
|
+
row = DB.connect[:assignment_assignment].where(:assignment_id => id).first
|
21
21
|
if row.nil?
|
22
22
|
raise ObjectNotFoundException.new(Assignment, id)
|
23
23
|
end
|
24
|
-
|
25
|
-
REXML::Document.new(row[:xml].read).write(xml, 2)
|
26
|
-
@@cache[id] = Assignment.new(id, site, xml)
|
24
|
+
@@cache[id] = Assignment.new(row)
|
27
25
|
end
|
28
26
|
@@cache[id]
|
29
27
|
end
|
30
28
|
|
31
29
|
# raw data constructor
|
32
|
-
def initialize(
|
33
|
-
@
|
34
|
-
|
35
|
-
@
|
30
|
+
def initialize(dbrow)
|
31
|
+
@dbrow = dbrow
|
32
|
+
|
33
|
+
@id = dbrow[:assignment_id]
|
34
|
+
@site_id = dbrow[:context]
|
35
|
+
|
36
36
|
parse_xml
|
37
37
|
end
|
38
38
|
|
39
39
|
# set lookup
|
40
|
+
def self.query_by_site_id(site_id)
|
41
|
+
DB.connect[:assignment_assignment].where(:context => site_id)
|
42
|
+
end
|
43
|
+
|
40
44
|
def self.find_by_site_id(site_id)
|
41
|
-
|
42
|
-
|
43
|
-
DB.connect[:assignment_assignment].filter(:context => site_id).all.each do |row|
|
44
|
-
id = row[:assignment_id]
|
45
|
-
xml = ""
|
46
|
-
REXML::Document.new(row[:xml].read).write(xml, 2)
|
47
|
-
assignments << Assignment.new(id, site, xml)
|
48
|
-
end
|
49
|
-
return assignments
|
45
|
+
Assignment.query_by_site_id(site_id).
|
46
|
+
all.collect { |row| Assignment.new(row) }
|
50
47
|
end
|
51
48
|
|
52
49
|
def self.count_by_site_id(site_id)
|
53
|
-
|
50
|
+
Assignment.query_by_site_id(site_id).count
|
54
51
|
end
|
55
52
|
|
56
53
|
# getters
|
@@ -58,12 +55,16 @@ module SakaiInfo
|
|
58
55
|
@attributes["title"]
|
59
56
|
end
|
60
57
|
|
58
|
+
def site
|
59
|
+
@site ||= Site.find(self.site_id)
|
60
|
+
end
|
61
|
+
|
61
62
|
def submissions
|
62
|
-
@submissions ||= AssignmentSubmission.find_by_assignment_id(
|
63
|
+
@submissions ||= AssignmentSubmission.find_by_assignment_id(self.id)
|
63
64
|
end
|
64
65
|
|
65
66
|
def submission_count
|
66
|
-
@submission_count ||= AssignmentSubmission.count_by_assignment_id(
|
67
|
+
@submission_count ||= AssignmentSubmission.count_by_assignment_id(self.id)
|
67
68
|
end
|
68
69
|
|
69
70
|
# yaml/json serialization
|
@@ -72,9 +73,7 @@ module SakaiInfo
|
|
72
73
|
"id" => self.id,
|
73
74
|
"title" => self.title,
|
74
75
|
"site" => self.site.serialize(:summary),
|
75
|
-
"
|
76
|
-
"created_at" => self.created_at,
|
77
|
-
"submissions" => self.submission_count
|
76
|
+
"submission_count" => self.submission_count
|
78
77
|
}
|
79
78
|
end
|
80
79
|
|
@@ -82,118 +81,122 @@ module SakaiInfo
|
|
82
81
|
{
|
83
82
|
"id" => self.id,
|
84
83
|
"title" => self.title,
|
85
|
-
"
|
86
|
-
|
84
|
+
"submission_count" => self.submission_count
|
85
|
+
}
|
86
|
+
end
|
87
|
+
|
88
|
+
def submissions_serialization
|
89
|
+
{
|
90
|
+
"submissions" => self.submissions.collect{|s|s.serialize(:assignment_summary)}
|
87
91
|
}
|
88
92
|
end
|
89
93
|
end
|
90
94
|
|
91
95
|
class AssignmentSubmission < SakaiXMLEntity
|
92
|
-
attr_reader :
|
96
|
+
attr_reader :dbrow, :assignment_id, :submitter_id
|
97
|
+
|
98
|
+
def initialize(dbrow)
|
99
|
+
@dbrow = dbrow
|
100
|
+
|
101
|
+
@id = dbrow[:submission_id]
|
102
|
+
@assignment_id = dbrow[:context]
|
103
|
+
@submitter_id = dbrow[:submitter_id]
|
104
|
+
@is_submitted = (dbrow[:submitted] == "true")
|
105
|
+
@is_graded = (dbrow[:graded] == "true")
|
93
106
|
|
94
|
-
def initialize(id, assignment, xml, submitter, submitted, graded)
|
95
|
-
@id = id
|
96
|
-
@assignment = assignment
|
97
|
-
@xml = xml
|
98
|
-
@submitter = submitter
|
99
|
-
@submitted = submitted
|
100
|
-
@graded = graded
|
101
107
|
parse_xml
|
102
108
|
end
|
103
109
|
|
104
110
|
@@cache = {}
|
105
111
|
def self.find(id)
|
106
112
|
if @@cache[id].nil?
|
107
|
-
|
108
|
-
xml = ""
|
109
|
-
row = DB.connect[:assignment_submission].filter(:submission_id => id).first
|
113
|
+
row = DB.connect[:assignment_submission].where(:submission_id => id).first
|
110
114
|
if row.nil?
|
111
115
|
raise ObjectNotFoundException.new(AssignmentSubmission, id)
|
112
116
|
end
|
113
117
|
|
114
|
-
|
115
|
-
REXML::Document.new(row[:xml].read).write(xml, 2)
|
116
|
-
submitter = User.find(row[:submitter_id])
|
117
|
-
submitted = (row[:submitted] == "true")
|
118
|
-
graded = (row[:graded] == "true")
|
119
|
-
|
120
|
-
@@cache[id] = AssignmentSubmission.new(id, assignment, xml, submitter, submitted, graded)
|
118
|
+
@@cache[id] = AssignmentSubmission.new(row)
|
121
119
|
end
|
122
120
|
@@cache[id]
|
123
121
|
end
|
124
122
|
|
123
|
+
def submitter
|
124
|
+
@submitter ||= User.find(self.submitter_id)
|
125
|
+
end
|
126
|
+
|
127
|
+
def assignment
|
128
|
+
@assignment ||= Assignment.find(self.assignment_id)
|
129
|
+
end
|
130
|
+
|
125
131
|
def submitted?
|
126
|
-
(
|
132
|
+
( self.created_by_id == self.submitter_id && @is_submitted ) || false
|
127
133
|
end
|
128
134
|
|
129
135
|
def graded?
|
130
|
-
@
|
136
|
+
@is_graded || false
|
131
137
|
end
|
132
138
|
|
133
139
|
def submitted_at
|
134
140
|
@submitted_at ||= format_entity_date(@attributes["datesubmitted"])
|
135
141
|
end
|
136
142
|
|
143
|
+
def self.query_by_assignment_id(assignment_id)
|
144
|
+
DB.connect[:assignment_submission].where(:context => assignment_id)
|
145
|
+
end
|
146
|
+
|
137
147
|
def self.find_by_assignment_id(assignment_id)
|
138
|
-
|
139
|
-
|
140
|
-
DB.connect[:assignment_submission].filter(:context => assignment_id).all.each do |row|
|
141
|
-
id = row[:submission_id]
|
142
|
-
xml = ""
|
143
|
-
REXML::Document.new(row[:xml].read).write(xml, 2)
|
144
|
-
submitter = User.find(row[:submitter_id])
|
145
|
-
submitted = (row[:submitted] == "true")
|
146
|
-
graded = (row[:graded] == "true")
|
147
|
-
submissions << AssignmentSubmission.new(id, assignment, xml, submitter, submitted, graded)
|
148
|
-
end
|
149
|
-
return submissions
|
148
|
+
AssignmentSubmission.query_by_assignment_id(assignment_id).
|
149
|
+
all.collect { |row| AssignmentSubmission.new(row) }
|
150
150
|
end
|
151
151
|
|
152
152
|
def self.count_by_assignment_id(assignment_id)
|
153
|
-
|
153
|
+
AssignmentSubmission.query_by_assignment_id(assignment_id).count
|
154
|
+
end
|
155
|
+
|
156
|
+
def self.query_by_user_id(user_id)
|
157
|
+
DB.connect[:assignment_submission].where(:submitter_id => user_id)
|
154
158
|
end
|
155
159
|
|
156
160
|
def self.find_by_user_id(user_id)
|
157
|
-
|
158
|
-
|
159
|
-
DB.connect[:assignment_submission].filter(:submitter_id => user_id).all.each do |row|
|
160
|
-
id = row[:submission_id]
|
161
|
-
assignment = Assignment.find(row[:context])
|
162
|
-
xml = ""
|
163
|
-
REXML::Document.new(row[:xml].read).write(xml, 2)
|
164
|
-
submitted = (row[:submitted] == "true")
|
165
|
-
graded = (row[:graded] == "true")
|
166
|
-
submissions << AssignmentSubmission.new(id, assignment, xml, submitter, submitted, graded)
|
167
|
-
end
|
168
|
-
return submissions
|
161
|
+
AssignmentSubmission.query_by_user_id(user_id).
|
162
|
+
all.collect { |row| AssignmentSubmission.new(row) }
|
169
163
|
end
|
170
164
|
|
171
165
|
def self.count_by_user_id(user_id)
|
172
|
-
|
166
|
+
AssignmentSubmission.query_by_user_id(user_id).count
|
173
167
|
end
|
174
168
|
|
175
169
|
# yaml/json serialization
|
176
170
|
def default_serialization
|
177
|
-
{
|
171
|
+
result = {
|
178
172
|
"id" => self.id,
|
179
173
|
"assignment" => self.assignment.serialize(:summary),
|
180
174
|
"submitter" => self.submitter.serialize(:summary),
|
181
|
-
"
|
175
|
+
"is_submitted" => self.submitted?,
|
182
176
|
"submitted_at" => self.submitted_at,
|
183
|
-
"
|
184
|
-
"created_by" => self.created_by.eid,
|
185
|
-
"created_at" => self.created_at,
|
186
|
-
"modified_by" => self.modified_by.eid,
|
187
|
-
"modified_at" => self.modified_at
|
177
|
+
"is_graded" => self.graded?,
|
188
178
|
}
|
179
|
+
if not self.submitted?
|
180
|
+
result.delete("submitted_at")
|
181
|
+
result.delete("is_graded")
|
182
|
+
end
|
183
|
+
result
|
189
184
|
end
|
190
185
|
|
191
186
|
def summary_serialization
|
192
187
|
{
|
193
188
|
"id" => self.id,
|
194
|
-
"assignment_id" => self.
|
195
|
-
"submitter" => self.
|
196
|
-
"
|
189
|
+
"assignment_id" => self.assignment_id,
|
190
|
+
"submitter" => User.get_eid(self.submitter_id),
|
191
|
+
"is_submitted" => self.submitted?
|
192
|
+
}
|
193
|
+
end
|
194
|
+
|
195
|
+
def assignment_summary_serialization
|
196
|
+
{
|
197
|
+
"id" => self.id,
|
198
|
+
"submitter" => User.get_eid(self.submitter_id),
|
199
|
+
"is_submitted" => self.submitted?
|
197
200
|
}
|
198
201
|
end
|
199
202
|
end
|
@@ -211,7 +214,7 @@ module SakaiInfo
|
|
211
214
|
@@cache = {}
|
212
215
|
def self.find(id)
|
213
216
|
if @@cache[id].nil?
|
214
|
-
row = DB.connect[:assignment_content].
|
217
|
+
row = DB.connect[:assignment_content].where(:content_id => id).first
|
215
218
|
if row.nil?
|
216
219
|
raise ObjectNotFoundException.new(AssignmentContent, id)
|
217
220
|
end
|
@@ -224,7 +227,7 @@ module SakaiInfo
|
|
224
227
|
|
225
228
|
def self.find_by_user_id(user_id)
|
226
229
|
contents = []
|
227
|
-
DB.connect[:assignment_content].
|
230
|
+
DB.connect[:assignment_content].where(:context => user_id).all.each do |row|
|
228
231
|
id = row[:content_id]
|
229
232
|
context = row[:context]
|
230
233
|
xml = ""
|
@@ -235,7 +238,7 @@ module SakaiInfo
|
|
235
238
|
end
|
236
239
|
|
237
240
|
def self.count_by_user_id(user_id)
|
238
|
-
DB.connect[:assignment_content].
|
241
|
+
DB.connect[:assignment_content].where(:context => user_id).count
|
239
242
|
end
|
240
243
|
|
241
244
|
# getters
|
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-02-
|
5
|
+
# Last updated 2012-02-29 daveadams@gmail.com
|
6
6
|
#
|
7
7
|
# https://github.com/daveadams/sakai-info
|
8
8
|
#
|
@@ -19,8 +19,13 @@ module SakaiInfo
|
|
19
19
|
"quiz" => Quiz,
|
20
20
|
"quiz-section" => QuizSection,
|
21
21
|
"quiz-item" => QuizItem,
|
22
|
+
"quiz-attempt" => QuizAttempt,
|
23
|
+
"quiz-attempt-item" => QuizAttemptItem,
|
24
|
+
"quiz-attempt-item-attachment" => QuizAttemptItemAttachment,
|
22
25
|
"qpool" => QuestionPool,
|
23
26
|
"question-pool" => QuestionPool,
|
27
|
+
"assignment" => Assignment,
|
28
|
+
"assignment-submission" => AssignmentSubmission,
|
24
29
|
}
|
25
30
|
end
|
26
31
|
end
|
data/lib/sakai-info/cli/help.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
# - sakai-info command line help
|
3
3
|
#
|
4
4
|
# Created 2012-02-19 daveadams@gmail.com
|
5
|
-
# Last updated 2012-02-
|
5
|
+
# Last updated 2012-02-29 daveadams@gmail.com
|
6
6
|
#
|
7
7
|
# https://github.com/daveadams/sakai-info
|
8
8
|
#
|
@@ -21,11 +21,22 @@ sakai-info #{VERSION}
|
|
21
21
|
Object commands:
|
22
22
|
user User information
|
23
23
|
site Site information
|
24
|
+
|
24
25
|
quiz Quiz aka Assessment information, pending or published
|
25
26
|
quiz-section Quiz section information, pending or published
|
26
27
|
quiz-item Quiz item information, pending or published
|
28
|
+
quiz-attempt Quiz attempt information
|
29
|
+
quiz-attempt-item
|
30
|
+
Information on attempted quiz items
|
31
|
+
quiz-attempt-item-attachment
|
32
|
+
Information on file attachments to attempted quiz items
|
33
|
+
|
27
34
|
question-pool Question Pool information
|
28
35
|
|
36
|
+
assignment Assignment information
|
37
|
+
assignment-submission
|
38
|
+
Assignment submission information
|
39
|
+
|
29
40
|
Misc commands:
|
30
41
|
test Tests configured database connections
|
31
42
|
help Prints general help
|
@@ -45,11 +56,17 @@ sakai-info #{VERSION}
|
|
45
56
|
trace log to STDOUT.
|
46
57
|
|
47
58
|
Options that work on most object types:
|
59
|
+
--dbrow
|
60
|
+
Print the raw database fields in addition to the usual summary.
|
61
|
+
|
48
62
|
--dbrow-only
|
49
63
|
Print only the raw database fields for the object requested.
|
50
64
|
|
51
65
|
--mod
|
52
|
-
Print creation and modification
|
66
|
+
Print creation and modification user EIDs and timestamps.
|
67
|
+
|
68
|
+
--mod-details
|
69
|
+
Print creation and modification user details and timestamps.
|
53
70
|
|
54
71
|
--all
|
55
72
|
Print all possible information (other than dbrow)
|
@@ -126,13 +143,12 @@ sakai-info quiz
|
|
126
143
|
include additional information:
|
127
144
|
|
128
145
|
--sections Print section summary list
|
146
|
+
--attempts Print summary of user quiz attempts
|
129
147
|
--mod Print creation/modification info
|
130
148
|
--all Print all possible details
|
131
|
-
--dbrow Print the raw database fields
|
132
149
|
|
133
150
|
Not yet implemented:
|
134
151
|
--items Print summary of items on the quiz
|
135
|
-
--attempts Print summary of user quiz attempts (for published quizzes)
|
136
152
|
EOF
|
137
153
|
|
138
154
|
"quiz-section" => <<EOF,
|
@@ -147,7 +163,6 @@ sakai-info quiz-section
|
|
147
163
|
--items Print summary of items in the section
|
148
164
|
--mod Print creation/modification info
|
149
165
|
--all Print all possible details
|
150
|
-
--dbrow Print the raw database fields
|
151
166
|
EOF
|
152
167
|
|
153
168
|
"quiz-item" => <<EOF,
|
@@ -161,7 +176,6 @@ sakai-info quiz-item
|
|
161
176
|
|
162
177
|
--mod Print creation/modification info
|
163
178
|
--all Print all possible details
|
164
|
-
--dbrow Print the raw database fields
|
165
179
|
EOF
|
166
180
|
|
167
181
|
"question-pool" => <<EOF,
|
@@ -174,7 +188,6 @@ sakai-info question-pool
|
|
174
188
|
may be passed to include additional information:
|
175
189
|
|
176
190
|
--mod Print creation/modification info
|
177
|
-
--dbrow Print the raw database fields
|
178
191
|
|
179
192
|
Not yet implemented:
|
180
193
|
--items Print summary of items in the pool
|
@@ -182,6 +195,69 @@ sakai-info question-pool
|
|
182
195
|
--all Print all possible details
|
183
196
|
EOF
|
184
197
|
|
198
|
+
"quiz-attempt" => <<EOF,
|
199
|
+
sakai-info quiz-attempt
|
200
|
+
|
201
|
+
Usage: sakai-info quiz-attempt <id> [<options>]
|
202
|
+
|
203
|
+
Prints information about the quiz attempt ID specified. Additional options
|
204
|
+
may be passed to include additional information:
|
205
|
+
|
206
|
+
--items Print list of attempted items
|
207
|
+
--all Print all possible details
|
208
|
+
EOF
|
209
|
+
|
210
|
+
|
211
|
+
"quiz-attempt-item" => <<EOF,
|
212
|
+
sakai-info quiz-attempt-item
|
213
|
+
|
214
|
+
Usage: sakai-info quiz-attempt-item <id> [<options>]
|
215
|
+
|
216
|
+
Prints information about the quiz attempt item ID specified. Additional
|
217
|
+
options may be passed to include additional information:
|
218
|
+
|
219
|
+
--attachments Print a list of file attachments, if any
|
220
|
+
--all Print all possible details
|
221
|
+
EOF
|
222
|
+
|
223
|
+
"quiz-attempt-item-attachment" => <<EOF,
|
224
|
+
sakai-info quiz-attempt-item-attachment
|
225
|
+
|
226
|
+
Usage: sakai-info quiz-attempt-item-attachment <id> [<options>]
|
227
|
+
|
228
|
+
Prints information about the quiz attempt item attachment ID specified.
|
229
|
+
Additional options may be passed to include additional information:
|
230
|
+
|
231
|
+
--mod Print creation/modification info
|
232
|
+
--all Print all possible details
|
233
|
+
EOF
|
234
|
+
|
235
|
+
"assignment" => <<EOF,
|
236
|
+
sakai-info assignment
|
237
|
+
|
238
|
+
Usage: sakai-info assignment <id> [<options>]
|
239
|
+
|
240
|
+
Prints information about the assignment ID specified. Additional options
|
241
|
+
may be passed to include additional information:
|
242
|
+
|
243
|
+
--submissions Print summary of all submissions
|
244
|
+
--xml Print the raw XML
|
245
|
+
--mod Print creation/modification info
|
246
|
+
--all Print all possible details
|
247
|
+
EOF
|
248
|
+
|
249
|
+
"assignment-submission" => <<EOF,
|
250
|
+
sakai-info assignment-submission
|
251
|
+
|
252
|
+
Usage: sakai-info assignment-submission <id> [<options>]
|
253
|
+
|
254
|
+
Prints information about the assignment submission ID specified. Additional
|
255
|
+
options may be passed to include additional information:
|
256
|
+
|
257
|
+
--xml Print the raw XML
|
258
|
+
--mod Print creation/modification info
|
259
|
+
--all Print all possible details
|
260
|
+
EOF
|
185
261
|
}
|
186
262
|
|
187
263
|
def self.help(topic = :default, io = STDOUT)
|
data/lib/sakai-info/mod_props.rb
CHANGED
@@ -61,10 +61,19 @@ module SakaiInfo
|
|
61
61
|
|
62
62
|
def mod_serialization
|
63
63
|
{
|
64
|
+
"created_at" => self.created_at,
|
65
|
+
"created_by" => User.get_eid(self.created_by_id),
|
66
|
+
"modified_at" => self.modified_at,
|
67
|
+
"modified_by" => User.get_eid(self.modified_by_id),
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
def mod_details_serialization
|
72
|
+
{
|
73
|
+
"created_at" => self.created_at,
|
64
74
|
"created_by" => self.created_by.serialize(:summary),
|
65
|
-
"
|
75
|
+
"modified_at" => self.modified_at,
|
66
76
|
"modified_by" => self.modified_by.serialize(:summary),
|
67
|
-
"modified_at" => self.modified_at.strftime("%Y-%m-%d %H:%M:%S")
|
68
77
|
}
|
69
78
|
end
|
70
79
|
}
|
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-02-
|
5
|
+
# Last updated 2012-02-28 daveadams@gmail.com
|
6
6
|
#
|
7
7
|
# https://github.com/daveadams/sakai-info
|
8
8
|
#
|
@@ -107,11 +107,17 @@ module SakaiInfo
|
|
107
107
|
"title" => self.title,
|
108
108
|
"site" => nil,
|
109
109
|
"type" => self.quiz_type,
|
110
|
-
"section_count" => self.section_count
|
110
|
+
"section_count" => self.section_count,
|
111
|
+
"attempt_count" => nil
|
111
112
|
}
|
112
113
|
if not self.site.nil?
|
113
114
|
result["site"] = self.site.serialize(:summary)
|
114
115
|
end
|
116
|
+
if self.respond_to? :attempt_count
|
117
|
+
result["attempt_count"] = self.attempt_count
|
118
|
+
else
|
119
|
+
result.delete("attempt_count")
|
120
|
+
end
|
115
121
|
result
|
116
122
|
end
|
117
123
|
|
@@ -140,6 +146,10 @@ module SakaiInfo
|
|
140
146
|
"sections" => self.sections.collect{|s|s.serialize(:quiz_summary)}
|
141
147
|
}
|
142
148
|
end
|
149
|
+
|
150
|
+
def self.all_serializations
|
151
|
+
[:default, :sections]
|
152
|
+
end
|
143
153
|
end
|
144
154
|
|
145
155
|
class PendingQuiz < Quiz
|
@@ -223,6 +233,24 @@ module SakaiInfo
|
|
223
233
|
def quiz_type
|
224
234
|
"published"
|
225
235
|
end
|
236
|
+
|
237
|
+
def attempt_count
|
238
|
+
@attempt_count ||= QuizAttempt.count_by_quiz_id(self.id)
|
239
|
+
end
|
240
|
+
|
241
|
+
def attempts
|
242
|
+
@attempts ||= QuizAttempt.find_by_quiz_id(self.id)
|
243
|
+
end
|
244
|
+
|
245
|
+
def attempts_serialization
|
246
|
+
{
|
247
|
+
"attempts" => self.attempts.collect { |a| a.serialize(:quiz_summary) }
|
248
|
+
}
|
249
|
+
end
|
250
|
+
|
251
|
+
def self.all_serializations
|
252
|
+
[:default, :sections, :attempts]
|
253
|
+
end
|
226
254
|
end
|
227
255
|
|
228
256
|
class QuizSection < SakaiObject
|
@@ -256,7 +284,7 @@ module SakaiInfo
|
|
256
284
|
begin
|
257
285
|
@@cache[id] = PublishedQuizSection.find(id)
|
258
286
|
rescue ObjectNotFoundException
|
259
|
-
raise ObjectNotFoundException(QuizSection, id)
|
287
|
+
raise ObjectNotFoundException.new(QuizSection, id)
|
260
288
|
end
|
261
289
|
end
|
262
290
|
end
|
@@ -347,7 +375,7 @@ module SakaiInfo
|
|
347
375
|
if @@cache[id].nil?
|
348
376
|
row = DB.connect[:sam_section_t].where(:sectionid => id).first
|
349
377
|
if row.nil?
|
350
|
-
raise ObjectNotFoundException(PendingQuizSection, id)
|
378
|
+
raise ObjectNotFoundException.new(PendingQuizSection, id)
|
351
379
|
end
|
352
380
|
|
353
381
|
@@cache[id] = PendingQuizSection.new(row)
|
@@ -367,7 +395,7 @@ module SakaiInfo
|
|
367
395
|
if @@cache[id].nil?
|
368
396
|
row = DB.connect[:sam_publishedsection_t].where(:sectionid => id).first
|
369
397
|
if row.nil?
|
370
|
-
raise ObjectNotFoundException(PublishedQuizSection, id)
|
398
|
+
raise ObjectNotFoundException.new(PublishedQuizSection, id)
|
371
399
|
end
|
372
400
|
|
373
401
|
@@cache[id] = PublishedQuizSection.new(row)
|
@@ -409,7 +437,7 @@ module SakaiInfo
|
|
409
437
|
begin
|
410
438
|
@@cache[id] = PublishedQuizItem.find(id)
|
411
439
|
rescue ObjectNotFoundException
|
412
|
-
raise ObjectNotFoundException(QuizItem, id)
|
440
|
+
raise ObjectNotFoundException.new(QuizItem, id)
|
413
441
|
end
|
414
442
|
end
|
415
443
|
end
|
@@ -500,7 +528,7 @@ module SakaiInfo
|
|
500
528
|
if @@cache[id].nil?
|
501
529
|
row = DB.connect[:sam_item_t].where(:itemid => id).first
|
502
530
|
if row.nil?
|
503
|
-
raise ObjectNotFoundException(PendingQuizItem, id)
|
531
|
+
raise ObjectNotFoundException.new(PendingQuizItem, id)
|
504
532
|
end
|
505
533
|
|
506
534
|
@@cache[id] = PendingQuizItem.new(row)
|
@@ -520,7 +548,7 @@ module SakaiInfo
|
|
520
548
|
if @@cache[id].nil?
|
521
549
|
row = DB.connect[:sam_publisheditem_t].where(:itemid => id).first
|
522
550
|
if row.nil?
|
523
|
-
raise ObjectNotFoundException(PublishedQuizItem, id)
|
551
|
+
raise ObjectNotFoundException.new(PublishedQuizItem, id)
|
524
552
|
end
|
525
553
|
|
526
554
|
@@cache[id] = PublishedQuizItem.new(row)
|
@@ -532,4 +560,295 @@ module SakaiInfo
|
|
532
560
|
"published"
|
533
561
|
end
|
534
562
|
end
|
563
|
+
|
564
|
+
# class QuizItemAttachment < SakaiObject
|
565
|
+
# end
|
566
|
+
|
567
|
+
# class PendingQuizItemAttachment < QuizItemAttachment
|
568
|
+
# end
|
569
|
+
|
570
|
+
# class PublishedQuizItemAttachment < QuizItemAttachment
|
571
|
+
# end
|
572
|
+
|
573
|
+
class QuizAttempt < SakaiObject
|
574
|
+
attr_reader :dbrow, :submitted_at, :total_auto_score, :status, :attempted_at
|
575
|
+
attr_reader :time_elapsed, :comments, :user_id, :quiz_id
|
576
|
+
|
577
|
+
def initialize(dbrow)
|
578
|
+
@dbrow = dbrow
|
579
|
+
|
580
|
+
@id = dbrow[:assessmentgradingid]
|
581
|
+
@submitted_at = dbrow[:submitteddate]
|
582
|
+
@user_id = dbrow[:agentid]
|
583
|
+
@quiz_id = dbrow[:publishedassessmentid]
|
584
|
+
@total_auto_score = dbrow[:totalautoscore]
|
585
|
+
@status = dbrow[:status]
|
586
|
+
@attempted_at = dbrow[:attempted_at]
|
587
|
+
@time_elapsed = dbrow[:timeelapsed]
|
588
|
+
@is_auto_submitted = dbrow[:is_auto_submitted]
|
589
|
+
@is_late = dbrow[:islate]
|
590
|
+
@comments = dbrow[:comments]
|
591
|
+
end
|
592
|
+
|
593
|
+
@@cache = {}
|
594
|
+
def self.find(id)
|
595
|
+
id = id.to_s
|
596
|
+
if @@cache[id].nil?
|
597
|
+
row = DB.connect[:sam_assessmentgrading_t].where(:assessmentgradingid => id).first
|
598
|
+
if row.nil?
|
599
|
+
raise ObjectNotFoundException.new(QuizAttempt, id)
|
600
|
+
end
|
601
|
+
|
602
|
+
@@cache[id] = QuizAttempt.new(row)
|
603
|
+
end
|
604
|
+
@@cache[id]
|
605
|
+
end
|
606
|
+
|
607
|
+
def self.query_by_quiz_id(quiz_id)
|
608
|
+
DB.connect[:sam_assessmentgrading_t].where(:publishedassessmentid => quiz_id)
|
609
|
+
end
|
610
|
+
|
611
|
+
def self.count_by_quiz_id(quiz_id)
|
612
|
+
QuizAttempt.query_by_quiz_id(quiz_id).count
|
613
|
+
end
|
614
|
+
|
615
|
+
def self.find_by_quiz_id(quiz_id)
|
616
|
+
QuizAttempt.query_by_quiz_id(quiz_id).
|
617
|
+
all.collect { |row| QuizAttempt.new(row) }
|
618
|
+
end
|
619
|
+
|
620
|
+
def items
|
621
|
+
@items ||= QuizAttemptItem.find_by_attempt_id(self.id)
|
622
|
+
end
|
623
|
+
|
624
|
+
def item_count
|
625
|
+
@item_count ||= QuizAttemptItem.count_by_attempt_id(self.id)
|
626
|
+
end
|
627
|
+
|
628
|
+
def user
|
629
|
+
@user ||= User.find(@user_id)
|
630
|
+
end
|
631
|
+
|
632
|
+
def quiz
|
633
|
+
@quiz ||= PublishedQuiz.find(@quiz_id)
|
634
|
+
end
|
635
|
+
|
636
|
+
def auto_submitted?
|
637
|
+
@is_auto_submitted == 1
|
638
|
+
end
|
639
|
+
|
640
|
+
def late?
|
641
|
+
@is_late == 1
|
642
|
+
end
|
643
|
+
|
644
|
+
def default_serialization
|
645
|
+
{
|
646
|
+
"id" => self.id,
|
647
|
+
"user" => self.user.serialize(:summary),
|
648
|
+
"quiz" => self.quiz.serialize(:summary),
|
649
|
+
"item_count" => self.item_count,
|
650
|
+
"submitted_at" => self.submitted_at,
|
651
|
+
"is_auto_submitted" => self.auto_submitted?,
|
652
|
+
"is_late" => self.late?,
|
653
|
+
"status" => self.status,
|
654
|
+
"total_auto_score" => self.total_auto_score
|
655
|
+
}
|
656
|
+
end
|
657
|
+
|
658
|
+
def summary_serialization
|
659
|
+
{
|
660
|
+
"id" => self.id,
|
661
|
+
"eid" => User.get_eid(self.user_id),
|
662
|
+
"quiz_id" => self.quiz_id,
|
663
|
+
"status" => self.status
|
664
|
+
}
|
665
|
+
end
|
666
|
+
|
667
|
+
def quiz_summary_serialization
|
668
|
+
{
|
669
|
+
"id" => self.id,
|
670
|
+
"eid" => User.get_eid(self.user_id),
|
671
|
+
"status" => self.status
|
672
|
+
}
|
673
|
+
end
|
674
|
+
|
675
|
+
def items_serialization
|
676
|
+
{
|
677
|
+
"items" => self.items.collect { |i| i.serialize(:attempt_summary) }
|
678
|
+
}
|
679
|
+
end
|
680
|
+
|
681
|
+
def self.all_serializations
|
682
|
+
[:default, :items]
|
683
|
+
end
|
684
|
+
end
|
685
|
+
|
686
|
+
class QuizAttemptItem < SakaiObject
|
687
|
+
attr_reader :dbrow, :submitted_at, :answer, :user_id, :item_id, :attempt_id
|
688
|
+
|
689
|
+
def initialize(dbrow)
|
690
|
+
@dbrow = dbrow
|
691
|
+
|
692
|
+
@id = dbrow[:itemgradingid]
|
693
|
+
@submitted_at = dbrow[:submitteddate]
|
694
|
+
@user_id = dbrow[:agentid]
|
695
|
+
@attempt_id = dbrow[:assessmentgradingid]
|
696
|
+
@item_id = dbrow[:publisheditemid]
|
697
|
+
@answer = dbrow[:answertext]
|
698
|
+
end
|
699
|
+
|
700
|
+
def user
|
701
|
+
@user ||= User.find(@user_id)
|
702
|
+
end
|
703
|
+
|
704
|
+
def attempt
|
705
|
+
@attempt ||= QuizAttempt.find(@attempt_id)
|
706
|
+
end
|
707
|
+
|
708
|
+
def item
|
709
|
+
@item ||= PublishedQuizItem.find(@item_id)
|
710
|
+
end
|
711
|
+
|
712
|
+
@@cache = {}
|
713
|
+
def self.find(id)
|
714
|
+
id = id.to_s
|
715
|
+
if @@cache[id].nil?
|
716
|
+
row = DB.connect[:sam_itemgrading_t].where(:itemgradingid => id).first
|
717
|
+
if row.nil?
|
718
|
+
raise ObjectNotFoundException.new(QuizAttemptItem, id)
|
719
|
+
end
|
720
|
+
|
721
|
+
@@cache[id] = QuizAttemptItem.new(row)
|
722
|
+
end
|
723
|
+
@@cache[id]
|
724
|
+
end
|
725
|
+
|
726
|
+
def self.query_by_attempt_id(attempt_id)
|
727
|
+
DB.connect[:sam_itemgrading_t].where(:assessmentgradingid => attempt_id)
|
728
|
+
end
|
729
|
+
|
730
|
+
def self.count_by_attempt_id(attempt_id)
|
731
|
+
QuizAttemptItem.query_by_attempt_id(attempt_id).count
|
732
|
+
end
|
733
|
+
|
734
|
+
def self.find_by_attempt_id(attempt_id)
|
735
|
+
QuizAttemptItem.query_by_attempt_id(attempt_id).
|
736
|
+
all.collect { |row| QuizAttemptItem.new(row) }
|
737
|
+
end
|
738
|
+
|
739
|
+
def attachments
|
740
|
+
@attachments ||=
|
741
|
+
QuizAttemptItemAttachment.find_by_quiz_attempt_item_id(self.id)
|
742
|
+
end
|
743
|
+
|
744
|
+
def default_serialization
|
745
|
+
{
|
746
|
+
"id" => self.id,
|
747
|
+
"user" => self.user.serialize(:summary),
|
748
|
+
"attempt" => self.attempt.serialize(:summary),
|
749
|
+
"item" => self.item.serialize(:summary),
|
750
|
+
"answer" => self.answer,
|
751
|
+
"attachment_count" => self.attachments.length
|
752
|
+
}
|
753
|
+
end
|
754
|
+
|
755
|
+
def summary_serialization
|
756
|
+
{
|
757
|
+
"id" => self.id,
|
758
|
+
"eid" => User.get_eid(self.user_id),
|
759
|
+
"attempt_id" => self.attempt_id,
|
760
|
+
"item_id" => self.item_id
|
761
|
+
}
|
762
|
+
end
|
763
|
+
|
764
|
+
def attempt_summary_serialization
|
765
|
+
{
|
766
|
+
"id" => self.id,
|
767
|
+
"item_id" => self.item_id
|
768
|
+
}
|
769
|
+
end
|
770
|
+
|
771
|
+
def attachments_serialization
|
772
|
+
{
|
773
|
+
"attachments" => self.attachments.collect{|a|a.serialize(:attempt_item_summary)}
|
774
|
+
}
|
775
|
+
end
|
776
|
+
|
777
|
+
def self.all_serializations
|
778
|
+
[:default, :attachments]
|
779
|
+
end
|
780
|
+
end
|
781
|
+
|
782
|
+
class QuizAttemptItemAttachment < SakaiObject
|
783
|
+
attr_reader :dbrow, :status, :filepath, :filename, :filesize, :mimetype
|
784
|
+
attr_reader :description, :quiz_attempt_item_id
|
785
|
+
|
786
|
+
include ModProps
|
787
|
+
created_by_key :createdby
|
788
|
+
created_at_key :createddate
|
789
|
+
modified_by_key :lastmodifiedby
|
790
|
+
modified_at_key :lastmodifieddate
|
791
|
+
|
792
|
+
def initialize(dbrow)
|
793
|
+
@dbrow = dbrow
|
794
|
+
|
795
|
+
@id = dbrow[:mediaid]
|
796
|
+
@quiz_attempt_item_id = dbrow[:itemgradingid]
|
797
|
+
@status = dbrow[:status]
|
798
|
+
@filepath = dbrow[:location]
|
799
|
+
@filename = dbrow[:filename]
|
800
|
+
@filesize = dbrow[:filesize]
|
801
|
+
@mimetype = dbrow[:mimetype]
|
802
|
+
@description = dbrow[:description]
|
803
|
+
end
|
804
|
+
|
805
|
+
def quiz_attempt_item
|
806
|
+
@quiz_attempt_item ||= QuizAttemptItem.find(@quiz_attempt_item_id)
|
807
|
+
end
|
808
|
+
|
809
|
+
def self.find_by_quiz_attempt_item_id(quiz_attempt_item_id)
|
810
|
+
DB.connect[:sam_media_t].where(:itemgradingid => quiz_attempt_item_id).
|
811
|
+
all.collect { |row| QuizAttemptItemAttachment.new(row) }
|
812
|
+
end
|
813
|
+
|
814
|
+
@@cache = {}
|
815
|
+
def self.find(id)
|
816
|
+
id = id.to_s
|
817
|
+
if @@cache[id].nil?
|
818
|
+
row = DB.connect[:sam_media_t].where(:mediaid => id).first
|
819
|
+
if row.nil?
|
820
|
+
raise ObjectNotFoundException.new(QuizAttemptItemAttachment, id)
|
821
|
+
end
|
822
|
+
|
823
|
+
@@cache[id] = QuizAttemptItemAttachment.new(row)
|
824
|
+
end
|
825
|
+
@@cache[id]
|
826
|
+
end
|
827
|
+
|
828
|
+
def default_serialization
|
829
|
+
{
|
830
|
+
"id" => self.id,
|
831
|
+
"filename" => self.filename,
|
832
|
+
"mimetype" => self.mimetype,
|
833
|
+
"filesize" => self.filesize,
|
834
|
+
"status" => self.status,
|
835
|
+
"quiz_attempt_item" => self.quiz_attempt_item.serialize(:summary)
|
836
|
+
}
|
837
|
+
end
|
838
|
+
|
839
|
+
def summary_serialization
|
840
|
+
{
|
841
|
+
"id" => self.id,
|
842
|
+
"filename" => self.filename,
|
843
|
+
"quiz_attempt_item_id" => self.quiz_attempt_item_id
|
844
|
+
}
|
845
|
+
end
|
846
|
+
|
847
|
+
def attempt_item_summary_serialization
|
848
|
+
{
|
849
|
+
"id" => self.id,
|
850
|
+
"filename" => self.filename
|
851
|
+
}
|
852
|
+
end
|
853
|
+
end
|
535
854
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
# SakaiInfo::SakaiObject
|
3
3
|
#
|
4
4
|
# Created 2012-02-15 daveadams@gmail.com
|
5
|
-
# Last updated 2012-02-
|
5
|
+
# Last updated 2012-02-29 daveadams@gmail.com
|
6
6
|
#
|
7
7
|
# https://github.com/daveadams/sakai-info
|
8
8
|
#
|
@@ -50,6 +50,14 @@ module SakaiInfo
|
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
|
+
def dbrow_only_serialization
|
54
|
+
if not self.dbrow_serialization["dbrow"].nil?
|
55
|
+
self.dbrow_serialization["dbrow"]
|
56
|
+
else
|
57
|
+
{}
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
53
61
|
def default_serialization
|
54
62
|
object_type_serialization
|
55
63
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
# SakaiInfo::SakaiXMLEntity
|
3
3
|
#
|
4
4
|
# Created 2012-02-16 daveadams@gmail.com
|
5
|
-
# Last updated 2012-02-
|
5
|
+
# Last updated 2012-02-29 daveadams@gmail.com
|
6
6
|
#
|
7
7
|
# https://github.com/daveadams/sakai-info
|
8
8
|
#
|
@@ -39,12 +39,22 @@ module SakaiInfo
|
|
39
39
|
class SakaiXMLEntity < SakaiObject
|
40
40
|
attr_reader :xml, :xmldoc, :attributes, :properties
|
41
41
|
|
42
|
-
|
42
|
+
include ModProps
|
43
|
+
created_by_key :_xml_entity_created_by
|
44
|
+
created_at_key :_xml_entity_created_at
|
45
|
+
modified_by_key :_xml_entity_modified_by
|
46
|
+
modified_at_key :_xml_entity_modified_at
|
47
|
+
|
43
48
|
# this method parses the universal XML field for all entities
|
44
49
|
# down to two collections: attributes (XML attributes defined in the
|
45
50
|
# top-level tag) and properties (<property> tags inside the top-level
|
46
51
|
# tag). Properties are generally base64 encoded
|
47
52
|
def parse_xml
|
53
|
+
if @xml.nil?
|
54
|
+
@xml = ""
|
55
|
+
REXML::Document.new(@dbrow[:xml].read).write(@xml, 2)
|
56
|
+
end
|
57
|
+
|
48
58
|
@xmldoc = REXML::Document.new(@xml)
|
49
59
|
@attributes = {}
|
50
60
|
@xmldoc.root.attributes.keys.each do |att_name|
|
@@ -60,67 +70,62 @@ module SakaiInfo
|
|
60
70
|
if prop_encoding == "BASE64"
|
61
71
|
prop_value = Base64.decode64(prop_value)
|
62
72
|
else
|
63
|
-
raise UnrecognizedPropertyEncodingException(prop_name, prop_encoding, prop_value)
|
73
|
+
raise UnrecognizedPropertyEncodingException.new(prop_name, prop_encoding, prop_value)
|
64
74
|
end
|
65
75
|
@properties[prop_name] = prop_value
|
66
76
|
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def format_entity_date(raw)
|
70
|
-
raw.gsub(/^(....)(..)(..)(..)(..)(..).*$/, '\1-\2-\3 \4:\5:\6')
|
71
|
-
end
|
72
|
-
|
73
|
-
public
|
74
|
-
# standard property for all entities
|
75
|
-
def created_by
|
76
|
-
@created_by ||= User.find(@properties["CHEF:creator"])
|
77
|
-
end
|
78
|
-
|
79
|
-
# standard property for all entities
|
80
|
-
def modified_by
|
81
|
-
@modified_by ||= User.find(@properties["CHEF:modifiedby"])
|
82
|
-
end
|
83
|
-
|
84
|
-
# standard property for all entities
|
85
|
-
def created_at
|
86
|
-
format_entity_date(@properties["DAV:creationdate"])
|
87
|
-
end
|
88
77
|
|
89
|
-
|
90
|
-
|
91
|
-
format_entity_date(@properties["DAV:
|
78
|
+
@dbrow[:_xml_entity_created_by] = @properties["CHEF:creator"]
|
79
|
+
@dbrow[:_xml_entity_modified_by] = @properties["CHEF:modifiedby"]
|
80
|
+
@dbrow[:_xml_entity_created_at] = format_entity_date(@properties["DAV:creationdate"])
|
81
|
+
@dbrow[:_xml_entity_modified_at] = format_entity_date(@properties["DAV:getlastmodified"])
|
92
82
|
end
|
93
83
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
"created_at" => self.created_at,
|
100
|
-
"modified_by" => self.modified_by,
|
101
|
-
"modified_at" => self.modified_at
|
102
|
-
}
|
84
|
+
def format_entity_date(raw)
|
85
|
+
if raw =~ /^(....)(..)(..)(..)(..)(..).*$/
|
86
|
+
# I believe these are usually in UTC
|
87
|
+
Time.utc($1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i).getlocal
|
88
|
+
end
|
103
89
|
end
|
104
90
|
|
105
91
|
# serialize all attributes
|
106
92
|
def attributes_serialization
|
107
93
|
{
|
108
|
-
"attributes" =>
|
94
|
+
"attributes" => self.attributes
|
109
95
|
}
|
110
96
|
end
|
111
97
|
|
112
98
|
# serialize all properties
|
113
99
|
def properties_serialization
|
114
100
|
{
|
115
|
-
"properties" =>
|
101
|
+
"properties" => self.properties
|
116
102
|
}
|
117
103
|
end
|
118
104
|
|
119
105
|
# xml dump serialization option
|
120
106
|
def xml_serialization
|
121
107
|
{
|
122
|
-
"xml" => xml
|
108
|
+
"xml" => self.xml
|
109
|
+
}
|
110
|
+
end
|
111
|
+
|
112
|
+
# tweak the dbrow out since we hacked dbrow for other purposes
|
113
|
+
# and since the xml field doesn't display typically
|
114
|
+
def dbrow_serialization
|
115
|
+
dbrow = super["dbrow"]
|
116
|
+
dbrow[:xml] = self.xml
|
117
|
+
dbrow.delete(:_xml_entity_created_by)
|
118
|
+
dbrow.delete(:_xml_entity_created_at)
|
119
|
+
dbrow.delete(:_xml_entity_modified_by)
|
120
|
+
dbrow.delete(:_xml_entity_modified_at)
|
121
|
+
|
122
|
+
{
|
123
|
+
"dbrow" => dbrow
|
123
124
|
}
|
124
125
|
end
|
126
|
+
|
127
|
+
def self.all_serializations
|
128
|
+
[ :default, :attributes, :properties, :xml ]
|
129
|
+
end
|
125
130
|
end
|
126
131
|
end
|
data/lib/sakai-info/site.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
# SakaiInfo::Site library
|
3
3
|
#
|
4
4
|
# Created 2012-02-17 daveadams@gmail.com
|
5
|
-
# Last updated 2012-02-
|
5
|
+
# Last updated 2012-02-28 daveadams@gmail.com
|
6
6
|
#
|
7
7
|
# https://github.com/daveadams/sakai-info
|
8
8
|
#
|
@@ -273,7 +273,7 @@ module SakaiInfo
|
|
273
273
|
"pending_quiz_count" => self.pending_quiz_count,
|
274
274
|
"published_quiz_count" => self.published_quiz_count,
|
275
275
|
"assignment_count" => self.assignment_count,
|
276
|
-
"announcement_count" => self.announcement_count,
|
276
|
+
# "announcement_count" => self.announcement_count,
|
277
277
|
"gradebook_item_count" => (self.gradebook.nil? ? 0 : self.gradebook.item_count),
|
278
278
|
"forum_count" => self.forum_count
|
279
279
|
}
|
@@ -445,7 +445,7 @@ module SakaiInfo
|
|
445
445
|
if @@cache[id].nil?
|
446
446
|
row = DB.connect[:sakai_site_page].where(:page_id => id).first
|
447
447
|
if row.nil?
|
448
|
-
raise ObjectNotFoundException(Page, id)
|
448
|
+
raise ObjectNotFoundException.new(Page, id)
|
449
449
|
end
|
450
450
|
|
451
451
|
site = Site.find(row[:site_id])
|
data/lib/sakai-info/version.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sakai-info
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 17
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 3
|
9
|
-
-
|
10
|
-
version: 0.3.
|
9
|
+
- 1
|
10
|
+
version: 0.3.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- David Adams
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-02-
|
18
|
+
date: 2012-02-29 00:00:00 -06:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|