Skip to content
Snippets Groups Projects
Commit 2b527578 authored by Bernardo Chagas's avatar Bernardo Chagas
Browse files

Merge branch 'master' of gitlab.c3sl.ufpr.br:portalmec/portalmec into delete_collections

parents 5fe14ab8 6cd2205a
No related branches found
No related tags found
1 merge request!319Change destroy method, only owner user can destroy collection
class V1::LearningObjects::ChunksController < ApplicationController
before_action :authorize!
before_action :chunk_service
# GET /learning_objects/:learning_object_id/chunk
def show
if @chunk.exist?
post_file
render status: :ok
else
render status: :not_found # chunk doesnt exists and needs to be uploaded
end
# chunk exist?
render status: File.exist?(chunk_file_path) ? 200 : 204
end
# POST /learning_objects/:learning_object_id/chunk
def create
@chunk.save
save_file!
post_file
if last_chunk?
combine_file!
post_file!
end
render status: :ok
render status: 200
rescue
render status: 500
end
private
def chunk_service
@chunk = ChunksService.new(chunks_params)
return render status: :unsupported_media_type if @chunk.nil?
def authorize!
@learning_object = LearningObject.find chunks_params[:id]
authorize(@learning_object, :update?)
end
def post_file
return false unless @chunk.concatenated
# Never trust parameters from the scary internet, only allow the white list through.
def chunks_params
params.permit(:id, :file, :flowChunkNumber, :flowTotalChunks, :flowFilename, :flowIdentifier)
end
def post_file!
publisher = LearningObjectPublisher.new(DspaceService.create_client)
publisher.upload @chunk.learning_object, @chunk.resumable_filename
publisher.upload @learning_object, final_file_path
end
def authorize!
learning_object = LearningObject.find chunks_params[:id]
authorize(learning_object, :update?)
##
# Move the temporary Sinatra upload to the chunk file location
def save_file!
return nil unless chunks_params[:file].try(:tempfile).is_a? Tempfile
# Ensure required paths exist
FileUtils.mkpath(chunk_file_directory)
# Move the temporary file upload to the temporary chunk file path
FileUtils.mv(chunks_params[:file].tempfile, chunk_file_path, force: true)
end
# Never trust parameters from the scary internet, only allow the white list through.
def chunks_params
params.permit(:id, :file, :resumableIdentifier, :resumableFilename, :resumableChunkNumber, :resumableTotalChunks, :resumableChunkSize, :resumableCurrentChunkSize, :resumableTotalSize, :resumableType, :resumableRelativePath)
##
# Build final file
def combine_file!
# Ensure required paths exist
FileUtils.mkpath(final_file_directory)
# Open final file in append mode
File.open(final_file_path, 'a') do |f|
file_chunks.each do |file_chunk_path|
# Write each chunk to the permanent file
f.write File.read(file_chunk_path)
end
end
# Cleanup chunk file directory and all chunk files
FileUtils.rm_rf(chunk_file_directory)
end
def valid_mime_type?
mime_types = @learning_object.object_type.mime_types.map(&:extension)
return true if mime_types.empty?
mime_types.include? chunks_params[:flowFilename].split('.').last
end
##
# Determine if this is the last chunk based in parts count.
def last_chunk?
Dir["#{chunk_file_directory}/#{chunks_params[:flowFilename]}.part*"].count == chunks_params[:flowTotalChunks].to_i
end
##
# ./tmp/flow/abc-123/upload.txt.part1
def chunk_file_path
File.join(chunk_file_directory, "#{chunks_params[:flowFilename]}.part#{chunks_params[:flowChunkNumber]}")
end
##
# ./tmp/flow/abc-123
def chunk_file_directory
File.join('tmp', 'flow', chunks_params[:flowIdentifier])
end
##
# /tmp/flow/upload.txt
def final_file_path
File.join(final_file_directory, chunks_params[:flowFilename])
end
##
# /tmp/flow
def final_file_directory
File.join('tmp', 'flow')
end
##
# Get all file chunks sorted by cardinality of their part number
def file_chunks
Dir["#{chunk_file_directory}/*.part*"].sort_by { |f| f.split('.part')[1].to_i }
end
end
......@@ -19,7 +19,30 @@ class LearningObjectSerializer < ActiveModel::Serializer
object.object_type.try(:name)
end
attributes :id, :name, :description, :author, :thumbnail, :publisher, :object_type, :language, :default_attachment_id, :default_location, :default_mime_type, :score, :state, :review_ratings_average, :license, :likes_count, :shares_count, :created_at, :updated_at
def liked?
object.liked? current_user
end
attributes :id,
:name,
:description,
:author,
:thumbnail,
:publisher,
:object_type,
:language,
:default_attachment_id,
:default_location,
:default_mime_type,
:score,
:state,
:review_ratings_average,
:license,
:liked?,
:likes_count,
:shares_count,
:created_at,
:updated_at
has_many :tags
has_many :subjects
......
class ChunksService
attr_reader :learning_object, :resumable_filename, :concatenated
def initialize(params)
@learning_object = LearningObject.find params[:id]
@concatenated = false
return nil if @learning_object.blank?
@dir = "/tmp/#{params[:resumableIdentifier]}"
@resumable_filename = "#{@dir}/#{params[:resumableFilename]}"
@resumable_file_extension = File.extname(@resumable_filename)[1..-1]
# return nil unless valid_mime_type?
@total_chunks = params[:resumableTotalChunks].to_i
@chunk_number = params[:resumableChunkNumber].to_i
@chunk_size = params[:resumableChunkSize].to_i
@chunk_tmpfile = params[:file].tempfile unless params[:file].nil?
@chunk = resumable_chunk @chunk_number
end
def exist?
File.exist? @chunk
end
def save
# Create chunks directory when not present on system
FileUtils.mkdir(@dir, mode: 0700) unless File.directory?(@dir)
# Move the uploaded chunk to the directory
FileUtils.mv @chunk_tmpfile, @chunk
concatenate_chunks if all_parts_exist?
end
private
def valid_mime_type?
mime_types = @learning_object.object_type.mime_types.map(&:extension)
return true if mime_types.empty?
mime_types.include? @resumable_file_extension
end
def resumable_chunk(part)
"#{@resumable_filename}.part#{part}"
end
def concatenate_chunks
File.open(@resumable_filename, 'a') do |target|
1.upto(@total_chunks) do |i|
chunk = File.open(resumable_chunk(i), 'r').read
chunk.each_line { |line| target << line }
FileUtils.rm resumable_chunk(i), force: true
end
Rails.logger.info "File saved to #{@resumable_filename}"
end
@concatenated = true
end
def all_parts_exist?
@total_chunks.downto(1) do |i|
return false unless File.exist?(resumable_chunk(i))
end
true
end
end
......@@ -34,14 +34,15 @@ class LearningObjectPublisher
end
def update_dspace(object)
item = @dspace.items.find(id: object.id_dspace)
metadata = []
dspace_metadata_mapper(object).each do |key, value|
next if value.blank?
value = [value] if value.is_a? String
value = [value] unless value.is_a? Array
value.each do |v|
item.add_metadata(key, v, object.language.try(:code) || 'pt') unless v.blank?
metadata << { 'key' => key, 'value' => v, 'language' => object.language.try(:code) || 'pt' } unless v.blank?
end
end
@dspace.items.add_metadata(metadata, id: object.id_dspace) unless metadata.empty?
end
private
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment