0
0

More than 3 years have passed since last update.

Qiitaに投稿した記事のリンクを楽にWordPressに送りたい #2

Last updated at Posted at 2020-03-02

2020/03/04
デッドロックする可能性があったので一部修正しました。

2020/03/11
WordPressの記事一覧取得が10記事までしか取得できなかったので、すべての記事を取得するように修正しました。WPService.cs
リンクはこちら

シリーズ

Qiitaに投稿した記事のリンクを楽にWordPressに送りたい #1
Qiitaに投稿した記事のリンクを楽にWordPressに送りたい #3
Qiitaに投稿した記事のリンクを楽にWordPressに送りたい #4

環境

IDE:VisualStudio2019
アプリケーション:コンソールアプリ
フレームワーク:.NET Core 3.1

アプリケーションパスワードを有効化してAPIをコールしてみたが・・・

前回の続きになります。

WordPressの環境を借りている方に、アプリケーションパスワードの設定を行ってもらった。
以下サイトを参考に設定してもらった。
WordPressのRESTAPIでアプリケーションパスワードの認証がとおらないなら

更新をやってみたところ、まだエラーが起きる。401のエラーであり、権限がないとのこと。

以下で追加した名前と発行されるパスワードを「名前:パスワード」の形で設定しているのになぜエラーに・・・
image.png

TryAddWithoutValidationが動作していない

以下の戻り値がfalseになっており、Authorizationヘッダーがうまく付与されていなかった。

content.Headers.TryAddWithoutValidation("Authorization", $"Basic {credentials}");

HttpRequestMessageを使用するらしい
調べると以下のようにHttpRequestMessageを使用して、ヘッダーに追加するとよいらしい。

        public async Task<bool> UpdateWPArticle(string id, string json)
        {
            var request = new HttpRequestMessage(HttpMethod.Post, URL_FIRST + string.Format(UPDATE_ARTICLE, id));
            var credentials = Convert.ToBase64String(Encoding.UTF8.GetBytes("名前:パスワード"));            
            request.Content = new StringContent(json, Encoding.UTF8, "application/json");
            request.Headers.Add("Authorization", $"Basic {credentials}");

            var result = await HpClient.SendAsync(request);

            if (result.StatusCode == HttpStatusCode.OK)
            {
                return true;
            }
            else
            {
                return false;
            }            
        }

HttpRequestMessageを使用してもまだエラーがでる

HttpRequestMessageを使用しても依然エラーとなる。
調べてみるとどうやら

var credentials = Convert.ToBase64String(Encoding.UTF8.GetBytes("名前:パスワード")); 

の「名前:パスワード」は誤りで、「WordPressのログインユーザーID:パスワード」らしい。
しかも、パスワードは「c8cO ABCD UUb9 7DDX Rq22 1shl」のように空白区切りで発行されるが、そのまま使用するらしい。
空白は除去しないで設定することでうまくいった。
めちゃめちゃわかりにくい!!!!!

var credentials = Convert.ToBase64String(Encoding.UTF8.GetBytes("user01:c8cO ABCD UUb9 7DDX Rq22 1shl")); 

記事の更新、追加

認証に成功したので、記事の更新/追加の処理を実装し、全体的に修正しました。

QiitaService

using Newtonsoft.Json.Linq;
using System.Threading.Tasks;

namespace TestProject.QiitaToWP
{
    /// <summary>
    /// QiitaAPI呼び出しクラス
    /// </summary>
    public class QiitaService : ServiceBase
    {
        /// <summary>
        /// TOPURL
        /// </summary>
        private const string TOP_URL = "https://qiita.com";

        /// <summary>
        /// 記事一覧取得定義
        /// </summary>
        private const string GET_ARTICLELIST = "/api/v2/users/{0}/items";

        /// <summary>
        /// 記事一覧取得
        /// </summary>
        /// <param name="param">パラメータ群</param>
        /// <returns>返り値JSON配列</returns>
        public override async Task<JArray> GetArticleList(params string[] param)
        {
            var body = await HpClient.GetStringAsync(TOP_URL + string.Format(GET_ARTICLELIST, param[0]));
            return JArray.Parse(body);
        }
    }
}

WPService

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace TestProject.QiitaToWP
{
    /// <summary>
    /// WordPress API呼び出しクラス
    /// </summary>
    public class WPService : ServiceBase
    {
        /// <summary>
        /// TOPURL
        /// </summary>
        private const string TOP_URL = "http://kurosu.s1009.xrea.com";

        /// <summary>
        /// 記事取得、投稿時の定義
        /// </summary>
        private const string POSTS = "/wp-json/wp/v2/posts";

        /// <summary>
        /// 記事更新時の定義
        /// </summary>
        private const string UPDATE_POSTS = "/wp-json/wp/v2/posts/{0}";

        /// <summary>
        /// アプリケーションキー(Basic認証に使用するキー)
        /// </summary>
        private readonly string apllicationKey;

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="applicationKey">アプリケーションキー(Basic認証に使用するキー)</param>
        public WPService(string applicationKey) : base()
        {
            this.apllicationKey = applicationKey;
        }

        /// <summary>
        /// 記事一覧取得
        /// </summary>
        /// <param name="param">パラメータ群</param>
        /// <returns>返り値JSON配列</returns>
        public override async Task<JArray> GetArticleList(params string[] param)
        {
            var body = await HpClient.GetStringAsync(TOP_URL + POSTS);
            return JArray.Parse(body);
        }

        /// <summary>
        /// 記事更新
        /// </summary>
        /// <param name="id">記事ID</param>
        /// <param name="json">更新情報JSON</param>
        /// <returns>処理の成否</returns>
        public async Task<bool> UpdateWPArticle(string id, object json)
        {
            var request = this.CreateHttpRequestMessage(HttpMethod.Post, TOP_URL + string.Format(UPDATE_POSTS, id));
            request.Content = new StringContent(JsonConvert.SerializeObject(json), Encoding.UTF8, "application/json"); ;

            // リクエスト
            var result = await HpClient.SendAsync(request);

            if (result.StatusCode == HttpStatusCode.OK)
            {
                return true;
            }
            else
            {
                // エラーメッセージ
                var resultJson = JObject.Parse(await result.Content.ReadAsStringAsync());
                Console.WriteLine(resultJson["message"].ToString());

                return false;
            }
        }

        /// <summary>
        /// 記事追加
        /// </summary>
        /// <param name="json">記事情報JSON</param>
        /// <returns>処理の成否</returns>
        public async Task<bool> InsertWPArticle(object json)
        {
            var request = this.CreateHttpRequestMessage(HttpMethod.Post, TOP_URL + POSTS);
            request.Content = new StringContent(JsonConvert.SerializeObject(json), Encoding.UTF8, "application/json");

            // リクエスト
            var result = await HpClient.SendAsync(request);

            if (result.StatusCode == HttpStatusCode.Created)
            {
                return true;
            }
            else
            {
                // エラーメッセージ
                var resultJson = JObject.Parse(await result.Content.ReadAsStringAsync());
                Console.WriteLine(resultJson["message"].ToString());

                return false;
            }
        }

        /// <summary>
        /// HttpRequestMessage作成
        /// </summary>
        /// <param name="method">Httpメソッド</param>
        /// <param name="url">URL</param>
        /// <returns>HttpRequestMessage</returns>
        private HttpRequestMessage CreateHttpRequestMessage(HttpMethod method, string url)
        {
            var request = new HttpRequestMessage(method, url);

            // Basi認証ヘッダー
            var credentials = Convert.ToBase64String(Encoding.UTF8.GetBytes(this.apllicationKey));
            request.Headers.Add("Authorization", $"Basic {credentials}");

            return request;
        }
    }
}

Qiita2WP

using System.Linq;
using System.Threading.Tasks;

namespace TestProject.QiitaToWP
{
    /// <summary>
    /// QiitaToWordPressクラス
    /// </summary>
    public class Qiita2WP
    {
        /// <summary>
        /// QiitaからWordPressに記事を転送
        /// </summary>
        /// <returns>Task</returns>
        public async Task Qiita2WPArticle()
        {
            // Qiita記事取得
            var qiitaService = new QiitaService();
            var qiitaList = await qiitaService.GetArticleList("GodPhwng");

            // WP記事取得
            var wpService = new WPService("ユーザID:アプリケーションパスワード");
            var wpList = await wpService.GetArticleList();

            foreach (var qiita in qiitaList)
            {
                var url = qiita["url"].ToString();
                var title = qiita["title"].ToString();

                // Qiitaの記事URLが含まれる物を取得
                var matchArticle = wpList.FirstOrDefault(w => w["content"]["rendered"].ToString().Contains(url));

                // リクエストBody作成
                var json = new
                {
                    // 公開範囲
                    status= "publish",

                    // タイトル
                    title = title,

                    // 本文
                    content = $"\n<p>{title}<a href=\"{url}\">{url}</a></p>\n"
                };

                if (matchArticle != null)
                {
                    // 更新
                    await wpService.UpdateWPArticle(matchArticle["id"].ToString(), json);               
                }                
                else
                {
                    // 新規追加
                    await wpService.InsertWPArticle(json);
                }
            }
        }
    }
}

メインクラス

using System;
using System.Threading.Tasks;

namespace TestProject.QiitaToWP
{
    /// <summary>
    /// メインクラス
    /// </summary>
    public class Program
    {
        /// <summary>
        /// メインエントリ
        /// </summary>
        /// <param name="args">実行時引数</param>
        /// <returns>Task</returns>
        public static async Task Main(string[] args)
        {
            try
            {
                var q2wp = new Qiita2WP();

                // Qiitaの記事をWordPressに反映
                await q2wp.Qiita2WPArticle();

                Console.WriteLine("処理終了");
            }
            catch (Exception err)
            {
                Console.WriteLine(err.Message);
            }
            finally
            {
                Console.Read();
            }
        }
    }
}

動作確認

実行前
image.png

実行後
image.png
4つほど記事が追加されました。

また、既存の記事は更新されています。

気になるのはQiitaの記事投稿順になっていないことです。
WordPress側で記事作成処理が非同期で動いてそうです。

GitHubのソースリンク

TestProject

次回はタグを自動設定

現状ではタグが何も設定されていないので、Qiitaから読み取ったタグを連携してみようとおもいます。
次回

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0