如何在 Bitnami 解析服务器上设置邮件适配器?

Posted

技术标签:

【中文标题】如何在 Bitnami 解析服务器上设置邮件适配器?【英文标题】:How do I set up mail adapter on Bitnami parse server? 【发布时间】:2020-06-13 23:07:59 【问题描述】:

我是 bitnami 的新手,所以设置电子邮件适配器对我的 android 应用程序来说非常困难,我们将不胜感激。我的目标是在用户在我的应用上输入他们的电子邮件地址后向他们发送密码重置。

到目前为止我做了什么

创建自定义域并设置 mailgun,获取 API 密钥 设置 AWS 并在 Bitnami 启动并运行后将 Parse 连接到我的应用程序 我确保已安装 parse-server-simple-mailgun-adapter 由于在以前的论坛中搜索时 app 文件夹和 server.js 文件不再存在,我将以下代码放入此 index.js 文件 - /opt/bitnami/parse/node_modules/parse-server/lib/index.js

我从以下条目https://github.com/ParsePlatform/parse-server获取此代码

目前在我的 index.js 文件中的代码如下所示:

"use strict";

Object.defineProperty(exports, "__esModule", 
  value: true
);
Object.defineProperty(exports, "S3Adapter", 
  enumerable: true,
  get: function () 
    return _s3FilesAdapter.default;
  
);
Object.defineProperty(exports, "FileSystemAdapter", 
  enumerable: true,
  get: function () 
    return _fsFilesAdapter.default;
  
);
Object.defineProperty(exports, "InMemoryCacheAdapter", 
  enumerable: true,
  get: function () 
    return _InMemoryCacheAdapter.default;
  
);
Object.defineProperty(exports, "NullCacheAdapter", 
  enumerable: true,
  get: function () 
    return _NullCacheAdapter.default;
  
);
Object.defineProperty(exports, "RedisCacheAdapter", 
  enumerable: true,
  get: function () 
    return _RedisCacheAdapter.default;
  
);
Object.defineProperty(exports, "LRUCacheAdapter", 
  enumerable: true,
  get: function () 
    return _LRUCache.default;
  
);
Object.defineProperty(exports, "PushWorker", 
  enumerable: true,
  get: function () 
    return _PushWorker.PushWorker;
  
);
Object.defineProperty(exports, "ParseGraphQLServer", 
  enumerable: true,
  get: function () 
    return _ParseGraphQLServer.ParseGraphQLServer;
  
);
exports.TestUtils = exports.ParseServer = exports.GCSAdapter = exports.default = void 

var _ParseServer2 = _interopRequireDefault(require("./ParseServer"));

var _s3FilesAdapter = _interopRequireDefault(require("@parse/s3-files-adapter"));

var _fsFilesAdapter = _interopRequireDefault(require("@parse/fs-files-adapter"));

var _InMemoryCacheAdapter = _interopRequireDefault(require("./Adapters/Cache/InMemoryC

var _NullCacheAdapter = _interopRequireDefault(require("./Adapters/Cache/NullCacheAdap

var _RedisCacheAdapter = _interopRequireDefault(require("./Adapters/Cache/RedisCacheAd

var _LRUCache = _interopRequireDefault(require("./Adapters/Cache/LRUCache.js"));

var TestUtils = _interopRequireWildcard(require("./TestUtils"));

exports.TestUtils = TestUtils;

var _deprecated = require("./deprecated");

var _logger = require("./logger");

var _PushWorker = require("./Push/PushWorker");

var _Options = require("./Options");

var _ParseGraphQLServer = require("./GraphQL/ParseGraphQLServer");

var server = ParseServer(
        ...otherOptions,
        // Enable email verification
verifyUserEmails: true,
// if `verifyUserEmails` is `true` and
        // //     if `emailVerifyTokenValidityDuration` is `undefined` then
        // //        email verify token never expires
        // //     else
        // //        email verify token expires after `emailVerifyTokenValidityDuration`
        // //
        // // `emailVerifyTokenValidityDuration` defaults to `undefined`
// email verify token below expires in 2 hours (= 2 * 60 * 60 == 7200 seconds)
        // emailVerifyTokenValidityDuration: 2 * 60 * 60, // in seconds (2 hours = 7200 seconds)

// set preventLoginWithUnverifiedEmail to false to allow user to login without verifying their email
        // // set preventLoginWithUnverifiedEmail to true to prevent user from login if their email is not verified
preventLoginWithUnverifiedEmail: false, // defaults to false

// The public URL of your app.
        // // This will appear in the link that is used to verify email addresses and reset passwords.
        // // Set the mount path as it is in serverURL
publicServerURL: 'https://xxxxxxxx/xxxxx/',
// Your apps name. This will appear in the subject and body of the emails that are sent.
appName: 'parse-server',
// The email adapter
emailAdapter: 
          module: '@parse/simple-mailgun-adapter',
          options: 
        // The address that your emails come from
          fromAddress: 'xxxxxxxxxxxxxxxxxxxxxxxxx',
         // Your domain from mailgun.com
        domain: 'xxxxxxxxxxxxxxx',
         // Your API key from mailgun.com
          apiKey: 'xxxxxxxxxxxxxxxxxxxxxxxxxx',
  
,

// account lockout policy setting (OPTIONAL) - defaults to undefined
        // // if the account lockout policy is set and there are more than `threshold` number of failed login attempts 
r code `Parse.Error.OBJECT_NOT_FOUND` with error message `Your account is locked due to multiple failed login attempts.
ute(s)`. After `duration` minutes of no login attempts, the application will allow the user to try login again.
accountLockout: 
        duration: 5, // duration policy setting determines the number of minutes that a locked-out account remains locked out before automatically becom
nlocked. Set it to a value greater than 0 and less than 100000.
          threshold: 3, // threshold policy setting determines the number of failed sign-in attempts that will cause a user account to be locked. Set it
n integer value greater than 0 and less than 1000.
,

// optional settings to enforce password policies
passwordPolicy: 
  // Two optional settings to enforce strong passwords. Either one or both can be specified.
        //   // If both are specified, both checks must pass to accept the password
        //     // 1. a RegExp object or a regex string representing the pattern to enforce
validatorPattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.8,)/, // enforce password with at least 8 char with at least 1 lower case, 1 upper case and 1
t
          // 2. a callback function to be invoked to validate the password
  validatorCallback: (password) =>  return validatePassword(password) ,
          doNotAllowUsername: true, // optional setting to disallow username in passwords
  maxPasswordAge: 90, // optional setting in days for password expiry. Login fails if user does not reset the password within this period after signup/l
eset.
maxPasswordHistory: 5, // optional setting to prevent reuse of previous n passwords. Maximum value that can be specified is 20. Not specifying it or spe
ng 0 will not enforce history.
          //optional setting to set a validity duration for password reset links (in seconds)
resetTokenValidityDuration: 24*60*60, // expire after 24 hours
        
);


function _getRequireWildcardCache()  if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function ()  ret
urn cache; ; return cache; 

function _interopRequireWildcard(obj)  if (obj && obj.__esModule)  return obj;  if (obj === null || typeof obj !== "object" && typeof obj !== "function") 
 return  default: obj ;  var cache = _getRequireWildcardCache(); if (cache && cache.has(obj))  return cache.get(obj);  var newObj = ; var hasProperty
Descriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj)  if (Object.prototype.hasOwnProperty.call(obj, key))  var desc 
= hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set))  Object.defineProperty(newObj, key, desc); 
 else  newObj[key] = obj[key];    newObj.default = obj; if (cache)  cache.set(obj, newObj);  return newObj; 

function _interopRequireDefault(obj)  return obj && obj.__esModule ? obj :  default: obj ; 

// Factory function
const _ParseServer = function (options) 
  const server = new _ParseServer2.default(options);
  return server.app;
; // Mount the create liveQueryServer


exports.ParseServer = _ParseServer;
_ParseServer.createLiveQueryServer = _ParseServer2.default.createLiveQueryServer;
_ParseServer.start = _ParseServer2.default.start;
const GCSAdapter = (0, _deprecated.useExternal)('GCSAdapter', '@parse/gcs-files-adapter');
exports.GCSAdapter = GCSAdapter;
Object.defineProperty(module.exports, 'logger', 
  get: _logger.getLogger
);
var _default = _ParseServer2.default;
exports.default = _default;                                                                                                                                                  

我的 config.json 文件看起来像这样(配置文件位于 /opt/bitnami/parse):


  "appId": "myapp",
  "masterKey": "NTxxxxxxmm",
  "appName": "parse-server",
  "mountPath": "/parse",
  "port": "1337",
  "host": "0.0.0.0",
  "serverURL": "http://3.1xxxxx5/parse/",
  "databaseURI": "mongodb://bn_parse:TFyNVz7Y45@127.xxxxx:27xx7/bitnami_parse"

当我使用以下代码运行我的应用程序时:

ParseUser.requestPasswordResetInBackground("myemail@gmail.com",
                    new RequestPasswordResetCallback() 
                        public void done(ParseException e) 
                            if (e == null) 
                                // An email was successfully sent with reset instructions.
                                Toast.makeText(getApplicationContext(),
                                        "Password Reset email has been sent to this email address",
                                        Toast.LENGTH_LONG).show();
                             else 
                                // Something went wrong. Look at the ParseException to see what's up.
                                Log.i("Error", "Password Reset Error", e);
                                Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
                                Toast.makeText(getApplicationContext(),
                                        "Saving user failed.", Toast.LENGTH_SHORT).show();
                            
                        
                    );

我在日志中收到以下错误消息:

2020-06-13 23:13:05.704 15647-15647/com.example.Fitness I/Error: Password Reset Error
    com.parse.ParseRequest$ParseRequestException: bad json response
        at com.parse.ParseRequest.newTemporaryException(ParseRequest.java:290)
        at com.parse.ParseRESTCommand.onResponseAsync(ParseRESTCommand.java:308)
        at com.parse.ParseRESTUserCommand.onResponseAsync(ParseRESTUserCommand.java:126)
        at com.parse.ParseRequest$3.then(ParseRequest.java:137)
        at com.parse.ParseRequest$3.then(ParseRequest.java:133)
        at bolts.Task$15.run(Task.java:917)
        at bolts.BoltsExecutors$ImmediateExecutor.execute(BoltsExecutors.java:105)
        at bolts.Task.completeAfterTask(Task.java:908)
        at bolts.Task.continueWithTask(Task.java:715)
        at bolts.Task.continueWithTask(Task.java:726)
        at bolts.Task$13.then(Task.java:818)
        at bolts.Task$13.then(Task.java:806)
        at bolts.Task$15.run(Task.java:917)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
        at java.lang.Thread.run(Thread.java:764)
     Caused by: org.json.JSONException: Value <!DOCTYPE of type java.lang.String cannot be converted to JSONObject
        at org.json.JSON.typeMismatch(JSON.java:111)
        at org.json.JSONObject.<init>(JSONObject.java:163)
        at org.json.JSONObject.<init>(JSONObject.java:176)
        at com.parse.ParseRESTCommand.onResponseAsync(ParseRESTCommand.java:298)
        at com.parse.ParseRESTUserCommand.onResponseAsync(ParseRESTUserCommand.java:126) 
        at com.parse.ParseRequest$3.then(ParseRequest.java:137) 
        at com.parse.ParseRequest$3.then(ParseRequest.java:133) 
        at bolts.Task$15.run(Task.java:917) 
        at bolts.BoltsExecutors$ImmediateExecutor.execute(BoltsExecutors.java:105) 
        at bolts.Task.completeAfterTask(Task.java:908) 
        at bolts.Task.continueWithTask(Task.java:715) 
        at bolts.Task.continueWithTask(Task.java:726) 
        at bolts.Task$13.then(Task.java:818) 
        at bolts.Task$13.then(Task.java:806) 
        at bolts.Task$15.run(Task.java:917) 
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) 
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) 
        at java.lang.Thread.run(Thread.java:764) 
2020-06-13 23:13:05.754 1441-1441/? D/gralloc_ranchu: gralloc_alloc: Creating ashmem region of size 360448

看起来作为字符串的电子邮件地址无法转换为 JSON 对象,我已检查并确保我的服务器 URL 在 URL 的末尾有一个“/”。我还在我的 gradle 中添加了 'com.parse:parse-android:1.12.0' 以查看是否可以解决它,但问题仍然存在。

如果我在错误的 index.js 文件中添加了这些条目或需要格式化文件,有人可以告诉我我做错了什么吗?

【问题讨论】:

【参考方案1】:

不幸的是,您复制和粘贴的代码很难理解,但是错误

原因:org.json.JSONException: Value

表示您的 Android 应用程序访问的 URL 未返回 JSON 数据。您的 Android 代码没有访问正确的 URL 来调用该函数,或者您的服务器配置错误并且正在向 Android 应用程序返回 html(可能是错误页面或 404)。除非您已经测试并验证您可以成功调用返回 JSON 的基本函数,否则我建议您删除所有与电子邮件相关的代码并先处理这些代码,然后再尝试将其放回原处。

【讨论】:

以上是关于如何在 Bitnami 解析服务器上设置邮件适配器?的主要内容,如果未能解决你的问题,请参考以下文章

在android studio上设置bitnami Parse服务器的电子邮件验证

Bitnami EC2 Parse Server Instance,更改默认电子邮件文件

从 android studio 在 bitnami Parse 服务器上设置电子邮件验证

在 Parse 服务器 CloudCode 中使用已初始化的邮件适配器

解析服务器电子邮件模板多种语言

AWS Bitnami Parse Server - 添加 HTTP 身份验证使我在解析仪表板中的应用程序“未经授权”