如何使用stripe_使用AngularJS,Stripe和Stamplay创建Book Club应用

如何使用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 IDAPI KEY ,如上所述,它们都可以在应用程序仪表板上找到。

一个读书俱乐部需要书籍

如果我们要有一个读书俱乐部,我们将需要书籍。 我们的应用程序已经在index.html有一个书单,在scripts/app.js已经有一个BooksController 。 让我们转到Stamplay并设置Book CustomObject,然后再将其连接到我们的应用程序中。

免费学习PHP!

全面介绍PHP和MySQL,从而实现服务器端编程的飞跃。

原价$ 11.95 您的完全免费

在应用的信息中心上,点击左侧菜单中的对象链接,然后点击+添加 。 在“对象名称”字段中enter book ,然后按enter键以开始填写其属性。

创建一个自定义书本对象

我们将只添加一个名为“ title”的字符串属性。

将Title属性添加到Book对象

试用Stamplay API控制台

Stamplay具有一个API控制台,可帮助您与应用程序进行交互。 它使您可以执行API操作来获取/设置数据,并查看您的应用程序如何响应。

让我们使用控制台添加我们的第一本书(稍后我们将使用自己的应用添加图书)。

单击Stamplay编辑器左侧菜单中的API Console。

从“操作”菜单中,选择“创建对象”。

在“ API URL”字段中,从下拉列表中选择“ book”。

创建对象API控制台

将出现一个表格,询问您要添加的书的标题。 让我们添加“杀死一只嘲笑的鸟”。 点击发送按钮。

当请求发送到您应用的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徽标,然后输入您的详细信息,然后点击保存。

使用Google+身份验证

就本教程而言,我们还将设置对公共应用的权限,这样我们就不必担心谁登录以及谁可以做什么。 也就是说,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>
  &nbsp;
  <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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值