Files
codeocean/app/controllers/community_solutions_controller.rb
kiragrammel 319c3ab3b4 Add ProgrammingGroup & ProgrammingGroupMembership
* User can create programming group with other users for exercise
* Submission is shared in a group
* Also adjust specs
2023-08-24 19:32:06 +02:00

106 lines
4.4 KiB
Ruby

# frozen_string_literal: true
class CommunitySolutionsController < ApplicationController
include CommonBehavior
include RedirectBehavior
include SubmissionParameters
before_action :require_user!
before_action :set_community_solution, only: %i[edit update]
before_action :set_community_solution_lock, only: %i[edit]
before_action :set_exercise_and_submission, only: %i[edit update]
# GET /community_solutions
def index
@community_solutions = CommunitySolution.all.paginate(page: params[:page], per_page: per_page_param)
authorize!
end
# GET /community_solutions/1/edit
def edit
authorize!
# Be safe. Only allow access to this page if user has valid lock
redirect_after_submit unless @community_solution_lock.present? && @community_solution_lock.active? && @community_solution_lock.user == current_user && @community_solution_lock.community_solution == @community_solution
# We don't want to perform any of the following steps if we rendered already (e.g. due to a redirect)
return if performed?
last_contribution = CommunitySolutionContribution.where(community_solution: @community_solution, timely_contribution: true, autosave: false, proposed_changes: true).order(created_at: :asc).last
@files = []
if last_contribution.blank?
last_contribution = @community_solution.exercise
new_readme_file = {content: '', file_type: FileType.find_by(file_extension: '.txt'), hidden: false, read_only: false, name: 'ReadMe', role: 'regular_file', context: @community_solution}
# If the first user did not save, the ReadMe file already exists
@files << CodeOcean::File.find_or_create_by!(new_readme_file)
end
all_visible_files = last_contribution.files.select(&:visible)
# Add the ReadMe file first
@files += all_visible_files.select {|f| CodeOcean::File.find_by(id: f.file_id)&.context_type == 'CommunitySolution' }
# Then, add all remaining files and sort them by name with extension
@files += (all_visible_files - @files).sort_by(&:filepath)
# Own Submission as a reference
@own_files = @submission.collect_files.select(&:visible).sort_by(&:filepath)
# Remove the file_id from the second graph. Otherwise, the comparison and file-tree selection does not work as expected
@own_files.map do |file|
file.file_id = nil
file.read_only = true
end
end
# PATCH/PUT /community_solutions/1
def update
authorize!
contribution_params = submission_params
cause = contribution_params.delete(:cause)
contribution_params[:proposed_changes] = cause == 'change-community-solution'
contribution_params[:autosave] = cause == 'autosave-community-solution'
contribution_params.delete(:exercise_id)
contribution_params[:community_solution] = @community_solution
# Acquire lock here! This is expensive but required for synchronization
@community_solution_lock = ActiveRecord::Base.transaction do
ApplicationRecord.connection.exec_query("LOCK #{CommunitySolutionLock.table_name} IN ACCESS EXCLUSIVE MODE")
lock = CommunitySolutionLock.where(user: current_user, community_solution: @community_solution).order(locked_until: :asc).last
if lock.active?
contribution_params[:timely_contribution] = true
# Update lock: Either expand the time (autosave) or return it (change / accept)
new_lock_time = contribution_params[:autosave] ? 5.minutes.from_now : Time.zone.now
lock.update!(locked_until: new_lock_time)
else
contribution_params[:timely_contribution] = false
end
# This is returned
lock
end
contribution_params[:community_solution_lock] = @community_solution_lock
contribution_params[:working_time] = @community_solution_lock.working_time
CommunitySolutionContribution.create(contribution_params)
redirect_after_submit
end
private
def authorize!
authorize(@community_solution || @community_solutions)
end
# Use callbacks to share common setup or constraints between actions.
def set_community_solution
@community_solution = CommunitySolution.find(params[:id])
end
def set_community_solution_lock
@community_solution_lock = CommunitySolutionLock.find(params[:lock_id])
end
def set_exercise_and_submission
@exercise = @community_solution.exercise
@submission = current_contributor.submissions.final.where(exercise: @community_solution.exercise).order(created_at: :desc).first
end
end