meibo 0.1.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 (75) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +13 -0
  4. data/CHANGELOG.md +5 -0
  5. data/CODE_OF_CONDUCT.md +84 -0
  6. data/Gemfile +16 -0
  7. data/Gemfile.lock +84 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +41 -0
  10. data/Rakefile +12 -0
  11. data/lib/meibo/academic_session.rb +48 -0
  12. data/lib/meibo/academic_session_set.rb +15 -0
  13. data/lib/meibo/base_profile.rb +37 -0
  14. data/lib/meibo/builder/academic_session_builder.rb +26 -0
  15. data/lib/meibo/builder/base_builder.rb +13 -0
  16. data/lib/meibo/builder/classroom_builder.rb +38 -0
  17. data/lib/meibo/builder/course_builder.rb +32 -0
  18. data/lib/meibo/builder/demographic_builder.rb +22 -0
  19. data/lib/meibo/builder/enrollment_builder.rb +30 -0
  20. data/lib/meibo/builder/organization_builder.rb +34 -0
  21. data/lib/meibo/builder/role_builder.rb +30 -0
  22. data/lib/meibo/builder/user_builder.rb +36 -0
  23. data/lib/meibo/builder/user_profile_builder.rb +22 -0
  24. data/lib/meibo/builder.rb +60 -0
  25. data/lib/meibo/classroom.rb +67 -0
  26. data/lib/meibo/classroom_set.rb +29 -0
  27. data/lib/meibo/converter.rb +259 -0
  28. data/lib/meibo/course.rb +45 -0
  29. data/lib/meibo/course_set.rb +23 -0
  30. data/lib/meibo/data_model.rb +84 -0
  31. data/lib/meibo/data_set.rb +44 -0
  32. data/lib/meibo/demographic.rb +70 -0
  33. data/lib/meibo/demographic_set.rb +18 -0
  34. data/lib/meibo/enrollment.rb +51 -0
  35. data/lib/meibo/enrollment_set.rb +22 -0
  36. data/lib/meibo/errors.rb +13 -0
  37. data/lib/meibo/factory_bot/academic_session.rb +23 -0
  38. data/lib/meibo/factory_bot/all.rb +13 -0
  39. data/lib/meibo/factory_bot/classroom.rb +28 -0
  40. data/lib/meibo/factory_bot/course.rb +21 -0
  41. data/lib/meibo/factory_bot/demographic.rb +16 -0
  42. data/lib/meibo/factory_bot/enrollment.rb +37 -0
  43. data/lib/meibo/factory_bot/manifest.rb +33 -0
  44. data/lib/meibo/factory_bot/memory_package.rb +11 -0
  45. data/lib/meibo/factory_bot/organization.rb +47 -0
  46. data/lib/meibo/factory_bot/role.rb +41 -0
  47. data/lib/meibo/factory_bot/user.rb +22 -0
  48. data/lib/meibo/factory_bot/user_profile.rb +21 -0
  49. data/lib/meibo/japan_profile/academic_session.rb +26 -0
  50. data/lib/meibo/japan_profile/classroom.rb +21 -0
  51. data/lib/meibo/japan_profile/course.rb +18 -0
  52. data/lib/meibo/japan_profile/demographic.rb +15 -0
  53. data/lib/meibo/japan_profile/enrollment.rb +35 -0
  54. data/lib/meibo/japan_profile/organization.rb +20 -0
  55. data/lib/meibo/japan_profile/role.rb +26 -0
  56. data/lib/meibo/japan_profile/user.rb +27 -0
  57. data/lib/meibo/japan_profile/user_profile.rb +7 -0
  58. data/lib/meibo/japan_profile.rb +39 -0
  59. data/lib/meibo/manifest/processing_mode.rb +40 -0
  60. data/lib/meibo/manifest.rb +163 -0
  61. data/lib/meibo/organization.rb +44 -0
  62. data/lib/meibo/organization_set.rb +15 -0
  63. data/lib/meibo/reader.rb +138 -0
  64. data/lib/meibo/role.rb +65 -0
  65. data/lib/meibo/role_set.rb +25 -0
  66. data/lib/meibo/roster.rb +166 -0
  67. data/lib/meibo/user.rb +71 -0
  68. data/lib/meibo/user_profile.rb +42 -0
  69. data/lib/meibo/user_profile_set.rb +18 -0
  70. data/lib/meibo/user_set.rb +24 -0
  71. data/lib/meibo/version.rb +5 -0
  72. data/lib/meibo.rb +17 -0
  73. data/meibo.gemspec +38 -0
  74. data/sig/meibo.rbs +4 -0
  75. metadata +148 -0
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Meibo
4
+ class Demographic
5
+ SEX = {
6
+ male: 'male',
7
+ female: 'female',
8
+ unspecified: 'unspecified',
9
+ other: 'other'
10
+ }.freeze
11
+
12
+ DataModel.define(
13
+ self,
14
+ attribute_name_to_header_field_map: {
15
+ sourced_id: 'sourcedId',
16
+ status: 'status',
17
+ date_last_modified: 'dateLastModified',
18
+ birth_date: 'birthDate',
19
+ sex: 'sex',
20
+ american_indian_or_alaska_native: 'americanIndianOrAlaskaNative',
21
+ asian: 'asian',
22
+ black_or_african_american: 'blackOrAfricanAmerican',
23
+ native_hawaiian_or_other_pacific_islander: 'nativeHawaiianOrOtherPacificIslander',
24
+ white: 'white',
25
+ demographic_race_two_or_more_races: 'demographicRaceTwoOrMoreRaces',
26
+ hispanic_or_latino_ethnicity: 'hispanicOrLatinoEthnicity',
27
+ country_of_birth_code: 'countryOfBirthCode',
28
+ state_of_birth_abbreviation: 'stateOfBirthAbbreviation',
29
+ city_of_birth: 'cityOfBirth',
30
+ public_school_residence_status: 'publicSchoolResidenceStatus'
31
+ }.freeze,
32
+ converters: {
33
+ boolean: [
34
+ :american_indian_or_alaska_native,
35
+ :asian,
36
+ :black_or_african_american,
37
+ :native_hawaiian_or_other_pacific_islander,
38
+ :white,
39
+ :demographic_race_two_or_more_races,
40
+ :hispanic_or_latino_ethnicity
41
+ ].freeze,
42
+ date: [:birth_date].freeze,
43
+ datetime: [:date_last_modified].freeze,
44
+ enum: { sex: [*SEX.values, ENUM_EXT_PATTERN].freeze }.freeze,
45
+ required: [:sourced_id].freeze,
46
+ status: [:status].freeze
47
+ }
48
+ )
49
+
50
+ def initialize(sourced_id:, status: nil, date_last_modified: nil, birth_date: nil, sex: nil, american_indian_or_alaska_native: nil, asian: nil, black_or_african_american: nil, native_hawaiian_or_other_pacific_islander: nil, white: nil, demographic_race_two_or_more_races: nil, hispanic_or_latino_ethnicity: nil, country_of_birth_code: nil, state_of_birth_abbreviation: nil, city_of_birth: nil, public_school_residence_status: nil, **extension_fields)
51
+ @sourced_id = sourced_id
52
+ @status = status
53
+ @date_last_modified = date_last_modified
54
+ @birth_date = birth_date
55
+ @sex = sex
56
+ @american_indian_or_alaska_native = american_indian_or_alaska_native
57
+ @asian = asian
58
+ @black_or_african_american = black_or_african_american
59
+ @native_hawaiian_or_other_pacific_islander = native_hawaiian_or_other_pacific_islander
60
+ @white = white
61
+ @demographic_race_two_or_more_races = demographic_race_two_or_more_races
62
+ @hispanic_or_latino_ethnicity = hispanic_or_latino_ethnicity
63
+ @country_of_birth_code = country_of_birth_code
64
+ @state_of_birth_abbreviation = state_of_birth_abbreviation
65
+ @city_of_birth = city_of_birth
66
+ @public_school_residence_status = public_school_residence_status
67
+ @extension_fields = extension_fields
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Meibo
4
+ class DemographicSet < DataSet
5
+ def initialize(data, user_set:)
6
+ super(data)
7
+ @user_set = user_set
8
+ end
9
+
10
+ def check_semantically_consistent
11
+ super
12
+
13
+ each do |demographic|
14
+ @user_set.find_by_sourced_id(demographic.sourced_id)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Meibo
4
+ class Enrollment
5
+ ROLES = {
6
+ administrator: 'administrator',
7
+ proctor: 'proctor',
8
+ student: 'student',
9
+ teacher: 'teacher'
10
+ }.freeze
11
+
12
+ DataModel.define(
13
+ self,
14
+ attribute_name_to_header_field_map: {
15
+ sourced_id: 'sourcedId',
16
+ status: 'status',
17
+ date_last_modified: 'dateLastModified',
18
+ class_sourced_id: 'classSourcedId',
19
+ school_sourced_id: 'schoolSourcedId',
20
+ user_sourced_id: 'userSourcedId',
21
+ role: 'role',
22
+ primary: 'primary',
23
+ begin_date: 'beginDate',
24
+ end_date: 'endDate'
25
+ }.freeze,
26
+ converters: {
27
+ boolean: [:primary].freeze,
28
+ date: [:begin_date, :end_date].freeze,
29
+ datetime: [:date_last_modified].freeze,
30
+ enum: { role: [*ROLES.values, ENUM_EXT_PATTERN].freeze }.freeze,
31
+ required: [:sourced_id, :class_sourced_id, :school_sourced_id, :user_sourced_id, :role].freeze,
32
+ status: [:status].freeze
33
+ }
34
+ )
35
+
36
+ def initialize(sourced_id:, status: nil, date_last_modified: nil, class_sourced_id:, school_sourced_id:, user_sourced_id:, role:, primary: nil, begin_date: nil, end_date: nil, shusseki_no: nil, public_flg: nil, **extension_fields)
37
+ @sourced_id = sourced_id
38
+ @status = status
39
+ @date_last_modified = date_last_modified
40
+ @class_sourced_id = class_sourced_id
41
+ @school_sourced_id = school_sourced_id
42
+ @user_sourced_id = user_sourced_id
43
+ @role = role
44
+ @begin_date = begin_date
45
+ @end_date = end_date
46
+ @shusseki_no = shusseki_no
47
+ @public_flg = public_flg
48
+ @extension_fields = extension_fields
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Meibo
4
+ class EnrollmentSet < DataSet
5
+ def initialize(data, classroom_set:, organization_set:, user_set:)
6
+ super(data)
7
+ @classroom_set = classroom_set
8
+ @organization_set = organization_set
9
+ @user_set = user_set
10
+ end
11
+
12
+ def check_semantically_consistent
13
+ super
14
+
15
+ each do |enrollment|
16
+ @classroom_set.find_by_sourced_id(enrollment.class_sourced_id)
17
+ @organization_set.find_by_sourced_id(enrollment.school_sourced_id)
18
+ @user_set.find_by_sourced_id(enrollment.user_sourced_id)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Meibo
4
+ class Error < StandardError; end
5
+ class CsvFileNotFoundError < Error; end
6
+ class DataNotFoundError < Error; end
7
+ class InvalidDataTypeError < Error; end
8
+ class MissingDataError < Error; end
9
+ class MissingHeadersError < Error; end
10
+ class NotSupportedError < Error; end
11
+ class ScrambledHeadersError < Error; end
12
+ class SourcedIdDuplicatedError < Error; end
13
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'factory_bot'
4
+ require 'securerandom'
5
+
6
+ FactoryBot.define do
7
+ factory :meibo_academic_session, class: 'Meibo::AcademicSession' do
8
+ initialize_with { new(**attributes) }
9
+
10
+ transient do
11
+ today { Date.today }
12
+ parent { nil }
13
+ end
14
+
15
+ sourced_id { SecureRandom.uuid }
16
+ title { "#{school_year}年度" }
17
+ type { Meibo::AcademicSession::TYPES[:school_year] }
18
+ start_date { Date.new(school_year, 4, 1).iso8601 }
19
+ end_date { Date.new(school_year + 1, 3, 31).iso8601 }
20
+ parent_sourced_id { parent&.sourced_id }
21
+ school_year { today.year }
22
+ end
23
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'meibo/factory_bot/academic_session'
4
+ require 'meibo/factory_bot/classroom'
5
+ require 'meibo/factory_bot/course'
6
+ require 'meibo/factory_bot/demographic'
7
+ require 'meibo/factory_bot/enrollment'
8
+ require 'meibo/factory_bot/manifest'
9
+ require 'meibo/factory_bot/memory_package'
10
+ require 'meibo/factory_bot/organization'
11
+ require 'meibo/factory_bot/role'
12
+ require 'meibo/factory_bot/user_profile'
13
+ require 'meibo/factory_bot/user'
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'factory_bot'
4
+ require 'securerandom'
5
+
6
+ FactoryBot.define do
7
+ factory :meibo_classroom, class: 'Meibo::Classroom' do
8
+ initialize_with { new(**attributes) }
9
+
10
+ transient do
11
+ course { nil }
12
+ school { nil }
13
+ terms { [] }
14
+ end
15
+
16
+ sourced_id { SecureRandom.uuid }
17
+ sequence(:title) {|n| "#{n}組" }
18
+ course_sourced_id { course&.sourced_id }
19
+ class_type { Meibo::Classroom::TYPES[:homeroom] }
20
+ school_sourced_id { school&.sourced_id }
21
+ term_sourced_ids { terms.map(&:sourced_id) }
22
+ special_needs { false }
23
+
24
+ trait :special_needs do
25
+ special_needs { true }
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'factory_bot'
4
+ require 'securerandom'
5
+
6
+ FactoryBot.define do
7
+ factory :meibo_course, class: 'Meibo::Course' do
8
+ initialize_with { new(**attributes) }
9
+
10
+ transient do
11
+ school_year { nil }
12
+ organization { nil }
13
+ end
14
+
15
+ sourced_id { SecureRandom.uuid }
16
+ school_year_sourced_id { school_year&.sourced_id }
17
+ title { "#{school_year&.title}ホームルーム" }
18
+ course_code { '' }
19
+ org_sourced_id { organization&.sourced_id }
20
+ end
21
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'factory_bot'
4
+ require 'securerandom'
5
+
6
+ FactoryBot.define do
7
+ factory :meibo_demographic, class: 'Meibo::Demographic' do
8
+ initialize_with { new(**attributes) }
9
+
10
+ transient do
11
+ user { nil }
12
+ end
13
+
14
+ sourced_id { user&.sourced_id || SecureRandom.uuid }
15
+ end
16
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'factory_bot'
4
+ require 'securerandom'
5
+
6
+ FactoryBot.define do
7
+ factory :meibo_enrollment, class: 'Meibo::Enrollment' do
8
+ initialize_with { new(**attributes) }
9
+
10
+ transient do
11
+ classroom { nil }
12
+ school { nil }
13
+ user { nil }
14
+ end
15
+
16
+ sourced_id { SecureRandom.uuid }
17
+ class_sourced_id { classroom&.sourced_id }
18
+ school_sourced_id { school&.sourced_id }
19
+ user_sourced_id { user&.sourced_id }
20
+
21
+ trait :student do
22
+ role { Meibo::Enrollment::ROLES[:student] }
23
+ end
24
+
25
+ trait :teacher do
26
+ role { Meibo::Enrollment::ROLES[:teacher] }
27
+ end
28
+
29
+ trait :administrator do
30
+ role { Meibo::Enrollment::ROLES[:administrator] }
31
+ end
32
+
33
+ trait :guardian do
34
+ role { Meibo::Enrollment::ROLES[:guardian] }
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'factory_bot'
4
+
5
+ FactoryBot.define do
6
+ factory :meibo_manifest, class: 'Meibo::Manifest' do
7
+ initialize_with { new(**attributes) }
8
+
9
+ manifest_version { Meibo::Manifest::EXPECTED_VALUES[:manifest_version] }
10
+ oneroster_version { Meibo::Manifest::EXPECTED_VALUES[:oneroster_version] }
11
+ file_academic_sessions { Meibo::Manifest::EXPECTED_VALUES[:file_academic_sessions] }
12
+ file_categories { Meibo::Manifest::EXPECTED_VALUES[:file_categories] }
13
+ file_classes { Meibo::Manifest::EXPECTED_VALUES[:file_classes] }
14
+ file_class_resources { Meibo::Manifest::EXPECTED_VALUES[:file_class_resources] }
15
+ file_courses { Meibo::Manifest::EXPECTED_VALUES[:file_courses] }
16
+ file_course_resources { Meibo::Manifest::EXPECTED_VALUES[:file_course_resources] }
17
+ file_demographics { Meibo::Manifest::EXPECTED_VALUES[:file_demographics] }
18
+ file_enrollments { Meibo::Manifest::EXPECTED_VALUES[:file_enrollments] }
19
+ file_line_item_learning_objective_ids { Meibo::Manifest::EXPECTED_VALUES[:file_line_item_learning_objective_ids] }
20
+ file_line_items { Meibo::Manifest::EXPECTED_VALUES[:file_line_items] }
21
+ file_line_item_score_scales { Meibo::Manifest::EXPECTED_VALUES[:file_line_item_score_scales] }
22
+ file_orgs { Meibo::Manifest::EXPECTED_VALUES[:file_orgs] }
23
+ file_resources { Meibo::Manifest::EXPECTED_VALUES[:file_resources] }
24
+ file_result_learning_objective_ids { Meibo::Manifest::EXPECTED_VALUES[:file_result_learning_objective_ids] }
25
+ file_results { Meibo::Manifest::EXPECTED_VALUES[:file_results] }
26
+ file_result_score_scales { Meibo::Manifest::EXPECTED_VALUES[:file_result_score_scales] }
27
+ file_roles { Meibo::Manifest::EXPECTED_VALUES[:file_roles] }
28
+ file_score_scales { Meibo::Manifest::EXPECTED_VALUES[:file_score_scales] }
29
+ file_user_profiles { Meibo::Manifest::EXPECTED_VALUES[:file_user_profiles] }
30
+ file_user_resources { Meibo::Manifest::EXPECTED_VALUES[:file_user_resources] }
31
+ file_users { Meibo::Manifest::EXPECTED_VALUES[:file_users] }
32
+ end
33
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'factory_bot'
4
+
5
+ FactoryBot.define do
6
+ factory :meibo_memory_package, class: 'Meibo::MemoryPackage' do
7
+ initialize_with { new(**attributes) }
8
+
9
+ manifest { build(:meibo_manifest) }
10
+ end
11
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'factory_bot'
4
+ require 'securerandom'
5
+
6
+ FactoryBot.define do
7
+ factory :meibo_organization, class: 'Meibo::Organization' do
8
+ initialize_with { new(**attributes) }
9
+
10
+ transient do
11
+ parent { nil }
12
+
13
+ # NOTE: https://www.mext.go.jp/content/20210128-mxt_chousa01-000011635_01.pdf
14
+ school_type { 'B1' } # 小学校
15
+ prefecture_no { '01' } # 北海道
16
+ kubun { '2' } #公立
17
+ sequence(:school_no) {|n| '%07d' % n }
18
+ end
19
+
20
+ sourced_id { SecureRandom.uuid }
21
+ parent_sourced_id { parent&.sourced_id }
22
+ identifier do
23
+ school_type_alphabet_map = { 'A' => '01', 'B' => '02', 'C' => '03', 'D' => '04', 'E' => '05', 'F' => '06', 'G' => '07', 'H' => '08' }.freeze
24
+ numerized_school_type = school_type.sub(/\A[A-H]/, school_type_alphabet_map)
25
+ numerized_school_code = "#{numerized_school_type}#{prefecture_no}#{kubun}#{school_no}"
26
+
27
+ raise unless numerized_school_code.size == 13
28
+
29
+ check_digit = (10 - (numerized_school_code.chars.map(&:to_i).zip([1, 2].cycle).map { (_1 * _2).digits.sum }.sum % 10)) % 10
30
+ "#{school_type}#{prefecture_no}#{kubun}#{school_no}#{check_digit}"
31
+ end
32
+
33
+ trait :district do
34
+ type { Meibo::Organization::TYPES[:district] }
35
+ end
36
+
37
+ trait :school do
38
+ type { Meibo::Organization::TYPES[:school] }
39
+ end
40
+
41
+ trait :elementary_school do |factory|
42
+ type { Meibo::Organization::TYPES[:school] }
43
+ sequence(:name) {|n| "第#{n}小学校" }
44
+ school_type { 'B1' }
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'factory_bot'
4
+ require 'securerandom'
5
+
6
+ FactoryBot.define do
7
+ factory :meibo_role, class: 'Meibo::Role' do
8
+ initialize_with { new(**attributes) }
9
+
10
+ transient do
11
+ user { nil }
12
+ organization { nil }
13
+ user_profile { nil }
14
+ end
15
+
16
+ sourced_id { SecureRandom.uuid }
17
+ user_sourced_id { user&.sourced_id }
18
+ org_sourced_id { organization&.sourced_id }
19
+ user_profile_sourced_id { user_profile&.sourced_id }
20
+
21
+ trait :primary do
22
+ role_type { Meibo::Role::TYPES[:primary] }
23
+ end
24
+
25
+ trait :secondary do
26
+ role_type { Meibo::Role::TYPES[:secondary] }
27
+ end
28
+
29
+ trait :teacher do
30
+ role { Meibo::Role::ROLES[:teacher] }
31
+ end
32
+
33
+ trait :student do
34
+ role { Meibo::Role::ROLES[:student] }
35
+ end
36
+
37
+ trait :guardian do
38
+ role { Meibo::Role::ROLES[:guardian] }
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'factory_bot'
4
+ require 'securerandom'
5
+
6
+ FactoryBot.define do
7
+ factory :meibo_user, class: 'Meibo::User' do
8
+ initialize_with { new(**attributes) }
9
+
10
+ transient do
11
+ agents { [] }
12
+ primary_organization { nil }
13
+ end
14
+
15
+ sourced_id { SecureRandom.uuid }
16
+ sequence(:username) {|n| "user#{n}@example.com" }
17
+ sequence(:given_name) {|n| "John#{n}" }
18
+ sequence(:family_name) {|n| "Doe#{n}" }
19
+ agent_sourced_ids { agents&.map(&:sourced_id) }
20
+ primary_org_sourced_id { primary_organization&.sourced_id }
21
+ end
22
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'factory_bot'
4
+ require 'securerandom'
5
+
6
+ FactoryBot.define do
7
+ factory :meibo_user_profile, class: 'Meibo::UserProfile' do
8
+ initialize_with { new(**attributes) }
9
+
10
+ transient do
11
+ user { nil }
12
+ end
13
+
14
+ sourced_id { SecureRandom.uuid }
15
+ user_sourced_id { user&.sourced_id }
16
+ profile_type { 'meibo test' }
17
+ vendor_id { 'meibo' }
18
+ credential_type { 'plain' }
19
+ sequence(:username) {|n| "user#{n}"}
20
+ end
21
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Meibo
4
+ module JapanProfile
5
+ class AcademicSession < ::Meibo::AcademicSession
6
+ TYPES = { school_year: 'schoolYear' }.freeze
7
+
8
+ DataModel.define(
9
+ self,
10
+ attribute_name_to_header_field_map: superclass.attribute_name_to_header_field_map,
11
+ converters: superclass.converters.merge(
12
+ enum: { type: TYPES.values.freeze }.freeze
13
+ )
14
+ )
15
+
16
+ # NOTE: 以下固定
17
+ # - titleは連携処理実行時の対象年度西暦 + 「年度」を設定
18
+ # - typeはschoolYear固定
19
+ # - start_dateは対象年度の開始日固定
20
+ # - end_dateは対象年度の終了日固定
21
+ def initialize(school_year:, title: "#{school_year}年度", type: TYPES[:school_year], start_date: Date.new(school_year, 4, 1), end_date: Date.new(school_year + 1, 3, 31), **other_fields)
22
+ super(school_year: school_year, title: title, type: type, start_date: start_date, end_date: end_date, **other_fields)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Meibo
4
+ module JapanProfile
5
+ class Classroom < ::Meibo::Classroom
6
+ DataModel.define(
7
+ self,
8
+ attribute_name_to_header_field_map: superclass.attribute_name_to_header_field_map.merge(special_needs: 'metadata.jp.specialNeeds').freeze,
9
+ converters: superclass.converters.merge(
10
+ boolean: [:special_needs].freeze,
11
+ enum: { class_type: TYPES.values.freeze }.freeze
12
+ ).freeze
13
+ )
14
+
15
+ def initialize(special_needs: nil, **other_fields)
16
+ super(**other_fields)
17
+ @special_needs = special_needs
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Meibo
4
+ module JapanProfile
5
+ class Course < ::Meibo::Course
6
+ DataModel.define(
7
+ self,
8
+ attribute_name_to_header_field_map: superclass.attribute_name_to_header_field_map,
9
+ converters: superclass.converters.merge(enum: { course_code: [''].freeze }.freeze)
10
+ )
11
+
12
+ # NOTE: courseCodeは空文字固定
13
+ def initialize(course_code: '', **other_fields)
14
+ super(course_code: course_code, **other_fields)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Meibo
4
+ module JapanProfile
5
+ class Demographic < ::Meibo::Demographic
6
+ DataModel.define(
7
+ self,
8
+ attribute_name_to_header_field_map: superclass.attribute_name_to_header_field_map,
9
+ converters: superclass.converters.merge(
10
+ enum: { sex: SEX.values.freeze }
11
+ ).freeze
12
+ )
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Meibo
4
+ module JapanProfile
5
+ class Enrollment < ::Meibo::Enrollment
6
+ ROLES = {
7
+ student: 'student',
8
+ teacher: 'teacher',
9
+ administrator: 'administrator',
10
+ guardian: 'guardian'
11
+ }.freeze
12
+
13
+ DataModel.define(
14
+ self,
15
+ attribute_name_to_header_field_map: superclass.attribute_name_to_header_field_map.merge(
16
+ shusseki_no: 'metadata.jp.ShussekiNo',
17
+ public_flg: 'metadata.jp.PublicFlg'
18
+ ).freeze,
19
+ converters: superclass.converters.merge(
20
+ boolean: [*superclass.converters[:boolean], :public_flg].freeze,
21
+ enum: { role: ROLES.values.freeze }.freeze,
22
+ integer: [:shusseki_no].freeze
23
+ ).freeze
24
+ )
25
+
26
+ # NOTE: 児童生徒の場合primaryはfalse固定
27
+ # MEMO: 保護者の場合もそうでは?
28
+ def initialize(shusseki_no: nil, public_flg: nil, role:, primary: (role == ROLES[:student] ? false : nil), **other_fields)
29
+ super(role: role, primary: primary, **other_fields)
30
+ @shusseki_no = shusseki_no
31
+ @public_flg = public_flg
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Meibo
4
+ module JapanProfile
5
+ class Organization < ::Meibo::Organization
6
+ TYPES = {
7
+ district: 'district',
8
+ school: 'school'
9
+ }.freeze
10
+
11
+ DataModel.define(
12
+ self,
13
+ attribute_name_to_header_field_map: superclass.attribute_name_to_header_field_map,
14
+ converters: superclass.converters.merge(
15
+ enum: { type: TYPES.values.freeze }
16
+ ).freeze
17
+ )
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Meibo
4
+ module JapanProfile
5
+ class Role < ::Meibo::Role
6
+ # NOTE: roleは固定
7
+ # - 児童生徒の場合student
8
+ # - 教職員の場合teacher
9
+ # - 保護者の場合guardian
10
+ # MEMO: enrollments.csvの方ではadministratorとguardianも許可されているがズレてないか
11
+ ROLES = {
12
+ teacher: 'teacher',
13
+ student: 'student',
14
+ guardian: 'guardian'
15
+ }.freeze
16
+
17
+ DataModel.define(
18
+ self,
19
+ attribute_name_to_header_field_map: superclass.attribute_name_to_header_field_map,
20
+ converters: superclass.converters.merge(
21
+ enum: superclass.converters[:enum].merge(role: ROLES.values).freeze
22
+ )
23
+ )
24
+ end
25
+ end
26
+ end