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