@@ -53,6 +53,11 @@ module Lti
|
|||||||
end
|
end
|
||||||
private :external_user_name
|
private :external_user_name
|
||||||
|
|
||||||
|
def mooc_course
|
||||||
|
# All Xikolo platforms set the custom_course to the course code
|
||||||
|
params[:custom_course]
|
||||||
|
end
|
||||||
|
|
||||||
def refuse_lti_launch(options = {})
|
def refuse_lti_launch(options = {})
|
||||||
return_to_consumer(lti_errorlog: options[:message], lti_errormsg: t('sessions.oauth.failure'))
|
return_to_consumer(lti_errorlog: options[:message], lti_errormsg: t('sessions.oauth.failure'))
|
||||||
end
|
end
|
||||||
@@ -134,6 +139,14 @@ module Lti
|
|||||||
end
|
end
|
||||||
private :set_current_user
|
private :set_current_user
|
||||||
|
|
||||||
|
|
||||||
|
def set_study_group_membership
|
||||||
|
return if mooc_course
|
||||||
|
group = StudyGroup.find_or_create_by(external_id: @provider.resource_link_id, consumer: @consumer)
|
||||||
|
group.users |= [@current_user] # add current user if not already member of the group
|
||||||
|
group.save
|
||||||
|
end
|
||||||
|
|
||||||
def set_embedding_options
|
def set_embedding_options
|
||||||
@embed_options = {}
|
@embed_options = {}
|
||||||
[:hide_navbar,
|
[:hide_navbar,
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
class SessionsController < ApplicationController
|
class SessionsController < ApplicationController
|
||||||
include Lti
|
include Lti
|
||||||
|
|
||||||
[:require_oauth_parameters, :require_valid_consumer_key, :require_valid_oauth_signature, :require_unique_oauth_nonce, :set_current_user, :require_valid_exercise_token, :set_embedding_options].each do |method_name|
|
[:require_oauth_parameters, :require_valid_consumer_key, :require_valid_oauth_signature, :require_unique_oauth_nonce, :set_current_user, :require_valid_exercise_token, :set_study_group_membership, :set_embedding_options].each do |method_name|
|
||||||
before_action(method_name, only: :create_through_lti)
|
before_action(method_name, only: :create_through_lti)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@@ -1,32 +0,0 @@
|
|||||||
module User
|
|
||||||
extend ActiveSupport::Concern
|
|
||||||
|
|
||||||
ROLES = %w(admin teacher)
|
|
||||||
|
|
||||||
included do
|
|
||||||
belongs_to :consumer
|
|
||||||
has_many :exercises, as: :user
|
|
||||||
has_many :file_types, as: :user
|
|
||||||
has_many :submissions, as: :user
|
|
||||||
has_many :participations, through: :submissions, source: :exercise, as: :user
|
|
||||||
has_many :user_proxy_exercise_exercises, as: :user
|
|
||||||
has_many :user_exercise_interventions, as: :user
|
|
||||||
has_many :interventions, through: :user_exercise_interventions
|
|
||||||
accepts_nested_attributes_for :user_proxy_exercise_exercises
|
|
||||||
|
|
||||||
|
|
||||||
scope :with_submissions, -> { where('id IN (SELECT user_id FROM submissions)') }
|
|
||||||
end
|
|
||||||
|
|
||||||
ROLES.each do |role|
|
|
||||||
define_method("#{role}?") { try(:role) == role }
|
|
||||||
end
|
|
||||||
|
|
||||||
[ExternalUser, InternalUser].each do |klass|
|
|
||||||
define_method("#{klass.name.underscore}?") { is_a?(klass) }
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_s
|
|
||||||
displayname
|
|
||||||
end
|
|
||||||
end
|
|
@@ -1,5 +1,4 @@
|
|||||||
class ExternalUser < ApplicationRecord
|
class ExternalUser < User
|
||||||
include User
|
|
||||||
|
|
||||||
validates :consumer_id, presence: true
|
validates :consumer_id, presence: true
|
||||||
validates :external_id, presence: true
|
validates :external_id, presence: true
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
class InternalUser < ApplicationRecord
|
class InternalUser < User
|
||||||
include User
|
|
||||||
|
|
||||||
authenticates_with_sorcery!
|
authenticates_with_sorcery!
|
||||||
|
|
||||||
|
11
app/models/study_group.rb
Normal file
11
app/models/study_group.rb
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class StudyGroup < ApplicationRecord
|
||||||
|
has_many :study_group_memberships
|
||||||
|
# Use `ExternalUser` as `source_type` for now.
|
||||||
|
# Using `User` will lead ActiveRecord to access the inexistent table `users`.
|
||||||
|
# Issue created: https://github.com/rails/rails/issues/34531
|
||||||
|
has_many :users, through: :study_group_memberships, source_type: 'ExternalUser'
|
||||||
|
has_many :submissions
|
||||||
|
belongs_to :consumer
|
||||||
|
end
|
8
app/models/study_group_membership.rb
Normal file
8
app/models/study_group_membership.rb
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class StudyGroupMembership < ApplicationRecord
|
||||||
|
belongs_to :user, polymorphic: true
|
||||||
|
belongs_to :study_group
|
||||||
|
|
||||||
|
validates_uniqueness_of :user_id, :scope => [:user_type, :study_group_id]
|
||||||
|
end
|
@@ -6,6 +6,7 @@ class Submission < ApplicationRecord
|
|||||||
FILENAME_URL_PLACEHOLDER = '{filename}'
|
FILENAME_URL_PLACEHOLDER = '{filename}'
|
||||||
|
|
||||||
belongs_to :exercise
|
belongs_to :exercise
|
||||||
|
belongs_to :study_group, optional: true
|
||||||
|
|
||||||
has_many :testruns
|
has_many :testruns
|
||||||
has_many :structured_errors
|
has_many :structured_errors
|
||||||
|
36
app/models/user.rb
Normal file
36
app/models/user.rb
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
class User < ApplicationRecord
|
||||||
|
self.abstract_class = true
|
||||||
|
|
||||||
|
ROLES = %w(admin teacher)
|
||||||
|
|
||||||
|
belongs_to :consumer
|
||||||
|
has_many :study_group_memberships, as: :user
|
||||||
|
has_many :study_groups, through: :study_group_memberships, as: :user
|
||||||
|
has_many :exercises, as: :user
|
||||||
|
has_many :file_types, as: :user
|
||||||
|
has_many :submissions, as: :user
|
||||||
|
has_many :participations, through: :submissions, source: :exercise, as: :user
|
||||||
|
has_many :user_proxy_exercise_exercises, as: :user
|
||||||
|
has_many :user_exercise_interventions, as: :user
|
||||||
|
has_many :interventions, through: :user_exercise_interventions
|
||||||
|
accepts_nested_attributes_for :user_proxy_exercise_exercises
|
||||||
|
|
||||||
|
|
||||||
|
scope :with_submissions, -> { where('id IN (SELECT user_id FROM submissions)') }
|
||||||
|
|
||||||
|
ROLES.each do |role|
|
||||||
|
define_method("#{role}?") { try(:role) == role }
|
||||||
|
end
|
||||||
|
|
||||||
|
def internal_user?
|
||||||
|
is_a?(InternalUser)
|
||||||
|
end
|
||||||
|
|
||||||
|
def external_user?
|
||||||
|
is_a?(ExternalUser)
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
displayname
|
||||||
|
end
|
||||||
|
end
|
13
db/migrate/20181122084546_create_study_groups.rb
Normal file
13
db/migrate/20181122084546_create_study_groups.rb
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
class CreateStudyGroups < ActiveRecord::Migration[5.2]
|
||||||
|
def change
|
||||||
|
create_table :study_groups do |t|
|
||||||
|
t.string :name
|
||||||
|
t.string :external_id
|
||||||
|
t.belongs_to :consumer
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
|
||||||
|
add_index :study_groups, [:external_id, :consumer_id], unique: true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@@ -0,0 +1,8 @@
|
|||||||
|
class CreateStudyGroupMemberships < ActiveRecord::Migration[5.2]
|
||||||
|
def change
|
||||||
|
create_table :study_group_memberships do |t|
|
||||||
|
t.belongs_to :study_group
|
||||||
|
t.belongs_to :user, polymorphic: true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@@ -0,0 +1,5 @@
|
|||||||
|
class AddStudyGroupToSubmission < ActiveRecord::Migration[5.2]
|
||||||
|
def change
|
||||||
|
add_reference :submissions, :study_group, index: true, null: true, foreign_key: true
|
||||||
|
end
|
||||||
|
end
|
20
db/schema.rb
20
db/schema.rb
@@ -319,6 +319,24 @@ ActiveRecord::Schema.define(version: 2018_11_29_093207) do
|
|||||||
t.index ["submission_id"], name: "index_structured_errors_on_submission_id"
|
t.index ["submission_id"], name: "index_structured_errors_on_submission_id"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
create_table "study_group_memberships", force: :cascade do |t|
|
||||||
|
t.bigint "study_group_id"
|
||||||
|
t.string "user_type"
|
||||||
|
t.bigint "user_id"
|
||||||
|
t.index ["study_group_id"], name: "index_study_group_memberships_on_study_group_id"
|
||||||
|
t.index ["user_type", "user_id"], name: "index_study_group_memberships_on_user_type_and_user_id"
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table "study_groups", force: :cascade do |t|
|
||||||
|
t.string "name"
|
||||||
|
t.string "external_id"
|
||||||
|
t.bigint "consumer_id"
|
||||||
|
t.datetime "created_at", null: false
|
||||||
|
t.datetime "updated_at", null: false
|
||||||
|
t.index ["consumer_id"], name: "index_study_groups_on_consumer_id"
|
||||||
|
t.index ["external_id", "consumer_id"], name: "index_study_groups_on_external_id_and_consumer_id", unique: true
|
||||||
|
end
|
||||||
|
|
||||||
create_table "submissions", force: :cascade do |t|
|
create_table "submissions", force: :cascade do |t|
|
||||||
t.integer "exercise_id"
|
t.integer "exercise_id"
|
||||||
t.float "score"
|
t.float "score"
|
||||||
@@ -327,7 +345,9 @@ ActiveRecord::Schema.define(version: 2018_11_29_093207) do
|
|||||||
t.datetime "updated_at"
|
t.datetime "updated_at"
|
||||||
t.string "cause", limit: 255
|
t.string "cause", limit: 255
|
||||||
t.string "user_type", limit: 255
|
t.string "user_type", limit: 255
|
||||||
|
t.bigint "study_group_id"
|
||||||
t.index ["exercise_id"], name: "index_submissions_on_exercise_id"
|
t.index ["exercise_id"], name: "index_submissions_on_exercise_id"
|
||||||
|
t.index ["study_group_id"], name: "index_submissions_on_study_group_id"
|
||||||
t.index ["user_id"], name: "index_submissions_on_user_id"
|
t.index ["user_id"], name: "index_submissions_on_user_id"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@@ -66,7 +66,7 @@ describe SessionsController do
|
|||||||
it 'refuses the LTI launch' do
|
it 'refuses the LTI launch' do
|
||||||
expect_any_instance_of(IMS::LTI::ToolProvider).to receive(:valid_request?).and_return(true)
|
expect_any_instance_of(IMS::LTI::ToolProvider).to receive(:valid_request?).and_return(true)
|
||||||
expect(controller).to receive(:refuse_lti_launch).with(message: I18n.t('sessions.oauth.invalid_exercise_token')).and_call_original
|
expect(controller).to receive(:refuse_lti_launch).with(message: I18n.t('sessions.oauth.invalid_exercise_token')).and_call_original
|
||||||
post :create_through_lti, params: { custom_token: '', oauth_consumer_key: consumer.oauth_key, oauth_nonce: nonce, oauth_signature: SecureRandom.hex }
|
post :create_through_lti, params: { custom_token: '', oauth_consumer_key: consumer.oauth_key, oauth_nonce: nonce, oauth_signature: SecureRandom.hex, user_id: '123' }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user