meibo 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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