Bivio::Biz::Model::FileChangeForm
# Copyright (c) 2008-2010 bivio Software, Inc. All Rights Reserved. # $Id$ package Bivio::Biz::Model::FileChangeForm; use strict; use Bivio::Base 'Biz.FormModel'; my($_FCM) = b_use('Type.FileChangeMode'); my($_FN) = b_use('Type.FileName'); my($_FP) = b_use('Type.FilePath'); my($_TA) = b_use('Type.TextArea'); my($_LOCK) = b_use('Model.RealmFileLock')->if_enabled; b_use('IO.Config')->register(my $_CFG = { show_comment => 0, }); sub QUERY_KEY { return 'mode'; } sub execute_cancel { my($self) = @_; _release_lock($self); return shift->SUPER::execute_cancel(@_); } sub execute_empty { my($self) = @_; $self->internal_put_field(mode => _default_mode($self)); $self->internal_put_field(folder_id => $self->get('realm_file')->get('folder_id')); $self->internal_put_field(rename_name => $_FP->get_tail( $self->get('realm_file')->get('path'))); return if $self->is_folder; $self->internal_put_field(content => ${$self->get('realm_file')->get_content}) if $self->is_text_content_type; return unless $_LOCK; return if $self->get('realm_file_lock'); $self->internal_put_field(realm_file_lock => $self->new_other('RealmFileLock')->create({ realm_file_id => $self->get('realm_file')->get('realm_file_id'), })); $self->internal_put_field('RealmFileLock.realm_file_lock_id' => $self->get('realm_file_lock')->get('realm_file_lock_id')); return; } sub execute_ok { my($self) = @_; if ($self->get('mode')->eq_rename) { _release_lock($self); my(@parts) = split('/', $self->get('realm_file')->get('path')); my($old_name) = pop(@parts); my($name) = _rename_file_name($self, $old_name); $self->get('realm_file')->update({ path => $_FP->join(@parts, $name), }) unless $old_name eq $name; } elsif ($self->get('mode')->eq_move) { _release_lock($self); return if $self->get('folder_id') eq $self->get('realm_file')->get('folder_id'); my($new_path) = $self->new_other('RealmFile')->load({ realm_file_id => $self->get('folder_id'), })->get('path'); _validate_move_folder($self, $new_path) if $self->is_folder; return if $self->in_error; $self->get('realm_file')->update({ path => $_FP->join($new_path, $_FP->get_tail($self->get('realm_file')->get('path'))), }); } elsif ($self->is_folder) { if ($self->get('mode')->equals_by_name(qw(UPLOAD TEXT_FILE))) { my($name, $content) = $self->get('mode')->eq_upload ? ($self->validate_file_name($self, 'file'), $self->get('file')->{content}) : ($self->get(qw(name content))); return if $self->in_error; my($realm_file_id) = $self->new_other('RealmFile') ->create_with_content({ path => $_FP->join($self->get('realm_file')->get('path'), $name), }, $content)->get('realm_file_id'); $self->new_other('RealmFileLock')->create({ realm_file_id => $realm_file_id, comment => $self->get('comment'), }) if $_LOCK && defined($self->get('comment')); } elsif ($self->get('mode')->eq_add_subfolder) { $self->new_other('RealmFile')->create_folder({ path => $_FP->join($self->get('realm_file')->get('path'), $self->get('name')), }); } elsif ($self->get('mode')->eq_delete) { $self->get('realm_file')->unauth_delete_deep; } else { die(); } } # file elsif ($self->get('mode')->equals_by_name(qw(UPLOAD TEXT_FILE))) { _release_lock($self); my($realm_file_id) = $self->get('realm_file') ->update_with_content({}, _content($self)) ->get('realm_file_id'); $self->new_other('RealmFileLock')->create({ realm_file_id => $realm_file_id, comment => $self->get('comment'), }) if $_LOCK && defined($self->get('comment')); } elsif ($self->get('mode')->eq_delete) { _release_lock($self); $self->get('realm_file')->delete; } else { die(); } if ($self->req('task')->get_attr_as_id('next')->eq_forum_file_upload_from_wysiwyg) { return { task_id => $self->req('task')->get_attr_as_id('next'), path_info => $self->req('path_info'), query => $self->req('query'), } } return; } sub get_fields_for_mode { my($self, $mode) = @_; my(@fields) = $mode->eq_upload ? qw(file comment) : $mode->eq_text_file ? ($self->is_folder ? 'name' : (), qw(content comment)) : $mode->eq_add_subfolder ? 'name' : $mode->eq_rename ? 'rename_name' : $mode->eq_move ? 'folder_id' # delete mode : 'comment'; return $_CFG->{show_comment} ? @fields : grep($_ ne 'comment', @fields); } sub handle_config { my(undef, $cfg) = @_; $_CFG = $cfg; $_CFG->{show_comment} = 0 unless $_LOCK; return; } sub internal_initialize { my($self) = @_; return $self->merge_initialize_info($self->SUPER::internal_initialize, { version => 1, require_context => 1, visible => [ map(+{ name => $_->[0], type => $_->[1], constraint => 'NONE', }, ( [qw(name NonHiddenFileName)], [qw(rename_name NonHiddenFileName)], [qw(folder_id RealmFile.realm_file_id)], [qw(file FileField)], [qw(comment RealmFileLock.comment)], [qw(content Text64K)], [qw(override_mode FileChangeMode)], )), ], hidden => [ { name => 'mode', type => 'FileChangeMode', constraint => 'NOT_NULL', }, !$_LOCK ? () : { name => 'RealmFileLock.realm_file_lock_id', constraint => 'NONE', }, ], other => [ # this field gets the EXISTS error, also used for forbidden error 'RealmFile.path_lc', { name => 'realm_file', type => 'Model.RealmFile', constraint => 'NOT_NULL', }, !$_LOCK ? () : { name => 'realm_file_lock', type => 'Model.RealmFileLock', constraint => 'NONE', }, ], }); } sub internal_pre_execute { my($self) = @_; my(@res) = shift->SUPER::internal_pre_execute(@_); $self->internal_put_field( realm_file => $self->new_other('RealmFile')->load({ path => $self->req('path_info') || '/', }), # allow form post to specify the mode $self->unsafe_get('override_mode') ? (mode => $self->get('override_mode')) : (), ); return unless $_LOCK; my($lock) = $self->new_other('RealmFileLock'); $self->internal_put_field( realm_file_lock => $lock->unsafe_load({ realm_file_id => $self->get('realm_file')->get('realm_file_id'), comment => undef, }) ? $lock : undef, ); if ($self->get('RealmFileLock.realm_file_lock_id')) { $self->internal_put_error('RealmFile.path_lc' => 'STALE_FILE_LOCK') unless $self->get('RealmFileLock.realm_file_lock_id') eq ($self->get('realm_file_lock') ? $self->get('realm_file_lock')->get('realm_file_lock_id') : ''); } $self->internal_put_field('RealmFileLock.realm_file_lock_id' => $self->get('realm_file_lock')->get('realm_file_lock_id')) if $self->get('realm_file_lock'); return { method => 'server_redirect', task_id => 'FORUM_FILE_OVERRIDE_LOCK', } if $self->get('realm_file_lock') && ! $self->is_lock_owner; return @res; } sub is_folder { my($self) = @_; return $self->get('realm_file')->get('is_folder'); } sub is_lock_owner { my($self) = @_; return 0 unless $_LOCK && $self->get('realm_file_lock'); return $self->get('realm_file_lock')->get('user_id') eq $self->req('auth_user_id') ? 1 : 0; } sub is_root { my($self) = @_; return $self->get('realm_file')->get('path') eq '/'; } sub is_text_content_type { my($self) = @_; my($rf) = $self->get('realm_file'); return !$rf->get('is_folder') && $rf->is_text_content_type && $rf->is_text_file && $rf->get_content_length < $_TA->get_width; } sub validate { my($self) = @_; foreach my $name ($self->get_fields_for_mode($self->get('mode'))) { $self->validate_not_null($name) unless $name eq 'comment'; } return; } sub validate_file_name { my($proto, $form, $file_field) = @_; my($name, $err) = $_FN->from_literal( $_FP->get_tail($form->get($file_field)->{filename})); if ($err) { $form->internal_put_error(file => $err); return; } $form->internal_put_error(file => 'FILE_NAME') unless defined($name); return $name; } sub _content { my($self) = @_; return $self->get('mode')->eq_upload ? $self->get('file')->{content} : $self->get('content'); } sub _default_mode { my($self) = @_; my($mode) = $_FCM->unsafe_from_any( ($self->req('query') || {})->{$self->QUERY_KEY}); return $mode if $mode; return $self->is_text_content_type ? $_FCM->TEXT_FILE : $_FCM->UPLOAD; } sub _release_lock { return unless $_LOCK; my($self) = @_; $self->get('realm_file_lock')->delete if $self->get('realm_file_lock'); return; } sub _rename_file_name { my($self, $old_name) = @_; my($suffix) = $_FP->get_suffix($old_name); return $self->get('rename_name') if $self->is_folder || ! $suffix; return lc($suffix) eq lc($_FP->get_suffix($self->get('rename_name'))) ? $self->get('rename_name') : join('.', $self->get('rename_name'), $_FP->get_suffix($old_name)); } sub _validate_move_folder { my($self, $new_path) = @_; my($path) = $self->get('realm_file')->get('path'); $self->internal_put_error(folder_id => 'INVALID_FOLDER') if $new_path =~ /^\Q$path/; return; } 1;