root/lang/perl/Catalyst-Controller-Atompub/tags/0.3.3/samples/MyBlog/lib/MyBlog/Controller/MediaCollection.pm @ 6742

Revision 6742, 5.9 kB (checked in by takemaru, 5 years ago)

lang/perl/Catalyst-Controller-Atompub: 0.3.3 released. fix many bugs, see Changes in details

Line 
1package # hide from PAUSE
2    MyBlog::Controller::MediaCollection;
3
4use strict;
5use warnings;
6
7use Atompub::DateTime qw( datetime );
8use Atompub::MediaType qw( media_type );
9use MIME::Base64;
10use HTTP::Status;
11use POSIX qw( strftime );
12use String::CamelCase qw( camelize );
13use Time::HiRes qw( gettimeofday );
14
15use base qw( Catalyst::Controller::Atompub::Collection );
16
17my $ENTRIES_PER_PAGE = 10;
18my $TABLE_NAME       = 'medias';
19
20my $MODEL = join '::', 'DBIC', camelize( $TABLE_NAME );
21
22sub get_feed :Atompub(list) {
23    my ( $self, $c ) = @_;
24
25    ## URI without parameters
26    my $uri = $self->collection_resource->uri;
27
28    my $feed = $self->collection_resource->body;
29
30    my $page = $c->req->param('page') || 1;
31
32    my $attr = {
33        offset   => ( $page - 1 ) * $ENTRIES_PER_PAGE,
34        rows     => $ENTRIES_PER_PAGE,
35        order_by => 'edited desc',
36    };
37
38    my $rs = $c->model( $MODEL )->search( {}, $attr );
39
40    while ( my $resource = $rs->next ) {
41        my $entry = XML::Atom::Entry->new( \$resource->entry_body );
42        $feed->add_entry( $entry );
43    }
44
45    $feed->alternate_link( $c->req->base . 'html' );
46    $feed->first_link( $uri );
47    $feed->previous_link( "$uri?page=" . ($page-1) ) if $page > 1;
48    $feed->next_link( "$uri?page=" . ($page+1) ) if $rs->count >= $ENTRIES_PER_PAGE;
49
50    return $self;
51}
52
53sub create_resource :Atompub(create) {
54    my ( $self, $c ) = @_;
55
56    # URIs were determined by C::C::Atompub
57    my $entry_uri = $self->media_link_entry->uri;
58    my $media_uri = $self->media_resource->uri;
59
60    return $self->error( $c, RC_CONFLICT, "Resource name is used (change Slug): $entry_uri" )
61        if $c->model( $MODEL )->search( { entry_uri => $entry_uri } )->count;
62
63    # Edit $entry and $media if needed ...
64
65    my $vals = {
66        edited     => $self->edited->epoch,
67        entry_uri  => $entry_uri,
68        entry_etag => $self->calculate_new_etag( $c, $entry_uri ),
69        entry_body => $self->media_link_entry->body->as_xml,
70        media_uri  => $media_uri,
71        media_etag => $self->calculate_new_etag( $c, $media_uri ),
72        media_body => MIME::Base64::encode( $self->media_resource->body ),
73        media_type => $self->media_resource->type,
74    };
75
76    $c->model( $MODEL )->create( $vals )
77        || return $self->error( $c, RC_INTERNAL_SERVER_ERROR,
78                                'Cannot create new media resource' );
79
80    return $self;
81}
82
83sub get_resource :Atompub(read) {
84    my ( $self, $c ) = @_;
85
86    my $uri = $c->req->uri;
87
88    my $cond = { '-or' => [ { entry_uri => $uri },
89                            { media_uri => $uri } ] };
90
91    my $rs = $c->model( $MODEL )->search( $cond )->first
92        || return $self->error( $c, RC_NOT_FOUND );
93
94    if ( $rs->entry_uri eq $uri ) {
95        $self->media_link_entry->body( XML::Atom::Entry->new( \$rs->entry_body ) );
96    }
97    else {
98        $self->media_resource->body( MIME::Base64::decode( $rs->media_body ) );
99        $self->media_resource->type( $rs->media_type );
100    }
101
102    return $self;
103}
104
105sub update_resource :Atompub(update) {
106    my ( $self, $c ) = @_;
107
108    my $uri = $c->req->uri;
109
110    my $cond = { '-or' => [ { entry_uri => $uri },
111                            { media_uri => $uri } ] };
112
113    my $rs = $c->model( $MODEL )->search( $cond )->first
114        || return $self->error( $c, RC_NOT_FOUND );
115
116    my $vals = { edited => $self->edited->epoch };
117
118    my ( $media_link_entry, $media_type );
119    if ( $rs->entry_uri eq $uri ) {
120        $media_link_entry = $self->media_link_entry->body;
121        $media_type = $rs->media_type;
122
123        # Don't update the Last-Modified value of the corresponding
124        # Media Resource if you use it
125    }
126    else {
127        $media_link_entry = XML::Atom::Entry->new( \$rs->entry_body )
128            || return $self->error( $c );
129
130        $vals->{media_etag} = $self->calculate_new_etag( $c, $rs->media_uri );
131        $vals->{media_body} = MIME::Base64::encode( $self->media_resource->body );
132        $vals->{media_type} = $media_type = $self->media_resource->type;
133
134        # Do update the Last-Modified value of the Media Resource if you use it
135    }
136
137    # app:edited and atom:content in Media Link Entry MUST be updated
138    $media_link_entry->edited( $self->edited->w3c );
139    my $content = XML::Atom::Content->new;
140       $content->src( $rs->media_uri );
141       $content->type( $media_type );
142    $media_link_entry->content( $content );
143
144    $vals->{entry_body} = $media_link_entry->as_xml;
145    $vals->{entry_etag} = $self->calculate_new_etag( $c, $rs->entry_uri );
146
147    $rs->update( $vals )
148        || return $self->error( $c, RC_INTERNAL_SERVER_ERROR, "Cannot update resource: $uri" );
149
150    return $self;
151}
152
153sub delete_resource :Atompub(delete) {
154    my ( $self, $c ) = @_;
155
156    my $uri = $c->req->uri;
157
158    my $cond = { '-or' => [ { entry_uri => $uri },
159                            { media_uri => $uri } ] };
160
161    my $rs = $c->model( $MODEL )->search( $cond )->first
162        || return $self->error( $c, RC_NOT_FOUND );
163
164    # delete entry and media resources at once
165    $rs->delete
166        || return $self->error( $c, RC_INTERNAL_SERVER_ERROR, "Cannot delete resource: $uri" );
167
168    return $self;
169}
170
171sub make_edit_uri {
172    my ( $self, $c, @args ) = @_;
173
174    my @uris = $self->SUPER::make_edit_uri( $c, @args );
175
176    my $cond = { '-or' => [ { entry_uri => $uris[0] },
177                            { media_uri => $uris[0] } ] };
178
179    # return, if $uris[0] is not used
180    return wantarray ? @uris : $uris[0]
181        unless $c->model( $MODEL )->search( $cond )->count;
182
183    my ( $sec, $usec ) = gettimeofday;
184    my $dt = strftime '%Y%m%d-%H%M%S', localtime( $sec );
185    $usec  = sprintf '%06d', $usec;
186
187    # insert $dt-$usec before extension
188    $_ =~ s{(\.[^./?]+)$}{-$dt-$usec$1} for @uris;
189
190    return @uris;
191}
192
193sub find_version {
194    my ( $self, $c, $uri ) = @_;
195
196    my $cond = { '-or' => [ { entry_uri => $uri },
197                            { media_uri => $uri } ] };
198
199    my $rs = $c->model( $MODEL )->search( $cond )->first || return;
200
201    if ( $rs->entry_uri eq $uri ) {
202        return ( etag => $rs->entry_etag );
203    }
204    else {
205        return ( etag => $rs->media_etag );
206    }
207}
208
209sub calculate_new_etag {
210    my ( $self, $c, $uri ) = @_;
211    my ( $sec, $usec ) = gettimeofday;
212    my $dt = join '-', strftime( '%Y%m%d-%H%M%S', localtime($sec) ), sprintf( '%06d', $usec );
213    join '/', $uri, $dt;
214}
215
2161;
Note: See TracBrowser for help on using the browser.