11月 25

Crab apples
Creative Commons License photo credit: ahisgett

Redmine Clientというアプリケーションがあります。Windows(.NET)上で動作するRedmineのクライアントで、機能的には、

  • チケットに費やした時間を計測する
  • 時間をRedmineへ登録する
  • 新しいチケットを登録する

というシンプルなものです。C#で書かれています。

このアプリケーションにはRedmineへアクセスするためのライブラリ(DLL)が添付されており、APIの仕様も公開されています。(どちらかと言うと、アプリケーションはこのライブラリのサンプル的な位置付けなのかな?)

Redmineは0.9でRESTfulになるらしいので、それまで待とうか…という気もしないではないのですが、このライブラリのFUTURE PLANSには“Making use of Redmine 0.9 RESTfull interface”とあり、0.9でRESTfullになったら対応する模様。

ということで、安心して?試してみました。

インストールと設定

  1. ここからredmineclient-0.3.0.zipをダウンロードする。
  2. アーカイブを解凍しNohal.Redmine.dllをVisual Studioのプロジェクトで参照設定する。

これだけです。

チケット一覧を取得するための基本的な流れ

以下のような流れでチケット一覧を取得できます。簡単。

  1. Redmineオブジェクトの生成
  2. RedmineのURLを設定(Redmine.RedmineBaseUriプロパティ)
  3. Redmineへのログイン(Redmine.LogInメソッド)
  4. プロジェクト一覧の取得(Redmine.GetProjectsメソッド)
  5. プロジェクトIDを指定してチケット一覧の取得(Redmine.GetIssuesメソッド)

(載せるまでも無いですが)実際のコードはこんな感じ。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Nohal.Redmine;

namespace RedmineTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Redmine redmine = new Redmine();
            redmine.RedmineBaseUri = "RedmineのURL";
            redmine.LogIn("Redmineのユーザ名", "Redmineのパスワード");

            List<Project> projects = redmine.GetProjects();
            textBox1.Text = "プロジェクト一覧\r\n";
            foreach (Project project in projects)
                textBox1.Text += project.Id.ToString() + ": " + project.Name + "\r\n";

            textBox1.Text += "チケット一覧\r\n";
            // GetIssues(3)の3はプロジェクトID。本来はGetProjects()で取得したIDを指定する。
            foreach (Issue issue in redmine.GetIssues(3))
                textBox1.Text += issue.Id + ": " + issue.Subject + "\r\n";
        }
    }
}

ざっとAPI仕様を眺めた限りでは、条件を指定してチケットを絞り込む方法が無さそうです。
このため、指定したプロジェクトの全チケットがListで返却されますので、チケット数が数千~数万のオーダーになると厳しいかもしれませんが、チケットの登録はイケるでしょう。

C#から簡単にRedmineへアクセスできるのはいいですね。Redmineクライアントの開発をお考えての方はお試しください。

Tagged with:
11月 23

Arnage 2
Creative Commons License photo credit: ArtBrom

MPXJというMicrosoft Projectのファイルへアクセスするためのライブラリを試してみました。MPXJは以下のファイル形式に対応しています。

  • Microsoft Project Exchange (MPX)
  • Microsoft Project (MPP,MPT)
  • Microsoft Project Data Interchange (MSPDI XML)
  • Microsoft Project Database (MPD),Planner (XML).

MPXJはJavaで書かれているのですがIKVMにより.NETからも使うことができます。

インストールと設定

  1. Browse MPXJ: Microsoft Project Exchange Files on SourceForge.netからmpxj-3.1.0.zipをダウンロードし、任意のディレクトリへ展開する。
  2. 展開後lib.netディレクトリにある以下のファイルをVisual Studioのプロジェクトから参照できるように設定する。
    • IKVM.OpenJDK.ClassLibrary.dll
    • IKVM.Runtime.dll
    • mpxj.dll
    • poi-3.2-FINAL-20081019.dll
  3. MPXJのクラスリファレンスはOverview (MPXJ API)を参照

これだけ。サンプルとしてこんなコードを書いてみました。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using net.sf.mpxj;
using net.sf.mpxj.reader;
using net.sf.mpxj.writer;

namespace MPXJTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
                OpenProjectFile(openFileDialog1.FileName);
        }

        private void OpenProjectFile(string fileName)
        {
            ProjectReader reader = ProjectReaderUtility.getProjectReader(fileName);
            ProjectFile projectFile = reader.read(fileName);

            ProjectHeader projectHeader = projectFile.getProjectHeader();

            textBox1.Text = "プロジェクト名: " + projectHeader.getProjectTitle();
            textBox1.Text += "\r\nプロジェクト開始日: " + projectHeader.getStartDate();
            textBox1.Text += "\r\nプロジェクト終了日: " + projectHeader.getFinishDate();

            textBox1.Text += "\r\n担当者";
            foreach (Resource resource in projectFile.getAllResources().toArray())
                textBox1.Text += "\r\n" + resource.getID() + ": " + resource.getName();

            textBox1.Text += "\r\nタスク";
            foreach (Task task in projectFile.getAllTasks().toArray())
                textBox1.Text += "\r\n" + GetTaskLevelIndent(task) + task.getName();
        }

        private string GetTaskLevelIndent(Task task)
        {
            string level = "";
            while ((task = task.getParentTask()) != null)
                level += "|--";
            return level;
        }
    }
}

このコードは指定されたMicrosoft Projectのファイルからプロジェクト名、プロジェクト開始日、プロジェクト終了日、担当者一覧、タスク一覧をテキストボックスへ出力するものです。

マイクロソフトのWebサイトで提供しているベンダーに対する提案依頼書の要請 – テンプレート – Microsoft Office Onlineを読み込んだ結果はこちら。

プロジェクト名:
プロジェクト開始日: Mon Jan 01 08:00:00 GMT 2007
プロジェクト終了日: Thu Feb 01 12:00:00 GMT 2007
担当者
0:
1: 購買マネージャ
2: ユーザー チーム
3: 評価委員会
4: 意思決定グループ
タスク
ベンダーに対する提案依頼書 (RFP) の要請
|--このテンプレートの目的を説明するメモを読む
|--RFP の基準
|--|--RFP 作成の正式なプロセスが必要かどうかを判断する基準のレビュー
|--|--購買担当に RFP を作成する必要があることについて通知
|--RFP 要請プロセス
|--|--要求の定義
|--|--|--製品とサービスのニーズを理解するためにユーザーにインタビュー
|--|--|--要求の文書化
|--|--|--回答の評価基準の定義
|--|--|--評価チームの特定
|--|--RFP の作成
|--|--|--購買担当から RFP の書式のテンプレートを取得
|--|--|--RFP のドラフト作成
|--|--|--購買担当、該当分野の専門家と RFP をレビュー
|--|--|--RFP の改良
|--|--|--RFP の内容の準備完了
|--|--市場調査
|--|--|--該当する製品またはサービスを提供するベンダー候補企業の特定
|--|--|--事前の情報提供依頼書 (RFI) が必要かどうかを決定
|--|--|--RFI の回答の収集 (必要な場合)
|--|--|--RFP の対象企業の最終決定
|--|--業界への RFP の送付
|--|--|--特定の回答段階についての期限の決定
|--|--|--期限と連絡先を記載した RFP の完成
|--|--|--RFP を対象企業に送付
|--|--|--RFP についての説明会の実施 (必要な場合)
|--|--RFP 収集プロセスの完了
|--収集後のプロセス
|--|--"入札意思あり" の回答のまとめ
|--|--質問回答プロセス
|--|--|--入札企業からの質問のまとめ
|--|--|--質問に対する正式な回答の準備
|--|--|--'入札意思あり' と表明したすべての企業に回答を公開
|--|--提案書のレビュー
|--|--|--初期評価を実施して問題を明確化
|--|--|--設定した基準に基づいて提案書を評価
|--|--|--基準を満たしていない提案企業を除外
|--|--|--残りの提案企業との話し合いの準備
|--|--個別会議/交渉
|--|--|--最終選考に残った企業にソリューションのプレゼンテーションを依頼
|--|--|--最終選考に残った企業のソリューションとデモを分析
|--|--選択の決定
|--|--|--提案書の最終分析
|--|--|--ベンダーの選択
|--|--|--契約の締結
|--|--|--選ばれなかった提案企業からフィードバックを収集
|--|--収集後のフェーズの完了
|--ベンダーからの提案依頼書 (RFP) の収集の完了

必要な情報だけを抜いてCSV出力するようなプログラムは簡単に書けそうですね。

弊社のプロジェクト管理ソフトProjectscapeでMicrosoft Projectファイルインポート機能をサポートするのにも使えそうな感じが…もう少し評価してみたいと思います。

Tagged with:
11月 07

evernote

Evernoteは開発者向けにAPIを提供しています。

C#で書こうとしているちょっとしたプログラムの調査のため、Evernote APIをラップするC#のライブラリEvernoteSharp試してみました。

Evernote APIを使うためには、API Keyを払い出してもらう必要があります。Request an API Keyから、必要事項を書いて申し込みます。私の場合は申し込んでから1時間半ぐらいでAPI Keyがメールで送られてきました。仕事が速いですね!

API Keyは開発用環境であるSandBoxのみで有効です。このため、普段使っているアカウントとは別にEvernote Registrationからテスト専用のアカウントを登録します。

次に、Visual StudioでWindowsアプリケーションのプロジェクトを作成します。EvernoteSharpをダウンロードし、アーカイブを解凍してEvernoteSharp.dllをプロジェクトの参照設定へ追加します。準備はこれで完了。

以下のコードは、指定した画像ファイルをEvernoteのデフォルトのノートブックへ追加するものです。

using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Security.Cryptography;
using EvernoteSharp;

namespace EvernoteSample
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            StoreFactory sf = new StoreFactory(new Uri("http://sandbox.evernote.com/"), "your-api-key-here!", "your-api-secret-here!");
            UserStoreWrapper userStore = sf.CreateUserStore();

            if (!userStore.CheckVersion())
                throw new Exception("Invalid API version");
            userStore.Authenticate("your-username", "your-password");

            NoteStoreWrapper noteStore = sf.CreateNoteStore();
            Evernote.EDAM.Type.Data data = new Evernote.EDAM.Type.Data();

            FileStream fs = new FileStream(tbTitle.Text, FileMode.Open, FileAccess.Read);
            byte[] bImageFile = new byte[fs.Length];
            fs.Read(bImageFile, 0, bImageFile.Length);
            fs.Close();

            MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
            byte[] bs = md5.ComputeHash(bImageFile);
            string hashHex = BitConverter.ToString(bs).ToLower().Replace("-","");

            data.Size = bImageFile.Length;
            data.BodyHash = bs;
            data.Body = bImageFile;

            Evernote.EDAM.Type.Resource resource = new Evernote.EDAM.Type.Resource();
            resource.Mime= "image/png";
            resource.Data = data;

            Evernote.EDAM.Type.Note note = new Evernote.EDAM.Type.Note();
            var defaultNotebook = noteStore.GetDefaultNotebook();

            note.NotebookGuid = defaultNotebook.Guid;
            note.Title = tbTitle.Text;
            note.Content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
                            "<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml.dtd\">" +
                            "<en-note>" +
                            "<en-media type=\"image/png\" hash=\"" + hashHex + "\"/>" +
                            "</en-note>";

            note.Updated = note.Created;
            List<Evernote.EDAM.Type.Resource> resourceList = new List<Evernote.EDAM.Type.Resource>();
            resourceList.Add(resource);
            note.Resources = resourceList;

            noteStore.CreateNote(note);

            MessageBox.Show(tbTitle.Text + "をEvernoteへ追加しました");
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
                tbTitle.Text = openFileDialog1.FileName;
        }
    }
}

うん、これでなんとかいけそう。

Evernote APIの資料はこちらです。

Tagged with:
preload preload preload