Skip to content

Manually Create Student Classroom Accounts

Campbell Allen edited this page Feb 1, 2023 · 5 revisions

Create the API User accounts

Run the following code on the panoptes API to create the relevant user accounts. Don't forget to copy the reporting logs out so you have a copy of the user credentials for logging in.

# frozen_string_literal: true

require 'securerandom'

def print_account_details(user)
  puts "login: #{user.login}, password: #{user.password}, email: #{user.email}"
end

def account_num_prefix(account_number)
  '%02d' % account_number
end

def log_account_errors(account)
  puts account.errors.full_messages
end

def find_or_build_account(login, display_name, email)
  account = User.find_or_initialize_by(login: login) do |u|
    u.login = login
    u.display_name = display_name
    u.email = email
    u.password = SecureRandom.hex(8)
    u.valid_email = false
    u.global_email_communication = false
    u.project_email_communication = false
    u.build_identity_group
  end

  return account if account.persisted?

  # log errors if account is invalid
  unless account.valid?
    log_account_errors(account)

    exit
  end

  account
end

# accounts data map
accounts_to_save = {}

# create a teacher account
accounts_to_save['teacher'] = find_or_build_account('classrooms-teacher-01', 'Classroom Teacher 01', '[email protected]')

# create the student accounts
# Can you set up 5 classrooms of 25 people each using whatever username makes sense?
# If they could be added to a classroom, owned by a teacher account, that would be fab.
# So teacher_1 with pupils class_1, class_2 etc. Thanks..
num_classrooms = (1..5).to_a
num_students = (1..25).to_a

num_classrooms.each do |classroom_number|
  # setup a class num label with 0 prefix
  class_numf = account_num_prefix(classroom_number)

  # NOTE: classroom's will be created later via education API code

  student_accounts = num_students.map do |student_number|
    # setup a student num label with 0 prefix
    student_numf = account_num_prefix(student_number)

    # create the student accounts
    login = "student-#{student_numf}-class-#{class_numf}"
    find_or_build_account(login, "Student #{student_numf} - Class #{class_numf}", "#{login}[email protected]")
  end

  # store the accounts in the hash
  accounts_to_save[class_numf] = student_accounts
end

# all the accounts should be valid but some may be persisted already if this has run before.
accounts_to_save.each do |account_type, accounts|
  puts "Saving account for: #{account_type}"
  Array.wrap(accounts).each do |account|
    raise StandardError, 'INVALID ACCOUNT WTF!' unless account.valid?

    puts 'Account is valid!'
    account.save!
  end
  puts
end; nil

# Pring the accounts details for reporting back
accounts_to_save.each do |account_type, accounts|
  puts "Saving account for: #{account_type}"
  Array.wrap(accounts).each do |account|
    print_account_details(account)
  end
  puts
end; nil

# DEBUG: CLEANUP the newly created accounts - used when testing/creating
# accounts_to_save.each do |account_type, accounts|
#   Array.wrap(accounts).each do |account|
#     account.reload
#     account.identity_group.destroy!
#     account.destroy!
#   end
# end; nil

Setup the classrooms via the Teacher Account

Use the web interface to setup the classrooms 0. visit https://classroom.zooniverse.org/#/astro-101-with-galaxy-zoo/educators/ 0. login as the Teacher account we created above 0. Use the forms to create the classrooms you need :)

Note: Logging in as the teacher will setup that account in the education api system.

Join student accounts to their classrooms

Run the following code on the panoptes API to ensure the students are joined to the correct classrooms. Note this builds on the output from the create account step above.

# frozen_string_literal: true

# setup student classroom account linkages
classroom_accounts = {
  '2448382' => [
    { id: 2565753, login: 'student-01-class-01' },
    { id: 2565754, login: 'student-02-class-01' },
    { id: 2565755, login: 'student-03-class-01' },
    { id: 2565756, login: 'student-04-class-01' },
    { id: 2565757, login: 'student-05-class-01' },
    { id: 2565758, login: 'student-06-class-01' },
    { id: 2565759, login: 'student-07-class-01' },
    { id: 2565760, login: 'student-08-class-01' },
    { id: 2565761, login: 'student-09-class-01' },
    { id: 2565762, login: 'student-10-class-01' },
    { id: 2565763, login: 'student-11-class-01' },
    { id: 2565764, login: 'student-12-class-01' },
    { id: 2565765, login: 'student-13-class-01' },
    { id: 2565766, login: 'student-14-class-01' },
    { id: 2565767, login: 'student-15-class-01' },
    { id: 2565768, login: 'student-16-class-01' },
    { id: 2565769, login: 'student-17-class-01' },
    { id: 2565770, login: 'student-18-class-01' },
    { id: 2565771, login: 'student-19-class-01' },
    { id: 2565772, login: 'student-20-class-01' },
    { id: 2565773, login: 'student-21-class-01' },
    { id: 2565774, login: 'student-22-class-01' },
    { id: 2565775, login: 'student-23-class-01' },
    { id: 2565776, login: 'student-24-class-01' },
    { id: 2565777, login: 'student-25-class-01' }
  ],
  '2448383' => [
    { id: 2565778, login: 'student-01-class-02' },
    { id: 2565779, login: 'student-02-class-02' },
    { id: 2565780, login: 'student-03-class-02' },
    { id: 2565781, login: 'student-04-class-02' },
    { id: 2565782, login: 'student-05-class-02' },
    { id: 2565783, login: 'student-06-class-02' },
    { id: 2565784, login: 'student-07-class-02' },
    { id: 2565785, login: 'student-08-class-02' },
    { id: 2565786, login: 'student-09-class-02' },
    { id: 2565787, login: 'student-10-class-02' },
    { id: 2565788, login: 'student-11-class-02' },
    { id: 2565789, login: 'student-12-class-02' },
    { id: 2565790, login: 'student-13-class-02' },
    { id: 2565791, login: 'student-14-class-02' },
    { id: 2565792, login: 'student-15-class-02' },
    { id: 2565793, login: 'student-16-class-02' },
    { id: 2565794, login: 'student-17-class-02' },
    { id: 2565795, login: 'student-18-class-02' },
    { id: 2565796, login: 'student-19-class-02' },
    { id: 2565797, login: 'student-20-class-02' },
    { id: 2565798, login: 'student-21-class-02' },
    { id: 2565799, login: 'student-22-class-02' },
    { id: 2565800, login: 'student-23-class-02' },
    { id: 2565801, login: 'student-24-class-02' },
    { id: 2565802, login: 'student-25-class-02' }
  ],
  '2448384' => [
    { id: 2565803, login: 'student-01-class-03' },
    { id: 2565804, login: 'student-02-class-03' },
    { id: 2565805, login: 'student-03-class-03' },
    { id: 2565806, login: 'student-04-class-03' },
    { id: 2565807, login: 'student-05-class-03' },
    { id: 2565808, login: 'student-06-class-03' },
    { id: 2565809, login: 'student-07-class-03' },
    { id: 2565810, login: 'student-08-class-03' },
    { id: 2565811, login: 'student-09-class-03' },
    { id: 2565812, login: 'student-10-class-03' },
    { id: 2565813, login: 'student-11-class-03' },
    { id: 2565814, login: 'student-12-class-03' },
    { id: 2565815, login: 'student-13-class-03' },
    { id: 2565816, login: 'student-14-class-03' },
    { id: 2565817, login: 'student-15-class-03' },
    { id: 2565818, login: 'student-16-class-03' },
    { id: 2565819, login: 'student-17-class-03' },
    { id: 2565820, login: 'student-18-class-03' },
    { id: 2565821, login: 'student-19-class-03' },
    { id: 2565822, login: 'student-20-class-03' },
    { id: 2565823, login: 'student-21-class-03' },
    { id: 2565824, login: 'student-22-class-03' },
    { id: 2565825, login: 'student-23-class-03' },
    { id: 2565826, login: 'student-24-class-03' },
    { id: 2565827, login: 'student-25-class-03' }
  ],
  '2448385' => [
    { id: 2565828, login: 'student-01-class-04' },
    { id: 2565829, login: 'student-02-class-04' },
    { id: 2565830, login: 'student-03-class-04' },
    { id: 2565831, login: 'student-04-class-04' },
    { id: 2565832, login: 'student-05-class-04' },
    { id: 2565833, login: 'student-06-class-04' },
    { id: 2565834, login: 'student-07-class-04' },
    { id: 2565835, login: 'student-08-class-04' },
    { id: 2565836, login: 'student-09-class-04' },
    { id: 2565837, login: 'student-10-class-04' },
    { id: 2565838, login: 'student-11-class-04' },
    { id: 2565839, login: 'student-12-class-04' },
    { id: 2565840, login: 'student-13-class-04' },
    { id: 2565841, login: 'student-14-class-04' },
    { id: 2565842, login: 'student-15-class-04' },
    { id: 2565843, login: 'student-16-class-04' },
    { id: 2565844, login: 'student-17-class-04' },
    { id: 2565845, login: 'student-18-class-04' },
    { id: 2565846, login: 'student-19-class-04' },
    { id: 2565847, login: 'student-20-class-04' },
    { id: 2565848, login: 'student-21-class-04' },
    { id: 2565849, login: 'student-22-class-04' },
    { id: 2565850, login: 'student-23-class-04' },
    { id: 2565851, login: 'student-24-class-04' },
    { id: 2565852, login: 'student-25-class-04' }
  ],
  '2448387' => [
    { id: 2565853, login: 'student-01-class-05' },
    { id: 2565854, login: 'student-02-class-05' },
    { id: 2565855, login: 'student-03-class-05' },
    { id: 2565856, login: 'student-04-class-05' },
    { id: 2565857, login: 'student-05-class-05' },
    { id: 2565858, login: 'student-06-class-05' },
    { id: 2565859, login: 'student-07-class-05' },
    { id: 2565860, login: 'student-08-class-05' },
    { id: 2565861, login: 'student-09-class-05' },
    { id: 2565862, login: 'student-10-class-05' },
    { id: 2565863, login: 'student-11-class-05' },
    { id: 2565864, login: 'student-12-class-05' },
    { id: 2565865, login: 'student-13-class-05' },
    { id: 2565866, login: 'student-14-class-05' },
    { id: 2565867, login: 'student-15-class-05' },
    { id: 2565868, login: 'student-16-class-05' },
    { id: 2565869, login: 'student-17-class-05' },
    { id: 2565870, login: 'student-18-class-05' },
    { id: 2565871, login: 'student-19-class-05' },
    { id: 2565872, login: 'student-20-class-05' },
    { id: 2565873, login: 'student-21-class-05' },
    { id: 2565874, login: 'student-22-class-05' },
    { id: 2565875, login: 'student-23-class-05' },
    { id: 2565876, login: 'student-24-class-05' },
    { id: 2565877, login: 'student-25-class-05' }
  ]
}

# find the student account by id
classroom_accounts.each do |classroom_id, student_accounts|
  user_group = UserGroup.find(classroom_id)
  raise StandardError, "Classroom Group not found: #{classroom_id}" unless user_group

  student_accounts.each do |student_account|
    student = User.find_by_lower_login(student_account[:login])
    raise StandardError, "Student not found: #{student_account[:login]}" unless student

    membership = Membership.find_or_initialize_by(user: student, user_group: user_group)
    membership.state = :active
    membership.save! unless membership.persisted?
    puts "Membership saved: #{membership.id}"
  end
end

Create the student user accounts and linkages in the Education API

Run the following code on the eduction API to ensure the students are setup and linked to the classrooms and assignments.

# frozen_string_literal: true

def find_or_create_account(id, login)
  user = User.find_or_create_by(zooniverse_id: id)
  user.zooniverse_login = login
  # display name will be updated on login to education api system via classroom
  user.save! if user.changed?
  user
end

def log_account(user)
  puts "login: #{user.zooniverse_login}, id: #{user.zooniverse_id}"
end

# link the API accounts to the education-api user accounts
# these come from the the setup code in panoptes API
# make sure you change the IDs to match the student accounts you are creating
# https://github.com/zooniverse/education-api/wiki/Manually-Create-Student-Classroom-Accounts

# setup student classroom account linkages
classroom_accounts = {
  'Classroom 01': [
    { id: 2565753, login: 'student-01-class-01' },
    { id: 2565754, login: 'student-02-class-01' },
    { id: 2565755, login: 'student-03-class-01' },
    { id: 2565756, login: 'student-04-class-01' },
    { id: 2565757, login: 'student-05-class-01' },
    { id: 2565758, login: 'student-06-class-01' },
    { id: 2565759, login: 'student-07-class-01' },
    { id: 2565760, login: 'student-08-class-01' },
    { id: 2565761, login: 'student-09-class-01' },
    { id: 2565762, login: 'student-10-class-01' },
    { id: 2565763, login: 'student-11-class-01' },
    { id: 2565764, login: 'student-12-class-01' },
    { id: 2565765, login: 'student-13-class-01' },
    { id: 2565766, login: 'student-14-class-01' },
    { id: 2565767, login: 'student-15-class-01' },
    { id: 2565768, login: 'student-16-class-01' },
    { id: 2565769, login: 'student-17-class-01' },
    { id: 2565770, login: 'student-18-class-01' },
    { id: 2565771, login: 'student-19-class-01' },
    { id: 2565772, login: 'student-20-class-01' },
    { id: 2565773, login: 'student-21-class-01' },
    { id: 2565774, login: 'student-22-class-01' },
    { id: 2565775, login: 'student-23-class-01' },
    { id: 2565776, login: 'student-24-class-01' },
    { id: 2565777, login: 'student-25-class-01' }
  ],
  'Classroom 02': [
    { id: 2565778, login: 'student-01-class-02' },
    { id: 2565779, login: 'student-02-class-02' },
    { id: 2565780, login: 'student-03-class-02' },
    { id: 2565781, login: 'student-04-class-02' },
    { id: 2565782, login: 'student-05-class-02' },
    { id: 2565783, login: 'student-06-class-02' },
    { id: 2565784, login: 'student-07-class-02' },
    { id: 2565785, login: 'student-08-class-02' },
    { id: 2565786, login: 'student-09-class-02' },
    { id: 2565787, login: 'student-10-class-02' },
    { id: 2565788, login: 'student-11-class-02' },
    { id: 2565789, login: 'student-12-class-02' },
    { id: 2565790, login: 'student-13-class-02' },
    { id: 2565791, login: 'student-14-class-02' },
    { id: 2565792, login: 'student-15-class-02' },
    { id: 2565793, login: 'student-16-class-02' },
    { id: 2565794, login: 'student-17-class-02' },
    { id: 2565795, login: 'student-18-class-02' },
    { id: 2565796, login: 'student-19-class-02' },
    { id: 2565797, login: 'student-20-class-02' },
    { id: 2565798, login: 'student-21-class-02' },
    { id: 2565799, login: 'student-22-class-02' },
    { id: 2565800, login: 'student-23-class-02' },
    { id: 2565801, login: 'student-24-class-02' },
    { id: 2565802, login: 'student-25-class-02' }
  ],
  'Classroom 03': [
    { id: 2565803, login: 'student-01-class-03' },
    { id: 2565804, login: 'student-02-class-03' },
    { id: 2565805, login: 'student-03-class-03' },
    { id: 2565806, login: 'student-04-class-03' },
    { id: 2565807, login: 'student-05-class-03' },
    { id: 2565808, login: 'student-06-class-03' },
    { id: 2565809, login: 'student-07-class-03' },
    { id: 2565810, login: 'student-08-class-03' },
    { id: 2565811, login: 'student-09-class-03' },
    { id: 2565812, login: 'student-10-class-03' },
    { id: 2565813, login: 'student-11-class-03' },
    { id: 2565814, login: 'student-12-class-03' },
    { id: 2565815, login: 'student-13-class-03' },
    { id: 2565816, login: 'student-14-class-03' },
    { id: 2565817, login: 'student-15-class-03' },
    { id: 2565818, login: 'student-16-class-03' },
    { id: 2565819, login: 'student-17-class-03' },
    { id: 2565820, login: 'student-18-class-03' },
    { id: 2565821, login: 'student-19-class-03' },
    { id: 2565822, login: 'student-20-class-03' },
    { id: 2565823, login: 'student-21-class-03' },
    { id: 2565824, login: 'student-22-class-03' },
    { id: 2565825, login: 'student-23-class-03' },
    { id: 2565826, login: 'student-24-class-03' },
    { id: 2565827, login: 'student-25-class-03' }
  ],
  'Classroom 04': [
    { id: 2565828, login: 'student-01-class-04' },
    { id: 2565829, login: 'student-02-class-04' },
    { id: 2565830, login: 'student-03-class-04' },
    { id: 2565831, login: 'student-04-class-04' },
    { id: 2565832, login: 'student-05-class-04' },
    { id: 2565833, login: 'student-06-class-04' },
    { id: 2565834, login: 'student-07-class-04' },
    { id: 2565835, login: 'student-08-class-04' },
    { id: 2565836, login: 'student-09-class-04' },
    { id: 2565837, login: 'student-10-class-04' },
    { id: 2565838, login: 'student-11-class-04' },
    { id: 2565839, login: 'student-12-class-04' },
    { id: 2565840, login: 'student-13-class-04' },
    { id: 2565841, login: 'student-14-class-04' },
    { id: 2565842, login: 'student-15-class-04' },
    { id: 2565843, login: 'student-16-class-04' },
    { id: 2565844, login: 'student-17-class-04' },
    { id: 2565845, login: 'student-18-class-04' },
    { id: 2565846, login: 'student-19-class-04' },
    { id: 2565847, login: 'student-20-class-04' },
    { id: 2565848, login: 'student-21-class-04' },
    { id: 2565849, login: 'student-22-class-04' },
    { id: 2565850, login: 'student-23-class-04' },
    { id: 2565851, login: 'student-24-class-04' },
    { id: 2565852, login: 'student-25-class-04' }
  ],
  'Classroom 05': [
    { id: 2565853, login: 'student-01-class-05' },
    { id: 2565854, login: 'student-02-class-05' },
    { id: 2565855, login: 'student-03-class-05' },
    { id: 2565856, login: 'student-04-class-05' },
    { id: 2565857, login: 'student-05-class-05' },
    { id: 2565858, login: 'student-06-class-05' },
    { id: 2565859, login: 'student-07-class-05' },
    { id: 2565860, login: 'student-08-class-05' },
    { id: 2565861, login: 'student-09-class-05' },
    { id: 2565862, login: 'student-10-class-05' },
    { id: 2565863, login: 'student-11-class-05' },
    { id: 2565864, login: 'student-12-class-05' },
    { id: 2565865, login: 'student-13-class-05' },
    { id: 2565866, login: 'student-14-class-05' },
    { id: 2565867, login: 'student-15-class-05' },
    { id: 2565868, login: 'student-16-class-05' },
    { id: 2565869, login: 'student-17-class-05' },
    { id: 2565870, login: 'student-18-class-05' },
    { id: 2565871, login: 'student-19-class-05' },
    { id: 2565872, login: 'student-20-class-05' },
    { id: 2565873, login: 'student-21-class-05' },
    { id: 2565874, login: 'student-22-class-05' },
    { id: 2565875, login: 'student-23-class-05' },
    { id: 2565876, login: 'student-24-class-05' },
    { id: 2565877, login: 'student-25-class-05' }
  ]
}

program = Program.where(slug: 'zooniverse-in-schools').first
raise StandardError, 'Found the wrong program - wat?!' unless program.name == 'Zooniverse In Schools'

# class rooms are created via the web interface
# https://classroom.zooniverse.org/#/astro-101-with-galaxy-zoo/educators/
# using the teacher login created before
# this will setup the user account in the education api
# and the required classrooms :)

# as there are too many student accounts to manually login and join the classrooms etc
# we will do this manually - a similar step for the teacher could have been performed
#
# for each of the classrooms setup above
# 1. create the student account
# 2. join the classrooms

classroom_accounts.each do |classroom_name, accounts|
  # find the classrooms
  classroom = Classroom.where(name: classroom_name).first
  raise StandardError, "Classroom not found: #{classroom_name}" unless classroom

  accounts.each do |student_account|
    student = find_or_create_account(student_account[:id], student_account[:login])
    log_account(student)

    # Student classroom joining is run via code in panoptes rails console
    # this is due to the educatino code relying on
    # the panoptes client to provide the auth of the logged in student user
    # i.e. they request to join the group - this is supplied to the education api from the front end client
    # so we need to do this manually for now via the join code in the API :(
    #
    # SEE "Join student accounts to their classrooms" code section above!

    # copied from the Classrooms::Join operation
    # now the students are linked to the classrooms in the panoptes API
    # we can create their linkage in the education API
    classroom.students << student
    # skip the student assigment linkage if it's a custom program
    # i still don't know what custom means after all this time.... nomeclature :shrug:
    next if classroom.program.custom?

    # and add the students to the assignments
    classroom.assignments.each do |assignment|
      student_user = StudentUser.where(user_id: student.id, classroom_id: classroom.id).first
      raise StandardError, "StudentUser not found for user: #{student.id} and classroom: #{classroom.id}" unless student_user

      assignment.student_users << student_user
    end
  end
end