oDeskでの作業を簡素化します

oDesk



こんにちは、habroproizolyov!



最近の記事を踏まえて、アイデアの開始から完成したアプリケーションまで、oDeskで約束された時間を監視するためのプログラムの登場の話をしたいと思います。



私の活動の性質上、私はほとんどの場合、ASP.NETに基づくWebアプリケーションの実装に従事しています。 しかし同時に、趣味として、デスクトップアプリケーションを作成することもあります。 通常、これらは狭い問題を解決するための小さなプログラムです。



クライアントとの作業では、しばしばoDeskを使用します。特に、開発者として、oDesk Team Roomアプリケーションを使用して作業プロセスを記録します。 時間が経ち、プロジェクトが拡大し、クライアントが満足します。しかし、契約に費やした時間を正確に知るために、誓約した時間を見る機会がなかったとしばしば思いました。 統計のために、「来週、私に25時間以内で過ごす」などのクライアントの特定の要求を満たす必要がある場合があります。 はい、もちろん、oDeskにはこのすべての情報を取得できるWebインターフェイスがありますが、oDeskページを常に開いたままにするか、定期的にアクセスする必要があるため、十分ではないように思えますこの瞬間に時間が約束されています。



ステージ1-アイデア



ある晩、メールを見ながら、oDeskで作業するときに「人生を簡素化する」というアイデアを思いつきました。 まず、アプリケーションから取得するもののリストを作成することにしました。 それは小さかったが、当時は私に完全に合っていた。



  1. 1日、1週間、1か月あたりの約束時間を表示する機能。
  2. 10分ごとにインジケーターを自動更新します。
  3. さらに、「すべてのためのプログラム」は必要ありません。
  4. 最小限のインターフェイス(「最小アクション-最大機能」);
  5. 実装に多くの時間を費やさないために、できるだけ早く既成のソリューションが必要でした。


次に、開発ツールを選択することにしました。 私の専門的な活動のために、私はほとんどの場合C#を使用し、さらに、WPFテクノロジを使用してwinアプリケーションを作成することを長い間望んでいました。 WPFを選ぶ理由 当時私にとって重要だった1つの理由だけで、これらは「自分用」のアプリケーションであり(他の誰かがそれを使用すると想定していませんでした)、WPF、特にXAMLを「ライブ」で試してみたかったのです。



ステージ2-分析と実装



まず、oDeskで認証がどのように発生するかを調べることにしました。 認証ページをざっと見てみると、3つのかなり標準的なタグにすぐに気付きました。



<form enctype="multipart/form-data" id="login_frm" name="" onsubmit="trim_all( this); disable_buttons(); " action="/login.php" method="post" accept-charset="utf-8"> <input id="login" type="text" maxlength="512" size="33" tabindex="1" value="" name="login" placeholder="user name" style="margin-bottom: 10px;"> <input id="password" type="password" maxlength="512" size="33" tabindex="2" value="" name="password" placeholder="password">
      
      







ログインするにはこれで十分です。 oDeskでの承認とさらなる作業のために、 HttpClientクラスを使用することにしました。 これは.NET 4.5の標準クラスですが、それでも、.NET 4.0のプロジェクトで使用できます。 承認のために、フォームが作成され、Postリクエストを介してサーバーに送信されます。



 MultipartFormDataContent data = new MultipartFormDataContent(); data.Add(new ByteArrayContent(Encoding.UTF8.GetBytes(this._login)), "login"); data.Add(new ByteArrayContent(Encoding.UTF8.GetBytes(this._password)), "password"); data.Add(new ByteArrayContent(Encoding.UTF8.GetBytes("login")), "action"); HttpResponseMessage response = this._client.Post("https://www.odesk.com/login.php", data);
      
      







次に、ログインしているユーザーのアクティブな契約のリストを取得する必要があります。 当時私に思えた最も簡単な解決策は、 https://www.odesk.com/team/scripts/login?initial = 1&after_login_location = http%3A%2F%2Fwww.odesk.com%2Fteam%ページからそれらを取得することでした2Fscripts%2Freport

このために、次の小さなメソッドが作成されました。



 this._companies = new List<String>(); HttpResponseMessage response = this._client.Get("https://www.odesk.com/team/scripts/login?initial=1&after_login_location=http%3A%2F%2Fwww.odesk.com%2Fteam%2Fscripts%2Freport"); Regex htmlCompaniesRegex = new Regex(@"(?<=<select name='selected_company'>)(\w|\W)+(?=</select>)"); String htmlCompanies = htmlCompaniesRegex.Match(response.Content.ReadAsString()).Value; Regex companiesRegex = new Regex("(?<=<option value=\")(\\w|\\W)+?(?=\">)"); foreach (Match company in companiesRegex.Matches(htmlCompanies)) { (this._companies as List<String>).Add(company.Value); }
      
      







複雑なことはなく、2つの正規表現を使用して値を選択しただけです。

結局、カウンターの直接値を取得する必要がありました。 https://www.odesk.com/team/scripts/reportのページを注意深く見ると、csvの形式でログをダウンロードするための便利なリンクが見つかりました。



www.odesk.com/team/scripts/report?company_id={_}&user_id={}&vs_users=&include_offline=1&include_overtime=0&include_online=1&include_memos=1&type=CSV&date={}&start_date={__}&end_date={__}&range=custom









これはまさにあなたが必要とするものです。 さらに、次の小さなコードが作成されました。



 private Boolean TryGetWorkedTime(String company, DateTime from, DateTime to, out TimeSpan workedTime) { workedTime = TimeSpan.FromMinutes(0); Boolean success = true; try { String timeUrl = "https://www.odesk.com/team/scripts/report?company_id={0}&user_id={1}&vs_users=&include_offline=1&include_overtime=0&include_online=1&include_memos=1&type=CSV&date={2:MM/dd/yy}&start_date={3:MM/dd/yy}&end_date={4:MM/dd/yy}&range=custom"; HttpResponseMessage response = this._client.Get(String.Format(timeUrl, company, this._login, to, from, to)); CsvReader reader = new CsvReader(new StreamReader(response.Content.ContentReadStream)); while (reader.Read()) { workedTime += reader.GetField<TimeSpan>(2); } } catch (Exception e) { workedTime = TimeSpan.MinValue; success = false; } return success; }
      
      







そして、すべての契約の合計時間を取得するメソッドを追加しました。



 public Boolean TryGetFullWorkedTime(DateTime date, ResultType type, out TimeSpan workedTime) { TimeSpan result = TimeSpan.FromSeconds(0); Boolean success = true; DateTime to = date; DateTime from = date; if (type == ResultType.Week) { from = from.AddDays(-(from.DayOfWeek == DayOfWeek.Sunday ? 6 : ((Int32)from.DayOfWeek - 1))); } if (type == ResultType.Month) { from = new DateTime(from.Year, from.Month, 1); } Object synchroPoint = new Object(); // get counter for each company (in parallel). if (this.Companies != null && this.Companies.Any()) { Parallel.ForEach(this.Companies.Except(this.IgnoredCompanies), company => { TimeSpan time; if (this.TryGetWorkedTime(company, from, to, out time)) { lock (synchroPoint) { result += time; } } else { success = false; result = TimeSpan.MinValue; } }); } else { success = false; result = TimeSpan.MinValue; } workedTime = result; return success; }
      
      







したがって、すべてを説明した後、既製のアプリケーションを作成するために必要なすべての方法がありました。 シンプルなインターフェースから始めました。







これは元のスクリーンショットではありません。 お土産としてやらなかったことを後悔しています。 しかし、この再現は非常によく似ており、オリジナルのくすみをよく伝えています。 私は翌日を続けることにしました。



翌日の朝、「このアプリケーションを見る頻度が最も高いのはなぜですか」と考えました。そして、その日の答えは「その日の時間インジケーターを監視する」ということでした。 これに基づいて、私はこの指標を他の指標に比べて大きくすることにしました。 およそ次のことが判明しました。







もちろん、それはすでにより良いですが、まだ何かが欠けているという感覚はまだそこにあります。 その結果、さらに検討とスケッチを重ねた後、私はこのオプションに到達しました。







私はこのオプションがより好きでした。 さらに、Windows 8 UIのMetro UIコンセプトにも非常によく適合します。



最終的なインターフェイス設計が承認された後、単純にXAMLに変換し、欠落している対話ロジックを追加しました。 その結果、それ自体にログインし、インジケータを定期的に更新できるプログラムができます。 これはほとんど私が必要としていたものでした。



ステージ3-はじめに



数日後、結果のソフトウェアを他の同僚に見せて、フィードバック、コメント、提案、提案を聞くことができると決めました。 彼らの驚いたことに、彼らはそのアイデアを気に入っており、それを改善するためのさまざまな提案が山ほどありました。 それらのいくつかを実装することにしましたが、同時に、すべてを知っている小さなユーティリティから「モンスター」を作成することになっていたため、多くの提案が受け入れられませんでした。 しかし、私は最初に定められた原則「これ以上ない」から逸脱しませんでした。



さらに数日間の改良の後、提案されたアイデアのいくつかが実装されました。



  1. デザインのテーマ;
  2. 更新プロセスを表示するProgressBar。
  3. インターネット接続が切断されたときの動作アルゴリズムをわずかに変更しました。
  4. 前月の統計( LMBダブルクリック);
  5. リストを無視する;
  6. スケーリングの可能性(Ctrl +スクロール)。


その結果、すべての作業が完了した後、次のようなことが起こりました。







最後の「タッチ」は、名前の選択とローカルサーバーへの展開でした。 名前としては、 oDesktopよりも良いものは考えませんでした(そして、その名前についてもう考えたくありませんでした) 。 しかし、それにもかかわらず、この名前は非常に意味があるように思えます。



完了



短い開発の後、私は非常に便利なプログラムを手に入れました(少なくとも私にとっては)過去6か月間に割り当てられた機能にうまく対処できました。 他の人のレビューから判断すると、多くの人もそれを気に入っており、彼らはそれを使用しています。 しかし、残念ながら、みんなを喜ばせることはできません。 彼女を好きではなかった人がいます...私は理由がわかりません。 彼らは説明しませんでした。 さらに、WPFを実践してみました。



今、私はこの小さなソフトインカをソースコードなしで一般に公開することにしました。 誰にも見せられる状態ではありませんが、その後gitに投稿されます。



アプリケーションのダウンロードページ。



これで、Windows 8用の同様のアプリケーションを実装するというアイデアが浮上しました。これは、私の意見では、この「ホーム」でおもしろいプロジェクトの良い継続です。



ご清聴ありがとうございました!



All Articles