meibo 0.16.0 → 0.17.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +8 -4
- data/.rubocop_todo.yml +130 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +11 -2
- data/lib/meibo/academic_session.rb +17 -16
- data/lib/meibo/builder/academic_session_builder.rb +2 -2
- data/lib/meibo/builder/base_builder.rb +3 -2
- data/lib/meibo/builder/classroom_builder.rb +3 -3
- data/lib/meibo/builder/course_builder.rb +3 -3
- data/lib/meibo/builder/demographic_builder.rb +2 -2
- data/lib/meibo/builder/enrollment_builder.rb +3 -3
- data/lib/meibo/builder/organization_builder.rb +2 -2
- data/lib/meibo/builder/role_builder.rb +3 -3
- data/lib/meibo/builder/user_builder.rb +2 -2
- data/lib/meibo/builder/user_profile_builder.rb +3 -3
- data/lib/meibo/builder.rb +3 -2
- data/lib/meibo/classroom.rb +27 -28
- data/lib/meibo/classroom_set.rb +1 -3
- data/lib/meibo/converter.rb +29 -31
- data/lib/meibo/course.rb +15 -16
- data/lib/meibo/course_set.rb +1 -3
- data/lib/meibo/data_model.rb +6 -9
- data/lib/meibo/data_set.rb +17 -8
- data/lib/meibo/demographic.rb +30 -29
- data/lib/meibo/enrollment.rb +18 -17
- data/lib/meibo/factory_bot/academic_session.rb +3 -3
- data/lib/meibo/factory_bot/all.rb +11 -11
- data/lib/meibo/factory_bot/classroom.rb +4 -4
- data/lib/meibo/factory_bot/course.rb +4 -4
- data/lib/meibo/factory_bot/demographic.rb +3 -3
- data/lib/meibo/factory_bot/enrollment.rb +3 -3
- data/lib/meibo/factory_bot/manifest.rb +2 -2
- data/lib/meibo/factory_bot/organization.rb +15 -12
- data/lib/meibo/factory_bot/role.rb +3 -3
- data/lib/meibo/factory_bot/roster.rb +2 -2
- data/lib/meibo/factory_bot/user.rb +6 -6
- data/lib/meibo/factory_bot/user_profile.rb +7 -7
- data/lib/meibo/japan_profile/academic_session.rb +4 -2
- data/lib/meibo/japan_profile/classroom.rb +1 -1
- data/lib/meibo/japan_profile/course.rb +2 -2
- data/lib/meibo/japan_profile/enrollment.rb +9 -8
- data/lib/meibo/japan_profile/organization.rb +2 -2
- data/lib/meibo/japan_profile/role.rb +3 -3
- data/lib/meibo/japan_profile/user.rb +6 -5
- data/lib/meibo/japan_profile/user_set.rb +1 -3
- data/lib/meibo/japan_profile.rb +2 -2
- data/lib/meibo/manifest/processing_mode.rb +6 -5
- data/lib/meibo/manifest.rb +47 -41
- data/lib/meibo/organization.rb +16 -15
- data/lib/meibo/profile.rb +3 -3
- data/lib/meibo/reader.rb +11 -7
- data/lib/meibo/role.rb +28 -27
- data/lib/meibo/role_set.rb +1 -3
- data/lib/meibo/roster.rb +64 -41
- data/lib/meibo/user.rb +29 -28
- data/lib/meibo/user_profile.rb +14 -13
- data/lib/meibo/user_set.rb +1 -3
- data/lib/meibo/version.rb +1 -1
- data/lib/meibo.rb +2 -2
- data/meibo.gemspec +2 -0
- metadata +19 -3
data/lib/meibo/roster.rb
CHANGED
@@ -1,34 +1,45 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
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
|
-
|
12
|
-
|
13
|
-
|
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
|
-
|
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,
|
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,
|
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: [],
|
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
|
102
|
-
Zip::File.
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
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
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
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\{[
|
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:
|
11
|
-
status:
|
12
|
-
date_last_modified:
|
13
|
-
enabled_user:
|
14
|
-
username:
|
15
|
-
user_ids:
|
16
|
-
given_name:
|
17
|
-
family_name:
|
18
|
-
middle_name:
|
19
|
-
identifier:
|
20
|
-
email:
|
21
|
-
sms:
|
22
|
-
phone:
|
23
|
-
agent_sourced_ids:
|
24
|
-
grades:
|
25
|
-
password:
|
26
|
-
user_master_identifier:
|
27
|
-
resource_sourced_ids:
|
28
|
-
preferred_given_name:
|
29
|
-
preferred_middle_name:
|
30
|
-
preferred_family_name:
|
31
|
-
primary_org_sourced_id:
|
32
|
-
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: [
|
38
|
-
required: [
|
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:,
|
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
|
data/lib/meibo/user_profile.rb
CHANGED
@@ -5,26 +5,27 @@ module Meibo
|
|
5
5
|
DataModel.define(
|
6
6
|
self,
|
7
7
|
attribute_name_to_header_field_map: {
|
8
|
-
sourced_id:
|
9
|
-
status:
|
10
|
-
date_last_modified:
|
11
|
-
user_sourced_id:
|
12
|
-
profile_type:
|
13
|
-
vendor_id:
|
14
|
-
application_id:
|
15
|
-
description:
|
16
|
-
credential_type:
|
17
|
-
username:
|
18
|
-
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: [
|
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:,
|
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
|
data/lib/meibo/user_set.rb
CHANGED
@@ -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
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 =
|
14
|
-
ENUM_EXT_PATTERN = /\Aext:[a-zA-Z0-9
|
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.
|
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
|
+
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.
|
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:
|