【发布时间】: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 文件中添加了这些条目或需要格式化文件,有人可以告诉我我做错了什么吗?
【问题讨论】:
标签: android amazon-ec2 parse-server mailgun bitnami