기본 콘텐츠로 건너뛰기

perl catalyst jquery file upload

perl catalyst 를 사용해 jquery file upload 를 구현.

html - angularjs.tx

<!DOCTYPE HTML>

<html lang="en">
<head>

<meta charset="utf-8">
<title>jQuery File Upload Demo - AngularJS version</title>

<!-- Bootstrap styles -->
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<!-- Generic page styles -->
<link rel="stylesheet" href="/vendor/jQuery-File-Upload-9.8.0/css/style.css">
<!-- blueimp Gallery styles -->
<link rel="stylesheet" href="//blueimp.github.io/Gallery/css/blueimp-gallery.min.css">
<!-- CSS to style the file input field as button and adjust the Bootstrap progress bars -->
<link rel="stylesheet" href="/vendor/jQuery-File-Upload-9.8.0/css/jquery.fileupload.css">
<link rel="stylesheet" href="/vendor/jQuery-File-Upload-9.8.0/css/jquery.fileupload-ui.css">
<!-- CSS adjustments for browsers with JavaScript disabled -->
<noscript><link rel="stylesheet" href="/vendor/jQuery-File-Upload-9.8.0/css/jquery.fileupload-noscript.css"></noscript>
<noscript><link rel="stylesheet" href="/vendor/jQuery-File-Upload-9.8.0/css/jquery.fileupload-ui-noscript.css"></noscript>
<style>
/* Hide Angular JS elements before initializing */
.ng-cloak {
    display: none;
}
</style>
</head>
<body>
<div class="container">
    <!-- The file upload form used as target for the file upload widget -->
    <form id="fileupload" action="/jqueryupload/upload" method="POST" enctype="multipart/form-data" data-ng-app="demo" data-ng-controller="DemoFileUploadController" data-file-upload="options" data-ng-class="{'fileupload-processing': processing() || loadingFiles}">
        <!-- Redirect browsers with JavaScript disabled to the origin page -->
        <noscript><input type="hidden" name="redirect" value="/jqueryupload/upload"></noscript>
        <!-- The fileupload-buttonbar contains buttons to add/delete files and start/cancel the upload -->
        <div class="row fileupload-buttonbar">
            <div class="col-lg-7">
                <!-- The fileinput-button span is used to style the file input field as button -->
                <span class="btn btn-success fileinput-button" ng-class="{disabled: disabled}">
                    <i class="glyphicon glyphicon-plus"></i>
                    <span>Add files...</span>
                    <input type="file" name="files[]" multiple ng-disabled="disabled">
                </span>
                <button type="button" class="btn btn-primary start" data-ng-click="submit()">
                    <i class="glyphicon glyphicon-upload"></i>
                    <span>Start upload</span>
                </button>
                <button type="button" class="btn btn-warning cancel" data-ng-click="cancel()">
                    <i class="glyphicon glyphicon-ban-circle"></i>
                    <span>Cancel upload</span>
                </button>
                <!-- The global file processing state -->
                <span class="fileupload-process"></span>
            </div>
            <!-- The global progress state -->
            <div class="col-lg-5 fade" data-ng-class="{in: active()}">
                <!-- The global progress bar -->
                <div class="progress progress-striped active" data-file-upload-progress="progress()"><div class="progress-bar progress-bar-success" data-ng-style="{width: num + '%'}"></div></div>
                <!-- The extended global progress state -->
                <div class="progress-extended">&nbsp;</div>
            </div>
        </div>
        <!-- The table listing the files available for upload/download -->
        <table class="table table-striped files ng-cloak">
            <tr data-ng-repeat="file in queue" data-ng-class="{'processing': file.$processing()}">
                <td data-ng-switch data-on="!!file.thumbnailUrl">
                    <div class="preview" data-ng-switch-when="true">
                        <a data-ng-href="{{file.url}}" title="{{file.name}}" download="{{file.name}}" data-gallery><img data-ng-src="{{file.thumbnailUrl}}" alt=""></a>
                    </div>
                    <div class="preview" data-ng-switch-default data-file-upload-preview="file"></div>
                </td>
                <td>
                    <p class="name" data-ng-switch data-on="!!file.url">
                        <span data-ng-switch-when="true" data-ng-switch data-on="!!file.thumbnailUrl">
                            <a data-ng-switch-when="true" data-ng-href="{{file.url}}" title="{{file.name}}" download="{{file.name}}" data-gallery>{{file.name}}</a>
                            <a data-ng-switch-default data-ng-href="{{file.url}}" title="{{file.name}}" download="{{file.name}}">{{file.name}}</a>
                        </span>
                        <span data-ng-switch-default>{{file.name}}</span>
                    </p>
                    <strong data-ng-show="file.error" class="error text-danger">{{file.error}}</strong>
                </td>
                <td>
                    <p class="size">{{file.size | formatFileSize}}</p>
                    <div class="progress progress-striped active fade" data-ng-class="{pending: 'in'}[file.$state()]" data-file-upload-progress="file.$progress()"><div class="progress-bar progress-bar-success" data-ng-style="{width: num + '%'}"></div></div>
                </td>
                <td>
                    <button type="button" class="btn btn-primary start" data-ng-click="file.$submit()" data-ng-hide="!file.$submit || options.autoUpload" data-ng-disabled="file.$state() == 'pending' || file.$state() == 'rejected'">
                        <i class="glyphicon glyphicon-upload"></i>
                        <span>Start</span>
                    </button>
                    <button type="button" class="btn btn-warning cancel" data-ng-click="file.$cancel()" data-ng-hide="!file.$cancel">
                        <i class="glyphicon glyphicon-ban-circle"></i>
                        <span>Cancel</span>
                    </button>
                    <button data-ng-controller="FileDestroyController" type="button" class="btn btn-danger destroy" data-ng-click="file.$destroy()" data-ng-hide="!file.$destroy">
                        <i class="glyphicon glyphicon-trash"></i>
                        <span>Delete</span>
                    </button>
                </td>
            </tr>
        </table>
    </form>
    <br>
  
</div>
<!-- The blueimp Gallery widget -->
<div id="blueimp-gallery" class="blueimp-gallery blueimp-gallery-controls" data-filter=":even">
    <div class="slides"></div>
    <h3 class="title"></h3>
    <a class="prev">‹</a>
    <a class="next">›</a>
    <a class="close">×</a>
    <a class="play-pause"></a>
    <ol class="indicator"></ol>
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<!-- The jQuery UI widget factory, can be omitted if jQuery UI is already included -->
<script src="/vendor/jQuery-File-Upload-9.8.0/js/vendor/jquery.ui.widget.js"></script>
<!-- The Load Image plugin is included for the preview images and image resizing functionality -->
<script src="//blueimp.github.io/JavaScript-Load-Image/js/load-image.all.min.js"></script>
<!-- The Canvas to Blob plugin is included for image resizing functionality -->
<script src="//blueimp.github.io/JavaScript-Canvas-to-Blob/js/canvas-to-blob.min.js"></script>
<!-- Bootstrap JS is not required, but included for the responsive demo navigation -->
<script src="//netdna.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
<!-- blueimp Gallery script -->
<script src="//blueimp.github.io/Gallery/js/jquery.blueimp-gallery.min.js"></script>
<!-- The Iframe Transport is required for browsers without support for XHR file uploads -->
<script src="/vendor/jQuery-File-Upload-9.8.0/js/jquery.iframe-transport.js"></script>
<!-- The basic File Upload plugin -->
<script src="/vendor/jQuery-File-Upload-9.8.0/js/jquery.fileupload.js"></script>
<!-- The File Upload processing plugin -->
<script src="/vendor/jQuery-File-Upload-9.8.0/js/jquery.fileupload-process.js"></script>
<!-- The File Upload image preview & resize plugin -->
<script src="/vendor/jQuery-File-Upload-9.8.0/js/jquery.fileupload-image.js"></script>
<!-- The File Upload audio preview plugin -->
<script src="/vendor/jQuery-File-Upload-9.8.0/js/jquery.fileupload-audio.js"></script>
<!-- The File Upload video preview plugin -->
<script src="/vendor/jQuery-File-Upload-9.8.0/js/jquery.fileupload-video.js"></script>
<!-- The File Upload validation plugin -->
<script src="/vendor/jQuery-File-Upload-9.8.0/js/jquery.fileupload-validate.js"></script>
<!-- The File Upload Angular JS module -->
<script src="/vendor/jQuery-File-Upload-9.8.0/js/jquery.fileupload-angular.js"></script>
<!-- The main application script -->
<script src="/vendor/jQuery-File-Upload-9.8.0/js/app.js"></script>
</body>
</html>




controller - Jqueryupload.pm

package Lars::Web::Controller::Jqueryupload;
use Moose;
use namespace::autoclean;
use utf8;
use JSON::XS;

BEGIN { extends 'Catalyst::Controller' }

sub index :Path :Args(0) {
    my ($self, $c) = @_;

    $c->stash->{template} = 'jqueryupload.tx';

sub jqueryui :Path("angularjs") :Args(0) {
    my ($self, $c) = @_;

    $c->stash->{template} = 'angularjs.tx';
}

# 업로드 구현
sub upload :Path("upload") :Args(0) :POST{
    my ($self, $c) = @_;

    my $file_upload = $c->req->upload('files[]');

    my $files;
    if ($file_upload) {
        $files = Lars::Util::Forum::image_path($file_upload->filename);
        $c->model('FsStore')->put_from_file($files, $file_upload->fh);
    }

    my $file = $c->model('DB::Attachment')->create(
        {
            create_date => \'now()',
            name => $file_upload->filename,
            path => $files,
        },
    );

    my $new_list = [
        { 
            url=>$files,
            thumbnail_url=>$files,
            name=>$file_upload->filename,
            size=>$file_upload->size,
            delete_url=>'http://url.to/delete /file/',
            delete_type=> 'DELETE'
        }
    ];

  
    $c->stash->{files} = $new_list;
    
    $c->forward('JSON');
    return;

}

util - Forum.pm 
package Lars::Util::Forum;
use strict;
use warnings;
use Data::Random qw/rand_chars/;

use Exporter 'import';
our @EXPORT_OK = qw/image_path/;

sub image_path {
    my $filename = shift;

    my $dt = DateTime->now;

    if ($filename =~ /\.(jpe?g|gif|png)$/i) {
        my $ext = lc $1;
        my $root = join '', '/image/', $dt->year, '/', $dt->month, '/', $dt->day;
        # my $name = Encode::encode('utf8', $filename);
        my $name = join '', time, rand_chars(size => 8, set => 'alphanumeric');
        # return $root.'/'.$name;
        return $root.'/'.$name . '.' . $ext;
    }
    return undef;
}

JSON Response 때문에 고생을 좀 했음. -_-... 굉장히 쓸데없는 고생었음.



{ 
  files:
    [
      {
        url: "http://url.to/file/or/page",
        thumbnail_url: "http://url.to/thumnail.jpg ",
        name: "thumb2.jpg",
        type: "image/jpeg",
        size: 46353,
        delete_url: "http://url.to/delete /file/",
        delete_type: "DELETE"
      }
    ]
}
이런 모양으로 받으면 됨.
빨간줄친모양으로 리턴 받으면 잘 됨. 

댓글

이 블로그의 인기 게시물

사원으로 가면 암걸리는 회사.

(1) 어떠한 일이 벌어지던 지휘 명령 체계를 반드시 지키도록 강요한다. 의사 결정을 앞당기기 위한 샛길을 허락하지 않는다. (2) 간단하게 해결할 수 있는 안건도 위원회에서 검토하게 하며, 위원회는 가능한 크게 만든다. 최소 5명 이상. (3) 될 수 있는 한 자주 회의를 열도록 유도한다. (4) 이전 회의에서 정해진 것을 되풀이해서 검토하도록 유도한다. (5) 중요한 업무가 있어도 회의를 열게 한다. (6) 문서의 형식, 제출 일자, 오탈자를 집요하게 추궁한다. (7) 될 수 있는 한 문서의 양을 늘린다. (8) 업무 승인 수속을 될 수 있는 한 복잡하게 한다. 제 아무리 간단한 일에도 3명 이상의 승인을 필수가 되도록 유도한다. (9) 조직내 권한 문제를 집요하게 추궁한다. 상층부의 허락을 받지 않고 독단으로 해결해도 되는 지 끊임없이 지적한다. (10) 업무할당을 할 경우, 항상 중요도가 낮은 업무에 집중하도록 유도한다. (11) 새로운 직원에게 경험을 쌓을 시간과 자원을 주지 않는다.

buddy

https://buddy.works/ 깃 서비스가 엄청나게 많아 지고 있는것 같다. 최근에 gogs 도 그렇고 예전에 쓰던 github clone 들... 찾아보면 많을 것 같다. 이번에 페이스북에 광고로 올라온 buddy도 그렇다. 1프로젝트당 1$ 라는데... 기회가 되면 써 봐야지 -.-

linux tar.gz comp

ftp로 파일을 전송하는데 잡다한 파일들이 너무 많아서 (약 2만개) 전송에 시간이 너무 오래 걸리더라. 처음에는 scp로 복사 하려고 했는데 잘 안되서 했더니 엉망...; 그냥 압축해서 한번에 전송해서 수십분을 아껼 수 있었다. 유형 tar => 파일을 하나로 모은다. gzip => 압축한다. tar.gz => 하나로 모아서 압축한다. 압축/해제 tar로 압축 => tar -cvf temp.tar temp tar 압축풀기 => tar -xvf temp.tar tar.gz 압축하기 => tar -zcvf temp.tar.gz temp tar.gz 압축풀기 => tar -zxvf temp.tar.gz 리눅스 시스템 내에 대량의 파일을 복사할 때도 사용하면 편하다...