見出し画像

レビューしていただいて、危険な箇所などを修正しました

URLのテキストを元にQRコードをブラウザに表示してみる」は力技で動作するところまでできたのですが、酒井(@sakay_y)さんにレビューしていただいて、危険なところや作法に合っていないところを修正しました。コメントいただいた内容については、改めて調べたりして、「何もわかっていない」から「少しわかった気がする」くらいになった気がします。(気がするだけかも)


レビュー後の修正

GitHub ActionsでkintoneのREST APIを使ってデータを読んだり、更新したりすることができるようになったのですが、ワークフローには入れなくて良いものや、危険な設定、job本体にもセキュリティ的に問題がある箇所のご指摘をいただいたので、修正しました。

APIトークンの保存場所はSecretsに

APIトークンをActions secrets and variablesのVariablesに登録していたのですが、これでは公開された状態で、ログにもトークンが出力されていたりして不適切でした。対象のkintoneアプリのAPIトークンを再生成して、Secretsに登録し直しました。

APIトークンをActions secrets and variablesのVariablesに登録
APIトークンをSecretsに登録し直し

@kintone/rest-api-clientはワークフローで個別にインストールしないで、package.jsonをもとにnpm ci

パッケージ管理のことがわかっていなくて、@kintone/rest-api-clientをローカル実行のときの手順をそのままにワークフローで実行していました。これは、package.jsonの”dependencies”に追加して、npm ci で必要なモジュールをインストールするのが正しいとのこと。他にも、今回処理を修正した際にaxiosを追加したので、こちらも併せて、package.jsonに追加されています。

package.jsonの修正箇所

  "dependencies": {
    "@kintone/rest-api-client": "^5.0.3",
    "@testing-library/jest-dom": "^5.17.0",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "axios": "^1.6.0",

ワークフローの修正箇所

      - name: Install modules
        run: npm ci

これ以外にも、cronの実行時間設定が、0:00 と9:00だけになっていたので、0-9 に変更して、0:00から9:00まで実行できるように修正しました。

kintoneデータ取得とファイル保存と参照の方法の変更

クライアントからリスト情報ファイルを読み込む方法がわからなくて、無理やりJavaScriptを生成してApp.jsでimportしていたのですが、これもセキュリティ上の問題があるとご指摘をいただいたので、ファイル操作について改めて調べた結果axiosを使って解決できました。
これに伴い、以下の処理に修正しました。
1.kintoneから新しく承認済になったレコードを取得
2.取得したデータをcsvファイルに追加出力して保存
3.csvファイルから表示用URLの情報を読み出して表示

修正後のjob本体

const {KintoneRestAPIClient} = require('@kintone/rest-api-client');
const {appendFile} = require('fs');

// リスト表示用csv出力データの取得
function getUrlList(id, title, url, descriptions) {
  return `${id},${title},${url},${descriptions}\n`;
}

(async () => {
    try {
      const LIST_PATH = '../public/url_list.csv';

      // クライアントの作成
      const client = new KintoneRestAPIClient({
        // kintoneのデータ取得先を設定
        baseUrl: 'https://[YourDomain].cybozu.com',
        auth: {
          apiToken: process.env.KINTONE_API_TOKEN
        }
      });
  
      // リクエストパラメータの設定
      const APP_ID = 2;
      const query_string = 'ステータス="accepted" order by $id';
      const params = {
        app: APP_ID,
        fields:['$id', 'ステータス', 'title', 'URL', 'descriptions'],
        query: query_string
      };
      
      // レコードの取得
      const resp = await client.record.getRecords(params);
      if(!resp || resp.records.length === 0){
        console.log('nodata');
        return;
      }
      const kintoneRows = resp.records.map(
        (record)=>{
          const jrec = JSON.parse(JSON.stringify(record));
          // リスト表示用データのcsvデータ
          const urldata = getUrlList(jrec.$id.value,
                                         jrec.title.value,
                                         jrec.URL.value,
                                         jrec.descriptions.value);
          // 表示用csvに追加
          appendFile(LIST_PATH, urldata, err => {
            if( err ){
              console.log(err.message);
            } else {
              console.log(`appended data file`);
            }
          }); 
          // 承認済データのステータス更新
          client.record.updateRecordStatus( {action:'公開する', app:APP_ID, id:jrec.$id.value});
       });

    } catch (err) {
      console.log(err);
    }
  })();

画面に表示する際に、Warning: Each child in a list should have a unique "key" prop.が発生しました。

Warning: Each child in a list should have a unique "key" prop.が発生している。
表示はできたがWarningが発生している

Warningでも気になるので、調べたところ、表示する各リストの行にユニークキーが付与されていないことが原因でした。各行に取得したkintoneのレコードIDを付与すれば良いと思い、そちらも修正しました。

修正後のApp.js

import {useState, useEffect,Fragment} from 'react';
import axios from 'axios';
import './App.css';

// csvから取得したデータをもとに表示用のタグ取得
function getList(csvdata){
  // csvファイルから取得したデータをもとにlist変換
  const colums = csvdata.split('\n');
  const lists = colums.filter((colum) => colum.length > 0).map(
    (colum) => {
      const cols = colum.split(',');
        console.log(`line=${colum}`);
        console.log(`col.id=${cols[0]}`);
        return  <Fragment key={cols[0]}><div className='item'><h2>{cols[1]}</h2><div className='qrcode'><img src={getQRCodeUrl(cols[2])} alt={cols[1]} /></div><div className='descriptions'>{cols[3]}</div></div></Fragment>
        });
      return lists;
}

// QRコード生成用URLの取得
function getQRCodeUrl(url) {
  return `http://api.qrserver.com/v1/create-qr-code/?data=${url}&size=100x100`;
}

const UrlList = () => { 
  const baseURL = './url_list.csv';
  const [post, setPost] = useState(null);
  useEffect(() => {
    axios.get(baseURL).then((response) => {
      setPost(getList(response.data));
    });
  }, []);

  if (!post) return <p>error!</p>;

  console.log(post);
  return (
    <div className='contents'>{post}</div>
  );
}

function App() {
  return(
    <div>
      <h1 className='title'>kintoneアプリから取得したURLのリスト</h1>
      <UrlList/>
  </div>
  );
 };

export default App;

見た目の改善

App.cssも修正しました。

.App {
  text-align: center;
}


.contents {
    display: inline-block;
}
.item {
    width: 540px;
    margin-bottom: 10px;
    padding: 10px;
    text-align: left;
    border: 1px #efefef ;
    border-radius: 30px;
    background-color: #efefef;
}

.qrcode{
  display: inline-block;
  width: 110px;
  margin: 3px 0;
  padding: 0;
}

.descriptions{
  display: inline-block;
  width: 400px;
  margin: 3px 0;
  padding: 0;
  vertical-align: top;
}

.title{
  margin-left:10px;
  margin-top: 0;
}

最終的な結果は、こちらです。

実行結果のブラウザ表示にkintoneアプリから取得したURLのリストが表示されている
リストの表示

まとめ

TypeScriptの写経をしても、スキルのほんの一部がちょこっと付加される程度で、実務で活かせるかどうかは微妙です。今まで開発したことがないウェブアプリの開発では別の知識が必要で、この状態では役立たずだなと再認識しました。形のあるものを作ることで必要な知識がわかるので、めげずに色々作ってみながら精進します。次回は、また次の週末の予定です。

参考リンク
npm ciと.npmを使ってGitHub Actionsを高速化する
npm install と npm ci って結局どう使うの?2023年版
React.jsでWarning: Each child in a list should have a unique "key" prop.が発生した時の原因と対処法
Axios client for the browser and node.js



この記事が気に入ったらサポートをしてみませんか?