meibo 0.16.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: