الدمج من جهة الخادم

يستخدم الناشرون بشكل أساسي الدمج من جهة الخادم لإدارة القرّاء المعلومات والواجبات. يستخدم الناشرون UpdateReaderEntitlements بشكل أساسي للتحديث سجلّ Google الخاص باستحقاق استخدام معرّف المنتج للمعرّف المقدَّم من الناشر (PPID)

إعداد Google Cloud

يشتمل إعداد ميزة "ربط الاشتراكات" في Google Cloud على مكوّنَين رئيسيَّين:

  1. تمكين واجهة برمجة التطبيقات لمشروع معين
  2. إنشاء حساب خدمة للوصول إلى واجهة برمجة التطبيقات

تفعيل واجهة Subscription Linking API

لاستخدام حساب خدمة وإدارة أذونات القارئ، يجب إنشاء حساب على Google Cloud أن يتضمن المشروع كلاً من Subscription Linking API مفعَّلًا وأن حساب خدمة OAuth المهيأ. لتفعيل واجهة Subscription Linking API المشروع، انتقل من القائمة -> واجهات برمجة التطبيقات الخدمات -> المكتبة والبحث عن Subscription Linking، أو زيارة الصفحة مباشرةً:


https://console.cloud.google.com/apis/library?project=gcp_project_id

واجهة برمجة التطبيقات

الشكل 1. الانتقال إلى مكتبة واجهة برمجة التطبيقات وتفعيل واجهة برمجة التطبيقات المشروع على السحابة الإلكترونية.

إنشاء حساب للخدمة

يتم استخدام حسابات الخدمة للسماح بالوصول من تطبيقك إلى Subscription Linking API

  1. إنشاء حساب خدمة ضمن حساب مشروعك وحدة التحكم.
  2. إنشاء بيانات اعتماد لحساب الخدمة وتخزينه ملف credentials.json في مكان آمن يمكن لتطبيقك الوصول إليه.
  3. منح دور "إدارة الهوية وإمكانية الوصول" "مشرف ربط الاشتراكات" إلى حساب الخدمة الذي أنشأته. للتحكّم بدقة في إمكانات يمكنك تعيين الدور المناسب من الجدول التالي.
الإمكانات / الدور مشرف ربط الاشتراكات عارض ربط الاشتراكات عارِض أذونات ربط الاشتراكات
الحصول على أذونات القرّاء
الحصول على قرّاء
تعديل أذونات القرّاء
حذف القرّاء

استخدام حسابات الخدمة من خلال Subscription Linking API

استخدام حسابات الخدمة للمصادقة على الطلبات المرسَلة إلى Subscription Linking API إما من خلال مكتبة برامج Chrome أو من خلال توقيع الطلبات باستخدام REST API. تعالج مكتبات العملاء تلقائيًا طلب access_token مناسب، بينما تتطلب واجهة برمجة تطبيقات REST استرداد id_token ثم استبدِلها مقابل access_token.

كل من العميل التالي ومكتبة REST API تستخدم نقطة النهاية getReader(). بث مباشر شرحًا لجميع طرق واجهة برمجة التطبيقات، راجع الموقع الإلكتروني للعرض التوضيحي لربط الاشتراكات أو الرمز الخاص به

نموذج طلب باستخدام مكتبة برامج googleapis.js

import {readerrevenuesubscriptionlinking_v1, Auth} from 'googleapis';
const subscriptionLinking = readerrevenuesubscriptionlinking_v1.Readerrevenuesubscriptionlinking;

class SubscriptionLinking {
  constructor() {
    this.auth = new Auth.GoogleAuth({
      keyFile: process.env.KEY_FILE,
      scopes: [
        'https://www.googleapis.com/auth/readerrevenue.subscriptionlinking.manage'
      ],
    })
  }

  init() {
    return new subscriptionLinking(
        {version: 'v1', auth: this.auth})
  }
}

const api = new SubscriptionLinking();
const client = api.init();

async function getReader(ppid) {
  const publicationId = process.env.PUBLICATION_ID;
  return await client.publications.readers.get({
    name: `publications/${publicationId}/readers/${ppid}`,
  });
};

async function updateEntitlements(ppid) {
  const publicationId = process.env.PUBLICATION_ID;
  const requestBody = {
    /*
    Refer to
    https://developers.google.com/news/subscribe/subscription-linking/appendix/glossary#entitlements_object
    */
    entitlements : [{
      product_id: `${publicationId}:basic`,
      subscription_token: 'abc1234',
      detail: 'This is our basic plan',
      expire_time: '2025-10-21T03:05:08.200564Z'
    }]
  };
  return await client.publications.readers.updateEntitlements({
    name: `publications/${publicationId}/readers/${ppid}`,
    requestBody
  });
};

التوقيع يدويًا على طلبات واجهة برمجة التطبيقات REST API

import fetch from 'node-fetch'
import jwt from 'jsonwebtoken'

function getSignedJwt() {
  /*
    Either store the credentials string in an environmental variable
    Or implement logic to fetch it.
  */
  const key_file = process.env.CREDENTIALS_STRING

  const issueDate = new Date()
  const expireMinutes = 60
  const offsetInSeconds = issueDate.getTimezoneOffset() * 60000
  const expireDate = new Date(issueDate.getTime() + (expireMinutes * 60000))
  const iat = Math.floor((issueDate.getTime() + offsetInSeconds) / 1000)
  const exp = Math.floor((expireDate.getTime() + offsetInSeconds) / 1000)

  const token = {
    iss: key_file.client_email,
    iat,
    exp,
    aud: 'https://oauth2.googleapis.com/token',
    scope:'https://www.googleapis.com/auth/readerrevenue.subscriptionlinking.manage',
  }
  return jwt.sign(token, key_file.private_key, {
    algorithm: 'RS256',
    keyid: key_file.private_key_id,
  })
}

async function getAccessToken(signedJwt) {
  let body = new URLSearchParams();
  body.set('grant_type', 'urn:ietf:params:oauth:grant-type:jwt-bearer')
  body.set('assertion', signedJwt)
  const request = await fetch('https://oauth2.googleapis.com/token', {
    method: 'POST',
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    body
  })

  const accessResponse = await accessFetch.json()
  return accessResponse.access_token
}

async function getReader(ppid) {
  const publicationId = process.env.PUBLICATION_ID
  const base_url = 'https://readerrevenuesubscriptionlinking.googleapis.com/v1'
  const endpoint = `${base_url}/publications/${publicationId}/readers/${ppid}`
  const signedJwt = await getSignedJwt()
  const accessToken = await getAccessToken(signedJwt)

  const reader = await fetch(endpoint, {
     method: 'GET',
     headers: {
       Authorization: `Bearer ${accessToken}`,
     },
   }).then((response) => {
    return response.json()
  })

  return reader
}