20200915のNode.jsに関する記事は7件です。

ElectronをバージョンアップしたらMacアプリのCode Signができなくなった話

前回に引き続きElectron9のにバージョンアップした際に困ったことメモです

MacアプリのCode Sign

  • Macアプリは10.14.5以降、署名と公証されていないといけなくなっています参考
  • なのでアプリの配布には署名作業が必須
  • 使っているライブラリ
    • 署名用ライブラリ: electron-osx-sign
    • アプリのビルド: electron-builder

Electron9へバージョンアップした後.appへの署名に失敗

  • [ERROR] app is not signed [xxxxxx.app]
  • と言われた

対策

  • electron-osx-signを最新化 v0.4.11 --> v0.4.17
  • electron-builderを最新化 v22.1.0 --> v22.7.0

これで署名できた!

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

discord.js スタートガイド(スマホ可)

どうも すえきゅーです
今回はdiscordのbotを作りたい方向けのスタートガイドをここに書きたいと思います

使うもの
・Heroku
・Github
・discord developer portal

まずdiscord developer portalでbotを登録しましょう

Botを登録する こ↑こ↓ でNew applicationを押します 50668E8C-5E1C-44C5-BB36-55B786D314F6.jpeg
訳:Botの名前を決めてね!
Botの名前はわかりやすくて他人に見られてもいいようにしましょう
名前を決めたら↓のような画面になります7DB887CC-2067-4D7B-8CC8-AA2624CC83D7.jpeg
アイコンは決めておきましょう
次は三本線を押してBotというところを押します
なんか下のようなものが出てくるのでAdd Botを押しましょうF2AD21CC-86F8-40C5-BC5F-26CDF04BEF74.jpeg
本当にするの?(下)が出てくるのでYes, do it!を押しましょう。6F1A339A-B53C-4206-AAB6-3E50FFC353AE.jpeg
こいつはBotを動かすために使うパスワードをコピーするボタンですね
注意!これを人に教えると乗っ取られます!絶対に教えないようにしましょう。
もし教えてしまったら隣のRegenerateというボタンを押しましょう。
C7667304-2B2E-4D8F-B532-4B1B2A6EC03E.jpeg
登録作業はこれで終わり!

Botの中身をつくる
まずこ↑こ↓にアクセスしUse this Templateを押す
そしたら68B32773-5822-4E82-B3DC-4993C9E22498.jpeg
こんな感じにリポジトリを作る
これで中身は完成
こいつ自体にライセンスはないです
index.jsがbotの中身だよ!
これで中身を作る作業は終わり

これで最後の作業だ!頑張れ!

Herokuで稼働させる
herokuアカウンk…アカウントを登録しましょう
職業の欄は学生でいいと思います
では次!
Newってところを押してcreate a New appを押します
そしてSettings(歯車のマーク)を押しここに行きます
こんな画面になると思うのでF1961DFE-342E-467E-A793-C6A3F9EAE518.jpeg
まずは Reveal Config Varsを押し
KEYにDISCORD_BOT_TOKENと入力したらVALUEにBOT登録作業で手に入れたTOKENをぶち込みます
次はAdd bulid packを押しNodejsを押します
なんか警告文見たいのが出ますが気にしないでください
最後!!!!
Deployで下にスクロールするとGithubとかよくわかんないのが並んでますがGithubを押しましょう それでリポジトリを作ったGithubアカウントでログインします
それでなんか下のようなところが出てくるので(語彙力0)
さっき作ったリポジトリの名前をぶち込んでサーチを押したらリポジトリが出てくるのでconnectします。
そしたら Enable Automatic Deployを押して Deploy Branchを押す
これで動くはずです…

動かなかったら discordで index#7595 にフレンド申請して質問するか 自鯖で質問してください。

最後まで見てくれてありがとうございます!
初めての記事なのであまり質が良くないかも知れません。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

HerokuでLINEとDiscordをつないでみる

はじめに

KC3 2020の勉強会で話した内容です。
DiscordとLINEでテキストメッセージのやり取りができるようにします。
画像のメッセージのやり取りの実装などは別記事でやります。

LINEでメッセージ送信 → LINE BotがHerokuにメッセージの内容を送信 → HerokuがDiscord Webhookにメッセージの内容を送信 → Discordでメッセージが表示される

Discordでメッセージ送信 → Discord BotがHerokuにメッセージの内容を送信 → HerokuがLINE Botにメッセージの内容を送信 → LINE Botが発言
大まかにはこのような構成になっています。

LINE Botの準備

LINE Developersにログイン

LINE Developersにログイン。LINEアカウントでログインできる。

Providerを作成

Providers一覧の上の”Create”ボタンを押し、名前を決めて新規作成。

Channelを作成

作成したProviderのChannelを作成する。Create a Messaging API Channelを選択。


入力項目を埋めてChannelを作成する。
このとき、ブラウザの拡張機能が干渉してインプットが消えてしまうことがあった。

LINE Botの設定を変更

LINE Official Account Managerの応答設定からLINE Botの設定のWebhookをオンにする。

LINE Botと友だちになる/グループに招待

グループに参加させるにはLINE DevelopersのChannel設定のMessaging APIタブからグループ参加を有効にする必要がある。
友だち追加はBasic settingsタブのQRコードなどから可能。
グループの各メンバーはBotを友だち追加する必要がある。

これでLINE Botの準備は完了。

[環境変数の登録などの諸設定](https://qiita.com/sanbasan/items/8145140bb67c4c6ef516#%E7%92%B0%E5%A2%83%E5%A4%89%E6%95%B0%E3%81%AE%E7%99%BB%E9%8C%B2%E3%81%AA%E3%81%A9%E3%81%AE%E8%AB%B8%E8%A8%AD%E5%AE%9Aでアクセストークンの確認とWebhook URLの設定をするためにLINE Developersを開く。

Discord Botの準備

Discord Developer Portalにログイン

Discord Developer Portalにログインする。

Applicationを作成

右上の"New Application"を押して名前を指定し、Applicationを新規作成する。

Discord Botの作成

BotタブからBotを新規作成する。

Discord Botをサーバーに招待

OAuth2タブで適宜必要なチェックを入れて生成されたURLを開く。
そのページでBotをサーバーに招待する。

これでDiscord Botの準備は完了。Botはサーバーに参加していてオフラインの状態。

コードを書いてHerokuにデプロイ

Node.js(今回は12.8.3を使用)でHerokuで行う処理を記述する。

下準備

git initnpm initなど叩いてgit・npmが使える状態にする。ここは割愛。
Heroku CLIを使用するのでインストールしておく。

必要なパッケージの導入

$ npm install @line/bot-sdk discord.js express axios

を実行してパッケージを導入。

LINE → Discordの処理

jsファイルを作成してコードを書いていく。

linebot.js
const express = require('express');
const axios = require('axios');
const line = require('@line/bot-sdk');

const PORT = process.env.PORT || 5000;

const lineConfig = {
  channelAccessToken: process.env.LINE_CHANNEL_ACCESS_TOKEN,
  channelSecret: process.env.LINE_CHANNEL_SECRET,
};
const lineClient = new line.Client(lineConfig);

const discordWebhookUrl = process.env.DISCORD_WEBHOOK_URL;
const discordWebhookConfig = {
  headers: {
    'Accept': 'application/json',
    'Content-type': 'application/json',
  },
};

const generatePostData = (event, profile) => {
  const type = event.message.type;
  if (type !== 'text') {
    return {
      username: profile.displayName,
      avatar_url: `${profile.pictureUrl}.png`,
      content: 'テキスト以外のメッセージを送信しました。',
    };
  }
  return {
    username: profile.displayName,
    avatar_url: `${profile.pictureUrl}.png`,
    content: event.message.text,
  };
};

const lineBot = async (req, res) => {
  res.status(200).end(); // 'status 200'をLINEのAPIに送信

  const events = req.body.events;
  events.forEach(async (event) => {
    try {
      const profile =  await lineClient.getProfile(event.source.userId);
      const postData = await generatePostData(event, profile);
      // DiscordのWebHookにPOST
      await axios.post(discordWebhookUrl, postData, discordWebhookConfig);
    } catch(error) {
      console.error(error);
    }
  });
};

const app = express();
app.post('/linehook/', line.middleware(lineConfig), (req, res) => lineBot(req, res));
app.listen(PORT, () => console.log(`Listening on ${ PORT } for LINE Messaging API.`));

expressでLINE BotからのPOSTを受けてDiscord WebhookにPOSTしている。
LINEのアイコンと名前をDiscordで出力する際に反映させている。

Discord → LINEの処理

おなじくjsファイルを作成してコードを書いていく。

discordbot.js
const line = require('@line/bot-sdk');
const discord = require('discord.js');

const lineConfig = {
  channelAccessToken: process.env.LINE_CHANNEL_ACCESS_TOKEN,
  channelSecret: process.env.LINE_CHANNEL_SECRET,
};
const lineClient = new line.Client(lineConfig);

const discordClient = new discord.Client();

const generateMessage = (event) => {
  const content = event.content;
  if (content.length === 0) {
    return {
      type: 'text',
      text: 'Discordで非対応の形式のメッセージを送信しました。',
      sender: {
        name: event.author.username,
        iconUrl: event.author.displayAvatarURL().replace('.webp', '.png'),
      },
    };
  }
  return {
    type: 'text',
    text: `${content}`,
    sender: {
      name: event.author.username,
      iconUrl: event.author.displayAvatarURL().replace('.webp', '.png'),
    },
  };
};

discordClient.on('message', async (event) => {
  try {
    // BOTのメッセージはスルー
    if (!event.author.bot) {
      const message = generateMessage(event);
      await lineClient.pushMessage(
        // 送信先のトークルームのグループ/ユーザーID
        process.env.LINE_TARGET_ID,
        message,
      );
    }
  } catch(error) {
    console.error(error);
  } 
});

discordClient.login(process.env.DISCORD_ACCESS_TOKEN);

DiscordのアイコンとユーザーIDをLINE Botが発言するときに使用する。

Procfileの記述

Herokuでjsファイルが実行できるようにProcfileを書いておく。

line: node linebot.js
dicord: node discordbot.js

Herokuにデプロイ

Heroku スターターガイド (Node.js)にあるようにHeroku CLIでデプロイする。

まだこの時点では動作しない。

環境変数の登録などの諸設定

Heroku DashboardのSettingsのConfig Varsから環境変数を設定できる。
Heroku CLIからも可能。Herokuで環境変数を設定する方法 - Qiita
上のコードだと以下の5つを設定する。

LINEのChannel access token

LINE DevelopersのChannelの設定画面のMessaging APIタブの一番下にChannel access token (long-lived)がある。
上のコードではLINE_CHANNEL_ACCESS_TOKENとして設定する。

LINEのChannel secret

LINE DevelopersのChannel設定画面のBasic settingsタブにChannel secretがある。
上のコードではLINE_CHANNEL_SECRETとして設定する。

LINE Messaging APIのWebhook URLを設定

LINE DevelopersのChannelの設定画面のMessaging APIタブでWebhook URLを"https://<Herokuのアプリ名>.heroku.com/linehook"に設定する。
設定するとVerifyというボタンが出る。押してSuccessと出れば成功。

DiscordのWebhook URL

タイトル: Webhooksへの序章 – Discord - Discord SupportのようにWebhook URLを取得し、それを上のコードではDISCORD_WEBHOOK_URLとして設定する。

DiscordのToken

Discord Developer Portalの作成したアプリケーションの画面のBotタブからTokenを取得し、上のコードではDISCORD_ACCESS_TOKENとして設定する。

Botが発言するトークルームのID

LINE Botが発言するトークルームのIDを指定しておく必要がある。
グループチャット | LINE DevelopersにあるようにメッセージイベントのsourceプロパティからIDを取得できる。linebot.jsにコードを書き足してログに表示するようにしておけばHerokuの実行ログから確認できる。それを上のコードではLINE_TARGET_IDとして設定する。

dynoを起動

Heroku Dashboardからdynoを起動する。
これでテキストメッセージのやり取りはできるようになる。

参照

これらの記事も参考になると思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Microsoft TeamsのWebhook URLにNode.jsから情報を送ってみる

最近仕事のやりとりでTemasを使う機会が増えてきました。

Teamsのハックを出来ないかと調べてみているメモです。

Webhook URLの取得

自分が管理権限があるチームの左下にアプリボタンがあると思います。

スクリーンショット 2020-09-15 16.27.59.png
割とこの第1ステップで迷いました。

ここからIncomming Webhookを探してチームに追加します。

利用するチャンネルを選びます。

名前を適当に決めましょう。

作成ボタンを押すとhttps://outlook.office.com/webhook/~~~というアドレスが発行されます。

CURLで試す

cURLだと以下をコピペで実行できます。

$ curl -H 'Content-Type: application/json' -d '{"text": "Hello World"}' <YOUR WEBHOOK URL>

実行結果はこんな感じです。

スクリーンショット 2020-09-15 16.36.56.png

参考: cURL を使用してメッセージを Webhook に投稿する

ここまできたらこちらのものですね。

Node.jsから試す

axiosを利用します。

$ npm ini -y
$ npm i axios
app.js
'use strict'

const axios = require('axios');
const URL = `https://outlook.office.com/webhook/~~~`; //各自のWebhook URL

axios.post(URL, {text: 'Node.jsから送信'})
    .then(res => console.log(res.data));

シンプルなコードですね。
実行します。

$ node app.js
1

res.dataには1という数字が返ってくる模様。

スクリーンショット 2020-09-15 16.53.26.png

所感

Webhook URLの発行で結構迷いました。Slack, LINE, Discordなど様々なBOTを触りましたが今回はどんなパターンだろう......といった感じです。今のところの結論はSlack BOTに近いような印象です。Incoming WebhookのアプリというかBOTアカウントをチームに追加すると、連動しているWebhook URLが発行されるといった流れ。

他にもやり方ある気がするので引き続き調べてみます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PervasiveデータベースにNode.jsから接続するサンプル

はじめに

20世紀に作られ現在も稼働中のVBのシステムにデータ出力の要件があったので、Node.jsで実装してみました。
あまりにも情報が少なすぎて苦労したので備忘録として残します。

環境

項目 内容
データベース Pervasive PSQL v10
(サービスとして起動)
OS Windwos10
node v13.9.0
jdbcライブラリ jdbc@0.7.2

準備

Pervasiveのインストールディレクトリ配下にある以下の3ファイルが必要です。

  • pvjdbc2.jar
  • pvjdbc2x.jar
  • jpscs.jar

プロジェクトディレクトリに drivers というディレクトリを作ってコピーしておきます。

ソース

PervasiveのMYDATAデータベースのMYTABLEテーブルから全レコードを取得してJSONを返すAPIサーバーのサンプルです。
なお、このプログラムにルーティングするExpress/Routerのプログラムが別途必要です。
Pervasiveのサービスが起動しているホスト上でプログラムが実行されることを前提としています。

const express = require("express");
const router = express.Router();
const JDBC = require("jdbc");
const jinst = require("jdbc/lib/jinst");

if (!jinst.isJvmCreated()) {
  jinst.addOption("-Xrs");
  jinst.setupClasspath([
    "./drivers/pvjdbc2.jar",
    "./drivers/pvjdbc2x.jar",
    "./drivers/jpscs.jar"
  ]);
}

const conf = {
  url: "jdbc:pervasive://localhost:1583/MYDATA?transport=tcp",
  drivername: "com.pervasive.jdbc.v2.Driver",
  minpoolsize: 10,
  maxpoolsize: 100,
  properties: {}
};

const initializeCB = err => {
  if (err) {
    console.log(err);
  }
};

const reserveCB = (err, connObj, sql) => {
  return new Promise((resolve, reject) => {
    if (!connObj) {
      console.log("connObj is undefined");
      reject(err);
    }
    const conn = connObj.conn;
    conn.createStatement((err, statement) => {
      if (err) {
        console.log(err);
        reject(err);
      }
      statement.executeQuery(sql, (err, resultset) => {
          if (err) {
            console.log(err);
            reject(err);
          }
          resultset.toObjArray((err, result) => {
            resolve(result);
          });
      });
    });
  });
};

module.exports = router;

/**
 * テーブルから全レコードを取得しJSONを返す
 */
router.post("/", (req, res) => {
  const jdbc = new JDBC(conf);
  jdbc.initialize(initializeCB);
  jdbc.reserve((err, connObj) => {
    reserveCB(err, connObj, "SELECT * FROM MYTABLE")
    .then(data => {
      const headers = {"Content-Type": "text/json;charset=utf-8"};
      res.set(headers).json(data);
    })
    .then(() => {jdbc.release(connObj, (err) => {if (err) {console.log(err.message);}})
    })
    .then(() => {jdbc.purge(err => {});});
  });
});

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

もうBacklogやRedmineは要らない? Exmentでガントチャート付きタスク管理を実践する

どうも、業務改善が大好きな筆者です。

さて、連日Exmentの記事を書いているわけですが、そろそろタスク管理についても触れたいなと思っています。

タスク管理といえば、TrelloやAsana、BacklogやRedmineなど、SaaSのサービスが乱立してますよね。(Redmineはオンプレも可能ですが)

一方で、Excelやスプレッドシートに書き込んで、お手製のタスク管理をされている方もいらっしゃると思います。

ガントチャート好きな人、多いですよね

筆者個人が、タスク管理でどうしても外せないのがガントチャートです。ガントチャート機能付きのタスク管理サービスというと、どうしても選択肢がせばまってきます。

今はToggl Planという名前になってTogglファミリーとなった、かつてのTeamweekが、個人的には一番好きでした。

Redmineにもガントチャートがありますが、デフォルトのあれはダメでしたね。何が良くて何がダメなのか。それはマウスでガントチャートを伸ばしたり縮めたりできるかどうかだと思ってます。

Teamweekはそれが出来たのですが、Redmineはタスクの日付を変えない限り伸び縮みしてくれませんでした…(デフォルトの話です)

ガントチャート使えるサービス、有料SaaSが多い件

Backlogのガントチャートもマウスで伸び縮みできるそうなんですが、Backlogは一零細副業家(筆者は副業の管理にExmentを試験導入しています)にとっては手が出せない価格なんですよね。基本1人で使うし… Asanaも有料プランですし…

Redmineはオンプレで使えますが、ガントチャート自体の昨日が今一つなので、試してすぐやめました…

もしガントチャート使えるのなら、タスク管理もExmentでやってみたい…

というわけで、これまでタスク管理は色々なものを主に無料プランで使ってきましたが、どれも一長一短で馴染むものがありませんでした。ガントチャートでいえばTeamweek(現:Toggl Plan)でしたが、カンバンの良さでいえばTrelloですよね…

そこに来て、現在筆者は

をExmentに集約しているので、タスク管理もここで案件と紐づけつつやってみたいなあ、という思いに至りました。なので、今回はExmentでタスク管理しつつ、API経由でガントチャートビューも実装してみたいと思います。

フロントにFrappe Ganttを採用

色々なJavaScriptのガントチャートライブラリを一通り調べてみましたが、シンプルさと機能の両立で言うと、Frappe Ganttが良いな、と思い今回採用してみました。

2020-09-15_10h14_42.png

もちろんマウスで伸び縮み出来ますし、バーを横に動かすこともできます。しかも進捗率もマウスで変更できます。

それでは、実装していきましょう。

Exment側のテーブル設計

まずは、Exment側のカスタムテーブルを用意します。カスタムテーブル名は「タスク管理」としました。

テーブル設計は

列名 列のタイプ
タイトル 1行テキスト
開始日 日付と時刻
終了日 日付と時刻
担当者 ユーザー
案件名 選択肢 (他のテーブルの値一覧から選択)
進捗率 整数(0~100)
ステータス 選択肢(値・見出しを登録)

ステータスの値と見出しは以下の通りです。

1,未整理
2,未着手
3,進行中
4,チェック待ち
5,完了
6,対応しない

フロントはExpress + pugでHTMLを出力

コスト管理(原価計算)の時のように、Express + pugで出力します。この時のapp.jsを使いまわそうと思います。なので、Expressやpugはインストール済みという前提にしたいと思います。

app.js
app.get('/tasks', async (req, res) => {

  ;(async () => {
    const exmentToken = JSON.parse(await fs.readFileSync('./exment_tokens.txt')).access_token
    let tasksData = await axios.get('https://example.com/api/data/tasks/?orderby=start_at', {
      headers: {
        'Authorization': 'Bearer ' + exmentToken
      }
    })
    .then(res => { return res.data.data })
    .catch(err => { console.error(err) })

    let tasksArray = []
    tasksData.forEach(item => {
      const id = item.id
      const name = item.value.title
      const start = moment(item.value.start_at).format('YYYY-MM-DD')
      const end = moment(item.value.end_at).format('YYYY-MM-DD')
      const progress = item.value.progress
      const custom_class = 'uplift-task'
      tasksArray.push({
        id: String(id),
        name: name,
        start: start,
        end: end,
        progress: progress,
        custom_class: custom_class
      })
    })
    // console.log(tasksArray)
    res.render('tasks-gantt', { tasks: JSON.stringify(tasksArray) })
  })()
})

まずは、タスクデータの取得です。ExmentのAPIからGETで取得し、Frappe Ganttのtaskデータ形式に整形しています。

次に、viewです。

tasks-gantt.pug
<!DOCTYPE html>
html(lang="en")
  head
    meta(charset="UTF-8")
    meta(name="viewport", content="width=device-width, initial-scale=1.0")
    title Document
    link(rel="stylesheet", href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css", integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z", crossorigin="anonymous")
    .
      <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/frappe-gantt/0.5.0/frappe-gantt.min.css" integrity="sha512-j2JEichKxgq6udg7yAJpsSwGLrHtxeTinqv4kzc+SXCJEhYzDT/JclOOOU28pD1jk1IEdt2FCQ/CnqdOzt7e6Q==" crossorigin="anonymous" />
  body
    #gantt
    .btn-group(role='group', aria-label='Basic example')
      button.btn.btn-secondary(type='button' onClick="changeDay()") Day
      button.btn.btn-secondary(type='button' onClick="changeWeek()") Week
      button.btn.btn-secondary(type='button' onClick="changeMonth()") Month

    .
      <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.26.0/moment.min.js" integrity="sha512-QkuqGuFAgaPp3RTyTyJZnB1IuwbVAqpVGN58UJ93pwZel7NZ8wJOGmpO1zPxZGehX+0pc9/dpNG9QdL52aI4Cg==" crossorigin="anonymous"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.5.1/snap.svg-min.js" integrity="sha512-Gk+uNk8NWN235mIkS6B7/424TsDuPDaoAsUekJCKTWLKP6wlaPv+PBGfO7dbvZeibVPGW+mYidz0vL0XaWwz4w==" crossorigin="anonymous"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/frappe-gantt/0.5.0/frappe-gantt.min.js" integrity="sha512-5M8ejeX3DuiV4VGIFjHP5gpryPQb1dWYjzTUhBUKj81aT6ZZz6+wIG8k89nbjsiHFJHQbi/CByHQTe4mJOi3hw==" crossorigin="anonymous"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.20.0/axios.min.js" integrity="sha512-quHCp3WbBNkwLfYUMd+KwBAgpVukJu5MncuQaWXgCrfgcxCJAq/fo+oqrRKOj+UKEmyMCG3tb8RB63W+EmrOBg==" crossorigin="anonymous"></script>
    script.
      const tasks = !{tasks}
      const options = {
        header_height: 50,
        column_width: 30,
        step: 24,
        view_modes: ['Day', 'Week', 'Month'],
        bar_height: 50,
        bar_corner_radius: 3  ,
        arrow_curve: 5,
        padding: 18,
        view_mode: 'Day',   
        date_format: 'YYYY-MM-DD',
        custom_popup_html: null,
        on_date_change: function(task, start, end) {
          axios.put('/tasks/date',{
            id: task.id,
            start_at: moment(start).format('YYYY-MM-DD HH:mm:ss'),
            end_at: moment(end).format('YYYY-MM-DD HH:mm:ss')
          })
          .then(function(res) {
            console.log(res)
          })
          .catch(function(err) {
            console.log(err)
          })
        },
        on_progress_change: function(task, progress) {
          console.log(task, progress);
          axios.put('/tasks/progress',{
            id: task.id,
            progress: progress
          })
          .then(function(res) {
            console.log(res)
          })
          .catch(function(err) {
            console.log(err)
          })
        },
      }
      const gantt = new Gantt('#gantt', tasks, options)

      function changeDay() {
        gantt.change_view_mode('Day')
      }
      function changeWeek() {
        gantt.change_view_mode('Week')
      }
      function changeMonth() {
        gantt.change_view_mode('Month')
      }

とりあえず動く、までが目標なので、あんまりきれいにまとまっていません。

まず、Frappe GanttはCDNから読み込みました。Frappe Ganttのdependanciesである、momentとsnap-svgもCDNから。Frappe GanttのinitもHTMLにべた書きです。

on_date_changeと、on_progress_changeが、バーを伸ばしたり進捗率を変更したときのコールバックになります。ここで、CDNから読み込んだaxiosを呼び出して、Exment側へPUTしています。

ExmentのAPIをJSから直接叩いても良かったのですが、認証のこともありますし、一旦Express側にAPIを作って、そこからデータを送っています。フロントとバックエンドで2回axiosのお世話になるという、なんだかなー、ということになってますが…

下記が、app.jsのPUTの箇所です。

app.js
app.put('/tasks/date', async (req, res) => {
  ;(async () => {
    const exmentToken = JSON.parse(await fs.readFileSync('./exment_tokens.txt')).access_token

    // console.log(req.body)
    await axios.put('https://example.com/api/data/tasks/' + req.body.id, {
      value: {
        start_at: req.body.start_at,
        end_at: req.body.end_at
      }
    }, {
      headers: {
        'Authorization': 'Bearer ' + exmentToken
      }
    })
    .then(res => { return res })
    .catch(err => { console.error(err) })
  })()
})

app.put('/tasks/progress', async (req, res) => {
  ;(async () => {
    const exmentToken = JSON.parse(await fs.readFileSync('./exment_tokens.txt')).access_token

    // console.log(req.body)
    await axios.put('https://example.com/api/data/tasks/' + req.body.id, {
      value: {
        progress: req.body.progress
      }
    }, {
      headers: {
        'Authorization': 'Bearer ' + exmentToken
      }
    })
    .then(res => { return res })
    .catch(err => { console.error(err) })
  })()
})

さて、うまく行けば下記のようになっているはずです。

2020-09-15_10h37_40.png

いい感じですね。

では、ドラッグアンドドロップのテストをしたいと思います。

先にExmentを開いて、開始日終了日の日付を確認しておきましょう。

2020-09-15_10h39_31.png

↑まず、日付はこうなっています。

次に、ガントチャート側でバーをドラッグして長さも変更してみましょう。

2020-09-15_10h40_44.png

ついでに、進捗率も変えちゃいましょう。

2020-09-15_10h42_30.png

では、Exment側に戻り、同じタスクの詳細画面をリロードします。

2020-09-15_10h43_44.png

しっかりと変更されてました!

しかし、課題もあります

タスクの依存関係が作れない

Frappe Gantt側ではその機能はあるのですが、Exmentでバックエンドを実装すると、同じカスタムテーブル内のレコード同士を紐づける設定が今のところないので、タスク同士の紐づけができません。

無理やり整数のカラムを作って、レコードIDを手入力することも考えられますが、それも何だかなあといった感じです。

日本語化されてない

月の表記が英語です。月だけは日本語化できそうなので、暇なときにプルリク作って送っておきますか。

土日祝日の色変更ができない

なんかIssueにはそれっぽいのが上がってるのですが、結局どうやって変更すればいいのか分かりませんでした。

ただまあ、個人的にはこれらの課題は些末なことだったので…

一旦ガントチャートにできれば十分だったので、この結果は満足しています。

もし、高度なガントチャートが必要であれば、別のライブラリを使えばいいと思います。

まとめ

  1. ExmentのAPIを使って、タスクをガントチャート化できるよ!(BacklogとかRedmineいらないかも)
  2. ガントチャートライブラリは色々あるけど、マウスでバーを伸び縮みできるのがいいなら、Frappe Ganttがおすすめ(課題はあるけど)
  3. ガントチャートライブラリは、お好みのものを選べばいいと思う。もっと高機能なものもあるしね!

といったところでしょうか。

個人的には、MFクラウド請求書で受注した見積書とタスクが紐づくことによって、Togglの記録とも連動させて

  • 営業判断
  • 工数原価管理
  • タスク管理

が一元化したのが気持ちいいなー、と思っています。BacklogやRedmineも良いですが、Exmentでタスク管理始めてみませんか?

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS lambdaで、node httpsモジュールでpostする

AWS lambda node、標準のhttpsモジュールで、chatwork APIにpostしたいと思ったが、検索してもrequest-promiseを追加しろみたいな話しかなく、AWS lambdaの標準パッケージでサクッと試したいだけだったのにサクっといかなかった。

https://nodejs.org/api/https.html#https_https_request_options_callback
公式にはgetの記述しかないのでpostができないのか、と思ったらできた。

writeにたどりつかなかった……

(参考)
https://qastack.jp/programming/6158933/how-is-an-http-post-request-made-in-node-js

const https = require('https');
const querystring = require('querystring');

exports.handler =  function(event, context){
    var postMessage = 'テスト'
    var post_data = querystring.stringify({body:postMessage});
    let options = {
        host: 'api.chatwork.com',
        path: '/v2/rooms/{roomid}/messages',
        port: 443,
        headers: {
            'X-ChatWorkToken': '{X-ChatWorkToken}',
            'Content-Type': 'application/x-www-form-urlencoded',
        },
        method: 'POST',
    };
    var post_req = https.request(options, function(res) {
        res.setEncoding('utf8');
        res.on('data', function (chunk) {
          console.log('Response: ' + chunk);
          context.succeed();
        });
        res.on('error', function (e) {
        console.log("Got error: " + e.message);
        context.done(null, 'FAILURE');
        });
     });
    post_req.write(post_data);
    post_req.end();
};
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む