From 7983c0797a53b6d21a104dad620f48ec71206cb2 Mon Sep 17 00:00:00 2001 From: Sebastian Serth Date: Fri, 14 Dec 2018 14:52:04 +0100 Subject: [PATCH] Add view for StudyGroups --- app/controllers/study_groups_controller.rb | 48 +++++++++++++++++++++ app/models/consumer.rb | 3 +- app/policies/study_group_policy.rb | 21 +++++++++ app/views/application/_navigation.html.slim | 1 + app/views/internal_users/index.html.slim | 2 +- app/views/proxy_exercises/show.html.slim | 7 --- app/views/study_groups/_form.html.slim | 19 ++++++++ app/views/study_groups/edit.html.slim | 3 ++ app/views/study_groups/index.html.slim | 32 ++++++++++++++ app/views/study_groups/show.html.slim | 21 +++++++++ config/locales/de.yml | 9 ++++ config/locales/en.yml | 9 ++++ config/routes.rb | 2 + 13 files changed, 168 insertions(+), 9 deletions(-) create mode 100644 app/controllers/study_groups_controller.rb create mode 100644 app/policies/study_group_policy.rb create mode 100644 app/views/study_groups/_form.html.slim create mode 100644 app/views/study_groups/edit.html.slim create mode 100644 app/views/study_groups/index.html.slim create mode 100644 app/views/study_groups/show.html.slim diff --git a/app/controllers/study_groups_controller.rb b/app/controllers/study_groups_controller.rb new file mode 100644 index 00000000..9e92949e --- /dev/null +++ b/app/controllers/study_groups_controller.rb @@ -0,0 +1,48 @@ +class StudyGroupsController < ApplicationController + include CommonBehavior + + before_action :set_group, only: MEMBER_ACTIONS + + def index + @search = StudyGroup.search(params[:q]) + @study_groups = @search.result.includes(:consumer).order(:name).paginate(page: params[:page]) + authorize! + end + + def show + @search = @study_group.users.search(params[:q]) + end + + def edit + @search = @study_group.users.search(params[:q]) + @members = StudyGroupMembership.where(user: @search.result) + end + + def update + myparams = study_group_params + myparams[:users] = StudyGroupMembership.find(myparams[:study_group_membership_ids].reject(&:empty?)).map(&:user) + myparams.delete(:study_group_membership_ids) + update_and_respond(object: @study_group, params: myparams) + end + + def destroy + destroy_and_respond(object: @study_group) + end + + def study_group_params + params[:study_group].permit(:id, :name, :study_group_membership_ids => []) if params[:study_group].present? + end + private :study_group_params + + def set_group + @study_group = StudyGroup.find(params[:id]) + authorize! + end + private :set_group + + def authorize! + authorize(@study_groups || @study_group) + end + private :authorize! + +end diff --git a/app/models/consumer.rb b/app/models/consumer.rb index 2dfb7c2a..0cefe9ec 100644 --- a/app/models/consumer.rb +++ b/app/models/consumer.rb @@ -1,7 +1,8 @@ class Consumer < ApplicationRecord has_many :users - scope :with_users, -> { where('id IN (SELECT consumer_id FROM internal_users)') } + scope :with_internal_users, -> { where('id IN (SELECT DISTINCT consumer_id FROM internal_users)') } + scope :with_study_groups, -> { where('id IN (SELECT DISTINCT consumer_id FROM study_groups)') } validates :name, presence: true validates :oauth_key, presence: true, uniqueness: true diff --git a/app/policies/study_group_policy.rb b/app/policies/study_group_policy.rb new file mode 100644 index 00000000..afdf8bc5 --- /dev/null +++ b/app/policies/study_group_policy.rb @@ -0,0 +1,21 @@ +class StudyGroupPolicy < AdminOnlyPolicy + def index? + admin? || teacher? + end + + [:show?, :destroy?, :edit?, :update?].each do |action| + define_method(action) { admin? || @user.teacher? && @record.users.include?(@user) } + end + + class Scope < Scope + def resolve + if @user.admin? + @scope.all + elsif @user.teacher? + @scope.joins(:study_group_memberships).where('user_id = ? AND user_type = ?', @user.id, @user.class.name) + else + @scope.none + end + end + end +end diff --git a/app/views/application/_navigation.html.slim b/app/views/application/_navigation.html.slim index 006de33b..968815d8 100644 --- a/app/views/application/_navigation.html.slim +++ b/app/views/application/_navigation.html.slim @@ -13,6 +13,7 @@ models: [Exercise, ExerciseCollection, ProxyExercise, Tag, Submission], link: exercises_path, cached: true) = render('navigation_submenu', title: t('navigation.sections.users'), models: [InternalUser, ExternalUser], cached: true) + = render('navigation_collection_link', model: StudyGroup, cached: true) = render('navigation_collection_link', model: ExecutionEnvironment, cached: true) = render('navigation_submenu', title: t('navigation.sections.errors'), models: [ErrorTemplate, ErrorTemplateAttribute], cached: true) diff --git a/app/views/internal_users/index.html.slim b/app/views/internal_users/index.html.slim index 29f07649..ca05b1fa 100644 --- a/app/views/internal_users/index.html.slim +++ b/app/views/internal_users/index.html.slim @@ -3,7 +3,7 @@ h1 = InternalUser.model_name.human(count: 2) = render(layout: 'shared/form_filters') do |f| .form-group = f.label(:consumer_id_eq, t('activerecord.attributes.internal_user.consumer'), class: 'sr-only') - = f.collection_select(:consumer_id_eq, Consumer.with_users, :id, :name, class: 'form-control', prompt: t('activerecord.attributes.internal_user.consumer')) + = f.collection_select(:consumer_id_eq, Consumer.with_internal_users, :id, :name, class: 'form-control', prompt: t('activerecord.attributes.internal_user.consumer')) .form-group = f.label(:email_cont, t('activerecord.attributes.internal_user.email'), class: 'sr-only') = f.search_field(:email_cont, class: 'form-control', placeholder: t('activerecord.attributes.internal_user.email')) diff --git a/app/views/proxy_exercises/show.html.slim b/app/views/proxy_exercises/show.html.slim index 4868443c..69603f4b 100644 --- a/app/views/proxy_exercises/show.html.slim +++ b/app/views/proxy_exercises/show.html.slim @@ -1,10 +1,3 @@ -- content_for :head do - // Force a full page reload, see https://github.com/turbolinks/turbolinks/issues/326. - Otherwise, code might not be highlighted correctly (race condition) - meta name='turbolinks-visit-control' content='reload' - = javascript_pack_tag('highlight', 'data-turbolinks-track': true) - = stylesheet_pack_tag('highlight', media: 'all', 'data-turbolinks-track': true) - h1 = @proxy_exercise.title - if policy(@proxy_exercise).edit? diff --git a/app/views/study_groups/_form.html.slim b/app/views/study_groups/_form.html.slim new file mode 100644 index 00000000..1872cdc5 --- /dev/null +++ b/app/views/study_groups/_form.html.slim @@ -0,0 +1,19 @@ += form_for(@study_group) do |f| + = render('shared/form_errors', object: @study_group) + .form-group + = f.label(:name) + = f.text_field(:name, class: 'form-control', required: true) + + h3 = t('activerecord.attributes.study_group.members') + .table-responsive + table.table + thead + tr + th = t('activerecord.attributes.exercise.selection') + th = sort_link(@search, :name, t('navigation.sections.users')) + = collection_check_boxes :study_group, :study_group_membership_ids, @members, :id, :id do |b| + tr + td = b.check_box + td = link_to_if(policy(b.object.user).show?, b.object.user.displayname, b.object.user) + + .actions = render('shared/submit_button', f: f, object: @study_group) diff --git a/app/views/study_groups/edit.html.slim b/app/views/study_groups/edit.html.slim new file mode 100644 index 00000000..3858b941 --- /dev/null +++ b/app/views/study_groups/edit.html.slim @@ -0,0 +1,3 @@ +h1 = @study_group + += render('form') diff --git a/app/views/study_groups/index.html.slim b/app/views/study_groups/index.html.slim new file mode 100644 index 00000000..be9405e3 --- /dev/null +++ b/app/views/study_groups/index.html.slim @@ -0,0 +1,32 @@ +h1 = StudyGroup.model_name.human(count: 2) + += render(layout: 'shared/form_filters') do |f| + .form-group + = f.label(:consumer_id_eq, t('activerecord.attributes.internal_user.consumer'), class: 'sr-only') + = f.collection_select(:consumer_id_eq, Consumer.with_study_groups, :id, :name, class: 'form-control', prompt: t('activerecord.attributes.internal_user.consumer')) + .form-group + = f.label(:name_cont, t('activerecord.attributes.study_group.name'), class: 'sr-only') + = f.search_field(:name_cont, class: 'form-control', placeholder: t('activerecord.attributes.study_group.name')) + +.table-responsive + table.table.mt-4 + thead + tr + th = t('activerecord.attributes.study_group.name') + th = t('activerecord.attributes.study_group.external_id') + th = t('activerecord.attributes.study_group.consumer') + th = t('activerecord.attributes.study_group.member_count') + th colspan=3 = t('shared.actions') + tbody + - @study_groups.each do |group| + tr + td = link_to_if(policy(group).show?, group.to_s, group) + td + code = group.external_id + td = link_to_if(policy(group.consumer).show?, group.consumer, group.consumer) + td = group.users.count + td = link_to(t('shared.show'), group) if policy(group).show? + td = link_to(t('shared.edit'), edit_study_group_path(group)) if policy(group).edit? + td = link_to(t('shared.destroy'), group, data: {confirm: t('shared.confirm_destroy')}, method: :delete) if policy(group).destroy? + += render('shared/pagination', collection: @study_groups) diff --git a/app/views/study_groups/show.html.slim b/app/views/study_groups/show.html.slim new file mode 100644 index 00000000..613ab6f3 --- /dev/null +++ b/app/views/study_groups/show.html.slim @@ -0,0 +1,21 @@ +h1 + = @study_group + - if policy(@study_group).edit? + = render('shared/edit_button', object: @study_group) + += row(label: 'study_group.name', value: @study_group.name) += row(label: 'study_group.external_id') do + code = @study_group.external_id += row(label: 'study_group.consumer', value: link_to_if(policy(@study_group).show?, @study_group.consumer, @study_group.consumer)) += row(label: 'study_group.member_count', value: @study_group.users.count) + + +h2.mt-4 = t('activerecord.attributes.study_group.members') +.table-responsive + table.table + thead + tr + th = sort_link(@search, :name, t('navigation.sections.users')) + - @study_group.users.each do |user| + tr + td = link_to_if(policy(user).show?, user.displayname, user) diff --git a/config/locales/de.yml b/config/locales/de.yml index f385a3d3..37d5a5c3 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -100,6 +100,12 @@ de: files: Dateien score: Punktzahl user: Autor + study_group: + name: Name + external_id: Externe ID + consumer: Konsument + members: Mitglieder + member_count: Anzahl der Mitglieder tag: name: Name usage: Verwendet @@ -180,6 +186,9 @@ de: submission: one: Abgabe other: Abgaben + study_group: + one: Lerngruppe + other: Lerngruppen tag: one: Tag other: Tags diff --git a/config/locales/en.yml b/config/locales/en.yml index 0bcfd014..6c8bb7e1 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -100,6 +100,12 @@ en: files: Files score: Score user: Author + study_group: + name: Name + external_id: External ID + consumer: Consumer + members: Members + member_count: Members Count tag: name: Name usage: Used @@ -180,6 +186,9 @@ en: submission: one: Submission other: Submissions + study_group: + one: Study Group + other: Study Groups tag: one: Tag other: Tags diff --git a/config/routes.rb b/config/routes.rb index dd3e16c5..40a9df2b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -165,6 +165,8 @@ Rails.application.routes.draw do end end + resources :study_groups, only: [:index, :show, :edit, :destroy, :update] + resources :events, only: [:create] post "/evaluate", to: 'remote_evaluation#evaluate', via: [:post]