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.
- 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
         |