Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions app/helpers/authorisation_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ def authorise?(user, object, action, perm_get_fn = method(:get_permission_hash),
obj_class = object.class == Class ? object : object.class

role_obj = object.role_for(user)
# To user read only
if role_obj.respond_to?(:observer) && role_obj.observer && action != :get
return false
end

return false if role_obj.nil?

Expand Down
5 changes: 5 additions & 0 deletions db/migrate/20250803223033_add_observer_to_unit_roles.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddObserverToUnitRoles < ActiveRecord::Migration[7.1]
def change
add_column :unit_roles, :observer, :boolean, default: false
end
end
71 changes: 36 additions & 35 deletions db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema[7.1].define(version: 2024_05_28_223908) do
create_table "activity_types", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t|
ActiveRecord::Schema[7.1].define(version: 2025_08_03_223033) do
create_table "activity_types", charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
t.string "name", null: false
t.string "abbreviation", null: false
t.datetime "created_at", null: false
Expand All @@ -20,21 +20,21 @@
t.index ["name"], name: "index_activity_types_on_name", unique: true
end

create_table "auth_tokens", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t|
create_table "auth_tokens", charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
t.datetime "auth_token_expiry", null: false
t.bigint "user_id"
t.string "authentication_token", null: false
t.index ["user_id"], name: "index_auth_tokens_on_user_id"
end

create_table "breaks", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t|
create_table "breaks", charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
t.datetime "start_date", null: false
t.integer "number_of_weeks", null: false
t.bigint "teaching_period_id"
t.index ["teaching_period_id"], name: "index_breaks_on_teaching_period_id"
end

create_table "campuses", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t|
create_table "campuses", charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
t.string "name", null: false
t.integer "mode", null: false
t.string "abbreviation", null: false
Expand All @@ -44,7 +44,7 @@
t.index ["name"], name: "index_campuses_on_name", unique: true
end

create_table "comments_read_receipts", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t|
create_table "comments_read_receipts", charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
t.bigint "task_comment_id", null: false
t.bigint "user_id", null: false
t.datetime "created_at", null: false
Expand All @@ -54,15 +54,15 @@
t.index ["user_id"], name: "index_comments_read_receipts_on_user_id"
end

create_table "discussion_comments", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t|
create_table "discussion_comments", charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
t.datetime "time_started"
t.datetime "time_completed"
t.integer "number_of_prompts"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end

create_table "group_memberships", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t|
create_table "group_memberships", charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
t.bigint "group_id"
t.bigint "project_id"
t.boolean "active", default: true
Expand All @@ -72,7 +72,7 @@
t.index ["project_id"], name: "index_group_memberships_on_project_id"
end

create_table "group_sets", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t|
create_table "group_sets", charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
t.bigint "unit_id"
t.string "name"
t.boolean "allow_students_to_create_groups", default: true
Expand All @@ -85,7 +85,7 @@
t.index ["unit_id"], name: "index_group_sets_on_unit_id"
end

create_table "group_submissions", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t|
create_table "group_submissions", charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
t.bigint "group_id"
t.string "notes"
t.bigint "submitted_by_project_id"
Expand All @@ -97,7 +97,7 @@
t.index ["task_definition_id"], name: "index_group_submissions_on_task_definition_id"
end

create_table "groups", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t|
create_table "groups", charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
t.bigint "group_set_id"
t.bigint "tutorial_id"
t.string "name"
Expand All @@ -109,7 +109,7 @@
t.index ["tutorial_id"], name: "index_groups_on_tutorial_id"
end

create_table "learning_outcome_task_links", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t|
create_table "learning_outcome_task_links", charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
t.text "description"
t.integer "rating"
t.bigint "task_definition_id"
Expand All @@ -122,7 +122,7 @@
t.index ["task_id"], name: "index_learning_outcome_task_links_on_task_id"
end

create_table "learning_outcomes", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t|
create_table "learning_outcomes", charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
t.bigint "unit_id"
t.integer "ilo_number"
t.string "name"
Expand All @@ -131,15 +131,15 @@
t.index ["unit_id"], name: "index_learning_outcomes_on_unit_id"
end

create_table "logins", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t|
create_table "logins", charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
t.datetime "timestamp"
t.bigint "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["user_id"], name: "index_logins_on_user_id"
end

create_table "overseer_assessments", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t|
create_table "overseer_assessments", charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
t.bigint "task_id", null: false
t.string "submission_timestamp", null: false
t.string "result_task_status"
Expand All @@ -150,7 +150,7 @@
t.index ["task_id"], name: "index_overseer_assessments_on_task_id"
end

create_table "overseer_images", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t|
create_table "overseer_images", charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
t.string "name", null: false
t.string "tag", null: false
t.datetime "created_at", null: false
Expand All @@ -160,7 +160,7 @@
t.datetime "last_pulled_date"
end

create_table "projects", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t|
create_table "projects", charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
t.bigint "unit_id"
t.string "project_role"
t.datetime "created_at", null: false
Expand All @@ -187,14 +187,14 @@
t.index ["user_id"], name: "index_projects_on_user_id"
end

create_table "roles", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t|
create_table "roles", charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
t.string "name"
t.text "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end

create_table "task_comments", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t|
create_table "task_comments", charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
t.bigint "task_id", null: false
t.bigint "user_id", null: false
t.string "comment", limit: 4096
Expand Down Expand Up @@ -225,7 +225,7 @@
t.index ["user_id"], name: "index_task_comments_on_user_id"
end

create_table "task_definitions", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t|
create_table "task_definitions", charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
t.bigint "unit_id"
t.string "name"
t.string "description", limit: 4096
Expand Down Expand Up @@ -256,7 +256,7 @@
t.index ["unit_id"], name: "index_task_definitions_on_unit_id"
end

create_table "task_engagements", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t|
create_table "task_engagements", charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
t.datetime "engagement_time"
t.string "engagement"
t.bigint "task_id"
Expand All @@ -265,7 +265,7 @@
t.index ["task_id"], name: "index_task_engagements_on_task_id"
end

create_table "task_pins", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t|
create_table "task_pins", charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
t.bigint "task_id", null: false
t.bigint "user_id", null: false
t.datetime "created_at", null: false
Expand All @@ -275,7 +275,7 @@
t.index ["user_id"], name: "fk_rails_915df186ed"
end

create_table "task_similarities", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t|
create_table "task_similarities", charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
t.bigint "task_id"
t.bigint "other_task_id"
t.integer "pct"
Expand All @@ -290,14 +290,14 @@
t.index ["tii_submission_id"], name: "index_task_similarities_on_tii_submission_id"
end

create_table "task_statuses", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t|
create_table "task_statuses", charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
t.string "name"
t.string "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end

create_table "task_submissions", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t|
create_table "task_submissions", charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
t.datetime "submission_time"
t.datetime "assessment_time"
t.string "outcome"
Expand All @@ -309,7 +309,7 @@
t.index ["task_id"], name: "index_task_submissions_on_task_id"
end

create_table "tasks", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t|
create_table "tasks", charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
t.bigint "task_definition_id"
t.bigint "project_id"
t.bigint "task_status_id"
Expand All @@ -335,7 +335,7 @@
t.index ["task_status_id"], name: "index_tasks_on_task_status_id"
end

create_table "teaching_periods", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t|
create_table "teaching_periods", charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
t.string "period", null: false
t.datetime "start_date", null: false
t.datetime "end_date", null: false
Expand Down Expand Up @@ -394,7 +394,7 @@
t.index ["tii_task_similarity_id"], name: "index_tii_submissions_on_tii_task_similarity_id"
end

create_table "tutorial_enrolments", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t|
create_table "tutorial_enrolments", charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.bigint "project_id", null: false
Expand All @@ -404,7 +404,7 @@
t.index ["tutorial_id"], name: "index_tutorial_enrolments_on_tutorial_id"
end

create_table "tutorial_streams", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t|
create_table "tutorial_streams", charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
t.string "name", null: false
t.string "abbreviation", null: false
t.datetime "created_at", null: false
Expand All @@ -418,7 +418,7 @@
t.index ["unit_id"], name: "index_tutorial_streams_on_unit_id"
end

create_table "tutorials", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t|
create_table "tutorials", charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
t.bigint "unit_id"
t.string "meeting_day"
t.string "meeting_time"
Expand All @@ -437,20 +437,21 @@
t.index ["unit_role_id"], name: "index_tutorials_on_unit_role_id"
end

create_table "unit_roles", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t|
create_table "unit_roles", charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
t.bigint "user_id"
t.bigint "tutorial_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.bigint "role_id"
t.bigint "unit_id"
t.boolean "observer", default: false
t.index ["role_id"], name: "index_unit_roles_on_role_id"
t.index ["tutorial_id"], name: "index_unit_roles_on_tutorial_id"
t.index ["unit_id"], name: "index_unit_roles_on_unit_id"
t.index ["user_id"], name: "index_unit_roles_on_user_id"
end

create_table "units", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t|
create_table "units", charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
t.string "name"
t.string "description", limit: 4096
t.datetime "start_date"
Expand Down Expand Up @@ -480,7 +481,7 @@
t.index ["teaching_period_id"], name: "index_units_on_teaching_period_id"
end

create_table "users", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t|
create_table "users", charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
Expand Down Expand Up @@ -513,15 +514,15 @@
t.index ["role_id"], name: "index_users_on_role_id"
end

create_table "webcal_unit_exclusions", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t|
create_table "webcal_unit_exclusions", charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
t.bigint "webcal_id", null: false
t.bigint "unit_id", null: false
t.index ["unit_id", "webcal_id"], name: "index_webcal_unit_exclusions_on_unit_id_and_webcal_id", unique: true
t.index ["unit_id"], name: "index_webcal_unit_exclusions_on_unit_id"
t.index ["webcal_id"], name: "fk_rails_d5fab02cb7"
end

create_table "webcals", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t|
create_table "webcals", charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
t.string "guid", limit: 36, null: false
t.boolean "include_start_dates", default: false, null: false
t.bigint "user_id"
Expand Down
61 changes: 61 additions & 0 deletions test/helpers/authorisation_helpers_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
require 'test_helper'

class AuthorisationHelpersTest < ActiveSupport::TestCase
test "observer user cannot perform non-GET actions" do
role = Role.create!(name: 'Tutor')
user = User.new(
email: 'observer@example.com',
encrypted_password: 'password',
first_name: 'Observer',
last_name: 'User',
username: 'observer_user',
role: role
)
user.save(validate: false)

unit = Unit.create!(
name: 'Test Unit',
code: 'TST101',
description: 'Test unit description',
start_date: Date.today,
end_date: Date.today + 90.days
)

unit_role = UnitRole.new(user: user, unit: unit, role: role, observer: true)
unit_role.save(validate: false)

unit.define_singleton_method(:role_for) { |_user| :tutor }

result = AuthorisationHelpers.authorise?(user, unit_role, :post)
assert_equal false, result
end

test "observer user can perform GET actions" do
role = Role.create!(name: 'Tutor')
user = User.new(
email: 'observer@example.com',
encrypted_password: 'password',
first_name: 'Observer',
last_name: 'User',
username: 'observer_user',
role: role
)
user.save(validate: false)

unit = Unit.create!(
name: 'Test Unit',
code: 'TST101',
description: 'Test unit description',
start_date: Date.today,
end_date: Date.today + 90.days
)

unit_role = UnitRole.new(user: user, unit: unit, role: role, observer: true)
unit_role.save(validate: false)

unit.define_singleton_method(:role_for) { |_user| :tutor }

result = AuthorisationHelpers.authorise?(user, unit_role, :get)
assert_equal true, result
end
end
Loading