Skip to content

Commit

Permalink
Merge pull request #122 from GoogleCloudPlatform/angular
Browse files Browse the repository at this point in the history
Move over appengine-angular-hello-world-python
  • Loading branch information
jerjou committed Sep 28, 2015
2 parents ba52d5b + 013673c commit 3e9cc9f
Show file tree
Hide file tree
Showing 12 changed files with 438 additions and 0 deletions.
43 changes: 43 additions & 0 deletions appengine/angular/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
## App Engine AngularJS "Hello World" Python

A simple [AngularJS](http://angularjs.org/) CRUD application
for [Google App Engine](https://appengine.google.com/).

Author: Fred Sauer <[email protected]>


## Project setup

1. Install the [App Engine Python SDK](https://developers.google.com/appengine/downloads)


## Testing the app locally

To run the app locally:

```
dev_appserver.py .
```


## Deploying

To deploy the application:

1. Use the [Google Cloud Console](https://cloud.google.com/console) to create a project
1. Replace `your-app-id` in `app.yaml` with the project id from the previous step
1. Deploy the application:

```
appcfg.py --oauth2 update .
```


## Contributing changes

See [CONTRIB.md](CONTRIB.md)


# Licensing

See [LICENSE](LICENSE)
21 changes: 21 additions & 0 deletions appengine/angular/app.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
application: your-app-id
version: 1
runtime: python27
threadsafe: true
api_version: 1

handlers:
- url: /favicon\.ico
static_files: favicon.ico
upload: favicon\.ico

- url: /rest/.*
script: main.APP

- url: (.*)/
static_files: app\1/index.html
upload: app

- url: (.*)
static_files: app\1
upload: app
5 changes: 5 additions & 0 deletions appengine/angular/app/css/app.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.status {
color: blue;
padding: 1em;
height: 1em;
}
14 changes: 14 additions & 0 deletions appengine/angular/app/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!doctype html>
<html ng-app="App">
<head>
<link rel="stylesheet" href="/css/app.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0-rc.3/angular.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0-rc.3/angular-route.js"></script>
<script src="/js/app.js"></script>
</head>
<body>
<h1>AngularJS Guest List</h1>
<pre class="status" ng-bind="status"></pre>
<div ng-view></div>
</body>
</html>
123 changes: 123 additions & 0 deletions appengine/angular/app/js/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
'use strict';

var App = angular.module('App', ['ngRoute']);

App.factory('myHttpInterceptor', function($rootScope, $q) {
return {
'requestError': function(config) {
$rootScope.status = 'HTTP REQUEST ERROR ' + config;
return config || $q.when(config);
},
'responseError': function(rejection) {
$rootScope.status = 'HTTP RESPONSE ERROR ' + rejection.status + '\n' +
rejection.data;
return $q.reject(rejection);
},
};
});

App.factory('guestService', function($rootScope, $http, $q, $log) {
$rootScope.status = 'Retrieving data...';
var deferred = $q.defer();
$http.get('rest/query')
.success(function(data, status, headers, config) {
$rootScope.guests = data;
deferred.resolve();
$rootScope.status = '';
});
return deferred.promise;
});

App.config(function($routeProvider) {
$routeProvider.when('/', {
controller : 'MainCtrl',
templateUrl: '/partials/main.html',
resolve : { 'guestService': 'guestService' },
});
$routeProvider.when('/invite', {
controller : 'InsertCtrl',
templateUrl: '/partials/insert.html',
});
$routeProvider.when('/update/:id', {
controller : 'UpdateCtrl',
templateUrl: '/partials/update.html',
resolve : { 'guestService': 'guestService' },
});
$routeProvider.otherwise({
redirectTo : '/'
});
});

App.config(function($httpProvider) {
$httpProvider.interceptors.push('myHttpInterceptor');
});

App.controller('MainCtrl', function($scope, $rootScope, $log, $http, $routeParams, $location, $route) {

$scope.invite = function() {
$location.path('/invite');
};

$scope.update = function(guest) {
$location.path('/update/' + guest.id);
};

$scope.delete = function(guest) {
$rootScope.status = 'Deleting guest ' + guest.id + '...';
$http.post('/rest/delete', {'id': guest.id})
.success(function(data, status, headers, config) {
for (var i=0; i<$rootScope.guests.length; i++) {
if ($rootScope.guests[i].id == guest.id) {
$rootScope.guests.splice(i, 1);
break;
}
}
$rootScope.status = '';
});
};

});

App.controller('InsertCtrl', function($scope, $rootScope, $log, $http, $routeParams, $location, $route) {

$scope.submitInsert = function() {
var guest = {
first : $scope.first,
last : $scope.last,
};
$rootScope.status = 'Creating...';
$http.post('/rest/insert', guest)
.success(function(data, status, headers, config) {
$rootScope.guests.push(data);
$rootScope.status = '';
});
$location.path('/');
}
});

App.controller('UpdateCtrl', function($routeParams, $rootScope, $scope, $log, $http, $location) {

for (var i=0; i<$rootScope.guests.length; i++) {
if ($rootScope.guests[i].id == $routeParams.id) {
$scope.guest = angular.copy($rootScope.guests[i]);
}
}

$scope.submitUpdate = function() {
$rootScope.status = 'Updating...';
$http.post('/rest/update', $scope.guest)
.success(function(data, status, headers, config) {
for (var i=0; i<$rootScope.guests.length; i++) {
if ($rootScope.guests[i].id == $scope.guest.id) {
$rootScope.guests.splice(i,1);
break;
}
}
$rootScope.guests.push(data);
$rootScope.status = '';
});
$location.path('/');
};

});

12 changes: 12 additions & 0 deletions appengine/angular/app/partials/insert.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<h2>Invite another guest</h2>
<form ng-submit="submitInsert()">
<p>
<label>First:</label>
<input type="text" ng-model="first" autofocus="true" />
</p>
<p>
<label>Last:</label>
<input type="text" ng-model="last" />
</p>
<input type="submit" class="btn" />
</form>
7 changes: 7 additions & 0 deletions appengine/angular/app/partials/main.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<h2>Guest list</h2>
<button ng-click="invite()">Invite another guest</button>
<div ng-repeat="guest in guests | orderBy:'last' | orderBy:'first'">
<button ng-click="delete(guest)">delete</button>
<button ng-click="update(guest)">update</button>
{{ $index + 1 }}. <b>{{ guest.first }} {{ guest.last }}</b>
</div>
16 changes: 16 additions & 0 deletions appengine/angular/app/partials/update.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<h2>Update guest information</h2>
<form ng-submit="submitUpdate()">
<p>
<label>Id:</label>
<input type="text" ng-model="guest.id" disabled="true" />
</p>
<p>
<label>First:</label>
<input type="text" ng-model="guest.first" autofocus="true" />
</p>
<p>
<label>Last:</label>
<input type="text" ng-model="guest.last" />
</p>
<input type="submit" class="btn" />
</form>
75 changes: 75 additions & 0 deletions appengine/angular/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Copyright 2013 Google, Inc
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import json

import model

import webapp2


def AsDict(guest):
return {'id': guest.key.id(), 'first': guest.first, 'last': guest.last}


class RestHandler(webapp2.RequestHandler):

def dispatch(self):
# time.sleep(1)
super(RestHandler, self).dispatch()

def SendJson(self, r):
self.response.headers['content-type'] = 'text/plain'
self.response.write(json.dumps(r))


class QueryHandler(RestHandler):

def get(self):
guests = model.AllGuests()
r = [AsDict(guest) for guest in guests]
self.SendJson(r)


class UpdateHandler(RestHandler):

def post(self):
r = json.loads(self.request.body)
guest = model.UpdateGuest(r['id'], r['first'], r['last'])
r = AsDict(guest)
self.SendJson(r)


class InsertHandler(RestHandler):

def post(self):
r = json.loads(self.request.body)
guest = model.InsertGuest(r['first'], r['last'])
r = AsDict(guest)
self.SendJson(r)


class DeleteHandler(RestHandler):

def post(self):
r = json.loads(self.request.body)
model.DeleteGuest(r['id'])


APP = webapp2.WSGIApplication([
('/rest/query', QueryHandler),
('/rest/insert', InsertHandler),
('/rest/delete', DeleteHandler),
('/rest/update', UpdateHandler),
], debug=True)
41 changes: 41 additions & 0 deletions appengine/angular/model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Copyright 2013 Google, Inc
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from google.appengine.ext import ndb


class Guest(ndb.Model):
first = ndb.StringProperty()
last = ndb.StringProperty()


def AllGuests():
return Guest.query()


def UpdateGuest(id, first, last):
guest = Guest(id=id, first=first, last=last)
guest.put()
return guest


def InsertGuest(first, last):
guest = Guest(first=first, last=last)
guest.put()
return guest


def DeleteGuest(id):
key = ndb.Key(Guest, id)
key.delete()
Loading

0 comments on commit 3e9cc9f

Please sign in to comment.