お知らせ:

当社は、お客様により充実したサポート情報を迅速に提供するため、本ページのコンテンツは機械翻訳を用いて日本語に翻訳しています。正確かつ最新のサポート情報をご覧いただくには、本内容の英語版を参照してください。

アプリケーションのコーディング

アプリケーションのコーディングを始めましょう。

アプリケーションのバックエンドロジックは、LeadManager/ディレクトリ内のmain.pyファイルにコーディングします。

コードのフロントエンドは以下のように保存されます:

  • LeadManager/templates/ディレクトリに、以下のファイルを作成します:

    • index.html:アプリケーションのフロントエンドのHTMLコードを含みます。
    • login.html:アプリケーションのEmbedded Authenticationを有効にするHTMLコードを含みます。
  • LeadManager/static/ディレクトリに、以下のファイルを作成します:

    • main.css:アプリに必要なスタイリング要素を含みます。
    • main.js:フロントエンドとバックエンドを接続するJavaScriptコードを含みます。

以下がLeadManagerプロジェクトの最終的なフォルダ構造です: catalyst_tutorials_leadmanager_appsail_flask_final_dir

main.pyindex.htmllogin.htmlmain.css、およびmain.jsファイルをコーディングします。また、app-config.jsonファイルも更新します。

Note: このセクションのコードを十分に理解するために、コードをよく確認してください。

以下のコードをコピーして、IDEを使用してプロジェクトのそれぞれのファイルに貼り付けて保存してください。

main.py
copy
import sys
sys.path.insert(0, './myenv/lib/python3.9/site-packages')
from flask import Flask, request, jsonify, make_response, redirect
import os
import json
import logging
import requests
from flask.templating import render_template
import zcatalyst_sdk

app = Flask(name, static_url_path=’/’, static_folder=‘static’, template_folder=‘templates’)

API_BASE = “https://www.zohoapis.com/crm/v2" LEADS_URL = f”{API_BASE}/Leads" TOKEN_URL = “https://accounts.zoho.com/oauth/v2/token"

CLIENT_ID = os.environ.get(‘ZOHO_CLIENT_ID’) CLIENT_SECRET = os.environ.get(‘ZOHO_CLIENT_SECRET’)

logger = logging.getLogger()

def is_valid_record_id(record_id): return isinstance(record_id, str) and record_id.isdigit()

@app.route(’/’) def index(): return render_template(‘index.html’)

@app.route(’/index.html’) def indexhtml(): return render_template(‘index.html’)

@app.route(’/login.html’) def login(): return render_template(’login.html’)

@app.route(’/generateToken’, methods=[‘GET’]) def generateToken(): try: catalyst_app = zcatalyst_sdk.initialize(req=request) user_management_service = catalyst_app.authentication() datastore = catalyst_app.datastore() code = request.args.get(‘code’) user_details = user_management_service.get_current_user() user_id = user_details[“user_id”] is_local = os.getenv(‘X_ZOHO_CATALYST_IS_LOCAL’) == ’true’ protocol = ‘http’ if is_local else ‘https’ host = request.headers[‘host’] if is_local else request.headers[‘host’].split(’:’)[0] domain = f”{protocol}://{host}" logger.info(f’domain:{domain}’) tab = datastore.table(‘2113000000078743’) #Table IDに置き換えてください refresh_token = getRefreshToken(code, domain) logger.info(‘refresh_token retrieved successfully’) # トークンの値はログに出力しないでください row = {“refresh_token”: refresh_token, “userId”: user_id} tab.insert_row(row) redirect_uri = f"{domain}/index.html" return redirect(redirect_uri) except Exception as err: logger.error(f’Error on generateToken: {err}’) return make_response({ “message”: “Internal Server Error. Please try again after sometime.” }, 500)

@app.route(’/getUserDetails’, methods=[‘GET’]) def userDetails(): try: catalyst_app = zcatalyst_sdk.initialize(req=request) user_details = getUserId(catalyst_app) if len(user_details) != 0: user_id = user_details[0][“Token”][“userId”] else: user_id = None return make_response({“userId”: user_id}, 200) except Exception as err: logger.error(f’Error on getUserDetails: {err}’) return make_response({ “message”: “Internal Server Error in getting user details. Please try again after sometime.” }, 500)

@app.route(’/crmData’, methods=[‘GET’]) def crmData(): try: catalyst_app = zcatalyst_sdk.initialize(req=request) user_details = getUserId(catalyst_app) access_token = getAccessToken(user_details, catalyst_app) headers = { ‘Authorization’: f’Zoho-oauthtoken {access_token}’, “Content-Type”: “application/json” } api_response = requests.get(LEADS_URL, headers=headers) return make_response(jsonify(api_response.json()), 200) except Exception as err: logger.error(err) return make_response({ “message”: “Internal Server Error. Please try again after sometime.” }, 500)

@app.route(’/crmData’, methods=[‘POST’]) def postcrmData(): try: catalyst_app = zcatalyst_sdk.initialize(req=request) data = {“data”: [json.loads(request.data)]} user_details = getUserId(catalyst_app) access_token = getAccessToken(user_details, catalyst_app) headers = { ‘Authorization’: f’Zoho-oauthtoken {access_token}’, “Content-Type”: “application/json” } api_response = requests.post(LEADS_URL, headers=headers, json=data) if api_response.status_code in (200, 201): return make_response(api_response.json(), 200) logger.error(api_response.json()) return make_response(api_response.json(), 500) except Exception as err: logger.error(err) return make_response({ “message”: “Internal Server Error. Please try again after sometime.” }, 500)

@app.route(’/crmData/<id>’, methods=[‘GET’]) def getCRMData(id): if not is_valid_record_id(id): return make_response({“message”: “Invalid record ID”}, 400) try: catalyst_app = zcatalyst_sdk.initialize(req=request) user_details = getUserId(catalyst_app) access_token = getAccessToken(user_details, catalyst_app) headers = { ‘Authorization’: f’Zoho-oauthtoken {access_token}’, “Content-Type”: “application/json” } api_response = requests.get(f"{LEADS_URL}/{id}", headers=headers) return make_response(api_response.json(), 200) except Exception as err: logger.error(err) return make_response({ “message”: “Internal Server Error. Please try again after sometime.” }, 500)

@app.route(’/crmData/<id>’, methods=[‘PUT’]) def putcrmData(id): if not is_valid_record_id(id): return make_response({“message”: “Invalid record ID”}, 400) try: catalyst_app = zcatalyst_sdk.initialize(req=request) req_data = request.get_json() if req_data is None: return make_response({“message”: “Update data not found”}, 400) data = {“data”: [req_data]} user_details = getUserId(catalyst_app) access_token = getAccessToken(user_details, catalyst_app) headers = { ‘Authorization’: f’Zoho-oauthtoken {access_token}’, “Content-Type”: “application/json” } api_response = requests.put(f"{LEADS_URL}/{id}", headers=headers, json=data) return make_response(api_response.json(), 200) except Exception as err: logger.error(err) return make_response({ “message”: “Internal Server Error. Please try again after sometime.” }, 500)

@app.route(’/crmData/<id>’, methods=[‘DELETE’]) def deletelead(id): if not is_valid_record_id(id): return make_response({“message”: “Invalid record ID”}, 400) try: catalyst_app = zcatalyst_sdk.initialize(req=request) user_details = getUserId(catalyst_app) access_token = getAccessToken(user_details, catalyst_app) headers = { ‘Authorization’: f’Zoho-oauthtoken {access_token}’, “Content-Type”: “application/json” } api_response = requests.delete(f"{LEADS_URL}/{id}", headers=headers) return make_response(api_response.json(), 200) except Exception as err: logger.error(err) return make_response({ “message”: “Internal Server Error. Please try again after sometime.” }, 500)

def getRefreshToken(code, domain): if not code: raise ValueError(“Authorization ‘code’ is missing from the request”) if not CLIENT_ID or not CLIENT_SECRET: raise ValueError(“ZOHO_CLIENT_ID / ZOHO_CLIENT_SECRET environment variables are not set”) params = { ‘code’: code, ‘client_id’: CLIENT_ID, ‘client_secret’: CLIENT_SECRET, ‘grant_type’: ‘authorization_code’, ‘redirect_uri’: f"{domain}/generateToken" } response = requests.post(TOKEN_URL, params=params) try: data = response.json() except ValueError: logger.error(f’Token endpoint returned non-JSON (status {response.status_code}): {response.text}’) raise if ‘refresh_token’ not in data: logger.error(f’Token exchange failed: {data}’) raise ValueError(data.get(’error’, ‘refresh_token not returned by token endpoint’)) return data[‘refresh_token’]

def getAccessToken(userdetails, catalyst_app): user_id = userdetails[0][‘Token’][‘userId’] zcql = catalyst_app.zcql() query = f"Select refresh_token FROM Token where userId={user_id}" response = zcql.execute_query(query) refresh_token = response[0][‘Token’][‘refresh_token’] args = { “client_id”: CLIENT_ID, “client_secret”: CLIENT_SECRET, “auth_url”: TOKEN_URL, “refresh_url”: TOKEN_URL, “refresh_token”: refresh_token, } connector_service = catalyst_app.connection({user_id: args}) access_token = connector_service.get_connector(user_id).get_access_token() return access_token

def getUserId(catalyst_app): user = catalyst_app.authentication().get_current_user() user_id = user[“user_id”] return catalyst_app.zcql().execute_query( f"Select * from Token where userId = {user_id}" )

if name == ‘main’: port = int(os.environ.get(‘X_ZOHO_CATALYST_LISTEN_PORT’, 9000)) app.run(host=‘0.0.0.0’, port=port)

View more

Note:
  • Zoho APIコンソールでクライアントを登録した後に取得したClient IDClient Secretの値は、ZOHO_CLIENT_IDおよびZOHO_CLIENT_SECRET環境変数から読み込まれます。これらの値はソースファイルに直接記述せず、AppSailアプリケーションの環境変数として設定してください。

  • Data Storeで作成したテーブルのTable ID57行目に追加してください。

index.html
copy
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>CRM Lead Manager</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" type="text/css" media="screen" href="main.css" />
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
        integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
    <link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.0/css/bootstrap.min.css" rel="stylesheet">
    <link href="https://cdnjs.cloudflare.com/ajax/libs/mdbootstrap/4.19.1/css/mdb.min.css" rel="stylesheet">
    <script src="https://code.jquery.com/jquery-3.4.1.min.js"
        integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"> </script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
        integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous">
        </script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
        integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous">
        </script>
    <script src="main.js"> </script>
    <script src="https://static.zohocdn.com/catalyst/sdk/js/4.6.2/catalystWebSDK.js"> </script>
    <script src="/__catalyst/sdk/init.js"> </script>
    <link href="//maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
    <style>
        #connect {
            height: 260px;
            width: 500px;
            position: absolute;
            top: 0;
            bottom: 0;
            left: 0;
            right: 0;
            margin: auto;
        }
    </style>
</head>
<body onload="getUserDetails()">
    <br>
    <center>
        <h1>CRM Lead Manager</h1> <br>
    </center>
    <div id="connect">
        <center>
            <p>Click here to connect to Zoho CRM</p>
            <button onclick='navigate()'>
                <img src="https://www.zohowebstatic.com/sites/default/files/styles/product-home-page/public/icon-crm_blue.png"
                    style="width: 180px;height: 130px;">
            </button>
        </center>
    </div>
    <div style="width: 200px;float: right; margin-right: 30px;"> <label for="logoutbtn"
            class="btn btn-success btn-block btn-outlined">Logout</label>
        <button id="logoutbtn" onclick="logout()" style="display: none;"> </button>
    </div>
    <div id="main">
        <div class="container">
            <ul class="nav nav-tabs nav-justified mb-3" id="myTab" role="tablist">
                <li class="nav-item">
                    <a class="nav-link active" id="check-tab" data-toggle="tab" href="#check" role="tab"
                        aria-controls="check" aria-selected="true">Add a Lead</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" id="report-tab" data-toggle="tab" href="#report" onclick="getLeads()" role="tab"
                        aria-controls="report" aria-selected="false">Manage Leads</a>
                </li>
            </ul> <br>
            <div class="tab-content" id="myTabContent">
                <div class="tab-pane fade show active" id="check" role="tabpanel" aria-labelledby="check-tab">
                    <div class="tab-pane fade show active" id="ex3-tabs-1" role="tabpanel" aria-labelledby="ex3-tab-1">
                        <div style="margin-left: 100px; margin-right:100px;">
                            <form id="leads">
                                <!-- 2 column grid layout with text inputs for the first and last names -->
                                <div class="row mb-4">
                                    <div class="col">
                                        <div class="form-outline">
                                            <label class="form-label" for="form6Example1">First name</label>
                                            <input type="text" id="firstName" class="form-control" />
                                        </div>
                                    </div>
                                    <div class="col">
                                        <div class="form-outline">
                                            <label class="form-label" for="form6Example2">Last name</label>
                                            <input type="text" id="lastName" class="form-control" required />
                                        </div>
                                    </div>
                                </div>
                                <!-- Text input -->
                                <div class="form-outline mb-4">
                                    <label class="form-label" for="form6Example3">Company name</label>
                                    <input type="text" id="companyName" class="form-control" />
                                </div>
                                <!-- Email input -->
                                <div class="form-outline mb-4">
                                    <label class="form-label" for="form6Example5">Email</label>
                                    <input type="email" id="email" class="form-control" />
                                </div>
                                <!-- Text input -->
                                <div class="form-outline mb-4">
                                    <label class="form-label" for="form6Example4">State</label>
                                    <input type="text" id="state" class="form-control" />
                                </div>
                                <!-- Number input -->
                                <div class="form-outline mb-4">
                                    <label class="form-label" for="form6Example6">Phone</label>
                                    <input type="number" id="phone" class="form-control" />
                                </div>
                                <!-- Number input -->
                                <div class="form-outline mb-4">
                                    <label class="form-label" for="form6Example6">Lead Source</label>
                                    <input type="text" id="leadSource" class="form-control" />
                                </div>
                                <!-- Submit button -->
                                <center> <button type="submit" onclick="createLead();return false;"
                                        class="btn btn-primary btn-block mb-4" style="width: 100px;">Add Lead</button>
                                    <div id="loader" style="display: none;">
                                        <div class="spinner-border" role="status">
                                            <span class="sr-only">Loading...</span>
                                        </div>
                                    </div>
                                </center>
                            </form>
                        </div>
                    </div>
                </div>
                <div class="tab-pane fade" id="report" role="tabpanel" aria-labelledby="report-tab">
                    <center>
                        <div id="loaders" style="display: none; padding-top: 200px;">
                            <div class="spinner-border" role="status">
                                <span class="sr-only">Loading...</span>
                            </div>
                        </div>
                    </center>
                    <p id="showData"> </p>
                </div>
            </div>
        </div>
        <!-- Modal -->
        <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"
            aria-hidden="true">
            <div class="vertical-alignment-helper">
                <div class="modal-dialog vertical-align-center">
                    <div class="modal-content">
                        <center>
                            <h4 class="modal-title" id="myModalLabel"> </h4>
                            <div class="modal-body" id="message"> </div>
                            <div class="modal-footer">
                                <button type="button" style="background-color: #007bff;color: white;"
                                    class="btn btn-default" data-dismiss="modal">Close</button>
                            </div>
                        </center>
                    </div>
                </div>
            </div>
        </div>
        <div class="modal fade" id="editForm" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"
            aria-hidden="true">
            <div class="vertical-alignment-helper">
                <div class="modal-dialog vertical-align-center">
                    <div class="modal-content">
                        <div style="margin-left: 80px; margin-right:80px;">
                            <br>
                            <center>
                                <h2>Edit Lead</h2>
                            </center>
                            <br>
                            <form id="editLeads">
                                <!-- 2 column grid layout with text inputs for the first and last names -->
                                <div class="row mb-4">
                                    <div class="col">
                                        <div class="form-outline">
                                            <label class="form-label" for="form6Example1">First name</label>
                                            <input type="text" id="editfirstName" class="form-control" />
                                        </div>
                                    </div>
                                    <div class="col">
                                        <div class="form-outline">
                                            <label class="form-label" for="form6Example2">Last name</label>
                                            <input type="text" id="editlastName" class="form-control" required />
                                        </div>
                                    </div>
                                </div>
                                <!-- Text input -->
                                <div class="form-outline mb-4">
                                    <label class="form-label" for="form6Example3">Company name</label>
                                    <input type="text" id="editcompanyName" class="form-control" />
                                </div>
                                <!-- Email input -->
                                <div class="form-outline mb-4">
                                    <label class="form-label" for="form6Example5">Email</label>
                                    <input type="email" id="editemail" class="form-control" />
                                </div>
                                <!-- Text input -->
                                <div class="form-outline mb-4">
                                    <label class="form-label" for="form6Example4">State</label>
                                    <input type="text" id="editstate" class="form-control" />
                                </div>
                                <!-- Number input -->
                                <div class="form-outline mb-4">
                                    <label class="form-label" for="form6Example6">Phone</label>
                                    <input type="number" id="editphone" class="form-control" />
                                </div>
                                <!-- Submit button -->
                                <center> <button type="submit" id="editBtn" onclick="editLead();return false;"
                                        class="btn btn-primary btn-block mb-4" style="width: 100px;">Edit</button>
                                    <div id="loader" style="display: none;">
                                        <div class="spinner-border" role="status">
                                            <span class="sr-only">Loading...</span>
                                        </div>
                                    </div>
                                </center>
                            </form>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <div class="modal fade right" id="ModalDanger" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"
            aria-hidden="true">
            <div class="modal-dialog modal-notify modal-danger modal-side modal-top-right" role="document">
                <!--Content-->
                <div class="modal-content">
                    <!--Header-->
                    <div class="modal-header">
                        <p class="heading">Lead Deletion</p>
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                            <span aria-hidden="true" class="white-text">×</span>
                        </button>
                    </div>
                    <!--Body-->
                    <div class="modal-body">
                        <div class="row">
                            <div class="col-9">
                                <p>Are you sure you want to delete the Lead?</p>
                            </div>
                        </div>
                    </div>
                    <!--Footer-->
                    <div class="modal-footer justify-content-center">
                        <a type="button" class="btn btn-danger" id="delete-btn" onclick="deleteLead()">Delete</a>
                        <a type="button" class="btn btn-outline-danger waves-effect" data-dismiss="modal">Cancel</a>
                    </div>
                </div>
                <!--/.Content-->
            </div>
        </div>
    </div>
</body>
<script>
    //クライアントIDを追加する
    function navigate() {
        window.location.href = "https://accounts.zoho.com/oauth/v2/auth?scope=ZohoCRM.modules.ALL&client_id={{client_id}}&response_type=code&access_type=offline&redirect_uri=" + location.protocol + '//' + location.host + "/generateToken";
    }
</script>
</html>

View more

Note: 252行目にClient IDを入力してください。
login.html
copy
<html>
</html>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>CRM Lead Manager</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" media="screen" href="main.css" />
<script src="main.js"> </script>
<link rel="stylesheet" type="text/css" media="screen" href="main.css" />
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
    integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="https://static.zohocdn.com/catalyst/sdk/js/4.6.2/catalystWebSDK.js"> </script>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"
    integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"> </script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
    integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous">
    </script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
    integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous">
    </script>
<script src="https://static.zohocdn.com/catalyst/sdk/js/4.6.2/catalystWebSDK.js"> </script>
<script src="/__catalyst/sdk/init.js"> </script>
<script>
    catalyst.auth.signIn("login");
</script>
<link href="//maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<style>
    #login {
        height: 100%;
        width: 100%;
        position: absolute;
        top: 0;
        bottom: 0;
        left: 0;
        right: 0;
        margin: auto;
    }
</style>
<body>
    <br>
    <center>
        <h1>CRM Lead Manager</h1>
    </center>
    <div id="login"> </div>
</body>
</html>

View more

main.css
copy
#dataTable {
    font-family: Arial, Helvetica, sans-serif;
    border-collapse: collapse;
    width: 100%;
  }

#dataTable td, #dataTable th { border: 1px solid #ddd; padding: 8px; }

#dataTable tr:nth-child(even){background-color: #f2f2f2;}

#dataTable tr:hover {background-color: #ddd;}

#dataTable th { padding-top: 12px; padding-bottom: 12px; text-align: left; background-color: #007bff; color: white; }

.vertical-alignment-helper { display: table; height: 100%; width: 100%; pointer-events: none; }

.vertical-align-center { display: table-cell; vertical-align: middle; pointer-events: none; }

.modal-content { width: inherit; max-width: inherit; height: inherit; margin: 0 auto; pointer-events: all; }

View more

main.js
copy
function createLead() {
    debugger;
    $("#loader").show();
    var firstName = $("#firstName").val();
    var lastName = $("#lastName").val();
    if (lastName == "") {
      alert("Kindly Enter the Last Name");
      $("#loader").hide();
      return;
    }
    var companyName = $("#companyName").val();
    var email = $("#email").val();
    var state = $("#state").val();
    var phone = $("#phone").val();
    var leadSource = $("#leadSource").val();
    $.ajax({
      url: "/crmData",
      type: "post",
      contentType: "application/json",
      data: JSON.stringify({
        "First_Name": firstName,
        "Last_Name": lastName,
        "Company": companyName,
        "Email": email,
        "State": state,
        "Phone": phone,
        "Lead_Source": leadSource,
      }),
      success: function (data) {
        debugger;
        $('#leads').trigger("reset");
        $("#myModalLabel").html("Success");
        $("#message").html("Lead Created Successfully");
        $("#loader").hide();
        $('#myModal').modal('show');
      },
      error: function (error) {
        $('#leads').trigger("reset");
        $("#myModalLabel").html("Failure");
        $("#message").html("Please try again after Sometime");
        $("#loader").hide();
        $('#myModal').modal('show');
      }
    });
  }
  function logout() {
    var redirectURL = "/login.html"; //Add your app domain
    var auth = catalyst.auth;
    auth.signOut(redirectURL);
  }
  function getUserDetails() {
    $("#main").hide();
    $("#connect").hide();
    catalyst.auth.isUserAuthenticated().then(result => {
      console.log(result)
      $("#loader").show();
      $.ajax({
        url: "/getUserDetails",
        type: "get",
        success: function (data) {
          $("#loader").hide();
          if (data.userId) {
            $("#main").show();
            $("#connect").hide();
          } else {
            $("#connect").show();
            $("#main").hide();
          }
        },
        error: function (error) {
          $("#myModalLabel").html("Failure");
          $("#message").html("Please try again after Sometime");
          $("#loader").hide();
          $('#myModal').modal('show');
        }
      });
    }).catch(err => {
      document.body.innerHTML = 'You are not logged in. Please log in to continue. Redirecting you to the login page..';
      setTimeout(function () {
        window.location.href = "login.html";
      }, 3000);
    });
  }
  function getLeads() {
    debugger;
    var tableContainer = document.getElementById("showData");
    tableContainer.innerHTML = "";
    $("#loaders").show();
    $.ajax({
      url: "/crmData",
      type: "get",
      success: function (data) {
        debugger;
        var reqData = getRequiredData(data.data);
        $("#loaders").hide();
        renderTable(reqData);
      },
      error: function (error) {
        $("#myModalLabel").html("Failure");
        $("#message").html("Please try again after Sometime");
        $("#loader").hide();
        $('#myModal').modal('show');
      }
    });
  }
  function showDeletePopup(leadID) {
    $('#ModalDanger').modal('show');
    var deleteBtn = document.getElementById("delete-btn");
    deleteBtn.value = leadID;
  }
  function deleteLead() {
    var leadID = document.getElementById('delete-btn').value;
    $.ajax({
      url: "/crmData/" + leadID,
      type: "delete",
      success: function (data) {
        debugger;
        $('#ModalDanger').modal('toggle');
        $("#myModalLabel").html("Success");
        $("#message").html("Lead Deleted Successfully");
        $('#myModal').modal('show');
        setTimeout(function () {
          location.reload();
        }, 3000);
      },
      error: function (error) {
        $("#myModalLabel").html("Failure");
        $("#message").html("Please try again after Sometime");
        $("#loader").hide();
        $('#myModal').modal('show');
      }
    });
  }
  function showEditPopup(leadID) {
    $.ajax({
      url: "/crmData/" + leadID,
      type: "get",
      success: function (data) {
        debugger;
        var respData = data.data;
        $('#editfirstName').val(respData[0].First_Name);
        $('#editlastName').val(respData[0].Last_Name);
        $('#editcompanyName').val(respData[0].Company);
        $('#editemail').val(respData[0].Email);
        $('#editstate').val(respData[0].State);
        $('#editphone').val(respData[0].Phone);
        $('#editleadSource').val(respData[0].Lead_Source);
        $('#editBtn').val(respData[0].id);
        $('#editfirstName').html(respData[0].First_Name);
        $('#editlastName').html(respData[0].Last_Name);
        $('#editcompanyName').html(respData[0].Company);
        $('#editemail').html(respData[0].Email);
        $('#editstate').html(respData[0].State);
        $('#editphone').html(respData[0].Phone);
        $('#editleadSource').html(respData[0].Lead_Source);
        $('#editForm').modal('show');
      },
      error: function (error) {
        $("#myModalLabel").html("Failure");
        $("#message").html("Please try again after Sometime");
        $("#loader").hide();
        $('#myModal').modal('show');
      }
    });
  }
  function editLead() {
    var firstName = $("#editfirstName").val();
    var lastName = $("#editlastName").val();
    if (lastName == "") {
      alert("Kindly Enter the Last Name");
      return;
    }
    var companyName = $("#editcompanyName").val();
    var email = $("#editemail").val();
    var state = $("#editstate").val();
    var phone = $("#editphone").val();
    var leadSource = $("#editleadSource").val();
    var leadID = $("#editBtn").val();
    $.ajax({
      url: "/crmData/" + leadID,
      type: "put",
      contentType: "application/json",
      data: JSON.stringify({
        "First_Name": firstName,
        "Last_Name": lastName,
        "Company": companyName,
        "Email": email,
        "State": state,
        "Phone": phone,
        "Lead_Source": leadSource
      }),
      success: function (data) {
        debugger;
        $('#editForm').modal('toggle');
        $("#myModalLabel").html("Success");
        $("#message").html("Lead Edited Successfully");
        $('#myModal').modal('show');
        setTimeout(function () {
          location.reload();
        }, 3000);
      },
      error: function (error) {
        $('#leads').trigger("reset");
        $("#myModalLabel").html("Failure");
        $("#message").html("Please try again after Sometime");
        $("#loader").hide();
        $('#myModal').modal('show');
      }
    });
  }
  function getRequiredData(data) {
    var i;
    var resp = [];
    for (i = 0; i < data.length; i++) {
      var gulp = {
        "First Name": data[i].First_Name,
        "Last Name": data[i].Last_Name,
        "Phone": data[i].Phone,
        "Email": data[i].Email,
        "Company": data[i].Company,
        "Edit": '<center><a href="javascript:showEditPopup(\'' + data[i].id + '\')">✎︎</a></center>',
        "Delete": '<center><a href="javascript:showDeletePopup(\'' + data[i].id + '\')">🗑︎</a></center>'
      }
      resp.push(gulp);
    }
    console.log(resp);
    return resp;
  }
  function renderTable(respData) {
    var col = [];
    for (var i = 0; i < respData.length; i++) {
      for (var key in respData[i]) {
        if (col.indexOf(key) === -1) {
          col.push(key);
        }
      }
    }
    var table = document.createElement("table");
    table.id = "dataTable";
    var tr = table.insertRow(-1);
    for (var i = 0; i < col.length; i++) {
      var th = document.createElement("th");
      th.innerHTML = col[i];
      tr.appendChild(th);
    }
    for (var i = 0; i < respData.length; i++) {
      tr = table.insertRow(-1);
      for (var j = 0; j < col.length; j++) {
        var tabCell = tr.insertCell(-1);
        tabCell.innerHTML = respData[i][col[j]];
      }
    }
    var divContainer = document.getElementById("showData");
    divContainer.innerHTML = "";
    divContainer.appendChild(table);
  }

View more

app-config.json
copy
{
	"command": "python3 -u main.py",
	"build_path": "/",
	"stack": "python_3_9",
	"env_variables": {},
	"memory": 256,
	"scripts": {},
	"raw": {},
	"catalyst_auth": true,
	"login_redirect": "/index.html"
}

View more

Note: buildpathキーに正しい値を指定してください。

それでは、アプリケーションコードのロジックと機能について説明します。

  • クライアントコンポーネントのlogin.htmlファイルは、Catalyst Embedded Authenticationログインを有効にし、Zohoソーシャルログインを使用してログインできるようにします。

  • index.htmlファイルには、クライアントのフロントエンドのコードが含まれています。Client IDやスコープなどの必要な認証情報を渡してCRMアカウントへの接続を有効にするnavigate()関数を定義しています。

  • アプリケーションのバックエンドロジックは、さまざまなアクションを実行する以下のAPIを定義しています:

    • /generateTokengetRefreshToken()関数を呼び出してRefresh Tokenを取得し、現在のユーザーのuserIDとともにData StoreTokenテーブルに挿入します。その後、クライアントのインデックスページにリダイレクトします。
    • /getUserDetailsgetUserDetails()関数を呼び出してユーザーの詳細を取得します。テーブルにレコードがない場合は、userIDのみを含むJSONレスポンスが送信されます。レコードがテーブルに存在する場合は、userIDとともに送信されます。
    • /crmData:このルートは、Leadsモジュールのすべてのリードのパスを定義します。Nodeファンクションは、このルートを使用してHTTP GETおよびPOST操作を実行し、すべてのリードの取得または新しいリードの作成をそれぞれ行います。
    • /crmData/:id:このルートは、Leadsモジュールの特定のリードのパスを定義します。idは、CRM内のリードの一意のIDを表します。ファンクションは、このルートを使用してHTTP PUTおよびDELETE操作を実行し、リードの編集または削除をそれぞれ行います。
  • バックエンドロジックは、APIから呼び出される以下の関数を使用して実装されています:

    • getRefreshToken()Client IDClient SecretRedirect URI、およびその他の必要な値をクエリ文字列パラメータとして渡すことで、Refresh Tokenを取得します。
    • getAccessToken()ZCQLを使用してTokenテーブルからクエリしたRefresh Tokenとその他の必要なパラメータを渡すことで、Access Tokenを取得します。Access Tokenは、リードの追加やリードの編集など、CRMモジュールで操作を実行する必要があるたびに取得されます。
    • getResponse():取得したAccess Tokenを渡して、CRMモジュールで各アクションを実行するために必要な認証を取得します。この関数は、各/crmDataおよび/crmData/:id APIでリクエストを認証するために呼び出されます。
    • getUserDetails()userIDを渡すことで、Refresh Tokenを含むTokenテーブルからレコードを取得します。
  • main.js:クライアントコンポーネントのJavaScript関数で、ファンクションから取得したJSONレスポンスを解析し、index.htmlページにレンダリングします。この関数は、クライアントアプリケーションのすべてのUI要素のアクションを定義します。例えば、getLeads()はファンクションのレスポンスからすべてのリードを取得してクライアントにレンダリングし、showEditPopup()はリードの編集アクションを定義します。

最終更新日 2026-09-02 11:52:26 +0530 IST

関連リンク

認証用Web SDK