sakai-info 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,20 @@
1
1
  # sakai-info Change History #
2
2
 
3
+ ### 0.5.1 ###
4
+
5
+ *Released 2012-10-07*
6
+
7
+ * Added new private-message lookup type
8
+ * Adjusted to new use of the 'author' field in PrivateMessage/ForumPost table
9
+ * Now including post body with forum-post
10
+ * Added new pending-quiz-access-control and published-quiz-access-control types
11
+ * Integrated access control objects with quiz object output
12
+ * New deleted-content-resource type
13
+ * New rake task to load test fixtures into database
14
+ * Added to_csv method with field selection to SakaiObject
15
+ * Added more use cases to POC query mode
16
+ * Added field selection to lookup via --fields=x,y,z
17
+
3
18
  ### 0.5.0 ###
4
19
 
5
20
  *Released 2012-06-21*
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # sakai-info #
2
2
 
3
- last updated: 2012-06-21
3
+ last updated: 2012-10-07
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.5.0.gem`.
27
+ `sakai-info-0.5.1.gem`.
28
28
 
29
29
  Cleanup built gems using:
30
30
 
data/ROADMAP.md CHANGED
@@ -1,27 +1,23 @@
1
1
  # sakai-info Roadmap #
2
2
 
3
- *Last updated 2012-06-21*
4
-
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
3
+ *Last updated 2012-10-07*
12
4
 
13
5
  ### 0.5.2 ###
14
6
 
15
- * Test fixture generation for quizzes
16
- * Better date formatting all around
7
+ * JSON output support
8
+ * Ability to specify alternate config file at the command line
9
+ * Better date formatting and proper time zone understanding
17
10
  * More query functionality
18
11
  * Proof-of-concept sin shell
19
12
  * Chat channel/message support
13
+ * Alias support
14
+ * Add simple tests against user/site fixture data
20
15
 
21
16
  ### 0.5.3 ###
22
17
 
23
18
  * RDS schema creation and data loading for MySQL and Oracle testing
24
19
  * More query and shell functionality
20
+ * Test fixture generation for quizzes
25
21
 
26
22
  ### 0.5.4 ###
27
23
 
@@ -45,4 +45,5 @@ require 'sakai-info/quiz'
45
45
  require 'sakai-info/question_pool'
46
46
  require 'sakai-info/generic_message'
47
47
  require 'sakai-info/forum'
48
+ require 'sakai-info/private_message'
48
49
 
@@ -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-06-21 daveadams@gmail.com
5
+ # Last updated 2012-10-03 daveadams@gmail.com
6
6
  #
7
7
  # https://github.com/daveadams/sakai-info
8
8
  #
@@ -24,11 +24,12 @@ Sakai INfo: sin #{VERSION}
24
24
  Supported object types:
25
25
  user, group, site, page, tool, pending-quiz, published-quiz,
26
26
  pending-quiz-section, published-quiz-section, pending-quiz-item,
27
- published-quiz-item, quiz-attempt, quiz-attempt-item,
27
+ published-quiz-item, pending-quiz-access-control,
28
+ published-quiz-access-control, quiz-attempt, quiz-attempt-item,
28
29
  quiz-attempt-item-attachment, question-pool, assignment,
29
30
  assignment-submission, forum, forum-thread, forum-post, content,
30
31
  announcement, announcement-channel, gradebook, gradebook-item,
31
- role, function, realm
32
+ role, function, realm, private-message
32
33
 
33
34
  QUERY MODE
34
35
  Query particular fields from certain objects given certain conditions.
@@ -78,6 +79,9 @@ Sakai Info: sin #{VERSION}
78
79
 
79
80
  --all
80
81
  Print all possible information (other than dbrow)
82
+
83
+ --fields=f1[,f2[,...]]
84
+ Include in output only those first-level hash keys given
81
85
  EOF
82
86
 
83
87
  "help" => <<EOF,
@@ -242,6 +246,24 @@ sin published-quiz-item
242
246
  --mod Print creation/modification info
243
247
  EOF
244
248
 
249
+ "pending-quiz-access-control" => <<EOF,
250
+ sin pending-quiz-access-control
251
+
252
+ Usage: sin pending-quiz-access-control <id> [<options>]
253
+
254
+ Prints information about the access control object attached to the
255
+ pending quiz ID specified.
256
+ EOF
257
+
258
+ "published-quiz-access-control" => <<EOF,
259
+ sin published-quiz-access-control
260
+
261
+ Usage: sin published-quiz-access-control <id> [<options>]
262
+
263
+ Prints information about the access control object attached to the
264
+ published quiz ID specified.
265
+ EOF
266
+
245
267
  "question-pool" => <<EOF,
246
268
  sin question-pool
247
269
 
@@ -364,6 +386,17 @@ sin content
364
386
  --children Recursively print collection children
365
387
  --full-children Print children with full IDs and file paths
366
388
  --mod Print creation/modification info
389
+ EOF
390
+ "deleted-content-resource" => <<EOF,
391
+ sin content
392
+
393
+ Usage: sin deleted-content-resource <id> [<options>]
394
+
395
+ Prints information about the deleted content resource ID specified.
396
+ Additional options may be passed to include additional information:
397
+
398
+ --properties Print all properties
399
+ --mod Print creation/modification info
367
400
  EOF
368
401
  "announcement" => <<EOF,
369
402
  sin announcement
@@ -427,6 +460,16 @@ sin realm
427
460
 
428
461
  --roles List roles associated with this realm
429
462
  --users List users in this realm
463
+ --mod Print creation/modification info
464
+ EOF
465
+ "private-message" => <<EOF,
466
+ sin private-message
467
+
468
+ Usage: sin private-message <id> [<options>]
469
+
470
+ Prints information about the private message ID specified. Additional options
471
+ may be passed to include additional information:
472
+
430
473
  --mod Print creation/modification info
431
474
  EOF
432
475
  "query" => <<EOF,
@@ -15,21 +15,42 @@ module SakaiInfo
15
15
  def self.process(args, flags)
16
16
  object_type = args.shift
17
17
  id = args.shift
18
+ fields = nil
19
+
20
+ flags.each do |flag|
21
+ if flag =~ /^--fields=(.+)$/
22
+ fields = $1.downcase.split(',')
23
+ flags.delete(flag)
24
+ end
25
+ end
18
26
 
19
27
  if flags.include? "--all"
20
28
  serials = CLI::LookupModes[object_type].all_serializations
21
- elsif
22
- flags.include? "--dbrow-only"
29
+ elsif flags.include? "--dbrow-only"
23
30
  serials = [:dbrow_only]
24
31
  else
25
32
  serials = [:default] + flags.collect{|flag|flag.gsub(/^--/,'').gsub("-","_").to_sym}
26
33
  end
34
+
35
+ object = nil
27
36
  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}'"
37
+ object = CLI::LookupModes[object_type].find(id)
38
+ rescue ObjectNotFoundException => e
39
+ STDERR.puts "ERROR: Could not find #{object_type} with an ID of '#{id}':"
40
+ STDERR.puts " #{e}"
31
41
  exit 1
32
42
  end
43
+
44
+ if fields.nil? or fields.empty?
45
+ puts object.to_yaml(serials)
46
+ else
47
+ object_hash = object.serialize(serials).delete_if{|k,v| not fields.include? k.to_s}
48
+ if object_hash.empty?
49
+ STDERR.puts "ERROR: no requested fields were found"
50
+ exit 1
51
+ end
52
+ puts object_hash.to_yaml
53
+ end
33
54
  end
34
55
  end
35
56
 
@@ -57,6 +78,10 @@ module SakaiInfo
57
78
  "nqi" => PendingQuizItem,
58
79
  "penqi" => PendingQuizItem,
59
80
  "pending-quiz-item" => PendingQuizItem,
81
+ "pqac" => PublishedQuizAccessControl,
82
+ "published-quiz-access-control" => PublishedQuizAccessControl,
83
+ "nqac" => PendingQuizAccessControl,
84
+ "pending-quiz-access-control" => PendingQuizAccessControl,
60
85
  "qa" => QuizAttempt,
61
86
  "quiz-attempt" => QuizAttempt,
62
87
  "qai" => QuizAttemptItem,
@@ -77,6 +102,9 @@ module SakaiInfo
77
102
  "fp" => ForumPost,
78
103
  "forum-post" => ForumPost,
79
104
  "content" => Content,
105
+ "deleted-content-resource" => DeletedContentResource,
106
+ "deleted-content" => DeletedContentResource,
107
+ "delcon" => DeletedContentResource,
80
108
  "ann" => Announcement,
81
109
  "announcement" => Announcement,
82
110
  "annchan" => AnnouncementChannel,
@@ -90,6 +118,8 @@ module SakaiInfo
90
118
  "func" => AuthzFunction,
91
119
  "function" => AuthzFunction,
92
120
  "realm" => AuthzRealm,
121
+ "private-message" => PrivateMessage,
122
+ "pm" => PrivateMessage,
93
123
  }
94
124
  end
95
125
  end
@@ -2,7 +2,7 @@
2
2
  # class for handling "query" command line mode
3
3
  #
4
4
  # Created 2012-05-23 daveadams@gmail.com
5
- # Last updated 2012-06-21 daveadams@gmail.com
5
+ # Last updated 2012-10-06 daveadams@gmail.com
6
6
  #
7
7
  # https://github.com/daveadams/sakai-info
8
8
  #
@@ -48,6 +48,45 @@ module SakaiInfo
48
48
  exit 1
49
49
  end
50
50
 
51
+ elsif object_type == "deleted-content"
52
+ userid = nil
53
+ while flags.length > 0
54
+ flag = flags.shift
55
+ if flag =~ /^--by=/
56
+ userid = flag.split('=')[1]
57
+ end
58
+ end
59
+
60
+ if userid.nil?
61
+ STDERR.puts "ERROR: you must specify --by=<userid>"
62
+ exit 1
63
+ end
64
+
65
+ begin
66
+ user = User.find(userid)
67
+ deleted_resources = DeletedContentResource.find_by_delete_userid(user.id)
68
+ deleted_resources.each do |dr|
69
+ puts dr.id
70
+ end
71
+ rescue ObjectNotFoundException => e
72
+ STDERR.puts "ERROR: #{e}"
73
+ exit 1
74
+ end
75
+
76
+ elsif object_type == "site"
77
+ title = args.shift
78
+
79
+ Site.find_by_title(title).each do |site|
80
+ puts site.to_csv(:id, :title)
81
+ end
82
+
83
+ elsif object_type == "user"
84
+ name = args.shift
85
+
86
+ User.find_by_name(name).each do |user|
87
+ puts user.to_csv(:eid, :name)
88
+ end
89
+
51
90
  else
52
91
  STDERR.puts "ERROR: Unrecognized object type"
53
92
  exit 1
@@ -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-20 daveadams@gmail.com
5
+ # Last updated 2012-10-04 daveadams@gmail.com
6
6
  #
7
7
  # https://github.com/daveadams/sakai-info
8
8
  #
@@ -219,6 +219,9 @@ module SakaiInfo
219
219
  if result["uuid"].nil?
220
220
  result.delete("uuid")
221
221
  end
222
+ if result["context"].nil?
223
+ result.delete("context")
224
+ end
222
225
  result
223
226
  end
224
227
 
@@ -238,6 +241,69 @@ module SakaiInfo
238
241
  end
239
242
  end
240
243
 
244
+ class DeletedContentResource < ContentResource
245
+ attr_reader :file_path, :uuid, :context, :resource_type_id, :deleted_at, :dbrow
246
+
247
+ def self.clear_cache
248
+ @@cache = {}
249
+ end
250
+ clear_cache
251
+
252
+ def initialize(dbrow)
253
+ super(dbrow)
254
+ @table_name = "content_resource_delete"
255
+ @deleted_at = @dbrow[:delete_date].strftime("%Y-%m-%d %H:%M:%S")
256
+ end
257
+
258
+ def self.find(id)
259
+ if @@cache[id].nil?
260
+ row = DB.connect[:content_resource_delete].where(:resource_id => id).first
261
+ if row.nil?
262
+ raise ObjectNotFoundException.new(DeletedContentResource, id)
263
+ end
264
+ @@cache[id] = DeletedContentResource.new(row)
265
+ end
266
+ @@cache[id]
267
+ end
268
+
269
+ def deleted_by
270
+ @deleted_by ||= User.find(@dbrow[:delete_userid])
271
+ end
272
+
273
+ def self.find_by_delete_userid(user_id)
274
+ resources = []
275
+ DB.connect[:content_resource_delete].where(:delete_userid => user_id).all.each do |row|
276
+ @@cache[row[:resource_id]] = DeletedContentResource.new(row)
277
+ resources << @@cache[row[:resource_id]]
278
+ end
279
+ resources
280
+ end
281
+
282
+ def self.query_by_parent(parent_id)
283
+ DB.connect[:content_resource_delete].where(:in_collection => parent_id)
284
+ end
285
+
286
+ def self.find_by_parent(parent_id)
287
+ resources = []
288
+ DeletedContentResource.query_by_parent(parent_id).all.each do |row|
289
+ @@cache[row[:resource_id]] = DeletedContentResource.new(row)
290
+ resources << @@cache[row[:resource_id]]
291
+ end
292
+ resources
293
+ end
294
+
295
+ def self.count_by_parent(parent_id)
296
+ DeletedContentResource.query_by_parent(parent_id).count
297
+ end
298
+
299
+ def default_serialization
300
+ result = super
301
+ result["deleted_at"] = self.deleted_at
302
+ result["deleted_by"] = self.deleted_by.serialize(:summary)
303
+ result
304
+ end
305
+ end
306
+
241
307
  class ContentCollection < Content
242
308
  attr_reader :dbrow
243
309
 
@@ -2,7 +2,7 @@
2
2
  # SakaiInfo::Forum library
3
3
  #
4
4
  # Created 2012-04-01 daveadams@gmail.com
5
- # Last updated 2012-05-10 daveadams@gmail.com
5
+ # Last updated 2012-09-25 daveadams@gmail.com
6
6
  #
7
7
  # https://github.com/daveadams/sakai-info
8
8
  #
@@ -231,18 +231,24 @@ module SakaiInfo
231
231
  def initialize(dbrow)
232
232
  @dbrow = dbrow
233
233
 
234
+ @dbrow[:body] = dbrow[:body].read
235
+
234
236
  @id = dbrow[:id].to_i
235
237
  @title = dbrow[:title]
236
238
  end
237
239
 
238
240
  def author
239
- @author ||= User.find(@dbrow[:author])
241
+ @author ||= User.find(@dbrow[:created_by])
240
242
  end
241
243
 
242
244
  def thread
243
245
  @thread ||= ForumThread.find(@dbrow[:surrogatekey])
244
246
  end
245
247
 
248
+ def body
249
+ @dbrow[:body]
250
+ end
251
+
246
252
  def self.query_by_thread_id(thread_id)
247
253
  DB.connect[:mfr_message_t].where(:surrogatekey => thread_id)
248
254
  end
@@ -265,6 +271,7 @@ module SakaiInfo
265
271
  "title" => self.title,
266
272
  "author" => self.author.serialize(:summary),
267
273
  "thread" => self.thread.serialize(:summary),
274
+ "body" => self.body,
268
275
  }
269
276
  end
270
277
 
@@ -62,12 +62,6 @@ module SakaiInfo
62
62
  GenericThread.types.keys.include?(mt)
63
63
  end
64
64
  end
65
-
66
- class PrivateMessage < GenericMessage
67
- def self.count_by_date(d)
68
- count_by_date_and_message_type(d, "PM")
69
- end
70
- end
71
65
  end
72
66
 
73
67
 
@@ -2,7 +2,7 @@
2
2
  # Hacks necessary to work around problems in external libraries
3
3
  #
4
4
  # Created 2012-05-20 daveadams@gmail.com
5
- # Last updated 2012-05-20 daveadams@gmail.com
5
+ # Last updated 2012-10-05 daveadams@gmail.com
6
6
  #
7
7
  # https://github.com/daveadams/sakai-info
8
8
  #
@@ -47,3 +47,10 @@ module Sequel
47
47
  end
48
48
  end
49
49
  end
50
+
51
+ # hack to get clobs in sqlite to work correctly
52
+ class String
53
+ def read
54
+ self
55
+ end
56
+ end
@@ -0,0 +1,78 @@
1
+ # sakai-info/private_message.rb
2
+ # SakaiInfo::PrivateMessage library
3
+ #
4
+ # Created 2012-09-25 daveadams@gmail.com
5
+ # Last updated 2012-09-25 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 PrivateMessage < GenericMessage
14
+ attr_reader :id, :title, :dbrow
15
+
16
+ include ModProps
17
+ created_by_key :created_by
18
+ created_at_key :created
19
+ modified_by_key :modified_by
20
+ modified_at_key :modified
21
+
22
+ def self.clear_cache
23
+ @@cache = {}
24
+ end
25
+ clear_cache
26
+
27
+ def self.find(id)
28
+ if @@cache[id.to_s].nil?
29
+ row = DB.connect[:mfr_message_t].where(:id => id, :message_dtype => "PM").first
30
+ if row.nil?
31
+ raise ObjectNotFoundException.new(PrivateMessage, id)
32
+ end
33
+ @@cache[id.to_s] = PrivateMessage.new(row)
34
+ end
35
+ @@cache[id.to_s]
36
+ end
37
+
38
+ def initialize(dbrow)
39
+ @dbrow = dbrow
40
+
41
+ @dbrow[:body] = dbrow[:body].read
42
+ @dbrow[:recipients_as_text] = dbrow[:recipients_as_text].read
43
+
44
+ @id = dbrow[:id].to_i
45
+ @title = dbrow[:title]
46
+ end
47
+
48
+ def author
49
+ # apparently the 'author' field is just a display string?!?
50
+ # as of 2.8, perhaps?
51
+ @author ||= User.find(@dbrow[:created_by])
52
+ end
53
+
54
+ def body
55
+ @dbrow[:body]
56
+ end
57
+
58
+ def self.count_by_date(d)
59
+ count_by_date_and_message_type(d, "PM")
60
+ end
61
+
62
+ def default_serialization
63
+ {
64
+ "id" => self.id,
65
+ "title" => self.title,
66
+ "author" => self.author.serialize(:summary),
67
+ "body" => self.body,
68
+ }
69
+ end
70
+
71
+ def summary_serialization
72
+ {
73
+ "id" => self.id,
74
+ "title" => self.title,
75
+ }
76
+ end
77
+ end
78
+ end
@@ -2,7 +2,7 @@
2
2
  # SakaiInfo::Quiz library
3
3
  #
4
4
  # Created 2012-02-17 daveadams@gmail.com
5
- # Last updated 2012-06-21 daveadams@gmail.com
5
+ # Last updated 2012-09-29 daveadams@gmail.com
6
6
  #
7
7
  # https://github.com/daveadams/sakai-info
8
8
  #
@@ -128,6 +128,10 @@ module SakaiInfo
128
128
  @items ||= self.item_class.find_by_quiz_id(self.id)
129
129
  end
130
130
 
131
+ def access_control
132
+ @access_control ||= self.access_control_class.find(self.id)
133
+ end
134
+
131
135
  def default_serialization
132
136
  result = {
133
137
  "id" => self.id,
@@ -137,7 +141,8 @@ module SakaiInfo
137
141
  "type" => self.quiz_type,
138
142
  "section_count" => self.section_count,
139
143
  "item_count" => self.item_count,
140
- "attempt_count" => nil
144
+ "attempt_count" => nil,
145
+ "access_control" => self.access_control.serialize(:quiz_summary)
141
146
  }
142
147
  if not self.site.nil?
143
148
  result["site"] = self.site.serialize(:summary)
@@ -172,6 +177,12 @@ module SakaiInfo
172
177
  }
173
178
  end
174
179
 
180
+ def access_control_summary_serialization
181
+ result = self.summary_serialization
182
+ result.delete("id")
183
+ result
184
+ end
185
+
175
186
  def sections_serialization
176
187
  {
177
188
  "sections" => self.sections.collect{|s|s.serialize(:quiz_summary)}
@@ -245,6 +256,10 @@ module SakaiInfo
245
256
  def item_class
246
257
  PendingQuizItem
247
258
  end
259
+
260
+ def access_control_class
261
+ PendingQuizAccessControl
262
+ end
248
263
  end
249
264
 
250
265
  class PublishedQuiz < Quiz
@@ -301,6 +316,10 @@ module SakaiInfo
301
316
  PublishedQuizItem
302
317
  end
303
318
 
319
+ def access_control_class
320
+ PublishedQuizAccessControl
321
+ end
322
+
304
323
  def attempt_count
305
324
  @attempt_count ||= QuizAttempt.count_by_quiz_id(self.id)
306
325
  end
@@ -1010,4 +1029,244 @@ module SakaiInfo
1010
1029
  }
1011
1030
  end
1012
1031
  end
1032
+
1033
+ class QuizAccessControl < SakaiObject
1034
+ attr_reader :id, :dbrow
1035
+
1036
+ def initialize(dbrow)
1037
+ @dbrow = dbrow
1038
+ @id = dbrow[:assessmentid]
1039
+ end
1040
+
1041
+ def unlimited_submissions?
1042
+ @dbrow[:unlimitedsubmissions] == 1
1043
+ end
1044
+
1045
+ def submissions_allowed
1046
+ @dbrow[:submissionsallowed]
1047
+ end
1048
+
1049
+ def submissions_saved
1050
+ @dbrow[:submissionssaved] == 1
1051
+ end
1052
+
1053
+ def question_layout
1054
+ case @dbrow[:assessmentformat]
1055
+ when 1
1056
+ "One question per page"
1057
+ when 2
1058
+ "One part per page"
1059
+ when 3
1060
+ "Single page quiz"
1061
+ else
1062
+ @dbrow[:assessmentformat]
1063
+ end
1064
+ end
1065
+
1066
+ def late_handling
1067
+ case @dbrow[:latehandling]
1068
+ when 1
1069
+ "Late submissions accepted"
1070
+ when 2
1071
+ "Late submissions NOT accepted"
1072
+ else
1073
+ @dbrow[:latehandling]
1074
+ end
1075
+ end
1076
+
1077
+ def item_navigation
1078
+ case @dbrow[:itemnavigation]
1079
+ when 1
1080
+ "Linear"
1081
+ when 2
1082
+ "Random"
1083
+ else
1084
+ @dbrow[:itemnavigation]
1085
+ end
1086
+ end
1087
+
1088
+ def item_numbering
1089
+ case @dbrow[:itemnumbering]
1090
+ when 1
1091
+ "Continuous through parts"
1092
+ when 2
1093
+ "Restart numbering at each part"
1094
+ else
1095
+ @dbrow[:itemnumbering]
1096
+ end
1097
+ end
1098
+
1099
+ def submission_message
1100
+ @dbrow[:submissionmessage]
1101
+ end
1102
+
1103
+ def release_to
1104
+ @dbrow[:releaseto]
1105
+ end
1106
+
1107
+ def username
1108
+ @dbrow[:username]
1109
+ end
1110
+
1111
+ def password
1112
+ @dbrow[:password]
1113
+ end
1114
+
1115
+ def final_page_url
1116
+ @dbrow[:finalpageurl]
1117
+ end
1118
+
1119
+ def mark_for_review_allowed?
1120
+ @dbrow[:markforreview] == 1
1121
+ end
1122
+
1123
+ def authenticated?
1124
+ not (self.username.nil? and self.password.nil?)
1125
+ end
1126
+
1127
+ def time_limit
1128
+ @dbrow[:timelimit]
1129
+ end
1130
+
1131
+ def timed?
1132
+ @dbrow[:timelimit] > 0
1133
+ end
1134
+
1135
+ def automatic_submission?
1136
+ @dbrow[:autosubmit] == 1
1137
+ end
1138
+
1139
+ def start_date
1140
+ if @dbrow[:startdate].nil?
1141
+ nil
1142
+ else
1143
+ @dbrow[:startdate].strftime("%Y-%m-%d %H:%M:%S")
1144
+ end
1145
+ end
1146
+
1147
+ def due_date
1148
+ if @dbrow[:duedate].nil?
1149
+ nil
1150
+ else
1151
+ @dbrow[:duedate].strftime("%Y-%m-%d %H:%M:%S")
1152
+ end
1153
+ end
1154
+
1155
+ def retract_date
1156
+ if @dbrow[:retractdate].nil?
1157
+ nil
1158
+ else
1159
+ @dbrow[:retractdate].strftime("%Y-%m-%d %H:%M:%S")
1160
+ end
1161
+ end
1162
+
1163
+ def feedback_date
1164
+ if @dbrow[:feedbackdate].nil?
1165
+ nil
1166
+ else
1167
+ @dbrow[:feedbackdate].strftime("%Y-%m-%d %H:%M:%S")
1168
+ end
1169
+ end
1170
+
1171
+ def score_date
1172
+ if @dbrow[:scoredate].nil?
1173
+ nil
1174
+ else
1175
+ @dbrow[:scoredate].strftime("%Y-%m-%d %H:%M:%S")
1176
+ end
1177
+ end
1178
+
1179
+ def default_serialization
1180
+ result = {
1181
+ "id" => self.id,
1182
+ "quiz" => self.quiz.serialize(:access_control_summary),
1183
+ "unlimited_submissions" => self.unlimited_submissions?,
1184
+ "submissions_allowed" => self.submissions_allowed,
1185
+ "timed" => self.timed?,
1186
+ "time_limit" => self.time_limit,
1187
+ "question_layout" => self.question_layout,
1188
+ "late_handling" => self.late_handling,
1189
+ "item_navigation" => self.item_navigation,
1190
+ "item_numbering" => self.item_numbering,
1191
+ "release_to" => self.release_to,
1192
+ "authenticated" => self.authenticated?,
1193
+ "automatic_submission" => self.automatic_submission?,
1194
+ "mark_for_review_allowed" => self.mark_for_review_allowed?,
1195
+ }
1196
+ if not self.timed?
1197
+ result.delete("time_limit")
1198
+ end
1199
+ if self.unlimited_submissions?
1200
+ result.delete("submissions_allowed")
1201
+ end
1202
+ %w(username start_date due_date score_date retract_date feedback_date submission_message final_page_url).each do |field_name|
1203
+ value = self.method(field_name.to_sym).call
1204
+ if not value.nil?
1205
+ result[field_name] = value
1206
+ end
1207
+ end
1208
+ result
1209
+ end
1210
+
1211
+ def quiz_summary_serialization
1212
+ result = default_serialization
1213
+ result.delete("quiz")
1214
+ result.delete("id")
1215
+ result
1216
+ end
1217
+
1218
+ def summary_serialization
1219
+ {
1220
+ "id" => self.id,
1221
+ }
1222
+ end
1223
+ end
1224
+
1225
+ class PendingQuizAccessControl < QuizAccessControl
1226
+ def self.clear_cache
1227
+ @@cache = {}
1228
+ end
1229
+ clear_cache
1230
+
1231
+ def self.find(id)
1232
+ id = id.to_s
1233
+ if @@cache[id].nil?
1234
+ row = DB.connect[:sam_assessaccesscontrol_t].where(:assessmentid => id.to_i).first
1235
+ if row.nil?
1236
+ raise ObjectNotFoundException.new(PendingQuizAccessControl, id)
1237
+ end
1238
+
1239
+ @@cache[id] = PendingQuizAccessControl.new(row)
1240
+ end
1241
+ @@cache[id]
1242
+ end
1243
+
1244
+ def quiz
1245
+ @quiz ||= PendingQuiz.find(self.id)
1246
+ end
1247
+ end
1248
+
1249
+ class PublishedQuizAccessControl < QuizAccessControl
1250
+ def self.clear_cache
1251
+ @@cache = {}
1252
+ end
1253
+ clear_cache
1254
+
1255
+ def self.find(id)
1256
+ id = id.to_s
1257
+ if @@cache[id].nil?
1258
+ row = DB.connect[:sam_publishedaccesscontrol_t].where(:assessmentid => id.to_i).first
1259
+ if row.nil?
1260
+ raise ObjectNotFoundException.new(PublishedQuizAccessControl, id)
1261
+ end
1262
+
1263
+ @@cache[id] = PublishedQuizAccessControl.new(row)
1264
+ end
1265
+ @@cache[id]
1266
+ end
1267
+
1268
+ def quiz
1269
+ @quiz ||= PublishedQuiz.find(self.id)
1270
+ end
1271
+ end
1013
1272
  end
@@ -2,7 +2,7 @@
2
2
  # SakaiInfo::SakaiObject
3
3
  #
4
4
  # Created 2012-02-15 daveadams@gmail.com
5
- # Last updated 2012-05-10 daveadams@gmail.com
5
+ # Last updated 2012-10-06 daveadams@gmail.com
6
6
  #
7
7
  # https://github.com/daveadams/sakai-info
8
8
  #
@@ -70,6 +70,16 @@ module SakaiInfo
70
70
  serialize(q).to_json
71
71
  end
72
72
 
73
+ def to_csv(*fields)
74
+ values = []
75
+ fields.each do |field|
76
+ m = self.method(field.to_sym)
77
+ next if m.nil?
78
+ values << m.call.to_s
79
+ end
80
+ values.collect{|v|"\"#{v}\""}.join(",")
81
+ end
82
+
73
83
  # support for CLI -- returns an array of symbols that can be
74
84
  # passed back to #serialize, #to_yaml, or #to_json
75
85
  # should be reimplemented in all object classes
@@ -2,7 +2,7 @@
2
2
  # SakaiInfo::Site library
3
3
  #
4
4
  # Created 2012-02-17 daveadams@gmail.com
5
- # Last updated 2012-05-14 daveadams@gmail.com
5
+ # Last updated 2012-10-06 daveadams@gmail.com
6
6
  #
7
7
  # https://github.com/daveadams/sakai-info
8
8
  #
@@ -237,6 +237,19 @@ module SakaiInfo
237
237
  where(:type => type).all.collect{|r| r[:site_id]}
238
238
  end
239
239
 
240
+ # by_title: uses like
241
+ def self.query_by_title(title)
242
+ DB.connect[:sakai_site].where("upper(title) like ?", "%#{title.upcase}%")
243
+ end
244
+
245
+ def self.find_by_title(title)
246
+ Site.query_by_title(title).all.collect{|row| @@cache[row[:site_id]] = Site.new(row)}
247
+ end
248
+
249
+ def self.find_ids_by_title(title)
250
+ Site.query_by_title(title).select(:site_id).all.collect{|row|row[:site_id]}
251
+ end
252
+
240
253
  # by_type queries
241
254
  def self.query_by_type(type)
242
255
  DB.connect[:sakai_site].where(:type => type)
@@ -2,7 +2,7 @@
2
2
  # SakaiInfo::User library
3
3
  #
4
4
  # Created 2012-02-17 daveadams@gmail.com
5
- # Last updated 2012-05-10 daveadams@gmail.com
5
+ # Last updated 2012-10-06 daveadams@gmail.com
6
6
  #
7
7
  # https://github.com/daveadams/sakai-info
8
8
  #
@@ -174,6 +174,19 @@ module SakaiInfo
174
174
  nil
175
175
  end
176
176
 
177
+ # by_name: uses like
178
+ def self.query_by_name(name)
179
+ DB.connect[:sakai_user].where("upper(first_name) like ? or upper(last_name) like ? or upper(first_name)||\' \'||upper(last_name) like ?", "%#{name.upcase}%", "%#{name.upcase}%", "%#{name.upcase}%")
180
+ end
181
+
182
+ def self.find_by_name(name)
183
+ User.query_by_name(name).all.collect{|row| @@cache[row[:user_id]] = User.new(row)}
184
+ end
185
+
186
+ def self.find_ids_by_name(name)
187
+ User.query_by_name(name).select(:user_id).all.collect{|row|row[:user_id]}
188
+ end
189
+
177
190
  # yaml/json serialization
178
191
  def default_serialization
179
192
  result = {
@@ -218,7 +231,12 @@ module SakaiInfo
218
231
  end
219
232
 
220
233
  def self.all_serializations
221
- [:default, :sites, :pools]
234
+ [
235
+ :default,
236
+ :sites,
237
+ :pools,
238
+ :mod,
239
+ ]
222
240
  end
223
241
  end
224
242
 
@@ -1,3 +1,3 @@
1
1
  module SakaiInfo
2
- VERSION = "0.5.0"
2
+ VERSION = "0.5.1"
3
3
  end
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.5.0
4
+ version: 0.5.1
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-06-21 00:00:00.000000000 Z
12
+ date: 2012-10-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sequel
@@ -54,6 +54,7 @@ files:
54
54
  - lib/sakai-info.rb
55
55
  - lib/sakai-info/util.rb
56
56
  - lib/sakai-info/group.rb
57
+ - lib/sakai-info/private_message.rb
57
58
  - lib/sakai-info/tool.rb
58
59
  - lib/sakai-info/cli/help.rb
59
60
  - lib/sakai-info/cli/query.rb