meibo 0.16.0 → 0.17.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +8 -4
  3. data/.rubocop_todo.yml +130 -0
  4. data/Gemfile +2 -0
  5. data/Gemfile.lock +11 -2
  6. data/lib/meibo/academic_session.rb +17 -16
  7. data/lib/meibo/builder/academic_session_builder.rb +2 -2
  8. data/lib/meibo/builder/base_builder.rb +3 -2
  9. data/lib/meibo/builder/classroom_builder.rb +3 -3
  10. data/lib/meibo/builder/course_builder.rb +3 -3
  11. data/lib/meibo/builder/demographic_builder.rb +2 -2
  12. data/lib/meibo/builder/enrollment_builder.rb +3 -3
  13. data/lib/meibo/builder/organization_builder.rb +2 -2
  14. data/lib/meibo/builder/role_builder.rb +3 -3
  15. data/lib/meibo/builder/user_builder.rb +2 -2
  16. data/lib/meibo/builder/user_profile_builder.rb +3 -3
  17. data/lib/meibo/builder.rb +3 -2
  18. data/lib/meibo/classroom.rb +27 -28
  19. data/lib/meibo/classroom_set.rb +1 -3
  20. data/lib/meibo/converter.rb +29 -31
  21. data/lib/meibo/course.rb +15 -16
  22. data/lib/meibo/course_set.rb +1 -3
  23. data/lib/meibo/data_model.rb +6 -9
  24. data/lib/meibo/data_set.rb +17 -8
  25. data/lib/meibo/demographic.rb +30 -29
  26. data/lib/meibo/enrollment.rb +18 -17
  27. data/lib/meibo/factory_bot/academic_session.rb +3 -3
  28. data/lib/meibo/factory_bot/all.rb +11 -11
  29. data/lib/meibo/factory_bot/classroom.rb +4 -4
  30. data/lib/meibo/factory_bot/course.rb +4 -4
  31. data/lib/meibo/factory_bot/demographic.rb +3 -3
  32. data/lib/meibo/factory_bot/enrollment.rb +3 -3
  33. data/lib/meibo/factory_bot/manifest.rb +2 -2
  34. data/lib/meibo/factory_bot/organization.rb +15 -12
  35. data/lib/meibo/factory_bot/role.rb +3 -3
  36. data/lib/meibo/factory_bot/roster.rb +2 -2
  37. data/lib/meibo/factory_bot/user.rb +6 -6
  38. data/lib/meibo/factory_bot/user_profile.rb +7 -7
  39. data/lib/meibo/japan_profile/academic_session.rb +4 -2
  40. data/lib/meibo/japan_profile/classroom.rb +1 -1
  41. data/lib/meibo/japan_profile/course.rb +2 -2
  42. data/lib/meibo/japan_profile/enrollment.rb +9 -8
  43. data/lib/meibo/japan_profile/organization.rb +2 -2
  44. data/lib/meibo/japan_profile/role.rb +3 -3
  45. data/lib/meibo/japan_profile/user.rb +6 -5
  46. data/lib/meibo/japan_profile/user_set.rb +1 -3
  47. data/lib/meibo/japan_profile.rb +2 -2
  48. data/lib/meibo/manifest/processing_mode.rb +6 -5
  49. data/lib/meibo/manifest.rb +47 -41
  50. data/lib/meibo/organization.rb +16 -15
  51. data/lib/meibo/profile.rb +3 -3
  52. data/lib/meibo/reader.rb +11 -7
  53. data/lib/meibo/role.rb +28 -27
  54. data/lib/meibo/role_set.rb +1 -3
  55. data/lib/meibo/roster.rb +64 -41
  56. data/lib/meibo/user.rb +29 -28
  57. data/lib/meibo/user_profile.rb +14 -13
  58. data/lib/meibo/user_set.rb +1 -3
  59. data/lib/meibo/version.rb +1 -1
  60. data/lib/meibo.rb +2 -2
  61. data/meibo.gemspec +2 -0
  62. metadata +19 -3
data/lib/meibo/roster.rb CHANGED
@@ -1,34 +1,45 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'zip'
4
- require 'csv'
3
+ require "zip"
4
+ require "csv"
5
5
 
6
6
  module Meibo
7
7
  class Roster
8
8
  class << self
9
9
  def from_file(file_path, profile: Meibo.default_profile)
10
10
  Reader.open(file_path, profile: profile) do |reader|
11
- begin
12
- manifest = reader.manifest
13
- rescue CsvFileNotFoundError
14
- raise NotSupportedError, 'OneRoster 1.0はサポートしていません'
15
- rescue
16
- raise NotSupportedError, "#{Meibo::Manifest.filename}の読み込みに失敗しました"
17
- end
18
-
19
- validate_manifest_version(manifest.manifest_version)
20
- validate_oneroster_version(manifest.oneroster_version)
21
- validate_supported_processing_mode(manifest)
22
- processing_modes = Meibo::Manifest::PROCESSING_MODES
23
- validate_absent_files(reader, manifest.filenames(processing_mode: processing_modes[:absent]))
24
- validate_bulk_files(reader, manifest.filenames(processing_mode: processing_modes[:bulk]))
11
+ return read_data(reader, profile)
12
+ end
13
+ end
25
14
 
26
- new(manifest_properties: manifest.to_h, profile: profile, **reader.load_bulk_files).tap(&:check_semantically_consistent)
15
+ def from_buffer(io, profile: Meibo.default_profile)
16
+ Reader.open_buffer(io, profile: profile) do |reader|
17
+ return read_data(reader, profile)
27
18
  end
28
19
  end
29
20
 
30
21
  private
31
22
 
23
+ def read_data(reader, profile)
24
+ begin
25
+ manifest = reader.manifest
26
+ rescue CsvFileNotFoundError
27
+ raise NotSupportedError, "OneRoster 1.0\u306F\u30B5\u30DD\u30FC\u30C8\u3057\u3066\u3044\u307E\u305B\u3093"
28
+ rescue StandardError
29
+ raise NotSupportedError, "#{Meibo::Manifest.filename}の読み込みに失敗しました"
30
+ end
31
+
32
+ validate_manifest_version(manifest.manifest_version)
33
+ validate_oneroster_version(manifest.oneroster_version)
34
+ validate_supported_processing_mode(manifest)
35
+ processing_modes = Meibo::Manifest::PROCESSING_MODES
36
+ validate_absent_files(reader, manifest.filenames(processing_mode: processing_modes[:absent]))
37
+ validate_bulk_files(reader, manifest.filenames(processing_mode: processing_modes[:bulk]))
38
+
39
+ new(manifest_properties: manifest.to_h, profile: profile,
40
+ **reader.load_bulk_files).tap(&:check_semantically_consistent)
41
+ end
42
+
32
43
  def validate_absent_files(reader, absent_filenames)
33
44
  absent_filenames.each do |absent_filename|
34
45
  next unless reader.file_entry?(absent_filename)
@@ -60,13 +71,15 @@ module Meibo
60
71
  def validate_supported_processing_mode(manifest)
61
72
  return if manifest.file_attributes(processing_mode: Meibo::Manifest::PROCESSING_MODES[:delta]).empty?
62
73
 
63
- raise NotSupportedError, 'DELTAはサポートしていません'
74
+ raise NotSupportedError, "DELTA\u306F\u30B5\u30DD\u30FC\u30C8\u3057\u3066\u3044\u307E\u305B\u3093"
64
75
  end
65
76
  end
66
77
 
67
- attr_reader :profile, :manifest_properties, :academic_sessions, :classes, :courses, :demographics, :enrollments, :organizations, :roles, :user_profiles, :users
78
+ attr_reader :profile, :manifest_properties, :academic_sessions, :classes, :courses, :demographics, :enrollments,
79
+ :organizations, :roles, :user_profiles, :users
68
80
 
69
- def initialize(profile: Meibo.default_profile, manifest_properties: {}, academic_sessions: [], classes: [], courses: [], demographics: [], enrollments: [], organizations: [], roles: [], user_profiles: [], users: [])
81
+ def initialize(profile: Meibo.default_profile, manifest_properties: {}, academic_sessions: [], classes: [],
82
+ courses: [], demographics: [], enrollments: [], organizations: [], roles: [], user_profiles: [], users: [])
70
83
  @profile = profile
71
84
  @manifest_properties = manifest_properties
72
85
  @academic_sessions = profile.data_set_for(:academic_sessions).new(academic_sessions, roster: self)
@@ -98,33 +111,43 @@ module Meibo
98
111
  ].each(&:check_semantically_consistent)
99
112
  end
100
113
 
101
- def write(path)
102
- Zip::File.open(path, ::Zip::File::CREATE) do |zipfile|
103
- manifest = build_manifest
104
- zipfile.get_output_stream(::Meibo::Manifest.filename) do |f|
105
- f.puts ::Meibo::Manifest.header_fields.to_csv
106
- manifest.to_a.each do |row|
107
- f.puts row.to_csv
108
- end
114
+ def write_to_buffer(io)
115
+ Zip::File.open_buffer(io) do |zipfile|
116
+ write(zipfile)
117
+ end
118
+ end
119
+
120
+ def write_to_file(path)
121
+ Zip::File.open(path) do |zipfile|
122
+ write(zipfile)
123
+ end
124
+ end
125
+
126
+ private
127
+
128
+ def write(zipfile)
129
+ manifest = build_manifest
130
+ zipfile.get_output_stream(::Meibo::Manifest.filename) do |f|
131
+ f.puts ::Meibo::Manifest.header_fields.to_csv
132
+ manifest.to_a.each do |row|
133
+ f.puts row.to_csv
109
134
  end
110
- file_properties.each do |file_attribute, processing_mode|
111
- next if processing_mode.absent?
112
-
113
- klass = profile.data_model_for(file_attribute)
114
- filename = Manifest.filename_for(file_attribute)
115
- data = data_for(file_attribute)
116
- zipfile.get_output_stream(filename) do |f|
117
- f.puts klass.header_fields.to_csv
118
- data.each do |row|
119
- f.puts row.to_csv(write_converters: klass.write_converters)
120
- end
135
+ end
136
+ file_properties.each do |file_attribute, processing_mode|
137
+ next if processing_mode.absent?
138
+
139
+ klass = profile.data_model_for(file_attribute)
140
+ filename = Manifest.filename_for(file_attribute)
141
+ data = data_for(file_attribute)
142
+ zipfile.get_output_stream(filename) do |f|
143
+ f.puts klass.header_fields.to_csv
144
+ data.each do |row|
145
+ f.puts row.to_csv(write_converters: klass.write_converters)
121
146
  end
122
147
  end
123
148
  end
124
149
  end
125
150
 
126
- private
127
-
128
151
  def build_manifest
129
152
  new_manifest_properties = file_properties.merge(manifest_properties)
130
153
  Meibo::Manifest.build_from_default(**new_manifest_properties)
data/lib/meibo/user.rb CHANGED
@@ -2,46 +2,47 @@
2
2
 
3
3
  module Meibo
4
4
  class User
5
- USER_ID_FORMAT_REGEXP = /\A\{[^:\}]+:[^\}]+\}\z/
5
+ USER_ID_FORMAT_REGEXP = /\A\{[^:}]+:[^}]+\}\z/.freeze
6
6
 
7
7
  DataModel.define(
8
8
  self,
9
9
  attribute_name_to_header_field_map: {
10
- sourced_id: 'sourcedId',
11
- status: 'status',
12
- date_last_modified: 'dateLastModified',
13
- enabled_user: 'enabledUser',
14
- username: 'username',
15
- user_ids: 'userIds',
16
- given_name: 'givenName',
17
- family_name: 'familyName',
18
- middle_name: 'middleName',
19
- identifier: 'identifier',
20
- email: 'email',
21
- sms: 'sms',
22
- phone: 'phone',
23
- agent_sourced_ids: 'agentSourcedIds',
24
- grades: 'grades',
25
- password: 'password',
26
- user_master_identifier: 'userMasterIdentifier',
27
- resource_sourced_ids: 'resourceSourcedIds',
28
- preferred_given_name: 'preferredGivenName',
29
- preferred_middle_name: 'preferredMiddleName',
30
- preferred_family_name: 'preferredFamilyName',
31
- primary_org_sourced_id: 'primaryOrgSourcedId',
32
- pronouns: 'pronouns'
10
+ sourced_id: "sourcedId",
11
+ status: "status",
12
+ date_last_modified: "dateLastModified",
13
+ enabled_user: "enabledUser",
14
+ username: "username",
15
+ user_ids: "userIds",
16
+ given_name: "givenName",
17
+ family_name: "familyName",
18
+ middle_name: "middleName",
19
+ identifier: "identifier",
20
+ email: "email",
21
+ sms: "sms",
22
+ phone: "phone",
23
+ agent_sourced_ids: "agentSourcedIds",
24
+ grades: "grades",
25
+ password: "password",
26
+ user_master_identifier: "userMasterIdentifier",
27
+ resource_sourced_ids: "resourceSourcedIds",
28
+ preferred_given_name: "preferredGivenName",
29
+ preferred_middle_name: "preferredMiddleName",
30
+ preferred_family_name: "preferredFamilyName",
31
+ primary_org_sourced_id: "primaryOrgSourcedId",
32
+ pronouns: "pronouns"
33
33
  }.freeze,
34
34
  converters: {
35
35
  boolean: [:enabled_user].freeze,
36
36
  datetime: [:date_last_modified].freeze,
37
- list: [:user_ids, :agent_sourced_ids, :grades, :resource_sourced_ids].freeze,
38
- required: [:sourced_id, :enabled_user, :username, :given_name, :family_name].freeze,
37
+ list: %i[user_ids agent_sourced_ids grades resource_sourced_ids].freeze,
38
+ required: %i[sourced_id enabled_user username given_name family_name].freeze,
39
39
  status: [:status].freeze,
40
40
  user_ids: [:user_ids].freeze
41
41
  }.freeze
42
42
  )
43
43
 
44
- def initialize(sourced_id:, status: nil, date_last_modified: nil, enabled_user: nil, username:, user_ids: nil, given_name:, family_name:, middle_name: nil, identifier: nil, email: nil, sms: nil, phone: nil, agent_sourced_ids: [], grades: nil, password: nil, user_master_identifier: nil, resource_sourced_ids: nil, preferred_given_name: nil, preferred_middle_name: nil, preferred_family_name: nil, primary_org_sourced_id: nil, pronouns: nil, **extension_fields)
44
+ def initialize(sourced_id:, username:, given_name:, family_name:, status: nil, date_last_modified: nil,
45
+ enabled_user: nil, user_ids: nil, middle_name: nil, identifier: nil, email: nil, sms: nil, phone: nil, agent_sourced_ids: [], grades: nil, password: nil, user_master_identifier: nil, resource_sourced_ids: nil, preferred_given_name: nil, preferred_middle_name: nil, preferred_family_name: nil, primary_org_sourced_id: nil, pronouns: nil, **extension_fields)
45
46
  @sourced_id = sourced_id
46
47
  @status = status
47
48
  @date_last_modified = date_last_modified
@@ -73,7 +74,7 @@ module Meibo
73
74
  end
74
75
 
75
76
  def agents
76
- agent_sourced_ids.map {|agent_sourced_id| Meibo.current_roster.users.find(agent_sourced_id) }
77
+ agent_sourced_ids.map { |agent_sourced_id| Meibo.current_roster.users.find(agent_sourced_id) }
77
78
  end
78
79
 
79
80
  def demographic
@@ -5,26 +5,27 @@ module Meibo
5
5
  DataModel.define(
6
6
  self,
7
7
  attribute_name_to_header_field_map: {
8
- sourced_id: 'sourcedId',
9
- status: 'status',
10
- date_last_modified: 'dateLastModified',
11
- user_sourced_id: 'userSourcedId',
12
- profile_type: 'profileType',
13
- vendor_id: 'vendorId',
14
- application_id: 'applicationId',
15
- description: 'description',
16
- credential_type: 'credentialType',
17
- username: 'username',
18
- password: 'password'
8
+ sourced_id: "sourcedId",
9
+ status: "status",
10
+ date_last_modified: "dateLastModified",
11
+ user_sourced_id: "userSourcedId",
12
+ profile_type: "profileType",
13
+ vendor_id: "vendorId",
14
+ application_id: "applicationId",
15
+ description: "description",
16
+ credential_type: "credentialType",
17
+ username: "username",
18
+ password: "password"
19
19
  },
20
20
  converters: {
21
21
  datetime: [:date_last_modified],
22
- required: [:sourced_id, :user_sourced_id, :profile_type, :vendor_id, :credential_type, :username],
22
+ required: %i[sourced_id user_sourced_id profile_type vendor_id credential_type username],
23
23
  status: [:status]
24
24
  }
25
25
  )
26
26
 
27
- def initialize(sourced_id:, status: nil, date_last_modified: nil, user_sourced_id:, profile_type:, vendor_id:, application_id: nil, description: nil, credential_type:, username:, password: nil, **extension_fields)
27
+ def initialize(sourced_id:, user_sourced_id:, profile_type:, vendor_id:, credential_type:, username:, status: nil, date_last_modified: nil,
28
+ application_id: nil, description: nil, password: nil, **extension_fields)
28
29
  @sourced_id = sourced_id
29
30
  @status = status
30
31
  @date_last_modified = date_last_modified
@@ -6,9 +6,7 @@ module Meibo
6
6
  super
7
7
 
8
8
  each do |user|
9
- if user.primary_org_sourced_id
10
- roster.organizations.find(user.primary_org_sourced_id)
11
- end
9
+ roster.organizations.find(user.primary_org_sourced_id) if user.primary_org_sourced_id
12
10
 
13
11
  user.agent_sourced_ids.each do |agent_sourced_id|
14
12
  find(agent_sourced_id)
data/lib/meibo/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Meibo
4
- VERSION = "0.16.0"
4
+ VERSION = "0.17.0"
5
5
  end
data/lib/meibo.rb CHANGED
@@ -10,8 +10,8 @@ require_relative "meibo/version"
10
10
  require_relative "meibo/errors"
11
11
 
12
12
  module Meibo
13
- CSV_ENCODING = 'UTF-8'
14
- ENUM_EXT_PATTERN = /\Aext:[a-zA-Z0-9\.\-_]+\z/
13
+ CSV_ENCODING = "UTF-8"
14
+ ENUM_EXT_PATTERN = /\Aext:[a-zA-Z0-9.\-_]+\z/.freeze
15
15
 
16
16
  class << self
17
17
  attr_accessor :default_profile
data/meibo.gemspec CHANGED
@@ -30,9 +30,11 @@ Gem::Specification.new do |spec|
30
30
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
31
31
  spec.require_paths = ["lib"]
32
32
 
33
+ spec.add_dependency "csv", ">= 3.1.4"
33
34
  spec.add_dependency "rubyzip"
34
35
  spec.add_dependency "zeitwerk"
35
36
 
36
37
  # For more information and examples about making a new gem, check out our
37
38
  # guide at: https://bundler.io/guides/creating_gem.html
39
+ spec.metadata["rubygems_mfa_required"] = "true"
38
40
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: meibo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.16.0
4
+ version: 0.17.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Seiei Miyagi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-11-24 00:00:00.000000000 Z
11
+ date: 2022-12-06 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: csv
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 3.1.4
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 3.1.4
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: rubyzip
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -47,6 +61,7 @@ extra_rdoc_files: []
47
61
  files:
48
62
  - ".rspec"
49
63
  - ".rubocop.yml"
64
+ - ".rubocop_todo.yml"
50
65
  - CHANGELOG.md
51
66
  - CODE_OF_CONDUCT.md
52
67
  - Gemfile
@@ -125,7 +140,8 @@ metadata:
125
140
  allowed_push_host: https://rubygems.org/
126
141
  homepage_uri: https://github.com/hanachin/meibo
127
142
  source_code_uri: https://github.com/hanachin/meibo
128
- changelog_uri: https://github.com/hanachin/meibo/blob/meibo/v0.16.0/CHANGELOG.md
143
+ changelog_uri: https://github.com/hanachin/meibo/blob/meibo/v0.17.0/CHANGELOG.md
144
+ rubygems_mfa_required: 'true'
129
145
  post_install_message:
130
146
  rdoc_options: []
131
147
  require_paths: