如何使用stripe
本文由Stamplay赞助。 感谢您支持使SitePoint成为可能的赞助商。
作为前端开发人员,我经常发现自己使用Angular和React之类的框架为自己的副项目创建了丰富的UI,但是有时候您的应用需要数据,持久性,业务逻辑,电子邮件以及其他通常是后端开发人员的领域。 Stamplay是一项服务,旨在使应用程序开发的这些方面像填写表格一样容易。
让我们通过使用Stamplay构建一个“后端”来充实一个简单的Book Club应用程序。 用户将能够对阅读过的书进行评分。 他们还可以投票其他评论。 我们会向用户收取对读书俱乐部的访问权限,并在他们注册时通过电子邮件向他们发送欢迎礼包。
入门
我已经为Book Club应用程序创建了一个前端外壳。 在学习本教程时,我们将使用Stamplay填补空白。
首先,您需要克隆以下存储库 :
git clone git@github.com:bradbarrow/sp-stamplay.git
在项目目录中,检出starter
分支:
git checkout starter
然后运行以下命令:
bower install
这将安装:
- AngularJS
- Stamplay SDK
- 引导CSS
- Angular Bootstrap用户界面
- 离子图标
- 阿尔及利亚搜索客户端
我们还包括了StripeJavaScript客户端。
要运行该应用程序,您需要安装http服务器。 我喜欢使用lr-http-server
,您可以通过运行以下命令进行安装:
npm install -g lr-http-server
然后在您的项目目录中,只需运行lr-http-server -p 8080
。
设置图章
Stamplay入门很容易。 只需访问他们的注册页面 ,然后单击“ 创建新帐户”按钮即可获得一个帐户。
创建我们的第一个应用
在Stamplay编辑器中,为您的新应用指定唯一的名称,然后单击“创建”按钮。 我们称我们的App Bookclub
现在,您将进入此应用程序的仪表板。 请注意此页面,因为它具有一些有关将前端连接到Stamplay的重要信息。
Stamplay CLI
为了使用Stamplay,我们需要将我们的应用程序连接到Stamplay的API。 Stamplay为此提供了一个npm软件包。 继续并安装stamplay-cli软件包。
npm install -g stamplay-cli
现在,您可以在项目目录中运行stamplay init
来生成stamplay.json
文件。
您将需要应用程序的APP ID和API KEY ,如上所述,它们都可以在应用程序仪表板上找到。
一个读书俱乐部需要书籍
如果我们要有一个读书俱乐部,我们将需要书籍。 我们的应用程序已经在index.html
有一个书单,在scripts/app.js
已经有一个BooksController
。 让我们转到Stamplay并设置Book CustomObject,然后再将其连接到我们的应用程序中。
![](https://i-blog.csdnimg.cn/blog_migrate/40e321fbc0c82bff2f640affbb1e5be6.png)
免费学习PHP!
全面介绍PHP和MySQL,从而实现服务器端编程的飞跃。
原价$ 11.95 您的完全免费
在应用的信息中心上,点击左侧菜单中的对象链接,然后点击+添加 。 在“对象名称”字段中enter
book
,然后按enter
键以开始填写其属性。
我们将只添加一个名为“ title”的字符串属性。
试用Stamplay API控制台
Stamplay具有一个API控制台,可帮助您与应用程序进行交互。 它使您可以执行API操作来获取/设置数据,并查看您的应用程序如何响应。
让我们使用控制台添加我们的第一本书(稍后我们将使用自己的应用添加图书)。
单击Stamplay编辑器左侧菜单中的API Console。
从“操作”菜单中,选择“创建对象”。
在“ API URL”字段中,从下拉列表中选择“ book”。
将出现一个表格,询问您要添加的书的标题。 让我们添加“杀死一只嘲笑的鸟”。 点击发送按钮。
当请求发送到您应用的API时,我们将看到该请求,最终我们将得到响应。 一切顺利,应该是200 OK。
让我们将“操作”更改为“获取所有对象”,然后再次选择“预订”。 再次点击发送,我们应该返回一个包含“杀死一只嘲笑鸟”的响应。
现在是时候将该数据放入我们的前端了。
将书籍连接到我们的前端
打开scripts/app.js
在文件的最上方添加以下行:
Stamplay.init('YOURAPPID');
这是使用Stamplay
全球从Stamplay SDK我们包括index.html
。 初始化函数标识我们的应用程序,以便我们其余的调用转到正确的应用程序。
接下来,我们将创建一个Book服务,以从Stamplay获取我们的图书。 如下更新app.js
:
Stamplay.init("bookclub");
var app = angular.module('stamplay', ['ngStamplay']);
app.controller('BooksController', function($scope, $rootScope, $stamplay, Book){
$scope.books = [];
Book.all().then(function(books){
$scope.books = books;
});
});
app.factory('Book', function($q, $stamplay){
function all() {
var deferred = $q.defer();
var BookCollection = $stamplay.Cobject('book').Collection;
BookCollection.fetch().then(function() {
deferred.resolve(BookCollection.instance);
});
return deferred.promise;
}
return {
all: all
}
});
您会注意到我们在这里使用
$stamplay
。 由于我们已包含ngStamplay模块,因此该功能可用。
我们在这里正在使用Angular Stamplay SDK来获取我们的藏书。 我们使用all()
方法创建了一个简单的Book服务。
all方法在内部调用Stamplay书籍Collection上的fetch()
,并返回promise 。 解决后,将填充BookCollection。 (请记住,Stamplay模型和集合本质上是Backbone.js结构。
在BooksController中,我们只需注入我们的服务并调用all()
方法即可在范围内填充books数组。
在index.html中,我们需要将{{book.title}}行更改为{{book.instance.title}},以符合Stamplay的数据结构。 您也可以调用book.get('title')。
现在,当您在浏览器中查看应用程序时,您应该在书单中看到“杀死一只模仿鸟”。
添加新书
让我们添加从应用程序创建新书的功能。 首先,我们将在图书清单的顶部创建一个表单:
<div class="panel panel-default" ng-controller="BooksController">
<div class="panel-heading">
Books
</div>
<div class="panel-body">
<form class="form-horizontal" ng-submit="addBook()">
<div class="form-group">
<label for="title" class="col-sm-2 control-label">Book Title</label>
<div class="col-sm-10">
<input
type="text"
ng-model="newBook.title"
class="form-control"
id="title"
placeholder="The Lord of the Rings"
autocomplete="off">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default">Add Book</button>
</div>
</div>
</form>
</div>
<div class="list-group">
<div class="list-group-item" ng-repeat="book in books">
{{book.instance.title}}
</div>
</div>
</div>
然后,我们将一个名为add
的新方法添加到Book服务中:
app.factory('Book', function($q, $stamplay){
function all() {
...
}
function add(book) {
var deferred = $q.defer();
var BookModel = $stamplay.Cobject('book').Model;
BookModel.set('title', book.title);
BookModel.save().then(function() {
deferred.resolve(BookModel);
});
return deferred.promise;
}
return {
all: all,
add: add
}
});
在这里,您可以看到我们使用自定义对象的模型而不是集合。 我们创建一本新的空书,为其分配书名然后保存。 然后,我们使用保存的实例实例来解决我们的承诺。
剩下的就是我们的BooksController处理表单提交:
app.controller('BooksController', function($scope, $rootScope, $stamplay, Book){
...
$scope.newBook = { title: '' }; // Empty book for form
$scope.addBook = function() {
Book.add($scope.newBook).then(function(savedBook){
$scope.books.push(savedBook); // Immediate UI response
});
$scope.newBook.title = ''; // Blank out the form
}
});
如果您填写表格,应该会看到您的书已添加到列表中。 刷新页面,它应该仍然存在。 我们刚刚使用Stamplay在应用程序中添加了持久性。 容易吧?
允许用户注册/登录
目前,我们网站的任何访问者都可以添加书籍。 假设我们只希望注册用户能够将新书添加到列表中。
Stamplay使登录变得容易。 首先,在Stamplay编辑器的左侧菜单中单击“用户”,然后单击“身份验证”。
在这里,您可以为Stamplay应用程序选择一系列身份验证解决方案。 今天,我们将使用Google Plus。
您可以在此处找到有关此过程的说明。 这非常容易,只需几分钟。
拥有Google Plus应用ID和密码后,请点击Stamplay身份验证部分中的Google Plus徽标,然后输入您的详细信息,然后点击保存。
就本教程而言,我们还将设置对公共应用的权限,这样我们就不必担心谁登录以及谁可以做什么。 也就是说,Stamplay中的角色和权限系统功能强大,可以轻松处理应用程序中复杂的用户权限设置。
要将权限设置为公共,请单击“用户”菜单下的“权限”,然后单击“公共”选项卡。
在我们的应用程序中实施Auth
既然我们已经连接了Google Plus,那么登录就很简单了。
我们将创建一个User服务,该服务允许我们登录和注销以及获取有关当前登录用户的信息:
app.factory('User', function($q, $stamplay){
function login() {
var deferred = $q.defer();
var User = $stamplay.User().Model;
User.login('google').then(function(){
deferred.resolve(User);
});
}
function active() {
var deferred = $q.defer();
var User = $stamplay.User().Model;
User.currentUser().then(function() {
deferred.resolve(User);
}).catch(function(err) {
deferred.reject(err);
});
return deferred.promise;
}
function logout() {
var User = $stamplay.User().Model;
User.logout();
}
return {
active: active,
logout: logout,
login: login
};
});
只需调用User.login('google')
,Stamplay将在返回用户登录之前通过OAuth流程发送我们的用户。
我们将向NavBar添加一个登录链接,但首先让我们创建一个NavController来处理操作:
app.controller('NavController', function($scope, User, $rootScope){
$scope.login = function(){
User.login().then(function(user){
// Add their details to root scope
$rootScope.$emit('User::loggedIn', {user: user});
});
}
$scope.logout = function(){
User.logout();
}
});
登录成功后,我们将发出一个包含用户详细信息的事件。 让我们为该事件设置一个侦听器:
app.run(function($rootScope, User){
// Listen for login events
$rootScope.$on('User::loggedIn', function(event, data){
$rootScope.loggedIn = true;
$rootScope.user = data.user;
});
// Check if there's a user logged in already
User.active().then(function(activeUser){
if(activeUser.isLogged()){
// Add their details to rootScope
$rootScope.$emit('User::loggedIn', {user: activeUser});
}
});
});
在Angular的run()
函数中,我们将为登录事件设置一个侦听器。 如果您以前没有使用过run()
函数,那么它基本上是一个在应用程序引导后立即运行的函数。
当用户登录时,我们将存储已登录用户的事实,并存储其详细信息。
下一节将检查是否有活动用户,如果他们已经登录,则会发出登录事件。 这是在这里,以便当已经登录的用户访问您的站点时,其详细信息将放回到$rootScope
。
现在我们知道某人是否已登录,并且有了登录和注销的方法,我们可以向导航栏添加一些链接:
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-6" ng-controller="NavController">
<ul class="nav navbar-nav">
<li class="active"><a ng-href="#">Books</a></li>
<li>
<a
ng-href="#"
ng-show="!loggedIn"
ng-click="login()">
Login
</a>
</li>
<li>
<a
ng-href="#"
ng-show="loggedIn"
ng-click="logout()">
Logout {{user.instance.displayName}}
</a>
</li>
</ul>
</div>
如果您在浏览器中打开它并进行尝试,您会注意到的第一件事是,单击链接会将您转到http://localhost/auth/v1/google/connect
或类似的网站。 由于Google(出于安全原因)希望使用真实的网址来处理身份验证,因此无法使用此功能。 幸运的是,Stamplay使我们可以轻松地将应用程序部署到真实URL。
只需在项目目录中运行stamplay deploy
。
完成后,您可以在http://yourappid.stamplayapp.com
看到您的应用程序。 现在,登录/注销过程也应正常工作。
最后,我们仅在用户登录后显示“添加书”表单:
<div class="panel-body" ng-show="loggedIn">
<form class="form-horizontal" ng-submit="addBook()">
...
</form>
</div>
发送邮件
让我们向新用户发送欢迎电子邮件。 单击Stamplay左侧菜单中“任务”下的“管理”,然后单击“新建任务”。 我们将选择:“当用户注册时,电子邮件–发送电子邮件”
单击“继续”进入第3步,您可以在其中使用右侧的值来填充您的电子邮件。
再次“继续”,给您的任务起一个名字。 新用户注册后,他们现在会收到您的电子邮件:)
创建书评
我们将允许我们的用户对他们阅读的书发表评论。 为此,我们在Stamplay中创建的审阅对象将连接到该审阅将要涉及的书对象,以便我们可以使用该关联。 我们还将把评论与登录的用户相关联。
在Stamplay编辑器中,让我们回到“对象”选项卡并添加一个名为“ review”的新自定义对象:
添加一个名为“ text”的字符串属性,该属性将保存评论内容。
现在,转到Stamplay编辑器中的book对象。 我们将向book对象添加一个字段,该字段是其评论的数组。
在书对象上创建一个名为“评论”的新字段,然后选择“对象关系–评论”作为类型。
申请表中的评论表格
现在,我们已经在Stamplay上设置了评论,我们需要添加将评论写到我们的应用程序的功能。
首先,让我们创建一个服务来处理“评论”的一些任务:
app.factory('Review', function($q, $stamplay, Book, $rootScope){
function all() {
var deferred = $q.defer();
var ReviewCollection = $stamplay.Cobject('review').Collection;
ReviewCollection.fetch().then(function() {
deferred.resolve(ReviewCollection.instance);
});
return deferred.promise;
}
function add(review) {
var deferred = $q.defer();
var ReviewModel = $stamplay.Cobject('review').Model;
ReviewModel.set('text', review.text); // The review text
ReviewModel.set('owner', $rootScope.user.instance.id); //Associate with logged in user
// Save the review
ReviewModel.save().then(function() {
// If it saves, update the book
Book.find(review.bookId).then(function(BookToUpdate){
// Store the saved review on the book
var currentReviews = BookToUpdate.get('reviews') || [];
currentReviews.push(ReviewModel.get('_id'));
BookToUpdate.set('reviews', currentReviews)
BookToUpdate.save().then(function(){
// We're done
deferred.resolve(ReviewModel);
});
});
});
return deferred.promise;
}
return {
all: all,
add: add,
}
});
这里重要的是:
- 添加评论时,我们将登录用户的ID保存为评论的所有者
- 添加评论时,我们会找到关联的书,然后在保存书之前将评论推入书评论列表。
我们需要在我们的Book服务中添加find()
方法:
function find(id) {
var deferred = $q.defer();
var BookModel = $stamplay.Cobject('book').Model;
BookModel.fetch(id).then(function() {
deferred.resolve(BookModel);
}).catch(function(err) {
deferred.reject(err);
});
return deferred.promise;
}
然后将其添加到服务的导出中:
return {
all: all,
add: add,
find: find // Now we can use Book.find()
}
fetch()
方法使用ID进行搜索。
现在我们有了一项可以处理评论的服务,让我们为表单创建一个控制器:
app.controller('ReviewController', function($scope, Book, $rootScope, Review){
$scope.bookOptions = [];
Book.all().then(function(books){
$scope.bookOptions = books;
});
$scope.newReview = {
bookId: null,
text: '',
};
$scope.leaveReview = function() {
Review.add($scope.newReview).then(function(savedReview){
$rootScope.$emit('Review::added', {review: savedReview});
$scope.newReview.text = '';
$scope.newReview.bookId = null;
});
}
});
在此控制器中需要注意一些事项。 首先,我们获得要显示在下拉列表中的书籍列表,以便用户可以选择要阅读的书籍。 当用户留下评论时,我们将使用评论服务来添加它,完成后,我们将发出一个事件来通知其余应用程序。
让我们在书本表单上方为评论添加一个新表单(仅在登录时显示):
<div class="row" ng-show="loggedIn">
<div class="col-md-12">
<div class="panel panel-default" ng-controller="ReviewController">
<div class="panel-heading">
Add a review
</div>
<div class="panel-body" ng-show="loggedIn">
<form class="form-horizontal" ng-submit="leaveReview()">
<div class="form-group">
<label for="book" class="col-sm-2 control-label">Book</label>
<div class="col-sm-10">
<select
ng-model="newReview.bookId"
ng-options="book.instance.id as book.instance.title for book in bookOptions"
class="form-control"
id="book"
autocomplete="off">
<option value="">-- Choose a book --</option>
</select>
</div>
</div>
<div class="form-group">
<label for="text" class="col-sm-2 control-label">Review</label>
<div class="col-sm-10">
<input
type="text"
ng-model="newReview.text"
class="form-control"
id="text"
placeholder="I thought it was hilarious!"
autocomplete="off">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default">Leave Review</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
现在,我们需要能够看到我们创建的评论。 让我们将它们放在它们所属的书下面。
首先,在获取书时,我们需要告诉Stamplay,我们还希望响应中包含所有相关的对象(评论)。 为此,我们在获取图书时将{populate: true}
指定为fetch方法。 如下更新您的图书服务:
app.factory('Book', function($q, $stamplay){
function all() {
var deferred = $q.defer();
var BookCollection = $stamplay.Cobject('book').Collection;
BookCollection.fetch({populate: true}).then(function() {
deferred.resolve(BookCollection.instance);
});
return deferred.promise;
}
...
});
现在,在我们的BooksController中,一旦我们加载了这些书,我们还可以访问每本书的评论。
每当我们添加新书和每次添加新评论时,我们都希望刷新我们的书数据。 因此,让我们听这些事件,并在发生这些事件时再次加载它们。
app.controller('BooksController', function($scope, $rootScope, $stamplay, Book, Review, User){
$scope.books = [];
var loadBooks = function(){
Book.all().then(function(books){
$scope.books = books;
});
}
$scope.newBook = {
title: ''
};
$scope.addBook = function() {
Book.add($scope.newBook).then(function(savedBook){
$scope.books.push(savedBook);
// Emit new book was added
$rootScope.$emit('Book::added');
});
$scope.newBook.title = '';
}
$rootScope.$on('Book::added', function(data){
loadBooks();
});
$rootScope.$on('Review::added', function(data){
loadBooks();
});
loadBooks();
});
我们将对图书清单的布局进行一些调整以适应评论,如下所示:
<div class="list-group" ng-repeat="book in books">
<div class="list-group-item">
<h4 class="list-group-item-heading">{{book.instance.title}}</h4>
</div>
<div class="list-group-item" ng-repeat="review in book.instance.reviews">
{{review.text}}
</div>
</div>
如果您现在启动浏览器,则应该可以添加新评论,并且保存后,它应该显示在正确的书下。
太好了,现在只剩下一件事了-很高兴在用户的评论中显示其姓名。
对于每条评论,我们都会要求提供所有者的信息,并将其存储在评论中,以便我们可以在视图中将其获取。
首先,我们需要在用户服务上使用find方法:
app.factory('User', function($q, $stamplay){
function find(id) {
var deferred = $q.defer();
var User = $stamplay.User().Model;
User.fetch(id).then(function() {
deferred.resolve(User);
}).catch(function(err) {
deferred.reject(err);
});
return deferred.promise;
}
...
});
将此添加到出口以为您提供服务:
return {
active: active,
logout: logout,
login: login,
find: find
};
然后,我们将在BooksController中使用它:
app.controller('BooksController', function($scope, $rootScope, $stamplay, Book, Review, User){
$scope.books = [];
var loadBooks = function(){
Book.all().then(function(books){
$scope.books = books;
$scope.books.forEach(function(book){
var reviews = book.instance.reviews || [];
reviews.forEach(function(review){
if(review.owner){
User.find(review.owner).then(function(user){
review.user = user.get('displayName');
});
} else {
review.user = 'Anonymous';
}
});
})
});
}
...
});
我们将在每次评论之前显示此新用户属性:
<div class="list-group-item" ng-repeat="review in book.instance.reviews">
<strong>{{review.user}}</strong> {{review.text}}
</div>
我们终于得到它了。 我们创建了一个表单,用于发布新评论,这些评论将显示在带有评论所有者姓名的正确书籍下。
现在可能是使用几个不同帐户部署和测试应用程序的好时机。
更多Stamplay集成
Stamplay为我们提供了各种即插即用功能。 让我们在UI中添加一些元素,以使我们的应用程序感觉功能丰富:
为我们的评论添加评分
通常,当您留下评论时,您还会给星级。 Stamplay具有对项目进行评分的内置功能。 让我们现在使用它。 首先,我们将在评分表单中添加一个新字段:
<div class="form-group">
<label for="text" class="col-sm-2 control-label">Rating</label>
<div class="col-sm-10">
<input
type="number"
ng-model="newReview.rating"
class="form-control"
id="text"
ng-minlength="1"
ng-maxlength="5"
placeholder="Rating out of 5"
autocomplete="off">
</div>
</div>
然后,当我们将评论保存在评论服务中时,我们只需要执行其他操作即可对书进行评分:
// Save the review
ReviewModel.save().then(function() {
// If it saves, update the book
Book.find(review.bookId).then(function(BookToUpdate){
// Rate it
BookToUpdate.rate(review.rating);
// Store the saved review on the book
var currentReviews = BookToUpdate.get('reviews') || [];
currentReviews.push(ReviewModel.get('_id'));
BookToUpdate.set('reviews', currentReviews)
BookToUpdate.save().then(function(){
// We're done
deferred.resolve(ReviewModel);
});
});
});
现在,我们可以使用action对象在视图中显示这些附加信息(以星标表示):
<div class="list-group" ng-repeat="book in books">
<div class="list-group-item">
<h4 class="list-group-item-heading">{{book.instance.title}}</h4>
<span ng-repeat="n in [1,2,3,4,5]">
<i class="icon ion-ios-star" ng-if="book.instance.actions.ratings.avg >= n"></i>
<i class="icon ion-ios-star-outline" ng-if="book.instance.actions.ratings.avg < n"></i>
</span>
</div>
<div class="list-group-item" ng-repeat="review in book.instance.reviews">
<strong>{{review.user}}</strong> {{review.text}}
</div>
</div>
在您的评论中添加赞
即使评论不好,评论也可能会很受欢迎……因此,让我们允许用户对喜欢的评论进行评论。
让我们增加我们的评论服务,以便它可以发布评论
app.factory('Review', function($q, $stamplay, Book){
function all() {
...
}
function upvote(review) {
var deferred = $q.defer();
var ReviewModel = $stamplay.Cobject('review').Model;
ReviewModel.fetch(review.id).then(function(){
ReviewModel.upVote().then(function(){
deferred.resolve(ReviewModel);
});
}).catch(function(err){
deferred.resolve(err);
});
return deferred.promise;
}
});
然后加:
return {
all: all,
add: add,
upvote: upvote
}
我们会在每个评论中添加一个按钮,以允许投票:
<div class="list-group-item" ng-repeat="review in book.instance.reviews">
<button class="btn-default btn btn-xs" ng-click="upvote(review)">
{{review.actions.votes.total}} <i class="icon ion-arrow-up-a"></i>
</button>
<strong>{{review.user}}</strong> {{review.text}}
</div>
然后,将upvote()
方法添加到BooksController中以保存upvote
$scope.upvote = function(review){
Review.upvote(review).then(function(){
$rootScope.$emit('Review::upvoted');
});
}
$rootScope.$on('Review::upvoted', function(data){
loadBooks();
});
现在,当您单击upvote按钮时,您会看到计数增加。 用户的评论每次只能投票一次。 尝试以其他人身份登录并发表评论。
连接条
我们的读书俱乐部非常棒,让我们向访客收取一个帐户的费用。 您需要此部分的Stripe帐户。
我们首先需要设置Stripe组件。 在Stamplay编辑器的任务菜单下,单击“组件”,然后单击“条纹”图标。
单击绿色的大连接按钮,系统将要求您登录您的Stripe帐户。 如果您没有,则可以在stripe.com上创建一个。 尽管我们在本教程中仅使用测试模式,但是您将需要输入银行详细信息(以便人们付款)。
按照提示登录并连接您的Stripe帐户。
完成后,您应该会看到一个绿色按钮,显示“组件已激活”
回到Stripe组件页面,您应该看到自己的详细信息(测试键等)。 确保禁用实时模式。
现在,我们需要创建一个任务,以便在用户注册时为他们创建新的Stripe客户。 单击任务菜单下的管理,然后单击“新任务”。
从下拉列表中,我们将选择“当用户注册时”,然后选择“剥离-添加客户”。
单击“下一步”,在步骤3中,确保您正在传递{{user._id}}
。
单击下一步,为您的任务命名,例如“创建客户”,然后单击“保存”。
现在,当用户注册时,我们将在Stripe中创建一个新的客户。
现在我们已经拥有与用户相关联的客户,我们可以对已登录的用户收费,然后他们才能访问该应用程序。
首先,我们首先将一个变量paid
设置为false,并使用它隐藏应用程序,直到用户付款为止。 我们还将在稍后设置一个对登录用户paid
的属性,因此我们也在此处进行检查:
app.run(function($rootScope, User){
$rootScope.paid = false;
// Listen for login events
$rootScope.$on('User::loggedIn', function(event, data){
$rootScope.loggedIn = true;
$rootScope.paid = data.user.instance.paid || false; // Has the user already paid?
$rootScope.user = data.user;
});
// Check if there's a user logged in already
User.active().then(function(activeUser){
...
});
});
当前在使用ng-show="loggedIn"
我们还要添加一张付款支票:
例如
<div class="panel-heading">
Books
</div>
<div class="panel-body" ng-show="loggedIn && paid">
<form class="form-horizontal" ng-submit="addBook()">
...
我们将创建一个控制器和一个用于处理付款的表格:
<div class="row" ng-show="loggedIn && !paid">
<div class="col-md-12">
<div class="panel panel-default" ng-controller="PaymentController">
<div class="panel-heading">
Pay to subscribe
</div>
<div class="panel-body" ng-show="loggedIn">
<form class="form-horizontal" ng-submit="pay()">
<div class="form-group">
<label for="book" class="col-sm-2 control-label">Card Number</label>
<div class="col-sm-10">
<input
type="text"
ng-model="card.number"
class="form-control"
id="text"
autocomplete="off">
</div>
</div>
<div class="form-group">
<label for="book" class="col-sm-2 control-label">CVC</label>
<div class="col-sm-10">
<input
type="text"
ng-model="card.cvc"
class="form-control"
id="text"
autocomplete="off">
</div>
</div>
<div class="form-group">
<label for="book" class="col-sm-2 control-label">Expiry Month</label>
<div class="col-sm-10">
<input
type="text"
ng-model="card.exp_month"
class="form-control"
id="text"
placeholder="02"
autocomplete="off">
</div>
</div>
<div class="form-group">
<label for="book" class="col-sm-2 control-label">Expiry Year</label>
<div class="col-sm-10">
<input
type="text"
ng-model="card.exp_year"
class="form-control"
id="text"
placeholder="2015"
autocomplete="off">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default">Pay</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
app.controller('PaymentController', function($scope, $rootScope, $stamplay, User){
Stripe.setPublishableKey('your_stripe_TEST_key');
$scope.card = {
number: '',
cvc: '',
exp_month: '',
exp_year: ''
}
$scope.pay = function(){
Stripe.card.createToken($scope.card, function(status, response){
if (response.error) {
console.log('error', response.error);
} else {
var token = response.id;
var customerStripe = new $stamplay.Stripe();
customerStripe.charge($rootScope.user.instance.id, token, 50, 'USD').then(function (response) {
$scope.$apply(function(){
User.update($rootScope.user.instance.id, 'paid', true).then(function(){
$rootScope.paid = true;
});
})
}, function(err){
console.log('error', err);
})
}
});
}
});
在控制器中,我们使用StripeJavaScript客户端获取卡的令牌,然后使用Stamplay的Stripe函数创建费用。 最后,我们更新为持久性paid
给用户的属性。 我们需要在User上创建update方法。
function update(id, key, value) {
var deferred = $q.defer();
var User = $stamplay.User().Model;
User.fetch(id).then(function() {
User.set(key, value);
User.save().then(function(){
deferred.resolve(User);
});
}).catch(function(err) {
deferred.reject(err);
});
return deferred.promise;
}
要测试Stripe实现,可以使用以下测试值。 有关在Stripe中进行测试的信息,请查阅文档 。
n.4242 4242 4242 4242
date: 07/2020
cvc: 424
实施搜索
随着越来越多的书籍加入我们的俱乐部,使用下拉菜单选择我们要阅读的书变得不切实际。 让我们实现一个预输入搜索。
Stamplay使我们能够与托管搜索后端Algolia集成。 我们需要此部分的Algolia帐户 (有免费试用版)。
在Stamplay中,我们需要连接到Algolia。 转到组件页面,然后单击Algolia。 输入您的详细信息(在Algolia仪表板的凭据选项卡上可用),然后单击connect。
我们需要在Algolia中创建一个索引 。 Algolia的在线应用程序使添加索引变得容易,其教程也很清晰。
我们将索引称为“书” –确保索引中没有任何数据(虚拟数据)。
现在,我们可以在Stamplay中添加新任务。
从条件中选择:创建新对象时,将数据推送到Algolia。
在接下来的页面上,我们将选择“书籍”(我们要搜索的对象),并将其放入名为“书籍”的索引中。
我们将title属性索引为“ title”,将“ _id”属性索引为bookId:
您在此之前添加的所有图书均不会编制索引。 您可以添加另一个任务以在它们更新时为其编制索引,或者由于它是测试数据,因此您可以删除较旧的书籍并添加新的书籍。 您添加的新书应出现在您的Algolia索引中。
现在,我们可以进入Algolia,然后选择要搜索的属性。 您可以在图书索引的“排名”标签上进行配置。 我们将使title属性可搜索。
让我们将该下拉菜单换成提前输入。 我们已经在index.html
包含了Algolia搜索客户端。 我们需要将其包含在Angular模块中:
var app = angular.module('stamplay', ['ngStamplay', 'algoliasearch']);
我们将使用Angular Bootstrap的typeahead指令。 我们已经将JS包含在index.html
因此我们也将其包含在Angular模块中:
var app = angular.module('stamplay', ['ngStamplay', 'algoliasearch', 'ui.bootstrap']);
我们将换掉typeahead指令的旧选择下拉列表:
<div class="form-group">
<label for="book" class="col-sm-2 control-label">Book</label>
<div class="col-sm-10">
<input
type="text"
ng-model="newReview.book"
placeholder="Find a book"
typeahead="book as book.title for book in findBook($viewValue)"
typeahead-loading="loadingBooks" class="form-control">
<i ng-show="loadingBooks" class="glyphicon glyphicon-refresh"></i>
</div>
</div>
您会注意到输入的内容会在结果中显示书名。 值(模型)将是book对象本身。 显示的列表是findBook()
函数的结果。 让我们现在实现它:
app.controller('ReviewController', function($scope, Book, $rootScope, Review, algolia, $q){
// Replace the following values by your ApplicationID and ApiKey.
var client = algolia.Client('FKSLNDAL5R', 'b1c739979a51be636bf6d2eb4eee8243');
// Replace the following value by the name of the index you want to query.
var index = client.initIndex('books');
$scope.findBook = function(value) {
var deferred = $q.defer();
index.search(value, { hitsPerPage: 5 }).then(function(content) {
if (content.query !== value) {
// do not take out-dated answers into account
return;
}
deferred.resolve(content.hits);
}, function(content) {
deferred.resolve([]);
return [];
});
return deferred.promise;
};
$scope.newReview = {
book: null,
text: '',
};
$scope.leaveReview = function() {
Review.add($scope.newReview).then(function(savedReview){
$rootScope.$emit('Review::added', {review: savedReview});
$scope.newReview.text = '';
$scope.newReview.book = null;
});
}
});
您还将注意到,我们已经将newReview
更新为具有book
属性而不是bookId
因为我们的类型是将整个book对象分配给模型。 (这是由于Bootstrap指令中的限制与表示值有关)
我们需要更新Review服务,以从Algolia book对象中获取bookId属性:
// Save the review
ReviewModel.save().then(function() {
// If it saves, update the book
// Access bookId on review.book (an Algolia object)
Book.find(review.book.bookId).then(function(BookToUpdate){
// Rate it
BookToUpdate.rate(review.rating);
// Store the saved review on the book
var currentReviews = BookToUpdate.get('reviews') || [];
currentReviews.push(ReviewModel.get('_id'));
BookToUpdate.set('reviews', currentReviews)
BookToUpdate.save().then(function(){
// We're done
deferred.resolve(ReviewModel);
});
});
});
如果您运行应用程序,则现在应该可以通过键入并从结果中进行选择来查找书籍。 添加评论应将评论与正确的书相关联。
结论
您可以在bookclub.stamplayapp.com上查看此应用程序的完整版本。 完整的代码也可以在master上找到 。
我们几乎所有的时间都花在了构建用户界面的前端应用程序中,但现在我们也拥有强大的后端。 Stamplay确实确实很容易实现常见的后端任务,使您可以专注于创建功能丰富的复杂应用程序。 我很想看看你用Stamplay创造的东西。
Stamplay已向SitePoint用户提供了独家优惠券,可免费提供3个月的高级计划(价值600美元)。 优惠券代码为STAMPLAY4SP,有效期至7月30日。
翻译自: https://www.sitepoint.com/creating-a-fully-featured-book-club-app-with-stamplay/
如何使用stripe