merge master

This commit is contained in:
Ralf Teusner
2016-07-14 13:22:24 +02:00
parent 59536ab189
commit f5868a4fa2
29 changed files with 78 additions and 351 deletions

View File

@ -19,6 +19,10 @@ $(function() {
var SERVER_SEND_EVENT = 2; var SERVER_SEND_EVENT = 2;
var editors = []; var editors = [];
var editor_for_file = new Map();
var regex_for_language = new Map();
var tracepositions_regex;
var active_file = undefined; var active_file = undefined;
var active_frame = undefined; var active_frame = undefined;
var running = false; var running = false;
@ -404,12 +408,18 @@ $(function() {
editor.setTheme(THEME); editor.setTheme(THEME);
editor.commands.bindKey("ctrl+alt+0", null); editor.commands.bindKey("ctrl+alt+0", null);
editors.push(editor); editors.push(editor);
editor_for_file.set($(element).parent().data('filename'), editor);
var session = editor.getSession(); var session = editor.getSession();
session.setMode($(element).data('mode')); session.setMode($(element).data('mode'));
session.setTabSize($(element).data('indent-size')); session.setTabSize($(element).data('indent-size'));
session.setUseSoftTabs(true); session.setUseSoftTabs(true);
session.setUseWrapMode(true); session.setUseWrapMode(true);
// set regex for parsing error traces based on the mode of the main file.
if( $(element).parent().data('role') == "main_file"){
tracepositions_regex = regex_for_language.get($(element).data('mode'));
}
var file_id = $(element).data('id'); var file_id = $(element).data('id');
/* /*
@ -457,6 +467,12 @@ $(function() {
$('#request-for-comments').on('click', requestComments); $('#request-for-comments').on('click', requestComments);
}; };
var initializeRegexes = function(){
regex_for_language.set("ace/mode/python", /File "(.+?)", line (\d+)/g);
regex_for_language.set("ace/mode/java", /(.*\.java):(\d+):/g);
}
var initializeTooltips = function() { var initializeTooltips = function() {
$('[data-tooltip]').tooltip(); $('[data-tooltip]').tooltip();
}; };
@ -587,7 +603,7 @@ $(function() {
} else if (output.stdout) { } else if (output.stdout) {
//if (output_mode_is_streaming){ //if (output_mode_is_streaming){
element.addClass('text-success').append(output.stdout); element.addClass('text-success').append(output.stdout);
flowrOutputBuffer += output.stdout; // flowrOutputBuffer += output.stdout;
//}else{ //}else{
// element.addClass('text-success'); // element.addClass('text-success');
// element.data('content_buffer' , element.data('content_buffer') + output.stdout); // element.data('content_buffer' , element.data('content_buffer') + output.stdout);
@ -876,7 +892,9 @@ $(function() {
} }
var showWorkspaceTab = function(event) { var showWorkspaceTab = function(event) {
event.preventDefault(); if(event){
event.preventDefault();
}
showTab(0); showTab(0);
}; };
@ -1036,6 +1054,7 @@ $(function() {
case 'exit': case 'exit':
killWebsocketAndContainer(); killWebsocketAndContainer();
handleStderrOutputForFlowr(); handleStderrOutputForFlowr();
augmentStacktraceInOutput();
break; break;
case 'timeout': case 'timeout':
// just show the timeout message here. Another exit command is sent by the rails backend when the socket to the docker container closes. // just show the timeout message here. Another exit command is sent by the rails backend when the socket to the docker container closes.
@ -1047,6 +1066,41 @@ $(function() {
} }
}; };
var jumpToSourceLine = function(event){
var file = $(event.target).data('file');
var line = $(event.target).data('line');
showWorkspaceTab(null);
// set active file ?!?!
var frame = $('div.frame[data-filename="' + file + '"]');
showFrame(frame);
var editor = editor_for_file.get(file);
editor.gotoLine(line, 0);
};
var augmentStacktraceInOutput = function() {
if(tracepositions_regex){
var element = $('#output>pre');
var text = element.text();
element.on( "click", "a", jumpToSourceLine);
var matches;
while(matches = tracepositions_regex.exec(text)){
var frame = $('div.frame[data-filename="' + matches[1] + '"]')
if(frame.length > 0){
element.html(text.replace(matches[0], "<a href='#' data-file='" + matches[1] + "' data-line='" + matches[2] + "'>" + matches[0] + "</a>"));
}
}
}
};
var renderWebsocketOutput = function(msg){ var renderWebsocketOutput = function(msg){
var element = findOrCreateRenderElement(0); var element = findOrCreateRenderElement(0);
element.append(msg.data); element.append(msg.data);
@ -1208,6 +1262,7 @@ $(function() {
if ($('#editor').isPresent()) { if ($('#editor').isPresent()) {
if (isBrowserSupported()) { if (isBrowserSupported()) {
initializeRegexes();
initializeCodePilot(); initializeCodePilot();
$('.score, #development-environment').show(); $('.score, #development-environment').show();
configureEditors(); configureEditors();

View File

@ -9,7 +9,6 @@ class ExercisesController < ApplicationController
before_action :set_exercise, only: MEMBER_ACTIONS + [:clone, :implement, :run, :statistics, :submit, :reload] before_action :set_exercise, only: MEMBER_ACTIONS + [:clone, :implement, :run, :statistics, :submit, :reload]
before_action :set_external_user, only: [:statistics] before_action :set_external_user, only: [:statistics]
before_action :set_file_types, only: [:create, :edit, :new, :update] before_action :set_file_types, only: [:create, :edit, :new, :update]
before_action :set_teams, only: [:create, :edit, :new, :update]
skip_before_filter :verify_authenticity_token, only: [:import_proforma_xml] skip_before_filter :verify_authenticity_token, only: [:import_proforma_xml]
skip_after_action :verify_authorized, only: [:import_proforma_xml] skip_after_action :verify_authorized, only: [:import_proforma_xml]
@ -119,7 +118,7 @@ class ExercisesController < ApplicationController
private :user_by_code_harbor_token private :user_by_code_harbor_token
def exercise_params def exercise_params
params[:exercise].permit(:description, :execution_environment_id, :file_id, :instructions, :public, :hide_file_tree, :allow_file_creation, :team_id, :title, files_attributes: file_attributes).merge(user_id: current_user.id, user_type: current_user.class.name) params[:exercise].permit(:description, :execution_environment_id, :file_id, :instructions, :public, :hide_file_tree, :allow_file_creation, :title, files_attributes: file_attributes).merge(user_id: current_user.id, user_type: current_user.class.name)
end end
private :exercise_params private :exercise_params
@ -195,11 +194,6 @@ class ExercisesController < ApplicationController
end end
private :set_file_types private :set_file_types
def set_teams
@teams = Team.all.order(:name)
end
private :set_teams
def show def show
end end

View File

@ -1,51 +0,0 @@
class TeamsController < ApplicationController
include CommonBehavior
before_action :set_team, only: MEMBER_ACTIONS
def authorize!
authorize(@team || @teams)
end
private :authorize!
def create
@team = Team.new(team_params)
authorize!
create_and_respond(object: @team)
end
def destroy
destroy_and_respond(object: @team)
end
def edit
end
def index
@teams = Team.all.includes(:internal_users).order(:name).paginate(page: params[:page])
authorize!
end
def new
@team = Team.new
authorize!
end
def set_team
@team = Team.find(params[:id])
authorize!
end
private :set_team
def show
end
def team_params
params[:team].permit(:name, internal_user_ids: [])
end
private :team_params
def update
update_and_respond(object: @team, params: team_params)
end
end

View File

@ -11,7 +11,6 @@ class Exercise < ActiveRecord::Base
belongs_to :execution_environment belongs_to :execution_environment
has_many :submissions has_many :submissions
belongs_to :team
has_many :external_users, source: :user, source_type: ExternalUser, through: :submissions has_many :external_users, source: :user, source_type: ExternalUser, through: :submissions
has_many :internal_users, source: :user, source_type: InternalUser, through: :submissions has_many :internal_users, source: :user, source_type: InternalUser, through: :submissions

View File

@ -3,8 +3,6 @@ class InternalUser < ActiveRecord::Base
authenticates_with_sorcery! authenticates_with_sorcery!
has_and_belongs_to_many :teams
validates :email, presence: true, uniqueness: true validates :email, presence: true, uniqueness: true
validates :password, confirmation: true, if: :password_void?, on: :update, presence: true validates :password, confirmation: true, if: :password_void?, on: :update, presence: true
validates :role, inclusion: {in: ROLES} validates :role, inclusion: {in: ROLES}

View File

@ -1,10 +0,0 @@
class Team < ActiveRecord::Base
has_and_belongs_to_many :internal_users
alias_method :members, :internal_users
validates :name, presence: true
def to_s
name
end
end

View File

@ -13,24 +13,19 @@ class ExercisePolicy < AdminOrAuthorPolicy
end end
[:clone?, :destroy?, :edit?, :statistics?, :update?].each do |action| [:clone?, :destroy?, :edit?, :statistics?, :update?].each do |action|
define_method(action) { admin? || author? || team_member? } define_method(action) { admin? || author?}
end end
[:implement?, :submit?, :reload?].each do |action| [:implement?, :submit?, :reload?].each do |action|
define_method(action) { everyone } define_method(action) { everyone }
end end
def team_member?
@record.team.try(:members, []).include?(@user) if @record.team
end
private :team_member?
class Scope < Scope class Scope < Scope
def resolve def resolve
if @user.admin? if @user.admin?
@scope.all @scope.all
elsif @user.internal_user? elsif @user.internal_user?
@scope.where('user_id = ? OR public = TRUE OR (team_id IS NOT NULL AND team_id IN (SELECT t.id FROM teams t JOIN internal_users_teams iut ON t.id = iut.team_id WHERE iut.internal_user_id = ?))', @user.id, @user.id) @scope.where('user_id = ? OR public = TRUE', @user.id)
else else
@scope.none @scope.none
end end

View File

@ -1,14 +0,0 @@
class TeamPolicy < ApplicationPolicy
[:create?, :index?, :new?].each do |action|
define_method(action) { admin? }
end
[:destroy?, :edit?, :show?, :update?].each do |action|
define_method(action) { admin? || member? }
end
def member?
@record.members.include?(@user)
end
private :member?
end

View File

@ -8,7 +8,7 @@
- if current_user.admin? - if current_user.admin?
li = link_to(t('breadcrumbs.dashboard.show'), admin_dashboard_path) li = link_to(t('breadcrumbs.dashboard.show'), admin_dashboard_path)
li.divider li.divider
- models = [ExecutionEnvironment, Exercise, Consumer, CodeHarborLink, ExternalUser, FileType, InternalUser, Submission, Team].sort_by { |model| model.model_name.human(count: 2) } - models = [ExecutionEnvironment, Exercise, Consumer, CodeHarborLink, ExternalUser, FileType, InternalUser, Submission].sort_by { |model| model.model_name.human(count: 2) }
- models.each do |model| - models.each do |model|
- if policy(model).index? - if policy(model).index?
li = link_to(model.model_name.human(count: 2), send(:"#{model.model_name.collection}_path")) li = link_to(model.model_name.human(count: 2), send(:"#{model.model_name.collection}_path"))

View File

@ -17,9 +17,6 @@
= f.label(:instructions) = f.label(:instructions)
= f.hidden_field(:instructions) = f.hidden_field(:instructions)
.form-control.markdown .form-control.markdown
/.form-group
= f.label(:team_id)
= f.collection_select(:team_id, @teams, :id, :name, {include_blank: true}, class: 'form-control')
.checkbox .checkbox
label label
= f.check_box(:public) = f.check_box(:public)

View File

@ -50,9 +50,9 @@ h1 = "#{@exercise} (external user #{@external_user})"
td td
-submission.testruns.each do |run| -submission.testruns.each do |run|
- if run.passed - if run.passed
.unit-test-result.positive-result .unit-test-result.positive-result title=run.output
- else - else
.unit-test-result.negative-result .unit-test-result.negative-result title=run.output
td = Time.at(deltas[1..index].inject(:+)).utc.strftime("%H:%M:%S") if index > 0 td = Time.at(deltas[1..index].inject(:+)).utc.strftime("%H:%M:%S") if index > 0
-working_times_until.push((Time.at(deltas[1..index].inject(:+)).utc.strftime("%H:%M:%S") if index > 0)) -working_times_until.push((Time.at(deltas[1..index].inject(:+)).utc.strftime("%H:%M:%S") if index > 0))
p = t('.addendum') p = t('.addendum')

View File

@ -12,7 +12,6 @@ h1
= row(label: 'exercise.description', value: render_markdown(@exercise.description)) = row(label: 'exercise.description', value: render_markdown(@exercise.description))
= row(label: 'exercise.execution_environment', value: link_to_if(policy(@exercise.execution_environment).show?, @exercise.execution_environment, @exercise.execution_environment)) = row(label: 'exercise.execution_environment', value: link_to_if(policy(@exercise.execution_environment).show?, @exercise.execution_environment, @exercise.execution_environment))
/= row(label: 'exercise.instructions', value: render_markdown(@exercise.instructions)) /= row(label: 'exercise.instructions', value: render_markdown(@exercise.instructions))
= row(label: 'exercise.team', value: @exercise.team ? link_to(@exercise.team, @exercise.team) : nil)
= row(label: 'exercise.maximum_score', value: @exercise.maximum_score) = row(label: 'exercise.maximum_score', value: @exercise.maximum_score)
= row(label: 'exercise.public', value: @exercise.public?) = row(label: 'exercise.public', value: @exercise.public?)
= row(label: 'exercise.hide_file_tree', value: @exercise.hide_file_tree?) = row(label: 'exercise.hide_file_tree', value: @exercise.hide_file_tree?)

View File

@ -1,9 +0,0 @@
= form_for(@team) do |f|
= render('shared/form_errors', object: @team)
.form-group
= f.label(:name)
= f.text_field(:name, class: 'form-control', required: true)
.form-group
= f.label(:internal_user_ids)
= f.collection_select(:internal_user_ids, InternalUser.all.order(:name), :id, :name, {}, {class: 'form-control', multiple: true})
.actions = render('shared/submit_button', f: f, object: @team)

View File

@ -1,3 +0,0 @@
h1 = @hint
= render('form')

View File

@ -1,20 +0,0 @@
h1 = Team.model_name.human(count: 2)
.table-responsive
table.table
thead
tr
th = t('activerecord.attributes.team.name')
th = t('activerecord.attributes.team.internal_user_ids')
th colspan=3 = t('shared.actions')
tbody
- @teams.each do |team|
tr
td = team.name
td = team.members.count
td = link_to(t('shared.show'), team_path(team.id))
td = link_to(t('shared.edit'), edit_team_path(team.id))
td = link_to(t('shared.destroy'), team_path(team.id), data: {confirm: t('shared.confirm_destroy')}, method: :delete)
= render('shared/pagination', collection: @teams)
p = render('shared/new_button', model: Team, path: new_team_path)

View File

@ -1,3 +0,0 @@
h1 = t('shared.new_model', model: Team.model_name.human)
= render('form')

View File

@ -1,9 +0,0 @@
h1
= @team
= render('shared/edit_button', object: @team, path: edit_team_path(@team.id))
= row(label: 'team.name', value: @team.name)
= row(label: 'team.internal_user_ids') do
ul.list-unstyled
- @team.members.order(:name).each do |internal_user|
li = link_to(internal_user, internal_user)

View File

@ -34,8 +34,6 @@ de:
instructions: Anweisungen instructions: Anweisungen
maximum_score: Erreichbare Punktzahl maximum_score: Erreichbare Punktzahl
public: Öffentlich public: Öffentlich
team: Team
team_id: Team
title: Titel title: Titel
user: Autor user: Autor
allow_file_creation: "Dateierstellung erlauben" allow_file_creation: "Dateierstellung erlauben"
@ -91,9 +89,6 @@ de:
files: Dateien files: Dateien
score: Punktzahl score: Punktzahl
user: Autor user: Autor
team:
internal_user_ids: Mitglieder
name: Name
models: models:
code_harbor_link: code_harbor_link:
one: CodeHarbor-Link one: CodeHarbor-Link
@ -128,9 +123,6 @@ de:
submission: submission:
one: Abgabe one: Abgabe
other: Abgaben other: Abgaben
team:
one: Team
other: Teams
errors: errors:
messages: messages:
together: 'muss zusammen mit %{attribute} definiert werden' together: 'muss zusammen mit %{attribute} definiert werden'

View File

@ -34,8 +34,6 @@ en:
instructions: Instructions instructions: Instructions
maximum_score: Maximum Score maximum_score: Maximum Score
public: Public public: Public
team: Team
team_id: Team
title: Title title: Title
user: Author user: Author
allow_file_creation: "Allow file creation" allow_file_creation: "Allow file creation"
@ -91,9 +89,6 @@ en:
files: Files files: Files
score: Score score: Score
user: Author user: Author
team:
internal_user_ids: Members
name: Name
models: models:
code_harbor_link: code_harbor_link:
one: CodeHarbor Link one: CodeHarbor Link
@ -128,9 +123,6 @@ en:
submission: submission:
one: Submission one: Submission
other: Submissions other: Submissions
team:
one: Team
other: Teams
errors: errors:
messages: messages:
together: 'has to be set along with %{attribute}' together: 'has to be set along with %{attribute}'

View File

@ -99,5 +99,4 @@ Rails.application.routes.draw do
end end
end end
resources :teams
end end

View File

@ -0,0 +1,7 @@
class RemoveTeams < ActiveRecord::Migration
def change
remove_reference :exercises, :team
drop_table :teams
drop_table :internal_users_teams
end
end

View File

@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20160630154310) do ActiveRecord::Schema.define(version: 20160704143402) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
@ -87,7 +87,6 @@ ActiveRecord::Schema.define(version: 20160630154310) do
t.boolean "public" t.boolean "public"
t.string "user_type" t.string "user_type"
t.string "token" t.string "token"
t.integer "team_id"
t.boolean "hide_file_tree" t.boolean "hide_file_tree"
t.boolean "allow_file_creation" t.boolean "allow_file_creation"
end end
@ -173,14 +172,6 @@ ActiveRecord::Schema.define(version: 20160630154310) do
add_index "internal_users", ["remember_me_token"], name: "index_internal_users_on_remember_me_token", using: :btree add_index "internal_users", ["remember_me_token"], name: "index_internal_users_on_remember_me_token", using: :btree
add_index "internal_users", ["reset_password_token"], name: "index_internal_users_on_reset_password_token", using: :btree add_index "internal_users", ["reset_password_token"], name: "index_internal_users_on_reset_password_token", using: :btree
create_table "internal_users_teams", force: true do |t|
t.integer "internal_user_id"
t.integer "team_id"
end
add_index "internal_users_teams", ["internal_user_id"], name: "index_internal_users_teams_on_internal_user_id", using: :btree
add_index "internal_users_teams", ["team_id"], name: "index_internal_users_teams_on_team_id", using: :btree
create_table "request_for_comments", force: true do |t| create_table "request_for_comments", force: true do |t|
t.integer "user_id", null: false t.integer "user_id", null: false
t.integer "exercise_id", null: false t.integer "exercise_id", null: false
@ -204,12 +195,6 @@ ActiveRecord::Schema.define(version: 20160630154310) do
t.string "user_type" t.string "user_type"
end end
create_table "teams", force: true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "testruns", force: true do |t| create_table "testruns", force: true do |t|
t.boolean "passed" t.boolean "passed"
t.text "output" t.text "output"

View File

@ -22,6 +22,3 @@ Hint.create_factories
# submissions # submissions
FactoryGirl.create(:submission, exercise: @exercises[:fibonacci]) FactoryGirl.create(:submission, exercise: @exercises[:fibonacci])
# teams
FactoryGirl.create(:team, internal_users: InternalUser.limit(10))

View File

@ -1,93 +0,0 @@
require 'rails_helper'
describe TeamsController do
let(:team) { FactoryGirl.create(:team) }
let(:user) { FactoryGirl.create(:admin) }
before(:each) { allow(controller).to receive(:current_user).and_return(user) }
describe 'POST #create' do
context 'with a valid team' do
let(:request) { proc { post :create, team: FactoryGirl.attributes_for(:team) } }
before(:each) { request.call }
expect_assigns(team: Team)
it 'creates the team' do
expect { request.call }.to change(Team, :count).by(1)
end
expect_redirect(Team.last)
end
context 'with an invalid team' do
before(:each) { post :create, team: {} }
expect_assigns(team: Team)
expect_status(200)
expect_template(:new)
end
end
describe 'DELETE #destroy' do
before(:each) { delete :destroy, id: team.id }
expect_assigns(team: Team)
it 'destroys the team' do
team = FactoryGirl.create(:team)
expect { delete :destroy, id: team.id }.to change(Team, :count).by(-1)
end
expect_redirect(:teams)
end
describe 'GET #edit' do
before(:each) { get :edit, id: team.id }
expect_assigns(team: Team)
expect_status(200)
expect_template(:edit)
end
describe 'GET #index' do
before(:all) { FactoryGirl.create_pair(:team) }
before(:each) { get :index }
expect_assigns(teams: Team.all)
expect_status(200)
expect_template(:index)
end
describe 'GET #new' do
before(:each) { get :new }
expect_assigns(team: Team)
expect_status(200)
expect_template(:new)
end
describe 'GET #show' do
before(:each) { get :show, id: team.id }
expect_assigns(team: :team)
expect_status(200)
expect_template(:show)
end
describe 'PUT #update' do
context 'with a valid team' do
before(:each) { put :update, team: FactoryGirl.attributes_for(:team), id: team.id }
expect_assigns(team: Team)
expect_redirect(:team)
end
context 'with an invalid team' do
before(:each) { put :update, team: {name: ''}, id: team.id }
expect_assigns(team: Team)
expect_status(200)
expect_template(:edit)
end
end
end

View File

@ -1,6 +0,0 @@
FactoryGirl.define do
factory :team do
internal_users { build_pair :teacher }
name 'The A-Team'
end
end

View File

@ -5,7 +5,7 @@ describe 'Authorization' do
let(:user) { FactoryGirl.create(:admin) } let(:user) { FactoryGirl.create(:admin) }
before(:each) { allow_any_instance_of(ApplicationController).to receive(:current_user).and_return(user) } before(:each) { allow_any_instance_of(ApplicationController).to receive(:current_user).and_return(user) }
[Consumer, ExecutionEnvironment, Exercise, FileType, InternalUser, Team].each do |model| [Consumer, ExecutionEnvironment, Exercise, FileType, InternalUser].each do |model|
expect_permitted_path(:"new_#{model.model_name.singular}_path") expect_permitted_path(:"new_#{model.model_name.singular}_path")
end end
end end
@ -14,7 +14,7 @@ describe 'Authorization' do
let(:user) { FactoryGirl.create(:external_user) } let(:user) { FactoryGirl.create(:external_user) }
before(:each) { allow_any_instance_of(ApplicationController).to receive(:current_user).and_return(user) } before(:each) { allow_any_instance_of(ApplicationController).to receive(:current_user).and_return(user) }
[Consumer, ExecutionEnvironment, Exercise, FileType, InternalUser, Team].each do |model| [Consumer, ExecutionEnvironment, Exercise, FileType, InternalUser].each do |model|
expect_forbidden_path(:"new_#{model.model_name.singular}_path") expect_forbidden_path(:"new_#{model.model_name.singular}_path")
end end
end end
@ -27,7 +27,7 @@ describe 'Authorization' do
expect_forbidden_path(:"new_#{model.model_name.singular}_path") expect_forbidden_path(:"new_#{model.model_name.singular}_path")
end end
[ExecutionEnvironment, Exercise, FileType, Team].each do |model| [ExecutionEnvironment, Exercise, FileType].each do |model|
expect_permitted_path(:"new_#{model.model_name.singular}_path") expect_permitted_path(:"new_#{model.model_name.singular}_path")
end end
end end

View File

@ -1,9 +0,0 @@
require 'rails_helper'
describe Team do
let(:team) { described_class.create }
it 'validates the presence of a name' do
expect(team.errors[:name]).to be_present
end
end

View File

@ -3,8 +3,8 @@ require 'rails_helper'
describe ExercisePolicy do describe ExercisePolicy do
subject { described_class } subject { described_class }
let(:exercise) { FactoryGirl.build(:dummy, team: FactoryGirl.create(:team)) } let(:exercise) { FactoryGirl.build(:dummy) }
permissions :batch_update? do permissions :batch_update? do
it 'grants access to admins only' do it 'grants access to admins only' do
expect(subject).to permit(FactoryGirl.build(:admin), exercise) expect(subject).to permit(FactoryGirl.build(:admin), exercise)
@ -40,10 +40,6 @@ describe ExercisePolicy do
expect(subject).to permit(exercise.author, exercise) expect(subject).to permit(exercise.author, exercise)
end end
it 'grants access to team members' do
expect(subject).to permit(exercise.team.members.first, exercise)
end
it 'does not grant access to all other users' do it 'does not grant access to all other users' do
[:external_user, :teacher].each do |factory_name| [:external_user, :teacher].each do |factory_name|
expect(subject).not_to permit(FactoryGirl.build(factory_name), exercise) expect(subject).not_to permit(FactoryGirl.build(factory_name), exercise)
@ -71,9 +67,7 @@ describe ExercisePolicy do
[@admin, @teacher].each do |user| [@admin, @teacher].each do |user|
[true, false].each do |public| [true, false].each do |public|
[@team, nil].each do |team| FactoryGirl.create(:dummy, public: public, user_id: user.id, user_type: InternalUser.class.name)
FactoryGirl.create(:dummy, public: public, team: team, user_id: user.id, user_type: InternalUser.class.name)
end
end end
end end
end end
@ -95,10 +89,6 @@ describe ExercisePolicy do
end end
context 'for teachers' do context 'for teachers' do
before(:each) do
@team = FactoryGirl.create(:team)
@team.members << @teacher
end
let(:scope) { Pundit.policy_scope!(@teacher, Exercise) } let(:scope) { Pundit.policy_scope!(@teacher, Exercise) }
@ -110,12 +100,8 @@ describe ExercisePolicy do
expect(scope.map(&:id)).to include(*Exercise.where(public: false, user_id: @teacher.id).map(&:id)) expect(scope.map(&:id)).to include(*Exercise.where(public: false, user_id: @teacher.id).map(&:id))
end end
it "includes all of team members' non-public exercises" do
expect(scope.map(&:id)).to include(*Exercise.where(public: false, team_id: @teacher.teams.first.id).map(&:id))
end
it "does not include other authors' non-public exercises" do it "does not include other authors' non-public exercises" do
expect(scope.map(&:id)).not_to include(*Exercise.where(public: false).where("team_id <> #{@team.id} AND user_id <> #{@teacher.id}").map(&:id)) expect(scope.map(&:id)).not_to include(*Exercise.where(public: false).where(user_id <> #{@teacher.id}").map(&:id))
end end
end end
end end

View File

@ -1,41 +0,0 @@
require 'rails_helper'
describe TeamPolicy do
subject { described_class }
let(:team) { FactoryGirl.build(:team) }
[:create?, :index?, :new?].each do |action|
permissions(action) do
it 'grants access to admins' do
expect(subject).to permit(FactoryGirl.build(:admin), team)
end
it 'grants access to teachers' do
expect(subject).to permit(FactoryGirl.build(:teacher), team)
end
it 'does not grant access to external users' do
expect(subject).not_to permit(FactoryGirl.build(:external_user), team)
end
end
end
[:destroy?, :edit?, :show?, :update?].each do |action|
permissions(action) do
it 'grants access to admins' do
expect(subject).to permit(FactoryGirl.build(:admin), team)
end
it 'grants access to members' do
expect(subject).to permit(team.members.last, team)
end
it 'does not grant access to all other users' do
[:external_user, :teacher].each do |factory_name|
expect(subject).not_to permit(FactoryGirl.build(factory_name), team)
end
end
end
end
end