first cut as slightly modified registration form
[angular-mojolicious.git] / angular-server.pl
1 #!/usr/bin/env perl
2
3 use lib 'common/mojo/lib';
4
5 use Mojolicious::Lite;
6 use Data::Dump qw(dump);
7 use Time::HiRes;
8 use Clone qw(clone);
9
10 sub new_uuid { Time::HiRes::time * 100000 }
11
12 # based on
13 # http://docs.getangular.com/REST.Basic
14 # http://angular.getangular.com/data
15
16 my $couchdb = 'http://localhost:5984';
17 our $couchdb_rev;
18
19 sub _couchdb_put {
20         my ( $database, $entity, $id, $data ) = @_;
21
22         $data->{'$entity'} = $entity;
23         if ( my $rev = $couchdb_rev->{$database}->{$entity}->{$id} ) {
24                 $data->{_rev} = $rev;
25         }
26
27         my $json = Mojo::JSON->new->encode( $data );
28         my $client = Mojo::Client->new;
29
30         warn "# _couchdb_put $couchdb/$database/$entity.$id = $json";
31         $client->put( "$couchdb/$database/$entity.$id" => $json => sub {
32                 my ($client,$tx) = @_;
33                 if ($tx->error) {
34                         die $tx->error;
35                 }
36                 my $response = $tx->res->json;
37                 warn "## CouchDB response ",dump($response);
38                 $couchdb_rev->{$database}->{$entity}->{$id} = $response->{rev} || die "no rev";
39         })->process;
40 }
41
42 sub _couchdb_get {
43         my ( $url ) = @_;
44         my $client = Mojo::Client->new;
45         my $return = $client->get( "$couchdb/$url" )->res->json;
46         warn "# _couchdb_get $url = ",dump($return);
47         return $return;
48 }
49
50 our $id2nr;
51
52
53 sub _render_jsonp {
54         my ( $self, $json ) = @_;
55 #warn "## _render_json ",dump($json);
56         my $data = $self->render( json => $json, partial => 1 );
57 warn "## _render_json $data";
58         if ( my $callback = $self->param('callback') ) {
59                 $data = "$callback($data)";
60         }
61         $self->render( data => $data, format => 'js' );
62 }
63
64 #get '/' => 'index';
65
66 get '/_replicate' => sub {
67         my $self = shift;
68
69         if ( my $from = $self->param('from') ) {
70                 my $got = $self->client->get( $from )->res->json;
71                 warn "# from $from ",dump($got);
72                 _render_jsonp( $self,  $got );
73
74                 my $database = $got->{name};
75                 my $entities = $got->{entities};
76
77                 if ( $database && $entities ) {
78                         foreach my $entity ( keys %$entities ) {
79                                 my $url = $from;
80                                 $url =~ s{/?$}{/}; # add slash at end
81                                 $url .= $entity;
82                                 my $e = $self->client->get( $url )->res->json;
83                                 warn "# replicated $url ", dump($e);
84                                 _chouchdb_put( $self, $database, $entity, $e->{'$id'}, $e );
85                         }
86                 }
87         }
88 };
89
90 get '/data/' => sub {
91         my $self = shift;
92         _render_jsonp( $self, _couchdb_get('/_all_dbs') );
93 };
94
95 get '/data/:database' => sub {
96         die "FIXME";
97 =for FIXME
98         my $self = shift;
99         my $database = $self->param('database');
100         my $list_databases = { name => $database };
101         foreach my $entity ( keys %{ $data->{ $database }} ) {
102 warn "# entry $entity ", dump( $data->{$database}->{$entity} );
103                 my $count = $#{ $data->{$database}->{$entity} } + 1;
104                 $list_databases->{entities}->{$entity} = $count;
105                 $list_databases->{document_count} += $count;
106         }
107         warn dump($list_databases);
108         _render_jsonp( $self,  $list_databases );
109 =cut
110 };
111
112 get '/data/:database/:entity' => sub {
113         my $self = shift;
114         _render_jsonp( $self, _couchdb_get( '/' . $self->param('database') . '/_all_docs' ) ); # FIXME
115 };
116
117 get '/data/:database/:entity/:id' => sub {
118     my $self = shift;
119
120         my $database = $self->param('database');
121         my $entity   = $self->param('entity');
122         my $id       = $self->param('id');
123
124         _render_jsonp( $self, _couchdb_get( "/$database/$entity.$id" ) );
125 };
126
127 any [ 'post' ] => '/data/:database/:entity' => sub {
128         my $self = shift;
129         my $json = $self->req->json;
130         my $id = $json->{'$id'} # XXX we don't get it back from angular.js
131                 || new_uuid;
132         warn "## $id body ",dump($self->req->body, $json);
133
134         $json->{'$id'} ||= $id; # make sure $id is in there
135
136         _couchdb_put( $self->param('database'), $self->param('entity'), $id, $json );
137
138         _render_jsonp( $self,  $json );
139 };
140
141
142 get '/' => sub { shift->redirect_to('/Cookbook') };
143
144 get '/Cookbook' => 'Cookbook';
145 get '/Cookbook/:example' => sub {
146         my $self = shift;
147         $self->render( "Cookbook/" . $self->param('example'), layout => 'angular' );
148 };
149
150 get '/conference/:page' => sub {
151         my $self = shift;
152         $self->render( "conference/" . $self->param('page'), layout => 'angular' );
153 };
154
155 app->start;
156 __DATA__
157
158 @@ index.html.ep
159 % layout 'funky';
160 Yea baby!
161
162 @@ layouts/funky.html.ep
163 <!doctype html><html>
164     <head><title>Funky!</title></head>
165     <body><%== content %></body>
166 </html>
167
168 @@ layouts/angular.html.ep
169 <!DOCTYPE HTML>
170 <html xmlns:ng="http://angularjs.org">
171   <head>
172    <meta charset="utf-8">
173 % my $ANGULAR_JS = $ENV{ANGULAR_JS} || ( -e 'public/angular/build/angular.js' ? '/angular/build/angular.js' : '/angular/src/angular-bootstrap.js' );
174     <script type="text/javascript"
175          src="<%== $ANGULAR_JS %>" ng:autobind></script>
176   </head>
177   <body><%== content %></body>
178 </html>