
We simplify work with oDesk

Hello, habroproizolyov!
In the light of a recent article, I would like to tell you the story of the appearance of a program for monitoring the amount of pledged time on oDesk from the inception of the idea to the finished application.
By the nature of my activity, I most often engage in the implementation of web applications based on ASP.NET. But at the same time, as a hobby, sometimes I write desktop applications. Usually these are small programs for solving narrow problems.
When working with clients, we often use oDeskand, in particular, I, as a developer, use the oDesk Team Room application to log the work process. And everything would be fine - time is running out, the project is growing, the client is happy - but I often found myself thinking that I didn’t have the opportunity to view the reserved time in order to know exactly how much time I spent on the contract. Sometimes it is necessary to satisfy the specific requests of customers such as “spend no more than 25 hours on me next week” and the like, and sometimes just for yourself, for statistics. Yes, of course, oDesk has a web interface where you can get all this information, but it seemed to me not enough, since I need to either constantly keep the oDesk page open, or periodically visit it, just to see how much time is pledged to this moment.
Stage 1 - an idea
One evening, while viewing mail, I came up with the idea of "simplifying my life" 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 completely suited me:
- Ability to view pledged time per day, week and month;
- Automatic updating of indicators every 10 minutes;
- Nothing more, I do not need a “program for everything”;
- Minimalistic interface (“Minimum actions - maximum functionality”);
- Not to spend a lot of time on implementation, a ready-made solution was needed as soon as possible.
Next, I decided to choose development tools. Due to my professional activity, I most often use C # and, in addition, I have long wanted to make a win-application using WPF technology. Why WPF? Just for one reason, but significant for me at that time, these were applications “for myself” (I didn’t assume that anyone else would use it) and I had long wanted to try WPF and, in particular, XAML “live”.
Stage 2 - analysis and implementation
First of all, I decided to find out how authorization on oDesk occurs. During a quick look at the authorization page, I immediately noticed 3 fairly standard tags:
This is enough to log in. For authorization and further work with oDesk, I decided to use the HttpClient class . This is a standard class from .NET 4.5, but, nevertheless, can be used in projects on .NET 4.0. For authorization, a form is created and, through a Post-request, is sent 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();
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(@"(?<=)");
String htmlCompanies = htmlCompaniesRegex.Match(response.Content.ReadAsString()).Value;
Regex companiesRegex = new Regex("(?<=
Nothing complicated, just selected values using two regular expressions.
Well, in the end, it was necessary to get the direct values of the counters. Looking carefully at the page https://www.odesk.com/team/scripts/report , I found a useful link to download the log in the form of csv: This is exactly what you need. Further, the following small code was written:
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(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 described, I had all the necessary methods to make the finished application. I started with a simple interface:

This is not an original screenshot. I regret that I did not do it then as a souvenir. But this reproduction is very similar and well conveys the dullness of the original. I decided to continue the very next day.
On the morning of the next day, I thought about “why most often will I 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 something like the following:

Of course it’s better, but still the feeling that something is missing is still there. As a result, after some more thought and sketching, I came to this option:

I liked this option more. In addition, it fits very well with the
After the final version of the interface design was approved, I just translated it into XAML and added the missing interaction logic. The result is a program that can log in and periodically update indicators. This was almost what I needed.
Stage 3 - Getting Started
After a couple of days, I decided that the resulting software can 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 proposals 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 I was supposed to make a “monster” from a small utility that knows everything. But I did not depart from the principle that was laid down at the very beginning - "nothing more."
After several more days of refinement, some of the proposed ideas were implemented:
- Themes of design;
- ProgressBar to display the process of updating readings;
- Slightly changed the behavior algorithm when the Internet connection is broken;
- Statistics for previous months ( LMB double click);
- Ignore list;
- Possibility of scaling (Ctrl + Scroll).
As a result, after all the work done, something happened as follows: The last “touches” were the choice of name and deployment to the local server. As a name, I didn’t think of anything better (and I didn’t want to think about the name anymore) than oDesktop . But, nevertheless, it seems to me that this name is quite meaningful.

Completion
After a short development, I got a very convenient (at least for me for sure) 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 why. They did not explain. In addition, I tried to practice WPF.
Now I decided to share this small software with the public, though so far without source codes. While they are not in a condition to show them to anyone, subsequently they will be posted on git.
Application download page.
Now the idea has appeared to implement a similar application for Windows 8, which, in my opinion, will be a good continuation of this “home” just-for-fun project.
Thanks for attention!