Supabase and Google Apps Script - javascript

Is it possible to use Supabase with Google Apps Script (GAS)?
I'm new to Supabase and I've never tried to import external library to GAS before. I'm planning to use Supabase as a database for my project in GAS. The project is built to run a bot in a chatting platform rather than a user interface. Based on the documentation from Supabase, it looks like it works by executing function from the Supabase library.
I have tried to use the Supabase library by copy-pasting the whole library from here or using eval(), but all of them return the error: ReferenceError: self is not defined.
Here is the function I run that uses eval():
function myFunction(){
var x = eval(UrlFetchApp.fetch("https://unpkg.com/#supabase/supabase-js").getContentText())
var supabase = createClient(supabaseUrl,supabaseKey)
}
createClient() is supposed to be a function from the Supabase library.

One possible route that I can think of to make this work is to use Postgrest, which is the underlining API server that Supabase users.
Since every Supabase instance can be accessed using rest API provided by Postgrest, you should be able to perform insert, update, delete and read operations to your Supabase database from your GAS project.
You can probably run something like this to access Supabase.
$anonKey = "YOUR_SUPABASE_ANON_KEY_HERE"
$url = "YOUR_SUPABASE_URL_HERE"
$var options = {
"async": true,
"crossDomain": true,
"method" : "GET",
"headers" : {
"Authorization" : "Bearer " + $anonKey,
"apikey": $anonKey
}
};
var response = UrlFetchApp.fetch($url + "YOUR_QUERY_PARAMETER_FOR_POSTGREST", options);

Related

Ionic 5 IOS & Stripe Payment Request Button - Stripe.js integrations must use HTTPS

I'm trying to add a Payment Request Button to my Ionic 5 app. However, no matter how I run the app, I always get the following message and the button won't show.
[warn] - You may test your Stripe.js integration over HTTP. However,
live Stripe.js integrations must use HTTPS.
I'm loading the Stripe API over https
<script src="https://js.stripe.com/v3/"></script>
I've imported it in to my page
declare var Stripe;
// Check the availability of the Payment Request API first.
const prButton = elements.create('paymentRequestButton', {
paymentRequest,
});
paymentRequest.canMakePayment().then(result => {
if (result) {
prButton.mount('#payment-request-button');
} else {
document.getElementById('payment-request-button').style.display = 'none';
}
);
I've tried running it in Safari on Mac (running with --ssl and a valid certificate), Xcode Emulator, A Real iPhone and the result is always the same.
Also worth noting is that I'm using Capacitor, not Cordova. I've tried this in my capacitor.config.json but it had no effect.
"iosScheme": "https",
Update:
So it turns out that it's because the app runs with the local urlScheme of capacitor:// rather than https:// and the development team at Ionic currently have no plans to rectify this. Is there any way to make the Payment Request Button appear in a non-https environment?
After a lot of back and forth with Stripe's support team, I finally came up with a solution. A lot of what they said is included in this answer (placed in blockquotes). I've also included a code example that will hopefully help make sense of it.
I'm absolutely aware this is quite complex but unfortunately when not
using our official iOS SDK the process is quite involved, and as of
right now we don't have any official support for cross-platform
technologies like Ionic or React Native.
You must have an apple developer account, a merchant id and have a payment processing certificate uploaded to stripe (see steps 1->3 of https://stripe.com/docs/apple-pay#native)
You can use the cordova plugin (https://github.com/samkelleher/cordova-plugin-applepay#example-response) to generate an apple pay token. This will then be submitted to the V1 stripe API and exchanged for a Stripe Token. This is how Stripe's official IOS SDK works by tokenizing the PKPayment object in to a Stripe Token.
The paramaters to pass to the end point (not in the documentation) are;
pk_token (the string that you get from base64 decoding the
paymentData)
pk_token_payment_netowrk (paymentMethodNetwork)
pk_token_instrument_name (paymentMethodDisplayName)
pk_token_transaction_id (transactionIdentifier)
The names in the brackets are what is returned when using the cordova plugin.
Once you call this endpoint, you should get back a standard Stripe
token object(but the request will fail if you haven't registered your
Apple Pay payment processing cert as mentioned above). The Stripe
token(tok_xxx) can be used for payments as normal — the easiest way is
to convert it to a PaymentMethod by calling /v1/payment_methods with
type=card&card[token]=tok_xxxx , and then using it to confirm a
PaymentIntent.
Code Example
completeApplePay(resp){
const _this = this;
return new Promise((resolution, rejection) => {
$.post({
url: 'https://api.stripe.com/v1/tokens',
beforeSend: function (xhr) {
xhr.setRequestHeader("Authorization", "Bearer pk_test_xxxxxxxxxxxxxxxx")
},
data: {
pk_token: atob(resp.paymentData),
pk_token_payment_network: resp.paymentMethodNetwork,
pk_token_instrument_name: resp.paymentMethodDisplayName,
pk_token_transaction_id: resp.transactionIdentifier
},
success: function (data) {
resolution({
token: data.id
});
}
});
});
}
The (resp) parameter in the function above is the response from the cordova plugin;
const applePayTransaction = await this.applePayController.makePaymentRequest(order).then(resp => {
this.stripe.completeApplePay(resp).then((stresp:any) => {
// code goes here to store order in database etc
})
});
await this.applePayController.completeLastTransaction('success');

Creating a YouTube Service via ASP.NET using a pre-existing Access Token

I've been working on a Website for users to upload videos to a shared YouTube account for later access. After much work I've been able to get an Active Token, and viable Refresh Token.
However, the code to initialize the YouTubeService object looks like this:
UserCredential credential;
using (var stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read))
{
credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
// This OAuth 2.0 access scope allows an application to upload files to the
// authenticated user's YouTube channel, but doesn't allow other types of access.
new[] { YouTubeService.Scope.YoutubeUpload },
"user",
CancellationToken.None
);
}
var youtubeService = new YouTubeService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = Assembly.GetExecutingAssembly().GetName().Name,
});
I've already got a token, and I want to use mine. I'm using ASP.NET version 3.5, and so I can't do an async call anyways.
Is there any way I can create a YouTubeService object without the async call, and using my own token? Is there a way I can build a credential object without the Authorization Broker?
Alternatively, the application used YouTube API V2 for quite some time, and had a form that took a token, and did a post action against a YouTube URI that was generated alongside the token in API V2. Is there a way I can implement that with V3? Is there a way to use Javascript to upload videos, and possibly an example that I could use in my code?
NOTE: I ended up upgrading my Framework to 4.5 to access the google libraries.
To programatically initialize a UserCredential Object you've got to build a Flow, and TokenResponse. A Flow Requires a Scope (aka the permissions we are seeking for the credentials.
using Google.Apis.Auth.OAuth2;
using Google.Apis.Auth.OAuth2.Responses;
using Google.Apis.Auth.OAuth2.Flows;
string[] scopes = new string[] {
YouTubeService.Scope.Youtube,
YouTubeService.Scope.YoutubeUpload
};
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = new ClientSecrets
{
ClientId = XXXXXXXXXX, <- Put your own values here
ClientSecret = XXXXXXXXXX <- Put your own values here
},
Scopes = scopes,
DataStore = new FileDataStore("Store")
});
TokenResponse token = new TokenResponse {
AccessToken = lblActiveToken.Text,
RefreshToken = lblRefreshToken.Text
};
UserCredential credential = new UserCredential(flow, Environment.UserName, token);
Hope that helps.
Currently the official Google .NET client library does not work with .NET Framework 3.5. (Note: this is an old question the library hasn't supported .NET 3.5 since 2014. So the statement would have been valid then as well.) That being said you are not going to be able to create a service for the Google .NET client library using an existing access token. Also not possible to create it with an access token using any .NET Framework you would need to create your own implementation of Idatastore and load a refresh token.
Supported Platforms
.NET Framework 4.5 and 4.6
.NET Core (via netstandard1.3 support)
Windows 8 Apps
Windows Phone 8 and 8.1
Portable Class Libraries
That being said you are going to have to code this yourself from the ground up. I have done it and it is doable.
Authentication :
You have stated you have your refresh token already so I won't go into how to create that.
The following is a HTTP POST call
Refresh access token request:
https://accounts.google.com/o/oauth2/token
client_id={ClientId}.apps.googleusercontent.com&client_secret={ClientSecret}&refresh_token=1/ffYmfI0sjR54Ft9oupubLzrJhD1hZS5tWQcyAvNECCA&grant_type=refresh_token
Refresh Access token response:
{ "access_token" : "ya29.1.AADtN_XK16As2ZHlScqOxGtntIlevNcasMSPwGiE3pe5ANZfrmJTcsI3ZtAjv4sDrPDRnQ", "token_type" : "Bearer", "expires_in" : 3600 }
An call you make to the YouTube API you can either add the access token as the authorization bearer token or you can just take it on to the end of any request
https://www.googleapis.com/youtube/v3/search?access_token={token here}
I have a full post on all of the calls to the auth server Google 3 legged Oauth2 flow. I just use normal webRequets for all my calls.
// Create a request for the URL.
WebRequest request = WebRequest.Create("http://www.contoso.com/default.html");
// If required by the server, set the credentials.
request.Credentials = CredentialCache.DefaultCredentials;
// Get the response.
WebResponse response = request.GetResponse();
// Display the status.
Console.WriteLine (((HttpWebResponse)response).StatusDescription);
// Get the stream containing content returned by the server.
Stream dataStream = response.GetResponseStream();
// Open the stream using a StreamReader for easy access.
StreamReader reader = new StreamReader(dataStream);
// Read the content.
string responseFromServer = reader.ReadToEnd();
// Display the content.
Console.WriteLine(responseFromServer);
// Clean up the streams and the response.
reader.Close();
response.Close();
Upgrade .NET 4+
If you can upgrade to the newest version of .NET using the library will be much easier. This is from Googles official documentation Web Applications ASP.NET. I have some additional sample code on my github account which shoes how to use the Google Drive API. Google dotnet samples YouTube data v3.
using System;
using System.Web.Mvc;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Auth.OAuth2.Flows;
using Google.Apis.Auth.OAuth2.Mvc;
using Google.Apis.Drive.v2;
using Google.Apis.Util.Store;
namespace Google.Apis.Sample.MVC4
{
public class AppFlowMetadata : FlowMetadata
{
private static readonly IAuthorizationCodeFlow flow =
new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = new ClientSecrets
{
ClientId = "PUT_CLIENT_ID_HERE",
ClientSecret = "PUT_CLIENT_SECRET_HERE"
},
Scopes = new[] { DriveService.Scope.Drive },
DataStore = new FileDataStore("Drive.Api.Auth.Store")
});
public override string GetUserId(Controller controller)
{
// In this sample we use the session to store the user identifiers.
// That's not the best practice, because you should have a logic to identify
// a user. You might want to use "OpenID Connect".
// You can read more about the protocol in the following link:
// https://developers.google.com/accounts/docs/OAuth2Login.
var user = controller.Session["user"];
if (user == null)
{
user = Guid.NewGuid();
controller.Session["user"] = user;
}
return user.ToString();
}
public override IAuthorizationCodeFlow Flow
{
get { return flow; }
}
}
}
Top tip YouTube doesn't support service accounts your going to have to stick with Oauth2. As long as you have authenticated your code once it should continue to work.

Retrieving an object/resource from a URL

I recently started using Google Apps Script to automate some Google Analytics reporting tasks. Many objects returned by Google Analytics Services have 'get' functions that return a URL in the form of a string. Actually, many Google Apps Script objects have functions that return these resource URLs, not just Google's Analytics Services. The indication is that I can somehow use these URLs to reference Google Apps resources and get objects in return, but I don't know how.
I tried simply loading one of these URLs in a browser expecting JSON or something else I could use, but received a 404 error instead. The same happened when I tried requesting the URL using a Google Apps Script UrlFetchApp.
Here's a simple example:
var accountId = '0123456789'; // Pretend this is a valid account number
// Get the first WebProperty
var webProp = Analytics.Management.Webproperties.list(accountId).getItems()[0];
// ...getHref() is along the lines of "https://www.googleapis.com/analytics/v3/management/accounts/0123456789"
var parentHref = webProp.getParetLink().getHref();
The question is, what do I do with parentHref to get an Analytics Account object back? I feel like I'm missing something that should be fairly basic...
Resources:
Google Apps Script Reference for Analytics Services
Read Using OAuth 2.0 to Access Google APIs, will help you get what you need.
I add a very basic code that can serve as a guide.
/* CODE FOR DEMONSTRATION PURPOSES */
function authorizeGAS() {
var result = false;
var oauthConfig = UrlFetchApp.addOAuthService("google");
oauthConfig.setAccessTokenUrl("https://www.google.com/accounts/OAuthGetAccessToken");
oauthConfig.setRequestTokenUrl("https://www.google.com/accounts/OAuthGetRequestToken?" +
"scope=https://www.googleapis.com/auth/analytics.readonly");
oauthConfig.setAuthorizationUrl("https://www.google.com/accounts/OAuthAuthorizeToken");
oauthConfig.setConsumerKey(ScriptProperties.getProperty("YOUR_ANALYTICS_CONSUMER_KEY"));
oauthConfig.setConsumerSecret(ScriptProperties.getProperty("YOUR_ANALYTICS_CONSUMER_SECRET"));
var requestData = {
"method": "GET",
"oAuthServiceName": "google",
"oAuthUseToken": "always"
};
var URL = "https://www.googleapis.com/analytics/v3/management/accounts/~all/webproperties/~all/profiles";
try {
result = JSON.parse(UrlFetchApp.fetch(URL, requestData).getContentText());
} catch (e) {
if (e.message) Logger.log(e.message);
}
Logger.log(result);
return result;
}
It's not about activating the API. It's obviously active since he is already getting analytics data.
You can't just urlfetch those URLs, because you are missing the OAuth-related code that goes with calling a URL that requires authentication and permission.

Is it possible to use the Yahoo BOSS OAuth with JavaScript only?

Here is the problem, I have a Google Chrome extension and I want to use the BOSS API in it. The problem is that I do not know if it is possible to use the API without a webserver running.
The documentation does not provide any example using JavaScript. Thus my question:
Is it possible to use the Yahoo BOSS OAuth with JavaScript only?
Probably not...
All the examples Yahoo provides are using server side languages
http://developer.yahoo.com/boss/search/boss_api_guide/codeexamples.html
First you'd have to figure out how to use OAuth with JavaScript, and how will you obscure your API keys from users in a JS File? If you don't have to worry about that, say you are just using this for personal use. Maybe check out the code sample for Node.JS and modify it for your own uses.
http://developer.yahoo.com/boss/search/boss_api_guide/codeexamples.html#oauth_js
function yahooSearch(consumerKey, consumerSecret, query, count,
callback_error_data_response){
var webSearchUrl = 'https://yboss.yahooapis.com/ysearch/web';
var finalUrl = webSearchUrl + '?' + qs.stringify({
q: query, //search keywords
format: 'json',
count: count,
});
var oa = new OAuth(webSearchUrl, webSearchUrl, consumerKey, consumerSecret, "1.0", null, "HMAC-SHA1");
oa.setClientOptions({ requestTokenHttpMethod: 'GET' });
oa.getProtectedResource(finalUrl, "GET", '','', callback_error_data_response);
}
// Use this function to make a call back. Make sure to provide the right key, secret and query for this to work correctly yahooSearch('YAHOO CONSUMER KEY GOES HERE', 'YAHOO CONSUMER SECRET GOES HERE', 'SEARCH QUERY', 10, function(error, data, response){
// enter some code here and access the results from the "data" variable in JSON format
});
You can go to YQL Console and then enter your request, you can select Json or XML, after your result is fetched, look at the bottom of the page and then copy the url. You will be able to use that url inside script tags in an html doc and run it with your browser without a server.

OAuth 2.0 for Server to Server Applications using JavaScript

I have been working with Google-bigquery and JavaScript for a little time now, after getting some help here, something i realised is that the you require your Google login details associated with the project to authorise and achieve what your trying to do.
What i am trying to achieve:-
Allow users to visit my page, and view the data. For example i may show some public data based on weather forecast, so i do not require any users authentication,
Currently for research & development purposed i am using I am using OAuth 2.0 for Web Server Applications, i want to get rid of this as we don't need any user data, apart from having my project client-id email-id etc...
I have read on OAuth 2.0 for Server to Server Applications, and there don't seem to be any support for JavaScript so the end-user doesn't have to be involved.
Is there any solution to this or a safe quick fix, i have tried changing the config code from this sample to see what happens but no luck -
var config = {
'client_id' : 'xxxxxxxxxxx.apps.googleusercontent.com',
"iss" : "xxxxxxxxxxxxxxxxxxxxxxxxxx#developer.gserviceaccount.com",
"scope" : "https://www.googleapis.com/auth/bigquery",
"aud" : "https://accounts.google.com/o/oauth2/token",
"exp" : 1328554385,
"iat" : 1328550785
};
What am i missing in here.
Thanks in advance for any help and advice, i have been struggling for a very loong time with this.
Because there is no way to hide a client secret in client-side JavaScript code, there is no way to authorize a client-side JavaScript application to use BigQuery via a server-to-server OAuth flow.
The only solution in this case is to use a server side proxy for your API calls from the JavaScript application. Here's a snippet below of how you could proxy query calls via AppEngine (note: the code below is open to any user, it does do any check to make sure the calls are being run through your particular JavaScript client).
import httplib2
from apiclient.discovery import build
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from oauth2client.appengine import AppAssertionCredentials
# BigQuery API Settings
SCOPE = 'https://www.googleapis.com/auth/bigquery'
PROJECT_ID = 'XXXXXXXXXX' # REPLACE WITH YOUR Project ID
# Create a new API service for interacting with BigQuery
credentials = AppAssertionCredentials(scope=SCOPE)
http = credentials.authorize(httplib2.Http())
bigquery_service = build('bigquery', 'v2', http=http)
class StartQueryHandler(webapp.RequestHandler):
def post(self):
query_string = self.request.get('query')
jobCollection = bigquery_service.jobs()
jobData = {
'configuration': {
'query': {
'query': query_string,
}
}
}
try:
insertResponse = jobCollection.insert(projectId=PROJECT_ID,
body=jobData).execute()
self.response.headers.add_header('content-type',
'application/json',
charset='utf-8')
self.response.out.write(insertResponse)
except:
self.response.out.write('Error connecting to the BigQuery API')
class CheckQueryHandler(webapp.RequestHandler):
def get(self, job_id):
query_job = bigquery_service.jobs()
try:
queryReply = query_job.getQueryResults(projectId=PROJECT_ID,
jobId=job_id).execute()
self.response.headers.add_header('content-type',
'application/json',
charset='utf-8')
self.response.out.write(queryReply)
except:
self.response.out.write('Error connecting to the BigQuery API')
application = webapp.WSGIApplication(
[('/startquery(.*)', StartQueryHandler),
('/checkquery/(.*)', CheckQueryHandler)],
debug=True)
def main():
run_wsgi_app(application)
if __name__ == "__main__":
main()

Categories