meibo 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +13 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +16 -0
- data/Gemfile.lock +84 -0
- data/LICENSE.txt +21 -0
- data/README.md +41 -0
- data/Rakefile +12 -0
- data/lib/meibo/academic_session.rb +48 -0
- data/lib/meibo/academic_session_set.rb +15 -0
- data/lib/meibo/base_profile.rb +37 -0
- data/lib/meibo/builder/academic_session_builder.rb +26 -0
- data/lib/meibo/builder/base_builder.rb +13 -0
- data/lib/meibo/builder/classroom_builder.rb +38 -0
- data/lib/meibo/builder/course_builder.rb +32 -0
- data/lib/meibo/builder/demographic_builder.rb +22 -0
- data/lib/meibo/builder/enrollment_builder.rb +30 -0
- data/lib/meibo/builder/organization_builder.rb +34 -0
- data/lib/meibo/builder/role_builder.rb +30 -0
- data/lib/meibo/builder/user_builder.rb +36 -0
- data/lib/meibo/builder/user_profile_builder.rb +22 -0
- data/lib/meibo/builder.rb +60 -0
- data/lib/meibo/classroom.rb +67 -0
- data/lib/meibo/classroom_set.rb +29 -0
- data/lib/meibo/converter.rb +259 -0
- data/lib/meibo/course.rb +45 -0
- data/lib/meibo/course_set.rb +23 -0
- data/lib/meibo/data_model.rb +84 -0
- data/lib/meibo/data_set.rb +44 -0
- data/lib/meibo/demographic.rb +70 -0
- data/lib/meibo/demographic_set.rb +18 -0
- data/lib/meibo/enrollment.rb +51 -0
- data/lib/meibo/enrollment_set.rb +22 -0
- data/lib/meibo/errors.rb +13 -0
- data/lib/meibo/factory_bot/academic_session.rb +23 -0
- data/lib/meibo/factory_bot/all.rb +13 -0
- data/lib/meibo/factory_bot/classroom.rb +28 -0
- data/lib/meibo/factory_bot/course.rb +21 -0
- data/lib/meibo/factory_bot/demographic.rb +16 -0
- data/lib/meibo/factory_bot/enrollment.rb +37 -0
- data/lib/meibo/factory_bot/manifest.rb +33 -0
- data/lib/meibo/factory_bot/memory_package.rb +11 -0
- data/lib/meibo/factory_bot/organization.rb +47 -0
- data/lib/meibo/factory_bot/role.rb +41 -0
- data/lib/meibo/factory_bot/user.rb +22 -0
- data/lib/meibo/factory_bot/user_profile.rb +21 -0
- data/lib/meibo/japan_profile/academic_session.rb +26 -0
- data/lib/meibo/japan_profile/classroom.rb +21 -0
- data/lib/meibo/japan_profile/course.rb +18 -0
- data/lib/meibo/japan_profile/demographic.rb +15 -0
- data/lib/meibo/japan_profile/enrollment.rb +35 -0
- data/lib/meibo/japan_profile/organization.rb +20 -0
- data/lib/meibo/japan_profile/role.rb +26 -0
- data/lib/meibo/japan_profile/user.rb +27 -0
- data/lib/meibo/japan_profile/user_profile.rb +7 -0
- data/lib/meibo/japan_profile.rb +39 -0
- data/lib/meibo/manifest/processing_mode.rb +40 -0
- data/lib/meibo/manifest.rb +163 -0
- data/lib/meibo/organization.rb +44 -0
- data/lib/meibo/organization_set.rb +15 -0
- data/lib/meibo/reader.rb +138 -0
- data/lib/meibo/role.rb +65 -0
- data/lib/meibo/role_set.rb +25 -0
- data/lib/meibo/roster.rb +166 -0
- data/lib/meibo/user.rb +71 -0
- data/lib/meibo/user_profile.rb +42 -0
- data/lib/meibo/user_profile_set.rb +18 -0
- data/lib/meibo/user_set.rb +24 -0
- data/lib/meibo/version.rb +5 -0
- data/lib/meibo.rb +17 -0
- data/meibo.gemspec +38 -0
- data/sig/meibo.rbs +4 -0
- 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
|
data/lib/meibo/errors.rb
ADDED
@@ -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,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
|