📜 ⬆️ ⬇️

Simplify working with oDesk

oDesk

Hello, Habruzovateli!

In the light of a recent article, I would like to tell you the story of the emergence of a program for monitoring the amount of time logged on oDesk from the inception of the idea to the finished application.

By the nature of my work, I most often deal with the implementation of ASP.NET-based web applications. But at the same time, as a hobby, I sometimes write a desktop application. Usually these are small programs for solving narrow problems.
')
When working with clients, we often use oDesk and, in particular, I, as a developer, use the oDesk Team Room application to log the work process. And everything would be fine - time goes on, the project grows, the client is satisfied - but I often caught myself thinking that I did not have enough opportunity to view the pledged time in order to know exactly how much time I spent on the contract. Sometimes it is necessary to satisfy the specific requests of clients like “next week spend no more than 25 hours on me” and the like, and sometimes just for yourself, for statistics. Yes, of course, oDesk has a web-interface, where all this information can be obtained, but it seemed to me that was not enough, because I need to either keep the oDesk page open all the time, or periodically visit it, just to see how much time is pledged to this point.

Stage 1 - an idea


One evening while viewing the mail, I got the idea to “simplify my life for myself” when working with oDesk. First of all, I decided to make a list of what I want to get from the application. It was small, but at that time I was completely satisfied:

  1. The ability to view the pledged time for the day, week and month;
  2. Automatic update of indicators every 10 minutes;
  3. Nothing extra, I do not need a "program for everything";
  4. Minimalistic interface (“Minimum actions - maximum functionality”);
  5. Not to spend a lot of time for implementation, the ready decision needed as soon as possible.

Next, I decided to choose development tools. Because of my professional activities, I most often use C # and, moreover, I have long wanted to make a win-application using WPF technology. Why WPF? Only one by one, but a weighty reason for me at the time - these are applications “for myself” (I didn’t expect anyone else to use them) and I have long wanted to try WPF and, in particular, XAML live.

Stage 2 - Analysis and Implementation


First of all, I decided to find out how the authorization on oDesk happens. When browsing through the authorization page, I immediately noticed 3 fairly standard tags:

<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"> 


This is quite enough to log in. For authorization and further work with oDesk, I decided to use the HttpClient class. This is the standard class from .NET 4.5, but can nevertheless be used in .NET 4.0 projects. For authorization, a form is created and sent via Post-request to the server:

 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); 


Next, you need to get a list of active contracts of the logged in user. The easiest solution, as it seemed to me at that time, was to take them from the page https://www.odesk.com/team/scripts/login?initial=1&after_login_location=http%3A%2F%2Fwww.odesk.com%2Fteam% 2Fscripts% 2Freport .
The following small method was written for this:

 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); } 


Nothing complicated, just chose the values ​​using two regular expressions.
Well, in the end it was necessary to get the immediate values ​​of the counters. Looking carefully at https://www.odesk.com/team/scripts/report , I found a useful link to download the log in the form of 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


This is exactly what you need. Next, I wrote the following small code:

 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; } 


And then I added a method to get the total time for all contracts:

 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; } 


So, after everything I described, I had all the necessary methods to make a complete application. I started with a simple interface:



This is not an original screenshot. I regret that I did not make it then as a memento. But this reproduction is very similar and not bad conveys the dullness of the original. I decided to continue the next day.

The next morning, I thought, “why most often I will look at this application?”, And the answer came somehow by itself: “to monitor the time indicator for the day.” Based on this, I decided to make this indicator larger in relation to the rest. It turned out about the following:



Of course, it is already better, but still the feeling that something is missing did not leave. In the end, after some more time thinking and sketching, I came up with this option:



I liked this version more. In addition, it fits very well with the Metro UI concept of Windows 8 UI, which I really like.

After the final version of the interface design was approved, I simply translated it into XAML and added the missing interaction logic. The result is a program that can authorize itself and periodically update the indicators. This was practically what I needed.

Stage 3 - Getting Started


A couple of days later I decided that the resulting software could be shown to other colleagues and hear their feedback, comments, suggestions and suggestions. To their great surprise, they liked the idea, and I was just bombarded with a mountain of various suggestions for improving it. I decided to implement some of them, but at the same time many proposals were not accepted due to the fact that they were supposed to make a “monster” out of a small utility that can do everything. But I did not deviate from the principle that I laid at the very beginning - “nothing superfluous”.

After a few more days of improvements, some of the proposed ideas were implemented:

  1. Themes;
  2. ProgressBar to display the process of updating the readings;
  3. Slightly changed the algorithm behavior when the Internet connection is broken;
  4. Statistics for previous months ( LMB double click);
  5. Ignore list;
  6. Scalable (Ctrl + Scroll).

In the end, after all the work done, the following came out:



The last "strokes" were the choice of name and deploy to the local server. As a name, I didn’t come up with anything better (and I didn’t want to think about the name any more) than oDesktop . But, nevertheless, it seems to me that this title is quite informative.

Completion


After a short development, I got quite a convenient (at least for me exactly) program that successfully copes with the function assigned to it for the past six months. Judging by the reviews of other people, many also liked it and they use it. But, unfortunately, it is not possible to please everyone. There are those who did not like her ... I do not know what. They did not explain. Also, I tried to practice WPF.

Now I decided to share this small soft with the public, though without source codes. While they are not in a condition to be shown to anyone, they will subsequently be posted on git.

Application download page.

Now there is an idea to implement a similar application for Windows 8; this will be, in my opinion, a good continuation of this “home-based” just-for-fun project.

Thanks for attention!

Source: https://habr.com/ru/post/153055/


All Articles