Skip to content

Move over appengine-angular-hello-world-python #122

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 28, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 <fredsa@google.com>


## 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