- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我已成功从 Firebase 检索数据以设置为客户端 ID 和客户端密码。为此,我必须使用 promise.then 以确保设置的凭据在检索数据后发生。
const SpotifyWebApi = require('spotify-web-api-node');
admin.firestore().collection('credentials').get().then((snapshot) => {
snapshot.docs.forEach(doc => {
console.log(JSON.stringify(doc.data().client_id));
// Credentials.client_id = JSON.stringify(doc.data().client_id);
console.log(JSON.stringify(doc.data().client_secret));
// Credentials.client_secret = JSON.stringify(doc.data().client_secret);
let client_id = JSON.stringify(doc.data().client_id);
let client_secret = JSON.stringify(doc.data().client_secret);
const credentials = new Credentials(regexIdAndSecret(client_id), regexIdAndSecret(client_secret));
const Spotify = new SpotifyWebApi({
client_id: credentials.client_id,
client_secret: credentials.client_secret,
redirectUri: `https://${process.env.GCLOUD_PROJECT}.firebaseapp.com/popup.html`
});
console.log('This is the client id after it has been set ' + credentials.client_id);
console.log('This is the client secret after it has been set ' + credentials.client_secret);
});
});
但是,我现在遇到了需要在其余代码中使用“Spotify”的困境。因为它在这个 promise 中,所以它的范围仅限于 promise 内部。如何使用正确检索的 Firebase 数据设置凭据,以便“Spotify”对象适用于整个类(class)?
我在下面使用 Spotify 对象的另一个地方的示例(但现在不工作,因为 Spotify 不再是类对象:
/**
* Redirects the User to the Spotify authentication consent screen. Also the 'state' cookie is set for later state
* verification.
*/
exports.redirect = functions.https.onRequest((req, res) => {
cookieParser()(req, res, () => {
const state = req.cookies.state || crypto.randomBytes(20).toString('hex');
console.log('Setting verification state:', state);
res.cookie('state', state.toString(), {maxAge: 3600000, secure: true, httpOnly: true});
const authorizeURL = Spotify.createAuthorizeURL(OAUTH_SCOPES, state.toString());
res.redirect(authorizeURL);
});
});
整个文件:
/**
* Main class holding all the logic which matches the Google assistant application to the Firebase database
* and the Spotify dashboard application. The application is formatted to reflect these three main parts with
* response-requests to Spotify for authorisation and to make api function calls (within the dialogflow fulfillment
* code towards the bottom of the class).
* Author: Marcus Watts
* Date Created: 01 July 2019
*/
'use strict';
/**
* --------------------------- Google/Dialogflow/Firebase Setup ---------------------------
* @type {{analytics; auth; crashlytics; database; firestore; https; pubsub; remoteConfig; storage; testLab; app: apps.Apps; Event: Event; EventContext: EventContext; Change: Change; ChangeJson: ChangeJson; Resource: Resource; TriggerAnnotated: TriggerAnnotated; Runnable: Runnable; HttpsFunction: HttpsFunction; CloudFunction: CloudFunction; MakeCloudFunctionArgs: MakeCloudFunctionArgs; makeCloudFunction; optionsToTrigger; config; firebaseConfig; region; runWith; FunctionBuilder: FunctionBuilder; SUPPORTED_REGIONS: readonly; MIN_TIMEOUT_SECONDS: number; MAX_TIMEOUT_SECONDS: number; VALID_MEMORY_OPTIONS: readonly; ScheduleRetryConfig: ScheduleRetryConfig; Schedule: Schedule; RuntimeOptions: RuntimeOptions; DeploymentOptions: DeploymentOptions}}
*/
// Modules being used
const functions = require('firebase-functions');
// Sets this file as the webhook for dialogflow filfillment
const {WebhookClient} = require('dialogflow-fulfillment');
// Used for storing the sign in data of the Spotify user
const cookieParser = require('cookie-parser');
const crypto = require('crypto');
// Firebase Setup
const admin = require('firebase-admin');
const serviceAccount = require('./service-account.json');
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: `https://${process.env.GCLOUD_PROJECT}.firebaseio.com`
});
// async function getCredentials() {
// const snapshot = await admin.firestore().collection('credentials').get();
// return snapshot;
// }
//
class Credentials {
constructor(client_id, client_secret) {
this.client_id = client_id;
console.log('Id in class ' + this.client_id);
this.client_secret = client_secret;
console.log('Secret in class ' + this.client_secret);
}
}
/**
* ----------------------Below section of code found at: LINK TO GIT REPOSTITORY---------------------------------
*/
function regexIdAndSecret(clientIdOrSecret){
const regex = /[(\w)]+/g;
let n;
let match;
while ((n = regex.exec(clientIdOrSecret)) !== null) {
// This is necessary to avoid infinite loops with zero-width matches
if (n.index === regex.lastIndex) {
regex.lastIndex++;
}
// The result can be accessed through the `n`-variable.
n.forEach((match, groupIndex) => {
return match;
console.log(`Found match, group ${groupIndex}: ${match}`);
});
console.log(`Found n, ${n}`);
return n;
}
}
// Spotify OAuth 2 setup
const SpotifyWebApi = require('spotify-web-api-node');
admin.firestore().collection('credentials').get().then((snapshot) => {
snapshot.docs.forEach(doc => {
console.log(JSON.stringify(doc.data().client_id));
// Credentials.client_id = JSON.stringify(doc.data().client_id);
console.log(JSON.stringify(doc.data().client_secret));
// Credentials.client_secret = JSON.stringify(doc.data().client_secret);
let client_id = JSON.stringify(doc.data().client_id);
let client_secret = JSON.stringify(doc.data().client_secret);
const credentials = new Credentials(regexIdAndSecret(client_id), regexIdAndSecret(client_secret));
const Spotify = new SpotifyWebApi({
client_id: credentials.client_id,
client_secret: credentials.client_secret,
redirectUri: `https://${process.env.GCLOUD_PROJECT}.firebaseapp.com/popup.html`
});
console.log('This is the client id after it has been set ' + credentials.client_id);
console.log('This is the client secret after it has been set ' + credentials.client_secret);
});
// Scopes to request. (Added in all the possible scopes for the auth so that it is possible to do any action that the
// Spotify api will allow i.e maximum permissions granted)
const OAUTH_SCOPES = [
'user-read-email',
'app-remote-control',
'streaming',
'user-modify-playback-state',
'playlist-read-private',
'user-library-modify',
'playlist-read-collaborative',
'playlist-modify-private',
'user-follow-modify',
'user-read-currently-playing',
'user-read-email',
'user-library-read',
'user-top-read',
'playlist-modify-public',
'user-follow-read',
'user-read-playback-state',
'user-read-recently-played'
];
/**
* Redirects the User to the Spotify authentication consent screen. Also the 'state' cookie is set for later state
* verification.
*/
exports.redirect = functions.https.onRequest((req, res) => {
cookieParser()(req, res, () => {
const state = req.cookies.state || crypto.randomBytes(20).toString('hex');
console.log('Setting verification state:', state);
res.cookie('state', state.toString(), {maxAge: 3600000, secure: true, httpOnly: true});
const authorizeURL = Spotify.createAuthorizeURL(OAUTH_SCOPES, state.toString());
res.redirect(authorizeURL);
});
});
/**
* Exchanges a given Spotify auth code passed in the 'code' URL query parameter for a Firebase auth token.
* The request also needs to specify a 'state' query parameter which will be checked against the 'state' cookie.
* The Firebase custom auth token is sent back in a JSONP callback function with function name defined by the
* 'callback' query parameter.
*/
exports.token = functions.https.onRequest((req, res) => {
try {
cookieParser()(req, res, () => {
console.log('Received verification state:', req.cookies.state);
console.log('Received state:', req.query.state);
if (!req.cookies.state) {
throw new Error(
'State cookie not set or expired. Maybe you took too long to authorize. Please try again.'
);
} else if (req.cookies.state !== req.query.state) {
throw new Error('State validation failed');
}
console.log('Received auth code:', req.query.code);
Spotify.authorizationCodeGrant(req.query.code, (error, data) => {
if (error) {
throw error;
}
/**
* Store the codes retained from the Authorization. (Added in the refresh token so that it can be used and set as appropriate to ensure
* the user is constantly connected to the Spotify api)
*/
console.log('Received Access Token:', data.body['access_token']);
console.log('Received Refresh Token:', data.body['refresh_token']);
Spotify.setAccessToken(data.body['access_token']);
Spotify.setRefreshToken(data.body['refresh_token']);
// setterForRefreshToken(data.body['refresh_token']);
Spotify.getMe(async (error, userResults) => {
if (error) {
throw error;
}
console.log('Auth code exchange result received:', userResults);
// We have a Spotify access token and the user identity now.
const accessToken = data.body['access_token'];
const spotifyUserID = userResults.body['id'];
const profilePic = userResults.body['images'][0]['url'];
const userName = userResults.body['display_name'];
const email = userResults.body['email'];
// Create a Firebase account and get the Custom Auth Token.
const firebaseToken = await createFirebaseAccount(
spotifyUserID,
userName,
profilePic,
email,
accessToken
);
// Serve an HTML page that signs the user in and updates the user profile.
res.jsonp({token: firebaseToken});
});
});
});
} catch (error) {
return res.jsonp({error: error.toString});
}
return null;
});
/**
* Creates a Firebase account with the given user profile and returns a custom auth token allowing
* signing-in this account.
* Also saves the accessToken to the datastore at /spotifyAccessToken/$uid
*
* @returns {Promise<string>} The Firebase custom auth token in a promise.
*/
async function createFirebaseAccount(spotifyID, displayName, photoURL, email, accessToken) {
// The UID we'll assign to the user.
const uid = `spotify:${spotifyID}`;
// Save the access token to the Firebase Realtime Database.
const databaseTask = admin.database().ref(`/spotifyAccessToken/${uid}`).set(accessToken);
// Create or update the user account.
const userCreationTask = admin
.auth()
.updateUser(uid, {
displayName: displayName,
photoURL: photoURL,
email: email,
emailVerified: true
})
.catch((error) => {
// If user does not exists we create it.
if (error.code === 'auth/user-not-found') {
return admin.auth().createUser({
uid: uid,
displayName: displayName,
photoURL: photoURL,
email: email,
emailVerified: true
});
}
throw error;
});
// Wait for all async tasks to complete, then generate and return a custom auth token.
await Promise.all([userCreationTask, databaseTask]);
// Create a Firebase custom auth token.
const token = await admin.auth().createCustomToken(uid);
console.log('Created Custom token for UID "', uid, '" Token:', token);
return token;
}
/**
* ----------------- Classes for storing the refresh and access tokens which are attained at sign in:-----------------
* used to create instance variables which can be accessible anywhere within the class
*/
class Refresh {
// Instance variables store the refresh token
constructor(refresh_token) {
this.refresh_token = refresh_token;
}
}
// Instance variables store the refresh token
class Access {
constructor(accessToken) {
this.accessToken = accessToken;
}
}
/**
* ---------------------------Setter and Getter Functions for Spotify Auth URL--------------------------------
*/
function setterForUpdatedAccessToken(splitString) {
Access.accessToken = splitString;
console.log('This is the access token being set in setterForUpdatedAccessToken', Access.accessToken);
}
function getterForUpdatedAccessToken() {
console.log('This is the access token being get in getterForUpdatedAccessToken', Access.accessToken);
return JSON.stringify(Access.accessToken);
}
更新:获取错误 Cannopt read property 'createAuthorizeURL' of undefined at spotify.then.Spotify
const spotify = admin.firestore().collection('credentials').get().then((snapshot) => {
snapshot.docs.forEach(doc => {
console.log(JSON.stringify(doc.data().client_id));
// Credentials.client_id = JSON.stringify(doc.data().client_id);
console.log(JSON.stringify(doc.data().client_secret));
// Credentials.client_secret = JSON.stringify(doc.data().client_secret);
let client_id = JSON.stringify(doc.data().client_id);
let client_secret = JSON.stringify(doc.data().client_secret);
const credentials = new Credentials(regexIdAndSecret(client_id), regexIdAndSecret(client_secret));
const Spotify = new SpotifyWebApi({
client_id: credentials.client_id,
client_secret: credentials.client_secret,
redirectUri: `https://${process.env.GCLOUD_PROJECT}.firebaseapp.com/popup.html`
});
console.log('This is the client id after it has been set ' + credentials.client_id);
console.log('This is the client secret after it has been set ' + credentials.client_secret);
return Spotify;
});
});
exports.redirect = functions.https.onRequest((req, res) => {
cookieParser()(req, res, () => {
const state = req.cookies.state || crypto.randomBytes(20).toString('hex');
console.log('Setting verification state:', state);
res.cookie('state', state.toString(), {maxAge: 3600000, secure: true, httpOnly: true});
spotify.then(Spotify => {
const authorizeURL = Spotify.createAuthorizeURL(OAUTH_SCOPES, state.toString());
res.redirect(authorizeURL);
});
});
});
最佳答案
从您的 .then
回调返回 spotify 类实例,并将 promise 存储在您所有其他代码可访问的某个地方。例如。在文件顶部或在单独的模块中:
// spotify.js
module.exports = admin.firestore().collection('credentials').get().then((snapshot) => {
/*...*/
return Spotify;
});
您可以在代码中的任何其他地方
const spotify = require('./spotify');
// ...
spotify.then(Spotify => {
// do stuff with Spotify
});
当然,如果您在异步函数中,您可以只使用 await
(但我会选择不同的变量名称):
const Spotify = await spotify;
// do stuff with Spotify
例如:
const spotify = require('./spotify');
// ...
exports.redirect = functions.https.onRequest((req, res) => {
cookieParser()(req, res, () => {
const state = req.cookies.state || crypto.randomBytes(20).toString('hex');
console.log('Setting verification state:', state);
res.cookie('state', state.toString(), {maxAge: 3600000, secure: true, httpOnly: true});
spotify.then(Spotify => {
const authorizeURL = Spotify.createAuthorizeURL(OAUTH_SCOPES, state.toString());
res.redirect(authorizeURL);
});
});
});
关于javascript - 范围问题 : storing account credentials in a new class object within a promise, 但现在需要在类的其余部分使用此对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57840709/
我正在尝试用 C 语言编写一个使用 gstreamer 的 GTK+ 应用程序。 GTK+ 需要 gtk_main() 来执行。 gstreamer 需要 g_main_loop_run() 来执行。
我已经使用 apt-get 安装了 opencv。我得到了以下版本的opencv2,它工作正常: rover@rover_pi:/usr/lib/arm-linux-gnueabihf $ pytho
我有一个看起来像这样的 View 层次结构(基于其他答案和 Apple 的使用 UIScrollView 的高级 AutoLayout 指南): ScrollView 所需的2 个步骤是: 为 Scr
我尝试安装 udev。 udev 在 ./configure 期间给我一个错误 --exists: command not found configure: error: pkg-config and
我正在使用 SQLite 3。我有一个表,forums,有 150 行,还有一个表,posts,有大约 440 万行。每个帖子都属于一个论坛。 我想从每个论坛中选择最新帖子的时间戳。如果我使用 SEL
使用 go 和以下包: github.com/julienschmidt/httprouter github.com/shwoodard/jsonapi gopkg.in/mgo.v2/bson
The database仅包含 2 个表: 钱包(100 万行) 事务(1500 万行) CockroachDB 19.2.6 在 3 台 Ubuntu 机器上运行 每个 2vCPU 每个 8GB R
我很难理解为什么在下面的代码中直接调用 std::swap() 会导致编译错误,而使用 std::iter_swap 编译却没有任何错误. 来自 iter_swap() versus swap() -
我有一个非常简单的 SELECT *用 WHERE NOT EXISTS 查询条款。 SELECT * FROM "BMAN_TP3"."TT_SPLDR_55E63A28_59358" SELECT
我试图按部分组织我的 .css 文件,我需要从任何文件访问文件组中的任何类。在 Less 中,我可以毫无问题地创建一个包含所有文件导入的主文件,并且每个文件都导入主文件,但在 Sass 中,我收到一个
Microsoft.AspNet.SignalR.Redis 和 StackExchange.Redis.Extensions.Core 在同一个项目中使用。前者需要StackExchange.Red
这个问题在这里已经有了答案: Updating from Rails 4.0 to 4.1 gives sass-rails railties version conflicts (4 个答案) 关
我们有一些使用 Azure DevOps 发布管道部署到的现场服务器。我们已经使用这些发布管道几个月了,没有出现任何问题。今天,我们在下载该项目的工件时开始出现身份验证错误。 部署组中的节点显示在线,
Tip: instead of creating indexes here, run queries in your code – if you're missing any indexes, you
你能解释一下 Elm 下一个声明中的意思吗? (=>) = (,) 我在 Elm architecture tutorial 的例子中找到了它 最佳答案 这是中缀符号。实际上,这定义了一个函数 (=>
我需要一个 .NET 程序集查看器,它可以显示低级详细信息,例如元数据表内容等。 最佳答案 ildasm 是 IL 反汇编程序,具有低级托管元数据 token 信息。安装 Visual Studio
我有两个列表要在 Excel 中进行比较。这是一个很长的列表,我需要一个 excel 函数或 vba 代码来执行此操作。我已经没有想法了,因此转向你: **Old List** A
Closed. This question does not meet Stack Overflow guidelines。它当前不接受答案。 想要改善这个问题吗?更新问题,以便将其作为on-topi
我正在学习 xml 和 xml 处理。我无法很好地理解命名空间的存在。 我了解到命名空间帮助我们在 xml 中分离相同命名的元素。我们不能通过具有相同名称的属性来区分元素吗?为什么命名空间很重要或需要
我搜索了 Azure 文档、各种社区论坛和 google,但没有找到关于需要在公司防火墙上打开哪些端口以允许 Azure 所有组件(blob、sql、compute、bus、publish)的简洁声明
我是一名优秀的程序员,十分优秀!