Skip to content

Instantly share code, notes, and snippets.

@auser
Last active January 26, 2021 01:59
Show Gist options
  • Star 41 You must be signed in to star a gist
  • Fork 27 You must be signed in to fork a gist
  • Save auser/7316267 to your computer and use it in GitHub Desktop.
Save auser/7316267 to your computer and use it in GitHub Desktop.
angular.module('myApp',
['ngRoute', 'myApp.services', 'myApp.directives']
)
.config(function(AWSServiceProvider) {
AWSServiceProvider.setArn('arn:aws:iam::<ACCOUNT_ID>:role/google-web-role');
})
.config(function(StripeServiceProvider) {
StripeServiceProvider.setPublishableKey('pk_test_YOURKEY');
})
.config(function($routeProvider) {
$routeProvider
.when('/', {
controller: 'MainCtrl',
templateUrl: 'templates/main.html',
})
.otherwise({
redirectTo: '/'
});
});
window.onLoadCallback = function() {
angular.element(document).ready(function() {
gapi.client.load('oauth2', 'v2', function() {
angular.bootstrap(
document,
['myApp']
);
});
});
}
angular.module('myApp')
.controller('MainCtrl',
function($scope, AWSService, UserService, StripeService) {
$scope.signedIn = function(oauth) {
UserService.setCurrentUser(oauth)
.then(function(user) {
$scope.user = user;
});
}
var getItemsForSale = function() {
UserService.itemsForSale()
.then(function(images) {
$scope.images = images;
});
}
$scope.onFile = function(files) {
UserService.uploadItemForSale(files)
.then(function(data) {
getItemsForSale();
});
}
$scope.sellImage = function(image) {
$scope.showCC = true;
$scope.currentItem = image;
}
$scope.submitPayment = function() {
UserService
.createPayment($scope.currentItem, $scope.charge)
.then(function(data) {
$scope.showCC = false;
});
}
getItemsForSale();
});
angular.module('myApp.directives', [])
.directive('googleSignin', function() {
return {
restrict: 'A',
template: '<span id="signinButton"></span>',
replace: true,
scope: {
afterSignin: '&'
},
link: function(scope, ele, attrs) {
attrs.$set('class', 'g-signin');
attrs.$set('data-clientid',
attrs.clientId+'.apps.googleusercontent.com');
var scopes = attrs.scopes || [
'auth/plus.login',
'auth/userinfo.email'
];
var scopeUrls = [];
for (var i = 0; i < scopes.length; i++) {
scopeUrls.push('https://www.googleapis.com/' + scopes[i]);
};
var callbackId = "_googleSigninCallback",
directiveScope = scope;
window[callbackId] = function() {
var oauth = arguments[0];
directiveScope.afterSignin({oauth: oauth});
window[callbackId] = null;
};
attrs.$set('data-callback', callbackId);
attrs.$set('data-cookiepolicy', 'single_host_origin');
attrs.$set('data-requestvisibleactions', 'http://schemas.google.com/AddActivity')
attrs.$set('data-scope', scopeUrls.join(' '));
(function() {
var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
po.src = 'https://apis.google.com/js/client:plusone.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
})();
}
}
})
.directive('fileUpload', function() {
return {
restrict: 'A',
scope: {
fileUpload: '&'
},
template: '<input type="file" id="file" /> ',
replace: true,
link: function(scope, ele, attrs) {
ele.bind('change', function() {
var file = ele[0].files;
if (file) {
scope.fileUpload({files: file});
}
})
}
}
})
<!doctype html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0-rc.3/angular.min.js"></script>
<script src="http://code.angularjs.org/1.2.0-rc.3/angular-route.min.js"></script>
<script src="https://sdk.amazonaws.com/js/aws-sdk-2.0.0-rc1.min.js"></script>
<link rel="stylesheet" href="styles/bootstrap.min.css">
</head>
<body>
<div ng-view></div>
<script src="scripts/app.js"></script>
<script src="scripts/controllers.js"></script>
<script src="scripts/services.js"></script>
<script src="scripts/directives.js"></script>
<script type="text/javascript" src="https://js.stripe.com/v2/"></script>
<script type="text/javascript">
(function() {
var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
po.src = 'https://apis.google.com/js/client:plusone.js?onload=onLoadCallback';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
})();
</script>
</body>
</html>
<div class="container">
<h1>Home</h1>
<div ng-show="!user" class="row">
<div class="col-md-12">
<h2>Signup or login to ngroad</h2>
<div google-signin
client-id='395118764200'
after-signin="signedIn(oauth)"></div>
</div>
</div>
<div ng-show="user">
<pre>{{ user | json }}</pre>
<div class="row"
<div class="col-md-12">
<div file-upload="onFile(files)"></div>
</div>
<div ng-show="images">
<div class="col-sm-6 col-md-4"
ng-repeat="image in images">
<div class="thumbnail">
<img ng-click="sellImage(image)"
data-ng-src="{{image.itemUrl}}" />
</div>
</div>
</div>
<div ng-show="showCC">
<form ng-submit="submitPayment()">
<span ng-bind="errors"></span>
<label>
<span>Card Number</span>
<input type="text"
ng-minlength="16"
ng-maxlength="20"
size="20"
data-stripe="number"
ng-model="charge.number" />
</label>
<label>
<span>CVC</span>
<input type="text"
ng-minlength="3"
ng-maxlength="4"
data-stripe="cvc"
ng-model="charge.cvc" />
</label>
<label>
<span>Expiration (MM/YYYY)</span>
<input type="text"
ng-minlength="2"
ng-maxlength="2"
size="2"
data-stripe="exp_month"
ng-model="charge.exp_month" />
</label>
<span> / </span>
<input type="text"
ng-minlength="4"
ng-maxlength="4"
size="4"
data-stripe="exp-year"
ng-model="charge.exp_year" />
<input type="hidden"
name="email"
value="user.email" />
<button type="submit">Submit Payment</button>
</form>
</div>
<div ng-show="!images">
<h4>You have nothing for sale. Upload something</h4>
</div>
</div>
</div>
</div>
{
"Version":"2012-10-17",
"Statement":[
{
"Action":[
"s3:GetObject",
"s3:ListBucket",
"s3:PutObject"
],
"Sid":"Stmt1383614419000",
"Resource":[
"arn:aws:s3:::ng-newsletter-example/*"
],
"Effect":"Allow"
},
{
"Action":[
"dynamodb:GetItem",
"dynamodb:ListTables",
"dynamodb:PutItem",
"dynamodb:Query"
],
"Sid":"Stmt1383614445000",
"Resource":[
"arn:aws:dynamodb:us-east-1:<ACCOUNT_ID>:table/Users",
"arn:aws:dynamodb:us-east-1:<ACCOUNT_ID>:table/UsersItems"
],
"Effect":"Allow"
},
{
"Action":[
"sns:ListSubscriptions",
"sns:ListTopics",
"sns:Publish",
"sns:Subscribe"
],
"Sid":"Stmt1383614467000",
"Resource":[
"arn:aws:sns:us-east-1:<ACCOUNT_ID>:upload_notifications"
],
"Effect":"Allow"
},
{
"Action":[
"sqs:ReceiveMessage",
"sqs:SendMessage"
],
"Sid":"Stmt1383648082000",
"Resource":[
"arn:aws:sqs:us-east-1:<ACCOUNT_ID>:UserCharges"
],
"Effect":"Allow"
}
]
}
angular.module('myApp.services', [])
.factory('UserService', function($q, $http, AWSService, StripeService) {
var service = {
_user: null,
UsersTable: "Users",
UserItemsTable: "UsersItems",
ChargeTable: "UserCharges",
Bucket: 'ng-newsletter-example',
setCurrentUser: function(u) {
if (u && !u.error) {
AWSService.setToken(u.id_token);
return service.currentUser();
} else {
var d = $q.defer();
d.reject(u.error);
return d.promise;
}
},
currentUser: function() {
var d = $q.defer();
if (service._user) {
d.resolve(service._user);
} else {
AWSService.credentials().then(function() {
gapi.client.oauth2.userinfo.get()
.execute(function(e) {
var email = e.email;
AWSService.dynamo({
params: {TableName: service.UsersTable}
})
.then(function(table) {
table.getItem({
Key: {
'User email': {
S: email
}
}
},
function(err, data) {
if (Object.keys(data).length == 0) {
// User didn't previously exist
var itemParams = {
Item: {
'User email': {S: email},
data: {
S: JSON.stringify(e)
}
}
};
table.putItem(itemParams, function(err, data) {
service._user = e;
d.resolve(e);
})
} else {
service._user = JSON.parse(
data.Item.data.S
);
d.resolve(service._user);
}
});
})
});
});
}
return d.promise;
},
itemsForSale: function() {
var d = $q.defer();
service.currentUser().then(function(user) {
AWSService.dynamo({
params: {TableName: service.UserItemsTable}
}).then(function(table) {
table.query({
TableName: service.UserItemsTable,
KeyConditions: {
"User email": {
"ComparisonOperator": "EQ",
"AttributeValueList": [
{S: user.email}
]
}
}
}, function(err, data) {
var items = [];
if (data) {
angular.forEach(data.Items, function(item) {
items.push(JSON.parse(item.data.S));
});
d.resolve(items);
} else {
d.reject(err);
}
})
});
});
return d.promise;
},
uploadItemForSale: function(items) {
var d = $q.defer();
service.currentUser().then(function(user) {
AWSService.s3({
params: {
Bucket: service.Bucket
}
}).then(function(s3) {
var file = items[0]; // only one at a time
var params = {
Key: file.name,
Body: file,
ContentType: file.type
}
s3.putObject(params, function(err, data) {
// Also, let's get a url
var params = {
Bucket: service.Bucket,
Key: file.name,
Expires: 900*4 // 1 hour
};
s3.getSignedUrl('getObject', params, function (err, url) {
AWSService.dynamo({
params: {TableName: service.UserItemsTable}
}).then(function(table) {
var itemParams = {
Item: {
'ItemId': {S: file.name},
'User email': {S: user.email},
data: {
S: JSON.stringify({
itemId: file.name,
itemSize: file.size,
itemUrl: url
})
}
}
};
table.putItem(itemParams, function(err, data) {
d.resolve(data);
});
});
});
});
});
});
return d.promise;
},
createPayment: function(item, charge) {
var d = $q.defer();
StripeService.createCharge(charge)
.then(function(data) {
var stripeToken = data.id;
AWSService.sqs(
{QueueName: service.ChargeTable}
).then(function(queue) {
queue.sendMessage({
MessageBody: JSON.stringify({
item: item,
stripeToken: stripeToken
})
}, function(err, data) {
d.resolve(data);
})
})
}, function(err) {
d.reject(err);
});
return d.promise;
}
};
return service;
})
.provider('AWSService', function() {
var self = this;
// Set defaults
AWS.config.region = 'us-east-1';
self.arn = null;
self.setArn = function(arn) {
if (arn) self.arn = arn;
}
self.setRegion = function(region) {
if (region) AWS.config.region = region;
}
self.setLogger = function(logger) {
if (logger) AWS.config.logger = logger;
}
self.$get = function($q, $cacheFactory) {
var s3Cache = $cacheFactory('s3Cache'),
dynamoCache = $cacheFactory('dynamo'),
snsCache = $cacheFactory('sns'),
sqsCache = $cacheFactory('sqs');
credentialsDefer = $q.defer(),
credentialsPromise = credentialsDefer.promise;
return {
credentials: function() {
return credentialsPromise;
},
setToken: function(token, providerId) {
var config = {
RoleArn: self.arn,
WebIdentityToken: token,
RoleSessionName: 'web-id'
}
if (providerId) {
config['ProviderId'] = providerId;
}
self.config = config;
AWS.config.credentials =
new AWS.WebIdentityCredentials(config);
credentialsDefer.resolve(AWS.config.credentials);
},
s3: function(params) {
var d = $q.defer();
credentialsPromise.then(function() {
var s3Obj = s3Cache.get(JSON.stringify(params));
if (!s3Obj) {
var s3Obj = new AWS.S3(params);
s3Cache.put(JSON.stringify(params), s3Obj);
}
d.resolve(s3Obj);
});
return d.promise;
},
dynamo: function(params) {
var d = $q.defer();
credentialsPromise.then(function() {
var table = dynamoCache.get(JSON.stringify(params));
if (!table) {
var table = new AWS.DynamoDB(params);
dynamoCache.put(JSON.stringify(params), table);
};
d.resolve(table);
});
return d.promise;
},
sns: function(params) {
var d = $q.defer();
credentialsPromise.then(function() {
var sns = snsCache.get(JSON.stringify(params));
if (!sns) {
sns = new AWS.SNS(params);
snsCache.put(JSON.stringify(params), sns);
}
d.resolve(sns);
})
return d.promise;
},
sqs: function(params) {
var d = $q.defer();
credentialsPromise.then(function() {
var url = sqsCache.get(JSON.stringify(params)),
queued = $q.defer();
if (!url) {
var sqs = new AWS.SQS();
sqs.createQueue(params, function(err, data) {
if (data) {
url = data.QueueUrl;
sqsCache.put(JSON.stringify(params), url);
queued.resolve(url);
} else {
queued.reject(err);
}
});
} else {
queued.resolve(url);
}
queued.promise.then(function(url) {
var queue = new AWS.SQS({params: {QueueUrl: url}});
d.resolve(queue);
});
})
return d.promise;
}
}
}
})
.provider('StripeService', function() {
var self = this;
self.setPublishableKey = function(key) {
Stripe.setPublishableKey(key);
}
self.$get = function($q) {
return {
createCharge: function(obj) {
var d = $q.defer();
if (!obj.hasOwnProperty('number') ||
!obj.hasOwnProperty('cvc') ||
!obj.hasOwnProperty('exp_month') ||
!obj.hasOwnProperty('exp_year')
) {
d.reject("Bad input", obj);
} else {
Stripe.card.createToken(obj,
function(status, resp) {
if (status == 200) {
d.resolve(resp);
} else {
d.reject(status);
}
});
}
return d.promise;
}
}
}
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment