MoreRSS

site iconDigital InspirationModify

Written by Amit Agarwal. The purpose of the site is to help you take maximum advantage of the software tools and web technologies at your disposal.
Please copy the RSS to your reader, or quickly subscribe to:

Inoreader Feedly Follow Feedbin Local Reader

Rss preview of Blog of Digital Inspiration

Create a Keyboard Shortcut for Apple Intelligence Writing Tools on Mac

2024-11-04 02:30:00

The recent release of Apple Intelligence has added a new set of helpful AI writing tools to your Mac. You can proofread emails, summarize documents and, the most useful of all, rewrite emails in professional or casual tone. You can access the writing tools wherever you type text on your Mac - in the Mail app, Gmail, Safari browser, and any other text editor.

Apple Intelligence is available on Macs running macOS Sequoia 15.1 and the device language is set to US English. The built-in AI integration means you can enhance your writing directly in your current app, without jumping back and forth between ChatGPT or Copilot in a separate window.

Apple Intelligence Writing Tools

To access the AI writing tools inside your current app, you can select the text you want to edit, right-click and select Writing Tools > Show Writing Tools from the context menu.

Launch AI Writing Tools with a Keyboard Shortcut

If you prefer to use a keyboard shortcut to launch the writing tools on your Mac, here’s how you can do it.

  1. Launch the Settings app on your Mac and select Keyboard. Click the Keyboard Shortcuts button.

Keyboard Shortcuts

  1. Go to the App Shortcuts section and click the + button to create a new shortcut.

Add Show Writing Tools Shortcut

  1. In the Menu Title field, enter Show Writing Tools while the Application field is set to All applications. In the Keyboard Shortcut field, press Command Shift . (period key). Click Add.

Show Writing Tools Shortcut

That’s it. Restart your current app and select the text you want to edit. Press Command Shift . to launch the writing tools without touching the mouse.

How to Generate Software License Keys and Verify Them

2024-10-07 02:30:00

You are running a small software business that sells digital downloads - apps, plugins, or even templates. When the buyer completes the purchase, you need to provide them with a license key that they can use to activate and validate the software.

Here’s how you can implement such a licensing system in your software:

  1. Generate a public and private key pair using the RSA algorithm.
  2. Sign a message with the private key. The message contains the buyer’s email address and the software SKU.
  3. The signed message is the license key that is sent back to the buyer’s email address.
  4. When the buyer activates the software, the license key is verified using the public key.

The Advantages

The advantage here is that the public key can be included in the software’s source code, there’s no need to use a database, and the buyer can verify the license key offline without the need to connect to your server.

Let’s now go through the implementation steps in detail.

1. Generate Public and Private Key Pair

RSA Private and Public Keys

We’ll generate a public and private key pair using the RSA algorithm. Launch the terminal and run the following openssl command.

openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out private_key.pem

It will generate a 2048-bit RSA private key and save it to a file called private_key.pem in the current folder. Next, we’ll write a command to generate a public key from the private key.

openssl rsa -pubout -in private_key.pem -out public_key.pem

Now that we have our keys, let’s print them to the console as we’ll need them in the next step.

openssl pkey -in private_key.pem && openssl pkey -pubin -in public_key.pem

2. Generate a License Key

We’ll write a simple Node.js script to generate a license key. It uses the crypto module to sign the message with the private key and the fs module to read the private key from the file system.

const crypto = require('crypto');
const fs = require('fs');

// Read private key from file system
const privateKey = fs.readFileSync('private_key.pem', 'utf8');

const buyerEmailAddress = '[email protected]';
const data = Buffer.from(buyerEmailAddress);

const signature = crypto.sign('sha256', data, {
  key: privateKey,
  padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
});

// Convert the signature to base64
const licenseKey = signature.toString('base64');

// Output the result
console.log(licenseKey);

3. Verify a License Key

The license key generated in the previous step is sent to the buyer’s email address and we need to verify it when the buyer activates the software.

This again is a simple Node.js script that uses the crypto module to verify the license key with the public key.

const crypto = require('crypto');
const fs = require('fs');

const buyerEmailAddress = '<<buyer email address>>';
const licenseKey = '<<license key>>';

const publicKey = fs.readFileSync('public_key.pem', 'utf8');
const signatureBuffer = Buffer.from(licenseKey, 'base64');

const licenseStatus = crypto.verify(
  'sha256',
  Buffer.from(buyerEmailAddress),
  {
    key: Buffer.from(publicKey),
    padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
  },
  signatureBuffer
);

console.log(licenseStatus ? 'Activated' : 'Invalid license key');

License Activation in Google Apps Script

If you are planning to include activation inside Google Workspace add-ons, you can build a Google Cloud Function or a Google Cloud Run service to handle the license activation.

Your Apps Script code can make a UrlFetch POST request to the web service with the license key and get back the activation status. In such a case, the public key need not be embedded in the script. Also, the user’s email address can be easily retrieved using the Session.getActiveUser().getEmail() method.

The Limitations

This is obviously a basic implementation of a software licensing system that doesn’t handle all the edge cases. It can be a starting point but there are many other things to consider like:

  • How to set expiration dates for the license keys.
  • How to revoke a license key.
  • How to prevent key sharing between users.

How to Accept Online Payments with Zoho Payments

2024-10-05 02:30:00

Zoho Payments is a new payment gateway that lets you accept payments on your website. You can visit this sample store to see the Zoho Payments widget in action.

Zoho Payments

Unlike Stripe or RazorPay which are more mature payment gateways, Zoho Payments only supports domestic payments in INR (₹). In the initial release, merchants can only accept one-time payments and customers can pay you with UPI, Net Banking, and Credit Cards.

The onboarding process is simple and, once you have uploaded your KYC documents, your account is approved within few business days. There’s no transaction fee for UPI payments while credit card transactions are subject to a 2% fee (excluding GST)

How to Accept Payments with Zoho Payments

In this tutorial, we’ll create a simple payment page in Google Apps Script and accept payments on our website using Zoho Payments.

Zoho Payments - Account ID and API Key

Assuming that you have signed up for Zoho Payments, you can visit the dashboard to find your “Account ID”. Next, go to Settings > Developer Space to find your “API Key”.

Setting up the Google Apps Script

Open the Google Script project and make a copy in your Google Drive.

Copy Google Apps Script

Inside the Apps Script editor, go to function dropown and select printZohoPaymentsRedirectUrl. Run the script and you should see a URL in the console window.

Go to your Zoho API Console api-console.zoho.in and add a new client. Set the Client Type to Server-based Applications and paste the Redirect URL from the previuos step in the Authorized Redirect URLs field. Give your application a name like MyPaymentsApp and click on Create. Make a note of the Client ID and Client Secret as we’ll need them in the next step.

Zoho API Console

Go back to the Apps Script editor and paste the Client ID and Client Secret in the corresponding variables. You will also need to paste your Account ID and API Key in the code.

Next, run the printZohoPaymentsAuthUrl function to generate the authorization URL. Open the URL in a new tab, allow the app to access your Zoho Payments data and you should see a success message. We are limiting the scope of the application to ZohoPay.payments.CREATE so that our application can only create payments but not read or update any other data.

Once the application is authorized, click the Deploy button and select New Deployment. Select the type as Web app, set the Execute as to Me and Who has access to Anyone. Click on Deploy and you will get the URL of your web payments page. Anyone can now make a payment by visiting this URL.

The Techical Details

The app uses the OAuth2 library to handle the authorization process and generate the access token for connecting to the Zoho Payments API.

const getZohoPaymentsService_ = () => {
  return OAuth2.createService(ZOHO_SERVICE_NAME)
    .setAuthorizationBaseUrl('https://accounts.zoho.in/oauth/v2/auth')
    .setTokenUrl('https://accounts.zoho.in/oauth/v2/token')
    .setClientId(ZOHO_PAYMENTS_CLIENT_ID)
    .setClientSecret(ZOHO_PAYMENTS_CLIENT_SECRET)
    .setCallbackFunction('zohoOauthCallback')
    .setPropertyStore(PropertiesService.getScriptProperties())
    .setCache(CacheService.getScriptCache())
    .setParam('response_type', 'code')
    .setScope('ZohoPay.payments.CREATE')
    .setParam('access_type', 'offline')
    .setParam('prompt', 'consent');
};

The createZohoPaymentSession function is used to create a new payment session. It takes the amount as a parameter and returns the payment session details which are then passed to the Zoho Payments widget on the client side.

const createZohoPaymentSession = (amount) => {
  const service = getZohoPaymentsService_();
  const baseUrl = 'https://payments.zoho.in/api/v1';
  const apiUrl = `${baseUrl}/paymentsessions?account_id=${ZOHO_PAYMENTS_ACCOUNT_ID}`;
  const response = UrlFetchApp.fetch(apiUrl, {
    method: 'post',
    payload: JSON.stringify({ amount, currency: 'INR' }),
    headers: {
      Authorization: `Zoho-oauthtoken ${service.getAccessToken()}`,
      'Content-Type': 'application/json',
    },
    muteHttpExceptions: true,
  });
  const result = JSON.parse(response.getContentText());
  const { message, payments_session } = result;
  return message === 'success'
    ? {
        account_id: ZOHO_PAYMENTS_ACCOUNT_ID,
        api_key: ZOHO_ACCOUNT_API_KEY,
        merchant_name: ZOHO_MERCHANT_NAME,
        session_id: payments_session.payments_session_id,
        order_amount: payments_session.amount,
      }
    : { error: message };
};

You can find the complete code on GitHub.

Zoho Payments

How to Export WooCommerce Customers to Google Sheets

2024-10-03 02:30:00

If you are running an online store running on WordPress, chances are you are using WooCommerce to manage your customers and orders. The holiday season in near and you may want to send your existing customers a special discount code for their next purchase. Or you may want to analyze your store’s data to see how your business is performing in various regions.

You can the built-in export feature of WooCommerce to export your customers data to a CSV file and then import the CSV file into Google Sheets. Go to your WooCommerce dashboard, navigate to the Customers section, and you’ll find an option to download the customers list as a CSV file.

If you are however looking for a more efficient way to export your WooCommerce customers to Google Sheets, you can use Google Apps Script to create a custom script that will export the customers to a Google Sheet.

Step 1: Create an API Key in WooCommerce

To get started, you’ll create an API key in WooCommerce. Go to your WooCommerce dashboard, navigate to the Settings section, and then click on the “Advanced” tab. Go to the “Rest API” section and click on the “Create API Key” button.

WooCommerce API Key

On the next screen, you’ll be asked to enter a name for the API key. You can use a name like “Import Customers to Google Sheets” or something similar. You can restrict the API key permissions to read only, which is all we need since we’re only going to be reading customer data and not modifying any data.

WooCommerce Read Permissions

WooCommerce will generate the consumer key and consumer secret for you. You’ll need to save the secret key somewhere, as you won’t be able to access it later from the WooCommerce dashboard.

WooCommerce Consumer Key and Secret

Step 2: Create a Google Sheet

Now that you have your WooCommerce credentials, let’s create a Google Sheet to store the customer data. Type sheets.new in your browser’s address bar to create a new spreadsheet. Go to Extensions > Apps Script to open the Google Apps Script editor associated with your spreadsheet.

Paste the following code into the Apps Script editor. Remember to replace the WooCommerce consumer key, consumer secret and WordPress domain with your own values. Do not add a slash at the end of the WordPress domain.

const MAX_PER_PAGE = 100;
const CONSUMER_KEY = '<<YOUR_CONSUMER_KEY>>';
const CONSUMER_SECRET = '<<YOUR_CONSUMER_SECRET>>';
const WORDPRESS_DOMAIN = '<<YOUR_WORDPRESS_DOMAIN>>';

const fetchWooCommerceCustomers = () => {
  const bearerToken = Utilities.base64Encode(`${CONSUMER_KEY}:${CONSUMER_SECRET}`);

  const getQueryString = (options) => {
    return Object.keys(options)
      .map((key) => `${key}=${options[key]}`)
      .join('&');
  };

  const getApiUrl = (pageNum) => {
    const options = {
      context: 'view',
      page: pageNum,
      per_page: MAX_PER_PAGE,
      order: 'desc',
      orderby: 'id',
      role: 'customer',
    };
    return `${WORDPRESS_DOMAIN}/wp-json/wc/v3/customers?${getQueryString(options)}`;
  };

  // Fetches a single page of customer data.
  const fetchPage = (pageNum) => {
    const url = getApiUrl(pageNum);
    const response = UrlFetchApp.fetch(url, {
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Basic ${bearerToken}`,
      },
    });

    return JSON.parse(response.getContentText());
  };

  let page = 1;
  let allCustomers = [];
  let hasMore = true;

  do {
    const customers = fetchPage(page);
    allCustomers = allCustomers.concat(customers);
    page += 1;
    hasMore = customers.length === MAX_PER_PAGE;
  } while (hasMore === true);

  return allCustomers;
};

The above script will fetch all the customers from your WooCommerce store. Next, we’ll add a function to flatten the customer data and store it in a Google Sheet.

Step 3: Flatten the Customer Data

To flatten the customer data, we’ll add the following function to the script.

const parseCustomer = (customer) => {
  const { id, first_name, last_name, email, billing = {} } = customer;
  return {
    customer_id: id,
    first_name,
    last_name,
    customer_email: email,
    billing_first_name: billing.first_name,
    billing_last_name: billing.last_name,
    billing_email: billing.email,
    billing_phone: billing.phone,
    billing_address_1: billing.address_1,
    billing_address_2: billing.address_2,
    billing_city: billing.city,
    billing_state: billing.state,
    billing_postcode: billing.postcode,
    billing_country: billing.country,
  };
};

Step 4: Store the Customer Data

To store the customer data in a Google Sheet, we’ll add the following function to the script.

const exportCustomersToGoogleSheet = () => {
  const wooData = fetchWooCommerceCustomers();
  const customers = wooData.map(parseCustomer);
  const headers = Object.keys(customers[0]);
  const rows = customers.map((c) => headers.map((header) => c[header] || ''));
  const data = [headers, ...rows];
  const sheet = SpreadsheetApp.getActiveSpreadsheet().insertSheet();
  sheet.getRange(1, 1, data.length, data[0].length).setValues(data);
  const message = rows.length + ' customers exported to sheet ' + sheet.getName();
  SpreadsheetApp.getUi().alert(message);
};

Step 5: Run the Export Function

Inside the Apps Script editor, click on the “exportCustomersToGoogleSheet” function and then click on the “Run” button. Authorize the script and watch as your customers data from WooCommerce magically appears in your Google Sheet.

You can then use Gmail Mail Merge to send personalized emails to your customers right inside the Google Sheet.

How to Rollback Changes to a Specific Commit in Github

2024-09-04 02:30:00

Let’s say you have a Github repository where you push all your code changes. Each commit has a unique commit hash, and you can use this hash to restore the code to a specific commit or a particular time.

It is advisable that you take a backup of your current code before proceeding.

Find the Commit Hash

To get started, open your repository on Github and find the commit you want to restore. You can do this by clicking on the “Commits” tab and finding the commit in the list. If you want to restore to a particular date, you can use the calendar dropdown to see all the commits for that day and find the one you want.

Github Commit Hash

You may also use the command line to find the commit hash.

git log --oneline

Once you have found the commit you want to restore, you can create a new branch at that commit. Let’s call this branch working-branch.

git checkout -b working-branch <commit-hash>

This git command will create a new branch named working-branch pointing to the specified commit and switches to that branch.

Next, you can force push the new branch to the remote repository.

git push -f origin working-branch

Rollback to a Specific Commit

Now that you have a new branch with the code at the specific commit, you can update the main branch to this restored state.

git checkout main
git reset --hard working-branch
git push -f origin main

⚠️ Please be careful when using these git commands since it will permanently delete all code changes made after the commit you are restoring.

How to Convert Google Slides to PNG Images with Google Script

2024-07-16 02:30:00

Document Studio can convert Google Slides into high-resolution PNG images. This can be useful if you want to create multiple variations of the same slide in bulk - create a single template in Google Slides and then use Document Studio to generate PNG images with different text or images, pulled from a Google Sheet or Google Forms.

Internally, the app uses the Google APIs to generate high-resolution thumbnail images of the slides and uploads the individual slides to the Google Drive of the current user.

In this tutorial, we’ll explore two methods to achieve the slide-to-png conversion using Google Apps Script.

Approach #1 - Use the Google Slides API

You can use the Google Slides API to get the thumbnail images of the slides, fetch the blob of the image, and then upload the image to Google Drive.

const generateSlideScreenshot = () => {
  const presentation = SlidesApp.getActivePresentation();
  const presentationId = presentation.getId();
  // Get the object ID of the first slide in the presentation
  const pageObjectId = presentation.getSlides()[0].getObjectId();
  const apiUrl = `https://slides.googleapis.com/v1/presentations/${presentationId}/pages/${pageObjectId}/thumbnail`;
  const apiUrlWithToken = `${apiUrl}?access_token=${ScriptApp.getOAuthToken()}`;

  // The thumbnail image URL is in the response
  const request = UrlFetchApp.fetch(apiUrlWithToken);
  const { contentUrl } = JSON.parse(request.getContentText());

  // The thumbnail image width of 1600px.
  const blob = UrlFetchApp.fetch(contentUrl).getBlob();
  DriveApp.createFile(blob).setName('image.png');
};

Limitations

There are a few limitations with the previous approach.

First, you would need to enable Google Slides API in the console of your Google Cloud project associated with the Google Apps Script project. Second, the thumbnail images has a fixed width of 1600px/800px/200px and you cannot change the size of the image.

Also, you need to make two API calls here. The first one is to get the thumbnail link of the presentation. The additional API call will fetch the thumbnail image from the URL.

Approach #2 - Use the Google Drive API

The recommended approach is to use the Google Drive API to export the slides as PNG images. The big advantage here is that the generated image is of the same resolution as the original slide. So if you have set your presentation page size as 600x800 pixels, the generated PNG image will also be of the same size.

And there’s one less API call to make since the Drive API can directly export the slide as an image.

const generateSlideScreenshotWithDrive = () => {
  const presentation = SlidesApp.getActivePresentation();
  const id = presentation.getId();
  const pageid = presentation.getSlides()[0].getObjectId();

  const apiUrl = `https://docs.google.com/presentation/d/${id}/export/png?id=${id}&pageid=${pageid}`;
  const parameters = {
    method: 'GET',
    headers: { Authorization: `Bearer ${ScriptApp.getOAuthToken()}` },
    contentType: 'application/json',
  };

  const request = UrlFetchApp.fetch(apiUrl, parameters);
  const blob = request.getBlob();
  DriveApp.createFile(blob).setName('image.png');
};

Also see: Convert Google Docs and Sheets